jqtree 1.8.4 → 1.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/node.ts CHANGED
@@ -4,20 +4,20 @@ import { Position } from "./position";
4
4
  type IterateCallback = (node: Node, level: number) => boolean;
5
5
 
6
6
  export class Node implements INode {
7
- public id?: NodeId;
8
- public name: string;
7
+ [key: string]: unknown;
8
+
9
9
  public children: Node[];
10
- public parent: Node | null;
10
+ public element?: HTMLElement;
11
+ public id?: NodeId;
11
12
  public idMapping: Map<NodeId, Node>;
12
- public tree?: Node;
13
- public nodeClass?: typeof Node;
14
- public load_on_demand: boolean;
15
- public is_open: boolean;
16
- public element: HTMLElement;
17
13
  public is_loading: boolean;
14
+ public is_open: boolean;
18
15
  public isEmptyFolder: boolean;
19
-
20
- [key: string]: unknown;
16
+ public load_on_demand: boolean;
17
+ public name: string;
18
+ public nodeClass?: typeof Node;
19
+ public parent: Node | null;
20
+ public tree?: Node;
21
21
 
22
22
  constructor(
23
23
  nodeData: NodeData | null = null,
@@ -44,76 +44,59 @@ export class Node implements INode {
44
44
  }
45
45
  }
46
46
 
47
- /*
48
- Set the data of this node.
47
+ private createNode(nodeData?: NodeData): Node {
48
+ const nodeClass = this.getNodeClass();
49
+ return new nodeClass(nodeData);
50
+ }
49
51
 
50
- setData(string): set the name of the node
51
- setData(object): set attributes of the node
52
+ private doRemoveChild(node: Node): void {
53
+ this.children.splice(this.getChildIndex(node), 1);
54
+ this.tree?.removeNodeFromIndex(node);
55
+ }
52
56
 
53
- Examples:
54
- setData('node1')
57
+ private getNodeClass(): typeof Node {
58
+ return this.nodeClass ?? this.tree?.nodeClass ?? Node;
59
+ }
55
60
 
56
- setData({ name: 'node1', id: 1});
61
+ // Load children data from nodeInfo if it has children
62
+ private loadChildrenFromData(nodeInfo: NodeData) {
63
+ if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
64
+ this.loadFromData(nodeInfo.children);
65
+ }
66
+ }
57
67
 
58
- setData({ name: 'node2', id: 2, color: 'green'});
68
+ private setParent(parent: Node): void {
69
+ this.parent = parent;
70
+ this.tree = parent.tree;
71
+ this.tree?.addNodeToIndex(this);
72
+ }
59
73
 
60
- * This is an internal function; it is not in the docs
61
- * Does not remove existing node values
62
- */
63
- public setData(o: NodeData | null): void {
64
- if (!o) {
65
- return;
66
- } else if (typeof o === "string") {
67
- this.name = o;
68
- } else if (typeof o === "object") {
69
- for (const key in o) {
70
- if (Object.prototype.hasOwnProperty.call(o, key)) {
71
- const value = o[key];
74
+ public addAfter(nodeInfo: NodeData): Node | null {
75
+ if (!this.parent) {
76
+ return null;
77
+ } else {
78
+ const node = this.createNode(nodeInfo);
72
79
 
73
- if (key === "label" || key === "name") {
74
- // You can use the 'label' key instead of 'name'; this is a legacy feature
75
- if (typeof value === "string") {
76
- this.name = value;
77
- }
78
- } else if (key !== "children" && key !== "parent") {
79
- // You can't update the children or the parent using this function
80
- this[key] = value;
81
- }
82
- }
83
- }
80
+ const childIndex = this.parent.getChildIndex(this);
81
+ this.parent.addChildAtPosition(node, childIndex + 1);
82
+
83
+ node.loadChildrenFromData(nodeInfo);
84
+ return node;
84
85
  }
85
86
  }
86
87
 
87
- /*
88
- Create tree from data.
89
-
90
- Structure of data is:
91
- [
92
- {
93
- name: 'node1',
94
- children: [
95
- { name: 'child1' },
96
- { name: 'child2' }
97
- ]
98
- },
99
- {
100
- name: 'node2'
101
- }
102
- ]
103
- */
104
- public loadFromData(data: NodeData[]): Node {
105
- this.removeChildren();
88
+ public addBefore(nodeInfo: NodeData): Node | null {
89
+ if (!this.parent) {
90
+ return null;
91
+ } else {
92
+ const node = this.createNode(nodeInfo);
106
93
 
107
- for (const childData of data) {
108
- const node = this.createNode(childData);
109
- this.addChild(node);
94
+ const childIndex = this.parent.getChildIndex(this);
95
+ this.parent.addChildAtPosition(node, childIndex);
110
96
 
111
- if (isNodeRecordWithChildren(childData)) {
112
- node.loadFromData(childData.children);
113
- }
97
+ node.loadChildrenFromData(nodeInfo);
98
+ return node;
114
99
  }
115
-
116
- return this;
117
100
  }
118
101
 
119
102
  /*
@@ -141,128 +124,62 @@ export class Node implements INode {
141
124
  node.setParent(this);
142
125
  }
143
126
 
144
- /*
145
- Remove child. This also removes the children of the node.
146
-
147
- tree.removeChild(tree.children[0]);
148
- */
149
- public removeChild(node: Node): void {
150
- // remove children from the index
151
- node.removeChildren();
152
-
153
- this.doRemoveChild(node);
127
+ public addNodeToIndex(node: Node): void {
128
+ if (node.id != null) {
129
+ this.idMapping.set(node.id, node);
130
+ }
154
131
  }
155
132
 
156
- /*
157
- Get child index.
158
-
159
- var index = getChildIndex(node);
160
- */
161
- public getChildIndex(node: Node): number {
162
- return this.children.indexOf(node);
163
- }
133
+ public addParent(nodeInfo: NodeData): Node | null {
134
+ if (!this.parent) {
135
+ return null;
136
+ } else {
137
+ const newParent = this.createNode(nodeInfo);
164
138
 
165
- /*
166
- Does the tree have children?
139
+ if (this.tree) {
140
+ newParent.setParent(this.tree);
141
+ }
142
+ const originalParent = this.parent;
167
143
 
168
- if (tree.hasChildren()) {
169
- //
170
- }
171
- */
172
- public hasChildren(): boolean {
173
- return this.children.length !== 0;
174
- }
144
+ for (const child of originalParent.children) {
145
+ newParent.addChild(child);
146
+ }
175
147
 
176
- public isFolder(): boolean {
177
- return this.hasChildren() || this.load_on_demand;
148
+ originalParent.children = [];
149
+ originalParent.addChild(newParent);
150
+ return newParent;
151
+ }
178
152
  }
179
153
 
180
- /*
181
- Iterate over all the nodes in the tree.
182
-
183
- Calls callback with (node, level).
184
-
185
- The callback must return true to continue the iteration on current node.
186
-
187
- tree.iterate(
188
- function(node, level) {
189
- console.log(node.name);
154
+ public append(nodeInfo: NodeData): Node {
155
+ const node = this.createNode(nodeInfo);
156
+ this.addChild(node);
190
157
 
191
- // stop iteration after level 2
192
- return (level <= 2);
193
- }
194
- );
158
+ node.loadChildrenFromData(nodeInfo);
159
+ return node;
160
+ }
195
161
 
196
- */
197
- public iterate(callback: IterateCallback): void {
198
- const _iterate = (node: Node, level: number): void => {
199
- if (node.children) {
200
- for (const child of node.children) {
201
- const result = callback(child, level);
162
+ public filter(f: (node: Node) => boolean): Node[] {
163
+ const result: Node[] = [];
202
164
 
203
- if (result && child.hasChildren()) {
204
- _iterate(child, level + 1);
205
- }
206
- }
165
+ this.iterate((node: Node) => {
166
+ if (f(node)) {
167
+ result.push(node);
207
168
  }
208
- };
209
169
 
210
- _iterate(this, 0);
170
+ return true;
171
+ });
172
+
173
+ return result;
211
174
  }
212
175
 
213
176
  /*
214
- Move node relative to another node.
215
-
216
- Argument position: Position.BEFORE, Position.AFTER or Position.Inside
177
+ Get child index.
217
178
 
218
- // move node1 after node2
219
- tree.moveNode(node1, node2, Position.AFTER);
179
+ var index = getChildIndex(node);
220
180
  */
221
- public moveNode(
222
- movedNode: Node,
223
- targetNode: Node,
224
- position: Position,
225
- ): boolean {
226
- if (!movedNode.parent || movedNode.isParentOf(targetNode)) {
227
- // - Node is parent of target node
228
- // - Or, parent is empty
229
- return false;
230
- } else {
231
- movedNode.parent.doRemoveChild(movedNode);
232
-
233
- switch (position) {
234
- case Position.After: {
235
- if (targetNode.parent) {
236
- targetNode.parent.addChildAtPosition(
237
- movedNode,
238
- targetNode.parent.getChildIndex(targetNode) + 1,
239
- );
240
- return true;
241
- }
242
- return false;
243
- }
244
-
245
- case Position.Before: {
246
- if (targetNode.parent) {
247
- targetNode.parent.addChildAtPosition(
248
- movedNode,
249
- targetNode.parent.getChildIndex(targetNode),
250
- );
251
- return true;
252
- }
253
- return false;
254
- }
255
-
256
- case Position.Inside: {
257
- // move inside as first child
258
- targetNode.addChildAtPosition(movedNode, 0);
259
- return true;
260
- }
261
-
262
- default:
263
- return false;
264
- }
265
- }
181
+ public getChildIndex(node: Node): number {
182
+ return this.children.indexOf(node);
266
183
  }
267
184
 
268
185
  /*
@@ -293,7 +210,7 @@ export class Node implements INode {
293
210
  }
294
211
 
295
212
  if (node.hasChildren()) {
296
- tmpNode["children"] = getDataFromNodes(node.children);
213
+ tmpNode.children = getDataFromNodes(node.children);
297
214
  }
298
215
 
299
216
  return tmpNode;
@@ -307,121 +224,22 @@ export class Node implements INode {
307
224
  }
308
225
  }
309
226
 
310
- public getNodeByName(name: string): Node | null {
311
- return this.getNodeByCallback((node: Node) => node.name === name);
312
- }
313
-
314
- public getNodeByNameMustExist(name: string): Node {
315
- const node = this.getNodeByCallback((n: Node) => n.name === name);
316
-
317
- if (!node) {
318
- throw `Node with name ${name} not found`;
319
- }
320
-
321
- return node;
322
- }
323
-
324
- public getNodeByCallback(callback: (node: Node) => boolean): Node | null {
325
- let result: Node | null = null;
326
-
327
- this.iterate((node: Node) => {
328
- if (result) {
329
- return false;
330
- } else if (callback(node)) {
331
- result = node;
332
- return false;
333
- } else {
334
- return true;
335
- }
336
- });
337
-
338
- return result;
339
- }
340
-
341
- public addAfter(nodeInfo: NodeData): Node | null {
342
- if (!this.parent) {
343
- return null;
344
- } else {
345
- const node = this.createNode(nodeInfo);
346
-
347
- const childIndex = this.parent.getChildIndex(this);
348
- this.parent.addChildAtPosition(node, childIndex + 1);
349
-
350
- node.loadChildrenFromData(nodeInfo);
351
- return node;
352
- }
353
- }
354
-
355
- public addBefore(nodeInfo: NodeData): Node | null {
356
- if (!this.parent) {
357
- return null;
358
- } else {
359
- const node = this.createNode(nodeInfo);
360
-
361
- const childIndex = this.parent.getChildIndex(this);
362
- this.parent.addChildAtPosition(node, childIndex);
363
-
364
- node.loadChildrenFromData(nodeInfo);
365
- return node;
366
- }
367
- }
368
-
369
- public addParent(nodeInfo: NodeData): Node | null {
370
- if (!this.parent) {
227
+ public getLastChild(): Node | null {
228
+ if (!this.hasChildren()) {
371
229
  return null;
372
230
  } else {
373
- const newParent = this.createNode(nodeInfo);
374
-
375
- if (this.tree) {
376
- newParent.setParent(this.tree);
377
- }
378
- const originalParent = this.parent;
231
+ const lastChild = this.children[this.children.length - 1];
379
232
 
380
- for (const child of originalParent.children) {
381
- newParent.addChild(child);
233
+ if (!lastChild) {
234
+ return null;
382
235
  }
383
236
 
384
- originalParent.children = [];
385
- originalParent.addChild(newParent);
386
- return newParent;
387
- }
388
- }
389
-
390
- public remove(): void {
391
- if (this.parent) {
392
- this.parent.removeChild(this);
393
- this.parent = null;
394
- }
395
- }
396
-
397
- public append(nodeInfo: NodeData): Node {
398
- const node = this.createNode(nodeInfo);
399
- this.addChild(node);
400
-
401
- node.loadChildrenFromData(nodeInfo);
402
- return node;
403
- }
404
-
405
- public prepend(nodeInfo: NodeData): Node {
406
- const node = this.createNode(nodeInfo);
407
- this.addChildAtPosition(node, 0);
408
-
409
- node.loadChildrenFromData(nodeInfo);
410
- return node;
411
- }
412
-
413
- public isParentOf(node: Node): boolean {
414
- let parent = node.parent;
415
-
416
- while (parent) {
417
- if (parent === this) {
418
- return true;
237
+ if (!(lastChild.hasChildren() && lastChild.is_open)) {
238
+ return lastChild;
239
+ } else {
240
+ return lastChild.getLastChild();
419
241
  }
420
-
421
- parent = parent.parent;
422
242
  }
423
-
424
- return false;
425
243
  }
426
244
 
427
245
  public getLevel(): number {
@@ -436,40 +254,18 @@ export class Node implements INode {
436
254
  return level;
437
255
  }
438
256
 
439
- public getNodeById(nodeId: NodeId): Node | null {
440
- return this.idMapping.get(nodeId) || null;
441
- }
442
-
443
- public addNodeToIndex(node: Node): void {
444
- if (node.id != null) {
445
- this.idMapping.set(node.id, node);
446
- }
447
- }
448
-
449
- public removeNodeFromIndex(node: Node): void {
450
- if (node.id != null) {
451
- this.idMapping.delete(node.id);
452
- }
453
- }
454
-
455
- public removeChildren(): void {
456
- this.iterate((child: Node) => {
457
- this.tree?.removeNodeFromIndex(child);
458
- return true;
459
- });
460
-
461
- this.children = [];
462
- }
463
-
464
- public getPreviousSibling(): Node | null {
465
- if (!this.parent) {
257
+ public getNextNode(includeChildren = true): Node | null {
258
+ if (includeChildren && this.hasChildren()) {
259
+ return this.children[0] ?? null;
260
+ } else if (!this.parent) {
466
261
  return null;
467
262
  } else {
468
- const previousIndex = this.parent.getChildIndex(this) - 1;
469
- if (previousIndex >= 0) {
470
- return this.parent.children[previousIndex] || null;
263
+ const nextSibling = this.getNextSibling();
264
+
265
+ if (nextSibling) {
266
+ return nextSibling;
471
267
  } else {
472
- return null;
268
+ return this.parent.getNextNode(false);
473
269
  }
474
270
  }
475
271
  }
@@ -480,51 +276,17 @@ export class Node implements INode {
480
276
  } else {
481
277
  const nextIndex = this.parent.getChildIndex(this) + 1;
482
278
  if (nextIndex < this.parent.children.length) {
483
- return this.parent.children[nextIndex] || null;
279
+ return this.parent.children[nextIndex] ?? null;
484
280
  } else {
485
281
  return null;
486
282
  }
487
283
  }
488
284
  }
489
285
 
490
- public getNodesByProperty(key: string, value: unknown): Node[] {
491
- return this.filter((node: Node) => node[key] === value);
492
- }
493
-
494
- public filter(f: (node: Node) => boolean): Node[] {
495
- const result: Node[] = [];
496
-
497
- this.iterate((node: Node) => {
498
- if (f(node)) {
499
- result.push(node);
500
- }
501
-
502
- return true;
503
- });
504
-
505
- return result;
506
- }
507
-
508
- public getNextNode(includeChildren = true): Node | null {
509
- if (includeChildren && this.hasChildren()) {
510
- return this.children[0] || null;
511
- } else if (!this.parent) {
512
- return null;
513
- } else {
514
- const nextSibling = this.getNextSibling();
515
-
516
- if (nextSibling) {
517
- return nextSibling;
518
- } else {
519
- return this.parent.getNextNode(false);
520
- }
521
- }
522
- }
523
-
524
286
  public getNextVisibleNode(): Node | null {
525
287
  if (this.hasChildren() && this.is_open) {
526
288
  // First child
527
- return this.children[0] || null;
289
+ return this.children[0] ?? null;
528
290
  } else {
529
291
  if (!this.parent) {
530
292
  return null;
@@ -541,6 +303,57 @@ export class Node implements INode {
541
303
  }
542
304
  }
543
305
 
306
+ public getNodeByCallback(callback: (node: Node) => boolean): Node | null {
307
+ let result: Node | null = null;
308
+
309
+ this.iterate((node: Node) => {
310
+ if (result) {
311
+ return false;
312
+ } else if (callback(node)) {
313
+ result = node;
314
+ return false;
315
+ } else {
316
+ return true;
317
+ }
318
+ });
319
+
320
+ return result;
321
+ }
322
+
323
+ public getNodeById(nodeId: NodeId): Node | null {
324
+ return this.idMapping.get(nodeId) ?? null;
325
+ }
326
+
327
+ public getNodeByName(name: string): Node | null {
328
+ return this.getNodeByCallback((node: Node) => node.name === name);
329
+ }
330
+
331
+ public getNodeByNameMustExist(name: string): Node {
332
+ const node = this.getNodeByCallback((n: Node) => n.name === name);
333
+
334
+ if (!node) {
335
+ throw new Error(`Node with name ${name} not found`);
336
+ }
337
+
338
+ return node;
339
+ }
340
+
341
+ public getNodesByProperty(key: string, value: unknown): Node[] {
342
+ return this.filter((node: Node) => node[key] === value);
343
+ }
344
+
345
+ public getParent(): Node | null {
346
+ // Return parent except if it is the root node
347
+ if (!this.parent) {
348
+ return null;
349
+ } else if (!this.parent.parent) {
350
+ // Root node -> null
351
+ return null;
352
+ } else {
353
+ return this.parent;
354
+ }
355
+ }
356
+
544
357
  public getPreviousNode(): Node | null {
545
358
  if (!this.parent) {
546
359
  return null;
@@ -557,6 +370,19 @@ export class Node implements INode {
557
370
  }
558
371
  }
559
372
 
373
+ public getPreviousSibling(): Node | null {
374
+ if (!this.parent) {
375
+ return null;
376
+ } else {
377
+ const previousIndex = this.parent.getChildIndex(this) - 1;
378
+ if (previousIndex >= 0) {
379
+ return this.parent.children[previousIndex] ?? null;
380
+ } else {
381
+ return null;
382
+ }
383
+ }
384
+ }
385
+
560
386
  public getPreviousVisibleNode(): Node | null {
561
387
  if (!this.parent) {
562
388
  return null;
@@ -578,34 +404,15 @@ export class Node implements INode {
578
404
  }
579
405
  }
580
406
 
581
- public getParent(): Node | null {
582
- // Return parent except if it is the root node
583
- if (!this.parent) {
584
- return null;
585
- } else if (!this.parent.parent) {
586
- // Root node -> null
587
- return null;
588
- } else {
589
- return this.parent;
590
- }
591
- }
592
-
593
- public getLastChild(): Node | null {
594
- if (!this.hasChildren()) {
595
- return null;
596
- } else {
597
- const lastChild = this.children[this.children.length - 1];
598
-
599
- if (!lastChild) {
600
- return null;
601
- }
407
+ /*
408
+ Does the tree have children?
602
409
 
603
- if (!(lastChild.hasChildren() && lastChild.is_open)) {
604
- return lastChild;
605
- } else {
606
- return lastChild?.getLastChild();
607
- }
608
- }
410
+ if (tree.hasChildren()) {
411
+ //
412
+ }
413
+ */
414
+ public hasChildren(): boolean {
415
+ return this.children.length !== 0;
609
416
  }
610
417
 
611
418
  // Init Node from data without making it the root of the tree
@@ -632,30 +439,221 @@ export class Node implements INode {
632
439
  addNode(data);
633
440
  }
634
441
 
635
- private setParent(parent: Node): void {
636
- this.parent = parent;
637
- this.tree = parent.tree;
638
- this.tree?.addNodeToIndex(this);
442
+ public isFolder(): boolean {
443
+ return this.hasChildren() || this.load_on_demand;
639
444
  }
640
445
 
641
- private doRemoveChild(node: Node): void {
642
- this.children.splice(this.getChildIndex(node), 1);
643
- this.tree?.removeNodeFromIndex(node);
446
+ public isParentOf(node: Node): boolean {
447
+ let parent = node.parent;
448
+
449
+ while (parent) {
450
+ if (parent === this) {
451
+ return true;
452
+ }
453
+
454
+ parent = parent.parent;
455
+ }
456
+
457
+ return false;
644
458
  }
645
459
 
646
- private getNodeClass(): typeof Node {
647
- return this.nodeClass || this?.tree?.nodeClass || Node;
460
+ /*
461
+ Iterate over all the nodes in the tree.
462
+
463
+ Calls callback with (node, level).
464
+
465
+ The callback must return true to continue the iteration on current node.
466
+
467
+ tree.iterate(
468
+ function(node, level) {
469
+ console.log(node.name);
470
+
471
+ // stop iteration after level 2
472
+ return (level <= 2);
473
+ }
474
+ );
475
+
476
+ */
477
+ public iterate(callback: IterateCallback): void {
478
+ const _iterate = (node: Node, level: number): void => {
479
+ for (const child of node.children) {
480
+ const result = callback(child, level);
481
+
482
+ if (result && child.hasChildren()) {
483
+ _iterate(child, level + 1);
484
+ }
485
+ }
486
+ };
487
+
488
+ _iterate(this, 0);
648
489
  }
649
490
 
650
- private createNode(nodeData?: NodeData): Node {
651
- const nodeClass = this.getNodeClass();
652
- return new nodeClass(nodeData);
491
+ /*
492
+ Create tree from data.
493
+
494
+ Structure of data is:
495
+ [
496
+ {
497
+ name: 'node1',
498
+ children: [
499
+ { name: 'child1' },
500
+ { name: 'child2' }
501
+ ]
502
+ },
503
+ {
504
+ name: 'node2'
505
+ }
506
+ ]
507
+ */
508
+ public loadFromData(data: NodeData[]): this {
509
+ this.removeChildren();
510
+
511
+ for (const childData of data) {
512
+ const node = this.createNode(childData);
513
+ this.addChild(node);
514
+
515
+ if (isNodeRecordWithChildren(childData)) {
516
+ node.loadFromData(childData.children);
517
+ }
518
+ }
519
+
520
+ return this;
653
521
  }
654
522
 
655
- // Load children data from nodeInfo if it has children
656
- private loadChildrenFromData(nodeInfo: NodeData) {
657
- if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
658
- this.loadFromData(nodeInfo.children);
523
+ /*
524
+ Move node relative to another node.
525
+
526
+ Argument position: Position.BEFORE, Position.AFTER or Position.Inside
527
+
528
+ // move node1 after node2
529
+ tree.moveNode(node1, node2, Position.AFTER);
530
+ */
531
+ public moveNode(
532
+ movedNode: Node,
533
+ targetNode: Node,
534
+ position: Position,
535
+ ): boolean {
536
+ if (!movedNode.parent || movedNode.isParentOf(targetNode)) {
537
+ // - Node is parent of target node
538
+ // - Or, parent is empty
539
+ return false;
540
+ } else {
541
+ movedNode.parent.doRemoveChild(movedNode);
542
+
543
+ switch (position) {
544
+ case Position.After: {
545
+ if (targetNode.parent) {
546
+ targetNode.parent.addChildAtPosition(
547
+ movedNode,
548
+ targetNode.parent.getChildIndex(targetNode) + 1,
549
+ );
550
+ return true;
551
+ }
552
+ return false;
553
+ }
554
+
555
+ case Position.Before: {
556
+ if (targetNode.parent) {
557
+ targetNode.parent.addChildAtPosition(
558
+ movedNode,
559
+ targetNode.parent.getChildIndex(targetNode),
560
+ );
561
+ return true;
562
+ }
563
+ return false;
564
+ }
565
+
566
+ case Position.Inside: {
567
+ // move inside as first child
568
+ targetNode.addChildAtPosition(movedNode, 0);
569
+ return true;
570
+ }
571
+
572
+ default:
573
+ return false;
574
+ }
575
+ }
576
+ }
577
+
578
+ public prepend(nodeInfo: NodeData): Node {
579
+ const node = this.createNode(nodeInfo);
580
+ this.addChildAtPosition(node, 0);
581
+
582
+ node.loadChildrenFromData(nodeInfo);
583
+ return node;
584
+ }
585
+
586
+ public remove(): void {
587
+ if (this.parent) {
588
+ this.parent.removeChild(this);
589
+ this.parent = null;
590
+ }
591
+ }
592
+
593
+ /*
594
+ Remove child. This also removes the children of the node.
595
+
596
+ tree.removeChild(tree.children[0]);
597
+ */
598
+ public removeChild(node: Node): void {
599
+ // remove children from the index
600
+ node.removeChildren();
601
+
602
+ this.doRemoveChild(node);
603
+ }
604
+
605
+ public removeChildren(): void {
606
+ this.iterate((child: Node) => {
607
+ this.tree?.removeNodeFromIndex(child);
608
+ return true;
609
+ });
610
+
611
+ this.children = [];
612
+ }
613
+
614
+ public removeNodeFromIndex(node: Node): void {
615
+ if (node.id != null) {
616
+ this.idMapping.delete(node.id);
617
+ }
618
+ }
619
+
620
+ /*
621
+ Set the data of this node.
622
+
623
+ setData(string): set the name of the node
624
+ setData(object): set attributes of the node
625
+
626
+ Examples:
627
+ setData('node1')
628
+
629
+ setData({ name: 'node1', id: 1});
630
+
631
+ setData({ name: 'node2', id: 2, color: 'green'});
632
+
633
+ * This is an internal function; it is not in the docs
634
+ * Does not remove existing node values
635
+ */
636
+ public setData(o: NodeData | null): void {
637
+ if (!o) {
638
+ return;
639
+ } else if (typeof o === "string") {
640
+ this.name = o;
641
+ } else if (typeof o === "object") {
642
+ for (const key in o) {
643
+ if (Object.prototype.hasOwnProperty.call(o, key)) {
644
+ const value = o[key];
645
+
646
+ if (key === "label" || key === "name") {
647
+ // You can use the 'label' key instead of 'name'; this is a legacy feature
648
+ if (typeof value === "string") {
649
+ this.name = value;
650
+ }
651
+ } else if (key !== "children" && key !== "parent") {
652
+ // You can't update the children or the parent using this function
653
+ this[key] = value;
654
+ }
655
+ }
656
+ }
659
657
  }
660
658
  }
661
659
  }