import { Component, Input, ElementRef, Output, EventEmitter, OnInit, OnChanges } from '@angular/core'; import { RdComponent } from '../../base/rdComponent'; export type TreePlugins = "search" | "checkbox" | "contextmenu" | "dnd"; export interface ITreeItem { id: string; text: string; global: boolean; parents: string; icon: string; a_attr: { href: string, title: string }, children: Array; } export enum ContextMenuOperationTypes { Create = "Create", Remove = "Remove", Rename = "Rename", Default = "Default" } export interface ContextMenuItem { label: string; action?: Function; icon?: string; // className or path (./) submenu?: Array; type: ContextMenuOperationTypes; } @Component({ selector: 'rd-tree', template: `
` }) export class RdTree extends RdComponent implements OnInit, OnChanges { constructor(private element: ElementRef) { super(); } @Input("rd-data") data: Array; @Input("rd-select-node") nodeID: number | string; @Input("rd-nodes") nodes; @Input("rd-search-text") searchText: string; @Input("rd-plugins") extraPlugins: Array = []; @Input("rd-context-menu") contextMenu: Array = []; @Output("rd-open") openEvent: EventEmitter = new EventEmitter(); @Output("rd-selected") selectEvent: EventEmitter = new EventEmitter(); @Output("rd-menu-event") menuEvent: EventEmitter = new EventEmitter(); container: any; instance: any; lastOpenedNode: any; plugins = ["types"]; ngOnInit() { this.plugins = [...this.plugins, ...this.extraPlugins]; this.container = this.jQuery(this.element.nativeElement).find("#tree"); this.container.jstree({ "core": { "themes": { "responsive": false }, "data": this.data, "check_callback": true }, "types": { "default": { "icon": "fas fa-folder m--font-warning icon-lg" }, "file": { "icon": "fas fa-file m--font-info icon-lg" } }, "plugins": this.plugins, 'animation': true, "contextmenu": { "items": ($node) => { return this.setContextMenu(this.contextMenu, $node) } } }); this.instance = this.container.jstree(true); if (this.plugins.includes("checkbox")) { this.container.on('changed.jstree', function (e, data) { let nodeList = data.instance.get_selected(true); let outputList = nodeList.map((item) => { return { id: item.id, text: item.text, global: item.original.IsGlobal, parents: item.parents, node: data.node.original } }); this.selectEvent.emit(outputList); }.bind(this)); } else { this.container.on('select_node.jstree', function (e, data) { this.selectEvent.emit({ id: data.node.id, text: data.node.text, global: data.node.original.IsGlobal, parents: data.node.parents, node: data.node.original }); }.bind(this)); } this.container.on('open_node.jstree', function (e, data) { this.lastOpenedNode = data.node; this.openEvent.emit(data.node); }.bind(this)); } ngOnChanges(changes) { if (!this.container) return; if (changes.data) this.refresh(); if (changes.nodeID) this.container.jstree("select_node", this.nodeID); if (changes.nodes) this.createNodes(this.nodes); if (changes.searchText) { this.instance.search(this.searchText ? this.searchText : ""); } } createNodes(nodes) { this.lastOpenedNode.children = []; for (let node of nodes) { this.container.jstree().create_node(this.lastOpenedNode.id, node, "last"); } } public refresh() { this.instance.settings.core.data = this.data; this.instance.refresh(); } setContextMenu(contextMenu: Array, node) { let contextItems = {}; for (let item of contextMenu) { if (item.submenu) contextItems[item.label] = { label: item.label, submenu: this.setContextMenu(item.submenu, node) }; else { contextItems[item.label] = { "label": item.label, "action": (obj) => { switch (item.type) { case ContextMenuOperationTypes.Create: node = this.instance.create_node(node); this.instance.edit(node, null, (newNode) => { this.menuEvent.emit({ type: item.type, node: node, newNode: newNode }); }); break; case ContextMenuOperationTypes.Remove: this.instance.delete_node(node); this.menuEvent.emit({ type: item.type, node: node }); break; case ContextMenuOperationTypes.Rename: this.instance.edit(node, null, () => { this.menuEvent.emit({ type: item.type, node: node }); }); break; default: this.menuEvent.emit({ type: item.type, node: node }); } } } } } return contextItems; } }