UNPKG

es-grid-template

Version:

es-grid-template

217 lines (213 loc) 6.33 kB
import isLeafNode from "../isLeafNode"; import { arrayUtils } from "../others"; class Wrapper { constructor(input) { Object.assign(this, input); } root; children; parent; // @ts-ignore node; detached; checked; exactChecked; parentChecked; anyDescendentsChecked; allChildrenChecked; } export default class TreeDataHelper { opts; // @ts-ignore wrapperMap; // @ts-ignore rootWrapper; constructor(opts) { this.opts = opts; this.initWrapperTree(); } get value() { return this.opts.value; } isDetached = node => { return this.opts.isDetached?.(node) ?? false; }; initWrapperTree() { const valueSet = new Set(this.value); this.rootWrapper = new Wrapper({ root: true, children: [] }); this.wrapperMap = new Map(); const getNodeValue = this.opts.getNodeValue; const { isDetached, wrapperMap } = this; dfs(this.rootWrapper, this.opts.tree, false); // const self = this function dfs(parentWrapper, nodes, inheritParentChecked) { parentWrapper.children ??= []; parentWrapper.allChildrenChecked = true; if (process.env.NODE_ENV !== 'production') { if (nodes.length > 0 && nodes.every(isDetached)) { console.warn('TreeDataHelper detected that some nodes have all of their child nodes in a detached state, which will cause those nodes to become "invalid nodes".', parentWrapper.node); } } for (const node of nodes) { const key = getNodeValue(node); if (wrapperMap.has(key)) { console.warn('Duplicate node value detected:', key); } const detached = isDetached(node); const exactChecked = valueSet.has(key); if (exactChecked && !detached) { parentWrapper.anyDescendentsChecked = true; } const parentChecked = !detached && inheritParentChecked; const checked = exactChecked || parentChecked; const wrapper = new Wrapper({ parent: parentWrapper, node, checked, exactChecked, parentChecked, anyDescendentsChecked: checked, detached }); wrapperMap.set(key, wrapper); parentWrapper.children.push(wrapper); if (!isLeafNode(node)) { wrapper.children = []; dfs(wrapper, node.children, checked); if (wrapper.anyDescendentsChecked && !detached) { parentWrapper.anyDescendentsChecked = true; } if (wrapper.allChildrenChecked) { wrapper.checked = true; for (const child of wrapper.children) { if (!child.detached) { child.parentChecked = true; } } } } if (!wrapper.checked && !detached) { parentWrapper.allChildrenChecked = false; } } } } isIndeterminate(nodeValue) { const wrapper = this.wrapperMap.get(nodeValue); return !wrapper?.checked && !!wrapper?.anyDescendentsChecked; } isChecked(nodeValue) { const wrapper = this.wrapperMap.get(nodeValue); return !!wrapper?.checked; } getValueAfterCheck(nodeValue) { if (this.isChecked(nodeValue)) { return this.getCleanValue(); } const nextValue = arrayUtils.merge(this.value, [nodeValue]); return new TreeDataHelper({ ...this.opts, value: nextValue }).getCleanValue(); } getValueAfterUncheck(nodeValue) { if (!this.isChecked(nodeValue)) { return this.getCleanValue(); } const wrapper = this.wrapperMap.get(nodeValue); const { getNodeValue } = this.opts; const appendArray = getAppendArray(wrapper); const removeSet = getRemoveSet(wrapper); const nextValue = arrayUtils.diff(this.value.concat(appendArray), removeSet); return new TreeDataHelper({ ...this.opts, value: nextValue }).getCleanValue(); function getAppendArray(startWrapper) { const result = []; let current = startWrapper; while (current.parentChecked && !current.detached) { const parent = current.parent; if (!parent) break; for (const sibling of parent.children ?? []) { if (sibling === current || sibling.exactChecked || sibling.detached) { continue; } result.push(getNodeValue(sibling.node)); } current = parent; } return result; } function getRemoveSet(startWrapper) { const result = new Set(); let wrapper1 = startWrapper; while (wrapper1) { result.add(getNodeValue(wrapper1.node)); if (wrapper1.detached || !wrapper1.parentChecked) { break; } wrapper1 = wrapper1.parent; } function dfs(wrappers) { for (const wrapperIt of wrappers) { if (wrapperIt.detached || !wrapperIt.checked) continue; result.add(getNodeValue(wrapperIt.node)); if (!isLeafNode(wrapperIt.node) && wrapperIt.anyDescendentsChecked) { dfs(wrapperIt.children ?? []); } } } dfs(startWrapper.children ?? []); return result; } } getValueAfterToggle(nodeValue) { if (this.isChecked(nodeValue)) { return this.getValueAfterUncheck(nodeValue); } return this.getValueAfterCheck(nodeValue); } getNode(nodeValue) { return this.wrapperMap.get(nodeValue)?.node; } getCleanValue() { const { checkedStrategy, getNodeValue } = this.opts; const result = this.value.filter(nodeValue => { return !this.wrapperMap.has(nodeValue); }); dfs(this.rootWrapper.children ?? []); return result; function dfs(wrappers) { for (const wrapper of wrappers) { if (wrapper.checked) { if (checkedStrategy === 'all') { result.push(getNodeValue(wrapper.node)); } else if (checkedStrategy === 'parent') { if (!wrapper.parentChecked) { result.push(getNodeValue(wrapper.node)); } } else { if (isLeafNode(wrapper.node)) { result.push(getNodeValue(wrapper.node)); } } } if (!isLeafNode(wrapper.node)) { dfs(wrapper.children ?? []); } } } } }