wunderbaum 0.0.7 → 0.0.8
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 -1
- package/dist/wunderbaum.css +1 -1
- package/dist/wunderbaum.d.ts +97 -53
- package/dist/wunderbaum.esm.js +330 -123
- package/dist/wunderbaum.esm.min.js +20 -20
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +330 -123
- package/dist/wunderbaum.umd.min.js +32 -32
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/common.ts +156 -14
- package/src/types.ts +43 -19
- package/src/util.ts +9 -4
- package/src/wb_node.ts +154 -53
- package/src/wunderbaum.ts +50 -55
package/src/wb_node.ts
CHANGED
|
@@ -9,12 +9,14 @@ import * as util from "./util";
|
|
|
9
9
|
|
|
10
10
|
import { Wunderbaum } from "./wunderbaum";
|
|
11
11
|
import {
|
|
12
|
+
AddChildrenOptions,
|
|
12
13
|
AddNodeType,
|
|
13
14
|
ApplyCommandType,
|
|
14
15
|
ChangeType,
|
|
15
16
|
ColumnEventInfos,
|
|
17
|
+
ExpandAllOptions,
|
|
16
18
|
MakeVisibleOptions,
|
|
17
|
-
|
|
19
|
+
MatcherCallback,
|
|
18
20
|
NodeAnyCallback,
|
|
19
21
|
NodeStatusType,
|
|
20
22
|
NodeVisitCallback,
|
|
@@ -34,6 +36,7 @@ import {
|
|
|
34
36
|
TITLE_SPAN_PAD_Y,
|
|
35
37
|
ROW_HEIGHT,
|
|
36
38
|
TEST_IMG,
|
|
39
|
+
inflateSourceData,
|
|
37
40
|
} from "./common";
|
|
38
41
|
import { Deferred } from "./deferred";
|
|
39
42
|
import { WbNodeData } from "./wb_options";
|
|
@@ -218,49 +221,55 @@ export class WunderbaumNode {
|
|
|
218
221
|
/**
|
|
219
222
|
* Append (or insert) a list of child nodes.
|
|
220
223
|
*
|
|
221
|
-
* Tip: pass `{ before: 0 }` to prepend children
|
|
222
|
-
*
|
|
223
|
-
* @param child node (or key or index of such).
|
|
224
|
-
* If omitted, the new children are appended.
|
|
224
|
+
* Tip: pass `{ before: 0 }` to prepend new nodes as first children.
|
|
225
|
+
*
|
|
225
226
|
* @returns first child added
|
|
226
227
|
*/
|
|
227
|
-
addChildren(
|
|
228
|
+
addChildren(
|
|
229
|
+
nodeData: WbNodeData | WbNodeData[],
|
|
230
|
+
options?: AddChildrenOptions
|
|
231
|
+
): WunderbaumNode {
|
|
228
232
|
const tree = this.tree;
|
|
229
|
-
|
|
230
|
-
let
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
nodeList = [];
|
|
233
|
+
let { before = null, applyMinExpanLevel = true, _level } = options ?? {};
|
|
234
|
+
// let { before, loadLazy=true, _level } = options ?? {};
|
|
235
|
+
// const isTopCall = _level == null;
|
|
236
|
+
_level ??= this.getLevel();
|
|
237
|
+
const nodeList = [];
|
|
235
238
|
|
|
236
239
|
try {
|
|
237
240
|
tree.enableUpdate(false);
|
|
238
241
|
|
|
239
242
|
if (util.isPlainObject(nodeData)) {
|
|
240
|
-
nodeData = [nodeData];
|
|
243
|
+
nodeData = [<WbNodeData>nodeData];
|
|
241
244
|
}
|
|
242
|
-
const forceExpand =
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
const forceExpand =
|
|
246
|
+
applyMinExpanLevel && _level < tree.options.minExpandLevel!;
|
|
247
|
+
for (let child of <WbNodeData[]>nodeData) {
|
|
248
|
+
const subChildren = child.children;
|
|
245
249
|
delete child.children;
|
|
246
250
|
|
|
247
|
-
|
|
248
|
-
if (forceExpand && !n.
|
|
251
|
+
const n = new WunderbaumNode(tree, this, child);
|
|
252
|
+
if (forceExpand && !n.isUnloaded()) {
|
|
253
|
+
n.expanded = true;
|
|
254
|
+
}
|
|
249
255
|
nodeList.push(n);
|
|
250
256
|
if (subChildren) {
|
|
251
|
-
n.addChildren(subChildren, {
|
|
257
|
+
n.addChildren(subChildren, { _level: _level + 1 });
|
|
252
258
|
}
|
|
253
259
|
}
|
|
254
260
|
|
|
255
261
|
if (!this.children) {
|
|
256
262
|
this.children = nodeList;
|
|
257
|
-
} else if (
|
|
263
|
+
} else if (before == null || this.children.length === 0) {
|
|
258
264
|
this.children = this.children.concat(nodeList);
|
|
259
265
|
} else {
|
|
260
|
-
// Returns null if
|
|
261
|
-
|
|
262
|
-
let pos = this.children.indexOf(
|
|
263
|
-
util.assert(
|
|
266
|
+
// Returns null if before is not a direct child:
|
|
267
|
+
before = this.findDirectChild(before)!;
|
|
268
|
+
let pos = this.children.indexOf(before);
|
|
269
|
+
util.assert(
|
|
270
|
+
pos >= 0,
|
|
271
|
+
`options.before must be a direct child of ${this}`
|
|
272
|
+
);
|
|
264
273
|
// insert nodeList after children[pos]
|
|
265
274
|
this.children.splice(pos, 0, ...nodeList);
|
|
266
275
|
}
|
|
@@ -270,10 +279,13 @@ export class WunderbaumNode {
|
|
|
270
279
|
// }
|
|
271
280
|
// this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null);
|
|
272
281
|
tree.setModified(ChangeType.structure);
|
|
273
|
-
return nodeList[0];
|
|
274
282
|
} finally {
|
|
275
283
|
tree.enableUpdate(true);
|
|
276
284
|
}
|
|
285
|
+
// if(isTopCall && loadLazy){
|
|
286
|
+
// this.logWarn("addChildren(): loadLazy is not yet implemented.")
|
|
287
|
+
// }
|
|
288
|
+
return nodeList[0];
|
|
277
289
|
}
|
|
278
290
|
|
|
279
291
|
/**
|
|
@@ -351,22 +363,99 @@ export class WunderbaumNode {
|
|
|
351
363
|
}
|
|
352
364
|
}
|
|
353
365
|
|
|
354
|
-
/** Call `setExpanded()` on
|
|
355
|
-
async expandAll(flag: boolean = true) {
|
|
356
|
-
this.
|
|
357
|
-
|
|
358
|
-
}
|
|
366
|
+
/** Call `setExpanded()` on all descendant nodes. */
|
|
367
|
+
async expandAll(flag: boolean = true, options?: ExpandAllOptions) {
|
|
368
|
+
const tree = this.tree;
|
|
369
|
+
const minExpandLevel = this.tree.options.minExpandLevel;
|
|
370
|
+
let { depth = 99, loadLazy, force } = options ?? {};
|
|
371
|
+
|
|
372
|
+
const expand_opts = {
|
|
373
|
+
scrollIntoView: false,
|
|
374
|
+
force: force,
|
|
375
|
+
loadLazy: loadLazy,
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// this.logInfo(`expandAll(${flag})`);
|
|
379
|
+
// Expand all direct children in parallel:
|
|
380
|
+
async function _iter(n: WunderbaumNode, level: number | null) {
|
|
381
|
+
// n.logInfo(` _iter(${level})`);
|
|
382
|
+
if (level === 0) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
// if (!flag && minExpandLevel && !force && n.getLevel() <= minExpandLevel) {
|
|
386
|
+
// return; // Do not collapse until minExpandLevel
|
|
387
|
+
// }
|
|
388
|
+
const level_1 = level == null ? null : level - 1;
|
|
389
|
+
const promises: Promise<unknown>[] = [];
|
|
390
|
+
n.children?.forEach((cn) => {
|
|
391
|
+
if (flag) {
|
|
392
|
+
if (!cn.expanded && (cn.children || (loadLazy && cn.lazy))) {
|
|
393
|
+
// Node is collapsed and may be expanded (i.e. has children or is lazy)
|
|
394
|
+
// Expanding may be async, so we store the promise.
|
|
395
|
+
// Also the recursion is delayed until expansion finished.
|
|
396
|
+
const p = cn.setExpanded(true, expand_opts);
|
|
397
|
+
promises.push(p);
|
|
398
|
+
p.then(async () => {
|
|
399
|
+
await _iter(cn, level_1);
|
|
400
|
+
});
|
|
401
|
+
} else {
|
|
402
|
+
// We don't expand the node, but still visit descendants.
|
|
403
|
+
// There we may find lazy nodes, so we
|
|
404
|
+
promises.push(_iter(cn, level_1));
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
// Collapsing is always synchronous, so no promises required
|
|
408
|
+
if (!minExpandLevel || force || cn.getLevel() > minExpandLevel) {
|
|
409
|
+
// Do not collapse until minExpandLevel
|
|
410
|
+
cn.setExpanded(false, expand_opts);
|
|
411
|
+
}
|
|
412
|
+
_iter(cn, level_1); // recursion, even if cn was already collapsed
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
return new Promise((resolve) => {
|
|
416
|
+
Promise.all(promises).then(() => {
|
|
417
|
+
resolve(true);
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const tag = tree.logTime(`${this}.expandAll(${flag})`);
|
|
423
|
+
try {
|
|
424
|
+
tree.enableUpdate(false);
|
|
425
|
+
await _iter(this, depth);
|
|
426
|
+
} finally {
|
|
427
|
+
tree.enableUpdate(true);
|
|
428
|
+
tree.logTimeEnd(tag);
|
|
429
|
+
}
|
|
359
430
|
}
|
|
360
431
|
|
|
361
|
-
/**
|
|
432
|
+
/**
|
|
433
|
+
* Find all descendant nodes that match condition (excluding self).
|
|
362
434
|
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
435
|
+
* If `match` is a string, search for exact node title.
|
|
436
|
+
* If `match` is a RegExp expression, apply it to node.title, using
|
|
437
|
+
* [RegExp.test()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test).
|
|
438
|
+
* If `match` is a callback, match all nodes for that the callback(node) returns true.
|
|
439
|
+
*
|
|
440
|
+
* Returns an empty array if no nodes were found.
|
|
441
|
+
*
|
|
442
|
+
* Examples:
|
|
443
|
+
* ```js
|
|
444
|
+
* // Match all node titles that match exactly 'Joe':
|
|
445
|
+
* nodeList = node.findAll("Joe")
|
|
446
|
+
* // Match all node titles that start with 'Joe' case sensitive:
|
|
447
|
+
* nodeList = node.findAll(/^Joe/)
|
|
448
|
+
* // Match all node titles that contain 'oe', case insensitive:
|
|
449
|
+
* nodeList = node.findAll(/oe/i)
|
|
450
|
+
* // Match all nodes with `data.price` >= 99:
|
|
451
|
+
* nodeList = node.findAll((n) => {
|
|
452
|
+
* return n.data.price >= 99;
|
|
453
|
+
* })
|
|
454
|
+
* ```
|
|
365
455
|
*/
|
|
366
|
-
findAll(match: string |
|
|
367
|
-
const matcher =
|
|
368
|
-
?
|
|
369
|
-
: makeNodeTitleMatcher(<string>match);
|
|
456
|
+
findAll(match: string | RegExp | MatcherCallback): WunderbaumNode[] {
|
|
457
|
+
const matcher =
|
|
458
|
+
typeof match === "function" ? match : makeNodeTitleMatcher(match);
|
|
370
459
|
const res: WunderbaumNode[] = [];
|
|
371
460
|
this.visit((n) => {
|
|
372
461
|
if (matcher(n)) {
|
|
@@ -398,15 +487,14 @@ export class WunderbaumNode {
|
|
|
398
487
|
return null;
|
|
399
488
|
}
|
|
400
489
|
|
|
401
|
-
/**
|
|
490
|
+
/**
|
|
491
|
+
* Find first descendant node that matches condition (excluding self) or null.
|
|
402
492
|
*
|
|
403
|
-
* @
|
|
404
|
-
* callback function that returns `true` if a node is matched.
|
|
493
|
+
* @see {@link WunderbaumNode.findAll} for examples.
|
|
405
494
|
*/
|
|
406
|
-
findFirst(match: string |
|
|
407
|
-
const matcher =
|
|
408
|
-
?
|
|
409
|
-
: makeNodeTitleMatcher(<string>match);
|
|
495
|
+
findFirst(match: string | RegExp | MatcherCallback): WunderbaumNode | null {
|
|
496
|
+
const matcher =
|
|
497
|
+
typeof match === "function" ? match : makeNodeTitleMatcher(match);
|
|
410
498
|
let res = null;
|
|
411
499
|
this.visit((n) => {
|
|
412
500
|
if (matcher(n)) {
|
|
@@ -596,7 +684,8 @@ export class WunderbaumNode {
|
|
|
596
684
|
* an expand operation is currently possible.
|
|
597
685
|
*/
|
|
598
686
|
isExpandable(andCollapsed = false): boolean {
|
|
599
|
-
return !!this.children && (!this.expanded || !andCollapsed);
|
|
687
|
+
// return !!this.children && (!this.expanded || !andCollapsed);
|
|
688
|
+
return !!(this.children || this.lazy) && (!this.expanded || !andCollapsed);
|
|
600
689
|
}
|
|
601
690
|
|
|
602
691
|
/** Return true if this node is currently in edit-title mode. */
|
|
@@ -734,6 +823,13 @@ export class WunderbaumNode {
|
|
|
734
823
|
source = { children: source };
|
|
735
824
|
}
|
|
736
825
|
util.assert(util.isPlainObject(source));
|
|
826
|
+
|
|
827
|
+
const format: string = source.format ?? "nested";
|
|
828
|
+
util.assert(format === "nested" || format === "flat");
|
|
829
|
+
|
|
830
|
+
// Pre-rocess for 'nested' or 'flat' format
|
|
831
|
+
inflateSourceData(source);
|
|
832
|
+
|
|
737
833
|
util.assert(
|
|
738
834
|
source.children,
|
|
739
835
|
"If `source` is an object, it must have a `children` property"
|
|
@@ -923,22 +1019,23 @@ export class WunderbaumNode {
|
|
|
923
1019
|
|
|
924
1020
|
/** Expand all parents and optionally scroll into visible area as neccessary.
|
|
925
1021
|
* Promise is resolved, when lazy loading and animations are done.
|
|
926
|
-
* @param {object} [
|
|
1022
|
+
* @param {object} [options] passed to `setExpanded()`.
|
|
927
1023
|
* Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true}
|
|
928
1024
|
*/
|
|
929
|
-
async makeVisible(
|
|
1025
|
+
async makeVisible(options?: MakeVisibleOptions) {
|
|
930
1026
|
let i,
|
|
931
1027
|
dfd = new Deferred(),
|
|
932
1028
|
deferreds = [],
|
|
933
1029
|
parents = this.getParentList(false, false),
|
|
934
1030
|
len = parents.length,
|
|
935
|
-
|
|
936
|
-
scroll =
|
|
1031
|
+
noAnimation = util.getOption(options, "noAnimation", false),
|
|
1032
|
+
scroll = util.getOption(options, "scrollIntoView", true);
|
|
1033
|
+
// scroll = !(options && options.scrollIntoView === false);
|
|
937
1034
|
|
|
938
1035
|
// Expand bottom-up, so only the top node is animated
|
|
939
1036
|
for (i = len - 1; i >= 0; i--) {
|
|
940
1037
|
// self.debug("pushexpand" + parents[i]);
|
|
941
|
-
const seOpts = { noAnimation:
|
|
1038
|
+
const seOpts = { noAnimation: noAnimation };
|
|
942
1039
|
deferreds.push(parents[i].setExpanded(true, seOpts));
|
|
943
1040
|
}
|
|
944
1041
|
Promise.all(deferreds).then(() => {
|
|
@@ -1727,11 +1824,12 @@ export class WunderbaumNode {
|
|
|
1727
1824
|
* Expand or collapse this node.
|
|
1728
1825
|
*/
|
|
1729
1826
|
async setExpanded(flag: boolean = true, options?: SetExpandedOptions) {
|
|
1827
|
+
const { force, scrollIntoView, immediate } = options ?? {};
|
|
1730
1828
|
if (
|
|
1731
1829
|
!flag &&
|
|
1732
1830
|
this.isExpanded() &&
|
|
1733
1831
|
this.getLevel() <= this.tree.getOption("minExpandLevel") &&
|
|
1734
|
-
!
|
|
1832
|
+
!force
|
|
1735
1833
|
) {
|
|
1736
1834
|
this.logDebug("Ignored collapse request below expandLevel.");
|
|
1737
1835
|
return;
|
|
@@ -1739,15 +1837,18 @@ export class WunderbaumNode {
|
|
|
1739
1837
|
if (!flag === !this.expanded) {
|
|
1740
1838
|
return; // Nothing to do
|
|
1741
1839
|
}
|
|
1840
|
+
// this.log("setExpanded()");
|
|
1742
1841
|
if (flag && this.lazy && this.children == null) {
|
|
1743
1842
|
await this.loadLazy();
|
|
1744
1843
|
}
|
|
1745
1844
|
this.expanded = flag;
|
|
1746
|
-
const updateOpts = { immediate:
|
|
1845
|
+
const updateOpts = { immediate: immediate };
|
|
1846
|
+
// const updateOpts = { immediate: !!util.getOption(options, "immediate") };
|
|
1747
1847
|
this.tree.setModified(ChangeType.structure, updateOpts);
|
|
1748
|
-
if (
|
|
1848
|
+
if (flag && scrollIntoView !== false) {
|
|
1749
1849
|
const lastChild = this.getLastChild();
|
|
1750
1850
|
if (lastChild) {
|
|
1851
|
+
this.tree.updatePendingModifications();
|
|
1751
1852
|
lastChild.scrollIntoView({ topNode: this });
|
|
1752
1853
|
}
|
|
1753
1854
|
}
|
package/src/wunderbaum.ts
CHANGED
|
@@ -23,8 +23,9 @@ import {
|
|
|
23
23
|
ApplyCommandType,
|
|
24
24
|
ChangeType,
|
|
25
25
|
ColumnDefinitionList,
|
|
26
|
+
ExpandAllOptions,
|
|
26
27
|
FilterModeType,
|
|
27
|
-
|
|
28
|
+
MatcherCallback,
|
|
28
29
|
NavigationOptions,
|
|
29
30
|
NodeStatusType,
|
|
30
31
|
NodeTypeDefinitions,
|
|
@@ -710,13 +711,13 @@ export class Wunderbaum {
|
|
|
710
711
|
/**
|
|
711
712
|
* Apply a modification (or navigation) operation on the **tree or active node**.
|
|
712
713
|
*/
|
|
713
|
-
applyCommand(cmd: ApplyCommandType,
|
|
714
|
+
applyCommand(cmd: ApplyCommandType, options?: any): any;
|
|
714
715
|
|
|
715
716
|
/**
|
|
716
717
|
* Apply a modification (or navigation) operation on a **node**.
|
|
717
718
|
* @see {@link WunderbaumNode.applyCommand}
|
|
718
719
|
*/
|
|
719
|
-
applyCommand(cmd: ApplyCommandType, node: WunderbaumNode,
|
|
720
|
+
applyCommand(cmd: ApplyCommandType, node: WunderbaumNode, options?: any): any;
|
|
720
721
|
|
|
721
722
|
/**
|
|
722
723
|
* Apply a modification or navigation operation.
|
|
@@ -737,23 +738,23 @@ export class Wunderbaum {
|
|
|
737
738
|
applyCommand(
|
|
738
739
|
cmd: ApplyCommandType,
|
|
739
740
|
nodeOrOpts?: WunderbaumNode | any,
|
|
740
|
-
|
|
741
|
+
options?: any
|
|
741
742
|
): any {
|
|
742
743
|
let // clipboard,
|
|
743
744
|
node,
|
|
744
745
|
refNode;
|
|
745
|
-
//
|
|
746
|
+
// options = $.extend(
|
|
746
747
|
// { setActive: true, clipboard: CLIPBOARD },
|
|
747
|
-
//
|
|
748
|
+
// options_
|
|
748
749
|
// );
|
|
749
750
|
if (nodeOrOpts instanceof WunderbaumNode) {
|
|
750
751
|
node = nodeOrOpts;
|
|
751
752
|
} else {
|
|
752
753
|
node = this.getActiveNode()!;
|
|
753
|
-
util.assert(
|
|
754
|
-
|
|
754
|
+
util.assert(options === undefined);
|
|
755
|
+
options = nodeOrOpts;
|
|
755
756
|
}
|
|
756
|
-
// clipboard =
|
|
757
|
+
// clipboard = options.clipboard;
|
|
757
758
|
|
|
758
759
|
switch (cmd) {
|
|
759
760
|
// Sorting and indentation:
|
|
@@ -973,15 +974,8 @@ export class Wunderbaum {
|
|
|
973
974
|
}
|
|
974
975
|
|
|
975
976
|
/** Recursively expand all expandable nodes (triggers lazy load id needed). */
|
|
976
|
-
async expandAll(flag: boolean = true) {
|
|
977
|
-
|
|
978
|
-
try {
|
|
979
|
-
this.enableUpdate(false);
|
|
980
|
-
await this.root.expandAll(flag);
|
|
981
|
-
} finally {
|
|
982
|
-
this.enableUpdate(true);
|
|
983
|
-
this.logTimeEnd(tag);
|
|
984
|
-
}
|
|
977
|
+
async expandAll(flag: boolean = true, options?: ExpandAllOptions) {
|
|
978
|
+
await this.root.expandAll(flag, options);
|
|
985
979
|
}
|
|
986
980
|
|
|
987
981
|
/** Recursively select all nodes. */
|
|
@@ -1018,26 +1012,20 @@ export class Wunderbaum {
|
|
|
1018
1012
|
}
|
|
1019
1013
|
|
|
1020
1014
|
/**
|
|
1021
|
-
* Find all nodes that
|
|
1022
|
-
*
|
|
1023
|
-
* @param match title string to search for, or a
|
|
1024
|
-
* callback function that returns `true` if a node is matched.
|
|
1015
|
+
* Find all nodes that match condition.
|
|
1025
1016
|
*
|
|
1026
1017
|
* @see {@link WunderbaumNode.findAll}
|
|
1027
1018
|
*/
|
|
1028
|
-
findAll(match: string |
|
|
1019
|
+
findAll(match: string | RegExp | MatcherCallback) {
|
|
1029
1020
|
return this.root.findAll(match);
|
|
1030
1021
|
}
|
|
1031
1022
|
|
|
1032
1023
|
/**
|
|
1033
1024
|
* Find first node that matches condition.
|
|
1034
1025
|
*
|
|
1035
|
-
* @param match title string to search for, or a
|
|
1036
|
-
* callback function that returns `true` if a node is matched.
|
|
1037
1026
|
* @see {@link WunderbaumNode.findFirst}
|
|
1038
|
-
*
|
|
1039
1027
|
*/
|
|
1040
|
-
findFirst(match: string |
|
|
1028
|
+
findFirst(match: string | RegExp | MatcherCallback) {
|
|
1041
1029
|
return this.root.findFirst(match);
|
|
1042
1030
|
}
|
|
1043
1031
|
|
|
@@ -1049,8 +1037,8 @@ export class Wunderbaum {
|
|
|
1049
1037
|
* @see {@link WunderbaumNode.findFirst}
|
|
1050
1038
|
*
|
|
1051
1039
|
*/
|
|
1052
|
-
findKey(key: string): WunderbaumNode |
|
|
1053
|
-
return this.keyMap.get(key);
|
|
1040
|
+
findKey(key: string): WunderbaumNode | null {
|
|
1041
|
+
return this.keyMap.get(key) || null;
|
|
1054
1042
|
}
|
|
1055
1043
|
|
|
1056
1044
|
/**
|
|
@@ -1058,7 +1046,7 @@ export class Wunderbaum {
|
|
|
1058
1046
|
* and wrap-around at the end.
|
|
1059
1047
|
*/
|
|
1060
1048
|
findNextNode(
|
|
1061
|
-
match: string |
|
|
1049
|
+
match: string | MatcherCallback,
|
|
1062
1050
|
startNode?: WunderbaumNode | null
|
|
1063
1051
|
): WunderbaumNode | null {
|
|
1064
1052
|
//, visibleOnly) {
|
|
@@ -1383,13 +1371,13 @@ export class Wunderbaum {
|
|
|
1383
1371
|
|
|
1384
1372
|
let node;
|
|
1385
1373
|
WunderbaumNode;
|
|
1386
|
-
let
|
|
1374
|
+
let options: ScrollToOptions | undefined;
|
|
1387
1375
|
|
|
1388
1376
|
if (nodeOrOpts instanceof WunderbaumNode) {
|
|
1389
1377
|
node = nodeOrOpts;
|
|
1390
1378
|
} else {
|
|
1391
|
-
|
|
1392
|
-
node =
|
|
1379
|
+
options = nodeOrOpts;
|
|
1380
|
+
node = options.node;
|
|
1393
1381
|
}
|
|
1394
1382
|
util.assert(node && node._rowIdx != null);
|
|
1395
1383
|
|
|
@@ -1401,7 +1389,7 @@ export class Wunderbaum {
|
|
|
1401
1389
|
const vpTop = headerHeight;
|
|
1402
1390
|
const vpRowTop = rowTop - scrollTop;
|
|
1403
1391
|
const vpRowBottom = vpRowTop + ROW_HEIGHT;
|
|
1404
|
-
const topNode =
|
|
1392
|
+
const topNode = options?.topNode;
|
|
1405
1393
|
|
|
1406
1394
|
// this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts );
|
|
1407
1395
|
let newScrollTop: number | null = null;
|
|
@@ -1670,11 +1658,13 @@ export class Wunderbaum {
|
|
|
1670
1658
|
}
|
|
1671
1659
|
}
|
|
1672
1660
|
/** Update column headers and width. */
|
|
1673
|
-
updateColumns(
|
|
1674
|
-
|
|
1661
|
+
updateColumns(options?: any) {
|
|
1662
|
+
options = Object.assign({ calculateCols: true, updateRows: true }, options);
|
|
1675
1663
|
const defaultMinWidth = 4;
|
|
1676
1664
|
const vpWidth = this.element.clientWidth;
|
|
1677
1665
|
const isGrid = this.isGrid();
|
|
1666
|
+
// Shorten last column width to avoid h-scrollbar
|
|
1667
|
+
const FIX_ADJUST_LAST_COL = 2;
|
|
1678
1668
|
|
|
1679
1669
|
let totalWidth = 0;
|
|
1680
1670
|
let totalWeight = 0;
|
|
@@ -1686,7 +1676,7 @@ export class Wunderbaum {
|
|
|
1686
1676
|
this.setCellNav(false);
|
|
1687
1677
|
}
|
|
1688
1678
|
|
|
1689
|
-
if (
|
|
1679
|
+
if (options.calculateCols) {
|
|
1690
1680
|
// Gather width definitions
|
|
1691
1681
|
this._columnsById = {};
|
|
1692
1682
|
for (let col of this.columns) {
|
|
@@ -1736,7 +1726,8 @@ export class Wunderbaum {
|
|
|
1736
1726
|
col._ofsPx = ofsPx;
|
|
1737
1727
|
ofsPx += col._widthPx!;
|
|
1738
1728
|
}
|
|
1739
|
-
|
|
1729
|
+
this.columns[this.columns.length - 1]._widthPx! -= FIX_ADJUST_LAST_COL;
|
|
1730
|
+
totalWidth = ofsPx - FIX_ADJUST_LAST_COL;
|
|
1740
1731
|
}
|
|
1741
1732
|
// if (this.options.fixedCol) {
|
|
1742
1733
|
// 'position: fixed' requires that the content has the correct size
|
|
@@ -1751,7 +1742,7 @@ export class Wunderbaum {
|
|
|
1751
1742
|
// util.error("BREAK");
|
|
1752
1743
|
if (modified) {
|
|
1753
1744
|
this._renderHeaderMarkup();
|
|
1754
|
-
if (
|
|
1745
|
+
if (options.updateRows) {
|
|
1755
1746
|
this._updateRows();
|
|
1756
1747
|
}
|
|
1757
1748
|
}
|
|
@@ -1819,6 +1810,9 @@ export class Wunderbaum {
|
|
|
1819
1810
|
* @internal
|
|
1820
1811
|
*/
|
|
1821
1812
|
protected _updateViewportImmediately() {
|
|
1813
|
+
// Shorten container height to avoid v-scrollbar
|
|
1814
|
+
const FIX_ADJUST_HEIGHT = 1;
|
|
1815
|
+
|
|
1822
1816
|
if (this._disableUpdateCount) {
|
|
1823
1817
|
this.log(
|
|
1824
1818
|
`IGNORED _updateViewportImmediately() disable level: ${this._disableUpdateCount}`
|
|
@@ -1835,7 +1829,8 @@ export class Wunderbaum {
|
|
|
1835
1829
|
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
1836
1830
|
// const headerHeight = this.options.headerHeightPx;
|
|
1837
1831
|
const headerHeight = this.headerElement.clientHeight; // May be 0
|
|
1838
|
-
const wantHeight =
|
|
1832
|
+
const wantHeight =
|
|
1833
|
+
this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
|
|
1839
1834
|
|
|
1840
1835
|
if (Math.abs(height - wantHeight) > 1.0) {
|
|
1841
1836
|
// this.log("resize", height, wantHeight);
|
|
@@ -1899,11 +1894,11 @@ export class Wunderbaum {
|
|
|
1899
1894
|
* (including upper and lower prefetch)
|
|
1900
1895
|
* -
|
|
1901
1896
|
*/
|
|
1902
|
-
protected _updateRows(
|
|
1897
|
+
protected _updateRows(options?: any): boolean {
|
|
1903
1898
|
// const label = this.logTime("_updateRows");
|
|
1904
1899
|
// this.log("_updateRows", opts)
|
|
1905
|
-
|
|
1906
|
-
const newNodesOnly = !!
|
|
1900
|
+
options = Object.assign({ newNodesOnly: false }, options);
|
|
1901
|
+
const newNodesOnly = !!options.newNodesOnly;
|
|
1907
1902
|
|
|
1908
1903
|
const row_height = ROW_HEIGHT;
|
|
1909
1904
|
const vp_height = this.element.clientHeight;
|
|
@@ -2013,15 +2008,15 @@ export class Wunderbaum {
|
|
|
2013
2008
|
* {start: First tree node, reverse: false, includeSelf: true, includeHidden: false, wrap: false}
|
|
2014
2009
|
* @returns {boolean} false if iteration was canceled
|
|
2015
2010
|
*/
|
|
2016
|
-
visitRows(callback: (node: WunderbaumNode) => any,
|
|
2011
|
+
visitRows(callback: (node: WunderbaumNode) => any, options?: any): boolean {
|
|
2017
2012
|
if (!this.root.hasChildren()) {
|
|
2018
2013
|
return false;
|
|
2019
2014
|
}
|
|
2020
|
-
if (
|
|
2021
|
-
delete
|
|
2022
|
-
return this._visitRowsUp(callback,
|
|
2015
|
+
if (options && options.reverse) {
|
|
2016
|
+
delete options.reverse;
|
|
2017
|
+
return this._visitRowsUp(callback, options);
|
|
2023
2018
|
}
|
|
2024
|
-
|
|
2019
|
+
options = options || {};
|
|
2025
2020
|
let i,
|
|
2026
2021
|
nextIdx,
|
|
2027
2022
|
parent,
|
|
@@ -2029,10 +2024,10 @@ export class Wunderbaum {
|
|
|
2029
2024
|
siblings,
|
|
2030
2025
|
stopNode: WunderbaumNode,
|
|
2031
2026
|
siblingOfs = 0,
|
|
2032
|
-
skipFirstNode =
|
|
2033
|
-
includeHidden = !!
|
|
2027
|
+
skipFirstNode = options.includeSelf === false,
|
|
2028
|
+
includeHidden = !!options.includeHidden,
|
|
2034
2029
|
checkFilter = !includeHidden && this.filterMode === "hide",
|
|
2035
|
-
node: WunderbaumNode =
|
|
2030
|
+
node: WunderbaumNode = options.start || this.root.children![0];
|
|
2036
2031
|
|
|
2037
2032
|
parent = node.parent;
|
|
2038
2033
|
while (parent) {
|
|
@@ -2091,11 +2086,11 @@ export class Wunderbaum {
|
|
|
2091
2086
|
parent = parent.parent;
|
|
2092
2087
|
siblingOfs = 1; //
|
|
2093
2088
|
|
|
2094
|
-
if (!parent &&
|
|
2089
|
+
if (!parent && options.wrap) {
|
|
2095
2090
|
this.logDebug("visitRows(): wrap around");
|
|
2096
|
-
util.assert(
|
|
2097
|
-
stopNode =
|
|
2098
|
-
|
|
2091
|
+
util.assert(options.start, "`wrap` option requires `start`");
|
|
2092
|
+
stopNode = options.start;
|
|
2093
|
+
options.wrap = false;
|
|
2099
2094
|
parent = this.root;
|
|
2100
2095
|
siblingOfs = 0;
|
|
2101
2096
|
}
|