UNPKG

jiku-ui

Version:

A Component Library for Vue.js.

284 lines (227 loc) 6.5 kB
import objectAssign from 'heiner-ui/src/utils/merge'; import { markNodeData, NODE_KEY } from './util'; import { arrayFindIndex } from 'heiner-ui/src/utils/util'; const getPropertyFromData = function(node, prop) { const props = node.store.props; const data = node.data || {}; const config = props[prop]; if (typeof config === 'function') { return config(data, node); } else if (typeof config === 'string') { return data[config]; } else if (typeof config === 'undefined') { const dataProp = data[prop]; return dataProp === undefined ? '' : dataProp; } }; let nodeIdSeed = 0; export default class Node { constructor(options) { this.id = nodeIdSeed++; this.text = null; this.data = null; this.expanded = false; this.parent = null; this.isCurrent = false; this.isLastChild = false; for (let name in options) { if (options.hasOwnProperty(name)) { this[name] = options[name]; } } // internal this.level = 0; this.childNodes = []; if (this.parent) { this.level = this.parent.level + 1; } const store = this.store; if (!store) { throw new Error('[Node]store is required!'); } store.registerNode(this); if (this.data) { this.setData(this.data); if (store.defaultExpandAll) { this.expanded = true; } } if (!Array.isArray(this.data)) { markNodeData(this, this.data); } if (!this.data) return; const key = store.key; if (key && store.currentNodeKey !== undefined && this.key === store.currentNodeKey) { store.currentNode = this; store.currentNode.isCurrent = true; } this.updateLeafState(); this.updateLastChildState(); } setData(data) { if (!Array.isArray(data)) { markNodeData(this, data); } this.data = data; this.childNodes = []; let children; if (this.level === 0 && this.data instanceof Array) { children = this.data; } else { children = getPropertyFromData(this, 'children') || []; } for (let i = 0, j = children.length; i < j; i++) { this.insertChild({ data: children[i] }); } } get label() { return getPropertyFromData(this, 'label'); } get key() { const nodeKey = this.store.key; if (this.data) return this.data[nodeKey]; return null; } remove() { const parent = this.parent; if (parent) { parent.removeChild(this); } } insertChild(child, index, batch) { if (!child) throw new Error('insertChild error: child is required.'); if (!(child instanceof Node)) { if (!batch) { const children = this.getChildren(true); if (children.indexOf(child.data) === -1) { if (typeof index === 'undefined' || index < 0) { children.push(child.data); } else { children.splice(index, 0, child.data); } } } objectAssign(child, { parent: this, store: this.store }); child = new Node(child); } child.level = this.level + 1; if (typeof index === 'undefined' || index < 0) { this.childNodes.push(child); } else { this.childNodes.splice(index, 0, child); } this.updateLeafState(); this.updateLastChildState(); } removeChild(child) { const children = this.getChildren() || []; const dataIndex = children.indexOf(child.data); if (dataIndex > -1) { children.splice(dataIndex, 1); } const index = this.childNodes.indexOf(child); if (index > -1) { this.store && this.store.deregisterNode(child); child.parent = null; this.childNodes.splice(index, 1); } this.updateLeafState(); this.updateLastChildState(); } removeChildByData(data) { let targetNode = null; for (let i = 0; i < this.childNodes.length; i++) { if (this.childNodes[i].data === data) { targetNode = this.childNodes[i]; break; } } if (targetNode) { this.removeChild(targetNode); } } expand(callback) { const done = () => { let parent = this.parent; while (parent.level > 0) { parent.expanded = true; parent = parent.parent; } this.expanded = true; if (callback) callback(); }; done(); } doCreateChildren(array, defaultProps = {}) { array.forEach((item) => { this.insertChild(objectAssign({ data: item }, defaultProps), undefined, true); }); } collapse() { this.expanded = false; } updateLeafState() { const childNodes = this.childNodes; this.isLeaf = !childNodes || childNodes.length === 0; } updateLastChildState() { if (!this.store.showBranch) return; const parentChildren = this.getParentChildren(); const isLastChild = parentChildren[parentChildren.length - 1] === this.data; this.isLastChild = isLastChild; } getChildren(forceInit = false) { // this is data if (this.level === 0) return this.data; const data = this.data; if (!data) return null; const props = this.store.props; let children = 'children'; if (props) { children = props.children || 'children'; } if (data[children] === undefined) { data[children] = null; } if (forceInit && !data[children]) { data[children] = []; } return data[children]; } getParentChildren() { const parent = this.parent; if (!parent) return []; if (this.level === 1) return parent.data; const props = this.store.props; let children = 'children'; if (props) { children = props.children || 'children'; } return parent.data[children] || []; } updateChildren() { const newData = this.getChildren() || []; const oldData = this.childNodes.map((node) => node.data); const newDataMap = {}; const newNodes = []; newData.forEach((item, index) => { const key = item[NODE_KEY]; const isNodeExists = !!key && arrayFindIndex(oldData, data => data[NODE_KEY] === key) >= 0; if (isNodeExists) { newDataMap[key] = { index, data: item }; } else { newNodes.push({ index, data: item }); } }); oldData.forEach((item) => { if (!newDataMap[item[NODE_KEY]]) this.removeChildByData(item); }); newNodes.forEach(({ index, data }) => { this.insertChild({ data }, index); }); this.updateLeafState(); this.updateLastChildState(); } }