К содержанию

Навигация

Персональный вид

Всё, что человек меняет во внешнем виде элемента, запоминается одинаково: порядок, ширина, видимость и закрепление колонок, сортировка, размер страницы, ширина панели. Для этого во Framework есть одно хранилище — SF.Preferences. Без сервера вид хранится в браузере, а на сайте с личными настройками (Larena) — ещё и у пользователя на сервере, и применяется до первой отрисовки: первый кадр с колонками данных уже стоит в раскладке человека.

Что считается видом

  • Вид — раскладка, порядок, размеры, видимость, сортировка, плотность, свёрнутость. Его хранит SF.Preferences.
  • Не вид — данные и фильтры со значениями. Сохранённый набор фильтров — это именованное представление, которым делятся; оно хранится отдельно.

Ключ и значение

Вид хранится под ключом <компонент>/<экземпляр>: sf-table/cms.solutions, sf-resizer/menu. Экземпляр — постоянное имя того, что показывается (коллекция, меню); его компоненту передаёт атрибут, например preferences-key у таблицы или storage-key у изменения ширины. Без ключа ничего не запоминается: таблица-пример в документации остаётся чистой.

Значение — обычный JSON-объект, которым владеет компонент; он читает только известные ему поля и не перезаписывает значение более новой версии, которое не понимает. Ключ, версию формата и поля значения компонент объявляет в манифесте (persistence.view_preference, см. Манифест); они перечислены в Поля значения. Значение таблицы под sf-table/<экземпляр> складывается из полей, которые пишут таблица и представление данных.

Поля значения

Раздел собран из манифестов выпуска ui-106d5901f8c3 и пакетов и обновляется вместе с ними. Поля объявляет persistence.view_preference.

<sf-resizer>

Ключ sf-resizer/<storage-key>; версия формата — v: 1. В столбце «Для первой отрисовки» «да» значит, что сервер может положить поле в блок data-sf-preferences страницы.

Поле Тип Пишет Для первой отрисовки Что в нём
width integer sf-resizer да Ширина, до которой человек дотянул панель, в пикселях CSS; при применении ограничивается min и max.

<sf-table>

