Внешний проигрыватель форм

В бизнес-приложениях на базе Synergy может возникнуть необходимость работы из внешних систем с формами Synergy. В этом случае можно использовать внешний проигрыватель форм.

Проигрыватель форм - это инструмент, который даёт возможность работать с формами, созданными и используемыми в Synergy, а также выполняет скрипты. При использовании во внешней системе проигрыватель позволяет:

Примечание: Проигрыватель форм запускается на стороне клиента, поэтому все события и скрипты срабатывают только при открытом проигрывателе.

Подключение проигрывателя форм

  1. Для подключения проигрывателя на страницу необходимо добавить код в раздел head:
<script>
         FORM_PLAYER_URL_PREFIX = "http://127.0.0.1:8080/Synergy/"; <!--служебная переменная для корректной работы компонента "HTD-редактор"-->
</script>
<link rel="stylesheet" href="http://127.0.0.1:8080/Synergy/js/form.player.css"/> <!--стандартный стиль компонентов формы-->
<script src="http://127.0.0.1:8080/Synergy/js/vendor.js" type="text/javascript"></script> <!--ссылка на сторонние библиотеки-->
<script src="http://127.0.0.1:8080/Synergy/js/form.player.js" type="text/javascript"></script> <!--ссылка на проигрыватель форм-->

и вставить сам проигрыватель в тело страницы:

<div id="form_player_container">
             <div id="form_player_div" > </div>
</div>
  1. Код скрипта, который использует проигрыватель, должен содержать ссылку на Synergy:

AS.OPTIONS.coreUrl = "http://127.0.0.1:8080/Synergy/"; //ссылка на экземпляр Synergy

Создание объекта проигрывателя выглядит следующим образом:

'use strict';

AS.OPTIONS.locale = "ru";
AS.OPTIONS.coreUrl = "http://127.0.0.1:8080/Synergy/";


var portal = {
    player : null,
    
    /**
     * очистить текущий проигрыватель форм
     */
    clearPlayer : function() {
        if(portal.player) {
            portal.player.destroy();
        }
    },
    /**
     * добавить новый проигрыватель форм
     */
    createPlayer : function(formCode){

        portal.clearPlayer();
        portal.player = AS.FORMS.createPlayer();
        
        portal.player.showFormByCode(formCode);

        portal.player.view.appendTo($('#form_player_div'));

    }
    
};


$(document).ready(function(){

    AS.OPTIONS.login = "login";
    AS.OPTIONS.password = "password";
    portal.createPlayer("formCode");

});

См. также документацию по скриптингу в формах и методам проигрывателя.

Варианты использования внешнего проигрывателя форм

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

Ссылки для быстрого перехода к примерам:

Вариант 1. Отображение проигрывателя, встроенного во внешний портал

На внешнем портале (веб-сайте) существует реестр заявок на закуп. На внешнем портале существует заявка, которую необходимо заполнить и запустить на исполнение. Заявка представляет из себя форму в Synergy. Все заявки собираются в реестре заявок.

Форма содержит следующие компоненты:

Компоненты обладают разными свойствами:

Исходный код JavaScript:


'use strict';

var synergyURL = "http://demoextfp.synergy.tm/Synergy/"; var tokenServiceURL = "http://demoextfp.synergy.tm/TokenService/rest/tokenService/getToken";

AS.OPTIONS.locale = "ru";
AS.OPTIONS.coreUrl = synergyURL;


