UNPKG

primeng

Version:

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![npm version](https://badge.fury.io/js/primeng.svg)](https://badge.fury.io/js/primeng) [![npm downloads](https://img.shields.io/npm/dm/primeng.sv

1,043 lines (1,042 loc) 102 kB
import * as i0 from '@angular/core'; import { forwardRef, Component, ViewEncapsulation, Inject, Input, EventEmitter, ChangeDetectionStrategy, Optional, Output, ContentChildren, ViewChild, NgModule } from '@angular/core'; import * as i4 from '@angular/cdk/scrolling'; import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i3 from 'primeng/api'; import { TranslationKeys, PrimeTemplate, SharedModule } from 'primeng/api'; import { ObjectUtils } from 'primeng/utils'; import { DomHandler } from 'primeng/dom'; import * as i2 from 'primeng/ripple'; import { RippleModule } from 'primeng/ripple'; class UITreeNode { constructor(tree) { this.tree = tree; } ngOnInit() { this.node.parent = this.parentNode; if (this.parentNode) { this.tree.syncNodeOption(this.node, this.tree.value, 'parent', this.tree.getNodeWithKey(this.parentNode.key, this.tree.value)); } } getIcon() { let icon; if (this.node.icon) icon = this.node.icon; else icon = this.node.expanded && this.node.children && this.node.children.length ? this.node.expandedIcon : this.node.collapsedIcon; return UITreeNode.ICON_CLASS + ' ' + icon; } isLeaf() { return this.tree.isNodeLeaf(this.node); } toggle(event) { if (this.node.expanded) this.collapse(event); else this.expand(event); } expand(event) { this.node.expanded = true; if (this.tree.virtualScroll) { this.tree.updateSerializedValue(); } this.tree.onNodeExpand.emit({ originalEvent: event, node: this.node }); } collapse(event) { this.node.expanded = false; if (this.tree.virtualScroll) { this.tree.updateSerializedValue(); } this.tree.onNodeCollapse.emit({ originalEvent: event, node: this.node }); } onNodeClick(event) { this.tree.onNodeClick(event, this.node); } onNodeKeydown(event) { if (event.which === 13) { this.tree.onNodeClick(event, this.node); } } onNodeTouchEnd() { this.tree.onNodeTouchEnd(); } onNodeRightClick(event) { this.tree.onNodeRightClick(event, this.node); } isSelected() { return this.tree.isSelected(this.node); } onDropPoint(event, position) { event.preventDefault(); let dragNode = this.tree.dragNode; let dragNodeIndex = this.tree.dragNodeIndex; let dragNodeScope = this.tree.dragNodeScope; let isValidDropPointIndex = this.tree.dragNodeTree === this.tree ? (position === 1 || dragNodeIndex !== this.index - 1) : true; if (this.tree.allowDrop(dragNode, this.node, dragNodeScope) && isValidDropPointIndex) { let dropParams = Object.assign({}, this.createDropPointEventMetadata(position)); if (this.tree.validateDrop) { this.tree.onNodeDrop.emit({ originalEvent: event, dragNode: dragNode, dropNode: this.node, index: this.index, accept: () => { this.processPointDrop(dropParams); } }); } else { this.processPointDrop(dropParams); this.tree.onNodeDrop.emit({ originalEvent: event, dragNode: dragNode, dropNode: this.node, index: this.index }); } } this.draghoverPrev = false; this.draghoverNext = false; } processPointDrop(event) { let newNodeList = event.dropNode.parent ? event.dropNode.parent.children : this.tree.value; event.dragNodeSubNodes.splice(event.dragNodeIndex, 1); let dropIndex = this.index; if (event.position < 0) { dropIndex = (event.dragNodeSubNodes === newNodeList) ? ((event.dragNodeIndex > event.index) ? event.index : event.index - 1) : event.index; newNodeList.splice(dropIndex, 0, event.dragNode); } else { dropIndex = newNodeList.length; newNodeList.push(event.dragNode); } this.tree.dragDropService.stopDrag({ node: event.dragNode, subNodes: event.dropNode.parent ? event.dropNode.parent.children : this.tree.value, index: event.dragNodeIndex }); } createDropPointEventMetadata(position) { return { dragNode: this.tree.dragNode, dragNodeIndex: this.tree.dragNodeIndex, dragNodeSubNodes: this.tree.dragNodeSubNodes, dropNode: this.node, index: this.index, position: position }; } onDropPointDragOver(event) { event.dataTransfer.dropEffect = 'move'; event.preventDefault(); } onDropPointDragEnter(event, position) { if (this.tree.allowDrop(this.tree.dragNode, this.node, this.tree.dragNodeScope)) { if (position < 0) this.draghoverPrev = true; else this.draghoverNext = true; } } onDropPointDragLeave(event) { this.draghoverPrev = false; this.draghoverNext = false; } onDragStart(event) { if (this.tree.draggableNodes && this.node.draggable !== false) { event.dataTransfer.setData("text", "data"); this.tree.dragDropService.startDrag({ tree: this, node: this.node, subNodes: this.node.parent ? this.node.parent.children : this.tree.value, index: this.index, scope: this.tree.draggableScope }); } else { event.preventDefault(); } } onDragStop(event) { this.tree.dragDropService.stopDrag({ node: this.node, subNodes: this.node.parent ? this.node.parent.children : this.tree.value, index: this.index }); } onDropNodeDragOver(event) { event.dataTransfer.dropEffect = 'move'; if (this.tree.droppableNodes) { event.preventDefault(); event.stopPropagation(); } } onDropNode(event) { if (this.tree.droppableNodes && this.node.droppable !== false) { let dragNode = this.tree.dragNode; if (this.tree.allowDrop(dragNode, this.node, this.tree.dragNodeScope)) { let dropParams = Object.assign({}, this.createDropNodeEventMetadata()); if (this.tree.validateDrop) { this.tree.onNodeDrop.emit({ originalEvent: event, dragNode: dragNode, dropNode: this.node, index: this.index, accept: () => { this.processNodeDrop(dropParams); } }); } else { this.processNodeDrop(dropParams); this.tree.onNodeDrop.emit({ originalEvent: event, dragNode: dragNode, dropNode: this.node, index: this.index }); } } } event.preventDefault(); event.stopPropagation(); this.draghoverNode = false; } createDropNodeEventMetadata() { return { dragNode: this.tree.dragNode, dragNodeIndex: this.tree.dragNodeIndex, dragNodeSubNodes: this.tree.dragNodeSubNodes, dropNode: this.node }; } processNodeDrop(event) { let dragNodeIndex = event.dragNodeIndex; event.dragNodeSubNodes.splice(dragNodeIndex, 1); if (event.dropNode.children) event.dropNode.children.push(event.dragNode); else event.dropNode.children = [event.dragNode]; this.tree.dragDropService.stopDrag({ node: event.dragNode, subNodes: event.dropNode.parent ? event.dropNode.parent.children : this.tree.value, index: dragNodeIndex }); } onDropNodeDragEnter(event) { if (this.tree.droppableNodes && this.node.droppable !== false && this.tree.allowDrop(this.tree.dragNode, this.node, this.tree.dragNodeScope)) { this.draghoverNode = true; } } onDropNodeDragLeave(event) { if (this.tree.droppableNodes) { let rect = event.currentTarget.getBoundingClientRect(); if (event.x > rect.left + rect.width || event.x < rect.left || event.y >= Math.floor(rect.top + rect.height) || event.y < rect.top) { this.draghoverNode = false; } } } onKeyDown(event) { const nodeElement = event.target.parentElement.parentElement; if (nodeElement.nodeName !== 'P-TREENODE' || (this.tree.contextMenu && this.tree.contextMenu.containerViewChild.nativeElement.style.display === 'block')) { return; } switch (event.which) { //down arrow case 40: const listElement = (this.tree.droppableNodes) ? nodeElement.children[1].children[1] : nodeElement.children[0].children[1]; if (listElement && listElement.children.length > 0) { this.focusNode(listElement.children[0]); } else { const nextNodeElement = nodeElement.nextElementSibling; if (nextNodeElement) { this.focusNode(nextNodeElement); } else { let nextSiblingAncestor = this.findNextSiblingOfAncestor(nodeElement); if (nextSiblingAncestor) { this.focusNode(nextSiblingAncestor); } } } event.preventDefault(); break; //up arrow case 38: if (nodeElement.previousElementSibling) { this.focusNode(this.findLastVisibleDescendant(nodeElement.previousElementSibling)); } else { let parentNodeElement = this.getParentNodeElement(nodeElement); if (parentNodeElement) { this.focusNode(parentNodeElement); } } event.preventDefault(); break; //right arrow case 39: if (!this.node.expanded && !this.tree.isNodeLeaf(this.node)) { this.expand(event); } event.preventDefault(); break; //left arrow case 37: if (this.node.expanded) { this.collapse(event); } else { let parentNodeElement = this.getParentNodeElement(nodeElement); if (parentNodeElement) { this.focusNode(parentNodeElement); } } event.preventDefault(); break; //enter case 13: this.tree.onNodeClick(event, this.node); event.preventDefault(); break; default: //no op break; } } findNextSiblingOfAncestor(nodeElement) { let parentNodeElement = this.getParentNodeElement(nodeElement); if (parentNodeElement) { if (parentNodeElement.nextElementSibling) return parentNodeElement.nextElementSibling; else return this.findNextSiblingOfAncestor(parentNodeElement); } else { return null; } } findLastVisibleDescendant(nodeElement) { const listElement = Array.from(nodeElement.children).find(el => DomHandler.hasClass(el, 'p-treenode')); const childrenListElement = listElement.children[1]; if (childrenListElement && childrenListElement.children.length > 0) { const lastChildElement = childrenListElement.children[childrenListElement.children.length - 1]; return this.findLastVisibleDescendant(lastChildElement); } else { return nodeElement; } } getParentNodeElement(nodeElement) { const parentNodeElement = nodeElement.parentElement.parentElement.parentElement; return parentNodeElement.tagName === 'P-TREENODE' ? parentNodeElement : null; } focusNode(element) { if (this.tree.droppableNodes) element.children[1].children[0].focus(); else element.children[0].children[0].focus(); } } UITreeNode.ICON_CLASS = 'p-treenode-icon '; UITreeNode.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.4", ngImport: i0, type: UITreeNode, deps: [{ token: forwardRef(() => Tree) }], target: i0.ɵɵFactoryTarget.Component }); UITreeNode.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.0.4", type: UITreeNode, selector: "p-treeNode", inputs: { rowNode: "rowNode", node: "node", parentNode: "parentNode", root: "root", index: "index", firstChild: "firstChild", lastChild: "lastChild", level: "level", indentation: "indentation" }, ngImport: i0, template: ` <ng-template [ngIf]="node"> <li *ngIf="tree.droppableNodes" class="p-treenode-droppoint" [ngClass]="{'p-treenode-droppoint-active':draghoverPrev}" (drop)="onDropPoint($event,-1)" (dragover)="onDropPointDragOver($event)" (dragenter)="onDropPointDragEnter($event,-1)" (dragleave)="onDropPointDragLeave($event)"></li> <li *ngIf="!tree.horizontal" [ngClass]="['p-treenode',node.styleClass||'', isLeaf() ? 'p-treenode-leaf': '']"> <div class="p-treenode-content" [style.paddingLeft]="(level * indentation) + 'rem'" (click)="onNodeClick($event)" (contextmenu)="onNodeRightClick($event)" (touchend)="onNodeTouchEnd()" (drop)="onDropNode($event)" (dragover)="onDropNodeDragOver($event)" (dragenter)="onDropNodeDragEnter($event)" (dragleave)="onDropNodeDragLeave($event)" [draggable]="tree.draggableNodes" (dragstart)="onDragStart($event)" (dragend)="onDragStop($event)" [attr.tabindex]="0" [ngClass]="{'p-treenode-selectable':tree.selectionMode && node.selectable !== false,'p-treenode-dragover':draghoverNode, 'p-highlight':isSelected()}" role="treeitem" (keydown)="onKeyDown($event)" [attr.aria-posinset]="this.index + 1" [attr.aria-expanded]="this.node.expanded" [attr.aria-selected]="isSelected()" [attr.aria-label]="node.label"> <button type="button" class="p-tree-toggler p-link" (click)="toggle($event)" pRipple tabindex="-1"> <span class="p-tree-toggler-icon pi pi-fw" [ngClass]="{'pi-chevron-right':!node.expanded,'pi-chevron-down':node.expanded}"></span> </button> <div class="p-checkbox p-component" [ngClass]="{'p-checkbox-disabled': node.selectable === false}" *ngIf="tree.selectionMode == 'checkbox'" [attr.aria-checked]="isSelected()"> <div class="p-checkbox-box" [ngClass]="{'p-highlight': isSelected(), 'p-indeterminate': node.partialSelected}"> <span class="p-checkbox-icon pi" [ngClass]="{'pi-check':isSelected(),'pi-minus':node.partialSelected}"></span> </div> </div> <span [class]="getIcon()" *ngIf="node.icon||node.expandedIcon||node.collapsedIcon"></span> <span class="p-treenode-label"> <span *ngIf="!tree.getTemplateForNode(node)">{{node.label}}</span> <span *ngIf="tree.getTemplateForNode(node)"> <ng-container *ngTemplateOutlet="tree.getTemplateForNode(node); context: {$implicit: node}"></ng-container> </span> </span> </div> <ul class="p-treenode-children" style="display: none;" *ngIf="!tree.virtualScroll && node.children && node.expanded" [style.display]="node.expanded ? 'block' : 'none'" role="group"> <p-treeNode *ngFor="let childNode of node.children;let firstChild=first;let lastChild=last; let index=index; trackBy: tree.trackBy" [node]="childNode" [parentNode]="node" [firstChild]="firstChild" [lastChild]="lastChild" [index]="index" [style.height.px]="tree.virtualNodeHeight" [level]="level + 1"></p-treeNode> </ul> </li> <li *ngIf="tree.droppableNodes&&lastChild" class="p-treenode-droppoint" [ngClass]="{'p-treenode-droppoint-active':draghoverNext}" (drop)="onDropPoint($event,1)" (dragover)="onDropPointDragOver($event)" (dragenter)="onDropPointDragEnter($event,1)" (dragleave)="onDropPointDragLeave($event)"></li> <table *ngIf="tree.horizontal" [class]="node.styleClass"> <tbody> <tr> <td class="p-treenode-connector" *ngIf="!root"> <table class="p-treenode-connector-table"> <tbody> <tr> <td [ngClass]="{'p-treenode-connector-line':!firstChild}"></td> </tr> <tr> <td [ngClass]="{'p-treenode-connector-line':!lastChild}"></td> </tr> </tbody> </table> </td> <td class="p-treenode" [ngClass]="{'p-treenode-collapsed':!node.expanded}"> <div class="p-treenode-content" tabindex="0" [ngClass]="{'p-treenode-selectable':tree.selectionMode,'p-highlight':isSelected()}" (click)="onNodeClick($event)" (contextmenu)="onNodeRightClick($event)" (touchend)="onNodeTouchEnd()" (keydown)="onNodeKeydown($event)"> <span class="p-tree-toggler pi pi-fw" [ngClass]="{'pi-plus':!node.expanded,'pi-minus':node.expanded}" *ngIf="!isLeaf()" (click)="toggle($event)"></span> <span [class]="getIcon()" *ngIf="node.icon||node.expandedIcon||node.collapsedIcon"></span> <span class="p-treenode-label"> <span *ngIf="!tree.getTemplateForNode(node)">{{node.label}}</span> <span *ngIf="tree.getTemplateForNode(node)"> <ng-container *ngTemplateOutlet="tree.getTemplateForNode(node); context: {$implicit: node}"></ng-container> </span> </span> </div> </td> <td class="p-treenode-children-container" *ngIf="node.children && node.expanded" [style.display]="node.expanded ? 'table-cell' : 'none'"> <div class="p-treenode-children"> <p-treeNode *ngFor="let childNode of node.children;let firstChild=first;let lastChild=last; trackBy: tree.trackBy" [node]="childNode" [firstChild]="firstChild" [lastChild]="lastChild"></p-treeNode> </div> </td> </tr> </tbody> </table> </ng-template> `, isInline: true, components: [{ type: UITreeNode, selector: "p-treeNode", inputs: ["rowNode", "node", "parentNode", "root", "index", "firstChild", "lastChild", "level", "indentation"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.Ripple, selector: "[pRipple]" }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], encapsulation: i0.ViewEncapsulation.None }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.4", ngImport: i0, type: UITreeNode, decorators: [{ type: Component, args: [{ selector: 'p-treeNode', template: ` <ng-template [ngIf]="node"> <li *ngIf="tree.droppableNodes" class="p-treenode-droppoint" [ngClass]="{'p-treenode-droppoint-active':draghoverPrev}" (drop)="onDropPoint($event,-1)" (dragover)="onDropPointDragOver($event)" (dragenter)="onDropPointDragEnter($event,-1)" (dragleave)="onDropPointDragLeave($event)"></li> <li *ngIf="!tree.horizontal" [ngClass]="['p-treenode',node.styleClass||'', isLeaf() ? 'p-treenode-leaf': '']"> <div class="p-treenode-content" [style.paddingLeft]="(level * indentation) + 'rem'" (click)="onNodeClick($event)" (contextmenu)="onNodeRightClick($event)" (touchend)="onNodeTouchEnd()" (drop)="onDropNode($event)" (dragover)="onDropNodeDragOver($event)" (dragenter)="onDropNodeDragEnter($event)" (dragleave)="onDropNodeDragLeave($event)" [draggable]="tree.draggableNodes" (dragstart)="onDragStart($event)" (dragend)="onDragStop($event)" [attr.tabindex]="0" [ngClass]="{'p-treenode-selectable':tree.selectionMode && node.selectable !== false,'p-treenode-dragover':draghoverNode, 'p-highlight':isSelected()}" role="treeitem" (keydown)="onKeyDown($event)" [attr.aria-posinset]="this.index + 1" [attr.aria-expanded]="this.node.expanded" [attr.aria-selected]="isSelected()" [attr.aria-label]="node.label"> <button type="button" class="p-tree-toggler p-link" (click)="toggle($event)" pRipple tabindex="-1"> <span class="p-tree-toggler-icon pi pi-fw" [ngClass]="{'pi-chevron-right':!node.expanded,'pi-chevron-down':node.expanded}"></span> </button> <div class="p-checkbox p-component" [ngClass]="{'p-checkbox-disabled': node.selectable === false}" *ngIf="tree.selectionMode == 'checkbox'" [attr.aria-checked]="isSelected()"> <div class="p-checkbox-box" [ngClass]="{'p-highlight': isSelected(), 'p-indeterminate': node.partialSelected}"> <span class="p-checkbox-icon pi" [ngClass]="{'pi-check':isSelected(),'pi-minus':node.partialSelected}"></span> </div> </div> <span [class]="getIcon()" *ngIf="node.icon||node.expandedIcon||node.collapsedIcon"></span> <span class="p-treenode-label"> <span *ngIf="!tree.getTemplateForNode(node)">{{node.label}}</span> <span *ngIf="tree.getTemplateForNode(node)"> <ng-container *ngTemplateOutlet="tree.getTemplateForNode(node); context: {$implicit: node}"></ng-container> </span> </span> </div> <ul class="p-treenode-children" style="display: none;" *ngIf="!tree.virtualScroll && node.children && node.expanded" [style.display]="node.expanded ? 'block' : 'none'" role="group"> <p-treeNode *ngFor="let childNode of node.children;let firstChild=first;let lastChild=last; let index=index; trackBy: tree.trackBy" [node]="childNode" [parentNode]="node" [firstChild]="firstChild" [lastChild]="lastChild" [index]="index" [style.height.px]="tree.virtualNodeHeight" [level]="level + 1"></p-treeNode> </ul> </li> <li *ngIf="tree.droppableNodes&&lastChild" class="p-treenode-droppoint" [ngClass]="{'p-treenode-droppoint-active':draghoverNext}" (drop)="onDropPoint($event,1)" (dragover)="onDropPointDragOver($event)" (dragenter)="onDropPointDragEnter($event,1)" (dragleave)="onDropPointDragLeave($event)"></li> <table *ngIf="tree.horizontal" [class]="node.styleClass"> <tbody> <tr> <td class="p-treenode-connector" *ngIf="!root"> <table class="p-treenode-connector-table"> <tbody> <tr> <td [ngClass]="{'p-treenode-connector-line':!firstChild}"></td> </tr> <tr> <td [ngClass]="{'p-treenode-connector-line':!lastChild}"></td> </tr> </tbody> </table> </td> <td class="p-treenode" [ngClass]="{'p-treenode-collapsed':!node.expanded}"> <div class="p-treenode-content" tabindex="0" [ngClass]="{'p-treenode-selectable':tree.selectionMode,'p-highlight':isSelected()}" (click)="onNodeClick($event)" (contextmenu)="onNodeRightClick($event)" (touchend)="onNodeTouchEnd()" (keydown)="onNodeKeydown($event)"> <span class="p-tree-toggler pi pi-fw" [ngClass]="{'pi-plus':!node.expanded,'pi-minus':node.expanded}" *ngIf="!isLeaf()" (click)="toggle($event)"></span> <span [class]="getIcon()" *ngIf="node.icon||node.expandedIcon||node.collapsedIcon"></span> <span class="p-treenode-label"> <span *ngIf="!tree.getTemplateForNode(node)">{{node.label}}</span> <span *ngIf="tree.getTemplateForNode(node)"> <ng-container *ngTemplateOutlet="tree.getTemplateForNode(node); context: {$implicit: node}"></ng-container> </span> </span> </div> </td> <td class="p-treenode-children-container" *ngIf="node.children && node.expanded" [style.display]="node.expanded ? 'table-cell' : 'none'"> <div class="p-treenode-children"> <p-treeNode *ngFor="let childNode of node.children;let firstChild=first;let lastChild=last; trackBy: tree.trackBy" [node]="childNode" [firstChild]="firstChild" [lastChild]="lastChild"></p-treeNode> </div> </td> </tr> </tbody> </table> </ng-template> `, encapsulation: ViewEncapsulation.None }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [forwardRef(() => Tree)] }] }]; }, propDecorators: { rowNode: [{ type: Input }], node: [{ type: Input }], parentNode: [{ type: Input }], root: [{ type: Input }], index: [{ type: Input }], firstChild: [{ type: Input }], lastChild: [{ type: Input }], level: [{ type: Input }], indentation: [{ type: Input }] } }); class Tree { constructor(el, dragDropService, config) { this.el = el; this.dragDropService = dragDropService; this.config = config; this.selectionChange = new EventEmitter(); this.onNodeSelect = new EventEmitter(); this.onNodeUnselect = new EventEmitter(); this.onNodeExpand = new EventEmitter(); this.onNodeCollapse = new EventEmitter(); this.onNodeContextMenuSelect = new EventEmitter(); this.onNodeDrop = new EventEmitter(); this.layout = 'vertical'; this.metaKeySelection = true; this.propagateSelectionUp = true; this.propagateSelectionDown = true; this.loadingIcon = 'pi pi-spinner'; this.emptyMessage = ''; this.filterBy = 'label'; this.filterMode = 'lenient'; this.indentation = 1.5; this.trackBy = (index, item) => item; this.onFilter = new EventEmitter(); } ngOnInit() { if (this.droppableNodes) { this.dragStartSubscription = this.dragDropService.dragStart$.subscribe(event => { this.dragNodeTree = event.tree; this.dragNode = event.node; this.dragNodeSubNodes = event.subNodes; this.dragNodeIndex = event.index; this.dragNodeScope = event.scope; }); this.dragStopSubscription = this.dragDropService.dragStop$.subscribe(event => { this.dragNodeTree = null; this.dragNode = null; this.dragNodeSubNodes = null; this.dragNodeIndex = null; this.dragNodeScope = null; this.dragHover = false; }); } } ngOnChanges(simpleChange) { if (simpleChange.value) { this.updateSerializedValue(); } if (simpleChange.scrollHeight && this.virtualScrollBody) { this.virtualScrollBody.ngOnInit(); } } get horizontal() { return this.layout == 'horizontal'; } get emptyMessageLabel() { return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE); } ngAfterContentInit() { if (this.templates.length) { this.templateMap = {}; } this.templates.forEach((item) => { switch (item.getType()) { case 'header': this.headerTemplate = item.template; break; case 'empty': this.emptyMessageTemplate = item.template; break; case 'footer': this.footerTemplate = item.template; break; default: this.templateMap[item.name] = item.template; break; } }); } updateSerializedValue() { this.serializedValue = []; this.serializeNodes(null, this.getRootNode(), 0, true); } serializeNodes(parent, nodes, level, visible) { if (nodes && nodes.length) { for (let node of nodes) { node.parent = parent; const rowNode = { node: node, parent: parent, level: level, visible: visible && (parent ? parent.expanded : true) }; this.serializedValue.push(rowNode); if (rowNode.visible && node.expanded) { this.serializeNodes(node, node.children, level + 1, rowNode.visible); } } } } onNodeClick(event, node) { let eventTarget = event.target; if (DomHandler.hasClass(eventTarget, 'p-tree-toggler') || DomHandler.hasClass(eventTarget, 'p-tree-toggler-icon')) { return; } else if (this.selectionMode) { if (node.selectable === false) { return; } if (this.hasFilteredNodes()) { node = this.getNodeWithKey(node.key, this.value); if (!node) { return; } } let index = this.findIndexInSelection(node); let selected = (index >= 0); if (this.isCheckboxSelectionMode()) { if (selected) { if (this.propagateSelectionDown) this.propagateDown(node, false); else this.selection = this.selection.filter((val, i) => i != index); if (this.propagateSelectionUp && node.parent) { this.propagateUp(node.parent, false); } this.selectionChange.emit(this.selection); this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { if (this.propagateSelectionDown) this.propagateDown(node, true); else this.selection = [...this.selection || [], node]; if (this.propagateSelectionUp && node.parent) { this.propagateUp(node.parent, true); } this.selectionChange.emit(this.selection); this.onNodeSelect.emit({ originalEvent: event, node: node }); } } else { let metaSelection = this.nodeTouched ? false : this.metaKeySelection; if (metaSelection) { let metaKey = (event.metaKey || event.ctrlKey); if (selected && metaKey) { if (this.isSingleSelectionMode()) { this.selectionChange.emit(null); } else { this.selection = this.selection.filter((val, i) => i != index); this.selectionChange.emit(this.selection); } this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { if (this.isSingleSelectionMode()) { this.selectionChange.emit(node); } else if (this.isMultipleSelectionMode()) { this.selection = (!metaKey) ? [] : this.selection || []; this.selection = [...this.selection, node]; this.selectionChange.emit(this.selection); } this.onNodeSelect.emit({ originalEvent: event, node: node }); } } else { if (this.isSingleSelectionMode()) { if (selected) { this.selection = null; this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { this.selection = node; this.onNodeSelect.emit({ originalEvent: event, node: node }); } } else { if (selected) { this.selection = this.selection.filter((val, i) => i != index); this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { this.selection = [...this.selection || [], node]; this.onNodeSelect.emit({ originalEvent: event, node: node }); } } this.selectionChange.emit(this.selection); } } } this.nodeTouched = false; } onNodeTouchEnd() { this.nodeTouched = true; } onNodeRightClick(event, node) { if (this.contextMenu) { let eventTarget = event.target; if (eventTarget.className && eventTarget.className.indexOf('p-tree-toggler') === 0) { return; } else { let index = this.findIndexInSelection(node); let selected = (index >= 0); if (!selected) { if (this.isSingleSelectionMode()) this.selectionChange.emit(node); else this.selectionChange.emit([node]); } this.contextMenu.show(event); this.onNodeContextMenuSelect.emit({ originalEvent: event, node: node }); } } } findIndexInSelection(node) { let index = -1; if (this.selectionMode && this.selection) { if (this.isSingleSelectionMode()) { let areNodesEqual = (this.selection.key && this.selection.key === node.key) || this.selection == node; index = areNodesEqual ? 0 : -1; } else { for (let i = 0; i < this.selection.length; i++) { let selectedNode = this.selection[i]; let areNodesEqual = (selectedNode.key && selectedNode.key === node.key) || selectedNode == node; if (areNodesEqual) { index = i; break; } } } } return index; } syncNodeOption(node, parentNodes, option, value) { // to synchronize the node option between the filtered nodes and the original nodes(this.value) const _node = this.hasFilteredNodes() ? this.getNodeWithKey(node.key, parentNodes) : null; if (_node) { _node[option] = value || node[option]; } } hasFilteredNodes() { return this.filter && this.filteredNodes && this.filteredNodes.length; } getNodeWithKey(key, nodes) { for (let node of nodes) { if (node.key === key) { return node; } if (node.children) { let matchedNode = this.getNodeWithKey(key, node.children); if (matchedNode) { return matchedNode; } } } } propagateUp(node, select) { if (node.children && node.children.length) { let selectedCount = 0; let childPartialSelected = false; for (let child of node.children) { if (this.isSelected(child)) { selectedCount++; } else if (child.partialSelected) { childPartialSelected = true; } } if (select && selectedCount == node.children.length) { this.selection = [...this.selection || [], node]; node.partialSelected = false; } else { if (!select) { let index = this.findIndexInSelection(node); if (index >= 0) { this.selection = this.selection.filter((val, i) => i != index); } } if (childPartialSelected || selectedCount > 0 && selectedCount != node.children.length) node.partialSelected = true; else node.partialSelected = false; } this.syncNodeOption(node, this.filteredNodes, 'partialSelected'); } let parent = node.parent; if (parent) { this.propagateUp(parent, select); } } propagateDown(node, select) { let index = this.findIndexInSelection(node); if (select && index == -1) { this.selection = [...this.selection || [], node]; } else if (!select && index > -1) { this.selection = this.selection.filter((val, i) => i != index); } node.partialSelected = false; this.syncNodeOption(node, this.filteredNodes, 'partialSelected'); if (node.children && node.children.length) { for (let child of node.children) { this.propagateDown(child, select); } } } isSelected(node) { return this.findIndexInSelection(node) != -1; } isSingleSelectionMode() { return this.selectionMode && this.selectionMode == 'single'; } isMultipleSelectionMode() { return this.selectionMode && this.selectionMode == 'multiple'; } isCheckboxSelectionMode() { return this.selectionMode && this.selectionMode == 'checkbox'; } isNodeLeaf(node) { return node.leaf == false ? false : !(node.children && node.children.length); } getRootNode() { return this.filteredNodes ? this.filteredNodes : this.value; } getTemplateForNode(node) { if (this.templateMap) return node.type ? this.templateMap[node.type] : this.templateMap['default']; else return null; } onDragOver(event) { if (this.droppableNodes && (!this.value || this.value.length === 0)) { event.dataTransfer.dropEffect = 'move'; event.preventDefault(); } } onDrop(event) { if (this.droppableNodes && (!this.value || this.value.length === 0)) { event.preventDefault(); let dragNode = this.dragNode; if (this.allowDrop(dragNode, null, this.dragNodeScope)) { let dragNodeIndex = this.dragNodeIndex; this.value = this.value || []; if (this.validateDrop) { this.onNodeDrop.emit({ originalEvent: event, dragNode: dragNode, dropNode: null, index: dragNodeIndex, accept: () => { this.processTreeDrop(dragNode, dragNodeIndex); } }); } else { this.onNodeDrop.emit({ originalEvent: event, dragNode: dragNode, dropNode: null, index: dragNodeIndex }); this.processTreeDrop(dragNode, dragNodeIndex); } } } } processTreeDrop(dragNode, dragNodeIndex) { this.dragNodeSubNodes.splice(dragNodeIndex, 1); this.value.push(dragNode); this.dragDropService.stopDrag({ node: dragNode }); } onDragEnter() { if (this.droppableNodes && this.allowDrop(this.dragNode, null, this.dragNodeScope)) { this.dragHover = true; } } onDragLeave(event) { if (this.droppableNodes) { let rect = event.currentTarget.getBoundingClientRect(); if (event.x > rect.left + rect.width || event.x < rect.left || event.y > rect.top + rect.height || event.y < rect.top) { this.dragHover = false; } } } allowDrop(dragNode, dropNode, dragNodeScope) { if (!dragNode) { //prevent random html elements to be dragged return false; } else if (this.isValidDragScope(dragNodeScope)) { let allow = true; if (dropNode) { if (dragNode === dropNode) { allow = false; } else { let parent = dropNode.parent; while (parent != null) { if (parent === dragNode) { allow = false; break; } parent = parent.parent; } } } return allow; } else { return false; } } isValidDragScope(dragScope) { let dropScope = this.droppableScope; if (dropScope) { if (typeof dropScope === 'string') { if (typeof dragScope === 'string') return dropScope === dragScope; else if (dragScope instanceof Array) return dragScope.indexOf(dropScope) != -1; } else if (dropScope instanceof Array) { if (typeof dragScope === 'string') { return dropScope.indexOf(dragScope) != -1; } else if (dragScope instanceof Array) { for (let s of dropScope) { for (let ds of dragScope) { if (s === ds) { return true; } } } } } return false; } else { return true; } } _filter(value) { let filterValue = value; if (filterValue === '') { this.filteredNodes = null; } else { this.filteredNodes = []; const searchFields = this.filterBy.split(','); const filterText = ObjectUtils.removeAccents(filterValue).toLocaleLowerCase(this.filterLocale); const isStrictMode = this.filterMode === 'strict'; for (let node of this.value) { let copyNode = Object.assign({}, node); let paramsWithoutNode = { searchFields, filterText, isStrictMode }; if ((isStrictMode && (this.findFilteredNodes(copyNode, paramsWithoutNode) || this.isFilterMatched(copyNode, paramsWithoutNode))) || (!isStrictMode && (this.isFilterMatched(copyNode, paramsWithoutNode) || this.findFilteredNodes(copyNode, paramsWithoutNode)))) { this.filteredNodes.push(copyNode); } } } this.updateSerializedValue(); this.onFilter.emit({ filter: filterValue, filteredValue: this.filteredNodes }); } resetFilter() { this.filteredNodes = null; if (this.filterViewChild && this.filterViewChild.nativeElement) { this.filterViewChild.nativeElement.value = ''; } } findFilteredNodes(node, paramsWithoutNode) { if (node) { let matched = false; if (node.children) { let childNodes = [...node.children]; node.children = []; for (let childNode of childNodes) { let copyChildNode = Object.assign({}, childNode); if (this.isFilterMatched(copyChildNode, paramsWithoutNode)) { matched = true; node.children.push(copyChildNode); } } } if (matched) { node.expanded = true; return true; } } } isFilterMatched(node, { searchFields, filterText, isStrictMode }) { let matched = false; for (let field of searchFields) { let fieldValue = ObjectUtils.removeAccents(String(ObjectUtils.resolveFieldData(node, field))).toLocaleLowerCase(this.filterLocale); if (fieldValue.indexOf(filterText) > -1) { matched = true; } } if (!matched || (isStrictMode && !this.isNodeLeaf(node))) { matched = this.findFilteredNodes(node, { searchFields, filterText, isStrictMode }) || matched; } return matched; } getBlockableElement() { return this.el.nativeElement.children[0]; } ngOnDestroy() { if (this.dragStartSubscription) { this.dragStartSubscription.unsubscribe(); } if (this.dragStopSubscription) { this.dragStopSubscription.unsubscribe(); } } } Tree.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.4", ngImport: i0, type: Tree, deps: [{ token: i0.ElementRef }, { token: i3.TreeDragDropService, optional: true }, { token: i3.PrimeNGConfig }], target: i0.ɵɵFactoryTarget.Component }); Tree.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.0.4", type: Tree, selector: "p-tree", inputs: { value: "value", selectionMode: "selectionMode", selection: "selection", style: "style", styleClass: "styleClass", contextMenu: "contextMenu", layout: "layout", draggableScope: "draggableScope", droppableScope: "droppableScope", draggableNodes: "draggableNodes", droppableNodes: "droppableNodes", metaKeySelection: "metaKeySelection", propagateSelectionUp: "propagateSelectionUp", propagateSelectionDown: "propagateSelectionDown", loading: "loading", loadingIcon: "loadingIcon", emptyMessage: "emptyMessage", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", validateDrop: "validateDrop", filter: "filter", filterBy: "filterBy", filterMode: "filterMode", filterPlaceholder: "filterPlaceholder", filterLocale: "filterLocale", scrollHeight: "scrollHeight", virtualScroll: "virtualScroll", virtualNodeHeight: "virtualNodeHeight", minBufferPx: "minBufferPx", maxBufferPx: "maxBufferPx", indentation: "indentation", trackBy: "trackBy" }, outputs: { selectionChange: "selectionChange", onNodeSelect: "onNodeSelect", onNodeUnselect: "onNodeUnselect", onNodeExpand: "onNodeExpand", onNodeCollap