ng-devui
Version:
DevUI components based on Angular
615 lines • 222 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { DOCUMENT } from '@angular/common';
import { Component, ContentChild, ElementRef, EventEmitter, HostListener, Inject, Input, Output, QueryList, TemplateRef, ViewChild, ViewChildren, } from '@angular/core';
import { I18nService } from 'ng-devui/i18n';
import { DevConfigService, WithConfig, expandCollapseForDomDestroy } from 'ng-devui/utils';
import { difference } from 'lodash-es';
import { TreeComponent } from './tree.component';
import * as i0 from "@angular/core";
import * as i1 from "ng-devui/i18n";
import * as i2 from "ng-devui/utils";
import * as i3 from "@angular/common";
import * as i4 from "@angular/forms";
import * as i5 from "ng-devui/loading";
import * as i6 from "ng-devui/checkbox";
import * as i7 from "ng-devui/popover";
import * as i8 from "./tree.component";
import * as i9 from "./tree-nodes.component";
import * as i10 from "./auto-focus.directive";
import * as i11 from "./pipe/transfer-to-array.pipe";
export class OperableTreeComponent {
static { this.ID_SEED = 0; }
constructor(doc, i18n, devConfigService) {
this.doc = doc;
this.i18n = i18n;
this.devConfigService = devConfigService;
this.checkable = true;
this.deletable = false;
this.addable = false;
this.editable = false;
this.draggable = false;
this.dropFromOutside = false;
this.checkboxInput = {};
this.canActivateNode = true;
this.canActivateParentNode = true;
this.canActivateMultipleNode = false;
this.treeNodeTitleKey = 'title';
this.virtualScroll = false;
this.virtualScrollHeight = '800px';
this.showAnimation = true;
this.itemSize = 30;
this.minBufferPx = 600;
this.maxBufferPx = 900;
this.checkableRelation = 'both';
this.indent = '16px';
/**
* @deprecated
*/
this.canIdEmpty = true;
this.operatorAlign = 'start';
this.nodeSelected = new EventEmitter();
this.nodeDblClicked = new EventEmitter();
this.nodeRightClicked = new EventEmitter();
this.nodeToggled = new EventEmitter();
this.afterTreeInit = new EventEmitter();
this.nodeDeleted = new EventEmitter();
this.nodeChecked = new EventEmitter();
this.currentNodeChecked = new EventEmitter();
this.nodeEdited = new EventEmitter();
this.editValueChange = new EventEmitter();
this.nodeDragStart = new EventEmitter();
this.nodeOnDrop = new EventEmitter();
this.dropType = {
dropPrev: false,
dropNext: false,
dropInner: true,
};
this.addingNode = false;
this.mouseRightButton = 2;
this.treeNodeDragoverResponder = {
node: null,
timeout: null,
};
this.dragState = {
showIndicator: true,
dropType: null,
draggingNode: null,
indicatorTop: 0,
indicatorLeft: 0,
indicatorWidth: 0,
};
this.afterInitAnimate = true;
this.isOpenedOonDragOver = [];
this.deleteNodesProxy = (event, treeNode) => {
this.deleteNodes(event, treeNode);
};
this.addChildNodeProxy = (event, treeNode, newNode) => {
this.addChildNode(event, treeNode, newNode);
};
this.editNodeProxy = (event, treeNode) => {
this.editNode(event, treeNode);
};
this.id = `d-operable-tree-${OperableTreeComponent.ID_SEED++}`;
this.document = this.doc;
}
ngOnInit() {
this.i18nCommonText = this.i18n.getI18nText().common;
this.i18nSubscription = this.i18n.langChange().subscribe((data) => {
this.i18nCommonText = data.common;
});
}
ngAfterViewInit() {
setTimeout(() => {
this.afterInitAnimate = false;
});
}
ngOnDestroy() {
if (this.i18nSubscription) {
this.i18nSubscription.unsubscribe();
}
}
contextmenuEvent(event, node) {
this.nodeRightClicked.emit({ node: node, event: event });
}
copyStyle(source, target) {
['id', 'class', 'style', 'draggable'].forEach((attr) => target.removeAttribute(attr));
const computedStyle = getComputedStyle(source);
for (let i = 0; i < computedStyle.length; i++) {
const key = computedStyle[i];
if (key.indexOf('transition') < 0) {
target.style[key] = computedStyle[key];
}
}
target.style.pointerEvents = 'none';
for (let i = 0; i < source.children.length; i++) {
this.copyStyle(source.children[i], target.children[i]);
}
}
multipleDragStyle(event, nodes, target) {
const num = nodes.length > 2 ? 2 : nodes.length - 1;
const cloneNodes = new Array(num).fill(null);
const container = this.document.createElement('div');
const cloneNode = target.cloneNode(true);
this.copyStyle(target, cloneNode);
cloneNode.style.position = 'absolute';
cloneNode.style.border = 'solid 1px var(--devui-connected-overlay-line, #526ecc)';
cloneNodes.push(cloneNode);
cloneNodes.forEach((node, index) => {
const child = node || cloneNode.cloneNode(true);
child.style.left = `${8 * (num - index)}px`;
child.style.top = `${4 * index}px`;
container.appendChild(child);
});
container.className = 'devui-tree-drag-ghost-container';
// setDragImage 只能对viewport内的 dom 起作用
this.document.body.appendChild(container);
event.dataTransfer.setDragImage(container, -16, 0);
setTimeout(() => container.remove());
}
onDragstart(event, treeNode) {
this.isOpenedOonDragOver = [];
this.dragState.draggingNode = event.target;
const result = { event, treeNode };
const data = {
type: 'operable-tree-node',
treeId: this.id,
nodeId: treeNode.id,
parentId: treeNode.parentId,
nodeTitle: treeNode.data.title,
isParent: treeNode.data.isParent,
isChecked: treeNode.data.isChecked,
halfChecked: treeNode.data.halfChecked,
};
if (this.canActivateMultipleNode) {
const activatedNodes = this.treeFactory.getActivatedNodes();
// 存在无激活项,直接拖拽单个节点情况
const availableNodes = activatedNodes.length ? activatedNodes : [treeNode];
data.multipleData = availableNodes;
result.treeNodes = availableNodes;
// 拖拽启用层叠样式,随拖拽个数变化
this.multipleDragStyle(event, availableNodes, event.target);
}
event.dataTransfer.setData('Text', JSON.stringify(data));
this.nodeDragStart.emit(result);
}
onDragover(event, droppable, treeNode) {
if (droppable) {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
if (this.dropType.dropInner &&
(!this.treeNodeDragoverResponder.node ||
(this.treeNodeDragoverResponder.node && this.treeNodeDragoverResponder.node.id !== treeNode.id))) {
clearTimeout(this.treeNodeDragoverResponder.timeout);
this.treeNodeDragoverResponder.node = treeNode;
this.treeNodeDragoverResponder.timeout = setTimeout(() => {
if (treeNode.data.isParent && !treeNode.data.isOpen) {
this.isOpenedOonDragOver.push(treeNode.id);
this.treeFactory.openNodesById(treeNode.id);
this.nodeToggled.emit(treeNode);
}
}, 1000);
}
this.handlerDragState(event, treeNode);
}
}
handlerDragState(event, treeNode) {
let dropType;
const dropPrev = this.dropType.dropPrev;
const dropNext = this.dropType.dropNext;
const dropInner = this.dropType.dropInner;
const treePosition = this.operableTreeEle.nativeElement.getBoundingClientRect();
const nextRes = dropNext ? 0.45 : 1;
const innerNextRes = dropInner ? 0.25 : nextRes;
const prevPercent = dropPrev ? innerNextRes : -1;
const prevRes = dropPrev ? 0.55 : 0;
const innerPrevRes = dropInner ? 0.75 : prevRes;
const nextPercent = dropNext ? innerPrevRes : 1;
const targetPosition = event.currentTarget.getBoundingClientRect();
const dom = event.currentTarget.querySelector('.devui-tree-drag-handle') || event.currentTarget.querySelector('.devui-tree-node__title');
const treeNodePosition = dom.getBoundingClientRect();
const distance = event.clientY - targetPosition.top;
if (distance < targetPosition.height * prevPercent) {
dropType = 'prev';
}
else if (distance > targetPosition.height * nextPercent) {
dropType = 'next';
}
else if (dropInner) {
dropType = 'inner';
}
else {
dropType = 'none';
}
if (dropType === 'prev') {
this.dragState.indicatorTop = treeNodePosition.top - treePosition.top - 10;
}
if (dropType === 'next') {
this.dragState.indicatorTop = treeNodePosition.bottom - treePosition.top + 10;
}
if (dropType === 'inner') {
event.currentTarget.classList.add('devui-drop-inner');
}
else {
event.currentTarget.classList.remove('devui-drop-inner');
}
this.dragState.indicatorLeft = treeNodePosition.left - treePosition.left;
this.dragState.indicatorWidth = treePosition.width - this.dragState.indicatorLeft;
this.dragState.dropType = dropType;
this.dragState.showIndicator = dropType === 'prev' || dropType === 'next';
}
onDragleave(event, treeNode) {
this.removeDraggingStyle(event.currentTarget);
if (this.treeNodeDragoverResponder.node && this.treeNodeDragoverResponder.node.id === treeNode.id) {
this.treeNodeDragoverResponder.node = null;
clearTimeout(this.treeNodeDragoverResponder.timeout);
}
}
removeDraggingStyle(target) {
this.dragState.showIndicator = false;
target.classList.remove('devui-drop-inner');
}
onDrop(event, dropNode) {
this.removeDraggingStyle(event.currentTarget);
if (!this.draggable && !this.dropFromOutside) {
return;
}
event.preventDefault();
const transferDataStr = event.dataTransfer.getData('Text');
if (transferDataStr) {
try {
const transferData = JSON.parse(transferDataStr);
if (typeof transferData === 'object' && transferData.type === 'operable-tree-node' && transferData.treeId === this.id) {
let dragResult = Promise.resolve(true);
const dragNodeId = transferData.nodeId;
const dragNodeIds = [];
const dropNodeId = dropNode.id;
// 使用对象存储选择状态,因为节点id为数字,避免产生长索引数组影响性能
const dragNodesCheckStatus = {};
const multipleData = transferData.multipleData;
if (this.canActivateMultipleNode && multipleData?.length > 1) {
// 多选时遍历所有被激活的节点确认是否为目标节点或其父节点并储存可用节点的选择状态
// 反序遍历用于先处理子节点以更新父子同时拖拽的状态
multipleData.reverse().forEach((node) => this.reverseSelection(node, dropNodeId, dragNodeIds, dragNodesCheckStatus));
}
else {
const isParent = this.treeFactory.checkIsParent(dropNodeId, dragNodeId);
if (dragNodeId === dropNodeId || isParent) {
return;
}
this.treeFactory.checkNodesById(dragNodeId, false, 'upward');
dragNodesCheckStatus[dragNodeId] = { checked: transferData.isChecked, halfChecked: transferData.halfChecked };
}
if (this.beforeNodeDrop) {
dragResult = this.beforeNodeDrop(dragNodeId, dropNodeId, this.dragState.dropType, dragNodeIds);
}
dragResult
.then(() => {
this.setSelection(dropNode, dragNodeId, dragNodeIds, dragNodesCheckStatus);
if (this.nodeOnDrop.observers.length > 0) {
if (this.isOpenedOonDragOver.length) {
const ids = this.treeFactory.getLineage(dropNode);
this.isOpenedOonDragOver = difference(this.isOpenedOonDragOver, ids);
}
this.nodeOnDrop.emit({ event, treeNode: dropNode, dropType: this.dragState.dropType });
}
});
}
else {
this.dropFormOutside(event, dropNode);
}
}
catch (e) {
this.dropFormOutside(event, dropNode);
}
}
}
dropFormOutside(event, dropNode) {
if (this.dropFromOutside && this.nodeOnDrop.observers.length > 0) {
this.nodeOnDrop.emit({ event, treeNode: dropNode, dropType: this.dragState.dropType, isFromOutside: true });
}
}
onDragend() {
this.isOpenedOonDragOver.forEach((id) => this.treeFactory.closeNodesById(id));
this.isOpenedOonDragOver = [];
}
reverseSelection(node, dropNodeId, dragNodeIds, dragNodesCheckStatus) {
const id = node.id;
const isParent = this.treeFactory.checkIsParent(dropNodeId, id);
if (!isParent && id !== dropNodeId) {
this.treeFactory.checkNodesById(id, false, 'upward');
// 获取更新后的node状态,不使用node旧数据避免父子同时拖拽状态被覆盖
const currentNode = this.treeFactory.getNodeById(id);
// 半选不保留,取最新状态,选中则保留原有状态
const checkedStatus = node.data.halfChecked ? currentNode.isChecked : node.data.isChecked;
dragNodesCheckStatus[id] = { checked: checkedStatus, halfChecked: currentNode.halfChecked };
dragNodeIds.push(id);
}
}
setSelection(dropNode, dragNodeId, dragNodeIds, dragNodesCheckStatus) {
let finalDragNodeIds = [dragNodeId];
if (this.canActivateMultipleNode && dragNodeIds?.length > 1) {
dragNodeIds.reverse().forEach((id) => this.handleDropNode(id, dropNode));
finalDragNodeIds = dragNodeIds;
}
else {
this.handleDropNode(dragNodeId, dropNode);
}
this.treeFactory.renderFlattenTree();
// 移动结束后向上整理选择状态,恢复半选状态
finalDragNodeIds.forEach((id) => {
const node = this.treeFactory.getCompleteNodeById(id);
node.data.isChecked = dragNodesCheckStatus[id].checked;
node.data.halfChecked = dragNodesCheckStatus[id].halfChecked;
this.treeFactory.checkParentNodes(node);
});
}
handleDropNode(dragNodeId, dropNode) {
const movingNode = this.treeFactory.nodes[dragNodeId];
const movingNodeIndex = this.treeFactory.getNodeIndex(movingNode);
const dropNodeIndex = this.treeFactory.getNodeIndex(dropNode);
const hasParentId = this.canIdEmpty ? movingNode.parentId : movingNode.parentId !== undefined;
const originalParentNode = hasParentId ? this.treeFactory.nodes[movingNode.parentId] : this.treeFactory.treeRoot;
switch (this.dragState.dropType) {
case 'prev':
this.handlerDropSort(movingNodeIndex, dropNodeIndex, movingNode, dropNode, originalParentNode, 'prev');
break;
case 'next':
this.handlerDropSort(movingNodeIndex, dropNodeIndex, movingNode, dropNode, originalParentNode, 'next');
break;
case 'inner':
this.handlerDropInner(movingNodeIndex, movingNode, dropNode, originalParentNode);
break;
default:
}
}
handlerDropSort(oldIndex, newIndex, movingNode, dropNode, originalParentNode, type) {
const dropIndex = type === 'next' ? newIndex + 1 : newIndex;
movingNode.parentId = dropNode.parentId;
let parentNode;
if (dropNode.parentId === undefined) {
parentNode = this.treeFactory.treeRoot;
parentNode.splice(dropIndex, 0, movingNode);
}
else {
parentNode = this.treeFactory.getNodeById(dropNode.parentId);
parentNode.children.splice(dropIndex, 0, movingNode);
}
if (dropNode.parentId === originalParentNode.id && newIndex < oldIndex) {
this.handlerOriginalParentNode(originalParentNode, oldIndex + 1);
}
else {
this.handlerOriginalParentNode(originalParentNode, oldIndex);
}
}
handlerOriginalParentNode(originalParentNode, oldIndex) {
if (originalParentNode.id === undefined) {
originalParentNode.splice(oldIndex, 1);
}
else {
originalParentNode.data.children.splice(oldIndex, 1);
if (!originalParentNode.data.children || !originalParentNode.data.children.length) {
originalParentNode.data.isParent = false;
}
}
}
handlerDropInner(oldIndex, movingNode, dropNode, originalParentNode) {
movingNode.parentId = dropNode.id;
dropNode.data.isParent = true;
this.treeFactory.openNodesById(dropNode.id);
this.treeFactory.addChildNode(dropNode, movingNode);
this.handlerOriginalParentNode(originalParentNode, oldIndex);
this.nodeToggled.emit(dropNode);
}
selectNode(event, treeNode) {
if (treeNode.data.disableSelect) {
return;
}
if (!this.operableTree.isSelectableRegion(event.target)) {
return;
}
let selectResult = Promise.resolve(true);
if (this.beforeSelectNode) {
selectResult = this.beforeSelectNode(treeNode);
}
selectResult.then((canSelect) => {
if (!canSelect) {
return;
}
if (!this.canActivateNode) {
this.checkNode(event, treeNode);
return;
}
if (this.canActivateParentNode || (!this.canActivateParentNode && !treeNode.data.isParent)) {
const isMultiple = this.canActivateMultipleNode && (event.ctrlKey || event.shiftKey);
this.treeFactory.activeNodeById(treeNode.id, isMultiple);
if (isMultiple) {
this.nodeSelected.emit(this.treeFactory.getActivatedNodes());
return;
}
}
else {
this.toggleNode(event, treeNode);
return;
}
this.nodeSelected.emit(treeNode);
});
}
toggleNode(event, treeNode) {
if (treeNode.data.disableToggle) {
return;
}
this.treeFactory.toggleNodeById(treeNode.id);
this.nodeToggled.emit(treeNode);
}
deleteNodes(event, treeNode) {
let delResult = Promise.resolve(true);
if (this.beforeDeleteNode) {
delResult = this.beforeDeleteNode(treeNode);
}
delResult.then((canDelete) => {
if (!canDelete) {
return;
}
this.treeFactory.deleteNodeById(treeNode.id);
this.nodeDeleted.emit(treeNode);
});
}
addChildNode(event, treeNode, newNode) {
let addResult = Promise.resolve(newNode ? newNode : true);
if (this.beforeAddNode) {
addResult = this.beforeAddNode(treeNode);
}
addResult.then((nodeInfo) => {
if (!nodeInfo) {
return;
}
const node = this.treeFactory.addNode({
parentId: treeNode.id,
title: nodeInfo.title ? nodeInfo.title : '新增节点',
isParent: nodeInfo.isParent,
id: nodeInfo.id ? nodeInfo.id : undefined,
data: nodeInfo.data,
}, nodeInfo.index, false);
this.treeFactory.editNodeTitle(node.id);
this.addingNode = true;
treeNode.data.isParent = true;
this.treeFactory.openNodesById(treeNode.id);
return treeNode;
});
}
editNode(event, treeNode) {
let editResult = Promise.resolve(true);
if (this.beforeEditNode) {
editResult = this.beforeEditNode(treeNode);
}
editResult.then((canEdit) => {
if (!canEdit) {
return;
}
this.treeFactory.editNodeTitle(treeNode.id);
});
}
checkNodeById(checked, id) {
const results = this.treeFactory.checkNodesById(id, checked, this.checkableRelation);
this.nodeChecked.emit(results);
this.currentNodeChecked.emit({ id: id, data: this.treeFactory.getNodeById(id) });
}
onBlurEdit(treeNode) {
if (!treeNode.data.errTips) {
treeNode.data.editable = false;
return this.postEditNode(treeNode);
}
}
onInputChange(event, treeNode) {
const targe = event.target;
this.editValueChange.emit({
value: targe.value,
callback: (validateInfo) => {
if (validateInfo && validateInfo.errTips) {
treeNode.data.errTips = validateInfo.errTips;
treeNode.data.errTipsPosition = validateInfo.errTipsPosition || 'top';
}
else {
if (treeNode.data.errTips) {
delete treeNode.data.errTips;
delete treeNode.data.errTipsPosition;
}
}
},
});
}
treeNodeHover(treeNode, type) {
if (this.disableMouseEvent || treeNode.data.disableMouseEvent) {
return;
}
treeNode.data.isHover = type === 'enter';
}
isSelectedNode(node) {
if (this.checkable) {
return node.isChecked;
}
else {
return node.isActive;
}
}
get nodes() {
return this.operableTree ? Object.keys(this.treeFactory.nodes).map((k) => this.treeFactory.nodes[k]) : [];
}
postEditNode(treeNode) {
if (this.addingNode === true) {
this.addingNode = false;
if (typeof this.postAddNode === 'function') {
const originalId = treeNode.id;
return this.postAddNode(treeNode)
.then((nodeInfo) => {
// Swap id if id was modified by outer system
treeNode.id = nodeInfo.id ? nodeInfo.id : originalId;
delete this.treeFactory.nodes[originalId];
if (Object.prototype.hasOwnProperty.call(nodeInfo, 'data') && nodeInfo.data) {
if (Object.prototype.hasOwnProperty.call(treeNode, 'data') && Object.prototype.hasOwnProperty.call(treeNode.data, 'data')) {
treeNode.data.data = { ...treeNode.data.data, ...nodeInfo.data };
}
else {
treeNode.data = Object.assign(treeNode.data, { data: nodeInfo.data });
}
}
this.treeFactory.nodes[treeNode.id] = treeNode;
return treeNode;
})
.catch((e, reaction = 'cancel') => {
switch (reaction) {
case 'justify': {
const parentNode = this.treeFactory.nodes[treeNode.parentId];
const title = treeNode.data.title;
this.treeFactory.deleteNodeById(treeNode.id);
this.addChildNode(null, parentNode, { title: title });
break;
}
case 'cancel':
default:
this.treeFactory.deleteNodeById(treeNode.id);
}
return Promise.reject(e);
});
}
}
else {
this.nodeEdited.emit(treeNode);
}
return Promise.resolve(treeNode);
}
appendTreeItems(treeItems, parentId) {
if (!this.treeFactory.nodes[parentId]) {
throw new Error('parent node does not exist.');
}
this.treeFactory.mapTreeItems({
treeItems: treeItems,
parentId: parentId,
treeNodeChildrenKey: this.treeNodeChildrenKey,
treeNodeIdKey: this.treeNodeIdKey,
checkboxDisabledKey: this.checkboxDisabledKey,
selectDisabledKey: this.selectDisabledKey,
toggleDisabledKey: this.toggleDisabledKey,
treeNodeTitleKey: this.treeNodeTitleKey,
});
}
get treeFactory() {
return this.operableTree.treeFactory;
}
checkNode(checked, treeNode) {
if (!treeNode.data.disabled) {
treeNode.data.isChecked = !treeNode.data.isChecked;
this.checkNodeById(treeNode.data.isChecked, treeNode.id);
}
}
nodeDblClick(event, node) {
this.nodeDblClicked.emit(node);
}
initTreeFinishEvent($event) {
this.afterTreeInit.emit($event);
}
eventTriggerBlur(event) {
event.target.blur();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OperableTreeComponent, deps: [{ token: DOCUMENT }, { token: i1.I18nService }, { token: i2.DevConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: OperableTreeComponent, selector: "d-operable-tree", inputs: { tree: "tree", treeNodeIdKey: "treeNodeIdKey", treeNodeChildrenKey: "treeNodeChildrenKey", checkboxDisabledKey: "checkboxDisabledKey", selectDisabledKey: "selectDisabledKey", toggleDisabledKey: "toggleDisabledKey", iconParentOpen: "iconParentOpen", iconParentClose: "iconParentClose", iconLeaf: "iconLeaf", showLoading: "showLoading", loadingTemplateRef: "loadingTemplateRef", treeNodesRef: "treeNodesRef", checkable: "checkable", deletable: "deletable", addable: "addable", editable: "editable", draggable: "draggable", dropFromOutside: "dropFromOutside", disableMouseEvent: "disableMouseEvent", checkboxInput: "checkboxInput", beforeAddNode: "beforeAddNode", beforeDeleteNode: "beforeDeleteNode", beforeEditNode: "beforeEditNode", beforeSelectNode: "beforeSelectNode", beforeNodeDrop: "beforeNodeDrop", canActivateNode: "canActivateNode", canActivateParentNode: "canActivateParentNode", canActivateMultipleNode: "canActivateMultipleNode", treeNodeTitleKey: "treeNodeTitleKey", postAddNode: "postAddNode", iconTemplatePosition: "iconTemplatePosition", virtualScroll: "virtualScroll", virtualScrollHeight: "virtualScrollHeight", showAnimation: "showAnimation", itemSize: "itemSize", minBufferPx: "minBufferPx", maxBufferPx: "maxBufferPx", checkableRelation: "checkableRelation", indent: "indent", canIdEmpty: "canIdEmpty", operatorAlign: "operatorAlign", dropType: "dropType" }, outputs: { nodeSelected: "nodeSelected", nodeDblClicked: "nodeDblClicked", nodeRightClicked: "nodeRightClicked", nodeToggled: "nodeToggled", afterTreeInit: "afterTreeInit", nodeDeleted: "nodeDeleted", nodeChecked: "nodeChecked", currentNodeChecked: "currentNodeChecked", nodeEdited: "nodeEdited", editValueChange: "editValueChange", nodeDragStart: "nodeDragStart", nodeOnDrop: "nodeOnDrop" }, host: { listeners: { "dragend": "onDragend()" } }, queries: [{ propertyName: "iconTemplate", first: true, predicate: ["iconTemplate"], descendants: true }, { propertyName: "nodeTemplate", first: true, predicate: ["nodeTemplate"], descendants: true }, { propertyName: "operatorTemplate", first: true, predicate: ["operatorTemplate"], descendants: true }, { propertyName: "statusTemplate", first: true, predicate: ["statusTemplate"], descendants: true }], viewQueries: [{ propertyName: "operableTree", first: true, predicate: ["operableTree"], descendants: true, static: true }, { propertyName: "operableTreeEle", first: true, predicate: ["operableTreeContainer"], descendants: true, static: true }, { propertyName: "treeDropIndicator", first: true, predicate: ["treeDropIndicator"], descendants: true }, { propertyName: "treeNodeContent", predicate: ["treeNodeContent"], descendants: true }], exportAs: ["dOperableTreeComponent"], ngImport: i0, template: "<div #operableTreeContainer style=\"position: relative\">\n <d-tree\n #operableTree\n [tree]=\"tree\"\n [virtualScroll]=\"virtualScroll\"\n [treeNodeIdKey]=\"treeNodeIdKey\"\n [treeNodeChildrenKey]=\"treeNodeChildrenKey\"\n [treeNodesRef]=\"treeNodesRef ? treeNodesRef : virtualScroll ? operableTreeVirtualScrollRef : operableTreeNodeRef\"\n [iconParentOpen]=\"iconParentOpen\"\n [iconParentClose]=\"iconParentClose\"\n [iconLeaf]=\"iconLeaf\"\n [treeNodeTitleKey]=\"treeNodeTitleKey\"\n [checkboxDisabledKey]=\"checkboxDisabledKey\"\n [selectDisabledKey]=\"selectDisabledKey\"\n [toggleDisabledKey]=\"toggleDisabledKey\"\n [virtualScrollHeight]=\"virtualScrollHeight\"\n [minBufferPx]=\"minBufferPx\"\n [maxBufferPx]=\"maxBufferPx\"\n [itemSize]=\"itemSize\"\n [indent]=\"indent\"\n [canIdEmpty]=\"canIdEmpty\"\n (afterTreeInit)=\"initTreeFinishEvent($event)\"\n >\n </d-tree>\n <div\n *ngIf=\"dragState.showIndicator\"\n #treeDropIndicator\n class=\"devui-tree-indicator\"\n [style.top.px]=\"dragState.indicatorTop\"\n [style.width.px]=\"dragState.indicatorWidth\"\n [style.left.px]=\"dragState.indicatorLeft\"\n ></div>\n</div>\n<!-- TODO: \u865A\u62DF\u6EDA\u52A8\u652F\u6301\u52A8\u6548 -->\n<ng-template #operableTreeVirtualScrollRef let-treeNode=\"treeNode\" let-treeFactory=\"treeFactory\">\n <div\n *ngIf=\"!treeNode.data.isHide\"\n [id]=\"'devui-tree-node-' + treeNode.id\"\n class=\"devui-tree-node devui-operable-tree-node\"\n [style.paddingLeft.px]=\"treeNode.data.depth * 24\"\n [ngClass]=\"{\n selected: isSelectedNode(treeNode.data),\n 'devui-tree-node__open': treeNode.data.isOpen,\n 'devui-tree-node__customIcon': iconParentClose\n }\"\n #treeNodeContent\n >\n <div\n class=\"devui-tree-vertical-line\"\n *ngFor=\"let item of treeNode.data.depth | transferToArrayPipe; let i = index\"\n [style.marginLeft.px]=\"i === 0 ? -16 : -16 - 24 * i\"\n [ngStyle]=\"{ height: i === 0 && treeNode.data.isLast && !treeNode.data.isOpen ? '15px' : '30px' }\"\n ></div>\n <div\n *ngIf=\"treeNode.data.depth\"\n [ngStyle]=\"{ width: treeNode.data.isParent ? '8px' : '16px' }\"\n class=\"devui-tree-horizontal-line\"\n ></div>\n <div\n class=\"devui-tree-node__content\"\n [class.active]=\"treeNode.data.isActive\"\n [class.devui-tree-node--parent]=\"(treeNode.data.children || []).length > 0\"\n (mouseenter)=\"treeNodeHover(treeNode, 'enter')\"\n (mouseleave)=\"treeNodeHover(treeNode, 'leave')\"\n [draggable]=\"draggable && !treeNode?.data?.editable\"\n (dragstart)=\"onDragstart($event, treeNode)\"\n (dragover)=\"onDragover($event, draggable, treeNode)\"\n (dragleave)=\"onDragleave($event, treeNode)\"\n (drop)=\"onDrop($event, treeNode)\"\n [class.disabled]=\"treeNode.data.disabled\"\n (click)=\"selectNode($event, treeNode)\"\n >\n <div class=\"devui-tree-node__content--value-wrapper\" [class.isMatch]=\"treeNode.data.isMatch\">\n <span\n (click)=\"toggleNode($event, treeNode)\"\n *ngIf=\"(treeNode.data.children || []).length > 0 || treeNode.data.isParent\"\n class=\"devui-tree-node__folder\"\n [class.toggle-disabled]=\"treeNode.data.disableToggle\"\n >\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: iconParentClose && !treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n [innerHTML]=\"iconParentClose | safe : 'html'\"\n ></span>\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: iconParentOpen && treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n [innerHTML]=\"iconParentOpen | safe : 'html'\"\n ></span>\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: !iconParentOpen && !treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n class=\"svg-icon\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"2\"></rect>\n <path\n d=\"M8.75,4 L8.75,7.25 L12,7.25 L12,8.75 L8.749,8.75 L8.75,12 L7.25,12 L7.249,8.75 L4,8.75 L4,7.25 L7.25,7.25 L7.25,4 L8.75,4 Z\"\n ></path>\n </g>\n </svg>\n </span>\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: !iconParentOpen && treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n class=\"svg-icon svg-icon-close\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"2\"></rect>\n <rect x=\"4\" y=\"7\" width=\"8\" height=\"2\"></rect>\n </g>\n </svg>\n </span>\n </span>\n <span class=\"devui-tree-node__leaf\" *ngIf=\"(treeNode.data.children || []).length === 0 && !treeNode.data.isParent\">\n <span *ngIf=\"!iconLeaf\" class=\"devui-leaf-icon-none\" [ngStyle]=\"{ width: indent }\"></span>\n <span *ngIf=\"iconLeaf\" [innerHTML]=\"iconLeaf | safe : 'html'\"></span>\n </span>\n <ng-container *ngIf=\"iconTemplate && iconTemplatePosition === 'before-checkbox'\">\n <ng-template [ngTemplateOutlet]=\"iconTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode.data, completeNode: treeNode }\">\n </ng-template>\n </ng-container>\n <d-checkbox\n *ngIf=\"checkable && (treeNode.data.showCheckbox === undefined ? true : treeNode.data.showCheckbox)\"\n [showAnimation]=\"treeNode.data.isHover\"\n [(ngModel)]=\"treeNode.data.isChecked\"\n (ngModelChange)=\"checkNodeById($event, treeNode.id)\"\n [halfchecked]=\"treeNode.data.halfChecked\"\n [color]=\"checkboxInput?.color\"\n [cssClass]=\"'devui-tree-node__checkbox'\"\n [disabled]=\"treeNode.data.disabled\"\n [showGlowStyle]=\"!virtualScroll\"\n >\n </d-checkbox>\n <ng-container *ngIf=\"iconTemplate && (!iconTemplatePosition || iconTemplatePosition === 'after-checkbox')\">\n <ng-template [ngTemplateOutlet]=\"iconTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode.data, completeNode: treeNode }\">\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"nodeTemplate\">\n <ng-template [ngTemplateOutlet]=\"nodeTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode.data, completeNode: treeNode }\">\n </ng-template>\n </ng-container>\n <span\n *ngIf=\"!nodeTemplate && !treeNode.data?.editable\"\n (dblclick)=\"nodeDblClick($event, treeNode)\"\n (contextmenu)=\"contextmenuEvent($event, treeNode)\"\n class=\"devui-tree-node__title devui-tree-drag-handle\"\n [class.select-disabled]=\"treeNode.data.disableSelect\"\n title=\"{{ treeNode.data.title }}\"\n >\n <d-highlight\n *ngIf=\"treeNode.data?.isMatch && !treeNode.data?.isCustomSearch\"\n [value]=\"treeNode.data.title\"\n [term]=\"treeFactory.searchItem\"\n >\n </d-highlight>\n <span *ngIf=\"treeNode.data?.isMatch && treeNode.data?.isCustomSearch\" class=\"devui-tree-node-highlight\">{{\n treeNode.data.title\n }}</span>\n <ng-container *ngIf=\"!treeNode.data?.isMatch\">{{ treeNode.data.title }}</ng-container>\n </span>\n <span class=\"devui-tree-node__edit\" *ngIf=\"!nodeTemplate && treeNode.data?.editable\">\n <input\n [class.error]=\"!!treeNode.data.errTips\"\n class=\"devui-form-control devui-input-sm\"\n type=\"text\"\n dTreeAutoFocus\n [(ngModel)]=\"treeNode.data.title\"\n (blur)=\"onBlurEdit(treeNode)\"\n (keyup.enter)=\"eventTriggerBlur($event)\"\n (input)=\"onInputChange($event, treeNode)\"\n dPopover\n [content]=\"treeNode.data.errTips\"\n [position]=\"treeNode.data.errTipsPosition\"\n [appendToBody]=\"true\"\n [visible]=\"!!treeNode.data.errTips\"\n [popType]=\"'error'\"\n />\n </span>\n <ng-container *ngIf=\"statusTemplate\">\n <ng-template [ngTemplateOutlet]=\"statusTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode }\"> </ng-template>\n </ng-container>\n <span\n dLoading\n [showLoading]=\"treeNode.data.loading\"\n [loadingTemplateRef]=\"loadingTemplateRef ? loadingTemplateRef : defaultLoadingTmpl\"\n >\n </span>\n <div class=\"devui-tree-icons-container\">\n <span\n class=\"devui-tree-icons\"\n *ngIf=\"!treeNode.data.disableAdd && (treeNode.data.isActive || treeNode.data.isHover) && addable\"\n (click)=\"addChildNode($event, treeNode)\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g fill-rule=\"nonzero\">\n <path\n d=\"M8,0 C12.418278,0 16,3.59071231 16,8 C16,12.418278 12.4092877,16 8,16 C3.581722,16 0,12.4092877 0,8 C0,3.581722 3.59071231,0 8,0 Z M8,1.5 C4.41577399,1.5 1.5,4.41351238 1.5,8 C1.5,11.584226 4.41351238,14.5 8,14.5 C11.584226,14.5 14.5,11.5864876 14.5,8 C14.5,4.41577399 11.5864876,1.5 8,1.5 Z M8,4.3 C8.38659932,4.3 8.7,4.61340068 8.7,5 L8.699,7.299 L11,7.3 C11.3865993,7.3 11.7,7.61340068 11.7,8 C11.7,8.38659932 11.3865993,8.7 11,8.7 L8.699,8.699 L8.7,11 C8.7,11.3865993 8.38659932,11.7 8,11.7 C7.61340068,11.7 7.3,11.3865993 7.3,11 L7.299,8.699 L5,8.7 C4.61340068,8.7 4.3,8.38659932 4.3,8 C4.3,7.61340068 4.61340068,7.3 5,7.3 L7.299,7.299 L7.3,5 C7.3,4.61340068 7.61340068,4.3 8,4.3 Z\"\n ></path>\n </g>\n </g>\n </svg>\n </span>\n <span\n class=\"devui-tree-icons\"\n *ngIf=\"!treeNode.data.disableEdit && (treeNode.data.isActive || treeNode.data.isHover) && editable\"\n (click)=\"editNode($event, treeNode)\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M12.3087741,0.74795609 L14.4300944,2.86927643 C14.9182498,3.3574318 14.9182498,4.14888802 14.4300944,4.63704339 L6.76529422,12.3018436 C6.6135568,12.453581 6.42531143,12.5637003 6.21868103,12.6215999 L3.29553945,13.4406895 C2.63078755,13.6269587 1.9408986,13.2390719 1.75462937,12.57432 C1.69358229,12.356457 1.69281139,12.1261099 1.75239888,11.9078433 L2.55548559,8.96616788 C2.61274771,8.75641893 2.7237298,8.5652334 2.87747239,8.41149081 L10.5410071,0.74795609 C11.0291625,0.259800726 11.8206187,0.259800726 12.3087741,0.74795609 Z M11.4248906,1.98539296 L3.98505387,9.42522967 L3.31563544,11.8772834 L5.75092262,11.1948948 L13.1926575,3.75315991 L11.4248906,1.98539296 Z\"\n fill-rule=\"nonzero\"\n ></path>\n <rect fill-rule=\"nonzero\" x=\"0\" y=\"14.5\" width=\"15\" height=\"1.5\" rx=\"0.75\"></rect>\n </g>\n </svg>\n </span>\n <span\n class=\"devui-tree-icons\"\n *ngIf=\"!treeNode.data.disableDelete && (treeNode.data.isActive || treeNode.data.isHover) && deletable\"\n (click)=\"deleteNodes($event, treeNode)\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g fill-rule=\"nonzero\">\n <path\n d=\"M13.0996399,1.27743711 C13.4935963,0.882043175 14.1784277,0.912988481 14.6292951,1.34651479 C15.0800797,1.78012228 15.1261817,2.45212782 14.7322253,2.84752174 L9.59690531,7.99860255 L14.7322253,13.1524782 C15.0903675,13.5119272 15.084825,14.0999809 14.7421763,14.5297048 L14.6292951,14.6534852 C14.1784277,15.0870115 13.4935963,15.1179567 13.0996399,14.7225628 L8,9.60284628 L2.90036004,14.7225628 C2.54221791,15.082012 1.94368316,15.0891145 1.49907515,14.7617204 L1.37070487,14.6534852 C0.919920289,14.2198777 0.873818322,13.5478721 1.26777466,13.1524782 L6.40166885,7.99860255 L1.26777466,2.84752174 C0.909632535,2.48807271 0.915174959,1.90001906 1.25782365,1.47029514 L1.37070487,1.34651479 C1.82157229,0.912988481 2.50640369,0.882043175 2.90036004,1.27743711 L8,6.39575625 L13.0996399,1.27743711 Z\"\n ></path>\n </g>\n </g>\n </svg>\n </span>\n <ng-container *ngIf=\"operatorTemplate && (treeNode.data.isActive || treeNode.data.isHover)\">\n <ng-template\n [ngTemplateOutlet]=\"operatorTemplate\"\n [ngTemplateOutletContext]=\"{\n $implicit: this,\n node: treeNode,\n addNode: addChildNodeProxy,\n editNode: editNodeProxy,\n deleteNode: deleteNodesProxy\n }\"\n >\n </ng-template>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n<ng-template #operableTreeNodeRef let-treeNode=\"treeNode\" let-treeFactory=\"treeFactory\">\n <div\n class=\"devui-tree-node devui-operable-tree-node devui-tree-without-virtual-scroll\"\n [style.display]=\"treeNode.data.isHide ? 'none' : ''\"\n [ngClass]=\"{\n selected: isSelectedNode(treeNode.data),\n 'devui-tree-node__open': treeNode.data.isOpen,\n 'devui-tree-node__customIcon': iconParentClose\n }\"\n #treeNodeContent\n >\n <div\n class=\"devui-tree-node__content\"\n [class.active]=\"treeNode.data.isActive\"\n [class.devui-tree-node--parent]=\"(treeNode.data.children || []).length > 0\"\n (mouseenter)=\"treeNodeHover(treeNode, 'enter')\"\n (mouseleave)=\"treeNodeHover(treeNode, 'leave')\"\n [draggable]=\"draggable && !treeNode?.data?.editable\"\n (dragstart)=\"onDragstart($event, treeNode)\"\n (dragover)=\"onDragover($event, draggable, treeNode)\"\n (dragleave)=\"onDragleave($event, treeNode)\"\n (drop)=\"onDrop($event, treeNode)\"\n [class.disabled]=\"treeNode.data.disabled\"\n (click)=\"selectNode($event, treeNode)\"\n >\n <div class=\"devui-tree-node__content--value-wrapper\" [class.isMatch]=\"treeNode.data.isMatch\">\n <span\n (click)=\"toggleNode($event, treeNode)\"\n *ngIf=\"(treeNode.data.children || []).length > 0 || treeNode.data.isParent\"\n class=\"devui-tree-node__folder\"\n [class.toggle-disabled]=\"treeNode.data.disableToggle\"\n >\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: iconParentClose && !treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n [innerHTML]=\"iconParentClose | safe : 'html'\"\n ></span>\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: iconParentOpen && treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n [innerHTML]=\"iconParentOpen | safe : 'html'\"\n ></span>\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: !iconParentOpen && !treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n class=\"svg-icon\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"2\"></rect>\n <path\n d=\"M8.75,4 L8.75,7.25 L12,7.25 L12,8.75 L8.749,8.75 L8.75,12 L7.25,12 L7.249,8.75 L4,8.75 L4,7.25 L7.25,7.25 L7.25,4 L8.75,4 Z\"\n ></path>\n </g>\n </svg>\n </span>\n <span\n class=\"devui-tree-node__folder--icon\"\n [ngStyle]=\"{\n display: !iconParentOpen && treeNode.data.isOpen ? 'inline-block' : 'none'\n }\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n class=\"svg-icon svg-icon-close\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"2\"></rect>\n <rect x=\"4\" y=\"7\" width=\"8\" height=\"2\"></rect>\n </g>\n </svg>\n </span>\n </span>\n <span class=\"devui-tree-node__leaf\" *ngIf=\"(treeNode.data.children || []).length === 0 && !treeNode.data.isParent\">\n <span *ngIf=\"!iconLeaf\" class=\"devui-leaf-icon-none\" [ngStyle]=\"{ width: indent }\"></span>\n <span *ngIf=\"iconLeaf\" [innerHTML]=\"iconLeaf | safe : 'html'\"></span>\n </span>\n <ng-container *ngIf=\"iconTemplate && iconTemplatePosition === 'before-checkbox'\">\n <ng-template [ngTemplateOutlet]=\"iconTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode.data, completeNode: treeNode }\">\n </ng-template>\n </ng-container>\n <d-checkbox\n *ngIf=\"checkable && checkable && (treeNode.data.showCheckbox === undefined ? true : treeNode.data.showCheckbox)\"\n [(ngModel)]=\"treeNode.data.isChecked\"\n (ngModelChange)=\"checkNodeById($event, treeNode.id)\"\n [halfchecked]=\"treeNode.data.halfChecked\"\n [color]=\"checkboxInput?.color\"\n [cssClass]=\"'devui-tree-node__checkbox'\"\n [disabled]=\"treeNode.data.disabled\"\n [showGlowStyle]=\"!virtualScroll\"\n >\n </d-checkbox>\n <ng-container *ngIf=\"iconTemplate && (!iconTemplatePosition || iconTemplatePosition === 'after-checkbox')\">\n <ng-template [ngTemplateOutlet]=\"iconTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode.data, completeNode: treeNode }\">\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"nodeTemplate\">\n <ng-template [ngTemplateOutlet]=\"nodeTemplate\" [ngTemplateOutletContext]=\"{ node: treeNode.data, completeNode: treeNode }\">\n </ng-template>\n </ng-container>\n <span\n *ngIf=\"!nodeTemplate && !treeNode.data?.editable\"\n (dblclick)=\"nodeDblClick($event, treeNode)\"\n (contextmenu)=\"contextmenuEvent($event, treeNode)\"\n class=\"devui-tree-node__title devui-tree-drag-handle\"\n [class.select-disabled]=\"treeNode.data.disableSelect\"\n title=\"{{ treeNode.data.title }