You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
419 lines
9.7 KiB
419 lines
9.7 KiB
import Node from './node'; |
|
import { |
|
getNodeKey, |
|
getPropertyFromData |
|
} from '../tool/util'; |
|
|
|
export default class TreeStore { |
|
constructor(options) { |
|
this.ready = false; |
|
this.currentNode = null; |
|
this.currentNodeKey = null; |
|
|
|
Object.assign(this, options); |
|
|
|
if (!this.key) { |
|
throw new Error('[Tree] nodeKey is required'); |
|
} |
|
|
|
this.nodesMap = {}; |
|
this.root = new Node({ |
|
data: this.data, |
|
store: this |
|
}); |
|
|
|
if (this.lazy && this.load) { |
|
const loadFn = this.load; |
|
loadFn(this.root, (data) => { |
|
this.root.doCreateChildren(data); |
|
this._initDefaultCheckedNodes(); |
|
this.ready = true; |
|
}); |
|
} else { |
|
this._initDefaultCheckedNodes(); |
|
this.ready = true; |
|
} |
|
} |
|
|
|
filter(value, data) { |
|
const filterNodeMethod = this.filterNodeMethod; |
|
const lazy = this.lazy; |
|
const _self = this; |
|
const traverse = function(node) { |
|
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(node.childNodesId); |
|
|
|
childNodes.forEach((child) => { |
|
if (data && typeof data === 'object') { |
|
let nodePath = _self.getNodePath(child.data); |
|
if (!nodePath.some(pathItem => pathItem[_self.key] === data[_self.key])) { |
|
child.visible = false; |
|
traverse(child); |
|
return; |
|
} |
|
} |
|
|
|
if (_self.childVisibleForFilterNode) { |
|
let parent = child.getParent(child.parentId); |
|
child.visible = filterNodeMethod.call(child, value, child.data, child) || (parent && parent.visible); |
|
} else { |
|
child.visible = filterNodeMethod.call(child, value, child.data, child); |
|
} |
|
|
|
traverse(child); |
|
}); |
|
|
|
if (!node.visible && childNodes.length) { |
|
let allHidden = true; |
|
allHidden = !childNodes.some(child => child.visible); |
|
|
|
if (node.root) { |
|
node.root.visible = allHidden === false; |
|
} else { |
|
node.visible = allHidden === false; |
|
} |
|
} |
|
|
|
if (!value) return; |
|
|
|
if (node.visible && !node.isLeaf && !lazy) node.expand(); |
|
}; |
|
|
|
traverse(this); |
|
} |
|
|
|
setData(newVal) { |
|
const instanceChanged = newVal !== this.root.data; |
|
if (instanceChanged) { |
|
this.root.setData(newVal); |
|
this._initDefaultCheckedNodes(); |
|
} else { |
|
this.root.updateChildren(); |
|
} |
|
} |
|
|
|
getNode(data) { |
|
if (data instanceof Node) return data; |
|
const key = typeof data !== 'object' ? data : getNodeKey(this.key, data); |
|
if (!key) return null; |
|
return this.nodesMap[key] || null; |
|
} |
|
|
|
insertBefore(data, refData) { |
|
const refNode = this.getNode(refData); |
|
let parent = refNode.getParent(refNode.parentId); |
|
parent.insertBefore({ |
|
data |
|
}, refNode); |
|
} |
|
|
|
insertAfter(data, refData) { |
|
const refNode = this.getNode(refData); |
|
let parent = refNode.getParent(refNode.parentId); |
|
parent.insertAfter({ |
|
data |
|
}, refNode); |
|
} |
|
|
|
remove(data) { |
|
const node = this.getNode(data); |
|
|
|
if (node && node.parentId !== null) { |
|
let parent = node.getParent(node.parentId); |
|
if (node === this.currentNode) { |
|
this.currentNode = null; |
|
} |
|
parent.removeChild(node); |
|
} |
|
} |
|
|
|
append(data, parentData) { |
|
const parentNode = parentData ? this.getNode(parentData) : this.root; |
|
|
|
if (parentNode) { |
|
parentNode.insertChild({ |
|
data |
|
}); |
|
} |
|
} |
|
|
|
_initDefaultCheckedNodes() { |
|
const defaultCheckedKeys = this.defaultCheckedKeys || []; |
|
const nodesMap = this.nodesMap; |
|
let checkedKeyfromData = []; |
|
let totalCheckedKeys = [] |
|
|
|
for (let key in nodesMap) { |
|
let checked = getPropertyFromData(nodesMap[key], 'checked') || false; |
|
checked && checkedKeyfromData.push(key); |
|
} |
|
|
|
totalCheckedKeys = Array.from(new Set([...defaultCheckedKeys, ...checkedKeyfromData])); |
|
totalCheckedKeys.forEach((checkedKey) => { |
|
const node = nodesMap[checkedKey]; |
|
|
|
if (node) { |
|
node.setChecked(true, !this.checkStrictly); |
|
} |
|
}); |
|
} |
|
|
|
_initDefaultCheckedNode(node) { |
|
const defaultCheckedKeys = this.defaultCheckedKeys || []; |
|
|
|
if (defaultCheckedKeys.indexOf(node.key) !== -1) { |
|
node.setChecked(true, !this.checkStrictly); |
|
} |
|
} |
|
|
|
toggleExpendAll(isExpandAll) { |
|
const allNodes = this._getAllNodes(); |
|
|
|
allNodes.forEach(item => { |
|
const node = this.getNode(item.key); |
|
|
|
if (node) isExpandAll ? node.expand() : node.collapse(); |
|
}); |
|
} |
|
|
|
setCheckAll(isCkeckAll) { |
|
const allNodes = this._getAllNodes(); |
|
|
|
allNodes.forEach(item => { |
|
item.setChecked(isCkeckAll, false); |
|
}); |
|
} |
|
|
|
setDefaultCheckedKey(newVal) { |
|
if (newVal !== this.defaultCheckedKeys) { |
|
this.defaultCheckedKeys = newVal; |
|
this._initDefaultCheckedNodes(); |
|
} |
|
} |
|
|
|
registerNode(node) { |
|
|
|
const key = this.key; |
|
if (!key || !node || !node.data) return; |
|
|
|
const nodeKey = node.key; |
|
if (nodeKey !== undefined) this.nodesMap[node.key] = node; |
|
} |
|
|
|
deregisterNode(node) { |
|
const key = this.key; |
|
if (!key || !node || !node.data) return; |
|
|
|
let childNodes = node.getChildNodes(node.childNodesId); |
|
childNodes.forEach(child => { |
|
this.deregisterNode(child); |
|
}); |
|
|
|
delete this.nodesMap[node.key]; |
|
} |
|
|
|
getNodePath(data) { |
|
if (!this.key) throw new Error('[Tree] nodeKey is required in getNodePath'); |
|
const node = this.getNode(data); |
|
if (!node) return []; |
|
|
|
const path = [node.data]; |
|
let parent = node.getParent(node.parentId); |
|
while (parent && parent !== this.root) { |
|
path.push(parent.data); |
|
parent = parent.getParent(parent.parentId); |
|
} |
|
return path.reverse(); |
|
} |
|
|
|
getCheckedNodes(leafOnly = false, includeHalfChecked = false) { |
|
const checkedNodes = []; |
|
const traverse = function(node) { |
|
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(node.childNodesId); |
|
|
|
childNodes.forEach((child) => { |
|
if ((child.checked || (includeHalfChecked && child.indeterminate)) && (!leafOnly || (leafOnly && child.isLeaf))) { |
|
checkedNodes.push(child.data); |
|
} |
|
|
|
traverse(child); |
|
}); |
|
}; |
|
|
|
traverse(this); |
|
|
|
return checkedNodes; |
|
} |
|
|
|
getCheckedKeys(leafOnly = false, includeHalfChecked = false) { |
|
return this.getCheckedNodes(leafOnly, includeHalfChecked).map((data) => (data || {})[this.key]); |
|
} |
|
|
|
getHalfCheckedNodes() { |
|
const nodes = []; |
|
const traverse = function(node) { |
|
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(node.childNodesId); |
|
|
|
childNodes.forEach((child) => { |
|
if (child.indeterminate) { |
|
nodes.push(child.data); |
|
} |
|
|
|
traverse(child); |
|
}); |
|
}; |
|
|
|
traverse(this); |
|
|
|
return nodes; |
|
} |
|
|
|
getHalfCheckedKeys() { |
|
return this.getHalfCheckedNodes().map((data) => (data || {})[this.key]); |
|
} |
|
|
|
_getAllNodes() { |
|
const allNodes = []; |
|
const nodesMap = this.nodesMap; |
|
for (let nodeKey in nodesMap) { |
|
if (nodesMap.hasOwnProperty(nodeKey)) { |
|
allNodes.push(nodesMap[nodeKey]); |
|
} |
|
} |
|
|
|
return allNodes; |
|
} |
|
|
|
updateChildren(key, data) { |
|
const node = this.nodesMap[key]; |
|
if (!node) return; |
|
const childNodes = node.getChildNodes(node.childNodesId); |
|
for (let i = childNodes.length - 1; i >= 0; i--) { |
|
const child = childNodes[i]; |
|
this.remove(child.data); |
|
} |
|
for (let i = 0, j = data.length; i < j; i++) { |
|
const child = data[i]; |
|
this.append(child, node.data); |
|
} |
|
} |
|
|
|
_setCheckedKeys(key, leafOnly = false, checkedKeys) { |
|
const allNodes = this._getAllNodes().sort((a, b) => b.level - a.level); |
|
const cache = Object.create(null); |
|
const keys = Object.keys(checkedKeys); |
|
allNodes.forEach(node => node.setChecked(false, false)); |
|
for (let i = 0, j = allNodes.length; i < j; i++) { |
|
const node = allNodes[i]; |
|
let nodeKey = node.data[key]; |
|
|
|
if (typeof nodeKey === 'undefined') continue; |
|
|
|
nodeKey = nodeKey.toString(); |
|
let checked = keys.indexOf(nodeKey) > -1; |
|
if (!checked) { |
|
if (node.checked && !cache[nodeKey]) { |
|
node.setChecked(false, false); |
|
} |
|
continue; |
|
} |
|
|
|
let parent = node.getParent(node.parentId); |
|
while (parent && parent.level > 0) { |
|
cache[parent.data[key]] = true; |
|
parent = parent.getParent(parent.parentId); |
|
} |
|
|
|
if (node.isLeaf || this.checkStrictly) { |
|
node.setChecked(true, false); |
|
continue; |
|
} |
|
node.setChecked(true, true); |
|
|
|
if (leafOnly) { |
|
node.setChecked(false, false); |
|
const traverse = function(node) { |
|
const childNodes = node.getChildNodes(node.childNodesId); |
|
childNodes.forEach((child) => { |
|
if (!child.isLeaf) { |
|
child.setChecked(false, false); |
|
} |
|
traverse(child); |
|
}); |
|
}; |
|
traverse(node); |
|
} |
|
} |
|
} |
|
|
|
setCheckedNodes(array, leafOnly = false) { |
|
const key = this.key; |
|
const checkedKeys = {}; |
|
array.forEach((item) => { |
|
checkedKeys[(item || {})[key]] = true; |
|
}); |
|
|
|
this._setCheckedKeys(key, leafOnly, checkedKeys); |
|
} |
|
|
|
setCheckedKeys(keys, leafOnly = false) { |
|
this.defaultCheckedKeys = keys; |
|
const key = this.key; |
|
const checkedKeys = {}; |
|
keys.forEach((key) => { |
|
checkedKeys[key] = true; |
|
}); |
|
|
|
this._setCheckedKeys(key, leafOnly, checkedKeys); |
|
} |
|
|
|
setDefaultExpandedKeys(keys) { |
|
keys = keys || []; |
|
this.defaultExpandedKeys = keys; |
|
|
|
keys.forEach((key) => { |
|
const node = this.getNode(key); |
|
if (node) node.expand(null, this.autoExpandParent); |
|
}); |
|
} |
|
|
|
setChecked(data, checked, deep) { |
|
const node = this.getNode(data); |
|
|
|
if (node) { |
|
node.setChecked(!!checked, deep); |
|
} |
|
} |
|
|
|
getCurrentNode() { |
|
return this.currentNode; |
|
} |
|
|
|
setCurrentNode(currentNode) { |
|
const prevCurrentNode = this.currentNode; |
|
if (prevCurrentNode) { |
|
prevCurrentNode.isCurrent = false; |
|
} |
|
this.currentNode = currentNode; |
|
this.currentNode.isCurrent = true; |
|
|
|
this.expandCurrentNodeParent && this.currentNode.expand(null, true) |
|
} |
|
|
|
setUserCurrentNode(node) { |
|
const key = node[this.key]; |
|
const currNode = this.nodesMap[key]; |
|
this.setCurrentNode(currNode); |
|
} |
|
|
|
setCurrentNodeKey(key) { |
|
if (key === null || key === undefined) { |
|
this.currentNode && (this.currentNode.isCurrent = false); |
|
this.currentNode = null; |
|
return; |
|
} |
|
const node = this.getNode(key); |
|
if (node) { |
|
this.setCurrentNode(node); |
|
} |
|
} |
|
};
|
|
|