UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

636 lines (503 loc) • 23 kB
"use strict"; var treeListCore = require("./ui.tree_list.core"), errors = require("../widget/ui.errors"), commonUtils = require("../../core/utils/common"), typeUtils = require("../../core/utils/type"), each = require("../../core/utils/iterator").each, dataCoreUtils = require("../../core/utils/data"), extend = require("../../core/utils/extend").extend, gridCoreUtils = require("../grid_core/ui.grid_core.utils"), ArrayStore = require("../../data/array_store"), query = require("../../data/query"), DataSourceAdapter = require("../grid_core/ui.grid_core.data_source_adapter"), Deferred = require("../../core/utils/deferred").Deferred, queryByOptions = require("../../data/store_helper").queryByOptions; var DEFAULT_KEY_EXPRESSION = "id"; DataSourceAdapter = DataSourceAdapter.inherit(function () { var getChildKeys = function getChildKeys(that, keys) { var childKeys = []; keys.forEach(function (key) { var node = that.getNodeByKey(key); node && node.children.forEach(function (child) { childKeys.push(child.key); }); }); return childKeys; }; return { _createKeyGetter: function _createKeyGetter() { var keyExpr = this.getKeyExpr(); return dataCoreUtils.compileGetter(keyExpr); }, _createKeySetter: function _createKeySetter() { var keyExpr = this.getKeyExpr(); return dataCoreUtils.compileSetter(keyExpr); }, _createParentIdGetter: function _createParentIdGetter() { return dataCoreUtils.compileGetter(this.option("parentIdExpr")); }, createParentIdSetter: function createParentIdSetter() { return dataCoreUtils.compileSetter(this.option("parentIdExpr")); }, _createItemsGetter: function _createItemsGetter() { return dataCoreUtils.compileGetter(this.option("itemsExpr")); }, _createHasItemsGetter: function _createHasItemsGetter() { var hasItemsExpr = this.option("hasItemsExpr"); return hasItemsExpr && dataCoreUtils.compileGetter(hasItemsExpr); }, _updateIndexByKeyObject: function _updateIndexByKeyObject(items) { var that = this; that._indexByKey = {}; each(items, function (index, item) { that._indexByKey[item.key] = index; }); }, _calculateHasItems: function _calculateHasItems(node, options) { var that = this, hasItems; if (that._hasItemsGetter) { hasItems = that._hasItemsGetter(node.data); } if (hasItems === undefined) { var hasItemsByMap = that._hasItemsMap[node.key]; if (hasItemsByMap !== undefined) { hasItems = hasItemsByMap; } else if (options.remoteOperations.filtering && options.storeLoadOptions.parentIds) { hasItems = true; } else { hasItems = node.hasChildren; } } return !!hasItems; }, _createVisibleItemsByNodes: function _createVisibleItemsByNodes(nodes, options) { var that = this, result = []; for (var i = 0; i < nodes.length; i++) { if (nodes[i].visible) { result.push(nodes[i]); } if ((that.isRowExpanded(nodes[i].key) || !nodes[i].visible) && nodes[i].hasChildren && nodes[i].children.length) { result = result.concat(that._createVisibleItemsByNodes(nodes[i].children, options)); } } return result; }, _convertItemToNode: function _convertItemToNode(item, rootValue, nodeByKey) { var key = this._keyGetter(item), parentId = this._parentIdGetter(item), parentNode, node; parentId = typeUtils.isDefined(parentId) ? parentId : rootValue; parentNode = nodeByKey[parentId] = nodeByKey[parentId] || { key: parentId, children: [] }; node = nodeByKey[key] = nodeByKey[key] || { key: key, children: [] }; node.data = item; node.parent = parentNode; return node; }, _createNodesByItems: function _createNodesByItems(items, visibleItems) { var that = this, rootValue = that.option("rootValue"), visibleByKey = {}, nodeByKey = that._nodeByKey = {}, i; if (visibleItems) { for (i = 0; i < visibleItems.length; i++) { visibleByKey[this._keyGetter(visibleItems[i])] = true; } } for (i = 0; i < items.length; i++) { var node = that._convertItemToNode(items[i], rootValue, nodeByKey); if (node.key === undefined) { return; } node.visible = !visibleItems || !!visibleByKey[node.key]; if (node.parent) { node.parent.children.push(node); } } var rootNode = nodeByKey[rootValue] || { key: rootValue, children: [] }; rootNode.level = -1; return rootNode; }, _convertDataToPlainStructure: function _convertDataToPlainStructure(data, parentId, result) { var key, item, itemsExpr, childItems; if (this._itemsGetter) { result = result || []; for (var i = 0; i < data.length; i++) { item = extend({}, data[i]); key = this._keyGetter(item); if (key === undefined) { key = result.length + 1; this._keySetter(item, key); } this._parentIdSetter(item, parentId === undefined ? this.option("rootValue") : parentId); result.push(item); childItems = this._itemsGetter(item); if (childItems && childItems.length) { this._convertDataToPlainStructure(childItems, key, result); itemsExpr = this.option("itemsExpr"); if (!typeUtils.isFunction(itemsExpr)) { delete item[itemsExpr]; } } } return result; } return data; }, _createIdFilter: function _createIdFilter(field, keys) { var parentIdFilters = []; for (var i = 0; i < keys.length; i++) { parentIdFilters.push([field, "=", keys[i]]); } return gridCoreUtils.combineFilters(parentIdFilters, "or"); }, _customizeRemoteOperations: function _customizeRemoteOperations(options, isReload, operationTypes) { this.callBase.apply(this, arguments); options.remoteOperations.paging = false; var expandVisibleNodes = false; if (this.option("autoExpandAll")) { options.remoteOperations.sorting = false; options.remoteOperations.filtering = false; if (isReload && !this._lastLoadOptions && !options.isCustomLoading) { expandVisibleNodes = true; } } this._isReload = this._isReload || isReload || operationTypes.reload; if (!options.isCustomLoading) { if (!options.cachedStoreData) { this._hasItemsMap = {}; } if (this.option("expandNodesOnFiltering") && (isReload || operationTypes.filtering)) { if (options.storeLoadOptions.filter || operationTypes.filtering && this.option("autoExpandAll")) { expandVisibleNodes = true; } } } options.expandVisibleNodes = expandVisibleNodes; }, _getParentIdsToLoad: function _getParentIdsToLoad(parentIds) { var parentIdsToLoad = []; for (var i = 0; i < parentIds.length; i++) { if (this._hasItemsMap[parentIds[i]] === undefined) { parentIdsToLoad.push(parentIds[i]); } } return parentIdsToLoad; }, _handleDataLoading: function _handleDataLoading(options) { var combinedParentIdFilter, parentIdsToLoad, rootValue = this.option("rootValue"), parentIdExpr = this.option("parentIdExpr"), expandedRowKeys = this.option("expandedRowKeys"), filterMode = this.option("filterMode"), parentIds = options.storeLoadOptions.parentIds; if (parentIds) { options.isCustomLoading = false; } this.callBase.apply(this, arguments); if (options.remoteOperations.filtering && !options.isCustomLoading) { if (filterMode === "standard" || !options.storeLoadOptions.filter) { parentIds = [rootValue].concat(expandedRowKeys).concat(parentIds || []); parentIdsToLoad = options.data ? this._getParentIdsToLoad(parentIds) : parentIds; if (parentIdsToLoad.length) { options.cachedPagingData = undefined; options.data = undefined; options.mergeStoreLoadData = true; } options.storeLoadOptions.parentIds = parentIdsToLoad; combinedParentIdFilter = this._createIdFilter(parentIdExpr, parentIdsToLoad); options.storeLoadOptions.filter = gridCoreUtils.combineFilters([combinedParentIdFilter, options.storeLoadOptions.filter]); } } }, _generateParentInfoToLoad: function _generateParentInfoToLoad(data) { var that = this, keyMap = {}, parentIdMap = {}, parentIds = [], rootValue = that.option("rootValue"), i; for (i = 0; i < data.length; i++) { keyMap[that._keyGetter(data[i])] = true; } for (i = 0; i < data.length; i++) { var parentId = that._parentIdGetter(data[i]); if (!parentIdMap[parentId] && !keyMap[parentId] && parentId !== rootValue) { parentIdMap[parentId] = true; parentIds.push(parentId); } } return { parentIdMap: parentIdMap, parentIds: parentIds }; }, _loadParents: function _loadParents(data, options) { var that = this, store, filter, filterLength, needLocalFiltering, parentInfo = that._generateParentInfoToLoad(data), parentIds = parentInfo.parentIds, parentIdMap = parentInfo.parentIdMap, d = new Deferred(), isRemoteFiltering = options.remoteOperations.filtering, maxFilterLengthInRequest = that.option("maxFilterLengthInRequest"), loadOptions = isRemoteFiltering ? options.storeLoadOptions : options.loadOptions; if (!parentIds.length) { return d.resolve(data); } filter = that._createIdFilter(that.getKeyExpr(), parentIds); filterLength = encodeURI(JSON.stringify(filter)).length; if (filterLength > maxFilterLengthInRequest) { filter = function filter(itemData) { return parentIdMap[that._keyGetter(itemData)]; }; needLocalFiltering = isRemoteFiltering; } loadOptions = extend({}, loadOptions, { filter: !needLocalFiltering ? filter : null }); store = options.fullData ? new ArrayStore(options.fullData) : that._dataSource.store(); store.load(loadOptions).done(function (loadedData) { if (loadedData.length) { if (needLocalFiltering) { loadedData = query(loadedData).filter(filter).toArray(); } that._loadParents(data.concat(loadedData), options).done(d.resolve).fail(d.reject); } else { d.resolve(data); } }).fail(d.reject); return d; }, _updateHasItemsMap: function _updateHasItemsMap(options) { var data = options.data, parentIds = options.storeLoadOptions.parentIds; if (parentIds) { for (var i = 0; i < parentIds.length; i++) { for (var dataIndex = 0; dataIndex < data.length; dataIndex++) { var parentId = this._parentIdGetter(data[dataIndex]); if (dataCoreUtils.toComparable(parentId, true) === dataCoreUtils.toComparable(parentIds[i], true)) { this._hasItemsMap[parentIds[i]] = true; break; } } if (dataIndex === data.length) { this._hasItemsMap[parentIds[i]] = false; } } } }, _handleDataLoaded: function _handleDataLoaded(options) { options.data = this._convertDataToPlainStructure(options.data); if (!options.remoteOperations.filtering) { options.fullData = queryByOptions(query(options.data), { sort: options.loadOptions && options.loadOptions.sort }).toArray(); } this._updateHasItemsMap(options); this.callBase(options); }, _fillNodes: function _fillNodes(nodes, options, expandedRowKeys, level) { level = level || 0; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; // node.hasChildren = false; this._fillNodes(nodes[i].children, options, expandedRowKeys, level + 1); node.level = level; node.hasChildren = this._calculateHasItems(node, options); if (node.visible && node.hasChildren && options.expandVisibleNodes) { expandedRowKeys.push(node.key); } if (node.visible || node.hasChildren) { node.parent.hasChildren = true; } } }, _processTreeStructure: function _processTreeStructure(options, visibleItems) { var data = options.data, expandedRowKeys = []; if (!options.fullData || this._isReload) { if (options.fullData && options.fullData.length > options.data.length) { data = options.fullData; visibleItems = visibleItems || options.data; } this._rootNode = this._createNodesByItems(data, visibleItems); if (!this._rootNode) { options.data = new Deferred().reject(errors.Error("E1046", this.getKeyExpr())); return; } this._fillNodes(this._rootNode.children, options, expandedRowKeys); this._isNodesInitializing = true; if (expandedRowKeys.length) { this.option("expandedRowKeys", expandedRowKeys); } this.executeAction("onNodesInitialized", { root: this._rootNode }); this._isNodesInitializing = false; this._isReload = false; } data = this._createVisibleItemsByNodes(this._rootNode.children, options); options.data = data; this._totalItemsCount = data.length; }, _handleDataLoadedCore: function _handleDataLoadedCore(options) { var that = this, data = options.data, callBase = that.callBase, filter = options.storeLoadOptions.filter || options.loadOptions.filter, filterMode = that.option("filterMode"), visibleItems; if (!options.isCustomLoading) { if (filter && !options.storeLoadOptions.parentIds && filterMode !== "standard") { var d = options.data = new Deferred(); if (filterMode === "smart") { visibleItems = data; } return that._loadParents(data, options).done(function (data) { options.data = data; that._processTreeStructure(options, visibleItems); callBase.call(that, options); d.resolve(options.data); }).fail(d.reject); } else { that._processTreeStructure(options); } } that.callBase(options); }, init: function init(dataSource, remoteOperations) { this.callBase.apply(this, arguments); var dataStructure = this.option("dataStructure"); this._keyGetter = this._createKeyGetter(); this._parentIdGetter = this._createParentIdGetter(); this._hasItemsGetter = this._createHasItemsGetter(); if (dataStructure === "tree") { this._itemsGetter = this._createItemsGetter(); this._keySetter = this._createKeySetter(); this._parentIdSetter = this.createParentIdSetter(); } this._nodeByKey = {}; this._hasItemsMap = {}; this._totalItemsCount = 0; this.createAction("onNodesInitialized"); }, getKeyExpr: function getKeyExpr() { var store = this.store(), key = store && store.key(), keyExpr = this.option("keyExpr"); if (typeUtils.isDefined(key) && typeUtils.isDefined(keyExpr)) { if (!commonUtils.equalByValue(key, keyExpr)) { throw errors.Error("E1044"); } } return key || keyExpr || DEFAULT_KEY_EXPRESSION; }, keyOf: function keyOf(data) { return this._keyGetter && this._keyGetter(data); }, getRootNode: function getRootNode() { return this._rootNode; }, totalItemsCount: function totalItemsCount() { return this._totalItemsCount; }, isRowExpanded: function isRowExpanded(key) { var indexExpandedNodeKey = gridCoreUtils.getIndexByKey(key, this.option("expandedRowKeys"), null); return indexExpandedNodeKey >= 0; }, _changeRowExpandCore: function _changeRowExpandCore(key) { var expandedRowKeys = this.option("expandedRowKeys"), indexExpandedNodeKey = gridCoreUtils.getIndexByKey(key, expandedRowKeys, null); if (indexExpandedNodeKey < 0) { expandedRowKeys.push(key); } else { expandedRowKeys.splice(indexExpandedNodeKey, 1); } this.option("expandedRowKeys", expandedRowKeys); }, changeRowExpand: function changeRowExpand(key) { this._changeRowExpandCore(key); return this._isNodesInitializing ? new Deferred().resolve() : this.load(); }, getNodeByKey: function getNodeByKey(key) { if (this._nodeByKey) { return this._nodeByKey[key]; } }, getNodeLeafKeys: function getNodeLeafKeys() { var that = this, node, result = [], keys = that._rootNode ? [that._rootNode.key] : []; keys.forEach(function (key) { node = that.getNodeByKey(key); node && treeListCore.foreachNodes([node], function (childNode) { !childNode.children.length && result.push(childNode.key); }); }); return result; }, getChildNodeKeys: function getChildNodeKeys(parentKey) { var node = this.getNodeByKey(parentKey), childrenKeys = []; node && treeListCore.foreachNodes(node.children, function (childNode) { childrenKeys.push(childNode.key); }); return childrenKeys; }, loadDescendants: function loadDescendants(keys, childrenOnly) { var that = this, loadOptions, d = new Deferred(), remoteOperations = that.remoteOperations(); if (typeUtils.isDefined(keys)) { keys = Array.isArray(keys) ? keys : [keys]; } else { keys = that.getNodeLeafKeys(); } if (!remoteOperations.filtering || !keys.length) { return d.resolve(); } loadOptions = that._dataSource._createStoreLoadOptions(); loadOptions.parentIds = keys; that.load(loadOptions).done(function () { if (!childrenOnly) { var childKeys = getChildKeys(that, keys); if (childKeys.length) { that.loadDescendants(childKeys, childrenOnly).done(d.resolve).fail(d.reject); return; } } d.resolve(); }).fail(d.reject); return d.promise(); }, forEachNode: function forEachNode() { var nodes = [], callback, rootNode; if (arguments.length === 1) { callback = arguments[0]; rootNode = this.getRootNode(); nodes = rootNode && rootNode.children || []; } else if (arguments.length === 2) { callback = arguments[1]; nodes = arguments[0]; nodes = Array.isArray(nodes) ? nodes : [nodes]; } treeListCore.foreachNodes(nodes, callback); } }; }()); module.exports = { extend: function extend(extender) { DataSourceAdapter = DataSourceAdapter.inherit(extender); }, create: function create(component) { return new DataSourceAdapter(component); } };