var portal = {
    player : null,
    /**
     * показать сообщение об ошибке
     * @param{string} message
     */
    showMessage : function(message) {
        jQuery("#message_text").html(message);
        jQuery("#message").show();
    },
    /**
     * скрыть панель сообщений
     */
    hideMessage : function(){
        jQuery("#message").hide();
    },
    /**
     * очистить текущий проигрыватель форм
     */
    clearPlayer : function() {
        if(portal.player) {
            portal.player.destroy();
        }
        jQuery("#send_button").hide();
        portal.player = null;
    },
    /**
     * добавить новый проигрыватель форм
     */
    createPlayer : function(dataId){

        portal.clearPlayer();
        portal.player = AS.FORMS.createPlayer();
        AS.FORMS.bus.on(AS.FORMS.EVENT_TYPE.formShow, function(event, model, view){
            model.on(AS.FORMS.EVENT_TYPE.dataLoad, function(){

            });

            if(view.editable) {
                jQuery("#send_button").show();
                jQuery("#send_button").removeAttr('disabled','disabled');
            }

        });


        portal.player.view.setEditable(_.isUndefined(dataId));
        portal.player.showFormData("7dd2a298-0cb7-4ec7-ba67-ecc59c86e1aa", 0, dataId);


        portal.player.view.appendTo($('#form_player_div'));

        portal.player.model.on("valueChange", function(){
            portal.hideMessage();
        });

    },
    /**
     * искать форму по указанному номеру
     */
    searchData : function(){

        var counterValue = jQuery("#search_input").val();
        AS.FORMS.ApiUtils.simpleAsyncGet("rest/api/asforms/search?formUUID=7dd2a298-0cb7-4ec7-ba67-ecc59c86e1aa&search="+encodeURIComponent(counterValue)+"&field=counter&type=exact", function(data){

            if(data === null || !(data instanceof Array) || data.length === 0) {
                portal.showMessage("Заявка с указанным номером не найдена");
                return;
            }
            var dataId = data[0];
            portal.createPlayer(dataId);
        });
    },
    /**
     * сохранить данные, получить их, отобразить номер счетчика для дальнейшего поиска
     */
    saveData : function(){
        var errors = portal.player.model.getErrors();
        if(errors.length > 0) {
            portal.showMessage("Введите все обязательные поля");
            return;
        }

        jQuery("#send_button").attr('disabled','disabled');

        var counterValue = portal.player.model.getModelWithId('counter').getValue();

        AS.FORMS.ApiUtils.simpleAsyncGet("rest/api/registry/create_doc?registryID=59ad0163-2eac-460a-af1f-c0f7c7757dec", function(result){
            if(result.errorCode != 0) {
                portal.showMessage("Во время сохранения данных по форме произошли ошибки. Обратитесь к администратору");
                return;
            }
            portal.player.model.asfDataId=result.dataUUID;
            portal.player.saveFormData(function(result){

                if(_.isUndefined(result)) {
                    portal.showMessage("Во время сохранения данных по форме произошли ошибки. Обратитесь к администратору");
                    return;
                }

                AS.FORMS.ApiUtils.simpleAsyncGet('rest/api/asforms/data/' + result, function(data){

                    data.data.forEach(function(value){
                        if(value.id === 'counter') {
                            counterValue = value.value;
                            portal.showMessage("Ваша заявка была принята в обработку. Номер заявки - "+counterValue);
                        }
                    });
                });
                portal.clearPlayer();
            });
        });
    }
};


$(document).ready(function(){

    jQuery.ajax({
        method: "GET",
        url : tokenServiceURL+"?url="+synergyURL,
        success : function(data){
            AS.OPTIONS.login = "$key";
            AS.OPTIONS.password = data;

            portal.createPlayer();
        }
    });



    jQuery(document).mouseup(function (e) {
        var container = jQuery("#message");
        if (!container.is(e.target) && container.has(e.target).length === 0) {
            container.hide();
        }
    });
});

Исходный код CSS:

body, div, span, input, button{
    font-family: "Droid Sans", arial, serif;
    font-size:14px;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}

.hidden{
    display:none;
}

.portal_button{
    background-color: #df6c6d;
    border-color: #df6c6d;
    color: #ffffff;
    padding-left:20px;
    padding-right:20px;
    height:30px;
    border:none;
    margin-left:10px;
    margin-right:10px;
}

.portal-center {
    text-align:center;
    vertical-align:top
}

.portal-toolbar{
    padding:10px;
    color:#6e8ebd
}

#form_player_container{
    border: 3px solid #6e8ebd ;
    outline: 1px #ffffff solid;
    margin-left:auto;
    margin-right:auto;
    width:1000px;
    min-height:400px;
    background-color: #ffffff;
    padding-top:20px;
    padding-bottom:60px;
    margin-bottom:20px;

}

#form_player_div{
    width:1000px;
    min-height:200px;
}

#search_input {
    background-color:#6e8ebd ;
    border: 1px #6e8ebd solid;
    height:30px;
    width:200px;
    padding-left:10px
}

#send_button{
    margin-left:auto;
    margin-right:auto;
    width:200px;
    margin-bottom:20px;
}

#message{
    background-color:#ffffff;
    border: 3px solid #df6c6d ;
    outline: 1px #932121 solid;
    z-index: 2;
    position:absolute;
    top:100px;
    left: 30%;
    color:#303030;
    padding:10px;
    max-width:40%;
    min-width:40%;
}

#message_text{
    color:#303030;
}

Вернуться в начало

Вариант 2. Изменение вида отображения формы согласно стилю портала (CSS)

Расширение варианта 1. Внешний вид отображения формы меняется согласно стилю портала:

Исходный код JavaScript и CSS формы аналогичны варианту 1.

Исходный код CSS портала для варианта 2:

.asf-textBox, .asf-dateBox, .asf-timeBox{
    background-color: #FFFFFF;
    background-image: none;
    border: 1px solid #e5e6e7;
    border-radius: 1px;
    padding: 6px 6px;
    font-family:"Droid Sans", arial, serif !important;
    font-size: 14px !important;
    height:34px;
    display:inline-block;
    transition: border 0.5s ease;
}


.asf-textBox:focus, .asf-dateBox:focus, .asf-timeBox:focus{
    border: 1px solid #1ab394;
}


.ns-tagItem{
    background-color:#c3ded9;
    border: 1px solid #1ab394;
    box-sizing:border-box;
    line-height:20px;
}

.ns-tagContainer{
    padding: 6px 0px 0 6px;
    min-height: 34px;
    border-radius:0;
    width: calc(100% - 34px) !important;
}

.asf-browseButton, .asf-calendar-button, .asf-file-choose-button, .asf-user-chooser{
    height: 34px;
    width: 34px;
    border-radius:0;
    background-color: #1ab394;
    border: 1px solid #1ab394;
}

