PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/Magento/Ui/view/base/web/js/grid/editing/record.js

https://gitlab.com/crazybutterfly815/magento2
JavaScript | 356 lines | 181 code | 51 blank | 124 comment | 10 complexity | 309dd8ac384f2854585bf59955c52981 MD5 | raw file
  1. /**
  2. * Copyright © 2016 Magento. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. define([
  6. 'underscore',
  7. 'mageUtils',
  8. 'uiLayout',
  9. 'uiCollection'
  10. ], function (_, utils, layout, Collection) {
  11. 'use strict';
  12. return Collection.extend({
  13. defaults: {
  14. active: true,
  15. hasChanges: false,
  16. fields: [],
  17. errorsCount: 0,
  18. fieldTmpl: 'ui/grid/editing/field',
  19. rowTmpl: 'ui/grid/editing/row',
  20. templates: {
  21. fields: {
  22. base: {
  23. parent: '${ $.$data.record.name }',
  24. name: '${ $.$data.column.index }',
  25. provider: '${ $.$data.record.name }',
  26. dataScope: 'data.${ $.$data.column.index }',
  27. imports: {
  28. disabled: '${ $.$data.record.parentName }:fields.${ $.$data.column.index }.disabled'
  29. },
  30. isEditor: true
  31. },
  32. text: {
  33. component: 'Magento_Ui/js/form/element/abstract',
  34. template: 'ui/form/element/input'
  35. },
  36. date: {
  37. component: 'Magento_Ui/js/form/element/date',
  38. template: 'ui/form/element/date',
  39. dateFormat: 'MMM d, y h:mm:ss a'
  40. },
  41. select: {
  42. component: 'Magento_Ui/js/form/element/select',
  43. template: 'ui/form/element/select',
  44. options: '${ JSON.stringify($.$data.column.options) }'
  45. }
  46. }
  47. },
  48. listens: {
  49. elems: 'updateFields',
  50. data: 'updateState'
  51. },
  52. imports: {
  53. onColumnsUpdate: '${ $.columnsProvider }:elems'
  54. },
  55. modules: {
  56. columns: '${ $.columnsProvider }',
  57. editor: '${ $.editorProvider }'
  58. }
  59. },
  60. /**
  61. * Initializes record component.
  62. *
  63. * @returns {Record} Chainable.
  64. */
  65. initialize: function () {
  66. _.bindAll(this, 'countErrors');
  67. utils.limit(this, 'updateState', 10);
  68. return this._super();
  69. },
  70. /**
  71. * Initializes observable properties.
  72. *
  73. * @returns {Record} Chainable.
  74. */
  75. initObservable: function () {
  76. this._super()
  77. .track('errorsCount hasChanges')
  78. .observe('active fields');
  79. return this;
  80. },
  81. /**
  82. * Adds listeners on a field.
  83. *
  84. * @returns {Record} Chainable.
  85. */
  86. initElement: function (field) {
  87. field.on('error', this.countErrors);
  88. return this._super();
  89. },
  90. /**
  91. * Creates new instance of a field.
  92. *
  93. * @param {Column} column - Column instance which contains field definition.
  94. * @returns {Record} Chainable.
  95. */
  96. initField: function (column) {
  97. var field = this.buildField(column);
  98. layout([field]);
  99. return this;
  100. },
  101. /**
  102. * Builds fields' configuration described in a provided column.
  103. *
  104. * @param {Column} column - Column instance which contains field definition.
  105. * @returns {Object} Complete fields' configuration.
  106. */
  107. buildField: function (column) {
  108. var fields = this.templates.fields,
  109. field = column.editor;
  110. if (_.isObject(field) && field.editorType) {
  111. field = utils.extend({}, fields[field.editorType], field);
  112. } else if (_.isString(field)) {
  113. field = fields[field];
  114. }
  115. field = utils.extend({}, fields.base, field);
  116. return utils.template(field, {
  117. record: this,
  118. column: column
  119. }, true, true);
  120. },
  121. /**
  122. * Creates fields for the specfied columns.
  123. *
  124. * @param {Array} columns - An array of column instances.
  125. * @returns {Record} Chainable.
  126. */
  127. createFields: function (columns) {
  128. columns.forEach(function (column) {
  129. if (column.editor && !this.hasChild(column.index)) {
  130. this.initField(column);
  131. }
  132. }, this);
  133. return this;
  134. },
  135. /**
  136. * Returns instance of a column found by provided index.
  137. *
  138. * @param {String} index - Index of a column (e.g. 'title').
  139. * @returns {Column}
  140. */
  141. getColumn: function (index) {
  142. return this.columns().getChild(index);
  143. },
  144. /**
  145. * Returns records' current data object.
  146. *
  147. * @returns {Object}
  148. */
  149. getData: function () {
  150. return this.filterData(this.data);
  151. },
  152. /**
  153. * Returns saved records' data. Data will be processed
  154. * with a 'filterData' and 'normalizeData' methods.
  155. *
  156. * @returns {Object} Saved records' data.
  157. */
  158. getSavedData: function () {
  159. var editor = this.editor(),
  160. savedData = editor.getRowData(this.index);
  161. savedData = this.filterData(savedData);
  162. return this.normalizeData(savedData);
  163. },
  164. /**
  165. * Replaces current records' data with the provided one.
  166. *
  167. * @param {Object} data - New records data.
  168. * @param {Boolean} [partial=false] - Flag that defines whether
  169. * to completely replace current data or to extend it.
  170. * @returns {Record} Chainable.
  171. */
  172. setData: function (data, partial) {
  173. var currentData = partial ? this.data : {};
  174. data = this.normalizeData(data);
  175. data = utils.extend({}, currentData, data);
  176. this.set('data', data)
  177. .updateState();
  178. return this;
  179. },
  180. /**
  181. * Filters provided object extracting from it values
  182. * that can be matched with an existing fields.
  183. *
  184. * @param {Object} data - Object to be processed.
  185. * @returns {Object}
  186. */
  187. filterData: function (data) {
  188. var fields = _.pluck(this.elems(), 'index');
  189. _.each(this.preserveFields, function (enabled, field) {
  190. if (enabled && !_.contains(fields, field)) {
  191. fields.push(field);
  192. }
  193. });
  194. return _.pick(data, fields);
  195. },
  196. /**
  197. * Parses values of a provided object with
  198. * a 'normalizeData' method of a corresponding field.
  199. *
  200. * @param {Object} data - Data to be processed.
  201. * @returns {Object}
  202. */
  203. normalizeData: function (data) {
  204. var index;
  205. this.elems.each(function (elem) {
  206. index = elem.index;
  207. if (data.hasOwnProperty(index)) {
  208. data[index] = elem.normalizeData(data[index]);
  209. }
  210. });
  211. return data;
  212. },
  213. /**
  214. * Clears values of all fields.
  215. *
  216. * @returns {Record} Chainable.
  217. */
  218. clear: function () {
  219. this.elems.each('clear');
  220. return this;
  221. },
  222. /**
  223. * Validates all of the available fields.
  224. *
  225. * @returns {Array} An array with validatation results.
  226. */
  227. validate: function () {
  228. return this.elems.map('validate');
  229. },
  230. /**
  231. * Checks if all fields are valid.
  232. *
  233. * @returns {Boolean}
  234. */
  235. isValid: function () {
  236. return _.every(this.validate(), 'valid');
  237. },
  238. /**
  239. * Counts total errors ammount accros all fields.
  240. *
  241. * @returns {Number}
  242. */
  243. countErrors: function () {
  244. var errorsCount = this.elems.filter('error').length;
  245. this.errorsCount = errorsCount;
  246. return errorsCount;
  247. },
  248. /**
  249. * Returns difference between current data and its'
  250. * initial state, retrieved from the records collection.
  251. *
  252. * @returns {Object} Object with changes descriptions.
  253. */
  254. checkChanges: function () {
  255. var savedData = this.getSavedData(),
  256. data = this.normalizeData(this.getData());
  257. return utils.compare(savedData, data);
  258. },
  259. /**
  260. * Updates 'fields' array filling it with available edtiors
  261. * or with column instances if associated field is not present.
  262. *
  263. * @returns {Record} Chainable.
  264. */
  265. updateFields: function () {
  266. var fields;
  267. fields = this.columns().elems.map(function (column) {
  268. return this.getChild(column.index) || column;
  269. }, this);
  270. this.fields(fields);
  271. return this;
  272. },
  273. /**
  274. * Updates state of a 'hasChanges' property.
  275. *
  276. * @returns {Record} Chainable.
  277. */
  278. updateState: function () {
  279. var diff = this.checkChanges(),
  280. changed = {};
  281. this.hasChanges = !diff.equal;
  282. changed[this.index] = this.data;
  283. this.editor().set('changed', [changed]);
  284. return this;
  285. },
  286. /**
  287. * Checks if provided column is an actions column.
  288. *
  289. * @param {Column} column - Column to be checked.
  290. * @returns {Boolean}
  291. */
  292. isActionsColumn: function (column) {
  293. return column.dataType === 'actions';
  294. },
  295. /**
  296. * Listener of columns provider child array changes.
  297. *
  298. * @param {Array} columns - Modified child elements array.
  299. */
  300. onColumnsUpdate: function (columns) {
  301. this.createFields(columns)
  302. .updateFields();
  303. }
  304. });
  305. });