devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,449 lines (1,321 loc) • 59.6 kB
JavaScript
"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" &&