UNPKG

@cisstech/nge

Version:

NG Essentials is a collection of libraries for Angular developers.

859 lines 115 kB
import { FlatTreeControl } from '@angular/cdk/tree'; import { ChangeDetectionStrategy, Component, ContentChild, HostListener, Input, } from '@angular/core'; import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; import { BehaviorSubject } from 'rxjs'; import { CURRENT_VISIBLE_TREES } from './internal'; import { TreeNodeDirective } from './tree-node.directive'; import { TreeFilter, } from './tree.model'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/forms"; import * as i3 from "./autofocus.directive"; export class TreeComponent { get treeHeight() { return this.adapter?.itemHeight?.toString() || '100%'; } constructor(elementRef, changeDetectorRef) { this.elementRef = elementRef; this.changeDetectorRef = changeDetectorRef; this.nodes = []; this.DATA_TREE_NODE_ID = 'data-tree-node-id'; this.nodesIndex = new Map(); this.parentsIndex = new Map(); this.hiddenNodes = new Map(); this.selectedNodes = new Map(); this.isEmpty = false; this.isShiftKeyPressed = false; this.editing = { text: '', node: undefined }; this.visibleNodes = new BehaviorSubject([]); this.filter = new TreeFilter(); this.controler = new FlatTreeControl((node) => node.level, (node) => node.expandable, { trackBy: (node) => node, }); this.flattener = new MatTreeFlattener((node, level) => this.transformer(node, level), (node) => node.level, (node) => node.expandable, (node) => this.children(node)); this.dataSource = new MatTreeFlatDataSource(this.controler, this.flattener); } ngOnInit() { if (!this.adapter.id?.trim()) { throw new Error('@Input() adapter.id is required !'); } CURRENT_VISIBLE_TREES.set(this.adapter.id, this); } ngOnChanges() { if (!this.adapter) { throw new Error('@Input() adapter is required !'); } const requires = ['id', 'idProvider', 'nameProvider', 'isExpandable', 'childrenProvider']; for (const key of requires) { const value = this.adapter[key]; if (!value || (typeof value === 'string' && value.trim() === '')) { throw new Error(`@Input() adapter.${key} is required !`); } } this.adapter.itemHeight = this.adapter.itemHeight || 32; this.adapter.treeHeight = this.adapter.treeHeight || '100%'; this.adapter.keepStateOnChangeNodes = this.adapter.keepStateOnChangeNodes ?? true; let state; if (this.adapter.keepStateOnChangeNodes) { state = this.saveState(); } this.buildIndexes(); if (state) { this.restoreState(state); } else { this.unselectAll(false); this.render(); } } ngOnDestroy() { if (this.adapter?.id) { CURRENT_VISIBLE_TREES.delete(this.adapter.id); } } //#region API selections() { return Array.from(this.selectedNodes.values()).map((e) => e.data); } focusedNode() { return this.activeNode?.data; } isFocused(node) { if (node == null) { throw new ReferenceError('Argument "node" is required.'); } if (!this.activeNode) { return false; } return this.findHolder(node)?.id === this.activeNode.id; } isExpanded(node) { if (node == null) { throw new ReferenceError('Argument "node" is required.'); } const holder = this.findHolder(node); if (!holder?.expandable) { return false; } return this.controler.isExpanded(holder); } isSelected(node) { if (node == null) { throw new ReferenceError('Argument "node" is required.'); } const holder = this.findHolder(node); if (!holder) { return false; } return this.selectedNodes.has(holder.id); } focus(node, render = true) { const holder = this.findHolder(node); if (holder) { if (this.activeNode) { this.unselect(this.activeNode, false); } this.activeNode = holder; this.select(node, false); this.expandAncestors(holder); if (render) { this.render(); } this.scrollInto(holder); } } unfocus() { this.activeNode = undefined; this.changeDetectorRef.detectChanges(); } expand(node, render = true) { if (!node) { return; } const holder = this.findHolder(node); if (!holder) { return; } if (holder.expandable && !this.controler.isExpanded(holder)) { this.controler.expand(holder); this.expandAncestors(holder); if (render) { this.render(); } } } expandAll(render = true) { this.controler.dataNodes?.forEach((node) => { this.controler.expand(node); }); // this.controler.expandAll(); // https://github.com/vmware/clarity/issues/4850 if (render) { this.render(); } } collapse(node, render = true) { if (!node) { return; } const holder = this.findHolder(node); if (!holder) { return; } if (holder.expandable && this.controler.isExpanded(holder)) { this.controler.collapse(holder); if (this.adapter.onDidCollapse) { this.adapter.onDidCollapse(holder.data); } if (render) { this.render(); } } } collapseAll(render = true) { this.controler.collapseAll(); if (render) { this.render(); } } toggle(node, render = true) { if (!node) { return; } const holder = this.findHolder(node); if (holder?.expandable) { if (this.controler.isExpanded(holder)) { this.collapse(node, render); } else { this.expand(node, render); } } } startEdition(node, creation) { if (!this.adapter.onDidEditName) return; if (!node) { throw new ReferenceError('Argument "node" is required.'); } const holder = this.findHolder(node); if (holder) { this.unselectAll(false); this.editing.node = holder.data; this.editing.text = creation ? '' : holder.name; this.editing.creation = creation; holder.renaming = !creation; holder.creating = creation; if (holder.expandable && !this.isExpanded(holder)) { this.expand(node); } } this.changeDetectorRef.detectChanges(); } endEdition() { const holder = this.findHolder(this.editing.node); if (holder) { holder.renaming = false; holder.creating = false; } this.editing = { text: '' }; this.changeDetectorRef.detectChanges(); } search(filter) { if (!this.filter.term) { this.stateBeforeSearching = this.saveState(); } this.filter.term = (filter.term || '').trim(); if (!this.filter.term) { if (this.stateBeforeSearching) { this.restoreState(this.stateBeforeSearching); this.stateBeforeSearching = undefined; } else { this.hiddenNodes.clear(); this.render(); } return; } const pattern = this.buildSearchPattern(); if (pattern) { this.activeNode = undefined; this.hiddenNodes.clear(); this.selectedNodes.clear(); this.collapseAll(false); const p = pattern; const matches = new Set(); const nodes = this.controler.dataNodes || []; const n = nodes.length - 1; for (let i = n; i >= 0; i--) { const node = nodes[i]; if (matches.has(node.id)) continue; if (node.name.toLowerCase().match(p)) { matches.add(node.id); this.iterateAncestors(node, (e) => { this.controler.expand(e); matches.add(e.id); }); } else { this.hiddenNodes.set(node.id, node); } } this.render(); } else { this.changeDetectorRef.detectChanges(); } } saveState() { const { term } = this.filter; const dataNodes = this.controler.dataNodes || []; const state = { filter: { term }, active: this.activeNode ? this.activeNode.id : '', expandedNodes: dataNodes .filter((e) => { return this.controler.isExpanded(e); }) .map((e) => e.id), }; return state; } restoreState(state) { state = state || { active: '', filter: new TreeFilter(), expandedNodes: [], }; state.active = state.active || ''; state.filter = state.filter || new TreeFilter(); state.expandedNodes = state.expandedNodes || []; this.hiddenNodes.clear(); this.selectedNodes.clear(); this.collapseAll(false); const { active, filter, expandedNodes } = state; if (filter.term) { this.search(filter); } else { expandedNodes.forEach((node) => this.expand(node, false)); this.render(); } if (active) { const activeNode = this.findHolder(active); if (activeNode) { this.focus(activeNode); } } } //#endregion //#region CALLED FROM TEMPLATE _onEdit(event) { if (this.adapter.onDidEditName) { event.stopPropagation(); const { node, text, creation } = this.editing; if (!node) { throw new Error('There is no focused node.'); } const isBlur = event instanceof FocusEvent && event.type === 'blur'; const isEnter = event instanceof KeyboardEvent && event.key === 'Enter'; const isEscape = event instanceof KeyboardEvent && event.key === 'Escape'; if (isEscape) { event.preventDefault(); this.endEdition(); } else if (isBlur || isEnter) { event.preventDefault(); const name = text?.trim() || ''; try { if (name) { this.adapter.onDidEditName({ node: node, text: name, creation, }); } } finally { this.focus(node); this.endEdition(); } } } } _clearFilter() { this.search({ term: '' }); } _isRenaming(node) { if (node == null) { throw new ReferenceError('Argument "node" is required.'); } if (!this.editing?.node) { return false; } return !this.editing.creation && this.findHolder(node)?.id === this.adapter.idProvider(this.editing.node); } _isCreating(node) { if (node == null) { throw new ReferenceError('Argument "node" is required.'); } if (!this.editing?.node) { return false; } return !!this.editing.creation && this.findHolder(node)?.id === this.adapter.idProvider(this.editing.node); } _trackById(_, e) { return e.id; } //#endregion //#region EVENTS keyup() { this.isShiftKeyPressed = false; } keydown($event) { this.isShiftKeyPressed = $event.shiftKey; if (this.isTreeContainsEvent($event)) { this.onKeyDown($event); } } mousedown($event) { this.changeDetectorRef.detach(); if (this.isTreeContainsEvent($event)) { this.changeDetectorRef.reattach(); this.onMouseDown($event); } } contextmenu($event) { this.changeDetectorRef.detach(); if (this.isTreeContainsEvent($event)) { this.changeDetectorRef.reattach(); this.onContextMenu($event); } } onKeyDown(event) { if (!this.activeNode && !this.isEmpty && !this.selectedNodes.size) { this.focus(this.controler.dataNodes[0]); } const element = this.activeNode ? this.domNode(this.activeNode) : undefined; if (element && this.activeNode) { switch (event.key) { case 'ArrowUp': event.preventDefault(); event.stopPropagation(); this.navigate(element, 'up'); break; case 'ArrowDown': event.preventDefault(); event.stopPropagation(); this.navigate(element, 'down'); break; case 'ArrowLeft': if (!this.isShiftKeyPressed) { event.preventDefault(); event.stopPropagation(); this.collapse(this.activeNode, true); } break; case 'ArrowRight': if (!this.isShiftKeyPressed) { event.preventDefault(); event.stopPropagation(); this.expand(this.activeNode, true); } break; default: this.triggerKeyboardEvent(event); this.triggerFilterEvent(event); break; } } else { this.triggerFilterEvent(event); } if (event.key === 'Backspace') { // prevent browser to navigate back if Backspace is pressed event.preventDefault(); } } onMouseDown(event) { const node = this.findHolderFromEvent(event); if (!node) { return; } if (this.isShiftKeyPressed && this.activeNode) { const domStart = this.domNode(this.activeNode); if (!domStart) { this.select(node); return; } const domEnd = this.domNode(node); if (!domEnd) { return; } // select all nodes between the focused and the target node. this.unselectAll(false); let cursor = domStart; const y2 = domEnd.getClientRects().item(0).top; const y1 = domStart.getClientRects().item(0).top; if (y1 < y2) { // traverse down do { this.select(cursor, false); cursor = cursor.nextElementSibling; } while (cursor && !cursor.isEqualNode(domEnd)); } else if (y1 > y2) { // traverse up do { this.select(cursor, false); cursor = cursor.previousElementSibling; } while (cursor && !cursor.isEqualNode(domEnd)); } this.select(domEnd, false); this.focus(node, true); } else { this.unselectAll(false); this.toggle(node, false); this.focus(node, true); const { actions } = this.adapter; if (actions?.mouse?.click) { actions.mouse.click({ node: node.data, event: event, }); } } } onContextMenu(e) { e.preventDefault(); e.stopPropagation(); const node = this.findHolderFromEvent(e); if (node) { if (!this.isSelected(node)) { this.unselectAll(false); } this.focus(node, true); } const { actions } = this.adapter; if (actions?.mouse?.rightClick) { actions.mouse.rightClick({ node: node?.data, event: e, }); } } isTreeContainsEvent(event) { return this.elementRef.nativeElement.contains(event.target); } triggerFilterEvent(e) { if (e.defaultPrevented || !this.adapter.enableKeyboardFiltering) { return; } // prevent browser to navigate back if Backspace is pressed e.preventDefault(); e.stopPropagation(); const { term } = this.filter; switch (e.key) { case 'Backspace': if (term) { this.search({ term: term.slice(0, -1) }); } break; case ' ': case 'Tab': break; default: if (e.key.length === 1) { this.search({ term: term + e.key }); } break; } } triggerKeyboardEvent(event) { if (!this.activeNode) { return; } const { actions } = this.adapter; if (actions) { const { keys } = actions; if (keys) { const action = keys[event.key]; if (action) { action({ event: event, node: this.activeNode.data, }); } } } } //#endregion //#region PRIVATE render() { const nodes = []; const dataNodes = this.controler.dataNodes || []; const expandedNodes = new Set(this.controler.expansionModel.selected.map((node) => node.id)); this.isEmpty = true; dataNodes.forEach((node) => { this.isEmpty = false; if (this.hiddenNodes.has(node.id)) { return; } node.focused = this.isFocused(node); node.expanded = this.isExpanded(node); node.renaming = this._isRenaming(node); node.creating = this._isCreating(node); node.selected = this.isSelected(node); // root nodes are always visible if (node.level === 0) { nodes.push(node); return; } let parent = this.findParent(node); while (parent != null) { // hide a node if any of its ancestors is not expanded if (!expandedNodes.has(parent.id)) { return; } if (parent.level === 0) { break; } parent = this.findParent(parent); } nodes.push(node); }); this.visibleNodes.next(nodes); this.changeDetectorRef.detectChanges(); } buildIndexes() { this.nodesIndex.clear(); this.parentsIndex.clear(); this.dataSource.data = this.nodes; this.controler.dataNodes?.forEach((node) => { this.nodesIndex.set(node.id, node); }); } buildSearchPattern() { let pattern; try { if (this.filter.term) { const escape = (text) => { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); }; pattern = new RegExp(`(${escape(this.filter.term)})`, 'g'); } } catch (error) { console.error(error); } return pattern; } /** * Gets the dom element associated to the given node. * @param e A node. */ domNode(e) { const node = this.findHolder(e); if (!node) { throw new Error(e + ' is not a registered node'); } return document.querySelector(`[${this.DATA_TREE_NODE_ID}="${node.id}"]`); } /** * Adds the given node to the selected nodes. * @param node The node to select. */ select(node, detectChanges = true) { const holder = this.findHolder(node); if (!holder) { return; } this.selectedNodes.set(holder.id, holder); if (detectChanges) { this.changeDetectorRef.detectChanges(); } } /** * Removes the given node to the selected nodes. * @param node The node to unselect. */ unselect(node, detectChanges = true) { const holder = this.findHolder(node); if (!holder) { return; } this.selectedNodes.delete(holder.id); if (holder.id === this.activeNode?.id) { this.activeNode = undefined; } if (detectChanges) { this.changeDetectorRef.detectChanges(); } } /** * Clears the selected nodes. */ unselectAll(detectChanges = true) { this.activeNode = undefined; this.selectedNodes.clear(); if (detectChanges) { this.changeDetectorRef.detectChanges(); } } /** * Expands the ancestors of the given node. * @param node A node reference. */ expandAncestors(node) { this.iterateAncestors(node, (e) => { if (e.expandable && !this.controler.isExpanded(e)) { this.controler.expand(e); if (this.adapter.onDidExpand) { this.adapter.onDidExpand(e.data); } } }); } /** * Call the given `action` for the ancestors of the given node. * @param node A node reference. * @param action A function to call for each ancestor. */ iterateAncestors(node, action) { const recursive = (e) => { action(e); const p = this.findParent(e); if (p && p.level >= 0) { recursive(p); } }; const parent = this.findParent(node); if (parent) { recursive(parent); } } /** * Moves the scrollbar to the given node. * @param node The node to show. */ scrollInto(node) { const holder = this.findHolder(node); if (holder) { const index = this.visibleNodes.value.indexOf(holder); if (index == -1) { return; } this.domNode(node)?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } } /** * Focus the node before of after `currEl` depending on the given `direction`. * @param currEl Current element * @param direction Navigation direction. */ navigate(currEl, direction) { this.unselectAll(); const currNode = this.findHolderFromElement(currEl); if (!currNode) { return; } const prevEl = currEl.previousElementSibling; const nextEl = currEl.nextElementSibling; const targEl = direction === 'up' ? prevEl : nextEl; if (!targEl) { return; } const targNode = this.findHolderFromElement(targEl); if (!targNode) { this.focus(currNode); return; } const prevNode = prevEl ? this.findHolderFromElement(prevEl) : undefined; if (prevNode && this.isSelected(prevNode) && targEl.isEqualNode(prevEl)) { this.unselect(currNode); } const nextNode = nextEl ? this.findHolderFromElement(nextEl) : undefined; if (nextNode && this.isSelected(nextNode) && targEl.isEqualNode(nextEl)) { this.unselect(currNode); } this.focus(targNode); } findParent(node) { const holder = this.findHolder(node); if (!holder) { return; } const parentId = this.parentsIndex.get(holder.id); if (parentId) { return this.nodesIndex.get(parentId); } return undefined; } findHolderFromId(id) { const { dataNodes } = this.controler; if (!dataNodes) { return undefined; } return dataNodes.find((n) => n.id === id); } findHolderFromData(data) { const { dataNodes } = this.controler; if (!dataNodes) { return undefined; } return this.nodesIndex.get(this.adapter.idProvider(data)); } findHolderFromEvent(event) { const { dataNodes } = this.controler; if (!dataNodes) { return undefined; } const dataId = this.DATA_TREE_NODE_ID; const fn = (target) => { if (!target) { return undefined; } const targetId = target.getAttribute(dataId); return targetId ? this.nodesIndex.get(targetId) : fn(target.parentElement); }; return fn(event.target); } findHolderFromElement(element) { const { dataNodes } = this.controler; if (!dataNodes) { return undefined; } const id = element.getAttribute(this.DATA_TREE_NODE_ID); if (!id) { return undefined; } return this.nodesIndex.get(id); } findHolder(node) { if (!node) { return undefined; } if (!this.controler.dataNodes) { return undefined; } if (typeof node === 'string') { return this.findHolderFromId(node); } if (node instanceof Element) { return this.findHolderFromElement(node); } // instanceof ITreeNodeHolder<T> if ('data' in node) { return node; } // instance of T return this.findHolderFromData(node); } children(node) { const children = this.adapter.childrenProvider(node) || []; const parentId = this.adapter.idProvider(node); children.forEach((child) => { this.parentsIndex.set(this.adapter.idProvider(child), parentId); }); return children; } transformer(node, level) { const expandable = this.adapter.isExpandable(node); return { id: this.adapter.idProvider(node), data: node, name: this.adapter.nameProvider(node), level: level, padding: level * 12 + 'px', tooltip: this.adapter.tooltipProvider?.(node), expandable, }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: TreeComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.1", type: TreeComponent, selector: "ui-tree", inputs: { nodes: "nodes", adapter: "adapter" }, host: { listeners: { "document:keyup": "keyup()", "document:keydown": "keydown($event)", "document:click": "mousedown($event)", "document:contextmenu": "contextmenu($event)" } }, queries: [{ propertyName: "nodeDirective", first: true, predicate: TreeNodeDirective, descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"filter.term\">\n <div class=\"tree-filter\" title=\"Filter\">\n <span class=\"tree-filter__label\">{{ filter.term }}</span>\n <div class=\"tree-filter__commands\">\n <span class=\"command-clear\" role=\"button\" title=\"Clear\" (click)=\"_clearFilter()\">&times;</span>\n </div>\n </div>\n</ng-container>\n\n<div\n tabindex=\"0\"\n class=\"tree-component\"\n [class.editing]=\"editing.node != null\"\n [style.height]=\"treeHeight\">\n <ng-container *ngFor=\"let node of visibleNodes|async; trackBy: _trackById;\">\n <!-- RENAMING -->\n <ng-container *ngIf=\"node.renaming; else: nodeTemplate\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n\n <!-- NODE -->\n <ng-template #nodeTemplate>\n <div\n class=\"tree-node tree-node--level-{{ node.level }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\"\n [ngClass]=\"{\n focused: node.focused,\n selected: node.selected,\n expanded: node.expanded\n }\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"nodeDirective.templateRef; context: { $implicit: node }\" />\n </div>\n </div>\n </ng-template>\n\n <!-- CREATING -->\n <ng-container *ngIf=\"node.creating\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #inputTemplate>\n <span class=\"tree-input\">\n <input\n autofocus\n type=\"text\"\n placeholder=\"Press Enter to create ESC to cancel...\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n [(ngModel)]=\"editing.text\"\n (keydown)=\"_onEdit($event)\"\n (blur)=\"_onEdit($event)\" />\n </span>\n</ng-template>\n", styles: [":host{position:relative;--tree-selection-color: #bae7ff}.tree-component{height:100%;background:transparent}.tree-component:hover{outline:none}.tree-component:hover .tree-node.focused,.tree-component:hover .tree-node.selected{background-color:var(--tree-selection-color)}.tree-component.editing .opaque{opacity:1!important}.tree-component.editing .tree-node{opacity:.4}.tree-node:hover,.tree-node.focused,.tree-node.selected{background-color:#4242420a}.tree-node,.tree-node__content{cursor:pointer;position:relative;width:100%;display:flex;overflow:hidden;align-items:center;box-sizing:border-box}.tree-node__content{padding:0 12px}.tree-input{display:flex;align-items:center;width:calc(100% - 4px);margin-right:4px}.tree-input input{width:100%;margin:0 0 0 8px;padding:.1rem .3rem;font-size:.8rem;line-height:1.5;background-clip:padding-box;border:1px solid #ced4da;border-radius:.15rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.tree-input input:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.tree-filter{background-color:#efc1ad;display:flex;align-items:center;position:absolute;border-radius:2px;padding:0 4px;max-width:calc(100% - 10px);text-overflow:ellipsis;overflow:hidden;text-align:right;box-sizing:border-box;cursor:all-scroll;font-size:13px;line-height:18px;height:20px;z-index:1;right:0;outline:rgba(0,0,0,0) solid 4px;transition:width .5s}.tree-filter:hover .tree-filter__commands{display:flex}.tree-filter .tree-filter__commands{display:none;display:flex;align-items:center}.tree-filter .tree-filter__commands span{cursor:pointer;font-size:18px;margin-left:4px}.tree-filter .command-filter{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.AutofocusDirective, selector: "input[autofocus]" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: TreeComponent, decorators: [{ type: Component, args: [{ selector: 'ui-tree', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"filter.term\">\n <div class=\"tree-filter\" title=\"Filter\">\n <span class=\"tree-filter__label\">{{ filter.term }}</span>\n <div class=\"tree-filter__commands\">\n <span class=\"command-clear\" role=\"button\" title=\"Clear\" (click)=\"_clearFilter()\">&times;</span>\n </div>\n </div>\n</ng-container>\n\n<div\n tabindex=\"0\"\n class=\"tree-component\"\n [class.editing]=\"editing.node != null\"\n [style.height]=\"treeHeight\">\n <ng-container *ngFor=\"let node of visibleNodes|async; trackBy: _trackById;\">\n <!-- RENAMING -->\n <ng-container *ngIf=\"node.renaming; else: nodeTemplate\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n\n <!-- NODE -->\n <ng-template #nodeTemplate>\n <div\n class=\"tree-node tree-node--level-{{ node.level }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\"\n [ngClass]=\"{\n focused: node.focused,\n selected: node.selected,\n expanded: node.expanded\n }\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"nodeDirective.templateRef; context: { $implicit: node }\" />\n </div>\n </div>\n </ng-template>\n\n <!-- CREATING -->\n <ng-container *ngIf=\"node.creating\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #inputTemplate>\n <span class=\"tree-input\">\n <input\n autofocus\n type=\"text\"\n placeholder=\"Press Enter to create ESC to cancel...\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n [(ngModel)]=\"editing.text\"\n (keydown)=\"_onEdit($event)\"\n (blur)=\"_onEdit($event)\" />\n </span>\n</ng-template>\n", styles: [":host{position:relative;--tree-selection-color: #bae7ff}.tree-component{height:100%;background:transparent}.tree-component:hover{outline:none}.tree-component:hover .tree-node.focused,.tree-component:hover .tree-node.selected{background-color:var(--tree-selection-color)}.tree-component.editing .opaque{opacity:1!important}.tree-component.editing .tree-node{opacity:.4}.tree-node:hover,.tree-node.focused,.tree-node.selected{background-color:#4242420a}.tree-node,.tree-node__content{cursor:pointer;position:relative;width:100%;display:flex;overflow:hidden;align-items:center;box-sizing:border-box}.tree-node__content{padding:0 12px}.tree-input{display:flex;align-items:center;width:calc(100% - 4px);margin-right:4px}.tree-input input{width:100%;margin:0 0 0 8px;padding:.1rem .3rem;font-size:.8rem;line-height:1.5;background-clip:padding-box;border:1px solid #ced4da;border-radius:.15rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.tree-input input:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.tree-filter{background-color:#efc1ad;display:flex;align-items:center;position:absolute;border-radius:2px;padding:0 4px;max-width:calc(100% - 10px);text-overflow:ellipsis;overflow:hidden;text-align:right;box-sizing:border-box;cursor:all-scroll;font-size:13px;line-height:18px;height:20px;z-index:1;right:0;outline:rgba(0,0,0,0) solid 4px;transition:width .5s}.tree-filter:hover .tree-filter__commands{display:flex}.tree-filter .tree-filter__commands{display:none;display:flex;align-items:center}.tree-filter .tree-filter__commands span{cursor:pointer;font-size:18px;margin-left:4px}.tree-filter .command-filter{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}\n"] }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { nodes: [{ type: Input }], adapter: [{ type: Input }], nodeDirective: [{ type: ContentChild, args: [TreeNodeDirective, { static: true }] }], keyup: [{ type: HostListener, args: ['document:keyup'] }], keydown: [{ type: HostListener, args: ['document:keydown', ['$event']] }], mousedown: [{ type: HostListener, args: ['document:click', ['$event']] }], contextmenu: [{ type: HostListener, args: ['document:contextmenu', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ2UvdWkvdHJlZS9zcmMvdHJlZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ2UvdWkvdHJlZS9zcmMvdHJlZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDbkQsT0FBTyxFQUNMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsWUFBWSxFQUVaLFlBQVksRUFDWixLQUFLLEdBSU4sTUFBTSxlQUFlLENBQUE7QUFDdEIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDaEYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLE1BQU0sQ0FBQTtBQUN0QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFDekQsT0FBTyxFQVFMLFVBQVUsR0FDWCxNQUFNLGNBQWMsQ0FBQTs7Ozs7QUFRckIsTUFBTSxPQUFPLGFBQWE7SUE0QnhCLElBQWMsVUFBVTtRQUN0QixPQUFPLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxJQUFJLE1BQU0sQ0FBQTtJQUN2RCxDQUFDO0lBRUQsWUFDbUIsVUFBbUMsRUFDbkMsaUJBQW9DO1FBRHBDLGVBQVUsR0FBVixVQUFVLENBQXlCO1FBQ25DLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFqQzlDLFVBQUssR0FBUSxFQUFFLENBQUE7UUFNUCxzQkFBaUIsR0FBRyxtQkFBbUIsQ0FBQTtRQUt2QyxlQUFVLEdBQUcsSUFBSSxHQUFHLEVBQThCLENBQUE7UUFDbEQsaUJBQVksR0FBRyxJQUFJLEdBQUcs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