// form config.js /* global uiLocale, urlVersions */ // from core.js /* global isEmpty, deleteFromRest, fillSelect, MessageTypesEnum, showFeedbackMessage, getCurrentVersionData */ /* global getFromRestWithParams, getFromRest */ /* global postToRestWithVersionAndParams, putToRestWithVersionAndParams */ // TODO: settings for table selection mode (single, multiple) var odinMetaList = "/meta/list"; var odinMetaElement = "/meta/element"; var odinCopy = "/copy-from-version"; /* exported OdinTableWithMeta */ function OdinTableWithMeta(divId, dataUrl, disableCopy) { return OdinTableWithMetaAndParams(divId, dataUrl, "", disableCopy, ""); } /* exported OdinTableWithMetaAndGlobalCallback */ function OdinTableWithMetaAndGlobalCallback(divId, dataUrl, disableCopy, globalSaveCallback, globalSelectCallback) { return OdinTableWithMetaAndParams(divId, dataUrl, "", disableCopy, globalSaveCallback, globalSelectCallback); } /* exported OdinTableWithMetaAndParams */ function OdinTableWithMetaAndParams(divId, dataUrl, params, disableCopy, globalSaveCallback, globalSelectCallback) { return new OdinTable(divId, dataUrl + odinMetaList, dataUrl + odinMetaElement, dataUrl, params, disableCopy, globalSaveCallback, globalSelectCallback); } function OdinTable(divId, listMetaDataUrl, elementMetaDataUrl, dataUrl, params, disableCopy, globalSaveCallback, globalSelectCallback) { var CLICK_DELAY = 250; var DATA_ATTR = "odin-data"; var DATA_VIEW_ATTR = "odin-data-view"; var TYPE_ATTR = "type"; var ID_ATTR = "id"; var DISABLED_ATTR = "disabled"; var REQUIRED_ATTR = "required"; var LABELS_SELECTOR = "label"; var INPUTS_SELECTOR = ":input"; var BUTTONS_SELECTOR = ":button"; var CHECKED_ATTR = "checked"; var NOT_CHECKED_ATTR = ""; var PAGINATOR_ITEMS_PER_PAGE = 10; var PAGINATOR_VISIBLE_BUTTONS_COUNT = 3; var odinTable; var L10nEnum = { VIEW: "Наименование", COLLECTION: "Коллеция объектов", GO_TO: "Перейти", BUTTON_ADD: "Добавить", BUTTON_CREATE: "Создать", BUTTON_EDIT: "Изменить", BUTTON_DELETE: "Удалить", BUTTON_COPY: "Копировать", BUTTON_OK: "Продолжить", BUTTON_CANCEL: "Отмена", BUTTON_SAVE: "Записать", BUTTON_CLOSE: "Закрыть", CAPTION_CREATE_FORM: "Новый элемент", CAPTION_EDIT_FORM: "(редактирование)", CAPTION_CHOOSE_FORM: "Выбор объекта", CAPTION_COPY_FORM: "Копирование данных", CAPTION_DEFAULT_TAB: "Реквизиты", CPATION_FORM_DEFAULT: "...", QUESTION_LOST_CHANGES: "Закрыть без сохранения?", QUESTION_DELETE_ITEM: "Выполнить удаление?", QUESTION_DEFAULT_CAPTION: "Продолжит?", ERROR_VERSIONS_MATCH: "Версии совпадают" }; Object.freeze(L10nEnum); var FieldTypesEnum = { BOOLEAN: "boolean", DATE: "date", NUMERIC: "numeric", STRING: "string", COLLECTION: "collection", OBJECT: "object" }; Object.freeze(FieldTypesEnum); var DateTypesEnum = { DATETIME: "datetime", DATE: "date", TIME: "time" }; Object.freeze(DateTypesEnum); var StringTypesEnum = { STRING: "string", PASSWORD: "password", TEXT: "text", EMAIL: "email", HREF: "href" }; Object.freeze(StringTypesEnum); var VisibleTypesEnum = { ALL: "all", ON_CREATE: "on_create", ON_UPDATE: "on_update", NONE: "none" }; Object.freeze(VisibleTypesEnum); var InputTypesEnum = { CHECKBOX: "checkbox", PASSWORD: "password", TEXT: "text", EMAIL: "email", DATE: "date", DATETIME: "datetime-local", TIME: "time", NUMBER: "number", HIDDEN: "hidden", SUBMIT: "submit" }; Object.freeze(InputTypesEnum); var FormTypesEnum = { FORM: "form", CONFIRM: "confirm", SIMPLE: "simple" }; Object.freeze(FormTypesEnum); var NumberAttrEnum = { MIN: "min", MAX: "max", STEP: "step" }; Object.freeze(NumberAttrEnum); var StringAttrEnum = { MIN: "minlength", MAX: "maxlength" }; Object.freeze(StringAttrEnum); $(document.body).append("
"); $("#odinTemplates").load("/templates/odin.html", function () { $("#" + divId).append("
" + " " + "
"); odinTable = new OdinTableMain(divId, listMetaDataUrl, elementMetaDataUrl, dataUrl, params, disableCopy, globalSaveCallback, globalSelectCallback); }); this.getSelectedItems = function () { return odinTable.getSelectedItems(); } function format(str, args) { if (isEmpty(str) || isEmpty(args)) { return str; } if (!Array.isArray(args)) { throw "Odin: Format args is not array"; } return str.replace(/\{(\d+)\}/g, function (match, number) { return typeof args[number] !== "undefined" ? args[number] : match; }); } function centerDiv(component) { if (isEmpty(component)) { return; } component.offset({ top: ($(window).height() - component.height()) / 2, left: ($(window).width() - component.width()) / 2 }); } function tmpl(id) { var html = $("#odinTemplates").find("#" + id).html(); if (isEmpty(html)) { throw "Odin: Template load error"; } var template = format(html.trim(), Array.prototype.slice.call(arguments, 1)); return $(template); } function find(object, selector) { var result = object.find(selector); if (isEmpty(result)) { throw "Can't find elements by selector " + selector; } return result; } function findFiltered(object, selector, notSelector) { var result = object.find(selector).not(notSelector); if (isEmpty(result)) { throw "Can't find elements by selector " + selector; } return result; } function OdinFormCommon(type) { var BUTTON_CLOSE_SELECTOR = "i.fa"; var CAPTION_SELECTOR = "#caption"; var PANEL_SELECTOR = ".panel"; var FORM_INPUTS_SELECTOR = ":input"; var DATA_CHANGED_ATTR = "changed"; var form; var header; var content; var footer; var createForm = function () { switch (type) { case FormTypesEnum.FORM: form = tmpl("form"); break; case FormTypesEnum.CONFIRM: form = tmpl("formConfirm"); break; default: form = tmpl("formSimple"); } if (isEmpty(form)) { throw "Odin: Unknown form type"; } header = createFormHeader(); content = createFormContent(); footer = createFormFooter(); var formPanel = tmpl("formPanel"); formPanel.append(header); formPanel.append(content); formPanel.append(footer); form.append(formPanel); setCaption(L10nEnum.CPATION_FORM_DEFAULT); $(document.body).append(form); }; var createFormHeader = function () { var fHeader = tmpl("formHeader"); fHeader.find(BUTTON_CLOSE_SELECTOR).click(function () { hideForm(); }); return fHeader; }; var createFormContent = function () { return tmpl("formContent"); }; var createFormFooter = function () { return tmpl("formFooter"); }; var setCaption = function (caption) { if (isEmpty(caption)) { throw "Odin: Caption is not set"; } find(header, CAPTION_SELECTOR).text(caption); }; var addFormClass = function (clazz) { if (isEmpty(clazz)) { throw "Odin: Additional class is not set"; } form.addClass(clazz); }; var isModified = function () { return form.data(DATA_CHANGED_ATTR); }; var setFormSubmit = function (callBack) { if (isEmpty(callBack)) { throw "Odin: Callback is not set"; } form.submit(function () { callBack(); return false; }); }; var showForm = function () { form.show(0, function () { centerDiv(find(form, PANEL_SELECTOR)); }); if (type === FormTypesEnum.FORM) { find(form, FORM_INPUTS_SELECTOR).change(function () { form.data(DATA_CHANGED_ATTR, true); }); } }; var hideForm = function () { var callBack = function () { form.hide(); form.remove(); }; callBack(); }; this._getHeader = function () { return header; }; this._getContent = function () { return content; }; this._getFooter = function () { return footer; }; this._setCaption = function (caption) { setCaption(caption); }; this._setFormSubmit = function (callBack) { setFormSubmit(callBack); }; this._addFormClass = function (clazz) { addFormClass(clazz); }; this._isModified = function () { return isModified(); }; this._show = function () { showForm(); }; this._hide = function () { hideForm(); }; createForm(); } function OdinToolbar(tableDiv, createCallBack, editCallBack, deleteCallBack) { var SELECTOR_ODIN_TABLE = ".odin-table"; var toolbar; var createButton; var editButton; var deleteButton; var initialize = function () { if (isEmpty(tableDiv)) { throw "Odin-Toolbar: Target div is not set"; } var table = find(tableDiv, SELECTOR_ODIN_TABLE); toolbar = tmpl("toolbar"); toolbar.insertBefore(table, null); if (!isEmpty(createCallBack)) { createButton = tmpl("createButton", L10nEnum.BUTTON_CREATE); createButton.click(function () { createCallBack(); }); toolbar.append(createButton); } if (!isEmpty(editCallBack)) { editButton = tmpl("editButton", L10nEnum.BUTTON_EDIT); editButton.click(function () { editCallBack(); }); setEditButtonState(false); toolbar.append(editButton); } if (!isEmpty(deleteCallBack)) { deleteButton = tmpl("deleteButton", L10nEnum.BUTTON_DELETE); deleteButton.click(function () { deleteCallBack(); }); setDeleteButtonState(false); toolbar.append(deleteButton); } }; var setEditButtonState = function (state) { if (isEmpty(editButton)) { return; } editButton.attr("disabled", !state); }; var setDeleteButtonState = function (state) { if (isEmpty(deleteButton)) { return; } deleteButton.attr("disabled", !state); }; this.addButton = function (caption, callBack) { if (isEmpty(caption) || isEmpty(callBack)) { throw "Odin-Toolbar: Caption or callback is not set"; } var button = tmpl("basicButton", caption); button.click(function () { callBack(); }); toolbar.append(button); }; this.setEditButtonState = function (state) { setEditButtonState(state); }; this.setDeleteButtonState = function (state) { setDeleteButtonState(state); }; initialize(); } function OdinPaginator(tableDiv, callBack) { var SELECTOR_PAGINATOR_CONTENT = ".odin-paginator-content"; var SELECTOR_PAGINATOR_BUTTON = "a"; var PAGINATOR_BUTTON_PREFIX = "odin-paginator-"; var PAGINATOR_SELECTED_BUTTON_CLASS = "active"; var initialize = function () { if (isEmpty(tableDiv)) { throw "Odin-Paginator: Target div is not set"; } if (isEmpty(callBack)) { throw "Odin-Paginator: Callback is not set"; } tableDiv.append(tmpl("paginator")); }; var drawPaginator = function (data, offset) { var paginatorContentDiv = find(tableDiv, SELECTOR_PAGINATOR_CONTENT); paginatorContentDiv.empty(); if (isEmpty(data)) { return; } $.each(data, function (index, value) { if (value.name) { paginatorContentDiv.append(tmpl("paginatorButton", value.offset, value.name)); } else { paginatorContentDiv.append(tmpl("paginatorSeparator")); } }); var buttons = find(paginatorContentDiv, SELECTOR_PAGINATOR_BUTTON); buttons.removeClass("active"); buttons.click(function () { $('#preloader').show(); var offset = $(this).attr(ID_ATTR).replace(PAGINATOR_BUTTON_PREFIX, ""); callBack(offset); }); find(paginatorContentDiv, "#" + PAGINATOR_BUTTON_PREFIX + offset) .addClass(PAGINATOR_SELECTED_BUTTON_CLASS); }; this.drawPaginator = function (offset, count) { var currentOffset = parseInt(offset ? offset : "0"); var buttonCount = Math.floor( count <= PAGINATOR_ITEMS_PER_PAGE ? 0 : count / PAGINATOR_ITEMS_PER_PAGE) + (count < PAGINATOR_ITEMS_PER_PAGE || count % PAGINATOR_ITEMS_PER_PAGE === 0 ? 0 : 1); var data = []; Array.apply(0, Array(buttonCount)).forEach(function (element, index) { if (index > 0 && index < buttonCount - 1 && buttonCount > PAGINATOR_VISIBLE_BUTTONS_COUNT * 2) { if (index === currentOffset - PAGINATOR_VISIBLE_BUTTONS_COUNT || index === currentOffset + PAGINATOR_VISIBLE_BUTTONS_COUNT + 1) { data.push({ "offset": null, "name": null }); } if (index <= currentOffset - PAGINATOR_VISIBLE_BUTTONS_COUNT || index > currentOffset + PAGINATOR_VISIBLE_BUTTONS_COUNT) { return true; } } data.push({ "offset": index, "name": index + 1 }); }); drawPaginator(data, currentOffset); }; initialize(); } function OdinTableFormatter() { var BOOLEAN_TRUE_CLASS = "fa-check"; var BOOLEAN_FALSE_CLASS = "fa-times"; var formatBooleanValue = function (value) { return tmpl("tableBoolean", (value ? BOOLEAN_TRUE_CLASS : BOOLEAN_FALSE_CLASS)); }; var formatDateValue = function (value, dateType) { var date = new Date(value); var formatterSettings = {}; switch (dateType) { case DateTypesEnum.DATETIME: formatterSettings = { year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric" }; break; case DateTypesEnum.TIME: formatterSettings = { hour: "numeric", minute: "numeric", second: "numeric" }; break; } var dateFormatter = new Intl.DateTimeFormat(uiLocale, formatterSettings); return dateFormatter.format(date); }; var formatNumericValue = function (value, positiveOnly, scale) { var numberFormatter = new Intl.NumberFormat(uiLocale, { useGrouping: false, minimumFractionDigits: scale }); var formattedValue = numberFormatter.format(value); if (positiveOnly && value < 0) { return tmpl("tableNumericNegative", formattedValue); } return formattedValue; }; var formatStringValue = function (value, maxLength, stringType) { switch (stringType) { case StringTypesEnum.HREF: return tmpl("anchor", value, L10nEnum.GO_TO); default: if (isEmpty(maxLength) || maxLength === 0) { return value; } return value.substring(0, Math.min(value.length, maxLength)); } }; this.formatValue = function (value, fieldParams) { if (isEmpty(value) || isEmpty(fieldParams)) { return ""; } if (fieldParams.hidden) { return value; } switch (fieldParams.fieldType) { case FieldTypesEnum.BOOLEAN: return formatBooleanValue(value); case FieldTypesEnum.DATE: return formatDateValue(value, fieldParams.type); case FieldTypesEnum.NUMERIC: return formatNumericValue(value, fieldParams.positiveOnly, fieldParams.scale); case FieldTypesEnum.STRING: return formatStringValue(value, fieldParams.maxLength, fieldParams.type); case FieldTypesEnum.COLLECTION: return L10nEnum.COLLECTION; case FieldTypesEnum.OBJECT: return value.view; default: return value; } }; } function OdinTableView(odinDiv, editCallback, globalSelectCallback) { var TABLEVIEW_SELECTED_LINE_CLASS = "odin-table-selected-line"; var TABLEVIEW_LINE_SELECTOR = "tr"; var TABLEVIEW_SELECTED_LINE_SELECTOR = TABLEVIEW_LINE_SELECTOR + "." + TABLEVIEW_SELECTED_LINE_CLASS; var TABLEVIEW_LINE_DATA_SELECTOR = TABLEVIEW_LINE_SELECTOR + "[" + DATA_ATTR + "=\"{0}\"]"; var TABLEVIEW_CHOOSABLE_CLASS = "table-hover odin-unselectable"; var TABLEVIEW_LINE_POINTED_CLASS = "odin-table-pointed-line"; var TABLEVIEW_HEAD_COLUMN_SELECTOR = "th:nth-child({0})"; var TABLEVIEW_BODY_COLUMN_SELECTOR = "td:nth-child({0})"; var tTable; var tHead; var tBody; var choosable; var formatter; var toolbar; var createLine = function (idValue) { var prevent = false; var timer = 0; var newLine = tmpl("tableLine"); if (!isEmpty(idValue) && choosable) { newLine.attr(DATA_ATTR, idValue); newLine.click(function () { var btn = $(this); timer = setTimeout(function () { if (!prevent) { btn.toggleClass(TABLEVIEW_SELECTED_LINE_CLASS); } prevent = false; if (!isEmpty(globalSelectCallback)) { globalSelectCallback(getLines()); } if (!isEmpty(toolbar)) { toolbar.setEditButtonState(!isEmpty(getLines())); toolbar.setDeleteButtonState(!isEmpty(getLines())); } }, CLICK_DELAY); }); if (!isEmpty(editCallback)) { newLine.dblclick(function () { clearTimeout(timer); prevent = true; editCallback(idValue); }); } newLine.addClass(TABLEVIEW_LINE_POINTED_CLASS); } return newLine; }; var addLineToHead = function (line) { tHead.append(line); }; var addLineToBody = function (line) { tBody.append(line); }; var clearBody = function () { tBody.empty(); }; var initialize = function () { if (isEmpty(odinDiv)) { throw "Odin: Odin div is not set"; } odinDiv.append(tmpl("table")); tTable = find(odinDiv, "table"); tHead = find(odinDiv, "thead"); tBody = find(odinDiv, "tbody"); formatter = new OdinTableFormatter(); }; var getLines = function (isAll) { var selector = isAll ? TABLEVIEW_LINE_SELECTOR : TABLEVIEW_SELECTED_LINE_SELECTOR; var selectedItems = []; try { find(tBody, selector).each(function () { selectedItems.push({ id: $(this).attr(DATA_ATTR), view: $(this).attr(DATA_VIEW_ATTR) }); }); } catch (e) { // Ignore } return selectedItems; }; var disableToolbar = function () { if (isEmpty(toolbar)) { return; } toolbar.setEditButtonState(false); toolbar.setDeleteButtonState(false); }; this.createHead = function (metaData, isOdinDto) { if (isEmpty(metaData)) { throw "Odin: Metadata is not set"; } choosable = isOdinDto; if (choosable) { tTable.addClass(TABLEVIEW_CHOOSABLE_CLASS); } var tHeadLine = createLine(); $.each(metaData, function (index, value) { tHeadLine.append(tmpl("tableHeadColumn", value.caption)); }); addLineToHead(tHeadLine); $.each(metaData, function (columnIndex, columnParams) { if (columnParams.visible === VisibleTypesEnum.NONE) { var index = columnIndex + 1; find(tHead, format(TABLEVIEW_HEAD_COLUMN_SELECTOR, [index])).hide(); } }); }; this.fillBody = function (metaData, data) { clearBody(); $.each(data, function (index, value) { var idValue = choosable ? value.id : null; var line = createLine(idValue); line.attr(DATA_VIEW_ATTR, value.view); $.each(metaData, function (columnIndex, columnParams) { var column = tmpl("tableBodyColumn"); column.append( formatter.formatValue(value[columnParams.fieldName], columnParams)); line.append(column); }); addLineToBody(line); }); if (!isEmpty(data)) { $.each(metaData, function (columnIndex, columnParams) { if (columnParams.visible === VisibleTypesEnum.NONE) { var index = columnIndex + 1; find(tBody, format(TABLEVIEW_BODY_COLUMN_SELECTOR, [index])).hide(); } }); } }; this.getSelectedItems = function () { return getLines(false); }; this.getItems = function () { return getLines(true); }; // Delete form view only! this.deleteById = function (id) { if (isEmpty(id)) { return; } try { find(tBody, format(TABLEVIEW_LINE_DATA_SELECTOR, [id])).remove(); disableToolbar(); } catch (e) { // Ignore } }; this.setToolbar = function (toolbarVar) { toolbar = toolbarVar; }; this.disableToolbar = function () { disableToolbar(); }; initialize(); } function OdinTableMain(divId, listMetaDataUrl, elementMetaDataUrl, dataUrl, args, disableCopy, globalSaveCallback, globalSelectCallback) { if (isEmpty(divId) || isEmpty(listMetaDataUrl) || isEmpty(dataUrl)) { throw "Odin: Not enough parameters"; } var OFFSET_ARG = "&offset="; var COUNT_ARG = "&count="; var odinDiv; var tableView; var paginator; var currentOffset; var listMetaData; var elementMetaData; var params = isEmpty(args) ? "" : args; var drawBody = function (offset) { if (isEmpty(listMetaData)) { throw "Odin: Meta data is not defined"; } currentOffset = isEmpty(offset) ? 0 : parseInt(offset); getFromRestWithParams(dataUrl, OFFSET_ARG + (currentOffset * PAGINATOR_ITEMS_PER_PAGE) + COUNT_ARG + PAGINATOR_ITEMS_PER_PAGE + params, function (data) { if (isEmpty(data)) { throw "Odin: Response data is null"; } tableView.fillBody(listMetaData, data.items); if (data.count > 0) { paginator.drawPaginator(offset, data.count); } tableView.disableToolbar(); $('#preloader').hide(); }); }; var initialize = function () { odinDiv = find($(document.body), "#" + divId); tableView = new OdinTableView(odinDiv, editItem, globalSelectCallback); paginator = new OdinPaginator(odinDiv, drawBody); getFromRest(listMetaDataUrl, function (data) { if (isEmpty(data) || isEmpty(data.fields)) { throw "Odin: Can't load list meta data"; } var isOdinDto = data.odinDto; listMetaData = data.fields; if (isOdinDto && !isEmpty(elementMetaDataUrl)) { getFromRest(elementMetaDataUrl, function (data) { if (isEmpty(data) || isEmpty(data.fields)) { throw "Odin: Can't load element meta data"; } elementMetaData = data.fields; var toolbar = new OdinToolbar(odinDiv, createItem, editItem, deleteItem, globalSaveCallback); tableView.setToolbar(toolbar); if (!disableCopy) { toolbar.addButton(L10nEnum.BUTTON_COPY, function () { new OdinCopyBox(dataUrl, drawBody); }); } }); } tableView.createHead(listMetaData, isOdinDto); drawBody(); }); }; var updateTable = function () { // TODO: recalculate offset before redraw table drawBody(currentOffset); }; var createItem = function () { new OdinForm(elementMetaData, dataUrl, updateTable, null, params); }; var editItem = function (value) { if (isEmpty(elementMetaDataUrl)) { return; } var curValue = value; if (isEmpty(value)) { var selectedItems = tableView.getSelectedItems(); if (!isEmpty(selectedItems)) { curValue = selectedItems[0].id; } } if (isEmpty(curValue)) { return; } new OdinForm(elementMetaData, dataUrl, updateTable, curValue, params); }; var deleteItem = function () { var selectedItems = tableView.getSelectedItems(); if (isEmpty(selectedItems)) { return; } var callBack = function () { $.each(selectedItems, function (index, value) { deleteFromRest(dataUrl + "/" + value.id, null, function () { if (index === selectedItems.length - 1) { updateTable(); } }); }); }; new OdinConfirmBox(callBack, L10nEnum.QUESTION_DELETE_ITEM); }; this.getSelectedItems = function () { return tableView.getSelectedItems(); }; initialize(); } function OdinFormControlGenerator() { this.createInputGroup = function () { return tmpl("formInputGroup"); }; this.createLabel = function (id, caption) { return tmpl("formLabel", id, caption); }; var createInput = function (id, value, type) { if (isEmpty(id)) { throw "Odin: Input id is not set"; } if (isEmpty(type)) { throw "Odin: Input type is not set"; } var curValue = isEmpty(value) ? "" : value; var wrapper = tmpl("formInputWrapper"); if (type === InputTypesEnum.CHECKBOX) { wrapper.append(tmpl("formInputCheckbox", id, (curValue ? CHECKED_ATTR : NOT_CHECKED_ATTR))); } else { wrapper.append(tmpl("formInput", id, curValue, type)); } return wrapper; }; this.createBooleanInput = function (id, value) { return createInput(id, value, InputTypesEnum.CHECKBOX); }; var fixDateUnit = function (dateUnitValue) { return dateUnitValue < 10 ? "0" + dateUnitValue : dateUnitValue; }; var dateToStr = function (value, type) { if (isEmpty(value)) { return ""; } var date = new Date(value); var year = fixDateUnit(date.getFullYear()); var month = fixDateUnit(date.getMonth() + 1); var day = fixDateUnit(date.getDate()); var hour = fixDateUnit(date.getHours()); var minute = fixDateUnit(date.getMinutes()); var formattedDate; switch (type) { case DateTypesEnum.DATETIME: formattedDate = year + "-" + month + "-" + day + "T" + hour + ":" + minute; break; case DateTypesEnum.TIME: formattedDate = hour + ":" + minute; break; default: formattedDate = year + "-" + month + "-" + day; } return formattedDate; }; this.createDateInput = function (id, value, type) { var dateType; switch (type) { case DateTypesEnum.DATETIME: dateType = InputTypesEnum.DATETIME; break; case DateTypesEnum.TIME: dateType = InputTypesEnum.TIME; break; default: dateType = InputTypesEnum.DATE; } return createInput(id, dateToStr(value, type), dateType); }; this.createNumericInput = function (id, value) { return createInput(id, value, InputTypesEnum.NUMBER); }; this.createStringInput = function (id, value, type) { var stringType; switch (type) { case StringTypesEnum.PASSWORD: stringType = InputTypesEnum.PASSWORD; break; case StringTypesEnum.EMAIL: stringType = InputTypesEnum.EMAIL; break; default: stringType = InputTypesEnum.TEXT; } return createInput(id, value, stringType); }; this.dateToStr = function (value, type) { return dateToStr(value, type); }; } function OdinFormContentGenerator(createNavTabCallBack, isCreateOperation) { var PRECISION_CHAR = "9"; var SCALE_PREFIX = "0."; var SCALE_CHAR = "0"; var SCALE_POSTFIX = "1"; var OBJECT_INPUT_CLASS = "input-group odin-input-group"; var CREATE_BUTTON_TEXT_SELECTOR = ".btn-success > span"; var CHOOSE_BTN_SELECTOR = ".odin-choose-btn"; var CLEAR_BTN_SELECTOR = ".odin-clear-btn"; var CLEARABLE_INPUT_SELECTOR = ".form-control"; var controlGenerator = new OdinFormControlGenerator(); var createBooleanControl = function (id, caption, value) { var group = controlGenerator.createInputGroup(); group.append(controlGenerator.createLabel(id, caption)); group.append(controlGenerator.createBooleanInput(id, value)); return group; }; var createDateControl = function (id, caption, value, type) { var group = controlGenerator.createInputGroup(); group.append(controlGenerator.createLabel(id, caption)); group.append(controlGenerator.createDateInput(id, value, type)); return group; }; var createNumericControl = function (id, caption, value, positiveOnly, precision, scale) { var group = controlGenerator.createInputGroup(); group.append(controlGenerator.createLabel(id, caption)); var control = controlGenerator.createNumericInput(id, value); find(control, INPUTS_SELECTOR).each(function () { var currentControl = $(this); if (positiveOnly) { currentControl.attr(NumberAttrEnum.MIN, 0); } if (precision) { currentControl .attr(NumberAttrEnum.MAX, Array(precision + 1).join(PRECISION_CHAR)); } if (scale) { var step = SCALE_PREFIX + Array(scale).join(SCALE_CHAR) + SCALE_POSTFIX; currentControl.attr(NumberAttrEnum.STEP, step); } }); group.append(control); return group; }; var createStringControl = function (id, caption, value, minLength, maxLength, type) { var group = controlGenerator.createInputGroup(); group.append(controlGenerator.createLabel(id, caption)); var control = controlGenerator.createStringInput(id, value, type); find(control, INPUTS_SELECTOR).each(function () { var currentControl = $(this); currentControl.attr(StringAttrEnum.MIN, minLength); currentControl.attr(StringAttrEnum.MAX, maxLength); }); group.append(control); return group; }; var createCollectionControl = function (id, caption, values, path) { // TODO: add required check if needed var content = $(tmpl("emptyDiv")); var tabView = new OdinTableView(content, null, null); var createAction = function () { new OdinChooseBox(path, function (selectedItems) { if (isEmpty(selectedItems)) { return; } var currentValues = tabView.getItems(); $.merge(currentValues, selectedItems); var existingIDs = []; currentValues = $.grep(currentValues, function (v) { if ($.inArray(v.id, existingIDs) !== -1) { return false; } else { existingIDs.push(v.id); return true; } }); tabView.fillBody(metaData, currentValues); }); }; var deleteAction = function () { var callBack = function () { $.each(tabView.getSelectedItems(), function (index, value) { tabView.deleteById(value.id); }); }; new OdinConfirmBox(callBack, L10nEnum.QUESTION_DELETE_ITEM); }; content.append(tabView); var metaData = [ { "fieldType": "string", "fieldName": "id", "caption": "id", "visible": "none" }, { "fieldType": "string", "fieldName": "view", "caption": L10nEnum.VIEW, "visible": "all" } ]; tabView.createHead(metaData, true); tabView.fillBody(metaData, values); createNavTabCallBack(id, caption, content); var toolbar = new OdinToolbar(content, createAction, null, deleteAction); tabView.setToolbar(toolbar); find(content, CREATE_BUTTON_TEXT_SELECTOR).text(L10nEnum.BUTTON_ADD); return null; }; var createObjectControl = function (id, caption, value, path) { // TODO: add required check if needed var chooseInput = controlGenerator.createStringInput( id, isEmpty(value) ? "" : value.view, StringTypesEnum.TEXT); chooseInput.addClass(OBJECT_INPUT_CLASS); var buttonGroup = tmpl("buttonGroup"); chooseInput.append(buttonGroup); var chooseButton = tmpl("chooseButton"); buttonGroup.append(chooseButton); find(buttonGroup, CHOOSE_BTN_SELECTOR).click(function () { new OdinChooseBox(path, function (selectedItems) { if (isEmpty(selectedItems)) { return; } find(chooseInput, CLEARABLE_INPUT_SELECTOR).each(function () { $(this) .val(selectedItems[0].view) .attr(DATA_ATTR, selectedItems[0].id); }); }); }); var clearButton = tmpl("clearButton"); buttonGroup.append(clearButton); find(buttonGroup, CLEAR_BTN_SELECTOR).click(function () { find(chooseInput, CLEARABLE_INPUT_SELECTOR).val(""); }); find(chooseInput, CLEARABLE_INPUT_SELECTOR).each(function () { $(this) .attr(DISABLED_ATTR, true) .attr(DATA_ATTR, isEmpty(value) ? "" : value.id); }); var group = controlGenerator.createInputGroup(); group.append(controlGenerator.createLabel(id, caption)); group.append(chooseInput); return group; }; var configureControl = function (control, hidden, readonly, notempty) { if (isEmpty(control)) { return; } find(control, LABELS_SELECTOR).each(function () { var currentControl = $(this); if (hidden) { currentControl.hide(); } }); find(control, INPUTS_SELECTOR).each(function () { var currentControl = $(this); if (hidden) { currentControl.hide(); currentControl.attr(TYPE_ATTR, InputTypesEnum.HIDDEN); } if (readonly) { currentControl.attr(DISABLED_ATTR, true); } if (notempty) { currentControl.attr(REQUIRED_ATTR, true); } }); return control; }; this.createFormControl = function (value, fieldParams) { if (isEmpty(fieldParams)) { return null; } var control; switch (fieldParams.fieldType) { case FieldTypesEnum.BOOLEAN: control = createBooleanControl(fieldParams.fieldName, fieldParams.caption, value); break; case FieldTypesEnum.DATE: control = createDateControl(fieldParams.fieldName, fieldParams.caption, value, fieldParams.type); break; case FieldTypesEnum.NUMERIC: control = createNumericControl(fieldParams.fieldName, fieldParams.caption, value, fieldParams.positiveOnly, fieldParams.precision, fieldParams.scale); break; case FieldTypesEnum.STRING: control = createStringControl(fieldParams.fieldName, fieldParams.caption, value, fieldParams.minLength, fieldParams.maxLength, fieldParams.type); break; case FieldTypesEnum.COLLECTION: control = createCollectionControl(fieldParams.fieldName, fieldParams.caption, value, fieldParams.path); break; case FieldTypesEnum.OBJECT: control = createObjectControl(fieldParams.fieldName, fieldParams.caption, value, fieldParams.path); break; default: return null; } var hidden; switch (fieldParams.visible) { case VisibleTypesEnum.NONE: hidden = true; break; case VisibleTypesEnum.ON_CREATE: case VisibleTypesEnum.ON_UPDATE: hidden = isCreateOperation; break; default: hidden = false; } return configureControl(control, hidden, fieldParams.readOnly, fieldParams.notEmpty); }; this.getCurrentDateStr = function () { return controlGenerator.dateToStr(new Date(), DateTypesEnum.DATE); }; } function OdinForm(metaData, dataUrl, tableCallBack, id, args) { if (isEmpty(metaData) || isEmpty(dataUrl) || isEmpty(tableCallBack)) { throw "Odin: Not enough parameters"; } var DEFAULT_TAB_SELECTOR = "odin-values"; var TABS_HEADER_SELECTOR = ".nav-tabs"; var TABS_CONTENT_SELECTOR = ".tab-content"; var TAB_SELECTOR = ".tab-pane"; var COLLECTION_ITEM_SELECTOR = "tbody > tr"; OdinFormCommon.call(this, FormTypesEnum.FORM); var self = this; var generator; var params = isEmpty(args) ? "" : args; var isCreateForm = function () { return isEmpty(id); }; var formToJson = function () { var formData = {}; try { findFiltered(self._getContent(), TAB_SELECTOR, "#" + DEFAULT_TAB_SELECTOR) .each(function () { var tabData = []; try { find($(this), COLLECTION_ITEM_SELECTOR) .each(function () { if ($(this).attr(DATA_ATTR)) { tabData.push({ id: $(this).attr(DATA_ATTR), view: $(this).attr(DATA_VIEW_ATTR) }); return true; } }); } catch (e) { // Ignore } formData[$(this).attr(ID_ATTR)] = tabData; }); } catch (e) { // Ignore } findFiltered(self._getContent(), INPUTS_SELECTOR, BUTTONS_SELECTOR) .each(function () { if (isEmpty($(this).val())) { return true; } if ($(this).attr(DATA_ATTR)) { formData[$(this).attr(ID_ATTR)] = { id: $(this).attr(DATA_ATTR), view: $(this).val() }; return true; } switch ($(this).attr(TYPE_ATTR)) { case InputTypesEnum.CHECKBOX: formData[$(this).attr(ID_ATTR)] = $(this).is(":" + CHECKED_ATTR); break; case InputTypesEnum.DATE: case InputTypesEnum.DATETIME: formData[$(this).attr(ID_ATTR)] = isEmpty($(this).val) ? "" : Date.parse($(this).val()); break; case InputTypesEnum.TIME: formData[$(this).attr(ID_ATTR)] = isEmpty($(this).val) ? "" : Date.parse(generator.getCurrentDateStr() + "T" + $(this).val()); break; case InputTypesEnum.NUMBER: formData[$(this).attr(ID_ATTR)] = parseFloat($(this).val()); break; default: formData[$(this).attr(ID_ATTR)] = $(this).val(); } }); return JSON.stringify(formData); }; var initialize = function () { generator = new OdinFormContentGenerator(createNavTab, isCreateForm()); self._getContent() .append(tmpl("formTabs", DEFAULT_TAB_SELECTOR, L10nEnum.CAPTION_DEFAULT_TAB)); var okBtn = tmpl("okButton", L10nEnum.BUTTON_SAVE); okBtn.attr(TYPE_ATTR, InputTypesEnum.SUBMIT); var closeBtn = tmpl("cancelButton", L10nEnum.BUTTON_CLOSE); self._getFooter().append(closeBtn); self._getFooter().append(okBtn); if (isCreateForm()) { configureAndShowForm(); } else { getFromRest(dataUrl + "/" + id, function (data) { if (isEmpty(data)) { throw format("Odin: Can't load data by id {0} and url {1}", [id, dataUrl]); } configureAndShowForm(data); }); } closeBtn.click(function () { closeForm(); }); }; var configureAndShowForm = function (data) { var saveCallBack = function () { saveData(formToJson()); }; self._setCaption(isEmpty(data) ? L10nEnum.CAPTION_CREATE_FORM : data.view + " " + L10nEnum.CAPTION_EDIT_FORM); self._setFormSubmit(saveCallBack); $.each(metaData, function (fieldIndex, fieldParams) { var value = isEmpty(data) ? null : data[fieldParams.fieldName]; find(self._getContent(), "#" + DEFAULT_TAB_SELECTOR) .append(generator.createFormControl(value, fieldParams)); }); self._show(); }; var createNavTab = function (id, caption, content) { find(self._getContent(), TABS_HEADER_SELECTOR).append(tmpl("formTab", id, caption)); var tab = tmpl("formTabContent", id); tab.append(content); find(self._getContent(), TABS_CONTENT_SELECTOR).append(tab); }; var saveData = function (data) { var saveCallback = function (responseData) { if (isEmpty(responseData)) { throw "Odin: Error on data save"; } self._hide(); tableCallBack(); if (!isEmpty(globalSaveCallback)) { globalSaveCallback(); } }; if (isCreateForm()) { postToRestWithParams(dataUrl, data, params, saveCallback); } else { putToRestWithParams(dataUrl, data, params, saveCallback); } }; var closeForm = function () { if (self._isModified()) { new OdinConfirmBox(self._hide, L10nEnum.QUESTION_LOST_CHANGES); return; } self._hide(); }; initialize(); } function OdinConfirmBox(callBack, questionText) { if (isEmpty(callBack) || isEmpty(questionText)) { throw "Odin: Not enough parameters"; } OdinFormCommon.call(this, FormTypesEnum.CONFIRM); var self = this; var initialize = function () { var yesBtn = tmpl("okButton", L10nEnum.BUTTON_OK); var cancelBtn = tmpl("cancelButton", L10nEnum.BUTTON_CANCEL); self._setCaption(L10nEnum.QUESTION_DEFAULT_CAPTION); self._getContent().text(questionText); self._getFooter().append(yesBtn); self._getFooter().append(cancelBtn); self._show(); yesBtn.click(function () { self._hide(); callBack(); if (!isEmpty(globalSaveCallback)) { globalSaveCallback(); } }); cancelBtn.click(function () { self._hide(); }); }; initialize(); } function OdinChooseBox(path, callBack) { if (isEmpty(path) || isEmpty(callBack)) { throw "Odin: Not enough parameters"; } var ADDITIONAL_FORM_CLASS = "odin-table-box"; var ADDITIONAL_CONTENT_CLASS = "odin-kill-padding"; var CONTENT_ID_VALUE = "table-block"; OdinFormCommon.call(this); var self = this; var initialize = function () { self._addFormClass(ADDITIONAL_FORM_CLASS); self._getContent().addClass(ADDITIONAL_CONTENT_CLASS); self._getContent().attr(ID_ATTR, CONTENT_ID_VALUE); var yesBtn = tmpl("okButton", L10nEnum.BUTTON_OK); var cancelBtn = tmpl("cancelButton", L10nEnum.BUTTON_CANCEL); self._getFooter().append(cancelBtn); self._getFooter().append(yesBtn); var table = new OdinTableMain("table-block", path + odinMetaList, null, path); self._show(); yesBtn.click(function () { self._hide(); callBack(table.getSelectedItems()); }); cancelBtn.click(function () { self._hide(); }); }; initialize(); } function OdinCopyBox(dataUrl, tableRedrawCallback) { if (isEmpty(dataUrl) || isEmpty(tableRedrawCallback)) { throw "Odin: Not enough parameters"; } var ADDITIONAL_FORM_CLASS = "odin-simple-form"; var FROM_VERSION_SELECTOR = "#fromVersion"; var VERSION_SELECTOR = "#version"; OdinFormCommon.call(this); var self = this; var initialize = function () { self._setCaption(L10nEnum.CAPTION_COPY_FORM); self._addFormClass(ADDITIONAL_FORM_CLASS); self._getContent().append(tmpl("copyForm")); var from = find(self._getContent(), FROM_VERSION_SELECTOR); var to = find(self._getContent(), VERSION_SELECTOR); var yesBtn = tmpl("okButton", L10nEnum.BUTTON_OK); var cancelBtn = tmpl("cancelButton", L10nEnum.BUTTON_CANCEL); self._getFooter().append(cancelBtn); self._getFooter().append(yesBtn); /*getFromRest(urlVersions, function (versions) { if (isEmpty(versions) || versions.count === 0) { return; } var versionsData = []; versions.items.forEach(function (version) { versionsData.push({ id: version.id, name: version.name + " от " + new Date(version.date).toLocaleDateString(uiLocale) }); }); fillSelect(from, versionsData.sort(function (a, b) { return a.id - b.id; })); var currentVersion = getCurrentVersionData(); if (!isEmpty(currentVersion)) { to.attr(DATA_ATTR, currentVersion.id); to.val(currentVersion.name); } self._show(); });*/ yesBtn.click(function () { if (isEmpty(from.val()) || isEmpty(to.val())) { return; } if (from.val() === to.attr(DATA_ATTR)) { showFeedbackMessage(L10nEnum.ERROR_VERSIONS_MATCH, MessageTypesEnum.DANGER); return; } postToRestWithVersionAndParams(dataUrl + odinCopy, null, "&fromVersionId=" + from.val(), function () { self._hide(); tableRedrawCallback(); }); }); cancelBtn.click(function () { self._hide(); }); }; initialize(); } }