Перейти к основному содержимому
Версия: 7.0

Brief: view logic

Формы

Структура формы

Форма — универсальный элемент, описывающий, какие объекты и какие свойства для них читаются. Объявляется инструкцией FORM и состоит из блоков:

  • OBJECTS — объекты формы с классами; объекты в одних скобках образуют группу объектов, наборы которой являются их декартовым произведением;
  • PROPERTIES — свойства и действия, которым передаются объекты формы;
  • FILTERS — свойства-условия: остаются наборы объектов со значением не NULL;
  • ORDERS — сортировка наборов объектов;
  • FILTERGROUP — фильтры, из которых пользователь выбирает один активный;
  • TREE — несколько групп объектов, показываемых одной таблицей-деревом.
FORM orders
OBJECTS o = Order
PROPERTIES(o) date, number
OBJECTS d = OrderDetail
PROPERTIES(d) nameSku, quantity
FILTERS order(d) = o
;

Аналогия: запрос SELECT сразу по нескольким наборам строк, каждый со своей выборкой. Подробно — структура формы.

Интерактивное представление

В интерактивном представлении пользователь работает с открытой формой: выбирает текущие объекты, меняет первичные свойства, вызывает действия. Данные читаются по мере необходимости, изменения сразу видны. Группа объектов показывается таблицей или панелью, и только группы, перечисленные в блоке TREE, объединяются в одно дерево; фильтры и сортировки пользователь может добавлять сам.

Свойство отображается ровно в одной группе объектов — своей группе отображения, по умолчанию последней из тех, чьи объекты ему переданы. Свойство, у которого группы отображения нет вовсе, — например, свойство без параметров — попадает в PANEL верхнего уровня формы, а в представлении TOOLBAR — в TOOLBARBOX.

Какое представление используется, задается не в форме, а в операторе ее открытия, поэтому одна форма обслуживает их все. Расположение компонентов на экране задает дизайн формы, см. Brief: дизайн форм.

Печатное представление

Печатное представление — одно из двух статичных: все данные читаются на момент открытия, обратной связи нет. Группы объектов выстраиваются в иерархию: свойства родительской группы выводятся по разу на каждый её собственный набор объектов, под ним идут соответствующие наборы дочерней, и затем всё повторяется для следующего набора. Файл получается из этого, только если задан формат; без него отчет отрисовывается интерактивно — показывается пользователю, уходит на принтер или доставляется сообщением. Группы объектов выстраиваются в иерархию — свойства родительской группы выводятся один раз, дочерней — для всех ее наборов объектов.

На выходе PDF, DOC, DOCX, XLS, XLSX, HTML, RTF: предпросмотр, печать на принтере или файл. Макет описывает дизайн отчета — файл-шаблон .jrxml, который ищется по каноническому имени формы; если шаблон не найден, платформа строит дизайн автоматически по структуре формы (Brief: отчеты).

Структурированное представление

Структурированное представление — второе статичное после печатного: оно читает все данные на момент открытия формы и берет иерархию ее групп объектов — свойства родительской группы по разу на каждый ЕЕ СОБСТВЕННЫЙ набор объектов, а под ним вложены соответствующие наборы дочерней, — но записанная как данные, а не как страница — JSON, XML, CSV, DBF, XLS, XLSX, TABLE.

Форма задает и структуру, в которую данные записываются, и структуру, из которой они читаются. При чтении форматы те же, только для Excel ключевое слово одно, XLS, и оно принимает файлы и .xls, и .xlsx. Что это означает для каждого направления — в Brief: экспорт данных и Brief: импорт данных.

Открытие формы (SHOW, DIALOG, PRINT, EXPORT)

Оператор открытия формы создает действие, которое открывает форму в выбранном представлении.

ОператорПредставлениеНазначение
SHOWинтерактивноепоказать форму пользователю
DIALOGинтерактивноето же плюс возврат текущего значения объекта как введенного значения
PRINTпечатноеотчет: предпросмотр, печать или файл
EXPORTструктурированноевыгрузка данных формы в файл

Оператор IMPORT форму не открывает: он разбирает файл и пишет значения в свойства формы так, чтобы обратная выгрузка этой формы воспроизвела исходный файл (импорт формы).

selectSku (OrderDetail d) { DIALOG skus OBJECTS s INPUT DO sku(d) <- s; }
printOrder (Order o) { PRINT printOrder OBJECTS o = o XLSX TO orderFile; }

Передача объектов и режим открытия

Блок OBJECTS оператора открытия передает форме значения объектов: в интерактивном представлении переданное значение становится текущим объектом, в статичном — добавляется фильтр на равенство ему. По умолчанию NULL среди передаваемых значений отменяет действие; ключевое слово NULL после значения это разрешает, а для объекта DIALOG, помеченного INPUT или CHANGE, разрешено автоматически.

У SHOW и DIALOG дополнительно задается расположение формы — FLOAT, DOCKED, EMBEDDED, POPUP, IN. У SHOW есть опция WAIT / NOWAIT; у DIALOG такой опции нет, и он выполняется синхронно всякий раз, когда его результат используется — блоком DO / ELSE или обратной записью CHANGE.

