wunderbaum 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/wunderbaum.css +381 -291
- package/dist/wunderbaum.css.map +1 -0
- package/dist/wunderbaum.d.ts +717 -642
- package/dist/wunderbaum.esm.js +591 -165
- package/dist/wunderbaum.esm.min.js +23 -23
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +591 -165
- package/dist/wunderbaum.umd.min.js +31 -30
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +10 -9
- package/src/common.ts +2 -2
- package/src/types.ts +38 -11
- package/src/wb_ext_dnd.ts +62 -21
- package/src/wb_ext_edit.ts +2 -2
- package/src/wb_ext_filter.ts +1 -2
- package/src/wb_ext_keynav.ts +4 -4
- package/src/wb_node.ts +361 -82
- package/src/wb_options.ts +11 -4
- package/src/wunderbaum.scss +18 -13
- package/src/wunderbaum.ts +134 -53
package/dist/wunderbaum.umd.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/*!
|
|
8
8
|
* Wunderbaum - util
|
|
9
9
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
10
|
-
* v0.
|
|
10
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
11
11
|
*/
|
|
12
12
|
/** @module util */
|
|
13
13
|
/** Readable names for `MouseEvent.button` */
|
|
@@ -762,10 +762,10 @@
|
|
|
762
762
|
/*!
|
|
763
763
|
* Wunderbaum - types
|
|
764
764
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
765
|
-
* v0.
|
|
765
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
766
766
|
*/
|
|
767
767
|
/**
|
|
768
|
-
* Possible values for {@link WunderbaumNode.
|
|
768
|
+
* Possible values for {@link WunderbaumNode.update()} and {@link Wunderbaum.update()}.
|
|
769
769
|
*/
|
|
770
770
|
var ChangeType;
|
|
771
771
|
(function (ChangeType) {
|
|
@@ -826,7 +826,7 @@
|
|
|
826
826
|
/*!
|
|
827
827
|
* Wunderbaum - wb_extension_base
|
|
828
828
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
829
|
-
* v0.
|
|
829
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
830
830
|
*/
|
|
831
831
|
class WunderbaumExtension {
|
|
832
832
|
constructor(tree, id, defaults) {
|
|
@@ -1113,11 +1113,75 @@
|
|
|
1113
1113
|
debounced.pending = pending;
|
|
1114
1114
|
return debounced;
|
|
1115
1115
|
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Creates a throttled function that only invokes `func` at most once per
|
|
1118
|
+
* every `wait` milliseconds (or once per browser frame). The throttled function
|
|
1119
|
+
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
|
1120
|
+
* `flush` method to immediately invoke them. Provide `options` to indicate
|
|
1121
|
+
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
1122
|
+
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
1123
|
+
* throttled function. Subsequent calls to the throttled function return the
|
|
1124
|
+
* result of the last `func` invocation.
|
|
1125
|
+
*
|
|
1126
|
+
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
1127
|
+
* invoked on the trailing edge of the timeout only if the throttled function
|
|
1128
|
+
* is invoked more than once during the `wait` timeout.
|
|
1129
|
+
*
|
|
1130
|
+
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
1131
|
+
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
1132
|
+
*
|
|
1133
|
+
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
|
1134
|
+
* invocation will be deferred until the next frame is drawn (typically about
|
|
1135
|
+
* 16ms).
|
|
1136
|
+
*
|
|
1137
|
+
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
|
1138
|
+
* for details over the differences between `throttle` and `debounce`.
|
|
1139
|
+
*
|
|
1140
|
+
* @since 0.1.0
|
|
1141
|
+
* @category Function
|
|
1142
|
+
* @param {Function} func The function to throttle.
|
|
1143
|
+
* @param {number} [wait=0]
|
|
1144
|
+
* The number of milliseconds to throttle invocations to; if omitted,
|
|
1145
|
+
* `requestAnimationFrame` is used (if available).
|
|
1146
|
+
* @param {Object} [options={}] The options object.
|
|
1147
|
+
* @param {boolean} [options.leading=true]
|
|
1148
|
+
* Specify invoking on the leading edge of the timeout.
|
|
1149
|
+
* @param {boolean} [options.trailing=true]
|
|
1150
|
+
* Specify invoking on the trailing edge of the timeout.
|
|
1151
|
+
* @returns {Function} Returns the new throttled function.
|
|
1152
|
+
* @example
|
|
1153
|
+
*
|
|
1154
|
+
* // Avoid excessively updating the position while scrolling.
|
|
1155
|
+
* jQuery(window).on('scroll', throttle(updatePosition, 100))
|
|
1156
|
+
*
|
|
1157
|
+
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
|
|
1158
|
+
* const throttled = throttle(renewToken, 300000, { 'trailing': false })
|
|
1159
|
+
* jQuery(element).on('click', throttled)
|
|
1160
|
+
*
|
|
1161
|
+
* // Cancel the trailing throttled invocation.
|
|
1162
|
+
* jQuery(window).on('popstate', throttled.cancel)
|
|
1163
|
+
*/
|
|
1164
|
+
function throttle(func, wait = 0, options = {}) {
|
|
1165
|
+
let leading = true;
|
|
1166
|
+
let trailing = true;
|
|
1167
|
+
if (typeof func !== "function") {
|
|
1168
|
+
throw new TypeError("Expected a function");
|
|
1169
|
+
}
|
|
1170
|
+
if (isObject(options)) {
|
|
1171
|
+
leading = "leading" in options ? !!options.leading : leading;
|
|
1172
|
+
trailing = "trailing" in options ? !!options.trailing : trailing;
|
|
1173
|
+
}
|
|
1174
|
+
return debounce(func, wait, {
|
|
1175
|
+
leading,
|
|
1176
|
+
trailing,
|
|
1177
|
+
maxWait: wait,
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1116
1180
|
|
|
1117
1181
|
/*!
|
|
1118
1182
|
* Wunderbaum - ext-filter
|
|
1119
1183
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1120
|
-
* v0.
|
|
1184
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
1121
1185
|
*/
|
|
1122
1186
|
const START_MARKER = "\uFFF7";
|
|
1123
1187
|
const END_MARKER = "\uFFF8";
|
|
@@ -1162,7 +1226,7 @@
|
|
|
1162
1226
|
}
|
|
1163
1227
|
}
|
|
1164
1228
|
_applyFilterNoUpdate(filter, branchMode, _opts) {
|
|
1165
|
-
return this.tree.
|
|
1229
|
+
return this.tree.runWithDeferredUpdate(() => {
|
|
1166
1230
|
return this._applyFilterImpl(filter, branchMode, _opts);
|
|
1167
1231
|
});
|
|
1168
1232
|
}
|
|
@@ -1374,7 +1438,6 @@
|
|
|
1374
1438
|
// "wb-ext-filter",
|
|
1375
1439
|
"wb-ext-filter-dim", "wb-ext-filter-hide");
|
|
1376
1440
|
// tree._callHook("treeStructureChanged", this, "clearFilter");
|
|
1377
|
-
// tree.render();
|
|
1378
1441
|
tree.enableUpdate(true);
|
|
1379
1442
|
}
|
|
1380
1443
|
}
|
|
@@ -1418,7 +1481,7 @@
|
|
|
1418
1481
|
/*!
|
|
1419
1482
|
* Wunderbaum - ext-keynav
|
|
1420
1483
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1421
|
-
* v0.
|
|
1484
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
1422
1485
|
*/
|
|
1423
1486
|
const QUICKSEARCH_DELAY = 500;
|
|
1424
1487
|
class KeynavExtension extends WunderbaumExtension {
|
|
@@ -1495,7 +1558,7 @@
|
|
|
1495
1558
|
tree.setFocus();
|
|
1496
1559
|
break;
|
|
1497
1560
|
case "Escape":
|
|
1498
|
-
node.
|
|
1561
|
+
node._render();
|
|
1499
1562
|
tree.setFocus();
|
|
1500
1563
|
break;
|
|
1501
1564
|
}
|
|
@@ -1565,7 +1628,7 @@
|
|
|
1565
1628
|
// tree._triggerNodeEvent("clickPaging", ctx, event);
|
|
1566
1629
|
// } else
|
|
1567
1630
|
if (node.getOption("checkbox")) {
|
|
1568
|
-
node.
|
|
1631
|
+
node.toggleSelected();
|
|
1569
1632
|
}
|
|
1570
1633
|
else {
|
|
1571
1634
|
node.setActive(true, { event: event });
|
|
@@ -1601,7 +1664,7 @@
|
|
|
1601
1664
|
if (inputHasFocus) {
|
|
1602
1665
|
if (eventName === "Escape") {
|
|
1603
1666
|
// Discard changes
|
|
1604
|
-
node.
|
|
1667
|
+
node._render();
|
|
1605
1668
|
// Keep cell-nav mode
|
|
1606
1669
|
node.logDebug(`Reset focused input`);
|
|
1607
1670
|
tree.setFocus();
|
|
@@ -1651,7 +1714,7 @@
|
|
|
1651
1714
|
break;
|
|
1652
1715
|
case " ": // Space
|
|
1653
1716
|
if (tree.activeColIdx === 0 && node.getOption("checkbox")) {
|
|
1654
|
-
node.
|
|
1717
|
+
node.toggleSelected();
|
|
1655
1718
|
handled = true;
|
|
1656
1719
|
}
|
|
1657
1720
|
else if (curInput && curInputType === "checkbox") {
|
|
@@ -1758,7 +1821,7 @@
|
|
|
1758
1821
|
/*!
|
|
1759
1822
|
* Wunderbaum - ext-logger
|
|
1760
1823
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1761
|
-
* v0.
|
|
1824
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
1762
1825
|
*/
|
|
1763
1826
|
class LoggerExtension extends WunderbaumExtension {
|
|
1764
1827
|
constructor(tree) {
|
|
@@ -1798,9 +1861,9 @@
|
|
|
1798
1861
|
/*!
|
|
1799
1862
|
* Wunderbaum - common
|
|
1800
1863
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1801
|
-
* v0.
|
|
1864
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
1802
1865
|
*/
|
|
1803
|
-
const DEFAULT_DEBUGLEVEL =
|
|
1866
|
+
const DEFAULT_DEBUGLEVEL = 3; // Replaced by rollup script
|
|
1804
1867
|
/**
|
|
1805
1868
|
* Fixed height of a row in pixel. Must match the SCSS variable `$row-outer-height`.
|
|
1806
1869
|
*/
|
|
@@ -1842,10 +1905,10 @@
|
|
|
1842
1905
|
// expanderLazy: "bi bi-chevron-bar-right",
|
|
1843
1906
|
checkChecked: "bi bi-check-square",
|
|
1844
1907
|
checkUnchecked: "bi bi-square",
|
|
1845
|
-
checkUnknown: "bi dash-square-dotted",
|
|
1908
|
+
checkUnknown: "bi bi-dash-square-dotted",
|
|
1846
1909
|
radioChecked: "bi bi-circle-fill",
|
|
1847
1910
|
radioUnchecked: "bi bi-circle",
|
|
1848
|
-
radioUnknown: "bi bi-circle
|
|
1911
|
+
radioUnknown: "bi bi-record-circle",
|
|
1849
1912
|
folder: "bi bi-folder2",
|
|
1850
1913
|
folderOpen: "bi bi-folder2-open",
|
|
1851
1914
|
folderLazy: "bi bi-folder-symlink",
|
|
@@ -2044,7 +2107,7 @@
|
|
|
2044
2107
|
/*!
|
|
2045
2108
|
* Wunderbaum - ext-dnd
|
|
2046
2109
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2047
|
-
* v0.
|
|
2110
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
2048
2111
|
*/
|
|
2049
2112
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
2050
2113
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -2067,6 +2130,7 @@
|
|
|
2067
2130
|
preventVoidMoves: true,
|
|
2068
2131
|
scroll: true,
|
|
2069
2132
|
scrollSensitivity: 20,
|
|
2133
|
+
// scrollnterval: 50, // Generste event every 50 ms
|
|
2070
2134
|
scrollSpeed: 5,
|
|
2071
2135
|
// setTextTypeJson: false, // Allow dragging of nodes to different IE windows
|
|
2072
2136
|
sourceCopyHook: null,
|
|
@@ -2088,6 +2152,8 @@
|
|
|
2088
2152
|
this.lastAllowedDropRegions = null;
|
|
2089
2153
|
this.lastDropEffect = null;
|
|
2090
2154
|
this.lastDropRegion = false;
|
|
2155
|
+
this.currentScrollDir = 0;
|
|
2156
|
+
this.applyScrollDirThrottled = throttle(this.applyScrollDir, 50);
|
|
2091
2157
|
}
|
|
2092
2158
|
init() {
|
|
2093
2159
|
super.init();
|
|
@@ -2158,22 +2224,55 @@
|
|
|
2158
2224
|
// return "over";
|
|
2159
2225
|
}
|
|
2160
2226
|
/* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
const
|
|
2166
|
-
if (
|
|
2167
|
-
sp.scrollTop =
|
|
2227
|
+
applyScrollDir() {
|
|
2228
|
+
if (this.isDragging() && this.currentScrollDir) {
|
|
2229
|
+
const dndOpts = this.tree.options.dnd;
|
|
2230
|
+
const sp = this.tree.element; // scroll parent
|
|
2231
|
+
const scrollTop = sp.scrollTop;
|
|
2232
|
+
if (this.currentScrollDir < 0) {
|
|
2233
|
+
sp.scrollTop = Math.max(0, scrollTop - dndOpts.scrollSpeed);
|
|
2234
|
+
}
|
|
2235
|
+
else if (this.currentScrollDir > 0) {
|
|
2236
|
+
sp.scrollTop = scrollTop + dndOpts.scrollSpeed;
|
|
2168
2237
|
}
|
|
2169
2238
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2239
|
+
}
|
|
2240
|
+
/* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
|
|
2241
|
+
autoScroll(viewportY) {
|
|
2242
|
+
const tree = this.tree;
|
|
2243
|
+
const dndOpts = tree.options.dnd;
|
|
2244
|
+
const sensitivity = dndOpts.scrollSensitivity;
|
|
2245
|
+
const sp = tree.element; // scroll parent
|
|
2246
|
+
const headerHeight = tree.headerElement.clientHeight; // May be 0
|
|
2247
|
+
// const height = sp.clientHeight - headerHeight;
|
|
2248
|
+
// const height = sp.offsetHeight + headerHeight;
|
|
2249
|
+
const height = sp.offsetHeight;
|
|
2250
|
+
const scrollTop = sp.scrollTop;
|
|
2251
|
+
// tree.logDebug(
|
|
2252
|
+
// `autoScroll: height=${height}, scrollTop=${scrollTop}, viewportY=${viewportY}`
|
|
2253
|
+
// );
|
|
2254
|
+
this.currentScrollDir = 0;
|
|
2255
|
+
if (scrollTop > 0 &&
|
|
2256
|
+
viewportY > 0 &&
|
|
2257
|
+
viewportY <= sensitivity + headerHeight) {
|
|
2258
|
+
// Mouse in top 20px area: scroll up
|
|
2259
|
+
// sp.scrollTop = Math.max(0, scrollTop - dndOpts.scrollSpeed);
|
|
2260
|
+
this.currentScrollDir = -1;
|
|
2261
|
+
}
|
|
2262
|
+
else if (scrollTop < sp.scrollHeight - height &&
|
|
2263
|
+
viewportY >= height - sensitivity) {
|
|
2264
|
+
// Mouse in bottom 20px area: scroll down
|
|
2265
|
+
// sp.scrollTop = scrollTop + dndOpts.scrollSpeed;
|
|
2266
|
+
this.currentScrollDir = +1;
|
|
2267
|
+
}
|
|
2268
|
+
if (this.currentScrollDir) {
|
|
2269
|
+
this.applyScrollDirThrottled();
|
|
2270
|
+
}
|
|
2271
|
+
return sp.scrollTop - scrollTop;
|
|
2272
|
+
}
|
|
2273
|
+
/** Return true if a drag operation currently in progress. */
|
|
2274
|
+
isDragging() {
|
|
2275
|
+
return !!this.srcNode;
|
|
2177
2276
|
}
|
|
2178
2277
|
onDragEvent(e) {
|
|
2179
2278
|
// const tree = this.tree;
|
|
@@ -2297,7 +2396,8 @@
|
|
|
2297
2396
|
// --- dragover ---
|
|
2298
2397
|
}
|
|
2299
2398
|
else if (e.type === "dragover") {
|
|
2300
|
-
this.
|
|
2399
|
+
const viewportY = e.clientY - this.tree.element.offsetTop;
|
|
2400
|
+
this.autoScroll(viewportY);
|
|
2301
2401
|
const region = this._calcDropRegion(e, this.lastAllowedDropRegions);
|
|
2302
2402
|
this.lastDropRegion = region;
|
|
2303
2403
|
if (dndOpts.autoExpandMS > 0 &&
|
|
@@ -2337,7 +2437,7 @@
|
|
|
2337
2437
|
/*!
|
|
2338
2438
|
* Wunderbaum - drag_observer
|
|
2339
2439
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2340
|
-
* v0.
|
|
2440
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
2341
2441
|
*/
|
|
2342
2442
|
/**
|
|
2343
2443
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2473,7 +2573,7 @@
|
|
|
2473
2573
|
/*!
|
|
2474
2574
|
* Wunderbaum - ext-grid
|
|
2475
2575
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2476
|
-
* v0.
|
|
2576
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
2477
2577
|
*/
|
|
2478
2578
|
class GridExtension extends WunderbaumExtension {
|
|
2479
2579
|
constructor(tree) {
|
|
@@ -2510,7 +2610,7 @@
|
|
|
2510
2610
|
/*!
|
|
2511
2611
|
* Wunderbaum - deferred
|
|
2512
2612
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2513
|
-
* v0.
|
|
2613
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
2514
2614
|
*/
|
|
2515
2615
|
/**
|
|
2516
2616
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -2563,32 +2663,20 @@
|
|
|
2563
2663
|
/*!
|
|
2564
2664
|
* Wunderbaum - wunderbaum_node
|
|
2565
2665
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2566
|
-
* v0.
|
|
2666
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
2667
|
+
*/
|
|
2668
|
+
/** WunderbaumNode properties that can be passed with source data.
|
|
2669
|
+
* (Any other source properties will be stored as `node.data.PROP`.)
|
|
2567
2670
|
*/
|
|
2568
|
-
/** Top-level properties that can be passed with `data`. */
|
|
2569
2671
|
const NODE_PROPS = new Set([
|
|
2570
|
-
// TODO: use NODE_ATTRS instead?
|
|
2571
|
-
"classes",
|
|
2572
|
-
"expanded",
|
|
2573
|
-
"icon",
|
|
2574
|
-
"key",
|
|
2575
|
-
"lazy",
|
|
2576
|
-
"refKey",
|
|
2577
|
-
"selected",
|
|
2578
|
-
"title",
|
|
2579
|
-
"tooltip",
|
|
2580
|
-
"type",
|
|
2581
|
-
]);
|
|
2582
|
-
const NODE_ATTRS = new Set([
|
|
2583
2672
|
"checkbox",
|
|
2584
|
-
"expanded",
|
|
2585
2673
|
"classes",
|
|
2586
|
-
"
|
|
2674
|
+
"expanded",
|
|
2587
2675
|
"icon",
|
|
2588
2676
|
"iconTooltip",
|
|
2589
2677
|
"key",
|
|
2590
2678
|
"lazy",
|
|
2591
|
-
"
|
|
2679
|
+
"_partsel",
|
|
2592
2680
|
"radiogroup",
|
|
2593
2681
|
"refKey",
|
|
2594
2682
|
"selected",
|
|
@@ -2597,9 +2685,16 @@
|
|
|
2597
2685
|
"tooltip",
|
|
2598
2686
|
"type",
|
|
2599
2687
|
"unselectable",
|
|
2600
|
-
"unselectableIgnore",
|
|
2601
|
-
"unselectableStatus",
|
|
2688
|
+
// "unselectableIgnore",
|
|
2689
|
+
// "unselectableStatus",
|
|
2602
2690
|
]);
|
|
2691
|
+
/** WunderbaumNode properties that will be returned by `node.toDict()`.)
|
|
2692
|
+
*/
|
|
2693
|
+
const NODE_DICT_PROPS = new Set(NODE_PROPS);
|
|
2694
|
+
NODE_DICT_PROPS.delete("_partsel");
|
|
2695
|
+
NODE_DICT_PROPS.delete("unselectable");
|
|
2696
|
+
// NODE_DICT_PROPS.delete("unselectableIgnore");
|
|
2697
|
+
// NODE_DICT_PROPS.delete("unselectableStatus");
|
|
2603
2698
|
/**
|
|
2604
2699
|
* A single tree node.
|
|
2605
2700
|
*
|
|
@@ -2621,7 +2716,7 @@
|
|
|
2621
2716
|
* @see {@link isExpandable}, {@link isExpanded}, {@link setExpanded}. */
|
|
2622
2717
|
this.expanded = false;
|
|
2623
2718
|
/** Selection state.
|
|
2624
|
-
* @see {@link isSelected}, {@link setSelected}. */
|
|
2719
|
+
* @see {@link isSelected}, {@link setSelected}, {@link toggleSelected}. */
|
|
2625
2720
|
this.selected = false;
|
|
2626
2721
|
/** Additional classes added to `div.wb-row`.
|
|
2627
2722
|
* @see {@link hasClass}, {@link setClass}. */
|
|
@@ -2643,16 +2738,23 @@
|
|
|
2643
2738
|
this.key = "" + ((_a = data.key) !== null && _a !== void 0 ? _a : ++WunderbaumNode.sequence);
|
|
2644
2739
|
this.title = "" + ((_b = data.title) !== null && _b !== void 0 ? _b : "<" + this.key + ">");
|
|
2645
2740
|
data.refKey != null ? (this.refKey = "" + data.refKey) : 0;
|
|
2646
|
-
data.statusNodeType != null
|
|
2647
|
-
? (this.statusNodeType = "" + data.statusNodeType)
|
|
2648
|
-
: 0;
|
|
2649
2741
|
data.type != null ? (this.type = "" + data.type) : 0;
|
|
2650
|
-
data.checkbox != null ? (this.checkbox = !!data.checkbox) : 0;
|
|
2651
|
-
data.colspan != null ? (this.colspan = !!data.colspan) : 0;
|
|
2652
2742
|
this.expanded = data.expanded === true;
|
|
2653
2743
|
data.icon != null ? (this.icon = data.icon) : 0;
|
|
2654
2744
|
this.lazy = data.lazy === true;
|
|
2745
|
+
data.statusNodeType != null
|
|
2746
|
+
? (this.statusNodeType = "" + data.statusNodeType)
|
|
2747
|
+
: 0;
|
|
2748
|
+
data.colspan != null ? (this.colspan = !!data.colspan) : 0;
|
|
2749
|
+
// Selection
|
|
2750
|
+
data.checkbox != null ? (this.checkbox = !!data.checkbox) : 0;
|
|
2751
|
+
data.radiogroup != null ? (this.radiogroup = !!data.radiogroup) : 0;
|
|
2655
2752
|
this.selected = data.selected === true;
|
|
2753
|
+
data.unselectable === true ? (this.unselectable = true) : 0;
|
|
2754
|
+
// data.unselectableStatus != null
|
|
2755
|
+
// ? (this.unselectableStatus = !!data.unselectableStatus)
|
|
2756
|
+
// : 0;
|
|
2757
|
+
// data.unselectableIgnore === true ? (this.unselectableIgnore = true) : 0;
|
|
2656
2758
|
if (data.classes) {
|
|
2657
2759
|
this.setClass(data.classes);
|
|
2658
2760
|
}
|
|
@@ -2776,14 +2878,17 @@
|
|
|
2776
2878
|
// insert nodeList after children[pos]
|
|
2777
2879
|
this.children.splice(pos, 0, ...nodeList);
|
|
2778
2880
|
}
|
|
2779
|
-
// TODO:
|
|
2780
|
-
// if (tree.options.selectMode === 3) {
|
|
2781
|
-
// this.fixSelection3FromEndNodes();
|
|
2782
|
-
// }
|
|
2783
2881
|
// this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null);
|
|
2784
|
-
tree.
|
|
2882
|
+
tree.update(ChangeType.structure);
|
|
2785
2883
|
}
|
|
2786
2884
|
finally {
|
|
2885
|
+
// if (tree.options.selectMode === "hier") {
|
|
2886
|
+
// if (this.parent && this.parent.children) {
|
|
2887
|
+
// this.fixSelection3FromEndNodes();
|
|
2888
|
+
// } else {
|
|
2889
|
+
// // my happen when loading __root__;
|
|
2890
|
+
// }
|
|
2891
|
+
// }
|
|
2787
2892
|
tree.enableUpdate(true);
|
|
2788
2893
|
}
|
|
2789
2894
|
// if(isTopCall && loadLazy){
|
|
@@ -2829,6 +2934,17 @@
|
|
|
2829
2934
|
applyCommand(cmd, options) {
|
|
2830
2935
|
return this.tree.applyCommand(cmd, this, options);
|
|
2831
2936
|
}
|
|
2937
|
+
/**
|
|
2938
|
+
* Collapse all expanded sibling nodes if any.
|
|
2939
|
+
* (Automatically called when `autoCollapse` is true.)
|
|
2940
|
+
*/
|
|
2941
|
+
collapseSiblings(options) {
|
|
2942
|
+
for (let node of this.parent.children) {
|
|
2943
|
+
if (node !== this && node.expanded) {
|
|
2944
|
+
node.setExpanded(false, options);
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2832
2948
|
/**
|
|
2833
2949
|
* Add/remove one or more classes to `<div class='wb-row'>`.
|
|
2834
2950
|
*
|
|
@@ -2868,7 +2984,7 @@
|
|
|
2868
2984
|
const tree = this.tree;
|
|
2869
2985
|
const minExpandLevel = this.tree.options.minExpandLevel;
|
|
2870
2986
|
let { depth = 99, loadLazy, force } = options !== null && options !== void 0 ? options : {};
|
|
2871
|
-
const
|
|
2987
|
+
const expandOpts = {
|
|
2872
2988
|
scrollIntoView: false,
|
|
2873
2989
|
force: force,
|
|
2874
2990
|
loadLazy: loadLazy,
|
|
@@ -2892,7 +3008,7 @@
|
|
|
2892
3008
|
// Node is collapsed and may be expanded (i.e. has children or is lazy)
|
|
2893
3009
|
// Expanding may be async, so we store the promise.
|
|
2894
3010
|
// Also the recursion is delayed until expansion finished.
|
|
2895
|
-
const p = cn.setExpanded(true,
|
|
3011
|
+
const p = cn.setExpanded(true, expandOpts);
|
|
2896
3012
|
promises.push(p);
|
|
2897
3013
|
p.then(async () => {
|
|
2898
3014
|
await _iter(cn, level_1);
|
|
@@ -2908,7 +3024,7 @@
|
|
|
2908
3024
|
// Collapsing is always synchronous, so no promises required
|
|
2909
3025
|
if (!minExpandLevel || force || cn.getLevel() > minExpandLevel) {
|
|
2910
3026
|
// Do not collapse until minExpandLevel
|
|
2911
|
-
cn.setExpanded(false,
|
|
3027
|
+
cn.setExpanded(false, expandOpts);
|
|
2912
3028
|
}
|
|
2913
3029
|
_iter(cn, level_1); // recursion, even if cn was already collapsed
|
|
2914
3030
|
}
|
|
@@ -3280,9 +3396,11 @@
|
|
|
3280
3396
|
isRootNode() {
|
|
3281
3397
|
return this.tree.root === this;
|
|
3282
3398
|
}
|
|
3283
|
-
/** Return true if this node is selected, i.e. the checkbox is set.
|
|
3399
|
+
/** Return true if this node is selected, i.e. the checkbox is set.
|
|
3400
|
+
* `undefined` if partly selected (tri-state), false otherwise.
|
|
3401
|
+
*/
|
|
3284
3402
|
isSelected() {
|
|
3285
|
-
return
|
|
3403
|
+
return this.selected ? true : this._partsel ? undefined : false;
|
|
3286
3404
|
}
|
|
3287
3405
|
/** Return true if this node is a temporarily generated system node like
|
|
3288
3406
|
* 'loading', 'paging', or 'error' (node.statusNodeType contains the type).
|
|
@@ -3354,7 +3472,7 @@
|
|
|
3354
3472
|
tree.logInfo("Redefine columns", source.columns);
|
|
3355
3473
|
tree.columns = source.columns;
|
|
3356
3474
|
delete source.columns;
|
|
3357
|
-
tree.
|
|
3475
|
+
tree.update(ChangeType.colStructure);
|
|
3358
3476
|
}
|
|
3359
3477
|
this.addChildren(source.children);
|
|
3360
3478
|
// Add extra data to `tree.data`
|
|
@@ -3364,6 +3482,9 @@
|
|
|
3364
3482
|
tree.logDebug(`Add source.${key} to tree.data.${key}`);
|
|
3365
3483
|
}
|
|
3366
3484
|
}
|
|
3485
|
+
if (tree.options.selectMode === "hier") {
|
|
3486
|
+
this.fixSelection3FromEndNodes();
|
|
3487
|
+
}
|
|
3367
3488
|
this._callEvent("load");
|
|
3368
3489
|
}
|
|
3369
3490
|
async _fetchWithOptions(source) {
|
|
@@ -3493,10 +3614,10 @@
|
|
|
3493
3614
|
await this.load(source); // also calls setStatus('ok')
|
|
3494
3615
|
if (wasExpanded) {
|
|
3495
3616
|
this.expanded = true;
|
|
3496
|
-
this.tree.
|
|
3617
|
+
this.tree.update(ChangeType.structure);
|
|
3497
3618
|
}
|
|
3498
3619
|
else {
|
|
3499
|
-
this.
|
|
3620
|
+
this.update(); // Fix expander icon to 'loaded'
|
|
3500
3621
|
}
|
|
3501
3622
|
}
|
|
3502
3623
|
catch (e) {
|
|
@@ -3653,7 +3774,7 @@
|
|
|
3653
3774
|
// Fix node.tree for all source nodes
|
|
3654
3775
|
// util.assert(false, "Cross-tree move is not yet implemented.");
|
|
3655
3776
|
this.logWarn("Cross-tree moveTo is experimental!");
|
|
3656
|
-
this.visit(
|
|
3777
|
+
this.visit((n) => {
|
|
3657
3778
|
// TODO: fix selection state and activation, ...
|
|
3658
3779
|
n.tree = targetNode.tree;
|
|
3659
3780
|
}, true);
|
|
@@ -3662,7 +3783,7 @@
|
|
|
3662
3783
|
// DragAndDrop to generate a dragend event on the source node
|
|
3663
3784
|
setTimeout(() => {
|
|
3664
3785
|
// Even indentation may have changed:
|
|
3665
|
-
tree.
|
|
3786
|
+
tree.update(ChangeType.any);
|
|
3666
3787
|
}, 0);
|
|
3667
3788
|
// TODO: fix selection state
|
|
3668
3789
|
// TODO: fix active state
|
|
@@ -3709,7 +3830,7 @@
|
|
|
3709
3830
|
n.removeMarkup();
|
|
3710
3831
|
tree._unregisterNode(n);
|
|
3711
3832
|
}, true);
|
|
3712
|
-
tree.
|
|
3833
|
+
tree.update(ChangeType.structure);
|
|
3713
3834
|
}
|
|
3714
3835
|
/** Remove all descendants of this node. */
|
|
3715
3836
|
removeChildren() {
|
|
@@ -3741,7 +3862,7 @@
|
|
|
3741
3862
|
if (!this.isRootNode()) {
|
|
3742
3863
|
this.expanded = false;
|
|
3743
3864
|
}
|
|
3744
|
-
this.tree.
|
|
3865
|
+
this.tree.update(ChangeType.structure);
|
|
3745
3866
|
}
|
|
3746
3867
|
/** Remove all HTML markup from the DOM. */
|
|
3747
3868
|
removeMarkup() {
|
|
@@ -3836,12 +3957,13 @@
|
|
|
3836
3957
|
}
|
|
3837
3958
|
/**
|
|
3838
3959
|
* Create a whole new `<div class="wb-row">` element.
|
|
3839
|
-
* @see {@link WunderbaumNode.
|
|
3960
|
+
* @see {@link WunderbaumNode._render}
|
|
3840
3961
|
*/
|
|
3841
3962
|
_render_markup(opts) {
|
|
3842
3963
|
const tree = this.tree;
|
|
3843
3964
|
const treeOptions = tree.options;
|
|
3844
|
-
const checkbox = this.getOption("checkbox")
|
|
3965
|
+
const checkbox = this.getOption("checkbox");
|
|
3966
|
+
// const checkbox = this.getOption("checkbox") !== false;
|
|
3845
3967
|
const columns = tree.columns;
|
|
3846
3968
|
const level = this.getLevel();
|
|
3847
3969
|
let elem;
|
|
@@ -3869,6 +3991,9 @@
|
|
|
3869
3991
|
if (checkbox) {
|
|
3870
3992
|
checkboxSpan = document.createElement("i");
|
|
3871
3993
|
checkboxSpan.classList.add("wb-checkbox");
|
|
3994
|
+
if (checkbox === "radio" || this.parent.radiogroup) {
|
|
3995
|
+
checkboxSpan.classList.add("wb-radio");
|
|
3996
|
+
}
|
|
3872
3997
|
nodeElem.appendChild(checkboxSpan);
|
|
3873
3998
|
ofsTitlePx += ICON_WIDTH;
|
|
3874
3999
|
}
|
|
@@ -3949,7 +4074,7 @@
|
|
|
3949
4074
|
/**
|
|
3950
4075
|
* Render `node.title`, `.icon` into an existing row.
|
|
3951
4076
|
*
|
|
3952
|
-
* @see {@link WunderbaumNode.
|
|
4077
|
+
* @see {@link WunderbaumNode._render}
|
|
3953
4078
|
*/
|
|
3954
4079
|
_render_data(opts) {
|
|
3955
4080
|
assert(this._rowElem);
|
|
@@ -4015,7 +4140,7 @@
|
|
|
4015
4140
|
}
|
|
4016
4141
|
/**
|
|
4017
4142
|
* Update row classes to reflect active, focuses, etc.
|
|
4018
|
-
* @see {@link WunderbaumNode.
|
|
4143
|
+
* @see {@link WunderbaumNode._render}
|
|
4019
4144
|
*/
|
|
4020
4145
|
_render_status(opts) {
|
|
4021
4146
|
// this.log("_render_status", opts);
|
|
@@ -4031,6 +4156,7 @@
|
|
|
4031
4156
|
this.expanded ? rowClasses.push("wb-expanded") : 0;
|
|
4032
4157
|
this.lazy ? rowClasses.push("wb-lazy") : 0;
|
|
4033
4158
|
this.selected ? rowClasses.push("wb-selected") : 0;
|
|
4159
|
+
this._partsel ? rowClasses.push("wb-partsel") : 0;
|
|
4034
4160
|
this === tree.activeNode ? rowClasses.push("wb-active") : 0;
|
|
4035
4161
|
this === tree.focusNode ? rowClasses.push("wb-focus") : 0;
|
|
4036
4162
|
this._errorInfo ? rowClasses.push("wb-error") : 0;
|
|
@@ -4070,12 +4196,30 @@
|
|
|
4070
4196
|
}
|
|
4071
4197
|
}
|
|
4072
4198
|
if (checkboxSpan) {
|
|
4073
|
-
|
|
4074
|
-
|
|
4199
|
+
let cbclass = "wb-checkbox ";
|
|
4200
|
+
if (this.parent.radiogroup) {
|
|
4201
|
+
cbclass += "wb-radio ";
|
|
4202
|
+
if (this.selected) {
|
|
4203
|
+
cbclass += iconMap.radioChecked;
|
|
4204
|
+
// } else if (this._partsel) {
|
|
4205
|
+
// cbclass += iconMap.radioUnknown;
|
|
4206
|
+
}
|
|
4207
|
+
else {
|
|
4208
|
+
cbclass += iconMap.radioUnchecked;
|
|
4209
|
+
}
|
|
4075
4210
|
}
|
|
4076
4211
|
else {
|
|
4077
|
-
|
|
4212
|
+
if (this.selected) {
|
|
4213
|
+
cbclass += iconMap.checkChecked;
|
|
4214
|
+
}
|
|
4215
|
+
else if (this._partsel) {
|
|
4216
|
+
cbclass += iconMap.checkUnknown;
|
|
4217
|
+
}
|
|
4218
|
+
else {
|
|
4219
|
+
cbclass += iconMap.checkUnchecked;
|
|
4220
|
+
}
|
|
4078
4221
|
}
|
|
4222
|
+
checkboxSpan.className = cbclass;
|
|
4079
4223
|
}
|
|
4080
4224
|
// Fix active cell in cell-nav mode
|
|
4081
4225
|
if (!opts.isNew) {
|
|
@@ -4103,7 +4247,7 @@
|
|
|
4103
4247
|
}
|
|
4104
4248
|
}
|
|
4105
4249
|
}
|
|
4106
|
-
|
|
4250
|
+
/*
|
|
4107
4251
|
* Create or update node's markup.
|
|
4108
4252
|
*
|
|
4109
4253
|
* `options.change` defaults to ChangeType.data, which updates the title,
|
|
@@ -4114,10 +4258,10 @@
|
|
|
4114
4258
|
* `options.change` should be set to ChangeType.status instead for best
|
|
4115
4259
|
* efficiency.
|
|
4116
4260
|
*
|
|
4117
|
-
* Calling `
|
|
4118
|
-
* @see {@link WunderbaumNode.
|
|
4261
|
+
* Calling `update()` is almost always a better alternative.
|
|
4262
|
+
* @see {@link WunderbaumNode.update}
|
|
4119
4263
|
*/
|
|
4120
|
-
|
|
4264
|
+
_render(options) {
|
|
4121
4265
|
// this.log("render", options);
|
|
4122
4266
|
const opts = Object.assign({ change: ChangeType.data }, options);
|
|
4123
4267
|
if (!this._rowElem) {
|
|
@@ -4147,7 +4291,7 @@
|
|
|
4147
4291
|
this.expanded = false;
|
|
4148
4292
|
this.lazy = true;
|
|
4149
4293
|
this.children = null;
|
|
4150
|
-
this.tree.
|
|
4294
|
+
this.tree.update(ChangeType.structure);
|
|
4151
4295
|
}
|
|
4152
4296
|
/** Convert node (or whole branch) into a plain object.
|
|
4153
4297
|
*
|
|
@@ -4162,7 +4306,7 @@
|
|
|
4162
4306
|
*/
|
|
4163
4307
|
toDict(recursive = false, callback) {
|
|
4164
4308
|
const dict = {};
|
|
4165
|
-
|
|
4309
|
+
NODE_DICT_PROPS.forEach((propName) => {
|
|
4166
4310
|
const val = this[propName];
|
|
4167
4311
|
if (val instanceof Set) {
|
|
4168
4312
|
// Convert Set to string (or skip if set is empty)
|
|
@@ -4287,7 +4431,7 @@
|
|
|
4287
4431
|
return;
|
|
4288
4432
|
}
|
|
4289
4433
|
tree.activeNode = null;
|
|
4290
|
-
prev === null || prev === void 0 ? void 0 : prev.
|
|
4434
|
+
prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status);
|
|
4291
4435
|
}
|
|
4292
4436
|
}
|
|
4293
4437
|
else if (prev === this || retrigger) {
|
|
@@ -4302,8 +4446,8 @@
|
|
|
4302
4446
|
if (focusTree)
|
|
4303
4447
|
tree.setFocus();
|
|
4304
4448
|
}
|
|
4305
|
-
prev === null || prev === void 0 ? void 0 : prev.
|
|
4306
|
-
this.
|
|
4449
|
+
prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status);
|
|
4450
|
+
this.update(ChangeType.status);
|
|
4307
4451
|
}
|
|
4308
4452
|
if (options &&
|
|
4309
4453
|
options.colIdx != null &&
|
|
@@ -4332,13 +4476,16 @@
|
|
|
4332
4476
|
return; // Nothing to do
|
|
4333
4477
|
}
|
|
4334
4478
|
// this.log("setExpanded()");
|
|
4479
|
+
if (flag && this.getOption("autoCollapse")) {
|
|
4480
|
+
this.collapseSiblings(options);
|
|
4481
|
+
}
|
|
4335
4482
|
if (flag && this.lazy && this.children == null) {
|
|
4336
4483
|
await this.loadLazy();
|
|
4337
4484
|
}
|
|
4338
4485
|
this.expanded = flag;
|
|
4339
4486
|
const updateOpts = { immediate: immediate };
|
|
4340
4487
|
// const updateOpts = { immediate: !!util.getOption(options, "immediate") };
|
|
4341
|
-
this.tree.
|
|
4488
|
+
this.tree.update(ChangeType.structure, updateOpts);
|
|
4342
4489
|
if (flag && scrollIntoView !== false) {
|
|
4343
4490
|
const lastChild = this.getLastChild();
|
|
4344
4491
|
if (lastChild) {
|
|
@@ -4355,18 +4502,25 @@
|
|
|
4355
4502
|
assert(!!flag, "blur is not yet implemented");
|
|
4356
4503
|
const prev = this.tree.focusNode;
|
|
4357
4504
|
this.tree.focusNode = this;
|
|
4358
|
-
prev === null || prev === void 0 ? void 0 : prev.
|
|
4359
|
-
this.
|
|
4505
|
+
prev === null || prev === void 0 ? void 0 : prev.update();
|
|
4506
|
+
this.update();
|
|
4360
4507
|
}
|
|
4361
4508
|
/** Set a new icon path or class. */
|
|
4362
4509
|
setIcon(icon) {
|
|
4363
4510
|
this.icon = icon;
|
|
4364
|
-
this.
|
|
4511
|
+
this.update();
|
|
4365
4512
|
}
|
|
4366
4513
|
/** Change node's {@link key} and/or {@link refKey}. */
|
|
4367
4514
|
setKey(key, refKey) {
|
|
4368
4515
|
throw new Error("Not yet implemented");
|
|
4369
4516
|
}
|
|
4517
|
+
/**
|
|
4518
|
+
* @deprecated since v0.3.6: use `update()` instead.
|
|
4519
|
+
*/
|
|
4520
|
+
setModified(change = ChangeType.data) {
|
|
4521
|
+
this.logWarn("setModified() is deprecated: use update() instead.");
|
|
4522
|
+
return this.update(change);
|
|
4523
|
+
}
|
|
4370
4524
|
/**
|
|
4371
4525
|
* Trigger a repaint, typically after a status or data change.
|
|
4372
4526
|
*
|
|
@@ -4374,22 +4528,219 @@
|
|
|
4374
4528
|
* and column content. It can be reduced to 'ChangeType.status' if only
|
|
4375
4529
|
* active/focus/selected state has changed.
|
|
4376
4530
|
*
|
|
4377
|
-
* This method will eventually call {@link WunderbaumNode.
|
|
4531
|
+
* This method will eventually call {@link WunderbaumNode._render()} with
|
|
4378
4532
|
* default options, but may be more consistent with the tree's
|
|
4379
|
-
* {@link Wunderbaum.
|
|
4533
|
+
* {@link Wunderbaum.update()} API.
|
|
4380
4534
|
*/
|
|
4381
|
-
|
|
4535
|
+
update(change = ChangeType.data) {
|
|
4382
4536
|
assert(change === ChangeType.status || change === ChangeType.data);
|
|
4383
|
-
this.tree.
|
|
4537
|
+
this.tree.update(change, this);
|
|
4538
|
+
}
|
|
4539
|
+
/**
|
|
4540
|
+
* Return an array of selected nodes.
|
|
4541
|
+
* @param stopOnParents only return the topmost selected node (useful with selectMode 'hier')
|
|
4542
|
+
*/
|
|
4543
|
+
getSelectedNodes(stopOnParents = false) {
|
|
4544
|
+
let nodeList = [];
|
|
4545
|
+
this.visit((node) => {
|
|
4546
|
+
if (node.selected) {
|
|
4547
|
+
nodeList.push(node);
|
|
4548
|
+
if (stopOnParents === true) {
|
|
4549
|
+
return "skip"; // stop processing this branch
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
});
|
|
4553
|
+
return nodeList;
|
|
4554
|
+
}
|
|
4555
|
+
/** Toggle the check/uncheck state. */
|
|
4556
|
+
toggleSelected(options) {
|
|
4557
|
+
let flag = this.isSelected();
|
|
4558
|
+
if (flag === undefined) {
|
|
4559
|
+
flag = this._anySelectable();
|
|
4560
|
+
}
|
|
4561
|
+
else {
|
|
4562
|
+
flag = !flag;
|
|
4563
|
+
}
|
|
4564
|
+
return this.setSelected(flag, options);
|
|
4565
|
+
}
|
|
4566
|
+
/** Return true if at least on selectable descendant end-node is unselected. @internal */
|
|
4567
|
+
_anySelectable() {
|
|
4568
|
+
let found = false;
|
|
4569
|
+
this.visit((node) => {
|
|
4570
|
+
if (node.selected === false &&
|
|
4571
|
+
!node.unselectable &&
|
|
4572
|
+
!node.hasChildren() &&
|
|
4573
|
+
!node.parent.radiogroup) {
|
|
4574
|
+
found = true;
|
|
4575
|
+
return false; // Stop iteration
|
|
4576
|
+
}
|
|
4577
|
+
});
|
|
4578
|
+
return found;
|
|
4579
|
+
}
|
|
4580
|
+
/* Apply selection state to a single node. */
|
|
4581
|
+
_changeSelectStatusProps(state) {
|
|
4582
|
+
let changed = false;
|
|
4583
|
+
switch (state) {
|
|
4584
|
+
case false:
|
|
4585
|
+
changed = this.selected || this._partsel;
|
|
4586
|
+
this.selected = false;
|
|
4587
|
+
this._partsel = false;
|
|
4588
|
+
break;
|
|
4589
|
+
case true:
|
|
4590
|
+
changed = !this.selected || !this._partsel;
|
|
4591
|
+
this.selected = true;
|
|
4592
|
+
this._partsel = true;
|
|
4593
|
+
break;
|
|
4594
|
+
case undefined:
|
|
4595
|
+
changed = this.selected || !this._partsel;
|
|
4596
|
+
this.selected = false;
|
|
4597
|
+
this._partsel = true;
|
|
4598
|
+
break;
|
|
4599
|
+
default:
|
|
4600
|
+
error(`Invalid state: ${state}`);
|
|
4601
|
+
}
|
|
4602
|
+
if (changed) {
|
|
4603
|
+
this.update();
|
|
4604
|
+
}
|
|
4605
|
+
return changed;
|
|
4606
|
+
}
|
|
4607
|
+
/**
|
|
4608
|
+
* Fix selection status, after this node was (de)selected in `selectMode: 'hier'`.
|
|
4609
|
+
* This includes (de)selecting all descendants.
|
|
4610
|
+
*/
|
|
4611
|
+
fixSelection3AfterClick(opts) {
|
|
4612
|
+
const force = !!(opts === null || opts === void 0 ? void 0 : opts.force);
|
|
4613
|
+
let flag = this.isSelected();
|
|
4614
|
+
this.visit((node) => {
|
|
4615
|
+
if (node.radiogroup) {
|
|
4616
|
+
return "skip"; // Don't (de)select this branch
|
|
4617
|
+
}
|
|
4618
|
+
if (force || !node.getOption("unselectable")) {
|
|
4619
|
+
node._changeSelectStatusProps(flag);
|
|
4620
|
+
}
|
|
4621
|
+
});
|
|
4622
|
+
this.fixSelection3FromEndNodes();
|
|
4623
|
+
}
|
|
4624
|
+
/**
|
|
4625
|
+
* Fix selection status for multi-hier mode.
|
|
4626
|
+
* Only end-nodes are considered to update the descendants branch and parents.
|
|
4627
|
+
* Should be called after this node has loaded new children or after
|
|
4628
|
+
* children have been modified using the API.
|
|
4629
|
+
*/
|
|
4630
|
+
fixSelection3FromEndNodes(opts) {
|
|
4631
|
+
const force = !!(opts === null || opts === void 0 ? void 0 : opts.force);
|
|
4632
|
+
assert(this.tree.options.selectMode === "hier", "expected selectMode 'hier'");
|
|
4633
|
+
// Visit all end nodes and adjust their parent's `selected` and `_partsel`
|
|
4634
|
+
// attributes. Return selection state true, false, or undefined.
|
|
4635
|
+
const _walk = (node) => {
|
|
4636
|
+
let state;
|
|
4637
|
+
const children = node.children;
|
|
4638
|
+
if (children && children.length) {
|
|
4639
|
+
// check all children recursively
|
|
4640
|
+
let allSelected = true;
|
|
4641
|
+
let someSelected = false;
|
|
4642
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
4643
|
+
const child = children[i];
|
|
4644
|
+
// the selection state of a node is not relevant; we need the end-nodes
|
|
4645
|
+
const s = _walk(child);
|
|
4646
|
+
if (s !== false) {
|
|
4647
|
+
someSelected = true;
|
|
4648
|
+
}
|
|
4649
|
+
if (s !== true) {
|
|
4650
|
+
allSelected = false;
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
state = allSelected ? true : someSelected ? undefined : false;
|
|
4654
|
+
}
|
|
4655
|
+
else {
|
|
4656
|
+
// This is an end-node: simply report the status
|
|
4657
|
+
state = !!node.selected;
|
|
4658
|
+
}
|
|
4659
|
+
// #939: Keep a `_partsel` flag that was explicitly set on a lazy node
|
|
4660
|
+
if (node._partsel &&
|
|
4661
|
+
!node.selected &&
|
|
4662
|
+
node.lazy &&
|
|
4663
|
+
node.children == null) {
|
|
4664
|
+
state = undefined;
|
|
4665
|
+
}
|
|
4666
|
+
if (force || !node.getOption("unselectable")) {
|
|
4667
|
+
node._changeSelectStatusProps(state);
|
|
4668
|
+
}
|
|
4669
|
+
return state;
|
|
4670
|
+
};
|
|
4671
|
+
_walk(this);
|
|
4672
|
+
// Update parent's state
|
|
4673
|
+
this.visitParents((node) => {
|
|
4674
|
+
let state;
|
|
4675
|
+
const children = node.children;
|
|
4676
|
+
let allSelected = true;
|
|
4677
|
+
let someSelected = false;
|
|
4678
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
4679
|
+
const child = children[i];
|
|
4680
|
+
state = !!child.selected;
|
|
4681
|
+
// When fixing the parents, we trust the sibling status (i.e. we don't recurse)
|
|
4682
|
+
if (state || child._partsel) {
|
|
4683
|
+
someSelected = true;
|
|
4684
|
+
}
|
|
4685
|
+
if (!state) {
|
|
4686
|
+
allSelected = false;
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
state = allSelected ? true : someSelected ? undefined : false;
|
|
4690
|
+
node._changeSelectStatusProps(state);
|
|
4691
|
+
});
|
|
4384
4692
|
}
|
|
4385
4693
|
/** Modify the check/uncheck state. */
|
|
4386
4694
|
setSelected(flag = true, options) {
|
|
4387
|
-
const
|
|
4388
|
-
|
|
4695
|
+
const tree = this.tree;
|
|
4696
|
+
const sendEvents = !(options === null || options === void 0 ? void 0 : options.noEvents); // Default: send events
|
|
4697
|
+
const prev = this.isSelected();
|
|
4698
|
+
const isRadio = this.parent && this.parent.radiogroup;
|
|
4699
|
+
const selectMode = tree.options.selectMode;
|
|
4700
|
+
const canSelect = (options === null || options === void 0 ? void 0 : options.force) || !this.getOption("unselectable");
|
|
4701
|
+
flag = !!flag;
|
|
4702
|
+
// this.logDebug(`setSelected(${flag})`, this);
|
|
4703
|
+
if (!canSelect) {
|
|
4704
|
+
return prev;
|
|
4705
|
+
}
|
|
4706
|
+
if ((options === null || options === void 0 ? void 0 : options.propagateDown) && selectMode === "multi") {
|
|
4707
|
+
tree.runWithDeferredUpdate(() => {
|
|
4708
|
+
this.visit((node) => {
|
|
4709
|
+
node.setSelected(flag);
|
|
4710
|
+
});
|
|
4711
|
+
});
|
|
4712
|
+
return prev;
|
|
4713
|
+
}
|
|
4714
|
+
if (flag === prev ||
|
|
4715
|
+
(sendEvents && this._callEvent("beforeSelect", { flag: flag }) === false)) {
|
|
4716
|
+
return prev;
|
|
4717
|
+
}
|
|
4718
|
+
tree.runWithDeferredUpdate(() => {
|
|
4719
|
+
if (isRadio) {
|
|
4720
|
+
// Radiobutton Group
|
|
4721
|
+
if (!flag && !(options === null || options === void 0 ? void 0 : options.force)) {
|
|
4722
|
+
return prev; // don't uncheck radio buttons
|
|
4723
|
+
}
|
|
4724
|
+
for (let sibling of this.parent.children) {
|
|
4725
|
+
sibling.selected = sibling === this;
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
else {
|
|
4729
|
+
this.selected = flag;
|
|
4730
|
+
if (selectMode === "hier") {
|
|
4731
|
+
this.fixSelection3AfterClick();
|
|
4732
|
+
}
|
|
4733
|
+
else if (selectMode === "single") {
|
|
4734
|
+
tree.visit((n) => {
|
|
4735
|
+
n.selected = false;
|
|
4736
|
+
});
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
});
|
|
4740
|
+
if (sendEvents) {
|
|
4389
4741
|
this._callEvent("select", { flag: flag });
|
|
4390
4742
|
}
|
|
4391
|
-
|
|
4392
|
-
this.setModified();
|
|
4743
|
+
return prev;
|
|
4393
4744
|
}
|
|
4394
4745
|
/** Display node status (ok, loading, error, noData) using styles and a dummy child node. */
|
|
4395
4746
|
setStatus(status, options) {
|
|
@@ -4414,7 +4765,7 @@
|
|
|
4414
4765
|
assert(!firstChild || !firstChild.isStatusNode());
|
|
4415
4766
|
statusNode = this.addNode(data, "prependChild");
|
|
4416
4767
|
statusNode.match = true;
|
|
4417
|
-
tree.
|
|
4768
|
+
tree.update(ChangeType.structure);
|
|
4418
4769
|
return statusNode;
|
|
4419
4770
|
};
|
|
4420
4771
|
_clearStatusNode();
|
|
@@ -4427,7 +4778,7 @@
|
|
|
4427
4778
|
this._isLoading = true;
|
|
4428
4779
|
this._errorInfo = null;
|
|
4429
4780
|
if (this.parent) {
|
|
4430
|
-
this.
|
|
4781
|
+
this.update(ChangeType.status);
|
|
4431
4782
|
}
|
|
4432
4783
|
else {
|
|
4433
4784
|
// If this is the invisible root, add a visible top-level node
|
|
@@ -4440,7 +4791,7 @@
|
|
|
4440
4791
|
tooltip: details,
|
|
4441
4792
|
});
|
|
4442
4793
|
}
|
|
4443
|
-
// this.
|
|
4794
|
+
// this.update();
|
|
4444
4795
|
break;
|
|
4445
4796
|
case "error":
|
|
4446
4797
|
_setStatusNode({
|
|
@@ -4469,13 +4820,13 @@
|
|
|
4469
4820
|
default:
|
|
4470
4821
|
error("invalid node status " + status);
|
|
4471
4822
|
}
|
|
4472
|
-
tree.
|
|
4823
|
+
tree.update(ChangeType.structure);
|
|
4473
4824
|
return statusNode;
|
|
4474
4825
|
}
|
|
4475
4826
|
/** Rename this node. */
|
|
4476
4827
|
setTitle(title) {
|
|
4477
4828
|
this.title = title;
|
|
4478
|
-
this.
|
|
4829
|
+
this.update();
|
|
4479
4830
|
// this.triggerModify("rename"); // TODO
|
|
4480
4831
|
}
|
|
4481
4832
|
_sortChildren(cmp, deep) {
|
|
@@ -4500,7 +4851,7 @@
|
|
|
4500
4851
|
*/
|
|
4501
4852
|
sortChildren(cmp = nodeTitleSorter, deep = false) {
|
|
4502
4853
|
this._sortChildren(cmp || nodeTitleSorter, deep);
|
|
4503
|
-
this.tree.
|
|
4854
|
+
this.tree.update(ChangeType.structure);
|
|
4504
4855
|
// this.triggerModify("sort"); // TODO
|
|
4505
4856
|
}
|
|
4506
4857
|
/**
|
|
@@ -4528,7 +4879,7 @@
|
|
|
4528
4879
|
this.parent.triggerModifyChild(operation, this, extra);
|
|
4529
4880
|
}
|
|
4530
4881
|
/**
|
|
4531
|
-
* Call `callback(node)` for all
|
|
4882
|
+
* Call `callback(node)` for all descendant nodes in hierarchical order (depth-first, pre-order).
|
|
4532
4883
|
*
|
|
4533
4884
|
* Stop iteration, if fn() returns false. Skip current branch, if fn()
|
|
4534
4885
|
* returns "skip".<br>
|
|
@@ -4608,7 +4959,7 @@
|
|
|
4608
4959
|
/*!
|
|
4609
4960
|
* Wunderbaum - ext-edit
|
|
4610
4961
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
4611
|
-
* v0.
|
|
4962
|
+
* v0.4.0, Wed, 06 Sep 2023 08:21:56 GMT (https://github.com/mar10/wunderbaum)
|
|
4612
4963
|
*/
|
|
4613
4964
|
// const START_MARKER = "\uFFF7";
|
|
4614
4965
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -4836,7 +5187,7 @@
|
|
|
4836
5187
|
node === null || node === void 0 ? void 0 : node.setTitle(newValue);
|
|
4837
5188
|
// NOTE: At least on Safari, this render call triggers a scroll event
|
|
4838
5189
|
// probably because the focused input is replaced.
|
|
4839
|
-
this.curEditNode.
|
|
5190
|
+
this.curEditNode._render({ preventScroll: true });
|
|
4840
5191
|
this.curEditNode = null;
|
|
4841
5192
|
this.relatedNode = null;
|
|
4842
5193
|
this.tree.setFocus(); // restore focus that was in the input element
|
|
@@ -4851,7 +5202,7 @@
|
|
|
4851
5202
|
// Discard the embedded `<input>`
|
|
4852
5203
|
// NOTE: At least on Safari, this render call triggers a scroll event
|
|
4853
5204
|
// probably because the focused input is replaced.
|
|
4854
|
-
this.curEditNode.
|
|
5205
|
+
this.curEditNode._render({ preventScroll: true });
|
|
4855
5206
|
this.curEditNode = null;
|
|
4856
5207
|
this.relatedNode = null;
|
|
4857
5208
|
// We discarded the <input>, so we have to acquire keyboard focus again
|
|
@@ -4904,9 +5255,10 @@
|
|
|
4904
5255
|
* https://github.com/mar10/wunderbaum
|
|
4905
5256
|
*
|
|
4906
5257
|
* Released under the MIT license.
|
|
4907
|
-
* @version v0.
|
|
4908
|
-
* @date
|
|
5258
|
+
* @version v0.4.0
|
|
5259
|
+
* @date Wed, 06 Sep 2023 08:21:56 GMT
|
|
4909
5260
|
*/
|
|
5261
|
+
// import "./wunderbaum.scss";
|
|
4910
5262
|
class WbSystemRoot extends WunderbaumNode {
|
|
4911
5263
|
constructor(tree) {
|
|
4912
5264
|
super(tree, null, {
|
|
@@ -4948,6 +5300,9 @@
|
|
|
4948
5300
|
this.pendingChangeTypes = new Set();
|
|
4949
5301
|
/** Expose some useful methods of the util.ts module as `tree._util`. */
|
|
4950
5302
|
this._util = util;
|
|
5303
|
+
// --- SELECT ---
|
|
5304
|
+
// /** @internal */
|
|
5305
|
+
// public selectRangeAnchor: WunderbaumNode | null = null;
|
|
4951
5306
|
// --- FILTER ---
|
|
4952
5307
|
this.filterMode = null;
|
|
4953
5308
|
// --- KEYNAV ---
|
|
@@ -4982,9 +5337,10 @@
|
|
|
4982
5337
|
checkbox: false,
|
|
4983
5338
|
minExpandLevel: 0,
|
|
4984
5339
|
emptyChildListExpandable: false,
|
|
4985
|
-
updateThrottleWait: 200,
|
|
5340
|
+
// updateThrottleWait: 200,
|
|
4986
5341
|
skeleton: false,
|
|
4987
5342
|
connectTopBreadcrumb: null,
|
|
5343
|
+
selectMode: "multi",
|
|
4988
5344
|
// --- KeyNav ---
|
|
4989
5345
|
navigationModeOption: null,
|
|
4990
5346
|
quicksearch: true,
|
|
@@ -5140,26 +5496,34 @@
|
|
|
5140
5496
|
}
|
|
5141
5497
|
// Async mode is sometimes required, because this.element.clientWidth
|
|
5142
5498
|
// has a wrong value at start???
|
|
5143
|
-
this.
|
|
5499
|
+
this.update(ChangeType.any);
|
|
5144
5500
|
// --- Bind listeners
|
|
5145
5501
|
this.element.addEventListener("scroll", (e) => {
|
|
5146
5502
|
// this.log(`scroll, scrollTop:${e.target.scrollTop}`, e);
|
|
5147
|
-
this.
|
|
5503
|
+
this.update(ChangeType.scroll);
|
|
5148
5504
|
});
|
|
5149
5505
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
5150
5506
|
// this.log("ResizeObserver: Size changed", entries);
|
|
5151
|
-
this.
|
|
5507
|
+
this.update(ChangeType.resize);
|
|
5152
5508
|
});
|
|
5153
5509
|
this.resizeObserver.observe(this.element);
|
|
5154
5510
|
onEvent(this.nodeListElement, "click", "div.wb-row", (e) => {
|
|
5155
5511
|
const info = Wunderbaum.getEventInfo(e);
|
|
5156
5512
|
const node = info.node;
|
|
5157
|
-
|
|
5513
|
+
const mouseEvent = e;
|
|
5514
|
+
// this.log("click", info);
|
|
5515
|
+
// if (this._selectRange(info) === false) {
|
|
5516
|
+
// return;
|
|
5517
|
+
// }
|
|
5158
5518
|
if (this._callEvent("click", { event: e, node: node, info: info }) === false) {
|
|
5159
5519
|
this.lastClickTime = Date.now();
|
|
5160
5520
|
return false;
|
|
5161
5521
|
}
|
|
5162
5522
|
if (node) {
|
|
5523
|
+
if (mouseEvent.ctrlKey) {
|
|
5524
|
+
node.toggleSelected();
|
|
5525
|
+
return;
|
|
5526
|
+
}
|
|
5163
5527
|
// Edit title if 'clickActive' is triggered:
|
|
5164
5528
|
const trigger = this.getOption("edit.trigger");
|
|
5165
5529
|
const slowClickDelay = this.getOption("edit.slowClickDelay");
|
|
@@ -5179,7 +5543,7 @@
|
|
|
5179
5543
|
node.setExpanded(!node.isExpanded());
|
|
5180
5544
|
}
|
|
5181
5545
|
else if (info.region === NodeRegion.checkbox) {
|
|
5182
|
-
node.
|
|
5546
|
+
node.toggleSelected();
|
|
5183
5547
|
}
|
|
5184
5548
|
}
|
|
5185
5549
|
this.lastClickTime = Date.now();
|
|
@@ -5626,7 +5990,7 @@
|
|
|
5626
5990
|
// public cellNavMode = false;
|
|
5627
5991
|
// public lastQuicksearchTime = 0;
|
|
5628
5992
|
// public lastQuicksearchTerm = "";
|
|
5629
|
-
this.
|
|
5993
|
+
this.update(ChangeType.structure);
|
|
5630
5994
|
}
|
|
5631
5995
|
/**
|
|
5632
5996
|
* Clear nodes and markup and detach events and observers.
|
|
@@ -5684,7 +6048,7 @@
|
|
|
5684
6048
|
this.options[name] = value;
|
|
5685
6049
|
switch (name) {
|
|
5686
6050
|
case "checkbox":
|
|
5687
|
-
this.
|
|
6051
|
+
this.update(ChangeType.any);
|
|
5688
6052
|
break;
|
|
5689
6053
|
case "enabled":
|
|
5690
6054
|
this.setEnabled(!!value);
|
|
@@ -5707,8 +6071,15 @@
|
|
|
5707
6071
|
const header = this.options.header;
|
|
5708
6072
|
return this.isGrid() ? header !== false : !!header;
|
|
5709
6073
|
}
|
|
5710
|
-
/** Run code, but defer rendering of viewport until done.
|
|
5711
|
-
|
|
6074
|
+
/** Run code, but defer rendering of viewport until done.
|
|
6075
|
+
*
|
|
6076
|
+
* ```
|
|
6077
|
+
* tree.runWithDeferredUpdate(() => {
|
|
6078
|
+
* return someFuncThatWouldUpdateManyNodes();
|
|
6079
|
+
* });
|
|
6080
|
+
* ```
|
|
6081
|
+
*/
|
|
6082
|
+
runWithDeferredUpdate(func, hint = null) {
|
|
5712
6083
|
try {
|
|
5713
6084
|
this.enableUpdate(false);
|
|
5714
6085
|
const res = func();
|
|
@@ -5719,29 +6090,66 @@
|
|
|
5719
6090
|
this.enableUpdate(true);
|
|
5720
6091
|
}
|
|
5721
6092
|
}
|
|
5722
|
-
/** Recursively expand all expandable nodes (triggers lazy load
|
|
6093
|
+
/** Recursively expand all expandable nodes (triggers lazy load if needed). */
|
|
5723
6094
|
async expandAll(flag = true, options) {
|
|
5724
6095
|
await this.root.expandAll(flag, options);
|
|
5725
6096
|
}
|
|
5726
6097
|
/** Recursively select all nodes. */
|
|
5727
6098
|
selectAll(flag = true) {
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
6099
|
+
return this.root.setSelected(flag, { propagateDown: true });
|
|
6100
|
+
}
|
|
6101
|
+
/** Toggle select all nodes. */
|
|
6102
|
+
toggleSelect() {
|
|
6103
|
+
this.selectAll(this.root._anySelectable());
|
|
6104
|
+
}
|
|
6105
|
+
/**
|
|
6106
|
+
* Return an array of selected nodes.
|
|
6107
|
+
* @param stopOnParents only return the topmost selected node (useful with selectMode 'hier')
|
|
6108
|
+
*/
|
|
6109
|
+
getSelectedNodes(stopOnParents = false) {
|
|
6110
|
+
return this.root.getSelectedNodes(stopOnParents);
|
|
6111
|
+
}
|
|
6112
|
+
/*
|
|
6113
|
+
* Return an array of selected nodes.
|
|
6114
|
+
*/
|
|
6115
|
+
_selectRange(eventInfo) {
|
|
6116
|
+
this.logDebug("_selectRange", eventInfo);
|
|
6117
|
+
error("Not yet implemented.");
|
|
6118
|
+
// const mode = this.options.selectMode!;
|
|
6119
|
+
// if (mode !== "multi") {
|
|
6120
|
+
// this.logDebug(`Range selection only available for selectMode 'multi'`);
|
|
6121
|
+
// return;
|
|
6122
|
+
// }
|
|
6123
|
+
// if (eventInfo.canonicalName === "Meta+click") {
|
|
6124
|
+
// eventInfo.node?.toggleSelected();
|
|
6125
|
+
// return false; // don't
|
|
6126
|
+
// } else if (eventInfo.canonicalName === "Shift+click") {
|
|
6127
|
+
// let from = this.activeNode;
|
|
6128
|
+
// let to = eventInfo.node;
|
|
6129
|
+
// if (!from || !to || from === to) {
|
|
6130
|
+
// return;
|
|
6131
|
+
// }
|
|
6132
|
+
// this.runWithDeferredUpdate(() => {
|
|
6133
|
+
// this.visitRows(
|
|
6134
|
+
// (node) => {
|
|
6135
|
+
// node.setSelected();
|
|
6136
|
+
// },
|
|
6137
|
+
// {
|
|
6138
|
+
// includeHidden: true,
|
|
6139
|
+
// includeSelf: false,
|
|
6140
|
+
// start: from,
|
|
6141
|
+
// reverse: from!._rowIdx! > to!._rowIdx!,
|
|
6142
|
+
// }
|
|
6143
|
+
// );
|
|
6144
|
+
// });
|
|
6145
|
+
// return false;
|
|
6146
|
+
// }
|
|
5737
6147
|
}
|
|
5738
|
-
/** Return the number of nodes in the data model
|
|
6148
|
+
/** Return the number of nodes in the data model.
|
|
6149
|
+
* @param visible if true, nodes that are hidden due to collapsed parents are ignored.
|
|
6150
|
+
*/
|
|
5739
6151
|
count(visible = false) {
|
|
5740
|
-
|
|
5741
|
-
return this.treeRowCount;
|
|
5742
|
-
// return this.viewNodes.size;
|
|
5743
|
-
}
|
|
5744
|
-
return this.keyMap.size;
|
|
6152
|
+
return visible ? this.treeRowCount : this.keyMap.size;
|
|
5745
6153
|
}
|
|
5746
6154
|
/** @internal sanity check. */
|
|
5747
6155
|
_check() {
|
|
@@ -5832,7 +6240,7 @@
|
|
|
5832
6240
|
break;
|
|
5833
6241
|
case "first":
|
|
5834
6242
|
// First visible node
|
|
5835
|
-
this.visit(
|
|
6243
|
+
this.visit((n) => {
|
|
5836
6244
|
if (n.isVisible()) {
|
|
5837
6245
|
res = n;
|
|
5838
6246
|
return false;
|
|
@@ -5840,7 +6248,7 @@
|
|
|
5840
6248
|
});
|
|
5841
6249
|
break;
|
|
5842
6250
|
case "last":
|
|
5843
|
-
this.visit(
|
|
6251
|
+
this.visit((n) => {
|
|
5844
6252
|
// last visible node
|
|
5845
6253
|
if (n.isVisible()) {
|
|
5846
6254
|
res = n;
|
|
@@ -5972,6 +6380,8 @@
|
|
|
5972
6380
|
*/
|
|
5973
6381
|
static getEventInfo(event) {
|
|
5974
6382
|
let target = event.target, cl = target.classList, parentCol = target.closest("span.wb-col"), node = Wunderbaum.getNode(target), tree = node ? node.tree : Wunderbaum.getTree(event), res = {
|
|
6383
|
+
event: event,
|
|
6384
|
+
canonicalName: eventToString(event),
|
|
5975
6385
|
tree: tree,
|
|
5976
6386
|
node: node,
|
|
5977
6387
|
region: NodeRegion.unknown,
|
|
@@ -6137,7 +6547,7 @@
|
|
|
6137
6547
|
// Make sure the topNode is always visible
|
|
6138
6548
|
this.scrollTo(topNode);
|
|
6139
6549
|
}
|
|
6140
|
-
// this.
|
|
6550
|
+
// this.update(ChangeType.scroll);
|
|
6141
6551
|
}
|
|
6142
6552
|
}
|
|
6143
6553
|
/**
|
|
@@ -6165,7 +6575,7 @@
|
|
|
6165
6575
|
// util.assert(node._rowIdx != null);
|
|
6166
6576
|
this.log(`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`);
|
|
6167
6577
|
this.element.scrollLeft = newLeft;
|
|
6168
|
-
// this.
|
|
6578
|
+
// this.update(ChangeType.scroll);
|
|
6169
6579
|
}
|
|
6170
6580
|
/**
|
|
6171
6581
|
* Set column #colIdx to 'active'.
|
|
@@ -6187,7 +6597,7 @@
|
|
|
6187
6597
|
}
|
|
6188
6598
|
}
|
|
6189
6599
|
}
|
|
6190
|
-
(_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.
|
|
6600
|
+
(_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.update(ChangeType.status);
|
|
6191
6601
|
// Update `wb-active` class for all cell spans
|
|
6192
6602
|
for (let rowDiv of this.nodeListElement.children) {
|
|
6193
6603
|
let i = 0;
|
|
@@ -6214,16 +6624,25 @@
|
|
|
6214
6624
|
this.element.blur();
|
|
6215
6625
|
}
|
|
6216
6626
|
}
|
|
6217
|
-
|
|
6627
|
+
/**
|
|
6628
|
+
* @deprecated since v0.3.6: use `update()` instead.
|
|
6629
|
+
*/
|
|
6630
|
+
setModified(change, ...args) {
|
|
6631
|
+
this.logWarn("setModified() is deprecated: use update() instead.");
|
|
6632
|
+
// @ts-ignore
|
|
6633
|
+
// (!) TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
6634
|
+
return this.update.call(this, change, ...args);
|
|
6635
|
+
}
|
|
6636
|
+
update(change, node, options) {
|
|
6218
6637
|
if (this._disableUpdateCount) {
|
|
6219
6638
|
// Assuming that we redraw all when enableUpdate() is re-enabled.
|
|
6220
6639
|
// this.log(
|
|
6221
|
-
// `IGNORED
|
|
6640
|
+
// `IGNORED update(${change}) node=${node} (disable level ${this._disableUpdateCount})`
|
|
6222
6641
|
// );
|
|
6223
6642
|
this._disableUpdateIgnoreCount++;
|
|
6224
6643
|
return;
|
|
6225
6644
|
}
|
|
6226
|
-
// this.log(`
|
|
6645
|
+
// this.log(`update(${change}) node=${node}`);
|
|
6227
6646
|
if (!(node instanceof WunderbaumNode)) {
|
|
6228
6647
|
options = node;
|
|
6229
6648
|
node = null;
|
|
@@ -6257,7 +6676,7 @@
|
|
|
6257
6676
|
// Single nodes are immediately updated if already inside the viewport
|
|
6258
6677
|
// (otherwise we can ignore)
|
|
6259
6678
|
if (node._rowElem) {
|
|
6260
|
-
node.
|
|
6679
|
+
node._render({ change: change });
|
|
6261
6680
|
}
|
|
6262
6681
|
break;
|
|
6263
6682
|
default:
|
|
@@ -6315,7 +6734,7 @@
|
|
|
6315
6734
|
this.setColumn(0);
|
|
6316
6735
|
}
|
|
6317
6736
|
this.element.classList.toggle("wb-cell-mode", flag);
|
|
6318
|
-
(_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.
|
|
6737
|
+
(_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.update(ChangeType.status);
|
|
6319
6738
|
}
|
|
6320
6739
|
/** Set the tree's navigation mode option. */
|
|
6321
6740
|
setNavigationOption(mode, reset = false) {
|
|
@@ -6479,7 +6898,7 @@
|
|
|
6479
6898
|
// if (modified) {
|
|
6480
6899
|
// this._renderHeaderMarkup();
|
|
6481
6900
|
// if (options.renderMarkup) {
|
|
6482
|
-
// this.
|
|
6901
|
+
// this.update(ChangeType.header, { removeMarkup: true });
|
|
6483
6902
|
// } else if (options.updateRows) {
|
|
6484
6903
|
// this._updateRows();
|
|
6485
6904
|
// }
|
|
@@ -6506,7 +6925,14 @@
|
|
|
6506
6925
|
colElem.style.left = col._ofsPx + "px";
|
|
6507
6926
|
colElem.style.width = col._widthPx + "px";
|
|
6508
6927
|
// Add classes from `columns` definition to `<div.wb-col>` cells
|
|
6509
|
-
|
|
6928
|
+
if (typeof col.headerClasses === "string") {
|
|
6929
|
+
col.headerClasses
|
|
6930
|
+
? colElem.classList.add(...col.headerClasses.split(" "))
|
|
6931
|
+
: 0;
|
|
6932
|
+
}
|
|
6933
|
+
else {
|
|
6934
|
+
col.classes ? colElem.classList.add(...col.classes.split(" ")) : 0;
|
|
6935
|
+
}
|
|
6510
6936
|
const title = escapeHtml(col.title || col.id);
|
|
6511
6937
|
let tooltip = "";
|
|
6512
6938
|
if (col.tooltip) {
|
|
@@ -6524,11 +6950,11 @@
|
|
|
6524
6950
|
}
|
|
6525
6951
|
}
|
|
6526
6952
|
/**
|
|
6527
|
-
* Render pending changes that were scheduled using {@link WunderbaumNode.
|
|
6953
|
+
* Render pending changes that were scheduled using {@link WunderbaumNode.update} if any.
|
|
6528
6954
|
*
|
|
6529
6955
|
* This is hardly ever neccessary, since we normally either
|
|
6530
|
-
* - call `
|
|
6531
|
-
* - call `
|
|
6956
|
+
* - call `update(ChangeType.TYPE)` (async, throttled), or
|
|
6957
|
+
* - call `update(ChangeType.TYPE, {immediate: true})` (synchronous)
|
|
6532
6958
|
*
|
|
6533
6959
|
* `updatePendingModifications()` will only force immediate execution of
|
|
6534
6960
|
* pending async changes if any.
|
|
@@ -6543,7 +6969,7 @@
|
|
|
6543
6969
|
* It calls `updateColumns()` and `_updateRows()`.
|
|
6544
6970
|
*
|
|
6545
6971
|
* This protected method should not be called directly but via
|
|
6546
|
-
* {@link WunderbaumNode.
|
|
6972
|
+
* {@link WunderbaumNode.update}`, {@link Wunderbaum.update},
|
|
6547
6973
|
* or {@link Wunderbaum.updatePendingModifications}.
|
|
6548
6974
|
* @internal
|
|
6549
6975
|
*/
|
|
@@ -6698,7 +7124,7 @@
|
|
|
6698
7124
|
if (rowDiv) {
|
|
6699
7125
|
rowDiv.style.top = idx * ROW_HEIGHT + "px";
|
|
6700
7126
|
}
|
|
6701
|
-
node.
|
|
7127
|
+
node._render({ top: top, after: prevElem });
|
|
6702
7128
|
// node.log("render", top, prevElem, "=>", node._rowElem);
|
|
6703
7129
|
prevElem = node._rowElem;
|
|
6704
7130
|
}
|
|
@@ -6778,7 +7204,7 @@
|
|
|
6778
7204
|
if (node.children &&
|
|
6779
7205
|
node.children.length &&
|
|
6780
7206
|
(includeHidden || node.expanded)) {
|
|
6781
|
-
res = node.visit(
|
|
7207
|
+
res = node.visit((n) => {
|
|
6782
7208
|
if (n === stopNode) {
|
|
6783
7209
|
return false;
|
|
6784
7210
|
}
|
|
@@ -6898,7 +7324,7 @@
|
|
|
6898
7324
|
if (this._disableUpdateCount === 0) {
|
|
6899
7325
|
this.logDebug(`enableUpdate(): active again. Re-painting to catch up with ${this._disableUpdateIgnoreCount} ignored update requests...`);
|
|
6900
7326
|
this._disableUpdateIgnoreCount = 0;
|
|
6901
|
-
this.
|
|
7327
|
+
this.update(ChangeType.any, { immediate: true });
|
|
6902
7328
|
}
|
|
6903
7329
|
}
|
|
6904
7330
|
else {
|
|
@@ -6952,7 +7378,7 @@
|
|
|
6952
7378
|
}
|
|
6953
7379
|
Wunderbaum.sequence = 0;
|
|
6954
7380
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
6955
|
-
Wunderbaum.version = "v0.
|
|
7381
|
+
Wunderbaum.version = "v0.4.0"; // Set to semver by 'grunt release'
|
|
6956
7382
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
6957
7383
|
Wunderbaum.util = util;
|
|
6958
7384
|
|