В бизнес-приложениях на базе Synergy может возникнуть необходимость работы из внешних систем с формами Synergy. В этом случае можно использовать внешний проигрыватель форм.
Проигрыватель форм - это инструмент, который даёт возможность работать с формами, созданными и используемыми в Synergy, а также выполняет скрипты. При использовании во внешней системе проигрыватель позволяет:
Примечание: Проигрыватель форм запускается на стороне клиента, поэтому все события и скрипты срабатывают только при открытом проигрывателе.
Подключение проигрывателя форм
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>
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");
});
См. также документацию по скриптингу в формах и методам проигрывателя.
В данном разделе описываются основные примеры использования внешнего проигрывателя форм. Каждый пример отражает одно из базовых требований к внешнему проигрывателю и содержит:
Ссылки для быстрого перехода к примерам:
На внешнем портале (веб-сайте) существует реестр заявок на закуп. На внешнем портале существует заявка, которую необходимо заполнить и запустить на исполнение. Заявка представляет из себя форму в 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;
}
Расширение варианта 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;
}
Расширение варианта 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);
});
Расширение варианта 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();
}
}
На текущую форму «Заявка на закуп» добавлен компонент «Пользовательский компонент». В его настройках значением выбран такой пользовательский компонент, который позволяет выбрать поставщика и посмотреть о нем подробную информацию. 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">✕ Удалить</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);
Аналогичен варианту 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");
}
}
Расширение варианта 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("Прошу закупить товар.");
});
});
Внешний портал изменяет компонент формы "Выпадающий список" на новый (при этом его значения не изменяются):
переход между страницами осуществляется пагинатором:
пагинатор также отображает общее количество страниц.
Исходный код 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;
}
Авторизация в 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;
}