wunderbaum 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/wunderbaum.css +1 -1
- package/dist/wunderbaum.d.ts +125 -60
- package/dist/wunderbaum.esm.js +480 -231
- package/dist/wunderbaum.esm.min.js +26 -26
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +480 -231
- package/dist/wunderbaum.umd.min.js +34 -34
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/common.ts +187 -26
- package/src/types.ts +43 -19
- package/src/util.ts +10 -5
- package/src/wb_ext_edit.ts +3 -2
- package/src/wb_ext_keynav.ts +12 -13
- package/src/wb_ext_logger.ts +1 -1
- package/src/wb_node.ts +173 -58
- package/src/wunderbaum.ts +63 -63
package/dist/wunderbaum.umd.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/*!
|
|
8
8
|
* Wunderbaum - util
|
|
9
9
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
10
|
-
* v0.0.
|
|
10
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
11
11
|
*/
|
|
12
12
|
/** @module util */
|
|
13
13
|
/** Readable names for `MouseEvent.button` */
|
|
@@ -287,11 +287,17 @@
|
|
|
287
287
|
case "week":
|
|
288
288
|
case "datetime":
|
|
289
289
|
case "datetime-local":
|
|
290
|
-
input.valueAsDate = value;
|
|
290
|
+
input.valueAsDate = new Date(value);
|
|
291
|
+
// input.valueAsDate = value; // breaks in Edge?
|
|
291
292
|
break;
|
|
292
293
|
case "number":
|
|
293
294
|
case "range":
|
|
294
|
-
|
|
295
|
+
if (value == null) {
|
|
296
|
+
input.value = value;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
input.valueAsNumber = value;
|
|
300
|
+
}
|
|
295
301
|
break;
|
|
296
302
|
case "radio":
|
|
297
303
|
error("Not implemented");
|
|
@@ -308,7 +314,7 @@
|
|
|
308
314
|
break;
|
|
309
315
|
case "text":
|
|
310
316
|
default:
|
|
311
|
-
input.value = value
|
|
317
|
+
input.value = value !== null && value !== void 0 ? value : "";
|
|
312
318
|
}
|
|
313
319
|
}
|
|
314
320
|
else if (tag === "SELECT") {
|
|
@@ -466,7 +472,7 @@
|
|
|
466
472
|
});
|
|
467
473
|
});
|
|
468
474
|
}
|
|
469
|
-
/** Return a wrapped handler method, that provides `this._super`.
|
|
475
|
+
/** Return a wrapped handler method, that provides `this._super` and `this._superApply`.
|
|
470
476
|
*
|
|
471
477
|
* ```ts
|
|
472
478
|
// Implement `opts.createNode` event to add the 'draggable' attribute
|
|
@@ -707,7 +713,7 @@
|
|
|
707
713
|
/*!
|
|
708
714
|
* Wunderbaum - types
|
|
709
715
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
710
|
-
* v0.0.
|
|
716
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
711
717
|
*/
|
|
712
718
|
/** Possible values for `setModified()`. */
|
|
713
719
|
var ChangeType;
|
|
@@ -759,7 +765,7 @@
|
|
|
759
765
|
/*!
|
|
760
766
|
* Wunderbaum - wb_extension_base
|
|
761
767
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
762
|
-
* v0.0.
|
|
768
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
763
769
|
*/
|
|
764
770
|
class WunderbaumExtension {
|
|
765
771
|
constructor(tree, id, defaults) {
|
|
@@ -1050,7 +1056,7 @@
|
|
|
1050
1056
|
/*!
|
|
1051
1057
|
* Wunderbaum - ext-filter
|
|
1052
1058
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1053
|
-
* v0.0.
|
|
1059
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
1054
1060
|
*/
|
|
1055
1061
|
const START_MARKER = "\uFFF7";
|
|
1056
1062
|
const END_MARKER = "\uFFF8";
|
|
@@ -1352,107 +1358,10 @@
|
|
|
1352
1358
|
return textPoses.join("");
|
|
1353
1359
|
}
|
|
1354
1360
|
|
|
1355
|
-
/*!
|
|
1356
|
-
* Wunderbaum - common
|
|
1357
|
-
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1358
|
-
* v0.0.6, Sat, 10 Sep 2022 19:29:21 GMT (https://github.com/mar10/wunderbaum)
|
|
1359
|
-
*/
|
|
1360
|
-
const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
|
|
1361
|
-
const ROW_HEIGHT = 22;
|
|
1362
|
-
// export const HEADER_HEIGHT = ROW_HEIGHT;
|
|
1363
|
-
const ICON_WIDTH = 20;
|
|
1364
|
-
const ROW_EXTRA_PAD = 7; // 2x $col-padding-x + 3px rounding errors
|
|
1365
|
-
const RENDER_MAX_PREFETCH = 5;
|
|
1366
|
-
const TEST_IMG = new RegExp(/\.|\//); // strings are considered image urls if they contain '.' or '/'
|
|
1367
|
-
// export const RECURSIVE_REQUEST_ERROR = "$recursive_request";
|
|
1368
|
-
// export const INVALID_REQUEST_TARGET_ERROR = "$request_target_invalid";
|
|
1369
|
-
let iconMap = {
|
|
1370
|
-
error: "bi bi-exclamation-triangle",
|
|
1371
|
-
// loading: "bi bi-hourglass-split wb-busy",
|
|
1372
|
-
loading: "bi bi-chevron-right wb-busy",
|
|
1373
|
-
// loading: "bi bi-arrow-repeat wb-spin",
|
|
1374
|
-
// loading: '<div class="spinner-border spinner-border-sm" role="status"> <span class="visually-hidden">Loading...</span> </div>',
|
|
1375
|
-
// noData: "bi bi-search",
|
|
1376
|
-
noData: "bi bi-question-circle",
|
|
1377
|
-
expanderExpanded: "bi bi-chevron-down",
|
|
1378
|
-
// expanderExpanded: "bi bi-dash-square",
|
|
1379
|
-
expanderCollapsed: "bi bi-chevron-right",
|
|
1380
|
-
// expanderCollapsed: "bi bi-plus-square",
|
|
1381
|
-
expanderLazy: "bi bi-chevron-right wb-helper-lazy-expander",
|
|
1382
|
-
// expanderLazy: "bi bi-chevron-bar-right",
|
|
1383
|
-
checkChecked: "bi bi-check-square",
|
|
1384
|
-
checkUnchecked: "bi bi-square",
|
|
1385
|
-
checkUnknown: "bi dash-square-dotted",
|
|
1386
|
-
radioChecked: "bi bi-circle-fill",
|
|
1387
|
-
radioUnchecked: "bi bi-circle",
|
|
1388
|
-
radioUnknown: "bi bi-circle-dotted",
|
|
1389
|
-
folder: "bi bi-folder2",
|
|
1390
|
-
folderOpen: "bi bi-folder2-open",
|
|
1391
|
-
doc: "bi bi-file-earmark",
|
|
1392
|
-
};
|
|
1393
|
-
/** Dict keys that are evaluated by source loader (others are added to `tree.data` instead). */
|
|
1394
|
-
const RESERVED_TREE_SOURCE_KEYS = new Set([
|
|
1395
|
-
"children",
|
|
1396
|
-
"columns",
|
|
1397
|
-
"format",
|
|
1398
|
-
"keyMap",
|
|
1399
|
-
"positional",
|
|
1400
|
-
"typeList",
|
|
1401
|
-
"types",
|
|
1402
|
-
"version", // reserved for future use
|
|
1403
|
-
]);
|
|
1404
|
-
/** Key codes that trigger grid navigation, even when inside an input element. */
|
|
1405
|
-
const INPUT_BREAKOUT_KEYS = new Set([
|
|
1406
|
-
// "ArrowDown",
|
|
1407
|
-
// "ArrowUp",
|
|
1408
|
-
"Enter",
|
|
1409
|
-
"Escape",
|
|
1410
|
-
]);
|
|
1411
|
-
/** Map `KeyEvent.key` to navigation action. */
|
|
1412
|
-
const KEY_TO_ACTION_DICT = {
|
|
1413
|
-
" ": "toggleSelect",
|
|
1414
|
-
"+": "expand",
|
|
1415
|
-
Add: "expand",
|
|
1416
|
-
ArrowDown: "down",
|
|
1417
|
-
ArrowLeft: "left",
|
|
1418
|
-
ArrowRight: "right",
|
|
1419
|
-
ArrowUp: "up",
|
|
1420
|
-
Backspace: "parent",
|
|
1421
|
-
"/": "collapseAll",
|
|
1422
|
-
Divide: "collapseAll",
|
|
1423
|
-
End: "lastCol",
|
|
1424
|
-
Home: "firstCol",
|
|
1425
|
-
"Control+End": "last",
|
|
1426
|
-
"Control+Home": "first",
|
|
1427
|
-
"Meta+ArrowDown": "last",
|
|
1428
|
-
"Meta+ArrowUp": "first",
|
|
1429
|
-
"*": "expandAll",
|
|
1430
|
-
Multiply: "expandAll",
|
|
1431
|
-
PageDown: "pageDown",
|
|
1432
|
-
PageUp: "pageUp",
|
|
1433
|
-
"-": "collapse",
|
|
1434
|
-
Subtract: "collapse",
|
|
1435
|
-
};
|
|
1436
|
-
/** Return a callback that returns true if the node title contains a substring (case-insensitive). */
|
|
1437
|
-
function makeNodeTitleMatcher(s) {
|
|
1438
|
-
s = escapeRegex(s.toLowerCase());
|
|
1439
|
-
return function (node) {
|
|
1440
|
-
return node.title.toLowerCase().indexOf(s) >= 0;
|
|
1441
|
-
};
|
|
1442
|
-
}
|
|
1443
|
-
/** Return a callback that returns true if the node title starts with a string (case-insensitive). */
|
|
1444
|
-
function makeNodeTitleStartMatcher(s) {
|
|
1445
|
-
s = escapeRegex(s);
|
|
1446
|
-
const reMatch = new RegExp("^" + s, "i");
|
|
1447
|
-
return function (node) {
|
|
1448
|
-
return reMatch.test(node.title);
|
|
1449
|
-
};
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
1361
|
/*!
|
|
1453
1362
|
* Wunderbaum - ext-keynav
|
|
1454
1363
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1455
|
-
* v0.0.
|
|
1364
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
1456
1365
|
*/
|
|
1457
1366
|
const QUICKSEARCH_DELAY = 500;
|
|
1458
1367
|
class KeynavExtension extends WunderbaumExtension {
|
|
@@ -1486,7 +1395,7 @@
|
|
|
1486
1395
|
const event = data.event, tree = this.tree, opts = data.options, activate = !event.ctrlKey || opts.autoActivate, curInput = this._getEmbeddedInputElem(event.target), navModeOption = opts.navigationModeOption;
|
|
1487
1396
|
// isCellEditMode = tree.navMode === NavigationMode.cellEdit;
|
|
1488
1397
|
let focusNode, eventName = eventToString(event), node = data.node, handled = true;
|
|
1489
|
-
tree.log(`onKeyEvent: ${eventName}, curInput`, curInput);
|
|
1398
|
+
// tree.log(`onKeyEvent: ${eventName}, curInput`, curInput);
|
|
1490
1399
|
if (!tree.isEnabled()) {
|
|
1491
1400
|
// tree.logDebug(`onKeyEvent ignored for disabled tree: ${eventName}`);
|
|
1492
1401
|
return false;
|
|
@@ -1609,10 +1518,11 @@
|
|
|
1609
1518
|
if (eventName === "Escape") {
|
|
1610
1519
|
// Discard changes
|
|
1611
1520
|
node.render();
|
|
1521
|
+
// } else if (!INPUT_BREAKOUT_KEYS.has(eventName)) {
|
|
1612
1522
|
}
|
|
1613
|
-
else if (
|
|
1523
|
+
else if (eventName !== "Enter") {
|
|
1614
1524
|
// Let current `<input>` handle it
|
|
1615
|
-
node.logDebug(`Ignored ${eventName} inside input`);
|
|
1525
|
+
node.logDebug(`Ignored ${eventName} inside focused input`);
|
|
1616
1526
|
return;
|
|
1617
1527
|
}
|
|
1618
1528
|
// const curInputType = curInput.type || curInput.tagName;
|
|
@@ -1683,24 +1593,24 @@
|
|
|
1683
1593
|
if (isColspan && node.isExpanded()) {
|
|
1684
1594
|
node.setExpanded(false);
|
|
1685
1595
|
}
|
|
1686
|
-
else if (tree.activeColIdx > 0) {
|
|
1596
|
+
else if (!isColspan && tree.activeColIdx > 0) {
|
|
1687
1597
|
tree.setColumn(tree.activeColIdx - 1);
|
|
1688
|
-
handled = true;
|
|
1689
1598
|
}
|
|
1690
1599
|
else if (navModeOption !== NavigationOptions.cell) {
|
|
1691
1600
|
tree.setCellNav(false); // row-nav mode
|
|
1692
|
-
handled = true;
|
|
1693
1601
|
}
|
|
1602
|
+
handled = true;
|
|
1694
1603
|
break;
|
|
1695
1604
|
case "ArrowRight":
|
|
1696
1605
|
tree.setFocus(); // Blur prev. input if any
|
|
1697
1606
|
if (isColspan && !node.isExpanded()) {
|
|
1698
1607
|
node.setExpanded();
|
|
1699
1608
|
}
|
|
1700
|
-
else if (
|
|
1609
|
+
else if (!isColspan &&
|
|
1610
|
+
tree.activeColIdx < tree.columns.length - 1) {
|
|
1701
1611
|
tree.setColumn(tree.activeColIdx + 1);
|
|
1702
|
-
handled = true;
|
|
1703
1612
|
}
|
|
1613
|
+
handled = true;
|
|
1704
1614
|
break;
|
|
1705
1615
|
case "ArrowDown":
|
|
1706
1616
|
case "ArrowUp":
|
|
@@ -1733,7 +1643,7 @@
|
|
|
1733
1643
|
/*!
|
|
1734
1644
|
* Wunderbaum - ext-logger
|
|
1735
1645
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1736
|
-
* v0.0.
|
|
1646
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
1737
1647
|
*/
|
|
1738
1648
|
class LoggerExtension extends WunderbaumExtension {
|
|
1739
1649
|
constructor(tree) {
|
|
@@ -1756,7 +1666,7 @@
|
|
|
1756
1666
|
if (ignoreEvents.has(name)) {
|
|
1757
1667
|
return tree._superApply(arguments);
|
|
1758
1668
|
}
|
|
1759
|
-
|
|
1669
|
+
const start = Date.now();
|
|
1760
1670
|
const res = tree._superApply(arguments);
|
|
1761
1671
|
console.debug(`${prefix}: callEvent('${name}') took ${Date.now() - start} ms.`, arguments[1]);
|
|
1762
1672
|
return res;
|
|
@@ -1770,10 +1680,250 @@
|
|
|
1770
1680
|
}
|
|
1771
1681
|
}
|
|
1772
1682
|
|
|
1683
|
+
/*!
|
|
1684
|
+
* Wunderbaum - common
|
|
1685
|
+
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1686
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
1687
|
+
*/
|
|
1688
|
+
const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
|
|
1689
|
+
/**
|
|
1690
|
+
* Fixed height of a row in pixel. Must match the SCSS variable `$row-outer-height`.
|
|
1691
|
+
*/
|
|
1692
|
+
const ROW_HEIGHT = 22;
|
|
1693
|
+
/**
|
|
1694
|
+
* Fixed width of node icons in pixel. Must match the SCSS variable `$icon-outer-width`.
|
|
1695
|
+
*/
|
|
1696
|
+
const ICON_WIDTH = 20;
|
|
1697
|
+
/**
|
|
1698
|
+
* Adjust the width of the title span, so overflow ellipsis work.
|
|
1699
|
+
* (2 x `$col-padding-x` + 3px rounding errors).
|
|
1700
|
+
*/
|
|
1701
|
+
const TITLE_SPAN_PAD_Y = 7;
|
|
1702
|
+
/** Render row markup for N nodes above and below the visible viewport. */
|
|
1703
|
+
const RENDER_MAX_PREFETCH = 5;
|
|
1704
|
+
/** Regular expression to detect if a string describes an image URL (in contrast
|
|
1705
|
+
* to a class name). Strings are considered image urls if they contain '.' or '/'.
|
|
1706
|
+
*/
|
|
1707
|
+
const TEST_IMG = new RegExp(/\.|\//);
|
|
1708
|
+
// export const RECURSIVE_REQUEST_ERROR = "$recursive_request";
|
|
1709
|
+
// export const INVALID_REQUEST_TARGET_ERROR = "$request_target_invalid";
|
|
1710
|
+
/**
|
|
1711
|
+
* Default node icons.
|
|
1712
|
+
* Requires bootstrap icons https://icons.getbootstrap.com
|
|
1713
|
+
*/
|
|
1714
|
+
const iconMap = {
|
|
1715
|
+
error: "bi bi-exclamation-triangle",
|
|
1716
|
+
// loading: "bi bi-hourglass-split wb-busy",
|
|
1717
|
+
loading: "bi bi-chevron-right wb-busy",
|
|
1718
|
+
// loading: "bi bi-arrow-repeat wb-spin",
|
|
1719
|
+
// loading: '<div class="spinner-border spinner-border-sm" role="status"> <span class="visually-hidden">Loading...</span> </div>',
|
|
1720
|
+
// noData: "bi bi-search",
|
|
1721
|
+
noData: "bi bi-question-circle",
|
|
1722
|
+
expanderExpanded: "bi bi-chevron-down",
|
|
1723
|
+
// expanderExpanded: "bi bi-dash-square",
|
|
1724
|
+
expanderCollapsed: "bi bi-chevron-right",
|
|
1725
|
+
// expanderCollapsed: "bi bi-plus-square",
|
|
1726
|
+
expanderLazy: "bi bi-chevron-right wb-helper-lazy-expander",
|
|
1727
|
+
// expanderLazy: "bi bi-chevron-bar-right",
|
|
1728
|
+
checkChecked: "bi bi-check-square",
|
|
1729
|
+
checkUnchecked: "bi bi-square",
|
|
1730
|
+
checkUnknown: "bi dash-square-dotted",
|
|
1731
|
+
radioChecked: "bi bi-circle-fill",
|
|
1732
|
+
radioUnchecked: "bi bi-circle",
|
|
1733
|
+
radioUnknown: "bi bi-circle-dotted",
|
|
1734
|
+
folder: "bi bi-folder2",
|
|
1735
|
+
folderOpen: "bi bi-folder2-open",
|
|
1736
|
+
folderLazy: "bi bi-folder-symlink",
|
|
1737
|
+
doc: "bi bi-file-earmark",
|
|
1738
|
+
};
|
|
1739
|
+
/** Dict keys that are evaluated by source loader (others are added to `tree.data` instead). */
|
|
1740
|
+
const RESERVED_TREE_SOURCE_KEYS = new Set([
|
|
1741
|
+
"_format",
|
|
1742
|
+
"_keyMap",
|
|
1743
|
+
"_positional",
|
|
1744
|
+
"_typeList",
|
|
1745
|
+
"_version",
|
|
1746
|
+
"children",
|
|
1747
|
+
"columns",
|
|
1748
|
+
"types",
|
|
1749
|
+
]);
|
|
1750
|
+
// /** Key codes that trigger grid navigation, even when inside an input element. */
|
|
1751
|
+
// export const INPUT_BREAKOUT_KEYS: Set<string> = new Set([
|
|
1752
|
+
// // "ArrowDown",
|
|
1753
|
+
// // "ArrowUp",
|
|
1754
|
+
// "Enter",
|
|
1755
|
+
// "Escape",
|
|
1756
|
+
// ]);
|
|
1757
|
+
/** Map `KeyEvent.key` to navigation action. */
|
|
1758
|
+
const KEY_TO_ACTION_DICT = {
|
|
1759
|
+
" ": "toggleSelect",
|
|
1760
|
+
"+": "expand",
|
|
1761
|
+
Add: "expand",
|
|
1762
|
+
ArrowDown: "down",
|
|
1763
|
+
ArrowLeft: "left",
|
|
1764
|
+
ArrowRight: "right",
|
|
1765
|
+
ArrowUp: "up",
|
|
1766
|
+
Backspace: "parent",
|
|
1767
|
+
"/": "collapseAll",
|
|
1768
|
+
Divide: "collapseAll",
|
|
1769
|
+
End: "lastCol",
|
|
1770
|
+
Home: "firstCol",
|
|
1771
|
+
"Control+End": "last",
|
|
1772
|
+
"Control+Home": "first",
|
|
1773
|
+
"Meta+ArrowDown": "last",
|
|
1774
|
+
"Meta+ArrowUp": "first",
|
|
1775
|
+
"*": "expandAll",
|
|
1776
|
+
Multiply: "expandAll",
|
|
1777
|
+
PageDown: "pageDown",
|
|
1778
|
+
PageUp: "pageUp",
|
|
1779
|
+
"-": "collapse",
|
|
1780
|
+
Subtract: "collapse",
|
|
1781
|
+
};
|
|
1782
|
+
/** Return a callback that returns true if the node title matches the string
|
|
1783
|
+
* or regular expression.
|
|
1784
|
+
* @see {@link WunderbaumNode.findAll}
|
|
1785
|
+
*/
|
|
1786
|
+
function makeNodeTitleMatcher(match) {
|
|
1787
|
+
if (match instanceof RegExp) {
|
|
1788
|
+
return function (node) {
|
|
1789
|
+
return match.test(node.title);
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
assert(typeof match === "string");
|
|
1793
|
+
// s = escapeRegex(s.toLowerCase());
|
|
1794
|
+
return function (node) {
|
|
1795
|
+
return node.title === match;
|
|
1796
|
+
// console.log("match " + node, node.title.toLowerCase().indexOf(match))
|
|
1797
|
+
// return node.title.toLowerCase().indexOf(match) >= 0;
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
/** Return a callback that returns true if the node title starts with a string (case-insensitive). */
|
|
1801
|
+
function makeNodeTitleStartMatcher(s) {
|
|
1802
|
+
s = escapeRegex(s);
|
|
1803
|
+
const reMatch = new RegExp("^" + s, "i");
|
|
1804
|
+
return function (node) {
|
|
1805
|
+
return reMatch.test(node.title);
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
function unflattenSource(source) {
|
|
1809
|
+
var _a, _b, _c;
|
|
1810
|
+
const { _format, _keyMap, _positional, children } = source;
|
|
1811
|
+
if (_format !== "flat") {
|
|
1812
|
+
throw new Error(`Expected source._format: "flat", but got ${_format}`);
|
|
1813
|
+
}
|
|
1814
|
+
if (_positional && _positional.includes("children")) {
|
|
1815
|
+
throw new Error(`source._positional must not include "children": ${_positional}`);
|
|
1816
|
+
}
|
|
1817
|
+
// Inverse keyMap:
|
|
1818
|
+
let longToShort = {};
|
|
1819
|
+
if (_keyMap) {
|
|
1820
|
+
for (const [key, value] of Object.entries(_keyMap)) {
|
|
1821
|
+
longToShort[value] = key;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
const positionalShort = _positional.map((e) => longToShort[e]);
|
|
1825
|
+
const newChildren = [];
|
|
1826
|
+
const keyToNodeMap = {};
|
|
1827
|
+
const indexToNodeMap = {};
|
|
1828
|
+
const keyAttrName = (_a = longToShort["key"]) !== null && _a !== void 0 ? _a : "key";
|
|
1829
|
+
const childrenAttrName = (_b = longToShort["children"]) !== null && _b !== void 0 ? _b : "children";
|
|
1830
|
+
for (const [index, node] of children.entries()) {
|
|
1831
|
+
// Node entry format:
|
|
1832
|
+
// [PARENT_ID, [POSITIONAL_ARGS]]
|
|
1833
|
+
// or
|
|
1834
|
+
// [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}]
|
|
1835
|
+
const [parentId, args, kwargs = {}] = node;
|
|
1836
|
+
// Free up some memory as we go
|
|
1837
|
+
node[1] = null;
|
|
1838
|
+
if (node[2] != null) {
|
|
1839
|
+
node[2] = null;
|
|
1840
|
+
}
|
|
1841
|
+
// console.log("flatten", parentId, args, kwargs)
|
|
1842
|
+
// We keep `kwargs` as our new node definition. Then we add all positional
|
|
1843
|
+
// values to this object:
|
|
1844
|
+
args.forEach((val, positionalIdx) => {
|
|
1845
|
+
kwargs[positionalShort[positionalIdx]] = val;
|
|
1846
|
+
});
|
|
1847
|
+
// Find the parent node. `null` means 'toplevel'. PARENT_ID may be the numeric
|
|
1848
|
+
// index of the source.children list. If PARENT_ID is a string, we search
|
|
1849
|
+
// a parent with node.key of this value.
|
|
1850
|
+
indexToNodeMap[index] = kwargs;
|
|
1851
|
+
const key = kwargs[keyAttrName];
|
|
1852
|
+
if (key != null) {
|
|
1853
|
+
keyToNodeMap[key] = kwargs;
|
|
1854
|
+
}
|
|
1855
|
+
let parentNode = null;
|
|
1856
|
+
if (parentId === null) ;
|
|
1857
|
+
else if (typeof parentId === "number") {
|
|
1858
|
+
parentNode = indexToNodeMap[parentId];
|
|
1859
|
+
if (parentNode === undefined) {
|
|
1860
|
+
throw new Error(`unflattenSource: Could not find parent node by index: ${parentId}.`);
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
else {
|
|
1864
|
+
parentNode = keyToNodeMap[parentId];
|
|
1865
|
+
if (parentNode === undefined) {
|
|
1866
|
+
throw new Error(`unflattenSource: Could not find parent node by key: ${parentId}`);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
if (parentNode) {
|
|
1870
|
+
(_c = parentNode[childrenAttrName]) !== null && _c !== void 0 ? _c : (parentNode[childrenAttrName] = []);
|
|
1871
|
+
parentNode[childrenAttrName].push(kwargs);
|
|
1872
|
+
}
|
|
1873
|
+
else {
|
|
1874
|
+
newChildren.push(kwargs);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
delete source.children;
|
|
1878
|
+
source.children = newChildren;
|
|
1879
|
+
}
|
|
1880
|
+
function inflateSourceData(source) {
|
|
1881
|
+
const { _format, _keyMap, _typeList } = source;
|
|
1882
|
+
if (_format === "flat") {
|
|
1883
|
+
unflattenSource(source);
|
|
1884
|
+
}
|
|
1885
|
+
delete source._format;
|
|
1886
|
+
delete source._version;
|
|
1887
|
+
delete source._keyMap;
|
|
1888
|
+
delete source._typeList;
|
|
1889
|
+
delete source._positional;
|
|
1890
|
+
function _iter(childList) {
|
|
1891
|
+
for (let node of childList) {
|
|
1892
|
+
// Expand short alias names
|
|
1893
|
+
if (_keyMap) {
|
|
1894
|
+
// Iterate over a list of names, because we modify inside the loop:
|
|
1895
|
+
Object.getOwnPropertyNames(node).forEach((propName) => {
|
|
1896
|
+
var _a;
|
|
1897
|
+
const long = (_a = _keyMap[propName]) !== null && _a !== void 0 ? _a : propName;
|
|
1898
|
+
if (long !== propName) {
|
|
1899
|
+
node[long] = node[propName];
|
|
1900
|
+
delete node[propName];
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
// `node` now has long attribute names
|
|
1905
|
+
// Resolve node type indexes
|
|
1906
|
+
const type = node.type;
|
|
1907
|
+
if (_typeList && type != null && typeof type === "number") {
|
|
1908
|
+
const newType = _typeList[type];
|
|
1909
|
+
if (newType == null) {
|
|
1910
|
+
throw new Error(`Expected typeList[${type}] entry in [${_typeList}]`);
|
|
1911
|
+
}
|
|
1912
|
+
node.type = newType;
|
|
1913
|
+
}
|
|
1914
|
+
// Recursion
|
|
1915
|
+
if (node.children) {
|
|
1916
|
+
_iter(node.children);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
_iter(source.children);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1773
1923
|
/*!
|
|
1774
1924
|
* Wunderbaum - ext-dnd
|
|
1775
1925
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1776
|
-
* v0.0.
|
|
1926
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
1777
1927
|
*/
|
|
1778
1928
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
1779
1929
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -2041,7 +2191,7 @@
|
|
|
2041
2191
|
/*!
|
|
2042
2192
|
* Wunderbaum - drag_observer
|
|
2043
2193
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2044
|
-
* v0.0.
|
|
2194
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
2045
2195
|
*/
|
|
2046
2196
|
/**
|
|
2047
2197
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2175,7 +2325,7 @@
|
|
|
2175
2325
|
/*!
|
|
2176
2326
|
* Wunderbaum - ext-grid
|
|
2177
2327
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2178
|
-
* v0.0.
|
|
2328
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
2179
2329
|
*/
|
|
2180
2330
|
class GridExtension extends WunderbaumExtension {
|
|
2181
2331
|
constructor(tree) {
|
|
@@ -2212,7 +2362,7 @@
|
|
|
2212
2362
|
/*!
|
|
2213
2363
|
* Wunderbaum - deferred
|
|
2214
2364
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2215
|
-
* v0.0.
|
|
2365
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
2216
2366
|
*/
|
|
2217
2367
|
/**
|
|
2218
2368
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -2265,7 +2415,7 @@
|
|
|
2265
2415
|
/*!
|
|
2266
2416
|
* Wunderbaum - wunderbaum_node
|
|
2267
2417
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2268
|
-
* v0.0.
|
|
2418
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
2269
2419
|
*/
|
|
2270
2420
|
/** Top-level properties that can be passed with `data`. */
|
|
2271
2421
|
const NODE_PROPS = new Set([
|
|
@@ -2406,57 +2556,63 @@
|
|
|
2406
2556
|
/**
|
|
2407
2557
|
* Append (or insert) a list of child nodes.
|
|
2408
2558
|
*
|
|
2409
|
-
* Tip: pass `{ before: 0 }` to prepend children
|
|
2410
|
-
*
|
|
2411
|
-
* @param child node (or key or index of such).
|
|
2412
|
-
* If omitted, the new children are appended.
|
|
2559
|
+
* Tip: pass `{ before: 0 }` to prepend new nodes as first children.
|
|
2560
|
+
*
|
|
2413
2561
|
* @returns first child added
|
|
2414
2562
|
*/
|
|
2415
2563
|
addChildren(nodeData, options) {
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
//
|
|
2420
|
-
|
|
2564
|
+
const tree = this.tree;
|
|
2565
|
+
let { before = null, applyMinExpanLevel = true, _level } = options !== null && options !== void 0 ? options : {};
|
|
2566
|
+
// let { before, loadLazy=true, _level } = options ?? {};
|
|
2567
|
+
// const isTopCall = _level == null;
|
|
2568
|
+
_level !== null && _level !== void 0 ? _level : (_level = this.getLevel());
|
|
2569
|
+
const nodeList = [];
|
|
2421
2570
|
try {
|
|
2422
|
-
|
|
2571
|
+
tree.enableUpdate(false);
|
|
2423
2572
|
if (isPlainObject(nodeData)) {
|
|
2424
2573
|
nodeData = [nodeData];
|
|
2425
2574
|
}
|
|
2575
|
+
const forceExpand = applyMinExpanLevel && _level < tree.options.minExpandLevel;
|
|
2426
2576
|
for (let child of nodeData) {
|
|
2427
|
-
|
|
2577
|
+
const subChildren = child.children;
|
|
2428
2578
|
delete child.children;
|
|
2429
|
-
|
|
2579
|
+
const n = new WunderbaumNode(tree, this, child);
|
|
2580
|
+
if (forceExpand && !n.isUnloaded()) {
|
|
2581
|
+
n.expanded = true;
|
|
2582
|
+
}
|
|
2430
2583
|
nodeList.push(n);
|
|
2431
2584
|
if (subChildren) {
|
|
2432
|
-
n.addChildren(subChildren, {
|
|
2585
|
+
n.addChildren(subChildren, { _level: _level + 1 });
|
|
2433
2586
|
}
|
|
2434
2587
|
}
|
|
2435
2588
|
if (!this.children) {
|
|
2436
2589
|
this.children = nodeList;
|
|
2437
2590
|
}
|
|
2438
|
-
else if (
|
|
2591
|
+
else if (before == null || this.children.length === 0) {
|
|
2439
2592
|
this.children = this.children.concat(nodeList);
|
|
2440
2593
|
}
|
|
2441
2594
|
else {
|
|
2442
|
-
// Returns null if
|
|
2443
|
-
|
|
2444
|
-
let pos = this.children.indexOf(
|
|
2445
|
-
assert(pos >= 0,
|
|
2595
|
+
// Returns null if before is not a direct child:
|
|
2596
|
+
before = this.findDirectChild(before);
|
|
2597
|
+
let pos = this.children.indexOf(before);
|
|
2598
|
+
assert(pos >= 0, `options.before must be a direct child of ${this}`);
|
|
2446
2599
|
// insert nodeList after children[pos]
|
|
2447
2600
|
this.children.splice(pos, 0, ...nodeList);
|
|
2448
2601
|
}
|
|
2449
2602
|
// TODO:
|
|
2450
|
-
// if (
|
|
2603
|
+
// if (tree.options.selectMode === 3) {
|
|
2451
2604
|
// this.fixSelection3FromEndNodes();
|
|
2452
2605
|
// }
|
|
2453
2606
|
// this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null);
|
|
2454
|
-
|
|
2455
|
-
return nodeList[0];
|
|
2607
|
+
tree.setModified(ChangeType.structure);
|
|
2456
2608
|
}
|
|
2457
2609
|
finally {
|
|
2458
|
-
|
|
2610
|
+
tree.enableUpdate(true);
|
|
2459
2611
|
}
|
|
2612
|
+
// if(isTopCall && loadLazy){
|
|
2613
|
+
// this.logWarn("addChildren(): loadLazy is not yet implemented.")
|
|
2614
|
+
// }
|
|
2615
|
+
return nodeList[0];
|
|
2460
2616
|
}
|
|
2461
2617
|
/**
|
|
2462
2618
|
* Append or prepend a node, or append a child node.
|
|
@@ -2530,21 +2686,98 @@
|
|
|
2530
2686
|
}
|
|
2531
2687
|
}
|
|
2532
2688
|
}
|
|
2533
|
-
/** Call `setExpanded()` on
|
|
2534
|
-
async expandAll(flag = true) {
|
|
2535
|
-
this.
|
|
2536
|
-
|
|
2537
|
-
}
|
|
2689
|
+
/** Call `setExpanded()` on all descendant nodes. */
|
|
2690
|
+
async expandAll(flag = true, options) {
|
|
2691
|
+
const tree = this.tree;
|
|
2692
|
+
const minExpandLevel = this.tree.options.minExpandLevel;
|
|
2693
|
+
let { depth = 99, loadLazy, force } = options !== null && options !== void 0 ? options : {};
|
|
2694
|
+
const expand_opts = {
|
|
2695
|
+
scrollIntoView: false,
|
|
2696
|
+
force: force,
|
|
2697
|
+
loadLazy: loadLazy,
|
|
2698
|
+
};
|
|
2699
|
+
// this.logInfo(`expandAll(${flag})`);
|
|
2700
|
+
// Expand all direct children in parallel:
|
|
2701
|
+
async function _iter(n, level) {
|
|
2702
|
+
var _a;
|
|
2703
|
+
// n.logInfo(` _iter(${level})`);
|
|
2704
|
+
if (level === 0) {
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
// if (!flag && minExpandLevel && !force && n.getLevel() <= minExpandLevel) {
|
|
2708
|
+
// return; // Do not collapse until minExpandLevel
|
|
2709
|
+
// }
|
|
2710
|
+
const level_1 = level == null ? null : level - 1;
|
|
2711
|
+
const promises = [];
|
|
2712
|
+
(_a = n.children) === null || _a === void 0 ? void 0 : _a.forEach((cn) => {
|
|
2713
|
+
if (flag) {
|
|
2714
|
+
if (!cn.expanded && (cn.children || (loadLazy && cn.lazy))) {
|
|
2715
|
+
// Node is collapsed and may be expanded (i.e. has children or is lazy)
|
|
2716
|
+
// Expanding may be async, so we store the promise.
|
|
2717
|
+
// Also the recursion is delayed until expansion finished.
|
|
2718
|
+
const p = cn.setExpanded(true, expand_opts);
|
|
2719
|
+
promises.push(p);
|
|
2720
|
+
p.then(async () => {
|
|
2721
|
+
await _iter(cn, level_1);
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
else {
|
|
2725
|
+
// We don't expand the node, but still visit descendants.
|
|
2726
|
+
// There we may find lazy nodes, so we
|
|
2727
|
+
promises.push(_iter(cn, level_1));
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
else {
|
|
2731
|
+
// Collapsing is always synchronous, so no promises required
|
|
2732
|
+
if (!minExpandLevel || force || cn.getLevel() > minExpandLevel) {
|
|
2733
|
+
// Do not collapse until minExpandLevel
|
|
2734
|
+
cn.setExpanded(false, expand_opts);
|
|
2735
|
+
}
|
|
2736
|
+
_iter(cn, level_1); // recursion, even if cn was already collapsed
|
|
2737
|
+
}
|
|
2738
|
+
});
|
|
2739
|
+
return new Promise((resolve) => {
|
|
2740
|
+
Promise.all(promises).then(() => {
|
|
2741
|
+
resolve(true);
|
|
2742
|
+
});
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
const tag = tree.logTime(`${this}.expandAll(${flag})`);
|
|
2746
|
+
try {
|
|
2747
|
+
tree.enableUpdate(false);
|
|
2748
|
+
await _iter(this, depth);
|
|
2749
|
+
}
|
|
2750
|
+
finally {
|
|
2751
|
+
tree.enableUpdate(true);
|
|
2752
|
+
tree.logTimeEnd(tag);
|
|
2753
|
+
}
|
|
2538
2754
|
}
|
|
2539
|
-
/**
|
|
2755
|
+
/**
|
|
2756
|
+
* Find all descendant nodes that match condition (excluding self).
|
|
2540
2757
|
*
|
|
2541
|
-
*
|
|
2542
|
-
*
|
|
2758
|
+
* If `match` is a string, search for exact node title.
|
|
2759
|
+
* If `match` is a RegExp expression, apply it to node.title, using
|
|
2760
|
+
* [RegExp.test()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test).
|
|
2761
|
+
* If `match` is a callback, match all nodes for that the callback(node) returns true.
|
|
2762
|
+
*
|
|
2763
|
+
* Returns an empty array if no nodes were found.
|
|
2764
|
+
*
|
|
2765
|
+
* Examples:
|
|
2766
|
+
* ```js
|
|
2767
|
+
* // Match all node titles that match exactly 'Joe':
|
|
2768
|
+
* nodeList = node.findAll("Joe")
|
|
2769
|
+
* // Match all node titles that start with 'Joe' case sensitive:
|
|
2770
|
+
* nodeList = node.findAll(/^Joe/)
|
|
2771
|
+
* // Match all node titles that contain 'oe', case insensitive:
|
|
2772
|
+
* nodeList = node.findAll(/oe/i)
|
|
2773
|
+
* // Match all nodes with `data.price` >= 99:
|
|
2774
|
+
* nodeList = node.findAll((n) => {
|
|
2775
|
+
* return n.data.price >= 99;
|
|
2776
|
+
* })
|
|
2777
|
+
* ```
|
|
2543
2778
|
*/
|
|
2544
2779
|
findAll(match) {
|
|
2545
|
-
const matcher =
|
|
2546
|
-
? match
|
|
2547
|
-
: makeNodeTitleMatcher(match);
|
|
2780
|
+
const matcher = typeof match === "function" ? match : makeNodeTitleMatcher(match);
|
|
2548
2781
|
const res = [];
|
|
2549
2782
|
this.visit((n) => {
|
|
2550
2783
|
if (matcher(n)) {
|
|
@@ -2574,15 +2807,13 @@
|
|
|
2574
2807
|
}
|
|
2575
2808
|
return null;
|
|
2576
2809
|
}
|
|
2577
|
-
/**
|
|
2810
|
+
/**
|
|
2811
|
+
* Find first descendant node that matches condition (excluding self) or null.
|
|
2578
2812
|
*
|
|
2579
|
-
* @
|
|
2580
|
-
* callback function that returns `true` if a node is matched.
|
|
2813
|
+
* @see {@link WunderbaumNode.findAll} for examples.
|
|
2581
2814
|
*/
|
|
2582
2815
|
findFirst(match) {
|
|
2583
|
-
const matcher =
|
|
2584
|
-
? match
|
|
2585
|
-
: makeNodeTitleMatcher(match);
|
|
2816
|
+
const matcher = typeof match === "function" ? match : makeNodeTitleMatcher(match);
|
|
2586
2817
|
let res = null;
|
|
2587
2818
|
this.visit((n) => {
|
|
2588
2819
|
if (matcher(n)) {
|
|
@@ -2746,7 +2977,8 @@
|
|
|
2746
2977
|
* an expand operation is currently possible.
|
|
2747
2978
|
*/
|
|
2748
2979
|
isExpandable(andCollapsed = false) {
|
|
2749
|
-
return !!this.children && (!this.expanded || !andCollapsed);
|
|
2980
|
+
// return !!this.children && (!this.expanded || !andCollapsed);
|
|
2981
|
+
return !!(this.children || this.lazy) && (!this.expanded || !andCollapsed);
|
|
2750
2982
|
}
|
|
2751
2983
|
/** Return true if this node is currently in edit-title mode. */
|
|
2752
2984
|
isEditing() {
|
|
@@ -2847,14 +3079,20 @@
|
|
|
2847
3079
|
// this.debug("isVisible: VISIBLE");
|
|
2848
3080
|
return true;
|
|
2849
3081
|
}
|
|
2850
|
-
_loadSourceObject(source) {
|
|
3082
|
+
_loadSourceObject(source, level) {
|
|
3083
|
+
var _a;
|
|
2851
3084
|
const tree = this.tree;
|
|
3085
|
+
level !== null && level !== void 0 ? level : (level = this.getLevel());
|
|
2852
3086
|
// Let caller modify the parsed JSON response:
|
|
2853
3087
|
this._callEvent("receive", { response: source });
|
|
2854
3088
|
if (isArray(source)) {
|
|
2855
3089
|
source = { children: source };
|
|
2856
3090
|
}
|
|
2857
3091
|
assert(isPlainObject(source));
|
|
3092
|
+
const format = (_a = source.format) !== null && _a !== void 0 ? _a : "nested";
|
|
3093
|
+
assert(format === "nested" || format === "flat");
|
|
3094
|
+
// Pre-rocess for 'nested' or 'flat' format
|
|
3095
|
+
inflateSourceData(source);
|
|
2858
3096
|
assert(source.children, "If `source` is an object, it must have a `children` property");
|
|
2859
3097
|
if (source.types) {
|
|
2860
3098
|
tree.logInfo("Redefine types", source.columns);
|
|
@@ -2868,7 +3106,6 @@
|
|
|
2868
3106
|
tree.updateColumns({ calculateCols: false });
|
|
2869
3107
|
}
|
|
2870
3108
|
this.addChildren(source.children);
|
|
2871
|
-
delete source.columns;
|
|
2872
3109
|
// Add extra data to `tree.data`
|
|
2873
3110
|
for (const [key, value] of Object.entries(source)) {
|
|
2874
3111
|
if (!RESERVED_TREE_SOURCE_KEYS.has(key)) {
|
|
@@ -3015,17 +3252,16 @@
|
|
|
3015
3252
|
}
|
|
3016
3253
|
/** Expand all parents and optionally scroll into visible area as neccessary.
|
|
3017
3254
|
* Promise is resolved, when lazy loading and animations are done.
|
|
3018
|
-
* @param {object} [
|
|
3255
|
+
* @param {object} [options] passed to `setExpanded()`.
|
|
3019
3256
|
* Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true}
|
|
3020
3257
|
*/
|
|
3021
|
-
async makeVisible(
|
|
3022
|
-
let i, dfd = new Deferred(), deferreds = [], parents = this.getParentList(false, false), len = parents.length,
|
|
3023
|
-
//
|
|
3024
|
-
scroll = !(opts && opts.scrollIntoView === false);
|
|
3258
|
+
async makeVisible(options) {
|
|
3259
|
+
let i, dfd = new Deferred(), deferreds = [], parents = this.getParentList(false, false), len = parents.length, noAnimation = getOption(options, "noAnimation", false), scroll = getOption(options, "scrollIntoView", true);
|
|
3260
|
+
// scroll = !(options && options.scrollIntoView === false);
|
|
3025
3261
|
// Expand bottom-up, so only the top node is animated
|
|
3026
3262
|
for (i = len - 1; i >= 0; i--) {
|
|
3027
3263
|
// self.debug("pushexpand" + parents[i]);
|
|
3028
|
-
const seOpts = { noAnimation:
|
|
3264
|
+
const seOpts = { noAnimation: noAnimation };
|
|
3029
3265
|
deferreds.push(parents[i].setExpanded(true, seOpts));
|
|
3030
3266
|
}
|
|
3031
3267
|
Promise.all(deferreds).then(() => {
|
|
@@ -3267,6 +3503,9 @@
|
|
|
3267
3503
|
else if (this.children) {
|
|
3268
3504
|
icon = iconMap.folder;
|
|
3269
3505
|
}
|
|
3506
|
+
else if (this.lazy) {
|
|
3507
|
+
icon = iconMap.folderLazy;
|
|
3508
|
+
}
|
|
3270
3509
|
else {
|
|
3271
3510
|
icon = iconMap.doc;
|
|
3272
3511
|
}
|
|
@@ -3430,13 +3669,13 @@
|
|
|
3430
3669
|
if (isColspan) {
|
|
3431
3670
|
let vpWidth = tree.element.clientWidth;
|
|
3432
3671
|
titleSpan.style.width =
|
|
3433
|
-
vpWidth - nodeElem._ofsTitlePx -
|
|
3672
|
+
vpWidth - nodeElem._ofsTitlePx - TITLE_SPAN_PAD_Y + "px";
|
|
3434
3673
|
}
|
|
3435
3674
|
else {
|
|
3436
3675
|
titleSpan.style.width =
|
|
3437
3676
|
columns[0]._widthPx -
|
|
3438
3677
|
nodeElem._ofsTitlePx -
|
|
3439
|
-
|
|
3678
|
+
TITLE_SPAN_PAD_Y +
|
|
3440
3679
|
"px";
|
|
3441
3680
|
}
|
|
3442
3681
|
}
|
|
@@ -3749,22 +3988,32 @@
|
|
|
3749
3988
|
* Expand or collapse this node.
|
|
3750
3989
|
*/
|
|
3751
3990
|
async setExpanded(flag = true, options) {
|
|
3991
|
+
const { force, scrollIntoView, immediate } = options !== null && options !== void 0 ? options : {};
|
|
3752
3992
|
if (!flag &&
|
|
3753
3993
|
this.isExpanded() &&
|
|
3754
3994
|
this.getLevel() <= this.tree.getOption("minExpandLevel") &&
|
|
3755
|
-
!
|
|
3995
|
+
!force) {
|
|
3756
3996
|
this.logDebug("Ignored collapse request below expandLevel.");
|
|
3757
3997
|
return;
|
|
3758
3998
|
}
|
|
3759
3999
|
if (!flag === !this.expanded) {
|
|
3760
4000
|
return; // Nothing to do
|
|
3761
4001
|
}
|
|
4002
|
+
// this.log("setExpanded()");
|
|
3762
4003
|
if (flag && this.lazy && this.children == null) {
|
|
3763
4004
|
await this.loadLazy();
|
|
3764
4005
|
}
|
|
3765
4006
|
this.expanded = flag;
|
|
3766
|
-
const updateOpts = { immediate:
|
|
4007
|
+
const updateOpts = { immediate: immediate };
|
|
4008
|
+
// const updateOpts = { immediate: !!util.getOption(options, "immediate") };
|
|
3767
4009
|
this.tree.setModified(ChangeType.structure, updateOpts);
|
|
4010
|
+
if (flag && scrollIntoView !== false) {
|
|
4011
|
+
const lastChild = this.getLastChild();
|
|
4012
|
+
if (lastChild) {
|
|
4013
|
+
this.tree.updatePendingModifications();
|
|
4014
|
+
lastChild.scrollIntoView({ topNode: this });
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
3768
4017
|
}
|
|
3769
4018
|
/**
|
|
3770
4019
|
* Set keyboard focus here.
|
|
@@ -3993,7 +4242,7 @@
|
|
|
3993
4242
|
/*!
|
|
3994
4243
|
* Wunderbaum - ext-edit
|
|
3995
4244
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
3996
|
-
* v0.0.
|
|
4245
|
+
* v0.0.8, Fri, 23 Sep 2022 20:47:29 GMT (https://github.com/mar10/wunderbaum)
|
|
3997
4246
|
*/
|
|
3998
4247
|
// const START_MARKER = "\uFFF7";
|
|
3999
4248
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -4139,8 +4388,9 @@
|
|
|
4139
4388
|
node.logInfo("beforeEdit canceled operation.");
|
|
4140
4389
|
return;
|
|
4141
4390
|
}
|
|
4142
|
-
// `beforeEdit(e)` may return an input HTML string. Otherwise use a default
|
|
4143
|
-
|
|
4391
|
+
// `beforeEdit(e)` may return an input HTML string. Otherwise use a default.
|
|
4392
|
+
// (we also treat a `true` return value as 'use default'):
|
|
4393
|
+
if (inputHtml === true || !inputHtml) {
|
|
4144
4394
|
const title = escapeHtml(node.title);
|
|
4145
4395
|
inputHtml = `<input type=text class="wb-input-edit" value="${title}" required autocorrect=off>`;
|
|
4146
4396
|
}
|
|
@@ -4285,8 +4535,8 @@
|
|
|
4285
4535
|
* https://github.com/mar10/wunderbaum
|
|
4286
4536
|
*
|
|
4287
4537
|
* Released under the MIT license.
|
|
4288
|
-
* @version v0.0.
|
|
4289
|
-
* @date
|
|
4538
|
+
* @version v0.0.8
|
|
4539
|
+
* @date Fri, 23 Sep 2022 20:47:29 GMT
|
|
4290
4540
|
*/
|
|
4291
4541
|
class WbSystemRoot extends WunderbaumNode {
|
|
4292
4542
|
constructor(tree) {
|
|
@@ -4857,22 +5107,22 @@
|
|
|
4857
5107
|
* - 'down', 'first', 'last', 'left', 'parent', 'right', 'up': navigate
|
|
4858
5108
|
*
|
|
4859
5109
|
*/
|
|
4860
|
-
applyCommand(cmd, nodeOrOpts,
|
|
5110
|
+
applyCommand(cmd, nodeOrOpts, options) {
|
|
4861
5111
|
let // clipboard,
|
|
4862
5112
|
node, refNode;
|
|
4863
|
-
//
|
|
5113
|
+
// options = $.extend(
|
|
4864
5114
|
// { setActive: true, clipboard: CLIPBOARD },
|
|
4865
|
-
//
|
|
5115
|
+
// options_
|
|
4866
5116
|
// );
|
|
4867
5117
|
if (nodeOrOpts instanceof WunderbaumNode) {
|
|
4868
5118
|
node = nodeOrOpts;
|
|
4869
5119
|
}
|
|
4870
5120
|
else {
|
|
4871
5121
|
node = this.getActiveNode();
|
|
4872
|
-
assert(
|
|
4873
|
-
|
|
5122
|
+
assert(options === undefined);
|
|
5123
|
+
options = nodeOrOpts;
|
|
4874
5124
|
}
|
|
4875
|
-
// clipboard =
|
|
5125
|
+
// clipboard = options.clipboard;
|
|
4876
5126
|
switch (cmd) {
|
|
4877
5127
|
// Sorting and indentation:
|
|
4878
5128
|
case "moveUp":
|
|
@@ -5078,16 +5328,8 @@
|
|
|
5078
5328
|
}
|
|
5079
5329
|
}
|
|
5080
5330
|
/** Recursively expand all expandable nodes (triggers lazy load id needed). */
|
|
5081
|
-
async expandAll(flag = true) {
|
|
5082
|
-
|
|
5083
|
-
try {
|
|
5084
|
-
this.enableUpdate(false);
|
|
5085
|
-
await this.root.expandAll(flag);
|
|
5086
|
-
}
|
|
5087
|
-
finally {
|
|
5088
|
-
this.enableUpdate(true);
|
|
5089
|
-
this.logTimeEnd(tag);
|
|
5090
|
-
}
|
|
5331
|
+
async expandAll(flag = true, options) {
|
|
5332
|
+
await this.root.expandAll(flag, options);
|
|
5091
5333
|
}
|
|
5092
5334
|
/** Recursively select all nodes. */
|
|
5093
5335
|
selectAll(flag = true) {
|
|
@@ -5121,10 +5363,7 @@
|
|
|
5121
5363
|
// util.assert(this.keyMap.size === i);
|
|
5122
5364
|
}
|
|
5123
5365
|
/**
|
|
5124
|
-
* Find all nodes that
|
|
5125
|
-
*
|
|
5126
|
-
* @param match title string to search for, or a
|
|
5127
|
-
* callback function that returns `true` if a node is matched.
|
|
5366
|
+
* Find all nodes that match condition.
|
|
5128
5367
|
*
|
|
5129
5368
|
* @see {@link WunderbaumNode.findAll}
|
|
5130
5369
|
*/
|
|
@@ -5134,10 +5373,7 @@
|
|
|
5134
5373
|
/**
|
|
5135
5374
|
* Find first node that matches condition.
|
|
5136
5375
|
*
|
|
5137
|
-
* @param match title string to search for, or a
|
|
5138
|
-
* callback function that returns `true` if a node is matched.
|
|
5139
5376
|
* @see {@link WunderbaumNode.findFirst}
|
|
5140
|
-
*
|
|
5141
5377
|
*/
|
|
5142
5378
|
findFirst(match) {
|
|
5143
5379
|
return this.root.findFirst(match);
|
|
@@ -5151,7 +5387,7 @@
|
|
|
5151
5387
|
*
|
|
5152
5388
|
*/
|
|
5153
5389
|
findKey(key) {
|
|
5154
|
-
return this.keyMap.get(key);
|
|
5390
|
+
return this.keyMap.get(key) || null;
|
|
5155
5391
|
}
|
|
5156
5392
|
/**
|
|
5157
5393
|
* Find the next visible node that starts with `match`, starting at `startNode`
|
|
@@ -5440,17 +5676,20 @@
|
|
|
5440
5676
|
}
|
|
5441
5677
|
/**
|
|
5442
5678
|
* Make sure that this node is vertically scrolled into the viewport.
|
|
5679
|
+
*
|
|
5680
|
+
* Nodes that are above the visible area become the top row, nodes that are
|
|
5681
|
+
* below the viewport become the bottom row.
|
|
5443
5682
|
*/
|
|
5444
5683
|
scrollTo(nodeOrOpts) {
|
|
5445
5684
|
const PADDING = 2; // leave some pixels between viewport bounds
|
|
5446
5685
|
let node;
|
|
5447
|
-
let
|
|
5686
|
+
let options;
|
|
5448
5687
|
if (nodeOrOpts instanceof WunderbaumNode) {
|
|
5449
5688
|
node = nodeOrOpts;
|
|
5450
5689
|
}
|
|
5451
5690
|
else {
|
|
5452
|
-
|
|
5453
|
-
node =
|
|
5691
|
+
options = nodeOrOpts;
|
|
5692
|
+
node = options.node;
|
|
5454
5693
|
}
|
|
5455
5694
|
assert(node && node._rowIdx != null);
|
|
5456
5695
|
const scrollParent = this.element;
|
|
@@ -5461,6 +5700,7 @@
|
|
|
5461
5700
|
const vpTop = headerHeight;
|
|
5462
5701
|
const vpRowTop = rowTop - scrollTop;
|
|
5463
5702
|
const vpRowBottom = vpRowTop + ROW_HEIGHT;
|
|
5703
|
+
const topNode = options === null || options === void 0 ? void 0 : options.topNode;
|
|
5464
5704
|
// this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts );
|
|
5465
5705
|
let newScrollTop = null;
|
|
5466
5706
|
if (vpRowTop >= vpTop) {
|
|
@@ -5468,17 +5708,21 @@
|
|
|
5468
5708
|
else {
|
|
5469
5709
|
// Node is below viewport
|
|
5470
5710
|
// this.log("Below viewport");
|
|
5471
|
-
newScrollTop = rowTop + ROW_HEIGHT - vpHeight + PADDING; // leave some pixels between
|
|
5711
|
+
newScrollTop = rowTop + ROW_HEIGHT - vpHeight + PADDING; // leave some pixels between viewport bounds
|
|
5472
5712
|
}
|
|
5473
5713
|
}
|
|
5474
5714
|
else {
|
|
5475
5715
|
// Node is above viewport
|
|
5476
5716
|
// this.log("Above viewport");
|
|
5477
|
-
newScrollTop = rowTop - vpTop - PADDING; // leave some pixels between
|
|
5717
|
+
newScrollTop = rowTop - vpTop - PADDING; // leave some pixels between viewport bounds
|
|
5478
5718
|
}
|
|
5479
5719
|
if (newScrollTop != null) {
|
|
5480
5720
|
this.log(`scrollTo(${rowTop}): ${scrollTop} => ${newScrollTop}`);
|
|
5481
5721
|
scrollParent.scrollTop = newScrollTop;
|
|
5722
|
+
if (topNode) {
|
|
5723
|
+
// Make sure the topNode is always visible
|
|
5724
|
+
this.scrollTo(topNode);
|
|
5725
|
+
}
|
|
5482
5726
|
// this.setModified(ChangeType.vscroll);
|
|
5483
5727
|
}
|
|
5484
5728
|
}
|
|
@@ -5507,10 +5751,9 @@
|
|
|
5507
5751
|
newLeft = colRight - vpWidth;
|
|
5508
5752
|
}
|
|
5509
5753
|
// util.assert(node._rowIdx != null);
|
|
5510
|
-
//
|
|
5511
|
-
|
|
5512
|
-
//
|
|
5513
|
-
// let newLeft;
|
|
5754
|
+
// this.log(
|
|
5755
|
+
// `scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`
|
|
5756
|
+
// );
|
|
5514
5757
|
this.element.scrollLeft = newLeft;
|
|
5515
5758
|
// this.setModified(ChangeType.vscroll);
|
|
5516
5759
|
// }
|
|
@@ -5701,11 +5944,13 @@
|
|
|
5701
5944
|
}
|
|
5702
5945
|
}
|
|
5703
5946
|
/** Update column headers and width. */
|
|
5704
|
-
updateColumns(
|
|
5705
|
-
|
|
5947
|
+
updateColumns(options) {
|
|
5948
|
+
options = Object.assign({ calculateCols: true, updateRows: true }, options);
|
|
5706
5949
|
const defaultMinWidth = 4;
|
|
5707
5950
|
const vpWidth = this.element.clientWidth;
|
|
5708
5951
|
const isGrid = this.isGrid();
|
|
5952
|
+
// Shorten last column width to avoid h-scrollbar
|
|
5953
|
+
const FIX_ADJUST_LAST_COL = 2;
|
|
5709
5954
|
let totalWidth = 0;
|
|
5710
5955
|
let totalWeight = 0;
|
|
5711
5956
|
let fixedWidth = 0;
|
|
@@ -5714,7 +5959,7 @@
|
|
|
5714
5959
|
if (!isGrid && this.isCellNav()) {
|
|
5715
5960
|
this.setCellNav(false);
|
|
5716
5961
|
}
|
|
5717
|
-
if (
|
|
5962
|
+
if (options.calculateCols) {
|
|
5718
5963
|
// Gather width definitions
|
|
5719
5964
|
this._columnsById = {};
|
|
5720
5965
|
for (let col of this.columns) {
|
|
@@ -5766,7 +6011,8 @@
|
|
|
5766
6011
|
col._ofsPx = ofsPx;
|
|
5767
6012
|
ofsPx += col._widthPx;
|
|
5768
6013
|
}
|
|
5769
|
-
|
|
6014
|
+
this.columns[this.columns.length - 1]._widthPx -= FIX_ADJUST_LAST_COL;
|
|
6015
|
+
totalWidth = ofsPx - FIX_ADJUST_LAST_COL;
|
|
5770
6016
|
}
|
|
5771
6017
|
// if (this.options.fixedCol) {
|
|
5772
6018
|
// 'position: fixed' requires that the content has the correct size
|
|
@@ -5780,7 +6026,7 @@
|
|
|
5780
6026
|
// util.error("BREAK");
|
|
5781
6027
|
if (modified) {
|
|
5782
6028
|
this._renderHeaderMarkup();
|
|
5783
|
-
if (
|
|
6029
|
+
if (options.updateRows) {
|
|
5784
6030
|
this._updateRows();
|
|
5785
6031
|
}
|
|
5786
6032
|
}
|
|
@@ -5843,6 +6089,8 @@
|
|
|
5843
6089
|
*/
|
|
5844
6090
|
_updateViewportImmediately() {
|
|
5845
6091
|
var _a;
|
|
6092
|
+
// Shorten container height to avoid v-scrollbar
|
|
6093
|
+
const FIX_ADJUST_HEIGHT = 1;
|
|
5846
6094
|
if (this._disableUpdateCount) {
|
|
5847
6095
|
this.log(`IGNORED _updateViewportImmediately() disable level: ${this._disableUpdateCount}`);
|
|
5848
6096
|
return;
|
|
@@ -5856,7 +6104,7 @@
|
|
|
5856
6104
|
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
5857
6105
|
// const headerHeight = this.options.headerHeightPx;
|
|
5858
6106
|
const headerHeight = this.headerElement.clientHeight; // May be 0
|
|
5859
|
-
const wantHeight = this.element.clientHeight - headerHeight;
|
|
6107
|
+
const wantHeight = this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
|
|
5860
6108
|
if (Math.abs(height - wantHeight) > 1.0) {
|
|
5861
6109
|
// this.log("resize", height, wantHeight);
|
|
5862
6110
|
this.scrollContainerElement.style.height = wantHeight + "px";
|
|
@@ -5913,14 +6161,15 @@
|
|
|
5913
6161
|
* (including upper and lower prefetch)
|
|
5914
6162
|
* -
|
|
5915
6163
|
*/
|
|
5916
|
-
_updateRows(
|
|
6164
|
+
_updateRows(options) {
|
|
5917
6165
|
// const label = this.logTime("_updateRows");
|
|
5918
6166
|
// this.log("_updateRows", opts)
|
|
5919
|
-
|
|
5920
|
-
const newNodesOnly = !!
|
|
6167
|
+
options = Object.assign({ newNodesOnly: false }, options);
|
|
6168
|
+
const newNodesOnly = !!options.newNodesOnly;
|
|
5921
6169
|
const row_height = ROW_HEIGHT;
|
|
5922
6170
|
const vp_height = this.element.clientHeight;
|
|
5923
6171
|
const prefetch = RENDER_MAX_PREFETCH;
|
|
6172
|
+
// const grace_prefetch = RENDER_MAX_PREFETCH - RENDER_MIN_PREFETCH;
|
|
5924
6173
|
const ofs = this.element.scrollTop;
|
|
5925
6174
|
let startIdx = Math.max(0, ofs / row_height - prefetch);
|
|
5926
6175
|
startIdx = Math.floor(startIdx);
|
|
@@ -6019,16 +6268,16 @@
|
|
|
6019
6268
|
* {start: First tree node, reverse: false, includeSelf: true, includeHidden: false, wrap: false}
|
|
6020
6269
|
* @returns {boolean} false if iteration was canceled
|
|
6021
6270
|
*/
|
|
6022
|
-
visitRows(callback,
|
|
6271
|
+
visitRows(callback, options) {
|
|
6023
6272
|
if (!this.root.hasChildren()) {
|
|
6024
6273
|
return false;
|
|
6025
6274
|
}
|
|
6026
|
-
if (
|
|
6027
|
-
delete
|
|
6028
|
-
return this._visitRowsUp(callback,
|
|
6275
|
+
if (options && options.reverse) {
|
|
6276
|
+
delete options.reverse;
|
|
6277
|
+
return this._visitRowsUp(callback, options);
|
|
6029
6278
|
}
|
|
6030
|
-
|
|
6031
|
-
let i, nextIdx, parent, res, siblings, stopNode, siblingOfs = 0, skipFirstNode =
|
|
6279
|
+
options = options || {};
|
|
6280
|
+
let i, nextIdx, parent, res, siblings, stopNode, siblingOfs = 0, skipFirstNode = options.includeSelf === false, includeHidden = !!options.includeHidden, checkFilter = !includeHidden && this.filterMode === "hide", node = options.start || this.root.children[0];
|
|
6032
6281
|
parent = node.parent;
|
|
6033
6282
|
while (parent) {
|
|
6034
6283
|
// visit siblings
|
|
@@ -6077,11 +6326,11 @@
|
|
|
6077
6326
|
node = parent;
|
|
6078
6327
|
parent = parent.parent;
|
|
6079
6328
|
siblingOfs = 1; //
|
|
6080
|
-
if (!parent &&
|
|
6329
|
+
if (!parent && options.wrap) {
|
|
6081
6330
|
this.logDebug("visitRows(): wrap around");
|
|
6082
|
-
assert(
|
|
6083
|
-
stopNode =
|
|
6084
|
-
|
|
6331
|
+
assert(options.start, "`wrap` option requires `start`");
|
|
6332
|
+
stopNode = options.start;
|
|
6333
|
+
options.wrap = false;
|
|
6085
6334
|
parent = this.root;
|
|
6086
6335
|
siblingOfs = 0;
|
|
6087
6336
|
}
|
|
@@ -6216,7 +6465,7 @@
|
|
|
6216
6465
|
}
|
|
6217
6466
|
Wunderbaum.sequence = 0;
|
|
6218
6467
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
6219
|
-
Wunderbaum.version = "v0.0.
|
|
6468
|
+
Wunderbaum.version = "v0.0.8"; // Set to semver by 'grunt release'
|
|
6220
6469
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
6221
6470
|
Wunderbaum.util = util;
|
|
6222
6471
|
|