Подробно — Открытие формы. Форма открывается также выбором пункта навигатора, см. Brief: навигатор.

Дизайн форм

Контейнеры

Дизайн формы описывает, как форма выглядит в интерактивном представлении. Это иерархия контейнеров и базовых компонентов, которые платформа создает по структуре формы: таблица / дерево (GRID), системный тулбар (TOOLBARSYSTEM), пользовательский фильтр (FILTERS), расчеты по колонкам (CALCULATIONS), группа фильтров (FILTERGROUP), панель свойства (PROPERTY).

Иерархию меняет инструкция DESIGN: NEW создает контейнер, MOVE переносит компонент, REMOVE убирает его, имя компонента с блоком редактирует его, propertyName = value задает свойство. Компонент выбирается по имени или конструкциями PROPERTY(...), GRID(...), BOX(...), PANEL(...), TOOLBARBOX, GROUP(...), PARENT(...); позиция вставки — FIRST, LAST, BEFORE, AFTER.

Раскладку потомков задают опции контейнера horizontal, tabbed, lines (вместе с grid), внешний вид — caption, image (иконки), border, collapsible (из кода такой контейнер сворачивают действия EXPAND и COLLAPSE), popup, showIf и custom — React-компонент или HTML-шаблон, только веб-клиент.

DESIGN order {
NEW header FIRST {
horizontal = TRUE;
MOVE PROPERTY(date(o));
MOVE PROPERTY(number(o)) { charWidth = 5; }
}
MOVE BOX(d) { fill = 1; }
REMOVE TOOLBARLEFT;
}

Размеры и выравнивание

Компоненту задается базовый размер в пикселях (size, width, height). Дальше вдоль основного направления контейнера свободное место делится между потомками пропорционально коэффициенту расширения flex (опция fill задает его вместе с выравниванием), а поперек работает выравнивание alignSTART, CENTER, END, STRETCH. Аналогия: CSS Flexible Box Layout, где flex — это flex-grow, а базовый размер — flex-basis; в веб-клиенте раскладка через него и реализована.

У свойства отдельно от всего компонента задается размер ячейки значения: valueWidth и valueHeight в пикселях, charWidth и charHeight в символах. Он же определяет ширину колонки, когда свойство показано в таблице. Опция autoSize подгоняет базовый размер под содержимое и применяется только к текстовым компонентам.

Дизайн по умолчанию

Платформа строит дизайн по умолчанию по структуре формы — BOX формы, а внутри него готовый контейнер для каждой группы объектов и дерева и для их таблиц, тулбаров и панелей, — и DESIGN правит именно его; ключевое слово CUSTOM в заголовке инструкции строит дизайн с нуля.

В какой контейнер попадет компонент свойства, определяют его вид на форме (GRID, PANEL, TOOLBAR, POPUP) и группа отображения — а когда ее нет, это PANEL или TOOLBARBOX верхнего уровня, — поэтому дизайн обычно сводится к переносу готовых контейнеров, а не к созданию компонентов.

Навигатор

Структура навигатора

Навигатор — дерево, с которого пользователь начинает работу с приложением. Элементы бывают трех типов: папка объединяет другие элементы, элемент-форма открывает форму в интерактивном представлении, элемент-действие выполняет действие, не принимающее аргументов. Корень — папка System.root. Аналогия: меню приложения вместе с его маршрутизацией.

Навигатор наполняет инструкция NAVIGATOR вложенными блоками: NEW FOLDER, NEW FORM и NEW ACTION создают элемент потомком текущего, MOVE переносит существующий, имя элемента с блоком редактирует его; позиция — FIRST, LAST, BEFORE, AFTER. Опции элемента: WINDOWокно для его потомков (с PARENT — и для него самого), HEADER — заголовок из свойства, SHOWIF — видимость, IMAGE / NOIMAGEиконка, CHANGEKEY и CHANGEMOUSE — горячая клавиша и привязка мыши, CLASS — CSS-класс. Инструкция SCHEDULE PERIOD создает планировщик, выполняющий действие с заданным периодом в секундах.

NAVIGATOR {
NEW FOLDER catalogs 'Справочники' WINDOW toolbar {
NEW items;
NEW FORM stocksNavigator 'Склады' = stocks;
}
NEW FOLDER documents 'Документы' WINDOW toolbar {
NEW ACTION recalculate;
}
}

Окна и расположение

Дизайн навигатора — набор окон, участков экрана, каждый из которых показывает свои элементы навигатора. Окно объявляет инструкция WINDOW: VERTICAL или HORIZONTAL задает ориентацию тулбара, POSITION(x, y, width, height) — место на рабочем столе размером 100 на 100 точек, а LEFT, RIGHT, TOP и BOTTOM прижимают окно к краю. Есть также HIDETITLE, HIDESCROLLBARS, выравнивания HALIGN, VALIGN, TEXTHALIGN, TEXTVALIGN, CLASS и CUSTOM — пользовательское представление окна, отрисовываемое React-компонентом или HTML-шаблоном. Рисует его только десктопный веб-клиент: мобильный веб-клиент и десктопный клиент оставляют стандартное меню.