.asf-file-choose-button{
    width: 120px;
    color:#ffffff;
}


.asf-label{
    font-weight:bold;
    color: #676a6c;
    font-family:"Droid Sans", arial, serif !important;
}


.signsList{
    color: #676a6c;
    font-family:"Droid Sans", arial, serif !important;
}

Вернуться в начало

Вариант 3. Автозаполнение данных формы из внешнего портала

Расширение варианта 1. По нажатию на кнопку внешнего портала «Заполнить ИИН» поле формы «ИИН» автоматически заполняется.

Исходный код JavaScript и CSS формы аналогичны варианту 1.

Исходный код JavaScript автозаполнения для варианта 3:

/**
 * Created by user on 11.08.16.
 */

// вешаем лисенер на событие открытия формы

var fillInIIN = jQuery("<button>", {class : "portal_button"});
fillInIIN.html("Заполнить ИИН");

fillInIIN.click(function(){

    if(portal.player == null) {
        return;
    }

    var user = portal.player.model.getModelWithId("author").getValue();
    if(user === null) {
        return;
    }
    var personID = user.personID;
    var IIN = "";  // some logic for getting IIN from server
    var utf8 = unescape(encodeURIComponent(personID));
    for (var i = 0; i < utf8.length; i++) {
        IIN+=utf8.charCodeAt(i)+"";
    }
    portal.player.model.getModelWithId("iin").setValue(IIN);
});

AS.FORMS.bus.on(AS.FORMS.EVENT_TYPE.formShow, function(event, model, view){

    // если проигрыватель открылся в режиме чтения то ничего не делаем
    if(!view.editable) {
        return;
    }

    jQuery("#portal_toolbar").append(fillInIIN);

});


AS.FORMS.bus.on(AS.FORMS.EVENT_TYPE.formDestroy, function(event, model, view){

    jQuery("#portal_toolbar").remove(fillInIIN);

});

Вернуться в начало

Вариант 4. Дополнительная валидация формы

Расширение варианта 1. Дополнительная валидация: значение поля «Итоговая сумма» должно быть не больше значения поля «Предварительная сумма». Иначе сразу по мере ввода некорректного значения поле подсвечивается красным и появляется оранжевая подпись под ним с текстом:

Значение данного поля не должно превышать значения поля "Предварительная сумма"

Исходный код JavaScript и CSS формы аналогичны варианту 1.

Исходный код JavaScript доп. ФЛК для варианта 4, который необходимо вставить во вкладку «Код скрипта» настроек компонента, соответствующему числовому полю «Итоговая сумма»:

/**
 * компонент поля Предварительная сумма
 */
var sum1 = model.playerModel.getModelWithId("sum1");

/**
 * функция проверяет меньше ли значение компонента чем значение компонента предварительная сумма
 * @returns {boolean}
 */
function checkSumValue(){
    return model.getValue() !==null &&  parseInt(sum1.getValue()) < parseInt(model.getValue()) ;
}

/**
 * лейб указывающий об ошибке заполнения
 */
var errorLabel = jQuery("<div>", {class : "asf-Label"});
errorLabel.css("color", "#ff9966");
errorLabel.html('Значение данного поля не должно превышать значения поля "Предварительная сумма"');
view.container.append(errorLabel);
errorLabel.hide();

/**
 * переопределяем метод для пометки компонента неправильно заполеннным (старый оставляем)
 * @type {view.markInvalid|*}
 */
view.originalMarkInvalid = view.markInvalid;
view.markInvalid = function(){
    view.originalMarkInvalid();
    errorLabel.show();
};

/**
 * переопределяем метод удаления отметки неправильно заполненного компонента
 * @type {view.unmarkInvalid|*}
 */
view.originalUnmarkInvalid = view.unmarkInvalid;
view.unmarkInvalid = function(){
    view.originalUnmarkInvalid();
    errorLabel.hide();
};

/**
 * подписываемся на событие изменения значения модели компонента Предварительная сумма
 */
sum1.on("valueChange", function(){
    view.checkValid();
});

/**
 * подписываемся на событие изменения значения собственного компонента
 */
model.on("valueChange", function(){
    view.checkValid();
});

/**
 * переопределяем метод получение ошибок заполнения (старый тоже оставляем)
 * @type {view.unmarkInvalid|*}
 */

model.originalErrors = model.getSpecialErrors;
model.getSpecialErrors = function(){
    if(checkSumValue()) {
        return {id : model.asfProperty.id, errorCode : AS.FORMS.INPUT_ERROR_TYPE.valueTooHigh};
    } else {
        return model.originalErrors();
    }
}

Вернуться в начало

Вариант 5. Создание нового компонента

На текущую форму «Заявка на закуп» добавлен компонент «Пользовательский компонент». В его настройках значением выбран такой пользовательский компонент, который позволяет выбрать поставщика и посмотреть о нем подробную информацию. HTML и JavaScript коды такого пользовательского компонента приведены ниже. Список доступных действий:

Исходный код JavaScript и CSS формы аналогичны варианту 1.

HTML код пользовательского компонента:

