1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | import { injectable } from 'inversify';
|
20 | import { MaybePromise } from '../../common/types';
|
21 | import { TreeImpl, CompositeTreeNode, TreeNode, SelectableTreeNode, ExpandableTreeNode } from '../tree';
|
22 | import { TreeElement, CompositeTreeElement, TreeSource } from './tree-source';
|
23 |
|
24 | @injectable()
|
25 | export class SourceTree extends TreeImpl {
|
26 |
|
27 | override async resolveChildren(parent: TreeElementNodeParent): Promise<TreeNode[]> {
|
28 | const elements = await this.resolveElements(parent);
|
29 | const nodes: TreeNode[] = [];
|
30 | let index = 0;
|
31 | for (const element of elements) {
|
32 | if (element.visible !== false) {
|
33 | nodes.push(this.toNode(element, index++, parent));
|
34 | }
|
35 | }
|
36 | return nodes;
|
37 | }
|
38 |
|
39 | protected resolveElements(parent: TreeElementNodeParent): MaybePromise<IterableIterator<TreeElement>> {
|
40 | if (TreeSourceNode.is(parent)) {
|
41 | return parent.source.getElements();
|
42 | }
|
43 | return parent.element.getElements();
|
44 | }
|
45 |
|
46 | protected toNode(element: TreeElement, index: number, parent: TreeElementNodeParent): TreeElementNode {
|
47 | const id = element.id ? String(element.id) : (parent.id + ':' + index);
|
48 | const name = id;
|
49 | const existing = this.getNode(id);
|
50 | const updated = existing && <TreeElementNode>Object.assign(existing, { element, parent });
|
51 | if (CompositeTreeElement.hasElements(element)) {
|
52 | if (updated) {
|
53 | if (!ExpandableTreeNode.is(updated)) {
|
54 | Object.assign(updated, { expanded: false });
|
55 | }
|
56 | if (!CompositeTreeNode.is(updated)) {
|
57 | Object.assign(updated, { children: [] });
|
58 | }
|
59 | return updated;
|
60 | }
|
61 | return {
|
62 | element,
|
63 | parent,
|
64 | id,
|
65 | name,
|
66 | selected: false,
|
67 | expanded: false,
|
68 | children: []
|
69 | } as TreeElementNode;
|
70 | }
|
71 | if (CompositeTreeElementNode.is(updated)) {
|
72 | delete (updated as any).expanded;
|
73 | delete (updated as any).children;
|
74 | }
|
75 | if (updated) {
|
76 | if (ExpandableTreeNode.is(updated)) {
|
77 | delete (updated as any).expanded;
|
78 | }
|
79 | if (CompositeTreeNode.is(updated)) {
|
80 | delete (updated as any).children;
|
81 | }
|
82 | return updated;
|
83 | }
|
84 | return {
|
85 | element,
|
86 | parent,
|
87 | id,
|
88 | name,
|
89 | selected: false
|
90 | };
|
91 | }
|
92 |
|
93 | }
|
94 |
|
95 | export type TreeElementNodeParent = CompositeTreeElementNode | TreeSourceNode;
|
96 |
|
97 | export interface TreeElementNode extends TreeNode, SelectableTreeNode {
|
98 | element: TreeElement
|
99 | parent: TreeElementNodeParent
|
100 | }
|
101 | export namespace TreeElementNode {
|
102 | export function is(node: TreeNode | undefined): node is TreeElementNode {
|
103 | return SelectableTreeNode.is(node) && 'element' in node;
|
104 | }
|
105 | }
|
106 |
|
107 | export interface CompositeTreeElementNode extends TreeElementNode, CompositeTreeNode, ExpandableTreeNode {
|
108 | element: CompositeTreeElement
|
109 | children: TreeElementNode[]
|
110 | parent: TreeElementNodeParent
|
111 | }
|
112 | export namespace CompositeTreeElementNode {
|
113 | export function is(node: TreeNode | undefined): node is CompositeTreeElementNode {
|
114 | return TreeElementNode.is(node) && CompositeTreeNode.is(node) && ExpandableTreeNode.is(node) && !!node.visible;
|
115 | }
|
116 | }
|
117 |
|
118 | export interface TreeSourceNode extends CompositeTreeNode, SelectableTreeNode {
|
119 | visible: false
|
120 | children: TreeElementNode[]
|
121 | parent: undefined
|
122 | source: TreeSource
|
123 | }
|
124 | export namespace TreeSourceNode {
|
125 | export function is(node: TreeNode | undefined): node is TreeSourceNode {
|
126 | return CompositeTreeNode.is(node) && !node.visible && 'source' in node;
|
127 | }
|
128 | export function to(source: undefined): undefined;
|
129 | export function to(source: TreeSource): TreeSourceNode;
|
130 | export function to(source: TreeSource | undefined): TreeSourceNode | undefined;
|
131 | export function to(source: TreeSource | undefined): TreeSourceNode | undefined {
|
132 | if (!source) {
|
133 | return source;
|
134 | }
|
135 | const id = source.id || '__source__';
|
136 | return {
|
137 | id,
|
138 | name: id,
|
139 | visible: false,
|
140 | children: [],
|
141 | source,
|
142 | parent: undefined,
|
143 | selected: false
|
144 | };
|
145 | }
|
146 | }
|