Icard/angular-clarity-master(work.../node_modules/primeng/esm2022/tree/tree.mjs

2024 lines
312 KiB
JavaScript
Raw Normal View History

2024-07-16 14:55:36 +00:00
import { CommonModule } from '@angular/common';
import { booleanAttribute, ChangeDetectionStrategy, Component, ContentChildren, EventEmitter, forwardRef, Inject, Input, NgModule, numberAttribute, Optional, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { PrimeTemplate, SharedModule, TranslationKeys } from 'primeng/api';
import { DomHandler } from 'primeng/dom';
import { RippleModule } from 'primeng/ripple';
import { ScrollerModule } from 'primeng/scroller';
import { ObjectUtils } from 'primeng/utils';
import { CheckIcon } from 'primeng/icons/check';
import { ChevronDownIcon } from 'primeng/icons/chevrondown';
import { ChevronRightIcon } from 'primeng/icons/chevronright';
import { MinusIcon } from 'primeng/icons/minus';
import { PlusIcon } from 'primeng/icons/plus';
import { SearchIcon } from 'primeng/icons/search';
import { SpinnerIcon } from 'primeng/icons/spinner';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "primeng/ripple";
import * as i3 from "primeng/api";
import * as i4 from "primeng/scroller";
export class UITreeNode {
static ICON_CLASS = 'p-treenode-icon ';
rowNode;
node;
parentNode;
root;
index;
firstChild;
lastChild;
level;
indentation;
itemSize;
loadingMode;
tree;
timeout;
draghoverPrev;
draghoverNext;
draghoverNode;
get ariaSelected() {
return this.tree.selectionMode === 'single' || this.tree.selectionMode === 'multiple' ? this.isSelected() : undefined;
}
get ariaChecked() {
return this.tree.selectionMode === 'checkbox' ? this.isSelected() : undefined;
}
constructor(tree) {
this.tree = tree;
}
ngOnInit() {
this.node.parent = this.parentNode;
if (this.parentNode) {
this.setAllNodesTabIndexes();
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);
event.stopPropagation();
}
expand(event) {
this.node.expanded = true;
if (this.tree.virtualScroll) {
this.tree.updateSerializedValue();
this.focusVirtualNode();
}
this.tree.onNodeExpand.emit({ originalEvent: event, node: this.node });
}
collapse(event) {
this.node.expanded = false;
if (this.tree.virtualScroll) {
this.tree.updateSerializedValue();
this.focusVirtualNode();
}
this.tree.onNodeCollapse.emit({ originalEvent: event, node: this.node });
}
onNodeClick(event) {
this.tree.onNodeClick(event, this.node);
}
onNodeKeydown(event) {
if (event.key === 'Enter') {
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);
}
isSameNode(event) {
return event.currentTarget && (event.currentTarget.isSameNode(event.target) || event.currentTarget.isSameNode(event.target.closest('[role="treeitem"]')));
}
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 = { ...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 = { ...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) {
if (!this.isSameNode(event) || (this.tree.contextMenu && this.tree.contextMenu.containerViewChild?.nativeElement.style.display === 'block')) {
return;
}
switch (event.code) {
//down arrow
case 'ArrowDown':
this.onArrowDown(event);
break;
//up arrow
case 'ArrowUp':
this.onArrowUp(event);
break;
//right arrow
case 'ArrowRight':
this.onArrowRight(event);
break;
//left arrow
case 'ArrowLeft':
this.onArrowLeft(event);
break;
//enter
case 'Enter':
case 'Space':
case 'NumpadEnter':
this.onEnter(event);
break;
//tab
case 'Tab':
this.setAllNodesTabIndexes();
break;
default:
//no op
break;
}
}
onArrowUp(event) {
const nodeElement = event.target.getAttribute('data-pc-section') === 'toggler' ? event.target.closest('[role="treeitem"]') : event.target.parentElement;
if (nodeElement.previousElementSibling) {
this.focusRowChange(nodeElement, nodeElement.previousElementSibling, this.findLastVisibleDescendant(nodeElement.previousElementSibling));
}
else {
let parentNodeElement = this.getParentNodeElement(nodeElement);
if (parentNodeElement) {
this.focusRowChange(nodeElement, parentNodeElement);
}
}
event.preventDefault();
}
onArrowDown(event) {
const nodeElement = event.target.getAttribute('data-pc-section') === 'toggler' ? event.target.closest('[role="treeitem"]') : event.target;
const listElement = nodeElement.children[1];
if (listElement && listElement.children.length > 0) {
this.focusRowChange(nodeElement, listElement.children[0]);
}
else {
if (nodeElement.parentElement.nextElementSibling) {
this.focusRowChange(nodeElement, nodeElement.parentElement.nextElementSibling);
}
else {
let nextSiblingAncestor = this.findNextSiblingOfAncestor(nodeElement.parentElement);
if (nextSiblingAncestor) {
this.focusRowChange(nodeElement, nextSiblingAncestor);
}
}
}
event.preventDefault();
}
onArrowRight(event) {
if (!this.node?.expanded && !this.tree.isNodeLeaf(this.node)) {
this.expand(event);
event.currentTarget.tabIndex = -1;
setTimeout(() => {
this.onArrowDown(event);
}, 1);
}
event.preventDefault();
}
onArrowLeft(event) {
const nodeElement = event.target.getAttribute('data-pc-section') === 'toggler' ? event.target.closest('[role="treeitem"]') : event.target;
if (this.level === 0 && !this.node?.expanded) {
return false;
}
if (this.node?.expanded) {
this.collapse(event);
return;
}
let parentNodeElement = this.getParentNodeElement(nodeElement.parentElement);
if (parentNodeElement) {
this.focusRowChange(event.currentTarget, parentNodeElement);
}
event.preventDefault();
}
onEnter(event) {
this.tree.onNodeClick(event, this.node);
this.setTabIndexForSelectionMode(event, this.tree.nodeTouched);
event.preventDefault();
}
setAllNodesTabIndexes() {
const nodes = DomHandler.find(this.tree.el.nativeElement, '.p-treenode');
const hasSelectedNode = [...nodes].some((node) => node.getAttribute('aria-selected') === 'true' || node.getAttribute('aria-checked') === 'true');
[...nodes].forEach((node) => {
node.tabIndex = -1;
});
if (hasSelectedNode) {
const selectedNodes = [...nodes].filter((node) => node.getAttribute('aria-selected') === 'true' || node.getAttribute('aria-checked') === 'true');
selectedNodes[0].tabIndex = 0;
return;
}
[...nodes][0].tabIndex = 0;
}
setTabIndexForSelectionMode(event, nodeTouched) {
if (this.tree.selectionMode !== null) {
const elements = [...DomHandler.find(this.tree.el.nativeElement, '.p-treenode')];
event.currentTarget.tabIndex = nodeTouched === false ? -1 : 0;
if (elements.every((element) => element.tabIndex === -1)) {
elements[0].tabIndex = 0;
}
}
}
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].focus();
else
element.children[0].focus();
}
focusRowChange(firstFocusableRow, currentFocusedRow, lastVisibleDescendant) {
firstFocusableRow.tabIndex = '-1';
currentFocusedRow.children[0].tabIndex = '0';
this.focusNode(lastVisibleDescendant || currentFocusedRow);
}
focusVirtualNode() {
this.timeout = setTimeout(() => {
let node = DomHandler.findSingle(document.body, `[data-id="${this.node?.key ?? this.node?.data}"]`);
DomHandler.focus(node);
}, 1);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: UITreeNode, deps: [{ token: forwardRef(() => Tree) }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "17.3.7", type: UITreeNode, selector: "p-treeNode", inputs: { rowNode: "rowNode", node: "node", parentNode: "parentNode", root: ["root", "root", booleanAttribute], index: ["index", "index", numberAttribute], firstChild: ["firstChild", "firstChild", booleanAttribute], lastChild: ["lastChild", "lastChild", booleanAttribute], level: ["level", "level", numberAttribute], indentation: ["indentation", "indentation", numberAttribute], itemSize: ["itemSize", "itemSize", numberAttribute], loadingMode: "loadingMode" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
<ng-template [ngIf]="node">
<li
*ngIf="tree.droppableNodes"
class="p-treenode-droppoint"
[attr.aria-hidden]="true"
[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' : '']"
[ngStyle]="{ height: itemSize + 'px' }"
[style]="node.style"
[attr.aria-label]="node.label"
[attr.aria-checked]="ariaChecked"
[attr.aria-setsize]="node.children ? node.children.length : 0"
[attr.aria-selected]="ariaSelected"
[attr.aria-expanded]="node.expanded"
[attr.aria-posinset]="index + 1"
[attr.aria-level]="level + 1"
[attr.tabindex]="index === 0 ? 0 : -1"
[attr.data-id]="node.key"
role="treeitem"
(keydown)="onKeyDown($event)"
>
<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)"
[ngClass]="{ 'p-treenode-selectable': tree.selectionMode && node.selectable !== false, 'p-treenode-dragover': draghoverNode, 'p-highlight': isSelected() }"
>
<button type="button" [attr.data-pc-section]="'toggler'" class="p-tree-toggler p-link" (click)="toggle($event)" pRipple tabindex="-1" aria-hidden="true">
<ng-container *ngIf="!tree.togglerIconTemplate">
<ng-container *ngIf="!node.loading">
<ChevronRightIcon *ngIf="!node.expanded" [styleClass]="'p-tree-toggler-icon'" />
<ChevronDownIcon *ngIf="node.expanded" [styleClass]="'p-tree-toggler-icon'" />
</ng-container>
<ng-container *ngIf="loadingMode === 'icon' && node.loading">
<SpinnerIcon [spin]="true" [styleClass]="'p-tree-node-toggler-icon'" />
</ng-container>
</ng-container>
<span *ngIf="tree.togglerIconTemplate" class="p-tree-toggler-icon">
<ng-template *ngTemplateOutlet="tree.togglerIconTemplate; context: { $implicit: node.expanded }"></ng-template>
</span>
</button>
<div
class="p-checkbox p-component"
[ngClass]="{ 'p-checkbox-disabled p-disabled': node.selectable === false, 'p-variant-filled': tree?.config.inputStyle() === 'filled' }"
*ngIf="tree.selectionMode == 'checkbox'"
aria-hidden="true"
>
<div class="p-checkbox-box" [ngClass]="{ 'p-highlight': isSelected(), 'p-indeterminate': node.partialSelected }" role="checkbox">
<ng-container *ngIf="!tree.checkboxIconTemplate">
<CheckIcon *ngIf="!node.partialSelected && isSelected()" [styleClass]="'p-checkbox-icon'" />
<MinusIcon *ngIf="node.partialSelected" [styleClass]="'p-checkbox-icon'" />
</ng-container>
<ng-template *ngTemplateOutlet="tree.checkboxIconTemplate; context: { $implicit: isSelected(), partialSelected: node.partialSelected }"></ng-template>
</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="tree">
<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"
[itemSize]="itemSize"
[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)"
[attr.aria-hidden]="true"
(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 *ngIf="!isLeaf()" [ngClass]="'p-tree-toggler'" (click)="toggle($event)">
<ng-container *ngIf="!tree.togglerIconTemplate">
<PlusIcon *ngIf="!node.expanded" [styleClass]="'p-tree-toggler-icon'" [ariaLabel]="tree.togglerAriaLabel" />
<MinusIcon *ngIf="node.expanded" [styleClass]="'p-tree-toggler-icon'" [ariaLabel]="tree.togglerAriaLabel" />
</ng-container>
<span *ngIf="tree.togglerIconTemplate" class="p-tree-toggler-icon">
<ng-template *ngTemplateOutlet="tree.togglerIconTemplate; context: { $implicit: node.expanded }"></ng-template>
</span>
</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, dependencies: [{ kind: "directive", type: i0.forwardRef(() => i1.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgForOf), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgStyle), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i0.forwardRef(() => i2.Ripple), selector: "[pRipple]" }, { kind: "component", type: i0.forwardRef(() => CheckIcon), selector: "CheckIcon" }, { kind: "component", type: i0.forwardRef(() => ChevronDownIcon), selector: "ChevronDownIcon" }, { kind: "component", type: i0.forwardRef(() => ChevronRightIcon), selector: "ChevronRightIcon" }, { kind: "component", type: i0.forwardRef(() => MinusIcon), selector: "MinusIcon" }, { kind: "component", type: i0.forwardRef(() => SpinnerIcon), selector: "SpinnerIcon" }, { kind: "component", type: i0.forwardRef(() => PlusIcon), selector: "PlusIcon" }, { kind: "component", type: i0.forwardRef(() => UITreeNode), selector: "p-treeNode", inputs: ["rowNode", "node", "parentNode", "root", "index", "firstChild", "lastChild", "level", "indentation", "itemSize", "loadingMode"] }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: UITreeNode, decorators: [{
type: Component,
args: [{
selector: 'p-treeNode',
template: `
<ng-template [ngIf]="node">
<li
*ngIf="tree.droppableNodes"
class="p-treenode-droppoint"
[attr.aria-hidden]="true"
[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' : '']"
[ngStyle]="{ height: itemSize + 'px' }"
[style]="node.style"
[attr.aria-label]="node.label"
[attr.aria-checked]="ariaChecked"
[attr.aria-setsize]="node.children ? node.children.length : 0"
[attr.aria-selected]="ariaSelected"
[attr.aria-expanded]="node.expanded"
[attr.aria-posinset]="index + 1"
[attr.aria-level]="level + 1"
[attr.tabindex]="index === 0 ? 0 : -1"
[attr.data-id]="node.key"
role="treeitem"
(keydown)="onKeyDown($event)"
>
<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)"
[ngClass]="{ 'p-treenode-selectable': tree.selectionMode && node.selectable !== false, 'p-treenode-dragover': draghoverNode, 'p-highlight': isSelected() }"
>
<button type="button" [attr.data-pc-section]="'toggler'" class="p-tree-toggler p-link" (click)="toggle($event)" pRipple tabindex="-1" aria-hidden="true">
<ng-container *ngIf="!tree.togglerIconTemplate">
<ng-container *ngIf="!node.loading">
<ChevronRightIcon *ngIf="!node.expanded" [styleClass]="'p-tree-toggler-icon'" />
<ChevronDownIcon *ngIf="node.expanded" [styleClass]="'p-tree-toggler-icon'" />
</ng-container>
<ng-container *ngIf="loadingMode === 'icon' && node.loading">
<SpinnerIcon [spin]="true" [styleClass]="'p-tree-node-toggler-icon'" />
</ng-container>
</ng-container>
<span *ngIf="tree.togglerIconTemplate" class="p-tree-toggler-icon">
<ng-template *ngTemplateOutlet="tree.togglerIconTemplate; context: { $implicit: node.expanded }"></ng-template>
</span>
</button>
<div
class="p-checkbox p-component"
[ngClass]="{ 'p-checkbox-disabled p-disabled': node.selectable === false, 'p-variant-filled': tree?.config.inputStyle() === 'filled' }"
*ngIf="tree.selectionMode == 'checkbox'"
aria-hidden="true"
>
<div class="p-checkbox-box" [ngClass]="{ 'p-highlight': isSelected(), 'p-indeterminate': node.partialSelected }" role="checkbox">
<ng-container *ngIf="!tree.checkboxIconTemplate">
<CheckIcon *ngIf="!node.partialSelected && isSelected()" [styleClass]="'p-checkbox-icon'" />
<MinusIcon *ngIf="node.partialSelected" [styleClass]="'p-checkbox-icon'" />
</ng-container>
<ng-template *ngTemplateOutlet="tree.checkboxIconTemplate; context: { $implicit: isSelected(), partialSelected: node.partialSelected }"></ng-template>
</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="tree">
<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"
[itemSize]="itemSize"
[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)"
[attr.aria-hidden]="true"
(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 *ngIf="!isLeaf()" [ngClass]="'p-tree-toggler'" (click)="toggle($event)">
<ng-container *ngIf="!tree.togglerIconTemplate">
<PlusIcon *ngIf="!node.expanded" [styleClass]="'p-tree-toggler-icon'" [ariaLabel]="tree.togglerAriaLabel" />
<MinusIcon *ngIf="node.expanded" [styleClass]="'p-tree-toggler-icon'" [ariaLabel]="tree.togglerAriaLabel" />
</ng-container>
<span *ngIf="tree.togglerIconTemplate" class="p-tree-toggler-icon">
<ng-template *ngTemplateOutlet="tree.togglerIconTemplate; context: { $implicit: node.expanded }"></ng-template>
</span>
</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,
host: {
class: 'p-element'
}
}]
}], ctorParameters: () => [{ type: Tree, decorators: [{
type: Inject,
args: [forwardRef(() => Tree)]
}] }], propDecorators: { rowNode: [{
type: Input
}], node: [{
type: Input
}], parentNode: [{
type: Input
}], root: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], index: [{
type: Input,
args: [{ transform: numberAttribute }]
}], firstChild: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], lastChild: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], level: [{
type: Input,
args: [{ transform: numberAttribute }]
}], indentation: [{
type: Input,
args: [{ transform: numberAttribute }]
}], itemSize: [{
type: Input,
args: [{ transform: numberAttribute }]
}], loadingMode: [{
type: Input
}] } });
/**
* Tree is used to display hierarchical data.
* @group Components
*/
export class Tree {
el;
dragDropService;
config;
cd;
/**
* An array of treenodes.
* @group Props
*/
value;
/**
* Defines the selection mode.
* @group Props
*/
selectionMode;
/**
* Loading mode display.
* @group Props
*/
loadingMode = 'mask';
/**
* A single treenode instance or an array to refer to the selections.
* @group Props
*/
selection;
/**
* Inline style of the component.
* @group Props
*/
style;
/**
* Style class of the component.
* @group Props
*/
styleClass;
/**
* Context menu instance.
* @group Props
*/
contextMenu;
/**
* Defines the orientation of the tree, valid values are 'vertical' and 'horizontal'.
* @group Props
*/
layout = 'vertical';
/**
* Scope of the draggable nodes to match a droppableScope.
* @group Props
*/
draggableScope;
/**
* Scope of the droppable nodes to match a draggableScope.
* @group Props
*/
droppableScope;
/**
* Whether the nodes are draggable.
* @group Props
*/
draggableNodes;
/**
* Whether the nodes are droppable.
* @group Props
*/
droppableNodes;
/**
* Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically.
* @group Props
*/
metaKeySelection = false;
/**
* Whether checkbox selections propagate to ancestor nodes.
* @group Props
*/
propagateSelectionUp = true;
/**
* Whether checkbox selections propagate to descendant nodes.
* @group Props
*/
propagateSelectionDown = true;
/**
* Displays a loader to indicate data load is in progress.
* @group Props
*/
loading;
/**
* The icon to show while indicating data load is in progress.
* @group Props
*/
loadingIcon;
/**
* Text to display when there is no data.
* @group Props
*/
emptyMessage = '';
/**
* Used to define a string that labels the tree.
* @group Props
*/
ariaLabel;
/**
* Defines a string that labels the toggler icon for accessibility.
* @group Props
*/
togglerAriaLabel;
/**
* Establishes relationships between the component and label(s) where its value should be one or more element IDs.
* @group Props
*/
ariaLabelledBy;
/**
* When enabled, drop can be accepted or rejected based on condition defined at onNodeDrop.
* @group Props
*/
validateDrop;
/**
* When specified, displays an input field to filter the items.
* @group Props
*/
filter;
/**
* When filtering is enabled, filterBy decides which field or fields (comma separated) to search against.
* @group Props
*/
filterBy = 'label';
/**
* Mode for filtering valid values are "lenient" and "strict". Default is lenient.
* @group Props
*/
filterMode = 'lenient';
/**
* Placeholder text to show when filter input is empty.
* @group Props
*/
filterPlaceholder;
/**
* Values after the tree nodes are filtered.
* @group Props
*/
filteredNodes;
/**
* Locale to use in filtering. The default locale is the host environment's current locale.
* @group Props
*/
filterLocale;
/**
* Height of the scrollable viewport.
* @group Props
*/
scrollHeight;
/**
* Defines if data is loaded and interacted with in lazy manner.
* @group Props
*/
lazy = false;
/**
* Whether the data should be loaded on demand during scroll.
* @group Props
*/
virtualScroll;
/**
* Height of an item in the list for VirtualScrolling.
* @group Props
*/
virtualScrollItemSize;
/**
* Whether to use the scroller feature. The properties of scroller component can be used like an object in it.
* @group Props
*/
virtualScrollOptions;
/**
* Indentation factor for spacing of the nested node when virtual scrolling is enabled.
* @group Props
*/
indentation = 1.5;
/**
* Custom templates of the component.
* @group Props
*/
_templateMap;
/**
* Function to optimize the node list rendering, default algorithm checks for object identity.
* @group Props
*/
trackBy = (index, item) => item;
/**
* Height of the node.
* @group Props
* @deprecated use virtualScrollItemSize property instead.
*/
_virtualNodeHeight;
get virtualNodeHeight() {
return this._virtualNodeHeight;
}
set virtualNodeHeight(val) {
this._virtualNodeHeight = val;
console.warn('The virtualNodeHeight property is deprecated, use virtualScrollItemSize property instead.');
}
/**
* Callback to invoke on selection change.
* @param {(TreeNode<any> | TreeNode<any>[] | null)} event - Custom selection change event.
* @group Emits
*/
selectionChange = new EventEmitter();
/**
* Callback to invoke when a node is selected.
* @param {TreeNodeSelectEvent} event - Node select event.
* @group Emits
*/
onNodeSelect = new EventEmitter();
/**
* Callback to invoke when a node is unselected.
* @param {TreeNodeUnSelectEvent} event - Node unselect event.
* @group Emits
*/
onNodeUnselect = new EventEmitter();
/**
* Callback to invoke when a node is expanded.
* @param {TreeNodeExpandEvent} event - Node expand event.
* @group Emits
*/
onNodeExpand = new EventEmitter();
/**
* Callback to invoke when a node is collapsed.
* @param {TreeNodeCollapseEvent} event - Node collapse event.
* @group Emits
*/
onNodeCollapse = new EventEmitter();
/**
* Callback to invoke when a node is selected with right click.
* @param {onNodeContextMenuSelect} event - Node context menu select event.
* @group Emits
*/
onNodeContextMenuSelect = new EventEmitter();
/**
* Callback to invoke when a node is dropped.
* @param {TreeNodeDropEvent} event - Node drop event.
* @group Emits
*/
onNodeDrop = new EventEmitter();
/**
* Callback to invoke in lazy mode to load new data.
* @param {TreeLazyLoadEvent} event - Custom lazy load event.
* @group Emits
*/
onLazyLoad = new EventEmitter();
/**
* Callback to invoke in virtual scroll mode when scroll position changes.
* @param {TreeScrollEvent} event - Custom scroll event.
* @group Emits
*/
onScroll = new EventEmitter();
/**
* Callback to invoke in virtual scroll mode when scroll position and item's range in view changes.
* @param {TreeScrollIndexChangeEvent} event - Scroll index change event.
* @group Emits
*/
onScrollIndexChange = new EventEmitter();
/**
* Callback to invoke when data is filtered.
* @param {TreeFilterEvent} event - Custom filter event.
* @group Emits
*/
onFilter = new EventEmitter();
templates;
filterViewChild;
scroller;
wrapperViewChild;
serializedValue;
headerTemplate;
footerTemplate;
loaderTemplate;
emptyMessageTemplate;
togglerIconTemplate;
checkboxIconTemplate;
loadingIconTemplate;
filterIconTemplate;
nodeTouched;
dragNodeTree;
dragNode;
dragNodeSubNodes;
dragNodeIndex;
dragNodeScope;
dragHover;
dragStartSubscription;
dragStopSubscription;
constructor(el, dragDropService, config, cd) {
this.el = el;
this.dragDropService = dragDropService;
this.config = config;
this.cd = cd;
}
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 (this.hasFilterActive()) {
this._filter(this.filterViewChild.nativeElement.value);
}
}
}
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;
case 'loader':
this.loaderTemplate = item.template;
break;
case 'togglericon':
this.togglerIconTemplate = item.template;
break;
case 'checkboxicon':
this.checkboxIconTemplate = item.template;
break;
case 'loadingicon':
this.loadingIconTemplate = item.template;
break;
case 'filtericon':
this.filterIconTemplate = 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.filteredNodes);
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;
}
hasFilterActive() {
return this.filter && this.filterViewChild?.nativeElement?.value.length > 0;
}
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 (Array.isArray(dragScope))
return dragScope.indexOf(dropScope) != -1;
}
else if (Array.isArray(dropScope)) {
if (typeof dragScope === 'string') {
return dropScope.indexOf(dragScope) != -1;
}
else if (Array.isArray(dragScope)) {
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 = { ...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
});
}
/**
* Resets filter.
* @group Method
*/
resetFilter() {
this.filteredNodes = null;
if (this.filterViewChild && this.filterViewChild.nativeElement) {
this.filterViewChild.nativeElement.value = '';
}
}
/**
* Scrolls to virtual index.
* @param {number} number - Index to be scrolled.
* @group Method
*/
scrollToVirtualIndex(index) {
this.virtualScroll && this.scroller?.scrollToIndex(index);
}
/**
* Scrolls to virtual index.
* @param {ScrollToOptions} options - Scroll options.
* @group Method
*/
scrollTo(options) {
if (this.virtualScroll) {
this.scroller?.scrollTo(options);
}
else if (this.wrapperViewChild && this.wrapperViewChild.nativeElement) {
if (this.wrapperViewChild.nativeElement.scrollTo) {
this.wrapperViewChild.nativeElement.scrollTo(options);
}
else {
this.wrapperViewChild.nativeElement.scrollLeft = options.left;
this.wrapperViewChild.nativeElement.scrollTop = options.top;
}
}
}
findFilteredNodes(node, paramsWithoutNode) {
if (node) {
let matched = false;
if (node.children) {
let childNodes = [...node.children];
node.children = [];
for (let childNode of childNodes) {
let copyChildNode = { ...childNode };
if (this.isFilterMatched(copyChildNode, paramsWithoutNode)) {
matched = true;
node.children.push(copyChildNode);
}
}
}
if (matched) {
node.expanded = true;
return true;
}
}
}
isFilterMatched(node, params) {
let { searchFields, filterText, isStrictMode } = params;
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;
}
getIndex(options, index) {
const getItemOptions = options['getItemOptions'];
return getItemOptions ? getItemOptions(index).index : index;
}
getBlockableElement() {
return this.el.nativeElement.children[0];
}
ngOnDestroy() {
if (this.dragStartSubscription) {
this.dragStartSubscription.unsubscribe();
}
if (this.dragStopSubscription) {
this.dragStopSubscription.unsubscribe();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: Tree, deps: [{ token: i0.ElementRef }, { token: i3.TreeDragDropService, optional: true }, { token: i3.PrimeNGConfig }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "17.3.7", type: Tree, selector: "p-tree", inputs: { value: "value", selectionMode: "selectionMode", loadingMode: "loadingMode", selection: "selection", style: "style", styleClass: "styleClass", contextMenu: "contextMenu", layout: "layout", draggableScope: "draggableScope", droppableScope: "droppableScope", draggableNodes: ["draggableNodes", "draggableNodes", booleanAttribute], droppableNodes: ["droppableNodes", "droppableNodes", booleanAttribute], metaKeySelection: ["metaKeySelection", "metaKeySelection", booleanAttribute], propagateSelectionUp: ["propagateSelectionUp", "propagateSelectionUp", booleanAttribute], propagateSelectionDown: ["propagateSelectionDown", "propagateSelectionDown", booleanAttribute], loading: ["loading", "loading", booleanAttribute], loadingIcon: "loadingIcon", emptyMessage: "emptyMessage", ariaLabel: "ariaLabel", togglerAriaLabel: "togglerAriaLabel", ariaLabelledBy: "ariaLabelledBy", validateDrop: ["validateDrop", "validateDrop", booleanAttribute], filter: ["filter", "filter", booleanAttribute], filterBy: "filterBy", filterMode: "filterMode", filterPlaceholder: "filterPlaceholder", filteredNodes: "filteredNodes", filterLocale: "filterLocale", scrollHeight: "scrollHeight", lazy: ["lazy", "lazy", booleanAttribute], virtualScroll: ["virtualScroll", "virtualScroll", booleanAttribute], virtualScrollItemSize: ["virtualScrollItemSize", "virtualScrollItemSize", numberAttribute], virtualScrollOptions: "virtualScrollOptions", indentation: ["indentation", "indentation", numberAttribute], _templateMap: "_templateMap", trackBy: "trackBy", virtualNodeHeight: "virtualNodeHeight" }, outputs: { selectionChange: "selectionChange", onNodeSelect: "onNodeSelect", onNodeUnselect: "onNodeUnselect", onNodeExpand: "onNodeExpand", onNodeCollapse: "onNodeCollapse", onNodeContextMenuSelect: "onNodeContextMenuSelect", onNodeDrop: "onNodeDrop", onLazyLoad: "onLazyLoad", onScroll: "onScroll", onScrollIndexChange: "onScrollIndexChange", onFilter: "onFilter" }, host: { classAttribute: "p-element" }, queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "filterViewChild", first: true, predicate: ["filter"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "wrapperViewChild", first: true, predicate: ["wrapper"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<div
[ngClass]="{ 'p-tree p-component': true, 'p-tree-selectable': selectionMode, 'p-treenode-dragover': dragHover, 'p-tree-loading': loading, 'p-tree-flex-scrollable': scrollHeight === 'flex' }"
[ngStyle]="style"
[class]="styleClass"
*ngIf="!horizontal"
(drop)="onDrop($event)"
(dragover)="onDragOver($event)"
(dragenter)="onDragEnter()"
(dragleave)="onDragLeave($event)"
>
<div class="p-tree-loading-overlay p-component-overlay" *ngIf="loading && loadingMode === 'mask'">
<i *ngIf="loadingIcon" [class]="'p-tree-loading-icon pi-spin ' + loadingIcon"></i>
<ng-container *ngIf="!loadingIcon">
<SpinnerIcon *ngIf="!loadingIconTemplate" [spin]="true" [styleClass]="'p-tree-loading-icon'" />
<span *ngIf="loadingIconTemplate" class="p-tree-loading-icon">
<ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
</span>
</ng-container>
</div>
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
<div *ngIf="filter" class="p-tree-filter-container">
<input #filter type="search" autocomplete="off" class="p-tree-filter p-inputtext p-component" [attr.placeholder]="filterPlaceholder" (keydown.enter)="$event.preventDefault()" (input)="_filter($event.target.value)" />
<SearchIcon *ngIf="!filterIconTemplate" [styleClass]="'p-tree-filter-icon'" />
<span *ngIf="filterIconTemplate" class="p-tree-filter-icon">
<ng-template *ngTemplateOutlet="filterIconTemplate"></ng-template>
</span>
</div>
<ng-container *ngIf="getRootNode()?.length">
<p-scroller
#scroller
*ngIf="virtualScroll"
[items]="serializedValue"
[tabindex]="-1"
styleClass="p-tree-wrapper"
[style]="{ height: scrollHeight !== 'flex' ? scrollHeight : undefined }"
[scrollHeight]="scrollHeight !== 'flex' ? undefined : '100%'"
[itemSize]="virtualScrollItemSize || _virtualNodeHeight"
[lazy]="lazy"
(onScroll)="onScroll.emit($event)"
(onScrollIndexChange)="onScrollIndexChange.emit($event)"
(onLazyLoad)="onLazyLoad.emit($event)"
[options]="virtualScrollOptions"
>
<ng-template pTemplate="content" let-items let-scrollerOptions="options">
<ul *ngIf="items" class="p-tree-container" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="tree" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy">
<p-treeNode
#treeNode
*ngFor="let rowNode of items; let firstChild = first; let lastChild = last; let index = index; trackBy: trackBy"
[level]="rowNode.level"
[rowNode]="rowNode"
[node]="rowNode.node"
[parentNode]="rowNode.parent"
[firstChild]="firstChild"
[lastChild]="lastChild"
[index]="getIndex(scrollerOptions, index)"
[itemSize]="scrollerOptions.itemSize"
[indentation]="indentation"
[loadingMode]="loadingMode"
></p-treeNode>
</ul>
</ng-template>
<ng-container *ngIf="loaderTemplate">
<ng-template pTemplate="loader" let-scrollerOptions="options">
<ng-container *ngTemplateOutlet="loaderTemplate; context: { options: scrollerOptions }"></ng-container>
</ng-template>
</ng-container>
</p-scroller>
<ng-container *ngIf="!virtualScroll">
<div #wrapper class="p-tree-wrapper" [style.max-height]="scrollHeight">
<ul class="p-tree-container" *ngIf="getRootNode()" role="tree" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy">
<p-treeNode
*ngFor="let node of getRootNode(); let firstChild = first; let lastChild = last; let index = index; trackBy: trackBy"
[node]="node"
[firstChild]="firstChild"
[lastChild]="lastChild"
[index]="index"
[level]="0"
[loadingMode]="loadingMode"
></p-treeNode>
</ul>
</div>
</ng-container>
</ng-container>
<div class="p-tree-empty-message" *ngIf="!loading && (getRootNode() == null || getRootNode().length === 0)">
<ng-container *ngIf="!emptyMessageTemplate; else emptyFilter">
{{ emptyMessageLabel }}
</ng-container>
<ng-container #emptyFilter *ngTemplateOutlet="emptyMessageTemplate"></ng-container>
</div>
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
</div>
<div [ngClass]="{ 'p-tree p-tree-horizontal p-component': true, 'p-tree-selectable': selectionMode }" [ngStyle]="style" [class]="styleClass" *ngIf="horizontal">
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
<div class="p-tree-loading-mask p-component-overlay" *ngIf="loading">
<i *ngIf="loadingIcon" [class]="'p-tree-loading-icon pi-spin ' + loadingIcon"></i>
<ng-container *ngIf="!loadingIcon">
<SpinnerIcon *ngIf="!loadingIconTemplate" [spin]="true" [styleClass]="'p-tree-loading-icon'" />
<span *ngIf="loadingIconTemplate" class="p-tree-loading-icon">
<ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
</span>
</ng-container>
</div>
<table *ngIf="value && value[0]">
<p-treeNode [node]="value[0]" [root]="true"></p-treeNode>
</table>
<div class="p-tree-empty-message" *ngIf="!loading && (getRootNode() == null || getRootNode().length === 0)">
<ng-container *ngIf="!emptyMessageTemplate; else emptyFilter">
{{ emptyMessageLabel }}
</ng-container>
<ng-container #emptyFilter *ngTemplateOutlet="emptyMessageTemplate"></ng-container>
</div>
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
</div>
`, isInline: true, styles: ["@layer primeng{.p-tree-container{margin:0;padding:0;list-style-type:none;overflow:auto}.p-treenode-children{margin:0;padding:0;list-style-type:none}.p-tree-wrapper{overflow:auto}.p-treenode-selectable{cursor:pointer;-webkit-user-select:none;user-select:none}.p-tree-toggler{cursor:pointer;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center;overflow:hidden;position:relative;flex-shrink:0}.p-treenode-leaf>.p-treenode-content .p-tree-toggler{visibility:hidden}.p-treenode-content{display:flex;align-items:center}.p-tree-filter{width:100%}.p-tree-filter-container{position:relative;display:block;width:100%}.p-tree-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-tree-loading{position:relative;min-height:4rem}.p-tree .p-tree-loading-overlay{position:absolute;display:flex;align-items:center;justify-content:center;z-index:2}.p-tree-flex-scrollable{display:flex;flex:1;height:100%;flex-direction:column}.p-tree-flex-scrollable .p-tree-wrapper{flex:1}.p-tree .p-treenode-droppoint{height:4px;list-style-type:none}.p-tree .p-treenode-droppoint-active{border:0 none}.p-tree-horizontal{width:auto;padding-left:0;padding-right:0;overflow:auto}.p-tree.p-tree-horizontal table,.p-tree.p-tree-horizontal tr,.p-tree.p-tree-horizontal td{border-collapse:collapse;margin:0;padding:0;vertical-align:middle}.p-tree-horizontal .p-treenode-content{font-weight:400;padding:.4em 1em .4em .2em;display:flex;align-items:center}.p-tree-horizontal .p-treenode-parent .p-treenode-content{font-weight:400;white-space:nowrap}.p-tree.p-tree-horizontal .p-treenode{background:url(data:image/gif;base64,R0lGODlhAQABAIAAALGxsf///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNC4xLWMwMzQgNDYuMjcyOTc2LCBTYXQgSmFuIDI3IDIwMDcgMjI6Mzc6MzcgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhhcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx4YXA6Q3JlYXRvclRvb2w+QWRvYmUgRmlyZXdvcmtzIENTMzwveGFwOkNyZWF0b3JUb29sPgogICAgICAgICA8eGFwOkNyZWF0ZURhdGU+MjAxMC0wMy0xMVQxMDoxNjo0MVo8L3hhcDpDcmVhdGVEYXRlPgogICAgICAgICA8eGFwOk1vZGlmeURhdGU+MjAxMC0wMy0xMVQxMjo0NDoxOVo8L3hhcDpNb2RpZnlEYXRlPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9naWY8L2RjOmZvcm1hdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: Tree, decorators: [{
type: Component,
args: [{ selector: 'p-tree', template: `
<div
[ngClass]="{ 'p-tree p-component': true, 'p-tree-selectable': selectionMode, 'p-treenode-dragover': dragHover, 'p-tree-loading': loading, 'p-tree-flex-scrollable': scrollHeight === 'flex' }"
[ngStyle]="style"
[class]="styleClass"
*ngIf="!horizontal"
(drop)="onDrop($event)"
(dragover)="onDragOver($event)"
(dragenter)="onDragEnter()"
(dragleave)="onDragLeave($event)"
>
<div class="p-tree-loading-overlay p-component-overlay" *ngIf="loading && loadingMode === 'mask'">
<i *ngIf="loadingIcon" [class]="'p-tree-loading-icon pi-spin ' + loadingIcon"></i>
<ng-container *ngIf="!loadingIcon">
<SpinnerIcon *ngIf="!loadingIconTemplate" [spin]="true" [styleClass]="'p-tree-loading-icon'" />
<span *ngIf="loadingIconTemplate" class="p-tree-loading-icon">
<ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
</span>
</ng-container>
</div>
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
<div *ngIf="filter" class="p-tree-filter-container">
<input #filter type="search" autocomplete="off" class="p-tree-filter p-inputtext p-component" [attr.placeholder]="filterPlaceholder" (keydown.enter)="$event.preventDefault()" (input)="_filter($event.target.value)" />
<SearchIcon *ngIf="!filterIconTemplate" [styleClass]="'p-tree-filter-icon'" />
<span *ngIf="filterIconTemplate" class="p-tree-filter-icon">
<ng-template *ngTemplateOutlet="filterIconTemplate"></ng-template>
</span>
</div>
<ng-container *ngIf="getRootNode()?.length">
<p-scroller
#scroller
*ngIf="virtualScroll"
[items]="serializedValue"
[tabindex]="-1"
styleClass="p-tree-wrapper"
[style]="{ height: scrollHeight !== 'flex' ? scrollHeight : undefined }"
[scrollHeight]="scrollHeight !== 'flex' ? undefined : '100%'"
[itemSize]="virtualScrollItemSize || _virtualNodeHeight"
[lazy]="lazy"
(onScroll)="onScroll.emit($event)"
(onScrollIndexChange)="onScrollIndexChange.emit($event)"
(onLazyLoad)="onLazyLoad.emit($event)"
[options]="virtualScrollOptions"
>
<ng-template pTemplate="content" let-items let-scrollerOptions="options">
<ul *ngIf="items" class="p-tree-container" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="tree" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy">
<p-treeNode
#treeNode
*ngFor="let rowNode of items; let firstChild = first; let lastChild = last; let index = index; trackBy: trackBy"
[level]="rowNode.level"
[rowNode]="rowNode"
[node]="rowNode.node"
[parentNode]="rowNode.parent"
[firstChild]="firstChild"
[lastChild]="lastChild"
[index]="getIndex(scrollerOptions, index)"
[itemSize]="scrollerOptions.itemSize"
[indentation]="indentation"
[loadingMode]="loadingMode"
></p-treeNode>
</ul>
</ng-template>
<ng-container *ngIf="loaderTemplate">
<ng-template pTemplate="loader" let-scrollerOptions="options">
<ng-container *ngTemplateOutlet="loaderTemplate; context: { options: scrollerOptions }"></ng-container>
</ng-template>
</ng-container>
</p-scroller>
<ng-container *ngIf="!virtualScroll">
<div #wrapper class="p-tree-wrapper" [style.max-height]="scrollHeight">
<ul class="p-tree-container" *ngIf="getRootNode()" role="tree" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy">
<p-treeNode
*ngFor="let node of getRootNode(); let firstChild = first; let lastChild = last; let index = index; trackBy: trackBy"
[node]="node"
[firstChild]="firstChild"
[lastChild]="lastChild"
[index]="index"
[level]="0"
[loadingMode]="loadingMode"
></p-treeNode>
</ul>
</div>
</ng-container>
</ng-container>
<div class="p-tree-empty-message" *ngIf="!loading && (getRootNode() == null || getRootNode().length === 0)">
<ng-container *ngIf="!emptyMessageTemplate; else emptyFilter">
{{ emptyMessageLabel }}
</ng-container>
<ng-container #emptyFilter *ngTemplateOutlet="emptyMessageTemplate"></ng-container>
</div>
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
</div>
<div [ngClass]="{ 'p-tree p-tree-horizontal p-component': true, 'p-tree-selectable': selectionMode }" [ngStyle]="style" [class]="styleClass" *ngIf="horizontal">
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
<div class="p-tree-loading-mask p-component-overlay" *ngIf="loading">
<i *ngIf="loadingIcon" [class]="'p-tree-loading-icon pi-spin ' + loadingIcon"></i>
<ng-container *ngIf="!loadingIcon">
<SpinnerIcon *ngIf="!loadingIconTemplate" [spin]="true" [styleClass]="'p-tree-loading-icon'" />
<span *ngIf="loadingIconTemplate" class="p-tree-loading-icon">
<ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
</span>
</ng-container>
</div>
<table *ngIf="value && value[0]">
<p-treeNode [node]="value[0]" [root]="true"></p-treeNode>
</table>
<div class="p-tree-empty-message" *ngIf="!loading && (getRootNode() == null || getRootNode().length === 0)">
<ng-container *ngIf="!emptyMessageTemplate; else emptyFilter">
{{ emptyMessageLabel }}
</ng-container>
<ng-container #emptyFilter *ngTemplateOutlet="emptyMessageTemplate"></ng-container>
</div>
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
</div>
`, changeDetection: ChangeDetectionStrategy.Default, encapsulation: ViewEncapsulation.None, host: {
class: 'p-element'
}, styles: ["@layer primeng{.p-tree-container{margin:0;padding:0;list-style-type:none;overflow:auto}.p-treenode-children{margin:0;padding:0;list-style-type:none}.p-tree-wrapper{overflow:auto}.p-treenode-selectable{cursor:pointer;-webkit-user-select:none;user-select:none}.p-tree-toggler{cursor:pointer;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center;overflow:hidden;position:relative;flex-shrink:0}.p-treenode-leaf>.p-treenode-content .p-tree-toggler{visibility:hidden}.p-treenode-content{display:flex;align-items:center}.p-tree-filter{width:100%}.p-tree-filter-container{position:relative;display:block;width:100%}.p-tree-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-tree-loading{position:relative;min-height:4rem}.p-tree .p-tree-loading-overlay{position:absolute;display:flex;align-items:center;justify-content:center;z-index:2}.p-tree-flex-scrollable{display:flex;flex:1;height:100%;flex-direction:column}.p-tree-flex-scrollable .p-tree-wrapper{flex:1}.p-tree .p-treenode-droppoint{height:4px;list-style-type:none}.p-tree .p-treenode-droppoint-active{border:0 none}.p-tree-horizontal{width:auto;padding-left:0;padding-right:0;overflow:auto}.p-tree.p-tree-horizontal table,.p-tree.p-tree-horizontal tr,.p-tree.p-tree-horizontal td{border-collapse:collapse;margin:0;padding:0;vertical-align:middle}.p-tree-horizontal .p-treenode-content{font-weight:400;padding:.4em 1em .4em .2em;display:flex;align-items:center}.p-tree-horizontal .p-treenode-parent .p-treenode-content{font-weight:400;white-space:nowrap}.p-tree.p-tree-horizontal .p-treenode{background:url(data:image/gif;base64,R0lGODlhAQABAIAAALGxsf///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNC4xLWMwMzQgNDYuMjcyOTc2LCBTYXQgSmFuIDI3IDIwMDcgMjI6Mzc6MzcgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhhcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx4YXA6Q3JlYXRvclRvb2w+QWRvYmUgRmlyZXdvcmtzIENTMzwveGFwOkNyZWF0b3JUb29sPgogICAgICAgICA8eGFwOkNyZWF0ZURhdGU+MjAxMC0wMy0xMVQxMDoxNjo0MVo8L3hhcDpDcmVhdGVEYXRlPgogICAgICAgICA8eGFwOk1vZGlmeURhdGU+MjAxMC0wMy0xMVQxMjo0NDoxOVo8L3hhcDpNb2RpZnlEYXRlPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9naWY8L2RjOmZvcm1hdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i3.TreeDragDropService, decorators: [{
type: Optional
}] }, { type: i3.PrimeNGConfig }, { type: i0.ChangeDetectorRef }], propDecorators: { value: [{
type: Input
}], selectionMode: [{
type: Input
}], loadingMode: [{
type: Input
}], selection: [{
type: Input
}], style: [{
type: Input
}], styleClass: [{
type: Input
}], contextMenu: [{
type: Input
}], layout: [{
type: Input
}], draggableScope: [{
type: Input
}], droppableScope: [{
type: Input
}], draggableNodes: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], droppableNodes: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], metaKeySelection: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], propagateSelectionUp: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], propagateSelectionDown: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], loading: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], loadingIcon: [{
type: Input
}], emptyMessage: [{
type: Input
}], ariaLabel: [{
type: Input
}], togglerAriaLabel: [{
type: Input
}], ariaLabelledBy: [{
type: Input
}], validateDrop: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], filter: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], filterBy: [{
type: Input
}], filterMode: [{
type: Input
}], filterPlaceholder: [{
type: Input
}], filteredNodes: [{
type: Input
}], filterLocale: [{
type: Input
}], scrollHeight: [{
type: Input
}], lazy: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], virtualScroll: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], virtualScrollItemSize: [{
type: Input,
args: [{ transform: numberAttribute }]
}], virtualScrollOptions: [{
type: Input
}], indentation: [{
type: Input,
args: [{ transform: numberAttribute }]
}], _templateMap: [{
type: Input
}], trackBy: [{
type: Input
}], virtualNodeHeight: [{
type: Input
}], selectionChange: [{
type: Output
}], onNodeSelect: [{
type: Output
}], onNodeUnselect: [{
type: Output
}], onNodeExpand: [{
type: Output
}], onNodeCollapse: [{
type: Output
}], onNodeContextMenuSelect: [{
type: Output
}], onNodeDrop: [{
type: Output
}], onLazyLoad: [{
type: Output
}], onScroll: [{
type: Output
}], onScrollIndexChange: [{
type: Output
}], onFilter: [{
type: Output
}], templates: [{
type: ContentChildren,
args: [PrimeTemplate]
}], filterViewChild: [{
type: ViewChild,
args: ['filter']
}], scroller: [{
type: ViewChild,
args: ['scroller']
}], wrapperViewChild: [{
type: ViewChild,
args: ['wrapper']
}] } });
export class TreeModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: TreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.7", ngImport: i0, type: TreeModule, declarations: [Tree, UITreeNode], imports: [CommonModule, SharedModule, RippleModule, ScrollerModule, CheckIcon, ChevronDownIcon, ChevronRightIcon, MinusIcon, SearchIcon, SpinnerIcon, PlusIcon], exports: [Tree, SharedModule, ScrollerModule] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: TreeModule, imports: [CommonModule, SharedModule, RippleModule, ScrollerModule, CheckIcon, ChevronDownIcon, ChevronRightIcon, MinusIcon, SearchIcon, SpinnerIcon, PlusIcon, SharedModule, ScrollerModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: TreeModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, SharedModule, RippleModule, ScrollerModule, CheckIcon, ChevronDownIcon, ChevronRightIcon, MinusIcon, SearchIcon, SpinnerIcon, PlusIcon],
exports: [Tree, SharedModule, ScrollerModule],
declarations: [Tree, UITreeNode]
}]
}] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcHAvY29tcG9uZW50cy90cmVlL3RyZWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFFSCxnQkFBZ0IsRUFDaEIsdUJBQXVCLEVBRXZCLFNBQVMsRUFDVCxlQUFlLEVBRWYsWUFBWSxFQUNaLFVBQVUsRUFDVixNQUFNLEVBQ04sS0FBSyxFQUNMLFFBQVEsRUFDUixlQUFlLEVBSWYsUUFBUSxFQUNSLE1BQU0sRUFJTixTQUFTLEVBQ1QsaUJBQWlCLEVBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBOEIsYUFBYSxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQWlDLE1BQU0sYUFBYSxDQUFDO0FBQ3RJLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDekMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBWSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUU1RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTVDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFDOzs7Ozs7QUFvTHBELE1BQU0sT0FBTyxVQUFVO0lBQ25CLE1BQU0sQ0FBQyxVQUFVLEdBQVcsa0JBQWtCLENBQUM7SUFFdEMsT0FBTyxDQUFNO0lBRWIsSUFBSSxDQUE0QjtJQUVoQyxVQUFVLENBQTRCO0lBRVAsSUFBSSxDQUFzQjtJQUUzQixLQUFLLENBQXFCO0lBRXpCLFVBQVUsQ0FBc0I7SUFFaEMsU0FBUyxDQUFzQjtJQUVoQyxLQUFLLENBQXFCO0lBRTFCLFdBQVcsQ0FBcUI7SUFFaEMsUUFBUSxDQUFxQjtJQUUzRCxXQUFXLENBQVM7SUFFN0IsSUFBSSxDQUFPO0lBRVgsT0FBTyxDQUFNO0lBRWIsYUFBYSxDQUFzQjtJQUVuQyxhQUFhLENBQXNCO0lBRW5DLGFBQWEsQ0FBc0I7SUFFbkMsSUFBSSxZQUFZO1FBQ1osT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUMxSCxDQUFDO0lBRUQsSUFBSSxXQUFXO1FBQ1gsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsS0FBSyxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2xGLENBQUM7SUFFRCxZQUE0QyxJQUFVO1FBQ2xELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBWSxDQUFDO0lBQzdCLENBQUM7SUFFRCxRQUFRO1FBQ08sSUFBSSxDQUFDLElBQUssQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQztRQUMvQyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDakIsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDN0IsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQVcsSUFBSSxDQUFDLElBQUksRUFBbUIsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFTLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFtQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDdEw7SUFDTCxDQUFDO0lBRUQsT0FBTztRQUNILElBQUksSUFBd0IsQ0FBQztRQUU3QixJQUFlLElBQUksQ0FBQyxJQUFLLENBQUMsSUFBSTtZQUFFLElBQUksR0FBYyxJQUFJLENBQUMsSUFBSyxDQUFDLElBQWMsQ0FBQzs7WUFDdkUsSUFBSSxHQUFjLElBQUksQ0FBQyxJQUFLLENBQUMsUUFBUSxJQUFlLElBQUksQ0FBQyxJQUFLLENBQUMsUUFBUSxJQUFlLElBQUksQ0FBQyxJQUFLLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQVksSUFBSSxDQUFDLElBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFZLElBQUksQ0FBQyxJQUFLLENBQUMsYUFBYSxDQUFDO1FBRWxNLE9BQU8sVUFBVSxDQUFDLFVBQVUsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDO0lBQzlDLENBQUM7SUFFRCxNQUFNO1FBQ0YsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBVyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFZO1FBQ2YsSUFBZSxJQUFJLENBQUMsSUFBSyxDQUFDLFFBQVE7WUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDOztZQUNwRCxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXhCLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQVk7UUFDSixJQUFJLENBQUMsSUFBSyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDdEMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUN6QixJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDbEMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7U0FDM0I7UUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBWSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBRUQsUUFBUSxDQUFDLEtBQVk7UUFDTixJQUFJLENBQUMsSUFBSyxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUM7UUFDdkMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUN6QixJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDbEMsSUFBSSxDQUFDLGdCQUFnQ