wunderbaum 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wunderbaum.css +4 -1
- package/dist/wunderbaum.css.map +1 -1
- package/dist/wunderbaum.d.ts +350 -221
- package/dist/wunderbaum.esm.js +716 -537
- package/dist/wunderbaum.esm.min.js +32 -32
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +7785 -7606
- package/dist/wunderbaum.umd.min.js +69 -70
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +2 -2
- package/src/common.ts +1 -1
- package/src/deferred.ts +9 -9
- package/src/types.ts +120 -36
- package/src/util.ts +73 -33
- package/src/wb_ext_dnd.ts +1 -1
- package/src/wb_ext_edit.ts +90 -58
- package/src/wb_ext_filter.ts +5 -1
- package/src/wb_ext_keynav.ts +20 -9
- package/src/wb_node.ts +78 -30
- package/src/wb_options.ts +1 -1
- package/src/wunderbaum.scss +7 -1
- package/src/wunderbaum.ts +114 -55
package/dist/wunderbaum.esm.js
CHANGED
|
@@ -1,7 +1,304 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* debounce & throttle, taken from https://github.com/lodash/lodash v4.17.21
|
|
3
|
+
* MIT License: https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/LICENSE
|
|
4
|
+
* Modified for TypeScript type annotations.
|
|
5
|
+
*/
|
|
6
|
+
/* --- */
|
|
7
|
+
/** Detect free variable `global` from Node.js. */
|
|
8
|
+
const freeGlobal = typeof global === "object" &&
|
|
9
|
+
global !== null &&
|
|
10
|
+
global.Object === Object &&
|
|
11
|
+
global;
|
|
12
|
+
/** Detect free variable `globalThis` */
|
|
13
|
+
const freeGlobalThis = typeof globalThis === "object" &&
|
|
14
|
+
globalThis !== null &&
|
|
15
|
+
globalThis.Object == Object &&
|
|
16
|
+
globalThis;
|
|
17
|
+
/** Detect free variable `self`. */
|
|
18
|
+
const freeSelf = typeof self === "object" && self !== null && self.Object === Object && self;
|
|
19
|
+
/** Used as a reference to the global object. */
|
|
20
|
+
const root = freeGlobalThis || freeGlobal || freeSelf || Function("return this")();
|
|
21
|
+
/**
|
|
22
|
+
* Checks if `value` is the
|
|
23
|
+
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
|
24
|
+
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
25
|
+
*
|
|
26
|
+
* @since 0.1.0
|
|
27
|
+
* @category Lang
|
|
28
|
+
* @param {*} value The value to check.
|
|
29
|
+
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
|
30
|
+
* @example
|
|
31
|
+
*
|
|
32
|
+
* isObject({})
|
|
33
|
+
* // => true
|
|
34
|
+
*
|
|
35
|
+
* isObject([1, 2, 3])
|
|
36
|
+
* // => true
|
|
37
|
+
*
|
|
38
|
+
* isObject(Function)
|
|
39
|
+
* // => true
|
|
40
|
+
*
|
|
41
|
+
* isObject(null)
|
|
42
|
+
* // => false
|
|
43
|
+
*/
|
|
44
|
+
function isObject(value) {
|
|
45
|
+
const type = typeof value;
|
|
46
|
+
return value != null && (type === "object" || type === "function");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Creates a debounced function that delays invoking `func` until after `wait`
|
|
50
|
+
* milliseconds have elapsed since the last time the debounced function was
|
|
51
|
+
* invoked, or until the next browser frame is drawn. The debounced function
|
|
52
|
+
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
|
53
|
+
* `flush` method to immediately invoke them. Provide `options` to indicate
|
|
54
|
+
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
55
|
+
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
56
|
+
* debounced function. Subsequent calls to the debounced function return the
|
|
57
|
+
* result of the last `func` invocation.
|
|
58
|
+
*
|
|
59
|
+
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
60
|
+
* invoked on the trailing edge of the timeout only if the debounced function
|
|
61
|
+
* is invoked more than once during the `wait` timeout.
|
|
62
|
+
*
|
|
63
|
+
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
64
|
+
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
65
|
+
*
|
|
66
|
+
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
|
67
|
+
* invocation will be deferred until the next frame is drawn (typically about
|
|
68
|
+
* 16ms).
|
|
69
|
+
*
|
|
70
|
+
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
|
71
|
+
* for details over the differences between `debounce` and `throttle`.
|
|
72
|
+
*
|
|
73
|
+
* @since 0.1.0
|
|
74
|
+
* @category Function
|
|
75
|
+
* @param {Function} func The function to debounce.
|
|
76
|
+
* @param {number} [wait=0]
|
|
77
|
+
* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
|
|
78
|
+
* used (if available).
|
|
79
|
+
* @param {Object} [options={}] The options object.
|
|
80
|
+
* @param {boolean} [options.leading=false]
|
|
81
|
+
* Specify invoking on the leading edge of the timeout.
|
|
82
|
+
* @param {number} [options.maxWait]
|
|
83
|
+
* The maximum time `func` is allowed to be delayed before it's invoked.
|
|
84
|
+
* @param {boolean} [options.trailing=true]
|
|
85
|
+
* Specify invoking on the trailing edge of the timeout.
|
|
86
|
+
* @returns {Function} Returns the new debounced function.
|
|
87
|
+
* @example
|
|
88
|
+
*
|
|
89
|
+
* // Avoid costly calculations while the window size is in flux.
|
|
90
|
+
* jQuery(window).on('resize', debounce(calculateLayout, 150))
|
|
91
|
+
*
|
|
92
|
+
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
|
93
|
+
* jQuery(element).on('click', debounce(sendMail, 300, {
|
|
94
|
+
* 'leading': true,
|
|
95
|
+
* 'trailing': false
|
|
96
|
+
* }))
|
|
97
|
+
*
|
|
98
|
+
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
|
99
|
+
* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
|
|
100
|
+
* const source = new EventSource('/stream')
|
|
101
|
+
* jQuery(source).on('message', debounced)
|
|
102
|
+
*
|
|
103
|
+
* // Cancel the trailing debounced invocation.
|
|
104
|
+
* jQuery(window).on('popstate', debounced.cancel)
|
|
105
|
+
*
|
|
106
|
+
* // Check for pending invocations.
|
|
107
|
+
* const status = debounced.pending() ? "Pending..." : "Ready"
|
|
108
|
+
*/
|
|
109
|
+
function debounce(func, wait = 0, options = {}) {
|
|
110
|
+
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime;
|
|
111
|
+
let lastInvokeTime = 0;
|
|
112
|
+
let leading = false;
|
|
113
|
+
let maxing = false;
|
|
114
|
+
let trailing = true;
|
|
115
|
+
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
|
|
116
|
+
const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === "function";
|
|
117
|
+
if (typeof func !== "function") {
|
|
118
|
+
throw new TypeError("Expected a function");
|
|
119
|
+
}
|
|
120
|
+
wait = +wait || 0;
|
|
121
|
+
if (isObject(options)) {
|
|
122
|
+
leading = !!options.leading;
|
|
123
|
+
maxing = "maxWait" in options;
|
|
124
|
+
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
|
|
125
|
+
trailing = "trailing" in options ? !!options.trailing : trailing;
|
|
126
|
+
}
|
|
127
|
+
function invokeFunc(time) {
|
|
128
|
+
const args = lastArgs;
|
|
129
|
+
const thisArg = lastThis;
|
|
130
|
+
lastArgs = lastThis = undefined;
|
|
131
|
+
lastInvokeTime = time;
|
|
132
|
+
result = func.apply(thisArg, args);
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
function startTimer(pendingFunc, wait) {
|
|
136
|
+
if (useRAF) {
|
|
137
|
+
root.cancelAnimationFrame(timerId);
|
|
138
|
+
return root.requestAnimationFrame(pendingFunc);
|
|
139
|
+
}
|
|
140
|
+
return setTimeout(pendingFunc, wait);
|
|
141
|
+
}
|
|
142
|
+
function cancelTimer(id) {
|
|
143
|
+
if (useRAF) {
|
|
144
|
+
return root.cancelAnimationFrame(id);
|
|
145
|
+
}
|
|
146
|
+
clearTimeout(id);
|
|
147
|
+
}
|
|
148
|
+
function leadingEdge(time) {
|
|
149
|
+
// Reset any `maxWait` timer.
|
|
150
|
+
lastInvokeTime = time;
|
|
151
|
+
// Start the timer for the trailing edge.
|
|
152
|
+
timerId = startTimer(timerExpired, wait);
|
|
153
|
+
// Invoke the leading edge.
|
|
154
|
+
return leading ? invokeFunc(time) : result;
|
|
155
|
+
}
|
|
156
|
+
function remainingWait(time) {
|
|
157
|
+
const timeSinceLastCall = time - lastCallTime;
|
|
158
|
+
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
159
|
+
const timeWaiting = wait - timeSinceLastCall;
|
|
160
|
+
return maxing
|
|
161
|
+
? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
|
|
162
|
+
: timeWaiting;
|
|
163
|
+
}
|
|
164
|
+
function shouldInvoke(time) {
|
|
165
|
+
const timeSinceLastCall = time - lastCallTime;
|
|
166
|
+
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
167
|
+
// Either this is the first call, activity has stopped and we're at the
|
|
168
|
+
// trailing edge, the system time has gone backwards and we're treating
|
|
169
|
+
// it as the trailing edge, or we've hit the `maxWait` limit.
|
|
170
|
+
return (lastCallTime === undefined ||
|
|
171
|
+
timeSinceLastCall >= wait ||
|
|
172
|
+
timeSinceLastCall < 0 ||
|
|
173
|
+
(maxing && timeSinceLastInvoke >= maxWait));
|
|
174
|
+
}
|
|
175
|
+
function timerExpired() {
|
|
176
|
+
const time = Date.now();
|
|
177
|
+
if (shouldInvoke(time)) {
|
|
178
|
+
return trailingEdge(time);
|
|
179
|
+
}
|
|
180
|
+
// Restart the timer.
|
|
181
|
+
timerId = startTimer(timerExpired, remainingWait(time));
|
|
182
|
+
}
|
|
183
|
+
function trailingEdge(time) {
|
|
184
|
+
timerId = undefined;
|
|
185
|
+
// Only invoke if we have `lastArgs` which means `func` has been
|
|
186
|
+
// debounced at least once.
|
|
187
|
+
if (trailing && lastArgs) {
|
|
188
|
+
return invokeFunc(time);
|
|
189
|
+
}
|
|
190
|
+
lastArgs = lastThis = undefined;
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
function cancel() {
|
|
194
|
+
if (timerId !== undefined) {
|
|
195
|
+
cancelTimer(timerId);
|
|
196
|
+
}
|
|
197
|
+
lastInvokeTime = 0;
|
|
198
|
+
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
|
199
|
+
}
|
|
200
|
+
function flush() {
|
|
201
|
+
return timerId === undefined ? result : trailingEdge(Date.now());
|
|
202
|
+
}
|
|
203
|
+
function pending() {
|
|
204
|
+
return timerId !== undefined;
|
|
205
|
+
}
|
|
206
|
+
function debounced(...args) {
|
|
207
|
+
const time = Date.now();
|
|
208
|
+
const isInvoking = shouldInvoke(time);
|
|
209
|
+
lastArgs = args;
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
211
|
+
lastThis = this;
|
|
212
|
+
lastCallTime = time;
|
|
213
|
+
if (isInvoking) {
|
|
214
|
+
if (timerId === undefined) {
|
|
215
|
+
return leadingEdge(lastCallTime);
|
|
216
|
+
}
|
|
217
|
+
if (maxing) {
|
|
218
|
+
// Handle invocations in a tight loop.
|
|
219
|
+
timerId = startTimer(timerExpired, wait);
|
|
220
|
+
return invokeFunc(lastCallTime);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (timerId === undefined) {
|
|
224
|
+
timerId = startTimer(timerExpired, wait);
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
debounced.cancel = cancel;
|
|
229
|
+
debounced.flush = flush;
|
|
230
|
+
debounced.pending = pending;
|
|
231
|
+
return debounced;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Creates a throttled function that only invokes `func` at most once per
|
|
235
|
+
* every `wait` milliseconds (or once per browser frame). The throttled function
|
|
236
|
+
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
|
237
|
+
* `flush` method to immediately invoke them. Provide `options` to indicate
|
|
238
|
+
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
239
|
+
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
240
|
+
* throttled function. Subsequent calls to the throttled function return the
|
|
241
|
+
* result of the last `func` invocation.
|
|
242
|
+
*
|
|
243
|
+
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
244
|
+
* invoked on the trailing edge of the timeout only if the throttled function
|
|
245
|
+
* is invoked more than once during the `wait` timeout.
|
|
246
|
+
*
|
|
247
|
+
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
248
|
+
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
249
|
+
*
|
|
250
|
+
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
|
251
|
+
* invocation will be deferred until the next frame is drawn (typically about
|
|
252
|
+
* 16ms).
|
|
253
|
+
*
|
|
254
|
+
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
|
255
|
+
* for details over the differences between `throttle` and `debounce`.
|
|
256
|
+
*
|
|
257
|
+
* @since 0.1.0
|
|
258
|
+
* @category Function
|
|
259
|
+
* @param {Function} func The function to throttle.
|
|
260
|
+
* @param {number} [wait=0]
|
|
261
|
+
* The number of milliseconds to throttle invocations to; if omitted,
|
|
262
|
+
* `requestAnimationFrame` is used (if available).
|
|
263
|
+
* @param {Object} [options={}] The options object.
|
|
264
|
+
* @param {boolean} [options.leading=true]
|
|
265
|
+
* Specify invoking on the leading edge of the timeout.
|
|
266
|
+
* @param {boolean} [options.trailing=true]
|
|
267
|
+
* Specify invoking on the trailing edge of the timeout.
|
|
268
|
+
* @returns {Function} Returns the new throttled function.
|
|
269
|
+
* @example
|
|
270
|
+
*
|
|
271
|
+
* // Avoid excessively updating the position while scrolling.
|
|
272
|
+
* jQuery(window).on('scroll', throttle(updatePosition, 100))
|
|
273
|
+
*
|
|
274
|
+
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
|
|
275
|
+
* const throttled = throttle(renewToken, 300000, { 'trailing': false })
|
|
276
|
+
* jQuery(element).on('click', throttled)
|
|
277
|
+
*
|
|
278
|
+
* // Cancel the trailing throttled invocation.
|
|
279
|
+
* jQuery(window).on('popstate', throttled.cancel)
|
|
280
|
+
*/
|
|
281
|
+
function throttle(func, wait = 0, options = {}) {
|
|
282
|
+
let leading = true;
|
|
283
|
+
let trailing = true;
|
|
284
|
+
if (typeof func !== "function") {
|
|
285
|
+
throw new TypeError("Expected a function");
|
|
286
|
+
}
|
|
287
|
+
if (isObject(options)) {
|
|
288
|
+
leading = "leading" in options ? !!options.leading : leading;
|
|
289
|
+
trailing = "trailing" in options ? !!options.trailing : trailing;
|
|
290
|
+
}
|
|
291
|
+
return debounce(func, wait, {
|
|
292
|
+
leading,
|
|
293
|
+
trailing,
|
|
294
|
+
maxWait: wait,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
1
298
|
/*!
|
|
2
299
|
* Wunderbaum - util
|
|
3
300
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
4
|
-
* v0.
|
|
301
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
5
302
|
*/
|
|
6
303
|
/** @module util */
|
|
7
304
|
/** Readable names for `MouseEvent.button` */
|
|
@@ -27,8 +324,21 @@ const ENTITY_MAP = {
|
|
|
27
324
|
"'": "'",
|
|
28
325
|
"/": "/",
|
|
29
326
|
};
|
|
327
|
+
/** A generic error that can be thrown to indicate a validation error when
|
|
328
|
+
* handling the `apply` event for a node title or the `change` event for a
|
|
329
|
+
* grid cell.
|
|
330
|
+
*/
|
|
331
|
+
class ValidationError extends Error {
|
|
332
|
+
constructor(message) {
|
|
333
|
+
super(message);
|
|
334
|
+
this.name = "ValidationError";
|
|
335
|
+
}
|
|
336
|
+
}
|
|
30
337
|
/**
|
|
31
338
|
* A ES6 Promise, that exposes the resolve()/reject() methods.
|
|
339
|
+
*
|
|
340
|
+
* TODO: See [Promise.withResolvers()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers#description)
|
|
341
|
+
* , a proposed standard, but not yet implemented in any browser.
|
|
32
342
|
*/
|
|
33
343
|
let Deferred$1 = class Deferred {
|
|
34
344
|
constructor() {
|
|
@@ -360,27 +670,29 @@ function elemFromHtml(html) {
|
|
|
360
670
|
t.innerHTML = html.trim();
|
|
361
671
|
return t.content.firstElementChild;
|
|
362
672
|
}
|
|
363
|
-
const _IGNORE_KEYS = new Set(["Alt", "Control", "Meta", "Shift"]);
|
|
364
|
-
/** Return a HtmlElement from selector or cast an existing element. */
|
|
365
|
-
function elemFromSelector(obj) {
|
|
366
|
-
if (!obj) {
|
|
367
|
-
return null; //(null as unknown) as HTMLElement;
|
|
368
|
-
}
|
|
369
|
-
if (typeof obj === "string") {
|
|
370
|
-
return document.querySelector(obj);
|
|
371
|
-
}
|
|
372
|
-
return obj;
|
|
373
|
-
}
|
|
374
|
-
/** Return a EventTarget from selector or cast an existing element. */
|
|
375
|
-
function eventTargetFromSelector(obj) {
|
|
673
|
+
const _IGNORE_KEYS = new Set(["Alt", "Control", "Meta", "Shift"]);
|
|
674
|
+
/** Return a HtmlElement from selector or cast an existing element. */
|
|
675
|
+
function elemFromSelector(obj) {
|
|
376
676
|
if (!obj) {
|
|
377
|
-
return null;
|
|
677
|
+
return null; //(null as unknown) as HTMLElement;
|
|
378
678
|
}
|
|
379
679
|
if (typeof obj === "string") {
|
|
380
680
|
return document.querySelector(obj);
|
|
381
681
|
}
|
|
382
682
|
return obj;
|
|
383
683
|
}
|
|
684
|
+
// /** Return a EventTarget from selector or cast an existing element. */
|
|
685
|
+
// export function eventTargetFromSelector(
|
|
686
|
+
// obj: string | EventTarget
|
|
687
|
+
// ): EventTarget | null {
|
|
688
|
+
// if (!obj) {
|
|
689
|
+
// return null;
|
|
690
|
+
// }
|
|
691
|
+
// if (typeof obj === "string") {
|
|
692
|
+
// return document.querySelector(obj) as EventTarget;
|
|
693
|
+
// }
|
|
694
|
+
// return obj as EventTarget;
|
|
695
|
+
// }
|
|
384
696
|
/**
|
|
385
697
|
* Return a canonical descriptive string for a keyboard or mouse event.
|
|
386
698
|
*
|
|
@@ -478,7 +790,8 @@ function isPlainObject(obj) {
|
|
|
478
790
|
function noop(...args) { }
|
|
479
791
|
function onEvent(rootTarget, eventNames, selectorOrHandler, handlerOrNone) {
|
|
480
792
|
let selector, handler;
|
|
481
|
-
rootTarget =
|
|
793
|
+
rootTarget = elemFromSelector(rootTarget);
|
|
794
|
+
// rootTarget = eventTargetFromSelector<EventTarget>(rootTarget)!;
|
|
482
795
|
if (handlerOrNone) {
|
|
483
796
|
selector = selectorOrHandler;
|
|
484
797
|
handler = handlerOrNone;
|
|
@@ -669,8 +982,6 @@ function type(obj) {
|
|
|
669
982
|
* ```
|
|
670
983
|
*/
|
|
671
984
|
function adaptiveThrottle(callback, options) {
|
|
672
|
-
let waiting = 0; // Initially, we're not waiting
|
|
673
|
-
let pendingArgs = null;
|
|
674
985
|
const opts = Object.assign({
|
|
675
986
|
minDelay: 16,
|
|
676
987
|
defaultDelay: 200,
|
|
@@ -679,6 +990,9 @@ function adaptiveThrottle(callback, options) {
|
|
|
679
990
|
}, options);
|
|
680
991
|
const minDelay = Math.max(16, +opts.minDelay);
|
|
681
992
|
const maxDelay = +opts.maxDelay;
|
|
993
|
+
let waiting = 0; // Initially, we're not waiting
|
|
994
|
+
let pendingArgs = null;
|
|
995
|
+
let pendingTimer = null;
|
|
682
996
|
const throttledFn = (...args) => {
|
|
683
997
|
if (waiting) {
|
|
684
998
|
pendingArgs = args;
|
|
@@ -705,9 +1019,10 @@ function adaptiveThrottle(callback, options) {
|
|
|
705
1019
|
// `adaptiveThrottle() calling worker took ${elap}ms. delay = ${curDelay}ms, using ${useDelay}ms`,
|
|
706
1020
|
// pendingArgs
|
|
707
1021
|
// );
|
|
708
|
-
setTimeout(() => {
|
|
1022
|
+
pendingTimer = setTimeout(() => {
|
|
709
1023
|
// Unblock, and trigger pending requests if any
|
|
710
1024
|
// const skipped = waiting - 1;
|
|
1025
|
+
pendingTimer = null;
|
|
711
1026
|
waiting = 0; // And allow future invocations
|
|
712
1027
|
if (pendingArgs != null) {
|
|
713
1028
|
// There was another request while running or waiting
|
|
@@ -720,52 +1035,68 @@ function adaptiveThrottle(callback, options) {
|
|
|
720
1035
|
}, useDelay);
|
|
721
1036
|
}
|
|
722
1037
|
};
|
|
1038
|
+
throttledFn.cancel = () => {
|
|
1039
|
+
if (pendingTimer) {
|
|
1040
|
+
clearTimeout(pendingTimer);
|
|
1041
|
+
pendingTimer = null;
|
|
1042
|
+
}
|
|
1043
|
+
pendingArgs = null;
|
|
1044
|
+
waiting = 0;
|
|
1045
|
+
};
|
|
1046
|
+
throttledFn.pending = () => {
|
|
1047
|
+
return !!pendingTimer;
|
|
1048
|
+
};
|
|
1049
|
+
throttledFn.flush = () => {
|
|
1050
|
+
throw new Error("Not implemented");
|
|
1051
|
+
};
|
|
723
1052
|
return throttledFn;
|
|
724
1053
|
}
|
|
725
1054
|
|
|
726
1055
|
var util = /*#__PURE__*/Object.freeze({
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1056
|
+
__proto__: null,
|
|
1057
|
+
Deferred: Deferred$1,
|
|
1058
|
+
MAX_INT: MAX_INT,
|
|
1059
|
+
MOUSE_BUTTONS: MOUSE_BUTTONS,
|
|
1060
|
+
ValidationError: ValidationError,
|
|
1061
|
+
adaptiveThrottle: adaptiveThrottle,
|
|
1062
|
+
assert: assert,
|
|
1063
|
+
debounce: debounce,
|
|
1064
|
+
documentReady: documentReady,
|
|
1065
|
+
documentReadyPromise: documentReadyPromise,
|
|
1066
|
+
each: each,
|
|
1067
|
+
elemFromHtml: elemFromHtml,
|
|
1068
|
+
elemFromSelector: elemFromSelector,
|
|
1069
|
+
error: error,
|
|
1070
|
+
escapeHtml: escapeHtml,
|
|
1071
|
+
escapeRegex: escapeRegex,
|
|
1072
|
+
escapeTooltip: escapeTooltip,
|
|
1073
|
+
eventToString: eventToString,
|
|
1074
|
+
extend: extend,
|
|
1075
|
+
extractHtmlText: extractHtmlText,
|
|
1076
|
+
getOption: getOption,
|
|
1077
|
+
getValueFromElem: getValueFromElem,
|
|
1078
|
+
isArray: isArray,
|
|
1079
|
+
isEmptyObject: isEmptyObject,
|
|
1080
|
+
isFunction: isFunction,
|
|
1081
|
+
isMac: isMac,
|
|
1082
|
+
isPlainObject: isPlainObject,
|
|
1083
|
+
noop: noop,
|
|
1084
|
+
onEvent: onEvent,
|
|
1085
|
+
overrideMethod: overrideMethod,
|
|
1086
|
+
setElemDisplay: setElemDisplay,
|
|
1087
|
+
setTimeoutPromise: setTimeoutPromise,
|
|
1088
|
+
setValueToElem: setValueToElem,
|
|
1089
|
+
sleep: sleep,
|
|
1090
|
+
throttle: throttle,
|
|
1091
|
+
toSet: toSet,
|
|
1092
|
+
toggleCheckbox: toggleCheckbox,
|
|
1093
|
+
type: type
|
|
763
1094
|
});
|
|
764
1095
|
|
|
765
1096
|
/*!
|
|
766
1097
|
* Wunderbaum - types
|
|
767
1098
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
768
|
-
* v0.
|
|
1099
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
769
1100
|
*/
|
|
770
1101
|
/**
|
|
771
1102
|
* Possible values for {@link WunderbaumNode.update()} and {@link Wunderbaum.update()}.
|
|
@@ -829,363 +1160,66 @@ var NavModeEnum;
|
|
|
829
1160
|
/*!
|
|
830
1161
|
* Wunderbaum - wb_extension_base
|
|
831
1162
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
832
|
-
* v0.
|
|
1163
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
833
1164
|
*/
|
|
834
1165
|
class WunderbaumExtension {
|
|
835
1166
|
constructor(tree, id, defaults) {
|
|
836
1167
|
this.enabled = true;
|
|
837
|
-
this.tree = tree;
|
|
838
|
-
this.id = id;
|
|
839
|
-
this.treeOpts = tree.options;
|
|
840
|
-
const opts = tree.options;
|
|
841
|
-
if (this.treeOpts[id] === undefined) {
|
|
842
|
-
opts[id] = this.extensionOpts = extend({}, defaults);
|
|
843
|
-
}
|
|
844
|
-
else {
|
|
845
|
-
// TODO: do we break existing object instance references here?
|
|
846
|
-
this.extensionOpts = extend({}, defaults, opts[id]);
|
|
847
|
-
opts[id] = this.extensionOpts;
|
|
848
|
-
}
|
|
849
|
-
this.enabled = this.getPluginOption("enabled", true);
|
|
850
|
-
}
|
|
851
|
-
/** Called on tree (re)init after all extensions are added, but before loading.*/
|
|
852
|
-
init() {
|
|
853
|
-
this.tree.element.classList.add("wb-ext-" + this.id);
|
|
854
|
-
}
|
|
855
|
-
// protected callEvent(type: string, extra?: any): any {
|
|
856
|
-
// let func = this.extensionOpts[type];
|
|
857
|
-
// if (func) {
|
|
858
|
-
// return func.call(
|
|
859
|
-
// this.tree,
|
|
860
|
-
// util.extend(
|
|
861
|
-
// {
|
|
862
|
-
// event: this.id + "." + type,
|
|
863
|
-
// },
|
|
864
|
-
// extra
|
|
865
|
-
// )
|
|
866
|
-
// );
|
|
867
|
-
// }
|
|
868
|
-
// }
|
|
869
|
-
getPluginOption(name, defaultValue) {
|
|
870
|
-
var _a;
|
|
871
|
-
return (_a = this.extensionOpts[name]) !== null && _a !== void 0 ? _a : defaultValue;
|
|
872
|
-
}
|
|
873
|
-
setPluginOption(name, value) {
|
|
874
|
-
this.extensionOpts[name] = value;
|
|
875
|
-
}
|
|
876
|
-
setEnabled(flag = true) {
|
|
877
|
-
return this.setPluginOption("enabled", !!flag);
|
|
878
|
-
// this.enabled = !!flag;
|
|
879
|
-
}
|
|
880
|
-
onKeyEvent(data) {
|
|
881
|
-
return;
|
|
882
|
-
}
|
|
883
|
-
onRender(data) {
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
/*!
|
|
889
|
-
* debounce & throttle, taken from https://github.com/lodash/lodash v4.17.21
|
|
890
|
-
* MIT License: https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/LICENSE
|
|
891
|
-
* Modified for TypeScript type annotations.
|
|
892
|
-
*/
|
|
893
|
-
/* --- */
|
|
894
|
-
/** Detect free variable `global` from Node.js. */
|
|
895
|
-
const freeGlobal = typeof global === "object" &&
|
|
896
|
-
global !== null &&
|
|
897
|
-
global.Object === Object &&
|
|
898
|
-
global;
|
|
899
|
-
/** Detect free variable `globalThis` */
|
|
900
|
-
const freeGlobalThis = typeof globalThis === "object" &&
|
|
901
|
-
globalThis !== null &&
|
|
902
|
-
globalThis.Object == Object &&
|
|
903
|
-
globalThis;
|
|
904
|
-
/** Detect free variable `self`. */
|
|
905
|
-
const freeSelf = typeof self === "object" && self !== null && self.Object === Object && self;
|
|
906
|
-
/** Used as a reference to the global object. */
|
|
907
|
-
const root = freeGlobalThis || freeGlobal || freeSelf || Function("return this")();
|
|
908
|
-
/**
|
|
909
|
-
* Checks if `value` is the
|
|
910
|
-
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
|
911
|
-
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
912
|
-
*
|
|
913
|
-
* @since 0.1.0
|
|
914
|
-
* @category Lang
|
|
915
|
-
* @param {*} value The value to check.
|
|
916
|
-
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
|
917
|
-
* @example
|
|
918
|
-
*
|
|
919
|
-
* isObject({})
|
|
920
|
-
* // => true
|
|
921
|
-
*
|
|
922
|
-
* isObject([1, 2, 3])
|
|
923
|
-
* // => true
|
|
924
|
-
*
|
|
925
|
-
* isObject(Function)
|
|
926
|
-
* // => true
|
|
927
|
-
*
|
|
928
|
-
* isObject(null)
|
|
929
|
-
* // => false
|
|
930
|
-
*/
|
|
931
|
-
function isObject(value) {
|
|
932
|
-
const type = typeof value;
|
|
933
|
-
return value != null && (type === "object" || type === "function");
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* Creates a debounced function that delays invoking `func` until after `wait`
|
|
937
|
-
* milliseconds have elapsed since the last time the debounced function was
|
|
938
|
-
* invoked, or until the next browser frame is drawn. The debounced function
|
|
939
|
-
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
|
940
|
-
* `flush` method to immediately invoke them. Provide `options` to indicate
|
|
941
|
-
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
942
|
-
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
943
|
-
* debounced function. Subsequent calls to the debounced function return the
|
|
944
|
-
* result of the last `func` invocation.
|
|
945
|
-
*
|
|
946
|
-
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
947
|
-
* invoked on the trailing edge of the timeout only if the debounced function
|
|
948
|
-
* is invoked more than once during the `wait` timeout.
|
|
949
|
-
*
|
|
950
|
-
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
951
|
-
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
952
|
-
*
|
|
953
|
-
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
|
954
|
-
* invocation will be deferred until the next frame is drawn (typically about
|
|
955
|
-
* 16ms).
|
|
956
|
-
*
|
|
957
|
-
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
|
958
|
-
* for details over the differences between `debounce` and `throttle`.
|
|
959
|
-
*
|
|
960
|
-
* @since 0.1.0
|
|
961
|
-
* @category Function
|
|
962
|
-
* @param {Function} func The function to debounce.
|
|
963
|
-
* @param {number} [wait=0]
|
|
964
|
-
* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
|
|
965
|
-
* used (if available).
|
|
966
|
-
* @param {Object} [options={}] The options object.
|
|
967
|
-
* @param {boolean} [options.leading=false]
|
|
968
|
-
* Specify invoking on the leading edge of the timeout.
|
|
969
|
-
* @param {number} [options.maxWait]
|
|
970
|
-
* The maximum time `func` is allowed to be delayed before it's invoked.
|
|
971
|
-
* @param {boolean} [options.trailing=true]
|
|
972
|
-
* Specify invoking on the trailing edge of the timeout.
|
|
973
|
-
* @returns {Function} Returns the new debounced function.
|
|
974
|
-
* @example
|
|
975
|
-
*
|
|
976
|
-
* // Avoid costly calculations while the window size is in flux.
|
|
977
|
-
* jQuery(window).on('resize', debounce(calculateLayout, 150))
|
|
978
|
-
*
|
|
979
|
-
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
|
980
|
-
* jQuery(element).on('click', debounce(sendMail, 300, {
|
|
981
|
-
* 'leading': true,
|
|
982
|
-
* 'trailing': false
|
|
983
|
-
* }))
|
|
984
|
-
*
|
|
985
|
-
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
|
986
|
-
* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
|
|
987
|
-
* const source = new EventSource('/stream')
|
|
988
|
-
* jQuery(source).on('message', debounced)
|
|
989
|
-
*
|
|
990
|
-
* // Cancel the trailing debounced invocation.
|
|
991
|
-
* jQuery(window).on('popstate', debounced.cancel)
|
|
992
|
-
*
|
|
993
|
-
* // Check for pending invocations.
|
|
994
|
-
* const status = debounced.pending() ? "Pending..." : "Ready"
|
|
995
|
-
*/
|
|
996
|
-
function debounce(func, wait = 0, options = {}) {
|
|
997
|
-
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime;
|
|
998
|
-
let lastInvokeTime = 0;
|
|
999
|
-
let leading = false;
|
|
1000
|
-
let maxing = false;
|
|
1001
|
-
let trailing = true;
|
|
1002
|
-
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
|
|
1003
|
-
const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === "function";
|
|
1004
|
-
if (typeof func !== "function") {
|
|
1005
|
-
throw new TypeError("Expected a function");
|
|
1006
|
-
}
|
|
1007
|
-
wait = +wait || 0;
|
|
1008
|
-
if (isObject(options)) {
|
|
1009
|
-
leading = !!options.leading;
|
|
1010
|
-
maxing = "maxWait" in options;
|
|
1011
|
-
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
|
|
1012
|
-
trailing = "trailing" in options ? !!options.trailing : trailing;
|
|
1013
|
-
}
|
|
1014
|
-
function invokeFunc(time) {
|
|
1015
|
-
const args = lastArgs;
|
|
1016
|
-
const thisArg = lastThis;
|
|
1017
|
-
lastArgs = lastThis = undefined;
|
|
1018
|
-
lastInvokeTime = time;
|
|
1019
|
-
result = func.apply(thisArg, args);
|
|
1020
|
-
return result;
|
|
1021
|
-
}
|
|
1022
|
-
function startTimer(pendingFunc, wait) {
|
|
1023
|
-
if (useRAF) {
|
|
1024
|
-
root.cancelAnimationFrame(timerId);
|
|
1025
|
-
return root.requestAnimationFrame(pendingFunc);
|
|
1026
|
-
}
|
|
1027
|
-
return setTimeout(pendingFunc, wait);
|
|
1028
|
-
}
|
|
1029
|
-
function cancelTimer(id) {
|
|
1030
|
-
if (useRAF) {
|
|
1031
|
-
return root.cancelAnimationFrame(id);
|
|
1032
|
-
}
|
|
1033
|
-
clearTimeout(id);
|
|
1034
|
-
}
|
|
1035
|
-
function leadingEdge(time) {
|
|
1036
|
-
// Reset any `maxWait` timer.
|
|
1037
|
-
lastInvokeTime = time;
|
|
1038
|
-
// Start the timer for the trailing edge.
|
|
1039
|
-
timerId = startTimer(timerExpired, wait);
|
|
1040
|
-
// Invoke the leading edge.
|
|
1041
|
-
return leading ? invokeFunc(time) : result;
|
|
1042
|
-
}
|
|
1043
|
-
function remainingWait(time) {
|
|
1044
|
-
const timeSinceLastCall = time - lastCallTime;
|
|
1045
|
-
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
1046
|
-
const timeWaiting = wait - timeSinceLastCall;
|
|
1047
|
-
return maxing
|
|
1048
|
-
? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
|
|
1049
|
-
: timeWaiting;
|
|
1050
|
-
}
|
|
1051
|
-
function shouldInvoke(time) {
|
|
1052
|
-
const timeSinceLastCall = time - lastCallTime;
|
|
1053
|
-
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
1054
|
-
// Either this is the first call, activity has stopped and we're at the
|
|
1055
|
-
// trailing edge, the system time has gone backwards and we're treating
|
|
1056
|
-
// it as the trailing edge, or we've hit the `maxWait` limit.
|
|
1057
|
-
return (lastCallTime === undefined ||
|
|
1058
|
-
timeSinceLastCall >= wait ||
|
|
1059
|
-
timeSinceLastCall < 0 ||
|
|
1060
|
-
(maxing && timeSinceLastInvoke >= maxWait));
|
|
1061
|
-
}
|
|
1062
|
-
function timerExpired() {
|
|
1063
|
-
const time = Date.now();
|
|
1064
|
-
if (shouldInvoke(time)) {
|
|
1065
|
-
return trailingEdge(time);
|
|
1066
|
-
}
|
|
1067
|
-
// Restart the timer.
|
|
1068
|
-
timerId = startTimer(timerExpired, remainingWait(time));
|
|
1069
|
-
}
|
|
1070
|
-
function trailingEdge(time) {
|
|
1071
|
-
timerId = undefined;
|
|
1072
|
-
// Only invoke if we have `lastArgs` which means `func` has been
|
|
1073
|
-
// debounced at least once.
|
|
1074
|
-
if (trailing && lastArgs) {
|
|
1075
|
-
return invokeFunc(time);
|
|
1168
|
+
this.tree = tree;
|
|
1169
|
+
this.id = id;
|
|
1170
|
+
this.treeOpts = tree.options;
|
|
1171
|
+
const opts = tree.options;
|
|
1172
|
+
if (this.treeOpts[id] === undefined) {
|
|
1173
|
+
opts[id] = this.extensionOpts = extend({}, defaults);
|
|
1076
1174
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
if (timerId !== undefined) {
|
|
1082
|
-
cancelTimer(timerId);
|
|
1175
|
+
else {
|
|
1176
|
+
// TODO: do we break existing object instance references here?
|
|
1177
|
+
this.extensionOpts = extend({}, defaults, opts[id]);
|
|
1178
|
+
opts[id] = this.extensionOpts;
|
|
1083
1179
|
}
|
|
1084
|
-
|
|
1085
|
-
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
|
1180
|
+
this.enabled = this.getPluginOption("enabled", true);
|
|
1086
1181
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1182
|
+
/** Called on tree (re)init after all extensions are added, but before loading.*/
|
|
1183
|
+
init() {
|
|
1184
|
+
this.tree.element.classList.add("wb-ext-" + this.id);
|
|
1089
1185
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1186
|
+
// protected callEvent(type: string, extra?: any): any {
|
|
1187
|
+
// let func = this.extensionOpts[type];
|
|
1188
|
+
// if (func) {
|
|
1189
|
+
// return func.call(
|
|
1190
|
+
// this.tree,
|
|
1191
|
+
// util.extend(
|
|
1192
|
+
// {
|
|
1193
|
+
// event: this.id + "." + type,
|
|
1194
|
+
// },
|
|
1195
|
+
// extra
|
|
1196
|
+
// )
|
|
1197
|
+
// );
|
|
1198
|
+
// }
|
|
1199
|
+
// }
|
|
1200
|
+
getPluginOption(name, defaultValue) {
|
|
1201
|
+
var _a;
|
|
1202
|
+
return (_a = this.extensionOpts[name]) !== null && _a !== void 0 ? _a : defaultValue;
|
|
1092
1203
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
const isInvoking = shouldInvoke(time);
|
|
1096
|
-
lastArgs = args;
|
|
1097
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1098
|
-
lastThis = this;
|
|
1099
|
-
lastCallTime = time;
|
|
1100
|
-
if (isInvoking) {
|
|
1101
|
-
if (timerId === undefined) {
|
|
1102
|
-
return leadingEdge(lastCallTime);
|
|
1103
|
-
}
|
|
1104
|
-
if (maxing) {
|
|
1105
|
-
// Handle invocations in a tight loop.
|
|
1106
|
-
timerId = startTimer(timerExpired, wait);
|
|
1107
|
-
return invokeFunc(lastCallTime);
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
if (timerId === undefined) {
|
|
1111
|
-
timerId = startTimer(timerExpired, wait);
|
|
1112
|
-
}
|
|
1113
|
-
return result;
|
|
1204
|
+
setPluginOption(name, value) {
|
|
1205
|
+
this.extensionOpts[name] = value;
|
|
1114
1206
|
}
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
return debounced;
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* Creates a throttled function that only invokes `func` at most once per
|
|
1122
|
-
* every `wait` milliseconds (or once per browser frame). The throttled function
|
|
1123
|
-
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
|
1124
|
-
* `flush` method to immediately invoke them. Provide `options` to indicate
|
|
1125
|
-
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
1126
|
-
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
1127
|
-
* throttled function. Subsequent calls to the throttled function return the
|
|
1128
|
-
* result of the last `func` invocation.
|
|
1129
|
-
*
|
|
1130
|
-
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
1131
|
-
* invoked on the trailing edge of the timeout only if the throttled function
|
|
1132
|
-
* is invoked more than once during the `wait` timeout.
|
|
1133
|
-
*
|
|
1134
|
-
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
1135
|
-
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
1136
|
-
*
|
|
1137
|
-
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
|
1138
|
-
* invocation will be deferred until the next frame is drawn (typically about
|
|
1139
|
-
* 16ms).
|
|
1140
|
-
*
|
|
1141
|
-
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
|
1142
|
-
* for details over the differences between `throttle` and `debounce`.
|
|
1143
|
-
*
|
|
1144
|
-
* @since 0.1.0
|
|
1145
|
-
* @category Function
|
|
1146
|
-
* @param {Function} func The function to throttle.
|
|
1147
|
-
* @param {number} [wait=0]
|
|
1148
|
-
* The number of milliseconds to throttle invocations to; if omitted,
|
|
1149
|
-
* `requestAnimationFrame` is used (if available).
|
|
1150
|
-
* @param {Object} [options={}] The options object.
|
|
1151
|
-
* @param {boolean} [options.leading=true]
|
|
1152
|
-
* Specify invoking on the leading edge of the timeout.
|
|
1153
|
-
* @param {boolean} [options.trailing=true]
|
|
1154
|
-
* Specify invoking on the trailing edge of the timeout.
|
|
1155
|
-
* @returns {Function} Returns the new throttled function.
|
|
1156
|
-
* @example
|
|
1157
|
-
*
|
|
1158
|
-
* // Avoid excessively updating the position while scrolling.
|
|
1159
|
-
* jQuery(window).on('scroll', throttle(updatePosition, 100))
|
|
1160
|
-
*
|
|
1161
|
-
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
|
|
1162
|
-
* const throttled = throttle(renewToken, 300000, { 'trailing': false })
|
|
1163
|
-
* jQuery(element).on('click', throttled)
|
|
1164
|
-
*
|
|
1165
|
-
* // Cancel the trailing throttled invocation.
|
|
1166
|
-
* jQuery(window).on('popstate', throttled.cancel)
|
|
1167
|
-
*/
|
|
1168
|
-
function throttle(func, wait = 0, options = {}) {
|
|
1169
|
-
let leading = true;
|
|
1170
|
-
let trailing = true;
|
|
1171
|
-
if (typeof func !== "function") {
|
|
1172
|
-
throw new TypeError("Expected a function");
|
|
1207
|
+
setEnabled(flag = true) {
|
|
1208
|
+
return this.setPluginOption("enabled", !!flag);
|
|
1209
|
+
// this.enabled = !!flag;
|
|
1173
1210
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1211
|
+
onKeyEvent(data) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
onRender(data) {
|
|
1215
|
+
return;
|
|
1177
1216
|
}
|
|
1178
|
-
return debounce(func, wait, {
|
|
1179
|
-
leading,
|
|
1180
|
-
trailing,
|
|
1181
|
-
maxWait: wait,
|
|
1182
|
-
});
|
|
1183
1217
|
}
|
|
1184
1218
|
|
|
1185
1219
|
/*!
|
|
1186
1220
|
* Wunderbaum - ext-filter
|
|
1187
1221
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1188
|
-
* v0.
|
|
1222
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
1189
1223
|
*/
|
|
1190
1224
|
const START_MARKER = "\uFFF7";
|
|
1191
1225
|
const END_MARKER = "\uFFF8";
|
|
@@ -1367,7 +1401,12 @@ class FilterExtension extends WunderbaumExtension {
|
|
|
1367
1401
|
});
|
|
1368
1402
|
treeOpts.autoCollapse = prevAutoCollapse;
|
|
1369
1403
|
if (count === 0 && opts.noData && hideMode) {
|
|
1370
|
-
|
|
1404
|
+
if (typeof opts.noData === "string") {
|
|
1405
|
+
tree.root.setStatus(NodeStatusType.noData, { message: opts.noData });
|
|
1406
|
+
}
|
|
1407
|
+
else {
|
|
1408
|
+
tree.root.setStatus(NodeStatusType.noData);
|
|
1409
|
+
}
|
|
1371
1410
|
}
|
|
1372
1411
|
// Redraw whole tree
|
|
1373
1412
|
tree.logInfo(`Filter '${match}' found ${count} nodes in ${Date.now() - start} ms.`);
|
|
@@ -1485,7 +1524,7 @@ function _markFuzzyMatchedChars(text, matches, escapeTitles = true) {
|
|
|
1485
1524
|
/*!
|
|
1486
1525
|
* Wunderbaum - ext-keynav
|
|
1487
1526
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1488
|
-
* v0.
|
|
1527
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
1489
1528
|
*/
|
|
1490
1529
|
const QUICKSEARCH_DELAY = 500;
|
|
1491
1530
|
class KeynavExtension extends WunderbaumExtension {
|
|
@@ -1507,6 +1546,13 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1507
1546
|
}
|
|
1508
1547
|
return input;
|
|
1509
1548
|
}
|
|
1549
|
+
// /* Return the current cell's embedded input that has keyboard focus. */
|
|
1550
|
+
// protected _getFocusedInputElem(): HTMLInputElement | null {
|
|
1551
|
+
// const ace = this.tree
|
|
1552
|
+
// .getActiveColElem()
|
|
1553
|
+
// ?.querySelector<HTMLInputElement>("input:focus,select:focus");
|
|
1554
|
+
// return ace || null;
|
|
1555
|
+
// }
|
|
1510
1556
|
/* Return true if the current cell's embedded input has keyboard focus. */
|
|
1511
1557
|
_isCurInputFocused() {
|
|
1512
1558
|
var _a;
|
|
@@ -1522,7 +1568,6 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1522
1568
|
const curInput = this._getEmbeddedInputElem(event.target);
|
|
1523
1569
|
const inputHasFocus = curInput && this._isCurInputFocused();
|
|
1524
1570
|
const navModeOption = opts.navigationModeOption;
|
|
1525
|
-
// isCellEditMode = tree.navMode === NavigationMode.cellEdit;
|
|
1526
1571
|
let focusNode, eventName = eventToString(event), node = data.node, handled = true;
|
|
1527
1572
|
// tree.log(`onKeyEvent: ${eventName}, curInput`, curInput);
|
|
1528
1573
|
if (!tree.isEnabled()) {
|
|
@@ -1667,22 +1712,34 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1667
1712
|
}
|
|
1668
1713
|
}
|
|
1669
1714
|
else {
|
|
1670
|
-
|
|
1715
|
+
// -----------------------------------------------------------------------
|
|
1716
|
+
// --- Cell Mode ---
|
|
1717
|
+
// -----------------------------------------------------------------------
|
|
1718
|
+
// // Standard navigation (cell mode)
|
|
1719
|
+
// if (isCellEditMode && INPUT_BREAKOUT_KEYS.has(eventName)) {
|
|
1720
|
+
// }
|
|
1721
|
+
// const curInput = this._getEmbeddedInputElem(null);
|
|
1671
1722
|
const curInputType = curInput ? curInput.type || curInput.tagName : "";
|
|
1672
|
-
const inputHasFocus = curInput && this._isCurInputFocused();
|
|
1723
|
+
// const inputHasFocus = curInput && this._isCurInputFocused();
|
|
1673
1724
|
const inputCanFocus = curInput && curInputType !== "checkbox";
|
|
1674
1725
|
if (inputHasFocus) {
|
|
1675
1726
|
if (eventName === "Escape") {
|
|
1676
|
-
|
|
1727
|
+
node.logDebug(`Reset focused input on Escape`);
|
|
1728
|
+
// Discard changes and reset input validation state
|
|
1729
|
+
curInput.setCustomValidity("");
|
|
1677
1730
|
node._render();
|
|
1678
1731
|
// Keep cell-nav mode
|
|
1679
|
-
node.logDebug(`Reset focused input`);
|
|
1680
1732
|
tree.setFocus();
|
|
1681
1733
|
tree.setColumn(tree.activeColIdx);
|
|
1682
1734
|
return;
|
|
1683
1735
|
// } else if (!INPUT_BREAKOUT_KEYS.has(eventName)) {
|
|
1684
1736
|
}
|
|
1685
1737
|
else if (eventName !== "Enter") {
|
|
1738
|
+
if (curInput && curInput.checkValidity && !curInput.checkValidity()) {
|
|
1739
|
+
// Invalid input: ignore all keys except Enter and Escape
|
|
1740
|
+
node.logDebug(`Ignored ${eventName} inside invalid input`);
|
|
1741
|
+
return false;
|
|
1742
|
+
}
|
|
1686
1743
|
// Let current `<input>` handle it
|
|
1687
1744
|
node.logDebug(`Ignored ${eventName} inside focused input`);
|
|
1688
1745
|
return;
|
|
@@ -1697,9 +1754,10 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1697
1754
|
else if (curInput) {
|
|
1698
1755
|
// On a cell that has an embedded, unfocused <input>
|
|
1699
1756
|
if (eventName.length === 1 && inputCanFocus) {
|
|
1757
|
+
// Typing a single char
|
|
1700
1758
|
curInput.focus();
|
|
1701
1759
|
curInput.value = "";
|
|
1702
|
-
node.logDebug(`Focus
|
|
1760
|
+
node.logDebug(`Focus input: ${eventName}`);
|
|
1703
1761
|
return false;
|
|
1704
1762
|
}
|
|
1705
1763
|
}
|
|
@@ -1711,7 +1769,6 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1711
1769
|
eventName = tree.activeColIdx > 0 ? "ArrowLeft" : "";
|
|
1712
1770
|
handled = true;
|
|
1713
1771
|
}
|
|
1714
|
-
else ;
|
|
1715
1772
|
switch (eventName) {
|
|
1716
1773
|
case "+":
|
|
1717
1774
|
case "Add":
|
|
@@ -1831,7 +1888,7 @@ class KeynavExtension extends WunderbaumExtension {
|
|
|
1831
1888
|
/*!
|
|
1832
1889
|
* Wunderbaum - ext-logger
|
|
1833
1890
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1834
|
-
* v0.
|
|
1891
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
1835
1892
|
*/
|
|
1836
1893
|
class LoggerExtension extends WunderbaumExtension {
|
|
1837
1894
|
constructor(tree) {
|
|
@@ -1873,7 +1930,7 @@ class LoggerExtension extends WunderbaumExtension {
|
|
|
1873
1930
|
/*!
|
|
1874
1931
|
* Wunderbaum - common
|
|
1875
1932
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
1876
|
-
* v0.
|
|
1933
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
1877
1934
|
*/
|
|
1878
1935
|
const DEFAULT_DEBUGLEVEL = 3; // Replaced by rollup script
|
|
1879
1936
|
/**
|
|
@@ -1992,7 +2049,7 @@ const KEY_TO_ACTION_DICT = {
|
|
|
1992
2049
|
};
|
|
1993
2050
|
/** Return a callback that returns true if the node title matches the string
|
|
1994
2051
|
* or regular expression.
|
|
1995
|
-
* @see {@link WunderbaumNode.findAll}
|
|
2052
|
+
* @see {@link WunderbaumNode.findAll()}
|
|
1996
2053
|
*/
|
|
1997
2054
|
function makeNodeTitleMatcher(match) {
|
|
1998
2055
|
if (match instanceof RegExp) {
|
|
@@ -2196,7 +2253,7 @@ function decompressSourceData(source) {
|
|
|
2196
2253
|
/*!
|
|
2197
2254
|
* Wunderbaum - ext-dnd
|
|
2198
2255
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2199
|
-
* v0.
|
|
2256
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
2200
2257
|
*/
|
|
2201
2258
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
2202
2259
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -2445,7 +2502,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2445
2502
|
if (e.type === "dragstart") {
|
|
2446
2503
|
// Set a default definition of allowed effects
|
|
2447
2504
|
e.dataTransfer.effectAllowed = dndOpts.effectAllowed; //"copyMove"; // "all";
|
|
2448
|
-
if (srcNode.
|
|
2505
|
+
if (srcNode.isEditingTitle()) {
|
|
2449
2506
|
srcNode.logDebug("Prevented dragging node in edit mode.");
|
|
2450
2507
|
e.preventDefault();
|
|
2451
2508
|
return false;
|
|
@@ -2627,7 +2684,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2627
2684
|
/*!
|
|
2628
2685
|
* Wunderbaum - drag_observer
|
|
2629
2686
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2630
|
-
* v0.
|
|
2687
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
2631
2688
|
*/
|
|
2632
2689
|
/**
|
|
2633
2690
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2763,7 +2820,7 @@ class DragObserver {
|
|
|
2763
2820
|
/*!
|
|
2764
2821
|
* Wunderbaum - ext-grid
|
|
2765
2822
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2766
|
-
* v0.
|
|
2823
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
2767
2824
|
*/
|
|
2768
2825
|
class GridExtension extends WunderbaumExtension {
|
|
2769
2826
|
constructor(tree) {
|
|
@@ -2800,7 +2857,7 @@ class GridExtension extends WunderbaumExtension {
|
|
|
2800
2857
|
/*!
|
|
2801
2858
|
* Wunderbaum - deferred
|
|
2802
2859
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2803
|
-
* v0.
|
|
2860
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
2804
2861
|
*/
|
|
2805
2862
|
/**
|
|
2806
2863
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -2824,27 +2881,27 @@ class Deferred {
|
|
|
2824
2881
|
this._reject = reject;
|
|
2825
2882
|
});
|
|
2826
2883
|
}
|
|
2827
|
-
/** Resolve the
|
|
2884
|
+
/** Resolve the Promise. */
|
|
2828
2885
|
resolve(value) {
|
|
2829
2886
|
this._resolve(value);
|
|
2830
2887
|
}
|
|
2831
|
-
/** Reject the
|
|
2888
|
+
/** Reject the Promise. */
|
|
2832
2889
|
reject(reason) {
|
|
2833
2890
|
this._reject(reason);
|
|
2834
2891
|
}
|
|
2835
|
-
/** Return the native
|
|
2892
|
+
/** Return the native Promise instance.*/
|
|
2836
2893
|
promise() {
|
|
2837
2894
|
return this._promise;
|
|
2838
2895
|
}
|
|
2839
|
-
/** Call
|
|
2896
|
+
/** Call Promise.then on the embedded promise instance.*/
|
|
2840
2897
|
then(cb) {
|
|
2841
2898
|
return this._promise.then(cb);
|
|
2842
2899
|
}
|
|
2843
|
-
/** Call
|
|
2900
|
+
/** Call Promise.catch on the embedded promise instance.*/
|
|
2844
2901
|
catch(cb) {
|
|
2845
2902
|
return this._promise.catch(cb);
|
|
2846
2903
|
}
|
|
2847
|
-
/** Call
|
|
2904
|
+
/** Call Promise.finally on the embedded promise instance.*/
|
|
2848
2905
|
finally(cb) {
|
|
2849
2906
|
return this._promise.finally(cb);
|
|
2850
2907
|
}
|
|
@@ -2853,7 +2910,7 @@ class Deferred {
|
|
|
2853
2910
|
/*!
|
|
2854
2911
|
* Wunderbaum - wunderbaum_node
|
|
2855
2912
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2856
|
-
* v0.
|
|
2913
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
2857
2914
|
*/
|
|
2858
2915
|
/** WunderbaumNode properties that can be passed with source data.
|
|
2859
2916
|
* (Any other source properties will be stored as `node.data.PROP`.)
|
|
@@ -3154,6 +3211,10 @@ class WunderbaumNode {
|
|
|
3154
3211
|
}
|
|
3155
3212
|
}
|
|
3156
3213
|
}
|
|
3214
|
+
/** Start editing this node's title. */
|
|
3215
|
+
startEditTitle() {
|
|
3216
|
+
this.tree._callMethod("edit.startEditTitle", this);
|
|
3217
|
+
}
|
|
3157
3218
|
/** Call `setExpanded()` on all descendant nodes. */
|
|
3158
3219
|
async expandAll(flag = true, options) {
|
|
3159
3220
|
const tree = this.tree;
|
|
@@ -3363,6 +3424,22 @@ class WunderbaumNode {
|
|
|
3363
3424
|
const colElems = (_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.querySelectorAll("span.wb-col");
|
|
3364
3425
|
return colElems ? colElems[colIdx] : null;
|
|
3365
3426
|
}
|
|
3427
|
+
/**
|
|
3428
|
+
* Return all nodes with the same refKey.
|
|
3429
|
+
*
|
|
3430
|
+
* @param includeSelf Include this node itself.
|
|
3431
|
+
* @see {@link Wunderbaum.findByRefKey}
|
|
3432
|
+
*/
|
|
3433
|
+
getCloneList(includeSelf = false) {
|
|
3434
|
+
if (!this.refKey) {
|
|
3435
|
+
return [];
|
|
3436
|
+
}
|
|
3437
|
+
const clones = this.tree.findByRefKey(this.refKey);
|
|
3438
|
+
if (includeSelf) {
|
|
3439
|
+
return clones;
|
|
3440
|
+
}
|
|
3441
|
+
return [...clones].filter((n) => n !== this);
|
|
3442
|
+
}
|
|
3366
3443
|
/** Return the first child node or null.
|
|
3367
3444
|
* @returns {WunderbaumNode | null}
|
|
3368
3445
|
*/
|
|
@@ -3467,17 +3544,22 @@ class WunderbaumNode {
|
|
|
3467
3544
|
return this.tree.activeNode === this;
|
|
3468
3545
|
}
|
|
3469
3546
|
/** Return true if this node is a direct or indirect parent of `other`.
|
|
3470
|
-
*
|
|
3547
|
+
* @see {@link WunderbaumNode.isParentOf}
|
|
3471
3548
|
*/
|
|
3472
3549
|
isAncestorOf(other) {
|
|
3473
3550
|
return other && other.isDescendantOf(this);
|
|
3474
3551
|
}
|
|
3475
3552
|
/** Return true if this node is a **direct** subnode of `other`.
|
|
3476
|
-
*
|
|
3553
|
+
* @see {@link WunderbaumNode.isDescendantOf}
|
|
3477
3554
|
*/
|
|
3478
3555
|
isChildOf(other) {
|
|
3479
3556
|
return other && this.parent === other;
|
|
3480
3557
|
}
|
|
3558
|
+
/** Return true if this node's refKey is used by at least one other node.
|
|
3559
|
+
*/
|
|
3560
|
+
isClone() {
|
|
3561
|
+
return !!this.refKey && this.tree.findByRefKey(this.refKey).length > 1;
|
|
3562
|
+
}
|
|
3481
3563
|
/** Return true if this node's title spans all columns, i.e. the node has no
|
|
3482
3564
|
* grid cells.
|
|
3483
3565
|
*/
|
|
@@ -3485,7 +3567,7 @@ class WunderbaumNode {
|
|
|
3485
3567
|
return !!this.getOption("colspan");
|
|
3486
3568
|
}
|
|
3487
3569
|
/** Return true if this node is a direct or indirect subnode of `other`.
|
|
3488
|
-
*
|
|
3570
|
+
* @see {@link WunderbaumNode.isChildOf}
|
|
3489
3571
|
*/
|
|
3490
3572
|
isDescendantOf(other) {
|
|
3491
3573
|
if (!other || other.tree !== this.tree) {
|
|
@@ -3520,8 +3602,11 @@ class WunderbaumNode {
|
|
|
3520
3602
|
}
|
|
3521
3603
|
return true;
|
|
3522
3604
|
}
|
|
3523
|
-
/** Return true if
|
|
3524
|
-
|
|
3605
|
+
/** Return true if _this_ node is currently in edit-title mode.
|
|
3606
|
+
*
|
|
3607
|
+
* See {@link Wunderbaum.startEditTitle} to check if any node is currently edited.
|
|
3608
|
+
*/
|
|
3609
|
+
isEditingTitle() {
|
|
3525
3610
|
return this.tree._callMethod("edit.isEditingTitle", this);
|
|
3526
3611
|
}
|
|
3527
3612
|
/** Return true if this node is currently expanded. */
|
|
@@ -3555,7 +3640,7 @@ class WunderbaumNode {
|
|
|
3555
3640
|
return this.statusNodeType === "paging";
|
|
3556
3641
|
}
|
|
3557
3642
|
/** Return true if this node is a **direct** parent of `other`.
|
|
3558
|
-
*
|
|
3643
|
+
* @see {@link WunderbaumNode.isAncestorOf}
|
|
3559
3644
|
*/
|
|
3560
3645
|
isParentOf(other) {
|
|
3561
3646
|
return other && other.parent === this;
|
|
@@ -3577,7 +3662,7 @@ class WunderbaumNode {
|
|
|
3577
3662
|
return !!this._rowElem;
|
|
3578
3663
|
}
|
|
3579
3664
|
/** Return true if this node is the (invisible) system root node.
|
|
3580
|
-
*
|
|
3665
|
+
* @see {@link WunderbaumNode.isTopLevel}
|
|
3581
3666
|
*/
|
|
3582
3667
|
isRootNode() {
|
|
3583
3668
|
return this.tree.root === this;
|
|
@@ -4456,6 +4541,7 @@ class WunderbaumNode {
|
|
|
4456
4541
|
let i = 0;
|
|
4457
4542
|
for (const colSpan of rowDiv.children) {
|
|
4458
4543
|
colSpan.classList.toggle("wb-active", i++ === tree.activeColIdx);
|
|
4544
|
+
colSpan.classList.remove("wb-error", "wb-invalid");
|
|
4459
4545
|
}
|
|
4460
4546
|
// Update icon (if not opts.isNew, which would rebuild markup anyway)
|
|
4461
4547
|
const iconSpan = nodeElem.querySelector("i.wb-icon");
|
|
@@ -4637,16 +4723,21 @@ class WunderbaumNode {
|
|
|
4637
4723
|
return this.tree.scrollTo(opts);
|
|
4638
4724
|
}
|
|
4639
4725
|
/**
|
|
4640
|
-
* Activate this node, deactivate previous, send events, activate column and
|
|
4726
|
+
* Activate this node, deactivate previous, send events, activate column and
|
|
4727
|
+
* scroll into viewport.
|
|
4641
4728
|
*/
|
|
4642
4729
|
async setActive(flag = true, options) {
|
|
4643
4730
|
const tree = this.tree;
|
|
4644
4731
|
const prev = tree.activeNode;
|
|
4645
4732
|
const retrigger = options === null || options === void 0 ? void 0 : options.retrigger; // Default: false
|
|
4646
4733
|
const focusTree = options === null || options === void 0 ? void 0 : options.focusTree; // Default: false
|
|
4647
|
-
const focusNode =
|
|
4734
|
+
// const focusNode = options?.focusNode !== false; // Default: true
|
|
4648
4735
|
const noEvents = options === null || options === void 0 ? void 0 : options.noEvents; // Default: false
|
|
4649
|
-
const orgEvent = options === null || options === void 0 ? void 0 : options.event; // Default:
|
|
4736
|
+
const orgEvent = options === null || options === void 0 ? void 0 : options.event; // Default: null
|
|
4737
|
+
const colIdx = options === null || options === void 0 ? void 0 : options.colIdx; // Default: null
|
|
4738
|
+
const edit = options === null || options === void 0 ? void 0 : options.edit; // Default: false
|
|
4739
|
+
assert(!colIdx || tree.isCellNav(), "colIdx requires cellNav");
|
|
4740
|
+
assert(!edit || colIdx != null, "edit requires colIdx");
|
|
4650
4741
|
if (!noEvents) {
|
|
4651
4742
|
if (flag) {
|
|
4652
4743
|
if (prev !== this || retrigger) {
|
|
@@ -4671,32 +4762,36 @@ class WunderbaumNode {
|
|
|
4671
4762
|
if (prev !== this) {
|
|
4672
4763
|
if (flag) {
|
|
4673
4764
|
tree.activeNode = this;
|
|
4674
|
-
if (focusNode || focusTree) {
|
|
4675
|
-
tree.focusNode = this;
|
|
4676
|
-
}
|
|
4677
|
-
if (focusTree) {
|
|
4678
|
-
tree.setFocus();
|
|
4679
|
-
}
|
|
4680
4765
|
}
|
|
4681
4766
|
prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status);
|
|
4682
4767
|
this.update(ChangeType.status);
|
|
4683
4768
|
}
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4769
|
+
return this.makeVisible().then(() => {
|
|
4770
|
+
if (flag) {
|
|
4771
|
+
if (focusTree || edit) {
|
|
4772
|
+
tree.setFocus();
|
|
4773
|
+
tree.focusNode = this;
|
|
4774
|
+
tree.focusNode.setFocus();
|
|
4775
|
+
}
|
|
4776
|
+
// if (focusNode || edit) {
|
|
4777
|
+
// tree.focusNode = this;
|
|
4778
|
+
// tree.focusNode.setFocus();
|
|
4779
|
+
// }
|
|
4780
|
+
if (colIdx != null && tree.isCellNav()) {
|
|
4781
|
+
tree.setColumn(colIdx, { edit: edit });
|
|
4782
|
+
}
|
|
4783
|
+
if (!noEvents) {
|
|
4784
|
+
this._callEvent("activate", { prevNode: prev, event: orgEvent });
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
});
|
|
4694
4788
|
}
|
|
4695
4789
|
/**
|
|
4696
4790
|
* Expand or collapse this node.
|
|
4697
4791
|
*/
|
|
4698
4792
|
async setExpanded(flag = true, options) {
|
|
4699
4793
|
const { force, scrollIntoView, immediate } = options !== null && options !== void 0 ? options : {};
|
|
4794
|
+
const sendEvents = !(options === null || options === void 0 ? void 0 : options.noEvents); // Default: send events
|
|
4700
4795
|
if (!flag &&
|
|
4701
4796
|
this.isExpanded() &&
|
|
4702
4797
|
this.getLevel() <= this.tree.getOption("minExpandLevel") &&
|
|
@@ -4707,6 +4802,10 @@ class WunderbaumNode {
|
|
|
4707
4802
|
if (!flag === !this.expanded) {
|
|
4708
4803
|
return; // Nothing to do
|
|
4709
4804
|
}
|
|
4805
|
+
if (sendEvents &&
|
|
4806
|
+
this._callEvent("beforeExpand", { flag: flag }) === false) {
|
|
4807
|
+
return;
|
|
4808
|
+
}
|
|
4710
4809
|
// this.log("setExpanded()");
|
|
4711
4810
|
if (flag && this.getOption("autoCollapse")) {
|
|
4712
4811
|
this.collapseSiblings(options);
|
|
@@ -4725,13 +4824,16 @@ class WunderbaumNode {
|
|
|
4725
4824
|
lastChild.scrollIntoView({ topNode: this });
|
|
4726
4825
|
}
|
|
4727
4826
|
}
|
|
4827
|
+
if (sendEvents) {
|
|
4828
|
+
this._callEvent("expand", { flag: flag });
|
|
4829
|
+
}
|
|
4728
4830
|
}
|
|
4729
4831
|
/**
|
|
4730
4832
|
* Set keyboard focus here.
|
|
4731
4833
|
* @see {@link setActive}
|
|
4732
4834
|
*/
|
|
4733
4835
|
setFocus(flag = true) {
|
|
4734
|
-
assert(!!flag, "
|
|
4836
|
+
assert(!!flag, "Blur is not yet implemented");
|
|
4735
4837
|
const prev = this.tree.focusNode;
|
|
4736
4838
|
this.tree.focusNode = this;
|
|
4737
4839
|
prev === null || prev === void 0 ? void 0 : prev.update();
|
|
@@ -5186,7 +5288,7 @@ WunderbaumNode.sequence = 0;
|
|
|
5186
5288
|
/*!
|
|
5187
5289
|
* Wunderbaum - ext-edit
|
|
5188
5290
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
5189
|
-
* v0.
|
|
5291
|
+
* v0.8.0, Thu, 11 Jan 2024 19:37:23 GMT (https://github.com/mar10/wunderbaum)
|
|
5190
5292
|
*/
|
|
5191
5293
|
// const START_MARKER = "\uFFF7";
|
|
5192
5294
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -5211,40 +5313,62 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5211
5313
|
this.debouncedOnChange = debounce(this._onChange.bind(this), this.getPluginOption("debounce"));
|
|
5212
5314
|
}
|
|
5213
5315
|
/*
|
|
5214
|
-
* Call an event handler, while marking the current node cell '
|
|
5316
|
+
* Call an event handler, while marking the current node cell 'busy'.
|
|
5317
|
+
* Deal with returned promises and ValidationError.
|
|
5318
|
+
* Convert a ValidationError into a input.setCustomValidity() call and vice versa.
|
|
5215
5319
|
*/
|
|
5216
|
-
_applyChange(eventName, node, colElem, extra) {
|
|
5217
|
-
let res;
|
|
5320
|
+
async _applyChange(eventName, node, colElem, inputElem, extra) {
|
|
5218
5321
|
node.log(`_applyChange(${eventName})`, extra);
|
|
5219
5322
|
colElem.classList.add("wb-busy");
|
|
5220
|
-
colElem.classList.remove("wb-error");
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
node.
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5323
|
+
colElem.classList.remove("wb-error", "wb-invalid");
|
|
5324
|
+
inputElem.setCustomValidity("");
|
|
5325
|
+
// Call event handler either ('change' or 'edit.appy'), which may return a
|
|
5326
|
+
// promise or a scalar value or throw a ValidationError.
|
|
5327
|
+
return new Promise((resolve, reject) => {
|
|
5328
|
+
const res = node._callEvent(eventName, extra);
|
|
5329
|
+
// normalize to promise, even if a scalar value was returned and await it
|
|
5330
|
+
Promise.resolve(res)
|
|
5331
|
+
.then((res) => {
|
|
5332
|
+
resolve(res);
|
|
5333
|
+
})
|
|
5334
|
+
.catch((err) => {
|
|
5335
|
+
reject(err);
|
|
5336
|
+
});
|
|
5337
|
+
})
|
|
5338
|
+
.then((res) => {
|
|
5339
|
+
if (!inputElem.checkValidity()) {
|
|
5340
|
+
// Native validation failed or handler called 'inputElem.setCustomValidity()'
|
|
5341
|
+
node.logWarn("inputElem.checkValidity() failed: throwing....");
|
|
5342
|
+
throw new ValidationError(inputElem.validationMessage);
|
|
5343
|
+
}
|
|
5344
|
+
return res;
|
|
5345
|
+
})
|
|
5234
5346
|
.catch((err) => {
|
|
5235
|
-
|
|
5236
|
-
|
|
5347
|
+
if (err instanceof ValidationError) {
|
|
5348
|
+
node.logWarn("catched ", err);
|
|
5349
|
+
colElem.classList.add("wb-invalid");
|
|
5350
|
+
if (inputElem.setCustomValidity && !inputElem.validationMessage) {
|
|
5351
|
+
inputElem.setCustomValidity(err.message);
|
|
5352
|
+
}
|
|
5353
|
+
if (inputElem.validationMessage) {
|
|
5354
|
+
inputElem.reportValidity();
|
|
5355
|
+
}
|
|
5356
|
+
// throw err;
|
|
5357
|
+
}
|
|
5358
|
+
else {
|
|
5359
|
+
node.logError(`Error in ${eventName} event handler (throw e.util.ValidationError instead if this was intended)`, err);
|
|
5360
|
+
colElem.classList.add("wb-error");
|
|
5361
|
+
throw err;
|
|
5362
|
+
}
|
|
5237
5363
|
})
|
|
5238
5364
|
.finally(() => {
|
|
5239
5365
|
colElem.classList.remove("wb-busy");
|
|
5240
5366
|
});
|
|
5241
|
-
return res;
|
|
5242
5367
|
}
|
|
5243
5368
|
/*
|
|
5244
5369
|
* Called for when a control that is embedded in a cell fires a `change` event.
|
|
5245
5370
|
*/
|
|
5246
5371
|
_onChange(e) {
|
|
5247
|
-
// let res;
|
|
5248
5372
|
const info = Wunderbaum.getEventInfo(e);
|
|
5249
5373
|
const node = info.node;
|
|
5250
5374
|
const colElem = info.colElem;
|
|
@@ -5252,16 +5376,15 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5252
5376
|
this.tree.log("Ignored change event for removed element or node title");
|
|
5253
5377
|
return;
|
|
5254
5378
|
}
|
|
5255
|
-
|
|
5379
|
+
// See also WbChangeEventType
|
|
5380
|
+
this._applyChange("change", node, colElem, e.target, {
|
|
5256
5381
|
info: info,
|
|
5257
5382
|
event: e,
|
|
5258
5383
|
inputElem: e.target,
|
|
5259
5384
|
inputValue: Wunderbaum.util.getValueFromElem(e.target),
|
|
5385
|
+
inputValid: e.target.checkValidity(),
|
|
5260
5386
|
});
|
|
5261
5387
|
}
|
|
5262
|
-
// handleKey(e:KeyboardEvent):boolean {
|
|
5263
|
-
// if(this.tree.cellNavMode )
|
|
5264
|
-
// }
|
|
5265
5388
|
init() {
|
|
5266
5389
|
super.init();
|
|
5267
5390
|
onEvent(this.tree.element, "change", //"change input",
|
|
@@ -5308,7 +5431,6 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5308
5431
|
break;
|
|
5309
5432
|
case "F2":
|
|
5310
5433
|
if (trigger.indexOf("F2") >= 0) {
|
|
5311
|
-
// tree.setNavigationMode(NavigationMode.cellEdit);
|
|
5312
5434
|
this.startEditTitle();
|
|
5313
5435
|
return false;
|
|
5314
5436
|
}
|
|
@@ -5333,14 +5455,21 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5333
5455
|
this.tree.logDebug(`startEditTitle(node=${node})`);
|
|
5334
5456
|
let inputHtml = node._callEvent("edit.beforeEdit");
|
|
5335
5457
|
if (inputHtml === false) {
|
|
5336
|
-
node.
|
|
5458
|
+
node.logDebug("beforeEdit canceled operation.");
|
|
5337
5459
|
return;
|
|
5338
5460
|
}
|
|
5339
|
-
// `beforeEdit(e)` may return an input HTML string. Otherwise use a default
|
|
5461
|
+
// `beforeEdit(e)` may return an input HTML string. Otherwise use a default
|
|
5340
5462
|
// (we also treat a `true` return value as 'use default'):
|
|
5341
5463
|
if (inputHtml === true || !inputHtml) {
|
|
5342
5464
|
const title = escapeHtml(node.title);
|
|
5343
|
-
|
|
5465
|
+
let opt = this.getPluginOption("maxlength");
|
|
5466
|
+
const maxlength = opt ? ` maxlength="${opt}"` : "";
|
|
5467
|
+
opt = this.getPluginOption("minlength");
|
|
5468
|
+
const minlength = opt ? ` minlength="${opt}"` : "";
|
|
5469
|
+
const required = opt > 0 ? " required" : "";
|
|
5470
|
+
inputHtml =
|
|
5471
|
+
`<input type=text class="wb-input-edit" tabindex=-1 value="${title}" ` +
|
|
5472
|
+
`autocorrect="off"${required}${minlength}${maxlength} >`;
|
|
5344
5473
|
}
|
|
5345
5474
|
const titleSpan = node
|
|
5346
5475
|
.getColElem(0)
|
|
@@ -5351,7 +5480,9 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5351
5480
|
// Permanently apply input validations (CSS and tooltip)
|
|
5352
5481
|
inputElem.addEventListener("keydown", (e) => {
|
|
5353
5482
|
inputElem.setCustomValidity("");
|
|
5354
|
-
if (!inputElem.reportValidity())
|
|
5483
|
+
if (!inputElem.reportValidity()) {
|
|
5484
|
+
node.logWarn(`Invalid input: '${inputElem.value}'`);
|
|
5485
|
+
}
|
|
5355
5486
|
});
|
|
5356
5487
|
}
|
|
5357
5488
|
inputElem.focus();
|
|
@@ -5398,12 +5529,12 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5398
5529
|
throw new Error(`Input validation failed for "${newValue}": ${errMsg}.`);
|
|
5399
5530
|
}
|
|
5400
5531
|
const colElem = node.getColElem(0);
|
|
5401
|
-
this._applyChange("edit.apply", node, colElem, {
|
|
5532
|
+
this._applyChange("edit.apply", node, colElem, focusElem, {
|
|
5402
5533
|
oldValue: node.title,
|
|
5403
5534
|
newValue: newValue,
|
|
5404
5535
|
inputElem: focusElem,
|
|
5405
|
-
|
|
5406
|
-
|
|
5536
|
+
inputValid: focusElem.checkValidity(),
|
|
5537
|
+
}).then((value) => {
|
|
5407
5538
|
const errMsg = focusElem.validationMessage;
|
|
5408
5539
|
if (validity && errMsg && value !== false) {
|
|
5409
5540
|
// Handler called 'inputElem.setCustomValidity()' to signal error
|
|
@@ -5422,10 +5553,10 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5422
5553
|
this.curEditNode = null;
|
|
5423
5554
|
this.relatedNode = null;
|
|
5424
5555
|
this.tree.setFocus(); // restore focus that was in the input element
|
|
5425
|
-
})
|
|
5426
|
-
.catch((err) => {
|
|
5427
|
-
node.logError(err);
|
|
5428
5556
|
});
|
|
5557
|
+
// .catch((err) => {
|
|
5558
|
+
// node.logError(err);
|
|
5559
|
+
// });
|
|
5429
5560
|
// Trigger 'change' event for embedded `<input>`
|
|
5430
5561
|
// focusElem.blur();
|
|
5431
5562
|
}
|
|
@@ -5486,8 +5617,8 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5486
5617
|
* https://github.com/mar10/wunderbaum
|
|
5487
5618
|
*
|
|
5488
5619
|
* Released under the MIT license.
|
|
5489
|
-
* @version v0.
|
|
5490
|
-
* @date
|
|
5620
|
+
* @version v0.8.0
|
|
5621
|
+
* @date Thu, 11 Jan 2024 19:37:23 GMT
|
|
5491
5622
|
*/
|
|
5492
5623
|
// import "./wunderbaum.scss";
|
|
5493
5624
|
class WbSystemRoot extends WunderbaumNode {
|
|
@@ -5504,7 +5635,7 @@ class WbSystemRoot extends WunderbaumNode {
|
|
|
5504
5635
|
/**
|
|
5505
5636
|
* A persistent plain object or array.
|
|
5506
5637
|
*
|
|
5507
|
-
* See also
|
|
5638
|
+
* See also {@link WunderbaumOptions}.
|
|
5508
5639
|
*/
|
|
5509
5640
|
class Wunderbaum {
|
|
5510
5641
|
constructor(options) {
|
|
@@ -5537,7 +5668,7 @@ class Wunderbaum {
|
|
|
5537
5668
|
// --- FILTER ---
|
|
5538
5669
|
this.filterMode = null;
|
|
5539
5670
|
// --- KEYNAV ---
|
|
5540
|
-
/** @internal Use `setColumn()`/`getActiveColElem()
|
|
5671
|
+
/** @internal Use `setColumn()`/`getActiveColElem()` to access. */
|
|
5541
5672
|
this.activeColIdx = 0;
|
|
5542
5673
|
/** @internal */
|
|
5543
5674
|
this._cellNavMode = false;
|
|
@@ -5713,6 +5844,7 @@ class Wunderbaum {
|
|
|
5713
5844
|
else {
|
|
5714
5845
|
this.setNavigationOption(opts.navigationModeOption);
|
|
5715
5846
|
}
|
|
5847
|
+
this.update(ChangeType.structure, { immediate: true });
|
|
5716
5848
|
readyDeferred.resolve();
|
|
5717
5849
|
})
|
|
5718
5850
|
.catch((error) => {
|
|
@@ -5764,7 +5896,7 @@ class Wunderbaum {
|
|
|
5764
5896
|
info.region === "title" &&
|
|
5765
5897
|
node.isActive() &&
|
|
5766
5898
|
(!slowClickDelay || Date.now() - this.lastClickTime < slowClickDelay)) {
|
|
5767
|
-
|
|
5899
|
+
node.startEditTitle();
|
|
5768
5900
|
}
|
|
5769
5901
|
if (info.colIdx >= 0) {
|
|
5770
5902
|
node.setActive(true, { colIdx: info.colIdx, event: e });
|
|
@@ -5811,7 +5943,7 @@ class Wunderbaum {
|
|
|
5811
5943
|
const flag = e.type === "focusin";
|
|
5812
5944
|
const targetNode = Wunderbaum.getNode(e);
|
|
5813
5945
|
this._callEvent("focus", { flag: flag, event: e });
|
|
5814
|
-
if (flag && this.isRowNav() && !this.
|
|
5946
|
+
if (flag && this.isRowNav() && !this.isEditingTitle()) {
|
|
5815
5947
|
if (opts.navigationModeOption === NavModeEnum.row) {
|
|
5816
5948
|
targetNode === null || targetNode === void 0 ? void 0 : targetNode.setActive();
|
|
5817
5949
|
}
|
|
@@ -5835,7 +5967,7 @@ class Wunderbaum {
|
|
|
5835
5967
|
* getTree(1); // Get second Wunderbaum instance on page
|
|
5836
5968
|
* getTree(event); // Get tree for this mouse- or keyboard event
|
|
5837
5969
|
* getTree("foo"); // Get tree for this `tree.options.id`
|
|
5838
|
-
* getTree("#tree"); // Get tree for
|
|
5970
|
+
* getTree("#tree"); // Get tree for first matching element selector
|
|
5839
5971
|
* ```
|
|
5840
5972
|
*/
|
|
5841
5973
|
static getTree(el) {
|
|
@@ -5942,31 +6074,33 @@ class Wunderbaum {
|
|
|
5942
6074
|
assert(key != null && !this.keyMap.has(key), `Missing or duplicate key: '${key}'.`);
|
|
5943
6075
|
this.keyMap.set(key, node);
|
|
5944
6076
|
const rk = node.refKey;
|
|
5945
|
-
if (rk) {
|
|
6077
|
+
if (rk != null) {
|
|
5946
6078
|
const rks = this.refKeyMap.get(rk); // Set of nodes with this refKey
|
|
5947
6079
|
if (rks) {
|
|
5948
6080
|
rks.add(node);
|
|
5949
6081
|
}
|
|
5950
6082
|
else {
|
|
5951
|
-
this.refKeyMap.set(rk, new Set());
|
|
6083
|
+
this.refKeyMap.set(rk, new Set([node]));
|
|
5952
6084
|
}
|
|
5953
6085
|
}
|
|
5954
6086
|
}
|
|
5955
6087
|
/** Remove node from tree's bookkeeping data structures. */
|
|
5956
6088
|
_unregisterNode(node) {
|
|
6089
|
+
// Remove refKey reference from map (if any)
|
|
5957
6090
|
const rk = node.refKey;
|
|
5958
|
-
if (rk) {
|
|
6091
|
+
if (rk != null) {
|
|
5959
6092
|
const rks = this.refKeyMap.get(rk);
|
|
5960
6093
|
if (rks && rks.delete(node) && !rks.size) {
|
|
5961
6094
|
// We just removed the last element
|
|
5962
6095
|
this.refKeyMap.delete(rk);
|
|
5963
6096
|
}
|
|
5964
6097
|
}
|
|
5965
|
-
//
|
|
6098
|
+
// Remove key reference from map
|
|
6099
|
+
this.keyMap.delete(node.key);
|
|
6100
|
+
// Mark as disposed
|
|
5966
6101
|
node.tree = null;
|
|
5967
6102
|
node.parent = null;
|
|
5968
|
-
//
|
|
5969
|
-
// this.viewNodes.delete(node);
|
|
6103
|
+
// Remove HTML markup
|
|
5970
6104
|
node.removeMarkup();
|
|
5971
6105
|
}
|
|
5972
6106
|
/** Call all hook methods of all registered extensions.*/
|
|
@@ -6170,7 +6304,7 @@ class Wunderbaum {
|
|
|
6170
6304
|
this._callMethod("edit.createNode", "after");
|
|
6171
6305
|
break;
|
|
6172
6306
|
case "rename":
|
|
6173
|
-
|
|
6307
|
+
node.startEditTitle();
|
|
6174
6308
|
break;
|
|
6175
6309
|
// Simple clipboard simulation:
|
|
6176
6310
|
// case "cut":
|
|
@@ -6217,7 +6351,6 @@ class Wunderbaum {
|
|
|
6217
6351
|
this.root.children = null;
|
|
6218
6352
|
this.keyMap.clear();
|
|
6219
6353
|
this.refKeyMap.clear();
|
|
6220
|
-
// this.viewNodes.clear();
|
|
6221
6354
|
this.treeRowCount = 0;
|
|
6222
6355
|
this.activeNode = null;
|
|
6223
6356
|
this.focusNode = null;
|
|
@@ -6410,14 +6543,31 @@ class Wunderbaum {
|
|
|
6410
6543
|
/**
|
|
6411
6544
|
* Find all nodes that match condition.
|
|
6412
6545
|
*
|
|
6546
|
+
* @param match title string to search for, or a
|
|
6547
|
+
* callback function that returns `true` if a node is matched.
|
|
6413
6548
|
* @see {@link WunderbaumNode.findAll}
|
|
6414
6549
|
*/
|
|
6415
6550
|
findAll(match) {
|
|
6416
6551
|
return this.root.findAll(match);
|
|
6417
6552
|
}
|
|
6553
|
+
/**
|
|
6554
|
+
* Find all nodes with a given _refKey_ (aka a list of clones).
|
|
6555
|
+
*
|
|
6556
|
+
* @param refKey a `node.refKey` value to search for.
|
|
6557
|
+
* @returns an array of matching nodes with at least two element or `[]`
|
|
6558
|
+
* if nothing found.
|
|
6559
|
+
*
|
|
6560
|
+
* @see {@link WunderbaumNode.getCloneList}
|
|
6561
|
+
*/
|
|
6562
|
+
findByRefKey(refKey) {
|
|
6563
|
+
const clones = this.refKeyMap.get(refKey);
|
|
6564
|
+
return clones ? Array.from(clones) : [];
|
|
6565
|
+
}
|
|
6418
6566
|
/**
|
|
6419
6567
|
* Find first node that matches condition.
|
|
6420
6568
|
*
|
|
6569
|
+
* @param match title string to search for, or a
|
|
6570
|
+
* callback function that returns `true` if a node is matched.
|
|
6421
6571
|
* @see {@link WunderbaumNode.findFirst}
|
|
6422
6572
|
*/
|
|
6423
6573
|
findFirst(match) {
|
|
@@ -6426,8 +6576,6 @@ class Wunderbaum {
|
|
|
6426
6576
|
/**
|
|
6427
6577
|
* Find first node that matches condition.
|
|
6428
6578
|
*
|
|
6429
|
-
* @param match title string to search for, or a
|
|
6430
|
-
* callback function that returns `true` if a node is matched.
|
|
6431
6579
|
* @see {@link WunderbaumNode.findFirst}
|
|
6432
6580
|
*
|
|
6433
6581
|
*/
|
|
@@ -6437,6 +6585,7 @@ class Wunderbaum {
|
|
|
6437
6585
|
/**
|
|
6438
6586
|
* Find the next visible node that starts with `match`, starting at `startNode`
|
|
6439
6587
|
* and wrap-around at the end.
|
|
6588
|
+
* Used by quicksearch and keyboard navigation.
|
|
6440
6589
|
*/
|
|
6441
6590
|
findNextNode(match, startNode) {
|
|
6442
6591
|
//, visibleOnly) {
|
|
@@ -6604,6 +6753,9 @@ class Wunderbaum {
|
|
|
6604
6753
|
}
|
|
6605
6754
|
/**
|
|
6606
6755
|
* Return the currently active node or null.
|
|
6756
|
+
* @see {@link WunderbaumNode.setActive}
|
|
6757
|
+
* @see {@link WunderbaumNode.isActive}
|
|
6758
|
+
* @see {@link WunderbaumNode.getFocusNode}
|
|
6607
6759
|
*/
|
|
6608
6760
|
getActiveNode() {
|
|
6609
6761
|
return this.activeNode;
|
|
@@ -6615,7 +6767,8 @@ class Wunderbaum {
|
|
|
6615
6767
|
return this.root.getFirstChild();
|
|
6616
6768
|
}
|
|
6617
6769
|
/**
|
|
6618
|
-
* Return the currently
|
|
6770
|
+
* Return the node that currently has keyboard focus or null.
|
|
6771
|
+
* @see {@link WunderbaumNode.getActiveNode}
|
|
6619
6772
|
*/
|
|
6620
6773
|
getFocusNode() {
|
|
6621
6774
|
return this.focusNode;
|
|
@@ -6692,8 +6845,19 @@ class Wunderbaum {
|
|
|
6692
6845
|
toString() {
|
|
6693
6846
|
return `Wunderbaum<'${this.id}'>`;
|
|
6694
6847
|
}
|
|
6695
|
-
/** Return true if any node is currently
|
|
6848
|
+
/** Return true if any node title or grid cell is currently beeing edited.
|
|
6849
|
+
*
|
|
6850
|
+
* See also {@link Wunderbaum.isEditingTitle}.
|
|
6851
|
+
*/
|
|
6696
6852
|
isEditing() {
|
|
6853
|
+
const focusElem = this.nodeListElement.querySelector("input:focus,select:focus");
|
|
6854
|
+
return !!focusElem;
|
|
6855
|
+
}
|
|
6856
|
+
/** Return true if any node is currently in edit-title mode.
|
|
6857
|
+
*
|
|
6858
|
+
* See also {@link WunderbaumNode.isEditingTitle} and {@link Wunderbaum.isEditing}.
|
|
6859
|
+
*/
|
|
6860
|
+
isEditingTitle() {
|
|
6697
6861
|
return this._callMethod("edit.isEditingTitle");
|
|
6698
6862
|
}
|
|
6699
6863
|
/**
|
|
@@ -6829,12 +6993,23 @@ class Wunderbaum {
|
|
|
6829
6993
|
/**
|
|
6830
6994
|
* Set column #colIdx to 'active'.
|
|
6831
6995
|
*
|
|
6832
|
-
* This higlights the column header and -cells by adding the `wb-active`
|
|
6996
|
+
* This higlights the column header and -cells by adding the `wb-active`
|
|
6997
|
+
* class to all grid cells of the active column. <br>
|
|
6833
6998
|
* Available in cell-nav mode only.
|
|
6999
|
+
*
|
|
7000
|
+
* If _options.edit_ is true, the embedded input element is focused, or if
|
|
7001
|
+
* colIdx is 0, the node title is put into edit mode.
|
|
6834
7002
|
*/
|
|
6835
|
-
setColumn(colIdx) {
|
|
6836
|
-
var _a;
|
|
6837
|
-
|
|
7003
|
+
setColumn(colIdx, options) {
|
|
7004
|
+
var _a, _b, _c;
|
|
7005
|
+
const edit = options === null || options === void 0 ? void 0 : options.edit;
|
|
7006
|
+
const scroll = (options === null || options === void 0 ? void 0 : options.scrollIntoView) !== false;
|
|
7007
|
+
assert(this.isCellNav(), "Expected cellNav mode");
|
|
7008
|
+
if (typeof colIdx === "string") {
|
|
7009
|
+
const cid = colIdx;
|
|
7010
|
+
colIdx = this.columns.findIndex((c) => c.id === colIdx);
|
|
7011
|
+
assert(colIdx >= 0, `Invalid colId: ${cid}`);
|
|
7012
|
+
}
|
|
6838
7013
|
assert(0 <= colIdx && colIdx < this.columns.length, `Invalid colIdx: ${colIdx}`);
|
|
6839
7014
|
this.activeColIdx = colIdx;
|
|
6840
7015
|
// Update `wb-active` class for all headers
|
|
@@ -6854,17 +7029,26 @@ class Wunderbaum {
|
|
|
6854
7029
|
colDiv.classList.toggle("wb-active", i++ === colIdx);
|
|
6855
7030
|
}
|
|
6856
7031
|
}
|
|
6857
|
-
//
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
7032
|
+
// Horizontically scroll into view
|
|
7033
|
+
if (scroll || edit) {
|
|
7034
|
+
this.scrollToHorz();
|
|
7035
|
+
}
|
|
7036
|
+
if (edit && this.activeNode) {
|
|
7037
|
+
// this.activeNode.setFocus(); // Blur prev. input if any
|
|
7038
|
+
if (colIdx === 0) {
|
|
7039
|
+
this.activeNode.startEditTitle();
|
|
7040
|
+
}
|
|
7041
|
+
else {
|
|
7042
|
+
(_c = (_b = this.getActiveColElem()) === null || _b === void 0 ? void 0 : _b.querySelector("input,select")) === null || _c === void 0 ? void 0 : _c.focus();
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
6861
7045
|
}
|
|
6862
|
-
/** Set or remove
|
|
7046
|
+
/** Set or remove keyboard focus to the tree container. */
|
|
6863
7047
|
setActiveNode(key, flag = true, options) {
|
|
6864
7048
|
var _a;
|
|
6865
7049
|
(_a = this.findKey(key)) === null || _a === void 0 ? void 0 : _a.setActive(flag, options);
|
|
6866
7050
|
}
|
|
6867
|
-
/** Set or remove
|
|
7051
|
+
/** Set or remove keyboard focus to the tree container. */
|
|
6868
7052
|
setFocus(flag = true) {
|
|
6869
7053
|
if (flag) {
|
|
6870
7054
|
this.element.focus();
|
|
@@ -6874,6 +7058,14 @@ class Wunderbaum {
|
|
|
6874
7058
|
}
|
|
6875
7059
|
}
|
|
6876
7060
|
update(change, node, options) {
|
|
7061
|
+
// this.log(`update(${change}) node=${node}`);
|
|
7062
|
+
if (!(node instanceof WunderbaumNode)) {
|
|
7063
|
+
options = node;
|
|
7064
|
+
node = undefined;
|
|
7065
|
+
}
|
|
7066
|
+
const immediate = !!getOption(options, "immediate");
|
|
7067
|
+
const RF = RenderFlag;
|
|
7068
|
+
const pending = this.pendingChangeTypes;
|
|
6877
7069
|
if (this._disableUpdateCount) {
|
|
6878
7070
|
// Assuming that we redraw all when enableUpdate() is re-enabled.
|
|
6879
7071
|
// this.log(
|
|
@@ -6882,14 +7074,6 @@ class Wunderbaum {
|
|
|
6882
7074
|
this._disableUpdateIgnoreCount++;
|
|
6883
7075
|
return;
|
|
6884
7076
|
}
|
|
6885
|
-
// this.log(`update(${change}) node=${node}`);
|
|
6886
|
-
if (!(node instanceof WunderbaumNode)) {
|
|
6887
|
-
options = node;
|
|
6888
|
-
node = null;
|
|
6889
|
-
}
|
|
6890
|
-
const immediate = !!getOption(options, "immediate");
|
|
6891
|
-
const RF = RenderFlag;
|
|
6892
|
-
const pending = this.pendingChangeTypes;
|
|
6893
7077
|
switch (change) {
|
|
6894
7078
|
case ChangeType.any:
|
|
6895
7079
|
case ChangeType.colStructure:
|
|
@@ -7217,10 +7401,14 @@ class Wunderbaum {
|
|
|
7217
7401
|
_updateViewportImmediately() {
|
|
7218
7402
|
var _a;
|
|
7219
7403
|
if (this._disableUpdateCount) {
|
|
7220
|
-
this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount})
|
|
7404
|
+
this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount}).`);
|
|
7221
7405
|
this._disableUpdateIgnoreCount++;
|
|
7222
7406
|
return;
|
|
7223
7407
|
}
|
|
7408
|
+
if (this._updateViewportThrottled.pending()) {
|
|
7409
|
+
// this.logWarn(`_updateViewportImmediately() cancel pending timer.`);
|
|
7410
|
+
this._updateViewportThrottled.cancel();
|
|
7411
|
+
}
|
|
7224
7412
|
// Shorten container height to avoid v-scrollbar
|
|
7225
7413
|
const FIX_ADJUST_HEIGHT = 1;
|
|
7226
7414
|
const RF = RenderFlag;
|
|
@@ -7324,9 +7512,6 @@ class Wunderbaum {
|
|
|
7324
7512
|
}
|
|
7325
7513
|
let endIdx = Math.max(0, (ofs + vp_height) / row_height + prefetch);
|
|
7326
7514
|
endIdx = Math.ceil(endIdx);
|
|
7327
|
-
// const obsoleteViewNodes = this.viewNodes;
|
|
7328
|
-
// this.viewNodes = new Set();
|
|
7329
|
-
// const viewNodes = this.viewNodes;
|
|
7330
7515
|
// this.debug("render", opts);
|
|
7331
7516
|
const obsoleteNodes = new Set();
|
|
7332
7517
|
this.nodeListElement.childNodes.forEach((elem) => {
|
|
@@ -7582,37 +7767,31 @@ class Wunderbaum {
|
|
|
7582
7767
|
* FILTER
|
|
7583
7768
|
* -------------------------------------------------------------------------*/
|
|
7584
7769
|
/**
|
|
7585
|
-
*
|
|
7770
|
+
* Dim or hide nodes.
|
|
7586
7771
|
*/
|
|
7587
7772
|
filterNodes(filter, options) {
|
|
7588
7773
|
return this.extensions.filter.filterNodes(filter, options);
|
|
7589
7774
|
}
|
|
7590
7775
|
/**
|
|
7591
|
-
*
|
|
7776
|
+
* Dim or hide whole branches.
|
|
7592
7777
|
*/
|
|
7593
7778
|
filterBranches(filter, options) {
|
|
7594
7779
|
return this.extensions.filter.filterBranches(filter, options);
|
|
7595
7780
|
}
|
|
7596
7781
|
/**
|
|
7597
|
-
*
|
|
7598
|
-
*
|
|
7599
|
-
* @requires [[FilterExtension]]
|
|
7782
|
+
* Reset the filter.
|
|
7600
7783
|
*/
|
|
7601
7784
|
clearFilter() {
|
|
7602
7785
|
return this.extensions.filter.clearFilter();
|
|
7603
7786
|
}
|
|
7604
7787
|
/**
|
|
7605
|
-
*
|
|
7606
|
-
*
|
|
7607
|
-
* @requires [[FilterExtension]]
|
|
7788
|
+
* Return true if a filter is currently applied.
|
|
7608
7789
|
*/
|
|
7609
7790
|
isFilterActive() {
|
|
7610
7791
|
return !!this.filterMode;
|
|
7611
7792
|
}
|
|
7612
7793
|
/**
|
|
7613
|
-
*
|
|
7614
|
-
*
|
|
7615
|
-
* @requires [[FilterExtension]]
|
|
7794
|
+
* Re-apply current filter.
|
|
7616
7795
|
*/
|
|
7617
7796
|
updateFilter() {
|
|
7618
7797
|
return this.extensions.filter.updateFilter();
|
|
@@ -7620,7 +7799,7 @@ class Wunderbaum {
|
|
|
7620
7799
|
}
|
|
7621
7800
|
Wunderbaum.sequence = 0;
|
|
7622
7801
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
7623
|
-
Wunderbaum.version = "v0.
|
|
7802
|
+
Wunderbaum.version = "v0.8.0"; // Set to semver by 'grunt release'
|
|
7624
7803
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
7625
7804
|
Wunderbaum.util = util;
|
|
7626
7805
|
|