UNPKG

element-ui

Version:

A Component Library for Vue.js.

167 lines (137 loc) 4.12 kB
import { isEqual, capitalize } from 'element-ui/src/utils/util'; import { isDef } from 'element-ui/src/utils/shared'; let uid = 0; export default class Node { constructor(data, config, parentNode) { this.data = data; this.config = config; this.parent = parentNode || null; this.level = !this.parent ? 1 : this.parent.level + 1; this.uid = uid++; this.initState(); this.initChildren(); } initState() { const { value: valueKey, label: labelKey } = this.config; this.value = this.data[valueKey]; this.label = this.data[labelKey]; this.pathNodes = this.calculatePathNodes(); this.path = this.pathNodes.map(node => node.value); this.pathLabels = this.pathNodes.map(node => node.label); // lazy load this.loading = false; this.loaded = false; } initChildren() { const { config } = this; const childrenKey = config.children; const childrenData = this.data[childrenKey]; this.hasChildren = Array.isArray(childrenData); this.children = (childrenData || []).map(child => new Node(child, config, this)); } get isDisabled() { const { data, parent, config } = this; const disabledKey = config.disabled; const { checkStrictly } = config; return data[disabledKey] || !checkStrictly && parent && parent.isDisabled; } get isLeaf() { const { data, loaded, hasChildren, children } = this; const { lazy, leaf: leafKey } = this.config; if (lazy) { const isLeaf = isDef(data[leafKey]) ? data[leafKey] : (loaded ? !children.length : false); this.hasChildren = !isLeaf; return isLeaf; } return !hasChildren; } calculatePathNodes() { const nodes = [this]; let parent = this.parent; while (parent) { nodes.unshift(parent); parent = parent.parent; } return nodes; } getPath() { return this.path; } getValue() { return this.value; } getValueByOption() { return this.config.emitPath ? this.getPath() : this.getValue(); } getText(allLevels, separator) { return allLevels ? this.pathLabels.join(separator) : this.label; } isSameNode(checkedValue) { const value = this.getValueByOption(); return this.config.multiple && Array.isArray(checkedValue) ? checkedValue.some(val => isEqual(val, value)) : isEqual(checkedValue, value); } broadcast(event, ...args) { const handlerName = `onParent${capitalize(event)}`; this.children.forEach(child => { if (child) { // bottom up child.broadcast(event, ...args); child[handlerName] && child[handlerName](...args); } }); } emit(event, ...args) { const { parent } = this; const handlerName = `onChild${capitalize(event)}`; if (parent) { parent[handlerName] && parent[handlerName](...args); parent.emit(event, ...args); } } onParentCheck(checked) { if (!this.isDisabled) { this.setCheckState(checked); } } onChildCheck() { const { children } = this; const validChildren = children.filter(child => !child.isDisabled); const checked = validChildren.length ? validChildren.every(child => child.checked) : false; this.setCheckState(checked); } setCheckState(checked) { const totalNum = this.children.length; const checkedNum = this.children.reduce((c, p) => { const num = p.checked ? 1 : (p.indeterminate ? 0.5 : 0); return c + num; }, 0); this.checked = checked; this.indeterminate = checkedNum !== totalNum && checkedNum > 0; } syncCheckState(checkedValue) { const value = this.getValueByOption(); const checked = this.isSameNode(checkedValue, value); this.doCheck(checked); } doCheck(checked) { if (this.checked !== checked) { if (this.config.checkStrictly) { this.checked = checked; } else { // bottom up to unify the calculation of the indeterminate state this.broadcast('check', checked); this.setCheckState(checked); this.emit('check'); } } } }