/** * Created by Zhong on 2018/3/21. */ const pmTree = { createNew: function (setting, arrData) { function sortTreeItems(tree) { const addItems = function (items) { for (const item of items) { tree.items.push(item); addItems(item.children); } }; tree.items.splice(0, tree.items.length); addItems(tree._root.children); } var Node = (function () { function Node(tree, data, nodeState = null) { this.parent = null; this.nextSibling = null; this.children = []; this.tree = tree; this.data = data; this.setting = tree.setting; this.expanded = true; this.row = null; this.expandBtn = null; if (nodeState) { for (const attr in nodeState) { this[attr] = nodeState[attr]; } } } Node.prototype.firstChild = function() { return (this.children.length === 0) ? null : this.children[0]; }; Node.prototype.lastChild = function () { return (this.children.length === 0) ? null : this.children[this.children.length - 1]; }; Node.prototype.deepestRow = function () { return (this.children.length === 0) ? this.row : this.lastChild().deepestRow(); }; Node.prototype.depth = function () { return this.parent ? this.parent.depth() + 1 : 0; }; Node.prototype.isFirst = function () { if (this.parent) { return this.parent.children.indexOf(this) === 0 ? true : false; } else { return this.tree._root.children.indexOf(this) === 0 ? true : false; } }; Node.prototype.isLast = function () { if (this.parent) { return this.parent.children.indexOf(this) === this.parent.children.length - 1 ? true : false; } else { return this.tree._root.children.indexOf(this) === this.tree._root.children.length - 1 ? true : false; } }; Node.prototype.setExpanded = function (expanded) { var setNodesVisible = function (nodes, visible) { nodes.forEach(function (node) { node.visible = visible; setNodesVisible(node.children, visible && node.expanded); }) }; this.expanded = expanded; setNodesVisible(this.children, expanded); }; Node.prototype.posterityCount = function () { var iCount = 0; if (this.children.length !== 0) { iCount += this.children.length; this.children.forEach(function (child) { iCount += child.posterityCount(); }); } return iCount; }; Node.prototype.addChild = function (child, childNext) { if (childNext){ this.children.push(child); } else { if (this.childIndex(childNext) > -1){ this.children.splice(this.childIndex(childNext) - 1, 0, child); } else { this.children.push(child); } } return child; }; Node.prototype.childIndex = function (child) { return this.children.indexOf(child); }; Node.prototype.depth = function () { return this.parent ? this.parent.depth() + 1 : 0; }; Node.prototype.domId = function () { return this.data ? this.tree.domId + '_' + this.data[this.setting.tree.id] : ''; }; Node.prototype.expand = function (bool) { this.expanded = bool; _view._refreshTreeBtn(this); if (this.expanded) { _view._showNodes(this.children); } else { _view._hideNodes(this.children); } }; Node.prototype.getCollapseParents = function () { const rst = []; let parent = this.parent; while (parent && parent.data) { if (!parent.expanded) { rst.push(parent); } parent = parent.parent; } return rst; }; Node.prototype.serialNo = function () { return this.tree.items.indexOf(this); }; Node.prototype.preSibling = function () { var iIndex = this.parent.childIndex(this); if (iIndex === -1){ return null; } else { return iIndex > 0 ? this.parent.children[iIndex-1] : null; } }; Node.prototype.setParent = function (parent) { if (parent && this.parent !== parent) { this.parent = parent; this.data[this.setting.tree.pid] = this.pid(); } }; Node.prototype.setNextSibling = function (nextSibling) { if (this.nextSibling !== nextSibling) { this.nextSibling = nextSibling; this.data[this.setting.tree.nid] = this.nid(); } } Node.prototype.id = function () { return this.data ? this.data[this.setting.tree.id] : -1; }; Node.prototype.pid = function () { return this.parent ? this.parent.id() : -1; }; Node.prototype.nid = function () { return this.nextSibling ? this.nextSibling.id() : -1; }; Node.prototype.propertyJoin = function (dataName) { return this.parent ? this.parent.propertyJoin(dataName) + ';' + this.data[dataName] : this.data[dataName]; }; Node.prototype.getAllChildren = function () { let childrenList = []; getChildren(this); function getChildren(node) { for(let c of node.children){ childrenList.push(c); getChildren(c) } } return childrenList; }; return Node; })(); var Tree = (function () { function Tree(setting) { this._root = new Node(this); this.items = []; this.selected = null; this.setting = setting; var _maxNodeId = 0; this.newNodeId = function (id) { if (arguments.length > 0){ _maxNodeId = (id > _maxNodeId) ? id : _maxNodeId; } else { _maxNodeId += 1; return _maxNodeId; } }; this.maxNodeId = function (id){ if (arguments.length > 0) { _maxNodeId = Math.max(id, _maxNodeId); } else { return _maxNodeId; } } }; Tree.prototype.firstNode = function (){ return this._root.firstChild(); }; Tree.prototype.traverseDF = function(callback){ var recurse = function (node) { var i; if (node !== this._root) { callback(node); } for (i = 0; i < node.children.length; i++){ recurse(node.children[i]); } } recurse(this._root); }; Tree.prototype.findNode = function (id){ var treenode = null, callback = function (node) { if (node.data && node.data[node.setting.tree.id] === id){ treenode = node; } }; this.traverseDF.call(this, callback); return treenode; }; Tree.prototype.findNodeByNid = function (nid) { let treenode = null, callback = function (node) { if(node.data && node.data[node.setting.tree.nid] === nid){ treenode = node; } }; this.traverseDF.call(this, callback); return treenode; }; Tree.prototype.removeNode = function (node) { var iIndex; if (node) { iIndex = node.parent.childIndex(node); if (iIndex > 0) { node.parent.children[iIndex - 1].setNextSibling(node.nextSibling); } node.parent.children.splice(iIndex, 1); } sortTreeItems(this); this.sourceData = this.items.reduce((acc, cur) => { acc.push(cur.data); return acc; }, []); }; Tree.prototype.loadData = function (arrData) { this.sourceData = arrData; let i, that = this; let nodesIndex = {}; function getPreNode(id){ for(let index in nodesIndex){ let node = nodesIndex[index]; if(node['data'][node.setting.tree.nid] === id){ return node; } } return null; } function loadNode (data, setting) {//mark var node = nodesIndex[data[setting.tree.id]] || null, parent = nodesIndex[data[setting.tree.pid]] || that._root, next = nodesIndex[data[setting.tree.nid]] || null, pre = getPreNode(data[setting.tree.id]) || null, tempData; if (!node) { node = new Node(that, data); } that.maxNodeId(node.id()); if(parent.childIndex(node) === -1){ if (!pre) { parent.children.unshift(node); } else if(pre && parent.childIndex(pre) !== -1){ parent.children.splice(parent.childIndex(pre) + 1, 0, node); } else if(next && parent.childIndex(next) !== -1){ parent.children.splice(parent.childIndex(next), 0, node); } else { parent.children.push(node); } } if(pre && parent.childIndex(pre) === -1){ parent.children.splice(parent.childIndex(node), 0, pre); } if(next && parent.childIndex(next) === -1){ parent.children.splice(parent.childIndex(node) + 1, 0, next); } if(pre && parent.childIndex(pre) !== parent.childIndex(node) - 1){ parent.children.splice(parent.childIndex(pre), 1); parent.children.splice(parent.childIndex(node), 0, pre); } if(next && parent.childIndex(next) !== parent.childIndex(node) + 1){ parent.children.splice(parent.childIndex(next), 1); parent.children.splice(parent.childIndex(node) + 1, 0, next); } node.parent = parent; node.nextSibling = next; } //建立索引 for(let data of arrData){ nodesIndex[data.ID] = new Node(that, data); } for (i = 0; i < arrData.length; i++){ loadNode(arrData[i], this.setting); } //set items sortTreeItems(this); }; Tree.prototype.addNodeData = function (data, parent, nextSibling, nodeState = null) { this.sourceData.push(data); var node = null; var pNode = parent ? parent : this._root; if (!nextSibling || (nextSibling.parent === pNode && pNode.childIndex(nextSibling) > -1)) { node = new Node(this, data, nodeState); this.maxNodeId(data[this.setting.tree.id]); this.move(node, pNode, nextSibling); } return node; }; Tree.prototype.move = function(node, parent, nextSibling) { var iIndex = -1, pre; if (parent && (!nextSibling || (nextSibling.parent === parent && parent.childIndex(nextSibling) > -1))) { if (node) { if (node.parent) { iIndex = node.parent.childIndex(node); if (iIndex > 0) { node.parent.children[iIndex - 1].setNextSibling(node.nextSibling); } node.parent.children.splice(iIndex, 1); } if (nextSibling) { iIndex = parent.childIndex(nextSibling); if (iIndex > 0){ pre = parent.children[iIndex - 1]; pre.setNextSibling(node); //parent.children.splice(iIndex - 1, 0, node); parent.children.splice(iIndex, 0, node); } else { parent.children.splice(0, 0, node); } } else { if (parent.children.length > 0){ pre = parent.lastChild(); pre.setNextSibling(node); } parent.children.push(node); } node.setParent(parent); node.setNextSibling(nextSibling); //sort items sortTreeItems(this); } } else { this.e.throw('Error: information of moving node has mistake.'); } }; Tree.prototype.insert = function (sheet, items, node) { const rIdx = items.indexOf(node); const cIdx = sheet.getActiveColumnIndex(); sheet.addRows(rIdx, 1); //set selection selected sheet.setSelection(rIdx, cIdx, 1, 1); this.selected = node; sheet.getCell(rIdx, 0).cellType(this); }; Tree.prototype.check = function (_root) { if (this.sourceData.length !== this.items.length) { const data = this.sourceData.filter(item => { const findData = this.items.find(node => node.data.ID === item.ID); return !findData; }); console.log('丢失数据:'); console.log(data); return false; } return isValid(_root.children); function isValid(nodes) { for (let node of nodes) { if (node.data.ParentID !== -1 && (!node.parent || node.parent.data.ID !== node.data.ParentID)) { console.log(`${node.serialNo() + 1}:${node.data.name} parent对应错误`); return false; } if (node.data.ParentID === -1 && node.parent && node.parent !== _root) { console.log(`${node.serialNo() + 1}:${node.data.name} 不应有parent`); return false; } if (node.data.NextSiblingID !== -1 && (!node.nextSibling || node.nextSibling.data.ID !== node.data.NextSiblingID)) { console.log(`${node.serialNo() + 1}:${node.data.name} next对应错误`); return false; } if (node.data.NextSiblingID === -1 && node.nextSibling) { console.log(`${node.serialNo() + 1}:${node.data.name} 不应有next`); return false; } let parent = node.parent, nodeIdx = parent.children.indexOf(node), nextIdx = parent.children.indexOf(node.nextSibling); if (nodeIdx !== -1 && nextIdx !== -1 && nodeIdx > nextIdx) { console.log(`${node.serialNo() + 1}:${node.data.name} node索引大于next索引`); return false; } // nextSibling跟parent children的下一节点对应不上 if (nodeIdx !== -1 && (nodeIdx === parent.children.length - 1 && nextIdx !== -1) || (nodeIdx !== parent.children.length - 1 && nodeIdx + 1 !== nextIdx)) { console.log(`${node.serialNo() + 1}:${node.data.name} nextSibling与树显示的下一节点对应不上`); return false; } if (node.nextSibling && node.parent !== node.nextSibling.parent) { console.log(`${node.serialNo() + 1}:${node.data.name} 与兄弟节点 ${node.nextSibling.serialNo() + 1}:${node.nextSibling.data.name} 父节点不同`); return false; } if (node.children.length) { let v = isValid(node.children); if (!v) { return false; } } } return true; } }; Tree.prototype.getExpState = function (nodes) { let sessionExpanded = []; function getStat(items){ for(let item of items){ sessionExpanded.push(item.expanded ? 1 : 0); } } getStat(nodes); let expState = sessionExpanded.join(''); return expState; }; //节点根据展开收起列表'010101'展开收起 Tree.prototype.setExpandedByState = function (nodes, expState) { let expStateArr = expState.split(''); for(let i = 0; i < nodes.length; i++){ let expanded = expStateArr[i] == 1 ? true : false; if(nodes[i].expanded === expanded){ continue; } nodes[i].setExpanded(expanded); } }; Tree.prototype.setNodesExpanded = function (nodes, sheet) { TREE_SHEET_HELPER.massOperationSheet(sheet, () => { nodes.forEach(node => { node.setExpanded(true); const index = node.serialNo(); const count = node.posterityCount(); for (let i = 0; i < count; i++) { const row = index + i; const child = this.items[row + 1]; sheet.setRowVisible(row + 1, child.visible); } }); }); }; return Tree; })() let tree = new Tree(setting); tree.loadData(arrData); return tree; } };