wunderbaum 0.0.4 → 0.0.5
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 +2 -0
- package/dist/wunderbaum.css +1 -1
- package/dist/wunderbaum.d.ts +141 -45
- package/dist/wunderbaum.esm.js +439 -184
- package/dist/wunderbaum.esm.min.js +25 -24
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +439 -184
- package/dist/wunderbaum.umd.min.js +30 -29
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +2 -2
- package/src/common.ts +35 -27
- package/src/util.ts +11 -9
- package/src/wb_ext_dnd.ts +10 -9
- package/src/wb_ext_edit.ts +9 -10
- package/src/wb_ext_filter.ts +14 -2
- package/src/wb_ext_keynav.ts +80 -13
- package/src/wb_node.ts +53 -35
- package/src/wb_options.ts +59 -5
- package/src/wunderbaum.scss +91 -23
- package/src/wunderbaum.ts +276 -100
package/dist/wunderbaum.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Wunderbaum - util
|
|
3
3
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
4
|
-
* v0.0.
|
|
4
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
5
5
|
*/
|
|
6
6
|
/** @module util */
|
|
7
7
|
/** Readable names for `MouseEvent.button` */
|
|
@@ -173,7 +173,7 @@ function extractHtmlText(s) {
|
|
|
173
173
|
*
|
|
174
174
|
* If a `<span class="wb-col">` is passed, the first child input is used.
|
|
175
175
|
* Depending on the target element type, `value` is interpreted accordingly.
|
|
176
|
-
* For example for a checkbox, a value of true, false, or null is returned if
|
|
176
|
+
* For example for a checkbox, a value of true, false, or null is returned if
|
|
177
177
|
* the element is checked, unchecked, or indeterminate.
|
|
178
178
|
* For datetime input control a numerical value is assumed, etc.
|
|
179
179
|
*
|
|
@@ -269,7 +269,9 @@ function setValueToElem(elem, value) {
|
|
|
269
269
|
const type = input.type;
|
|
270
270
|
switch (type) {
|
|
271
271
|
case "checkbox":
|
|
272
|
-
|
|
272
|
+
// An explicit `null` value is interpreted as 'indeterminate'.
|
|
273
|
+
// `undefined` is interpreted as 'unchecked'
|
|
274
|
+
input.indeterminate = value === null;
|
|
273
275
|
input.checked = !!value;
|
|
274
276
|
break;
|
|
275
277
|
case "date":
|
|
@@ -565,7 +567,7 @@ function toSet(val) {
|
|
|
565
567
|
}
|
|
566
568
|
throw new Error("Cannot convert to Set<string>: " + val);
|
|
567
569
|
}
|
|
568
|
-
/**Return a canonical string representation for an object's type (e.g. 'array', 'number', ...) */
|
|
570
|
+
/** Return a canonical string representation for an object's type (e.g. 'array', 'number', ...). */
|
|
569
571
|
function type(obj) {
|
|
570
572
|
return Object.prototype.toString
|
|
571
573
|
.call(obj)
|
|
@@ -579,12 +581,12 @@ function type(obj) {
|
|
|
579
581
|
* previous call.
|
|
580
582
|
* Example:
|
|
581
583
|
* ```js
|
|
582
|
-
* throttledFoo = util.
|
|
584
|
+
* throttledFoo = util.adaptiveThrottle(foo.bind(this), {});
|
|
583
585
|
* throttledFoo();
|
|
584
586
|
* throttledFoo();
|
|
585
587
|
* ```
|
|
586
588
|
*/
|
|
587
|
-
function
|
|
589
|
+
function adaptiveThrottle(callback, options) {
|
|
588
590
|
let waiting = 0; // Initially, we're not waiting
|
|
589
591
|
let pendingArgs = null;
|
|
590
592
|
const opts = Object.assign({
|
|
@@ -598,7 +600,7 @@ function addaptiveThrottle(callback, options) {
|
|
|
598
600
|
const throttledFn = (...args) => {
|
|
599
601
|
if (waiting) {
|
|
600
602
|
pendingArgs = args;
|
|
601
|
-
// console.log(`
|
|
603
|
+
// console.log(`adaptiveThrottle() queing request #${waiting}...`, args);
|
|
602
604
|
waiting += 1;
|
|
603
605
|
}
|
|
604
606
|
else {
|
|
@@ -606,7 +608,7 @@ function addaptiveThrottle(callback, options) {
|
|
|
606
608
|
waiting = 1;
|
|
607
609
|
const useArgs = args; // pendingArgs || args;
|
|
608
610
|
pendingArgs = null;
|
|
609
|
-
// console.log(`
|
|
611
|
+
// console.log(`adaptiveThrottle() execute...`, useArgs);
|
|
610
612
|
const start = Date.now();
|
|
611
613
|
try {
|
|
612
614
|
callback.apply(this, useArgs);
|
|
@@ -618,7 +620,7 @@ function addaptiveThrottle(callback, options) {
|
|
|
618
620
|
const curDelay = Math.min(Math.max(minDelay, elap * opts.delayFactor), maxDelay);
|
|
619
621
|
const useDelay = Math.max(minDelay, curDelay - elap);
|
|
620
622
|
// console.log(
|
|
621
|
-
// `
|
|
623
|
+
// `adaptiveThrottle() calling worker took ${elap}ms. delay = ${curDelay}ms, using ${useDelay}ms`,
|
|
622
624
|
// pendingArgs
|
|
623
625
|
// );
|
|
624
626
|
setTimeout(() => {
|
|
@@ -628,7 +630,7 @@ function addaptiveThrottle(callback, options) {
|
|
|
628
630
|
if (pendingArgs != null) {
|
|
629
631
|
// There was another request while running or waiting
|
|
630
632
|
// console.log(
|
|
631
|
-
// `
|
|
633
|
+
// `adaptiveThrottle() re-trigger (missed ${skipped})...`,
|
|
632
634
|
// pendingArgs
|
|
633
635
|
// );
|
|
634
636
|
throttledFn.apply(this, pendingArgs);
|
|
@@ -674,13 +676,13 @@ var util = /*#__PURE__*/Object.freeze({
|
|
|
674
676
|
getOption: getOption,
|
|
675
677
|
toSet: toSet,
|
|
676
678
|
type: type,
|
|
677
|
-
|
|
679
|
+
adaptiveThrottle: adaptiveThrottle
|
|
678
680
|
});
|
|
679
681
|
|
|
680
682
|
/*!
|
|
681
683
|
* Wunderbaum - common
|
|
682
684
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
683
|
-
* v0.0.
|
|
685
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
684
686
|
*/
|
|
685
687
|
const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
|
|
686
688
|
const ROW_HEIGHT = 22;
|
|
@@ -688,6 +690,7 @@ const ICON_WIDTH = 20;
|
|
|
688
690
|
const ROW_EXTRA_PAD = 7; // 2x $col-padding-x + 3px rounding errors
|
|
689
691
|
const RENDER_MAX_PREFETCH = 5;
|
|
690
692
|
const TEST_IMG = new RegExp(/\.|\//); // strings are considered image urls if they contain '.' or '/'
|
|
693
|
+
/** Possible values for `setModified()`. */
|
|
691
694
|
var ChangeType;
|
|
692
695
|
(function (ChangeType) {
|
|
693
696
|
/** Re-render the whole viewport, headers, and all rows. */
|
|
@@ -705,6 +708,7 @@ var ChangeType;
|
|
|
705
708
|
/** Update the 'top' property of all rows. */
|
|
706
709
|
ChangeType["vscroll"] = "vscroll";
|
|
707
710
|
})(ChangeType || (ChangeType = {}));
|
|
711
|
+
/** Possible values for `setStatus()`. */
|
|
708
712
|
var NodeStatusType;
|
|
709
713
|
(function (NodeStatusType) {
|
|
710
714
|
NodeStatusType["ok"] = "ok";
|
|
@@ -713,7 +717,7 @@ var NodeStatusType;
|
|
|
713
717
|
NodeStatusType["noData"] = "noData";
|
|
714
718
|
// paging = "paging",
|
|
715
719
|
})(NodeStatusType || (NodeStatusType = {}));
|
|
716
|
-
/**Define the subregion of a node, where an event occurred. */
|
|
720
|
+
/** Define the subregion of a node, where an event occurred. */
|
|
717
721
|
var TargetType;
|
|
718
722
|
(function (TargetType) {
|
|
719
723
|
TargetType["unknown"] = "";
|
|
@@ -726,8 +730,9 @@ var TargetType;
|
|
|
726
730
|
})(TargetType || (TargetType = {}));
|
|
727
731
|
let iconMap = {
|
|
728
732
|
error: "bi bi-exclamation-triangle",
|
|
729
|
-
// loading: "bi bi-hourglass-split",
|
|
730
|
-
loading: "bi bi-
|
|
733
|
+
// loading: "bi bi-hourglass-split wb-busy",
|
|
734
|
+
loading: "bi bi-chevron-right wb-busy",
|
|
735
|
+
// loading: "bi bi-arrow-repeat wb-spin",
|
|
731
736
|
// loading: '<div class="spinner-border spinner-border-sm" role="status"> <span class="visually-hidden">Loading...</span> </div>',
|
|
732
737
|
// noData: "bi bi-search",
|
|
733
738
|
noData: "bi bi-question-circle",
|
|
@@ -747,6 +752,7 @@ let iconMap = {
|
|
|
747
752
|
folderOpen: "bi bi-folder2-open",
|
|
748
753
|
doc: "bi bi-file-earmark",
|
|
749
754
|
};
|
|
755
|
+
/** Initial navigation mode and possible transition. */
|
|
750
756
|
var NavigationModeOption;
|
|
751
757
|
(function (NavigationModeOption) {
|
|
752
758
|
NavigationModeOption["startRow"] = "startRow";
|
|
@@ -754,6 +760,7 @@ var NavigationModeOption;
|
|
|
754
760
|
NavigationModeOption["startCell"] = "startCell";
|
|
755
761
|
NavigationModeOption["row"] = "row";
|
|
756
762
|
})(NavigationModeOption || (NavigationModeOption = {}));
|
|
763
|
+
/** Tree's current navigation mode (see `tree.setNavigationMode()`). */
|
|
757
764
|
var NavigationMode;
|
|
758
765
|
(function (NavigationMode) {
|
|
759
766
|
NavigationMode["row"] = "row";
|
|
@@ -785,14 +792,14 @@ const KEY_TO_ACTION_DICT = {
|
|
|
785
792
|
"-": "collapse",
|
|
786
793
|
Subtract: "collapse",
|
|
787
794
|
};
|
|
788
|
-
/** */
|
|
795
|
+
/** Return a callback that returns true if the node title contains a substring (case-insensitive). */
|
|
789
796
|
function makeNodeTitleMatcher(s) {
|
|
790
797
|
s = escapeRegex(s.toLowerCase());
|
|
791
798
|
return function (node) {
|
|
792
799
|
return node.title.toLowerCase().indexOf(s) >= 0;
|
|
793
800
|
};
|
|
794
801
|
}
|
|
795
|
-
/** */
|
|
802
|
+
/** Return a callback that returns true if the node title starts with a string (case-insensitive). */
|
|
796
803
|
function makeNodeTitleStartMatcher(s) {
|
|
797
804
|
s = escapeRegex(s);
|
|
798
805
|
const reMatch = new RegExp("^" + s, "i");
|
|
@@ -804,7 +811,7 @@ function makeNodeTitleStartMatcher(s) {
|
|
|
804
811
|
/*!
|
|
805
812
|
* Wunderbaum - wb_extension_base
|
|
806
813
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
807
|
-
* v0.0.
|
|
814
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
808
815
|
*/
|
|
809
816
|
class WunderbaumExtension {
|
|
810
817
|
constructor(tree, id, defaults) {
|
|
@@ -1095,7 +1102,7 @@ function debounce(func, wait = 0, options = {}) {
|
|
|
1095
1102
|
/*!
|
|
1096
1103
|
* Wunderbaum - ext-filter
|
|
1097
1104
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1098
|
-
* v0.0.
|
|
1105
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1099
1106
|
*/
|
|
1100
1107
|
const START_MARKER = "\uFFF7";
|
|
1101
1108
|
const END_MARKER = "\uFFF8";
|
|
@@ -1104,6 +1111,7 @@ const RE_END_MARTKER = new RegExp(escapeRegex(END_MARKER), "g");
|
|
|
1104
1111
|
class FilterExtension extends WunderbaumExtension {
|
|
1105
1112
|
constructor(tree) {
|
|
1106
1113
|
super(tree, "filter", {
|
|
1114
|
+
attachInput: null,
|
|
1107
1115
|
autoApply: true,
|
|
1108
1116
|
autoExpand: false,
|
|
1109
1117
|
counter: true,
|
|
@@ -1112,14 +1120,14 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1112
1120
|
hideExpanders: false,
|
|
1113
1121
|
highlight: true,
|
|
1114
1122
|
leavesOnly: false,
|
|
1115
|
-
mode: "
|
|
1123
|
+
mode: "dim",
|
|
1116
1124
|
noData: true, // Display a 'no data' status node if result is empty
|
|
1117
1125
|
});
|
|
1118
1126
|
this.lastFilterArgs = null;
|
|
1119
1127
|
}
|
|
1120
1128
|
init() {
|
|
1121
1129
|
super.init();
|
|
1122
|
-
|
|
1130
|
+
const attachInput = this.getPluginOption("attachInput");
|
|
1123
1131
|
if (attachInput) {
|
|
1124
1132
|
this.queryInput = elemFromSelector(attachInput);
|
|
1125
1133
|
onEvent(this.queryInput, "input", debounce((e) => {
|
|
@@ -1128,6 +1136,16 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1128
1136
|
}, 700));
|
|
1129
1137
|
}
|
|
1130
1138
|
}
|
|
1139
|
+
setPluginOption(name, value) {
|
|
1140
|
+
// alert("filter opt=" + name + ", " + value)
|
|
1141
|
+
super.setPluginOption(name, value);
|
|
1142
|
+
switch (name) {
|
|
1143
|
+
case "mode":
|
|
1144
|
+
this.tree.filterMode = value === "hide" ? "hide" : "dim";
|
|
1145
|
+
this.tree.updateFilter();
|
|
1146
|
+
break;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1131
1149
|
_applyFilterNoUpdate(filter, branchMode, _opts) {
|
|
1132
1150
|
return this.tree.runWithoutUpdate(() => {
|
|
1133
1151
|
return this._applyFilterImpl(filter, branchMode, _opts);
|
|
@@ -1389,16 +1407,39 @@ function _markFuzzyMatchedChars(text, matches, escapeTitles = true) {
|
|
|
1389
1407
|
/*!
|
|
1390
1408
|
* Wunderbaum - ext-keynav
|
|
1391
1409
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1392
|
-
* v0.0.
|
|
1410
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1393
1411
|
*/
|
|
1394
1412
|
class KeynavExtension extends WunderbaumExtension {
|
|
1395
1413
|
constructor(tree) {
|
|
1396
1414
|
super(tree, "keynav", {});
|
|
1397
1415
|
}
|
|
1416
|
+
_getEmbeddedInputElem(elem, setFocus = false) {
|
|
1417
|
+
var _a;
|
|
1418
|
+
let input = null;
|
|
1419
|
+
if (elem && elem.type != null) {
|
|
1420
|
+
input = elem;
|
|
1421
|
+
}
|
|
1422
|
+
else {
|
|
1423
|
+
// ,[contenteditable]
|
|
1424
|
+
const ace = (_a = this.tree.getActiveColElem()) === null || _a === void 0 ? void 0 : _a.querySelector("input,select");
|
|
1425
|
+
if (ace) {
|
|
1426
|
+
input = ace;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
if (setFocus && input) {
|
|
1430
|
+
this.tree.log("focus", input);
|
|
1431
|
+
input.focus();
|
|
1432
|
+
}
|
|
1433
|
+
return input;
|
|
1434
|
+
}
|
|
1398
1435
|
onKeyEvent(data) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
tree.
|
|
1436
|
+
const event = data.event, tree = this.tree, opts = data.options, activate = !event.ctrlKey || opts.autoActivate, curInput = this._getEmbeddedInputElem(event.target), navModeOption = opts.navigationMode, isCellEditMode = tree.navMode === NavigationMode.cellEdit;
|
|
1437
|
+
let focusNode, eventName = eventToString(event), node = data.node, handled = true;
|
|
1438
|
+
tree.log(`onKeyEvent: ${eventName}, curInput`, curInput);
|
|
1439
|
+
if (!tree.isEnabled()) {
|
|
1440
|
+
// tree.logDebug(`onKeyEvent ignored for disabled tree: ${eventName}`);
|
|
1441
|
+
return false;
|
|
1442
|
+
}
|
|
1402
1443
|
// Let callback prevent default processing
|
|
1403
1444
|
if (tree._callEvent("keydown", data) === false) {
|
|
1404
1445
|
return false;
|
|
@@ -1424,12 +1465,14 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1424
1465
|
}
|
|
1425
1466
|
}
|
|
1426
1467
|
if (tree.navMode === NavigationMode.row) {
|
|
1468
|
+
// -----------------------------------------------------------------------
|
|
1469
|
+
// --- Row Mode ---
|
|
1470
|
+
// -----------------------------------------------------------------------
|
|
1427
1471
|
// --- Quick-Search
|
|
1428
1472
|
if (opts.quicksearch &&
|
|
1429
1473
|
eventName.length === 1 &&
|
|
1430
|
-
/^\w$/.test(eventName)
|
|
1431
|
-
|
|
1432
|
-
) {
|
|
1474
|
+
/^\w$/.test(eventName) &&
|
|
1475
|
+
!curInput) {
|
|
1433
1476
|
// Allow to search for longer streaks if typed in quickly
|
|
1434
1477
|
const stamp = Date.now();
|
|
1435
1478
|
if (stamp - tree.lastQuicksearchTime > 500) {
|
|
@@ -1506,7 +1549,18 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1506
1549
|
}
|
|
1507
1550
|
}
|
|
1508
1551
|
else {
|
|
1509
|
-
//
|
|
1552
|
+
// -----------------------------------------------------------------------
|
|
1553
|
+
// --- Cell Mode ---
|
|
1554
|
+
// -----------------------------------------------------------------------
|
|
1555
|
+
// // Standard navigation (cell mode)
|
|
1556
|
+
// if (isCellEditMode && NAVIGATE_IN_INPUT_KEYS.has(eventName)) {
|
|
1557
|
+
// }
|
|
1558
|
+
if (eventName === "Tab") {
|
|
1559
|
+
eventName = "ArrowRight";
|
|
1560
|
+
}
|
|
1561
|
+
else if (eventName === "Shift+Tab") {
|
|
1562
|
+
eventName = tree.activeColIdx > 0 ? "ArrowLeft" : "";
|
|
1563
|
+
}
|
|
1510
1564
|
switch (eventName) {
|
|
1511
1565
|
case " ":
|
|
1512
1566
|
if (tree.activeColIdx === 0 && node.getOption("checkbox")) {
|
|
@@ -1525,13 +1579,21 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1525
1579
|
node.setExpanded(!node.isExpanded());
|
|
1526
1580
|
handled = true;
|
|
1527
1581
|
}
|
|
1582
|
+
else if (!isCellEditMode &&
|
|
1583
|
+
(navModeOption === NavigationModeOption.startCell ||
|
|
1584
|
+
navModeOption === NavigationModeOption.startRow)) {
|
|
1585
|
+
tree.setNavigationMode(NavigationMode.cellEdit);
|
|
1586
|
+
this._getEmbeddedInputElem(null, true); // set focus to input
|
|
1587
|
+
handled = true;
|
|
1588
|
+
}
|
|
1528
1589
|
break;
|
|
1529
1590
|
case "Escape":
|
|
1530
1591
|
if (tree.navMode === NavigationMode.cellEdit) {
|
|
1531
1592
|
tree.setNavigationMode(NavigationMode.cellNav);
|
|
1532
1593
|
handled = true;
|
|
1533
1594
|
}
|
|
1534
|
-
else if (tree.navMode === NavigationMode.cellNav
|
|
1595
|
+
else if (tree.navMode === NavigationMode.cellNav &&
|
|
1596
|
+
navModeOption !== NavigationModeOption.cell) {
|
|
1535
1597
|
tree.setNavigationMode(NavigationMode.row);
|
|
1536
1598
|
handled = true;
|
|
1537
1599
|
}
|
|
@@ -1539,6 +1601,9 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1539
1601
|
case "ArrowLeft":
|
|
1540
1602
|
if (tree.activeColIdx > 0) {
|
|
1541
1603
|
tree.setColumn(tree.activeColIdx - 1);
|
|
1604
|
+
if (isCellEditMode) {
|
|
1605
|
+
this._getEmbeddedInputElem(null, true); // set focus to input
|
|
1606
|
+
}
|
|
1542
1607
|
handled = true;
|
|
1543
1608
|
}
|
|
1544
1609
|
else if (navModeOption !== NavigationModeOption.cell) {
|
|
@@ -1549,6 +1614,9 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1549
1614
|
case "ArrowRight":
|
|
1550
1615
|
if (tree.activeColIdx < tree.columns.length - 1) {
|
|
1551
1616
|
tree.setColumn(tree.activeColIdx + 1);
|
|
1617
|
+
if (isCellEditMode) {
|
|
1618
|
+
this._getEmbeddedInputElem(null, true); // set focus to input
|
|
1619
|
+
}
|
|
1552
1620
|
handled = true;
|
|
1553
1621
|
}
|
|
1554
1622
|
break;
|
|
@@ -1564,6 +1632,10 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1564
1632
|
case "PageDown":
|
|
1565
1633
|
case "PageUp":
|
|
1566
1634
|
node.navigate(eventName, { activate: activate, event: event });
|
|
1635
|
+
if (isCellEditMode) {
|
|
1636
|
+
this._getEmbeddedInputElem(null, true); // set focus to input
|
|
1637
|
+
}
|
|
1638
|
+
handled = true;
|
|
1567
1639
|
break;
|
|
1568
1640
|
default:
|
|
1569
1641
|
handled = false;
|
|
@@ -1579,7 +1651,7 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1579
1651
|
/*!
|
|
1580
1652
|
* Wunderbaum - ext-logger
|
|
1581
1653
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1582
|
-
* v0.0.
|
|
1654
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1583
1655
|
*/
|
|
1584
1656
|
class LoggerExtension extends WunderbaumExtension {
|
|
1585
1657
|
constructor(tree) {
|
|
@@ -1619,7 +1691,7 @@ class LoggerExtension extends WunderbaumExtension {
|
|
|
1619
1691
|
/*!
|
|
1620
1692
|
* Wunderbaum - ext-dnd
|
|
1621
1693
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1622
|
-
* v0.0.
|
|
1694
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1623
1695
|
*/
|
|
1624
1696
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
1625
1697
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -1689,7 +1761,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
1689
1761
|
const ltn = this.lastTargetNode;
|
|
1690
1762
|
this.lastEnterStamp = 0;
|
|
1691
1763
|
if (ltn) {
|
|
1692
|
-
ltn.
|
|
1764
|
+
ltn.setClass("wb-drop-target wb-drop-over wb-drop-after wb-drop-before", false);
|
|
1693
1765
|
this.lastTargetNode = null;
|
|
1694
1766
|
}
|
|
1695
1767
|
}
|
|
@@ -1733,7 +1805,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
1733
1805
|
}
|
|
1734
1806
|
/* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
|
|
1735
1807
|
autoScroll(event) {
|
|
1736
|
-
let tree = this.tree, dndOpts = tree.options.dnd, sp = tree.
|
|
1808
|
+
let tree = this.tree, dndOpts = tree.options.dnd, sp = tree.scrollContainerElement, sensitivity = dndOpts.scrollSensitivity, speed = dndOpts.scrollSpeed, scrolled = 0;
|
|
1737
1809
|
const scrollTop = sp.offsetTop;
|
|
1738
1810
|
if (scrollTop + sp.offsetHeight - event.pageY < sensitivity) {
|
|
1739
1811
|
const delta = sp.scrollHeight - sp.clientHeight - scrollTop;
|
|
@@ -1783,13 +1855,13 @@ class DndExtension extends WunderbaumExtension {
|
|
|
1783
1855
|
setTimeout(() => {
|
|
1784
1856
|
// Decouple this call, so the CSS is applied to the node, but not to
|
|
1785
1857
|
// the system generated drag image
|
|
1786
|
-
srcNode.
|
|
1858
|
+
srcNode.setClass("wb-drag-source");
|
|
1787
1859
|
}, 0);
|
|
1788
1860
|
// --- drag ---
|
|
1789
1861
|
}
|
|
1790
1862
|
else if (e.type === "drag") ;
|
|
1791
1863
|
else if (e.type === "dragend") {
|
|
1792
|
-
srcNode.
|
|
1864
|
+
srcNode.setClass("wb-drag-source", false);
|
|
1793
1865
|
this.srcNode = null;
|
|
1794
1866
|
if (this.lastTargetNode) {
|
|
1795
1867
|
this._leaveNode();
|
|
@@ -1843,7 +1915,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
1843
1915
|
}
|
|
1844
1916
|
this.lastAllowedDropRegions = regionSet;
|
|
1845
1917
|
this.lastDropEffect = dt.dropEffect;
|
|
1846
|
-
targetNode.
|
|
1918
|
+
targetNode.setClass("wb-drop-target");
|
|
1847
1919
|
e.preventDefault(); // Allow drop (Drop operation is denied by default)
|
|
1848
1920
|
return false;
|
|
1849
1921
|
// --- dragover ---
|
|
@@ -1862,9 +1934,9 @@ class DndExtension extends WunderbaumExtension {
|
|
|
1862
1934
|
if (!region) {
|
|
1863
1935
|
return; // We already rejected in dragenter
|
|
1864
1936
|
}
|
|
1865
|
-
targetNode.
|
|
1866
|
-
targetNode.
|
|
1867
|
-
targetNode.
|
|
1937
|
+
targetNode.setClass("wb-drop-over", region === "over");
|
|
1938
|
+
targetNode.setClass("wb-drop-before", region === "before");
|
|
1939
|
+
targetNode.setClass("wb-drop-after", region === "after");
|
|
1868
1940
|
// console.log("dragover", e);
|
|
1869
1941
|
// dt.dropEffect = this.lastDropEffect!;
|
|
1870
1942
|
e.preventDefault(); // Allow drop (Drop operation is denied by default)
|
|
@@ -1887,7 +1959,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
1887
1959
|
/*!
|
|
1888
1960
|
* Wunderbaum - drag_observer
|
|
1889
1961
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1890
|
-
* v0.0.
|
|
1962
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
1891
1963
|
*/
|
|
1892
1964
|
/**
|
|
1893
1965
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2021,7 +2093,7 @@ class DragObserver {
|
|
|
2021
2093
|
/*!
|
|
2022
2094
|
* Wunderbaum - ext-grid
|
|
2023
2095
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2024
|
-
* v0.0.
|
|
2096
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2025
2097
|
*/
|
|
2026
2098
|
class GridExtension extends WunderbaumExtension {
|
|
2027
2099
|
constructor(tree) {
|
|
@@ -2058,7 +2130,7 @@ class GridExtension extends WunderbaumExtension {
|
|
|
2058
2130
|
/*!
|
|
2059
2131
|
* Wunderbaum - deferred
|
|
2060
2132
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2061
|
-
* v0.0.
|
|
2133
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2062
2134
|
*/
|
|
2063
2135
|
/**
|
|
2064
2136
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -2111,7 +2183,7 @@ class Deferred {
|
|
|
2111
2183
|
/*!
|
|
2112
2184
|
* Wunderbaum - wunderbaum_node
|
|
2113
2185
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2114
|
-
* v0.0.
|
|
2186
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
2115
2187
|
*/
|
|
2116
2188
|
/** Top-level properties that can be passed with `data`. */
|
|
2117
2189
|
const NODE_PROPS = new Set([
|
|
@@ -2130,7 +2202,7 @@ const NODE_PROPS = new Set([
|
|
|
2130
2202
|
const NODE_ATTRS = new Set([
|
|
2131
2203
|
"checkbox",
|
|
2132
2204
|
"expanded",
|
|
2133
|
-
"
|
|
2205
|
+
"classes",
|
|
2134
2206
|
"folder",
|
|
2135
2207
|
"icon",
|
|
2136
2208
|
"iconTooltip",
|
|
@@ -2172,8 +2244,8 @@ class WunderbaumNode {
|
|
|
2172
2244
|
* @see {@link isSelected}, {@link setSelected}. */
|
|
2173
2245
|
this.selected = false;
|
|
2174
2246
|
/** Additional classes added to `div.wb-row`.
|
|
2175
|
-
* @see {@link
|
|
2176
|
-
this.
|
|
2247
|
+
* @see {@link hasClass}, {@link setClass}. */
|
|
2248
|
+
this.classes = null; //new Set<string>();
|
|
2177
2249
|
/** Custom data that was passed to the constructor */
|
|
2178
2250
|
this.data = {};
|
|
2179
2251
|
this._isLoading = false;
|
|
@@ -2202,9 +2274,7 @@ class WunderbaumNode {
|
|
|
2202
2274
|
this.lazy = data.lazy === true;
|
|
2203
2275
|
this.selected = data.selected === true;
|
|
2204
2276
|
if (data.classes) {
|
|
2205
|
-
|
|
2206
|
-
this.extraClasses.add(c.trim());
|
|
2207
|
-
}
|
|
2277
|
+
this.setClass(data.classes);
|
|
2208
2278
|
}
|
|
2209
2279
|
// Store custom fields as `node.data`
|
|
2210
2280
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -2222,7 +2292,7 @@ class WunderbaumNode {
|
|
|
2222
2292
|
* @internal
|
|
2223
2293
|
*/
|
|
2224
2294
|
toString() {
|
|
2225
|
-
return
|
|
2295
|
+
return `WunderbaumNode@${this.key}<'${this.title}'>`;
|
|
2226
2296
|
}
|
|
2227
2297
|
// /** Return an option value. */
|
|
2228
2298
|
// protected _getOpt(
|
|
@@ -2344,29 +2414,39 @@ class WunderbaumNode {
|
|
|
2344
2414
|
applyCommand(cmd, opts) {
|
|
2345
2415
|
return this.tree.applyCommand(cmd, this, opts);
|
|
2346
2416
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
const cnSet = toSet(className);
|
|
2357
|
-
cnSet.forEach((cn) => {
|
|
2358
|
-
var _a;
|
|
2359
|
-
this.extraClasses.delete(cn);
|
|
2360
|
-
(_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.classList.remove(cn);
|
|
2361
|
-
});
|
|
2362
|
-
}
|
|
2363
|
-
toggleClass(className, flag) {
|
|
2417
|
+
/**
|
|
2418
|
+
* Add/remove one or more classes to `<div class='wb-row'>`.
|
|
2419
|
+
*
|
|
2420
|
+
* This also maintains `node.classes`, so the class will survive a re-render.
|
|
2421
|
+
*
|
|
2422
|
+
* @param className one or more class names. Multiple classes can be passed
|
|
2423
|
+
* as space-separated string, array of strings, or set of strings.
|
|
2424
|
+
*/
|
|
2425
|
+
setClass(className, flag = true) {
|
|
2364
2426
|
const cnSet = toSet(className);
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2427
|
+
if (flag) {
|
|
2428
|
+
if (this.classes === null) {
|
|
2429
|
+
this.classes = new Set();
|
|
2430
|
+
}
|
|
2431
|
+
cnSet.forEach((cn) => {
|
|
2432
|
+
var _a;
|
|
2433
|
+
this.classes.add(cn);
|
|
2434
|
+
(_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.classList.toggle(cn, flag);
|
|
2435
|
+
});
|
|
2436
|
+
}
|
|
2437
|
+
else {
|
|
2438
|
+
if (this.classes === null) {
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
cnSet.forEach((cn) => {
|
|
2442
|
+
var _a;
|
|
2443
|
+
this.classes.delete(cn);
|
|
2444
|
+
(_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.classList.toggle(cn, flag);
|
|
2445
|
+
});
|
|
2446
|
+
if (this.classes.size === 0) {
|
|
2447
|
+
this.classes = null;
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2370
2450
|
}
|
|
2371
2451
|
/** */
|
|
2372
2452
|
async expandAll(flag = true) {
|
|
@@ -2540,6 +2620,10 @@ class WunderbaumNode {
|
|
|
2540
2620
|
}
|
|
2541
2621
|
return !!(this.children && this.children.length);
|
|
2542
2622
|
}
|
|
2623
|
+
/** Return true if node has className set. */
|
|
2624
|
+
hasClass(className) {
|
|
2625
|
+
return this.classes ? this.classes.has(className) : false;
|
|
2626
|
+
}
|
|
2543
2627
|
/** Return true if this node is the currently active tree node. */
|
|
2544
2628
|
isActive() {
|
|
2545
2629
|
return this.tree.activeNode === this;
|
|
@@ -2685,8 +2769,11 @@ class WunderbaumNode {
|
|
|
2685
2769
|
assert(isPlainObject(source));
|
|
2686
2770
|
assert(source.children, "If `source` is an object, it must have a `children` property");
|
|
2687
2771
|
if (source.types) {
|
|
2688
|
-
|
|
2689
|
-
|
|
2772
|
+
tree.setTypes(source.types, false);
|
|
2773
|
+
}
|
|
2774
|
+
if (source.columns) {
|
|
2775
|
+
tree.columns = source.columns;
|
|
2776
|
+
tree.updateColumns({ calculateCols: false });
|
|
2690
2777
|
}
|
|
2691
2778
|
this.addChildren(source.children);
|
|
2692
2779
|
this._callEvent("load");
|
|
@@ -3282,8 +3369,8 @@ class WunderbaumNode {
|
|
|
3282
3369
|
treeOptions.skeleton ? rowClasses.push("wb-skeleton") : 0;
|
|
3283
3370
|
// Replace previous classes:
|
|
3284
3371
|
rowDiv.className = rowClasses.join(" ");
|
|
3285
|
-
// Add classes from `node.
|
|
3286
|
-
rowDiv.classList.add(...this.
|
|
3372
|
+
// Add classes from `node.classes`
|
|
3373
|
+
this.classes ? rowDiv.classList.add(...this.classes) : 0;
|
|
3287
3374
|
// Add classes from `tree.types[node.type]`
|
|
3288
3375
|
if (typeInfo && typeInfo.classes) {
|
|
3289
3376
|
rowDiv.classList.add(...typeInfo.classes);
|
|
@@ -3678,9 +3765,9 @@ class WunderbaumNode {
|
|
|
3678
3765
|
* @param {object} [extra]
|
|
3679
3766
|
*/
|
|
3680
3767
|
triggerModify(operation, extra) {
|
|
3681
|
-
if (!this.parent) {
|
|
3682
|
-
|
|
3683
|
-
}
|
|
3768
|
+
// if (!this.parent) {
|
|
3769
|
+
// return;
|
|
3770
|
+
// }
|
|
3684
3771
|
this.parent.triggerModifyChild(operation, this, extra);
|
|
3685
3772
|
}
|
|
3686
3773
|
/**
|
|
@@ -3763,7 +3850,7 @@ WunderbaumNode.sequence = 0;
|
|
|
3763
3850
|
/*!
|
|
3764
3851
|
* Wunderbaum - ext-edit
|
|
3765
3852
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
3766
|
-
* v0.0.
|
|
3853
|
+
* v0.0.5, Sun, 21 Aug 2022 15:04:31 GMT (https://github.com/mar10/wunderbaum)
|
|
3767
3854
|
*/
|
|
3768
3855
|
// const START_MARKER = "\uFFF7";
|
|
3769
3856
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -3793,7 +3880,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
3793
3880
|
_applyChange(eventName, node, colElem, extra) {
|
|
3794
3881
|
let res;
|
|
3795
3882
|
node.log(`_applyChange(${eventName})`, extra);
|
|
3796
|
-
colElem.classList.add("wb-
|
|
3883
|
+
colElem.classList.add("wb-busy");
|
|
3797
3884
|
colElem.classList.remove("wb-error");
|
|
3798
3885
|
try {
|
|
3799
3886
|
res = node._callEvent(eventName, extra);
|
|
@@ -3801,7 +3888,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
3801
3888
|
catch (err) {
|
|
3802
3889
|
node.logError(`Error in ${eventName} event handler`, err);
|
|
3803
3890
|
colElem.classList.add("wb-error");
|
|
3804
|
-
colElem.classList.remove("wb-
|
|
3891
|
+
colElem.classList.remove("wb-busy");
|
|
3805
3892
|
}
|
|
3806
3893
|
// Convert scalar return value to a resolved promise
|
|
3807
3894
|
if (!(res instanceof Promise)) {
|
|
@@ -3813,7 +3900,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
3813
3900
|
colElem.classList.add("wb-error");
|
|
3814
3901
|
})
|
|
3815
3902
|
.finally(() => {
|
|
3816
|
-
colElem.classList.remove("wb-
|
|
3903
|
+
colElem.classList.remove("wb-busy");
|
|
3817
3904
|
});
|
|
3818
3905
|
return res;
|
|
3819
3906
|
}
|
|
@@ -3852,12 +3939,12 @@ class EditExtension extends WunderbaumExtension {
|
|
|
3852
3939
|
const eventName = eventToString(event);
|
|
3853
3940
|
const tree = this.tree;
|
|
3854
3941
|
const trigger = this.getPluginOption("trigger");
|
|
3855
|
-
const inputElem =
|
|
3856
|
-
//
|
|
3942
|
+
// const inputElem =
|
|
3943
|
+
// event.target && event.target.closest("input,[contenteditable]");
|
|
3857
3944
|
tree.logDebug(`_preprocessKeyEvent: ${eventName}`);
|
|
3858
3945
|
// --- Title editing: apply/discard ---
|
|
3859
|
-
if (inputElem) {
|
|
3860
|
-
|
|
3946
|
+
// if (inputElem) {
|
|
3947
|
+
if (this.isEditingTitle()) {
|
|
3861
3948
|
switch (eventName) {
|
|
3862
3949
|
case "Enter":
|
|
3863
3950
|
this._stopEditTitle(true, { event: event });
|
|
@@ -3920,7 +4007,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
3920
4007
|
titleSpan.innerHTML = inputHtml;
|
|
3921
4008
|
const inputElem = titleSpan.firstElementChild;
|
|
3922
4009
|
if (validity) {
|
|
3923
|
-
// Permanently apply
|
|
4010
|
+
// Permanently apply input validations (CSS and tooltip)
|
|
3924
4011
|
inputElem.addEventListener("keydown", (e) => {
|
|
3925
4012
|
inputElem.setCustomValidity("");
|
|
3926
4013
|
if (!inputElem.reportValidity()) ;
|
|
@@ -4036,7 +4123,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
4036
4123
|
return;
|
|
4037
4124
|
}
|
|
4038
4125
|
const newNode = node.addNode(init, mode);
|
|
4039
|
-
newNode.
|
|
4126
|
+
newNode.setClass("wb-edit-new");
|
|
4040
4127
|
this.relatedNode = node;
|
|
4041
4128
|
// Don't filter new nodes:
|
|
4042
4129
|
newNode.match = true;
|
|
@@ -4049,17 +4136,29 @@ class EditExtension extends WunderbaumExtension {
|
|
|
4049
4136
|
/*!
|
|
4050
4137
|
* wunderbaum.ts
|
|
4051
4138
|
*
|
|
4052
|
-
* A
|
|
4139
|
+
* A treegrid control.
|
|
4053
4140
|
*
|
|
4054
4141
|
* Copyright (c) 2021-2022, Martin Wendt (https://wwWendt.de).
|
|
4055
|
-
*
|
|
4142
|
+
* https://github.com/mar10/wunderbaum
|
|
4056
4143
|
*
|
|
4057
|
-
*
|
|
4058
|
-
* @
|
|
4144
|
+
* Released under the MIT license.
|
|
4145
|
+
* @version v0.0.5
|
|
4146
|
+
* @date Sun, 21 Aug 2022 15:04:31 GMT
|
|
4059
4147
|
*/
|
|
4060
4148
|
// const class_prefix = "wb-";
|
|
4061
4149
|
// const node_props: string[] = ["title", "key", "refKey"];
|
|
4062
4150
|
// const MAX_CHANGED_NODES = 10;
|
|
4151
|
+
class WbSystemRoot extends WunderbaumNode {
|
|
4152
|
+
constructor(tree) {
|
|
4153
|
+
super(tree, null, {
|
|
4154
|
+
key: "__root__",
|
|
4155
|
+
title: tree.id,
|
|
4156
|
+
});
|
|
4157
|
+
}
|
|
4158
|
+
toString() {
|
|
4159
|
+
return `WbSystemRoot@${this.key}<'${this.tree.id}'>`;
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4063
4162
|
/**
|
|
4064
4163
|
* A persistent plain object or array.
|
|
4065
4164
|
*
|
|
@@ -4067,6 +4166,7 @@ class EditExtension extends WunderbaumExtension {
|
|
|
4067
4166
|
*/
|
|
4068
4167
|
class Wunderbaum {
|
|
4069
4168
|
constructor(options) {
|
|
4169
|
+
this.enabled = true;
|
|
4070
4170
|
this.extensionList = [];
|
|
4071
4171
|
this.extensions = {};
|
|
4072
4172
|
this.keyMap = new Map();
|
|
@@ -4119,11 +4219,14 @@ class Wunderbaum {
|
|
|
4119
4219
|
columns: null,
|
|
4120
4220
|
types: null,
|
|
4121
4221
|
// escapeTitles: true,
|
|
4222
|
+
enabled: true,
|
|
4223
|
+
fixedCol: false,
|
|
4122
4224
|
showSpinner: false,
|
|
4123
|
-
checkbox:
|
|
4225
|
+
checkbox: false,
|
|
4124
4226
|
minExpandLevel: 0,
|
|
4125
4227
|
updateThrottleWait: 200,
|
|
4126
4228
|
skeleton: false,
|
|
4229
|
+
attachBreadcrumb: null,
|
|
4127
4230
|
// --- KeyNav ---
|
|
4128
4231
|
navigationMode: NavigationModeOption.startRow,
|
|
4129
4232
|
quicksearch: true,
|
|
@@ -4167,10 +4270,7 @@ class Wunderbaum {
|
|
|
4167
4270
|
}
|
|
4168
4271
|
});
|
|
4169
4272
|
this.id = opts.id || "wb_" + ++Wunderbaum.sequence;
|
|
4170
|
-
this.root = new
|
|
4171
|
-
key: "__root__",
|
|
4172
|
-
// title: "__root__",
|
|
4173
|
-
});
|
|
4273
|
+
this.root = new WbSystemRoot(this);
|
|
4174
4274
|
this._registerExtension(new KeynavExtension(this));
|
|
4175
4275
|
this._registerExtension(new EditExtension(this));
|
|
4176
4276
|
this._registerExtension(new FilterExtension(this));
|
|
@@ -4180,18 +4280,14 @@ class Wunderbaum {
|
|
|
4180
4280
|
// --- Evaluate options
|
|
4181
4281
|
this.columns = opts.columns;
|
|
4182
4282
|
delete opts.columns;
|
|
4183
|
-
if (!this.columns) {
|
|
4283
|
+
if (!this.columns || !this.columns.length) {
|
|
4184
4284
|
let defaultName = typeof opts.header === "string" ? opts.header : this.id;
|
|
4185
4285
|
this.columns = [{ id: "*", title: defaultName, width: "*" }];
|
|
4186
4286
|
}
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
// Convert `TYPE.classes` to a Set
|
|
4190
|
-
for (let t of Object.values(this.types)) {
|
|
4191
|
-
if (t.classes) {
|
|
4192
|
-
t.classes = toSet(t.classes);
|
|
4193
|
-
}
|
|
4287
|
+
if (opts.types) {
|
|
4288
|
+
this.setTypes(opts.types, true);
|
|
4194
4289
|
}
|
|
4290
|
+
delete opts.types;
|
|
4195
4291
|
if (this.columns.length === 1) {
|
|
4196
4292
|
opts.navigationMode = NavigationModeOption.row;
|
|
4197
4293
|
}
|
|
@@ -4199,7 +4295,7 @@ class Wunderbaum {
|
|
|
4199
4295
|
opts.navigationMode === NavigationModeOption.startCell) {
|
|
4200
4296
|
this.navMode = NavigationMode.cellNav;
|
|
4201
4297
|
}
|
|
4202
|
-
this._updateViewportThrottled =
|
|
4298
|
+
this._updateViewportThrottled = adaptiveThrottle(this._updateViewport.bind(this), {});
|
|
4203
4299
|
// --- Create Markup
|
|
4204
4300
|
this.element = elemFromSelector(opts.element);
|
|
4205
4301
|
assert(!!this.element, `Invalid 'element' option: ${opts.element}`);
|
|
@@ -4243,13 +4339,17 @@ class Wunderbaum {
|
|
|
4243
4339
|
<div class="wb-scroll-container">
|
|
4244
4340
|
<div class="wb-node-list"></div>
|
|
4245
4341
|
</div>`;
|
|
4246
|
-
this.
|
|
4247
|
-
this.nodeListElement = this.
|
|
4342
|
+
this.scrollContainerElement = this.element.querySelector("div.wb-scroll-container");
|
|
4343
|
+
this.nodeListElement = this.scrollContainerElement.querySelector("div.wb-node-list");
|
|
4248
4344
|
this.headerElement = this.element.querySelector("div.wb-header");
|
|
4249
|
-
|
|
4250
|
-
this.element.classList.add("wb-grid");
|
|
4251
|
-
}
|
|
4345
|
+
this.element.classList.toggle("wb-grid", this.columns.length > 1);
|
|
4252
4346
|
this._initExtensions();
|
|
4347
|
+
// --- apply initial options
|
|
4348
|
+
["enabled", "fixedCol"].forEach((optName) => {
|
|
4349
|
+
if (opts[optName] != null) {
|
|
4350
|
+
this.setOption(optName, opts[optName]);
|
|
4351
|
+
}
|
|
4352
|
+
});
|
|
4253
4353
|
// --- Load initial data
|
|
4254
4354
|
if (opts.source) {
|
|
4255
4355
|
if (opts.showSpinner) {
|
|
@@ -4278,9 +4378,14 @@ class Wunderbaum {
|
|
|
4278
4378
|
this.updateViewport();
|
|
4279
4379
|
}, 50);
|
|
4280
4380
|
// --- Bind listeners
|
|
4281
|
-
this.
|
|
4381
|
+
this.element.addEventListener("scroll", (e) => {
|
|
4382
|
+
// this.log("scroll", e);
|
|
4282
4383
|
this.setModified(ChangeType.vscroll);
|
|
4283
4384
|
});
|
|
4385
|
+
// this.scrollContainerElement.addEventListener("scroll", (e: Event) => {
|
|
4386
|
+
// this.log("scroll", e)
|
|
4387
|
+
// this.setModified(ChangeType.vscroll);
|
|
4388
|
+
// });
|
|
4284
4389
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
4285
4390
|
this.setModified(ChangeType.vscroll);
|
|
4286
4391
|
// this.log("ResizeObserver: Size changed", entries);
|
|
@@ -4322,9 +4427,10 @@ class Wunderbaum {
|
|
|
4322
4427
|
onEvent(this.element, "keydown", (e) => {
|
|
4323
4428
|
const info = Wunderbaum.getEventInfo(e);
|
|
4324
4429
|
const eventName = eventToString(e);
|
|
4430
|
+
const node = info.node || this.getFocusNode();
|
|
4325
4431
|
this._callHook("onKeyEvent", {
|
|
4326
4432
|
event: e,
|
|
4327
|
-
node:
|
|
4433
|
+
node: node,
|
|
4328
4434
|
info: info,
|
|
4329
4435
|
eventName: eventName,
|
|
4330
4436
|
});
|
|
@@ -4524,28 +4630,28 @@ class Wunderbaum {
|
|
|
4524
4630
|
}
|
|
4525
4631
|
/** Return the topmost visible node in the viewport. */
|
|
4526
4632
|
getTopmostVpNode(complete = true) {
|
|
4527
|
-
let topIdx;
|
|
4528
4633
|
const gracePy = 1; // ignore subpixel scrolling
|
|
4634
|
+
const scrollParent = this.element;
|
|
4635
|
+
let topIdx;
|
|
4529
4636
|
if (complete) {
|
|
4530
|
-
topIdx = Math.ceil((
|
|
4637
|
+
topIdx = Math.ceil((scrollParent.scrollTop - gracePy) / ROW_HEIGHT);
|
|
4531
4638
|
}
|
|
4532
4639
|
else {
|
|
4533
|
-
topIdx = Math.floor(
|
|
4640
|
+
topIdx = Math.floor(scrollParent.scrollTop / ROW_HEIGHT);
|
|
4534
4641
|
}
|
|
4535
4642
|
return this._getNodeByRowIdx(topIdx);
|
|
4536
4643
|
}
|
|
4537
4644
|
/** Return the lowest visible node in the viewport. */
|
|
4538
4645
|
getLowestVpNode(complete = true) {
|
|
4646
|
+
const scrollParent = this.element;
|
|
4539
4647
|
let bottomIdx;
|
|
4540
4648
|
if (complete) {
|
|
4541
4649
|
bottomIdx =
|
|
4542
|
-
Math.floor((
|
|
4543
|
-
ROW_HEIGHT) - 1;
|
|
4650
|
+
Math.floor((scrollParent.scrollTop + scrollParent.clientHeight) / ROW_HEIGHT) - 1;
|
|
4544
4651
|
}
|
|
4545
4652
|
else {
|
|
4546
4653
|
bottomIdx =
|
|
4547
|
-
Math.ceil((
|
|
4548
|
-
ROW_HEIGHT) - 1;
|
|
4654
|
+
Math.ceil((scrollParent.scrollTop + scrollParent.clientHeight) / ROW_HEIGHT) - 1;
|
|
4549
4655
|
}
|
|
4550
4656
|
bottomIdx = Math.min(bottomIdx, this.count(true) - 1);
|
|
4551
4657
|
return this._getNodeByRowIdx(bottomIdx);
|
|
@@ -4742,7 +4848,7 @@ class Wunderbaum {
|
|
|
4742
4848
|
* Return `tree.option.NAME` (also resolving if this is a callback).
|
|
4743
4849
|
*
|
|
4744
4850
|
* See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
|
|
4745
|
-
* to
|
|
4851
|
+
* to evaluate `node.NAME` setting and `tree.types[node.type].NAME`.
|
|
4746
4852
|
*
|
|
4747
4853
|
* @param name option name (use dot notation to access extension option, e.g.
|
|
4748
4854
|
* `filter.mode`)
|
|
@@ -4761,6 +4867,7 @@ class Wunderbaum {
|
|
|
4761
4867
|
value = value({ type: "resolve", tree: this });
|
|
4762
4868
|
}
|
|
4763
4869
|
// Use value from value options dict, fallback do default
|
|
4870
|
+
// console.info(name, value, opts)
|
|
4764
4871
|
return value !== null && value !== void 0 ? value : defaultValue;
|
|
4765
4872
|
}
|
|
4766
4873
|
/**
|
|
@@ -4769,14 +4876,20 @@ class Wunderbaum {
|
|
|
4769
4876
|
* @param value
|
|
4770
4877
|
*/
|
|
4771
4878
|
setOption(name, value) {
|
|
4879
|
+
// this.log(`setOption(${name}, ${value})`);
|
|
4772
4880
|
if (name.indexOf(".") === -1) {
|
|
4773
4881
|
this.options[name] = value;
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4882
|
+
switch (name) {
|
|
4883
|
+
case "checkbox":
|
|
4884
|
+
this.setModified(ChangeType.any, { removeMarkup: true });
|
|
4885
|
+
break;
|
|
4886
|
+
case "enabled":
|
|
4887
|
+
this.setEnabled(!!value);
|
|
4888
|
+
break;
|
|
4889
|
+
case "fixedCol":
|
|
4890
|
+
this.element.classList.toggle("wb-fixed-col", !!value);
|
|
4891
|
+
break;
|
|
4892
|
+
}
|
|
4780
4893
|
return;
|
|
4781
4894
|
}
|
|
4782
4895
|
const parts = name.split(".");
|
|
@@ -4811,6 +4924,18 @@ class Wunderbaum {
|
|
|
4811
4924
|
this.logTimeEnd(tag);
|
|
4812
4925
|
}
|
|
4813
4926
|
}
|
|
4927
|
+
/** Recursively select all nodes. */
|
|
4928
|
+
selectAll(flag = true) {
|
|
4929
|
+
try {
|
|
4930
|
+
this.enableUpdate(false);
|
|
4931
|
+
this.visit((node) => {
|
|
4932
|
+
node.setSelected(flag);
|
|
4933
|
+
});
|
|
4934
|
+
}
|
|
4935
|
+
finally {
|
|
4936
|
+
this.enableUpdate(true);
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4814
4939
|
/** Return the number of nodes in the data model.*/
|
|
4815
4940
|
count(visible = false) {
|
|
4816
4941
|
if (visible) {
|
|
@@ -4852,6 +4977,17 @@ class Wunderbaum {
|
|
|
4852
4977
|
findFirst(match) {
|
|
4853
4978
|
return this.root.findFirst(match);
|
|
4854
4979
|
}
|
|
4980
|
+
/**
|
|
4981
|
+
* Find first node that matches condition.
|
|
4982
|
+
*
|
|
4983
|
+
* @param match title string to search for, or a
|
|
4984
|
+
* callback function that returns `true` if a node is matched.
|
|
4985
|
+
* @see {@link WunderbaumNode.findFirst}
|
|
4986
|
+
*
|
|
4987
|
+
*/
|
|
4988
|
+
findKey(key) {
|
|
4989
|
+
return this.keyMap.get(key);
|
|
4990
|
+
}
|
|
4855
4991
|
/**
|
|
4856
4992
|
* Find the next visible node that starts with `match`, starting at `startNode`
|
|
4857
4993
|
* and wrap-around at the end.
|
|
@@ -4894,7 +5030,7 @@ class Wunderbaum {
|
|
|
4894
5030
|
*/
|
|
4895
5031
|
findRelatedNode(node, where, includeHidden = false) {
|
|
4896
5032
|
let res = null;
|
|
4897
|
-
const pageSize = Math.floor(this.
|
|
5033
|
+
const pageSize = Math.floor(this.scrollContainerElement.clientHeight / ROW_HEIGHT);
|
|
4898
5034
|
switch (where) {
|
|
4899
5035
|
case "parent":
|
|
4900
5036
|
if (node.parent && node.parent.parent) {
|
|
@@ -5044,6 +5180,10 @@ class Wunderbaum {
|
|
|
5044
5180
|
const idx = Array.prototype.indexOf.call(parentCol.parentNode.children, parentCol);
|
|
5045
5181
|
res.colIdx = idx;
|
|
5046
5182
|
}
|
|
5183
|
+
else if (cl.contains("wb-row")) {
|
|
5184
|
+
// Plain tree
|
|
5185
|
+
res.region = TargetType.title;
|
|
5186
|
+
}
|
|
5047
5187
|
else {
|
|
5048
5188
|
// Somewhere near the title
|
|
5049
5189
|
if (event.type !== "mousemove" && !(event instanceof KeyboardEvent)) {
|
|
@@ -5072,7 +5212,7 @@ class Wunderbaum {
|
|
|
5072
5212
|
* @internal
|
|
5073
5213
|
*/
|
|
5074
5214
|
toString() {
|
|
5075
|
-
return
|
|
5215
|
+
return `Wunderbaum<'${this.id}'>`;
|
|
5076
5216
|
}
|
|
5077
5217
|
/** Return true if any node is currently in edit-title mode. */
|
|
5078
5218
|
isEditing() {
|
|
@@ -5134,9 +5274,8 @@ class Wunderbaum {
|
|
|
5134
5274
|
}
|
|
5135
5275
|
}
|
|
5136
5276
|
/**
|
|
5137
|
-
* Make sure that this node is scrolled into the viewport.
|
|
5277
|
+
* Make sure that this node is vertically scrolled into the viewport.
|
|
5138
5278
|
*
|
|
5139
|
-
* @param {boolean | PlainObject} [effects=false] animation options.
|
|
5140
5279
|
* @param {object} [options=null] {topNode: null, effects: ..., parent: ...}
|
|
5141
5280
|
* this node will remain visible in
|
|
5142
5281
|
* any case, even if `this` is outside the scroll pane.
|
|
@@ -5145,8 +5284,8 @@ class Wunderbaum {
|
|
|
5145
5284
|
const MARGIN = 1;
|
|
5146
5285
|
const node = opts.node || this.getActiveNode();
|
|
5147
5286
|
assert(node._rowIdx != null);
|
|
5148
|
-
const curTop = this.
|
|
5149
|
-
const height = this.
|
|
5287
|
+
const curTop = this.scrollContainerElement.scrollTop;
|
|
5288
|
+
const height = this.scrollContainerElement.clientHeight;
|
|
5150
5289
|
const nodeOfs = node._rowIdx * ROW_HEIGHT;
|
|
5151
5290
|
let newTop;
|
|
5152
5291
|
if (nodeOfs > curTop) {
|
|
@@ -5162,10 +5301,49 @@ class Wunderbaum {
|
|
|
5162
5301
|
}
|
|
5163
5302
|
if (newTop != null) {
|
|
5164
5303
|
this.log("scrollTo(" + nodeOfs + "): " + curTop + " => " + newTop, height);
|
|
5165
|
-
this.
|
|
5304
|
+
this.scrollContainerElement.scrollTop = newTop;
|
|
5166
5305
|
this.setModified(ChangeType.vscroll);
|
|
5167
5306
|
}
|
|
5168
5307
|
}
|
|
5308
|
+
/**
|
|
5309
|
+
* Make sure that this node is horizontally scrolled into the viewport.
|
|
5310
|
+
*
|
|
5311
|
+
* Used for `fixedCol` mode.
|
|
5312
|
+
*
|
|
5313
|
+
* @param {boolean | PlainObject} [effects=false] animation options.
|
|
5314
|
+
* @param {object} [options=null] {topNode: null, effects: ..., parent: ...}
|
|
5315
|
+
* this node will remain visible in
|
|
5316
|
+
* any case, even if `this` is outside the scroll pane.
|
|
5317
|
+
*/
|
|
5318
|
+
scrollToHorz(opts) {
|
|
5319
|
+
const fixedWidth = this.columns[0]._widthPx;
|
|
5320
|
+
const vpWidth = this.element.clientWidth;
|
|
5321
|
+
const scrollLeft = this.element.scrollLeft;
|
|
5322
|
+
// if (scrollLeft <= 0) {
|
|
5323
|
+
// return; // Not scrolled horizontally: Nothing to do
|
|
5324
|
+
// }
|
|
5325
|
+
// const MARGIN = 1;
|
|
5326
|
+
const colElem = this.getActiveColElem();
|
|
5327
|
+
const colLeft = Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.left, 10);
|
|
5328
|
+
const colRight = colLeft + Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.width, 10);
|
|
5329
|
+
let newLeft = scrollLeft;
|
|
5330
|
+
if (colLeft - scrollLeft < fixedWidth) {
|
|
5331
|
+
// The current column is scrolled behind the left fixed column
|
|
5332
|
+
newLeft = colLeft - fixedWidth;
|
|
5333
|
+
}
|
|
5334
|
+
else if (colRight - scrollLeft > vpWidth) {
|
|
5335
|
+
// The current column is scrolled outside the right side
|
|
5336
|
+
newLeft = colRight - vpWidth;
|
|
5337
|
+
}
|
|
5338
|
+
// util.assert(node._rowIdx != null);
|
|
5339
|
+
// const curLeft = this.scrollContainer.scrollLeft;
|
|
5340
|
+
this.log(`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`);
|
|
5341
|
+
// const nodeOfs = node._rowIdx * ROW_HEIGHT;
|
|
5342
|
+
// let newLeft;
|
|
5343
|
+
this.element.scrollLeft = newLeft;
|
|
5344
|
+
// this.setModified(ChangeType.vscroll);
|
|
5345
|
+
// }
|
|
5346
|
+
}
|
|
5169
5347
|
/**
|
|
5170
5348
|
* Set column #colIdx to 'active'.
|
|
5171
5349
|
*
|
|
@@ -5194,6 +5372,15 @@ class Wunderbaum {
|
|
|
5194
5372
|
colDiv.classList.toggle("wb-active", i++ === colIdx);
|
|
5195
5373
|
}
|
|
5196
5374
|
}
|
|
5375
|
+
// Vertical scroll into view
|
|
5376
|
+
// if (this.options.fixedCol) {
|
|
5377
|
+
this.scrollToHorz({});
|
|
5378
|
+
// }
|
|
5379
|
+
}
|
|
5380
|
+
/** Set or remove keybaord focus to the tree container. */
|
|
5381
|
+
setActiveNode(key, flag = true, options) {
|
|
5382
|
+
var _a;
|
|
5383
|
+
(_a = this.findKey(key)) === null || _a === void 0 ? void 0 : _a.setActive(flag, options);
|
|
5197
5384
|
}
|
|
5198
5385
|
/** Set or remove keybaord focus to the tree container. */
|
|
5199
5386
|
setFocus(flag = true) {
|
|
@@ -5217,6 +5404,12 @@ class Wunderbaum {
|
|
|
5217
5404
|
options = node;
|
|
5218
5405
|
}
|
|
5219
5406
|
const immediate = !!getOption(options, "immediate");
|
|
5407
|
+
const removeMarkup = !!getOption(options, "removeMarkup");
|
|
5408
|
+
if (removeMarkup) {
|
|
5409
|
+
this.visit((n) => {
|
|
5410
|
+
n.removeMarkup();
|
|
5411
|
+
});
|
|
5412
|
+
}
|
|
5220
5413
|
switch (change) {
|
|
5221
5414
|
case ChangeType.any:
|
|
5222
5415
|
case ChangeType.structure:
|
|
@@ -5240,11 +5433,14 @@ class Wunderbaum {
|
|
|
5240
5433
|
error(`Invalid change type ${change}`);
|
|
5241
5434
|
}
|
|
5242
5435
|
}
|
|
5436
|
+
/** Get the tree's navigation mode. */
|
|
5437
|
+
getNavigationMode() {
|
|
5438
|
+
return this.navMode;
|
|
5439
|
+
}
|
|
5243
5440
|
/** Set the tree's navigation mode. */
|
|
5244
5441
|
setNavigationMode(mode) {
|
|
5245
5442
|
var _a;
|
|
5246
|
-
|
|
5247
|
-
// util.assert(0 <= colIdx && colIdx < this.columns.length);
|
|
5443
|
+
assert(mode in NavigationMode, `Invalid mode '${mode}'`);
|
|
5248
5444
|
if (mode === this.navMode) {
|
|
5249
5445
|
return;
|
|
5250
5446
|
}
|
|
@@ -5259,20 +5455,56 @@ class Wunderbaum {
|
|
|
5259
5455
|
// this.setModified(ChangeType.row, this.activeNode);
|
|
5260
5456
|
(_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.setModified(ChangeType.status);
|
|
5261
5457
|
}
|
|
5458
|
+
/** Disable mouse and keyboard interaction (return prev. state). */
|
|
5459
|
+
setEnabled(flag = true) {
|
|
5460
|
+
const prev = this.enabled;
|
|
5461
|
+
this.enabled = !!flag;
|
|
5462
|
+
this.element.classList.toggle("wb-disabled", !flag);
|
|
5463
|
+
return prev;
|
|
5464
|
+
}
|
|
5465
|
+
/** Return false if tree is disabled. */
|
|
5466
|
+
isEnabled() {
|
|
5467
|
+
return this.enabled;
|
|
5468
|
+
}
|
|
5469
|
+
/** Return true if tree has one or more data columns in addition to the plain nodes. */
|
|
5470
|
+
isGrid() {
|
|
5471
|
+
return this.columns && this.columns.length > 1;
|
|
5472
|
+
}
|
|
5262
5473
|
/** Display tree status (ok, loading, error, noData) using styles and a dummy root node. */
|
|
5263
5474
|
setStatus(status, message, details) {
|
|
5264
5475
|
return this.root.setStatus(status, message, details);
|
|
5265
5476
|
}
|
|
5477
|
+
/** Add or redefine node type definitions. */
|
|
5478
|
+
setTypes(types, replace = true) {
|
|
5479
|
+
assert(isPlainObject(types));
|
|
5480
|
+
if (replace) {
|
|
5481
|
+
this.types = types;
|
|
5482
|
+
}
|
|
5483
|
+
else {
|
|
5484
|
+
extend(this.types, types);
|
|
5485
|
+
}
|
|
5486
|
+
// Convert `TYPE.classes` to a Set
|
|
5487
|
+
for (let t of Object.values(this.types)) {
|
|
5488
|
+
if (t.classes) {
|
|
5489
|
+
t.classes = toSet(t.classes);
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5266
5493
|
/** Update column headers and width. */
|
|
5267
5494
|
updateColumns(opts) {
|
|
5268
5495
|
opts = Object.assign({ calculateCols: true, updateRows: true }, opts);
|
|
5269
|
-
const
|
|
5496
|
+
const defaultMinWidth = 4;
|
|
5270
5497
|
const vpWidth = this.element.clientWidth;
|
|
5498
|
+
let totalWidth = 0;
|
|
5271
5499
|
let totalWeight = 0;
|
|
5272
5500
|
let fixedWidth = 0;
|
|
5273
5501
|
let modified = false;
|
|
5502
|
+
this.element.classList.toggle("wb-grid", this.columns.length > 1);
|
|
5503
|
+
if (this.columns.length < 2) {
|
|
5504
|
+
this.setNavigationMode(NavigationMode.row);
|
|
5505
|
+
}
|
|
5274
5506
|
if (opts.calculateCols) {
|
|
5275
|
-
// Gather width
|
|
5507
|
+
// Gather width definitions
|
|
5276
5508
|
this._columnsById = {};
|
|
5277
5509
|
for (let col of this.columns) {
|
|
5278
5510
|
this._columnsById[col.id] = col;
|
|
@@ -5295,14 +5527,25 @@ class Wunderbaum {
|
|
|
5295
5527
|
fixedWidth += px;
|
|
5296
5528
|
}
|
|
5297
5529
|
else {
|
|
5298
|
-
error(
|
|
5530
|
+
error(`Invalid column width: ${cw}`);
|
|
5299
5531
|
}
|
|
5300
5532
|
}
|
|
5301
5533
|
// Share remaining space between non-fixed columns
|
|
5302
5534
|
const restPx = Math.max(0, vpWidth - fixedWidth);
|
|
5303
5535
|
let ofsPx = 0;
|
|
5304
5536
|
for (let col of this.columns) {
|
|
5537
|
+
let minWidth;
|
|
5305
5538
|
if (col._weight) {
|
|
5539
|
+
const cmw = col.minWidth;
|
|
5540
|
+
if (typeof cmw === "number") {
|
|
5541
|
+
minWidth = cmw;
|
|
5542
|
+
}
|
|
5543
|
+
else if (typeof cmw === "string" && cmw.endsWith("px")) {
|
|
5544
|
+
minWidth = parseFloat(cmw.slice(0, -2));
|
|
5545
|
+
}
|
|
5546
|
+
else {
|
|
5547
|
+
minWidth = defaultMinWidth;
|
|
5548
|
+
}
|
|
5306
5549
|
const px = Math.max(minWidth, (restPx * col._weight) / totalWeight);
|
|
5307
5550
|
if (col._widthPx != px) {
|
|
5308
5551
|
modified = true;
|
|
@@ -5312,7 +5555,14 @@ class Wunderbaum {
|
|
|
5312
5555
|
col._ofsPx = ofsPx;
|
|
5313
5556
|
ofsPx += col._widthPx;
|
|
5314
5557
|
}
|
|
5558
|
+
totalWidth = ofsPx;
|
|
5315
5559
|
}
|
|
5560
|
+
// if (this.options.fixedCol) {
|
|
5561
|
+
// 'position: fixed' requires that the content has the correct size
|
|
5562
|
+
const tw = `${totalWidth}px`;
|
|
5563
|
+
this.headerElement ? (this.headerElement.style.width = tw) : 0;
|
|
5564
|
+
this.scrollContainerElement.style.width = tw;
|
|
5565
|
+
// }
|
|
5316
5566
|
// Every column has now a calculated `_ofsPx` and `_widthPx`
|
|
5317
5567
|
// this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element);
|
|
5318
5568
|
// console.trace();
|
|
@@ -5364,13 +5614,14 @@ class Wunderbaum {
|
|
|
5364
5614
|
* @internal
|
|
5365
5615
|
*/
|
|
5366
5616
|
_updateViewport() {
|
|
5617
|
+
var _a;
|
|
5367
5618
|
if (this._disableUpdateCount) {
|
|
5368
5619
|
this.log(`IGNORED _updateViewport() disable level: ${this._disableUpdateCount}`);
|
|
5369
5620
|
return;
|
|
5370
5621
|
}
|
|
5371
5622
|
const newNodesOnly = !this.changeRedrawRequestPending;
|
|
5372
5623
|
this.changeRedrawRequestPending = false;
|
|
5373
|
-
let height = this.
|
|
5624
|
+
let height = this.scrollContainerElement.clientHeight;
|
|
5374
5625
|
// We cannot get the height for absolute positioned parent, so look at first col
|
|
5375
5626
|
// let headerHeight = this.headerElement.clientHeight
|
|
5376
5627
|
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
@@ -5378,43 +5629,52 @@ class Wunderbaum {
|
|
|
5378
5629
|
const wantHeight = this.element.clientHeight - headerHeight;
|
|
5379
5630
|
if (Math.abs(height - wantHeight) > 1.0) {
|
|
5380
5631
|
// this.log("resize", height, wantHeight);
|
|
5381
|
-
this.
|
|
5632
|
+
this.scrollContainerElement.style.height = wantHeight + "px";
|
|
5382
5633
|
height = wantHeight;
|
|
5383
5634
|
}
|
|
5384
5635
|
// console.profile(`_updateViewport()`)
|
|
5385
5636
|
this.updateColumns({ updateRows: false });
|
|
5386
5637
|
this._updateRows({ newNodesOnly: newNodesOnly });
|
|
5387
5638
|
// console.profileEnd(`_updateViewport()`)
|
|
5639
|
+
if (this.options.attachBreadcrumb) {
|
|
5640
|
+
let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > ");
|
|
5641
|
+
path = path ? path + " >" : "";
|
|
5642
|
+
this.options.attachBreadcrumb.textContent = path;
|
|
5643
|
+
}
|
|
5388
5644
|
this._callEvent("update");
|
|
5389
5645
|
}
|
|
5390
|
-
/**
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
_validateRows() {
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5646
|
+
// /**
|
|
5647
|
+
// * Assert that TR order matches the natural node order
|
|
5648
|
+
// * @internal
|
|
5649
|
+
// */
|
|
5650
|
+
// protected _validateRows(): boolean {
|
|
5651
|
+
// let trs = this.nodeListElement.childNodes;
|
|
5652
|
+
// let i = 0;
|
|
5653
|
+
// let prev = -1;
|
|
5654
|
+
// let ok = true;
|
|
5655
|
+
// trs.forEach((element) => {
|
|
5656
|
+
// const tr = element as HTMLTableRowElement;
|
|
5657
|
+
// const top = Number.parseInt(tr.style.top);
|
|
5658
|
+
// const n = (<any>tr)._wb_node;
|
|
5659
|
+
// // if (i < 4) {
|
|
5660
|
+
// // console.info(
|
|
5661
|
+
// // `TR#${i}, rowIdx=${n._rowIdx} , top=${top}px: '${n.title}'`
|
|
5662
|
+
// // );
|
|
5663
|
+
// // }
|
|
5664
|
+
// if (prev >= 0 && top !== prev + ROW_HEIGHT) {
|
|
5665
|
+
// n.logWarn(
|
|
5666
|
+
// `TR order mismatch at index ${i}: top=${top}px != ${
|
|
5667
|
+
// prev + ROW_HEIGHT
|
|
5668
|
+
// }`
|
|
5669
|
+
// );
|
|
5670
|
+
// // throw new Error("fault");
|
|
5671
|
+
// ok = false;
|
|
5672
|
+
// }
|
|
5673
|
+
// prev = top;
|
|
5674
|
+
// i++;
|
|
5675
|
+
// });
|
|
5676
|
+
// return ok;
|
|
5677
|
+
// }
|
|
5418
5678
|
/*
|
|
5419
5679
|
* - Traverse all *visible* of the whole tree, i.e. skip collapsed nodes.
|
|
5420
5680
|
* - Store count of rows to `tree.treeRowCount`.
|
|
@@ -5429,9 +5689,9 @@ class Wunderbaum {
|
|
|
5429
5689
|
opts = Object.assign({ newNodesOnly: false }, opts);
|
|
5430
5690
|
const newNodesOnly = !!opts.newNodesOnly;
|
|
5431
5691
|
const row_height = ROW_HEIGHT;
|
|
5432
|
-
const vp_height = this.
|
|
5692
|
+
const vp_height = this.element.clientHeight;
|
|
5433
5693
|
const prefetch = RENDER_MAX_PREFETCH;
|
|
5434
|
-
const ofs = this.
|
|
5694
|
+
const ofs = this.element.scrollTop;
|
|
5435
5695
|
let startIdx = Math.max(0, ofs / row_height - prefetch);
|
|
5436
5696
|
startIdx = Math.floor(startIdx);
|
|
5437
5697
|
// Make sure start is always even, so the alternating row colors don't
|
|
@@ -5499,7 +5759,7 @@ class Wunderbaum {
|
|
|
5499
5759
|
// this.nodeListElement.style.height
|
|
5500
5760
|
// );
|
|
5501
5761
|
this.logTimeEnd(label);
|
|
5502
|
-
this._validateRows();
|
|
5762
|
+
// this._validateRows();
|
|
5503
5763
|
return modified;
|
|
5504
5764
|
}
|
|
5505
5765
|
/**
|
|
@@ -5646,17 +5906,11 @@ class Wunderbaum {
|
|
|
5646
5906
|
/**
|
|
5647
5907
|
* Reload the tree with a new source.
|
|
5648
5908
|
*
|
|
5649
|
-
* Previous data is cleared.
|
|
5650
|
-
*
|
|
5909
|
+
* Previous data is cleared. Note that also column- and type defintions may
|
|
5910
|
+
* be passed with the `source` object.
|
|
5651
5911
|
*/
|
|
5652
|
-
load(source
|
|
5912
|
+
load(source) {
|
|
5653
5913
|
this.clear();
|
|
5654
|
-
const columns = options.columns || source.columns;
|
|
5655
|
-
if (columns) {
|
|
5656
|
-
this.columns = options.columns;
|
|
5657
|
-
// this._renderHeaderMarkup();
|
|
5658
|
-
this.updateColumns({ calculateCols: false });
|
|
5659
|
-
}
|
|
5660
5914
|
return this.root.load(source);
|
|
5661
5915
|
}
|
|
5662
5916
|
/**
|
|
@@ -5688,6 +5942,7 @@ class Wunderbaum {
|
|
|
5688
5942
|
// `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...`
|
|
5689
5943
|
// );
|
|
5690
5944
|
if (this._disableUpdateCount === 0) {
|
|
5945
|
+
this.changeRedrawRequestPending = true; // make sure, we re-render all markup
|
|
5691
5946
|
this.updateViewport();
|
|
5692
5947
|
}
|
|
5693
5948
|
}
|
|
@@ -5730,7 +5985,7 @@ class Wunderbaum {
|
|
|
5730
5985
|
}
|
|
5731
5986
|
Wunderbaum.sequence = 0;
|
|
5732
5987
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
5733
|
-
Wunderbaum.version = "v0.0.
|
|
5988
|
+
Wunderbaum.version = "v0.0.5"; // Set to semver by 'grunt release'
|
|
5734
5989
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
5735
5990
|
Wunderbaum.util = util;
|
|
5736
5991
|
|