Руководство для разработчиков

XML-описание страниц

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

  • Дашборд
  • Форма
  • Список (таблица)
  • Отчет
  • Страница помощи

Ниже будет более подробно описана структура XML для страниц форм и списков.

Для дашборда и отчетов есть соответствующие статьи в справочной документации: дашборд , отчеты.

На самом верхнем уровне XML-описания страниц всех видов похожи, обобщенно их структуру можно описать так:

<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[функция]">
    <metadata type="тип_страницы">
        <!-- ...метаданные, отличаются для разных типов страниц -->
    </metadata>
    <messages>
        <msg name="имя_строки">Текст</msg>
        <!-- ... строки <msg> ... -->
    </messages>
</doc>

 

Обратите внимание
  • В атрибуте func тэга doc нужно указывать функцию, соответствующую данной странице. В случае, если один обработчик обслуживает несколько разных функций, обрабатываемую функцию можно получить из переменной окружения PARAM_func.
  • Атрибут type тэга <metadata> принимает одно из пяти значений, соответствующих типам страниц: dashboard, form, list, report, helpboard
  • В отличие от XML-описания плагина, здесь не используется тэг <lang>, позволяющий указать язык для отображаемых строк. Если нужно отображать плагин на разных языках, это можно сделать через XML-описание плагина (см ниже соответствующий раздел) с использованием тэга <lang>. Сопоставление строки в <messages> с элементами UI происходит по атрибуту name.

Составление XML-описаний страниц по аналогии с существующими

При создании XML-описаний страниц, возвращаемых обработчиками плагинов, часто удобно взять XML-описание какой-то существующей страницы за основу или готовить свое XML-описание по аналогии с существующим. Для этого достаточно использовать утилиту mgrctl с опцией -o devel, например, вот так можно получить XML для формы создания сайта:

/usr/local/mgr5/sbin/mgrctl -m ispmgr webdomain.edit -o devel

Вывод этой команды может содержать какое-то количество элементов вне <metadata> и <messages>, часть которых не будет иметь эффекта при использовании в плагине, поэтому лучше брать за основу в первую очередь содержимое элементов <metadata> и <messages>.

XML-описание формы

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

<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[функция]">
    <metadata type="form">
        <form>
		<field name="имя_поля">
		    <!-- элементы <input>, 
		        <select>, <textdata> и т.п.
		    -->
		</field>
		<!-- ... элементы <field> ... -->
		<buttons>
		    <button name="имя_кнопки" type="тип_кнопки">
		</buttons>
        </form>
    </metadata>
    <messages>
        <msg name="имя_поля">Подпись поля</msg>
        <msg name="имя_кнопки">Текст на кнопке</msg>
        <msg name="title">Заголовок формы</msg>
        <!-- ... строки <msg> ... -->
    </messages>
    <имя_поля>Значение поля</имя_поля>
</doc>

В случае, если поля формы сгруппированы в разделы, структура внутри элемента <form> будет выглядеть так:

<form>
    <page name="имя_раздела">
        <field name="имя_поля">
        <!-- элементы <input>, 
	         <select>, <textdata> и т.п.
        -->
        </field>
        <!-- ... элементы <field> ... -->
    </page>
    <!-- ... элементы <page> ... -->
    <buttons>
        <button name="имя_кнопки" type="тип_кнопки">
    </buttons>
</form>

Несколько пояснений:

  • Значение атрибута name="title" на элементе <msg> зарезервировано для передачи заголовка страницы.
  • Подпись к полю задается на уровне элемента <field>, за исключением групп чекбоксов, для каждого из которых задается подпись по его атрибуту name, помимо подписи ко всей группе.
  • Внутри одного элемента <field> как правило бывает один элемент <input>, <select>, <textdata>, <textarea> и т.п., но бывают и исключения, одно из них - группа чекбоксов.
  • Если нужно передать начальные значения для полей формы, это делается посредством XML-элементов вида <имя_поля>. Значение поля</имя_поля>, причем имя_поля здесь соответствует значению атрибута name на элементе внутри элемента <field>, то есть если нужно задать значение для поля ввода: <field name="fieldname"><input name="inputname" /></field>, то это делается так: <inputname>Значение поля</inputname>

