wunderbaum 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/dist/wunderbaum.css +4 -1
- package/dist/wunderbaum.css.map +1 -1
- package/dist/wunderbaum.d.ts +365 -224
- package/dist/wunderbaum.esm.js +796 -557
- package/dist/wunderbaum.esm.min.js +29 -29
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +7785 -7546
- 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 +108 -43
- package/src/deferred.ts +9 -9
- package/src/types.ts +123 -37
- package/src/util.ts +73 -33
- package/src/wb_ext_dnd.ts +3 -1
- package/src/wb_ext_edit.ts +90 -58
- package/src/wb_ext_filter.ts +5 -1
- package/src/wb_ext_keynav.ts +20 -9
- package/src/wb_node.ts +83 -33
- package/src/wb_options.ts +1 -1
- package/src/wunderbaum.scss +7 -1
- package/src/wunderbaum.ts +114 -55
package/src/common.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { MatcherCallback } from "./types";
|
|
7
|
+
import { MatcherCallback, SourceListType, SourceObjectType } from "./types";
|
|
8
8
|
import * as util from "./util";
|
|
9
9
|
import { WunderbaumNode } from "./wb_node";
|
|
10
10
|
|
|
@@ -101,9 +101,10 @@ export const INPUT_KEYS: { [key: string]: Array<string> } = {
|
|
|
101
101
|
/** Dict keys that are evaluated by source loader (others are added to `tree.data` instead). */
|
|
102
102
|
export const RESERVED_TREE_SOURCE_KEYS: Set<string> = new Set([
|
|
103
103
|
"_format", // reserved for future use
|
|
104
|
-
"_keyMap", //
|
|
105
|
-
"_positional", //
|
|
106
|
-
"_typeList", //
|
|
104
|
+
"_keyMap", // Used for compressed data format
|
|
105
|
+
"_positional", // Used for compressed data format
|
|
106
|
+
"_typeList", // Used for compressed data format @deprecated
|
|
107
|
+
"_valueMap", // Used for compressed data format
|
|
107
108
|
"_version", // reserved for future use
|
|
108
109
|
"children",
|
|
109
110
|
"columns",
|
|
@@ -146,7 +147,7 @@ export const KEY_TO_ACTION_DICT: { [key: string]: string } = {
|
|
|
146
147
|
|
|
147
148
|
/** Return a callback that returns true if the node title matches the string
|
|
148
149
|
* or regular expression.
|
|
149
|
-
* @see {@link WunderbaumNode.findAll}
|
|
150
|
+
* @see {@link WunderbaumNode.findAll()}
|
|
150
151
|
*/
|
|
151
152
|
export function makeNodeTitleMatcher(match: string | RegExp): MatcherCallback {
|
|
152
153
|
if (match instanceof RegExp) {
|
|
@@ -184,8 +185,20 @@ export function nodeTitleSorter(a: WunderbaumNode, b: WunderbaumNode): number {
|
|
|
184
185
|
return x === y ? 0 : x > y ? 1 : -1;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Convert 'flat' to 'nested' format.
|
|
190
|
+
*
|
|
191
|
+
* Flat node entry format:
|
|
192
|
+
* [PARENT_ID, [POSITIONAL_ARGS]]
|
|
193
|
+
* or
|
|
194
|
+
* [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}]
|
|
195
|
+
*
|
|
196
|
+
* 1. Parent-referencing list is converted to a list of nested dicts with
|
|
197
|
+
* optional `children` properties.
|
|
198
|
+
* 2. `[POSITIONAL_ARGS]` are added as dict attributes.
|
|
199
|
+
*/
|
|
200
|
+
function unflattenSource(source: SourceObjectType): void {
|
|
201
|
+
const { _format, _keyMap = {}, _positional = [], children } = source;
|
|
189
202
|
|
|
190
203
|
if (_format !== "flat") {
|
|
191
204
|
throw new Error(`Expected source._format: "flat", but got ${_format}`);
|
|
@@ -195,31 +208,35 @@ function unflattenSource(source: any): void {
|
|
|
195
208
|
`source._positional must not include "children": ${_positional}`
|
|
196
209
|
);
|
|
197
210
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
let longToShort = _keyMap;
|
|
212
|
+
if (_keyMap.t) {
|
|
213
|
+
// Inverse keyMap was used (pre 0.7.0)
|
|
214
|
+
// TODO: raise Error on final 1.x release
|
|
215
|
+
const msg = `source._keyMap maps from long to short since v0.7.0. Flip key/value!`;
|
|
216
|
+
console.warn(msg); // eslint-disable-line no-console
|
|
217
|
+
longToShort = {};
|
|
201
218
|
for (const [key, value] of Object.entries(_keyMap)) {
|
|
202
|
-
longToShort[
|
|
219
|
+
longToShort[value] = key;
|
|
203
220
|
}
|
|
204
221
|
}
|
|
205
222
|
const positionalShort = _positional.map((e: string) => longToShort[e]);
|
|
206
|
-
const newChildren:
|
|
223
|
+
const newChildren: SourceListType = [];
|
|
207
224
|
const keyToNodeMap: { [key: string]: number } = {};
|
|
208
225
|
const indexToNodeMap: { [key: number]: any } = {};
|
|
209
226
|
const keyAttrName = longToShort["key"] ?? "key";
|
|
210
227
|
const childrenAttrName = longToShort["children"] ?? "children";
|
|
211
228
|
|
|
212
|
-
for (const [index,
|
|
229
|
+
for (const [index, nodeTuple] of children.entries()) {
|
|
213
230
|
// Node entry format:
|
|
214
231
|
// [PARENT_ID, [POSITIONAL_ARGS]]
|
|
215
232
|
// or
|
|
216
233
|
// [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}]
|
|
217
|
-
const [parentId, args, kwargs = {}] =
|
|
234
|
+
const [parentId, args, kwargs = {}] = <any>nodeTuple;
|
|
218
235
|
|
|
219
236
|
// Free up some memory as we go
|
|
220
|
-
|
|
221
|
-
if (
|
|
222
|
-
|
|
237
|
+
nodeTuple[1] = null;
|
|
238
|
+
if (nodeTuple[2] != null) {
|
|
239
|
+
nodeTuple[2] = null;
|
|
223
240
|
}
|
|
224
241
|
// console.log("flatten", parentId, args, kwargs)
|
|
225
242
|
|
|
@@ -262,13 +279,52 @@ function unflattenSource(source: any): void {
|
|
|
262
279
|
newChildren.push(kwargs);
|
|
263
280
|
}
|
|
264
281
|
}
|
|
265
|
-
|
|
266
|
-
delete source.children;
|
|
267
282
|
source.children = newChildren;
|
|
268
283
|
}
|
|
269
284
|
|
|
270
|
-
|
|
271
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Decompresses the source data by
|
|
287
|
+
* - converting from 'flat' to 'nested' format
|
|
288
|
+
* - expanding short alias names to long names (if defined in _keyMap)
|
|
289
|
+
* - resolving value indexes to value strings (if defined in _valueMap)
|
|
290
|
+
*
|
|
291
|
+
* @param source - The source object to be decompressed.
|
|
292
|
+
* @returns void
|
|
293
|
+
*/
|
|
294
|
+
export function decompressSourceData(source: SourceObjectType): void {
|
|
295
|
+
let { _format, _version = 1, _keyMap, _valueMap } = source;
|
|
296
|
+
|
|
297
|
+
util.assert(_version === 1, `Expected file version 1 instead of ${_version}`);
|
|
298
|
+
|
|
299
|
+
let longToShort = _keyMap;
|
|
300
|
+
let shortToLong: { [key: string]: string } = {};
|
|
301
|
+
|
|
302
|
+
if (longToShort) {
|
|
303
|
+
for (const [key, value] of Object.entries(longToShort)) {
|
|
304
|
+
shortToLong[value] = key;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Fallback for old format (pre 0.7.0, using _keyMap in reverse direction)
|
|
309
|
+
// TODO: raise Error on final 1.x release
|
|
310
|
+
if (longToShort && longToShort.t) {
|
|
311
|
+
const msg = `source._keyMap maps from long to short since v0.7.0. Flip key/value!`;
|
|
312
|
+
console.warn(msg); // eslint-disable-line no-console
|
|
313
|
+
[longToShort, shortToLong] = [shortToLong, longToShort];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Fallback for old format (pre 0.7.0, using _typeList instead of _valueMap)
|
|
317
|
+
// TODO: raise Error on final 1.x release
|
|
318
|
+
if ((<any>source)._typeList != null) {
|
|
319
|
+
const msg = `source._typeList is deprecated since v0.7.0: use source._valueMap: {"type": [...]} instead.`;
|
|
320
|
+
if (_valueMap != null) {
|
|
321
|
+
throw new Error(msg);
|
|
322
|
+
} else {
|
|
323
|
+
console.warn(msg); // eslint-disable-line no-console
|
|
324
|
+
_valueMap = { type: (<any>source)._typeList };
|
|
325
|
+
delete (<any>source)._typeList;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
272
328
|
|
|
273
329
|
if (_format === "flat") {
|
|
274
330
|
unflattenSource(source);
|
|
@@ -276,33 +332,40 @@ export function inflateSourceData(source: any): void {
|
|
|
276
332
|
delete source._format;
|
|
277
333
|
delete source._version;
|
|
278
334
|
delete source._keyMap;
|
|
279
|
-
delete source.
|
|
335
|
+
delete source._valueMap;
|
|
280
336
|
delete source._positional;
|
|
281
337
|
|
|
282
|
-
function _iter(childList:
|
|
338
|
+
function _iter(childList: SourceListType) {
|
|
283
339
|
for (const node of childList) {
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
340
|
+
// Iterate over a list of names, because we modify inside the loop
|
|
341
|
+
// (for ... of ... does not allow this)
|
|
342
|
+
Object.getOwnPropertyNames(node).forEach((propName) => {
|
|
343
|
+
const value: any = node[propName];
|
|
344
|
+
|
|
345
|
+
// Replace short names with long names if defined in _keyMap
|
|
346
|
+
let longName = propName;
|
|
347
|
+
if (_keyMap && shortToLong[propName] != null) {
|
|
348
|
+
longName = shortToLong[propName];
|
|
349
|
+
if (longName !== propName) {
|
|
350
|
+
node[longName] = value;
|
|
291
351
|
delete node[propName];
|
|
292
352
|
}
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
// `node` now has long attribute names
|
|
296
|
-
|
|
297
|
-
// Resolve node type indexes
|
|
298
|
-
const type = node.type;
|
|
299
|
-
if (_typeList && type != null && typeof type === "number") {
|
|
300
|
-
const newType = _typeList[type];
|
|
301
|
-
if (newType == null) {
|
|
302
|
-
throw new Error(`Expected typeList[${type}] entry in [${_typeList}]`);
|
|
303
353
|
}
|
|
304
|
-
|
|
305
|
-
|
|
354
|
+
// Replace type index with type name if defined in _valueMap
|
|
355
|
+
if (
|
|
356
|
+
_valueMap &&
|
|
357
|
+
typeof value === "number" &&
|
|
358
|
+
_valueMap[longName] != null
|
|
359
|
+
) {
|
|
360
|
+
const newValue = _valueMap[longName][value];
|
|
361
|
+
if (newValue == null) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`Expected valueMap[${longName}][${value}] entry in [${_valueMap[longName]}]`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
node[longName] = newValue;
|
|
367
|
+
}
|
|
368
|
+
});
|
|
306
369
|
|
|
307
370
|
// Recursion
|
|
308
371
|
if (node.children) {
|
|
@@ -310,5 +373,7 @@ export function inflateSourceData(source: any): void {
|
|
|
310
373
|
}
|
|
311
374
|
}
|
|
312
375
|
}
|
|
313
|
-
|
|
376
|
+
if (_keyMap || _valueMap) {
|
|
377
|
+
_iter(source.children);
|
|
378
|
+
}
|
|
314
379
|
}
|
package/src/deferred.ts
CHANGED
|
@@ -22,38 +22,38 @@ type finallyCallbackType = () => void;
|
|
|
22
22
|
* }
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
export class Deferred {
|
|
26
|
-
private _promise: Promise<
|
|
25
|
+
export class Deferred<T> {
|
|
26
|
+
private _promise: Promise<T>;
|
|
27
27
|
protected _resolve: any;
|
|
28
28
|
protected _reject: any;
|
|
29
29
|
|
|
30
30
|
constructor() {
|
|
31
|
-
this._promise = new Promise((resolve, reject) => {
|
|
31
|
+
this._promise = new Promise<T>((resolve, reject) => {
|
|
32
32
|
this._resolve = resolve;
|
|
33
33
|
this._reject = reject;
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
-
/** Resolve the
|
|
36
|
+
/** Resolve the Promise. */
|
|
37
37
|
resolve(value?: any) {
|
|
38
38
|
this._resolve(value);
|
|
39
39
|
}
|
|
40
|
-
/** Reject the
|
|
40
|
+
/** Reject the Promise. */
|
|
41
41
|
reject(reason?: any) {
|
|
42
42
|
this._reject(reason);
|
|
43
43
|
}
|
|
44
|
-
/** Return the native
|
|
44
|
+
/** Return the native Promise instance.*/
|
|
45
45
|
promise() {
|
|
46
46
|
return this._promise;
|
|
47
47
|
}
|
|
48
|
-
/** Call
|
|
48
|
+
/** Call Promise.then on the embedded promise instance.*/
|
|
49
49
|
then(cb: PromiseCallbackType) {
|
|
50
50
|
return this._promise.then(cb);
|
|
51
51
|
}
|
|
52
|
-
/** Call
|
|
52
|
+
/** Call Promise.catch on the embedded promise instance.*/
|
|
53
53
|
catch(cb: PromiseCallbackType) {
|
|
54
54
|
return this._promise.catch(cb);
|
|
55
55
|
}
|
|
56
|
-
/** Call
|
|
56
|
+
/** Call Promise.finally on the embedded promise instance.*/
|
|
57
57
|
finally(cb: finallyCallbackType) {
|
|
58
58
|
return this._promise.finally(cb);
|
|
59
59
|
}
|
package/src/types.ts
CHANGED
|
@@ -33,12 +33,14 @@ export interface SourceAjaxType {
|
|
|
33
33
|
export type SourceListType = Array<WbNodeData>;
|
|
34
34
|
export interface SourceObjectType {
|
|
35
35
|
_format?: "nested" | "flat";
|
|
36
|
+
_version?: number;
|
|
36
37
|
types?: NodeTypeDefinitionMap;
|
|
37
38
|
columns?: ColumnDefinitionList;
|
|
38
39
|
children: SourceListType;
|
|
39
40
|
_keyMap?: { [key: string]: string };
|
|
40
|
-
_typeList?: Array<string>;
|
|
41
41
|
_positional?: Array<string>;
|
|
42
|
+
// _typeList?: Array<string>;
|
|
43
|
+
_valueMap?: { [key: string]: Array<string> };
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
/** Possible initilization for tree nodes. */
|
|
@@ -153,32 +155,67 @@ export interface WbActivateEventType extends WbNodeEventType {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
export interface WbChangeEventType extends WbNodeEventType {
|
|
158
|
+
/** Additional information derived from the original change event. */
|
|
156
159
|
info: WbEventInfo;
|
|
157
|
-
|
|
160
|
+
/** The embedded element that fired the change event. */
|
|
161
|
+
inputElem: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
162
|
+
/** The new value of the embedded element, depending on the input element type. */
|
|
158
163
|
inputValue: any;
|
|
164
|
+
/** Result of `inputElem.checkValidity()`. */
|
|
165
|
+
inputValid: boolean;
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
export interface WbClickEventType extends WbTreeEventType {
|
|
162
169
|
/** The original event. */
|
|
163
170
|
event: MouseEvent;
|
|
171
|
+
/** The clicked node if any. */
|
|
164
172
|
node: WunderbaumNode;
|
|
173
|
+
/** Additional information derived from the original mouse event. */
|
|
165
174
|
info: WbEventInfo;
|
|
166
175
|
}
|
|
167
176
|
|
|
168
|
-
export interface WbErrorEventType extends WbNodeEventType {
|
|
169
|
-
error: any;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
177
|
export interface WbDeactivateEventType extends WbNodeEventType {
|
|
173
178
|
nextNode: WunderbaumNode;
|
|
174
179
|
/** The original event. */
|
|
175
180
|
event: Event;
|
|
176
181
|
}
|
|
177
182
|
|
|
183
|
+
export interface WbEditApplyEventType extends WbNodeEventType {
|
|
184
|
+
/** Additional information derived from the original change event. */
|
|
185
|
+
info: WbEventInfo;
|
|
186
|
+
/** The input element of the node title that fired the change event. */
|
|
187
|
+
inputElem: HTMLInputElement;
|
|
188
|
+
/** The previous node title. */
|
|
189
|
+
oldValue: string;
|
|
190
|
+
/** The new node title. */
|
|
191
|
+
newValue: string;
|
|
192
|
+
/** Result of `inputElem.checkValidity()`. */
|
|
193
|
+
inputValid: boolean;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface WbEditEditEventType extends WbNodeEventType {
|
|
197
|
+
/** The input element of the node title that was just created. */
|
|
198
|
+
inputElem: HTMLInputElement;
|
|
199
|
+
}
|
|
200
|
+
|
|
178
201
|
// export interface WbEnhanceTitleEventType extends WbNodeEventType {
|
|
179
202
|
// titleSpan: HTMLSpanElement;
|
|
180
203
|
// }
|
|
181
204
|
|
|
205
|
+
export interface WbErrorEventType extends WbNodeEventType {
|
|
206
|
+
error: any;
|
|
207
|
+
}
|
|
208
|
+
export interface WbExpandEventType extends WbNodeEventType {
|
|
209
|
+
flag: boolean;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface WbFocusEventType extends WbTreeEventType {
|
|
213
|
+
/** The original event. */
|
|
214
|
+
event: FocusEvent;
|
|
215
|
+
/** True if `focusin`, false if `focusout`. */
|
|
216
|
+
flag: boolean;
|
|
217
|
+
}
|
|
218
|
+
|
|
182
219
|
export interface WbIconBadgeEventType extends WbNodeEventType {
|
|
183
220
|
iconSpan: HTMLElement;
|
|
184
221
|
}
|
|
@@ -191,33 +228,32 @@ export interface WbIconBadgeEventResultType {
|
|
|
191
228
|
badgeTooltip?: string;
|
|
192
229
|
}
|
|
193
230
|
|
|
194
|
-
export interface
|
|
195
|
-
|
|
196
|
-
event: FocusEvent;
|
|
197
|
-
/** True if `focusin`, false if `focusout`. */
|
|
198
|
-
flag: boolean;
|
|
231
|
+
export interface WbInitEventType extends WbTreeEventType {
|
|
232
|
+
error?: any;
|
|
199
233
|
}
|
|
200
234
|
|
|
201
235
|
export interface WbKeydownEventType extends WbTreeEventType {
|
|
202
236
|
/** The original event. */
|
|
203
237
|
event: KeyboardEvent;
|
|
204
238
|
node: WunderbaumNode;
|
|
239
|
+
/** Additional information derived from the original keyboard event. */
|
|
205
240
|
info: WbEventInfo;
|
|
206
241
|
}
|
|
207
242
|
|
|
208
|
-
export interface WbInitEventType extends WbTreeEventType {
|
|
209
|
-
error?: any;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
243
|
export interface WbReceiveEventType extends WbNodeEventType {
|
|
213
244
|
response: any;
|
|
214
245
|
}
|
|
246
|
+
export interface WbSelectEventType extends WbNodeEventType {
|
|
247
|
+
flag: boolean;
|
|
248
|
+
}
|
|
215
249
|
|
|
216
250
|
export interface WbRenderEventType extends WbNodeEventType {
|
|
217
251
|
/**
|
|
218
252
|
* True if the node's markup was not yet created. In this case the render
|
|
219
253
|
* event should create embedded input controls (in addition to update the
|
|
220
|
-
* values according to to current node data).
|
|
254
|
+
* values according to to current node data). <br>
|
|
255
|
+
* False if the node's markup was already created. In this case the render
|
|
256
|
+
* event should only update the values according to to current node data.
|
|
221
257
|
*/
|
|
222
258
|
isNew: boolean;
|
|
223
259
|
/** The node's `<span class='wb-node'>` element. */
|
|
@@ -231,9 +267,20 @@ export interface WbRenderEventType extends WbNodeEventType {
|
|
|
231
267
|
*/
|
|
232
268
|
allColInfosById: ColumnEventInfoMap;
|
|
233
269
|
/**
|
|
234
|
-
* Array of node's `<span class='wb-node'>` elements,
|
|
270
|
+
* Array of node's `<span class='wb-node'>` elements,
|
|
271
|
+
* *that should be rendered by the event handler*.
|
|
235
272
|
* In contrast to `allColInfosById`, the node title is not part of this array.
|
|
236
273
|
* If node.isColspan() is true, this array is empty (`[]`).
|
|
274
|
+
* This allows to iterate over all relevant in a simple loop:
|
|
275
|
+
* ```
|
|
276
|
+
* for (const col of Object.values(e.renderColInfosById)) {
|
|
277
|
+
* switch (col.id) {
|
|
278
|
+
* default:
|
|
279
|
+
* // Assumption: we named column.id === node.data.NAME
|
|
280
|
+
* col.elem.textContent = node.data[col.id];
|
|
281
|
+
* break;
|
|
282
|
+
* }
|
|
283
|
+
* }
|
|
237
284
|
*/
|
|
238
285
|
renderColInfosById: ColumnEventInfoMap;
|
|
239
286
|
}
|
|
@@ -290,15 +337,17 @@ export interface ColumnDefinition {
|
|
|
290
337
|
* elements of that column.
|
|
291
338
|
*/
|
|
292
339
|
classes?: string;
|
|
293
|
-
/** If `headerClasses` is a
|
|
294
|
-
*
|
|
340
|
+
/** If `headerClasses` is a set, it will be used for the header element only
|
|
341
|
+
* (unlike `classes`, which is used for body and header cells).
|
|
295
342
|
*/
|
|
296
343
|
headerClasses?: string;
|
|
297
344
|
/** Optional HTML content that is rendered into all `span.wb-col` elements of that column.*/
|
|
298
345
|
html?: string;
|
|
299
|
-
|
|
346
|
+
/** @internal */
|
|
300
347
|
_weight?: number;
|
|
348
|
+
/** @internal */
|
|
301
349
|
_widthPx?: number;
|
|
350
|
+
/** @internal */
|
|
302
351
|
_ofsPx?: number;
|
|
303
352
|
// ... and more
|
|
304
353
|
[key: string]: unknown;
|
|
@@ -323,7 +372,7 @@ export interface ColumnEventInfo {
|
|
|
323
372
|
export type ColumnEventInfoMap = { [colId: string]: ColumnEventInfo };
|
|
324
373
|
|
|
325
374
|
/**
|
|
326
|
-
* Additional
|
|
375
|
+
* Additional information derived from mouse or keyboard events.
|
|
327
376
|
* @see {@link Wunderbaum.getEventInfo}
|
|
328
377
|
*/
|
|
329
378
|
export interface WbEventInfo {
|
|
@@ -540,23 +589,43 @@ export interface ScrollToOptions extends ScrollIntoViewOptions {
|
|
|
540
589
|
node: WunderbaumNode;
|
|
541
590
|
}
|
|
542
591
|
|
|
543
|
-
/** Possible values for {@link WunderbaumNode.setActive
|
|
592
|
+
/** Possible values for {@link WunderbaumNode.setActive} `options` argument. */
|
|
544
593
|
export interface SetActiveOptions {
|
|
545
|
-
/** Generate (de)activate event, even if node already has this status (default: false). */
|
|
594
|
+
/** Generate (de)activate event, even if node already has this status (@default: false). */
|
|
546
595
|
retrigger?: boolean;
|
|
547
|
-
/** Do not generate (de)activate event (default: false). */
|
|
596
|
+
/** Do not generate (de)activate event (@default: false). */
|
|
548
597
|
noEvents?: boolean;
|
|
549
|
-
/**
|
|
550
|
-
|
|
551
|
-
|
|
598
|
+
// /** Mark node as focused node (default: true).
|
|
599
|
+
// * Combine with `focusTree: true` to set keyboard focus to tree container.
|
|
600
|
+
// */
|
|
601
|
+
// focusNode?: boolean;
|
|
602
|
+
/** Call `tree.setFocus()` to acquire keyboard focus (@default: false). */
|
|
552
603
|
focusTree?: boolean;
|
|
553
604
|
/** Optional original event that will be passed to the (de)activate handler. */
|
|
554
605
|
event?: Event;
|
|
555
|
-
/**
|
|
556
|
-
colIdx?: number;
|
|
606
|
+
/** Also call {@link Wunderbaum.setColumn()}. */
|
|
607
|
+
colIdx?: number | string;
|
|
608
|
+
/**
|
|
609
|
+
* Focus embedded input control of the grid cell if any (requires colIdx >= 0).
|
|
610
|
+
* If colIdx is 0 or '*', the node title is put into edit mode.
|
|
611
|
+
* Implies `focusTree: true`, requires `colIdx`.
|
|
612
|
+
*/
|
|
613
|
+
edit?: boolean;
|
|
557
614
|
}
|
|
558
615
|
|
|
559
|
-
/** Possible values for {@link WunderbaumNode.
|
|
616
|
+
/** Possible values for {@link WunderbaumNode.setColumn()} `options` argument. */
|
|
617
|
+
export interface SetColumnOptions {
|
|
618
|
+
/**
|
|
619
|
+
* Focus embedded input control of the grid cell if any .
|
|
620
|
+
* If colIdx is 0 or '*', the node title is put into edit mode.
|
|
621
|
+
* @default false
|
|
622
|
+
*/
|
|
623
|
+
edit?: boolean;
|
|
624
|
+
/** Horizontically scroll into view. @default: true */
|
|
625
|
+
scrollIntoView?: boolean;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** Possible values for {@link WunderbaumNode.setExpanded} `options` argument. */
|
|
560
629
|
export interface SetExpandedOptions {
|
|
561
630
|
/** Ignore {@link WunderbaumOptions.minExpandLevel}. @default false */
|
|
562
631
|
force?: boolean;
|
|
@@ -665,53 +734,70 @@ export type FilterOptionsType = {
|
|
|
665
734
|
* Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
|
|
666
735
|
* @default 'dim'
|
|
667
736
|
*/
|
|
668
|
-
mode?:
|
|
737
|
+
mode?: FilterModeType;
|
|
669
738
|
/**
|
|
670
|
-
* Display a 'no data' status node if result is empty
|
|
739
|
+
* Display a 'no data' status node if result is empty (hide-mode only).
|
|
740
|
+
* Pass false to simply show an empy pane, or pass a string to customize the message.
|
|
671
741
|
* @default true
|
|
672
742
|
*/
|
|
673
|
-
noData?: boolean;
|
|
743
|
+
noData?: boolean | string;
|
|
674
744
|
};
|
|
675
745
|
|
|
746
|
+
/**
|
|
747
|
+
* Note: <br>
|
|
748
|
+
* This options are used for renaming node titles. <br>
|
|
749
|
+
* There is also the `tree.change` event to handle modifying node data from
|
|
750
|
+
* input controls that are embedded in grid cells.
|
|
751
|
+
*/
|
|
676
752
|
export type EditOptionsType = {
|
|
677
753
|
/**
|
|
754
|
+
* Used to debounce the `change` event handler for grid cells [ms].
|
|
678
755
|
* @default 100
|
|
679
756
|
*/
|
|
680
757
|
debounce?: number;
|
|
681
758
|
/**
|
|
759
|
+
* Minimum number of characters required for node title input field.
|
|
682
760
|
* @default 1
|
|
683
761
|
*/
|
|
684
762
|
minlength?: number;
|
|
685
763
|
/**
|
|
764
|
+
* Maximum number of characters allowed for node title input field.
|
|
686
765
|
* @default null;
|
|
687
766
|
*/
|
|
688
767
|
maxlength?: null | number;
|
|
689
768
|
/**
|
|
690
|
-
*
|
|
769
|
+
* Array of strings to determine which user input should trigger edit mode.
|
|
770
|
+
* E.g. `["clickActive", "F2", "macEnter"]`: <br>
|
|
771
|
+
* 'clickActive': single click on active node title <br>
|
|
772
|
+
* 'F2': press F2 key <br>
|
|
773
|
+
* 'macEnter': press Enter (on macOS only) <br>
|
|
774
|
+
* Pass an empty array to disable edit mode.
|
|
691
775
|
* @default []
|
|
692
776
|
*/
|
|
693
777
|
trigger?: string[];
|
|
694
778
|
/**
|
|
779
|
+
* Trim whitespace before saving a node title.
|
|
695
780
|
* @default true
|
|
696
781
|
*/
|
|
697
782
|
trim?: boolean;
|
|
698
783
|
/**
|
|
784
|
+
* Select all text of a node title, so it can be overwritten by typing.
|
|
699
785
|
* @default true
|
|
700
786
|
*/
|
|
701
787
|
select?: boolean;
|
|
702
788
|
/**
|
|
703
|
-
* Handle 'clickActive' only if last click is less than this old (0: always)
|
|
789
|
+
* Handle 'clickActive' only if last click is less than this ms old (0: always)
|
|
704
790
|
* @default 1000
|
|
705
791
|
*/
|
|
706
792
|
slowClickDelay?: number;
|
|
707
793
|
/**
|
|
708
|
-
*
|
|
794
|
+
* Permanently apply node title input validations (CSS and tooltip) on keydown.
|
|
709
795
|
* @default true
|
|
710
796
|
*/
|
|
711
797
|
validity?: boolean;
|
|
712
798
|
|
|
713
799
|
// --- Events ---
|
|
714
|
-
|
|
800
|
+
|
|
715
801
|
/**
|
|
716
802
|
* `beforeEdit(e)` may return an input HTML string. Otherwise use a default.
|
|
717
803
|
*/
|