wunderbaum 0.7.0 → 0.8.1
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 +492 -277
- package/dist/wunderbaum.esm.js +915 -668
- package/dist/wunderbaum.esm.min.js +32 -32
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +7853 -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 +186 -45
- package/src/util.ts +73 -33
- package/src/wb_ext_dnd.ts +37 -13
- package/src/wb_ext_edit.ts +90 -58
- package/src/wb_ext_filter.ts +5 -1
- package/src/wb_ext_keynav.ts +22 -11
- package/src/wb_ext_logger.ts +2 -1
- package/src/wb_node.ts +114 -50
- package/src/wb_options.ts +55 -29
- package/src/wunderbaum.scss +7 -1
- package/src/wunderbaum.ts +168 -74
package/dist/wunderbaum.esm.js
CHANGED
|
@@ -1,108 +1,418 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
5
|
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const REX_TOOLTIP = /[<>"'/]/g; // Don't escape `&` in tooltips
|
|
22
|
-
const ENTITY_MAP = {
|
|
23
|
-
"&": "&",
|
|
24
|
-
"<": "<",
|
|
25
|
-
">": ">",
|
|
26
|
-
'"': """,
|
|
27
|
-
"'": "'",
|
|
28
|
-
"/": "/",
|
|
29
|
-
};
|
|
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")();
|
|
30
21
|
/**
|
|
31
|
-
*
|
|
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
|
|
32
43
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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");
|
|
38
119
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.thens.forEach((t) => t(value));
|
|
46
|
-
this.thens = []; // Avoid memleaks.
|
|
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;
|
|
47
126
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.catches = []; // Avoid memleaks.
|
|
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;
|
|
56
134
|
}
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
else {
|
|
62
|
-
this.thens.unshift(cb);
|
|
135
|
+
function startTimer(pendingFunc, wait) {
|
|
136
|
+
if (useRAF) {
|
|
137
|
+
root.cancelAnimationFrame(timerId);
|
|
138
|
+
return root.requestAnimationFrame(pendingFunc);
|
|
63
139
|
}
|
|
140
|
+
return setTimeout(pendingFunc, wait);
|
|
64
141
|
}
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
this.catches.unshift(cb);
|
|
142
|
+
function cancelTimer(id) {
|
|
143
|
+
if (useRAF) {
|
|
144
|
+
return root.cancelAnimationFrame(id);
|
|
71
145
|
}
|
|
146
|
+
clearTimeout(id);
|
|
72
147
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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;
|
|
78
155
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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;
|
|
85
163
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
function documentReady(callback) {
|
|
97
|
-
if (document.readyState === "loading") {
|
|
98
|
-
document.addEventListener("DOMContentLoaded", callback);
|
|
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));
|
|
99
174
|
}
|
|
100
|
-
|
|
101
|
-
|
|
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));
|
|
102
182
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
+
|
|
298
|
+
/*!
|
|
299
|
+
* Wunderbaum - util
|
|
300
|
+
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
301
|
+
* v0.8.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
302
|
+
*/
|
|
303
|
+
/** @module util */
|
|
304
|
+
/** Readable names for `MouseEvent.button` */
|
|
305
|
+
const MOUSE_BUTTONS = {
|
|
306
|
+
0: "",
|
|
307
|
+
1: "left",
|
|
308
|
+
2: "middle",
|
|
309
|
+
3: "right",
|
|
310
|
+
4: "back",
|
|
311
|
+
5: "forward",
|
|
312
|
+
};
|
|
313
|
+
const MAX_INT = 9007199254740991;
|
|
314
|
+
const userInfo = _getUserInfo();
|
|
315
|
+
/**True if the client is using a macOS platform. */
|
|
316
|
+
const isMac = userInfo.isMac;
|
|
317
|
+
const REX_HTML = /[&<>"'/]/g; // Escape those characters
|
|
318
|
+
const REX_TOOLTIP = /[<>"'/]/g; // Don't escape `&` in tooltips
|
|
319
|
+
const ENTITY_MAP = {
|
|
320
|
+
"&": "&",
|
|
321
|
+
"<": "<",
|
|
322
|
+
">": ">",
|
|
323
|
+
'"': """,
|
|
324
|
+
"'": "'",
|
|
325
|
+
"/": "/",
|
|
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
|
+
}
|
|
337
|
+
/**
|
|
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.
|
|
342
|
+
*/
|
|
343
|
+
let Deferred$1 = class Deferred {
|
|
344
|
+
constructor() {
|
|
345
|
+
this.thens = [];
|
|
346
|
+
this.catches = [];
|
|
347
|
+
this.status = "";
|
|
348
|
+
}
|
|
349
|
+
resolve(value) {
|
|
350
|
+
if (this.status) {
|
|
351
|
+
throw new Error("already settled");
|
|
352
|
+
}
|
|
353
|
+
this.status = "resolved";
|
|
354
|
+
this.resolvedValue = value;
|
|
355
|
+
this.thens.forEach((t) => t(value));
|
|
356
|
+
this.thens = []; // Avoid memleaks.
|
|
357
|
+
}
|
|
358
|
+
reject(error) {
|
|
359
|
+
if (this.status) {
|
|
360
|
+
throw new Error("already settled");
|
|
361
|
+
}
|
|
362
|
+
this.status = "rejected";
|
|
363
|
+
this.rejectedError = error;
|
|
364
|
+
this.catches.forEach((c) => c(error));
|
|
365
|
+
this.catches = []; // Avoid memleaks.
|
|
366
|
+
}
|
|
367
|
+
then(cb) {
|
|
368
|
+
if (status === "resolved") {
|
|
369
|
+
cb(this.resolvedValue);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
this.thens.unshift(cb);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch(cb) {
|
|
376
|
+
if (this.status === "rejected") {
|
|
377
|
+
cb(this.rejectedError);
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.catches.unshift(cb);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
promise() {
|
|
384
|
+
return {
|
|
385
|
+
then: this.then,
|
|
386
|
+
catch: this.catch,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
/**Throw an `Error` if `cond` is falsey. */
|
|
391
|
+
function assert(cond, msg) {
|
|
392
|
+
if (!cond) {
|
|
393
|
+
msg = msg || "Assertion failed.";
|
|
394
|
+
throw new Error(msg);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function _getUserInfo() {
|
|
398
|
+
const nav = navigator;
|
|
399
|
+
// const ua = nav.userAgentData;
|
|
400
|
+
const res = {
|
|
401
|
+
isMac: /Mac/.test(nav.platform),
|
|
402
|
+
};
|
|
403
|
+
return res;
|
|
404
|
+
}
|
|
405
|
+
/** Run `callback` when document was loaded. */
|
|
406
|
+
function documentReady(callback) {
|
|
407
|
+
if (document.readyState === "loading") {
|
|
408
|
+
document.addEventListener("DOMContentLoaded", callback);
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
callback();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/** Resolve when document was loaded. */
|
|
415
|
+
function documentReadyPromise() {
|
|
106
416
|
return new Promise((resolve) => {
|
|
107
417
|
documentReady(resolve);
|
|
108
418
|
});
|
|
@@ -371,16 +681,18 @@ function elemFromSelector(obj) {
|
|
|
371
681
|
}
|
|
372
682
|
return obj;
|
|
373
683
|
}
|
|
374
|
-
/** Return a EventTarget from selector or cast an existing element. */
|
|
375
|
-
function eventTargetFromSelector(
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
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.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
769
1100
|
*/
|
|
770
1101
|
/**
|
|
771
1102
|
* Possible values for {@link WunderbaumNode.update()} and {@link Wunderbaum.update()}.
|
|
@@ -829,7 +1160,7 @@ 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.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
833
1164
|
*/
|
|
834
1165
|
class WunderbaumExtension {
|
|
835
1166
|
constructor(tree, id, defaults) {
|
|
@@ -839,353 +1170,56 @@ class WunderbaumExtension {
|
|
|
839
1170
|
this.treeOpts = tree.options;
|
|
840
1171
|
const opts = tree.options;
|
|
841
1172
|
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);
|
|
1076
|
-
}
|
|
1077
|
-
lastArgs = lastThis = undefined;
|
|
1078
|
-
return result;
|
|
1079
|
-
}
|
|
1080
|
-
function cancel() {
|
|
1081
|
-
if (timerId !== undefined) {
|
|
1082
|
-
cancelTimer(timerId);
|
|
1083
|
-
}
|
|
1084
|
-
lastInvokeTime = 0;
|
|
1085
|
-
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
|
1086
|
-
}
|
|
1087
|
-
function flush() {
|
|
1088
|
-
return timerId === undefined ? result : trailingEdge(Date.now());
|
|
1089
|
-
}
|
|
1090
|
-
function pending() {
|
|
1091
|
-
return timerId !== undefined;
|
|
1092
|
-
}
|
|
1093
|
-
function debounced(...args) {
|
|
1094
|
-
const time = Date.now();
|
|
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
|
-
}
|
|
1173
|
+
opts[id] = this.extensionOpts = extend({}, defaults);
|
|
1109
1174
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1175
|
+
else {
|
|
1176
|
+
// TODO: do we break existing object instance references here?
|
|
1177
|
+
this.extensionOpts = extend({}, defaults, opts[id]);
|
|
1178
|
+
opts[id] = this.extensionOpts;
|
|
1112
1179
|
}
|
|
1113
|
-
|
|
1180
|
+
this.enabled = this.getPluginOption("enabled", true);
|
|
1114
1181
|
}
|
|
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");
|
|
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);
|
|
1173
1185
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
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;
|
|
1203
|
+
}
|
|
1204
|
+
setPluginOption(name, value) {
|
|
1205
|
+
this.extensionOpts[name] = value;
|
|
1206
|
+
}
|
|
1207
|
+
setEnabled(flag = true) {
|
|
1208
|
+
return this.setPluginOption("enabled", !!flag);
|
|
1209
|
+
// this.enabled = !!flag;
|
|
1210
|
+
}
|
|
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.1, Sat, 20 Jan 2024 15:57:59 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.1, Sat, 20 Jan 2024 15:57:59 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.1, Sat, 20 Jan 2024 15:57:59 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.1, Sat, 20 Jan 2024 15:57:59 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.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
2200
2257
|
*/
|
|
2201
2258
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
2202
2259
|
class DndExtension extends WunderbaumExtension {
|
|
@@ -2435,7 +2492,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2435
2492
|
const dndOpts = this.treeOpts.dnd;
|
|
2436
2493
|
const srcNode = Wunderbaum.getNode(e);
|
|
2437
2494
|
if (!srcNode) {
|
|
2438
|
-
this.tree.logWarn(`onDragEvent.${e.type} no node`);
|
|
2495
|
+
this.tree.logWarn(`onDragEvent.${e.type}: no node`);
|
|
2439
2496
|
return;
|
|
2440
2497
|
}
|
|
2441
2498
|
if (["dragstart", "dragend"].includes(e.type)) {
|
|
@@ -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;
|
|
@@ -2510,6 +2567,13 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2510
2567
|
const dndOpts = this.treeOpts.dnd;
|
|
2511
2568
|
const dt = e.dataTransfer;
|
|
2512
2569
|
const dropRegion = this._calcDropRegion(e, this.lastAllowedDropRegions);
|
|
2570
|
+
/** Helper to log a message if predicate is false. */
|
|
2571
|
+
const _t = (pred, msg) => {
|
|
2572
|
+
if (pred) {
|
|
2573
|
+
this.tree.log(`Prevented drop operation (${msg}).`);
|
|
2574
|
+
}
|
|
2575
|
+
return pred;
|
|
2576
|
+
};
|
|
2513
2577
|
if (!targetNode) {
|
|
2514
2578
|
this._leaveNode();
|
|
2515
2579
|
return;
|
|
@@ -2520,6 +2584,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2520
2584
|
}
|
|
2521
2585
|
// --- dragenter ---
|
|
2522
2586
|
if (e.type === "dragenter") {
|
|
2587
|
+
// this.tree.logWarn(` onDropEvent.${e.type} targetNode: ${targetNode}`, e);
|
|
2523
2588
|
this.lastAllowedDropRegions = null;
|
|
2524
2589
|
// `dragleave` is not reliable with event delegation, so we generate it
|
|
2525
2590
|
// from dragenter:
|
|
@@ -2530,29 +2595,33 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2530
2595
|
this.lastEnterStamp = Date.now();
|
|
2531
2596
|
if (
|
|
2532
2597
|
// Don't drop on status node:
|
|
2533
|
-
targetNode.isStatusNode() ||
|
|
2598
|
+
_t(targetNode.isStatusNode(), "is status node") ||
|
|
2534
2599
|
// Prevent dropping nodes from different Wunderbaum trees:
|
|
2535
|
-
(dndOpts.preventForeignNodes && targetNode.tree !== srcTree) ||
|
|
2600
|
+
_t(dndOpts.preventForeignNodes && targetNode.tree !== srcTree, "preventForeignNodes") ||
|
|
2536
2601
|
// Prevent dropping items on unloaded lazy Wunderbaum tree nodes:
|
|
2537
|
-
(dndOpts.preventLazyParents && !targetNode.isLoaded()) ||
|
|
2602
|
+
_t(dndOpts.preventLazyParents && !targetNode.isLoaded(), "preventLazyParents") ||
|
|
2538
2603
|
// Prevent dropping items other than Wunderbaum tree nodes:
|
|
2539
|
-
(dndOpts.preventNonNodes && !srcNode) ||
|
|
2604
|
+
_t(dndOpts.preventNonNodes && !srcNode, "preventNonNodes") ||
|
|
2540
2605
|
// Prevent dropping nodes on own descendants:
|
|
2541
|
-
(dndOpts.preventRecursion && (srcNode === null || srcNode === void 0 ? void 0 : srcNode.isAncestorOf(targetNode))) ||
|
|
2606
|
+
_t(dndOpts.preventRecursion && (srcNode === null || srcNode === void 0 ? void 0 : srcNode.isAncestorOf(targetNode)), "preventRecursion") ||
|
|
2542
2607
|
// Prevent dropping nodes under same direct parent:
|
|
2543
2608
|
(dndOpts.preventSameParent &&
|
|
2544
2609
|
srcNode &&
|
|
2545
|
-
targetNode.parent === srcNode.parent
|
|
2610
|
+
targetNode.parent === srcNode.parent,
|
|
2611
|
+
"preventSameParent") ||
|
|
2546
2612
|
// Don't allow void operation ('drop on self'): TODO: should be checked on move only
|
|
2547
2613
|
(dndOpts.preventVoidMoves && targetNode === srcNode)) {
|
|
2548
2614
|
dt.dropEffect = "none";
|
|
2549
|
-
this.tree.log("Prevented drop operation");
|
|
2615
|
+
// this.tree.log("Prevented drop operation");
|
|
2550
2616
|
return true; // Prevent drop operation
|
|
2551
2617
|
}
|
|
2552
2618
|
// User may return a set of regions (or `false` to prevent drop)
|
|
2553
2619
|
// Figure out a drop effect (copy/link/move) using opinated conventions.
|
|
2554
2620
|
dt.dropEffect = this._guessDropEffect(e) || "none";
|
|
2555
|
-
let regionSet = targetNode._callEvent("dnd.dragEnter", {
|
|
2621
|
+
let regionSet = targetNode._callEvent("dnd.dragEnter", {
|
|
2622
|
+
event: e,
|
|
2623
|
+
sourceNode: srcNode,
|
|
2624
|
+
});
|
|
2556
2625
|
//
|
|
2557
2626
|
regionSet = this.unifyDragover(regionSet);
|
|
2558
2627
|
if (!regionSet) {
|
|
@@ -2570,7 +2639,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2570
2639
|
const viewportY = e.clientY - this.tree.element.offsetTop;
|
|
2571
2640
|
this._autoScroll(viewportY);
|
|
2572
2641
|
dt.dropEffect = this._guessDropEffect(e) || "none";
|
|
2573
|
-
targetNode._callEvent("dnd.dragOver", { event: e });
|
|
2642
|
+
targetNode._callEvent("dnd.dragOver", { event: e, sourceNode: srcNode });
|
|
2574
2643
|
const region = this._calcDropRegion(e, this.lastAllowedDropRegions);
|
|
2575
2644
|
this.lastDropRegion = region;
|
|
2576
2645
|
this.lastDropEffect = dt.dropEffect;
|
|
@@ -2578,7 +2647,10 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2578
2647
|
targetNode.isExpandable(true) &&
|
|
2579
2648
|
!targetNode._isLoading &&
|
|
2580
2649
|
Date.now() - this.lastEnterStamp > dndOpts.autoExpandMS &&
|
|
2581
|
-
targetNode._callEvent("dnd.dragExpand", {
|
|
2650
|
+
targetNode._callEvent("dnd.dragExpand", {
|
|
2651
|
+
event: e,
|
|
2652
|
+
sourceNode: srcNode,
|
|
2653
|
+
}) !== false) {
|
|
2582
2654
|
targetNode.setExpanded();
|
|
2583
2655
|
}
|
|
2584
2656
|
if (!region || this._isVoidDrop(targetNode, srcNode, region)) {
|
|
@@ -2594,7 +2666,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2594
2666
|
else if (e.type === "dragleave") {
|
|
2595
2667
|
// NOTE: we cannot trust this event, since it is always fired,
|
|
2596
2668
|
// Instead we remove the marker on dragenter
|
|
2597
|
-
targetNode._callEvent("dnd.dragLeave", { event: e });
|
|
2669
|
+
targetNode._callEvent("dnd.dragLeave", { event: e, sourceNode: srcNode });
|
|
2598
2670
|
// --- drop ---
|
|
2599
2671
|
}
|
|
2600
2672
|
else if (e.type === "drop") {
|
|
@@ -2627,7 +2699,7 @@ class DndExtension extends WunderbaumExtension {
|
|
|
2627
2699
|
/*!
|
|
2628
2700
|
* Wunderbaum - drag_observer
|
|
2629
2701
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2630
|
-
* v0.
|
|
2702
|
+
* v0.8.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
2631
2703
|
*/
|
|
2632
2704
|
/**
|
|
2633
2705
|
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
@@ -2763,7 +2835,7 @@ class DragObserver {
|
|
|
2763
2835
|
/*!
|
|
2764
2836
|
* Wunderbaum - ext-grid
|
|
2765
2837
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2766
|
-
* v0.
|
|
2838
|
+
* v0.8.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
2767
2839
|
*/
|
|
2768
2840
|
class GridExtension extends WunderbaumExtension {
|
|
2769
2841
|
constructor(tree) {
|
|
@@ -2800,7 +2872,7 @@ class GridExtension extends WunderbaumExtension {
|
|
|
2800
2872
|
/*!
|
|
2801
2873
|
* Wunderbaum - deferred
|
|
2802
2874
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2803
|
-
* v0.
|
|
2875
|
+
* v0.8.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
2804
2876
|
*/
|
|
2805
2877
|
/**
|
|
2806
2878
|
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
|
|
@@ -2824,27 +2896,27 @@ class Deferred {
|
|
|
2824
2896
|
this._reject = reject;
|
|
2825
2897
|
});
|
|
2826
2898
|
}
|
|
2827
|
-
/** Resolve the
|
|
2899
|
+
/** Resolve the Promise. */
|
|
2828
2900
|
resolve(value) {
|
|
2829
2901
|
this._resolve(value);
|
|
2830
2902
|
}
|
|
2831
|
-
/** Reject the
|
|
2903
|
+
/** Reject the Promise. */
|
|
2832
2904
|
reject(reason) {
|
|
2833
2905
|
this._reject(reason);
|
|
2834
2906
|
}
|
|
2835
|
-
/** Return the native
|
|
2907
|
+
/** Return the native Promise instance.*/
|
|
2836
2908
|
promise() {
|
|
2837
2909
|
return this._promise;
|
|
2838
2910
|
}
|
|
2839
|
-
/** Call
|
|
2911
|
+
/** Call Promise.then on the embedded promise instance.*/
|
|
2840
2912
|
then(cb) {
|
|
2841
2913
|
return this._promise.then(cb);
|
|
2842
2914
|
}
|
|
2843
|
-
/** Call
|
|
2915
|
+
/** Call Promise.catch on the embedded promise instance.*/
|
|
2844
2916
|
catch(cb) {
|
|
2845
2917
|
return this._promise.catch(cb);
|
|
2846
2918
|
}
|
|
2847
|
-
/** Call
|
|
2919
|
+
/** Call Promise.finally on the embedded promise instance.*/
|
|
2848
2920
|
finally(cb) {
|
|
2849
2921
|
return this._promise.finally(cb);
|
|
2850
2922
|
}
|
|
@@ -2853,7 +2925,7 @@ class Deferred {
|
|
|
2853
2925
|
/*!
|
|
2854
2926
|
* Wunderbaum - wunderbaum_node
|
|
2855
2927
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
2856
|
-
* v0.
|
|
2928
|
+
* v0.8.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
2857
2929
|
*/
|
|
2858
2930
|
/** WunderbaumNode properties that can be passed with source data.
|
|
2859
2931
|
* (Any other source properties will be stored as `node.data.PROP`.)
|
|
@@ -3154,6 +3226,10 @@ class WunderbaumNode {
|
|
|
3154
3226
|
}
|
|
3155
3227
|
}
|
|
3156
3228
|
}
|
|
3229
|
+
/** Start editing this node's title. */
|
|
3230
|
+
startEditTitle() {
|
|
3231
|
+
this.tree._callMethod("edit.startEditTitle", this);
|
|
3232
|
+
}
|
|
3157
3233
|
/** Call `setExpanded()` on all descendant nodes. */
|
|
3158
3234
|
async expandAll(flag = true, options) {
|
|
3159
3235
|
const tree = this.tree;
|
|
@@ -3363,6 +3439,22 @@ class WunderbaumNode {
|
|
|
3363
3439
|
const colElems = (_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.querySelectorAll("span.wb-col");
|
|
3364
3440
|
return colElems ? colElems[colIdx] : null;
|
|
3365
3441
|
}
|
|
3442
|
+
/**
|
|
3443
|
+
* Return all nodes with the same refKey.
|
|
3444
|
+
*
|
|
3445
|
+
* @param includeSelf Include this node itself.
|
|
3446
|
+
* @see {@link Wunderbaum.findByRefKey}
|
|
3447
|
+
*/
|
|
3448
|
+
getCloneList(includeSelf = false) {
|
|
3449
|
+
if (!this.refKey) {
|
|
3450
|
+
return [];
|
|
3451
|
+
}
|
|
3452
|
+
const clones = this.tree.findByRefKey(this.refKey);
|
|
3453
|
+
if (includeSelf) {
|
|
3454
|
+
return clones;
|
|
3455
|
+
}
|
|
3456
|
+
return [...clones].filter((n) => n !== this);
|
|
3457
|
+
}
|
|
3366
3458
|
/** Return the first child node or null.
|
|
3367
3459
|
* @returns {WunderbaumNode | null}
|
|
3368
3460
|
*/
|
|
@@ -3467,17 +3559,22 @@ class WunderbaumNode {
|
|
|
3467
3559
|
return this.tree.activeNode === this;
|
|
3468
3560
|
}
|
|
3469
3561
|
/** Return true if this node is a direct or indirect parent of `other`.
|
|
3470
|
-
*
|
|
3562
|
+
* @see {@link WunderbaumNode.isParentOf}
|
|
3471
3563
|
*/
|
|
3472
3564
|
isAncestorOf(other) {
|
|
3473
3565
|
return other && other.isDescendantOf(this);
|
|
3474
3566
|
}
|
|
3475
3567
|
/** Return true if this node is a **direct** subnode of `other`.
|
|
3476
|
-
*
|
|
3568
|
+
* @see {@link WunderbaumNode.isDescendantOf}
|
|
3477
3569
|
*/
|
|
3478
3570
|
isChildOf(other) {
|
|
3479
3571
|
return other && this.parent === other;
|
|
3480
3572
|
}
|
|
3573
|
+
/** Return true if this node's refKey is used by at least one other node.
|
|
3574
|
+
*/
|
|
3575
|
+
isClone() {
|
|
3576
|
+
return !!this.refKey && this.tree.findByRefKey(this.refKey).length > 1;
|
|
3577
|
+
}
|
|
3481
3578
|
/** Return true if this node's title spans all columns, i.e. the node has no
|
|
3482
3579
|
* grid cells.
|
|
3483
3580
|
*/
|
|
@@ -3485,7 +3582,7 @@ class WunderbaumNode {
|
|
|
3485
3582
|
return !!this.getOption("colspan");
|
|
3486
3583
|
}
|
|
3487
3584
|
/** Return true if this node is a direct or indirect subnode of `other`.
|
|
3488
|
-
*
|
|
3585
|
+
* @see {@link WunderbaumNode.isChildOf}
|
|
3489
3586
|
*/
|
|
3490
3587
|
isDescendantOf(other) {
|
|
3491
3588
|
if (!other || other.tree !== this.tree) {
|
|
@@ -3520,8 +3617,11 @@ class WunderbaumNode {
|
|
|
3520
3617
|
}
|
|
3521
3618
|
return true;
|
|
3522
3619
|
}
|
|
3523
|
-
/** Return true if
|
|
3524
|
-
|
|
3620
|
+
/** Return true if _this_ node is currently in edit-title mode.
|
|
3621
|
+
*
|
|
3622
|
+
* See {@link Wunderbaum.startEditTitle} to check if any node is currently edited.
|
|
3623
|
+
*/
|
|
3624
|
+
isEditingTitle() {
|
|
3525
3625
|
return this.tree._callMethod("edit.isEditingTitle", this);
|
|
3526
3626
|
}
|
|
3527
3627
|
/** Return true if this node is currently expanded. */
|
|
@@ -3555,7 +3655,7 @@ class WunderbaumNode {
|
|
|
3555
3655
|
return this.statusNodeType === "paging";
|
|
3556
3656
|
}
|
|
3557
3657
|
/** Return true if this node is a **direct** parent of `other`.
|
|
3558
|
-
*
|
|
3658
|
+
* @see {@link WunderbaumNode.isAncestorOf}
|
|
3559
3659
|
*/
|
|
3560
3660
|
isParentOf(other) {
|
|
3561
3661
|
return other && other.parent === this;
|
|
@@ -3577,7 +3677,7 @@ class WunderbaumNode {
|
|
|
3577
3677
|
return !!this._rowElem;
|
|
3578
3678
|
}
|
|
3579
3679
|
/** Return true if this node is the (invisible) system root node.
|
|
3580
|
-
*
|
|
3680
|
+
* @see {@link WunderbaumNode.isTopLevel}
|
|
3581
3681
|
*/
|
|
3582
3682
|
isRootNode() {
|
|
3583
3683
|
return this.tree.root === this;
|
|
@@ -3785,13 +3885,20 @@ class WunderbaumNode {
|
|
|
3785
3885
|
}
|
|
3786
3886
|
}
|
|
3787
3887
|
}
|
|
3788
|
-
/**
|
|
3888
|
+
/**
|
|
3889
|
+
* Load content of a lazy node.
|
|
3890
|
+
* If the node is already loaded, nothing happens.
|
|
3891
|
+
* @param [forceReload=false] If true, reload even if already loaded.
|
|
3892
|
+
*/
|
|
3789
3893
|
async loadLazy(forceReload = false) {
|
|
3790
3894
|
const wasExpanded = this.expanded;
|
|
3791
3895
|
assert(this.lazy, "load() requires a lazy node");
|
|
3792
|
-
// _assert( forceReload || this.isUndefined(), "Pass forceReload=true to re-load a lazy node" );
|
|
3793
3896
|
if (!forceReload && !this.isUnloaded()) {
|
|
3794
|
-
return;
|
|
3897
|
+
return; // Already loaded: nothing to do
|
|
3898
|
+
}
|
|
3899
|
+
if (this.isLoading()) {
|
|
3900
|
+
this.logWarn("loadLazy() called while already loading: ignored.");
|
|
3901
|
+
return; // Already loading: prevent duplicate requests
|
|
3795
3902
|
}
|
|
3796
3903
|
if (this.isLoaded()) {
|
|
3797
3904
|
this.resetLazy(); // Also collapses if currently expanded
|
|
@@ -3807,7 +3914,7 @@ class WunderbaumNode {
|
|
|
3807
3914
|
}
|
|
3808
3915
|
assert(isArray(source) || (source && source.url), "The lazyLoad event must return a node list, `{url: ...}`, or false.");
|
|
3809
3916
|
await this.load(source);
|
|
3810
|
-
this.setStatus(NodeStatusType.ok);
|
|
3917
|
+
this.setStatus(NodeStatusType.ok); // Also resets `this._isLoading`
|
|
3811
3918
|
if (wasExpanded) {
|
|
3812
3919
|
this.expanded = true;
|
|
3813
3920
|
this.tree.update(ChangeType.structure);
|
|
@@ -3819,33 +3926,41 @@ class WunderbaumNode {
|
|
|
3819
3926
|
catch (e) {
|
|
3820
3927
|
this.logError("Error during loadLazy()", e);
|
|
3821
3928
|
this._callEvent("error", { error: e });
|
|
3929
|
+
// Also resets `this._isLoading`:
|
|
3822
3930
|
this.setStatus(NodeStatusType.error, { message: "" + e });
|
|
3823
3931
|
}
|
|
3824
3932
|
return;
|
|
3825
3933
|
}
|
|
3826
|
-
/**
|
|
3934
|
+
/** Write to `console.log` with node name as prefix if opts.debugLevel >= 4.
|
|
3935
|
+
* @see {@link WunderbaumNode.logDebug}
|
|
3936
|
+
*/
|
|
3827
3937
|
log(...args) {
|
|
3828
|
-
this.
|
|
3938
|
+
if (this.tree.options.debugLevel >= 4) {
|
|
3939
|
+
console.log(this.toString(), ...args); // eslint-disable-line no-console
|
|
3940
|
+
}
|
|
3829
3941
|
}
|
|
3830
|
-
|
|
3942
|
+
/** Write to `console.debug` with node name as prefix if opts.debugLevel >= 4
|
|
3943
|
+
* and browser console level includes debug/verbose messages.
|
|
3944
|
+
* @see {@link WunderbaumNode.log}
|
|
3945
|
+
*/
|
|
3831
3946
|
logDebug(...args) {
|
|
3832
3947
|
if (this.tree.options.debugLevel >= 4) {
|
|
3833
|
-
console.
|
|
3948
|
+
console.debug(this.toString(), ...args); // eslint-disable-line no-console
|
|
3834
3949
|
}
|
|
3835
3950
|
}
|
|
3836
|
-
|
|
3951
|
+
/** Write to `console.error` with node name as prefix if opts.debugLevel >= 1. */
|
|
3837
3952
|
logError(...args) {
|
|
3838
3953
|
if (this.tree.options.debugLevel >= 1) {
|
|
3839
3954
|
console.error(this.toString(), ...args); // eslint-disable-line no-console
|
|
3840
3955
|
}
|
|
3841
3956
|
}
|
|
3842
|
-
|
|
3957
|
+
/** Write to `console.info` with node name as prefix if opts.debugLevel >= 3. */
|
|
3843
3958
|
logInfo(...args) {
|
|
3844
3959
|
if (this.tree.options.debugLevel >= 3) {
|
|
3845
3960
|
console.info(this.toString(), ...args); // eslint-disable-line no-console
|
|
3846
3961
|
}
|
|
3847
3962
|
}
|
|
3848
|
-
|
|
3963
|
+
/** Write to `console.warn` with node name as prefix if opts.debugLevel >= 2. */
|
|
3849
3964
|
logWarn(...args) {
|
|
3850
3965
|
if (this.tree.options.debugLevel >= 2) {
|
|
3851
3966
|
console.warn(this.toString(), ...args); // eslint-disable-line no-console
|
|
@@ -4036,15 +4151,16 @@ class WunderbaumNode {
|
|
|
4036
4151
|
}
|
|
4037
4152
|
/** Remove all descendants of this node. */
|
|
4038
4153
|
removeChildren() {
|
|
4154
|
+
var _a, _b;
|
|
4039
4155
|
const tree = this.tree;
|
|
4040
4156
|
if (!this.children) {
|
|
4041
4157
|
return;
|
|
4042
4158
|
}
|
|
4043
|
-
if (tree.activeNode
|
|
4159
|
+
if ((_a = tree.activeNode) === null || _a === void 0 ? void 0 : _a.isDescendantOf(this)) {
|
|
4044
4160
|
tree.activeNode.setActive(false); // TODO: don't fire events
|
|
4045
4161
|
}
|
|
4046
|
-
if (tree.focusNode
|
|
4047
|
-
tree.
|
|
4162
|
+
if ((_b = tree.focusNode) === null || _b === void 0 ? void 0 : _b.isDescendantOf(this)) {
|
|
4163
|
+
tree._setFocusNode(null);
|
|
4048
4164
|
}
|
|
4049
4165
|
// TODO: persist must take care to clear select and expand cookies
|
|
4050
4166
|
// Unlink children to support GC
|
|
@@ -4456,6 +4572,7 @@ class WunderbaumNode {
|
|
|
4456
4572
|
let i = 0;
|
|
4457
4573
|
for (const colSpan of rowDiv.children) {
|
|
4458
4574
|
colSpan.classList.toggle("wb-active", i++ === tree.activeColIdx);
|
|
4575
|
+
colSpan.classList.remove("wb-error", "wb-invalid");
|
|
4459
4576
|
}
|
|
4460
4577
|
// Update icon (if not opts.isNew, which would rebuild markup anyway)
|
|
4461
4578
|
const iconSpan = nodeElem.querySelector("i.wb-icon");
|
|
@@ -4637,16 +4754,21 @@ class WunderbaumNode {
|
|
|
4637
4754
|
return this.tree.scrollTo(opts);
|
|
4638
4755
|
}
|
|
4639
4756
|
/**
|
|
4640
|
-
* Activate this node, deactivate previous, send events, activate column and
|
|
4757
|
+
* Activate this node, deactivate previous, send events, activate column and
|
|
4758
|
+
* scroll into viewport.
|
|
4641
4759
|
*/
|
|
4642
4760
|
async setActive(flag = true, options) {
|
|
4643
4761
|
const tree = this.tree;
|
|
4644
|
-
const prev = tree.
|
|
4762
|
+
const prev = tree.getActiveNode();
|
|
4645
4763
|
const retrigger = options === null || options === void 0 ? void 0 : options.retrigger; // Default: false
|
|
4646
4764
|
const focusTree = options === null || options === void 0 ? void 0 : options.focusTree; // Default: false
|
|
4647
|
-
const focusNode =
|
|
4765
|
+
// const focusNode = options?.focusNode !== false; // Default: true
|
|
4648
4766
|
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:
|
|
4767
|
+
const orgEvent = options === null || options === void 0 ? void 0 : options.event; // Default: null
|
|
4768
|
+
const colIdx = options === null || options === void 0 ? void 0 : options.colIdx; // Default: null
|
|
4769
|
+
const edit = options === null || options === void 0 ? void 0 : options.edit; // Default: false
|
|
4770
|
+
assert(!colIdx || tree.isCellNav(), "colIdx requires cellNav");
|
|
4771
|
+
assert(!edit || colIdx != null, "edit requires colIdx");
|
|
4650
4772
|
if (!noEvents) {
|
|
4651
4773
|
if (flag) {
|
|
4652
4774
|
if (prev !== this || retrigger) {
|
|
@@ -4660,7 +4782,7 @@ class WunderbaumNode {
|
|
|
4660
4782
|
}) === false) {
|
|
4661
4783
|
return;
|
|
4662
4784
|
}
|
|
4663
|
-
tree.
|
|
4785
|
+
tree._setActiveNode(null);
|
|
4664
4786
|
prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status);
|
|
4665
4787
|
}
|
|
4666
4788
|
}
|
|
@@ -4670,43 +4792,51 @@ class WunderbaumNode {
|
|
|
4670
4792
|
}
|
|
4671
4793
|
if (prev !== this) {
|
|
4672
4794
|
if (flag) {
|
|
4673
|
-
tree.
|
|
4674
|
-
if (focusNode || focusTree) {
|
|
4675
|
-
tree.focusNode = this;
|
|
4676
|
-
}
|
|
4677
|
-
if (focusTree) {
|
|
4678
|
-
tree.setFocus();
|
|
4679
|
-
}
|
|
4795
|
+
tree._setActiveNode(this);
|
|
4680
4796
|
}
|
|
4681
4797
|
prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status);
|
|
4682
4798
|
this.update(ChangeType.status);
|
|
4683
4799
|
}
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4800
|
+
return this.makeVisible().then(() => {
|
|
4801
|
+
if (flag) {
|
|
4802
|
+
if (focusTree || edit) {
|
|
4803
|
+
tree.setFocus();
|
|
4804
|
+
tree._setFocusNode(this);
|
|
4805
|
+
tree.focusNode.setFocus();
|
|
4806
|
+
}
|
|
4807
|
+
// if (focusNode || edit) {
|
|
4808
|
+
// tree.focusNode = this;
|
|
4809
|
+
// tree.focusNode.setFocus();
|
|
4810
|
+
// }
|
|
4811
|
+
if (colIdx != null && tree.isCellNav()) {
|
|
4812
|
+
tree.setColumn(colIdx, { edit: edit });
|
|
4813
|
+
}
|
|
4814
|
+
if (!noEvents) {
|
|
4815
|
+
this._callEvent("activate", { prevNode: prev, event: orgEvent });
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
});
|
|
4694
4819
|
}
|
|
4695
4820
|
/**
|
|
4696
4821
|
* Expand or collapse this node.
|
|
4697
4822
|
*/
|
|
4698
4823
|
async setExpanded(flag = true, options) {
|
|
4699
4824
|
const { force, scrollIntoView, immediate } = options !== null && options !== void 0 ? options : {};
|
|
4825
|
+
const sendEvents = !(options === null || options === void 0 ? void 0 : options.noEvents); // Default: send events
|
|
4700
4826
|
if (!flag &&
|
|
4701
4827
|
this.isExpanded() &&
|
|
4702
4828
|
this.getLevel() <= this.tree.getOption("minExpandLevel") &&
|
|
4703
4829
|
!force) {
|
|
4704
|
-
this.logDebug("Ignored collapse request below
|
|
4830
|
+
this.logDebug("Ignored collapse request below minExpandLevel.");
|
|
4705
4831
|
return;
|
|
4706
4832
|
}
|
|
4707
4833
|
if (!flag === !this.expanded) {
|
|
4708
4834
|
return; // Nothing to do
|
|
4709
4835
|
}
|
|
4836
|
+
if (sendEvents &&
|
|
4837
|
+
this._callEvent("beforeExpand", { flag: flag }) === false) {
|
|
4838
|
+
return;
|
|
4839
|
+
}
|
|
4710
4840
|
// this.log("setExpanded()");
|
|
4711
4841
|
if (flag && this.getOption("autoCollapse")) {
|
|
4712
4842
|
this.collapseSiblings(options);
|
|
@@ -4725,15 +4855,18 @@ class WunderbaumNode {
|
|
|
4725
4855
|
lastChild.scrollIntoView({ topNode: this });
|
|
4726
4856
|
}
|
|
4727
4857
|
}
|
|
4858
|
+
if (sendEvents) {
|
|
4859
|
+
this._callEvent("expand", { flag: flag });
|
|
4860
|
+
}
|
|
4728
4861
|
}
|
|
4729
4862
|
/**
|
|
4730
4863
|
* Set keyboard focus here.
|
|
4731
4864
|
* @see {@link setActive}
|
|
4732
4865
|
*/
|
|
4733
4866
|
setFocus(flag = true) {
|
|
4734
|
-
assert(!!flag, "
|
|
4867
|
+
assert(!!flag, "Blur is not yet implemented");
|
|
4735
4868
|
const prev = this.tree.focusNode;
|
|
4736
|
-
this.tree.
|
|
4869
|
+
this.tree._setFocusNode(this);
|
|
4737
4870
|
prev === null || prev === void 0 ? void 0 : prev.update();
|
|
4738
4871
|
this.update();
|
|
4739
4872
|
}
|
|
@@ -5186,7 +5319,7 @@ WunderbaumNode.sequence = 0;
|
|
|
5186
5319
|
/*!
|
|
5187
5320
|
* Wunderbaum - ext-edit
|
|
5188
5321
|
* Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license.
|
|
5189
|
-
* v0.
|
|
5322
|
+
* v0.8.1, Sat, 20 Jan 2024 15:57:59 GMT (https://github.com/mar10/wunderbaum)
|
|
5190
5323
|
*/
|
|
5191
5324
|
// const START_MARKER = "\uFFF7";
|
|
5192
5325
|
class EditExtension extends WunderbaumExtension {
|
|
@@ -5211,40 +5344,62 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5211
5344
|
this.debouncedOnChange = debounce(this._onChange.bind(this), this.getPluginOption("debounce"));
|
|
5212
5345
|
}
|
|
5213
5346
|
/*
|
|
5214
|
-
* Call an event handler, while marking the current node cell '
|
|
5347
|
+
* Call an event handler, while marking the current node cell 'busy'.
|
|
5348
|
+
* Deal with returned promises and ValidationError.
|
|
5349
|
+
* Convert a ValidationError into a input.setCustomValidity() call and vice versa.
|
|
5215
5350
|
*/
|
|
5216
|
-
_applyChange(eventName, node, colElem, extra) {
|
|
5217
|
-
let res;
|
|
5351
|
+
async _applyChange(eventName, node, colElem, inputElem, extra) {
|
|
5218
5352
|
node.log(`_applyChange(${eventName})`, extra);
|
|
5219
5353
|
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
|
-
|
|
5354
|
+
colElem.classList.remove("wb-error", "wb-invalid");
|
|
5355
|
+
inputElem.setCustomValidity("");
|
|
5356
|
+
// Call event handler either ('change' or 'edit.appy'), which may return a
|
|
5357
|
+
// promise or a scalar value or throw a ValidationError.
|
|
5358
|
+
return new Promise((resolve, reject) => {
|
|
5359
|
+
const res = node._callEvent(eventName, extra);
|
|
5360
|
+
// normalize to promise, even if a scalar value was returned and await it
|
|
5361
|
+
Promise.resolve(res)
|
|
5362
|
+
.then((res) => {
|
|
5363
|
+
resolve(res);
|
|
5364
|
+
})
|
|
5365
|
+
.catch((err) => {
|
|
5366
|
+
reject(err);
|
|
5367
|
+
});
|
|
5368
|
+
})
|
|
5369
|
+
.then((res) => {
|
|
5370
|
+
if (!inputElem.checkValidity()) {
|
|
5371
|
+
// Native validation failed or handler called 'inputElem.setCustomValidity()'
|
|
5372
|
+
node.logWarn("inputElem.checkValidity() failed: throwing....");
|
|
5373
|
+
throw new ValidationError(inputElem.validationMessage);
|
|
5374
|
+
}
|
|
5375
|
+
return res;
|
|
5376
|
+
})
|
|
5234
5377
|
.catch((err) => {
|
|
5235
|
-
|
|
5236
|
-
|
|
5378
|
+
if (err instanceof ValidationError) {
|
|
5379
|
+
node.logWarn("catched ", err);
|
|
5380
|
+
colElem.classList.add("wb-invalid");
|
|
5381
|
+
if (inputElem.setCustomValidity && !inputElem.validationMessage) {
|
|
5382
|
+
inputElem.setCustomValidity(err.message);
|
|
5383
|
+
}
|
|
5384
|
+
if (inputElem.validationMessage) {
|
|
5385
|
+
inputElem.reportValidity();
|
|
5386
|
+
}
|
|
5387
|
+
// throw err;
|
|
5388
|
+
}
|
|
5389
|
+
else {
|
|
5390
|
+
node.logError(`Error in ${eventName} event handler (throw e.util.ValidationError instead if this was intended)`, err);
|
|
5391
|
+
colElem.classList.add("wb-error");
|
|
5392
|
+
throw err;
|
|
5393
|
+
}
|
|
5237
5394
|
})
|
|
5238
5395
|
.finally(() => {
|
|
5239
5396
|
colElem.classList.remove("wb-busy");
|
|
5240
5397
|
});
|
|
5241
|
-
return res;
|
|
5242
5398
|
}
|
|
5243
5399
|
/*
|
|
5244
5400
|
* Called for when a control that is embedded in a cell fires a `change` event.
|
|
5245
5401
|
*/
|
|
5246
5402
|
_onChange(e) {
|
|
5247
|
-
// let res;
|
|
5248
5403
|
const info = Wunderbaum.getEventInfo(e);
|
|
5249
5404
|
const node = info.node;
|
|
5250
5405
|
const colElem = info.colElem;
|
|
@@ -5252,16 +5407,15 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5252
5407
|
this.tree.log("Ignored change event for removed element or node title");
|
|
5253
5408
|
return;
|
|
5254
5409
|
}
|
|
5255
|
-
|
|
5410
|
+
// See also WbChangeEventType
|
|
5411
|
+
this._applyChange("change", node, colElem, e.target, {
|
|
5256
5412
|
info: info,
|
|
5257
5413
|
event: e,
|
|
5258
5414
|
inputElem: e.target,
|
|
5259
5415
|
inputValue: Wunderbaum.util.getValueFromElem(e.target),
|
|
5416
|
+
inputValid: e.target.checkValidity(),
|
|
5260
5417
|
});
|
|
5261
5418
|
}
|
|
5262
|
-
// handleKey(e:KeyboardEvent):boolean {
|
|
5263
|
-
// if(this.tree.cellNavMode )
|
|
5264
|
-
// }
|
|
5265
5419
|
init() {
|
|
5266
5420
|
super.init();
|
|
5267
5421
|
onEvent(this.tree.element, "change", //"change input",
|
|
@@ -5308,7 +5462,6 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5308
5462
|
break;
|
|
5309
5463
|
case "F2":
|
|
5310
5464
|
if (trigger.indexOf("F2") >= 0) {
|
|
5311
|
-
// tree.setNavigationMode(NavigationMode.cellEdit);
|
|
5312
5465
|
this.startEditTitle();
|
|
5313
5466
|
return false;
|
|
5314
5467
|
}
|
|
@@ -5333,14 +5486,21 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5333
5486
|
this.tree.logDebug(`startEditTitle(node=${node})`);
|
|
5334
5487
|
let inputHtml = node._callEvent("edit.beforeEdit");
|
|
5335
5488
|
if (inputHtml === false) {
|
|
5336
|
-
node.
|
|
5489
|
+
node.logDebug("beforeEdit canceled operation.");
|
|
5337
5490
|
return;
|
|
5338
5491
|
}
|
|
5339
|
-
// `beforeEdit(e)` may return an input HTML string. Otherwise use a default
|
|
5492
|
+
// `beforeEdit(e)` may return an input HTML string. Otherwise use a default
|
|
5340
5493
|
// (we also treat a `true` return value as 'use default'):
|
|
5341
5494
|
if (inputHtml === true || !inputHtml) {
|
|
5342
5495
|
const title = escapeHtml(node.title);
|
|
5343
|
-
|
|
5496
|
+
let opt = this.getPluginOption("maxlength");
|
|
5497
|
+
const maxlength = opt ? ` maxlength="${opt}"` : "";
|
|
5498
|
+
opt = this.getPluginOption("minlength");
|
|
5499
|
+
const minlength = opt ? ` minlength="${opt}"` : "";
|
|
5500
|
+
const required = opt > 0 ? " required" : "";
|
|
5501
|
+
inputHtml =
|
|
5502
|
+
`<input type=text class="wb-input-edit" tabindex=-1 value="${title}" ` +
|
|
5503
|
+
`autocorrect="off"${required}${minlength}${maxlength} >`;
|
|
5344
5504
|
}
|
|
5345
5505
|
const titleSpan = node
|
|
5346
5506
|
.getColElem(0)
|
|
@@ -5351,7 +5511,9 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5351
5511
|
// Permanently apply input validations (CSS and tooltip)
|
|
5352
5512
|
inputElem.addEventListener("keydown", (e) => {
|
|
5353
5513
|
inputElem.setCustomValidity("");
|
|
5354
|
-
if (!inputElem.reportValidity())
|
|
5514
|
+
if (!inputElem.reportValidity()) {
|
|
5515
|
+
node.logWarn(`Invalid input: '${inputElem.value}'`);
|
|
5516
|
+
}
|
|
5355
5517
|
});
|
|
5356
5518
|
}
|
|
5357
5519
|
inputElem.focus();
|
|
@@ -5398,12 +5560,12 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5398
5560
|
throw new Error(`Input validation failed for "${newValue}": ${errMsg}.`);
|
|
5399
5561
|
}
|
|
5400
5562
|
const colElem = node.getColElem(0);
|
|
5401
|
-
this._applyChange("edit.apply", node, colElem, {
|
|
5563
|
+
this._applyChange("edit.apply", node, colElem, focusElem, {
|
|
5402
5564
|
oldValue: node.title,
|
|
5403
5565
|
newValue: newValue,
|
|
5404
5566
|
inputElem: focusElem,
|
|
5405
|
-
|
|
5406
|
-
|
|
5567
|
+
inputValid: focusElem.checkValidity(),
|
|
5568
|
+
}).then((value) => {
|
|
5407
5569
|
const errMsg = focusElem.validationMessage;
|
|
5408
5570
|
if (validity && errMsg && value !== false) {
|
|
5409
5571
|
// Handler called 'inputElem.setCustomValidity()' to signal error
|
|
@@ -5422,10 +5584,10 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5422
5584
|
this.curEditNode = null;
|
|
5423
5585
|
this.relatedNode = null;
|
|
5424
5586
|
this.tree.setFocus(); // restore focus that was in the input element
|
|
5425
|
-
})
|
|
5426
|
-
.catch((err) => {
|
|
5427
|
-
node.logError(err);
|
|
5428
5587
|
});
|
|
5588
|
+
// .catch((err) => {
|
|
5589
|
+
// node.logError(err);
|
|
5590
|
+
// });
|
|
5429
5591
|
// Trigger 'change' event for embedded `<input>`
|
|
5430
5592
|
// focusElem.blur();
|
|
5431
5593
|
}
|
|
@@ -5486,8 +5648,8 @@ class EditExtension extends WunderbaumExtension {
|
|
|
5486
5648
|
* https://github.com/mar10/wunderbaum
|
|
5487
5649
|
*
|
|
5488
5650
|
* Released under the MIT license.
|
|
5489
|
-
* @version v0.
|
|
5490
|
-
* @date Sat,
|
|
5651
|
+
* @version v0.8.1
|
|
5652
|
+
* @date Sat, 20 Jan 2024 15:57:59 GMT
|
|
5491
5653
|
*/
|
|
5492
5654
|
// import "./wunderbaum.scss";
|
|
5493
5655
|
class WbSystemRoot extends WunderbaumNode {
|
|
@@ -5504,9 +5666,25 @@ class WbSystemRoot extends WunderbaumNode {
|
|
|
5504
5666
|
/**
|
|
5505
5667
|
* A persistent plain object or array.
|
|
5506
5668
|
*
|
|
5507
|
-
* See also
|
|
5669
|
+
* See also {@link WunderbaumOptions}.
|
|
5508
5670
|
*/
|
|
5509
5671
|
class Wunderbaum {
|
|
5672
|
+
/** Currently active node if any.
|
|
5673
|
+
* Use @link {WunderbaumNode.setActive|setActive} to modify.
|
|
5674
|
+
*/
|
|
5675
|
+
get activeNode() {
|
|
5676
|
+
var _a;
|
|
5677
|
+
// Check for deleted node, i.e. node.tree === null
|
|
5678
|
+
return ((_a = this._activeNode) === null || _a === void 0 ? void 0 : _a.tree) ? this._activeNode : null;
|
|
5679
|
+
}
|
|
5680
|
+
/** Current node hat has keyboard focus if any.
|
|
5681
|
+
* Use @link {WunderbaumNode.setFocus|setFocus()} to modify.
|
|
5682
|
+
*/
|
|
5683
|
+
get focusNode() {
|
|
5684
|
+
var _a;
|
|
5685
|
+
// Check for deleted node, i.e. node.tree === null
|
|
5686
|
+
return ((_a = this._focusNode) === null || _a === void 0 ? void 0 : _a.tree) ? this._focusNode : null;
|
|
5687
|
+
}
|
|
5510
5688
|
constructor(options) {
|
|
5511
5689
|
this.enabled = true;
|
|
5512
5690
|
/** Contains additional data that was sent as response to an Ajax source load request. */
|
|
@@ -5518,10 +5696,8 @@ class Wunderbaum {
|
|
|
5518
5696
|
this.treeRowCount = 0;
|
|
5519
5697
|
this._disableUpdateCount = 0;
|
|
5520
5698
|
this._disableUpdateIgnoreCount = 0;
|
|
5521
|
-
|
|
5522
|
-
this.
|
|
5523
|
-
/** Current node hat has keyboard focus if any. */
|
|
5524
|
-
this.focusNode = null;
|
|
5699
|
+
this._activeNode = null;
|
|
5700
|
+
this._focusNode = null;
|
|
5525
5701
|
/** Shared properties, referenced by `node.type`. */
|
|
5526
5702
|
this.types = {};
|
|
5527
5703
|
/** List of column definitions. */
|
|
@@ -5537,7 +5713,7 @@ class Wunderbaum {
|
|
|
5537
5713
|
// --- FILTER ---
|
|
5538
5714
|
this.filterMode = null;
|
|
5539
5715
|
// --- KEYNAV ---
|
|
5540
|
-
/** @internal Use `setColumn()`/`getActiveColElem()
|
|
5716
|
+
/** @internal Use `setColumn()`/`getActiveColElem()` to access. */
|
|
5541
5717
|
this.activeColIdx = 0;
|
|
5542
5718
|
/** @internal */
|
|
5543
5719
|
this._cellNavMode = false;
|
|
@@ -5547,10 +5723,6 @@ class Wunderbaum {
|
|
|
5547
5723
|
this.lastQuicksearchTerm = "";
|
|
5548
5724
|
// --- EDIT ---
|
|
5549
5725
|
this.lastClickTime = 0;
|
|
5550
|
-
/** Alias for {@link Wunderbaum.logDebug}.
|
|
5551
|
-
* @alias Wunderbaum.logDebug
|
|
5552
|
-
*/
|
|
5553
|
-
this.log = this.logDebug;
|
|
5554
5726
|
const opts = (this.options = extend({
|
|
5555
5727
|
id: null,
|
|
5556
5728
|
source: null,
|
|
@@ -5713,6 +5885,7 @@ class Wunderbaum {
|
|
|
5713
5885
|
else {
|
|
5714
5886
|
this.setNavigationOption(opts.navigationModeOption);
|
|
5715
5887
|
}
|
|
5888
|
+
this.update(ChangeType.structure, { immediate: true });
|
|
5716
5889
|
readyDeferred.resolve();
|
|
5717
5890
|
})
|
|
5718
5891
|
.catch((error) => {
|
|
@@ -5764,7 +5937,7 @@ class Wunderbaum {
|
|
|
5764
5937
|
info.region === "title" &&
|
|
5765
5938
|
node.isActive() &&
|
|
5766
5939
|
(!slowClickDelay || Date.now() - this.lastClickTime < slowClickDelay)) {
|
|
5767
|
-
|
|
5940
|
+
node.startEditTitle();
|
|
5768
5941
|
}
|
|
5769
5942
|
if (info.colIdx >= 0) {
|
|
5770
5943
|
node.setActive(true, { colIdx: info.colIdx, event: e });
|
|
@@ -5811,7 +5984,7 @@ class Wunderbaum {
|
|
|
5811
5984
|
const flag = e.type === "focusin";
|
|
5812
5985
|
const targetNode = Wunderbaum.getNode(e);
|
|
5813
5986
|
this._callEvent("focus", { flag: flag, event: e });
|
|
5814
|
-
if (flag && this.isRowNav() && !this.
|
|
5987
|
+
if (flag && this.isRowNav() && !this.isEditingTitle()) {
|
|
5815
5988
|
if (opts.navigationModeOption === NavModeEnum.row) {
|
|
5816
5989
|
targetNode === null || targetNode === void 0 ? void 0 : targetNode.setActive();
|
|
5817
5990
|
}
|
|
@@ -5835,7 +6008,7 @@ class Wunderbaum {
|
|
|
5835
6008
|
* getTree(1); // Get second Wunderbaum instance on page
|
|
5836
6009
|
* getTree(event); // Get tree for this mouse- or keyboard event
|
|
5837
6010
|
* getTree("foo"); // Get tree for this `tree.options.id`
|
|
5838
|
-
* getTree("#tree"); // Get tree for
|
|
6011
|
+
* getTree("#tree"); // Get tree for first matching element selector
|
|
5839
6012
|
* ```
|
|
5840
6013
|
*/
|
|
5841
6014
|
static getTree(el) {
|
|
@@ -5939,34 +6112,37 @@ class Wunderbaum {
|
|
|
5939
6112
|
/** Add node to tree's bookkeeping data structures. */
|
|
5940
6113
|
_registerNode(node) {
|
|
5941
6114
|
const key = node.key;
|
|
5942
|
-
assert(key != null
|
|
6115
|
+
assert(key != null, `Missing key: '${node}'.`);
|
|
6116
|
+
assert(!this.keyMap.has(key), `Duplicate key: '${key}': ${node}.`);
|
|
5943
6117
|
this.keyMap.set(key, node);
|
|
5944
6118
|
const rk = node.refKey;
|
|
5945
|
-
if (rk) {
|
|
6119
|
+
if (rk != null) {
|
|
5946
6120
|
const rks = this.refKeyMap.get(rk); // Set of nodes with this refKey
|
|
5947
6121
|
if (rks) {
|
|
5948
6122
|
rks.add(node);
|
|
5949
6123
|
}
|
|
5950
6124
|
else {
|
|
5951
|
-
this.refKeyMap.set(rk, new Set());
|
|
6125
|
+
this.refKeyMap.set(rk, new Set([node]));
|
|
5952
6126
|
}
|
|
5953
6127
|
}
|
|
5954
6128
|
}
|
|
5955
6129
|
/** Remove node from tree's bookkeeping data structures. */
|
|
5956
6130
|
_unregisterNode(node) {
|
|
6131
|
+
// Remove refKey reference from map (if any)
|
|
5957
6132
|
const rk = node.refKey;
|
|
5958
|
-
if (rk) {
|
|
6133
|
+
if (rk != null) {
|
|
5959
6134
|
const rks = this.refKeyMap.get(rk);
|
|
5960
6135
|
if (rks && rks.delete(node) && !rks.size) {
|
|
5961
6136
|
// We just removed the last element
|
|
5962
6137
|
this.refKeyMap.delete(rk);
|
|
5963
6138
|
}
|
|
5964
6139
|
}
|
|
5965
|
-
//
|
|
6140
|
+
// Remove key reference from map
|
|
6141
|
+
this.keyMap.delete(node.key);
|
|
6142
|
+
// Mark as disposed
|
|
5966
6143
|
node.tree = null;
|
|
5967
6144
|
node.parent = null;
|
|
5968
|
-
//
|
|
5969
|
-
// this.viewNodes.delete(node);
|
|
6145
|
+
// Remove HTML markup
|
|
5970
6146
|
node.removeMarkup();
|
|
5971
6147
|
}
|
|
5972
6148
|
/** Call all hook methods of all registered extensions.*/
|
|
@@ -6170,7 +6346,7 @@ class Wunderbaum {
|
|
|
6170
6346
|
this._callMethod("edit.createNode", "after");
|
|
6171
6347
|
break;
|
|
6172
6348
|
case "rename":
|
|
6173
|
-
|
|
6349
|
+
node.startEditTitle();
|
|
6174
6350
|
break;
|
|
6175
6351
|
// Simple clipboard simulation:
|
|
6176
6352
|
// case "cut":
|
|
@@ -6217,10 +6393,9 @@ class Wunderbaum {
|
|
|
6217
6393
|
this.root.children = null;
|
|
6218
6394
|
this.keyMap.clear();
|
|
6219
6395
|
this.refKeyMap.clear();
|
|
6220
|
-
// this.viewNodes.clear();
|
|
6221
6396
|
this.treeRowCount = 0;
|
|
6222
|
-
this.
|
|
6223
|
-
this.
|
|
6397
|
+
this._activeNode = null;
|
|
6398
|
+
this._focusNode = null;
|
|
6224
6399
|
// this.types = {};
|
|
6225
6400
|
// this. columns =[];
|
|
6226
6401
|
// this._columnsById = {};
|
|
@@ -6410,14 +6585,31 @@ class Wunderbaum {
|
|
|
6410
6585
|
/**
|
|
6411
6586
|
* Find all nodes that match condition.
|
|
6412
6587
|
*
|
|
6588
|
+
* @param match title string to search for, or a
|
|
6589
|
+
* callback function that returns `true` if a node is matched.
|
|
6413
6590
|
* @see {@link WunderbaumNode.findAll}
|
|
6414
6591
|
*/
|
|
6415
6592
|
findAll(match) {
|
|
6416
6593
|
return this.root.findAll(match);
|
|
6417
6594
|
}
|
|
6595
|
+
/**
|
|
6596
|
+
* Find all nodes with a given _refKey_ (aka a list of clones).
|
|
6597
|
+
*
|
|
6598
|
+
* @param refKey a `node.refKey` value to search for.
|
|
6599
|
+
* @returns an array of matching nodes with at least two element or `[]`
|
|
6600
|
+
* if nothing found.
|
|
6601
|
+
*
|
|
6602
|
+
* @see {@link WunderbaumNode.getCloneList}
|
|
6603
|
+
*/
|
|
6604
|
+
findByRefKey(refKey) {
|
|
6605
|
+
const clones = this.refKeyMap.get(refKey);
|
|
6606
|
+
return clones ? Array.from(clones) : [];
|
|
6607
|
+
}
|
|
6418
6608
|
/**
|
|
6419
6609
|
* Find first node that matches condition.
|
|
6420
6610
|
*
|
|
6611
|
+
* @param match title string to search for, or a
|
|
6612
|
+
* callback function that returns `true` if a node is matched.
|
|
6421
6613
|
* @see {@link WunderbaumNode.findFirst}
|
|
6422
6614
|
*/
|
|
6423
6615
|
findFirst(match) {
|
|
@@ -6426,8 +6618,6 @@ class Wunderbaum {
|
|
|
6426
6618
|
/**
|
|
6427
6619
|
* Find first node that matches condition.
|
|
6428
6620
|
*
|
|
6429
|
-
* @param match title string to search for, or a
|
|
6430
|
-
* callback function that returns `true` if a node is matched.
|
|
6431
6621
|
* @see {@link WunderbaumNode.findFirst}
|
|
6432
6622
|
*
|
|
6433
6623
|
*/
|
|
@@ -6437,6 +6627,7 @@ class Wunderbaum {
|
|
|
6437
6627
|
/**
|
|
6438
6628
|
* Find the next visible node that starts with `match`, starting at `startNode`
|
|
6439
6629
|
* and wrap-around at the end.
|
|
6630
|
+
* Used by quicksearch and keyboard navigation.
|
|
6440
6631
|
*/
|
|
6441
6632
|
findNextNode(match, startNode) {
|
|
6442
6633
|
//, visibleOnly) {
|
|
@@ -6603,7 +6794,13 @@ class Wunderbaum {
|
|
|
6603
6794
|
return null;
|
|
6604
6795
|
}
|
|
6605
6796
|
/**
|
|
6606
|
-
* Return the currently active node or null.
|
|
6797
|
+
* Return the currently active node or null (alias for `tree.activeNode`).
|
|
6798
|
+
* Alias for {@link Wunderbaum.activeNode}.
|
|
6799
|
+
*
|
|
6800
|
+
* @see {@link WunderbaumNode.setActive}
|
|
6801
|
+
* @see {@link WunderbaumNode.isActive}
|
|
6802
|
+
* @see {@link Wunderbaum.activeNode}
|
|
6803
|
+
* @see {@link Wunderbaum.focusNode}
|
|
6607
6804
|
*/
|
|
6608
6805
|
getActiveNode() {
|
|
6609
6806
|
return this.activeNode;
|
|
@@ -6615,7 +6812,12 @@ class Wunderbaum {
|
|
|
6615
6812
|
return this.root.getFirstChild();
|
|
6616
6813
|
}
|
|
6617
6814
|
/**
|
|
6618
|
-
* Return the currently
|
|
6815
|
+
* Return the node that currently has keyboard focus or null.
|
|
6816
|
+
* Alias for {@link Wunderbaum.focusNode}.
|
|
6817
|
+
* @see {@link WunderbaumNode.setFocus}
|
|
6818
|
+
* @see {@link WunderbaumNode.hasFocus}
|
|
6819
|
+
* @see {@link Wunderbaum.activeNode}
|
|
6820
|
+
* @see {@link Wunderbaum.focusNode}
|
|
6619
6821
|
*/
|
|
6620
6822
|
getFocusNode() {
|
|
6621
6823
|
return this.focusNode;
|
|
@@ -6692,8 +6894,19 @@ class Wunderbaum {
|
|
|
6692
6894
|
toString() {
|
|
6693
6895
|
return `Wunderbaum<'${this.id}'>`;
|
|
6694
6896
|
}
|
|
6695
|
-
/** Return true if any node is currently
|
|
6897
|
+
/** Return true if any node title or grid cell is currently beeing edited.
|
|
6898
|
+
*
|
|
6899
|
+
* See also {@link Wunderbaum.isEditingTitle}.
|
|
6900
|
+
*/
|
|
6696
6901
|
isEditing() {
|
|
6902
|
+
const focusElem = this.nodeListElement.querySelector("input:focus,select:focus");
|
|
6903
|
+
return !!focusElem;
|
|
6904
|
+
}
|
|
6905
|
+
/** Return true if any node is currently in edit-title mode.
|
|
6906
|
+
*
|
|
6907
|
+
* See also {@link WunderbaumNode.isEditingTitle} and {@link Wunderbaum.isEditing}.
|
|
6908
|
+
*/
|
|
6909
|
+
isEditingTitle() {
|
|
6697
6910
|
return this._callMethod("edit.isEditingTitle");
|
|
6698
6911
|
}
|
|
6699
6912
|
/**
|
|
@@ -6710,19 +6923,30 @@ class Wunderbaum {
|
|
|
6710
6923
|
}, true);
|
|
6711
6924
|
return res;
|
|
6712
6925
|
}
|
|
6713
|
-
/**
|
|
6714
|
-
|
|
6926
|
+
/** Write to `console.log` with tree name as prefix if opts.debugLevel >= 4.
|
|
6927
|
+
* @see {@link Wunderbaum.logDebug}
|
|
6928
|
+
*/
|
|
6929
|
+
log(...args) {
|
|
6715
6930
|
if (this.options.debugLevel >= 4) {
|
|
6716
6931
|
console.log(this.toString(), ...args); // eslint-disable-line no-console
|
|
6717
6932
|
}
|
|
6718
6933
|
}
|
|
6719
|
-
/**
|
|
6934
|
+
/** Write to `console.debug` with tree name as prefix if opts.debugLevel >= 4.
|
|
6935
|
+
* and browser console level includes debug/verbose messages.
|
|
6936
|
+
* @see {@link Wunderbaum.log}
|
|
6937
|
+
*/
|
|
6938
|
+
logDebug(...args) {
|
|
6939
|
+
if (this.options.debugLevel >= 4) {
|
|
6940
|
+
console.debug(this.toString(), ...args); // eslint-disable-line no-console
|
|
6941
|
+
}
|
|
6942
|
+
}
|
|
6943
|
+
/** Write to `console.error` with tree name as prefix. */
|
|
6720
6944
|
logError(...args) {
|
|
6721
6945
|
if (this.options.debugLevel >= 1) {
|
|
6722
6946
|
console.error(this.toString(), ...args); // eslint-disable-line no-console
|
|
6723
6947
|
}
|
|
6724
6948
|
}
|
|
6725
|
-
/**
|
|
6949
|
+
/** Write to `console.info` with tree name as prefix if opts.debugLevel >= 3. */
|
|
6726
6950
|
logInfo(...args) {
|
|
6727
6951
|
if (this.options.debugLevel >= 3) {
|
|
6728
6952
|
console.info(this.toString(), ...args); // eslint-disable-line no-console
|
|
@@ -6741,7 +6965,7 @@ class Wunderbaum {
|
|
|
6741
6965
|
console.timeEnd(this + ": " + label); // eslint-disable-line no-console
|
|
6742
6966
|
}
|
|
6743
6967
|
}
|
|
6744
|
-
/**
|
|
6968
|
+
/** Write to `console.warn` with tree name as prefix with if opts.debugLevel >= 2. */
|
|
6745
6969
|
logWarn(...args) {
|
|
6746
6970
|
if (this.options.debugLevel >= 2) {
|
|
6747
6971
|
console.warn(this.toString(), ...args); // eslint-disable-line no-console
|
|
@@ -6829,12 +7053,23 @@ class Wunderbaum {
|
|
|
6829
7053
|
/**
|
|
6830
7054
|
* Set column #colIdx to 'active'.
|
|
6831
7055
|
*
|
|
6832
|
-
* This higlights the column header and -cells by adding the `wb-active`
|
|
7056
|
+
* This higlights the column header and -cells by adding the `wb-active`
|
|
7057
|
+
* class to all grid cells of the active column. <br>
|
|
6833
7058
|
* Available in cell-nav mode only.
|
|
7059
|
+
*
|
|
7060
|
+
* If _options.edit_ is true, the embedded input element is focused, or if
|
|
7061
|
+
* colIdx is 0, the node title is put into edit mode.
|
|
6834
7062
|
*/
|
|
6835
|
-
setColumn(colIdx) {
|
|
6836
|
-
var _a;
|
|
6837
|
-
|
|
7063
|
+
setColumn(colIdx, options) {
|
|
7064
|
+
var _a, _b, _c;
|
|
7065
|
+
const edit = options === null || options === void 0 ? void 0 : options.edit;
|
|
7066
|
+
const scroll = (options === null || options === void 0 ? void 0 : options.scrollIntoView) !== false;
|
|
7067
|
+
assert(this.isCellNav(), "Expected cellNav mode");
|
|
7068
|
+
if (typeof colIdx === "string") {
|
|
7069
|
+
const cid = colIdx;
|
|
7070
|
+
colIdx = this.columns.findIndex((c) => c.id === colIdx);
|
|
7071
|
+
assert(colIdx >= 0, `Invalid colId: ${cid}`);
|
|
7072
|
+
}
|
|
6838
7073
|
assert(0 <= colIdx && colIdx < this.columns.length, `Invalid colIdx: ${colIdx}`);
|
|
6839
7074
|
this.activeColIdx = colIdx;
|
|
6840
7075
|
// Update `wb-active` class for all headers
|
|
@@ -6854,17 +7089,30 @@ class Wunderbaum {
|
|
|
6854
7089
|
colDiv.classList.toggle("wb-active", i++ === colIdx);
|
|
6855
7090
|
}
|
|
6856
7091
|
}
|
|
6857
|
-
//
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
7092
|
+
// Horizontically scroll into view
|
|
7093
|
+
if (scroll || edit) {
|
|
7094
|
+
this.scrollToHorz();
|
|
7095
|
+
}
|
|
7096
|
+
if (edit && this.activeNode) {
|
|
7097
|
+
// this.activeNode.setFocus(); // Blur prev. input if any
|
|
7098
|
+
if (colIdx === 0) {
|
|
7099
|
+
this.activeNode.startEditTitle();
|
|
7100
|
+
}
|
|
7101
|
+
else {
|
|
7102
|
+
(_c = (_b = this.getActiveColElem()) === null || _b === void 0 ? void 0 : _b.querySelector("input,select")) === null || _c === void 0 ? void 0 : _c.focus();
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
6861
7105
|
}
|
|
6862
|
-
|
|
7106
|
+
/* Set or remove keyboard focus to the tree container. @internal */
|
|
7107
|
+
_setActiveNode(node) {
|
|
7108
|
+
this._activeNode = node;
|
|
7109
|
+
}
|
|
7110
|
+
/** Set or remove keyboard focus to the tree container. */
|
|
6863
7111
|
setActiveNode(key, flag = true, options) {
|
|
6864
7112
|
var _a;
|
|
6865
7113
|
(_a = this.findKey(key)) === null || _a === void 0 ? void 0 : _a.setActive(flag, options);
|
|
6866
7114
|
}
|
|
6867
|
-
/** Set or remove
|
|
7115
|
+
/** Set or remove keyboard focus to the tree container. */
|
|
6868
7116
|
setFocus(flag = true) {
|
|
6869
7117
|
if (flag) {
|
|
6870
7118
|
this.element.focus();
|
|
@@ -6873,7 +7121,19 @@ class Wunderbaum {
|
|
|
6873
7121
|
this.element.blur();
|
|
6874
7122
|
}
|
|
6875
7123
|
}
|
|
7124
|
+
/* Set or remove keyboard focus to the tree container. @internal */
|
|
7125
|
+
_setFocusNode(node) {
|
|
7126
|
+
this._focusNode = node;
|
|
7127
|
+
}
|
|
6876
7128
|
update(change, node, options) {
|
|
7129
|
+
// this.log(`update(${change}) node=${node}`);
|
|
7130
|
+
if (!(node instanceof WunderbaumNode)) {
|
|
7131
|
+
options = node;
|
|
7132
|
+
node = undefined;
|
|
7133
|
+
}
|
|
7134
|
+
const immediate = !!getOption(options, "immediate");
|
|
7135
|
+
const RF = RenderFlag;
|
|
7136
|
+
const pending = this.pendingChangeTypes;
|
|
6877
7137
|
if (this._disableUpdateCount) {
|
|
6878
7138
|
// Assuming that we redraw all when enableUpdate() is re-enabled.
|
|
6879
7139
|
// this.log(
|
|
@@ -6882,14 +7142,6 @@ class Wunderbaum {
|
|
|
6882
7142
|
this._disableUpdateIgnoreCount++;
|
|
6883
7143
|
return;
|
|
6884
7144
|
}
|
|
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
7145
|
switch (change) {
|
|
6894
7146
|
case ChangeType.any:
|
|
6895
7147
|
case ChangeType.colStructure:
|
|
@@ -7217,10 +7469,14 @@ class Wunderbaum {
|
|
|
7217
7469
|
_updateViewportImmediately() {
|
|
7218
7470
|
var _a;
|
|
7219
7471
|
if (this._disableUpdateCount) {
|
|
7220
|
-
this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount})
|
|
7472
|
+
this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount}).`);
|
|
7221
7473
|
this._disableUpdateIgnoreCount++;
|
|
7222
7474
|
return;
|
|
7223
7475
|
}
|
|
7476
|
+
if (this._updateViewportThrottled.pending()) {
|
|
7477
|
+
// this.logWarn(`_updateViewportImmediately() cancel pending timer.`);
|
|
7478
|
+
this._updateViewportThrottled.cancel();
|
|
7479
|
+
}
|
|
7224
7480
|
// Shorten container height to avoid v-scrollbar
|
|
7225
7481
|
const FIX_ADJUST_HEIGHT = 1;
|
|
7226
7482
|
const RF = RenderFlag;
|
|
@@ -7324,9 +7580,6 @@ class Wunderbaum {
|
|
|
7324
7580
|
}
|
|
7325
7581
|
let endIdx = Math.max(0, (ofs + vp_height) / row_height + prefetch);
|
|
7326
7582
|
endIdx = Math.ceil(endIdx);
|
|
7327
|
-
// const obsoleteViewNodes = this.viewNodes;
|
|
7328
|
-
// this.viewNodes = new Set();
|
|
7329
|
-
// const viewNodes = this.viewNodes;
|
|
7330
7583
|
// this.debug("render", opts);
|
|
7331
7584
|
const obsoleteNodes = new Set();
|
|
7332
7585
|
this.nodeListElement.childNodes.forEach((elem) => {
|
|
@@ -7582,37 +7835,31 @@ class Wunderbaum {
|
|
|
7582
7835
|
* FILTER
|
|
7583
7836
|
* -------------------------------------------------------------------------*/
|
|
7584
7837
|
/**
|
|
7585
|
-
*
|
|
7838
|
+
* Dim or hide nodes.
|
|
7586
7839
|
*/
|
|
7587
7840
|
filterNodes(filter, options) {
|
|
7588
7841
|
return this.extensions.filter.filterNodes(filter, options);
|
|
7589
7842
|
}
|
|
7590
7843
|
/**
|
|
7591
|
-
*
|
|
7844
|
+
* Dim or hide whole branches.
|
|
7592
7845
|
*/
|
|
7593
7846
|
filterBranches(filter, options) {
|
|
7594
7847
|
return this.extensions.filter.filterBranches(filter, options);
|
|
7595
7848
|
}
|
|
7596
7849
|
/**
|
|
7597
|
-
*
|
|
7598
|
-
*
|
|
7599
|
-
* @requires [[FilterExtension]]
|
|
7850
|
+
* Reset the filter.
|
|
7600
7851
|
*/
|
|
7601
7852
|
clearFilter() {
|
|
7602
7853
|
return this.extensions.filter.clearFilter();
|
|
7603
7854
|
}
|
|
7604
7855
|
/**
|
|
7605
|
-
*
|
|
7606
|
-
*
|
|
7607
|
-
* @requires [[FilterExtension]]
|
|
7856
|
+
* Return true if a filter is currently applied.
|
|
7608
7857
|
*/
|
|
7609
7858
|
isFilterActive() {
|
|
7610
7859
|
return !!this.filterMode;
|
|
7611
7860
|
}
|
|
7612
7861
|
/**
|
|
7613
|
-
*
|
|
7614
|
-
*
|
|
7615
|
-
* @requires [[FilterExtension]]
|
|
7862
|
+
* Re-apply current filter.
|
|
7616
7863
|
*/
|
|
7617
7864
|
updateFilter() {
|
|
7618
7865
|
return this.extensions.filter.updateFilter();
|
|
@@ -7620,7 +7867,7 @@ class Wunderbaum {
|
|
|
7620
7867
|
}
|
|
7621
7868
|
Wunderbaum.sequence = 0;
|
|
7622
7869
|
/** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
|
|
7623
|
-
Wunderbaum.version = "v0.
|
|
7870
|
+
Wunderbaum.version = "v0.8.1"; // Set to semver by 'grunt release'
|
|
7624
7871
|
/** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
|
|
7625
7872
|
Wunderbaum.util = util;
|
|
7626
7873
|
|