wunderbaum 0.0.4 → 0.0.5

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/src/util.ts CHANGED
@@ -198,7 +198,7 @@ export function extractHtmlText(s: string) {
198
198
  *
199
199
  * If a `<span class="wb-col">` is passed, the first child input is used.
200
200
  * Depending on the target element type, `value` is interpreted accordingly.
201
- * For example for a checkbox, a value of true, false, or null is returned if the
201
+ * For example for a checkbox, a value of true, false, or null is returned if
202
202
  * the element is checked, unchecked, or indeterminate.
203
203
  * For datetime input control a numerical value is assumed, etc.
204
204
  *
@@ -300,7 +300,9 @@ export function setValueToElem(elem: HTMLElement, value: any): void {
300
300
 
301
301
  switch (type) {
302
302
  case "checkbox":
303
- input.indeterminate = value == null;
303
+ // An explicit `null` value is interpreted as 'indeterminate'.
304
+ // `undefined` is interpreted as 'unchecked'
305
+ input.indeterminate = value === null;
304
306
  input.checked = !!value;
305
307
  break;
306
308
  case "date":
@@ -682,7 +684,7 @@ export function toSet(val: any): Set<string> {
682
684
  throw new Error("Cannot convert to Set<string>: " + val);
683
685
  }
684
686
 
685
- /**Return a canonical string representation for an object's type (e.g. 'array', 'number', ...) */
687
+ /** Return a canonical string representation for an object's type (e.g. 'array', 'number', ...). */
686
688
  export function type(obj: any): string {
687
689
  return Object.prototype.toString
688
690
  .call(obj)
@@ -697,12 +699,12 @@ export function type(obj: any): string {
697
699
  * previous call.
698
700
  * Example:
699
701
  * ```js
700
- * throttledFoo = util.addaptiveThrottle(foo.bind(this), {});
702
+ * throttledFoo = util.adaptiveThrottle(foo.bind(this), {});
701
703
  * throttledFoo();
702
704
  * throttledFoo();
703
705
  * ```
704
706
  */
705
- export function addaptiveThrottle(
707
+ export function adaptiveThrottle(
706
708
  this: unknown,
707
709
  callback: (...args: any[]) => void,
708
710
  options: any
@@ -724,7 +726,7 @@ export function addaptiveThrottle(
724
726
  const throttledFn = (...args: any[]) => {
725
727
  if (waiting) {
726
728
  pendingArgs = args;
727
- // console.log(`addaptiveThrottle() queing request #${waiting}...`, args);
729
+ // console.log(`adaptiveThrottle() queing request #${waiting}...`, args);
728
730
  waiting += 1;
729
731
  } else {
730
732
  // Prevent invocations while running or blocking
@@ -732,7 +734,7 @@ export function addaptiveThrottle(
732
734
  const useArgs = args; // pendingArgs || args;
733
735
  pendingArgs = null;
734
736
 
735
- // console.log(`addaptiveThrottle() execute...`, useArgs);
737
+ // console.log(`adaptiveThrottle() execute...`, useArgs);
736
738
  const start = Date.now();
737
739
  try {
738
740
  callback.apply(this, useArgs);
@@ -747,7 +749,7 @@ export function addaptiveThrottle(
747
749
  );
748
750
  const useDelay = Math.max(minDelay, curDelay - elap);
749
751
  // console.log(
750
- // `addaptiveThrottle() calling worker took ${elap}ms. delay = ${curDelay}ms, using ${useDelay}ms`,
752
+ // `adaptiveThrottle() calling worker took ${elap}ms. delay = ${curDelay}ms, using ${useDelay}ms`,
751
753
  // pendingArgs
752
754
  // );
753
755
  setTimeout(() => {
@@ -757,7 +759,7 @@ export function addaptiveThrottle(
757
759
  if (pendingArgs != null) {
758
760
  // There was another request while running or waiting
759
761
  // console.log(
760
- // `addaptiveThrottle() re-trigger (missed ${skipped})...`,
762
+ // `adaptiveThrottle() re-trigger (missed ${skipped})...`,
761
763
  // pendingArgs
762
764
  // );
763
765
  throttledFn.apply(this, pendingArgs);
package/src/wb_ext_dnd.ts CHANGED
@@ -245,8 +245,9 @@ export class DndExtension extends WunderbaumExtension {
245
245
  const ltn = this.lastTargetNode;
246
246
  this.lastEnterStamp = 0;
247
247
  if (ltn) {
248
- ltn.removeClass(
249
- "wb-drop-target wb-drop-over wb-drop-after wb-drop-before"
248
+ ltn.setClass(
249
+ "wb-drop-target wb-drop-over wb-drop-after wb-drop-before",
250
+ false
250
251
  );
251
252
  this.lastTargetNode = null;
252
253
  }
@@ -295,7 +296,7 @@ export class DndExtension extends WunderbaumExtension {
295
296
  protected autoScroll(event: DragEvent): number {
296
297
  let tree = this.tree,
297
298
  dndOpts = tree.options.dnd!,
298
- sp = tree.scrollContainer,
299
+ sp = tree.scrollContainerElement,
299
300
  sensitivity = dndOpts.scrollSensitivity,
300
301
  speed = dndOpts.scrollSpeed,
301
302
  scrolled = 0;
@@ -352,7 +353,7 @@ export class DndExtension extends WunderbaumExtension {
352
353
  setTimeout(() => {
353
354
  // Decouple this call, so the CSS is applied to the node, but not to
354
355
  // the system generated drag image
355
- srcNode.addClass("wb-drag-source");
356
+ srcNode.setClass("wb-drag-source");
356
357
  }, 0);
357
358
 
358
359
  // --- drag ---
@@ -360,7 +361,7 @@ export class DndExtension extends WunderbaumExtension {
360
361
  // This event occurs very often...
361
362
  // --- dragend ---
362
363
  } else if (e.type === "dragend") {
363
- srcNode.removeClass("wb-drag-source");
364
+ srcNode.setClass("wb-drag-source", false);
364
365
  this.srcNode = null;
365
366
  if (this.lastTargetNode) {
366
367
  this._leaveNode();
@@ -424,7 +425,7 @@ export class DndExtension extends WunderbaumExtension {
424
425
  }
425
426
  this.lastAllowedDropRegions = regionSet;
426
427
  this.lastDropEffect = dt.dropEffect;
427
- targetNode.addClass("wb-drop-target");
428
+ targetNode.setClass("wb-drop-target");
428
429
 
429
430
  e.preventDefault(); // Allow drop (Drop operation is denied by default)
430
431
  return false;
@@ -450,9 +451,9 @@ export class DndExtension extends WunderbaumExtension {
450
451
  if (!region) {
451
452
  return; // We already rejected in dragenter
452
453
  }
453
- targetNode.toggleClass("wb-drop-over", region === "over");
454
- targetNode.toggleClass("wb-drop-before", region === "before");
455
- targetNode.toggleClass("wb-drop-after", region === "after");
454
+ targetNode.setClass("wb-drop-over", region === "over");
455
+ targetNode.setClass("wb-drop-before", region === "before");
456
+ targetNode.setClass("wb-drop-after", region === "after");
456
457
  // console.log("dragover", e);
457
458
 
458
459
  // dt.dropEffect = this.lastDropEffect!;
@@ -63,14 +63,14 @@ export class EditExtension extends WunderbaumExtension {
63
63
 
64
64
  node.log(`_applyChange(${eventName})`, extra);
65
65
 
66
- colElem.classList.add("wb-dirty");
66
+ colElem.classList.add("wb-busy");
67
67
  colElem.classList.remove("wb-error");
68
68
  try {
69
69
  res = node._callEvent(eventName, extra);
70
70
  } catch (err) {
71
71
  node.logError(`Error in ${eventName} event handler`, err);
72
72
  colElem.classList.add("wb-error");
73
- colElem.classList.remove("wb-dirty");
73
+ colElem.classList.remove("wb-busy");
74
74
  }
75
75
  // Convert scalar return value to a resolved promise
76
76
  if (!(res instanceof Promise)) {
@@ -82,7 +82,7 @@ export class EditExtension extends WunderbaumExtension {
82
82
  colElem.classList.add("wb-error");
83
83
  })
84
84
  .finally(() => {
85
- colElem.classList.remove("wb-dirty");
85
+ colElem.classList.remove("wb-busy");
86
86
  });
87
87
  return res;
88
88
  }
@@ -130,15 +130,14 @@ export class EditExtension extends WunderbaumExtension {
130
130
  const eventName = eventToString(event);
131
131
  const tree = this.tree;
132
132
  const trigger = this.getPluginOption("trigger");
133
- const inputElem =
134
- event.target && event.target.closest("input,[contenteditable]");
135
- // let handled = true;
133
+ // const inputElem =
134
+ // event.target && event.target.closest("input,[contenteditable]");
136
135
 
137
136
  tree.logDebug(`_preprocessKeyEvent: ${eventName}`);
138
137
 
139
138
  // --- Title editing: apply/discard ---
140
- if (inputElem) {
141
- //this.isEditingTitle()) {
139
+ // if (inputElem) {
140
+ if (this.isEditingTitle()) {
142
141
  switch (eventName) {
143
142
  case "Enter":
144
143
  this._stopEditTitle(true, { event: event });
@@ -205,7 +204,7 @@ export class EditExtension extends WunderbaumExtension {
205
204
  titleSpan.innerHTML = inputHtml;
206
205
  const inputElem = titleSpan.firstElementChild as HTMLInputElement;
207
206
  if (validity) {
208
- // Permanently apply input validations (CSS and tooltip)
207
+ // Permanently apply input validations (CSS and tooltip)
209
208
  inputElem.addEventListener("keydown", (e) => {
210
209
  inputElem.setCustomValidity("");
211
210
  if (!inputElem.reportValidity()) {
@@ -336,7 +335,7 @@ export class EditExtension extends WunderbaumExtension {
336
335
  return;
337
336
  }
338
337
  const newNode = node.addNode(init, mode);
339
- newNode.addClass("wb-edit-new");
338
+ newNode.setClass("wb-edit-new");
340
339
  this.relatedNode = node;
341
340
 
342
341
  // Don't filter new nodes:
@@ -28,6 +28,7 @@ export class FilterExtension extends WunderbaumExtension {
28
28
 
29
29
  constructor(tree: Wunderbaum) {
30
30
  super(tree, "filter", {
31
+ attachInput: null, // Element or selector of an input control for filter query strings
31
32
  autoApply: true, // Re-apply last filter if lazy data is loaded
32
33
  autoExpand: false, // Expand all branches that contain matches while filtered
33
34
  counter: true, // Show a badge with number of matching child nodes near parent icons
@@ -36,14 +37,14 @@ export class FilterExtension extends WunderbaumExtension {
36
37
  hideExpanders: false, // Hide expanders if all child nodes are hidden by filter
37
38
  highlight: true, // Highlight matches by wrapping inside <mark> tags
38
39
  leavesOnly: false, // Match end nodes only
39
- mode: "hide", // Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
40
+ mode: "dim", // Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
40
41
  noData: true, // Display a 'no data' status node if result is empty
41
42
  });
42
43
  }
43
44
 
44
45
  init() {
45
46
  super.init();
46
- let attachInput = this.getPluginOption("attachInput");
47
+ const attachInput = this.getPluginOption("attachInput");
47
48
  if (attachInput) {
48
49
  this.queryInput = elemFromSelector(attachInput) as HTMLInputElement;
49
50
  onEvent(
@@ -57,6 +58,17 @@ export class FilterExtension extends WunderbaumExtension {
57
58
  }
58
59
  }
59
60
 
61
+ setPluginOption(name: string, value: any): void {
62
+ // alert("filter opt=" + name + ", " + value)
63
+ super.setPluginOption(name, value);
64
+ switch (name) {
65
+ case "mode":
66
+ this.tree.filterMode = value === "hide" ? "hide" : "dim";
67
+ this.tree.updateFilter();
68
+ break;
69
+ }
70
+ }
71
+
60
72
  _applyFilterNoUpdate(
61
73
  filter: string | NodeFilterCallback,
62
74
  branchMode: boolean,
@@ -4,7 +4,11 @@
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
7
- import { NavigationMode, NavigationModeOption } from "./common";
7
+ import {
8
+ // NAVIGATE_IN_INPUT_KEYS,
9
+ NavigationMode,
10
+ NavigationModeOption,
11
+ } from "./common";
8
12
  import { eventToString } from "./util";
9
13
  import { Wunderbaum } from "./wunderbaum";
10
14
  import { WunderbaumNode } from "./wb_node";
@@ -15,18 +19,47 @@ export class KeynavExtension extends WunderbaumExtension {
15
19
  super(tree, "keynav", {});
16
20
  }
17
21
 
22
+ protected _getEmbeddedInputElem(
23
+ elem: any,
24
+ setFocus = false
25
+ ): HTMLInputElement | null {
26
+ let input = null;
27
+
28
+ if (elem && elem.type != null) {
29
+ input = elem;
30
+ } else {
31
+ // ,[contenteditable]
32
+ const ace = this.tree.getActiveColElem()?.querySelector("input,select");
33
+ if (ace) {
34
+ input = ace as HTMLInputElement;
35
+ }
36
+ }
37
+ if (setFocus && input) {
38
+ this.tree.log("focus", input);
39
+ input.focus();
40
+ }
41
+ return input;
42
+ }
43
+
18
44
  onKeyEvent(data: any): boolean | undefined {
19
- let event = data.event,
20
- eventName = eventToString(event),
21
- focusNode,
22
- node = data.node as WunderbaumNode,
45
+ const event = data.event,
23
46
  tree = this.tree,
24
47
  opts = data.options,
25
- handled = true,
26
- activate = !event.ctrlKey || opts.autoActivate;
27
- const navModeOption = opts.navigationMode;
48
+ activate = !event.ctrlKey || opts.autoActivate,
49
+ curInput = this._getEmbeddedInputElem(event.target),
50
+ navModeOption = opts.navigationMode as NavigationModeOption,
51
+ isCellEditMode = tree.navMode === NavigationMode.cellEdit;
28
52
 
29
- tree.logDebug(`onKeyEvent: ${eventName}`);
53
+ let focusNode,
54
+ eventName = eventToString(event),
55
+ node = data.node as WunderbaumNode,
56
+ handled = true;
57
+
58
+ tree.log(`onKeyEvent: ${eventName}, curInput`, curInput);
59
+ if (!tree.isEnabled()) {
60
+ // tree.logDebug(`onKeyEvent ignored for disabled tree: ${eventName}`);
61
+ return false;
62
+ }
30
63
 
31
64
  // Let callback prevent default processing
32
65
  if (tree._callEvent("keydown", data) === false) {
@@ -58,12 +91,15 @@ export class KeynavExtension extends WunderbaumExtension {
58
91
  }
59
92
 
60
93
  if (tree.navMode === NavigationMode.row) {
94
+ // -----------------------------------------------------------------------
95
+ // --- Row Mode ---
96
+ // -----------------------------------------------------------------------
61
97
  // --- Quick-Search
62
98
  if (
63
99
  opts.quicksearch &&
64
100
  eventName.length === 1 &&
65
- /^\w$/.test(eventName)
66
- // && !$target.is(":input:enabled")
101
+ /^\w$/.test(eventName) &&
102
+ !curInput
67
103
  ) {
68
104
  // Allow to search for longer streaks if typed in quickly
69
105
  const stamp = Date.now();
@@ -143,7 +179,17 @@ export class KeynavExtension extends WunderbaumExtension {
143
179
  handled = false;
144
180
  }
145
181
  } else {
146
- // Standard navigation (cell mode)
182
+ // -----------------------------------------------------------------------
183
+ // --- Cell Mode ---
184
+ // -----------------------------------------------------------------------
185
+ // // Standard navigation (cell mode)
186
+ // if (isCellEditMode && NAVIGATE_IN_INPUT_KEYS.has(eventName)) {
187
+ // }
188
+ if (eventName === "Tab") {
189
+ eventName = "ArrowRight";
190
+ } else if (eventName === "Shift+Tab") {
191
+ eventName = tree.activeColIdx > 0 ? "ArrowLeft" : "";
192
+ }
147
193
  switch (eventName) {
148
194
  case " ":
149
195
  if (tree.activeColIdx === 0 && node.getOption("checkbox")) {
@@ -162,13 +208,24 @@ export class KeynavExtension extends WunderbaumExtension {
162
208
  if (tree.activeColIdx === 0 && node.isExpandable()) {
163
209
  node.setExpanded(!node.isExpanded());
164
210
  handled = true;
211
+ } else if (
212
+ !isCellEditMode &&
213
+ (navModeOption === NavigationModeOption.startCell ||
214
+ navModeOption === NavigationModeOption.startRow)
215
+ ) {
216
+ tree.setNavigationMode(NavigationMode.cellEdit);
217
+ this._getEmbeddedInputElem(null, true); // set focus to input
218
+ handled = true;
165
219
  }
166
220
  break;
167
221
  case "Escape":
168
222
  if (tree.navMode === NavigationMode.cellEdit) {
169
223
  tree.setNavigationMode(NavigationMode.cellNav);
170
224
  handled = true;
171
- } else if (tree.navMode === NavigationMode.cellNav) {
225
+ } else if (
226
+ tree.navMode === NavigationMode.cellNav &&
227
+ navModeOption !== NavigationModeOption.cell
228
+ ) {
172
229
  tree.setNavigationMode(NavigationMode.row);
173
230
  handled = true;
174
231
  }
@@ -176,6 +233,9 @@ export class KeynavExtension extends WunderbaumExtension {
176
233
  case "ArrowLeft":
177
234
  if (tree.activeColIdx > 0) {
178
235
  tree.setColumn(tree.activeColIdx - 1);
236
+ if (isCellEditMode) {
237
+ this._getEmbeddedInputElem(null, true); // set focus to input
238
+ }
179
239
  handled = true;
180
240
  } else if (navModeOption !== NavigationModeOption.cell) {
181
241
  tree.setNavigationMode(NavigationMode.row);
@@ -185,6 +245,9 @@ export class KeynavExtension extends WunderbaumExtension {
185
245
  case "ArrowRight":
186
246
  if (tree.activeColIdx < tree.columns.length - 1) {
187
247
  tree.setColumn(tree.activeColIdx + 1);
248
+ if (isCellEditMode) {
249
+ this._getEmbeddedInputElem(null, true); // set focus to input
250
+ }
188
251
  handled = true;
189
252
  }
190
253
  break;
@@ -200,6 +263,10 @@ export class KeynavExtension extends WunderbaumExtension {
200
263
  case "PageDown":
201
264
  case "PageUp":
202
265
  node.navigate(eventName, { activate: activate, event: event });
266
+ if (isCellEditMode) {
267
+ this._getEmbeddedInputElem(null, true); // set focus to input
268
+ }
269
+ handled = true;
203
270
  break;
204
271
  default:
205
272
  handled = false;
package/src/wb_node.ts CHANGED
@@ -50,7 +50,7 @@ const NODE_PROPS = new Set<string>([
50
50
  const NODE_ATTRS = new Set<string>([
51
51
  "checkbox",
52
52
  "expanded",
53
- "extraClasses", // TODO: rename to classes
53
+ "classes",
54
54
  "folder",
55
55
  "icon",
56
56
  "iconTooltip",
@@ -108,8 +108,8 @@ export class WunderbaumNode {
108
108
  public type?: string;
109
109
  public tooltip?: string;
110
110
  /** Additional classes added to `div.wb-row`.
111
- * @see {@link addClass}, {@link removeClass}, {@link toggleClass}. */
112
- public extraClasses = new Set<string>();
111
+ * @see {@link hasClass}, {@link setClass}. */
112
+ public classes: Set<string> | null = null; //new Set<string>();
113
113
  /** Custom data that was passed to the constructor */
114
114
  public data: any = {};
115
115
  // --- Node Status ---
@@ -150,9 +150,7 @@ export class WunderbaumNode {
150
150
  this.lazy = data.lazy === true;
151
151
  this.selected = data.selected === true;
152
152
  if (data.classes) {
153
- for (const c of data.classes.split(" ")) {
154
- this.extraClasses.add(c.trim());
155
- }
153
+ this.setClass(data.classes);
156
154
  }
157
155
  // Store custom fields as `node.data`
158
156
  for (const [key, value] of Object.entries(data)) {
@@ -172,7 +170,7 @@ export class WunderbaumNode {
172
170
  * @internal
173
171
  */
174
172
  toString() {
175
- return "WunderbaumNode@" + this.key + "<'" + this.title + "'>";
173
+ return `WunderbaumNode@${this.key}<'${this.title}'>`;
176
174
  }
177
175
 
178
176
  // /** Return an option value. */
@@ -307,28 +305,39 @@ export class WunderbaumNode {
307
305
  return this.tree.applyCommand(cmd, this, opts);
308
306
  }
309
307
 
310
- addClass(className: string | string[] | Set<string>) {
311
- const cnSet = util.toSet(className);
312
- cnSet.forEach((cn) => {
313
- this.extraClasses.add(cn);
314
- this._rowElem?.classList.add(cn);
315
- });
316
- }
317
-
318
- removeClass(className: string | string[] | Set<string>) {
319
- const cnSet = util.toSet(className);
320
- cnSet.forEach((cn) => {
321
- this.extraClasses.delete(cn);
322
- this._rowElem?.classList.remove(cn);
323
- });
324
- }
325
-
326
- toggleClass(className: string | string[] | Set<string>, flag: boolean) {
308
+ /**
309
+ * Add/remove one or more classes to `<div class='wb-row'>`.
310
+ *
311
+ * This also maintains `node.classes`, so the class will survive a re-render.
312
+ *
313
+ * @param className one or more class names. Multiple classes can be passed
314
+ * as space-separated string, array of strings, or set of strings.
315
+ */
316
+ setClass(
317
+ className: string | string[] | Set<string>,
318
+ flag: boolean = true
319
+ ): void {
327
320
  const cnSet = util.toSet(className);
328
- cnSet.forEach((cn) => {
329
- flag ? this.extraClasses.add(cn) : this.extraClasses.delete(cn);
330
- this._rowElem?.classList.toggle(cn, flag);
331
- });
321
+ if (flag) {
322
+ if (this.classes === null) {
323
+ this.classes = new Set<string>();
324
+ }
325
+ cnSet.forEach((cn) => {
326
+ this.classes!.add(cn);
327
+ this._rowElem?.classList.toggle(cn, flag);
328
+ });
329
+ } else {
330
+ if (this.classes === null) {
331
+ return;
332
+ }
333
+ cnSet.forEach((cn) => {
334
+ this.classes!.delete(cn);
335
+ this._rowElem?.classList.toggle(cn, flag);
336
+ });
337
+ if (this.classes.size === 0) {
338
+ this.classes = null;
339
+ }
340
+ }
332
341
  }
333
342
 
334
343
  /** */
@@ -527,6 +536,11 @@ export class WunderbaumNode {
527
536
  return !!(this.children && this.children.length);
528
537
  }
529
538
 
539
+ /** Return true if node has className set. */
540
+ hasClass(className: string): boolean {
541
+ return this.classes ? this.classes.has(className) : false;
542
+ }
543
+
530
544
  /** Return true if this node is the currently active tree node. */
531
545
  isActive() {
532
546
  return this.tree.activeNode === this;
@@ -705,9 +719,13 @@ export class WunderbaumNode {
705
719
  "If `source` is an object, it must have a `children` property"
706
720
  );
707
721
  if (source.types) {
708
- // TODO: convert types.classes to Set()
709
- util.extend(tree.types, source.types);
722
+ tree.setTypes(source.types, false);
723
+ }
724
+ if (source.columns) {
725
+ tree.columns = source.columns;
726
+ tree.updateColumns({ calculateCols: false });
710
727
  }
728
+
711
729
  this.addChildren(source.children);
712
730
 
713
731
  this._callEvent("load");
@@ -1381,8 +1399,8 @@ export class WunderbaumNode {
1381
1399
  // Replace previous classes:
1382
1400
  rowDiv.className = rowClasses.join(" ");
1383
1401
 
1384
- // Add classes from `node.extraClasses`
1385
- rowDiv.classList.add(...this.extraClasses);
1402
+ // Add classes from `node.classes`
1403
+ this.classes ? rowDiv.classList.add(...this.classes) : 0;
1386
1404
 
1387
1405
  // Add classes from `tree.types[node.type]`
1388
1406
  if (typeInfo && typeInfo.classes) {
@@ -1823,9 +1841,9 @@ export class WunderbaumNode {
1823
1841
  * @param {object} [extra]
1824
1842
  */
1825
1843
  triggerModify(operation: string, extra?: any) {
1826
- if (!this.parent) {
1827
- return;
1828
- }
1844
+ // if (!this.parent) {
1845
+ // return;
1846
+ // }
1829
1847
  this.parent.triggerModifyChild(operation, this, extra);
1830
1848
  }
1831
1849
 
package/src/wb_options.ts CHANGED
@@ -23,6 +23,43 @@ export interface WbNodeData {
23
23
  // ...any?: Any;
24
24
  }
25
25
 
26
+ export interface ColumnDefinition {
27
+ /** Column ID (pass "*" for the main tree nodes column ) */
28
+ id: string;
29
+ /** Column header (defaults to id) */
30
+ title: string;
31
+ /** Column width or weight.
32
+ * Either an absolute pixel value (e.g. `"50px"`) or a relative weight (e.g. `1`)
33
+ * that is used to calculate the width inside the remaining available space.
34
+ * Default: `"*"`, which is interpreted as `1`.
35
+ */
36
+ width?: string | number;
37
+ /** Only used for columns with a relative weight.
38
+ * Default: `4px`.
39
+ */
40
+ minWidth?: string | number;
41
+ /** Optional class names that are added to all `span.wb-col` elements of that column.*/
42
+ classes?: string;
43
+ /** Optional HTML content that is rendered into all `span.wb-col` elements of that column.*/
44
+ html: string;
45
+ }
46
+
47
+ export interface TypeDefinition {
48
+ // /** Type ID that matches `node.type`. */
49
+ // id: string;
50
+ /** En/disable checkbox for matching nodes.*/
51
+ checkbox?: boolean | BoolOptionResolver;
52
+ /** Optional class names that are added to all `div.wb-row` elements of matching nodes.*/
53
+ classes?: string;
54
+ /**Default icon for matching nodes.*/
55
+ icon?: boolean | string | BoolOptionResolver;
56
+ /**
57
+ * See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
58
+ * to evaluate `node.NAME` setting and `tree.types[node.type].NAME`.
59
+ */
60
+ _any: any;
61
+ }
62
+
26
63
  /**
27
64
  * Available options for [[Wunderbaum]].
28
65
  *
@@ -79,7 +116,7 @@ export interface WunderbaumOptions {
79
116
  *
80
117
  * Default: `{}`.
81
118
  */
82
- types?: any; //[key: string]: any;
119
+ types?: { [key: string]: TypeDefinition };
83
120
  /**
84
121
  * A list of maps that define column headers. If this option is set,
85
122
  * Wunderbaum becomes a treegrid control instead of a plain tree.
@@ -87,7 +124,7 @@ export interface WunderbaumOptions {
87
124
  * response.
88
125
  * Default: `[]` meaning this is a plain tree.
89
126
  */
90
- columns?: Array<any>;
127
+ columns?: Array<ColumnDefinition>;
91
128
  /**
92
129
  * If true, add a `wb-skeleton` class to all nodes, that will result in a
93
130
  * 'glow' effect. Typically used with initial dummy nodes, while loading the
@@ -106,7 +143,7 @@ export interface WunderbaumOptions {
106
143
  debugLevel: number;
107
144
  /**
108
145
  * Number of levels that are forced to be expanded, and have no expander icon.
109
- * Default: 0
146
+ * Default: 0
110
147
  */
111
148
  minExpandLevel?: number;
112
149
  // escapeTitles: boolean;
@@ -125,6 +162,11 @@ export interface WunderbaumOptions {
125
162
  * Default: false
126
163
  */
127
164
  autoCollapse?: boolean;
165
+ /**
166
+ * HTMLElement that receives the top nodes breadcrumb.
167
+ * Default: undefined
168
+ */
169
+ attachBreadcrumb?: HTMLElement;
128
170
  /**
129
171
  * Default: NavigationModeOption.startRow
130
172
  */
@@ -145,17 +187,29 @@ export interface WunderbaumOptions {
145
187
  * Default: 200
146
188
  */
147
189
  updateThrottleWait?: number;
190
+ /**
191
+ * Default: true
192
+ */
193
+ enabled?: boolean;
194
+ /**
195
+ * Default: false
196
+ */
197
+ fixedCol?: boolean;
198
+
148
199
  // --- KeyNav ---
149
200
  /**
150
201
  * Default: true
151
202
  */
152
203
  quicksearch?: boolean;
153
204
 
154
- // --- Extensions ---
205
+ // --- Extensions ------------------------------------------------------------
155
206
  dnd?: DndOptionsType; // = {};
207
+ edit: any; // = {};
156
208
  filter: any; // = {};
157
209
  grid: any; // = {};
158
- // --- Events ---
210
+
211
+ // --- Events ----------------------------------------------------------------
212
+
159
213
  /**
160
214
  *
161
215
  * @category Callback