UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

420 lines (418 loc) • 16.6 kB
/** * DevExtreme (ui/hierarchical_collection/ui.data_adapter.js) * Version: 18.1.3 * Build date: Tue May 15 2018 * * Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var Class = require("../../core/class"), commonUtils = require("../../core/utils/common"), iteratorUtils = require("../../core/utils/iterator"), each = require("../../core/utils/iterator").each, typeUtils = require("../../core/utils/type"), extend = require("../../core/utils/extend").extend, errors = require("../../ui/widget/ui.errors"), inArray = require("../../core/utils/array").inArray, query = require("../../data/query"), storeHelper = require("../../data/store_helper"), HierarchicalDataConverter = require("./ui.data_converter"); var EXPANDED = "expanded", SELECTED = "selected", DISABLED = "disabled"; var DataAdapter = Class.inherit({ ctor: function(options) { this.options = {}; extend(this.options, this._defaultOptions(), options); this.options.dataConverter.setDataAccessors(this.options.dataAccessors); this._selectedNodesKeys = []; this._expandedNodesKeys = []; this._dataStructure = []; this._createInternalDataStructure(); this.getTreeNodes() }, setOption: function(name, value) { this.options[name] = value; if ("recursiveSelection" === name) { this._updateSelection() } }, _defaultOptions: function() { return { dataAccessors: void 0, items: [], multipleSelection: true, recursiveSelection: false, recursiveExpansion: false, rootValue: 0, searchValue: "", dataType: "tree", searchMode: "contains", dataConverter: new HierarchicalDataConverter, onNodeChanged: commonUtils.noop, sort: null } }, _createInternalDataStructure: function() { this._initialDataStructure = this.options.dataConverter.createPlainStructure(this.options.items, this.options.rootValue, this.options.dataType); this._dataStructure = this.options.searchValue.length ? this.search(this.options.searchValue) : this._initialDataStructure; this.options.dataConverter._dataStructure = this._dataStructure; this._updateSelection(); this._updateExpansion() }, _updateSelection: function() { if (this.options.recursiveSelection) { this._setChildrenSelection(); this._setParentSelection() } this._selectedNodesKeys = this._updateNodesKeysArray(SELECTED) }, _updateExpansion: function(key) { if (this.options.recursiveExpansion) { key ? this._updateOneBranch(key) : this._setParentExpansion() } this._expandedNodesKeys = this._updateNodesKeysArray(EXPANDED) }, _updateNodesKeysArray: function(property) { var that = this, array = []; each(that._getDataBySelectionMode(), function(_, node) { if (!that._isNodeVisible(node)) { return } if (!!node.internalFields[property]) { if (property === EXPANDED || that.options.multipleSelection) { array.push(node.internalFields.key) } else { array.length && that.toggleSelection(array[0], false, true); array = [node.internalFields.key] } } }); return array }, _getDataBySelectionMode: function() { return this.options.multipleSelection ? this.getData() : this.getFullData() }, _isNodeVisible: function(node) { return false !== node.internalFields.item.visible }, _getByKey: function(data, key) { return data === this._dataStructure ? this.options.dataConverter._getByKey(key) : this.options.dataConverter.getByKey(data, key) }, _setChildrenSelection: function() { var that = this; each(this._dataStructure, function(_, node) { if (!node.internalFields.childrenKeys.length) { return } var isSelected = node.internalFields.selected; true === isSelected && that._toggleChildrenSelection(node, isSelected) }) }, _setParentSelection: function() { var that = this; each(this._dataStructure, function(_, node) { var parent = that.options.dataConverter.getParentNode(node); if (parent && node.internalFields.parentKey !== that.options.rootValue) { that._iterateParents(node, function(parent) { var newParentState = that._calculateSelectedState(parent); that._setFieldState(parent, SELECTED, newParentState) }) } }) }, _setParentExpansion: function() { var that = this; each(this._dataStructure, function(_, node) { if (!node.internalFields.expanded) { return } that._updateOneBranch(node.internalFields.key) }) }, _updateOneBranch: function(key) { var that = this, node = this.getNodeByKey(key); that._iterateParents(node, function(parent) { that._setFieldState(parent, EXPANDED, true) }) }, _iterateChildren: function(node, recursive, callback) { var that = this; each(node.internalFields.childrenKeys, function(_, key) { var child = that.getNodeByKey(key); typeUtils.isFunction(callback) && callback(child); if (child.internalFields.childrenKeys.length && recursive) { that._iterateChildren(child, recursive, callback) } }) }, _iterateParents: function(node, callback) { if (node.internalFields.parentKey === this.options.rootValue) { return } var parent = this.options.dataConverter.getParentNode(node); if (parent) { typeUtils.isFunction(callback) && callback(parent); if (parent.internalFields.parentKey !== this.options.rootValue) { this._iterateParents(parent, callback) } } }, _calculateSelectedState: function(node) { var itemsCount = node.internalFields.childrenKeys.length, selectedItemsCount = 0, invisibleItemsCount = 0, result = false; for (var i = 0; i <= itemsCount - 1; i++) { var childNode = this.getNodeByKey(node.internalFields.childrenKeys[i]), isChildInvisible = false === childNode.internalFields.item.visible, childState = childNode.internalFields.selected; if (isChildInvisible) { invisibleItemsCount++; continue } if (childState) { selectedItemsCount++ } else { if (void 0 === childState) { selectedItemsCount += .5 } } } if (selectedItemsCount) { result = selectedItemsCount === itemsCount - invisibleItemsCount ? true : void 0 } return result }, _toggleChildrenSelection: function(node, state) { var that = this; this._iterateChildren(node, true, function(child) { if (that._isNodeVisible(child)) { that._setFieldState(child, SELECTED, state) } }) }, _setFieldState: function(node, field, state) { if (node.internalFields[field] === state) { return } node.internalFields[field] = state; if (node.internalFields.publicNode) { node.internalFields.publicNode[field] = state } this.options.dataAccessors.setters[field](node.internalFields.item, state); this.options.onNodeChanged(node) }, _markChildren: function(keys) { var that = this; each(keys, function(_, key) { var index = that.getIndexByKey(key), node = that.getNodeByKey(key); that._dataStructure[index] = 0; node.internalFields.childrenKeys.length && that._markChildren(node.internalFields.childrenKeys) }) }, _removeNode: function(key) { var node = this.getNodeByKey(key); this._dataStructure[this.getIndexByKey(key)] = 0; this._markChildren(node.internalFields.childrenKeys); var that = this, counter = 0, items = extend([], this._dataStructure); each(items, function(index, item) { if (!item) { that._dataStructure.splice(index - counter, 1); counter++ } }) }, _addNode: function(item) { var dataConverter = this.options.dataConverter, node = dataConverter._convertItemToNode(item, this.options.dataAccessors.getters.parentKey(item)); this._dataStructure = this._dataStructure.concat(node); this._initialDataStructure = this._initialDataStructure.concat(node); dataConverter._dataStructure = dataConverter._dataStructure.concat(node) }, _updateFields: function() { this.options.dataConverter.updateChildrenKeys(); this._updateSelection(); this._updateExpansion() }, getSelectedNodesKeys: function() { return this._selectedNodesKeys }, getExpandedNodesKeys: function() { return this._expandedNodesKeys }, getData: function() { return this._dataStructure }, getFullData: function() { return this._initialDataStructure }, getNodeByItem: function(item) { var result = null; each(this._dataStructure, function(_, node) { if (node.internalFields.item === item) { result = node; return false } }); return result }, getNodesByItems: function(items) { var that = this, nodes = []; each(items, function(_, item) { var node = that.getNodeByItem(item); node && nodes.push(node) }); return nodes }, getNodeByKey: function(key, data) { return this._getByKey(data || this._getDataBySelectionMode(), key) }, getTreeNodes: function() { return this.options.dataConverter.convertToPublicNodes(this.getRootNodes()) }, getItemsCount: function() { return this.options.dataConverter.getItemsCount() }, getVisibleItemsCount: function() { return this.options.dataConverter.getVisibleItemsCount() }, getPublicNode: function(node) { return node.internalFields.publicNode }, getRootNodes: function() { return this.getChildrenNodes(this.options.rootValue) }, getChildrenNodes: function(parentKey) { return query(this._dataStructure).filter(["internalFields.parentKey", parentKey]).toArray() }, getIndexByKey: function(key) { return this.options.dataConverter.getIndexByKey(key) }, addItem: function(item) { this._addNode(item); this._updateFields() }, removeItem: function(key) { this._removeNode(key); this._updateFields() }, toggleSelection: function(key, state, selectRecursive) { var isSingleModeUnselect = this._isSingleModeUnselect(state), node = this._getByKey(selectRecursive || isSingleModeUnselect ? this._initialDataStructure : this._dataStructure, key); this._setFieldState(node, SELECTED, state); if (this.options.recursiveSelection && !selectRecursive) { state ? this._setChildrenSelection() : this._toggleChildrenSelection(node, state); this._setParentSelection() } this._selectedNodesKeys = this._updateNodesKeysArray(SELECTED) }, _isSingleModeUnselect: function(selectionState) { return !this.options.multipleSelection && !selectionState }, toggleNodeDisabledState: function(key, state) { var node = this.getNodeByKey(key); this._setFieldState(node, DISABLED, state) }, toggleSelectAll: function(state) { if (!typeUtils.isDefined(state)) { return } var that = this, dataStructure = that._isSingleModeUnselect(state) ? this._initialDataStructure : this._dataStructure; each(dataStructure, function(_, node) { if (!that._isNodeVisible(node)) { return } that._setFieldState(node, SELECTED, state) }); that._selectedNodesKeys = that._updateNodesKeysArray(SELECTED) }, isAllSelected: function() { if (this.getSelectedNodesKeys().length) { return this.getSelectedNodesKeys().length === this.getVisibleItemsCount() ? true : void 0 } else { return false } }, toggleExpansion: function(key, state) { var node = this.getNodeByKey(key); this._setFieldState(node, EXPANDED, state); if (state) { this._updateExpansion(key) } this._expandedNodesKeys = this._updateNodesKeysArray(EXPANDED) }, isFiltered: function(item) { return !this.options.searchValue.length || !!this._filterDataStructure(this.options.searchValue, [item]).length }, _createCriteria: function(selector, value, operation) { var searchFilter = []; if (!Array.isArray(selector)) { return [selector, operation, value] } iteratorUtils.each(selector, function(i, item) { searchFilter.push([item, operation, value], "or") }); searchFilter.pop(); return searchFilter }, _filterDataStructure: function(filterValue, dataStructure) { var selector = this.options.searchExpr || this.options.dataAccessors.getters.display, criteria = this._createCriteria(selector, filterValue, this.options.searchMode); dataStructure = dataStructure || this._initialDataStructure; return query(dataStructure).filter(criteria).toArray() }, search: function(searchValue) { var that = this, matches = this._filterDataStructure(searchValue), dataConverter = this.options.dataConverter; function lookForParents(matches, index) { var length = matches.length; while (index < length) { var node = matches[index]; if (node.internalFields.parentKey === that.options.rootValue) { index++; continue } var parent = dataConverter.getParentNode(node); if (!parent) { errors.log("W1007", node.internalFields.parentKey, node.internalFields.key); index++; continue } if (!parent.internalFields.expanded) { that._setFieldState(parent, EXPANDED, true) } if (inArray(parent, matches) > -1) { index++; continue } matches.splice(index, 0, parent); lookForParents(matches, index) } } lookForParents(matches, 0); if (this.options.sort) { matches = storeHelper.queryByOptions(query(matches), { sort: this.options.sort }).toArray() } dataConverter._indexByKey = {}; each(matches, function(index, node) { node.internalFields.childrenKeys = []; dataConverter._indexByKey[node.internalFields.key] = index }); dataConverter._dataStructure = matches; dataConverter.setChildrenKeys(); return dataConverter._dataStructure } }); module.exports = DataAdapter;