Внешние модули-компоненты (ВМК)
===============================

Механизм внешнего-модуля компонента предназначена для добавления
или замены каких-либо элементов пользовательского web-интерфейса ARTA Synergy.
Для этого необходимо описать пользовательский компонент, который и будет
служить внешним модулем-компонентом, а затем указать для него место размещения
в интерфейсе (GUI) и способ вставки.

Добавление ВМК
--------------

Для настройки пользовательских компонентов необходимо во вкладке
"Процессы" конфигуратора выбрать пункт "Пользовательские компоненты".

.. figure:: _static/img/extcmp/extcmp-1.png

    Пользовательские компоненты

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

* **"Название"** - название пользовательского компонента, является обязательным
  полем;
* **"Код"** - название пользовательского компонента, является обязательным
  полем;
* **"Использовать в формах"** - данная опция позволяет использовать компонент
  в формах (в качестве пользовательского компонента);
* **"HTML код"** - HTML код(в том числе CSS), который будет вставлен в страницу
  ARTA Synergy;
* **"JAVASCRIPT код"** - основной код компонента на JavaScript, который будет
  вставлен в страницу ARTA Synergy.

.. attention::  Начиная с версии Synergy 3.14, все пользовательские скрипты
                выполняются с добавлением директивы `use strict`. Эта директива
                означает, что соответствующий ей код будет выполнятся в так
                называемом **"строгом режиме"**, поддерживающем стандарт JavaScript
                `ECMAScript5 <http://www.ecma-international.org/publications/standards/Ecma-262.htm>`_.

.. warning::    Если код скрипта содержит конструкции, не соответствующие стандарту ES5,
                то они не будут выполняться. Это не является ошибкой Synergy.

**Пример:**

В качестве примера рассмотрим реализацию пользовательского компонента "Load info",
который показывает перегруженных сотрудников при создании работы (данный
компонент входит в стандартную поставку Synergy).

Исходный код содержит следующий простой `HTML` код:

.. code-block:: xml

    <!-- Определим добавляемый элемент, указав для него необходимый стиль. -->
    <span id = "workloadLable" style="color:red; padding-top: 10px"> </span>
    <!-- За содержимое элемента будет отвечать исходный код скрипта.       -->


Исходный код скрипта устроен более сложным образом. Рассмотрим реализацию
функции получающей данные посредством вызова REST API:

.. code-block:: javascript

    function ajaxUserWL(ar){
        // Функция filtrAr() исключает из массива повторения пользователей.
        ar = filtreAr(ar);

        // Используем массив, который подходит под формат `json`, определенный в `api`.
        // Данный формат необходимо всегда уточнять в javadoc.
        var req = [];
        for (var i = 0; i < ar.length; i++){
            var r = {userID: ar[i].userId,
                startDate: getCurrentDateFormated(),
                finishDate: getCurrentDateFormated()};
            req.push(r);
        }

        // Вызываем функцию, которая для пользователей из массива req, вызовет
        // api, возвращающую их загруженность. Перегруженные пользователи
        // добавляются в массив res и формируют содержимое HTML тага.
        jQuery.ajax({

            // Вызов необходимого api.
            url: 'rest/person/workload/m',
            type: 'post',
            data: JSON.stringify(req),
            contentType: 'application/json',
            dataType: 'json',

            // Функция осуществляет проверку на перегруженность и помещает таких
            // сотрудников в массив res
            success: function (data) {
                res = [];
                for (var i = 0; i < ar.length; i++) {
                    var user = data[ar[i].userId];
                    if (user == null) {
                        continue;
                    }
                    for (var j = 0; j < user.length; j++) {

                        // Проверка на перегруженность.
                        if (parseFloat(user[j].value) > 100) {
                            res.push(ar[i]);
                        }
                    }
                }

                // Функция определяет формат, в котором будет выводиться инофрмация.
                overloadUsers(res);
            }
        });
    }


.. note:: Полную реализацию компонента можно посмотреть в настройках пользовательских
          компонентов, выбрав компонент "Load info".

