ui.form.layout_manager.js 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. /**
  2. * DevExtreme (ui/form/ui.form.layout_manager.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _renderer = require("../../core/renderer");
  11. var _renderer2 = _interopRequireDefault(_renderer);
  12. var _events_engine = require("../../events/core/events_engine");
  13. var _events_engine2 = _interopRequireDefault(_events_engine);
  14. var _guid = require("../../core/guid");
  15. var _guid2 = _interopRequireDefault(_guid);
  16. var _uiForm = require("./ui.form.items_runtime_info");
  17. var _uiForm2 = _interopRequireDefault(_uiForm);
  18. var _component_registrator = require("../../core/component_registrator");
  19. var _component_registrator2 = _interopRequireDefault(_component_registrator);
  20. var _type = require("../../core/utils/type");
  21. var _dom = require("../../core/utils/dom");
  22. var _dom2 = _interopRequireDefault(_dom);
  23. var _variable_wrapper = require("../../core/utils/variable_wrapper");
  24. var _window = require("../../core/utils/window");
  25. var _window2 = _interopRequireDefault(_window);
  26. var _string = require("../../core/utils/string");
  27. var _string2 = _interopRequireDefault(_string);
  28. var _iterator = require("../../core/utils/iterator");
  29. var _extend = require("../../core/utils/extend");
  30. var _array = require("../../core/utils/array");
  31. var _data = require("../../core/utils/data");
  32. var _data2 = _interopRequireDefault(_data);
  33. var _remove_event = require("../../core/remove_event");
  34. var _remove_event2 = _interopRequireDefault(_remove_event);
  35. var _click = require("../../events/click");
  36. var _click2 = _interopRequireDefault(_click);
  37. var _ui = require("../widget/ui.errors");
  38. var _ui2 = _interopRequireDefault(_ui);
  39. var _message = require("../../localization/message");
  40. var _message2 = _interopRequireDefault(_message);
  41. var _style = require("../../core/utils/style");
  42. var _style2 = _interopRequireDefault(_style);
  43. var _inflector = require("../../core/utils/inflector");
  44. var _inflector2 = _interopRequireDefault(_inflector);
  45. var _ui3 = require("../widget/ui.widget");
  46. var _ui4 = _interopRequireDefault(_ui3);
  47. var _validator = require("../validator");
  48. var _validator2 = _interopRequireDefault(_validator);
  49. var _responsive_box = require("../responsive_box");
  50. var _responsive_box2 = _interopRequireDefault(_responsive_box);
  51. var _themes = require("../themes");
  52. var _themes2 = _interopRequireDefault(_themes);
  53. require("../text_box");
  54. require("../number_box");
  55. require("../check_box");
  56. require("../date_box");
  57. require("../button");
  58. function _interopRequireDefault(obj) {
  59. return obj && obj.__esModule ? obj : {
  60. "default": obj
  61. }
  62. }
  63. function _typeof(obj) {
  64. "@babel/helpers - typeof";
  65. return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
  66. return typeof obj
  67. } : function(obj) {
  68. return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
  69. }, _typeof(obj)
  70. }
  71. var FORM_EDITOR_BY_DEFAULT = "dxTextBox";
  72. var FIELD_ITEM_CLASS = "dx-field-item";
  73. var FIELD_EMPTY_ITEM_CLASS = "dx-field-empty-item";
  74. var FIELD_BUTTON_ITEM_CLASS = "dx-field-button-item";
  75. var FIELD_ITEM_REQUIRED_CLASS = "dx-field-item-required";
  76. var FIELD_ITEM_OPTIONAL_CLASS = "dx-field-item-optional";
  77. var FIELD_ITEM_REQUIRED_MARK_CLASS = "dx-field-item-required-mark";
  78. var FIELD_ITEM_OPTIONAL_MARK_CLASS = "dx-field-item-optional-mark";
  79. var FIELD_ITEM_LABEL_CLASS = "dx-field-item-label";
  80. var FIELD_ITEM_LABEL_ALIGN_CLASS = "dx-field-item-label-align";
  81. var FIELD_ITEM_LABEL_CONTENT_CLASS = "dx-field-item-label-content";
  82. var FIELD_ITEM_LABEL_TEXT_CLASS = "dx-field-item-label-text";
  83. var FIELD_ITEM_LABEL_LOCATION_CLASS = "dx-field-item-label-location-";
  84. var FIELD_ITEM_CONTENT_CLASS = "dx-field-item-content";
  85. var FIELD_ITEM_CONTENT_LOCATION_CLASS = "dx-field-item-content-location-";
  86. var FIELD_ITEM_CONTENT_WRAPPER_CLASS = "dx-field-item-content-wrapper";
  87. var FIELD_ITEM_HELP_TEXT_CLASS = "dx-field-item-help-text";
  88. var SINGLE_COLUMN_ITEM_CONTENT = "dx-single-column-item-content";
  89. var LABEL_HORIZONTAL_ALIGNMENT_CLASS = "dx-label-h-align";
  90. var LABEL_VERTICAL_ALIGNMENT_CLASS = "dx-label-v-align";
  91. var FORM_LAYOUT_MANAGER_CLASS = "dx-layout-manager";
  92. var LAYOUT_MANAGER_FIRST_ROW_CLASS = "dx-first-row";
  93. var LAYOUT_MANAGER_FIRST_COL_CLASS = "dx-first-col";
  94. var LAYOUT_MANAGER_LAST_COL_CLASS = "dx-last-col";
  95. var LAYOUT_MANAGER_ONE_COLUMN = "dx-layout-manager-one-col";
  96. var FLEX_LAYOUT_CLASS = "dx-flex-layout";
  97. var INVALID_CLASS = "dx-invalid";
  98. var LAYOUT_STRATEGY_FLEX = "flex";
  99. var LAYOUT_STRATEGY_FALLBACK = "fallback";
  100. var SIMPLE_ITEM_TYPE = "simple";
  101. var TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper";
  102. var DATA_OPTIONS = ["dataSource", "items"];
  103. var EDITORS_WITH_ARRAY_VALUE = ["dxTagBox", "dxRangeSlider"];
  104. var LayoutManager = _ui4.default.inherit({
  105. _getDefaultOptions: function() {
  106. return (0, _extend.extend)(this.callBase(), {
  107. layoutData: {},
  108. readOnly: false,
  109. colCount: 1,
  110. colCountByScreen: void 0,
  111. labelLocation: "left",
  112. onFieldDataChanged: null,
  113. onEditorEnterKey: null,
  114. customizeItem: null,
  115. alignItemLabels: true,
  116. minColWidth: 200,
  117. showRequiredMark: true,
  118. screenByWidth: null,
  119. showOptionalMark: false,
  120. requiredMark: "*",
  121. optionalMark: _message2.default.format("dxForm-optionalMark"),
  122. requiredMessage: _message2.default.getFormatter("dxForm-requiredMessage")
  123. })
  124. },
  125. _setOptionsByReference: function() {
  126. this.callBase();
  127. (0, _extend.extend)(this._optionsByReference, {
  128. layoutData: true,
  129. validationGroup: true
  130. })
  131. },
  132. _init: function() {
  133. var layoutData = this.option("layoutData");
  134. this.callBase();
  135. this._itemWatchers = [];
  136. this._itemsRunTimeInfo = new _uiForm2.default;
  137. this._updateReferencedOptions(layoutData);
  138. this._initDataAndItems(layoutData)
  139. },
  140. _dispose: function() {
  141. this.callBase();
  142. this._cleanItemWatchers()
  143. },
  144. _initDataAndItems: function(initialData) {
  145. this._syncDataWithItems();
  146. this._updateItems(initialData)
  147. },
  148. _syncDataWithItems: function() {
  149. var that = this;
  150. var userItems = that.option("items");
  151. if ((0, _type.isDefined)(userItems)) {
  152. (0, _iterator.each)(userItems, function(index, item) {
  153. var value;
  154. if (item.dataField && void 0 === that._getDataByField(item.dataField)) {
  155. if (item.editorOptions) {
  156. value = item.editorOptions.value
  157. }
  158. that._updateFieldValue(item.dataField, value)
  159. }
  160. })
  161. }
  162. },
  163. _getDataByField: function(dataField) {
  164. return dataField ? this.option("layoutData." + dataField) : null
  165. },
  166. _updateFieldValue: function(dataField, value) {
  167. var layoutData = this.option("layoutData");
  168. var newValue = value;
  169. if (!(0, _variable_wrapper.isWrapped)(layoutData[dataField]) && (0, _type.isDefined)(dataField)) {
  170. this.option("layoutData." + dataField, newValue)
  171. } else {
  172. if ((0, _variable_wrapper.isWritableWrapped)(layoutData[dataField])) {
  173. newValue = (0, _type.isFunction)(newValue) ? newValue() : newValue;
  174. layoutData[dataField](newValue)
  175. }
  176. }
  177. this._triggerOnFieldDataChanged({
  178. dataField: dataField,
  179. value: newValue
  180. })
  181. },
  182. _triggerOnFieldDataChanged: function(args) {
  183. this._createActionByOption("onFieldDataChanged")(args)
  184. },
  185. _updateItems: function(layoutData) {
  186. var that = this;
  187. var userItems = this.option("items");
  188. var isUserItemsExist = (0, _type.isDefined)(userItems);
  189. var customizeItem = that.option("customizeItem");
  190. var items = isUserItemsExist ? userItems : this._generateItemsByData(layoutData);
  191. if ((0, _type.isDefined)(items)) {
  192. var processedItems = [];
  193. (0, _iterator.each)(items, function(index, item) {
  194. if (that._isAcceptableItem(item)) {
  195. item = that._processItem(item);
  196. customizeItem && customizeItem(item);
  197. if ((0, _type.isObject)(item) && false !== (0, _variable_wrapper.unwrap)(item.visible)) {
  198. processedItems.push(item)
  199. }
  200. }
  201. });
  202. if (!that._itemWatchers.length || !isUserItemsExist) {
  203. that._updateItemWatchers(items)
  204. }
  205. this._items = processedItems;
  206. this._sortItems()
  207. }
  208. },
  209. _cleanItemWatchers: function() {
  210. this._itemWatchers.forEach(function(dispose) {
  211. dispose()
  212. });
  213. this._itemWatchers = []
  214. },
  215. _updateItemWatchers: function(items) {
  216. var that = this;
  217. var watch = that._getWatch();
  218. items.forEach(function(item) {
  219. if ((0, _type.isObject)(item) && (0, _type.isDefined)(item.visible) && (0, _type.isFunction)(watch)) {
  220. that._itemWatchers.push(watch(function() {
  221. return (0, _variable_wrapper.unwrap)(item.visible)
  222. }, function() {
  223. that._updateItems(that.option("layoutData"));
  224. that.repaint()
  225. }, {
  226. skipImmediate: true
  227. }))
  228. }
  229. })
  230. },
  231. _generateItemsByData: function(layoutData) {
  232. var result = [];
  233. if ((0, _type.isDefined)(layoutData)) {
  234. (0, _iterator.each)(layoutData, function(dataField) {
  235. result.push({
  236. dataField: dataField
  237. })
  238. })
  239. }
  240. return result
  241. },
  242. _isAcceptableItem: function(item) {
  243. var itemField = item.dataField || item;
  244. var itemData = this._getDataByField(itemField);
  245. return !((0, _type.isFunction)(itemData) && !(0, _variable_wrapper.isWrapped)(itemData))
  246. },
  247. _processItem: function(item) {
  248. if ("string" === typeof item) {
  249. item = {
  250. dataField: item
  251. }
  252. }
  253. if ("object" === _typeof(item) && !item.itemType) {
  254. item.itemType = SIMPLE_ITEM_TYPE
  255. }
  256. if (!(0, _type.isDefined)(item.editorType) && (0, _type.isDefined)(item.dataField)) {
  257. var value = this._getDataByField(item.dataField);
  258. item.editorType = (0, _type.isDefined)(value) ? this._getEditorTypeByDataType((0, _type.type)(value)) : FORM_EDITOR_BY_DEFAULT
  259. }
  260. return item
  261. },
  262. _getEditorTypeByDataType: function(dataType) {
  263. switch (dataType) {
  264. case "number":
  265. return "dxNumberBox";
  266. case "date":
  267. return "dxDateBox";
  268. case "boolean":
  269. return "dxCheckBox";
  270. default:
  271. return "dxTextBox"
  272. }
  273. },
  274. _sortItems: function() {
  275. (0, _array.normalizeIndexes)(this._items, "visibleIndex");
  276. this._sortIndexes()
  277. },
  278. _sortIndexes: function() {
  279. this._items.sort(function(itemA, itemB) {
  280. var indexA = itemA.visibleIndex;
  281. var indexB = itemB.visibleIndex;
  282. var result;
  283. if (indexA > indexB) {
  284. result = 1
  285. } else {
  286. if (indexA < indexB) {
  287. result = -1
  288. } else {
  289. result = 0
  290. }
  291. }
  292. return result
  293. })
  294. },
  295. _initMarkup: function() {
  296. this._itemsRunTimeInfo.clear();
  297. this.$element().addClass(FORM_LAYOUT_MANAGER_CLASS);
  298. this.callBase();
  299. this._renderResponsiveBox()
  300. },
  301. _hasBrowserFlex: function() {
  302. return _style2.default.styleProp(LAYOUT_STRATEGY_FLEX) === LAYOUT_STRATEGY_FLEX
  303. },
  304. _renderResponsiveBox: function() {
  305. var that = this;
  306. var templatesInfo = [];
  307. if (that._items && that._items.length) {
  308. var colCount = that._getColCount();
  309. var $container = (0, _renderer2.default)("<div>").appendTo(that.$element());
  310. that._prepareItemsWithMerging(colCount);
  311. var layoutItems = that._generateLayoutItems();
  312. that._extendItemsWithDefaultTemplateOptions(layoutItems, that._items);
  313. that._responsiveBox = that._createComponent($container, _responsive_box2.default, that._getResponsiveBoxConfig(layoutItems, colCount, templatesInfo));
  314. if (!_window2.default.hasWindow()) {
  315. that._renderTemplates(templatesInfo)
  316. }
  317. }
  318. },
  319. _extendItemsWithDefaultTemplateOptions: function(targetItems, sourceItems) {
  320. sourceItems.forEach(function(item) {
  321. if (!item.merged) {
  322. if ((0, _type.isDefined)(item.disabled)) {
  323. targetItems[item.visibleIndex].disabled = item.disabled
  324. }
  325. if ((0, _type.isDefined)(item.visible)) {
  326. targetItems[item.visibleIndex].visible = item.visible
  327. }
  328. }
  329. })
  330. },
  331. _itemStateChangedHandler: function(e) {
  332. this._refresh()
  333. },
  334. _renderTemplate: function($container, item) {
  335. switch (item.itemType) {
  336. case "empty":
  337. this._renderEmptyItem($container);
  338. break;
  339. case "button":
  340. this._renderButtonItem(item, $container);
  341. break;
  342. default:
  343. this._renderFieldItem(item, $container)
  344. }
  345. },
  346. _renderTemplates: function(templatesInfo) {
  347. var that = this;
  348. (0, _iterator.each)(templatesInfo, function(index, info) {
  349. that._renderTemplate(info.container, info.formItem)
  350. })
  351. },
  352. _getResponsiveBoxConfig: function(layoutItems, colCount, templatesInfo) {
  353. var that = this;
  354. var colCountByScreen = that.option("colCountByScreen");
  355. var xsColCount = colCountByScreen && colCountByScreen.xs;
  356. return {
  357. onItemStateChanged: this._itemStateChangedHandler.bind(this),
  358. _layoutStrategy: that._hasBrowserFlex() ? LAYOUT_STRATEGY_FLEX : LAYOUT_STRATEGY_FALLBACK,
  359. onLayoutChanged: function onLayoutChanged() {
  360. var onLayoutChanged = that.option("onLayoutChanged");
  361. var isSingleColumnMode = that.isSingleColumnMode();
  362. if (onLayoutChanged) {
  363. that.$element().toggleClass(LAYOUT_MANAGER_ONE_COLUMN, isSingleColumnMode);
  364. onLayoutChanged(isSingleColumnMode)
  365. }
  366. },
  367. onContentReady: function(e) {
  368. if (_window2.default.hasWindow()) {
  369. that._renderTemplates(templatesInfo)
  370. }
  371. if (that.option("onLayoutChanged")) {
  372. that.$element().toggleClass(LAYOUT_MANAGER_ONE_COLUMN, that.isSingleColumnMode(e.component))
  373. }
  374. that._fireContentReadyAction()
  375. },
  376. itemTemplate: function(e, itemData, itemElement) {
  377. if (!e.location) {
  378. return
  379. }
  380. var $itemElement = (0, _renderer2.default)(itemElement);
  381. var itemRenderedCountInPreviousRows = e.location.row * colCount;
  382. var item = that._items[e.location.col + itemRenderedCountInPreviousRows];
  383. var $fieldItem = (0, _renderer2.default)("<div>").addClass(item.cssClass).appendTo($itemElement);
  384. templatesInfo.push({
  385. container: $fieldItem,
  386. formItem: item
  387. });
  388. $itemElement.toggleClass(SINGLE_COLUMN_ITEM_CONTENT, that.isSingleColumnMode(this));
  389. if (0 === e.location.row) {
  390. $fieldItem.addClass(LAYOUT_MANAGER_FIRST_ROW_CLASS)
  391. }
  392. if (0 === e.location.col) {
  393. $fieldItem.addClass(LAYOUT_MANAGER_FIRST_COL_CLASS)
  394. }
  395. if (e.location.col === colCount - 1 || e.location.col + e.location.colspan === colCount) {
  396. $fieldItem.addClass(LAYOUT_MANAGER_LAST_COL_CLASS)
  397. }
  398. },
  399. cols: that._generateRatio(colCount),
  400. rows: that._generateRatio(that._getRowsCount(), true),
  401. dataSource: layoutItems,
  402. screenByWidth: that.option("screenByWidth"),
  403. singleColumnScreen: xsColCount ? false : "xs"
  404. }
  405. },
  406. _getColCount: function() {
  407. var colCount = this.option("colCount");
  408. var colCountByScreen = this.option("colCountByScreen");
  409. if (colCountByScreen) {
  410. var screenFactor = this.option("form").getTargetScreenFactor();
  411. if (!screenFactor) {
  412. screenFactor = _window2.default.hasWindow() ? _window2.default.getCurrentScreenFactor(this.option("screenByWidth")) : "lg"
  413. }
  414. colCount = colCountByScreen[screenFactor] || colCount
  415. }
  416. if ("auto" === colCount) {
  417. if (this._cashedColCount) {
  418. return this._cashedColCount
  419. }
  420. this._cashedColCount = colCount = this._getMaxColCount()
  421. }
  422. return colCount < 1 ? 1 : colCount
  423. },
  424. _getMaxColCount: function() {
  425. if (!_window2.default.hasWindow()) {
  426. return 1
  427. }
  428. var minColWidth = this.option("minColWidth");
  429. var width = this.$element().width();
  430. var itemsCount = this._items.length;
  431. var maxColCount = Math.floor(width / minColWidth) || 1;
  432. return itemsCount < maxColCount ? itemsCount : maxColCount
  433. },
  434. isCachedColCountObsolete: function() {
  435. return this._cashedColCount && this._getMaxColCount() !== this._cashedColCount
  436. },
  437. _prepareItemsWithMerging: function(colCount) {
  438. var items = this._items.slice(0);
  439. var result = [];
  440. for (var i = 0; i < items.length; i++) {
  441. var item = items[i];
  442. result.push(item);
  443. if (this.option("alignItemLabels") || item.alignItemLabels || item.colSpan) {
  444. item.col = this._getColByIndex(result.length - 1, colCount)
  445. }
  446. if (item.colSpan > 1 && item.col + item.colSpan <= colCount) {
  447. var itemsMergedByCol = [];
  448. for (var j = 0; j < item.colSpan - 1; j++) {
  449. itemsMergedByCol.push({
  450. merged: true
  451. })
  452. }
  453. result = result.concat(itemsMergedByCol)
  454. } else {
  455. delete item.colSpan
  456. }
  457. }
  458. this._items = result
  459. },
  460. _getColByIndex: function(index, colCount) {
  461. return index % colCount
  462. },
  463. _generateLayoutItems: function() {
  464. var items = this._items;
  465. var colCount = this._getColCount();
  466. var result = [];
  467. for (var i = 0; i < items.length; i++) {
  468. var item = items[i];
  469. if (!item.merged) {
  470. var generatedItem = {
  471. location: {
  472. row: parseInt(i / colCount),
  473. col: this._getColByIndex(i, colCount)
  474. }
  475. };
  476. if ((0, _type.isDefined)(item.colSpan)) {
  477. generatedItem.location.colspan = item.colSpan
  478. }
  479. if ((0, _type.isDefined)(item.rowSpan)) {
  480. generatedItem.location.rowspan = item.rowSpan
  481. }
  482. result.push(generatedItem)
  483. }
  484. }
  485. return result
  486. },
  487. _renderEmptyItem: function($container) {
  488. return $container.addClass(FIELD_EMPTY_ITEM_CLASS).html("&nbsp;")
  489. },
  490. _getButtonHorizontalAlignment: function(item) {
  491. if ((0, _type.isDefined)(item.horizontalAlignment)) {
  492. return item.horizontalAlignment
  493. }
  494. if ((0, _type.isDefined)(item.alignment)) {
  495. _ui2.default.log("W0001", "dxForm", "alignment", "18.1", "Use the 'horizontalAlignment' option in button items instead.");
  496. return item.alignment
  497. }
  498. return "right"
  499. },
  500. _getButtonVerticalAlignment: function(item) {
  501. switch (item.verticalAlignment) {
  502. case "center":
  503. return "center";
  504. case "bottom":
  505. return "flex-end";
  506. default:
  507. return "flex-start"
  508. }
  509. },
  510. _renderButtonItem: function(item, $container) {
  511. var $button = (0, _renderer2.default)("<div>").appendTo($container);
  512. var defaultOptions = {
  513. validationGroup: this.option("validationGroup")
  514. };
  515. $container.addClass(FIELD_BUTTON_ITEM_CLASS).css("textAlign", this._getButtonHorizontalAlignment(item));
  516. $container.parent().css("justifyContent", this._getButtonVerticalAlignment(item));
  517. var instance = this._createComponent($button, "dxButton", (0, _extend.extend)(defaultOptions, item.buttonOptions));
  518. this._itemsRunTimeInfo.add({
  519. item: item,
  520. widgetInstance: instance,
  521. guid: item.guid,
  522. $itemContainer: $container
  523. });
  524. this._addItemClasses($container, item.col);
  525. return $button
  526. },
  527. _addItemClasses: function($item, column) {
  528. $item.addClass(FIELD_ITEM_CLASS).addClass(this.option("cssItemClass")).addClass((0, _type.isDefined)(column) ? "dx-col-" + column : "")
  529. },
  530. _renderFieldItem: function(item, $container) {
  531. var that = this;
  532. var name = that._getName(item);
  533. var id = that.getItemID(name);
  534. var isRequired = (0, _type.isDefined)(item.isRequired) ? item.isRequired : !!that._hasRequiredRuleInSet(item.validationRules);
  535. var labelOptions = that._getLabelOptions(item, id, isRequired);
  536. var $editor = (0, _renderer2.default)("<div>");
  537. var helpID = item.helpText ? "dx-" + new _guid2.default : null;
  538. var $label;
  539. this._addItemClasses($container, item.col);
  540. $container.addClass(isRequired ? FIELD_ITEM_REQUIRED_CLASS : FIELD_ITEM_OPTIONAL_CLASS);
  541. if (labelOptions.visible && labelOptions.text) {
  542. $label = that._renderLabel(labelOptions).appendTo($container)
  543. }
  544. if (item.itemType === SIMPLE_ITEM_TYPE) {
  545. if (that._isLabelNeedBaselineAlign(item) && "top" !== labelOptions.location) {
  546. $container.addClass(FIELD_ITEM_LABEL_ALIGN_CLASS)
  547. }
  548. that._hasBrowserFlex() && $container.addClass(FLEX_LAYOUT_CLASS)
  549. }
  550. $editor.data("dx-form-item", item);
  551. that._appendEditorToField({
  552. $fieldItem: $container,
  553. $label: $label,
  554. $editor: $editor,
  555. labelOptions: labelOptions
  556. });
  557. var instance = that._renderEditor({
  558. $container: $editor,
  559. dataField: item.dataField,
  560. name: item.name,
  561. editorType: item.editorType,
  562. editorOptions: item.editorOptions,
  563. template: that._getTemplateByFieldItem(item),
  564. isRequired: isRequired,
  565. helpID: helpID,
  566. labelID: labelOptions.labelID,
  567. id: id,
  568. validationBoundary: that.option("validationBoundary")
  569. });
  570. this._itemsRunTimeInfo.add({
  571. item: item,
  572. widgetInstance: instance,
  573. guid: item.guid,
  574. $itemContainer: $container
  575. });
  576. var editorElem = $editor.children().first();
  577. var $validationTarget = editorElem.hasClass(TEMPLATE_WRAPPER_CLASS) ? editorElem.children().first() : editorElem;
  578. if ($validationTarget && $validationTarget.data("dx-validation-target")) {
  579. that._renderValidator($validationTarget, item)
  580. }
  581. that._renderHelpText(item, $editor, helpID);
  582. that._attachClickHandler($label, $editor, item.editorType)
  583. },
  584. _hasRequiredRuleInSet: function(rules) {
  585. var hasRequiredRule;
  586. if (rules && rules.length) {
  587. (0, _iterator.each)(rules, function(index, rule) {
  588. if ("required" === rule.type) {
  589. hasRequiredRule = true;
  590. return false
  591. }
  592. })
  593. }
  594. return hasRequiredRule
  595. },
  596. _getName: function(item) {
  597. return item.dataField || item.name
  598. },
  599. _isLabelNeedBaselineAlign: function(item) {
  600. var largeEditors = ["dxTextArea", "dxRadioGroup", "dxCalendar", "dxHtmlEditor"];
  601. return !!item.helpText && !this._hasBrowserFlex() || (0, _array.inArray)(item.editorType, largeEditors) !== -1
  602. },
  603. _isLabelNeedId: function(item) {
  604. var editorsRequiringIdForLabel = ["dxRadioGroup", "dxCheckBox", "dxLookup", "dxSlider", "dxRangeSlider", "dxSwitch", "dxHtmlEditor"];
  605. return (0, _array.inArray)(item.editorType, editorsRequiringIdForLabel) !== -1
  606. },
  607. _getLabelOptions: function(item, id, isRequired) {
  608. var labelOptions = (0, _extend.extend)({
  609. showColon: this.option("showColonAfterLabel"),
  610. location: this.option("labelLocation"),
  611. id: id,
  612. visible: true,
  613. isRequired: isRequired
  614. }, item ? item.label : {});
  615. if (this._isLabelNeedId(item)) {
  616. labelOptions.labelID = "dx-label-".concat(new _guid2.default)
  617. }
  618. if (!labelOptions.text && item.dataField) {
  619. labelOptions.text = _inflector2.default.captionize(item.dataField)
  620. }
  621. if (labelOptions.text) {
  622. labelOptions.text += labelOptions.showColon ? ":" : ""
  623. }
  624. return labelOptions
  625. },
  626. _renderLabel: function(options) {
  627. var text = options.text,
  628. id = options.id,
  629. location = options.location,
  630. alignment = options.alignment,
  631. isRequired = options.isRequired,
  632. _options$labelID = options.labelID,
  633. labelID = void 0 === _options$labelID ? null : _options$labelID;
  634. if ((0, _type.isDefined)(text) && text.length > 0) {
  635. var labelClasses = FIELD_ITEM_LABEL_CLASS + " " + FIELD_ITEM_LABEL_LOCATION_CLASS + location;
  636. var $label = (0, _renderer2.default)("<label>").addClass(labelClasses).attr("for", id).attr("id", labelID);
  637. var $labelContent = (0, _renderer2.default)("<span>").addClass(FIELD_ITEM_LABEL_CONTENT_CLASS).appendTo($label);
  638. (0, _renderer2.default)("<span>").addClass(FIELD_ITEM_LABEL_TEXT_CLASS).text(text).appendTo($labelContent);
  639. if (alignment) {
  640. $label.css("textAlign", alignment)
  641. }
  642. $labelContent.append(this._renderLabelMark(isRequired));
  643. return $label
  644. }
  645. },
  646. _renderLabelMark: function(isRequired) {
  647. var $mark;
  648. var requiredMarksConfig = this._getRequiredMarksConfig();
  649. var isRequiredMark = requiredMarksConfig.showRequiredMark && isRequired;
  650. var isOptionalMark = requiredMarksConfig.showOptionalMark && !isRequired;
  651. if (isRequiredMark || isOptionalMark) {
  652. var markClass = isRequiredMark ? FIELD_ITEM_REQUIRED_MARK_CLASS : FIELD_ITEM_OPTIONAL_MARK_CLASS;
  653. var markText = isRequiredMark ? requiredMarksConfig.requiredMark : requiredMarksConfig.optionalMark;
  654. $mark = (0, _renderer2.default)("<span>").addClass(markClass).html("&nbsp" + markText)
  655. }
  656. return $mark
  657. },
  658. _getRequiredMarksConfig: function() {
  659. if (!this._cashedRequiredConfig) {
  660. this._cashedRequiredConfig = {
  661. showRequiredMark: this.option("showRequiredMark"),
  662. showOptionalMark: this.option("showOptionalMark"),
  663. requiredMark: this.option("requiredMark"),
  664. optionalMark: this.option("optionalMark")
  665. }
  666. }
  667. return this._cashedRequiredConfig
  668. },
  669. _renderEditor: function(options) {
  670. var dataValue = this._getDataByField(options.dataField);
  671. var defaultEditorOptions = void 0 !== dataValue ? {
  672. value: dataValue
  673. } : {};
  674. var isDeepExtend = true;
  675. if (EDITORS_WITH_ARRAY_VALUE.indexOf(options.editorType) !== -1) {
  676. defaultEditorOptions.value = defaultEditorOptions.value || []
  677. }
  678. var formInstance = this.option("form");
  679. var editorOptions = (0, _extend.extend)(isDeepExtend, defaultEditorOptions, options.editorOptions, {
  680. inputAttr: {
  681. id: options.id
  682. },
  683. validationBoundary: options.validationBoundary,
  684. stylingMode: formInstance && formInstance.option("stylingMode")
  685. });
  686. this._replaceDataOptions(options.editorOptions, editorOptions);
  687. var renderOptions = {
  688. editorType: options.editorType,
  689. dataField: options.dataField,
  690. template: options.template,
  691. name: options.name,
  692. helpID: options.helpID,
  693. labelID: options.labelID,
  694. isRequired: options.isRequired
  695. };
  696. return this._createEditor(options.$container, renderOptions, editorOptions)
  697. },
  698. _replaceDataOptions: function(originalOptions, resultOptions) {
  699. if (originalOptions) {
  700. DATA_OPTIONS.forEach(function(item) {
  701. if (resultOptions[item]) {
  702. resultOptions[item] = originalOptions[item]
  703. }
  704. })
  705. }
  706. },
  707. _renderValidator: function($editor, item) {
  708. var fieldName = this._getFieldLabelName(item);
  709. var validationRules = this._prepareValidationRules(item.validationRules, item.isRequired, item.itemType, fieldName);
  710. if (Array.isArray(validationRules) && validationRules.length) {
  711. this._createComponent($editor, _validator2.default, {
  712. validationRules: validationRules,
  713. validationGroup: this.option("validationGroup")
  714. })
  715. }
  716. },
  717. _getFieldLabelName: function(item) {
  718. var isItemHaveCustomLabel = item.label && item.label.text;
  719. var itemName = isItemHaveCustomLabel ? null : this._getName(item);
  720. return isItemHaveCustomLabel ? item.label.text : itemName && _inflector2.default.captionize(itemName)
  721. },
  722. _prepareValidationRules: function(userValidationRules, isItemRequired, itemType, itemName) {
  723. var isSimpleItem = itemType === SIMPLE_ITEM_TYPE;
  724. var validationRules;
  725. if (isSimpleItem) {
  726. if (userValidationRules) {
  727. validationRules = userValidationRules
  728. } else {
  729. var requiredMessage = _string2.default.format(this.option("requiredMessage"), itemName || "");
  730. validationRules = isItemRequired ? [{
  731. type: "required",
  732. message: requiredMessage
  733. }] : null
  734. }
  735. }
  736. return validationRules
  737. },
  738. _addWrapperInvalidClass: function(editorInstance) {
  739. var wrapperClass = "." + FIELD_ITEM_CONTENT_WRAPPER_CLASS;
  740. var toggleInvalidClass = function(e) {
  741. (0, _renderer2.default)(e.element).parents(wrapperClass).toggleClass(INVALID_CLASS, e.component._isFocused() && false === e.component.option("isValid"))
  742. };
  743. editorInstance.on("focusIn", toggleInvalidClass).on("focusOut", toggleInvalidClass).on("enterKey", toggleInvalidClass)
  744. },
  745. _createEditor: function($container, renderOptions, editorOptions) {
  746. var that = this;
  747. var template = renderOptions.template;
  748. var editorInstance;
  749. if (renderOptions.dataField && !editorOptions.name) {
  750. editorOptions.name = renderOptions.dataField
  751. }
  752. that._addItemContentClasses($container);
  753. if (template) {
  754. var data = {
  755. dataField: renderOptions.dataField,
  756. editorType: renderOptions.editorType,
  757. editorOptions: editorOptions,
  758. component: that._getComponentOwner(),
  759. name: renderOptions.name
  760. };
  761. template.render({
  762. model: data,
  763. container: _dom2.default.getPublicElement($container)
  764. })
  765. } else {
  766. var $editor = (0, _renderer2.default)("<div>").appendTo($container);
  767. try {
  768. editorInstance = that._createComponent($editor, renderOptions.editorType, editorOptions);
  769. editorInstance.setAria("describedby", renderOptions.helpID);
  770. editorInstance.setAria("labelledby", renderOptions.labelID);
  771. editorInstance.setAria("required", renderOptions.isRequired);
  772. if (_themes2.default.isMaterial()) {
  773. that._addWrapperInvalidClass(editorInstance)
  774. }
  775. if (renderOptions.dataField) {
  776. that._bindDataField(editorInstance, renderOptions, $container)
  777. }
  778. } catch (e) {
  779. _ui2.default.log("E1035", e.message)
  780. }
  781. }
  782. return editorInstance
  783. },
  784. _getComponentOwner: function() {
  785. return this.option("form") || this
  786. },
  787. _bindDataField: function(editorInstance, renderOptions, $container) {
  788. var componentOwner = this._getComponentOwner();
  789. editorInstance.on("enterKey", function(args) {
  790. componentOwner._createActionByOption("onEditorEnterKey")((0, _extend.extend)(args, {
  791. dataField: renderOptions.dataField
  792. }))
  793. });
  794. this._createWatcher(editorInstance, $container, renderOptions);
  795. this.linkEditorToDataField(editorInstance, renderOptions.dataField, renderOptions.editorType)
  796. },
  797. _createWatcher: function(editorInstance, $container, renderOptions) {
  798. var that = this;
  799. var watch = that._getWatch();
  800. if (!(0, _type.isFunction)(watch)) {
  801. return
  802. }
  803. var dispose = watch(function() {
  804. return that._getDataByField(renderOptions.dataField)
  805. }, function() {
  806. editorInstance.option("value", that._getDataByField(renderOptions.dataField))
  807. }, {
  808. deep: true,
  809. skipImmediate: true
  810. });
  811. _events_engine2.default.on($container, _remove_event2.default, dispose)
  812. },
  813. _getWatch: function() {
  814. if (!(0, _type.isDefined)(this._watch)) {
  815. var formInstance = this.option("form");
  816. this._watch = formInstance && formInstance.option("integrationOptions.watchMethod")
  817. }
  818. return this._watch
  819. },
  820. _addItemContentClasses: function($itemContent) {
  821. var locationSpecificClass = this._getItemContentLocationSpecificClass();
  822. $itemContent.addClass([FIELD_ITEM_CONTENT_CLASS, locationSpecificClass].join(" "))
  823. },
  824. _getItemContentLocationSpecificClass: function() {
  825. var labelLocation = this.option("labelLocation");
  826. var oppositeClasses = {
  827. right: "left",
  828. left: "right",
  829. top: "bottom"
  830. };
  831. return FIELD_ITEM_CONTENT_LOCATION_CLASS + oppositeClasses[labelLocation]
  832. },
  833. _createComponent: function($editor, type, editorOptions) {
  834. var that = this;
  835. var readOnlyState = this.option("readOnly");
  836. var instance = that.callBase($editor, type, editorOptions);
  837. readOnlyState && instance.option("readOnly", readOnlyState);
  838. that.on("optionChanged", function(args) {
  839. if ("readOnly" === args.name && !(0, _type.isDefined)(editorOptions.readOnly)) {
  840. instance.option(args.name, args.value)
  841. }
  842. });
  843. return instance
  844. },
  845. _getTemplateByFieldItem: function(fieldItem) {
  846. return fieldItem.template ? this._getTemplate(fieldItem.template) : null
  847. },
  848. _appendEditorToField: function(params) {
  849. if (params.$label) {
  850. var location = params.labelOptions.location;
  851. if ("top" === location || "left" === location) {
  852. params.$fieldItem.append(params.$editor)
  853. }
  854. if ("right" === location) {
  855. params.$fieldItem.prepend(params.$editor)
  856. }
  857. this._addInnerItemAlignmentClass(params.$fieldItem, location)
  858. } else {
  859. params.$fieldItem.append(params.$editor)
  860. }
  861. },
  862. _addInnerItemAlignmentClass: function($fieldItem, location) {
  863. if ("top" === location) {
  864. $fieldItem.addClass(LABEL_VERTICAL_ALIGNMENT_CLASS)
  865. } else {
  866. $fieldItem.addClass(LABEL_HORIZONTAL_ALIGNMENT_CLASS)
  867. }
  868. },
  869. _renderHelpText: function(fieldItem, $editor, helpID) {
  870. var helpText = fieldItem.helpText;
  871. var isSimpleItem = fieldItem.itemType === SIMPLE_ITEM_TYPE;
  872. if (helpText && isSimpleItem) {
  873. var $editorWrapper = (0, _renderer2.default)("<div>").addClass(FIELD_ITEM_CONTENT_WRAPPER_CLASS);
  874. $editor.wrap($editorWrapper);
  875. (0, _renderer2.default)("<div>").addClass(FIELD_ITEM_HELP_TEXT_CLASS).attr("id", helpID).text(helpText).appendTo($editor.parent())
  876. }
  877. },
  878. _attachClickHandler: function($label, $editor, editorType) {
  879. var isBooleanEditors = "dxCheckBox" === editorType || "dxSwitch" === editorType;
  880. if ($label && isBooleanEditors) {
  881. _events_engine2.default.on($label, _click2.default.name, function() {
  882. _events_engine2.default.trigger($editor.children(), _click2.default.name)
  883. })
  884. }
  885. },
  886. _generateRatio: function(count, isAutoSize) {
  887. var result = [];
  888. for (var i = 0; i < count; i++) {
  889. var ratio = {
  890. ratio: 1
  891. };
  892. if (isAutoSize) {
  893. ratio.baseSize = "auto"
  894. }
  895. result.push(ratio)
  896. }
  897. return result
  898. },
  899. _getRowsCount: function() {
  900. return Math.ceil(this._items.length / this._getColCount())
  901. },
  902. _updateReferencedOptions: function(newLayoutData) {
  903. var _this = this;
  904. var layoutData = this.option("layoutData");
  905. if ((0, _type.isObject)(layoutData)) {
  906. Object.getOwnPropertyNames(layoutData).forEach(function(property) {
  907. return delete _this._optionsByReference["layoutData." + property]
  908. })
  909. }
  910. if ((0, _type.isObject)(newLayoutData)) {
  911. Object.getOwnPropertyNames(newLayoutData).forEach(function(property) {
  912. return _this._optionsByReference["layoutData." + property] = true
  913. })
  914. }
  915. },
  916. _resetWidget: function(instance) {
  917. var defaultOptions = instance._getDefaultOptions();
  918. instance._setOptionSilent("value", defaultOptions.value);
  919. instance.option("isValid", true)
  920. },
  921. _optionChanged: function(args) {
  922. var _this2 = this;
  923. if (0 === args.fullName.search("layoutData.")) {
  924. return
  925. }
  926. switch (args.name) {
  927. case "showRequiredMark":
  928. case "showOptionalMark":
  929. case "requiredMark":
  930. case "optionalMark":
  931. this._cashedRequiredConfig = null;
  932. this._invalidate();
  933. break;
  934. case "layoutData":
  935. this._updateReferencedOptions(args.value);
  936. if (this.option("items")) {
  937. if (!(0, _type.isEmptyObject)(args.value)) {
  938. this._itemsRunTimeInfo.each(function(_, itemRunTimeInfo) {
  939. if ((0, _type.isDefined)(itemRunTimeInfo.item)) {
  940. var dataField = itemRunTimeInfo.item.dataField;
  941. if (dataField && (0, _type.isDefined)(itemRunTimeInfo.widgetInstance)) {
  942. var valueGetter = _data2.default.compileGetter(dataField);
  943. var dataValue = valueGetter(args.value);
  944. if (void 0 === dataValue) {
  945. _this2._resetWidget(itemRunTimeInfo.widgetInstance)
  946. } else {
  947. itemRunTimeInfo.widgetInstance.option("value", dataValue)
  948. }
  949. }
  950. }
  951. })
  952. }
  953. } else {
  954. this._initDataAndItems(args.value);
  955. this._invalidate()
  956. }
  957. break;
  958. case "items":
  959. this._cleanItemWatchers();
  960. this._initDataAndItems(args.value);
  961. this._invalidate();
  962. break;
  963. case "alignItemLabels":
  964. case "labelLocation":
  965. case "requiredMessage":
  966. this._invalidate();
  967. break;
  968. case "customizeItem":
  969. this._updateItems(this.option("layoutData"));
  970. this._invalidate();
  971. break;
  972. case "colCount":
  973. this._resetColCount();
  974. break;
  975. case "minColWidth":
  976. if ("auto" === this.option("colCount")) {
  977. this._resetColCount()
  978. }
  979. break;
  980. case "readOnly":
  981. break;
  982. case "width":
  983. this.callBase(args);
  984. if ("auto" === this.option("colCount")) {
  985. this._resetColCount()
  986. }
  987. break;
  988. case "onFieldDataChanged":
  989. break;
  990. default:
  991. this.callBase(args)
  992. }
  993. },
  994. _resetColCount: function() {
  995. this._cashedColCount = null;
  996. this._invalidate()
  997. },
  998. linkEditorToDataField: function(editorInstance, dataField) {
  999. var _this3 = this;
  1000. this.on("optionChanged", function(args) {
  1001. if (args.fullName === "layoutData.".concat(dataField)) {
  1002. editorInstance._setOptionSilent("value", args.value)
  1003. }
  1004. });
  1005. editorInstance.on("valueChanged", function(args) {
  1006. if (!((0, _type.isObject)(args.value) && args.value === args.previousValue)) {
  1007. _this3._updateFieldValue(dataField, args.value)
  1008. }
  1009. })
  1010. },
  1011. _dimensionChanged: function() {
  1012. if ("auto" === this.option("colCount") && this.isCachedColCountObsolete()) {
  1013. this.fireEvent("autoColCountChanged")
  1014. }
  1015. },
  1016. getItemID: function(name) {
  1017. var formInstance = this.option("form");
  1018. return formInstance && formInstance.getItemID(name)
  1019. },
  1020. updateData: function(data, value) {
  1021. var that = this;
  1022. if ((0, _type.isObject)(data)) {
  1023. (0, _iterator.each)(data, function(dataField, fieldValue) {
  1024. that._updateFieldValue(dataField, fieldValue)
  1025. })
  1026. } else {
  1027. if ("string" === typeof data) {
  1028. that._updateFieldValue(data, value)
  1029. }
  1030. }
  1031. },
  1032. getEditor: function(field) {
  1033. return this._itemsRunTimeInfo.findWidgetInstanceByDataField(field) || this._itemsRunTimeInfo.findWidgetInstanceByName(field)
  1034. },
  1035. isSingleColumnMode: function(component) {
  1036. var responsiveBox = this._responsiveBox || component;
  1037. if (responsiveBox) {
  1038. return responsiveBox.option("currentScreenFactor") === responsiveBox.option("singleColumnScreen")
  1039. }
  1040. }
  1041. });
  1042. (0, _component_registrator2.default)("dxLayoutManager", LayoutManager);
  1043. module.exports = LayoutManager;