<div innerId="textView" style="text-decoration:underline; cursor:pointer;width:calc(100% ); margin-bottom:2px"></div>
<input type="text" class="asf-textBox" innerId="name" style="width:calc(100% )"/>
<div style="color:#606060; text-decoration:underline" class="asf-InlineBlock asf-cursorPointer" innerId="add">+Создать</div>
<div style="color:#606060; margin-left:10px; text-decoration:underline" class="asf-InlineBlock asf-cursorPointer" innerId="browse">Выбрать из реестра</div>
<div style="color:#606060; margin-left:10px; text-decoration:underline" class="asf-InlineBlock asf-cursorPointer" innerId="delete">&#10005; Удалить</div>

JavaScript код пользовательского компонента:


/* инициализация модели */
/**
 * текстовое значение записи реестра
 * @type {string}
 */
model.textValue = "";
/**
 * идентификатор файла по форме выбранной записи реестра
 * @type {string}
 */
model.asfDataId = null;

/**
 * метод должен возвращать идентификатор реестра, можно переопределить в скрипте пользовательского компонента
 * @returns {string}
 */
if(!model.getRegistryID) {
    model.getRegistryID = function () {
        return "5279da23-4cdb-4527-92f8-eb70b6983a48";
    };
}

/**
 * обновить текстовое представление записи реестра
 */
model.updateTextView = function () {
    if(!model.getValue()) {
        model.textValue = "";
        model.asfDataId = null;
        model.trigger(AS.FORMS.EVENT_TYPE.dataLoad, [model]);
        return;
    }
    AS.FORMS.ApiUtils.getAsfDataUUID(model.getValue(), function (newAsfDataId) {
        model.asfDataId = newAsfDataId;
        AS.FORMS.ApiUtils.getDocMeaningContent(model.getRegistryID(), newAsfDataId, function (text) {
            model.textValue = text;
            model.trigger(AS.FORMS.EVENT_TYPE.dataLoad, [model]);
        });
    });
};

/**
 * получить тесктовое представление записи реестра
 * @returns {string|string|*}
 */
model.getTextValue = function(){
    return model.textValue;
};

// подписываемся на событие модели об изменении содержания, чтобы подгрузить дополнительные данные
model.on(AS.FORMS.EVENT_TYPE.valueChange, function(){
    model.updateTextView();
});

/**
 * метод реализовывает вставку asfData
 * @param asfData
 */
model.setAsfData = function(asfData){
    model.setValue(asfData.key);
};

/**
 * метод реализовывает получение данных компонента для сохранения
 * @param blockNumber
 * @returns {*}
 */
model.getAsfData = function(blockNumber){
    return AS.FORMS.ASFDataUtils.getBaseAsfData(model.asfProperty, blockNumber, model.textValue, model.value);
};



/* инициализация отображения */


/**
 * реестр
 * @type {object}
 */
var registry = null;
/**
 * видимые колонки реестра
 * @type {Array}
 */
var registryColumns = [];


/**
 * поле ввода для поиска записей реестра
 * @type {XMLList|*}
 */
var input = jQuery(view.container).children("[innerId='name']");
/**
 * поле для отображения выбранной записи реестра
 * @type {XMLList|*}
 */
var textView = jQuery(view.container).children("[innerId='textView']");
/**
 * кнопка добавления записи
 * @type {XMLList|*}
 */
var addIcon = jQuery(view.container).children("[innerId='add']");
/**
 * кнопка выбора записи из реестра
 * @type {XMLList|*}
 */
var browseIcon = jQuery(view.container).children("[innerId='browse']");
/**
 * кнопка удаления текущей выбранной записи
 * @type {XMLList|*}
 */
var deleteIcon = jQuery(view.container).children("[innerId='delete']");

// кнопку удаления текущей выбраннйо записи скрываем
deleteIcon.hide();

// по нажатию на кнопку "выбрать из реестра" открываем стандартный диалог выбра записи реестра
browseIcon.click(function(){
    AS.SERVICES.showRegisterLinkDialog(registry, function(documentId){
        model.setValue(documentId);
    });
});

// по нажатию на кнопку "создать" открываем форму создания записи реестра
addIcon.click(function(){
    if(!registry.rr_create) {
        alert("У вас нет прав на создание записей данного реестра");
        return;
    }

    var createPlayerDiv = jQuery("<div>");
    createPlayerDiv.css("width", "800px");

    createPlayerDiv.css("border", "1px solid #afafaf");

    var saveButton = jQuery("<button>", {class : "ns-approveButton ns-basicChooserApplyButton"});
    saveButton.button();
    saveButton.html("Добавить поставщика");
    saveButton.css("margin", "auto");
    saveButton.css("display", "block");

    var player = AS.FORMS.createPlayer();

    player.view.setEditable(true);
    player.showFormData(registry.formId);
    player.view.appendTo(createPlayerDiv);

    createPlayerDiv.append(saveButton);



    createPlayerDiv.dialog({
        width: 1000,
        height: 400,
        modal : true
    });


    saveButton.click(function(){
        var valid = player.model.isValid();
        if(!valid) {
            alert("Введите все обязательные поля");
            return;
        }

        AS.SERVICES.showWaitWindow();
        AS.FORMS.ApiUtils.simpleAsyncGet("rest/api/registry/create_doc?registryID="+registry.registryID, function(result){
            if(result.errorCode != 0) {
                AS.SERVICES.hideWaitWindow();
                alert("Во время сохранения данных по форме произошли ошибки. Обратитесь к администратору");
                return;
            }
            player.model.asfDataId=result.dataUUID;
            player.saveFormData(function(result){
                AS.SERVICES.hideWaitWindow();
                if(_.isUndefined(result)) {
                    alert("Во время сохранения данных по форме произошли ошибки. Обратитесь к администратору");
                    return;
                };


                createPlayerDiv.dialog( "destroy" );

                AS.FORMS.ApiUtils.getDocumentIdentifier(result, function(documentID){
                    model.setValue(documentID);
                });

            });
        });

    });


});