.. **Замечание:**

    Для API, находящихся по `URL` rest/%api/method%, авторизация будет происходить
    по куки (как в браузере), поэтому его можно вызывать авторизованному в Synergy
    пользователю. Для API, находящихся по другим адресам `URL`, необходимо
    настроить процесс авторизации (см. [Способы авторизации](#integration.auth)).
    Сделать это можно например так: вызвать API по адресу
    `https://%логин%:%пароль%@%адрес/метода/api%`

Для того, чтобы выбрать, где использовать пользовательский компонент,
необходимо во вкладке "Процессы" выбрать пункт "Внешние модули-компоненты"
и добавить новый внешний модуль-компонент.

.. figure:: _static/img/extcmp/extcmp-2.png
   :scale: 50%
   :alt: Внешние модули-компоненты

    Внешние модули-компоненты

Настройка внешнего модуля-компонента включает в себя настройку следующих полей:

*   **"Название"** - название внешнего модуля-компонента, является обязательным
    полем;
*   **"Код"** - код внешнего модуля-компонента, является обязательным
    полем;
*   **"Место размещения"** - выбрать один из доступных вариантов для указания
    места, в котором будет находиться пользовательский компонент. На данный
    момент доступны следующие альтернативы:

        * ``onLoad`` - пользовательский компонент будет выводиться при загрузке
          приложения;
        * ``Depricated`` - место, используемое для вывода пользовательских
          компонентов в старых версиях, не рекомендуется к применению;
        * ``BPM/Workflow/Create/Work`` - пользовательский компонент будет
          выводиться в диалоговом окне создания работы;
        * ``Shell/TopPanel/Right`` - пользовательский компонент будет выводиться
          на верхней панели оболочки Synergy, левее поля "Поиск".

*   **"Название пользовательского компонента"** - выбрать один из доступных
    вариантов пользовательских компонентов, настроенных ранее;

*   **Тип вставки** - выбрать один из доступных вариантов:

        * ``ADD`` - добавляет тег пользовательского компонента к тегу места
          размещения;
        * ``REPLACE`` - удаляются потомки тега места размещения и в него
          помещается пользовательский тег (замена всех потомков тега места размещения).

События для ВМК
---------------

Для работы ВМК в Synergy реализована отправка событий в JS EventBus.

**Пример использования события из нового проигрывателя форм в JS:**

```javascript
AS.FORMS.bus.on(AS.FORMS.EVENT_TYPE.formShow, function (event, model, view) {
    var calendarModel = model.getModelWithId('cmp-1'); //Передается идентификатор компонента
    calendarModel.on(AS.FORMS.EVENT_TYPE.valueChange, function () {
        var value = calendarModel.getValue();
        console.log(value);
    });
});
```

Ниже описаны параметры для каждого события.

##### WORK_USERS_CHANGED {#integration.methods.user-component.events.WORK_USERS_CHANGED}

WORK_USERS_CHANGED - изменены исполнители работы в диалоге создания работы.

* в качестве аргумента передается список выбранных пользователей в виде массива JSON с полями: *userId, lastname, firstname, patronymic*

* *добавлено в версии 3.0*

##### WORK_DIALOG_UPDATE {#integration.methods.user-component.events.WORK_DIALOG_UPDATE}

WORK_DIALOG_UPDATE - обновлен диалог создания работы.

* в качестве аргумента передается список выбранных пользователей в виде массива JSON с полями: *userId, lastname, firstname, patronymic*

* *добавлено в версии 3.0*

##### SETTINGS_LOADED {#integration.methods.user-component.events.SETTINGS_LOADED}

SETTINGS_LOADED - загружены настройки приложения.

* в качестве аргумента передается *null*

* *добавлено в версии 3.3*

##### DEPARTMENT_ENTITY_CHANGED {#integration.methods.user-component.events.DEPARTMENT_ENTITY_CHANGED}

DEPARTMENT_ENTITY_CHANGED - подразделение обновлено в компоненте формы.

* в качестве аргумента передается JSON с полями *id* и *values*

* values - массив JSON с полями: *value* - отображаемое имя, *key* - идентификатор пользователя

* *добавлено в версии 3.6*

##### FORM_LOADED {#integration.methods.user-component.events.FORM_LOADED}

FORM_LOADED - компоненты формы прорисованы

* в качестве аргумента передаётся пустой JSON объект с полем dataID.

* *добавлено в версии 3.6*

**Пример использования события в JS:**

```javascript
$EVENT_BUS.subscribe(new EventHandler('FORM_LOADED', handlerUsersSelected));
        function handlerUsersSelected(event, args) {
            console.log("event FORM_LOADED");
            var component = jQuery('img#image_for_portlet');
            if (component === null || component.length === 0) {
                console.log("no success");
                return;
            }
            console.log("success!!");
            console.log(component.parentNode);
            console.log(component);
            var mySpan = document.createElement("div");
            mySpan.innerHTML = "<div id='portlet_div' ><iframe frameborder = \"0\" height = \"100%\" id = \"portlet1\" src = \"http://192.168.2.119:8080/widget/web/guest/home/-/meetups\" width = \"100%\" > </iframe ></div > ";
            component.replaceWith(mySpan.innerHTML);
        }
            var checkAgain = function() {
                setTimeout(handlerUsersSelected, 5000);
            };
```

##### REGISTRY_SELECTED {#integration.methods.user-component.events.REGISTRY_SELECTED}

REGISTRY_SELECTED - нажата кнопка "Создать", когда в навигаторе выделен активный
реестр.

* в качестве аргумента передаётся JSON объект вида:

```
registryCode:"reg_code"
registryId:"9034810f-5f18-44b9-948a-8f78a5f1ec9d"
```

* *добавлено в версии 3.14*

Кроме того, атрибуты `registryCode` и `registryId` содержатся в элементе списка реестров,
например:

```xml
<table cellspacing="0"
       cellpadding="0"
       synergytest="RegistryTreeElement"
       registryid="82356e07-a859-49cc-8adf-896c32725810"
       registrycode="Заявление_о_приеме_на_работу_(вариант_2,_на_двух_языках)"
       style="display: inline;"
       class="commonLabelBold">
<colgroup> <col> </colgroup>
<tbody>
    <tr>
        <td>007 Заявление о приеме на работу на период</td>
        <td style="white-space: nowrap;"></td>
    </tr>
</tbody>
</table>
```

##### USER_CHOOSER_CREATED {#integration.methods.user-component.events.USER_CHOOSER_CREATED}

USER_CHOOSER_CREATED - обновлено тэговое поле выбора пользователя в диалоге.

* в качестве аргумента передаются два параметра: событие и объект, содержащий ссылку на компонент выбор пользователя (в поле args).

* *добавлено в версии 3.12 Tengri*

**Пример обработчика события добавления компонента выбора пользователя,
который выводит идентификатор компонента в консоль браузера:**

```javascript
function onUserChooserCreated(evt, chooser){
        var id = getUserChooserId(chooser.args);
        console.log(id);
}
```

Оперировать компонентом выбора пользователя можно следующими функциями:

- `getUserChooserId(chooserComponent)` - получение идентификатора компонента
выбора пользователя;

- `getUserChooserShowAll(chooserComponent)` - получение настройки "Разрешить
добавлять соисполнителей к работам, не являющихся подчиненными"

- `setUserChooserSelectedIds(chooserComponent, arrayOfUsersIds)` - выбрать
переданных пользователей;

- `getUserChooserSelectedIds(chooserComponent)` - получить идентификаторы
выбранных пользователей.

**Идентификаторы компонентов выбора пользователя:**

1. Диалог создания работы создания работы:

	- исполнитель - `editWorkUserChooser`

	- ответственные - `editWorkResponsibleUserChooser`

	- автор - `editWorkAuthorUserChooser`

2. Отправить-> переслать:

	- адресаты - `sendDocumentUserChooser`

3. Отправить -> перепоручить:

	- исполнитель - `assignmentSendUserChooser`

	- ответственные - `assignmentSendResponsibleUserChooser`

4. Отправить на согласование, утверждение, ознакомление:

	- адресаты - `sendWorkUserChooser`

5. Отправить по маршруту:

	- ответственный - `editRouteSendDialog`

6. все остальные компоненты будут иметь идентификатор `userChooser`.

В каждый DOM элемент компонента выбора пользователя добавляется атрибут
`userchooser` со значением идентификатора компонента выбора пользователя.
