UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,449 lines (1,321 loc) • 59.6 kB
"use strict"; var $ = require("../../core/renderer"), eventsEngine = require("../../events/core/events_engine"), registerComponent = require("../../core/component_registrator"), Guid = require("../../core/guid"), utils = require("../../core/utils/common"), typeUtils = require("../../core/utils/type"), each = require("../../core/utils/iterator").each, inArray = require("../../core/utils/array").inArray, extend = require("../../core/utils/extend").extend, stringUtils = require("../../core/utils/string"), errors = require("../widget/ui.errors"), browser = require("../../core/utils/browser"), domUtils = require("../../core/utils/dom"), messageLocalization = require("../../localization/message"), Widget = require("../widget/ui.widget"), windowUtils = require("../../core/utils/window"), ValidationEngine = require("../validation_engine"), LayoutManager = require("./ui.form.layout_manager"), TabPanel = require("../tab_panel"), Scrollable = require("../scroll_view/ui.scrollable"), Deferred = require("../../core/utils/deferred").Deferred, themes = require("../themes"); require("../validation_summary"); require("../validation_group"); var FORM_CLASS = "dx-form", FIELD_ITEM_CLASS = "dx-field-item", FIELD_ITEM_LABEL_TEXT_CLASS = "dx-field-item-label-text", FORM_GROUP_CLASS = "dx-form-group", FORM_GROUP_CONTENT_CLASS = "dx-form-group-content", FORM_GROUP_WITH_CAPTION_CLASS = "dx-form-group-with-caption", FORM_GROUP_CAPTION_CLASS = "dx-form-group-caption", HIDDEN_LABEL_CLASS = "dx-layout-manager-hidden-label", FIELD_ITEM_LABEL_CLASS = "dx-field-item-label", FIELD_ITEM_LABEL_CONTENT_CLASS = "dx-field-item-label-content", FIELD_ITEM_TAB_CLASS = "dx-field-item-tab", FORM_FIELD_ITEM_COL_CLASS = "dx-col-", GROUP_COL_COUNT_CLASS = "dx-group-colcount-", FIELD_ITEM_CONTENT_CLASS = "dx-field-item-content", FORM_VALIDATION_SUMMARY = "dx-form-validation-summary", WIDGET_CLASS = "dx-widget", FOCUSED_STATE_CLASS = "dx-state-focused"; var Form = Widget.inherit({ _init: function _init() { this.callBase(); this._cachedColCountOptions = []; this._groupsColCount = []; }, _initOptions: function _initOptions(options) { if (!("screenByWidth" in options)) { options.screenByWidth = windowUtils.defaultScreenFactorFunc; } this.callBase(options); }, _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { formID: "dx-" + new Guid(), /** * @name dxFormOptions.formData * @publicName formData * @type object * @default {} * @fires dxFormOptions.onFieldDataChanged */ formData: {}, /** * @name dxFormOptions.colCount * @publicName colCount * @type number|Enums.Mode * @default 1 */ colCount: 1, /** * @name dxFormOptions.screenByWidth * @publicName screenByWidth * @type function * @default null */ screenByWidth: null, /** * @pseudo ColCountResponsibleType * @type object */ /** * @name ColCountResponsible * @publicName ColCountResponsible * @hidden */ /** * @name ColCountResponsible.xs * @publicName xs * @type number * @default undefined */ /** * @name ColCountResponsible.sm * @publicName sm * @type number * @default undefined */ /** * @name ColCountResponsible.md * @publicName md * @type number * @default undefined */ /** * @name ColCountResponsible.lg * @publicName lg * @type number * @default undefined */ /** * @name dxFormOptions.colCountByScreen * @publicName colCountByScreen * @extends ColCountResponsibleType * @inherits ColCountResponsible * @default undefined */ colCountByScreen: undefined, /** * @name dxFormOptions.labelLocation * @publicName labelLocation * @type Enums.FormLabelLocation * @default "left" */ labelLocation: "left", /** * @name dxFormOptions.readOnly * @publicName readOnly * @type boolean * @default false */ readOnly: false, /** * @name dxFormOptions.onFieldDataChanged * @publicName onFieldDataChanged * @extends Action * @type function(e) * @type_function_param1 e:object * @type_function_param1_field4 dataField:string * @type_function_param1_field5 value:object * @action */ onFieldDataChanged: null, /** * @name dxFormOptions.customizeItem * @publicName customizeItem * @type function * @type_function_param1 item:dxFormSimpleItem|dxFormGroupItem|dxFormTabbedItem|dxFormEmptyItem|dxFormButtonItem */ customizeItem: null, /** * @name dxFormOptions.onEditorEnterKey * @publicName onEditorEnterKey * @extends Action * @type function(e) * @type_function_param1 e:object * @type_function_param1_field4 dataField:string * @action */ onEditorEnterKey: null, /** * @name dxFormOptions.minColWidth * @publicName minColWidth * @type number * @default 200 */ minColWidth: 200, /** * @name dxFormOptions.alignItemLabels * @publicName alignItemLabels * @type boolean * @default true */ alignItemLabels: true, /** * @name dxFormOptions.alignItemLabelsInAllGroups * @publicName alignItemLabelsInAllGroups * @type boolean * @default true */ alignItemLabelsInAllGroups: true, /** * @name dxFormOptions.showColonAfterLabel * @publicName showColonAfterLabel * @type boolean * @default true */ showColonAfterLabel: true, /** * @name dxFormOptions.showRequiredMark * @publicName showRequiredMark * @type boolean * @default true */ showRequiredMark: true, /** * @name dxFormOptions.showOptionalMark * @publicName showOptionalMark * @type boolean * @default false */ showOptionalMark: false, /** * @name dxFormOptions.requiredMark * @publicName requiredMark * @type string * @default "*" */ requiredMark: "*", /** * @name dxFormOptions.optionalMark * @publicName optionalMark * @type string * @default "optional" */ optionalMark: messageLocalization.format("dxForm-optionalMark"), /** * @name dxFormOptions.requiredMessage * @publicName requiredMessage * @type string * @default "{0} is required" */ requiredMessage: messageLocalization.getFormatter("dxForm-requiredMessage"), /** * @name dxFormOptions.showValidationSummary * @publicName showValidationSummary * @type boolean * @default false */ showValidationSummary: false, /** * @name dxFormOptions.items * @publicName items * @type Array<dxFormSimpleItem,dxFormGroupItem,dxFormTabbedItem,dxFormEmptyItem,dxFormButtonItem> * @default undefined */ items: undefined, /** * @name dxFormOptions.scrollingEnabled * @publicName scrollingEnabled * @type boolean * @default false */ scrollingEnabled: false, /** * @name dxFormOptions.validationGroup * @publicName validationGroup * @type string * @default undefined */ validationGroup: undefined /** * @name dxFormSimpleItem * @publicName SimpleItem * @section FormItems * @type object */ /** * @name dxFormSimpleItem.dataField * @publicName dataField * @type string * @default undefined */ /** * @name dxFormSimpleItem.name * @publicName name * @type string * @default undefined */ /** * @name dxFormSimpleItem.editorType * @publicName editorType * @type Enums.FormItemEditorType */ /** * @name dxFormSimpleItem.editorOptions * @publicName editorOptions * @type object * @default undefined */ /** * @name dxFormSimpleItem.colSpan * @publicName colSpan * @type number * @default undefined */ /** * @name dxFormSimpleItem.itemType * @publicName itemType * @type Enums.FormItemType * @default "simple" */ /** * @name dxFormSimpleItem.visible * @publicName visible * @type boolean * @default true */ /** * @name dxFormSimpleItem.cssClass * @publicName cssClass * @type string * @default undefined */ /** * @name dxFormSimpleItem.visibleIndex * @publicName visibleIndex * @type number * @default undefined */ /** * @name dxFormSimpleItem.template * @publicName template * @type template|function * @type_function_param1 data:object * @type_function_param1_field1 component:dxForm * @type_function_param1_field2 dataField:string * @type_function_param1_field3 editorOptions:object * @type_function_param1_field4 editorType:string * @type_function_param2 itemElement:dxElement * @type_function_return string|Node|jQuery */ /** * @name dxFormSimpleItem.label * @publicName label * @type object * @default undefined */ /** * @name dxFormSimpleItem.label.text * @publicName text * @type string * @default undefined */ /** * @name dxFormSimpleItem.label.visible * @publicName visible * @type boolean * @default true */ /** * @name dxFormSimpleItem.label.showColon * @publicName showColon * @type boolean * @default from showColonAfterLabel */ /** * @name dxFormSimpleItem.label.location * @publicName location * @type Enums.FormLabelLocation * @default "left" */ /** * @name dxFormSimpleItem.label.alignment * @publicName alignment * @type Enums.HorizontalAlignment * @default "left" */ /** * @name dxFormSimpleItem.helpText * @publicName helpText * @type string * @default undefined */ /** * @name dxFormSimpleItem.isRequired * @publicName isRequired * @type boolean * @default undefined */ /** * @name dxFormSimpleItem.validationRules * @publicName validationRules * @type Array<RequiredRule,NumericRule,RangeRule,StringLengthRule,CustomRule,CompareRule,PatternRule,EmailRule> * @default undefined */ /** * @name dxFormGroupItem * @publicName GroupItem * @section FormItems * @type object */ /** * @name dxFormGroupItem.caption * @publicName caption * @type string * @default undefined */ /** * @name dxFormGroupItem.name * @publicName name * @type string * @default undefined */ /** * @name dxFormGroupItem.colCount * @publicName colCount * @type number * @default 1 */ /** * @name dxFormGroupItem.colCountByScreen * @publicName colCountByScreen * @extends ColCountResponsibleType * @inherits ColCountResponsible * @default undefined */ /** * @name dxFormGroupItem.itemType * @publicName itemType * @type Enums.FormItemType * @default "simple" */ /** * @name dxFormGroupItem.colSpan * @publicName colSpan * @type number * @default undefined */ /** * @name dxFormGroupItem.visible * @publicName visible * @type boolean * @default true */ /** * @name dxFormGroupItem.cssClass * @publicName cssClass * @type string * @default undefined */ /** * @name dxFormGroupItem.visibleIndex * @publicName visibleIndex * @type number * @default undefined */ /** * @name dxFormGroupItem.alignItemLabels * @publicName alignItemLabels * @type boolean * @default true */ /** * @name dxFormGroupItem.template * @publicName template * @type template|function * @type_function_param1 data:object * @type_function_param1_field1 component:dxForm * @type_function_param1_field2 formData:object * @type_function_param2 itemElement:dxElement * @type_function_return string|Node|jQuery */ /** * @name dxFormGroupItem.items * @publicName items * @type Array<dxFormSimpleItem,dxFormGroupItem,dxFormTabbedItem,dxFormEmptyItem,dxFormButtonItem> * @default undefined */ /** * @name dxFormTabbedItem * @publicName TabbedItem * @section FormItems * @type object */ /** * @name dxFormTabbedItem.name * @publicName name * @type string * @default undefined */ /** * @name dxFormTabbedItem.visible * @publicName visible * @type boolean * @default true */ /** * @name dxFormTabbedItem.itemType * @publicName itemType * @type Enums.FormItemType * @default "simple" */ /** * @name dxFormTabbedItem.cssClass * @publicName cssClass * @type string * @default undefined */ /** * @name dxFormTabbedItem.visibleIndex * @publicName visibleIndex * @type number * @default undefined */ /** * @name dxFormTabbedItem.tabPanelOptions * @publicName tabPanelOptions * @type dxTabPanelOptions * @default undefined */ /** * @name dxFormTabbedItem.colSpan * @publicName colSpan * @type number * @default undefined */ /** * @name dxFormTabbedItem.tabs * @publicName tabs * @type Array<Object> * @default undefined */ /** * @name dxFormTabbedItem.tabs.alignItemLabels * @publicName alignItemLabels * @type boolean * @default true */ /** * @name dxFormTabbedItem.tabs.title * @publicName title * @type string * @default undefined */ /** * @name dxFormTabbedItem.tabs.colCount * @publicName colCount * @type number * @default 1 */ /** * @name dxFormTabbedItem.tabs.colCountByScreen * @publicName colCountByScreen * @extends ColCountResponsibleType * @inherits ColCountResponsible * @default undefined */ /** * @name dxFormTabbedItem.tabs.items * @publicName items * @type Array<dxFormSimpleItem,dxFormGroupItem,dxFormTabbedItem,dxFormEmptyItem,dxFormButtonItem> * @default undefined */ /** * @name dxFormTabbedItem.tabs.badge * @publicName badge * @type string * @default undefined */ /** * @name dxFormTabbedItem.tabs.disabled * @publicName disabled * @type boolean * @default false */ /** * @name dxFormTabbedItem.tabs.icon * @publicName icon * @type string * @default undefined */ /** * @name dxFormTabbedItem.tabs.tabTemplate * @publicName tabTemplate * @type template|function * @type_function_param1 tabData:object * @type_function_param2 tabIndex:number * @type_function_param3 tabElement:dxElement * @default undefined */ /** * @name dxFormTabbedItem.tabs.template * @publicName template * @type template|function * @type_function_param1 tabData:object * @type_function_param2 tabIndex:number * @type_function_param3 tabElement:dxElement * @default undefined */ /** * @name dxFormEmptyItem * @publicName EmptyItem * @section FormItems * @type object */ /** * @name dxFormEmptyItem.name * @publicName name * @type string * @default undefined */ /** * @name dxFormEmptyItem.colSpan * @publicName colSpan * @type number * @default undefined */ /** * @name dxFormEmptyItem.itemType * @publicName itemType * @type Enums.FormItemType * @default "simple" */ /** * @name dxFormEmptyItem.visible * @publicName visible * @type boolean * @default true */ /** * @name dxFormEmptyItem.cssClass * @publicName cssClass * @type string * @default undefined */ /** * @name dxFormEmptyItem.visibleIndex * @publicName visibleIndex * @type number * @default undefined */ /** * @name dxFormButtonItem * @publicName ButtonItem * @section FormItems * @type object */ /** * @name dxFormButtonItem.name * @publicName name * @type string * @default undefined */ /** * @name dxFormButtonItem.colSpan * @publicName colSpan * @type number * @default undefined */ /** * @name dxFormButtonItem.itemType * @publicName itemType * @type Enums.FormItemType * @default "simple" */ /** * @name dxFormButtonItem.visible * @publicName visible * @type boolean * @default true */ /** * @name dxFormButtonItem.cssClass * @publicName cssClass * @type string * @default undefined */ /** * @name dxFormButtonItem.visibleIndex * @publicName visibleIndex * @type number * @default undefined */ /** * @name dxFormButtonItem.buttonOptions * @publicName buttonOptions * @type dxButtonOptions * @default undefined */ /** * @name dxFormButtonItem.alignment * @publicName alignment * @type Enums.HorizontalAlignment * @default "right" */ }); }, _defaultOptionsRules: function _defaultOptionsRules() { return this.callBase().concat([{ device: function device() { return themes.isMaterial(); }, options: { /** * @name dxFormOptions.showColonAfterLabel * @publicName showColonAfterLabel * @type boolean * @default false @for Material */ showColonAfterLabel: false, /** * @name dxFormOptions.labelLocation * @publicName labelLocation * @type Enums.FormLabelLocation * @default "top" @for Material */ labelLocation: "top" } }]); }, _setOptionsByReference: function _setOptionsByReference() { this.callBase(); extend(this._optionsByReference, { formData: true, validationGroup: true }); }, _getColCount: function _getColCount($element) { var index = 0, isColsExist = true, $cols; while (isColsExist) { $cols = $element.find("." + FORM_FIELD_ITEM_COL_CLASS + index); if (!$cols.length) { isColsExist = false; } else { index++; } } return index; }, _createHiddenElement: function _createHiddenElement(rootLayoutManager) { this._$hiddenElement = $("<div>").addClass(WIDGET_CLASS).addClass(HIDDEN_LABEL_CLASS).appendTo("body"); var $hiddenLabel = rootLayoutManager._renderLabel({ text: " ", location: this.option("labelLocation") }).appendTo(this._$hiddenElement); this._hiddenLabelText = $hiddenLabel.find("." + FIELD_ITEM_LABEL_TEXT_CLASS)[0]; }, _removeHiddenElement: function _removeHiddenElement() { this._$hiddenElement.remove(); this._hiddenLabelText = null; }, _getLabelWidthByText: function _getLabelWidthByText(text) { // this code has slow performance this._hiddenLabelText.innerHTML = text; return this._hiddenLabelText.offsetWidth; }, _getLabelsSelectorByCol: function _getLabelsSelectorByCol(index, options) { options = options || {}; var fieldItemClass = options.inOneColumn ? FIELD_ITEM_CLASS : FORM_FIELD_ITEM_COL_CLASS + index, cssExcludeTabbedSelector = options.excludeTabbed ? ":not(." + FIELD_ITEM_TAB_CLASS + ")" : "", childLabelContentSelector = "> ." + FIELD_ITEM_LABEL_CLASS + " > ." + FIELD_ITEM_LABEL_CONTENT_CLASS; return "." + fieldItemClass + cssExcludeTabbedSelector + childLabelContentSelector; }, _getLabelText: function _getLabelText(labelText) { var length = labelText.children.length, child, result = "", i; for (i = 0; i < length; i++) { child = labelText.children[i]; result = result + (!stringUtils.isEmpty(child.innerText) ? child.innerText : child.innerHTML); } return result; }, _applyLabelsWidthByCol: function _applyLabelsWidthByCol($container, index, options) { var $labelTexts = $container.find(this._getLabelsSelectorByCol(index, options)), $labelTextsLength = $labelTexts.length, labelWidth, i, maxWidth = 0; for (i = 0; i < $labelTextsLength; i++) { labelWidth = this._getLabelWidthByText(this._getLabelText($labelTexts[i])); if (labelWidth > maxWidth) { maxWidth = labelWidth; } } for (i = 0; i < $labelTextsLength; i++) { $labelTexts[i].style.width = maxWidth + "px"; } }, _applyLabelsWidth: function _applyLabelsWidth($container, excludeTabbed, inOneColumn, colCount) { colCount = inOneColumn ? 1 : colCount || this._getColCount($container); var applyLabelsOptions = { excludeTabbed: excludeTabbed, inOneColumn: inOneColumn }, i; for (i = 0; i < colCount; i++) { this._applyLabelsWidthByCol($container, i, applyLabelsOptions); } }, _getGroupElementsInColumn: function _getGroupElementsInColumn($container, columnIndex, colCount) { var cssColCountSelector = typeUtils.isDefined(colCount) ? "." + GROUP_COL_COUNT_CLASS + colCount : "", groupSelector = "." + FORM_FIELD_ITEM_COL_CLASS + columnIndex + " > ." + FIELD_ITEM_CONTENT_CLASS + " > ." + FORM_GROUP_CLASS + cssColCountSelector; return $container.find(groupSelector); }, _applyLabelsWidthWithGroups: function _applyLabelsWidthWithGroups($container, colCount, excludeTabbed) { var alignItemLabelsInAllGroups = this.option("alignItemLabelsInAllGroups"); if (alignItemLabelsInAllGroups) { this._applyLabelsWidthWithNestedGroups($container, colCount, excludeTabbed); } else { var $groups = this.$element().find("." + FORM_GROUP_CLASS), i; for (i = 0; i < $groups.length; i++) { this._applyLabelsWidth($groups.eq(i), excludeTabbed); } } }, _applyLabelsWidthWithNestedGroups: function _applyLabelsWidthWithNestedGroups($container, colCount, excludeTabbed) { var applyLabelsOptions = { excludeTabbed: excludeTabbed }, colIndex, groupsColIndex, groupColIndex, $groupsByCol; for (colIndex = 0; colIndex < colCount; colIndex++) { $groupsByCol = this._getGroupElementsInColumn($container, colIndex); this._applyLabelsWidthByCol($groupsByCol, 0, applyLabelsOptions); for (groupsColIndex = 0; groupsColIndex < this._groupsColCount.length; groupsColIndex++) { $groupsByCol = this._getGroupElementsInColumn($container, colIndex, this._groupsColCount[groupsColIndex]); var groupColCount = this._getColCount($groupsByCol); for (groupColIndex = 1; groupColIndex < groupColCount; groupColIndex++) { this._applyLabelsWidthByCol($groupsByCol, groupColIndex, applyLabelsOptions); } } } }, _alignLabelsInColumn: function _alignLabelsInColumn(options) { if (!windowUtils.hasWindow()) { return; } this._createHiddenElement(options.layoutManager); if (options.inOneColumn) { this._applyLabelsWidth(options.$container, options.excludeTabbed, true); } else { if (this._checkGrouping(options.items)) { this._applyLabelsWidthWithGroups(options.$container, options.layoutManager._getColCount(), options.excludeTabbed); } else { this._applyLabelsWidth(options.$container, options.excludeTabbed, false, options.layoutManager._getColCount()); } } this._removeHiddenElement(); }, _prepareFormData: function _prepareFormData() { if (!typeUtils.isDefined(this.option("formData"))) { this.option("formData", {}); } }, _initMarkup: function _initMarkup() { this._clearCachedInstances(); this._prepareFormData(); this.$element().addClass(FORM_CLASS); this.callBase(); this.setAria("role", "form", this.$element()); if (this.option("scrollingEnabled")) { this._renderScrollable(); } this._renderLayout(); this._renderValidationSummary(); this._attachSyncSubscriptions(); this._cachedScreenFactor = this._getCurrentScreenFactor(); }, _getCurrentScreenFactor: function _getCurrentScreenFactor() { return windowUtils.hasWindow() ? windowUtils.getCurrentScreenFactor(this.option("screenByWidth")) : "lg"; }, _clearCachedInstances: function _clearCachedInstances() { this._editorInstancesByField = {}; this._cachedLayoutManagers = []; }, _alignLabels: function _alignLabels(layoutManager, inOneColumn) { this._alignLabelsInColumn({ $container: this.$element(), layoutManager: layoutManager, excludeTabbed: true, items: this.option("items"), inOneColumn: inOneColumn }); }, _clean: function _clean() { this.callBase(); this._groupsColCount = []; this._cachedColCountOptions = []; delete this._cachedScreenFactor; }, _renderScrollable: function _renderScrollable() { var useNativeScrolling = this.option("useNativeScrolling"); this._scrollable = new Scrollable(this.$element(), { useNative: !!useNativeScrolling, useSimulatedScrollbar: !useNativeScrolling, useKeyboard: false, direction: "both", bounceEnabled: false }); }, _getContent: function _getContent() { return this.option("scrollingEnabled") ? this._scrollable.$content() : this.$element(); }, _renderValidationSummary: function _renderValidationSummary() { var $validationSummary = this.$element().find("." + FORM_VALIDATION_SUMMARY); if ($validationSummary.length > 0) { $validationSummary.remove(); } if (this.option("showValidationSummary")) { $("<div>").addClass(FORM_VALIDATION_SUMMARY).dxValidationSummary({ validationGroup: this._getValidationGroup() }).appendTo(this._getContent()); } }, _prepareItems: function _prepareItems(items, isTabbed) { if (items) { var that = this, extendedItems = [], i, item, clonedItem; for (i = 0; i < items.length; i++) { item = items[i]; clonedItem = typeUtils.isObject(item) ? extend({}, item) : item; that._prepareGroupItem(clonedItem); that._prepareTabbedItem(clonedItem); that._prepareItemTemplate(clonedItem); if (typeUtils.isObject(clonedItem)) { if (isTabbed) { clonedItem.cssItemClass = FIELD_ITEM_TAB_CLASS; } clonedItem.items = this._prepareItems(clonedItem.items, isTabbed); } extendedItems.push(clonedItem); } return extendedItems; } }, _prepareGroupItem: function _prepareGroupItem(item) { if (item.itemType === "group") { item.alignItemLabels = utils.ensureDefined(item.alignItemLabels, true); if (item.template) { item.groupContentTemplate = this._getTemplate(item.template); } item.template = this._itemGroupTemplate.bind(this, item); } }, _prepareTabbedItem: function _prepareTabbedItem(item) { if (item.itemType === "tabbed") { item.template = this._itemTabbedTemplate.bind(this, item); item.tabs = this._prepareItems(item.tabs, true); } }, _prepareItemTemplate: function _prepareItemTemplate(item) { if (item.template) { item.template = this._getTemplate(item.template); } }, _checkGrouping: function _checkGrouping(items) { if (items) { for (var i = 0; i < items.length; i++) { var item = items[i]; if (item.itemType === "group") { return true; } } } }, _renderLayout: function _renderLayout() { var that = this, items = that.option("items"), $content = that._getContent(); items = that._prepareItems(items); //#DEBUG that._testResultItems = items; //#ENDDEBUG that._rootLayoutManager = that._renderLayoutManager(items, $content, { colCount: that.option("colCount"), alignItemLabels: that.option("alignItemLabels"), screenByWidth: this.option("screenByWidth"), colCountByScreen: this.option("colCountByScreen"), onLayoutChanged: function onLayoutChanged(inOneColumn) { that._alignLabels.bind(that)(that._rootLayoutManager, inOneColumn); }, onContentReady: function onContentReady(e) { that._alignLabels(e.component, e.component.isSingleColumnMode()); } }); }, _itemTabbedTemplate: function _itemTabbedTemplate(item, e, $container) { var that = this, $tabPanel = $("<div>").appendTo($container), tabPanelOptions = extend({}, item.tabPanelOptions, { dataSource: item.tabs, onItemRendered: function onItemRendered(args) { domUtils.triggerShownEvent(args.itemElement); }, itemTemplate: function itemTemplate(itemData, e, container) { var layoutManager, $container = $(container), alignItemLabels = utils.ensureDefined(itemData.alignItemLabels, true); layoutManager = that._renderLayoutManager(itemData.items, $container, { colCount: itemData.colCount, alignItemLabels: alignItemLabels, screenByWidth: this.option("screenByWidth"), colCountByScreen: itemData.colCountByScreen, cssItemClass: itemData.cssItemClass, onLayoutChanged: function onLayoutChanged(inOneColumn) { that._alignLabelsInColumn.bind(that)({ $container: $container, layoutManager: layoutManager, items: itemData.items, inOneColumn: inOneColumn }); } }); if (alignItemLabels) { that._alignLabelsInColumn.bind(that)({ $container: $container, layoutManager: layoutManager, items: itemData.items, inOneColumn: layoutManager.isSingleColumnMode() }); } } }); that._createComponent($tabPanel, TabPanel, tabPanelOptions); }, _itemGroupTemplate: function _itemGroupTemplate(item, e, $container) { var $group = $("<div>").toggleClass(FORM_GROUP_WITH_CAPTION_CLASS, typeUtils.isDefined(item.caption) && item.caption.length).addClass(FORM_GROUP_CLASS).appendTo($container), $groupContent, colCount, layoutManager; if (item.caption) { $("<span>").addClass(FORM_GROUP_CAPTION_CLASS).text(item.caption).appendTo($group); } $groupContent = $("<div>").addClass(FORM_GROUP_CONTENT_CLASS).appendTo($group); if (item.groupContentTemplate) { var data = { formData: this.option("formData"), component: this }; item.groupContentTemplate.render({ model: data, container: domUtils.getPublicElement($groupContent) }); } else { layoutManager = this._renderLayoutManager(item.items, $groupContent, { colCount: item.colCount, colCountByScreen: item.colCountByScreen, alignItemLabels: item.alignItemLabels, cssItemClass: item.cssItemClass }); colCount = layoutManager._getColCount(); if (inArray(colCount, this._groupsColCount) === -1) { this._groupsColCount.push(colCount); } $group.addClass(GROUP_COL_COUNT_CLASS + colCount); } }, _renderLayoutManager: function _renderLayoutManager(items, $rootElement, options) { var $element = $("<div>"), that = this, instance, config = that._getLayoutManagerConfig(items, options), baseColCountByScreen = { lg: options.colCount, md: options.colCount, sm: options.colCount, xs: 1 }; that._cachedColCountOptions.push({ colCountByScreen: extend(baseColCountByScreen, options.colCountByScreen) }); $element.appendTo($rootElement); instance = that._createComponent($element, "dxLayoutManager", config); instance.on("autoColCountChanged", function () { that._refresh(); }); that._cachedLayoutManagers.push(instance); return instance; }, _getValidationGroup: function _getValidationGroup() { return this.option("validationGroup") || this; }, _getLayoutManagerConfig: function _getLayoutManagerConfig(items, options) { var that = this, baseConfig = { form: that, validationGroup: that._getValidationGroup(), showRequiredMark: that.option("showRequiredMark"), showOptionalMark: that.option("showOptionalMark"), requiredMark: that.option("requiredMark"), optionalMark: that.option("optionalMark"), requiredMessage: that.option("requiredMessage"), screenByWidth: that.option("screenByWidth"), layoutData: that.option("formData"), labelLocation: that.option("labelLocation"), customizeItem: that.option("customizeItem"), minColWidth: that.option("minColWidth"), showColonAfterLabel: that.option("showColonAfterLabel"), onEditorEnterKey: that.option("onEditorEnterKey"), onFieldDataChanged: function onFieldDataChanged(args) { if (!that._isDataUpdating) { that._triggerOnFieldDataChanged(args); } }, validationBoundary: that.option("scrollingEnabled") ? that.$element() : undefined }; return extend(baseConfig, { items: items, onContentReady: function onContentReady(args) { that._updateEditorInstancesFromLayoutManager(args.component._editorInstancesByField); options.onContentReady && options.onContentReady(args); }, colCount: options.colCount, alignItemLabels: options.alignItemLabels, cssItemClass: options.cssItemClass, colCountByScreen: options.colCountByScreen, onLayoutChanged: options.onLayoutChanged, width: options.width }); }, _updateEditorInstancesFromLayoutManager: function _updateEditorInstancesFromLayoutManager(instancesByDataFields) { extend(this._editorInstancesByField, instancesByDataFields); }, _createComponent: function _createComponent($element, type, config) { var that = this; config = config || {}; that._extendConfig(config, { readOnly: that.option("readOnly") }); return that.callBase($element, type, config); }, _attachSyncSubscriptions: function _attachSyncSubscriptions() { var that = this; that.off("optionChanged").on("optionChanged", function (args) { var optionFullName = args.fullName; if (optionFullName === "formData") { if (!typeUtils.isDefined(args.value)) { that._options.formData = args.value = {}; } that._triggerOnFieldDataChangedByDataSet(args.value); } if (that._cachedLayoutManagers.length) { each(that._cachedLayoutManagers, function (index, layoutManager) { if (optionFullName === "formData") { that._isDataUpdating = true; layoutManager.option("layoutData", args.value); that._isDataUpdating = false; } if (args.name === "readOnly" || args.name === "disabled") { layoutManager.option(optionFullName, args.value); } }); } }); }, _optionChanged: function _optionChanged(args) { var rootNameOfComplexOption = this._getRootLevelOfExpectedComplexOption(args.fullName, ["formData", "items"]); if (rootNameOfComplexOption) { this._customHandlerOfComplexOption(args, rootNameOfComplexOption); return; } switch (args.name) { case "formData": if (!this.option("items")) { this._invalidate(); } else if (typeUtils.isEmptyObject(args.value)) { this._resetValues(); } break; case "items": case "colCount": case "onFieldDataChanged": case "onEditorEnterKey": case "labelLocation": case "alignItemLabels": case "showColonAfterLabel": case "customizeItem": case "alignItemLabelsInAllGroups": case "showRequiredMark": case "showOptionalMark": case "requiredMark": case "optionalMark": case "requiredMessage": case "scrollingEnabled": case "formID": case "colCountByScreen": case "screenByWidth": this._invalidate(); break; case "showValidationSummary": this._renderValidationSummary(); break; case "minColWidth": if (this.option("colCount") === "auto") { this._invalidate(); } break; case "readOnly": break; case "width": this.callBase(args); this._rootLayoutManager.option(args.name, args.value); this._alignLabels(this._rootLayoutManager, this._rootLayoutManager.isSingleColumnMode()); break; case "visible": this.callBase(args); if (args.value) { domUtils.triggerShownEvent(this.$element()); } break; default: this.callBase(args); } }, _getRootLevelOfExpectedComplexOption: function _getRootLevelOfExpectedComplexOption(fullOptionName, expectedRootNames) { var splitFullName = fullOptionName.split("."), result; if (splitFullName.length > 1) { var i, rootOptionName = splitFullName[0]; for (i = 0; i < expectedRootNames.length; i++) { if (rootOptionName.search(expectedRootNames[i]) !== -1) { result = expectedRootNames[i]; } } } return result; }, _customHandlerOfComplexOption: function _customHandlerOfComplexOption(args, rootOptionName) { var nameParts = args.fullName.split("."); switch (rootOptionName) { case "items": var itemPath = this._getItemPath(nameParts), instance, item = this.option(itemPath); if (args.fullName.search("editorOptions") !== -1) { instance = this.getEditor(item.dataField) || this.getEditor(item.name); instance && instance.option(item.editorOptions); } if (!instance && item) { var name = args.fullName.replace(itemPath + ".", ""), items; this._changeItemOption(item, name, args.value); items = this._generateItemsFromData(this.option("items")); this.option("items", items); } break; case "formData": var dataField = nameParts.slice(1).join("."), editor = this.getEditor(dataField); if (editor) { editor.option("value", args.value); } else { this._triggerOnFieldDataChanged({ dataField: dataField, value: args.value }); } break; } }, _getItemPath: function _getItemPath(nameParts) { var itemPath = nameParts[0], i; for (i = 1; i < nameParts.length; i++) { if (nameParts[i].search("items|tabs") !== -1) { itemPath += "." + nameParts[i]; } else { break; } } return itemPath; }, _triggerOnFieldDataChanged: function _triggerOnFieldDataChanged(args) { this._createActionByOption("onFieldDataChanged")(args); }, _triggerOnFieldDataChangedByDataSet: function _triggerOnFieldDataChangedByDataSet(data) { var that = this; if (data && typeUtils.isObject(data)) { each(data, function (dataField, value) { that._triggerOnFieldDataChanged({ dataField: dataField, value: value }); }); } }, _updateFieldValue: function _updateFieldValue(dataField, value) { if (typeUtils.isDefined(this.option("formData"))) { var editor = this.getEditor(dataField); this.option("formData." + dataField, value); if (editor) { var editorValue = editor.option("value"); if (editorValue !== value) { editor.option("value", value); } } } }, _generateItemsFromData: function _generateItemsFromData(items) { var formData = this.option("formData"), result = []; if (!items && typeUtils.isDefined(formData)) { each(formData, function (dataField) { result.push({ dataField: dataField }); }); } if (items) { each(items, function (index, item) { if (typeUtils.isObject(item)) { result.push(item); } else { result.push({ dataField: item }); } }); } return result; }, _getItemByField: function _getItemByField(field, items) { var that = this, fieldParts = typeUtils.isObject(field) ? field : that._getFieldParts(field), fieldName = fieldParts.fieldName, fieldPath = fieldParts.fieldPath, resultItem; if (items.length) { each(items, function (index, item) { var itemType = item.itemType; if (fieldPath.length) { var path = fieldPath.slice(); item = that._getItemByFieldPath(path, fieldName, item); } else if (itemType === "group" &&