В каком окне рисуется элемент, задает опция WINDOW его родительской папки. Элемент, попавший в окно, отличное от окна своей папки, показывается только тогда, когда эта папка выбрана пользователем в своем окне, — так папка переключает содержимое соседнего окна.

Системные окна создает платформа: System.forms — окно, в котором открываются формы, System.log — сообщения пользователю, System.root и System.toolbar — горизонтальный и вертикальный тулбары навигатора, System.system — системные кнопки, System.logo — логотип. Инструкция EXTEND WINDOW ... CUSTOM меняет отрисовщик уже объявленного окна, HIDE WINDOW скрывает его. Из NATIVE-окон отрисовщик принимают только System.forms и System.log, и только React-компонент — ему передается то, что положило в окно приложение, вместо элементов навигатора; остальные не содержат элементов навигатора и не принимают ни компонента, ни шаблона.

Отчёты

Печатное представление

Отчет — это шаблон, при подстановке данных в который строится документ. Печатное представление формы состоит из набора отчетов, каждому из которых отведен свой набор групп объектов формы; как группы разбиваются по отчетам и как опция SUBREPORT у группы выделяет ее в отдельный отчет — подотчет — описано в построении иерархии отчетов.

Что происходит с документом, выбирают параметры оператора PRINT, у которых есть два варианта. MESSAGE показывает форму пользователю сообщением: свойства корневой группы становятся его заголовком, а таблица под ним берется из ПЕРВОЙ дочерней группы — форма без дочерней группы дает пустую таблицу, а всякая дочерняя группа после первой не попадает в результат. Второй вариант — интерактивный: previewMode — это либо PREVIEW, значение по умолчанию, когда отчет показывается пользователю, либо NOPREVIEW, когда он напрямую уходит на принтер (TO <выражение> выбирает принтер), а формат — PDF, DOC, DOCX, XLS, XLSX, HTML, RTF — вместе с TO <свойство> записывает документ в файл на сервере. SHEET и PASSWORD доступны для XLS и XLSX.

FORM printOrder
OBJECTS o = Order
PROPERTIES(o) date, nameCustomer

OBJECTS d = OrderDetail SUBREPORT
PROPERTIES(d) nameSku, quantity
FILTERS order(d) = o
;

print (Order o) { PRINT printOrder OBJECTS o = o DOCX TO orderFile; }

Дизайн отчёта

Дизайн отчета — то, как отчет раскладывается в документе. Отчет описывает шаблонфайл .jrxml технологии JasperReports, который платформа ищет в classpath сервера по имени, производному от канонического имени формы; полями шаблона служат свойства формы, их имена и типы совпадают. Точные правила именования и цена ошибки в имени — Правила: отчеты.

Своего шаблона может и не быть: если хотя бы один не найден, платформа строит автоматический дизайн по структуре формы. Шаблон задается и явно, свойством с именем файла или самим файлом: блок REPORT инструкции FORM — для верхнего отчета, REPORTS (синоним REPORTFILES) — для перечисленных групп объектов, выражение после SUBREPORT в блоке объектов — для своей группы.

Интернационализация

Локализация строк и подписей

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

CLASS Book '{use.case.i18n.book}';
name '{use.case.i18n.book.name}' = DATA STRING[40] (Book);

Текущую локаль — язык, страну, часовой пояс — платформа берёт из свойств Authentication.language[CustomUser] и им подобных, а для действий, запущенных системой, — из локали сервера; пользовательские данные не переводятся. Механизм — интернационализация.

Аналогия: ключи ResourceBundle прямо в тексте подписи, а не вызов функции перевода.

Обратный перевод

Обратный перевод избавляет от расстановки идентификаторов вручную: подписи пишутся в коде обычным текстом на одном языке, а запись, значением которой этот текст является, платформа находит сама — ключом записи остается ее собственный идентификатор, а текст является ее значением. Включается параметром запуска logics.lsfStrLiteralsLanguage, задающим язык строковых литералов lsf-кода: при старте сервера по всем ResourceBundle файлам проекта в этой локали строится словарь значение -> идентификатор, и обычный литерал, совпавший со значением записи, при разборе кода заменяется её идентификатором и дальше ведёт себя как локализуемый. Ведущие и конечные пробелы в сопоставлении не участвуют и сохраняются вокруг подстановки, а литерал пустой или состоящий из одних пробелов не заменяется вовсе.

Замена касается любого обычного литерала, а не только подписей, поэтому технические строки — ключи JSON, адреса, форматы, внешние идентификаторы — записываются сырой формой строкового литерала, которая не участвует ни в локализации, ни в обратном переводе:

'content'    // обычный: локализуется и при совпадении заменяется обратным переводом
r'rawContent' // сырой: ни того, ни другого