oscript-ui
oscript-ui

Каркас страницы

Каркас печатает всё, что стоит вокруг экрана: голову документа с темой, шапку, единое меню, подвал и скрипты. Экран отдаёт ему только содержимое.

Что печатает каркас#

  • Голову: кодировку, viewport, color-scheme, заголовок вкладки, значки, карточку ссылки Open Graph, токены темы инлайном, базовый лист кита, лист инсталляции.
  • Шапку: знак, верхние дороги, переключатель темы и действия инсталляции справа.
  • Единое меню: если слот заполнен — бургер на телефоне и панель с дорогами, разделами экрана и темой.
  • Основное: ваше содержимое в <main>.
  • Подвал с подписью инсталляции.
  • Скрипты: скрипт кита, затем скрипт инсталляции, оба отложенные.

Токены темы печатаются в голове, а не лежат в листе: страница приезжает уже нужного цвета и не мигает, пока лист в пути. Тема и акцент берутся из cookie посетителя поверх оформления инсталляции.

Вызов#

Контекст = Каркас.КонтекстСтраницы(Пользователь, КукиЗапроса, ПоказатьАдмин, Приватная, ПутьЗапроса, Сессия);
Ответ.ТелоТекст = Каркас.Страница("Проекты", Холст, Контекст, РазделыЭкрана);

Сессия (необязательная, дев-сборка 10) — сессия запроса, которую уже прочитал страж приложения: кит её не читает, а довозит до обрамления полем Контекст.Сессия — оттуда берут токен формы выхода, не читая сессию по куке второй раз. Двери, которые получают готовый контекст, добавляют сессию Каркас.КонтекстССессией(Контекст, Сессия).

Содержимое — узел холста или готовая строка HTML. РазделыЭкрана — разделы текущего экрана: на телефоне они уезжают в единое меню отдельной секцией. Именно так оглавление этой документации попадает в шторку на узком экране.

КаркасСтраницы.КонтекстСтраницы()src/Классы/каркас/КаркасСтраницы.os

Собирает контекст запроса. КукиЗапроса обязательны: страница без них молча потеряла бы
оформление читателя, поэтому тот, кому нечего передать, пишет Неопределено явно.

Параметры:
 Пользователь  - Произвольный, Неопределено - принципал запроса; посетитель —
                 Неопределено.
 КукиЗапроса   - Куки, Неопределено - куки запроса winow.
 ПоказатьАдмин - Булево - (необязательный, по умолчанию Ложь) показывать ли разделы
                 администратора в навигации приватной части.
 Приватная     - Булево - (необязательный, по умолчанию Ложь) страница приватной
                 части: над содержимым встаёт её навигация.
 Путь          - Строка - (необязательный, по умолчанию "") путь текущего запроса.
                 Кит его НЕ разбирает и ни с чем не сравнивает — только довозит
                 до обрамления: какая дорога сейчас активна, знает инсталляция,
                 потому что адреса дорог придумала она. Пусто — как было раньше.
 Сессия        - Произвольный, Неопределено - (необязательный, дев-сборка 10) сессия
                 запроса, которую уже прочитал страж: токен формы выхода, срок. Кит её
                 не читает — довозит до обрамления (Обрамление(Контекст).Сессия), чтобы
                 страница собиралась из одного чтения сессии, а не второго по куке.

Возвращаемое значение:
 Структура - Пользователь, КукиЗапроса, ПоказатьАдмин, Приватная, Путь, Сессия.

КаркасСтраницы.КонтекстССессией()src/Классы/каркас/КаркасСтраницы.os

Контекст страницы с сессией запроса (дев-сборка 10): тот же контекст, что пришёл, и сессия,
прочитанная стражем, — для дверей, которые получают готовый контекст или собирают его
в одном месте, а сессию узнают позже.

Параметры:
 Контекст - Структура - контекст запроса, см. КонтекстСтраницы().
 Сессия   - Произвольный - сессия запроса.

Возвращаемое значение:
 Структура - копия контекста с полем Сессия.

