wunderbaum 0.0.1-0 → 0.0.3
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/README.md +6 -5
- package/dist/wunderbaum.css +1 -1
- package/dist/wunderbaum.d.ts +634 -171
- package/dist/wunderbaum.esm.js +818 -436
- package/dist/wunderbaum.esm.min.js +31 -21
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +820 -438
- package/dist/wunderbaum.umd.min.js +34 -24
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +35 -32
- package/src/common.ts +37 -5
- package/src/drag_observer.ts +169 -0
- package/src/util.ts +48 -13
- package/src/wb_ext_dnd.ts +145 -4
- package/src/wb_ext_edit.ts +10 -1
- package/src/wb_ext_filter.ts +35 -40
- package/src/wb_ext_grid.ts +45 -0
- package/src/wb_ext_keynav.ts +8 -4
- package/src/wb_node.ts +142 -78
- package/src/wb_options.ts +138 -25
- package/src/wunderbaum.scss +28 -5
- package/src/wunderbaum.ts +481 -321
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Wunderbaum - ext-grid
|
|
3
|
+
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
4
|
+
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
|
|
5
|
+
*/
|
|
6
|
+
import { Wunderbaum } from "./wunderbaum";
|
|
7
|
+
import { WunderbaumExtension } from "./wb_extension_base";
|
|
8
|
+
import { DragCallbackArgType, DragObserver } from "./drag_observer";
|
|
9
|
+
|
|
10
|
+
export class GridExtension extends WunderbaumExtension {
|
|
11
|
+
protected observer: DragObserver;
|
|
12
|
+
|
|
13
|
+
constructor(tree: Wunderbaum) {
|
|
14
|
+
super(tree, "grid", {
|
|
15
|
+
// throttle: 200,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
this.observer = new DragObserver({
|
|
19
|
+
root: window.document,
|
|
20
|
+
selector: "span.wb-col-resizer",
|
|
21
|
+
thresh: 4,
|
|
22
|
+
// throttle: 400,
|
|
23
|
+
dragstart: (e) => {
|
|
24
|
+
return this.tree.element.contains(e.dragElem);
|
|
25
|
+
},
|
|
26
|
+
drag: (e) => {
|
|
27
|
+
// TODO: throttle
|
|
28
|
+
return this.handleDrag(e);
|
|
29
|
+
},
|
|
30
|
+
dragstop: (e) => {
|
|
31
|
+
return this.handleDrag(e);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
init() {
|
|
37
|
+
super.init();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected handleDrag(e: DragCallbackArgType): void {
|
|
41
|
+
const info = Wunderbaum.getEventInfo(e.event);
|
|
42
|
+
// this.tree.options.
|
|
43
|
+
this.tree.log(`${e.type}(${e.dx})`, e, info);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/wb_ext_keynav.ts
CHANGED
|
@@ -94,7 +94,7 @@ export class KeynavExtension extends WunderbaumExtension {
|
|
|
94
94
|
if (!node.expanded && (node.children || node.lazy)) {
|
|
95
95
|
eventName = "Add"; // expand
|
|
96
96
|
} else if (navModeOption === NavigationModeOption.startRow) {
|
|
97
|
-
tree.
|
|
97
|
+
tree.setNavigationMode(NavigationMode.cellNav);
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
100
|
break;
|
|
@@ -133,6 +133,8 @@ export class KeynavExtension extends WunderbaumExtension {
|
|
|
133
133
|
case "Home":
|
|
134
134
|
case "Control+End":
|
|
135
135
|
case "Control+Home":
|
|
136
|
+
case "Meta+ArrowDown":
|
|
137
|
+
case "Meta+ArrowUp":
|
|
136
138
|
case "PageDown":
|
|
137
139
|
case "PageUp":
|
|
138
140
|
node.navigate(eventName, { activate: activate, event: event });
|
|
@@ -164,10 +166,10 @@ export class KeynavExtension extends WunderbaumExtension {
|
|
|
164
166
|
break;
|
|
165
167
|
case "Escape":
|
|
166
168
|
if (tree.navMode === NavigationMode.cellEdit) {
|
|
167
|
-
tree.
|
|
169
|
+
tree.setNavigationMode(NavigationMode.cellNav);
|
|
168
170
|
handled = true;
|
|
169
171
|
} else if (tree.navMode === NavigationMode.cellNav) {
|
|
170
|
-
tree.
|
|
172
|
+
tree.setNavigationMode(NavigationMode.row);
|
|
171
173
|
handled = true;
|
|
172
174
|
}
|
|
173
175
|
break;
|
|
@@ -176,7 +178,7 @@ export class KeynavExtension extends WunderbaumExtension {
|
|
|
176
178
|
tree.setColumn(tree.activeColIdx - 1);
|
|
177
179
|
handled = true;
|
|
178
180
|
} else if (navModeOption !== NavigationModeOption.cell) {
|
|
179
|
-
tree.
|
|
181
|
+
tree.setNavigationMode(NavigationMode.row);
|
|
180
182
|
handled = true;
|
|
181
183
|
}
|
|
182
184
|
break;
|
|
@@ -193,6 +195,8 @@ export class KeynavExtension extends WunderbaumExtension {
|
|
|
193
195
|
case "Home":
|
|
194
196
|
case "Control+End":
|
|
195
197
|
case "Control+Home":
|
|
198
|
+
case "Meta+ArrowDown":
|
|
199
|
+
case "Meta+ArrowUp":
|
|
196
200
|
case "PageDown":
|
|
197
201
|
case "PageUp":
|
|
198
202
|
node.navigate(eventName, { activate: activate, event: event });
|
package/src/wb_node.ts
CHANGED
|
@@ -25,6 +25,9 @@ import {
|
|
|
25
25
|
TEST_IMG,
|
|
26
26
|
ApplyCommandType,
|
|
27
27
|
AddNodeType,
|
|
28
|
+
SetActiveOptions,
|
|
29
|
+
SetExpandedOptions,
|
|
30
|
+
SetSelectedOptions,
|
|
28
31
|
} from "./common";
|
|
29
32
|
import { Deferred } from "./deferred";
|
|
30
33
|
import { WbNodeData } from "./wb_options";
|
|
@@ -66,6 +69,13 @@ const NODE_ATTRS = new Set<string>([
|
|
|
66
69
|
"unselectableStatus",
|
|
67
70
|
]);
|
|
68
71
|
|
|
72
|
+
/**
|
|
73
|
+
* A single tree node.
|
|
74
|
+
*
|
|
75
|
+
* **NOTE:** <br>
|
|
76
|
+
* Generally you should not modify properties directly, since this may break
|
|
77
|
+
* the internal bookkeeping.
|
|
78
|
+
*/
|
|
69
79
|
export class WunderbaumNode {
|
|
70
80
|
static sequence = 0;
|
|
71
81
|
|
|
@@ -73,19 +83,32 @@ export class WunderbaumNode {
|
|
|
73
83
|
public tree: Wunderbaum;
|
|
74
84
|
/** Parent node (null for the invisible root node `tree.root`). */
|
|
75
85
|
public parent: WunderbaumNode;
|
|
86
|
+
/** Name of the node.
|
|
87
|
+
* @see Use {@link setTitle} to modify. */
|
|
76
88
|
public title: string;
|
|
89
|
+
/** Unique key. Passed with constructor or defaults to `SEQUENCE`.
|
|
90
|
+
* @see Use {@link setKey} to modify. */
|
|
77
91
|
public readonly key: string;
|
|
92
|
+
/** Reference key. Unlike {@link key}, a `refKey` may occur multiple
|
|
93
|
+
* times within a tree (in this case we have 'clone nodes').
|
|
94
|
+
* @see Use {@link setKey} to modify.
|
|
95
|
+
*/
|
|
78
96
|
public readonly refKey: string | undefined = undefined;
|
|
79
97
|
public children: WunderbaumNode[] | null = null;
|
|
80
98
|
public checkbox?: boolean;
|
|
81
99
|
public colspan?: boolean;
|
|
82
100
|
public icon?: boolean | string;
|
|
83
101
|
public lazy: boolean = false;
|
|
102
|
+
/** Expansion state.
|
|
103
|
+
* @see {@link isExpandable}, {@link isExpanded}, {@link setExpanded}. */
|
|
84
104
|
public expanded: boolean = false;
|
|
105
|
+
/** Selection state.
|
|
106
|
+
* @see {@link isSelected}, {@link setSelected}. */
|
|
85
107
|
public selected: boolean = false;
|
|
86
108
|
public type?: string;
|
|
87
109
|
public tooltip?: string;
|
|
88
|
-
/** Additional classes added to `div.wb-row`.
|
|
110
|
+
/** Additional classes added to `div.wb-row`.
|
|
111
|
+
* @see {@link addClass}, {@link removeClass}, {@link toggleClass}. */
|
|
89
112
|
public extraClasses = new Set<string>();
|
|
90
113
|
/** Custom data that was passed to the constructor */
|
|
91
114
|
public data: any = {};
|
|
@@ -100,6 +123,7 @@ export class WunderbaumNode {
|
|
|
100
123
|
public match?: boolean; // Added and removed by filter code
|
|
101
124
|
public subMatchCount?: number = 0;
|
|
102
125
|
public subMatchBadge?: HTMLElement;
|
|
126
|
+
/** @internal */
|
|
103
127
|
public titleWithHighlight?: string;
|
|
104
128
|
public _filterAutoExpanded?: boolean;
|
|
105
129
|
|
|
@@ -236,7 +260,7 @@ export class WunderbaumNode {
|
|
|
236
260
|
// this.fixSelection3FromEndNodes();
|
|
237
261
|
// }
|
|
238
262
|
// this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null);
|
|
239
|
-
this.tree.setModified(ChangeType.structure
|
|
263
|
+
this.tree.setModified(ChangeType.structure);
|
|
240
264
|
return nodeList[0];
|
|
241
265
|
} finally {
|
|
242
266
|
this.tree.enableUpdate(true);
|
|
@@ -276,7 +300,8 @@ export class WunderbaumNode {
|
|
|
276
300
|
|
|
277
301
|
/**
|
|
278
302
|
* Apply a modification (or navigation) operation.
|
|
279
|
-
*
|
|
303
|
+
*
|
|
304
|
+
* @see {@link Wunderbaum.applyCommand}
|
|
280
305
|
*/
|
|
281
306
|
applyCommand(cmd: ApplyCommandType, opts: any): any {
|
|
282
307
|
return this.tree.applyCommand(cmd, this, opts);
|
|
@@ -374,8 +399,7 @@ export class WunderbaumNode {
|
|
|
374
399
|
|
|
375
400
|
/** Find a node relative to self.
|
|
376
401
|
*
|
|
377
|
-
* @
|
|
378
|
-
* or a keyword ('down', 'first', 'last', 'left', 'parent', 'right', 'up').
|
|
402
|
+
* @see {@link Wunderbaum.findRelatedNode|tree.findRelatedNode()}
|
|
379
403
|
*/
|
|
380
404
|
findRelatedNode(where: string, includeHidden = false) {
|
|
381
405
|
return this.tree.findRelatedNode(this, where, includeHidden);
|
|
@@ -739,7 +763,7 @@ export class WunderbaumNode {
|
|
|
739
763
|
util.assert(!this.parent);
|
|
740
764
|
tree.columns = data.columns;
|
|
741
765
|
delete data.columns;
|
|
742
|
-
tree.
|
|
766
|
+
tree.updateColumns({ calculateCols: false });
|
|
743
767
|
}
|
|
744
768
|
this._loadSourceObject(data);
|
|
745
769
|
}
|
|
@@ -777,20 +801,21 @@ export class WunderbaumNode {
|
|
|
777
801
|
}
|
|
778
802
|
util.assert(
|
|
779
803
|
util.isArray(source) || (source && source.url),
|
|
780
|
-
"The lazyLoad event must return a node list, `{url: ...}
|
|
804
|
+
"The lazyLoad event must return a node list, `{url: ...}`, or false."
|
|
781
805
|
);
|
|
782
806
|
|
|
783
807
|
await this.load(source); // also calls setStatus('ok')
|
|
784
808
|
|
|
785
809
|
if (wasExpanded) {
|
|
786
810
|
this.expanded = true;
|
|
787
|
-
this.tree.
|
|
811
|
+
this.tree.setModified(ChangeType.structure);
|
|
788
812
|
} else {
|
|
789
|
-
this.
|
|
813
|
+
this.setModified(); // Fix expander icon to 'loaded'
|
|
790
814
|
}
|
|
791
815
|
} catch (e) {
|
|
816
|
+
this.logError("Error during loadLazy()", e);
|
|
817
|
+
this._callEvent("error", { error: e });
|
|
792
818
|
this.setStatus(NodeStatusType.error, "" + e);
|
|
793
|
-
// } finally {
|
|
794
819
|
}
|
|
795
820
|
return;
|
|
796
821
|
}
|
|
@@ -956,7 +981,7 @@ export class WunderbaumNode {
|
|
|
956
981
|
}, true);
|
|
957
982
|
}
|
|
958
983
|
|
|
959
|
-
tree.
|
|
984
|
+
tree.setModified(ChangeType.structure);
|
|
960
985
|
// TODO: fix selection state
|
|
961
986
|
// TODO: fix active state
|
|
962
987
|
}
|
|
@@ -978,31 +1003,33 @@ export class WunderbaumNode {
|
|
|
978
1003
|
where = KEY_TO_ACTION_DICT[where] || where;
|
|
979
1004
|
|
|
980
1005
|
// Otherwise activate or focus the related node
|
|
981
|
-
|
|
982
|
-
if (node) {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1006
|
+
const node = this.findRelatedNode(where);
|
|
1007
|
+
if (!node) {
|
|
1008
|
+
this.logWarn(`Could not find related node '${where}'.`);
|
|
1009
|
+
return Promise.resolve(this);
|
|
1010
|
+
}
|
|
1011
|
+
// setFocus/setActive will scroll later (if autoScroll is specified)
|
|
1012
|
+
try {
|
|
1013
|
+
node.makeVisible({ scrollIntoView: false });
|
|
1014
|
+
} catch (e) {} // #272
|
|
1015
|
+
node.setFocus();
|
|
1016
|
+
if (options?.activate === false) {
|
|
1017
|
+
return Promise.resolve(this);
|
|
992
1018
|
}
|
|
993
|
-
|
|
994
|
-
return Promise.resolve(this);
|
|
1019
|
+
return node.setActive(true, { event: options?.event });
|
|
995
1020
|
}
|
|
996
1021
|
|
|
997
1022
|
/** Delete this node and all descendants. */
|
|
998
1023
|
remove() {
|
|
999
1024
|
const tree = this.tree;
|
|
1000
1025
|
const pos = this.parent.children!.indexOf(this);
|
|
1026
|
+
this.triggerModify("remove");
|
|
1001
1027
|
this.parent.children!.splice(pos, 1);
|
|
1002
1028
|
this.visit((n) => {
|
|
1003
1029
|
n.removeMarkup();
|
|
1004
1030
|
tree._unregisterNode(n);
|
|
1005
1031
|
}, true);
|
|
1032
|
+
tree.setModified(ChangeType.structure);
|
|
1006
1033
|
}
|
|
1007
1034
|
|
|
1008
1035
|
/** Remove all descendants of this node. */
|
|
@@ -1035,7 +1062,7 @@ export class WunderbaumNode {
|
|
|
1035
1062
|
if (!this.isRootNode()) {
|
|
1036
1063
|
this.expanded = false;
|
|
1037
1064
|
}
|
|
1038
|
-
this.tree.
|
|
1065
|
+
this.tree.setModified(ChangeType.structure);
|
|
1039
1066
|
}
|
|
1040
1067
|
|
|
1041
1068
|
/** Remove all HTML markup from the DOM. */
|
|
@@ -1135,6 +1162,10 @@ export class WunderbaumNode {
|
|
|
1135
1162
|
tree.navMode === NavigationMode.row ? null : tree.activeColIdx;
|
|
1136
1163
|
// let colElems: HTMLElement[];
|
|
1137
1164
|
const isNew = !rowDiv;
|
|
1165
|
+
util.assert(
|
|
1166
|
+
!isNew || (opts && opts.after),
|
|
1167
|
+
"opts.after expected, unless updating"
|
|
1168
|
+
);
|
|
1138
1169
|
|
|
1139
1170
|
util.assert(!this.isRootNode());
|
|
1140
1171
|
//
|
|
@@ -1194,7 +1225,7 @@ export class WunderbaumNode {
|
|
|
1194
1225
|
ofsTitlePx += ICON_WIDTH;
|
|
1195
1226
|
}
|
|
1196
1227
|
|
|
1197
|
-
if (level > treeOptions.minExpandLevel) {
|
|
1228
|
+
if (!treeOptions.minExpandLevel || level > treeOptions.minExpandLevel) {
|
|
1198
1229
|
expanderSpan = document.createElement("i");
|
|
1199
1230
|
nodeElem.appendChild(expanderSpan);
|
|
1200
1231
|
ofsTitlePx += ICON_WIDTH;
|
|
@@ -1214,7 +1245,7 @@ export class WunderbaumNode {
|
|
|
1214
1245
|
// Store the width of leading icons with the node, so we can calculate
|
|
1215
1246
|
// the width of the embedded title span later
|
|
1216
1247
|
(<any>nodeElem)._ofsTitlePx = ofsTitlePx;
|
|
1217
|
-
if (tree.options.dnd
|
|
1248
|
+
if (tree.options.dnd!.dragStart) {
|
|
1218
1249
|
nodeElem.draggable = true;
|
|
1219
1250
|
}
|
|
1220
1251
|
|
|
@@ -1290,10 +1321,11 @@ export class WunderbaumNode {
|
|
|
1290
1321
|
|
|
1291
1322
|
if (this.titleWithHighlight) {
|
|
1292
1323
|
titleSpan.innerHTML = this.titleWithHighlight;
|
|
1293
|
-
} else if (tree.options.escapeTitles) {
|
|
1294
|
-
titleSpan.textContent = this.title;
|
|
1295
1324
|
} else {
|
|
1296
|
-
|
|
1325
|
+
// } else if (tree.options.escapeTitles) {
|
|
1326
|
+
titleSpan.textContent = this.title;
|
|
1327
|
+
// } else {
|
|
1328
|
+
// titleSpan.innerHTML = this.title;
|
|
1297
1329
|
}
|
|
1298
1330
|
// Set the width of the title span, so overflow ellipsis work
|
|
1299
1331
|
if (!treeOptions.skeleton) {
|
|
@@ -1328,9 +1360,19 @@ export class WunderbaumNode {
|
|
|
1328
1360
|
}
|
|
1329
1361
|
|
|
1330
1362
|
// Attach to DOM as late as possible
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1363
|
+
if (isNew) {
|
|
1364
|
+
const after = opts ? opts.after : "last";
|
|
1365
|
+
switch (after) {
|
|
1366
|
+
case "first":
|
|
1367
|
+
tree.nodeListElement.prepend(rowDiv);
|
|
1368
|
+
break;
|
|
1369
|
+
case "last":
|
|
1370
|
+
tree.nodeListElement.appendChild(rowDiv);
|
|
1371
|
+
break;
|
|
1372
|
+
default:
|
|
1373
|
+
opts.after.after(rowDiv);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1334
1376
|
}
|
|
1335
1377
|
|
|
1336
1378
|
/**
|
|
@@ -1342,7 +1384,7 @@ export class WunderbaumNode {
|
|
|
1342
1384
|
this.expanded = false;
|
|
1343
1385
|
this.lazy = true;
|
|
1344
1386
|
this.children = null;
|
|
1345
|
-
this.tree.
|
|
1387
|
+
this.tree.setModified(ChangeType.structure);
|
|
1346
1388
|
}
|
|
1347
1389
|
|
|
1348
1390
|
/** Convert node (or whole branch) into a plain object.
|
|
@@ -1408,14 +1450,15 @@ export class WunderbaumNode {
|
|
|
1408
1450
|
*
|
|
1409
1451
|
* Evaluation sequence:
|
|
1410
1452
|
*
|
|
1411
|
-
* If `tree.options.<name>` is a callback that returns something, use that.
|
|
1412
|
-
* Else if `node.<name>` is defined, use that.
|
|
1413
|
-
* Else if `tree.types[<node.type>]` is a value, use that.
|
|
1414
|
-
* Else if `tree.options.<name>` is a value, use that.
|
|
1415
|
-
* Else use `defaultValue`.
|
|
1453
|
+
* - If `tree.options.<name>` is a callback that returns something, use that.
|
|
1454
|
+
* - Else if `node.<name>` is defined, use that.
|
|
1455
|
+
* - Else if `tree.types[<node.type>]` is a value, use that.
|
|
1456
|
+
* - Else if `tree.options.<name>` is a value, use that.
|
|
1457
|
+
* - Else use `defaultValue`.
|
|
1416
1458
|
*
|
|
1417
1459
|
* @param name name of the option property (on node and tree)
|
|
1418
1460
|
* @param defaultValue return this if nothing else matched
|
|
1461
|
+
* {@link Wunderbaum.getOption|Wunderbaum.getOption()}
|
|
1419
1462
|
*/
|
|
1420
1463
|
getOption(name: string, defaultValue?: any) {
|
|
1421
1464
|
let tree = this.tree;
|
|
@@ -1453,17 +1496,23 @@ export class WunderbaumNode {
|
|
|
1453
1496
|
return value ?? defaultValue;
|
|
1454
1497
|
}
|
|
1455
1498
|
|
|
1499
|
+
/** Make sure that this node is visible in the viewport.
|
|
1500
|
+
* @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo()}
|
|
1501
|
+
*/
|
|
1456
1502
|
async scrollIntoView(options?: any) {
|
|
1457
1503
|
return this.tree.scrollTo(this);
|
|
1458
1504
|
}
|
|
1459
1505
|
|
|
1460
|
-
|
|
1506
|
+
/**
|
|
1507
|
+
* Activate this node, deactivate previous, send events, activate column and scroll int viewport.
|
|
1508
|
+
*/
|
|
1509
|
+
async setActive(flag: boolean = true, options?: SetActiveOptions) {
|
|
1461
1510
|
const tree = this.tree;
|
|
1462
1511
|
const prev = tree.activeNode;
|
|
1463
1512
|
const retrigger = options?.retrigger;
|
|
1464
|
-
const
|
|
1513
|
+
const noEvents = options?.noEvents;
|
|
1465
1514
|
|
|
1466
|
-
if (!
|
|
1515
|
+
if (!noEvents) {
|
|
1467
1516
|
let orgEvent = options?.event;
|
|
1468
1517
|
if (flag) {
|
|
1469
1518
|
if (prev !== this || retrigger) {
|
|
@@ -1482,7 +1531,7 @@ export class WunderbaumNode {
|
|
|
1482
1531
|
}) === false
|
|
1483
1532
|
) {
|
|
1484
1533
|
tree.activeNode = null;
|
|
1485
|
-
prev?.
|
|
1534
|
+
prev?.setModified();
|
|
1486
1535
|
return;
|
|
1487
1536
|
}
|
|
1488
1537
|
}
|
|
@@ -1493,8 +1542,8 @@ export class WunderbaumNode {
|
|
|
1493
1542
|
|
|
1494
1543
|
if (prev !== this) {
|
|
1495
1544
|
tree.activeNode = this;
|
|
1496
|
-
prev?.
|
|
1497
|
-
this.
|
|
1545
|
+
prev?.setModified();
|
|
1546
|
+
this.setModified();
|
|
1498
1547
|
}
|
|
1499
1548
|
if (
|
|
1500
1549
|
options &&
|
|
@@ -1507,22 +1556,13 @@ export class WunderbaumNode {
|
|
|
1507
1556
|
// requestAnimationFrame(() => {
|
|
1508
1557
|
// this.scrollIntoView();
|
|
1509
1558
|
// })
|
|
1510
|
-
this.scrollIntoView();
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
setDirty(type: ChangeType) {
|
|
1514
|
-
if (this.tree._disableUpdate) {
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
if (type === ChangeType.structure) {
|
|
1518
|
-
this.tree.updateViewport();
|
|
1519
|
-
} else if (this._rowElem) {
|
|
1520
|
-
// otherwise not in viewport, so no need to render
|
|
1521
|
-
this.render();
|
|
1522
|
-
}
|
|
1559
|
+
return this.scrollIntoView();
|
|
1523
1560
|
}
|
|
1524
1561
|
|
|
1525
|
-
|
|
1562
|
+
/**
|
|
1563
|
+
* Expand or collapse this node.
|
|
1564
|
+
*/
|
|
1565
|
+
async setExpanded(flag: boolean = true, options?: SetExpandedOptions) {
|
|
1526
1566
|
// alert("" + this.getLevel() + ", "+ this.getOption("minExpandLevel");
|
|
1527
1567
|
if (
|
|
1528
1568
|
!flag &&
|
|
@@ -1530,45 +1570,61 @@ export class WunderbaumNode {
|
|
|
1530
1570
|
this.getLevel() < this.getOption("minExpandLevel") &&
|
|
1531
1571
|
!util.getOption(options, "force")
|
|
1532
1572
|
) {
|
|
1533
|
-
this.logDebug("Ignored collapse request.");
|
|
1573
|
+
this.logDebug("Ignored collapse request below expandLevel.");
|
|
1534
1574
|
return;
|
|
1535
1575
|
}
|
|
1536
1576
|
if (flag && this.lazy && this.children == null) {
|
|
1537
1577
|
await this.loadLazy();
|
|
1538
1578
|
}
|
|
1539
1579
|
this.expanded = flag;
|
|
1540
|
-
this.
|
|
1580
|
+
this.tree.setModified(ChangeType.structure);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* Set keyboard focus here.
|
|
1585
|
+
* @see {@link setActive}
|
|
1586
|
+
*/
|
|
1587
|
+
setFocus(flag: boolean = true, options?: any) {
|
|
1588
|
+
const prev = this.tree.focusNode;
|
|
1589
|
+
this.tree.focusNode = this;
|
|
1590
|
+
prev?.setModified();
|
|
1591
|
+
this.setModified();
|
|
1541
1592
|
}
|
|
1542
1593
|
|
|
1594
|
+
/** Set a new icon path or class. */
|
|
1543
1595
|
setIcon() {
|
|
1544
1596
|
throw new Error("Not yet implemented");
|
|
1545
|
-
// this.
|
|
1597
|
+
// this.setModified();
|
|
1546
1598
|
}
|
|
1547
1599
|
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1600
|
+
/** Change node's {@link key} and/or {@link refKey}. */
|
|
1601
|
+
setKey(key: string | null, refKey: string | null) {
|
|
1602
|
+
throw new Error("Not yet implemented");
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
/** Schedule a render, typically called to update after a status or data change. */
|
|
1606
|
+
setModified(change: ChangeType = ChangeType.status) {
|
|
1607
|
+
util.assert(change === ChangeType.status);
|
|
1608
|
+
this.tree.setModified(ChangeType.row, this);
|
|
1553
1609
|
}
|
|
1554
1610
|
|
|
1555
|
-
|
|
1611
|
+
/** Modify the check/uncheck state. */
|
|
1612
|
+
setSelected(flag: boolean = true, options?: SetSelectedOptions) {
|
|
1556
1613
|
const prev = this.selected;
|
|
1557
1614
|
if (!!flag !== prev) {
|
|
1558
1615
|
this._callEvent("select", { flag: flag });
|
|
1559
1616
|
}
|
|
1560
1617
|
this.selected = !!flag;
|
|
1561
|
-
this.
|
|
1618
|
+
this.setModified();
|
|
1562
1619
|
}
|
|
1563
1620
|
|
|
1564
|
-
/**
|
|
1565
|
-
*/
|
|
1621
|
+
/** Display node status (ok, loading, error, noData) using styles and a dummy child node. */
|
|
1566
1622
|
setStatus(
|
|
1567
1623
|
status: NodeStatusType,
|
|
1568
1624
|
message?: string,
|
|
1569
1625
|
details?: string
|
|
1570
1626
|
): WunderbaumNode | null {
|
|
1571
|
-
|
|
1627
|
+
const tree = this.tree;
|
|
1572
1628
|
let statusNode: WunderbaumNode | null = null;
|
|
1573
1629
|
|
|
1574
1630
|
const _clearStatusNode = () => {
|
|
@@ -1649,13 +1705,14 @@ export class WunderbaumNode {
|
|
|
1649
1705
|
default:
|
|
1650
1706
|
util.error("invalid node status " + status);
|
|
1651
1707
|
}
|
|
1652
|
-
tree.
|
|
1708
|
+
tree.setModified(ChangeType.structure);
|
|
1653
1709
|
return statusNode;
|
|
1654
1710
|
}
|
|
1655
1711
|
|
|
1712
|
+
/** Rename this node. */
|
|
1656
1713
|
setTitle(title: string): void {
|
|
1657
1714
|
this.title = title;
|
|
1658
|
-
this.
|
|
1715
|
+
this.setModified();
|
|
1659
1716
|
// this.triggerModify("rename"); // TODO
|
|
1660
1717
|
}
|
|
1661
1718
|
|
|
@@ -1684,12 +1741,18 @@ export class WunderbaumNode {
|
|
|
1684
1741
|
* @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
|
|
1685
1742
|
* @param {object} [extra]
|
|
1686
1743
|
*/
|
|
1687
|
-
triggerModify(operation: string, extra
|
|
1744
|
+
triggerModify(operation: string, extra?: any) {
|
|
1745
|
+
if (!this.parent) {
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1688
1748
|
this.parent.triggerModifyChild(operation, this, extra);
|
|
1689
1749
|
}
|
|
1690
1750
|
|
|
1691
|
-
/**
|
|
1692
|
-
*
|
|
1751
|
+
/**
|
|
1752
|
+
* Call fn(node) for all child nodes in hierarchical order (depth-first).
|
|
1753
|
+
*
|
|
1754
|
+
* Stop iteration, if fn() returns false. Skip current branch, if fn()
|
|
1755
|
+
* returns "skip".<br>
|
|
1693
1756
|
* Return false if iteration was stopped.
|
|
1694
1757
|
*
|
|
1695
1758
|
* @param {function} callback the callback function.
|
|
@@ -1745,7 +1808,8 @@ export class WunderbaumNode {
|
|
|
1745
1808
|
return true;
|
|
1746
1809
|
}
|
|
1747
1810
|
|
|
1748
|
-
/**
|
|
1811
|
+
/**
|
|
1812
|
+
* Call fn(node) for all sibling nodes.<br>
|
|
1749
1813
|
* Stop iteration, if fn() returns false.<br>
|
|
1750
1814
|
* Return false if iteration was stopped.
|
|
1751
1815
|
*
|