Подробнее об XML-описании форм, типах полей ввода и кнопок и атрибутах элементов можно прочитать в справочной статье.

XML-описание списков (таблиц)

Страница списка состоит из заголовка, тулбара (строки кнопок) и таблицы. Для таблицы возможен поиск по строке, сортировка и фильтрация (за исключением столбцов, по которым фильтрация запрещена метаданными столбца). В случае, если не получено ни одной строки для отображения в таблице с учетом фильтров и поисковой строки, отображается сообщение “Список пуст”.

XML-описание списка можно обобщенно представить так:

<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[функция]">
    <metadata type="form" 
        key="поле_id_строки" 
        keyname="поле_имени_строки">
        <toolbar>
            <toolgrp name="update">
                <toolbtn name="имя_кнопки"
                    func="функция_вызываемая_по_кнопке"
                    type="тип_кнопки" 
                    default="yes"/>
                <!-- ... элементы <toolbtn> ... -->
            </toolgrp>
            <!-- ... элементы <toolgrp> ... -->
        </toolbar>
        <coldata>
            <col name="имя_столбца" 
                type="тип_столбца" 
                sort="тип_сортировки" />
            <!-- ... элементы <col> ... -->
        </coldata>
    </metadata>
    <messages>
        <msg name="имя_столбца">Заголовок столбца</msg>
        <msg name="имя_кнопки">Текст на кнопке</msg>
        <msg name="title">Заголовок списка</msg>
        <!-- ... строки <msg> ... -->
    </messages>
    <elem>
        <имя_столбца>Значение ячейки</имя_столбца>
        <!-- ... элементы вида 
<имя столбца1 /> 
<имя столбца2 /> и т.д... -->
    </elem>
    <!-- ... элементы <elem> ... -->
</doc>

