wunderbaum 0.0.1-0 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/wunderbaum.css +1 -1
- package/dist/wunderbaum.d.ts +634 -171
- package/dist/wunderbaum.esm.js +818 -436
- package/dist/wunderbaum.esm.min.js +31 -21
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +820 -438
- package/dist/wunderbaum.umd.min.js +34 -24
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +35 -32
- package/src/common.ts +37 -5
- package/src/drag_observer.ts +169 -0
- package/src/util.ts +48 -13
- package/src/wb_ext_dnd.ts +145 -4
- package/src/wb_ext_edit.ts +10 -1
- package/src/wb_ext_filter.ts +35 -40
- package/src/wb_ext_grid.ts +45 -0
- package/src/wb_ext_keynav.ts +8 -4
- package/src/wb_node.ts +142 -78
- package/src/wb_options.ts +138 -25
- package/src/wunderbaum.scss +28 -5
- package/src/wunderbaum.ts +481 -321
package/dist/wunderbaum.umd.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
3
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.mar10 = {}));
|
|
5
|
-
}(this, (function (exports) { 'use strict';
|
|
5
|
+
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
7
|
/*!
|
|
8
8
|
* Wunderbaum - util
|
|
9
9
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
10
|
-
* v0.0.
|
|
10
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
11
11
|
*/
|
|
12
|
+
/** @module util */
|
|
12
13
|
/** Readable names for `MouseEvent.button` */
|
|
13
14
|
const MOUSE_BUTTONS = {
|
|
14
15
|
0: "",
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
};
|
|
21
22
|
const MAX_INT = 9007199254740991;
|
|
22
23
|
const userInfo = _getUserInfo();
|
|
23
|
-
/**True if the
|
|
24
|
+
/**True if the client is using a macOS platform. */
|
|
24
25
|
const isMac = userInfo.isMac;
|
|
25
26
|
const REX_HTML = /[&<>"'/]/g; // Escape those characters
|
|
26
27
|
const REX_TOOLTIP = /[<>"'/]/g; // Don't escape `&` in tooltips
|
|
@@ -168,7 +169,7 @@
|
|
|
168
169
|
/** TODO */
|
|
169
170
|
function extractHtmlText(s) {
|
|
170
171
|
if (s.indexOf(">") >= 0) {
|
|
171
|
-
error("
|
|
172
|
+
error("Not implemented");
|
|
172
173
|
// return $("<div/>").html(s).text();
|
|
173
174
|
}
|
|
174
175
|
return s;
|
|
@@ -290,7 +291,7 @@
|
|
|
290
291
|
input.valueAsNumber = value;
|
|
291
292
|
break;
|
|
292
293
|
case "radio":
|
|
293
|
-
|
|
294
|
+
error("Not implemented");
|
|
294
295
|
// const name = input.name;
|
|
295
296
|
// const checked = input.parentElement!.querySelector(
|
|
296
297
|
// `input[name="${name}"]:checked`
|
|
@@ -313,7 +314,7 @@
|
|
|
313
314
|
}
|
|
314
315
|
// return value;
|
|
315
316
|
}
|
|
316
|
-
/**
|
|
317
|
+
/** Create and return an unconnected `HTMLElement` from a HTML string. */
|
|
317
318
|
function elemFromHtml(html) {
|
|
318
319
|
const t = document.createElement("template");
|
|
319
320
|
t.innerHTML = html.trim();
|
|
@@ -330,11 +331,23 @@
|
|
|
330
331
|
}
|
|
331
332
|
return obj;
|
|
332
333
|
}
|
|
334
|
+
/** Return a EventTarget from selector or cast an existing element. */
|
|
335
|
+
function eventTargetFromSelector(obj) {
|
|
336
|
+
if (!obj) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
if (typeof obj === "string") {
|
|
340
|
+
return document.querySelector(obj);
|
|
341
|
+
}
|
|
342
|
+
return obj;
|
|
343
|
+
}
|
|
333
344
|
/**
|
|
334
|
-
* Return a descriptive string for a keyboard or mouse event.
|
|
345
|
+
* Return a canonical descriptive string for a keyboard or mouse event.
|
|
335
346
|
*
|
|
336
347
|
* The result also contains a prefix for modifiers if any, for example
|
|
337
348
|
* `"x"`, `"F2"`, `"Control+Home"`, or `"Shift+clickright"`.
|
|
349
|
+
* This is especially useful in `switch` statements, to make sure that modifier
|
|
350
|
+
* keys are considered and handled correctly.
|
|
338
351
|
*/
|
|
339
352
|
function eventToString(event) {
|
|
340
353
|
let key = event.key, et = event.type, s = [];
|
|
@@ -366,6 +379,13 @@
|
|
|
366
379
|
}
|
|
367
380
|
return s.join("+");
|
|
368
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Copy allproperties from one or more source objects to a target object.
|
|
384
|
+
*
|
|
385
|
+
* @returns the modified target object.
|
|
386
|
+
*/
|
|
387
|
+
// TODO: use Object.assign()? --> https://stackoverflow.com/a/42740894
|
|
388
|
+
// TODO: support deep merge --> https://stackoverflow.com/a/42740894
|
|
369
389
|
function extend(...args) {
|
|
370
390
|
for (let i = 1; i < args.length; i++) {
|
|
371
391
|
let arg = args[i];
|
|
@@ -380,23 +400,27 @@
|
|
|
380
400
|
}
|
|
381
401
|
return args[0];
|
|
382
402
|
}
|
|
403
|
+
/** Return true if `obj` is of type `array`. */
|
|
383
404
|
function isArray(obj) {
|
|
384
405
|
return Array.isArray(obj);
|
|
385
406
|
}
|
|
407
|
+
/** Return true if `obj` is of type `Object` and has no propertied. */
|
|
386
408
|
function isEmptyObject(obj) {
|
|
387
409
|
return Object.keys(obj).length === 0 && obj.constructor === Object;
|
|
388
410
|
}
|
|
411
|
+
/** Return true if `obj` is of type `function`. */
|
|
389
412
|
function isFunction(obj) {
|
|
390
413
|
return typeof obj === "function";
|
|
391
414
|
}
|
|
415
|
+
/** Return true if `obj` is of type `Object`. */
|
|
392
416
|
function isPlainObject(obj) {
|
|
393
417
|
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
394
418
|
}
|
|
395
419
|
/** A dummy function that does nothing ('no operation'). */
|
|
396
420
|
function noop(...args) { }
|
|
397
|
-
function onEvent(
|
|
421
|
+
function onEvent(rootTarget, eventNames, selectorOrHandler, handlerOrNone) {
|
|
398
422
|
let selector, handler;
|
|
399
|
-
|
|
423
|
+
rootTarget = eventTargetFromSelector(rootTarget);
|
|
400
424
|
if (handlerOrNone) {
|
|
401
425
|
selector = selectorOrHandler;
|
|
402
426
|
handler = handlerOrNone;
|
|
@@ -406,7 +430,7 @@
|
|
|
406
430
|
handler = selectorOrHandler;
|
|
407
431
|
}
|
|
408
432
|
eventNames.split(" ").forEach((evn) => {
|
|
409
|
-
|
|
433
|
+
rootTarget.addEventListener(evn, function (e) {
|
|
410
434
|
if (!selector) {
|
|
411
435
|
return handler(e); // no event delegation
|
|
412
436
|
}
|
|
@@ -484,6 +508,13 @@
|
|
|
484
508
|
}
|
|
485
509
|
/**
|
|
486
510
|
* Set or rotate checkbox status with support for tri-state.
|
|
511
|
+
*
|
|
512
|
+
* An initial 'indeterminate' state becomes 'checked' on the first call.
|
|
513
|
+
*
|
|
514
|
+
* If the input element has the class 'wb-tristate' assigned, the sequence is:<br>
|
|
515
|
+
* 'indeterminate' -> 'checked' -> 'unchecked' -> 'indeterminate' -> ...<br>
|
|
516
|
+
* Otherwise we toggle like <br>
|
|
517
|
+
* 'checked' -> 'unchecked' -> 'checked' -> ...
|
|
487
518
|
*/
|
|
488
519
|
function toggleCheckbox(element, value, tristate) {
|
|
489
520
|
const input = elemFromSelector(element);
|
|
@@ -541,6 +572,7 @@
|
|
|
541
572
|
}
|
|
542
573
|
throw new Error("Cannot convert to Set<string>: " + val);
|
|
543
574
|
}
|
|
575
|
+
/**Return a canonical string representation for an object's type (e.g. 'array', 'number', ...) */
|
|
544
576
|
function type(obj) {
|
|
545
577
|
return Object.prototype.toString
|
|
546
578
|
.call(obj)
|
|
@@ -567,6 +599,7 @@
|
|
|
567
599
|
setValueToElem: setValueToElem,
|
|
568
600
|
elemFromHtml: elemFromHtml,
|
|
569
601
|
elemFromSelector: elemFromSelector,
|
|
602
|
+
eventTargetFromSelector: eventTargetFromSelector,
|
|
570
603
|
eventToString: eventToString,
|
|
571
604
|
extend: extend,
|
|
572
605
|
isArray: isArray,
|
|
@@ -587,7 +620,7 @@
|
|
|
587
620
|
/*!
|
|
588
621
|
* Wunderbaum - common
|
|
589
622
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
590
|
-
* v0.0.
|
|
623
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
591
624
|
*/
|
|
592
625
|
const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
|
|
593
626
|
const ROW_HEIGHT = 22;
|
|
@@ -601,6 +634,8 @@
|
|
|
601
634
|
ChangeType["row"] = "row";
|
|
602
635
|
ChangeType["structure"] = "structure";
|
|
603
636
|
ChangeType["status"] = "status";
|
|
637
|
+
ChangeType["vscroll"] = "vscroll";
|
|
638
|
+
ChangeType["header"] = "header";
|
|
604
639
|
})(ChangeType || (ChangeType = {}));
|
|
605
640
|
var NodeStatusType;
|
|
606
641
|
(function (NodeStatusType) {
|
|
@@ -673,6 +708,8 @@
|
|
|
673
708
|
Home: "firstCol",
|
|
674
709
|
"Control+End": "last",
|
|
675
710
|
"Control+Home": "first",
|
|
711
|
+
"Meta+ArrowDown": "last",
|
|
712
|
+
"Meta+ArrowUp": "first",
|
|
676
713
|
"*": "expandAll",
|
|
677
714
|
Multiply: "expandAll",
|
|
678
715
|
PageDown: "pageDown",
|
|
@@ -699,7 +736,7 @@
|
|
|
699
736
|
/*!
|
|
700
737
|
* Wunderbaum - wb_extension_base
|
|
701
738
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
702
|
-
* v0.0.
|
|
739
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
703
740
|
*/
|
|
704
741
|
class WunderbaumExtension {
|
|
705
742
|
constructor(tree, id, defaults) {
|
|
@@ -1054,7 +1091,7 @@
|
|
|
1054
1091
|
/*!
|
|
1055
1092
|
* Wunderbaum - ext-filter
|
|
1056
1093
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1057
|
-
* v0.0.
|
|
1094
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1058
1095
|
*/
|
|
1059
1096
|
const START_MARKER = "\uFFF7";
|
|
1060
1097
|
const END_MARKER = "\uFFF8";
|
|
@@ -1093,7 +1130,9 @@
|
|
|
1093
1130
|
});
|
|
1094
1131
|
}
|
|
1095
1132
|
_applyFilterImpl(filter, branchMode, _opts) {
|
|
1096
|
-
let match, temp, start = Date.now(), count = 0, tree = this.tree, treeOpts = tree.options,
|
|
1133
|
+
let match, temp, start = Date.now(), count = 0, tree = this.tree, treeOpts = tree.options,
|
|
1134
|
+
// escapeTitles = treeOpts.escapeTitles,
|
|
1135
|
+
prevAutoCollapse = treeOpts.autoCollapse, opts = extend({}, treeOpts.filter, _opts), hideMode = opts.mode === "hide", leavesOnly = !!opts.leavesOnly && !branchMode;
|
|
1097
1136
|
// Default to 'match title substring (case insensitive)'
|
|
1098
1137
|
if (typeof filter === "string") {
|
|
1099
1138
|
if (filter === "") {
|
|
@@ -1126,37 +1165,36 @@
|
|
|
1126
1165
|
if (!node.title) {
|
|
1127
1166
|
return false;
|
|
1128
1167
|
}
|
|
1129
|
-
let text = escapeTitles ? node.title : extractHtmlText(node.title);
|
|
1168
|
+
// let text = escapeTitles ? node.title : extractHtmlText(node.title);
|
|
1169
|
+
let text = node.title;
|
|
1130
1170
|
// `.match` instead of `.test` to get the capture groups
|
|
1131
1171
|
let res = text.match(re);
|
|
1132
1172
|
if (res && opts.highlight) {
|
|
1133
|
-
if (escapeTitles) {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
}
|
|
1137
|
-
else {
|
|
1138
|
-
// #740: we must not apply the marks to escaped entity names, e.g. `"`
|
|
1139
|
-
// Use some exotic characters to mark matches:
|
|
1140
|
-
temp = text.replace(reHighlight, function (s) {
|
|
1141
|
-
return START_MARKER + s + END_MARKER;
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
// now we can escape the title...
|
|
1145
|
-
node.titleWithHighlight = escapeHtml(temp)
|
|
1146
|
-
// ... and finally insert the desired `<mark>` tags
|
|
1147
|
-
.replace(RE_START_MARKER, "<mark>")
|
|
1148
|
-
.replace(RE_END_MARTKER, "</mark>");
|
|
1173
|
+
// if (escapeTitles) {
|
|
1174
|
+
if (opts.fuzzy) {
|
|
1175
|
+
temp = _markFuzzyMatchedChars(text, res, true);
|
|
1149
1176
|
}
|
|
1150
1177
|
else {
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
return "<mark>" + s + "</mark>";
|
|
1157
|
-
});
|
|
1158
|
-
}
|
|
1178
|
+
// #740: we must not apply the marks to escaped entity names, e.g. `"`
|
|
1179
|
+
// Use some exotic characters to mark matches:
|
|
1180
|
+
temp = text.replace(reHighlight, function (s) {
|
|
1181
|
+
return START_MARKER + s + END_MARKER;
|
|
1182
|
+
});
|
|
1159
1183
|
}
|
|
1184
|
+
// now we can escape the title...
|
|
1185
|
+
node.titleWithHighlight = escapeHtml(temp)
|
|
1186
|
+
// ... and finally insert the desired `<mark>` tags
|
|
1187
|
+
.replace(RE_START_MARKER, "<mark>")
|
|
1188
|
+
.replace(RE_END_MARTKER, "</mark>");
|
|
1189
|
+
// } else {
|
|
1190
|
+
// if (opts.fuzzy) {
|
|
1191
|
+
// node.titleWithHighlight = _markFuzzyMatchedChars(text, res);
|
|
1192
|
+
// } else {
|
|
1193
|
+
// node.titleWithHighlight = text.replace(reHighlight, function (s) {
|
|
1194
|
+
// return "<mark>" + s + "</mark>";
|
|
1195
|
+
// });
|
|
1196
|
+
// }
|
|
1197
|
+
// }
|
|
1160
1198
|
// node.debug("filter", escapeTitles, text, node.titleWithHighlight);
|
|
1161
1199
|
}
|
|
1162
1200
|
return !!res;
|
|
@@ -1242,8 +1280,6 @@
|
|
|
1242
1280
|
}
|
|
1243
1281
|
/**
|
|
1244
1282
|
* [ext-filter] Re-apply current filter.
|
|
1245
|
-
*
|
|
1246
|
-
* @requires jquery.fancytree.filter.js
|
|
1247
1283
|
*/
|
|
1248
1284
|
updateFilter() {
|
|
1249
1285
|
let tree = this.tree;
|
|
@@ -1258,14 +1294,11 @@
|
|
|
1258
1294
|
}
|
|
1259
1295
|
/**
|
|
1260
1296
|
* [ext-filter] Reset the filter.
|
|
1261
|
-
*
|
|
1262
|
-
* @alias Fancytree#clearFilter
|
|
1263
|
-
* @requires jquery.fancytree.filter.js
|
|
1264
1297
|
*/
|
|
1265
1298
|
clearFilter() {
|
|
1266
|
-
let tree = this.tree
|
|
1299
|
+
let tree = this.tree;
|
|
1267
1300
|
// statusNode = tree.root.findDirectChild(KEY_NODATA),
|
|
1268
|
-
escapeTitles = tree.options.escapeTitles;
|
|
1301
|
+
// escapeTitles = tree.options.escapeTitles;
|
|
1269
1302
|
// enhanceTitle = tree.options.enhanceTitle,
|
|
1270
1303
|
tree.enableUpdate(false);
|
|
1271
1304
|
// if (statusNode) {
|
|
@@ -1279,12 +1312,11 @@
|
|
|
1279
1312
|
if (node.match && node._rowElem) {
|
|
1280
1313
|
// #491, #601
|
|
1281
1314
|
let titleElem = node._rowElem.querySelector("span.wb-title");
|
|
1282
|
-
if (escapeTitles) {
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
}
|
|
1315
|
+
// if (escapeTitles) {
|
|
1316
|
+
titleElem.textContent = node.title;
|
|
1317
|
+
// } else {
|
|
1318
|
+
// titleElem.innerHTML = node.title;
|
|
1319
|
+
// }
|
|
1288
1320
|
node._callEvent("enhanceTitle", { titleElem: titleElem });
|
|
1289
1321
|
}
|
|
1290
1322
|
delete node.match;
|
|
@@ -1320,7 +1352,7 @@
|
|
|
1320
1352
|
* @param {string} text
|
|
1321
1353
|
* @param {RegExpMatchArray} matches
|
|
1322
1354
|
*/
|
|
1323
|
-
function _markFuzzyMatchedChars(text, matches, escapeTitles =
|
|
1355
|
+
function _markFuzzyMatchedChars(text, matches, escapeTitles = true) {
|
|
1324
1356
|
let matchingIndices = [];
|
|
1325
1357
|
// get the indices of matched characters (Iterate through `RegExpMatchArray`)
|
|
1326
1358
|
for (let _matchingArrIdx = 1; _matchingArrIdx < matches.length; _matchingArrIdx++) {
|
|
@@ -1335,7 +1367,7 @@
|
|
|
1335
1367
|
// Map each `text` char to its position and store in `textPoses`.
|
|
1336
1368
|
let textPoses = text.split("");
|
|
1337
1369
|
if (escapeTitles) {
|
|
1338
|
-
// If escaping the title, then wrap the
|
|
1370
|
+
// If escaping the title, then wrap the matching char within exotic chars
|
|
1339
1371
|
matchingIndices.forEach(function (v) {
|
|
1340
1372
|
textPoses[v] = START_MARKER + textPoses[v] + END_MARKER;
|
|
1341
1373
|
});
|
|
@@ -1353,7 +1385,7 @@
|
|
|
1353
1385
|
/*!
|
|
1354
1386
|
* Wunderbaum - ext-keynav
|
|
1355
1387
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1356
|
-
* v0.0.
|
|
1388
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1357
1389
|
*/
|
|
1358
1390
|
class KeynavExtension extends WunderbaumExtension {
|
|
1359
1391
|
constructor(tree) {
|
|
@@ -1420,7 +1452,7 @@
|
|
|
1420
1452
|
eventName = "Add"; // expand
|
|
1421
1453
|
}
|
|
1422
1454
|
else if (navModeOption === NavigationModeOption.startRow) {
|
|
1423
|
-
tree.
|
|
1455
|
+
tree.setNavigationMode(NavigationMode.cellNav);
|
|
1424
1456
|
return;
|
|
1425
1457
|
}
|
|
1426
1458
|
break;
|
|
@@ -1459,6 +1491,8 @@
|
|
|
1459
1491
|
case "Home":
|
|
1460
1492
|
case "Control+End":
|
|
1461
1493
|
case "Control+Home":
|
|
1494
|
+
case "Meta+ArrowDown":
|
|
1495
|
+
case "Meta+ArrowUp":
|
|
1462
1496
|
case "PageDown":
|
|
1463
1497
|
case "PageUp":
|
|
1464
1498
|
node.navigate(eventName, { activate: activate, event: event });
|
|
@@ -1490,11 +1524,11 @@
|
|
|
1490
1524
|
break;
|
|
1491
1525
|
case "Escape":
|
|
1492
1526
|
if (tree.navMode === NavigationMode.cellEdit) {
|
|
1493
|
-
tree.
|
|
1527
|
+
tree.setNavigationMode(NavigationMode.cellNav);
|
|
1494
1528
|
handled = true;
|
|
1495
1529
|
}
|
|
1496
1530
|
else if (tree.navMode === NavigationMode.cellNav) {
|
|
1497
|
-
tree.
|
|
1531
|
+
tree.setNavigationMode(NavigationMode.row);
|
|
1498
1532
|
handled = true;
|
|
1499
1533
|
}
|
|
1500
1534
|
break;
|
|
@@ -1504,7 +1538,7 @@
|
|
|
1504
1538
|
handled = true;
|
|
1505
1539
|
}
|
|
1506
1540
|
else if (navModeOption !== NavigationModeOption.cell) {
|
|
1507
|
-
tree.
|
|
1541
|
+
tree.setNavigationMode(NavigationMode.row);
|
|
1508
1542
|
handled = true;
|
|
1509
1543
|
}
|
|
1510
1544
|
break;
|
|
@@ -1521,6 +1555,8 @@
|
|
|
1521
1555
|
case "Home":
|
|
1522
1556
|
case "Control+End":
|
|
1523
1557
|
case "Control+Home":
|
|
1558
|
+
case "Meta+ArrowDown":
|
|
1559
|
+
case "Meta+ArrowUp":
|
|
1524
1560
|
case "PageDown":
|
|
1525
1561
|
case "PageUp":
|
|
1526
1562
|
node.navigate(eventName, { activate: activate, event: event });
|
|
@@ -1539,7 +1575,7 @@
|
|
|
1539
1575
|
/*!
|
|
1540
1576
|
* Wunderbaum - ext-logger
|
|
1541
1577
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1542
|
-
* v0.0.
|
|
1578
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1543
1579
|
*/
|
|
1544
1580
|
class LoggerExtension extends WunderbaumExtension {
|
|
1545
1581
|
constructor(tree) {
|
|
@@ -1579,19 +1615,9 @@
|
|
|
1579
1615
|
/*!
|
|
1580
1616
|
* Wunderbaum - ext-dnd
|
|
1581
1617
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1582
|
-
* v0.0.
|
|
1618
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1583
1619
|
*/
|
|
1584
|
-
const nodeMimeType = "application/x-
|
|
1585
|
-
// type AllowedDropRegionType =
|
|
1586
|
-
// | "after"
|
|
1587
|
-
// | "afterBefore"
|
|
1588
|
-
// // | "afterBeforeOver" // == all == true
|
|
1589
|
-
// | "afterOver"
|
|
1590
|
-
// | "all" // == true
|
|
1591
|
-
// | "before"
|
|
1592
|
-
// | "beforeOver"
|
|
1593
|
-
// | "none" // == false == "" == null
|
|
1594
|
-
// | "over"; // == "child"
|
|
1620
|
+
const nodeMimeType = "application/x-wunderbaum-node";
|
|
1595
1621
|
class DndExtension extends WunderbaumExtension {
|
|
1596
1622
|
constructor(tree) {
|
|
1597
1623
|
super(tree, "dnd", {
|
|
@@ -1854,10 +1880,181 @@
|
|
|
1854
1880
|
}
|
|
1855
1881
|
}
|
|
1856
1882
|
|
|
1883
|
+
/*!
|
|
1884
|
+
* Wunderbaum - drag_observer
|
|
1885
|
+
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1886
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1887
|
+
*/
|
|
1888
|
+
/**
|
|
1889
|
+
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
1890
|
+
*/
|
|
1891
|
+
class DragObserver {
|
|
1892
|
+
constructor(opts) {
|
|
1893
|
+
this.start = {
|
|
1894
|
+
x: 0,
|
|
1895
|
+
y: 0,
|
|
1896
|
+
altKey: false,
|
|
1897
|
+
ctrlKey: false,
|
|
1898
|
+
metaKey: false,
|
|
1899
|
+
shiftKey: false,
|
|
1900
|
+
};
|
|
1901
|
+
this.dragElem = null;
|
|
1902
|
+
this.dragging = false;
|
|
1903
|
+
// TODO: touch events
|
|
1904
|
+
this.events = ["mousedown", "mouseup", "mousemove", "keydown"];
|
|
1905
|
+
assert(opts.root);
|
|
1906
|
+
this.opts = extend({ thresh: 5 }, opts);
|
|
1907
|
+
this.root = opts.root;
|
|
1908
|
+
this._handler = this.handleEvent.bind(this);
|
|
1909
|
+
this.events.forEach((type) => {
|
|
1910
|
+
this.root.addEventListener(type, this._handler);
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
/** Unregister all event listeners. */
|
|
1914
|
+
disconnect() {
|
|
1915
|
+
this.events.forEach((type) => {
|
|
1916
|
+
this.root.removeEventListener(type, this._handler);
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
getDragElem() {
|
|
1920
|
+
return this.dragElem;
|
|
1921
|
+
}
|
|
1922
|
+
isDragging() {
|
|
1923
|
+
return this.dragging;
|
|
1924
|
+
}
|
|
1925
|
+
stopDrag(cb_event) {
|
|
1926
|
+
if (this.dragging && this.opts.dragstop && cb_event) {
|
|
1927
|
+
cb_event.type = "dragstop";
|
|
1928
|
+
this.opts.dragstop(cb_event);
|
|
1929
|
+
}
|
|
1930
|
+
this.dragElem = null;
|
|
1931
|
+
this.dragging = false;
|
|
1932
|
+
}
|
|
1933
|
+
handleEvent(e) {
|
|
1934
|
+
const type = e.type;
|
|
1935
|
+
const opts = this.opts;
|
|
1936
|
+
const cb_event = {
|
|
1937
|
+
type: e.type,
|
|
1938
|
+
event: e,
|
|
1939
|
+
dragElem: this.dragElem,
|
|
1940
|
+
dx: e.pageX - this.start.x,
|
|
1941
|
+
dy: e.pageY - this.start.y,
|
|
1942
|
+
apply: undefined,
|
|
1943
|
+
};
|
|
1944
|
+
switch (type) {
|
|
1945
|
+
case "keydown":
|
|
1946
|
+
this.stopDrag(cb_event);
|
|
1947
|
+
break;
|
|
1948
|
+
case "mousedown":
|
|
1949
|
+
if (this.dragElem) {
|
|
1950
|
+
this.stopDrag(cb_event);
|
|
1951
|
+
break;
|
|
1952
|
+
}
|
|
1953
|
+
if (opts.selector) {
|
|
1954
|
+
let elem = e.target;
|
|
1955
|
+
if (elem.matches(opts.selector)) {
|
|
1956
|
+
this.dragElem = elem;
|
|
1957
|
+
}
|
|
1958
|
+
else {
|
|
1959
|
+
elem = elem.closest(opts.selector);
|
|
1960
|
+
if (elem) {
|
|
1961
|
+
this.dragElem = elem;
|
|
1962
|
+
}
|
|
1963
|
+
else {
|
|
1964
|
+
break; // no event delegation selector matched
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
this.start.x = e.pageX;
|
|
1969
|
+
this.start.y = e.pageY;
|
|
1970
|
+
this.start.altKey = e.altKey;
|
|
1971
|
+
this.start.ctrlKey = e.ctrlKey;
|
|
1972
|
+
this.start.metaKey = e.metaKey;
|
|
1973
|
+
this.start.shiftKey = e.shiftKey;
|
|
1974
|
+
break;
|
|
1975
|
+
case "mousemove":
|
|
1976
|
+
// TODO: debounce/throttle?
|
|
1977
|
+
// TODO: horizontal mode: ignore if dx unchanged
|
|
1978
|
+
if (!this.dragElem) {
|
|
1979
|
+
break;
|
|
1980
|
+
}
|
|
1981
|
+
if (!this.dragging) {
|
|
1982
|
+
if (opts.thresh) {
|
|
1983
|
+
const dist2 = cb_event.dx * cb_event.dx + cb_event.dy * cb_event.dy;
|
|
1984
|
+
if (dist2 < opts.thresh * opts.thresh) {
|
|
1985
|
+
break;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
cb_event.type = "dragstart";
|
|
1989
|
+
if (opts.dragstart(cb_event) === false) {
|
|
1990
|
+
this.stopDrag(cb_event);
|
|
1991
|
+
break;
|
|
1992
|
+
}
|
|
1993
|
+
this.dragging = true;
|
|
1994
|
+
}
|
|
1995
|
+
if (this.dragging && this.opts.drag) {
|
|
1996
|
+
cb_event.type = "drag";
|
|
1997
|
+
this.opts.drag(cb_event);
|
|
1998
|
+
}
|
|
1999
|
+
break;
|
|
2000
|
+
case "mouseup":
|
|
2001
|
+
if (!this.dragging) {
|
|
2002
|
+
this.stopDrag(cb_event);
|
|
2003
|
+
break;
|
|
2004
|
+
}
|
|
2005
|
+
if (e.button === 0) {
|
|
2006
|
+
cb_event.apply = true;
|
|
2007
|
+
}
|
|
2008
|
+
else {
|
|
2009
|
+
cb_event.apply = false;
|
|
2010
|
+
}
|
|
2011
|
+
this.stopDrag(cb_event);
|
|
2012
|
+
break;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/*!
|
|
2018
|
+
* Wunderbaum - ext-grid
|
|
2019
|
+
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
2020
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
2021
|
+
*/
|
|
2022
|
+
class GridExtension extends WunderbaumExtension {
|
|
2023
|
+
constructor(tree) {
|
|
2024
|
+
super(tree, "grid", {
|
|
2025
|
+
// throttle: 200,
|
|
2026
|
+
});
|
|
2027
|
+
this.observer = new DragObserver({
|
|
2028
|
+
root: window.document,
|
|
2029
|
+
selector: "span.wb-col-resizer",
|
|
2030
|
+
thresh: 4,
|
|
2031
|
+
// throttle: 400,
|
|
2032
|
+
dragstart: (e) => {
|
|
2033
|
+
return this.tree.element.contains(e.dragElem);
|
|
2034
|
+
},
|
|
2035
|
+
drag: (e) => {
|
|
2036
|
+
// TODO: throttle
|
|
2037
|
+
return this.handleDrag(e);
|
|
2038
|
+
},
|
|
2039
|
+
dragstop: (e) => {
|
|
2040
|
+
return this.handleDrag(e);
|
|
2041
|
+
},
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
init() {
|
|
2045
|
+
super.init();
|
|
2046
|
+
}
|
|
2047
|
+
handleDrag(e) {
|
|
2048
|
+
const info = Wunderbaum.getEventInfo(e.event);
|
|
2049
|
+
// this.tree.options.
|
|
2050
|
+
this.tree.log(`${e.type}(${e.dx})`, e, info);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1857
2054
|
/*!
|
|
1858
2055
|
* Wunderbaum - deferred
|
|
1859
2056
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1860
|
-
* v0.0.
|
|
2057
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1861
2058
|
*/
|
|
1862
2059
|
/**
|
|
1863
2060
|
* Deferred is a ES6 Promise, that exposes the resolve() and reject()` method.
|
|
@@ -1900,7 +2097,7 @@
|
|
|
1900
2097
|
/*!
|
|
1901
2098
|
* Wunderbaum - wunderbaum_node
|
|
1902
2099
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
1903
|
-
* v0.0.
|
|
2100
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
1904
2101
|
*/
|
|
1905
2102
|
/** Top-level properties that can be passed with `data`. */
|
|
1906
2103
|
const NODE_PROPS = new Set([
|
|
@@ -1937,15 +2134,31 @@
|
|
|
1937
2134
|
"unselectableIgnore",
|
|
1938
2135
|
"unselectableStatus",
|
|
1939
2136
|
]);
|
|
2137
|
+
/**
|
|
2138
|
+
* A single tree node.
|
|
2139
|
+
*
|
|
2140
|
+
* **NOTE:** <br>
|
|
2141
|
+
* Generally you should not modify properties directly, since this may break
|
|
2142
|
+
* the internal bookkeeping.
|
|
2143
|
+
*/
|
|
1940
2144
|
class WunderbaumNode {
|
|
1941
2145
|
constructor(tree, parent, data) {
|
|
1942
2146
|
var _a, _b;
|
|
2147
|
+
/** Reference key. Unlike {@link key}, a `refKey` may occur multiple
|
|
2148
|
+
* times within a tree (in this case we have 'clone nodes').
|
|
2149
|
+
* @see Use {@link setKey} to modify.
|
|
2150
|
+
*/
|
|
1943
2151
|
this.refKey = undefined;
|
|
1944
2152
|
this.children = null;
|
|
1945
2153
|
this.lazy = false;
|
|
2154
|
+
/** Expansion state.
|
|
2155
|
+
* @see {@link isExpandable}, {@link isExpanded}, {@link setExpanded}. */
|
|
1946
2156
|
this.expanded = false;
|
|
2157
|
+
/** Selection state.
|
|
2158
|
+
* @see {@link isSelected}, {@link setSelected}. */
|
|
1947
2159
|
this.selected = false;
|
|
1948
|
-
/** Additional classes added to `div.wb-row`.
|
|
2160
|
+
/** Additional classes added to `div.wb-row`.
|
|
2161
|
+
* @see {@link addClass}, {@link removeClass}, {@link toggleClass}. */
|
|
1949
2162
|
this.extraClasses = new Set();
|
|
1950
2163
|
/** Custom data that was passed to the constructor */
|
|
1951
2164
|
this.data = {};
|
|
@@ -2072,7 +2285,7 @@
|
|
|
2072
2285
|
// this.fixSelection3FromEndNodes();
|
|
2073
2286
|
// }
|
|
2074
2287
|
// this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null);
|
|
2075
|
-
this.tree.setModified(ChangeType.structure
|
|
2288
|
+
this.tree.setModified(ChangeType.structure);
|
|
2076
2289
|
return nodeList[0];
|
|
2077
2290
|
}
|
|
2078
2291
|
finally {
|
|
@@ -2111,7 +2324,8 @@
|
|
|
2111
2324
|
}
|
|
2112
2325
|
/**
|
|
2113
2326
|
* Apply a modification (or navigation) operation.
|
|
2114
|
-
*
|
|
2327
|
+
*
|
|
2328
|
+
* @see {@link Wunderbaum.applyCommand}
|
|
2115
2329
|
*/
|
|
2116
2330
|
applyCommand(cmd, opts) {
|
|
2117
2331
|
return this.tree.applyCommand(cmd, this, opts);
|
|
@@ -2204,8 +2418,7 @@
|
|
|
2204
2418
|
}
|
|
2205
2419
|
/** Find a node relative to self.
|
|
2206
2420
|
*
|
|
2207
|
-
* @
|
|
2208
|
-
* or a keyword ('down', 'first', 'last', 'left', 'parent', 'right', 'up').
|
|
2421
|
+
* @see {@link Wunderbaum.findRelatedNode|tree.findRelatedNode()}
|
|
2209
2422
|
*/
|
|
2210
2423
|
findRelatedNode(where, includeHidden = false) {
|
|
2211
2424
|
return this.tree.findRelatedNode(this, where, includeHidden);
|
|
@@ -2506,7 +2719,7 @@
|
|
|
2506
2719
|
assert(!this.parent);
|
|
2507
2720
|
tree.columns = data.columns;
|
|
2508
2721
|
delete data.columns;
|
|
2509
|
-
tree.
|
|
2722
|
+
tree.updateColumns({ calculateCols: false });
|
|
2510
2723
|
}
|
|
2511
2724
|
this._loadSourceObject(data);
|
|
2512
2725
|
}
|
|
@@ -2542,19 +2755,20 @@
|
|
|
2542
2755
|
this.setStatus(NodeStatusType.ok);
|
|
2543
2756
|
return;
|
|
2544
2757
|
}
|
|
2545
|
-
assert(isArray(source) || (source && source.url), "The lazyLoad event must return a node list, `{url: ...}
|
|
2758
|
+
assert(isArray(source) || (source && source.url), "The lazyLoad event must return a node list, `{url: ...}`, or false.");
|
|
2546
2759
|
await this.load(source); // also calls setStatus('ok')
|
|
2547
2760
|
if (wasExpanded) {
|
|
2548
2761
|
this.expanded = true;
|
|
2549
|
-
this.tree.
|
|
2762
|
+
this.tree.setModified(ChangeType.structure);
|
|
2550
2763
|
}
|
|
2551
2764
|
else {
|
|
2552
|
-
this.
|
|
2765
|
+
this.setModified(); // Fix expander icon to 'loaded'
|
|
2553
2766
|
}
|
|
2554
2767
|
}
|
|
2555
2768
|
catch (e) {
|
|
2769
|
+
this.logError("Error during loadLazy()", e);
|
|
2770
|
+
this._callEvent("error", { error: e });
|
|
2556
2771
|
this.setStatus(NodeStatusType.error, "" + e);
|
|
2557
|
-
// } finally {
|
|
2558
2772
|
}
|
|
2559
2773
|
return;
|
|
2560
2774
|
}
|
|
@@ -2702,7 +2916,7 @@
|
|
|
2702
2916
|
n.tree = targetNode.tree;
|
|
2703
2917
|
}, true);
|
|
2704
2918
|
}
|
|
2705
|
-
tree.
|
|
2919
|
+
tree.setModified(ChangeType.structure);
|
|
2706
2920
|
// TODO: fix selection state
|
|
2707
2921
|
// TODO: fix active state
|
|
2708
2922
|
}
|
|
@@ -2722,31 +2936,33 @@
|
|
|
2722
2936
|
// Allow to pass 'ArrowLeft' instead of 'left'
|
|
2723
2937
|
where = KEY_TO_ACTION_DICT[where] || where;
|
|
2724
2938
|
// Otherwise activate or focus the related node
|
|
2725
|
-
|
|
2726
|
-
if (node) {
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
node.
|
|
2733
|
-
if ((options === null || options === void 0 ? void 0 : options.activate) === false) {
|
|
2734
|
-
return Promise.resolve(this);
|
|
2735
|
-
}
|
|
2736
|
-
return node.setActive(true, { event: options === null || options === void 0 ? void 0 : options.event });
|
|
2939
|
+
const node = this.findRelatedNode(where);
|
|
2940
|
+
if (!node) {
|
|
2941
|
+
this.logWarn(`Could not find related node '${where}'.`);
|
|
2942
|
+
return Promise.resolve(this);
|
|
2943
|
+
}
|
|
2944
|
+
// setFocus/setActive will scroll later (if autoScroll is specified)
|
|
2945
|
+
try {
|
|
2946
|
+
node.makeVisible({ scrollIntoView: false });
|
|
2737
2947
|
}
|
|
2738
|
-
|
|
2739
|
-
|
|
2948
|
+
catch (e) { } // #272
|
|
2949
|
+
node.setFocus();
|
|
2950
|
+
if ((options === null || options === void 0 ? void 0 : options.activate) === false) {
|
|
2951
|
+
return Promise.resolve(this);
|
|
2952
|
+
}
|
|
2953
|
+
return node.setActive(true, { event: options === null || options === void 0 ? void 0 : options.event });
|
|
2740
2954
|
}
|
|
2741
2955
|
/** Delete this node and all descendants. */
|
|
2742
2956
|
remove() {
|
|
2743
2957
|
const tree = this.tree;
|
|
2744
2958
|
const pos = this.parent.children.indexOf(this);
|
|
2959
|
+
this.triggerModify("remove");
|
|
2745
2960
|
this.parent.children.splice(pos, 1);
|
|
2746
2961
|
this.visit((n) => {
|
|
2747
2962
|
n.removeMarkup();
|
|
2748
2963
|
tree._unregisterNode(n);
|
|
2749
2964
|
}, true);
|
|
2965
|
+
tree.setModified(ChangeType.structure);
|
|
2750
2966
|
}
|
|
2751
2967
|
/** Remove all descendants of this node. */
|
|
2752
2968
|
removeChildren() {
|
|
@@ -2778,7 +2994,7 @@
|
|
|
2778
2994
|
if (!this.isRootNode()) {
|
|
2779
2995
|
this.expanded = false;
|
|
2780
2996
|
}
|
|
2781
|
-
this.tree.
|
|
2997
|
+
this.tree.setModified(ChangeType.structure);
|
|
2782
2998
|
}
|
|
2783
2999
|
/** Remove all HTML markup from the DOM. */
|
|
2784
3000
|
removeMarkup() {
|
|
@@ -2871,6 +3087,7 @@
|
|
|
2871
3087
|
const activeColIdx = tree.navMode === NavigationMode.row ? null : tree.activeColIdx;
|
|
2872
3088
|
// let colElems: HTMLElement[];
|
|
2873
3089
|
const isNew = !rowDiv;
|
|
3090
|
+
assert(!isNew || (opts && opts.after), "opts.after expected, unless updating");
|
|
2874
3091
|
assert(!this.isRootNode());
|
|
2875
3092
|
//
|
|
2876
3093
|
let rowClasses = ["wb-row"];
|
|
@@ -2922,7 +3139,7 @@
|
|
|
2922
3139
|
nodeElem.appendChild(elem);
|
|
2923
3140
|
ofsTitlePx += ICON_WIDTH;
|
|
2924
3141
|
}
|
|
2925
|
-
if (level > treeOptions.minExpandLevel) {
|
|
3142
|
+
if (!treeOptions.minExpandLevel || level > treeOptions.minExpandLevel) {
|
|
2926
3143
|
expanderSpan = document.createElement("i");
|
|
2927
3144
|
nodeElem.appendChild(expanderSpan);
|
|
2928
3145
|
ofsTitlePx += ICON_WIDTH;
|
|
@@ -3013,11 +3230,11 @@
|
|
|
3013
3230
|
if (this.titleWithHighlight) {
|
|
3014
3231
|
titleSpan.innerHTML = this.titleWithHighlight;
|
|
3015
3232
|
}
|
|
3016
|
-
else if (tree.options.escapeTitles) {
|
|
3017
|
-
titleSpan.textContent = this.title;
|
|
3018
|
-
}
|
|
3019
3233
|
else {
|
|
3020
|
-
|
|
3234
|
+
// } else if (tree.options.escapeTitles) {
|
|
3235
|
+
titleSpan.textContent = this.title;
|
|
3236
|
+
// } else {
|
|
3237
|
+
// titleSpan.innerHTML = this.title;
|
|
3021
3238
|
}
|
|
3022
3239
|
// Set the width of the title span, so overflow ellipsis work
|
|
3023
3240
|
if (!treeOptions.skeleton) {
|
|
@@ -3051,9 +3268,19 @@
|
|
|
3051
3268
|
});
|
|
3052
3269
|
}
|
|
3053
3270
|
// Attach to DOM as late as possible
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3271
|
+
if (isNew) {
|
|
3272
|
+
const after = opts ? opts.after : "last";
|
|
3273
|
+
switch (after) {
|
|
3274
|
+
case "first":
|
|
3275
|
+
tree.nodeListElement.prepend(rowDiv);
|
|
3276
|
+
break;
|
|
3277
|
+
case "last":
|
|
3278
|
+
tree.nodeListElement.appendChild(rowDiv);
|
|
3279
|
+
break;
|
|
3280
|
+
default:
|
|
3281
|
+
opts.after.after(rowDiv);
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3057
3284
|
}
|
|
3058
3285
|
/**
|
|
3059
3286
|
* Remove all children, collapse, and set the lazy-flag, so that the lazyLoad
|
|
@@ -3064,7 +3291,7 @@
|
|
|
3064
3291
|
this.expanded = false;
|
|
3065
3292
|
this.lazy = true;
|
|
3066
3293
|
this.children = null;
|
|
3067
|
-
this.tree.
|
|
3294
|
+
this.tree.setModified(ChangeType.structure);
|
|
3068
3295
|
}
|
|
3069
3296
|
/** Convert node (or whole branch) into a plain object.
|
|
3070
3297
|
*
|
|
@@ -3127,14 +3354,15 @@
|
|
|
3127
3354
|
*
|
|
3128
3355
|
* Evaluation sequence:
|
|
3129
3356
|
*
|
|
3130
|
-
* If `tree.options.<name>` is a callback that returns something, use that.
|
|
3131
|
-
* Else if `node.<name>` is defined, use that.
|
|
3132
|
-
* Else if `tree.types[<node.type>]` is a value, use that.
|
|
3133
|
-
* Else if `tree.options.<name>` is a value, use that.
|
|
3134
|
-
* Else use `defaultValue`.
|
|
3357
|
+
* - If `tree.options.<name>` is a callback that returns something, use that.
|
|
3358
|
+
* - Else if `node.<name>` is defined, use that.
|
|
3359
|
+
* - Else if `tree.types[<node.type>]` is a value, use that.
|
|
3360
|
+
* - Else if `tree.options.<name>` is a value, use that.
|
|
3361
|
+
* - Else use `defaultValue`.
|
|
3135
3362
|
*
|
|
3136
3363
|
* @param name name of the option property (on node and tree)
|
|
3137
3364
|
* @param defaultValue return this if nothing else matched
|
|
3365
|
+
* {@link Wunderbaum.getOption|Wunderbaum.getOption()}
|
|
3138
3366
|
*/
|
|
3139
3367
|
getOption(name, defaultValue) {
|
|
3140
3368
|
let tree = this.tree;
|
|
@@ -3169,15 +3397,21 @@
|
|
|
3169
3397
|
// Use value from value options dict, fallback do default
|
|
3170
3398
|
return value !== null && value !== void 0 ? value : defaultValue;
|
|
3171
3399
|
}
|
|
3400
|
+
/** Make sure that this node is visible in the viewport.
|
|
3401
|
+
* @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo()}
|
|
3402
|
+
*/
|
|
3172
3403
|
async scrollIntoView(options) {
|
|
3173
3404
|
return this.tree.scrollTo(this);
|
|
3174
3405
|
}
|
|
3406
|
+
/**
|
|
3407
|
+
* Activate this node, deactivate previous, send events, activate column and scroll int viewport.
|
|
3408
|
+
*/
|
|
3175
3409
|
async setActive(flag = true, options) {
|
|
3176
3410
|
const tree = this.tree;
|
|
3177
3411
|
const prev = tree.activeNode;
|
|
3178
3412
|
const retrigger = options === null || options === void 0 ? void 0 : options.retrigger;
|
|
3179
|
-
const
|
|
3180
|
-
if (!
|
|
3413
|
+
const noEvents = options === null || options === void 0 ? void 0 : options.noEvents;
|
|
3414
|
+
if (!noEvents) {
|
|
3181
3415
|
let orgEvent = options === null || options === void 0 ? void 0 : options.event;
|
|
3182
3416
|
if (flag) {
|
|
3183
3417
|
if (prev !== this || retrigger) {
|
|
@@ -3192,7 +3426,7 @@
|
|
|
3192
3426
|
orgEvent: orgEvent,
|
|
3193
3427
|
}) === false) {
|
|
3194
3428
|
tree.activeNode = null;
|
|
3195
|
-
prev === null || prev === void 0 ? void 0 : prev.
|
|
3429
|
+
prev === null || prev === void 0 ? void 0 : prev.setModified();
|
|
3196
3430
|
return;
|
|
3197
3431
|
}
|
|
3198
3432
|
}
|
|
@@ -3203,8 +3437,8 @@
|
|
|
3203
3437
|
}
|
|
3204
3438
|
if (prev !== this) {
|
|
3205
3439
|
tree.activeNode = this;
|
|
3206
|
-
prev === null || prev === void 0 ? void 0 : prev.
|
|
3207
|
-
this.
|
|
3440
|
+
prev === null || prev === void 0 ? void 0 : prev.setModified();
|
|
3441
|
+
this.setModified();
|
|
3208
3442
|
}
|
|
3209
3443
|
if (options &&
|
|
3210
3444
|
options.colIdx != null &&
|
|
@@ -3215,57 +3449,62 @@
|
|
|
3215
3449
|
// requestAnimationFrame(() => {
|
|
3216
3450
|
// this.scrollIntoView();
|
|
3217
3451
|
// })
|
|
3218
|
-
this.scrollIntoView();
|
|
3219
|
-
}
|
|
3220
|
-
setDirty(type) {
|
|
3221
|
-
if (this.tree._disableUpdate) {
|
|
3222
|
-
return;
|
|
3223
|
-
}
|
|
3224
|
-
if (type === ChangeType.structure) {
|
|
3225
|
-
this.tree.updateViewport();
|
|
3226
|
-
}
|
|
3227
|
-
else if (this._rowElem) {
|
|
3228
|
-
// otherwise not in viewport, so no need to render
|
|
3229
|
-
this.render();
|
|
3230
|
-
}
|
|
3452
|
+
return this.scrollIntoView();
|
|
3231
3453
|
}
|
|
3454
|
+
/**
|
|
3455
|
+
* Expand or collapse this node.
|
|
3456
|
+
*/
|
|
3232
3457
|
async setExpanded(flag = true, options) {
|
|
3233
3458
|
// alert("" + this.getLevel() + ", "+ this.getOption("minExpandLevel");
|
|
3234
3459
|
if (!flag &&
|
|
3235
3460
|
this.isExpanded() &&
|
|
3236
3461
|
this.getLevel() < this.getOption("minExpandLevel") &&
|
|
3237
3462
|
!getOption(options, "force")) {
|
|
3238
|
-
this.logDebug("Ignored collapse request.");
|
|
3463
|
+
this.logDebug("Ignored collapse request below expandLevel.");
|
|
3239
3464
|
return;
|
|
3240
3465
|
}
|
|
3241
3466
|
if (flag && this.lazy && this.children == null) {
|
|
3242
3467
|
await this.loadLazy();
|
|
3243
3468
|
}
|
|
3244
3469
|
this.expanded = flag;
|
|
3245
|
-
this.
|
|
3246
|
-
}
|
|
3247
|
-
setIcon() {
|
|
3248
|
-
throw new Error("Not yet implemented");
|
|
3249
|
-
// this.setDirty(ChangeType.status);
|
|
3470
|
+
this.tree.setModified(ChangeType.structure);
|
|
3250
3471
|
}
|
|
3472
|
+
/**
|
|
3473
|
+
* Set keyboard focus here.
|
|
3474
|
+
* @see {@link setActive}
|
|
3475
|
+
*/
|
|
3251
3476
|
setFocus(flag = true, options) {
|
|
3252
3477
|
const prev = this.tree.focusNode;
|
|
3253
3478
|
this.tree.focusNode = this;
|
|
3254
|
-
prev === null || prev === void 0 ? void 0 : prev.
|
|
3255
|
-
this.
|
|
3479
|
+
prev === null || prev === void 0 ? void 0 : prev.setModified();
|
|
3480
|
+
this.setModified();
|
|
3256
3481
|
}
|
|
3482
|
+
/** Set a new icon path or class. */
|
|
3483
|
+
setIcon() {
|
|
3484
|
+
throw new Error("Not yet implemented");
|
|
3485
|
+
// this.setModified();
|
|
3486
|
+
}
|
|
3487
|
+
/** Change node's {@link key} and/or {@link refKey}. */
|
|
3488
|
+
setKey(key, refKey) {
|
|
3489
|
+
throw new Error("Not yet implemented");
|
|
3490
|
+
}
|
|
3491
|
+
/** Schedule a render, typically called to update after a status or data change. */
|
|
3492
|
+
setModified(change = ChangeType.status) {
|
|
3493
|
+
assert(change === ChangeType.status);
|
|
3494
|
+
this.tree.setModified(ChangeType.row, this);
|
|
3495
|
+
}
|
|
3496
|
+
/** Modify the check/uncheck state. */
|
|
3257
3497
|
setSelected(flag = true, options) {
|
|
3258
3498
|
const prev = this.selected;
|
|
3259
3499
|
if (!!flag !== prev) {
|
|
3260
3500
|
this._callEvent("select", { flag: flag });
|
|
3261
3501
|
}
|
|
3262
3502
|
this.selected = !!flag;
|
|
3263
|
-
this.
|
|
3503
|
+
this.setModified();
|
|
3264
3504
|
}
|
|
3265
|
-
/**
|
|
3266
|
-
*/
|
|
3505
|
+
/** Display node status (ok, loading, error, noData) using styles and a dummy child node. */
|
|
3267
3506
|
setStatus(status, message, details) {
|
|
3268
|
-
|
|
3507
|
+
const tree = this.tree;
|
|
3269
3508
|
let statusNode = null;
|
|
3270
3509
|
const _clearStatusNode = () => {
|
|
3271
3510
|
// Remove dedicated dummy node, if any
|
|
@@ -3336,12 +3575,13 @@
|
|
|
3336
3575
|
default:
|
|
3337
3576
|
error("invalid node status " + status);
|
|
3338
3577
|
}
|
|
3339
|
-
tree.
|
|
3578
|
+
tree.setModified(ChangeType.structure);
|
|
3340
3579
|
return statusNode;
|
|
3341
3580
|
}
|
|
3581
|
+
/** Rename this node. */
|
|
3342
3582
|
setTitle(title) {
|
|
3343
3583
|
this.title = title;
|
|
3344
|
-
this.
|
|
3584
|
+
this.setModified();
|
|
3345
3585
|
// this.triggerModify("rename"); // TODO
|
|
3346
3586
|
}
|
|
3347
3587
|
/**
|
|
@@ -3362,10 +3602,16 @@
|
|
|
3362
3602
|
* @param {object} [extra]
|
|
3363
3603
|
*/
|
|
3364
3604
|
triggerModify(operation, extra) {
|
|
3605
|
+
if (!this.parent) {
|
|
3606
|
+
return;
|
|
3607
|
+
}
|
|
3365
3608
|
this.parent.triggerModifyChild(operation, this, extra);
|
|
3366
3609
|
}
|
|
3367
|
-
/**
|
|
3368
|
-
*
|
|
3610
|
+
/**
|
|
3611
|
+
* Call fn(node) for all child nodes in hierarchical order (depth-first).
|
|
3612
|
+
*
|
|
3613
|
+
* Stop iteration, if fn() returns false. Skip current branch, if fn()
|
|
3614
|
+
* returns "skip".<br>
|
|
3369
3615
|
* Return false if iteration was stopped.
|
|
3370
3616
|
*
|
|
3371
3617
|
* @param {function} callback the callback function.
|
|
@@ -3409,7 +3655,8 @@
|
|
|
3409
3655
|
}
|
|
3410
3656
|
return true;
|
|
3411
3657
|
}
|
|
3412
|
-
/**
|
|
3658
|
+
/**
|
|
3659
|
+
* Call fn(node) for all sibling nodes.<br>
|
|
3413
3660
|
* Stop iteration, if fn() returns false.<br>
|
|
3414
3661
|
* Return false if iteration was stopped.
|
|
3415
3662
|
*
|
|
@@ -3440,7 +3687,7 @@
|
|
|
3440
3687
|
/*!
|
|
3441
3688
|
* Wunderbaum - ext-edit
|
|
3442
3689
|
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
3443
|
-
* v0.0.
|
|
3690
|
+
* v0.0.3, Mon, 18 Apr 2022 11:52:44 GMT (https://github.com/mar10/wunderbaum)
|
|
3444
3691
|
*/
|
|
3445
3692
|
// const START_MARKER = "\uFFF7";
|
|
3446
3693
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -3558,7 +3805,7 @@
|
|
|
3558
3805
|
break;
|
|
3559
3806
|
case "F2":
|
|
3560
3807
|
if (trigger.indexOf("F2") >= 0) {
|
|
3561
|
-
// tree.
|
|
3808
|
+
// tree.setNavigationMode(NavigationMode.cellEdit);
|
|
3562
3809
|
this.startEditTitle();
|
|
3563
3810
|
return false;
|
|
3564
3811
|
}
|
|
@@ -3599,6 +3846,7 @@
|
|
|
3599
3846
|
if (validity) {
|
|
3600
3847
|
// Permanently apply input validations (CSS and tooltip)
|
|
3601
3848
|
inputElem.addEventListener("keydown", (e) => {
|
|
3849
|
+
inputElem.setCustomValidity("");
|
|
3602
3850
|
if (!inputElem.reportValidity()) ;
|
|
3603
3851
|
});
|
|
3604
3852
|
}
|
|
@@ -3639,6 +3887,11 @@
|
|
|
3639
3887
|
}
|
|
3640
3888
|
node.logDebug(`stopEditTitle(${apply})`, opts, focusElem, newValue);
|
|
3641
3889
|
if (apply && newValue !== null && newValue !== node.title) {
|
|
3890
|
+
const errMsg = focusElem.validationMessage;
|
|
3891
|
+
if (errMsg) {
|
|
3892
|
+
// input element's native validation failed
|
|
3893
|
+
throw new Error(`Input validation failed for "${newValue}": ${errMsg}.`);
|
|
3894
|
+
}
|
|
3642
3895
|
const colElem = node.getColElem(0);
|
|
3643
3896
|
this._applyChange("edit.apply", node, colElem, {
|
|
3644
3897
|
oldValue: node.title,
|
|
@@ -3725,12 +3978,12 @@
|
|
|
3725
3978
|
* Copyright (c) 2021-2022, Martin Wendt (https://wwWendt.de).
|
|
3726
3979
|
* Released under the MIT license.
|
|
3727
3980
|
*
|
|
3728
|
-
* @version v0.0.
|
|
3729
|
-
* @date
|
|
3981
|
+
* @version v0.0.3
|
|
3982
|
+
* @date Mon, 18 Apr 2022 11:52:44 GMT
|
|
3730
3983
|
*/
|
|
3731
3984
|
// const class_prefix = "wb-";
|
|
3732
3985
|
// const node_props: string[] = ["title", "key", "refKey"];
|
|
3733
|
-
const MAX_CHANGED_NODES = 10;
|
|
3986
|
+
// const MAX_CHANGED_NODES = 10;
|
|
3734
3987
|
/**
|
|
3735
3988
|
* A persistent plain object or array.
|
|
3736
3989
|
*
|
|
@@ -3742,36 +3995,43 @@
|
|
|
3742
3995
|
this.extensions = {};
|
|
3743
3996
|
this.keyMap = new Map();
|
|
3744
3997
|
this.refKeyMap = new Map();
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3998
|
+
// protected viewNodes = new Set<WunderbaumNode>();
|
|
3999
|
+
this.treeRowCount = 0;
|
|
4000
|
+
this._disableUpdateCount = 0;
|
|
3748
4001
|
// protected eventHandlers : Array<function> = [];
|
|
4002
|
+
/** Currently active node if any. */
|
|
3749
4003
|
this.activeNode = null;
|
|
4004
|
+
/** Current node hat has keyboard focus if any. */
|
|
3750
4005
|
this.focusNode = null;
|
|
3751
|
-
this._disableUpdate = 0;
|
|
3752
|
-
this._disableUpdateCount = 0;
|
|
3753
4006
|
/** Shared properties, referenced by `node.type`. */
|
|
3754
4007
|
this.types = {};
|
|
3755
4008
|
/** List of column definitions. */
|
|
3756
4009
|
this.columns = [];
|
|
3757
4010
|
this._columnsById = {};
|
|
3758
4011
|
// Modification Status
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
4012
|
+
// protected changedSince = 0;
|
|
4013
|
+
// protected changes = new Set<ChangeType>();
|
|
4014
|
+
// protected changedNodes = new Set<WunderbaumNode>();
|
|
4015
|
+
this.changeRedrawRequestPending = false;
|
|
4016
|
+
/** Expose some useful methods of the util.ts module as `tree._util`. */
|
|
4017
|
+
this._util = util;
|
|
3762
4018
|
// --- FILTER ---
|
|
3763
4019
|
this.filterMode = null;
|
|
3764
4020
|
// --- KEYNAV ---
|
|
4021
|
+
/** @internal Use `setColumn()`/`getActiveColElem()`*/
|
|
3765
4022
|
this.activeColIdx = 0;
|
|
4023
|
+
/** @internal */
|
|
3766
4024
|
this.navMode = NavigationMode.row;
|
|
4025
|
+
/** @internal */
|
|
3767
4026
|
this.lastQuicksearchTime = 0;
|
|
4027
|
+
/** @internal */
|
|
3768
4028
|
this.lastQuicksearchTerm = "";
|
|
3769
4029
|
// --- EDIT ---
|
|
3770
4030
|
this.lastClickTime = 0;
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
this.log = this.logDebug;
|
|
4031
|
+
/** Alias for {@link Wunderbaum.logDebug}.
|
|
4032
|
+
* @alias Wunderbaum.logDebug
|
|
4033
|
+
*/
|
|
4034
|
+
this.log = this.logDebug;
|
|
3775
4035
|
let opts = (this.options = extend({
|
|
3776
4036
|
id: null,
|
|
3777
4037
|
source: null,
|
|
@@ -3782,7 +4042,7 @@
|
|
|
3782
4042
|
rowHeightPx: ROW_HEIGHT,
|
|
3783
4043
|
columns: null,
|
|
3784
4044
|
types: null,
|
|
3785
|
-
escapeTitles: true,
|
|
4045
|
+
// escapeTitles: true,
|
|
3786
4046
|
showSpinner: false,
|
|
3787
4047
|
checkbox: true,
|
|
3788
4048
|
minExpandLevel: 0,
|
|
@@ -3839,6 +4099,7 @@
|
|
|
3839
4099
|
this._registerExtension(new EditExtension(this));
|
|
3840
4100
|
this._registerExtension(new FilterExtension(this));
|
|
3841
4101
|
this._registerExtension(new DndExtension(this));
|
|
4102
|
+
this._registerExtension(new GridExtension(this));
|
|
3842
4103
|
this._registerExtension(new LoggerExtension(this));
|
|
3843
4104
|
// --- Evaluate options
|
|
3844
4105
|
this.columns = opts.columns;
|
|
@@ -3932,11 +4193,9 @@
|
|
|
3932
4193
|
var _a;
|
|
3933
4194
|
(_a = this.element.querySelector("progress.spinner")) === null || _a === void 0 ? void 0 : _a.remove();
|
|
3934
4195
|
this.element.classList.remove("wb-initializing");
|
|
3935
|
-
// this.updateViewport();
|
|
3936
4196
|
});
|
|
3937
4197
|
}
|
|
3938
4198
|
else {
|
|
3939
|
-
// this.updateViewport();
|
|
3940
4199
|
readyDeferred.resolve();
|
|
3941
4200
|
}
|
|
3942
4201
|
// TODO: This is sometimes required, because this.element.clientWidth
|
|
@@ -3946,13 +4205,10 @@
|
|
|
3946
4205
|
}, 50);
|
|
3947
4206
|
// --- Bind listeners
|
|
3948
4207
|
this.scrollContainer.addEventListener("scroll", (e) => {
|
|
3949
|
-
this.
|
|
4208
|
+
this.setModified(ChangeType.vscroll);
|
|
3950
4209
|
});
|
|
3951
|
-
// window.addEventListener("resize", (e: Event) => {
|
|
3952
|
-
// this.updateViewport();
|
|
3953
|
-
// });
|
|
3954
4210
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
3955
|
-
this.
|
|
4211
|
+
this.setModified(ChangeType.vscroll);
|
|
3956
4212
|
console.log("ResizeObserver: Size changed", entries);
|
|
3957
4213
|
});
|
|
3958
4214
|
this.resizeObserver.observe(this.element);
|
|
@@ -4009,37 +4265,18 @@
|
|
|
4009
4265
|
forceClose: true,
|
|
4010
4266
|
});
|
|
4011
4267
|
}
|
|
4012
|
-
// if (flag && !this.activeNode ) {
|
|
4013
|
-
// setTimeout(() => {
|
|
4014
|
-
// if (!this.activeNode) {
|
|
4015
|
-
// const firstNode = this.getFirstChild();
|
|
4016
|
-
// if (firstNode && !firstNode?.isStatusNode()) {
|
|
4017
|
-
// firstNode.logInfo("Activate on focus", e);
|
|
4018
|
-
// firstNode.setActive(true, { event: e });
|
|
4019
|
-
// }
|
|
4020
|
-
// }
|
|
4021
|
-
// }, 10);
|
|
4022
|
-
// }
|
|
4023
4268
|
});
|
|
4024
4269
|
}
|
|
4025
|
-
/**
|
|
4026
|
-
|
|
4027
|
-
// const coldivs = "<span class='wb-col'></span>".repeat(this.columns.length);
|
|
4028
|
-
// this.element.innerHTML = `
|
|
4029
|
-
// <div class='wb-header'>
|
|
4030
|
-
// <div class='wb-row'>
|
|
4031
|
-
// ${coldivs}
|
|
4032
|
-
// </div>
|
|
4033
|
-
// </div>`;
|
|
4034
|
-
// }
|
|
4035
|
-
/** Return a Wunderbaum instance, from element, index, or event.
|
|
4270
|
+
/**
|
|
4271
|
+
* Return a Wunderbaum instance, from element, id, index, or event.
|
|
4036
4272
|
*
|
|
4037
|
-
*
|
|
4038
|
-
* getTree();
|
|
4039
|
-
* getTree(1);
|
|
4040
|
-
* getTree(event);
|
|
4041
|
-
* getTree("foo");
|
|
4273
|
+
* ```js
|
|
4274
|
+
* getTree(); // Get first Wunderbaum instance on page
|
|
4275
|
+
* getTree(1); // Get second Wunderbaum instance on page
|
|
4276
|
+
* getTree(event); // Get tree for this mouse- or keyboard event
|
|
4277
|
+
* getTree("foo"); // Get tree for this `tree.options.id`
|
|
4042
4278
|
* getTree("#tree"); // Get tree for this matching element
|
|
4279
|
+
* ```
|
|
4043
4280
|
*/
|
|
4044
4281
|
static getTree(el) {
|
|
4045
4282
|
if (el instanceof Wunderbaum) {
|
|
@@ -4080,9 +4317,8 @@
|
|
|
4080
4317
|
}
|
|
4081
4318
|
return null;
|
|
4082
4319
|
}
|
|
4083
|
-
/**
|
|
4084
|
-
*
|
|
4085
|
-
* @param el
|
|
4320
|
+
/**
|
|
4321
|
+
* Return a WunderbaumNode instance from element or event.
|
|
4086
4322
|
*/
|
|
4087
4323
|
static getNode(el) {
|
|
4088
4324
|
if (!el) {
|
|
@@ -4104,7 +4340,7 @@
|
|
|
4104
4340
|
}
|
|
4105
4341
|
return null;
|
|
4106
4342
|
}
|
|
4107
|
-
/** */
|
|
4343
|
+
/** @internal */
|
|
4108
4344
|
_registerExtension(extension) {
|
|
4109
4345
|
this.extensionList.push(extension);
|
|
4110
4346
|
this.extensions[extension.id] = extension;
|
|
@@ -4146,7 +4382,7 @@
|
|
|
4146
4382
|
node.tree = null;
|
|
4147
4383
|
node.parent = null;
|
|
4148
4384
|
// node.title = "DISPOSED: " + node.title
|
|
4149
|
-
this.viewNodes.delete(node);
|
|
4385
|
+
// this.viewNodes.delete(node);
|
|
4150
4386
|
node.removeMarkup();
|
|
4151
4387
|
}
|
|
4152
4388
|
/** Call all hook methods of all registered extensions.*/
|
|
@@ -4164,7 +4400,9 @@
|
|
|
4164
4400
|
}
|
|
4165
4401
|
return res;
|
|
4166
4402
|
}
|
|
4167
|
-
/**
|
|
4403
|
+
/**
|
|
4404
|
+
* Call tree method or extension method if defined.
|
|
4405
|
+
*
|
|
4168
4406
|
* Example:
|
|
4169
4407
|
* ```js
|
|
4170
4408
|
* tree._callMethod("edit.startEdit", "arg1", "arg2")
|
|
@@ -4181,7 +4419,9 @@
|
|
|
4181
4419
|
this.logError(`Calling undefined method '${name}()'.`);
|
|
4182
4420
|
}
|
|
4183
4421
|
}
|
|
4184
|
-
/**
|
|
4422
|
+
/**
|
|
4423
|
+
* Call event handler if defined in tree or tree.EXTENSION options.
|
|
4424
|
+
*
|
|
4185
4425
|
* Example:
|
|
4186
4426
|
* ```js
|
|
4187
4427
|
* tree._callEvent("edit.beforeEdit", {foo: 42})
|
|
@@ -4197,27 +4437,33 @@
|
|
|
4197
4437
|
// this.logError(`Triggering undefined event '${name}'.`)
|
|
4198
4438
|
}
|
|
4199
4439
|
}
|
|
4200
|
-
/** Return the
|
|
4201
|
-
|
|
4202
|
-
let topIdx, node;
|
|
4203
|
-
if (complete) {
|
|
4204
|
-
topIdx = Math.ceil(this.scrollContainer.scrollTop / ROW_HEIGHT);
|
|
4205
|
-
}
|
|
4206
|
-
else {
|
|
4207
|
-
topIdx = Math.floor(this.scrollContainer.scrollTop / ROW_HEIGHT);
|
|
4208
|
-
}
|
|
4440
|
+
/** Return the node for given row index. */
|
|
4441
|
+
_getNodeByRowIdx(idx) {
|
|
4209
4442
|
// TODO: start searching from active node (reverse)
|
|
4443
|
+
let node = null;
|
|
4210
4444
|
this.visitRows((n) => {
|
|
4211
|
-
if (n._rowIdx ===
|
|
4445
|
+
if (n._rowIdx === idx) {
|
|
4212
4446
|
node = n;
|
|
4213
4447
|
return false;
|
|
4214
4448
|
}
|
|
4215
4449
|
});
|
|
4216
4450
|
return node;
|
|
4217
4451
|
}
|
|
4218
|
-
/** Return the
|
|
4452
|
+
/** Return the topmost visible node in the viewport. */
|
|
4453
|
+
_firstNodeInView(complete = true) {
|
|
4454
|
+
let topIdx;
|
|
4455
|
+
const gracePy = 1; // ignore subpixel scrolling
|
|
4456
|
+
if (complete) {
|
|
4457
|
+
topIdx = Math.ceil((this.scrollContainer.scrollTop - gracePy) / ROW_HEIGHT);
|
|
4458
|
+
}
|
|
4459
|
+
else {
|
|
4460
|
+
topIdx = Math.floor(this.scrollContainer.scrollTop / ROW_HEIGHT);
|
|
4461
|
+
}
|
|
4462
|
+
return this._getNodeByRowIdx(topIdx);
|
|
4463
|
+
}
|
|
4464
|
+
/** Return the lowest visible node in the viewport. */
|
|
4219
4465
|
_lastNodeInView(complete = true) {
|
|
4220
|
-
let bottomIdx
|
|
4466
|
+
let bottomIdx;
|
|
4221
4467
|
if (complete) {
|
|
4222
4468
|
bottomIdx =
|
|
4223
4469
|
Math.floor((this.scrollContainer.scrollTop + this.scrollContainer.clientHeight) /
|
|
@@ -4228,16 +4474,10 @@
|
|
|
4228
4474
|
Math.ceil((this.scrollContainer.scrollTop + this.scrollContainer.clientHeight) /
|
|
4229
4475
|
ROW_HEIGHT) - 1;
|
|
4230
4476
|
}
|
|
4231
|
-
|
|
4232
|
-
this.
|
|
4233
|
-
if (n._rowIdx === bottomIdx) {
|
|
4234
|
-
node = n;
|
|
4235
|
-
return false;
|
|
4236
|
-
}
|
|
4237
|
-
});
|
|
4238
|
-
return node;
|
|
4477
|
+
bottomIdx = Math.min(bottomIdx, this.count(true) - 1);
|
|
4478
|
+
return this._getNodeByRowIdx(bottomIdx);
|
|
4239
4479
|
}
|
|
4240
|
-
/** Return preceeding visible node in the viewport */
|
|
4480
|
+
/** Return preceeding visible node in the viewport. */
|
|
4241
4481
|
_getPrevNodeInView(node, ofs = 1) {
|
|
4242
4482
|
this.visitRows((n) => {
|
|
4243
4483
|
node = n;
|
|
@@ -4247,7 +4487,7 @@
|
|
|
4247
4487
|
}, { reverse: true, start: node || this.getActiveNode() });
|
|
4248
4488
|
return node;
|
|
4249
4489
|
}
|
|
4250
|
-
/** Return following visible node in the viewport */
|
|
4490
|
+
/** Return following visible node in the viewport. */
|
|
4251
4491
|
_getNextNodeInView(node, ofs = 1) {
|
|
4252
4492
|
this.visitRows((n) => {
|
|
4253
4493
|
node = n;
|
|
@@ -4257,10 +4497,15 @@
|
|
|
4257
4497
|
}, { reverse: false, start: node || this.getActiveNode() });
|
|
4258
4498
|
return node;
|
|
4259
4499
|
}
|
|
4500
|
+
/**
|
|
4501
|
+
* Append (or insert) a list of toplevel nodes.
|
|
4502
|
+
*
|
|
4503
|
+
* @see {@link WunderbaumNode.addChildren}
|
|
4504
|
+
*/
|
|
4260
4505
|
addChildren(nodeData, options) {
|
|
4261
4506
|
return this.root.addChildren(nodeData, options);
|
|
4262
4507
|
}
|
|
4263
|
-
|
|
4508
|
+
/**
|
|
4264
4509
|
* Apply a modification or navigation operation.
|
|
4265
4510
|
*
|
|
4266
4511
|
* Most of these commands simply map to a node or tree method.
|
|
@@ -4385,16 +4630,17 @@
|
|
|
4385
4630
|
this.root.children = null;
|
|
4386
4631
|
this.keyMap.clear();
|
|
4387
4632
|
this.refKeyMap.clear();
|
|
4388
|
-
this.viewNodes.clear();
|
|
4633
|
+
// this.viewNodes.clear();
|
|
4634
|
+
this.treeRowCount = 0;
|
|
4389
4635
|
this.activeNode = null;
|
|
4390
4636
|
this.focusNode = null;
|
|
4391
4637
|
// this.types = {};
|
|
4392
4638
|
// this. columns =[];
|
|
4393
4639
|
// this._columnsById = {};
|
|
4394
4640
|
// Modification Status
|
|
4395
|
-
this.changedSince = 0;
|
|
4396
|
-
this.changes.clear();
|
|
4397
|
-
this.changedNodes.clear();
|
|
4641
|
+
// this.changedSince = 0;
|
|
4642
|
+
// this.changes.clear();
|
|
4643
|
+
// this.changedNodes.clear();
|
|
4398
4644
|
// // --- FILTER ---
|
|
4399
4645
|
// public filterMode: FilterModeType = null;
|
|
4400
4646
|
// // --- KEYNAV ---
|
|
@@ -4402,7 +4648,7 @@
|
|
|
4402
4648
|
// public cellNavMode = false;
|
|
4403
4649
|
// public lastQuicksearchTime = 0;
|
|
4404
4650
|
// public lastQuicksearchTerm = "";
|
|
4405
|
-
this.
|
|
4651
|
+
this.setModified(ChangeType.structure);
|
|
4406
4652
|
}
|
|
4407
4653
|
/**
|
|
4408
4654
|
* Clear nodes and markup and detach events and observers.
|
|
@@ -4422,10 +4668,11 @@
|
|
|
4422
4668
|
/**
|
|
4423
4669
|
* Return `tree.option.NAME` (also resolving if this is a callback).
|
|
4424
4670
|
*
|
|
4425
|
-
* See also
|
|
4426
|
-
* `tree.types[node.type].NAME`.
|
|
4671
|
+
* See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
|
|
4672
|
+
* to consider `node.NAME` setting and `tree.types[node.type].NAME`.
|
|
4427
4673
|
*
|
|
4428
|
-
* @param name option name (use dot notation to access extension option, e.g.
|
|
4674
|
+
* @param name option name (use dot notation to access extension option, e.g.
|
|
4675
|
+
* `filter.mode`)
|
|
4429
4676
|
*/
|
|
4430
4677
|
getOption(name, defaultValue) {
|
|
4431
4678
|
let ext;
|
|
@@ -4469,18 +4716,14 @@
|
|
|
4469
4716
|
}
|
|
4470
4717
|
/** Run code, but defer `updateViewport()` until done. */
|
|
4471
4718
|
runWithoutUpdate(func, hint = null) {
|
|
4472
|
-
// const prev = this._disableUpdate;
|
|
4473
|
-
// const start = Date.now();
|
|
4474
|
-
// this._disableUpdate = Date.now();
|
|
4475
4719
|
try {
|
|
4476
4720
|
this.enableUpdate(false);
|
|
4477
|
-
|
|
4721
|
+
const res = func();
|
|
4722
|
+
assert(!(res instanceof Promise));
|
|
4723
|
+
return res;
|
|
4478
4724
|
}
|
|
4479
4725
|
finally {
|
|
4480
4726
|
this.enableUpdate(true);
|
|
4481
|
-
// if (!prev && this._disableUpdate === start) {
|
|
4482
|
-
// this._disableUpdate = 0;
|
|
4483
|
-
// }
|
|
4484
4727
|
}
|
|
4485
4728
|
}
|
|
4486
4729
|
/** Recursively expand all expandable nodes (triggers lazy load id needed). */
|
|
@@ -4498,11 +4741,12 @@
|
|
|
4498
4741
|
/** Return the number of nodes in the data model.*/
|
|
4499
4742
|
count(visible = false) {
|
|
4500
4743
|
if (visible) {
|
|
4501
|
-
return this.
|
|
4744
|
+
return this.treeRowCount;
|
|
4745
|
+
// return this.viewNodes.size;
|
|
4502
4746
|
}
|
|
4503
4747
|
return this.keyMap.size;
|
|
4504
4748
|
}
|
|
4505
|
-
|
|
4749
|
+
/** @internal sanity check. */
|
|
4506
4750
|
_check() {
|
|
4507
4751
|
let i = 0;
|
|
4508
4752
|
this.visit((n) => {
|
|
@@ -4513,25 +4757,30 @@
|
|
|
4513
4757
|
}
|
|
4514
4758
|
// util.assert(this.keyMap.size === i);
|
|
4515
4759
|
}
|
|
4516
|
-
/**
|
|
4760
|
+
/**
|
|
4761
|
+
* Find all nodes that matches condition.
|
|
4517
4762
|
*
|
|
4518
4763
|
* @param match title string to search for, or a
|
|
4519
4764
|
* callback function that returns `true` if a node is matched.
|
|
4520
|
-
*
|
|
4765
|
+
*
|
|
4766
|
+
* @see {@link WunderbaumNode.findAll}
|
|
4521
4767
|
*/
|
|
4522
4768
|
findAll(match) {
|
|
4523
4769
|
return this.root.findAll(match);
|
|
4524
4770
|
}
|
|
4525
|
-
/**
|
|
4771
|
+
/**
|
|
4772
|
+
* Find first node that matches condition.
|
|
4526
4773
|
*
|
|
4527
4774
|
* @param match title string to search for, or a
|
|
4528
4775
|
* callback function that returns `true` if a node is matched.
|
|
4529
|
-
* @see
|
|
4776
|
+
* @see {@link WunderbaumNode.findFirst}
|
|
4777
|
+
*
|
|
4530
4778
|
*/
|
|
4531
4779
|
findFirst(match) {
|
|
4532
4780
|
return this.root.findFirst(match);
|
|
4533
4781
|
}
|
|
4534
|
-
/**
|
|
4782
|
+
/**
|
|
4783
|
+
* Find the next visible node that starts with `match`, starting at `startNode`
|
|
4535
4784
|
* and wrap-around at the end.
|
|
4536
4785
|
*/
|
|
4537
4786
|
findNextNode(match, startNode) {
|
|
@@ -4561,7 +4810,8 @@
|
|
|
4561
4810
|
}
|
|
4562
4811
|
return res;
|
|
4563
4812
|
}
|
|
4564
|
-
/**
|
|
4813
|
+
/**
|
|
4814
|
+
* Find a node relative to another node.
|
|
4565
4815
|
*
|
|
4566
4816
|
* @param node
|
|
4567
4817
|
* @param where 'down', 'first', 'last', 'left', 'parent', 'right', or 'up'.
|
|
@@ -4571,7 +4821,7 @@
|
|
|
4571
4821
|
*/
|
|
4572
4822
|
findRelatedNode(node, where, includeHidden = false) {
|
|
4573
4823
|
let res = null;
|
|
4574
|
-
|
|
4824
|
+
const pageSize = Math.floor(this.scrollContainer.clientHeight / ROW_HEIGHT);
|
|
4575
4825
|
switch (where) {
|
|
4576
4826
|
case "parent":
|
|
4577
4827
|
if (node.parent && node.parent.parent) {
|
|
@@ -4627,9 +4877,9 @@
|
|
|
4627
4877
|
res = this._getNextNodeInView(node);
|
|
4628
4878
|
break;
|
|
4629
4879
|
case "pageDown":
|
|
4630
|
-
|
|
4631
|
-
// this.logDebug(where
|
|
4632
|
-
if (
|
|
4880
|
+
const bottomNode = this._lastNodeInView();
|
|
4881
|
+
// this.logDebug(`${where}(${node}) -> ${bottomNode}`);
|
|
4882
|
+
if (node._rowIdx < bottomNode._rowIdx) {
|
|
4633
4883
|
res = bottomNode;
|
|
4634
4884
|
}
|
|
4635
4885
|
else {
|
|
@@ -4637,12 +4887,13 @@
|
|
|
4637
4887
|
}
|
|
4638
4888
|
break;
|
|
4639
4889
|
case "pageUp":
|
|
4640
|
-
if (
|
|
4641
|
-
res =
|
|
4890
|
+
if (node._rowIdx === 0) {
|
|
4891
|
+
res = node;
|
|
4642
4892
|
}
|
|
4643
4893
|
else {
|
|
4644
|
-
|
|
4645
|
-
|
|
4894
|
+
const topNode = this._firstNodeInView();
|
|
4895
|
+
// this.logDebug(`${where}(${node}) -> ${topNode}`);
|
|
4896
|
+
if (node._rowIdx > topNode._rowIdx) {
|
|
4646
4897
|
res = topNode;
|
|
4647
4898
|
}
|
|
4648
4899
|
else {
|
|
@@ -4656,7 +4907,7 @@
|
|
|
4656
4907
|
return res;
|
|
4657
4908
|
}
|
|
4658
4909
|
/**
|
|
4659
|
-
* Return the active cell of the currently active node or null.
|
|
4910
|
+
* Return the active cell (`span.wb-col`) of the currently active node or null.
|
|
4660
4911
|
*/
|
|
4661
4912
|
getActiveColElem() {
|
|
4662
4913
|
if (this.activeNode && this.activeColIdx >= 0) {
|
|
@@ -4670,8 +4921,8 @@
|
|
|
4670
4921
|
getActiveNode() {
|
|
4671
4922
|
return this.activeNode;
|
|
4672
4923
|
}
|
|
4673
|
-
/**
|
|
4674
|
-
*
|
|
4924
|
+
/**
|
|
4925
|
+
* Return the first top level node if any (not the invisible root node).
|
|
4675
4926
|
*/
|
|
4676
4927
|
getFirstChild() {
|
|
4677
4928
|
return this.root.getFirstChild();
|
|
@@ -4682,14 +4933,15 @@
|
|
|
4682
4933
|
getFocusNode() {
|
|
4683
4934
|
return this.focusNode;
|
|
4684
4935
|
}
|
|
4685
|
-
/** Return a {node:
|
|
4936
|
+
/** Return a {node: WunderbaumNode, region: TYPE} object for a mouse event.
|
|
4686
4937
|
*
|
|
4687
4938
|
* @param {Event} event Mouse event, e.g. click, ...
|
|
4688
|
-
* @returns {object} Return a {node:
|
|
4939
|
+
* @returns {object} Return a {node: WunderbaumNode, region: TYPE} object
|
|
4689
4940
|
* TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined
|
|
4690
4941
|
*/
|
|
4691
4942
|
static getEventInfo(event) {
|
|
4692
|
-
let target = event.target, cl = target.classList, parentCol = target.closest(".wb-col"), node = Wunderbaum.getNode(target), res = {
|
|
4943
|
+
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 = {
|
|
4944
|
+
tree: tree,
|
|
4693
4945
|
node: node,
|
|
4694
4946
|
region: TargetType.unknown,
|
|
4695
4947
|
colDef: undefined,
|
|
@@ -4721,13 +4973,15 @@
|
|
|
4721
4973
|
}
|
|
4722
4974
|
else {
|
|
4723
4975
|
// Somewhere near the title
|
|
4724
|
-
|
|
4976
|
+
if (event.type !== "mousemove" && !(event instanceof KeyboardEvent)) {
|
|
4977
|
+
console.warn("getEventInfo(): not found", event, res);
|
|
4978
|
+
}
|
|
4725
4979
|
return res;
|
|
4726
4980
|
}
|
|
4727
4981
|
if (res.colIdx === -1) {
|
|
4728
4982
|
res.colIdx = 0;
|
|
4729
4983
|
}
|
|
4730
|
-
res.colDef =
|
|
4984
|
+
res.colDef = tree === null || tree === void 0 ? void 0 : tree.columns[res.colIdx];
|
|
4731
4985
|
res.colDef != null ? (res.colId = res.colDef.id) : 0;
|
|
4732
4986
|
// this.log("Event", event, res);
|
|
4733
4987
|
return res;
|
|
@@ -4751,7 +5005,8 @@
|
|
|
4751
5005
|
isEditing() {
|
|
4752
5006
|
return this._callMethod("edit.isEditingTitle");
|
|
4753
5007
|
}
|
|
4754
|
-
/**
|
|
5008
|
+
/**
|
|
5009
|
+
* Return true if any node is currently beeing loaded, i.e. a Ajax request is pending.
|
|
4755
5010
|
*/
|
|
4756
5011
|
isLoading() {
|
|
4757
5012
|
var res = false;
|
|
@@ -4778,7 +5033,7 @@
|
|
|
4778
5033
|
console.error.apply(console, args);
|
|
4779
5034
|
}
|
|
4780
5035
|
}
|
|
4781
|
-
|
|
5036
|
+
/** Log to console if opts.debugLevel >= 3 */
|
|
4782
5037
|
logInfo(...args) {
|
|
4783
5038
|
if (this.options.debugLevel >= 3) {
|
|
4784
5039
|
Array.prototype.unshift.call(args, this.toString());
|
|
@@ -4805,77 +5060,13 @@
|
|
|
4805
5060
|
console.warn.apply(console, args);
|
|
4806
5061
|
}
|
|
4807
5062
|
}
|
|
4808
|
-
/** */
|
|
4809
|
-
render(opts) {
|
|
4810
|
-
const label = this.logTime("render");
|
|
4811
|
-
let idx = 0;
|
|
4812
|
-
let top = 0;
|
|
4813
|
-
const height = ROW_HEIGHT;
|
|
4814
|
-
let modified = false;
|
|
4815
|
-
let start = opts === null || opts === void 0 ? void 0 : opts.startIdx;
|
|
4816
|
-
let end = opts === null || opts === void 0 ? void 0 : opts.endIdx;
|
|
4817
|
-
const obsoleteViewNodes = this.viewNodes;
|
|
4818
|
-
this.viewNodes = new Set();
|
|
4819
|
-
let viewNodes = this.viewNodes;
|
|
4820
|
-
// this.debug("render", opts);
|
|
4821
|
-
assert(start != null && end != null);
|
|
4822
|
-
// Make sure start is always even, so the alternating row colors don't
|
|
4823
|
-
// change when scrolling:
|
|
4824
|
-
if (start % 2) {
|
|
4825
|
-
start--;
|
|
4826
|
-
}
|
|
4827
|
-
this.visitRows(function (node) {
|
|
4828
|
-
const prevIdx = node._rowIdx;
|
|
4829
|
-
viewNodes.add(node);
|
|
4830
|
-
obsoleteViewNodes.delete(node);
|
|
4831
|
-
if (prevIdx !== idx) {
|
|
4832
|
-
node._rowIdx = idx;
|
|
4833
|
-
modified = true;
|
|
4834
|
-
}
|
|
4835
|
-
if (idx < start || idx > end) {
|
|
4836
|
-
node._callEvent("discard");
|
|
4837
|
-
node.removeMarkup();
|
|
4838
|
-
}
|
|
4839
|
-
else {
|
|
4840
|
-
// if (!node._rowElem || prevIdx != idx) {
|
|
4841
|
-
node.render({ top: top });
|
|
4842
|
-
}
|
|
4843
|
-
idx++;
|
|
4844
|
-
top += height;
|
|
4845
|
-
});
|
|
4846
|
-
for (const prevNode of obsoleteViewNodes) {
|
|
4847
|
-
prevNode._callEvent("discard");
|
|
4848
|
-
prevNode.removeMarkup();
|
|
4849
|
-
}
|
|
4850
|
-
// Resize tree container
|
|
4851
|
-
this.nodeListElement.style.height = "" + top + "px";
|
|
4852
|
-
// this.log("render()", this.nodeListElement.style.height);
|
|
4853
|
-
this.logTimeEnd(label);
|
|
4854
|
-
return modified;
|
|
4855
|
-
}
|
|
4856
|
-
/**Recalc and apply header columns from `this.columns`. */
|
|
4857
|
-
renderHeader() {
|
|
4858
|
-
if (!this.headerElement) {
|
|
4859
|
-
return;
|
|
4860
|
-
}
|
|
4861
|
-
const headerRow = this.headerElement.querySelector(".wb-row");
|
|
4862
|
-
assert(headerRow);
|
|
4863
|
-
headerRow.innerHTML = "<span class='wb-col'></span>".repeat(this.columns.length);
|
|
4864
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4865
|
-
let col = this.columns[i];
|
|
4866
|
-
let colElem = headerRow.children[i];
|
|
4867
|
-
colElem.style.left = col._ofsPx + "px";
|
|
4868
|
-
colElem.style.width = col._widthPx + "px";
|
|
4869
|
-
colElem.textContent = col.title || col.id;
|
|
4870
|
-
}
|
|
4871
|
-
}
|
|
4872
5063
|
/**
|
|
5064
|
+
* Make sure that this node is scrolled into the viewport.
|
|
4873
5065
|
*
|
|
4874
5066
|
* @param {boolean | PlainObject} [effects=false] animation options.
|
|
4875
5067
|
* @param {object} [options=null] {topNode: null, effects: ..., parent: ...}
|
|
4876
5068
|
* this node will remain visible in
|
|
4877
5069
|
* any case, even if `this` is outside the scroll pane.
|
|
4878
|
-
* Make sure that a node is scrolled into the viewport.
|
|
4879
5070
|
*/
|
|
4880
5071
|
scrollTo(opts) {
|
|
4881
5072
|
const MARGIN = 1;
|
|
@@ -4896,30 +5087,18 @@
|
|
|
4896
5087
|
// Node is above viewport
|
|
4897
5088
|
newTop = nodeOfs + MARGIN;
|
|
4898
5089
|
}
|
|
4899
|
-
this.log("scrollTo(" + nodeOfs + "): " + curTop + " => " + newTop, height);
|
|
4900
5090
|
if (newTop != null) {
|
|
5091
|
+
this.log("scrollTo(" + nodeOfs + "): " + curTop + " => " + newTop, height);
|
|
4901
5092
|
this.scrollContainer.scrollTop = newTop;
|
|
4902
|
-
this.
|
|
4903
|
-
}
|
|
4904
|
-
}
|
|
4905
|
-
/** */
|
|
4906
|
-
setCellMode(mode) {
|
|
4907
|
-
// util.assert(this.cellNavMode);
|
|
4908
|
-
// util.assert(0 <= colIdx && colIdx < this.columns.length);
|
|
4909
|
-
if (mode === this.navMode) {
|
|
4910
|
-
return;
|
|
4911
|
-
}
|
|
4912
|
-
const prevMode = this.navMode;
|
|
4913
|
-
const cellMode = mode !== NavigationMode.row;
|
|
4914
|
-
this.navMode = mode;
|
|
4915
|
-
if (cellMode && prevMode === NavigationMode.row) {
|
|
4916
|
-
this.setColumn(0);
|
|
5093
|
+
this.setModified(ChangeType.vscroll);
|
|
4917
5094
|
}
|
|
4918
|
-
this.element.classList.toggle("wb-cell-mode", cellMode);
|
|
4919
|
-
this.element.classList.toggle("wb-cell-edit-mode", mode === NavigationMode.cellEdit);
|
|
4920
|
-
this.setModified(ChangeType.row, this.activeNode);
|
|
4921
5095
|
}
|
|
4922
|
-
/**
|
|
5096
|
+
/**
|
|
5097
|
+
* Set column #colIdx to 'active'.
|
|
5098
|
+
*
|
|
5099
|
+
* This higlights the column header and -cells by adding the `wb-active` class.
|
|
5100
|
+
* Available in cell-nav and cell-edit mode, not in row-mode.
|
|
5101
|
+
*/
|
|
4923
5102
|
setColumn(colIdx) {
|
|
4924
5103
|
assert(this.navMode !== NavigationMode.row);
|
|
4925
5104
|
assert(0 <= colIdx && colIdx < this.columns.length);
|
|
@@ -4944,7 +5123,7 @@
|
|
|
4944
5123
|
}
|
|
4945
5124
|
}
|
|
4946
5125
|
}
|
|
4947
|
-
/** */
|
|
5126
|
+
/** Set or remove keybaord focus to the tree container. */
|
|
4948
5127
|
setFocus(flag = true) {
|
|
4949
5128
|
if (flag) {
|
|
4950
5129
|
this.element.focus();
|
|
@@ -4953,88 +5132,145 @@
|
|
|
4953
5132
|
this.element.blur();
|
|
4954
5133
|
}
|
|
4955
5134
|
}
|
|
4956
|
-
/** */
|
|
4957
5135
|
setModified(change, node, options) {
|
|
4958
|
-
if (
|
|
4959
|
-
|
|
5136
|
+
if (this._disableUpdateCount) {
|
|
5137
|
+
// Assuming that we redraw all when enableUpdate() is re-enabled.
|
|
5138
|
+
// this.log(
|
|
5139
|
+
// `IGNORED setModified(${change}) node=${node} (disable level ${this._disableUpdateCount})`
|
|
5140
|
+
// );
|
|
5141
|
+
return;
|
|
4960
5142
|
}
|
|
4961
|
-
this.
|
|
4962
|
-
if (
|
|
4963
|
-
|
|
5143
|
+
// this.log(`setModified(${change}) node=${node}`);
|
|
5144
|
+
if (!(node instanceof WunderbaumNode)) {
|
|
5145
|
+
options = node;
|
|
5146
|
+
}
|
|
5147
|
+
const immediate = !!getOption(options, "immediate");
|
|
5148
|
+
switch (change) {
|
|
5149
|
+
case ChangeType.any:
|
|
5150
|
+
case ChangeType.structure:
|
|
5151
|
+
case ChangeType.header:
|
|
5152
|
+
this.changeRedrawRequestPending = true;
|
|
5153
|
+
this.updateViewport(immediate);
|
|
5154
|
+
break;
|
|
5155
|
+
case ChangeType.vscroll:
|
|
5156
|
+
this.updateViewport(immediate);
|
|
5157
|
+
break;
|
|
5158
|
+
case ChangeType.row:
|
|
5159
|
+
case ChangeType.status:
|
|
5160
|
+
// Single nodes are immedialtely updated if already inside the viewport
|
|
5161
|
+
// (otherwise we can ignore)
|
|
5162
|
+
if (node._rowElem) {
|
|
5163
|
+
node.render();
|
|
5164
|
+
}
|
|
5165
|
+
break;
|
|
5166
|
+
default:
|
|
5167
|
+
error(`Invalid change type ${change}`);
|
|
4964
5168
|
}
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
}
|
|
5169
|
+
}
|
|
5170
|
+
/** Set the tree's navigation mode. */
|
|
5171
|
+
setNavigationMode(mode) {
|
|
5172
|
+
// util.assert(this.cellNavMode);
|
|
5173
|
+
// util.assert(0 <= colIdx && colIdx < this.columns.length);
|
|
5174
|
+
if (mode === this.navMode) {
|
|
5175
|
+
return;
|
|
4973
5176
|
}
|
|
4974
|
-
|
|
5177
|
+
const prevMode = this.navMode;
|
|
5178
|
+
const cellMode = mode !== NavigationMode.row;
|
|
5179
|
+
this.navMode = mode;
|
|
5180
|
+
if (cellMode && prevMode === NavigationMode.row) {
|
|
5181
|
+
this.setColumn(0);
|
|
5182
|
+
}
|
|
5183
|
+
this.element.classList.toggle("wb-cell-mode", cellMode);
|
|
5184
|
+
this.element.classList.toggle("wb-cell-edit-mode", mode === NavigationMode.cellEdit);
|
|
5185
|
+
this.setModified(ChangeType.row, this.activeNode);
|
|
4975
5186
|
}
|
|
5187
|
+
/** Display tree status (ok, loading, error, noData) using styles and a dummy root node. */
|
|
4976
5188
|
setStatus(status, message, details) {
|
|
4977
5189
|
return this.root.setStatus(status, message, details);
|
|
4978
5190
|
}
|
|
4979
5191
|
/** Update column headers and width. */
|
|
4980
5192
|
updateColumns(opts) {
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
5193
|
+
opts = Object.assign({ calculateCols: true, updateRows: true }, opts);
|
|
5194
|
+
const minWidth = 4;
|
|
5195
|
+
const vpWidth = this.element.clientWidth;
|
|
4984
5196
|
let totalWeight = 0;
|
|
4985
5197
|
let fixedWidth = 0;
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
this._columnsById
|
|
4990
|
-
let
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
col._widthPx
|
|
5198
|
+
let modified = false;
|
|
5199
|
+
if (opts.calculateCols) {
|
|
5200
|
+
// Gather width requests
|
|
5201
|
+
this._columnsById = {};
|
|
5202
|
+
for (let col of this.columns) {
|
|
5203
|
+
this._columnsById[col.id] = col;
|
|
5204
|
+
let cw = col.width;
|
|
5205
|
+
if (!cw || cw === "*") {
|
|
5206
|
+
col._weight = 1.0;
|
|
5207
|
+
totalWeight += 1.0;
|
|
5208
|
+
}
|
|
5209
|
+
else if (typeof cw === "number") {
|
|
5210
|
+
col._weight = cw;
|
|
5211
|
+
totalWeight += cw;
|
|
5212
|
+
}
|
|
5213
|
+
else if (typeof cw === "string" && cw.endsWith("px")) {
|
|
5214
|
+
col._weight = 0;
|
|
5215
|
+
let px = parseFloat(cw.slice(0, -2));
|
|
5216
|
+
if (col._widthPx != px) {
|
|
5217
|
+
modified = true;
|
|
5218
|
+
col._widthPx = px;
|
|
5219
|
+
}
|
|
5220
|
+
fixedWidth += px;
|
|
5221
|
+
}
|
|
5222
|
+
else {
|
|
5223
|
+
error("Invalid column width: " + cw);
|
|
5005
5224
|
}
|
|
5006
|
-
fixedWidth += px;
|
|
5007
5225
|
}
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
if (col._widthPx != px) {
|
|
5019
|
-
modified = true;
|
|
5020
|
-
col._widthPx = px;
|
|
5226
|
+
// Share remaining space between non-fixed columns
|
|
5227
|
+
const restPx = Math.max(0, vpWidth - fixedWidth);
|
|
5228
|
+
let ofsPx = 0;
|
|
5229
|
+
for (let col of this.columns) {
|
|
5230
|
+
if (col._weight) {
|
|
5231
|
+
const px = Math.max(minWidth, (restPx * col._weight) / totalWeight);
|
|
5232
|
+
if (col._widthPx != px) {
|
|
5233
|
+
modified = true;
|
|
5234
|
+
col._widthPx = px;
|
|
5235
|
+
}
|
|
5021
5236
|
}
|
|
5237
|
+
col._ofsPx = ofsPx;
|
|
5238
|
+
ofsPx += col._widthPx;
|
|
5022
5239
|
}
|
|
5023
|
-
col._ofsPx = ofsPx;
|
|
5024
|
-
ofsPx += col._widthPx;
|
|
5025
5240
|
}
|
|
5026
5241
|
// Every column has now a calculated `_ofsPx` and `_widthPx`
|
|
5027
5242
|
// this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element);
|
|
5028
5243
|
// console.trace();
|
|
5029
5244
|
// util.error("BREAK");
|
|
5030
5245
|
if (modified) {
|
|
5031
|
-
this.
|
|
5032
|
-
if (opts.
|
|
5033
|
-
this.
|
|
5246
|
+
this._renderHeaderMarkup();
|
|
5247
|
+
if (opts.updateRows) {
|
|
5248
|
+
this._updateRows();
|
|
5034
5249
|
}
|
|
5035
5250
|
}
|
|
5036
5251
|
}
|
|
5037
|
-
/**
|
|
5252
|
+
/** Create/update header markup from `this.columns` definition.
|
|
5253
|
+
* @internal
|
|
5254
|
+
*/
|
|
5255
|
+
_renderHeaderMarkup() {
|
|
5256
|
+
if (!this.headerElement) {
|
|
5257
|
+
return;
|
|
5258
|
+
}
|
|
5259
|
+
const headerRow = this.headerElement.querySelector(".wb-row");
|
|
5260
|
+
assert(headerRow);
|
|
5261
|
+
headerRow.innerHTML = "<span class='wb-col'></span>".repeat(this.columns.length);
|
|
5262
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
5263
|
+
const col = this.columns[i];
|
|
5264
|
+
const colElem = headerRow.children[i];
|
|
5265
|
+
colElem.style.left = col._ofsPx + "px";
|
|
5266
|
+
colElem.style.width = col._widthPx + "px";
|
|
5267
|
+
// colElem.textContent = col.title || col.id;
|
|
5268
|
+
const title = escapeHtml(col.title || col.id);
|
|
5269
|
+
colElem.innerHTML = `<span class="wb-col-title">${title}</span> <span class="wb-col-resizer"></span>`;
|
|
5270
|
+
// colElem.innerHTML = `${title} <span class="wb-col-resizer"></span>`;
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
/** Render header and all rows that are visible in the viewport (async, throttled). */
|
|
5038
5274
|
updateViewport(immediate = false) {
|
|
5039
5275
|
// Call the `throttle` wrapper for `this._updateViewport()` which will
|
|
5040
5276
|
// execute immediately on the leading edge of a sequence:
|
|
@@ -5043,39 +5279,163 @@
|
|
|
5043
5279
|
this._updateViewportThrottled.flush();
|
|
5044
5280
|
}
|
|
5045
5281
|
}
|
|
5282
|
+
/**
|
|
5283
|
+
* This is the actual update method, which is wrapped inside a throttle method.
|
|
5284
|
+
* This protected method should not be called directly but via
|
|
5285
|
+
* `tree.updateViewport()` or `tree.setModified()`.
|
|
5286
|
+
* It calls `updateColumns()` and `_updateRows()`.
|
|
5287
|
+
* @internal
|
|
5288
|
+
*/
|
|
5046
5289
|
_updateViewport() {
|
|
5047
|
-
if (this.
|
|
5290
|
+
if (this._disableUpdateCount) {
|
|
5291
|
+
this.log(`IGNORED _updateViewport() disable level: ${this._disableUpdateCount}`);
|
|
5048
5292
|
return;
|
|
5049
5293
|
}
|
|
5294
|
+
const newNodesOnly = !this.changeRedrawRequestPending;
|
|
5295
|
+
this.changeRedrawRequestPending = false;
|
|
5050
5296
|
let height = this.scrollContainer.clientHeight;
|
|
5051
|
-
// We cannot get the height for
|
|
5297
|
+
// We cannot get the height for absolute positioned parent, so look at first col
|
|
5052
5298
|
// let headerHeight = this.headerElement.clientHeight
|
|
5053
5299
|
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
5054
5300
|
const headerHeight = this.options.headerHeightPx;
|
|
5055
|
-
|
|
5056
|
-
let ofs = this.scrollContainer.scrollTop;
|
|
5301
|
+
const wantHeight = this.element.clientHeight - headerHeight;
|
|
5057
5302
|
if (Math.abs(height - wantHeight) > 1.0) {
|
|
5058
5303
|
// this.log("resize", height, wantHeight);
|
|
5059
5304
|
this.scrollContainer.style.height = wantHeight + "px";
|
|
5060
5305
|
height = wantHeight;
|
|
5061
5306
|
}
|
|
5062
|
-
this.updateColumns({
|
|
5063
|
-
this.
|
|
5064
|
-
startIdx: Math.max(0, ofs / ROW_HEIGHT - RENDER_MAX_PREFETCH),
|
|
5065
|
-
endIdx: Math.max(0, (ofs + height) / ROW_HEIGHT + RENDER_MAX_PREFETCH),
|
|
5066
|
-
});
|
|
5307
|
+
this.updateColumns({ updateRows: false });
|
|
5308
|
+
this._updateRows({ newNodesOnly: newNodesOnly });
|
|
5067
5309
|
this._callEvent("update");
|
|
5068
5310
|
}
|
|
5069
|
-
/**
|
|
5311
|
+
/**
|
|
5312
|
+
* Assert that TR order matches the natural node order
|
|
5313
|
+
* @internal
|
|
5314
|
+
*/
|
|
5315
|
+
_validateRows() {
|
|
5316
|
+
let trs = this.nodeListElement.childNodes;
|
|
5317
|
+
let i = 0;
|
|
5318
|
+
let prev = -1;
|
|
5319
|
+
let ok = true;
|
|
5320
|
+
trs.forEach((element) => {
|
|
5321
|
+
const tr = element;
|
|
5322
|
+
const top = Number.parseInt(tr.style.top);
|
|
5323
|
+
const n = tr._wb_node;
|
|
5324
|
+
// if (i < 4) {
|
|
5325
|
+
// console.info(
|
|
5326
|
+
// `TR#${i}, rowIdx=${n._rowIdx} , top=${top}px: '${n.title}'`
|
|
5327
|
+
// );
|
|
5328
|
+
// }
|
|
5329
|
+
if (top <= prev) {
|
|
5330
|
+
console.warn(`TR order mismatch at index ${i}: top=${top}px, node=${n}`);
|
|
5331
|
+
// throw new Error("fault");
|
|
5332
|
+
ok = false;
|
|
5333
|
+
}
|
|
5334
|
+
prev = top;
|
|
5335
|
+
i++;
|
|
5336
|
+
});
|
|
5337
|
+
return ok;
|
|
5338
|
+
}
|
|
5339
|
+
/*
|
|
5340
|
+
* - Traverse all *visible* of the whole tree, i.e. skip collapsed nodes.
|
|
5341
|
+
* - Store count of rows to `tree.treeRowCount`.
|
|
5342
|
+
* - Renumber `node._rowIdx` for all visible nodes.
|
|
5343
|
+
* - Calculate the index range that must be rendered to fill the viewport
|
|
5344
|
+
* (including upper and lower prefetch)
|
|
5345
|
+
* -
|
|
5346
|
+
*/
|
|
5347
|
+
_updateRows(opts) {
|
|
5348
|
+
const label = this.logTime("_updateRows");
|
|
5349
|
+
opts = Object.assign({ newNodesOnly: false }, opts);
|
|
5350
|
+
const newNodesOnly = !!opts.newNodesOnly;
|
|
5351
|
+
const row_height = ROW_HEIGHT;
|
|
5352
|
+
const vp_height = this.scrollContainer.clientHeight;
|
|
5353
|
+
const prefetch = RENDER_MAX_PREFETCH;
|
|
5354
|
+
const ofs = this.scrollContainer.scrollTop;
|
|
5355
|
+
let startIdx = Math.max(0, ofs / row_height - prefetch);
|
|
5356
|
+
startIdx = Math.floor(startIdx);
|
|
5357
|
+
// Make sure start is always even, so the alternating row colors don't
|
|
5358
|
+
// change when scrolling:
|
|
5359
|
+
if (startIdx % 2) {
|
|
5360
|
+
startIdx--;
|
|
5361
|
+
}
|
|
5362
|
+
let endIdx = Math.max(0, (ofs + vp_height) / row_height + prefetch);
|
|
5363
|
+
endIdx = Math.ceil(endIdx);
|
|
5364
|
+
// const obsoleteViewNodes = this.viewNodes;
|
|
5365
|
+
// this.viewNodes = new Set();
|
|
5366
|
+
// const viewNodes = this.viewNodes;
|
|
5367
|
+
// this.debug("render", opts);
|
|
5368
|
+
const obsoleteNodes = new Set();
|
|
5369
|
+
this.nodeListElement.childNodes.forEach((elem) => {
|
|
5370
|
+
const tr = elem;
|
|
5371
|
+
obsoleteNodes.add(tr._wb_node);
|
|
5372
|
+
});
|
|
5373
|
+
let idx = 0;
|
|
5374
|
+
let top = 0;
|
|
5375
|
+
let modified = false;
|
|
5376
|
+
let prevElem = "first";
|
|
5377
|
+
this.visitRows(function (node) {
|
|
5378
|
+
// console.log("visit", node)
|
|
5379
|
+
const rowDiv = node._rowElem;
|
|
5380
|
+
// Renumber all expanded nodes
|
|
5381
|
+
if (node._rowIdx !== idx) {
|
|
5382
|
+
node._rowIdx = idx;
|
|
5383
|
+
modified = true;
|
|
5384
|
+
}
|
|
5385
|
+
if (idx < startIdx || idx > endIdx) {
|
|
5386
|
+
// row is outside viewport bounds
|
|
5387
|
+
if (rowDiv) {
|
|
5388
|
+
prevElem = rowDiv;
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
else if (rowDiv && newNodesOnly) {
|
|
5392
|
+
obsoleteNodes.delete(node);
|
|
5393
|
+
// no need to update existing node markup
|
|
5394
|
+
rowDiv.style.top = idx * ROW_HEIGHT + "px";
|
|
5395
|
+
prevElem = rowDiv;
|
|
5396
|
+
}
|
|
5397
|
+
else {
|
|
5398
|
+
obsoleteNodes.delete(node);
|
|
5399
|
+
// Create new markup
|
|
5400
|
+
node.render({ top: top, after: prevElem });
|
|
5401
|
+
// console.log("render", top, prevElem, "=>", node._rowElem);
|
|
5402
|
+
prevElem = node._rowElem;
|
|
5403
|
+
}
|
|
5404
|
+
idx++;
|
|
5405
|
+
top += row_height;
|
|
5406
|
+
});
|
|
5407
|
+
this.treeRowCount = idx;
|
|
5408
|
+
for (const n of obsoleteNodes) {
|
|
5409
|
+
n._callEvent("discard");
|
|
5410
|
+
n.removeMarkup();
|
|
5411
|
+
}
|
|
5412
|
+
// Resize tree container
|
|
5413
|
+
this.nodeListElement.style.height = `${top}px`;
|
|
5414
|
+
// this.log(
|
|
5415
|
+
// `render(scrollOfs:${ofs}, ${startIdx}..${endIdx})`,
|
|
5416
|
+
// this.nodeListElement.style.height
|
|
5417
|
+
// );
|
|
5418
|
+
this.logTimeEnd(label);
|
|
5419
|
+
this._validateRows();
|
|
5420
|
+
return modified;
|
|
5421
|
+
}
|
|
5422
|
+
/**
|
|
5423
|
+
* Call callback(node) for all nodes in hierarchical order (depth-first).
|
|
5070
5424
|
*
|
|
5071
5425
|
* @param {function} callback the callback function.
|
|
5072
|
-
* Return false to stop iteration, return "skip" to skip this node and
|
|
5426
|
+
* Return false to stop iteration, return "skip" to skip this node and
|
|
5427
|
+
* children only.
|
|
5073
5428
|
* @returns {boolean} false, if the iterator was stopped.
|
|
5074
5429
|
*/
|
|
5075
5430
|
visit(callback) {
|
|
5076
5431
|
return this.root.visit(callback, false);
|
|
5077
5432
|
}
|
|
5078
|
-
/**
|
|
5433
|
+
/**
|
|
5434
|
+
* Call fn(node) for all nodes in vertical order, top down (or bottom up).
|
|
5435
|
+
*
|
|
5436
|
+
* Note that this considers expansion state, i.e. children of collapsed nodes
|
|
5437
|
+
* are skipped.
|
|
5438
|
+
*
|
|
5079
5439
|
* Stop iteration, if fn() returns false.<br>
|
|
5080
5440
|
* Return false if iteration was stopped.
|
|
5081
5441
|
*
|
|
@@ -5155,7 +5515,8 @@
|
|
|
5155
5515
|
}
|
|
5156
5516
|
return true;
|
|
5157
5517
|
}
|
|
5158
|
-
/**
|
|
5518
|
+
/**
|
|
5519
|
+
* Call fn(node) for all nodes in vertical order, bottom up.
|
|
5159
5520
|
* @internal
|
|
5160
5521
|
*/
|
|
5161
5522
|
_visitRowsUp(callback, opts) {
|
|
@@ -5199,19 +5560,36 @@
|
|
|
5199
5560
|
}
|
|
5200
5561
|
return true;
|
|
5201
5562
|
}
|
|
5202
|
-
/**
|
|
5563
|
+
/**
|
|
5564
|
+
* Reload the tree with a new source.
|
|
5565
|
+
*
|
|
5566
|
+
* Previous data is cleared.
|
|
5567
|
+
* Pass `options.columns` to define a header (may also be part of `source.columns`).
|
|
5568
|
+
*/
|
|
5203
5569
|
load(source, options = {}) {
|
|
5204
5570
|
this.clear();
|
|
5205
5571
|
const columns = options.columns || source.columns;
|
|
5206
5572
|
if (columns) {
|
|
5207
5573
|
this.columns = options.columns;
|
|
5208
|
-
this.
|
|
5209
|
-
|
|
5574
|
+
// this._renderHeaderMarkup();
|
|
5575
|
+
this.updateColumns({ calculateCols: false });
|
|
5210
5576
|
}
|
|
5211
5577
|
return this.root.load(source);
|
|
5212
5578
|
}
|
|
5213
5579
|
/**
|
|
5580
|
+
* Disable render requests during operations that would trigger many updates.
|
|
5214
5581
|
*
|
|
5582
|
+
* ```js
|
|
5583
|
+
* try {
|
|
5584
|
+
* tree.enableUpdate(false);
|
|
5585
|
+
* // ... (long running operation that would trigger many updates)
|
|
5586
|
+
* foo();
|
|
5587
|
+
* // ... NOTE: make sure that async operations have finished
|
|
5588
|
+
* await foo();
|
|
5589
|
+
* } finally {
|
|
5590
|
+
* tree.enableUpdate(true);
|
|
5591
|
+
* }
|
|
5592
|
+
* ```
|
|
5215
5593
|
*/
|
|
5216
5594
|
enableUpdate(flag) {
|
|
5217
5595
|
/*
|
|
@@ -5219,20 +5597,22 @@
|
|
|
5219
5597
|
1 >-------------------------------------<
|
|
5220
5598
|
2 >--------------------<
|
|
5221
5599
|
3 >--------------------------<
|
|
5222
|
-
|
|
5223
|
-
5
|
|
5224
|
-
|
|
5225
5600
|
*/
|
|
5226
|
-
// this.logDebug( `enableUpdate(${flag}): count=${this._disableUpdateCount}...` );
|
|
5227
5601
|
if (flag) {
|
|
5228
|
-
assert(this._disableUpdateCount > 0);
|
|
5602
|
+
assert(this._disableUpdateCount > 0, "enableUpdate(true) was called too often");
|
|
5229
5603
|
this._disableUpdateCount--;
|
|
5604
|
+
// this.logDebug(
|
|
5605
|
+
// `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...`
|
|
5606
|
+
// );
|
|
5230
5607
|
if (this._disableUpdateCount === 0) {
|
|
5231
5608
|
this.updateViewport();
|
|
5232
5609
|
}
|
|
5233
5610
|
}
|
|
5234
5611
|
else {
|
|
5235
5612
|
this._disableUpdateCount++;
|
|
5613
|
+
// this.logDebug(
|
|
5614
|
+
// `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...`
|
|
5615
|
+
// );
|
|
5236
5616
|
// this._disableUpdate = Date.now();
|
|
5237
5617
|
}
|
|
5238
5618
|
// return !flag; // return previous value
|
|
@@ -5265,12 +5645,14 @@
|
|
|
5265
5645
|
return this.extensions.filter.updateFilter();
|
|
5266
5646
|
}
|
|
5267
5647
|
}
|
|
5268
|
-
Wunderbaum.version = "v0.0.1-0"; // Set to semver by 'grunt release'
|
|
5269
5648
|
Wunderbaum.sequence = 0;
|
|
5649
|
+
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
5650
|
+
Wunderbaum.version = "v0.0.3"; // Set to semver by 'grunt release'
|
|
5651
|
+
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
5270
5652
|
Wunderbaum.util = util;
|
|
5271
5653
|
|
|
5272
5654
|
exports.Wunderbaum = Wunderbaum;
|
|
5273
5655
|
|
|
5274
5656
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5275
5657
|
|
|
5276
|
-
}))
|
|
5658
|
+
}));
|