wunderbaum 0.1.1 → 0.3.0
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/LICENSE +1 -1
- package/README.md +2 -8
- package/dist/wunderbaum.css +3 -3
- package/dist/wunderbaum.d.ts +198 -105
- package/dist/wunderbaum.esm.js +473 -208
- package/dist/wunderbaum.esm.min.js +36 -36
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +473 -208
- package/dist/wunderbaum.umd.min.js +44 -44
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/common.ts +9 -1
- package/src/deferred.ts +1 -1
- package/src/drag_observer.ts +1 -1
- package/src/types.ts +99 -70
- package/src/util.ts +61 -10
- package/src/wb_ext_dnd.ts +27 -7
- package/src/wb_ext_edit.ts +4 -4
- package/src/wb_ext_filter.ts +1 -5
- package/src/wb_ext_grid.ts +1 -1
- package/src/wb_ext_keynav.ts +26 -2
- package/src/wb_ext_logger.ts +1 -1
- package/src/wb_extension_base.ts +1 -1
- package/src/wb_node.ts +130 -30
- package/src/wb_options.ts +9 -3
- package/src/wunderbaum.scss +6 -3
- package/src/wunderbaum.ts +243 -139
package/dist/wunderbaum.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Wunderbaum - util
|
|
3
|
-
* Copyright (c) 2021-
|
|
4
|
-
* v0.
|
|
3
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
4
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
5
5
|
*/
|
|
6
6
|
/** @module util */
|
|
7
7
|
/** Readable names for `MouseEvent.button` */
|
|
@@ -177,17 +177,19 @@ function extractHtmlText(s) {
|
|
|
177
177
|
* the element is checked, unchecked, or indeterminate.
|
|
178
178
|
* For datetime input control a numerical value is assumed, etc.
|
|
179
179
|
*
|
|
180
|
-
* Common use case: store the new user input in
|
|
180
|
+
* Common use case: store the new user input in a `change` event handler:
|
|
181
181
|
*
|
|
182
182
|
* ```ts
|
|
183
183
|
* change: (e) => {
|
|
184
|
+
* const tree = e.tree;
|
|
185
|
+
* const node = e.node;
|
|
184
186
|
* // Read the value from the input control that triggered the change event:
|
|
185
|
-
* let value =
|
|
186
|
-
* //
|
|
187
|
-
*
|
|
187
|
+
* let value = tree.getValueFromElem(e.element);
|
|
188
|
+
* // and store it to the node model (assuming the column id matches the property name)
|
|
189
|
+
* node.data[e.info.colId] = value;
|
|
188
190
|
* },
|
|
189
191
|
* ```
|
|
190
|
-
* @param elem `<input>` or `<select>` element Also a parent `span.wb-col` is accepted.
|
|
192
|
+
* @param elem `<input>` or `<select>` element. Also a parent `span.wb-col` is accepted.
|
|
191
193
|
* @param coerce pass true to convert date/time inputs to `Date`.
|
|
192
194
|
* @returns the value
|
|
193
195
|
*/
|
|
@@ -251,6 +253,23 @@ function getValueFromElem(elem, coerce = false) {
|
|
|
251
253
|
* value is truethy, falsy, or `null`.
|
|
252
254
|
* For datetime input control a numerical value is assumed, etc.
|
|
253
255
|
*
|
|
256
|
+
* Common use case: update embedded input controls in a `render` event handler:
|
|
257
|
+
*
|
|
258
|
+
* ```ts
|
|
259
|
+
* render: (e) => {
|
|
260
|
+
* // e.node.log(e.type, e, e.node.data);
|
|
261
|
+
*
|
|
262
|
+
* for (const col of Object.values(e.renderColInfosById)) {
|
|
263
|
+
* switch (col.id) {
|
|
264
|
+
* default:
|
|
265
|
+
* // Assumption: we named column.id === node.data.NAME
|
|
266
|
+
* util.setValueToElem(col.elem, e.node.data[col.id]);
|
|
267
|
+
* break;
|
|
268
|
+
* }
|
|
269
|
+
* }
|
|
270
|
+
* },
|
|
271
|
+
* ```
|
|
272
|
+
*
|
|
254
273
|
* @param elem `<input>` or `<select>` element Also a parent `span.wb-col` is accepted.
|
|
255
274
|
* @param value a value that matches the target element.
|
|
256
275
|
*/
|
|
@@ -282,7 +301,6 @@ function setValueToElem(elem, value) {
|
|
|
282
301
|
case "datetime":
|
|
283
302
|
case "datetime-local":
|
|
284
303
|
input.valueAsDate = new Date(value);
|
|
285
|
-
// input.valueAsDate = value; // breaks in Edge?
|
|
286
304
|
break;
|
|
287
305
|
case "number":
|
|
288
306
|
case "range":
|
|
@@ -294,7 +312,7 @@ function setValueToElem(elem, value) {
|
|
|
294
312
|
}
|
|
295
313
|
break;
|
|
296
314
|
case "radio":
|
|
297
|
-
error(
|
|
315
|
+
error(`Not yet implemented: ${type}`);
|
|
298
316
|
// const name = input.name;
|
|
299
317
|
// const checked = input.parentElement!.querySelector(
|
|
300
318
|
// `input[name="${name}"]:checked`
|
|
@@ -321,7 +339,7 @@ function setValueToElem(elem, value) {
|
|
|
321
339
|
}
|
|
322
340
|
}
|
|
323
341
|
}
|
|
324
|
-
/** Show/hide element by setting the `display`style to 'none'. */
|
|
342
|
+
/** Show/hide element by setting the `display` style to 'none'. */
|
|
325
343
|
function setElemDisplay(elem, flag) {
|
|
326
344
|
const style = elemFromSelector(elem).style;
|
|
327
345
|
if (flag) {
|
|
@@ -366,7 +384,23 @@ function eventTargetFromSelector(obj) {
|
|
|
366
384
|
* The result also contains a prefix for modifiers if any, for example
|
|
367
385
|
* `"x"`, `"F2"`, `"Control+Home"`, or `"Shift+clickright"`.
|
|
368
386
|
* This is especially useful in `switch` statements, to make sure that modifier
|
|
369
|
-
* keys are considered and handled correctly
|
|
387
|
+
* keys are considered and handled correctly:
|
|
388
|
+
* ```ts
|
|
389
|
+
* const eventName = util.eventToString(e);
|
|
390
|
+
* switch (eventName) {
|
|
391
|
+
* case "+":
|
|
392
|
+
* case "Add":
|
|
393
|
+
* ...
|
|
394
|
+
* break;
|
|
395
|
+
* case "Enter":
|
|
396
|
+
* case "End":
|
|
397
|
+
* case "Control+End":
|
|
398
|
+
* case "Meta+ArrowDown":
|
|
399
|
+
* case "PageDown":
|
|
400
|
+
* ...
|
|
401
|
+
* break;
|
|
402
|
+
* }
|
|
403
|
+
* ```
|
|
370
404
|
*/
|
|
371
405
|
function eventToString(event) {
|
|
372
406
|
let key = event.key, et = event.type, s = [];
|
|
@@ -591,6 +625,21 @@ function toSet(val) {
|
|
|
591
625
|
}
|
|
592
626
|
throw new Error("Cannot convert to Set<string>: " + val);
|
|
593
627
|
}
|
|
628
|
+
// /** Check if a string is contained in an Array or Set. */
|
|
629
|
+
// export function isAnyOf(s: string, items: Array<string>|Set<string>): boolean {
|
|
630
|
+
// return Array.prototype.includes.call(items, s)
|
|
631
|
+
// }
|
|
632
|
+
// /** Check if an Array or Set has at least one matching entry. */
|
|
633
|
+
// export function hasAnyOf(container: Array<string>|Set<string>, items: Array<string>): boolean {
|
|
634
|
+
// if (Array.isArray(container)) {
|
|
635
|
+
// return container.some(v => )
|
|
636
|
+
// }
|
|
637
|
+
// return container.some(v => {})
|
|
638
|
+
// // const container = toSet(items);
|
|
639
|
+
// // const itemSet = toSet(items);
|
|
640
|
+
// // Array.prototype.includes
|
|
641
|
+
// // throw new Error("Cannot convert to Set<string>: " + val);
|
|
642
|
+
// }
|
|
594
643
|
/** Return a canonical string representation for an object's type (e.g. 'array', 'number', ...). */
|
|
595
644
|
function type(obj) {
|
|
596
645
|
return Object.prototype.toString
|
|
@@ -706,28 +755,40 @@ var util = /*#__PURE__*/Object.freeze({
|
|
|
706
755
|
|
|
707
756
|
/*!
|
|
708
757
|
* Wunderbaum - types
|
|
709
|
-
* Copyright (c) 2021-
|
|
710
|
-
* v0.
|
|
758
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
759
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
760
|
+
*/
|
|
761
|
+
/**
|
|
762
|
+
* Possible values for {@link WunderbaumNode.setModified()} and {@link Wunderbaum.setModified()}.
|
|
711
763
|
*/
|
|
712
|
-
/** Possible values for `setModified()`. */
|
|
713
764
|
var ChangeType;
|
|
714
765
|
(function (ChangeType) {
|
|
715
766
|
/** Re-render the whole viewport, headers, and all rows. */
|
|
716
767
|
ChangeType["any"] = "any";
|
|
717
|
-
/**
|
|
768
|
+
/** A node's title, icon, columns, or status have changed. Update the existing row markup. */
|
|
718
769
|
ChangeType["data"] = "data";
|
|
719
|
-
/**
|
|
720
|
-
ChangeType["
|
|
721
|
-
/**
|
|
770
|
+
/** The `tree.columns` definition has changed beyond simple width adjustments. */
|
|
771
|
+
ChangeType["colStructure"] = "colStructure";
|
|
772
|
+
/** The viewport/window was resized. Adjust layout attributes for all elements. */
|
|
773
|
+
ChangeType["resize"] = "resize";
|
|
774
|
+
/** A node's definition has changed beyond status and data. Re-render the whole row's markup. */
|
|
722
775
|
ChangeType["row"] = "row";
|
|
723
|
-
/**
|
|
776
|
+
/** Nodes have been added, removed, etc. Update markup. */
|
|
724
777
|
ChangeType["structure"] = "structure";
|
|
725
|
-
/** Update current row's classes, to reflect active, selected, ... */
|
|
778
|
+
/** A node's status has changed. Update current row's classes, to reflect active, selected, ... */
|
|
726
779
|
ChangeType["status"] = "status";
|
|
727
|
-
/** Update the 'top' property of all rows. */
|
|
728
|
-
ChangeType["
|
|
780
|
+
/** Vertical scroll event. Update the 'top' property of all rows. */
|
|
781
|
+
ChangeType["scroll"] = "scroll";
|
|
729
782
|
})(ChangeType || (ChangeType = {}));
|
|
730
|
-
|
|
783
|
+
/* Internal use. */
|
|
784
|
+
var RenderFlag;
|
|
785
|
+
(function (RenderFlag) {
|
|
786
|
+
RenderFlag["clearMarkup"] = "clearMarkup";
|
|
787
|
+
RenderFlag["header"] = "header";
|
|
788
|
+
RenderFlag["redraw"] = "redraw";
|
|
789
|
+
RenderFlag["scroll"] = "scroll";
|
|
790
|
+
})(RenderFlag || (RenderFlag = {}));
|
|
791
|
+
/** Possible values for {@link WunderbaumNode.setStatus()}. */
|
|
731
792
|
var NodeStatusType;
|
|
732
793
|
(function (NodeStatusType) {
|
|
733
794
|
NodeStatusType["ok"] = "ok";
|
|
@@ -758,8 +819,8 @@ var NavModeEnum;
|
|
|
758
819
|
|
|
759
820
|
/*!
|
|
760
821
|
* Wunderbaum - wb_extension_base
|
|
761
|
-
* Copyright (c) 2021-
|
|
762
|
-
* v0.
|
|
822
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
823
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
763
824
|
*/
|
|
764
825
|
class WunderbaumExtension {
|
|
765
826
|
constructor(tree, id, defaults) {
|
|
@@ -1049,8 +1110,8 @@ function debounce(func, wait = 0, options = {}) {
|
|
|
1049
1110
|
|
|
1050
1111
|
/*!
|
|
1051
1112
|
* Wunderbaum - ext-filter
|
|
1052
|
-
* Copyright (c) 2021-
|
|
1053
|
-
* v0.
|
|
1113
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1114
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
1054
1115
|
*/
|
|
1055
1116
|
const START_MARKER = "\uFFF7";
|
|
1056
1117
|
const END_MARKER = "\uFFF8";
|
|
@@ -1234,16 +1295,12 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1234
1295
|
}
|
|
1235
1296
|
/**
|
|
1236
1297
|
* [ext-filter] Dim or hide nodes.
|
|
1237
|
-
*
|
|
1238
|
-
* @param {boolean} [options={autoExpand: false, leavesOnly: false}]
|
|
1239
1298
|
*/
|
|
1240
1299
|
filterNodes(filter, options) {
|
|
1241
1300
|
return this._applyFilterNoUpdate(filter, false, options);
|
|
1242
1301
|
}
|
|
1243
1302
|
/**
|
|
1244
1303
|
* [ext-filter] Dim or hide whole branches.
|
|
1245
|
-
*
|
|
1246
|
-
* @param {boolean} [options={autoExpand: false}]
|
|
1247
1304
|
*/
|
|
1248
1305
|
filterBranches(filter, options) {
|
|
1249
1306
|
return this._applyFilterNoUpdate(filter, true, options);
|
|
@@ -1354,8 +1411,8 @@ function _markFuzzyMatchedChars(text, matches, escapeTitles = true) {
|
|
|
1354
1411
|
|
|
1355
1412
|
/*!
|
|
1356
1413
|
* Wunderbaum - ext-keynav
|
|
1357
|
-
* Copyright (c) 2021-
|
|
1358
|
-
* v0.
|
|
1414
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1415
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
1359
1416
|
*/
|
|
1360
1417
|
const QUICKSEARCH_DELAY = 500;
|
|
1361
1418
|
class KeynavExtension extends WunderbaumExtension {
|
|
@@ -1382,11 +1439,10 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1382
1439
|
var _a;
|
|
1383
1440
|
const ace = (_a = this.tree
|
|
1384
1441
|
.getActiveColElem()) === null || _a === void 0 ? void 0 : _a.querySelector("input:focus,select:focus");
|
|
1385
|
-
console.log(`_isCurInputFocused`, ace);
|
|
1386
1442
|
return !!ace;
|
|
1387
1443
|
}
|
|
1388
1444
|
onKeyEvent(data) {
|
|
1389
|
-
const event = data.event, tree = this.tree, opts = data.options, activate = !event.ctrlKey || opts.autoActivate, curInput = this._getEmbeddedInputElem(event.target), navModeOption = opts.navigationModeOption;
|
|
1445
|
+
const event = data.event, tree = this.tree, opts = data.options, activate = !event.ctrlKey || opts.autoActivate, curInput = this._getEmbeddedInputElem(event.target), inputHasFocus = curInput && this._isCurInputFocused(), navModeOption = opts.navigationModeOption;
|
|
1390
1446
|
// isCellEditMode = tree.navMode === NavigationMode.cellEdit;
|
|
1391
1447
|
let focusNode, eventName = eventToString(event), node = data.node, handled = true;
|
|
1392
1448
|
// tree.log(`onKeyEvent: ${eventName}, curInput`, curInput);
|
|
@@ -1423,6 +1479,22 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1423
1479
|
// -----------------------------------------------------------------------
|
|
1424
1480
|
// --- Row Mode ---
|
|
1425
1481
|
// -----------------------------------------------------------------------
|
|
1482
|
+
if (inputHasFocus) {
|
|
1483
|
+
// If editing an embedded input control, let the control handle all
|
|
1484
|
+
// keys. Only Enter and Escape should apply / discard, but keep the
|
|
1485
|
+
// keyboard focus.
|
|
1486
|
+
switch (eventName) {
|
|
1487
|
+
case "Enter":
|
|
1488
|
+
curInput.blur();
|
|
1489
|
+
tree.setFocus();
|
|
1490
|
+
break;
|
|
1491
|
+
case "Escape":
|
|
1492
|
+
node.render();
|
|
1493
|
+
tree.setFocus();
|
|
1494
|
+
break;
|
|
1495
|
+
}
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1426
1498
|
// --- Quick-Search
|
|
1427
1499
|
if (opts.quicksearch &&
|
|
1428
1500
|
eventName.length === 1 &&
|
|
@@ -1524,6 +1596,11 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1524
1596
|
if (eventName === "Escape") {
|
|
1525
1597
|
// Discard changes
|
|
1526
1598
|
node.render();
|
|
1599
|
+
// Keep cell-nav mode
|
|
1600
|
+
node.logDebug(`Reset focused input`);
|
|
1601
|
+
tree.setFocus();
|
|
1602
|
+
tree.setColumn(tree.activeColIdx);
|
|
1603
|
+
return;
|
|
1527
1604
|
// } else if (!INPUT_BREAKOUT_KEYS.has(eventName)) {
|
|
1528
1605
|
}
|
|
1529
1606
|
else if (eventName !== "Enter") {
|
|
@@ -1598,8 +1675,11 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1598
1675
|
break;
|
|
1599
1676
|
case "Escape":
|
|
1600
1677
|
tree.setFocus(); // Blur prev. input if any
|
|
1678
|
+
node.log(`keynav: focus tree...`);
|
|
1601
1679
|
if (tree.isCellNav() && navModeOption !== NavModeEnum.cell) {
|
|
1680
|
+
node.log(`keynav: setCellNav(false)`);
|
|
1602
1681
|
tree.setCellNav(false); // row-nav mode
|
|
1682
|
+
tree.setFocus(); //
|
|
1603
1683
|
handled = true;
|
|
1604
1684
|
}
|
|
1605
1685
|
break;
|
|
@@ -1671,8 +1751,8 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1671
1751
|
|
|
1672
1752
|
/*!
|
|
1673
1753
|
* Wunderbaum - ext-logger
|
|
1674
|
-
* Copyright (c) 2021-
|
|
1675
|
-
* v0.
|
|
1754
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1755
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
1676
1756
|
*/
|
|
1677
1757
|
class LoggerExtension extends WunderbaumExtension {
|
|
1678
1758
|
constructor(tree) {
|
|
@@ -1711,8 +1791,8 @@ class LoggerExtension extends WunderbaumExtension {
|
|
|
1711
1791
|
|
|
1712
1792
|
/*!
|
|
1713
1793
|
* Wunderbaum - common
|
|
1714
|
-
* Copyright (c) 2021-
|
|
1715
|
-
* v0.
|
|
1794
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1795
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
1716
1796
|
*/
|
|
1717
1797
|
const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
|
|
1718
1798
|
/**
|
|
@@ -1834,6 +1914,12 @@ function makeNodeTitleStartMatcher(s) {
|
|
|
1834
1914
|
return reMatch.test(node.title);
|
|
1835
1915
|
};
|
|
1836
1916
|
}
|
|
1917
|
+
/** Compare two nodes by title (case-insensitive). */
|
|
1918
|
+
function nodeTitleSorter(a, b) {
|
|
1919
|
+
const x = a.title.toLowerCase();
|
|
1920
|
+
const y = b.title.toLowerCase();
|
|
1921
|
+
return x === y ? 0 : x > y ? 1 : -1;
|
|
1922
|
+
}
|
|
1837
1923
|
function unflattenSource(source) {
|
|
1838
1924
|
var _a, _b, _c;
|
|
1839
1925
|
const { _format, _keyMap, _positional, children } = source;
|
|
@@ -1951,8 +2037,8 @@ function inflateSourceData(source) {
|
|
|
1951
2037
|
|
|
1952
2038
|
/*!
|
|
1953
2039
|
* Wunderbaum - ext-dnd
|
|
1954
|
-
* Copyright (c) 2021-
|
|
1955
|
-
* v0.
|
|
2040
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2041
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
1956
2042
|
*/
|
|
1957
2043
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
1958
2044
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -2063,6 +2149,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2063
2149
|
// Only 'before' and 'after':
|
|
2064
2150
|
return dy > ROW_HEIGHT / 2 ? "after" : "before";
|
|
2065
2151
|
}
|
|
2152
|
+
// return "over";
|
|
2066
2153
|
}
|
|
2067
2154
|
/* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
|
|
2068
2155
|
autoScroll(event) {
|
|
@@ -2137,6 +2224,8 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2137
2224
|
}
|
|
2138
2225
|
onDropEvent(e) {
|
|
2139
2226
|
// const isLink = event.dataTransfer.types.includes("text/uri-list");
|
|
2227
|
+
const srcNode = this.srcNode;
|
|
2228
|
+
const srcTree = srcNode ? srcNode.tree : null;
|
|
2140
2229
|
const targetNode = Wunderbaum.getNode(e);
|
|
2141
2230
|
const dndOpts = this.treeOpts.dnd;
|
|
2142
2231
|
const dt = e.dataTransfer;
|
|
@@ -2144,7 +2233,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2144
2233
|
this._leaveNode();
|
|
2145
2234
|
return;
|
|
2146
2235
|
}
|
|
2147
|
-
if (
|
|
2236
|
+
if (!["dragenter", "dragover", "dragleave"].includes(e.type)) {
|
|
2148
2237
|
this.tree.logDebug("onDropEvent." +
|
|
2149
2238
|
e.type +
|
|
2150
2239
|
" targetNode: " +
|
|
@@ -2165,9 +2254,24 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2165
2254
|
this.lastTargetNode = targetNode;
|
|
2166
2255
|
this.lastEnterStamp = Date.now();
|
|
2167
2256
|
if (
|
|
2168
|
-
// Don't
|
|
2169
|
-
|
|
2170
|
-
|
|
2257
|
+
// Don't drop on status node:
|
|
2258
|
+
targetNode.isStatusNode() ||
|
|
2259
|
+
// Prevent dropping nodes from different Wunderbaum trees:
|
|
2260
|
+
(dndOpts.preventForeignNodes && targetNode.tree !== srcTree) ||
|
|
2261
|
+
// Prevent dropping items on unloaded lazy Wunderbaum tree nodes:
|
|
2262
|
+
(dndOpts.preventLazyParents && !targetNode.isLoaded()) ||
|
|
2263
|
+
// Prevent dropping items other than Wunderbaum tree nodes:
|
|
2264
|
+
(dndOpts.preventNonNodes && !srcNode) ||
|
|
2265
|
+
// Prevent dropping nodes on own descendants:
|
|
2266
|
+
(dndOpts.preventRecursion &&
|
|
2267
|
+
srcNode &&
|
|
2268
|
+
srcNode.isAncestorOf(targetNode)) ||
|
|
2269
|
+
// Prevent dropping nodes under same direct parent:
|
|
2270
|
+
(dndOpts.preventSameParent &&
|
|
2271
|
+
srcNode &&
|
|
2272
|
+
targetNode.parent === srcNode.parent) ||
|
|
2273
|
+
// Don't allow void operation ('drop on self'): TODO: should be checke onn move only
|
|
2274
|
+
(dndOpts.preventVoidMoves && targetNode === srcNode)) {
|
|
2171
2275
|
dt.dropEffect = "none";
|
|
2172
2276
|
return true; // Prevent drop operation
|
|
2173
2277
|
}
|
|
@@ -2213,9 +2317,11 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2213
2317
|
else if (e.type === "drop") {
|
|
2214
2318
|
e.stopPropagation(); // prevent browser from opening links?
|
|
2215
2319
|
this._leaveNode();
|
|
2320
|
+
const region = this.lastDropRegion;
|
|
2216
2321
|
targetNode._callEvent("dnd.drop", {
|
|
2217
2322
|
event: e,
|
|
2218
|
-
region:
|
|
2323
|
+
region: region,
|
|
2324
|
+
defaultDropMode: region === "over" ? "appendChild" : region,
|
|
2219
2325
|
sourceNode: this.srcNode,
|
|
2220
2326
|
});
|
|
2221
2327
|
}
|
|
@@ -2224,8 +2330,8 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2224
2330
|
|
|
2225
2331
|
/*!
|
|
2226
2332
|
* Wunderbaum - drag_observer
|
|
2227
|
-
* Copyright (c) 2021-
|
|
2228
|
-
* v0.
|
|
2333
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2334
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
2229
2335
|
*/
|
|
2230
2336
|
/**
|
|
2231
2337
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2360,8 +2466,8 @@ class DragObserver {
|
|
|
2360
2466
|
|
|
2361
2467
|
/*!
|
|
2362
2468
|
* Wunderbaum - ext-grid
|
|
2363
|
-
* Copyright (c) 2021-
|
|
2364
|
-
* v0.
|
|
2469
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2470
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
2365
2471
|
*/
|
|
2366
2472
|
class GridExtension extends WunderbaumExtension {
|
|
2367
2473
|
constructor(tree) {
|
|
@@ -2397,8 +2503,8 @@ class GridExtension extends WunderbaumExtension {
|
|
|
2397
2503
|
|
|
2398
2504
|
/*!
|
|
2399
2505
|
* Wunderbaum - deferred
|
|
2400
|
-
* Copyright (c) 2021-
|
|
2401
|
-
* v0.
|
|
2506
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2507
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
2402
2508
|
*/
|
|
2403
2509
|
/**
|
|
2404
2510
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -2450,8 +2556,8 @@ class Deferred {
|
|
|
2450
2556
|
|
|
2451
2557
|
/*!
|
|
2452
2558
|
* Wunderbaum - wunderbaum_node
|
|
2453
|
-
* Copyright (c) 2021-
|
|
2454
|
-
* v0.
|
|
2559
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2560
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
2455
2561
|
*/
|
|
2456
2562
|
/** Top-level properties that can be passed with `data`. */
|
|
2457
2563
|
const NODE_PROPS = new Set([
|
|
@@ -2688,9 +2794,9 @@ class WunderbaumNode {
|
|
|
2688
2794
|
* @param [mode=child] 'before', 'after', 'firstChild', or 'child' ('over' is a synonym for 'child')
|
|
2689
2795
|
* @returns new node
|
|
2690
2796
|
*/
|
|
2691
|
-
addNode(nodeData, mode = "
|
|
2797
|
+
addNode(nodeData, mode = "appendChild") {
|
|
2692
2798
|
if (mode === "over") {
|
|
2693
|
-
mode = "
|
|
2799
|
+
mode = "appendChild"; // compatible with drop region
|
|
2694
2800
|
}
|
|
2695
2801
|
switch (mode) {
|
|
2696
2802
|
case "after":
|
|
@@ -2699,11 +2805,11 @@ class WunderbaumNode {
|
|
|
2699
2805
|
});
|
|
2700
2806
|
case "before":
|
|
2701
2807
|
return this.parent.addChildren(nodeData, { before: this });
|
|
2702
|
-
case "
|
|
2808
|
+
case "prependChild":
|
|
2703
2809
|
// Insert before the first child if any
|
|
2704
2810
|
// let insertBefore = this.children ? this.children[0] : undefined;
|
|
2705
2811
|
return this.addChildren(nodeData, { before: 0 });
|
|
2706
|
-
case "
|
|
2812
|
+
case "appendChild":
|
|
2707
2813
|
return this.addChildren(nodeData);
|
|
2708
2814
|
}
|
|
2709
2815
|
assert(false, "Invalid mode: " + mode);
|
|
@@ -3098,8 +3204,17 @@ class WunderbaumNode {
|
|
|
3098
3204
|
* an expand operation is currently possible.
|
|
3099
3205
|
*/
|
|
3100
3206
|
isExpandable(andCollapsed = false) {
|
|
3101
|
-
//
|
|
3102
|
-
|
|
3207
|
+
// `false` is never expandable (unoffical)
|
|
3208
|
+
if ((andCollapsed && this.expanded) || this.children === false) {
|
|
3209
|
+
return false;
|
|
3210
|
+
}
|
|
3211
|
+
if (this.children == null) {
|
|
3212
|
+
return this.lazy; // null or undefined can trigger lazy load
|
|
3213
|
+
}
|
|
3214
|
+
if (this.children.length === 0) {
|
|
3215
|
+
return !!this.tree.options.emptyChildListExpandable;
|
|
3216
|
+
}
|
|
3217
|
+
return true;
|
|
3103
3218
|
}
|
|
3104
3219
|
/** Return true if this node is currently in edit-title mode. */
|
|
3105
3220
|
isEditing() {
|
|
@@ -3233,7 +3348,7 @@ class WunderbaumNode {
|
|
|
3233
3348
|
tree.logInfo("Redefine columns", source.columns);
|
|
3234
3349
|
tree.columns = source.columns;
|
|
3235
3350
|
delete source.columns;
|
|
3236
|
-
tree.
|
|
3351
|
+
tree.setModified(ChangeType.colStructure);
|
|
3237
3352
|
}
|
|
3238
3353
|
this.addChildren(source.children);
|
|
3239
3354
|
// Add extra data to `tree.data`
|
|
@@ -3245,12 +3360,50 @@ class WunderbaumNode {
|
|
|
3245
3360
|
}
|
|
3246
3361
|
this._callEvent("load");
|
|
3247
3362
|
}
|
|
3363
|
+
async _fetchWithOptions(source) {
|
|
3364
|
+
var _a, _b;
|
|
3365
|
+
// Either a URL string or an object with a `.url` property.
|
|
3366
|
+
let url, params, body, options, rest;
|
|
3367
|
+
let fetchOpts = {};
|
|
3368
|
+
if (typeof source === "string") {
|
|
3369
|
+
// source is a plain URL string: assume GET request
|
|
3370
|
+
url = source;
|
|
3371
|
+
fetchOpts.method = "GET";
|
|
3372
|
+
}
|
|
3373
|
+
else if (isPlainObject(source)) {
|
|
3374
|
+
// source is a plain object with `.url` property.
|
|
3375
|
+
({ url, params, body, options, ...rest } = source);
|
|
3376
|
+
assert(typeof url === "string", `expected source.url as string`);
|
|
3377
|
+
if (isPlainObject(options)) {
|
|
3378
|
+
fetchOpts = options;
|
|
3379
|
+
}
|
|
3380
|
+
if (isPlainObject(body)) {
|
|
3381
|
+
// we also accept 'body' as object...
|
|
3382
|
+
assert(!fetchOpts.body, "options.body should be passed as source.body");
|
|
3383
|
+
fetchOpts.body = JSON.stringify(fetchOpts.body);
|
|
3384
|
+
(_a = fetchOpts.method) !== null && _a !== void 0 ? _a : (fetchOpts.method = "POST"); // set default
|
|
3385
|
+
}
|
|
3386
|
+
if (isPlainObject(params)) {
|
|
3387
|
+
url += "?" + new URLSearchParams(params);
|
|
3388
|
+
(_b = fetchOpts.method) !== null && _b !== void 0 ? _b : (fetchOpts.method = "GET"); // set default
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
else {
|
|
3392
|
+
url = ""; // keep linter happy
|
|
3393
|
+
error(`Unsupported source format: ${source}`);
|
|
3394
|
+
}
|
|
3395
|
+
this.setStatus(NodeStatusType.loading);
|
|
3396
|
+
const response = await fetch(url, fetchOpts);
|
|
3397
|
+
if (!response.ok) {
|
|
3398
|
+
error(`GET ${url} returned ${response.status}, ${response}`);
|
|
3399
|
+
}
|
|
3400
|
+
return await response.json();
|
|
3401
|
+
}
|
|
3248
3402
|
/** Download data from the cloud, then call `.update()`. */
|
|
3249
3403
|
async load(source) {
|
|
3250
3404
|
const tree = this.tree;
|
|
3251
3405
|
const requestId = Date.now();
|
|
3252
3406
|
const prevParent = this.parent;
|
|
3253
|
-
const url = typeof source === "string" ? source : source.url;
|
|
3254
3407
|
const start = Date.now();
|
|
3255
3408
|
let elap = 0, elapLoad = 0, elapProcess = 0;
|
|
3256
3409
|
// Check for overlapping requests
|
|
@@ -3261,17 +3414,16 @@ class WunderbaumNode {
|
|
|
3261
3414
|
this._requestId = requestId;
|
|
3262
3415
|
// const timerLabel = tree.logTime(this + ".load()");
|
|
3263
3416
|
try {
|
|
3417
|
+
let url = typeof source === "string" ? source : source.url;
|
|
3264
3418
|
if (!url) {
|
|
3419
|
+
// An array or a plain object (that does NOT contain a `.url` property)
|
|
3420
|
+
// will be treated as native Wunderbaum data
|
|
3265
3421
|
this._loadSourceObject(source);
|
|
3266
3422
|
elapProcess = Date.now() - start;
|
|
3267
3423
|
}
|
|
3268
3424
|
else {
|
|
3269
|
-
|
|
3270
|
-
const
|
|
3271
|
-
if (!response.ok) {
|
|
3272
|
-
error(`GET ${url} returned ${response.status}, ${response}`);
|
|
3273
|
-
}
|
|
3274
|
-
const data = await response.json();
|
|
3425
|
+
// Either a URL string or an object with a `.url` property.
|
|
3426
|
+
const data = await this._fetchWithOptions(source);
|
|
3275
3427
|
elapLoad = Date.now() - start;
|
|
3276
3428
|
if (this._requestId && this._requestId > requestId) {
|
|
3277
3429
|
this.logWarn(`Ignored load response #${requestId} because #${this._requestId} is pending.`);
|
|
@@ -3414,6 +3566,9 @@ class WunderbaumNode {
|
|
|
3414
3566
|
}
|
|
3415
3567
|
/** Move this node to targetNode. */
|
|
3416
3568
|
moveTo(targetNode, mode = "appendChild", map) {
|
|
3569
|
+
if (mode === "over") {
|
|
3570
|
+
mode = "appendChild"; // compatible with drop region
|
|
3571
|
+
}
|
|
3417
3572
|
if (mode === "prependChild") {
|
|
3418
3573
|
if (targetNode.children && targetNode.children.length) {
|
|
3419
3574
|
mode = "before";
|
|
@@ -3470,7 +3625,7 @@ class WunderbaumNode {
|
|
|
3470
3625
|
targetParent.children.splice(pos + 1, 0, this);
|
|
3471
3626
|
break;
|
|
3472
3627
|
default:
|
|
3473
|
-
error(
|
|
3628
|
+
error(`Invalid mode '${mode}'.`);
|
|
3474
3629
|
}
|
|
3475
3630
|
}
|
|
3476
3631
|
else {
|
|
@@ -3497,7 +3652,12 @@ class WunderbaumNode {
|
|
|
3497
3652
|
n.tree = targetNode.tree;
|
|
3498
3653
|
}, true);
|
|
3499
3654
|
}
|
|
3500
|
-
|
|
3655
|
+
// Make sure we update async, because discarding the markup would prevent
|
|
3656
|
+
// DragAndDrop to generate a dragend event on the source node
|
|
3657
|
+
setTimeout(() => {
|
|
3658
|
+
// Even indentation may have changed:
|
|
3659
|
+
tree.setModified(ChangeType.any);
|
|
3660
|
+
}, 0);
|
|
3501
3661
|
// TODO: fix selection state
|
|
3502
3662
|
// TODO: fix active state
|
|
3503
3663
|
}
|
|
@@ -3623,7 +3783,7 @@ class WunderbaumNode {
|
|
|
3623
3783
|
icon = iconMap.loading;
|
|
3624
3784
|
}
|
|
3625
3785
|
if (icon === false) {
|
|
3626
|
-
return null;
|
|
3786
|
+
return null; // explicitly disabled: don't try default icons
|
|
3627
3787
|
}
|
|
3628
3788
|
if (typeof icon === "string") ;
|
|
3629
3789
|
else if (this.statusNodeType) {
|
|
@@ -3642,7 +3802,11 @@ class WunderbaumNode {
|
|
|
3642
3802
|
icon = iconMap.doc;
|
|
3643
3803
|
}
|
|
3644
3804
|
// this.log("_createIcon: " + icon);
|
|
3645
|
-
if (icon
|
|
3805
|
+
if (!icon) {
|
|
3806
|
+
iconSpan = document.createElement("i");
|
|
3807
|
+
iconSpan.className = "wb-icon";
|
|
3808
|
+
}
|
|
3809
|
+
else if (icon.indexOf("<") >= 0) {
|
|
3646
3810
|
// HTML
|
|
3647
3811
|
iconSpan = elemFromHtml(icon);
|
|
3648
3812
|
}
|
|
@@ -3960,9 +4124,12 @@ class WunderbaumNode {
|
|
|
3960
4124
|
case "data":
|
|
3961
4125
|
this._render_data(opts);
|
|
3962
4126
|
break;
|
|
3963
|
-
|
|
4127
|
+
case "row":
|
|
4128
|
+
// _rowElem is not yet created (asserted in _render_markup)
|
|
3964
4129
|
this._render_markup(opts);
|
|
3965
4130
|
break;
|
|
4131
|
+
default:
|
|
4132
|
+
error(`Invalid change type '${opts.change}'.`);
|
|
3966
4133
|
}
|
|
3967
4134
|
}
|
|
3968
4135
|
/**
|
|
@@ -4184,20 +4351,24 @@ class WunderbaumNode {
|
|
|
4184
4351
|
this.setModified();
|
|
4185
4352
|
}
|
|
4186
4353
|
/** Set a new icon path or class. */
|
|
4187
|
-
setIcon() {
|
|
4188
|
-
|
|
4189
|
-
|
|
4354
|
+
setIcon(icon) {
|
|
4355
|
+
this.icon = icon;
|
|
4356
|
+
this.setModified();
|
|
4190
4357
|
}
|
|
4191
4358
|
/** Change node's {@link key} and/or {@link refKey}. */
|
|
4192
4359
|
setKey(key, refKey) {
|
|
4193
4360
|
throw new Error("Not yet implemented");
|
|
4194
4361
|
}
|
|
4195
4362
|
/**
|
|
4196
|
-
*
|
|
4363
|
+
* Trigger a repaint, typically after a status or data change.
|
|
4197
4364
|
*
|
|
4198
4365
|
* `change` defaults to 'data', which handles modifcations of title, icon,
|
|
4199
4366
|
* and column content. It can be reduced to 'ChangeType.status' if only
|
|
4200
4367
|
* active/focus/selected state has changed.
|
|
4368
|
+
*
|
|
4369
|
+
* This method will eventually call {@link WunderbaumNode.render()} with
|
|
4370
|
+
* default options, but may be more consistent with the tree's
|
|
4371
|
+
* {@link Wunderbaum.setModified()} API.
|
|
4201
4372
|
*/
|
|
4202
4373
|
setModified(change = ChangeType.data) {
|
|
4203
4374
|
assert(change === ChangeType.status || change === ChangeType.data);
|
|
@@ -4233,7 +4404,7 @@ class WunderbaumNode {
|
|
|
4233
4404
|
let firstChild = children ? children[0] : null;
|
|
4234
4405
|
assert(data.statusNodeType);
|
|
4235
4406
|
assert(!firstChild || !firstChild.isStatusNode());
|
|
4236
|
-
statusNode = this.addNode(data, "
|
|
4407
|
+
statusNode = this.addNode(data, "prependChild");
|
|
4237
4408
|
statusNode.match = true;
|
|
4238
4409
|
tree.setModified(ChangeType.structure);
|
|
4239
4410
|
return statusNode;
|
|
@@ -4299,11 +4470,37 @@ class WunderbaumNode {
|
|
|
4299
4470
|
this.setModified();
|
|
4300
4471
|
// this.triggerModify("rename"); // TODO
|
|
4301
4472
|
}
|
|
4473
|
+
_sortChildren(cmp, deep) {
|
|
4474
|
+
const cl = this.children;
|
|
4475
|
+
if (!cl) {
|
|
4476
|
+
return;
|
|
4477
|
+
}
|
|
4478
|
+
cl.sort(cmp);
|
|
4479
|
+
if (deep) {
|
|
4480
|
+
for (let i = 0, l = cl.length; i < l; i++) {
|
|
4481
|
+
if (cl[i].children) {
|
|
4482
|
+
cl[i]._sortChildren(cmp, deep);
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
}
|
|
4487
|
+
/**
|
|
4488
|
+
* Sort child list by title or custom criteria.
|
|
4489
|
+
* @param {function} cmp custom compare function(a, b) that returns -1, 0, or 1
|
|
4490
|
+
* (defaults to sorting by title).
|
|
4491
|
+
* @param {boolean} deep pass true to sort all descendant nodes recursively
|
|
4492
|
+
*/
|
|
4493
|
+
sortChildren(cmp = nodeTitleSorter, deep = false) {
|
|
4494
|
+
this._sortChildren(cmp || nodeTitleSorter, deep);
|
|
4495
|
+
this.tree.setModified(ChangeType.structure);
|
|
4496
|
+
// this.triggerModify("sort"); // TODO
|
|
4497
|
+
}
|
|
4302
4498
|
/**
|
|
4303
4499
|
* Trigger `modifyChild` event on a parent to signal that a child was modified.
|
|
4304
4500
|
* @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
|
|
4305
4501
|
*/
|
|
4306
4502
|
triggerModifyChild(operation, child, extra) {
|
|
4503
|
+
this.logDebug(`modifyChild(${operation})`, extra, child);
|
|
4307
4504
|
if (!this.tree.options.modifyChild)
|
|
4308
4505
|
return;
|
|
4309
4506
|
if (child && child.parent !== this) {
|
|
@@ -4402,8 +4599,8 @@ WunderbaumNode.sequence = 0;
|
|
|
4402
4599
|
|
|
4403
4600
|
/*!
|
|
4404
4601
|
* Wunderbaum - ext-edit
|
|
4405
|
-
* Copyright (c) 2021-
|
|
4406
|
-
* v0.
|
|
4602
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
4603
|
+
* v0.3.0, Sat, 27 May 2023 04:56:52 GMT (https://github.com/mar10/wunderbaum)
|
|
4407
4604
|
*/
|
|
4408
4605
|
// const START_MARKER = "\uFFF7";
|
|
4409
4606
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -4494,7 +4691,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
4494
4691
|
const trigger = this.getPluginOption("trigger");
|
|
4495
4692
|
// const inputElem =
|
|
4496
4693
|
// event.target && event.target.closest("input,[contenteditable]");
|
|
4497
|
-
// tree.logDebug(`_preprocessKeyEvent: ${eventName}`);
|
|
4694
|
+
// tree.logDebug(`_preprocessKeyEvent: ${eventName}, editing:${this.isEditingTitle()}`);
|
|
4498
4695
|
// --- Title editing: apply/discard ---
|
|
4499
4696
|
// if (inputElem) {
|
|
4500
4697
|
if (this.isEditingTitle()) {
|
|
@@ -4694,12 +4891,12 @@ class EditExtension extends WunderbaumExtension {
|
|
|
4694
4891
|
*
|
|
4695
4892
|
* A treegrid control.
|
|
4696
4893
|
*
|
|
4697
|
-
* Copyright (c) 2021-
|
|
4894
|
+
* Copyright (c) 2021-2023, Martin Wendt (https://wwWendt.de).
|
|
4698
4895
|
* https://github.com/mar10/wunderbaum
|
|
4699
4896
|
*
|
|
4700
4897
|
* Released under the MIT license.
|
|
4701
|
-
* @version v0.
|
|
4702
|
-
* @date
|
|
4898
|
+
* @version v0.3.0
|
|
4899
|
+
* @date Sat, 27 May 2023 04:56:52 GMT
|
|
4703
4900
|
*/
|
|
4704
4901
|
class WbSystemRoot extends WunderbaumNode {
|
|
4705
4902
|
constructor(tree) {
|
|
@@ -4728,6 +4925,7 @@ class Wunderbaum {
|
|
|
4728
4925
|
this.refKeyMap = new Map();
|
|
4729
4926
|
this.treeRowCount = 0;
|
|
4730
4927
|
this._disableUpdateCount = 0;
|
|
4928
|
+
this._disableUpdateIgnoreCount = 0;
|
|
4731
4929
|
/** Currently active node if any. */
|
|
4732
4930
|
this.activeNode = null;
|
|
4733
4931
|
/** Current node hat has keyboard focus if any. */
|
|
@@ -4738,8 +4936,7 @@ class Wunderbaum {
|
|
|
4738
4936
|
this.columns = []; // any[] = [];
|
|
4739
4937
|
this._columnsById = {};
|
|
4740
4938
|
// Modification Status
|
|
4741
|
-
this.
|
|
4742
|
-
this.changeScrollRequestPending = false;
|
|
4939
|
+
this.pendingChangeTypes = new Set();
|
|
4743
4940
|
/** Expose some useful methods of the util.ts module as `tree._util`. */
|
|
4744
4941
|
this._util = util;
|
|
4745
4942
|
// --- FILTER ---
|
|
@@ -4775,6 +4972,7 @@ class Wunderbaum {
|
|
|
4775
4972
|
showSpinner: false,
|
|
4776
4973
|
checkbox: false,
|
|
4777
4974
|
minExpandLevel: 0,
|
|
4975
|
+
emptyChildListExpandable: false,
|
|
4778
4976
|
updateThrottleWait: 200,
|
|
4779
4977
|
skeleton: false,
|
|
4780
4978
|
connectTopBreadcrumb: null,
|
|
@@ -4937,11 +5135,11 @@ class Wunderbaum {
|
|
|
4937
5135
|
// --- Bind listeners
|
|
4938
5136
|
this.element.addEventListener("scroll", (e) => {
|
|
4939
5137
|
// this.log(`scroll, scrollTop:${e.target.scrollTop}`, e);
|
|
4940
|
-
this.setModified(ChangeType.
|
|
5138
|
+
this.setModified(ChangeType.scroll);
|
|
4941
5139
|
});
|
|
4942
5140
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
4943
|
-
this.setModified(ChangeType.vscroll);
|
|
4944
5141
|
// this.log("ResizeObserver: Size changed", entries);
|
|
5142
|
+
this.setModified(ChangeType.resize);
|
|
4945
5143
|
});
|
|
4946
5144
|
this.resizeObserver.observe(this.element);
|
|
4947
5145
|
onEvent(this.nodeListElement, "click", "div.wb-row", (e) => {
|
|
@@ -4986,6 +5184,7 @@ class Wunderbaum {
|
|
|
4986
5184
|
return false;
|
|
4987
5185
|
}
|
|
4988
5186
|
if (node && info.colIdx === 0 && node.isExpandable()) {
|
|
5187
|
+
this._callMethod("edit._stopEditTitle");
|
|
4989
5188
|
node.setExpanded(!node.isExpanded());
|
|
4990
5189
|
}
|
|
4991
5190
|
});
|
|
@@ -5002,7 +5201,16 @@ class Wunderbaum {
|
|
|
5002
5201
|
});
|
|
5003
5202
|
onEvent(this.element, "focusin focusout", (e) => {
|
|
5004
5203
|
const flag = e.type === "focusin";
|
|
5204
|
+
const targetNode = Wunderbaum.getNode(e);
|
|
5005
5205
|
this._callEvent("focus", { flag: flag, event: e });
|
|
5206
|
+
if (flag && this.isRowNav() && !this.isEditing()) {
|
|
5207
|
+
if (opts.navigationModeOption === NavModeEnum.row) {
|
|
5208
|
+
targetNode === null || targetNode === void 0 ? void 0 : targetNode.setActive();
|
|
5209
|
+
}
|
|
5210
|
+
else {
|
|
5211
|
+
this.setCellNav();
|
|
5212
|
+
}
|
|
5213
|
+
}
|
|
5006
5214
|
if (!flag) {
|
|
5007
5215
|
this._callMethod("edit._stopEditTitle", true, {
|
|
5008
5216
|
event: e,
|
|
@@ -5467,7 +5675,7 @@ class Wunderbaum {
|
|
|
5467
5675
|
this.options[name] = value;
|
|
5468
5676
|
switch (name) {
|
|
5469
5677
|
case "checkbox":
|
|
5470
|
-
this.setModified(ChangeType.any
|
|
5678
|
+
this.setModified(ChangeType.any);
|
|
5471
5679
|
break;
|
|
5472
5680
|
case "enabled":
|
|
5473
5681
|
this.setEnabled(!!value);
|
|
@@ -5767,8 +5975,9 @@ class Wunderbaum {
|
|
|
5767
5975
|
res.region = NodeRegion.title;
|
|
5768
5976
|
}
|
|
5769
5977
|
else if (cl.contains("wb-expander")) {
|
|
5770
|
-
res.region =
|
|
5771
|
-
|
|
5978
|
+
res.region = node.isExpandable()
|
|
5979
|
+
? NodeRegion.expander
|
|
5980
|
+
: NodeRegion.prefix;
|
|
5772
5981
|
}
|
|
5773
5982
|
else if (cl.contains("wb-checkbox")) {
|
|
5774
5983
|
res.region = NodeRegion.checkbox;
|
|
@@ -5919,7 +6128,7 @@ class Wunderbaum {
|
|
|
5919
6128
|
// Make sure the topNode is always visible
|
|
5920
6129
|
this.scrollTo(topNode);
|
|
5921
6130
|
}
|
|
5922
|
-
// this.setModified(ChangeType.
|
|
6131
|
+
// this.setModified(ChangeType.scroll);
|
|
5923
6132
|
}
|
|
5924
6133
|
}
|
|
5925
6134
|
/**
|
|
@@ -5947,7 +6156,7 @@ class Wunderbaum {
|
|
|
5947
6156
|
// util.assert(node._rowIdx != null);
|
|
5948
6157
|
this.log(`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`);
|
|
5949
6158
|
this.element.scrollLeft = newLeft;
|
|
5950
|
-
// this.setModified(ChangeType.
|
|
6159
|
+
// this.setModified(ChangeType.scroll);
|
|
5951
6160
|
}
|
|
5952
6161
|
/**
|
|
5953
6162
|
* Set column #colIdx to 'active'.
|
|
@@ -6002,34 +6211,40 @@ class Wunderbaum {
|
|
|
6002
6211
|
// this.log(
|
|
6003
6212
|
// `IGNORED setModified(${change}) node=${node} (disable level ${this._disableUpdateCount})`
|
|
6004
6213
|
// );
|
|
6214
|
+
this._disableUpdateIgnoreCount++;
|
|
6005
6215
|
return;
|
|
6006
6216
|
}
|
|
6007
6217
|
// this.log(`setModified(${change}) node=${node}`);
|
|
6008
6218
|
if (!(node instanceof WunderbaumNode)) {
|
|
6009
6219
|
options = node;
|
|
6220
|
+
node = null;
|
|
6010
6221
|
}
|
|
6011
6222
|
const immediate = !!getOption(options, "immediate");
|
|
6012
|
-
const
|
|
6013
|
-
|
|
6014
|
-
this.visit((n) => {
|
|
6015
|
-
n.removeMarkup();
|
|
6016
|
-
});
|
|
6017
|
-
}
|
|
6018
|
-
let callUpdate = false;
|
|
6223
|
+
const RF = RenderFlag;
|
|
6224
|
+
const pending = this.pendingChangeTypes;
|
|
6019
6225
|
switch (change) {
|
|
6020
6226
|
case ChangeType.any:
|
|
6227
|
+
case ChangeType.colStructure:
|
|
6228
|
+
pending.add(RF.header);
|
|
6229
|
+
pending.add(RF.clearMarkup);
|
|
6230
|
+
pending.add(RF.redraw);
|
|
6231
|
+
pending.add(RF.scroll);
|
|
6232
|
+
break;
|
|
6233
|
+
case ChangeType.resize:
|
|
6234
|
+
// case ChangeType.colWidth:
|
|
6235
|
+
pending.add(RF.header);
|
|
6236
|
+
pending.add(RF.redraw);
|
|
6237
|
+
break;
|
|
6021
6238
|
case ChangeType.structure:
|
|
6022
|
-
|
|
6023
|
-
this.changeRedrawRequestPending = true;
|
|
6024
|
-
callUpdate = true;
|
|
6239
|
+
pending.add(RF.redraw);
|
|
6025
6240
|
break;
|
|
6026
|
-
case ChangeType.
|
|
6027
|
-
|
|
6028
|
-
callUpdate = true;
|
|
6241
|
+
case ChangeType.scroll:
|
|
6242
|
+
pending.add(RF.scroll);
|
|
6029
6243
|
break;
|
|
6030
6244
|
case ChangeType.row:
|
|
6031
6245
|
case ChangeType.data:
|
|
6032
6246
|
case ChangeType.status:
|
|
6247
|
+
assert(node, `Option '${change}' requires a node.`);
|
|
6033
6248
|
// Single nodes are immediately updated if already inside the viewport
|
|
6034
6249
|
// (otherwise we can ignore)
|
|
6035
6250
|
if (node._rowElem) {
|
|
@@ -6037,9 +6252,16 @@ class Wunderbaum {
|
|
|
6037
6252
|
}
|
|
6038
6253
|
break;
|
|
6039
6254
|
default:
|
|
6040
|
-
error(`Invalid change type ${change}
|
|
6255
|
+
error(`Invalid change type '${change}'.`);
|
|
6256
|
+
}
|
|
6257
|
+
if (change === ChangeType.colStructure) {
|
|
6258
|
+
const isGrid = this.isGrid();
|
|
6259
|
+
this.element.classList.toggle("wb-grid", isGrid);
|
|
6260
|
+
if (!isGrid && this.isCellNav()) {
|
|
6261
|
+
this.setCellNav(false);
|
|
6262
|
+
}
|
|
6041
6263
|
}
|
|
6042
|
-
if (
|
|
6264
|
+
if (pending.size > 0) {
|
|
6043
6265
|
if (immediate) {
|
|
6044
6266
|
this._updateViewportImmediately();
|
|
6045
6267
|
}
|
|
@@ -6111,7 +6333,7 @@ class Wunderbaum {
|
|
|
6111
6333
|
}
|
|
6112
6334
|
break;
|
|
6113
6335
|
default:
|
|
6114
|
-
error(`Invalid mode '${mode}'
|
|
6336
|
+
error(`Invalid mode '${mode}'.`);
|
|
6115
6337
|
}
|
|
6116
6338
|
}
|
|
6117
6339
|
/** Display tree status (ok, loading, error, noData) using styles and a dummy root node. */
|
|
@@ -6134,81 +6356,96 @@ class Wunderbaum {
|
|
|
6134
6356
|
}
|
|
6135
6357
|
}
|
|
6136
6358
|
}
|
|
6137
|
-
/**
|
|
6359
|
+
/**
|
|
6360
|
+
* Sort nodes list by title or custom criteria.
|
|
6361
|
+
* @param {function} cmp custom compare function(a, b) that returns -1, 0, or 1
|
|
6362
|
+
* (defaults to sorting by title).
|
|
6363
|
+
* @param {boolean} deep pass true to sort all descendant nodes recursively
|
|
6364
|
+
*/
|
|
6365
|
+
sortChildren(cmp = nodeTitleSorter, deep = false) {
|
|
6366
|
+
this.root.sortChildren(cmp, deep);
|
|
6367
|
+
}
|
|
6368
|
+
/**
|
|
6369
|
+
* Update column headers and column width.
|
|
6138
6370
|
* Return true if at least one column width changed.
|
|
6139
6371
|
*/
|
|
6140
|
-
|
|
6141
|
-
|
|
6372
|
+
// _updateColumnWidths(options?: UpdateColumnsOptions): boolean {
|
|
6373
|
+
_updateColumnWidths() {
|
|
6374
|
+
// options = Object.assign({ updateRows: true, renderMarkup: false }, options);
|
|
6142
6375
|
const defaultMinWidth = 4;
|
|
6143
6376
|
const vpWidth = this.element.clientWidth;
|
|
6144
|
-
const isGrid = this.isGrid();
|
|
6145
6377
|
// Shorten last column width to avoid h-scrollbar
|
|
6146
6378
|
const FIX_ADJUST_LAST_COL = 2;
|
|
6379
|
+
const columns = this.columns;
|
|
6380
|
+
const col0 = columns[0];
|
|
6147
6381
|
let totalWidth = 0;
|
|
6148
6382
|
let totalWeight = 0;
|
|
6149
6383
|
let fixedWidth = 0;
|
|
6150
6384
|
let modified = false;
|
|
6151
|
-
this.element.classList.toggle("wb-grid", isGrid);
|
|
6152
|
-
if (!isGrid && this.isCellNav()) {
|
|
6153
|
-
|
|
6154
|
-
}
|
|
6155
|
-
if (options.calculateCols) {
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6385
|
+
// this.element.classList.toggle("wb-grid", isGrid);
|
|
6386
|
+
// if (!isGrid && this.isCellNav()) {
|
|
6387
|
+
// this.setCellNav(false);
|
|
6388
|
+
// }
|
|
6389
|
+
// if (options.calculateCols) {
|
|
6390
|
+
if (col0.id !== "*") {
|
|
6391
|
+
throw new Error(`First column must have id '*': got '${col0.id}'.`);
|
|
6392
|
+
}
|
|
6393
|
+
// Gather width definitions
|
|
6394
|
+
this._columnsById = {};
|
|
6395
|
+
for (let col of columns) {
|
|
6396
|
+
this._columnsById[col.id] = col;
|
|
6397
|
+
let cw = col.width;
|
|
6398
|
+
if (col.id === "*" && col !== col0) {
|
|
6399
|
+
throw new Error(`Column id '*' must be defined only once: '${col.title}'.`);
|
|
6400
|
+
}
|
|
6401
|
+
if (!cw || cw === "*") {
|
|
6402
|
+
col._weight = 1.0;
|
|
6403
|
+
totalWeight += 1.0;
|
|
6404
|
+
}
|
|
6405
|
+
else if (typeof cw === "number") {
|
|
6406
|
+
col._weight = cw;
|
|
6407
|
+
totalWeight += cw;
|
|
6408
|
+
}
|
|
6409
|
+
else if (typeof cw === "string" && cw.endsWith("px")) {
|
|
6410
|
+
col._weight = 0;
|
|
6411
|
+
let px = parseFloat(cw.slice(0, -2));
|
|
6412
|
+
if (col._widthPx != px) {
|
|
6413
|
+
modified = true;
|
|
6414
|
+
col._widthPx = px;
|
|
6164
6415
|
}
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6416
|
+
fixedWidth += px;
|
|
6417
|
+
}
|
|
6418
|
+
else {
|
|
6419
|
+
error(`Invalid column width: ${cw} (expected string ending with 'px' or number, e.g. "<num>px" or <int>).`);
|
|
6420
|
+
}
|
|
6421
|
+
}
|
|
6422
|
+
// Share remaining space between non-fixed columns
|
|
6423
|
+
const restPx = Math.max(0, vpWidth - fixedWidth);
|
|
6424
|
+
let ofsPx = 0;
|
|
6425
|
+
for (let col of columns) {
|
|
6426
|
+
let minWidth;
|
|
6427
|
+
if (col._weight) {
|
|
6428
|
+
const cmw = col.minWidth;
|
|
6429
|
+
if (typeof cmw === "number") {
|
|
6430
|
+
minWidth = cmw;
|
|
6168
6431
|
}
|
|
6169
|
-
else if (typeof
|
|
6170
|
-
|
|
6171
|
-
let px = parseFloat(cw.slice(0, -2));
|
|
6172
|
-
if (col._widthPx != px) {
|
|
6173
|
-
modified = true;
|
|
6174
|
-
col._widthPx = px;
|
|
6175
|
-
}
|
|
6176
|
-
fixedWidth += px;
|
|
6432
|
+
else if (typeof cmw === "string" && cmw.endsWith("px")) {
|
|
6433
|
+
minWidth = parseFloat(cmw.slice(0, -2));
|
|
6177
6434
|
}
|
|
6178
6435
|
else {
|
|
6179
|
-
|
|
6436
|
+
minWidth = defaultMinWidth;
|
|
6180
6437
|
}
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
for (let col of this.columns) {
|
|
6186
|
-
let minWidth;
|
|
6187
|
-
if (col._weight) {
|
|
6188
|
-
const cmw = col.minWidth;
|
|
6189
|
-
if (typeof cmw === "number") {
|
|
6190
|
-
minWidth = cmw;
|
|
6191
|
-
}
|
|
6192
|
-
else if (typeof cmw === "string" && cmw.endsWith("px")) {
|
|
6193
|
-
minWidth = parseFloat(cmw.slice(0, -2));
|
|
6194
|
-
}
|
|
6195
|
-
else {
|
|
6196
|
-
minWidth = defaultMinWidth;
|
|
6197
|
-
}
|
|
6198
|
-
const px = Math.max(minWidth, (restPx * col._weight) / totalWeight);
|
|
6199
|
-
if (col._widthPx != px) {
|
|
6200
|
-
modified = true;
|
|
6201
|
-
col._widthPx = px;
|
|
6202
|
-
}
|
|
6438
|
+
const px = Math.max(minWidth, (restPx * col._weight) / totalWeight);
|
|
6439
|
+
if (col._widthPx != px) {
|
|
6440
|
+
modified = true;
|
|
6441
|
+
col._widthPx = px;
|
|
6203
6442
|
}
|
|
6204
|
-
col._ofsPx = ofsPx;
|
|
6205
|
-
ofsPx += col._widthPx;
|
|
6206
6443
|
}
|
|
6207
|
-
|
|
6208
|
-
|
|
6444
|
+
col._ofsPx = ofsPx;
|
|
6445
|
+
ofsPx += col._widthPx;
|
|
6209
6446
|
}
|
|
6210
|
-
|
|
6211
|
-
|
|
6447
|
+
columns[columns.length - 1]._widthPx -= FIX_ADJUST_LAST_COL;
|
|
6448
|
+
totalWidth = ofsPx - FIX_ADJUST_LAST_COL;
|
|
6212
6449
|
const tw = `${totalWidth}px`;
|
|
6213
6450
|
this.headerElement.style.width = tw;
|
|
6214
6451
|
this.listContainerElement.style.width = tw;
|
|
@@ -6217,12 +6454,14 @@ class Wunderbaum {
|
|
|
6217
6454
|
// this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element);
|
|
6218
6455
|
// console.trace();
|
|
6219
6456
|
// util.error("BREAK");
|
|
6220
|
-
if (modified) {
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6457
|
+
// if (modified) {
|
|
6458
|
+
// this._renderHeaderMarkup();
|
|
6459
|
+
// if (options.renderMarkup) {
|
|
6460
|
+
// this.setModified(ChangeType.header, { removeMarkup: true });
|
|
6461
|
+
// } else if (options.updateRows) {
|
|
6462
|
+
// this._updateRows();
|
|
6463
|
+
// }
|
|
6464
|
+
// }
|
|
6226
6465
|
return modified;
|
|
6227
6466
|
}
|
|
6228
6467
|
/** Create/update header markup from `this.columns` definition.
|
|
@@ -6271,7 +6510,7 @@ class Wunderbaum {
|
|
|
6271
6510
|
* pending async changes if any.
|
|
6272
6511
|
*/
|
|
6273
6512
|
updatePendingModifications() {
|
|
6274
|
-
if (this.
|
|
6513
|
+
if (this.pendingChangeTypes.size > 0) {
|
|
6275
6514
|
this._updateViewportImmediately();
|
|
6276
6515
|
}
|
|
6277
6516
|
}
|
|
@@ -6286,31 +6525,50 @@ class Wunderbaum {
|
|
|
6286
6525
|
*/
|
|
6287
6526
|
_updateViewportImmediately() {
|
|
6288
6527
|
var _a;
|
|
6289
|
-
// Shorten container height to avoid v-scrollbar
|
|
6290
|
-
const FIX_ADJUST_HEIGHT = 1;
|
|
6291
6528
|
if (this._disableUpdateCount) {
|
|
6292
|
-
this.log(`
|
|
6529
|
+
this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount})`);
|
|
6530
|
+
this._disableUpdateIgnoreCount++;
|
|
6293
6531
|
return;
|
|
6294
6532
|
}
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
this.listContainerElement.
|
|
6308
|
-
height
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6533
|
+
// Shorten container height to avoid v-scrollbar
|
|
6534
|
+
const FIX_ADJUST_HEIGHT = 1;
|
|
6535
|
+
const RF = RenderFlag;
|
|
6536
|
+
const pending = new Set(this.pendingChangeTypes);
|
|
6537
|
+
this.pendingChangeTypes.clear();
|
|
6538
|
+
const scrollOnly = pending.has(RF.scroll) && pending.size === 1;
|
|
6539
|
+
if (scrollOnly) {
|
|
6540
|
+
this._updateRows({ newNodesOnly: true });
|
|
6541
|
+
// this.log("_updateViewportImmediately(): scroll only.");
|
|
6542
|
+
}
|
|
6543
|
+
else {
|
|
6544
|
+
this.log("_updateViewportImmediately():", pending);
|
|
6545
|
+
let height = this.listContainerElement.clientHeight;
|
|
6546
|
+
// We cannot get the height for absolute positioned parent, so look at first col
|
|
6547
|
+
// let headerHeight = this.headerElement.clientHeight
|
|
6548
|
+
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
6549
|
+
// const headerHeight = this.options.headerHeightPx;
|
|
6550
|
+
const headerHeight = this.headerElement.clientHeight; // May be 0
|
|
6551
|
+
const wantHeight = this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
|
|
6552
|
+
if (Math.abs(height - wantHeight) > 1.0) {
|
|
6553
|
+
// this.log("resize", height, wantHeight);
|
|
6554
|
+
this.listContainerElement.style.height = wantHeight + "px";
|
|
6555
|
+
height = wantHeight;
|
|
6556
|
+
}
|
|
6557
|
+
// console.profile(`_updateViewportImmediately()`)
|
|
6558
|
+
if (pending.has(RF.clearMarkup)) {
|
|
6559
|
+
this.visit((n) => {
|
|
6560
|
+
n.removeMarkup();
|
|
6561
|
+
});
|
|
6562
|
+
}
|
|
6563
|
+
// let widthModified = false;
|
|
6564
|
+
if (pending.has(RF.header)) {
|
|
6565
|
+
// widthModified = this._updateColumnWidths();
|
|
6566
|
+
this._updateColumnWidths();
|
|
6567
|
+
this._renderHeaderMarkup();
|
|
6568
|
+
}
|
|
6569
|
+
this._updateRows();
|
|
6570
|
+
// console.profileEnd(`_updateViewportImmediately()`)
|
|
6571
|
+
}
|
|
6314
6572
|
if (this.options.connectTopBreadcrumb) {
|
|
6315
6573
|
let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > ");
|
|
6316
6574
|
path = path ? path + " >" : "";
|
|
@@ -6451,19 +6709,14 @@ class Wunderbaum {
|
|
|
6451
6709
|
return this.root.visit(callback, false);
|
|
6452
6710
|
}
|
|
6453
6711
|
/**
|
|
6454
|
-
* Call
|
|
6712
|
+
* Call callback(node) for all nodes in vertical order, top down (or bottom up).
|
|
6455
6713
|
*
|
|
6456
|
-
* Note that this considers expansion state, i.e.
|
|
6457
|
-
* are skipped.
|
|
6714
|
+
* Note that this considers expansion state, i.e. filtered nodes and children
|
|
6715
|
+
* of collapsed nodes are skipped, unless `includeHidden` is set.
|
|
6458
6716
|
*
|
|
6459
|
-
* Stop iteration
|
|
6717
|
+
* Stop iteration if callback() returns false.<br>
|
|
6460
6718
|
* Return false if iteration was stopped.
|
|
6461
6719
|
*
|
|
6462
|
-
* @param callback the callback function.
|
|
6463
|
-
* Return false to stop iteration, return "skip" to skip this node and children only.
|
|
6464
|
-
* @param [options]
|
|
6465
|
-
* Defaults:
|
|
6466
|
-
* {start: First tree node, reverse: false, includeSelf: true, includeHidden: false, wrap: false}
|
|
6467
6720
|
* @returns {boolean} false if iteration was canceled
|
|
6468
6721
|
*/
|
|
6469
6722
|
visitRows(callback, options) {
|
|
@@ -6481,7 +6734,7 @@ class Wunderbaum {
|
|
|
6481
6734
|
// visit siblings
|
|
6482
6735
|
siblings = parent.children;
|
|
6483
6736
|
nextIdx = siblings.indexOf(node) + siblingOfs;
|
|
6484
|
-
assert(nextIdx >= 0,
|
|
6737
|
+
assert(nextIdx >= 0, `Could not find ${node} in parent's children: ${parent}`);
|
|
6485
6738
|
for (i = nextIdx; i < siblings.length; i++) {
|
|
6486
6739
|
node = siblings[i];
|
|
6487
6740
|
if (node === stopNode) {
|
|
@@ -6619,8 +6872,8 @@ class Wunderbaum {
|
|
|
6619
6872
|
// `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...`
|
|
6620
6873
|
// );
|
|
6621
6874
|
if (this._disableUpdateCount === 0) {
|
|
6622
|
-
|
|
6623
|
-
|
|
6875
|
+
this.logDebug(`enableUpdate(): active again. Re-painting to catch up with ${this._disableUpdateIgnoreCount} ignored update requests...`);
|
|
6876
|
+
this._disableUpdateIgnoreCount = 0;
|
|
6624
6877
|
this.setModified(ChangeType.any, { immediate: true });
|
|
6625
6878
|
}
|
|
6626
6879
|
}
|
|
@@ -6636,6 +6889,18 @@ class Wunderbaum {
|
|
|
6636
6889
|
/* ---------------------------------------------------------------------------
|
|
6637
6890
|
* FILTER
|
|
6638
6891
|
* -------------------------------------------------------------------------*/
|
|
6892
|
+
/**
|
|
6893
|
+
* [ext-filter] Dim or hide nodes.
|
|
6894
|
+
*/
|
|
6895
|
+
filterNodes(filter, options) {
|
|
6896
|
+
return this.extensions.filter.filterNodes(filter, options);
|
|
6897
|
+
}
|
|
6898
|
+
/**
|
|
6899
|
+
* [ext-filter] Dim or hide whole branches.
|
|
6900
|
+
*/
|
|
6901
|
+
filterBranches(filter, options) {
|
|
6902
|
+
return this.extensions.filter.filterBranches(filter, options);
|
|
6903
|
+
}
|
|
6639
6904
|
/**
|
|
6640
6905
|
* [ext-filter] Reset the filter.
|
|
6641
6906
|
*
|
|
@@ -6663,7 +6928,7 @@ class Wunderbaum {
|
|
|
6663
6928
|
}
|
|
6664
6929
|
Wunderbaum.sequence = 0;
|
|
6665
6930
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
6666
|
-
Wunderbaum.version = "v0.
|
|
6931
|
+
Wunderbaum.version = "v0.3.0"; // Set to semver by 'grunt release'
|
|
6667
6932
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
6668
6933
|
Wunderbaum.util = util;
|
|
6669
6934
|
|