// по нажатию на кнопку удалить  - удаляем выбранное значение
deleteIcon.click(function(){
    model.setValue(null);
});


// по нажатию на текстовое отображение  - открываем запись реестра на просмотр
textView.click(function(){
    var createPlayerDiv = jQuery("<div>");
    createPlayerDiv.css("width", "800px");

    createPlayerDiv.css("border", "1px solid #afafaf");

    var player = AS.FORMS.createPlayer();

    player.view.setEditable(false);
    player.showFormData(null, null, model.asfDataId, 0);
    player.view.appendTo(createPlayerDiv);

    createPlayerDiv.dialog({
        width: 1000,
        height: 330,
        modal : true
    });
});


// скрываем или отображаем поля ввода в зависимости от того режим чтения это или редактирования
if (editable) {
    textView.hide();
} else {
    input.hide();
    addIcon.hide();
    browseIcon.hide();
    deleteIcon.hide();
}

// реализовываем метод обновления отображения согласно изменившимся данным модели
view.updateValueFromModel = function(){
    input.val("");
    if(model.getValue()) {
        textView.css("display", "");
        input.hide();
        textView.html(model.getTextValue());
        input.hide();
        if(editable) {
            deleteIcon.css("display", "");
        }
    } else {

        if(editable) {
            textView.hide();
            input.css("display", "");
        } else {
            textView.css("display", "");
            input.hide();
        }

        textView.html("");
        input.text("");
        deleteIcon.hide();
    }
};

// подписываем на событие подгрузки дополнительных данных значения
model.on(AS.FORMS.EVENT_TYPE.dataLoad, function () {
    view.updateValueFromModel();
});


/**
 * если нет прав создания записи реестра, то кнопки создать не должно быть видно
 */
function validateIconsState() {
    addIcon.hide();
    if(registry.rr_create) {
        addIcon.css("display", "");
    }
}

/**
 * инициализируем компонент (получаем реестр, колонки)
 */
function initComponent() {
    if(!model.getRegistryID()) {
        return;
    }
    AS.FORMS.ApiUtils.getRegistry(model.getRegistryID(), function(reg){
        registry = reg;

        registry.registryID = model.getRegistryID();

        registryColumns = [];
        registry.columns.forEach(function(col){
            if(col.visible != 1) {
                return;
            }
            registryColumns.push(col);
        });

        registryColumns = registryColumns.sort(function(item1, item2){
            var number1 = item1.order;
            var number2 = item2.order;
            if(number1 === number2) {
                if(item1.name < item2.name) {
                    return -1;
                } else if(item1.name > item2.name) {
                    return 1;
                }
            } else {
                if(number1 === 0 ) {
                    return 1;
                } else if(number2 === 0 ) {
                    return -1;
                } else if(number1 < number2) {
                    return -1;
                } else {
                    return 1;
                }
            }
            return 0;
        });

        validateIconsState();
    });
}

// при вводе пользователя отображаем первые 10 результатов поиска
input.on("input", function(){
    var search = input.val();
    if(search.length === 0 || !registry) {
        AS.SERVICES.showDropDown([]);
        return;
    }

    AS.FORMS.ApiUtils.getRegistryData(model.getRegistryID(), 0, 10, search, null, null, function(foundData){
        var values = [];
        foundData.result.forEach(function(record){
            var value = {value : record.documentID};
            var label = "";

            registryColumns.forEach(function(column){
                label += record.fieldValue[column.columnID]+" - ";
            });

            value.title = label;
            values.push(value);
        });

        AS.SERVICES.showDropDown(values, input, null, function(selectedValue){
            model.setValue(selectedValue);
            view.updateValueFromModel();
        });

    });

});


setTimeout(function(){
    initComponent();
}, 0);





Вернуться в начало

Вариант 6. Использование внешнего проигрывателя в портлетах

Аналогичен варианту 5, только в портлете.

Исходный java-код портлета:

package kz.arta.synergy.formPlayer.portlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
/**
 * Created by exile
 * Date: 16.08.16
 * Time: 10:57
 */


public class FormPlayerPortlet extends GenericPortlet{