Комментарии к коду выше:

  • Поведение UI после нажатия на кнопку может сильно различаться в зависимости от типа кнопки, задаваемого атрибутом type элемента <toolbtn>
  • Атрибут default="yes" элемента <toolbtn> позволяет указать кнопку, поведение которой будет срабатывать при двойном клике по строчке таблицы
  • Как и для формы, элемент <msg name="title"> позволяет задать заголовок для всей страницы
  • Атрибут sort элемента <col> указывает на тип сортировки столбца, которая будет применена по клику на его заголовке, примеры значений - "alpha" - сортировка по алфавиту, "digit" - сортировка чисел и т.п., все варианты описаны в справочной статье об XML списков по ссылке в последнем пункте
  • Для простоты объяснения обобщенная структура кода не включает ряд элементов и атрибутов, позволяющих описать важный функционал UI списка (информация об этом приведена в справочной статье об XML-описании списков,

    например:

    • Пагинация
    • Фильтрация
    • Иконки кнопок
    • Отображение кнопок по условию

XML-описание ошибок и сообщений об успехе действий

Кнопки и другие UI-элементы форм и списков приводят к выполнению обработчиков плагинов и/или запросам к стандартному API ispmanager. UI ispmanager получает обратную связь о результате таких действий посредством сообщения одного из трех типов:

  • XML-описание страницы -  в этом случае новая страница открывается вместо текущей или в новой вкладке, в зависимости от типа кнопки;
  • XML-описание результата успешного выполнения действия - при получении такого сообщения текущая вкладка может быть закрыта или быть сохранена, или может произойти редирект на другую страницу, в зависимости от типа кнопки и содержания сообщения;
  • XML-описание ошибки - в этом случае сообщение об ошибки отображается в виде уведомления (при действии по кнопке списка), в виде сообщения рядом с полем формы или баннера над кнопками формы.

Сообщение об успешном выполнении действия

Ниже представлена обобщенная структура сообщения об успехе действия:

<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[вызванная_функция]">
    <ok>
        <!-- элемент <ok> может быть пустым, либо включать
            информацию о редиректе -->
    </ok>
    <!-- могут быть другие элементы, помимо <ok>,
        но при наличии <ok> они в основном игнорируются -->
</doc>

В этой структуре имеет значение содержимое элемента <ok>, о возможных опциях можно прочесть в разделе справочной статьи о формах. В наиболее частом и простом случае, если от UI требуется остаться на том же списке или закрыть форму, <ok> будет пустым.

Сообщение об ошибке

Обобщенная структура сообщения об ошибке:

<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[вызванная_функция]">
    <error type="тип_ошибки" object="имя_элемента_UI">
        <msg>Текст сообщения об ошибке</msg>
        <!-- другие элементы информации об ошибке -->
    </error>
</doc>

Для возврата сообщений об ошибках в плагинах достаточно такой упрощенной структуры, однако у элемента <error> возможны и другие атрибуты и дочерние элементы, пример можно найти здесь

Реакция UI ispmanager на полученное сообщение об ошибке будет зависеть от типа страницы, на которой выполнялось действие, а также от типа кнопки или другого UI-элемента, с помощью которого было инициировано действие. В случае формы в атрибуте object может быть указано имя поля, в которое введена невалидная информация, тогда ошибка будет отображена рядом с этим полем.

XML-описание плагинов

Обработчики плагинов возвращают XML-описания страниц, сообщения об успехе или ошибке, и это всегда происходит в процессе запроса к той или иной функции (func).

Привязка обработчика к функции происходит посредством XML-описания плагина, кроме того, в XML-описании плагина задаются строки локализации для разных языков и настраиваются некоторые важные аспекты вызова обработчика.

Файлы XML-описаний плагинов помещаются в папку /usr/local/mgr5/etc/xml и должны иметь имя вида ispmgr_mod_[имя_плагина].xml, например: ispmgr_mod_helloworld.xml.

Применение изменений в XML-описании плагинов

Чтобы начал работать новый плагин, для которого только что добавлено XML-описание, или чтобы применить изменения в XML-описании существующего плагина, нужно перезапустить панель следующей Shell-командой:

pkill core

Обратите внимание, что данная команда перезапускает только панель ispmanager, а не весь сервер.

Структура XML-описания плагина

Обобщенная структура XML-описания плагина:

<?xml version="1.0" encoding="UTF-8"?>
<!-- тэг mgrdata всегда должен быть на верхнем уровне любого плагина -->
<mgrdata>
    <mainmenu>
        <modernmenu>
            <node name="имя_группы">
                <node name="имя_пункта_меню"/>
            </node>
        </modernmenu>
    </mainmenu>
    <handler name="имя_файла_обработчика" type="xml">
        <func name="имя_функции" />
        <event name="имя_функции" after="yes"/>
        <!-- ... элементы <func> и <event> --> 
    </handler>
    <lang name="ru">
        <messages name="desktop">
            <msg name="modernmenu_имя_пункта_меню">
                Текст пункта меню
            </msg>
            <!-- элементы <msg> --> 
        </messages>
        <!-- элементы <messages> -->
    </lang>
</mgrdata>

XML-описание плагина состоит из элемента <mgrdata>, внутри которого может быть любое количество элементов <mainmenu>, <handler> и <lang>. В XML-описании плагина может быть любое количество элементов <mainmenu>, <handler> и <lang> внутри элемента <mgrdata> в том числе любой из этих трех элементов может отсутствовать. Далее о каждом из них подробнее.

Элемент <handler>

<handler> связывает обработчик и обрабатываемую функцию. Путь к исполняемому файлу обработчика задается атрибутом name, это относительный путь от папки /usr/local/mgr5/addon

Возможны два способа привязки обработчика к функции:

  • Обработка функции с привязкой посредством элемента <func>: данный обработчик становится основным для данной функции. Имя функции задается в атрибуте name.
  • Выполнение обработчика до или после основного обработчика, привязка посредством элемента <event>. Имя функции задается в атрибуте name, если требуется выполнить обработчик до основного обработчика, используется атрибут before="yes", если после - используется атрибут after="yes". 

Внутри элемента <handler> может быть любое число элементов <func>и <event>, то есть один обработчик может обрабатывать любое число функций в каждой из этих двух ролей. Имя обрабатываемой функции в коде обработчика можно получить из переменной окружения PARAM_func.

Добавление дополнительных UI-элементов в стандартные страницы 

Привязка обработчика к функции посредством элемента <event> дает возможность добавлять дополнительную функциональность в стандартные страницы ispmanager. При использовании атрибута after="yes" обработчик плагина выполняется после стандартного обработчика встроенной функции ispmanager и получает в STDIN XML-описание страницы, созданное стандартным обработчиком.

В это XML-описание обработчик плагина может добавлять свои UI-элементы, менять логику существующих или при необходимости создавать свое XML-описание, которое заменит полученное от стандартного обработчика. Итоговое XML-описание обработчик плагина, как обычно, должен передать в STDOUT и затем оно будет использовано ispmanager для создания страницы. 

Пример использования этой возможности дан в статье [Добавление быстрого действия в стандартный дашборд (будущая страница: Добавление быстрого действия в стандартный дашборд)].

Элемент <mainmenu>

<mainmenu> позволяет добавлять пункты в навигационное меню ispmanager. Атрибут level этого элемента задает уровень доступа, для которого отображаются пункты, заданные внутри: 30 - root, 29 - администратор, 16 - обычный пользователь, 9 - пользователь почтового ящика.

Путь к любому пункту меню имеет два уровня, оба задаются элементами <node>: верхний уровень - группы меню, второй - сами пункты меню, которые являются ссылками на соответствующие страницы:

<mainmenu>
    <node name="имя_группы">
        <node name="имя_пункта_меню"/>
    </node>
</mainmenu>

Код выше описывает структуру добавляемых пунктов меню для ispmanager Business, а в ispmanager Lite (Pro, Host) элементы <node> верхнего уровня помещаются в промежуточный элемент <modernmenu>:

<mainmenu>
    <modernmenu>
        <node name="имя_группы">
            <node name="имя_пункта_меню"/>
        </node>
    </modernmenu>
</mainmenu>

Атрибут name элемента <node> второго уровня задает функцию (func), которая должна быть выполнена при клике по соответствующему пункту меню. К тому же атрибут name   на обоих уровнях элемента <node> привязывает его к соответствующему элементу <msg> для задания отображаемого текста группы/пункта меню (с использованием соответствующего префикса - см. об этом в разделе об элементе <lang>).

Если нужно добавить пункт меню в имеющуюся группу, то для <node> верхнего уровня задается атрибут name, соответствующий имеющейся группе; например, код ниже показывает, как добавить пункт меню в группу "Настройки" (name="set") в ispmanager:

<mainmenu>
    <modernmenu>
        <node name="set">
            <node name="myfunc"/>
        </node>
    </modernmenu>
</mainmenu>

Если нужно отобразить пункт меню без группы, элементу <node> верхнего уровня, то добавляется атрибут type="noname" (см. пример в статье.

В XML-описании плагина может быть только один элемент <mainmenu>, либо он может отсутствовать.

Элемент <lang>

Элемент <lang> задает группу строк локализации для одного языка (код языка задается атрибутом name, например <lang name="ru">).

Внутри элемента <lang> может быть любое число элементов <messages>, каждый из которых задает группу строк локализации для одной функции (имя функции задается атрибутом name). Каждая строка локализации внутри <messages> задается элементом <msg> c указанием имени соответствующего UI-элемента в атрибуте name, иногда с использованием префикса, например: <msg name="myfield"> для поля формы с name="myfield" или <msg name="modernmenu_myfunc" > для пункта меню в ispmanager Lite c name="myfunc".

Некоторые используемые префиксы:

  • menu_ — для пунктов меню в ispmanager Business
  • modernmenu_ — для пунктов меню в ispmanager Lite (Pro, Host)
  • msg_— для кнопок

При задании строк локализации для навигационного меню нужно использовать <messages name="desktop">.

В XML-описании плагина может быть любое количество элементов <lang>, по одному для каждого языка, для которого задаются строки локализации. Пример одной такой группы:

<lang name="ru">
    <messages name="desktop">
        <msg name="modernmenu_writetosupport">Отправка сообщения в поддержку</msg>
    </messages>
    <messages name="writetosupport">
        <msg name="messagetext">Введите текст:</msg>
        <msg name="msg_send">Отправить</msg>
        <msg name="title">Отправка сообщения в поддержку</msg>
    </messages>
</lang>