Шаблон веб-страницы

Введение

Controls/Application — это контрол, в TMPL-файле которого описана вёрстка страницы, включая теги html, head, body и многие другие. С точки зрения контролного подхода построения страниц приложения, Controls/Application является родителем (вершина иерархии) по отношению к любым другим контролам. Его нужно использовать в качестве шаблона страниц, а также можно применить для создания собственных шаблонов.

Благодаря API Controls/Application можно изменить заголовок страницы, основной контент, подключить внешние библиотеки, скрипты. В Таблице 1 приведён список опций контрола.


Таблица 1. API контрола Controls/Application.
Имя опцииТипОписание
titleStringЗаголовок страницы. Встраивается в содержимое тега title.
head (deprecated, используйте опцию headJson)HTMLРазметка, которая будет встроена в содержимое тега head. Используйте эту опцию, чтобы подключить на страницу внешние библиотеки (скрипты), стили или шрифты.

Когда для файла установлен относительный путь, то он будет рассчитан от корня сайта, а не от виртуального каталога сервиса (см. опция virtual directory). Например, для сервиса wi.sbis-doc опция virtual directory установлена в значение /materials/. Т.е. интерфейс сервиса будет доступен по адресу /materials/. Затем вы создаете контрол с такой разметкой в *.tmpl.
<Controls.Application>
    <ws:head>
        <link rel="stylesheet" href="/online.css" type="text/css" />
    </ws:head>
    ...
</Controls.Application>
Файл online.css будет запрошен по адресу /online.css.
headJsonJsonMLРазметка, которая будет встроена в содержимое тега head. Используйте эту опцию, чтобы подключить на страницу внешние библиотеки (скрипты), стили или шрифты.

Список разрешённых тегов: link, style, script, meta, title.

Список разрешённых атрибутов: rel, as, name, sizes, crossorigin, type, href, property, http-equiv, content, id, class.

Пример 1. Значение опции задаётся в JS-модуль и передаётся в шаблон контрола.

Пример 2. Значение опции устанавливается в шаблоне контрола.
appRootStringКорень приложения. Относительно него создаются пути к ресурсам приложения. По умолчанию установлен просто слеш — /.
contentHTMLРазметка, которая будет встроена в содержимое тега body.
bodyClassStringДополнительный CSS-класс, который будет задан для тега body.

Схематично разметку контрола можно представить следующим образом:

<html>
    <head>
        {{ headJson }}
        <title>{{ title }}</title>
    </head>
    <body class="{{ bodyClass }}">
        {{ content }}
        {{ scripts }}
    </body>
</html>

В следующем примере шаблон контрола создан через использование Controls/Application:

<Controls.Application title="Демо-пример для wi.sbis.ru" appRoot="/materials/">
    <ws:headJson>
        <link rel="stylesheet" href="/resources/SBIS3.CONTROLS/themes/online/online.css" type="text/css" />
    </ws:headJson>
    <ws:content>
        <Controls.list:View
                source = "{{_viewSource}}"
                markedKey="{{1}}"
                allowEmptySelection="{{false}}"
                keyProperty="id"
                itemActions="{{_itemActions}}"
                on:actionClick="_onActionClick()"
                multiSelectVisibility="visible"
                class="examples-Swipe__list">
            <ws:itemTemplate>
                <ws:partial template="Controls/list:ItemTemplate">
                    <ws:contentTemplate>
                            <div style="height:{{itemTemplate.itemData.item.id=== 3 ?  _height + 'px' : '37px'}}"  on:click="_contentClick( itemTemplate.itemData)">
                                <div class="examples-Swipe__height_item">Съешь ещё этих мягких французских булок, да выпей [же] чаю.</div>
                            </div>
                    </ws:contentTemplate>
                </ws:partial>
            </ws:itemTemplate>
        </Controls.list:View>
    </ws:content>
</Controls.Application>

Совместимость шаблона с контролами из разных пространств имён

Контрол Controls/Application поддерживает работу только с контролами VDOM, которые доступны из пространства имён Controls.

Шаблон не работает с контролами из пространств имён SBIS3.CONTROLS, Lib/Controls и других. Однако вы можете использовать шаблон Controls/Application/Compatible, который обеспечивает совместимость с другими пространствами имён.

Контрол Controls/Application/Compatible. Совместимость с контролами без VDOM

Контрол Controls/Application/Compatible обеспечивает совместимость со "старым" типом страниц, на которых активно используются контролы, наследующиеся от классов SBIS3.CONTROLS/CompoundControl и Lib/Control/CompoundControl/CompoundControl. Контрол обладает тем же API, что и контрол Controls/Application.

<Controls.Application.Compatible>
  <div>
     <SBIS3.CONTROLS.Button caption='Hello, World'/>
  </div>
</Controls.Application.Compatible>

Создание шаблона страницы

В простом случае, чтобы объявить шаблон страницы, необходимо создать контрол, расширяющий класс UI/Base:Control, а в разметке — использовать шаблон-контрол Controls/Application.