    @Override
    protected void doView(RenderRequest req, RenderResponse res) throws PortletException, IOException {
        res.setContentType("text/html; charset=utf-8");
        PrintWriter out=res.getWriter();
        out.println("    <div>n" +
                "n" +
                "        <!--  LOCALIZATION LIBRARY  -->n" +
                "n" +
                "        <script src="http://demoextfp.synergy.tm/Synergy/js/i18next.min.js" type="application/javascript"></script>n" +
                "n" +
                "        <script>n" +
                "            FORM_PLAYER_URL_PREFIX = "http://demoextfp.synergy.tm/Synergy/";n" +
                "        </script>" +
                "n" +
                "        <!--  JS FORMS  -->n" +
                "n" +
                "        <link rel="stylesheet" href="http://demoextfp.synergy.tm/Synergy/js/form.player.css"/>n" +
                "        <script src="http://demoextfp.synergy.tm/Synergy/js/vendor.js" type="text/javascript"></script>n" +
                "        <script src="http://demoextfp.synergy.tm/Synergy/js/form.player.js" type="text/javascript"></script>n" +
                "n" +
                "        <!--  PORTAL SCRIPTS AND STYLESHEET  -->n" +
                "n" +
                "        <script src="http://demoextfp.synergy.tm/FormPlayer/index.js" type="text/javascript"></script>n" +
                "n" +

                "n" +
                "        <link href="http://demoextfp.synergy.tm/FormPlayer/index.css" rel="stylesheet"/>n" +
                "n" +
                "        <div style="z-index: 0" class="portal-center">n" +

                "        <style scoped>n" +
                "             input { margin-bottom: 0px; }n" +
                "        </style>      n" +

                "            <div class="portal-toolbar" id="portal_toolbar">n" +
                "                <span> Введите номер заявки </span><input type="text" id="search_input" /><button id="search_button" class="portal_button search_button" value="SEARCH" onclick="portal.searchData()"> SEARCH </button>n" +
                "                <button id="create_button" class="portal_button create_button" value="CREATE" onclick="portal.createPlayer()"> CREATE </button>n" +
                "            </div>n" +
                "            <div id="form_player_container">n" +
                "n" +
                "n" +
                "                <div id="form_player_div" >n" +
                "n" +
                "                </div>n" +
                "            </div>n" +
                "            <button id="send_button" class="portal_button hidden" value="SEND" onclick="portal.saveData()"> SEND </button>n" +
                "        </div>n" +
                "n" +
                "        <div id="message" class="hidden">n" +
                "            <span id="message_text"></span>n" +
                "        </div>n" +
                "n");
    }

}

Вернуться в начало

Вариант 7. Предварительное заполнение данных формы внешним порталом

Расширение варианта 1. Перед отображением формы ее данные предзаполняются внешним порталом.

Исходный код JavaScript и CSS формы аналогичны варианту 1.

Исходный код JavaScript предварительного заполнения для варианта 7:

/**
 * Created by m.milutin on 15.08.16.
 */
AS.FORMS.bus.on(AS.FORMS.EVENT_TYPE.formShow, function(event, model, view){
    var playerModel = model
    playerModel.on(AS.FORMS.EVENT_TYPE.dataLoad, function(){
        // если проигрыватель открылся в режиме чтения то ничего не делаем
        if(!view.editable) {
            return;
        }

        var user = playerModel.getModelWithId("author").getValue();
        if(user === null) {
            return;
        }
        var personID = user.personID;
        var IIN = "";  // some logic for getting IIN from server
        var utf8 = unescape(encodeURIComponent(personID));
        for (var i = 0; i < utf8.length; i++) {
            IIN+=utf8.charCodeAt(i)+"";
        }
        playerModel.getModelWithId("iin").setValue(IIN);

        //Предзаполненный шаблон заявки на материал
        var text = 'Необходимых материалов для ремонта кабинетов ' +
            '<br/>1. ГКЛ ……………………………………………………………… м2. ' +
            '<br/>2. Фанера ……………………………………………………….… м2. ' +
            '<br/>3. Саморезы по дереву 35×3,5 ………………………………… шт. ' +
            '<br/>4. Дюбель саморезы 75×4 ……………………………………… шт. ' +
            '<br/>5. Подвесной потолок в комплекте …………………………… м2.'
        playerModel.getModelWithId("text").setValue(text);

        var regLingRecordIdentifier = "3d488280-5e22-11e6-8e70-fe5400e1ce06";

        playerModel.getModelWithId("registry").setValue(regLingRecordIdentifier);
        playerModel.getModelWithId("sum1").setValue("555999.99");
        playerModel.getModelWithId("sum2").setValue("666660.99");

        playerModel.getModelWithId("sum2").setValue("666660.99");

        playerModel.getModelWithId("date1").setValue("2016-08-15 00:00:00");
        playerModel.getModelWithId("date2").setValue("2016-08-16 00:00:00");

        playerModel.getModelWithId("note").setValue("Прошу закупить товар.");
    });

});


Вернуться в начало

Вариант 8. Изменение компонента формы

Внешний портал изменяет компонент формы "Выпадающий список" на новый (при этом его значения не изменяются):

Исходный код JavaScript и CSS формы аналогичны варианту 1.

Исходный код JavaScript для варианта 8:

/**
 * Created by m.milutin on 16.08.16.
 */

//Все элементы выпадающего списка
var elements = [];

//Элементы которые подходят по запросу поиска
var filteredElements = [];

//Количество доступных страниц
var allSize = 0;

//Модель изначального комбобокса
var comboModel;

//Запись от которой начинается отображение
var start = 0;

//До какой записи отображать значения
var end = start + 15;

//Текущая страница
var currentPage = 0;

AS.FORMS.bus.on(AS.FORMS.EVENT_TYPE.formShow, function (event, model, view) {
    var playerModel = model;

    if(playerModel.formId != 'e0bb813a-fc15-4acc-bcf2-fd5c1ee303ef') {
        return;
    }

    if(!view.editable) {
        return;
    }
    var comboView = view.getViewWithId('dirty-combobox');
    var comboModel = playerModel.getModelWithId('dirty-combobox');
    playerModel.on(AS.FORMS.EVENT_TYPE.dataLoad, function () {
        //Убираем изначальный комбобокс
        comboView.container.empty();

        //Создаем поле для ввода запроса
        var input = jQuery("<input/>", {type: "text", class: "drop_down_input"});
        input[0].setValue = function(id, text){
           comboModel.setValue(id);
        };

        //Вставляем в ту зону в которой был старый комбо
        comboView.container.append(input);

        //Когда произведен клик по полю ввода отобразить выпадающий список
        input.on('click', function () {
            showDropDownInput();
        });

        //Когда нажата клавиша отобразить выпадающий список и начать поиск
        input.keypress(function () {
            showDropDownInput();
            search(jQuery('.drop_down_input').val());
        });

        comboModel.on("valueChange", function(){
            input.val(comboModel.getTextValue());
        });

        //Берем модель и подписываемся на событие загрузки данных, для получения справочника
    });



    comboModel.on(AS.FORMS.EVENT_TYPE.dataLoad, function () {
        elements = comboModel.listElements;
        filteredElements = comboModel.listElements;
        allSize = Math.ceil(filteredElements.length / 15);
        //Сбрасываем текущую страницу
        setCurrentPage(1);
    });

    addHandlers();
});

/**
 * Добавление событий
 * */
var addHandlers = function () {
    //Нажатие на кнопку следующая страница
    jQuery(".next_page").on('click', function () {
        next();
    });

    //Нажатие на кнопку предыдущая страница
    jQuery(".previous_page").on('click', function () {
        previous();
    });

    //Нажатие на кнопку первая страница
    jQuery(".first_page").on('click', function () {
        firstPage();
    });

    //Нажатие на кнопку последняя страница
    jQuery(".last_page").on('click', function () {
        lastPage();
    });

    //Ввод страницы, по нажатию на энтер будет произведен переход
    jQuery('.input_page').keypress(function (e) {
        if (e.which == 13) {
            setCurrentPage(jQuery('.input_page').val());
        }
    });

    //Скрытие выпадающего списка, по нажатию на поле вне его
    jQuery(document).mouseup(function (e) {
        var container = jQuery(".drop_down_list");
        if (!container.is(e.target) && container.has(e.target).length === 0) {
            container.hide();
        }
    });
};

/**
 * Отображение выпадающего списка
 */
var showDropDownInput = function () {
    var input = jQuery('.drop_down_input');
    var position = input.position();
    var list = jQuery('.drop_down_list');
    list.css({top: position.top + input.height() + 6, left: position.left});
    list.css({width: input.width()})
    list.show();
};

/**
 * Следующая страница
 */
var next = function () {
    if (currentPage + 1 > allSize) {
        return;
    }
    start = end;
    currentPage++;
    end = start + 15;
    setPage();
};

/**
 * Поиск
 *
 * @param value - значение поиска
 */
var search = function (value) {
    start = 0;
    end = start + 15;
    currentPage = 1;
    filteredElements = [];
    elements.forEach(function (element) {
        if (element.label.toLowerCase().indexOf(value.toLowerCase()) !== -1) {
            filteredElements.push(element);
        }
    });
    allSize = Math.ceil(filteredElements.length / 15);
    setPage();
};

/**
 * Предыдущая страница
 */
var previous = function () {
    if (currentPage - 1 < 1) {
        return;
    }
    start = start - 15;
    currentPage--;
    end = start + 15;
    setPage();
};

/**
 * Изменение положения страницы в зависимости от состояния глобальных переменных
 */
var setPage = function () {
    var showed = filteredElements.slice(start, end);
    jQuery(".result_search_combo").empty()

    showed.forEach(function (element) {
        var opt = jQuery("<div class='result_element' code='" + element.value + "'>" + element.label + "</div>");
        opt.on('click', function () {
            jQuery('.drop_down_input')[0].setValue(jQuery(this).attr('code'), jQuery(this).html());
            jQuery(".drop_down_list").hide();
        });
        jQuery('.result_search_combo').append(opt);
    });

    jQuery('.input_page').val(currentPage);
    jQuery('.count_result').html(allSize);
};

/**
 * Первая страница
 */
var firstPage = function () {
    setCurrentPage(1);
};

/**
 * Последняя страница
 */