КаркасСтраницы.Страница()src/Классы/каркас/КаркасСтраницы.os

Полный HTML-документ вокруг содержимого.

Параметры:
 Заголовок      - Строка - заголовок вкладки; пустой оставляет во вкладке один знак.
 Содержимое     - ЭлементЭкрана, Строка - то, ради чего страницу открыли. Строка —
                  ДОВЕРЕННЫЙ HTML непереведённого экрана, она заворачивается в готовый
                  фрагмент.
 Контекст       - Структура - контекст запроса, см. КонтекстСтраницы().
 РазделыЭкрана  - Массив, Структура, Неопределено - (необязательный, по умолчанию
                  Неопределено) разделы ТЕКУЩЕГО экрана (Подпись, Адрес, Иконка, Активен,
                  Рубрика, Опасный, Счётчик, ПодписьСчётчика) — их знает не инсталляция,
                  а сама страница, поэтому они приходят сюда, а не обрамлением. Уезжают
                  в единое меню первой группой под учёткой; пусто — группы нет. Структура
                  Заголовок, Разделы называет группу именем экрана; у массива группа
                  подписана заголовком дома настроек (Кит.ДомНастроек), если он — содержимое
                  страницы, иначе словарём (chrome.menu.section.screen). Не передан, а
                  содержимое — дом: разделы берутся у дома, группа называется его заголовком.
 КарточкаСсылки - Массив из Структура, Неопределено - (необязательный, по умолчанию
                  Неопределено) свойства карточки, которую чужой сервис строит по ссылке
                  на страницу: Свойство (og:title, og:image…) и Содержание. Печатаются
                  в голове объявлениями <meta property> в порядке массива; пара с пустым
                  свойством или содержанием не печатается. Пусто — голова прежняя.

Возвращаемое значение:
 Строка - HTML-документ.

Обрамление — контракт инсталляции#

Как приложение называется, куда ведут его дороги и где его лист стилей, кит не знает. Это знает обрамление — желудь с прозвищем ОбрамлениеИнсталляции. Кит везёт пустое обрамление по умолчанию, а приложение подставляет своё с пометкой &Верховный.

Функция Обрамление(Знач Контекст) Экспорт

	Результат = Новый Структура();
	Результат.Вставить("Язык", "ru");
	Результат.Вставить("Знак", "Ромашка");
	Результат.Вставить("Разделы", Дороги(Контекст.Путь));
	Результат.Вставить("АдресСтилей", Активы.Адрес("ромашка.css"));
	// … остальные поля — см. справку ниже
	Возврат Результат;

КонецФункции

&Верховный
&Прозвище("ОбрамлениеИнсталляции")
&Желудь
Процедура ПриСозданииОбъекта(&Пластилин(Значение = "АктивыСтатики") _Активы) Экспорт
	Активы = _Активы;
КонецПроцедуры

Обрамление спрашивается на каждый запрос: знак, активная дорога и имя вошедшего меняются от запроса к запросу. Путь текущего запроса приходит в Контекст.Путь, и активную дорогу вычисляет само приложение.

ОбрамлениеИнсталляцииПоУмолчанию.Обрамление()src/Классы/каркас/ОбрамлениеИнсталляцииПоУмолчанию.os

Чем инсталляция обрамляет содержимое страницы. Спрашивается НА КАЖДЫЙ запрос:
и знак, и разделы, и имя вошедшего меняются от запроса к запросу.

Параметры:
 Контекст - Структура - контекст запроса: Пользователь, КукиЗапроса, ПоказатьАдмин,
            Приватная, Путь (путь текущего запроса; кит его не разбирает, а довозит
            сюда — по нему инсталляция и решает, какая её дорога активна).

