wunderbaum 0.12.0 → 0.13.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/dist/wunderbaum.css +10 -1
- package/dist/wunderbaum.css.map +1 -1
- package/dist/wunderbaum.d.ts +214 -59
- package/dist/wunderbaum.esm.js +417 -222
- package/dist/wunderbaum.esm.min.js +42 -42
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +417 -222
- package/dist/wunderbaum.umd.min.js +45 -45
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +30 -28
- package/src/common.ts +58 -16
- package/src/debounce.ts +5 -0
- package/src/deferred.ts +1 -1
- package/src/drag_observer.ts +1 -1
- package/src/types.ts +163 -21
- package/src/util.ts +1 -14
- package/src/wb_ext_dnd.ts +3 -3
- package/src/wb_ext_edit.ts +2 -2
- package/src/wb_ext_filter.ts +119 -44
- package/src/wb_ext_grid.ts +1 -1
- package/src/wb_ext_keynav.ts +1 -1
- package/src/wb_ext_logger.ts +1 -1
- package/src/wb_extension_base.ts +4 -3
- package/src/wb_node.ts +27 -98
- package/src/wb_options.ts +7 -5
- package/src/wunderbaum.scss +12 -4
- package/src/wunderbaum.ts +272 -48
package/dist/wunderbaum.esm.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
+
* Wunderbaum - debounce.ts
|
|
3
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
4
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
5
|
+
*/
|
|
6
|
+
/*
|
|
2
7
|
* debounce & throttle, taken from https://github.com/lodash/lodash v4.17.21
|
|
3
8
|
* MIT License: https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/LICENSE
|
|
4
9
|
* Modified for TypeScript type annotations.
|
|
@@ -287,8 +292,8 @@ function throttle(func, wait = 0, options = {}) {
|
|
|
287
292
|
|
|
288
293
|
/*!
|
|
289
294
|
* Wunderbaum - util
|
|
290
|
-
* Copyright (c) 2021-
|
|
291
|
-
* v0.
|
|
295
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
296
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
292
297
|
*/
|
|
293
298
|
/** @module util */
|
|
294
299
|
/** Readable names for `MouseEvent.button` */
|
|
@@ -671,18 +676,6 @@ function elemFromSelector(obj) {
|
|
|
671
676
|
}
|
|
672
677
|
return obj;
|
|
673
678
|
}
|
|
674
|
-
// /** Return a EventTarget from selector or cast an existing element. */
|
|
675
|
-
// export function eventTargetFromSelector(
|
|
676
|
-
// obj: string | EventTarget
|
|
677
|
-
// ): EventTarget | null {
|
|
678
|
-
// if (!obj) {
|
|
679
|
-
// return null;
|
|
680
|
-
// }
|
|
681
|
-
// if (typeof obj === "string") {
|
|
682
|
-
// return document.querySelector(obj) as EventTarget;
|
|
683
|
-
// }
|
|
684
|
-
// return obj as EventTarget;
|
|
685
|
-
// }
|
|
686
679
|
/**
|
|
687
680
|
* Return a canonical descriptive string for a keyboard or mouse event.
|
|
688
681
|
*
|
|
@@ -1141,8 +1134,8 @@ var util = /*#__PURE__*/Object.freeze({
|
|
|
1141
1134
|
|
|
1142
1135
|
/*!
|
|
1143
1136
|
* Wunderbaum - types
|
|
1144
|
-
* Copyright (c) 2021-
|
|
1145
|
-
* v0.
|
|
1137
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
1138
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1146
1139
|
*/
|
|
1147
1140
|
/**
|
|
1148
1141
|
* Possible values for {@link WunderbaumNode.update} and {@link Wunderbaum.update}.
|
|
@@ -1166,7 +1159,7 @@ var ChangeType;
|
|
|
1166
1159
|
/** Vertical scroll event. Update the 'top' property of all rows. */
|
|
1167
1160
|
ChangeType["scroll"] = "scroll";
|
|
1168
1161
|
})(ChangeType || (ChangeType = {}));
|
|
1169
|
-
|
|
1162
|
+
/** @internal */
|
|
1170
1163
|
var RenderFlag;
|
|
1171
1164
|
(function (RenderFlag) {
|
|
1172
1165
|
RenderFlag["clearMarkup"] = "clearMarkup";
|
|
@@ -1197,16 +1190,20 @@ var NodeRegion;
|
|
|
1197
1190
|
/** Initial navigation mode and possible transition. */
|
|
1198
1191
|
var NavModeEnum;
|
|
1199
1192
|
(function (NavModeEnum) {
|
|
1193
|
+
/** Start with row mode, but allow cell-nav mode */
|
|
1200
1194
|
NavModeEnum["startRow"] = "startRow";
|
|
1195
|
+
/** Cell-nav mode only */
|
|
1201
1196
|
NavModeEnum["cell"] = "cell";
|
|
1197
|
+
/** Start in cell-nav mode, but allow row mode */
|
|
1202
1198
|
NavModeEnum["startCell"] = "startCell";
|
|
1199
|
+
/** Row mode only */
|
|
1203
1200
|
NavModeEnum["row"] = "row";
|
|
1204
1201
|
})(NavModeEnum || (NavModeEnum = {}));
|
|
1205
1202
|
|
|
1206
1203
|
/*!
|
|
1207
1204
|
* Wunderbaum - wb_extension_base
|
|
1208
|
-
* Copyright (c) 2021-
|
|
1209
|
-
* v0.
|
|
1205
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
1206
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1210
1207
|
*/
|
|
1211
1208
|
class WunderbaumExtension {
|
|
1212
1209
|
constructor(tree, id, defaults) {
|
|
@@ -1264,8 +1261,8 @@ class WunderbaumExtension {
|
|
|
1264
1261
|
|
|
1265
1262
|
/*!
|
|
1266
1263
|
* Wunderbaum - ext-filter
|
|
1267
|
-
* Copyright (c) 2021-
|
|
1268
|
-
* v0.
|
|
1264
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
1265
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1269
1266
|
*/
|
|
1270
1267
|
const START_MARKER = "\uFFF7";
|
|
1271
1268
|
const END_MARKER = "\uFFF8";
|
|
@@ -1277,7 +1274,7 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1277
1274
|
autoApply: true, // Re-apply last filter if lazy data is loaded
|
|
1278
1275
|
autoExpand: false, // Expand all branches that contain matches while filtered
|
|
1279
1276
|
matchBranch: false, // Whether to implicitly match all children of matched nodes
|
|
1280
|
-
|
|
1277
|
+
connect: null, // Element or selector of an input control for filter query strings
|
|
1281
1278
|
fuzzy: false, // Match single characters in order, e.g. 'fb' will match 'FooBar'
|
|
1282
1279
|
hideExpanders: false, // Hide expanders if all child nodes are hidden by filter
|
|
1283
1280
|
highlight: true, // Highlight matches by wrapping inside <mark> tags
|
|
@@ -1285,36 +1282,117 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1285
1282
|
mode: "dim", // Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
|
|
1286
1283
|
noData: true, // Display a 'no data' status node if result is empty
|
|
1287
1284
|
});
|
|
1285
|
+
this.queryInput = null;
|
|
1286
|
+
this.prevButton = null;
|
|
1287
|
+
this.nextButton = null;
|
|
1288
|
+
this.modeButton = null;
|
|
1289
|
+
this.matchInfoElem = null;
|
|
1288
1290
|
this.lastFilterArgs = null;
|
|
1289
1291
|
}
|
|
1290
1292
|
init() {
|
|
1291
1293
|
super.init();
|
|
1292
|
-
const
|
|
1293
|
-
if (
|
|
1294
|
-
this.
|
|
1295
|
-
assert(this.queryInput, `Invalid 'filter.connectInput' option: ${connectInput}.`);
|
|
1296
|
-
onEvent(this.queryInput, "input", debounce((e) => {
|
|
1297
|
-
// this.tree.log("query", e);
|
|
1298
|
-
this.filterNodes(this.queryInput.value.trim(), {});
|
|
1299
|
-
}, 700));
|
|
1294
|
+
const connect = this.getPluginOption("connect");
|
|
1295
|
+
if (connect) {
|
|
1296
|
+
this._connectControls();
|
|
1300
1297
|
}
|
|
1301
1298
|
}
|
|
1302
1299
|
setPluginOption(name, value) {
|
|
1303
|
-
// alert("filter opt=" + name + ", " + value)
|
|
1304
1300
|
super.setPluginOption(name, value);
|
|
1305
1301
|
switch (name) {
|
|
1306
1302
|
case "mode":
|
|
1307
|
-
this.tree.filterMode =
|
|
1303
|
+
this.tree.filterMode =
|
|
1304
|
+
value === "hide" ? "hide" : value === "mark" ? "mark" : "dim";
|
|
1308
1305
|
this.tree.updateFilter();
|
|
1309
1306
|
break;
|
|
1310
1307
|
}
|
|
1311
1308
|
}
|
|
1309
|
+
_updatedConnectedControls() {
|
|
1310
|
+
var _a;
|
|
1311
|
+
const filterActive = this.tree.filterMode !== null;
|
|
1312
|
+
const activeNode = this.tree.getActiveNode();
|
|
1313
|
+
const matchCount = filterActive ? this.countMatches() : 0;
|
|
1314
|
+
const strings = this.treeOpts.strings;
|
|
1315
|
+
let matchIdx = "?";
|
|
1316
|
+
if (this.matchInfoElem) {
|
|
1317
|
+
if (filterActive) {
|
|
1318
|
+
let info;
|
|
1319
|
+
if (matchCount === 0) {
|
|
1320
|
+
info = strings.noMatch;
|
|
1321
|
+
}
|
|
1322
|
+
else if (activeNode && activeNode.match >= 1) {
|
|
1323
|
+
matchIdx = (_a = activeNode.match) !== null && _a !== void 0 ? _a : "?";
|
|
1324
|
+
info = strings.matchIndex;
|
|
1325
|
+
}
|
|
1326
|
+
else {
|
|
1327
|
+
info = strings.queryResult;
|
|
1328
|
+
}
|
|
1329
|
+
info = info
|
|
1330
|
+
.replace("${count}", this.tree.count().toLocaleString())
|
|
1331
|
+
.replace("${match}", "" + matchIdx)
|
|
1332
|
+
.replace("${matches}", matchCount.toLocaleString());
|
|
1333
|
+
this.matchInfoElem.textContent = info;
|
|
1334
|
+
}
|
|
1335
|
+
else {
|
|
1336
|
+
this.matchInfoElem.textContent = "";
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (this.nextButton instanceof HTMLButtonElement) {
|
|
1340
|
+
this.nextButton.disabled = !matchCount;
|
|
1341
|
+
}
|
|
1342
|
+
if (this.prevButton instanceof HTMLButtonElement) {
|
|
1343
|
+
this.prevButton.disabled = !matchCount;
|
|
1344
|
+
}
|
|
1345
|
+
if (this.modeButton) {
|
|
1346
|
+
this.modeButton.disabled = !filterActive;
|
|
1347
|
+
this.modeButton.classList.toggle("wb-filter-hide", this.tree.filterMode === "hide");
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
_connectControls() {
|
|
1351
|
+
const tree = this.tree;
|
|
1352
|
+
const connect = this.getPluginOption("connect");
|
|
1353
|
+
if (!connect) {
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
this.queryInput = elemFromSelector(connect.inputElem);
|
|
1357
|
+
if (!this.queryInput) {
|
|
1358
|
+
throw new Error(`Invalid 'filter.connect' option: ${connect.inputElem}.`);
|
|
1359
|
+
}
|
|
1360
|
+
this.prevButton = elemFromSelector(connect.prevButton);
|
|
1361
|
+
this.nextButton = elemFromSelector(connect.nextButton);
|
|
1362
|
+
this.modeButton = elemFromSelector(connect.modeButton);
|
|
1363
|
+
this.matchInfoElem = elemFromSelector(connect.matchInfoElem);
|
|
1364
|
+
if (this.prevButton) {
|
|
1365
|
+
onEvent(this.prevButton, "click", () => {
|
|
1366
|
+
tree.findRelatedNode(tree.getActiveNode() || tree.getFirstChild(), "prevMatch");
|
|
1367
|
+
this._updatedConnectedControls();
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
if (this.nextButton) {
|
|
1371
|
+
onEvent(this.nextButton, "click", () => {
|
|
1372
|
+
tree.findRelatedNode(tree.getActiveNode() || tree.getFirstChild(), "nextMatch");
|
|
1373
|
+
this._updatedConnectedControls();
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
if (this.modeButton) {
|
|
1377
|
+
onEvent(this.modeButton, "click", (e) => {
|
|
1378
|
+
if (!this.tree.filterMode) {
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
this.setPluginOption("mode", tree.filterMode === "dim" ? "hide" : "dim");
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
onEvent(this.queryInput, "input", debounce((e) => {
|
|
1385
|
+
this.filterNodes(this.queryInput.value.trim(), {});
|
|
1386
|
+
}, 700));
|
|
1387
|
+
this._updatedConnectedControls();
|
|
1388
|
+
}
|
|
1312
1389
|
_applyFilterNoUpdate(filter, _opts) {
|
|
1313
1390
|
return this.tree.runWithDeferredUpdate(() => {
|
|
1314
1391
|
return this._applyFilterImpl(filter, _opts);
|
|
1315
1392
|
});
|
|
1316
1393
|
}
|
|
1317
1394
|
_applyFilterImpl(filter, _opts) {
|
|
1395
|
+
var _a;
|
|
1318
1396
|
let //temp,
|
|
1319
1397
|
count = 0;
|
|
1320
1398
|
const start = Date.now();
|
|
@@ -1396,11 +1474,11 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1396
1474
|
return !!res;
|
|
1397
1475
|
};
|
|
1398
1476
|
}
|
|
1399
|
-
tree.filterMode = opts.mode;
|
|
1400
|
-
// eslint-disable-next-line prefer-rest-params
|
|
1477
|
+
tree.filterMode = (_a = opts.mode) !== null && _a !== void 0 ? _a : "dim";
|
|
1478
|
+
// eslint-disable-next-line prefer-rest-params
|
|
1401
1479
|
this.lastFilterArgs = arguments;
|
|
1402
1480
|
tree.element.classList.toggle("wb-ext-filter-hide", !!hideMode);
|
|
1403
|
-
tree.element.classList.toggle("wb-ext-filter-dim",
|
|
1481
|
+
tree.element.classList.toggle("wb-ext-filter-dim", opts.mode === "dim");
|
|
1404
1482
|
tree.element.classList.toggle("wb-ext-filter-hide-expanders", !!opts.hideExpanders);
|
|
1405
1483
|
// Reset current filter
|
|
1406
1484
|
tree.root.subMatchCount = 0;
|
|
@@ -1409,10 +1487,6 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1409
1487
|
delete node.titleWithHighlight;
|
|
1410
1488
|
node.subMatchCount = 0;
|
|
1411
1489
|
});
|
|
1412
|
-
// statusNode = tree.root.findDirectChild(KEY_NODATA);
|
|
1413
|
-
// if (statusNode) {
|
|
1414
|
-
// statusNode.remove();
|
|
1415
|
-
// }
|
|
1416
1490
|
tree.setStatus(NodeStatusType.ok);
|
|
1417
1491
|
// Adjust node.hide, .match, and .subMatchCount properties
|
|
1418
1492
|
treeOpts.autoCollapse = false; // #528
|
|
@@ -1423,7 +1497,7 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1423
1497
|
let res = filter(node);
|
|
1424
1498
|
if (res === "skip") {
|
|
1425
1499
|
node.visit(function (c) {
|
|
1426
|
-
c.match =
|
|
1500
|
+
c.match = undefined;
|
|
1427
1501
|
}, true);
|
|
1428
1502
|
return "skip";
|
|
1429
1503
|
}
|
|
@@ -1434,7 +1508,7 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1434
1508
|
}
|
|
1435
1509
|
if (res) {
|
|
1436
1510
|
count++;
|
|
1437
|
-
node.match =
|
|
1511
|
+
node.match = count;
|
|
1438
1512
|
node.visitParents((p) => {
|
|
1439
1513
|
if (p !== node) {
|
|
1440
1514
|
p.subMatchCount += 1;
|
|
@@ -1461,6 +1535,7 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1461
1535
|
}
|
|
1462
1536
|
// Redraw whole tree
|
|
1463
1537
|
tree.logDebug(`Filter '${filter}' found ${count} nodes in ${Date.now() - start} ms.`);
|
|
1538
|
+
this._updatedConnectedControls();
|
|
1464
1539
|
return count;
|
|
1465
1540
|
}
|
|
1466
1541
|
/**
|
|
@@ -1505,34 +1580,22 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1505
1580
|
else {
|
|
1506
1581
|
tree.logWarn("updateFilter(): no filter active.");
|
|
1507
1582
|
}
|
|
1583
|
+
this._updatedConnectedControls();
|
|
1508
1584
|
}
|
|
1509
1585
|
/**
|
|
1510
1586
|
* [ext-filter] Reset the filter.
|
|
1511
1587
|
*/
|
|
1512
1588
|
clearFilter() {
|
|
1513
1589
|
const tree = this.tree;
|
|
1514
|
-
// statusNode = tree.root.findDirectChild(KEY_NODATA),
|
|
1515
|
-
// escapeTitles = tree.options.escapeTitles;
|
|
1516
1590
|
tree.enableUpdate(false);
|
|
1517
|
-
// if (statusNode) {
|
|
1518
|
-
// statusNode.remove();
|
|
1519
|
-
// }
|
|
1520
1591
|
tree.setStatus(NodeStatusType.ok);
|
|
1521
1592
|
// we also counted root node's subMatchCount
|
|
1522
1593
|
delete tree.root.match;
|
|
1523
1594
|
delete tree.root.subMatchCount;
|
|
1524
1595
|
tree.visit((node) => {
|
|
1525
|
-
// if (node.match && node._rowElem) {
|
|
1526
|
-
// let titleElem = node._rowElem.querySelector("span.wb-title")!;
|
|
1527
|
-
// node._callEvent("enhanceTitle", { titleElem: titleElem });
|
|
1528
|
-
// }
|
|
1529
1596
|
delete node.match;
|
|
1530
1597
|
delete node.subMatchCount;
|
|
1531
1598
|
delete node.titleWithHighlight;
|
|
1532
|
-
// if (node.subMatchBadge) {
|
|
1533
|
-
// node.subMatchBadge.remove();
|
|
1534
|
-
// delete node.subMatchBadge;
|
|
1535
|
-
// }
|
|
1536
1599
|
if (node._filterAutoExpanded && node.expanded) {
|
|
1537
1600
|
node.setExpanded(false, {
|
|
1538
1601
|
noAnimation: true,
|
|
@@ -1546,7 +1609,7 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1546
1609
|
tree.element.classList.remove(
|
|
1547
1610
|
// "wb-ext-filter",
|
|
1548
1611
|
"wb-ext-filter-dim", "wb-ext-filter-hide");
|
|
1549
|
-
|
|
1612
|
+
this._updatedConnectedControls();
|
|
1550
1613
|
tree.enableUpdate(true);
|
|
1551
1614
|
}
|
|
1552
1615
|
}
|
|
@@ -1589,8 +1652,8 @@ function _markFuzzyMatchedChars(text, matches, escapeTitles = true) {
|
|
|
1589
1652
|
|
|
1590
1653
|
/*!
|
|
1591
1654
|
* Wunderbaum - ext-keynav
|
|
1592
|
-
* Copyright (c) 2021-
|
|
1593
|
-
* v0.
|
|
1655
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
1656
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1594
1657
|
*/
|
|
1595
1658
|
const QUICKSEARCH_DELAY = 500;
|
|
1596
1659
|
class KeynavExtension extends WunderbaumExtension {
|
|
@@ -1953,8 +2016,8 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1953
2016
|
|
|
1954
2017
|
/*!
|
|
1955
2018
|
* Wunderbaum - ext-logger
|
|
1956
|
-
* Copyright (c) 2021-
|
|
1957
|
-
* v0.
|
|
2019
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
2020
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1958
2021
|
*/
|
|
1959
2022
|
class LoggerExtension extends WunderbaumExtension {
|
|
1960
2023
|
constructor(tree) {
|
|
@@ -1995,8 +2058,8 @@ class LoggerExtension extends WunderbaumExtension {
|
|
|
1995
2058
|
|
|
1996
2059
|
/*!
|
|
1997
2060
|
* Wunderbaum - ext-dnd
|
|
1998
|
-
* Copyright (c) 2021-
|
|
1999
|
-
* v0.
|
|
2061
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
2062
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2000
2063
|
*/
|
|
2001
2064
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
2002
2065
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -2216,7 +2279,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2216
2279
|
viewportY >= height - sensitivity) {
|
|
2217
2280
|
// Mouse in bottom 20px area: scroll down
|
|
2218
2281
|
// sp.scrollTop = scrollTop + dndOpts.scrollSpeed;
|
|
2219
|
-
this.currentScrollDir =
|
|
2282
|
+
this.currentScrollDir = 1;
|
|
2220
2283
|
}
|
|
2221
2284
|
if (this.currentScrollDir) {
|
|
2222
2285
|
this.applyScrollDirThrottled();
|
|
@@ -2445,8 +2508,8 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2445
2508
|
|
|
2446
2509
|
/*!
|
|
2447
2510
|
* Wunderbaum - drag_observer
|
|
2448
|
-
* Copyright (c) 2021-
|
|
2449
|
-
* v0.
|
|
2511
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
2512
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2450
2513
|
*/
|
|
2451
2514
|
/**
|
|
2452
2515
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2594,8 +2657,8 @@ class DragObserver {
|
|
|
2594
2657
|
|
|
2595
2658
|
/*!
|
|
2596
2659
|
* Wunderbaum - common
|
|
2597
|
-
* Copyright (c) 2021-
|
|
2598
|
-
* v0.
|
|
2660
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
2661
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2599
2662
|
*/
|
|
2600
2663
|
const DEFAULT_DEBUGLEVEL = 3; // Replaced by rollup script
|
|
2601
2664
|
/**
|
|
@@ -2622,8 +2685,11 @@ const TEST_IMG = new RegExp(/\.|\//);
|
|
|
2622
2685
|
// export const RECURSIVE_REQUEST_ERROR = "$recursive_request";
|
|
2623
2686
|
// export const INVALID_REQUEST_TARGET_ERROR = "$request_target_invalid";
|
|
2624
2687
|
/**
|
|
2625
|
-
* Default node icons
|
|
2626
|
-
*
|
|
2688
|
+
* Default node icons for icon libraries
|
|
2689
|
+
*
|
|
2690
|
+
* - 'bootstrap': {@link https://icons.getbootstrap.com}
|
|
2691
|
+
* - 'fontawesome6' {@link https://fontawesome.com/icons}
|
|
2692
|
+
*
|
|
2627
2693
|
*/
|
|
2628
2694
|
const iconMaps = {
|
|
2629
2695
|
bootstrap: {
|
|
@@ -2705,29 +2771,20 @@ const RESERVED_TREE_SOURCE_KEYS = new Set([
|
|
|
2705
2771
|
// "Escape",
|
|
2706
2772
|
// ]);
|
|
2707
2773
|
/** Map `KeyEvent.key` to navigation action. */
|
|
2708
|
-
const
|
|
2709
|
-
" ": "toggleSelect",
|
|
2710
|
-
"+": "expand",
|
|
2711
|
-
Add: "expand",
|
|
2774
|
+
const KEY_TO_NAVIGATION_MAP = {
|
|
2712
2775
|
ArrowDown: "down",
|
|
2713
2776
|
ArrowLeft: "left",
|
|
2714
2777
|
ArrowRight: "right",
|
|
2715
2778
|
ArrowUp: "up",
|
|
2716
2779
|
Backspace: "parent",
|
|
2717
|
-
"/": "collapseAll",
|
|
2718
|
-
Divide: "collapseAll",
|
|
2719
2780
|
End: "lastCol",
|
|
2720
2781
|
Home: "firstCol",
|
|
2721
2782
|
"Control+End": "last",
|
|
2722
2783
|
"Control+Home": "first",
|
|
2723
2784
|
"Meta+ArrowDown": "last", // macOs
|
|
2724
2785
|
"Meta+ArrowUp": "first", // macOs
|
|
2725
|
-
"*": "expandAll",
|
|
2726
|
-
Multiply: "expandAll",
|
|
2727
2786
|
PageDown: "pageDown",
|
|
2728
2787
|
PageUp: "pageUp",
|
|
2729
|
-
"-": "collapse",
|
|
2730
|
-
Subtract: "collapse",
|
|
2731
2788
|
};
|
|
2732
2789
|
/** Return a callback that returns true if the node title matches the string
|
|
2733
2790
|
* or regular expression.
|
|
@@ -2764,10 +2821,12 @@ function nodeTitleSorter(a, b) {
|
|
|
2764
2821
|
/**
|
|
2765
2822
|
* Convert 'flat' to 'nested' format.
|
|
2766
2823
|
*
|
|
2767
|
-
*
|
|
2768
|
-
* [
|
|
2769
|
-
*
|
|
2770
|
-
* [
|
|
2824
|
+
* Flat node entry format:
|
|
2825
|
+
* [PARENT_IDX, {KEY_VALUE_ARGS}]
|
|
2826
|
+
* or, if N _positional re defined:
|
|
2827
|
+
* [PARENT_IDX, POSITIONAL_ARG_1, POSITIONAL_ARG_2, ..., POSITIONAL_ARG_N]
|
|
2828
|
+
* Even if _positional additional are defined, KEY_VALUE_ARGS can be appended:
|
|
2829
|
+
* [PARENT_IDX, POSITIONAL_ARG_1, ..., {KEY_VALUE_ARGS}]
|
|
2771
2830
|
*
|
|
2772
2831
|
* 1. Parent-referencing list is converted to a list of nested dicts with
|
|
2773
2832
|
* optional `children` properties.
|
|
@@ -2776,10 +2835,11 @@ function nodeTitleSorter(a, b) {
|
|
|
2776
2835
|
function unflattenSource(source) {
|
|
2777
2836
|
var _a, _b, _c;
|
|
2778
2837
|
const { _format, _keyMap = {}, _positional = [], children } = source;
|
|
2838
|
+
const _positionalCount = _positional.length;
|
|
2779
2839
|
if (_format !== "flat") {
|
|
2780
2840
|
throw new Error(`Expected source._format: "flat", but got ${_format}`);
|
|
2781
2841
|
}
|
|
2782
|
-
if (
|
|
2842
|
+
if (_positionalCount && _positional.includes("children")) {
|
|
2783
2843
|
throw new Error(`source._positional must not include "children": ${_positional}`);
|
|
2784
2844
|
}
|
|
2785
2845
|
let longToShort = _keyMap;
|
|
@@ -2793,7 +2853,7 @@ function unflattenSource(source) {
|
|
|
2793
2853
|
longToShort[value] = key;
|
|
2794
2854
|
}
|
|
2795
2855
|
}
|
|
2796
|
-
const positionalShort = _positional.map((e) => longToShort[e]);
|
|
2856
|
+
const positionalShort = _positional.map((e) => { var _a; return (_a = longToShort[e]) !== null && _a !== void 0 ? _a : e; });
|
|
2797
2857
|
const newChildren = [];
|
|
2798
2858
|
const keyToNodeMap = {};
|
|
2799
2859
|
const indexToNodeMap = {};
|
|
@@ -2803,19 +2863,32 @@ function unflattenSource(source) {
|
|
|
2803
2863
|
// Node entry format:
|
|
2804
2864
|
// [PARENT_ID, [POSITIONAL_ARGS]]
|
|
2805
2865
|
// or
|
|
2806
|
-
// [PARENT_ID,
|
|
2807
|
-
|
|
2866
|
+
// [PARENT_ID, POSITIONAL_ARG_1, POSITIONAL_ARG_2, ..., {KEY_VALUE_ARGS}]
|
|
2867
|
+
let kwargs;
|
|
2868
|
+
const [parentId, ...args] = nodeTuple;
|
|
2869
|
+
if (args.length === _positionalCount) {
|
|
2870
|
+
kwargs = {};
|
|
2871
|
+
}
|
|
2872
|
+
else if (args.length === _positionalCount + 1) {
|
|
2873
|
+
kwargs = args.pop();
|
|
2874
|
+
if (typeof kwargs !== "object") {
|
|
2875
|
+
throw new Error(`unflattenSource: Expected dict as last tuple element: ${nodeTuple}`);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
else {
|
|
2879
|
+
throw new Error(`unflattenSource: unexpected tuple length: ${nodeTuple}`);
|
|
2880
|
+
}
|
|
2808
2881
|
// Free up some memory as we go
|
|
2809
2882
|
nodeTuple[1] = null;
|
|
2810
2883
|
if (nodeTuple[2] != null) {
|
|
2811
2884
|
nodeTuple[2] = null;
|
|
2812
2885
|
}
|
|
2813
|
-
// console.log("flatten", parentId, args, kwargs)
|
|
2814
2886
|
// We keep `kwargs` as our new node definition. Then we add all positional
|
|
2815
2887
|
// values to this object:
|
|
2816
2888
|
args.forEach((val, positionalIdx) => {
|
|
2817
2889
|
kwargs[positionalShort[positionalIdx]] = val;
|
|
2818
2890
|
});
|
|
2891
|
+
args.length = 0;
|
|
2819
2892
|
// Find the parent node. `null` means 'toplevel'. PARENT_ID may be the numeric
|
|
2820
2893
|
// index of the source.children list. If PARENT_ID is a string, we search
|
|
2821
2894
|
// a parent with node.key of this value.
|
|
@@ -2934,8 +3007,8 @@ function decompressSourceData(source) {
|
|
|
2934
3007
|
|
|
2935
3008
|
/*!
|
|
2936
3009
|
* Wunderbaum - ext-grid
|
|
2937
|
-
* Copyright (c) 2021-
|
|
2938
|
-
* v0.
|
|
3010
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
3011
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2939
3012
|
*/
|
|
2940
3013
|
class GridExtension extends WunderbaumExtension {
|
|
2941
3014
|
constructor(tree) {
|
|
@@ -3025,8 +3098,8 @@ class GridExtension extends WunderbaumExtension {
|
|
|
3025
3098
|
|
|
3026
3099
|
/*!
|
|
3027
3100
|
* Wunderbaum - deferred
|
|
3028
|
-
* Copyright (c) 2021-
|
|
3029
|
-
* v0.
|
|
3101
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
3102
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
3030
3103
|
*/
|
|
3031
3104
|
/**
|
|
3032
3105
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -3078,8 +3151,8 @@ class Deferred {
|
|
|
3078
3151
|
|
|
3079
3152
|
/*!
|
|
3080
3153
|
* Wunderbaum - wunderbaum_node
|
|
3081
|
-
* Copyright (c) 2021-
|
|
3082
|
-
* v0.
|
|
3154
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
3155
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
3083
3156
|
*/
|
|
3084
3157
|
/** WunderbaumNode properties that can be passed with source data.
|
|
3085
3158
|
* (Any other source properties will be stored as `node.data.PROP`.)
|
|
@@ -3861,7 +3934,7 @@ class WunderbaumNode {
|
|
|
3861
3934
|
isParentOf(other) {
|
|
3862
3935
|
return other && other.parent === this;
|
|
3863
3936
|
}
|
|
3864
|
-
/**
|
|
3937
|
+
/** Return true if this node is partially loaded. @experimental */
|
|
3865
3938
|
isPartload() {
|
|
3866
3939
|
return !!this._partload;
|
|
3867
3940
|
}
|
|
@@ -4319,10 +4392,11 @@ class WunderbaumNode {
|
|
|
4319
4392
|
* @param options
|
|
4320
4393
|
*/
|
|
4321
4394
|
async navigate(where, options) {
|
|
4395
|
+
var _a;
|
|
4322
4396
|
// Allow to pass 'ArrowLeft' instead of 'left'
|
|
4323
|
-
|
|
4397
|
+
const navType = ((_a = KEY_TO_NAVIGATION_MAP[where]) !== null && _a !== void 0 ? _a : where);
|
|
4324
4398
|
// Otherwise activate or focus the related node
|
|
4325
|
-
const node = this.findRelatedNode(
|
|
4399
|
+
const node = this.findRelatedNode(navType);
|
|
4326
4400
|
if (!node) {
|
|
4327
4401
|
this.logWarn(`Could not find related node '${where}'.`);
|
|
4328
4402
|
return Promise.resolve(this);
|
|
@@ -4419,86 +4493,17 @@ class WunderbaumNode {
|
|
|
4419
4493
|
renderColInfosById: renderColInfosById,
|
|
4420
4494
|
};
|
|
4421
4495
|
}
|
|
4422
|
-
_createIcon(
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
}
|
|
4428
|
-
else if (this._isLoading && showLoading) {
|
|
4429
|
-
// Status nodes, or nodes without expander (< minExpandLevel) should
|
|
4430
|
-
// display the 'loading' status with the i.wb-icon span
|
|
4431
|
-
icon = iconMap.loading;
|
|
4432
|
-
}
|
|
4433
|
-
if (icon === false) {
|
|
4434
|
-
return null; // explicitly disabled: don't try default icons
|
|
4435
|
-
}
|
|
4436
|
-
if (typeof icon === "string") ;
|
|
4437
|
-
else if (this.statusNodeType) {
|
|
4438
|
-
icon = iconMap[this.statusNodeType];
|
|
4439
|
-
}
|
|
4440
|
-
else if (this.expanded) {
|
|
4441
|
-
icon = iconMap.folderOpen;
|
|
4442
|
-
}
|
|
4443
|
-
else if (this.children) {
|
|
4444
|
-
icon = iconMap.folder;
|
|
4445
|
-
}
|
|
4446
|
-
else if (this.lazy) {
|
|
4447
|
-
icon = iconMap.folderLazy;
|
|
4448
|
-
}
|
|
4449
|
-
else {
|
|
4450
|
-
icon = iconMap.doc;
|
|
4451
|
-
}
|
|
4452
|
-
// this.log("_createIcon: " + icon);
|
|
4453
|
-
if (!icon) {
|
|
4454
|
-
iconSpan = document.createElement("i");
|
|
4455
|
-
iconSpan.className = "wb-icon";
|
|
4456
|
-
}
|
|
4457
|
-
else if (icon.indexOf("<") >= 0) {
|
|
4458
|
-
// HTML
|
|
4459
|
-
iconSpan = elemFromHtml(icon);
|
|
4460
|
-
}
|
|
4461
|
-
else if (TEST_IMG.test(icon)) {
|
|
4462
|
-
// Image URL
|
|
4463
|
-
iconSpan = elemFromHtml(`<i class="wb-icon" style="background-image: url('${icon}');">`);
|
|
4464
|
-
}
|
|
4465
|
-
else {
|
|
4466
|
-
// Class name
|
|
4467
|
-
iconSpan = document.createElement("i");
|
|
4468
|
-
iconSpan.className = "wb-icon " + icon;
|
|
4469
|
-
}
|
|
4470
|
-
if (replaceChild) {
|
|
4471
|
-
parentElem.replaceChild(iconSpan, replaceChild);
|
|
4472
|
-
}
|
|
4473
|
-
else {
|
|
4474
|
-
parentElem.appendChild(iconSpan);
|
|
4475
|
-
}
|
|
4476
|
-
// Event handler `tree.iconBadge` can return a badge text or HTMLSpanElement
|
|
4477
|
-
const cbRes = this._callEvent("iconBadge", { iconSpan: iconSpan });
|
|
4478
|
-
let badge = null;
|
|
4479
|
-
if (cbRes != null && cbRes !== false) {
|
|
4480
|
-
let classes = "";
|
|
4481
|
-
let tooltip = "";
|
|
4482
|
-
if (isPlainObject(cbRes)) {
|
|
4483
|
-
badge = "" + cbRes.badge;
|
|
4484
|
-
classes = cbRes.badgeClass ? " " + cbRes.badgeClass : "";
|
|
4485
|
-
tooltip = cbRes.badgeTooltip ? ` title="${cbRes.badgeTooltip}"` : "";
|
|
4486
|
-
}
|
|
4487
|
-
else if (typeof cbRes === "number") {
|
|
4488
|
-
badge = "" + cbRes;
|
|
4496
|
+
_createIcon(parentElem, replaceChild, showLoading) {
|
|
4497
|
+
const iconElem = this.tree._createNodeIcon(this, showLoading, true);
|
|
4498
|
+
if (iconElem) {
|
|
4499
|
+
if (replaceChild) {
|
|
4500
|
+
parentElem.replaceChild(iconElem, replaceChild);
|
|
4489
4501
|
}
|
|
4490
4502
|
else {
|
|
4491
|
-
|
|
4492
|
-
}
|
|
4493
|
-
if (typeof badge === "string") {
|
|
4494
|
-
badge = elemFromHtml(`<span class="wb-badge${classes}"${tooltip}>${escapeHtml(badge)}</span>`);
|
|
4495
|
-
}
|
|
4496
|
-
if (badge) {
|
|
4497
|
-
iconSpan.append(badge);
|
|
4503
|
+
parentElem.appendChild(iconElem);
|
|
4498
4504
|
}
|
|
4499
4505
|
}
|
|
4500
|
-
|
|
4501
|
-
return iconSpan;
|
|
4506
|
+
return iconElem;
|
|
4502
4507
|
}
|
|
4503
4508
|
/**
|
|
4504
4509
|
* Create a whole new `<div class="wb-row">` element.
|
|
@@ -4553,7 +4558,7 @@ class WunderbaumNode {
|
|
|
4553
4558
|
}
|
|
4554
4559
|
// Render the icon (show a 'loading' icon if we do not have an expander that
|
|
4555
4560
|
// we would prefer).
|
|
4556
|
-
const iconSpan = this._createIcon(
|
|
4561
|
+
const iconSpan = this._createIcon(nodeElem, null, !expanderSpan);
|
|
4557
4562
|
if (iconSpan) {
|
|
4558
4563
|
ofsTitlePx += ICON_WIDTH;
|
|
4559
4564
|
}
|
|
@@ -4785,7 +4790,7 @@ class WunderbaumNode {
|
|
|
4785
4790
|
// Update icon (if not opts.isNew, which would rebuild markup anyway)
|
|
4786
4791
|
const iconSpan = nodeElem.querySelector("i.wb-icon");
|
|
4787
4792
|
if (iconSpan) {
|
|
4788
|
-
this._createIcon(
|
|
4793
|
+
this._createIcon(nodeElem, iconSpan, !expanderSpan);
|
|
4789
4794
|
}
|
|
4790
4795
|
}
|
|
4791
4796
|
// Adjust column width
|
|
@@ -5163,7 +5168,8 @@ class WunderbaumNode {
|
|
|
5163
5168
|
case undefined:
|
|
5164
5169
|
changed = this.selected || !this._partsel;
|
|
5165
5170
|
this.selected = false;
|
|
5166
|
-
|
|
5171
|
+
// #110: end nodess cannot have a `_partsel` flag
|
|
5172
|
+
this._partsel = this.hasChildren() ? true : false;
|
|
5167
5173
|
break;
|
|
5168
5174
|
default:
|
|
5169
5175
|
error(`Invalid state: ${state}`);
|
|
@@ -5333,7 +5339,7 @@ class WunderbaumNode {
|
|
|
5333
5339
|
assert(data.statusNodeType, "Not a status node");
|
|
5334
5340
|
assert(!firstChild || !firstChild.isStatusNode(), "Child must not be a status node");
|
|
5335
5341
|
statusNode = this.addNode(data, "prependChild");
|
|
5336
|
-
statusNode.match =
|
|
5342
|
+
statusNode.match = -1; // Mark as 'match' to avoid hiding
|
|
5337
5343
|
tree.update(ChangeType.structure);
|
|
5338
5344
|
return statusNode;
|
|
5339
5345
|
};
|
|
@@ -5624,8 +5630,8 @@ WunderbaumNode.sequence = 0;
|
|
|
5624
5630
|
|
|
5625
5631
|
/*!
|
|
5626
5632
|
* Wunderbaum - ext-edit
|
|
5627
|
-
* Copyright (c) 2021-
|
|
5628
|
-
* v0.
|
|
5633
|
+
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
|
|
5634
|
+
* v0.13.0, Sat, 08 Mar 2025 14:16:31 GMT (https://github.com/mar10/wunderbaum)
|
|
5629
5635
|
*/
|
|
5630
5636
|
// const START_MARKER = "\uFFF7";
|
|
5631
5637
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -5944,7 +5950,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5944
5950
|
newNode.setClass("wb-edit-new");
|
|
5945
5951
|
this.relatedNode = node;
|
|
5946
5952
|
// Don't filter new nodes:
|
|
5947
|
-
newNode.match =
|
|
5953
|
+
newNode.match = -1;
|
|
5948
5954
|
newNode.makeVisible({ noAnimation: true }).then(() => {
|
|
5949
5955
|
this.startEditTitle(newNode);
|
|
5950
5956
|
});
|
|
@@ -5956,12 +5962,12 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5956
5962
|
*
|
|
5957
5963
|
* A treegrid control.
|
|
5958
5964
|
*
|
|
5959
|
-
* Copyright (c) 2021-
|
|
5965
|
+
* Copyright (c) 2021-2025, Martin Wendt (https://wwWendt.de).
|
|
5960
5966
|
* https://github.com/mar10/wunderbaum
|
|
5961
5967
|
*
|
|
5962
5968
|
* Released under the MIT license.
|
|
5963
|
-
* @version v0.
|
|
5964
|
-
* @date
|
|
5969
|
+
* @version v0.13.0
|
|
5970
|
+
* @date Sat, 08 Mar 2025 14:16:31 GMT
|
|
5965
5971
|
*/
|
|
5966
5972
|
// import "./wunderbaum.scss";
|
|
5967
5973
|
class WbSystemRoot extends WunderbaumNode {
|
|
@@ -5982,7 +5988,7 @@ class WbSystemRoot extends WunderbaumNode {
|
|
|
5982
5988
|
*/
|
|
5983
5989
|
class Wunderbaum {
|
|
5984
5990
|
/** Currently active node if any.
|
|
5985
|
-
* Use @link
|
|
5991
|
+
* Use {@link WunderbaumNode.setActive|setActive} to modify.
|
|
5986
5992
|
*/
|
|
5987
5993
|
get activeNode() {
|
|
5988
5994
|
var _a;
|
|
@@ -5990,7 +5996,7 @@ class Wunderbaum {
|
|
|
5990
5996
|
return ((_a = this._activeNode) === null || _a === void 0 ? void 0 : _a.tree) ? this._activeNode : null;
|
|
5991
5997
|
}
|
|
5992
5998
|
/** Current node hat has keyboard focus if any.
|
|
5993
|
-
* Use @link
|
|
5999
|
+
* Use {@link WunderbaumNode.setFocus|setFocus()} to modify.
|
|
5994
6000
|
*/
|
|
5995
6001
|
get focusNode() {
|
|
5996
6002
|
var _a;
|
|
@@ -6022,6 +6028,9 @@ class Wunderbaum {
|
|
|
6022
6028
|
// --- SELECT ---
|
|
6023
6029
|
// /** @internal */
|
|
6024
6030
|
// public selectRangeAnchor: WunderbaumNode | null = null;
|
|
6031
|
+
// --- BREADCRUMB ---
|
|
6032
|
+
/** Filter options (used as defaults for calls to {@link Wunderbaum.filterNodes} ) */
|
|
6033
|
+
this.breadcrumb = null;
|
|
6025
6034
|
// --- FILTER ---
|
|
6026
6035
|
/** Filter options (used as defaults for calls to {@link Wunderbaum.filterNodes} ) */
|
|
6027
6036
|
this.filterMode = null;
|
|
@@ -6056,10 +6065,10 @@ class Wunderbaum {
|
|
|
6056
6065
|
emptyChildListExpandable: false,
|
|
6057
6066
|
// updateThrottleWait: 200,
|
|
6058
6067
|
skeleton: false,
|
|
6059
|
-
connectTopBreadcrumb: null,
|
|
6068
|
+
connectTopBreadcrumb: null,
|
|
6060
6069
|
selectMode: "multi", // SelectModeType
|
|
6061
6070
|
// --- KeyNav ---
|
|
6062
|
-
navigationModeOption: null, // NavModeEnum
|
|
6071
|
+
navigationModeOption: null, // NavModeEnum,
|
|
6063
6072
|
quicksearch: true,
|
|
6064
6073
|
// --- Events ---
|
|
6065
6074
|
iconBadge: null,
|
|
@@ -6071,8 +6080,11 @@ class Wunderbaum {
|
|
|
6071
6080
|
strings: {
|
|
6072
6081
|
loadError: "Error",
|
|
6073
6082
|
loading: "Loading...",
|
|
6074
|
-
// loading: "Loading…",
|
|
6075
6083
|
noData: "No data",
|
|
6084
|
+
breadcrumbDelimiter: " » ",
|
|
6085
|
+
queryResult: "Found ${matches} of ${count}",
|
|
6086
|
+
noMatch: "No results",
|
|
6087
|
+
matchIndex: "${match} of ${matches}",
|
|
6076
6088
|
},
|
|
6077
6089
|
}, options));
|
|
6078
6090
|
const readyDeferred = new Deferred();
|
|
@@ -6140,7 +6152,7 @@ class Wunderbaum {
|
|
|
6140
6152
|
const wantHeader = opts.header == null ? this.columns.length > 1 : !!opts.header;
|
|
6141
6153
|
if (this.headerElement) {
|
|
6142
6154
|
// User existing header markup to define `this.columns`
|
|
6143
|
-
assert(!this.columns, "`opts.columns` must not be set if markup already contains a header");
|
|
6155
|
+
assert(!this.columns, "`opts.columns` must not be set if table markup already contains a header");
|
|
6144
6156
|
this.columns = [];
|
|
6145
6157
|
const rowElement = this.headerElement.querySelector("div.wb-row");
|
|
6146
6158
|
for (const colDiv of rowElement.querySelectorAll("div")) {
|
|
@@ -6178,6 +6190,19 @@ class Wunderbaum {
|
|
|
6178
6190
|
this.headerElement =
|
|
6179
6191
|
this.element.querySelector("div.wb-header");
|
|
6180
6192
|
this.element.classList.toggle("wb-grid", this.columns.length > 1);
|
|
6193
|
+
if (this.options.connectTopBreadcrumb) {
|
|
6194
|
+
this.breadcrumb = elemFromSelector(this.options.connectTopBreadcrumb);
|
|
6195
|
+
assert(!this.breadcrumb || this.breadcrumb.innerHTML != null, `Invalid 'connectTopBreadcrumb' option: ${this.breadcrumb}.`);
|
|
6196
|
+
this.breadcrumb.addEventListener("click", (e) => {
|
|
6197
|
+
// const node = Wunderbaum.getNode(e)!;
|
|
6198
|
+
const elem = e.target;
|
|
6199
|
+
if (elem && elem.matches("a.wb-breadcrumb")) {
|
|
6200
|
+
const node = this.keyMap.get(elem.dataset.key);
|
|
6201
|
+
node === null || node === void 0 ? void 0 : node.setActive();
|
|
6202
|
+
e.preventDefault();
|
|
6203
|
+
}
|
|
6204
|
+
});
|
|
6205
|
+
}
|
|
6181
6206
|
this._initExtensions();
|
|
6182
6207
|
// --- apply initial options
|
|
6183
6208
|
["enabled", "fixedCol"].forEach((optName) => {
|
|
@@ -6188,8 +6213,7 @@ class Wunderbaum {
|
|
|
6188
6213
|
// --- Load initial data
|
|
6189
6214
|
if (opts.source) {
|
|
6190
6215
|
if (opts.showSpinner) {
|
|
6191
|
-
this.nodeListElement.innerHTML =
|
|
6192
|
-
"<progress class='spinner'>loading...</progress>";
|
|
6216
|
+
this.nodeListElement.innerHTML = `<progress class='spinner'>${opts.strings.loading}</progress>`;
|
|
6193
6217
|
}
|
|
6194
6218
|
this.load(opts.source)
|
|
6195
6219
|
.then(() => {
|
|
@@ -6542,7 +6566,10 @@ class Wunderbaum {
|
|
|
6542
6566
|
});
|
|
6543
6567
|
return node;
|
|
6544
6568
|
}
|
|
6545
|
-
/** Return the topmost visible node in the viewport.
|
|
6569
|
+
/** Return the topmost visible node in the viewport.
|
|
6570
|
+
* @param complete If `false`, the node is considered visible if at least one
|
|
6571
|
+
* pixel is visible.
|
|
6572
|
+
*/
|
|
6546
6573
|
getTopmostVpNode(complete = true) {
|
|
6547
6574
|
const rowHeight = this.options.rowHeightPx;
|
|
6548
6575
|
const gracePx = 1; // ignore subpixel scrolling
|
|
@@ -6575,24 +6602,19 @@ class Wunderbaum {
|
|
|
6575
6602
|
bottomIdx = Math.min(bottomIdx, this.count(true) - 1);
|
|
6576
6603
|
return this._getNodeByRowIdx(bottomIdx);
|
|
6577
6604
|
}
|
|
6578
|
-
/** Return
|
|
6579
|
-
|
|
6605
|
+
/** Return following visible node in the viewport. */
|
|
6606
|
+
_getNextNodeInView(node, options) {
|
|
6607
|
+
let ofs = (options === null || options === void 0 ? void 0 : options.ofs) || 1;
|
|
6608
|
+
const reverse = !!(options === null || options === void 0 ? void 0 : options.reverse);
|
|
6580
6609
|
this.visitRows((n) => {
|
|
6581
6610
|
node = n;
|
|
6582
|
-
if (
|
|
6611
|
+
if ((options === null || options === void 0 ? void 0 : options.cb) && options.cb(n)) {
|
|
6583
6612
|
return false;
|
|
6584
6613
|
}
|
|
6585
|
-
}, { reverse: true, start: node || this.getActiveNode() });
|
|
6586
|
-
return node;
|
|
6587
|
-
}
|
|
6588
|
-
/** Return following visible node in the viewport. */
|
|
6589
|
-
_getNextNodeInView(node, ofs = 1) {
|
|
6590
|
-
this.visitRows((n) => {
|
|
6591
|
-
node = n;
|
|
6592
6614
|
if (ofs-- <= 0) {
|
|
6593
6615
|
return false;
|
|
6594
6616
|
}
|
|
6595
|
-
}, { reverse:
|
|
6617
|
+
}, { reverse: reverse, start: node || this.getActiveNode() });
|
|
6596
6618
|
return node;
|
|
6597
6619
|
}
|
|
6598
6620
|
/**
|
|
@@ -6712,9 +6734,11 @@ class Wunderbaum {
|
|
|
6712
6734
|
case "first":
|
|
6713
6735
|
case "last":
|
|
6714
6736
|
case "left":
|
|
6737
|
+
case "nextMatch":
|
|
6715
6738
|
case "pageDown":
|
|
6716
6739
|
case "pageUp":
|
|
6717
6740
|
case "parent":
|
|
6741
|
+
case "prevMatch":
|
|
6718
6742
|
case "right":
|
|
6719
6743
|
case "up":
|
|
6720
6744
|
return node.navigate(cmd);
|
|
@@ -6906,6 +6930,11 @@ class Wunderbaum {
|
|
|
6906
6930
|
count(visible = false) {
|
|
6907
6931
|
return visible ? this.treeRowCount : this.keyMap.size;
|
|
6908
6932
|
}
|
|
6933
|
+
/** Return the number of *unique* nodes in the data model, i.e. unique `node.refKey`.
|
|
6934
|
+
*/
|
|
6935
|
+
countUnique() {
|
|
6936
|
+
return this.refKeyMap.size;
|
|
6937
|
+
}
|
|
6909
6938
|
/** @internal sanity check. */
|
|
6910
6939
|
_check() {
|
|
6911
6940
|
let i = 0;
|
|
@@ -6964,12 +6993,14 @@ class Wunderbaum {
|
|
|
6964
6993
|
* and wrap-around at the end.
|
|
6965
6994
|
* Used by quicksearch and keyboard navigation.
|
|
6966
6995
|
*/
|
|
6967
|
-
findNextNode(match, startNode) {
|
|
6996
|
+
findNextNode(match, startNode, reverse = false) {
|
|
6968
6997
|
//, visibleOnly) {
|
|
6969
6998
|
let res = null;
|
|
6970
6999
|
const firstNode = this.getFirstChild();
|
|
7000
|
+
// Last visible node (calculation is expensive, so do only if we need it):
|
|
7001
|
+
const lastNode = reverse ? this.findRelatedNode(firstNode, "last") : null;
|
|
6971
7002
|
const matcher = typeof match === "string" ? makeNodeTitleStartMatcher(match) : match;
|
|
6972
|
-
startNode = startNode || firstNode;
|
|
7003
|
+
startNode = startNode || (reverse ? lastNode : firstNode);
|
|
6973
7004
|
function _checkNode(n) {
|
|
6974
7005
|
// console.log("_check " + n)
|
|
6975
7006
|
if (matcher(n)) {
|
|
@@ -6982,12 +7013,14 @@ class Wunderbaum {
|
|
|
6982
7013
|
this.visitRows(_checkNode, {
|
|
6983
7014
|
start: startNode,
|
|
6984
7015
|
includeSelf: false,
|
|
7016
|
+
reverse: reverse,
|
|
6985
7017
|
});
|
|
6986
7018
|
// Wrap around search
|
|
6987
7019
|
if (!res && startNode !== firstNode) {
|
|
6988
7020
|
this.visitRows(_checkNode, {
|
|
6989
|
-
start: firstNode,
|
|
7021
|
+
start: reverse ? lastNode : firstNode,
|
|
6990
7022
|
includeSelf: true,
|
|
7023
|
+
reverse: reverse,
|
|
6991
7024
|
});
|
|
6992
7025
|
}
|
|
6993
7026
|
return res;
|
|
@@ -7054,7 +7087,7 @@ class Wunderbaum {
|
|
|
7054
7087
|
// }
|
|
7055
7088
|
break;
|
|
7056
7089
|
case "up":
|
|
7057
|
-
res = this.
|
|
7090
|
+
res = this._getNextNodeInView(node, { reverse: true });
|
|
7058
7091
|
break;
|
|
7059
7092
|
case "down":
|
|
7060
7093
|
res = this._getNextNodeInView(node);
|
|
@@ -7067,7 +7100,10 @@ class Wunderbaum {
|
|
|
7067
7100
|
res = bottomNode;
|
|
7068
7101
|
}
|
|
7069
7102
|
else {
|
|
7070
|
-
res = this._getNextNodeInView(node,
|
|
7103
|
+
res = this._getNextNodeInView(node, {
|
|
7104
|
+
reverse: false,
|
|
7105
|
+
ofs: pageSize,
|
|
7106
|
+
});
|
|
7071
7107
|
}
|
|
7072
7108
|
}
|
|
7073
7109
|
break;
|
|
@@ -7082,10 +7118,23 @@ class Wunderbaum {
|
|
|
7082
7118
|
res = topNode;
|
|
7083
7119
|
}
|
|
7084
7120
|
else {
|
|
7085
|
-
res = this.
|
|
7121
|
+
res = this._getNextNodeInView(node, {
|
|
7122
|
+
reverse: true,
|
|
7123
|
+
ofs: pageSize,
|
|
7124
|
+
});
|
|
7086
7125
|
}
|
|
7087
7126
|
}
|
|
7088
7127
|
break;
|
|
7128
|
+
case "prevMatch":
|
|
7129
|
+
// fallthrough
|
|
7130
|
+
case "nextMatch":
|
|
7131
|
+
if (!this.isFilterActive) {
|
|
7132
|
+
this.logWarn(`${where}: Filter is not active.`);
|
|
7133
|
+
break;
|
|
7134
|
+
}
|
|
7135
|
+
res = this.findNextNode((n) => n.isMatched(), node, where === "prevMatch");
|
|
7136
|
+
res === null || res === void 0 ? void 0 : res.setActive();
|
|
7137
|
+
break;
|
|
7089
7138
|
default:
|
|
7090
7139
|
this.logWarn("Unknown relation '" + where + "'.");
|
|
7091
7140
|
}
|
|
@@ -7147,6 +7196,12 @@ class Wunderbaum {
|
|
|
7147
7196
|
getFirstChild() {
|
|
7148
7197
|
return this.root.getFirstChild();
|
|
7149
7198
|
}
|
|
7199
|
+
/**
|
|
7200
|
+
* Return the last top level node if any (not the invisible root node).
|
|
7201
|
+
*/
|
|
7202
|
+
getLastChild() {
|
|
7203
|
+
return this.root.getLastChild();
|
|
7204
|
+
}
|
|
7150
7205
|
/**
|
|
7151
7206
|
* Return the node that currently has keyboard focus or null.
|
|
7152
7207
|
* Alias for {@link Wunderbaum.focusNode}.
|
|
@@ -7474,6 +7529,51 @@ class Wunderbaum {
|
|
|
7474
7529
|
_setFocusNode(node) {
|
|
7475
7530
|
this._focusNode = node;
|
|
7476
7531
|
}
|
|
7532
|
+
/** Return the current selection/expansion/activation status. @experimental */
|
|
7533
|
+
getState(options) {
|
|
7534
|
+
var _a, _b;
|
|
7535
|
+
let expandedKeys = undefined;
|
|
7536
|
+
if (options.expandedKeys !== false) {
|
|
7537
|
+
expandedKeys = [];
|
|
7538
|
+
for (const node of this) {
|
|
7539
|
+
if (node.expanded) {
|
|
7540
|
+
expandedKeys.push(node.key);
|
|
7541
|
+
}
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
const state = {
|
|
7545
|
+
activeKey: (_b = (_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.key) !== null && _b !== void 0 ? _b : null,
|
|
7546
|
+
activeColIdx: this.activeColIdx,
|
|
7547
|
+
selectedKeys: options.selectedKeys === false
|
|
7548
|
+
? undefined
|
|
7549
|
+
: this.getSelectedNodes().flatMap((n) => n.key),
|
|
7550
|
+
expandedKeys: expandedKeys,
|
|
7551
|
+
};
|
|
7552
|
+
return state;
|
|
7553
|
+
}
|
|
7554
|
+
/** Apply selection/expansion/activation status. @experimental */
|
|
7555
|
+
setState(state, options) {
|
|
7556
|
+
this.runWithDeferredUpdate(() => {
|
|
7557
|
+
var _a, _b;
|
|
7558
|
+
if (state.selectedKeys) {
|
|
7559
|
+
this.selectAll(false);
|
|
7560
|
+
for (const key of state.selectedKeys) {
|
|
7561
|
+
(_a = this.findKey(key)) === null || _a === void 0 ? void 0 : _a.setSelected(true);
|
|
7562
|
+
}
|
|
7563
|
+
}
|
|
7564
|
+
if (state.expandedKeys) {
|
|
7565
|
+
for (const key of state.expandedKeys) {
|
|
7566
|
+
(_b = this.findKey(key)) === null || _b === void 0 ? void 0 : _b.setExpanded(true);
|
|
7567
|
+
}
|
|
7568
|
+
}
|
|
7569
|
+
if (state.activeKey) {
|
|
7570
|
+
this.setActiveNode(state.activeKey);
|
|
7571
|
+
}
|
|
7572
|
+
if (state.activeColIdx != null) {
|
|
7573
|
+
this.setColumn(state.activeColIdx);
|
|
7574
|
+
}
|
|
7575
|
+
});
|
|
7576
|
+
}
|
|
7477
7577
|
update(change, node, options) {
|
|
7478
7578
|
// this.log(`update(${change}) node=${node}`);
|
|
7479
7579
|
if (!(node instanceof WunderbaumNode)) {
|
|
@@ -7755,11 +7855,11 @@ class Wunderbaum {
|
|
|
7755
7855
|
// }
|
|
7756
7856
|
return modified;
|
|
7757
7857
|
}
|
|
7758
|
-
_insertIcon(icon, elem) {
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
}
|
|
7858
|
+
// protected _insertIcon(icon: string, elem: HTMLElement) {
|
|
7859
|
+
// const iconElem = document.createElement("i");
|
|
7860
|
+
// iconElem.className = icon;
|
|
7861
|
+
// elem.appendChild(iconElem);
|
|
7862
|
+
// }
|
|
7763
7863
|
/** Create/update header markup from `this.columns` definition.
|
|
7764
7864
|
* @internal
|
|
7765
7865
|
*/
|
|
@@ -7857,6 +7957,104 @@ class Wunderbaum {
|
|
|
7857
7957
|
this._updateViewportImmediately();
|
|
7858
7958
|
}
|
|
7859
7959
|
}
|
|
7960
|
+
/** @internal */
|
|
7961
|
+
_createNodeIcon(node, showLoading, showBadge) {
|
|
7962
|
+
const iconMap = this.iconMap;
|
|
7963
|
+
let iconElem;
|
|
7964
|
+
let icon = node.getOption("icon");
|
|
7965
|
+
if (node._errorInfo) {
|
|
7966
|
+
icon = iconMap.error;
|
|
7967
|
+
}
|
|
7968
|
+
else if (node._isLoading && showLoading) {
|
|
7969
|
+
// Status nodes, or nodes without expander (< minExpandLevel) should
|
|
7970
|
+
// display the 'loading' status with the i.wb-icon span
|
|
7971
|
+
icon = iconMap.loading;
|
|
7972
|
+
}
|
|
7973
|
+
if (icon === false) {
|
|
7974
|
+
return null; // explicitly disabled: don't try default icons
|
|
7975
|
+
}
|
|
7976
|
+
if (typeof icon === "string") ;
|
|
7977
|
+
else if (node.statusNodeType) {
|
|
7978
|
+
icon = iconMap[node.statusNodeType];
|
|
7979
|
+
}
|
|
7980
|
+
else if (node.expanded) {
|
|
7981
|
+
icon = iconMap.folderOpen;
|
|
7982
|
+
}
|
|
7983
|
+
else if (node.children) {
|
|
7984
|
+
icon = iconMap.folder;
|
|
7985
|
+
}
|
|
7986
|
+
else if (node.lazy) {
|
|
7987
|
+
icon = iconMap.folderLazy;
|
|
7988
|
+
}
|
|
7989
|
+
else {
|
|
7990
|
+
icon = iconMap.doc;
|
|
7991
|
+
}
|
|
7992
|
+
if (!icon) {
|
|
7993
|
+
iconElem = document.createElement("i");
|
|
7994
|
+
iconElem.className = "wb-icon";
|
|
7995
|
+
}
|
|
7996
|
+
else if (icon.indexOf("<") >= 0) {
|
|
7997
|
+
// HTML
|
|
7998
|
+
iconElem = elemFromHtml(icon);
|
|
7999
|
+
}
|
|
8000
|
+
else if (TEST_IMG.test(icon)) {
|
|
8001
|
+
// Image URL
|
|
8002
|
+
iconElem = elemFromHtml(`<i class="wb-icon" style="background-image: url('${icon}');">`);
|
|
8003
|
+
}
|
|
8004
|
+
else {
|
|
8005
|
+
// Class name
|
|
8006
|
+
iconElem = document.createElement("i");
|
|
8007
|
+
iconElem.className = "wb-icon " + icon;
|
|
8008
|
+
}
|
|
8009
|
+
// Event handler `tree.iconBadge` can return a badge text or HTMLSpanElement
|
|
8010
|
+
const cbRes = showBadge && node._callEvent("iconBadge", { iconSpan: iconElem });
|
|
8011
|
+
let badge = null;
|
|
8012
|
+
if (cbRes != null && cbRes !== false) {
|
|
8013
|
+
let classes = "";
|
|
8014
|
+
let tooltip = "";
|
|
8015
|
+
if (isPlainObject(cbRes)) {
|
|
8016
|
+
badge = "" + cbRes.badge;
|
|
8017
|
+
classes = cbRes.badgeClass ? " " + cbRes.badgeClass : "";
|
|
8018
|
+
tooltip = cbRes.badgeTooltip ? ` title="${cbRes.badgeTooltip}"` : "";
|
|
8019
|
+
}
|
|
8020
|
+
else if (typeof cbRes === "number") {
|
|
8021
|
+
badge = "" + cbRes;
|
|
8022
|
+
}
|
|
8023
|
+
else {
|
|
8024
|
+
badge = cbRes; // string or HTMLSpanElement
|
|
8025
|
+
}
|
|
8026
|
+
if (typeof badge === "string") {
|
|
8027
|
+
badge = elemFromHtml(`<span class="wb-badge${classes}"${tooltip}>${escapeHtml(badge)}</span>`);
|
|
8028
|
+
}
|
|
8029
|
+
if (badge) {
|
|
8030
|
+
iconElem.append(badge);
|
|
8031
|
+
}
|
|
8032
|
+
}
|
|
8033
|
+
return iconElem;
|
|
8034
|
+
}
|
|
8035
|
+
_updateTopBreadcrumb() {
|
|
8036
|
+
const breadcrumb = this.breadcrumb;
|
|
8037
|
+
const topmost = this.getTopmostVpNode(true);
|
|
8038
|
+
const parentList = topmost === null || topmost === void 0 ? void 0 : topmost.getParentList(false, false);
|
|
8039
|
+
if (parentList === null || parentList === void 0 ? void 0 : parentList.length) {
|
|
8040
|
+
breadcrumb.innerHTML = "";
|
|
8041
|
+
for (const n of topmost.getParentList(false, false)) {
|
|
8042
|
+
const icon = this._createNodeIcon(n, false, false);
|
|
8043
|
+
if (icon) {
|
|
8044
|
+
breadcrumb.append(icon, " ");
|
|
8045
|
+
}
|
|
8046
|
+
const part = document.createElement("a");
|
|
8047
|
+
part.textContent = n.title;
|
|
8048
|
+
part.href = "#";
|
|
8049
|
+
part.classList.add("wb-breadcrumb");
|
|
8050
|
+
part.dataset.key = n.key;
|
|
8051
|
+
breadcrumb.append(part, this.options.strings.breadcrumbDelimiter);
|
|
8052
|
+
}
|
|
8053
|
+
}
|
|
8054
|
+
else {
|
|
8055
|
+
breadcrumb.innerHTML = " ";
|
|
8056
|
+
}
|
|
8057
|
+
}
|
|
7860
8058
|
/**
|
|
7861
8059
|
* This is the actual update method, which is wrapped inside a throttle method.
|
|
7862
8060
|
* It calls `updateColumns()` and `_updateRows()`.
|
|
@@ -7867,7 +8065,6 @@ class Wunderbaum {
|
|
|
7867
8065
|
* @internal
|
|
7868
8066
|
*/
|
|
7869
8067
|
_updateViewportImmediately() {
|
|
7870
|
-
var _a;
|
|
7871
8068
|
if (this._disableUpdateCount) {
|
|
7872
8069
|
this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount}).`);
|
|
7873
8070
|
this._disableUpdateIgnoreCount++;
|
|
@@ -7914,11 +8111,8 @@ class Wunderbaum {
|
|
|
7914
8111
|
this._updateRows();
|
|
7915
8112
|
// console.profileEnd(`_updateViewportImmediately()`)
|
|
7916
8113
|
}
|
|
7917
|
-
if (this.
|
|
7918
|
-
|
|
7919
|
-
let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > ");
|
|
7920
|
-
path = path ? path + " >" : "";
|
|
7921
|
-
this.options.connectTopBreadcrumb.textContent = path;
|
|
8114
|
+
if (this.breadcrumb) {
|
|
8115
|
+
this._updateTopBreadcrumb();
|
|
7922
8116
|
}
|
|
7923
8117
|
this._callEvent("update");
|
|
7924
8118
|
}
|
|
@@ -7984,8 +8178,9 @@ class Wunderbaum {
|
|
|
7984
8178
|
// this.debug("render", opts);
|
|
7985
8179
|
const obsoleteNodes = new Set();
|
|
7986
8180
|
this.nodeListElement.childNodes.forEach((elem) => {
|
|
7987
|
-
|
|
7988
|
-
|
|
8181
|
+
if (elem._wb_node) {
|
|
8182
|
+
obsoleteNodes.add(elem._wb_node);
|
|
8183
|
+
}
|
|
7989
8184
|
});
|
|
7990
8185
|
let idx = 0;
|
|
7991
8186
|
let top = 0;
|
|
@@ -8286,7 +8481,7 @@ class Wunderbaum {
|
|
|
8286
8481
|
}
|
|
8287
8482
|
Wunderbaum.sequence = 0;
|
|
8288
8483
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
8289
|
-
Wunderbaum.version = "v0.
|
|
8484
|
+
Wunderbaum.version = "v0.13.0"; // Set to semver by 'grunt release'
|
|
8290
8485
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
8291
8486
|
Wunderbaum.util = util;
|
|
8292
8487
|
|