var lastPage = function () {
    setCurrentPage(allSize);
};

/**
 * Изменить состояние страницы
 *
 * @param value - значение
 */
var setCurrentPage = function (value) {
    if (!jQuery.isNumeric(value)) {
        setCurrentPage(currentPage);
        return;
    }
    if (value > allSize) {
        value = allSize;
    } else if (value < 1) {
        value = 1;
    }
    currentPage = value;

    end = currentPage * 15;
    start = end - 15;

    setPage();
};






Исходный код CSS окна:

.drop_down_list {
    background-color: white;
    display: none;
    position: absolute;
    box-shadow: 0 0 35px #d6d6d6;
}

.drop_down_input {
    width: 100%;
    font-family: arial, tahoma, sans-serif;
    font-size: 12px;
    padding-left: 2px;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    height: 28px;
    align-self: center;
    border: solid 1px #d6d6d6;
    border-radius: 4px;
    background-color: #ffffff;
    display: inline-block;
    vertical-align: middle;
    line-height: 28px;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    cursor: pointer;
}

.result_search_combo {
    height: 80%;
    overflow-y: scroll;
    max-height: 300px;
}

.result_element {
    padding: 5px 10px;
    text-align: left;
    border-bottom: 1px solid #d6d6d6;
    margin: 0px 3px;
    font-family: arial, tahoma, sans-serif;
    font-size: 12px;
}

.result_element:hover {
    background-color: #deefff;
}

.drop_down_toolbar {
    display: inline-block;
    padding: 10px;
}
.drop_down_toolbar1 {
    display: flex;
    width: 290px;
}

.first_page {
    background-size: 100% 100%;
    width: 20px;
    height: 20px;
    background-image: url("icon/first.ico");
}

.first_page:hover {
    background-color: #deefff;
}

.previous_page {
    background-size: 100% 100%;
    width: 20px;
    height: 20px;
    background-image: url("icon/previous.ico");
}

.previous_page:hover {
    background-color: #deefff;
}

.next_page {
    background-size: 100% 100%;
    width: 20px;
    height: 20px;
    background-image: url("icon/next.ico");
}

.next_page:hover {
    background-color: #deefff;
}

.last_page {
    background-size: 100% 100%;
    width: 20px;
    height: 20px;
    background-image: url("icon/last.ico");
}

.last_page:hover {
    background-color: #deefff;
}

.padding {
    padding: 0px 5px;
}
.input_page {
    width: 40px;
}

.margin {
    margin: 0px 5px;
}


Вернуться в начало

Вариант 9. Авторизация во внешнем проигрывателе

Авторизация в Synergy внутри внешнего проигрывателя форм. В результате успешной авторизации открывается форма из варианта 8.

Примеры логинов/паролей для варианта 9:

Исходный код JavaScript и CSS формы аналогичны варианту 8.

Исходный код JavaScript для варианта 9:

/**
 * Перехватываем событие неудачной авторизации
 */
AS.SERVICES.unAuthorized = function () {
    portal.showMessage("Ошибка авторизации");

    //Отображаем панель ввода логина/пароля
    jQuery(".auth_panel").show();
    addHandlers();
};

/**
 * Добавлены ли уже слушатели
 */
var existHandlers = false;

/**
 * Добавление слушателей
 */
var addHandlers = function(){
    if(!existHandlers){
        //Нажатие на кнопку войти
        jQuery(".submit_auth").on("click", function (event) {
            //Если не ввели логин или пароль выдаем ошибку
            if (jQuery(".login").val().isEmpty() || jQuery(".password").val().isEmpty()) {
                portal.showMessage("Введите логин и пароль");
                event.stopPropagation();
            } else {
                //В случае ввода заменяем значение переменных авторизации и прячем панель ввода, загружаем форму
                AS.OPTIONS.login = jQuery(".login").val();
                AS.OPTIONS.password = jQuery(".password").val();
                jQuery(".auth_panel").hide();
                portal.createPlayer();
            }
        });

        //При нажатии на панель авторизации скрывать сообщение об ошибке
        jQuery(".auth_panel").on("click", function () {
            portal.hideMessage();
        });
    }

    existHandlers = true;
};

Исходный код CSS окна:

.auth_panel{
    display: none;
    left: 50%;
    transform: translate(-50%, 0);
    width: 350px;
    height: 200px;
    background-color: white;
    position: absolute;
    border-color: #24282B;
    border-style: none solid solid;
    border-width: 1px;
    top: 150px;
}

.auth_header{
    background-color: #4C5256;
    padding: 12px;
    color: white;
    font-family: arial, tahoma, sans-serif;
    font-size: 10pt;
    font-weight: bold;
    cursor: pointer;
}

.auth_fields{
    width: 200px;
    display: inline-block;
    height: calc(100% - 80px);
}

.login{
    margin-top: 30px;
}

.password {
    margin-top: 20px;
}

.buttons {
    height: 30px;
}

.submit_auth{
    height: 100%;
    width: 100px;
    border-radius: 5px;
    background-color: #49b785;
    border-color: #49b785;
    color: #ffffff;
}

Вернуться в начало