Возвращаемое значение:
 Структура:
  Язык             - Строка - код языка страницы; "" — язык не объявляется;
  Знак             - Строка - как инсталляция называет себя в шапке и во вкладке;
  Подпись          - Строка - строка подвала;
  ПолитикаПерехода - Строка - что уходит наружу в заголовке перехода;
  АдресСтилей      - Строка - адрес СВОЕГО листа стилей; он встаёт вторым после
                     базового листа библиотеки и потому перебивает его правила.
                     Пусто — инсталляции хватает базового листа;
  АдресСкрипта     - Строка - адрес скрипта страницы;
  Иконки           - Массив из Структура(Отношение, Тип, Размеры, Адрес);
  Знамя            - Структура(Адрес, Ширина, Название): картинка знака, её известная
                     ширина в пикселях (0 — пропорции произвольны, считает браузер)
                     и печатать ли название рядом с картинкой;
  Разделы          - Массив из Структура(Подпись, Адрес, Иконка) — верхняя навигация;
  Приватные        - Массив той же формы — навигация приватной части; пустой массив
                     означает, что страница публичная;
  Действия         - Массив - что стоит в шапке справа от дорог, по порядку: вход,
                     кабинет, выход, меню учётки, ссылка на репозиторий — что угодно.
                     Кит своих действий не сочиняет. Элемент — модель кнопки кита
                     (Структура: Подпись, Адрес, Иконка, Вариант, ТолькоИконка…), узел
                     холста (Кит.Меню с полем Аккаунт — меню учётки; Кит.ФормаБезТокена —
                     форма выхода) либо ДОВЕРЕННЫЙ фрагмент HTML (Строка). На телефоне
                     с единым меню действия уезжают в его панель кнопками во всю ширину;
  МенюХаба         - Структура, Неопределено - слот ЕДИНОГО меню инсталляции. Заполнен —
                     дороги, тема, действия и учётка собираются в одну панель.
                     На широком экране шапка прежняя (знак, дороги, тема, действия),
                     а кнопка учётки открывает панель выпадающим меню; на телефоне
                     полоса ходов прячется, слева встаёт бургер, панель выезжает
                     шторкой. Поля:
                     Счётчик и ПодписьСчётчика — сумма дел на бургере и как она
                     зовётся в речи. ПРАВИЛО ПАРЫ: задано непустое ненулевое число —
                     обязана быть и подпись, иначе меню не соберётся; ноль и пусто
                     не печатаются вовсе. Правило одно и то же для суммы на бургере
                     и для числа у пункта;
                     Учётка — Структура(Логин, Роль, Адрес): вошедший, его роль словами
                     и ход в кабинет. Логин пуст — блока учётки нет;
                     Дела — Массив(Подпись, Адрес, Иконка, Счётчик, ПодписьСчётчика,
                     Активен): личные дела с РАЗДЕЛЬНЫМИ числами;
                     Настройки — Массив той же формы, что Дела: ходы в настройки
                     (свои и приложения), отдельной группой после дел; в сумму на
                     бургере их числа не входят;
                     Навигация — Массив(Подпись, Адрес, Иконка, Активен): дороги хаба;
                     они же становятся значками рейки. Активен подсвечивает дорогу
                     В ОБОИХ местах разом — и пункт панели, и значок рейки. Активен
                     вычисляет ИНСТАЛЛЯЦИЯ, сравнивая свои адреса с Путём контекста:
                     кит адресов не знает и сравнивать их не берётся;
                     разделы ТЕКУЩЕГО экрана в слот НЕ входят: их знает не инсталляция,
                     а сама страница, и они приходят четвёртым параметром
                     КаркасСтраницы.Страница(..., РазделыЭкрана);
                     Выход — форма выхода в подвале панели: узел холста (дев-сборка 10:
                     Кит.Форма(…) с токеном, собранная деревом) либо ДОВЕРЕННЫЙ фрагмент
                     строкой, как прежде.
                     Ни дел, ни навигации, ни логина — слот пуст, и шапка остаётся
                     прежней целиком;
  Адреса           - Структура(Корень, Оформление): ход знака и адрес POST
                     переключателя темы. Пустое Оформление — переключателя нет.

Дев-сборка 10: в контексте приходит и Сессия — сессия запроса, которую уже прочитал страж
(КаркасСтраницы.КонтекстСтраницы, шестой параметр): из неё берут токен формы выхода, не
читая сессию по куке второй раз.

