thingsboard/ui-ngx/src/app/shared/components/nav-tree.component.ts

279 lines
9.1 KiB
TypeScript
Raw Normal View History

2020-01-31 20:26:08 +02:00
///
2021-01-11 13:42:16 +02:00
/// Copyright © 2016-2021 The Thingsboard Authors
2020-01-31 20:26:08 +02:00
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, ElementRef, Input, NgZone, OnInit, ViewEncapsulation } from '@angular/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { deepClone } from '@core/utils';
export interface NavTreeNodeState {
disabled?: boolean;
opened?: boolean;
loaded?: boolean;
}
export interface NavTreeNode {
id: string;
icon?: boolean;
text?: string;
state?: NavTreeNodeState;
children?: NavTreeNode[] | boolean;
data?: any;
}
export interface NavTreeEditCallbacks {
selectNode?: (id: string) => void;
deselectAll?: () => void;
getNode?: (id: string) => NavTreeNode;
getParentNodeId?: (id: string) => string;
openNode?: (id: string, cb?: () => void) => void;
nodeIsOpen?: (id: string) => boolean;
nodeIsLoaded?: (id: string) => boolean;
refreshNode?: (id: string) => void;
updateNode?: (id: string, newName: string, updatedData?: any) => void;
2020-04-15 13:00:32 +03:00
createNode?: (parentId: string, node: NavTreeNode, pos: number | string) => void;
2020-01-31 20:26:08 +02:00
deleteNode?: (id: string) => void;
disableNode?: (id: string) => void;
enableNode?: (id: string) => void;
setNodeHasChildren?: (id: string, hasChildren: boolean) => void;
search?: (searchText: string) => void;
clearSearch?: () => void;
}
export type NodesCallback = (nodes: NavTreeNode[]) => void;
export type LoadNodesCallback = (node: NavTreeNode, cb: NodesCallback) => void;
export type NodeSearchCallback = (searchText: string, node: NavTreeNode) => boolean;
export type NodeSelectedCallback = (node: NavTreeNode, event: Event) => void;
export type NodesInsertedCallback = (nodes: string[], parent: string) => void;
@Component({
selector: 'tb-nav-tree',
templateUrl: './nav-tree.component.html',
styleUrls: ['./nav-tree.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class NavTreeComponent implements OnInit {
private enableSearchValue: boolean;
get enableSearch(): boolean {
return this.enableSearchValue;
}
@Input()
set enableSearch(value: boolean) {
this.enableSearchValue = coerceBooleanProperty(value);
}
@Input()
2021-12-06 12:54:48 +02:00
loadNodes: LoadNodesCallback;
2020-01-31 20:26:08 +02:00
@Input()
2021-12-06 12:54:48 +02:00
searchCallback: NodeSearchCallback;
2020-01-31 20:26:08 +02:00
@Input()
2021-12-06 12:54:48 +02:00
onNodeSelected: NodeSelectedCallback;
2020-01-31 20:26:08 +02:00
@Input()
2021-12-06 12:54:48 +02:00
onNodesInserted: NodesInsertedCallback;
2020-01-31 20:26:08 +02:00
@Input()
2021-12-06 12:54:48 +02:00
editCallbacks: NavTreeEditCallbacks;
2020-01-31 20:26:08 +02:00
private treeElement: JSTree;
constructor(private elementRef: ElementRef<HTMLElement>,
private ngZone: NgZone) {
}
ngOnInit(): void {
this.initTree();
}
private initTree() {
const loadNodes: LoadNodesCallback = (node, cb) => {
const outCb = (nodes: NavTreeNode[]) => {
2020-01-31 20:26:08 +02:00
const copied: NavTreeNode[] = [];
if (nodes) {
nodes.forEach((n) => {
2020-01-31 20:26:08 +02:00
copied.push(deepClone(n, ['data']));
});
}
cb(copied);
};
this.ngZone.runOutsideAngular(() => {
this.loadNodes(node, outCb);
});
};
const config: JSTreeStaticDefaults = {
core: {
worker: false,
multiple: false,
check_callback: true,
themes: { name: 'proton', responsive: true },
data: loadNodes,
error: () => {
console.error('Unexpected jstree error!');
}
},
plugins: []
};
if (this.enableSearch) {
config.plugins.push('search');
config.search = {
ajax: false,
fuzzy: false,
close_opened_onclear: true,
case_sensitive: false,
show_only_matches: true,
show_only_matches_children: false,
search_leaves_only: false,
search_callback: this.searchCallback
};
}
2021-01-05 11:37:05 +02:00
import('jstree').then(() => {
2020-01-31 20:26:08 +02:00
2021-01-05 11:37:05 +02:00
this.treeElement = $('.tb-nav-tree-container', this.elementRef.nativeElement).jstree(config);
2020-01-31 20:26:08 +02:00
2021-01-05 11:37:05 +02:00
this.treeElement.on('changed.jstree', (e: any, data) => {
const node: NavTreeNode = data.instance.get_selected(true)[0];
if (this.onNodeSelected) {
this.ngZone.run(() => this.onNodeSelected(node, e as Event));
2020-01-31 20:26:08 +02:00
}
2021-01-05 11:37:05 +02:00
});
this.treeElement.on('model.jstree', (e: any, data) => {
if (this.onNodesInserted) {
this.ngZone.run(() => this.onNodesInserted(data.nodes, data.parent));
2020-01-31 20:26:08 +02:00
}
2021-01-05 11:37:05 +02:00
});
if (this.editCallbacks) {
this.editCallbacks.selectNode = id => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
this.treeElement.jstree('deselect_all', true);
this.treeElement.jstree('select_node', node);
}
};
this.editCallbacks.deselectAll = () => {
this.treeElement.jstree('deselect_all');
};
this.editCallbacks.getNode = (id) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
return node;
};
this.editCallbacks.getParentNodeId = (id) => {
2020-01-31 20:26:08 +02:00
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
2021-01-05 11:37:05 +02:00
return this.treeElement.jstree('get_parent', node);
}
};
this.editCallbacks.openNode = (id, cb) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
this.treeElement.jstree('open_node', node, cb);
}
};
this.editCallbacks.nodeIsOpen = (id) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
return this.treeElement.jstree('is_open', node);
} else {
return true;
}
};
this.editCallbacks.nodeIsLoaded = (id) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
return this.treeElement.jstree('is_loaded', node);
} else {
return true;
}
};
this.editCallbacks.refreshNode = (id) => {
if (id === '#') {
this.treeElement.jstree('refresh');
2020-01-31 20:26:08 +02:00
this.treeElement.jstree('redraw');
2021-01-05 11:37:05 +02:00
} else {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
const opened = this.treeElement.jstree('is_open', node);
this.treeElement.jstree('refresh_node', node);
this.treeElement.jstree('redraw');
if (node.children && opened/* && !node.children.length*/) {
this.treeElement.jstree('open_node', node);
}
2020-01-31 20:26:08 +02:00
}
}
2021-01-05 11:37:05 +02:00
};
this.editCallbacks.updateNode = (id, newName, updatedData) => {
2021-01-05 11:37:05 +02:00
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
this.treeElement.jstree('rename_node', node, newName);
2020-01-31 20:26:08 +02:00
}
if (updatedData && node.data) {
Object.assign(node.data, updatedData);
}
2021-01-05 11:37:05 +02:00
};
this.editCallbacks.createNode = (parentId, node, pos) => {
const parentNode: NavTreeNode = this.treeElement.jstree('get_node', parentId);
if (parentNode) {
this.treeElement.jstree('create_node', parentNode, node, pos);
}
};
this.editCallbacks.deleteNode = (id) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
this.treeElement.jstree('delete_node', node);
}
};
this.editCallbacks.disableNode = (id) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
this.treeElement.jstree('disable_node', node);
}
};
this.editCallbacks.enableNode = (id) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
this.treeElement.jstree('enable_node', node);
}
};
this.editCallbacks.setNodeHasChildren = (id, hasChildren) => {
const node: NavTreeNode = this.treeElement.jstree('get_node', id);
if (node) {
if (!node.children || (Array.isArray(node.children) && !node.children.length)) {
node.children = hasChildren;
node.state.loaded = !hasChildren;
node.state.opened = false;
this.treeElement.jstree('_node_changed', node.id);
this.treeElement.jstree('redraw');
}
}
};
this.editCallbacks.search = (searchText) => {
this.treeElement.jstree('search', searchText);
};
this.editCallbacks.clearSearch = () => {
this.treeElement.jstree('clear_search');
};
}
});
2020-01-31 20:26:08 +02:00
}
}