Ключ sf-table/<preferences-key>, общий для всех элементов этого вида — sf-table/*; версия формата — v: 1. В столбце «Для первой отрисовки» «да» значит, что сервер может положить поле в блок data-sf-preferences страницы.

Поле Тип Пишет Для первой отрисовки Что в нём
columnSettings object sf-table да Раскладка колонок человека по ключу колонки: visible (логическое), width (длина CSS), order (число), pinned (start или end). Накладывается на настройки колонок хоста, поэтому колонка, которой в ней нет, остаётся как у хоста.
widths object sf-table да Ширины колонок, которые человек задал перетаскиванием, по ключу колонки, в виде "<N>px". Хранятся и без preferences-key, если у таблицы есть remember-widths, — тогда под собственным ключом таблицы.
view object sf-table да Вид таблицы: density (compact, normal, spacious), stripes, lines, singleLine, stickyHead. Под sf-table/* это вид всех таблиц человека; он читается под видом этой таблицы.
sort array sf-data-view да Сортировка, которую выбрал человек: [{key, direction}]. Пишет и читает представление данных, в котором стоит таблица, поэтому первый запрос уже приходит в этом порядке.
pageSize integer sf-data-view да Размер страницы, который выбрал человек. Пишет и читает представление данных, поэтому первый запрос уже просит этот размер.

Где хранится

Где Когда Как
Браузер всегда localStorage, ключ sf-pref:<ключ>; это ещё и кеш для первой отрисовки
Сервер, у пользователя когда страница подключила хранилище хоста SF.Preferences.useHost(adapter); значения хоста важнее браузерных

Копия в браузере принадлежит браузеру, а не человеку: её видит каждый, кто входит на сайт с этого браузера. Поэтому на сайте с личными настройками сервер кладёт в страницу каждый ключ, который она читает, — и null для ключа, которого у человека нет (см. Подключение хранилища хоста). Иначе человек увидит вид предыдущего, а после «Сбросить» на другом устройстве — старую копию из браузера.

Запись в браузер происходит сразу, на сервер — с задержкой 400 мс на ключ, а при уходе со страницы всё, что ждёт, отправляется немедленно. Если вид поменяли в другой вкладке, компоненты получают новое значение.

Компонент сам localStorage не трогает: это проверяет контракт Framework.

Подключение хранилища хоста

SF.Preferences есть сразу после выполнения core.js, поэтому хранилище хоста подключают встроенным скриптом сразу после него, до того как Loader загрузит Smart-элементы:

JavaScript
SF.Preferences.useHost({
  save: (key, value) => fetch(`/admin/preferences/${encodeURIComponent(key)}`, {
    method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(value), keepalive: true,
  }),
  remove: (key) => fetch(`/admin/preferences/${encodeURIComponent(key)}`, {method: 'DELETE', keepalive: true}),
  load: (keys) => fetch(`/admin/preferences?keys=${keys.map(encodeURIComponent).join(',')}`).then((r) => r.json()),
});

save обязателен, remove и load — нет. load(keys) получает массив ключей и возвращает обещание объекта {ключ: значение}; в примере ключи идут в адрес через запятую, каждый закодирован encodeURIComponent. Ключ, которого у человека нет, хост возвращает со значением null: ключ, которого в ответе нет, остаётся с копией из браузера. keepalive: true нужен потому, что при уходе со страницы отложенные записи отправляются из обработчика pagehide, и без него браузер может оборвать запрос.

save получает только ключ и значение, без ревизии: побеждает последняя запись. Если обещание save или remove отклонено, SF.Preferences пишет предупреждение в консоль и запись не повторяет. Если вид человека меняют с нескольких устройств и потерянная запись важна, защиту от конфликта делает адаптер: хранит ревизию, которую сервер отдал со значением, отправляет её с записью (например, в заголовке If-Match), а на отказ сервера читает текущее значение, сливает его со своим и записывает снова.

Чтобы и первый заход с нового устройства был в виде человека, сервер кладёт его значения прямо в страницу — они читаются до первой отрисовки:

HTML
<script type="application/json" data-sf-preferences>
  {"sf-table/cms.solutions": {"v": 1, "sort": [{"key": "updated", "direction": "desc"}], "pageSize": 50,
   "columnSettings": {"code": {"order": 10, "visible": true, "pinned": false, "width": "120px"}}},
   "sf-tabs/vm-record": null}
</script>

Сервер кладёт в блок каждый ключ, который читает страница. Если у человека значения нет, ключ всё равно стоит в блоке со значением null, как sf-tabs/vm-record выше: null стирает копию в браузере. Без него страница возьмёт копию из браузера — вид человека, который входил с этого браузера раньше, или раскладку, которую на другом устройстве уже сбросили.

Блок может стоять в любом месте страницы до подключения компонентов: он читается один раз, при первом чтении вида.

То же делает SF.Preferences.preload(values) из кода. Значения, которые расходятся с браузерной копией, заменяют её, и компоненты получают новое значение. Таблица накладывает раскладку из нового значения на колонки, которые дал хост: колонка, которой в значении нет, возвращается к настройкам хоста.

Чтение и запись

Функция Что делает
read(key) значение под ключом: хоста, если он его дал, иначе браузера; сразу, без ожидания
readMerged(...keys) несколько ключей от общего к частному, слитые по полям: sf-table/* (общие настройки таблиц человека) под sf-table/<экземпляр>
write(key, value) записать вид; значение, равное уже хранимому, не записывается и хосту не отправляется
remove(key) «Сбросить вид»: убрать из браузера и с сервера
subscribe(key, fn) узнавать о новом значении — из другой вкладки, от хоста и после remove(key) на этой странице (со значением null); возвращает функцию отписки
load(keys) запросить у хоста ключи, которых он ещё не дал (компонент появился позже)
flush() отправить отложенные записи сейчас; работает сразу и ничего не возвращает

Раскладка таблицы: предпочтение и слой порта

У <sf-data-view> раскладку колонок помнят два места, и у каждого своя роль:

  • Предпочтение sf-table/<preferences-key> — значение из таблицы выше. Оно читается до первого запроса: запрос несёт сортировку и размер страницы человека, а первый кадр с колонками данных стоит в его раскладке. Сортировка и размер страницы хранятся только здесь.
  • Личный слой порта — data.column_settings.layers.personal в ответе приложения на запрос. При изменении колонок представление отправляет приложению намерение settings.save_personal с ревизией этого слоя, и приложение записывает раскладку у себя с проверкой ревизии.

Изменение колонок записывается в оба места сразу. На экране действуют колонки из ответа приложения (data.columns с их порядком, шириной и видимостью), а поверх них — предпочтение. Слои порта представление к таблице само не применяет: ревизия слоя нужна ему для записи.

Поэтому приложение, которое хочет, чтобы раскладка человека была на любом устройстве, делает одно из двух: подключает хранилище хоста и кладёт значения в блок data-sf-preferences, или учитывает личный слой, когда собирает data.columns. Ответ на запрос несёт личный слой с ревизией или хотя бы target с ней: без ревизии запись колонок не отправляется (см. Представление данных → Шаблоны и настройки колонок).

Уровни

Вид складывается из уровней, поздний уровень важнее по каждому полю:

  1. значение по умолчанию компонента;
  2. значение по умолчанию у хоста для экземпляра — то, что хост отдаёт в своих данных: у представления данных это колонки data.columns с их порядком, шириной и видимостью;
  3. общие предпочтения человека для всех таблиц — плотность, полосы, перенос (sf-table/*);
  4. вид человека для этого экземпляра (sf-table/<экземпляр>).

Сброс

Компонент, который хранит вид, предлагает «Сбросить вид» там, где лежат его настройки. Кнопка «Сбросить» в настройках таблицы убирает из значения раскладку колонок (columnSettings и widths), а сортировку, размер страницы и view оставляет; в <sf-data-view> она ещё записывает пустую раскладку {} в личный слой порта против его ревизии. Ширину панели сбрасывает двойной щелчок по ручке.

SF.Preferences.remove(key) из кода страницы стирает значение целиком и в браузере, и у хоста; открытая таблица сразу возвращается к колонкам, которые дало приложение. Сортировку и размер страницы открытого представления remove() не меняет: они вернутся к значениям по умолчанию после перезагрузки. Кнопка страницы «Сбросить вид таблицы» поэтому делает три шага:

JavaScript
SF.Preferences.remove('sf-table/cms.solutions');
view.resetColumnSettings();
view.changeQuery({sort: [], per_page: 25, page: 1});

Какие компоненты уже хранят вид

  • Изменение ширины — ширина панели под sf-resizer/<storage-key>.
  • Представление данных — раскладка таблицы, сортировка и размер страницы под sf-table/<preferences-key>.
  • Меню администратора Larena — свёрнутость и открытый раздел под sf-admin-menu/main; ширины колонок навигации порта хранят его ручки под sf-resizer/admin-nav-first и sf-resizer/admin-nav-second.

Вкладки с configurable вид не хранят: порядок и скрытые вкладки приходят событием sf-tabs-settings-change, и приложение сохраняет их само — у себя или через SF.Preferences.write('sf-tabs/<ключ>', {v: 1, order, hidden}) — и возвращает методом setSettings(). v — версия формата значения, как у таблицы и панели.

Смотрите также

Поиск по документации

Введите минимум 2 символа

    Настройки

    Тема
    Размер шрифта
    Ширина страницы