Действия шапки#

Справа от дорог стоит то, что даёт приложение полем обрамления Действия, — по порядку и ничего сверх. Кит своих кнопок в шапку не добавляет: у сайта без учёток не появится «Войти», у приложения с учётками вход и меню учётки — его собственные действия.

Элемент — узел холста, модель кнопки кита (прежний вид) или готовый HTML:

Функция Действия(Знач Вошедший)

	Результат = Новый Массив();
	Если НЕ ЗначениеЗаполнено(Вошедший) Тогда
		Результат.Добавить(Кит.Кнопка("Войти").Вторичная().Адрес("/вход").Иконка("аккаунт"));
		Возврат Результат;
	КонецЕсли;

	Результат.Добавить(Кит.Меню("Меню учётки",
		Кит.ПунктМеню("Личное", "/личное").Иконка("аккаунт"),
		Кит.ФормаБезТокена("/выход", Кит.Кнопка("Выйти").Иконка("выход")).Вид("меню"))
		.Аккаунт(Вошедший));
	Возврат Результат;

КонецФункции

Так выглядят оба случая:

Гость — действие «Войти»

HTML = Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Адрес, Вариант, Иконка", "Войти", "/вход", "вторичная", "аккаунт"));

Вошедший — меню учётки действием

HTML = Кит.Меню("Меню учётки", Кит.ПунктМеню("Личное", "/личное").Иконка("аккаунт")).Аккаунт("алиса").Рендер();

На телефоне с единым меню полоса ходов спрятана, поэтому действия повторяются в его панели кнопками во всю ширину. Переключатель темы — возможность кита, и включает её адрес Адреса.Оформление: нет адреса — нет и переключателя.

Переключатель — обычная POST-форма на этот адрес, и без скрипта она работает перезагрузкой страницы. Со скриптом кита тема меняется сразу, без перезагрузки: обе палитры уже в голове страницы, а форма уходит на сервер в фоне, и cookie, как и прежде, пишет сервер. От инсталляции требуется одно: после записи cookie перенаправить обратно на страницу, с которой пришёл запрос.

Выглядит переключатель пилюлей с бегунком, как на сайте oscript.io: дорожка 44 × 24, в бегунке солнце в светлой теме и луна в тёмной. Это кнопка отправки формы с ролью переключателя (role="switch"): включён — тёмная тема, имя — состояние словами из словаря (theme.switch.dark — «Тема: тёмная», theme.switch.light — «Тема: светлая»), подсказка — куда переключит (chrome.top.theme.to-light, chrome.top.theme.to-dark). Бегунок стоит по теме страницы, поэтому со скриптом он едет в тот же миг, что перекрашивается страница (0.2 с; при «уменьшить движение» — без перехода). В шторке единого меню переключатель — строкой: подпись словами, пилюля в конце строки. В дереве экрана он узел компонент[переключатель-темы] — его печатает каркас (Кит.ПереключательТемы).

Остальные контракты#

Прозвище Что даёт приложение Что будет без него
ОбрамлениеИнсталляции знак, дороги, подпись, свой лист и скрипт, слоты меню пустая шапка без знака
СловарьИнтерфейса тексты шапки и меню по ключам chrome.* на месте текста ключ в скобках [?chrome.menu.open]
СтатикаИнсталляции свой каталог статики и список файлов раздаются только файлы кита
ОформлениеИнсталляции тема и акцент по умолчанию, имя cookie тёмная тема, базовый акцент, cookie ui

Готовые реализации всех четырёх — в исходниках этого сайта: документация/src/Классы/сайт/.

Гайдлайны#

  • Отдавайте каркасу узел холста, а не склеенную строку: так экран остаётся деревом до последнего момента.
  • Активную дорогу вычисляйте в обрамлении по Контекст.Путь. Кит адресов не знает и сравнивать их не берётся.
  • Не печатайте второе единое меню руками: его идентификатор на странице один, и вторая кнопка открыла бы чужую панель.