devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
515 lines (406 loc) • 16.8 kB
JavaScript
"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 ctor(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 setOption(name, value) {
this.options[name] = value;
if (name === "recursiveSelection") {
this._updateSelection();
}
},
_defaultOptions: function _defaultOptions() {
return {
dataAccessors: undefined,
items: [],
multipleSelection: true,
recursiveSelection: false,
recursiveExpansion: false,
rootValue: 0,
searchValue: "",
dataType: "tree",
searchMode: "contains",
dataConverter: new HierarchicalDataConverter(),
onNodeChanged: commonUtils.noop,
sort: null
};
},
_createInternalDataStructure: function _createInternalDataStructure() {
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 _updateSelection() {
if (this.options.recursiveSelection) {
this._setChildrenSelection();
this._setParentSelection();
}
this._selectedNodesKeys = this._updateNodesKeysArray(SELECTED);
},
_updateExpansion: function _updateExpansion(key) {
if (this.options.recursiveExpansion) {
key ? this._updateOneBranch(key) : this._setParentExpansion();
}
this._expandedNodesKeys = this._updateNodesKeysArray(EXPANDED);
},
_updateNodesKeysArray: function _updateNodesKeysArray(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 _getDataBySelectionMode() {
return this.options.multipleSelection ? this.getData() : this.getFullData();
},
_isNodeVisible: function _isNodeVisible(node) {
return node.internalFields.item.visible !== false;
},
_getByKey: function _getByKey(data, key) {
return data === this._dataStructure ? this.options.dataConverter._getByKey(key) : this.options.dataConverter.getByKey(data, key);
},
_setChildrenSelection: function _setChildrenSelection() {
var that = this;
each(this._dataStructure, function (_, node) {
if (!node.internalFields.childrenKeys.length) {
return;
}
var isSelected = node.internalFields.selected;
isSelected === true && that._toggleChildrenSelection(node, isSelected);
});
},
_setParentSelection: function _setParentSelection() {
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 _setParentExpansion() {
var that = this;
each(this._dataStructure, function (_, node) {
if (!node.internalFields.expanded) {
return;
}
that._updateOneBranch(node.internalFields.key);
});
},
_updateOneBranch: function _updateOneBranch(key) {
var that = this,
node = this.getNodeByKey(key);
that._iterateParents(node, function (parent) {
that._setFieldState(parent, EXPANDED, true);
});
},
_iterateChildren: function _iterateChildren(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 _iterateParents(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 _calculateSelectedState(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 = childNode.internalFields.item.visible === false,
childState = childNode.internalFields.selected;
if (isChildInvisible) {
invisibleItemsCount++;
continue;
}
if (childState) {
selectedItemsCount++;
} else if (childState === undefined) {
selectedItemsCount += 0.5;
}
}
if (selectedItemsCount) {
result = selectedItemsCount === itemsCount - invisibleItemsCount ? true : undefined;
}
return result;
},
_toggleChildrenSelection: function _toggleChildrenSelection(node, state) {
var that = this;
this._iterateChildren(node, true, function (child) {
if (that._isNodeVisible(child)) {
that._setFieldState(child, SELECTED, state);
}
});
},
_setFieldState: function _setFieldState(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 _markChildren(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 _removeNode(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 _addNode(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 _updateFields() {
this.options.dataConverter.updateChildrenKeys();
this._updateSelection();
this._updateExpansion();
},
getSelectedNodesKeys: function getSelectedNodesKeys() {
return this._selectedNodesKeys;
},
getExpandedNodesKeys: function getExpandedNodesKeys() {
return this._expandedNodesKeys;
},
getData: function getData() {
return this._dataStructure;
},
getFullData: function getFullData() {
return this._initialDataStructure;
},
getNodeByItem: function getNodeByItem(item) {
var result = null;
each(this._dataStructure, function (_, node) {
if (node.internalFields.item === item) {
result = node;
return false;
}
});
return result;
},
getNodesByItems: function getNodesByItems(items) {
var that = this,
nodes = [];
each(items, function (_, item) {
var node = that.getNodeByItem(item);
node && nodes.push(node);
});
return nodes;
},
getNodeByKey: function getNodeByKey(key, data) {
return this._getByKey(data || this._getDataBySelectionMode(), key);
},
getTreeNodes: function getTreeNodes() {
return this.options.dataConverter.convertToPublicNodes(this.getRootNodes());
},
getItemsCount: function getItemsCount() {
return this.options.dataConverter.getItemsCount();
},
getVisibleItemsCount: function getVisibleItemsCount() {
return this.options.dataConverter.getVisibleItemsCount();
},
getPublicNode: function getPublicNode(node) {
return node.internalFields.publicNode;
},
getRootNodes: function getRootNodes() {
return this.getChildrenNodes(this.options.rootValue);
},
getChildrenNodes: function getChildrenNodes(parentKey) {
return query(this._dataStructure).filter(["internalFields.parentKey", parentKey]).toArray();
},
getIndexByKey: function getIndexByKey(key) {
return this.options.dataConverter.getIndexByKey(key);
},
addItem: function addItem(item) {
this._addNode(item);
this._updateFields();
},
removeItem: function removeItem(key) {
this._removeNode(key);
this._updateFields();
},
toggleSelection: function toggleSelection(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 _isSingleModeUnselect(selectionState) {
return !this.options.multipleSelection && !selectionState;
},
toggleNodeDisabledState: function toggleNodeDisabledState(key, state) {
var node = this.getNodeByKey(key);
this._setFieldState(node, DISABLED, state);
},
toggleSelectAll: function toggleSelectAll(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 isAllSelected() {
if (this.getSelectedNodesKeys().length) {
return this.getSelectedNodesKeys().length === this.getVisibleItemsCount() ? true : undefined;
} else {
return false;
}
},
toggleExpansion: function toggleExpansion(key, state) {
var node = this.getNodeByKey(key);
this._setFieldState(node, EXPANDED, state);
if (state) {
this._updateExpansion(key);
}
this._expandedNodesKeys = this._updateNodesKeysArray(EXPANDED);
},
isFiltered: function isFiltered(item) {
return !this.options.searchValue.length || !!this._filterDataStructure(this.options.searchValue, [item]).length;
},
_createCriteria: function _createCriteria(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 _filterDataStructure(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 search(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;