UNPKG

v-tree-vue

Version:

A light-weight library for management of hierachical content. Most solutions I found did not offer the depth of flexibility I needed with the tree. I decided to solve my problem and also give back to the Vue community. Feel free to log issues, I will jump

107 lines (81 loc) 3.7 kB
import { TreeViewItem, CheckedState, SelectionMode, TreeViewViewModel } from "@/businessLogic/contracts/types"; import { eventHub } from "@/businessLogic/eventHub/explorerEventPublisher"; import { cascadeStateToDescendants, flattenNodes } from "../hierachyTraversal/hierachyTraversal"; let flattenedNodesLookUp: { [id: string]: TreeViewItem } = {}; export const notifyParentOfSelection = (item: TreeViewItem): void => { const parentId = item.parentId as string; if (!parentId) return; const parent = flattenedNodesLookUp[parentId]; // This solution is inefficient and can be optimised with a single O(n) solution. // But we can keep this simple and readable for now. :) const isEveryChildChecked = parent.children?.every(child => child.checkedStatus == 'True'); const isAnyIntermediate = parent.children?.some(child => child.checkedStatus == 'Indeterminate'); const hasAnUncheckedChild = parent.children?.some(child => child.checkedStatus == 'False'); const hasACheckedChild = parent.children?.some(child => child.checkedStatus == 'True'); if (isEveryChildChecked) { parent.checkedStatus = 'True'; } else if (isAnyIntermediate || (hasAnUncheckedChild && hasACheckedChild)) { parent.checkedStatus = 'Indeterminate'; } else { parent.checkedStatus = 'False'; } notifyParentOfSelection(parent); } export const TreeViewModel: TreeViewViewModel = { loadNodes(nodes: TreeViewItem[]): void { flattenedNodesLookUp = flattenNodes(nodes); }, getNodes(): { [id: string]: TreeViewItem } { return flattenedNodesLookUp }, checkedStatusChanged(item: TreeViewItem): void { if (item.checkedStatus == 'True') { eventHub.onItemChecked(item); } else { eventHub.onItemUnChecked(item); } cascadeStateToDescendants(item, item.checkedStatus as CheckedState); notifyParentOfSelection(item); }, removeTreeViewItem(id: string): boolean { const itemToBeRemoved = flattenedNodesLookUp[id]; if (!itemToBeRemoved) return false; const parentId = itemToBeRemoved.parentId; if (parentId) this.removeFromParentNode(itemToBeRemoved); if (!itemToBeRemoved.children) return false; while (itemToBeRemoved.children.length > 0) { this.removeChildNodes(itemToBeRemoved.children[0]) } delete flattenedNodesLookUp[id]; return true }, removeFromParentNode(itemToRemove: TreeViewItem): void { const parentId = itemToRemove.parentId; if (!parentId) return; const parent = flattenedNodesLookUp[parentId]; const index = parent.children?.findIndex(node => node.id == itemToRemove.id) if (index! > -1) parent.children?.splice(index!, 1) }, removeChildNodes(node: TreeViewItem) { if (!node.children) return; while (node.children.length > 0) { this.removeChildNodes(node.children[0]) } this.removeFromParentNode(node) delete flattenedNodesLookUp[node.id]; }, addTreeViewItem(TreeViewItem: TreeViewItem): void { flattenedNodesLookUp[TreeViewItem.id] = TreeViewItem; if(!TreeViewItem.parentId) return; const parent = flattenedNodesLookUp[TreeViewItem.parentId] parent.children?.push(TreeViewItem); }, setSelectionMode(mode: SelectionMode): void { eventHub.setSelectionMode(mode); }, selectedItems: eventHub.selectedItems }