В следующем примере показано, как создать простой пользовательский контрол — MyModule/MyPage — для использования в качестве шаблона страницы. Контрол встраивает кнопку с подписью "Hello, World!" в контент страницы.

  • JS-модуль
    define('MyModule/MyPage',
       // Массив зависимостей контрола.
       [
          // Подключаем базовый класс, от которого наследуются контролы.
          'UI/Base',
          // Подключаем файл с разметкой контрола.
          'wml!MyModule/MyPage',
       ],
       // Функция конструктора модуля.
       function(Base, template) {
          // Создание нового класса.
          var moduleClass = Base.Control.extend({
             // Функция, в которую передают разметку контрола.
             _template: template
          });
          return moduleClass;
       }
    );
  • WML-шаблон
    <Controls.Application>
      <div>
          <Controls.buttons:Button caption="Hello, World!" />
      </div>
    </Controls.Application>

В следующем разделе будет показано, как сопоставить URL с созданным шаблоном.

Получение данных

Поскольку MyModule/MyPage является контролом четвертого поколения платформы, мы можем организовать получение данных прямо в нем. Более подробно об асинхронном получении данных читайте здесь.

Генерация HTML-страницы

Создайте в любом месте интерфейсного модуля файл с именем вида Name.html.tmpl. Внутри файла добавьте любой контрол-шаблон, включающий в себя Controls/Application.

<!-- Файл MyPage.html.tmpl -->
<MyModule.MyPage myOption="myValue" />
<!-- Файл MyPage.tmpl -->
<Controls.Application>
   <div>Hello, World!</div>
</Controls.Application>

На этапе сборки приложения (см. Builder. Утилита сборки статики) файл будет преобразован в статическую HTML-страницу и размещён рядом с файлом *.html.tmpl.

Установка title и og-meta тегов страницы

Для установки title и og-meta тегов станицы используются singleton UI/_base/HTML/meta:Stack
MetaStack представляет собой хранилище состояний title и meta-тегов. Он реализует интерфейс IMetaStack

Установка

Чтобы выставить теги, передайте объект мета-данных (IMeta) в метод stack.push(meta); Экземпляр State, возвращаемый stack.push(meta), представляет собой состояние тегов страницы, реализует интерфейс IMetaState
Устанавливать title можно на Сервисе Представления.

Удаление

Экземпляр State необходимо передать в stack.remove(state) для удаления. Удаление по state гарантирует, что удалить state может только тот, кто его создал. После удаления, будет установлено предыдущее состояние.

Применение

import { Control, getMetaStack, IMetaState, IMeta } from 'UI/Base';

class MyControl extends Control {
   private metaStates: IMetaState[] = [];

   setTitle(title: string) {
      const meta: IMeta = { title }; // см. описание https://wi.sbis.ru/docs/js/UI/_base/HTML/_meta/IMeta/
      const state: IMetaState = getMetaStack().push(meta); // см. описание https://wi.sbis.ru/docs/js/UI/_base/HTML/_meta/IMetaState/
      this.metaStates.push(state); // сохранение состояний для обеспечения возможности их удалить
   }

   _beforeUnmount() {
      this.metaStates.forEach(getMetaStack().remove); // удаление состояний
   }
}

Дополнительные обобщения

Окно обновления сервиса

Подключение

Указать в зависимости вашему приложению контрол ServiceUpdateNotifier/ServiceUpdateNotifier.

Добавление сервиса в отслеживаемые

Выписать задачу на Санникова К.А. по включению своего дистрибутива в список обновляемых. В задаче указать имя дистрибутива.

Тестирование

Диалог обновления появляется после выхода из спящего режима либо после получения события с сервера versionmanager.updatestaticcomplete, если версия страницы отличается от версии сервиса на сервере.

Версия сайта проверяется по файлу version.xml, который находится в корне папки ресурса. По умолчанию это — /resources/version.xml. Диалог обновления будет показан лишь в случае, когда version.xml будет содержать более новую версию.

Если человек отказался от обновления, то версия страницы будет обновлена до актуальной, для предотвращения показа диалога обновления по текущей версии.

Версия проверяется по ключам из XML-файла:

  • versionversion_number
  • versionbuild_number
  • versionversion_coreversion_number
  • versionversion_corebuild_number

Если хоть одно из значений отличается от предыдущего, то окошко будет показано при событии обновления.

Следующий JS-код можно выполнить из консоли веб-браузера, чтобы принудительно инициировать проверку версии открытой страницы. В результате будет показан модальный диалог, предлагающий пользователю обновить страницу:

/* После этого проверка будет произведена через 7 секунд.
Эмуляция выхода из спящего режима. */
require(["Core/EventBus"], function (bus) {
    bus.globalChannel().notify('onwakeup');
});

/* Проверка сервиса "inside", произведётся мгновенно.
Эмуляция события от сервера. */
require(['Browser/Event', 'Types/entity'], function(bus, entity) {
    var record = new entity.Record({
        rawData: {
            Distribution: 'inside',
            Product: 'inside'
        },
        adapter: 'adapter.json'
    });
    bus.Server.serverChannel('versionmanager.updatestaticcomplete').notify('onmessage', record);
});