wunderbaum 0.12.0 → 0.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wunderbaum",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "title": "A treegrid control.",
5
5
  "description": "JavaScript tree/grid/treegrid control.",
6
6
  "homepage": "https://github.com/mar10/wunderbaum",
@@ -47,40 +47,42 @@
47
47
  "control"
48
48
  ],
49
49
  "devDependencies": {
50
- "@rollup/plugin-replace": "^5.0.2",
51
- "@rollup/plugin-terser": "^0.4.3",
52
- "@rollup/plugin-typescript": "^11.1.1",
53
- "@types/jest": "^29.5.2",
54
- "@typescript-eslint/eslint-plugin": "^6.7.5",
55
- "@typescript-eslint/parser": "^6.7.5",
56
- "concurrently": "^8.1.0",
57
- "eslint": "^8.51.0",
58
- "eslint-config-jquery": "^3.0.0",
59
- "eslint-config-prettier": "^8.8.0",
60
- "eslint-plugin-prettier": "^4.2.1",
50
+ "@eslint/eslintrc": "^3.2.0",
51
+ "@eslint/js": "^9.20.0",
52
+ "@rollup/plugin-replace": "^6.0.2",
53
+ "@rollup/plugin-terser": "^0.4.4",
54
+ "@rollup/plugin-typescript": "^12.1.2",
55
+ "@types/jest": "^29.5.14",
56
+ "@typescript-eslint/eslint-plugin": "^8.24.0",
57
+ "@typescript-eslint/parser": "^8.24.0",
58
+ "concurrently": "^9.1.2",
59
+ "eslint": "^9.20.1",
60
+ "eslint-config-jquery": "^3.0.2",
61
+ "eslint-config-prettier": "^10.0.1",
62
+ "eslint-plugin-prettier": "^5.2.3",
61
63
  "grunt": "^1.6.1",
62
- "grunt-contrib-connect": "^3.0.0",
64
+ "grunt-contrib-connect": "^5.0.1",
63
65
  "grunt-contrib-qunit": "^10.1.1",
64
66
  "grunt-contrib-watch": "^1.1.0",
65
67
  "grunt-exec": "^3.0.0",
66
68
  "grunt-yabs": "^1.3.0",
67
69
  "http-server": "^14.1.1",
68
- "nodemon": "^2.0.22",
69
- "postcss": "^8.2.24",
70
+ "nodemon": "^3.1.9",
71
+ "postcss": "^8.5.2",
70
72
  "postcss-url": "^10.1.3",
71
- "prettier": "^2.8.8",
72
- "pretty-quick": "^3.1.3",
73
- "puppeteer": "^23.10.0",
74
- "qunit": "^2.19.4",
75
- "rollup": "^3.23.0",
76
- "rollup-plugin-scss": "^4.0.0",
77
- "sass": "^1.63.6",
78
- "terser": "^5.17.7",
79
- "ts-jest": "^29.1.0",
80
- "ts-node": "^10.9.1",
81
- "tslib": "^2.5.2",
82
- "typedoc": "^0.25.2",
83
- "typescript": "^5.2.2",
73
+ "prettier": "^3.5.1",
74
+ "pretty-quick": "^4.0.0",
75
+ "puppeteer": "^24.2.0",
76
+ "qunit": "^2.24.1",
77
+ "rollup": "^4.34.6",
78
+ "rollup-plugin-scss": "^4.0.1",
79
+ "sass": "^1.84.0",
80
+ "terser": "^5.39.0",
81
+ "ts-jest": "^29.2.5",
82
+ "ts-node": "^10.9.2",
83
+ "tslib": "^2.8.1",
84
+ "typedoc": "^0.27.7",
85
+ "typescript": "^5.7",
84
86
  "yarn-audit-fix": "^10.1.1"
85
87
  },
86
88
  "nodemonConfig": {
package/src/common.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - common
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -36,8 +36,11 @@ export const TEST_IMG = new RegExp(/\.|\//);
36
36
  // export const INVALID_REQUEST_TARGET_ERROR = "$request_target_invalid";
37
37
 
38
38
  /**
39
- * Default node icons.
40
- * Requires bootstrap icons https://icons.getbootstrap.com
39
+ * Default node icons for icon libraries
40
+ *
41
+ * - 'bootstrap': {@link https://icons.getbootstrap.com}
42
+ * - 'fontawesome6' {@link https://fontawesome.com/icons}
43
+ *
41
44
  */
42
45
  export const iconMaps: { [key: string]: { [key: string]: string } } = {
43
46
  bootstrap: {
@@ -205,10 +208,12 @@ export function nodeTitleSorter(a: WunderbaumNode, b: WunderbaumNode): number {
205
208
  /**
206
209
  * Convert 'flat' to 'nested' format.
207
210
  *
208
- * Flat node entry format:
209
- * [PARENT_ID, [POSITIONAL_ARGS]]
210
- * or
211
- * [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}]
211
+ * Flat node entry format:
212
+ * [PARENT_IDX, {KEY_VALUE_ARGS}]
213
+ * or, if N _positional re defined:
214
+ * [PARENT_IDX, POSITIONAL_ARG_1, POSITIONAL_ARG_2, ..., POSITIONAL_ARG_N]
215
+ * Even if _positional additional are defined, KEY_VALUE_ARGS can be appended:
216
+ * [PARENT_IDX, POSITIONAL_ARG_1, ..., {KEY_VALUE_ARGS}]
212
217
  *
213
218
  * 1. Parent-referencing list is converted to a list of nested dicts with
214
219
  * optional `children` properties.
@@ -216,11 +221,12 @@ export function nodeTitleSorter(a: WunderbaumNode, b: WunderbaumNode): number {
216
221
  */
217
222
  function unflattenSource(source: SourceObjectType): void {
218
223
  const { _format, _keyMap = {}, _positional = [], children } = source;
224
+ const _positionalCount = _positional.length;
219
225
 
220
226
  if (_format !== "flat") {
221
227
  throw new Error(`Expected source._format: "flat", but got ${_format}`);
222
228
  }
223
- if (_positional && _positional.includes("children")) {
229
+ if (_positionalCount && _positional.includes("children")) {
224
230
  throw new Error(
225
231
  `source._positional must not include "children": ${_positional}`
226
232
  );
@@ -236,7 +242,7 @@ function unflattenSource(source: SourceObjectType): void {
236
242
  longToShort[value] = key;
237
243
  }
238
244
  }
239
- const positionalShort = _positional.map((e: string) => longToShort[e]);
245
+ const positionalShort = _positional.map((e: string) => longToShort[e] ?? e);
240
246
  const newChildren: SourceListType = [];
241
247
  const keyToNodeMap: { [key: string]: number } = {};
242
248
  const indexToNodeMap: { [key: number]: any } = {};
@@ -247,21 +253,33 @@ function unflattenSource(source: SourceObjectType): void {
247
253
  // Node entry format:
248
254
  // [PARENT_ID, [POSITIONAL_ARGS]]
249
255
  // or
250
- // [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}]
251
- const [parentId, args, kwargs = {}] = <any>nodeTuple;
256
+ // [PARENT_ID, POSITIONAL_ARG_1, POSITIONAL_ARG_2, ..., {KEY_VALUE_ARGS}]
257
+ let kwargs;
258
+ const [parentId, ...args] = <any>nodeTuple;
259
+ if (args.length === _positionalCount) {
260
+ kwargs = {};
261
+ } else if (args.length === _positionalCount + 1) {
262
+ kwargs = args.pop();
263
+ if (typeof kwargs !== "object") {
264
+ throw new Error(
265
+ `unflattenSource: Expected dict as last tuple element: ${nodeTuple}`
266
+ );
267
+ }
268
+ } else {
269
+ throw new Error(`unflattenSource: unexpected tuple length: ${nodeTuple}`);
270
+ }
252
271
 
253
272
  // Free up some memory as we go
254
273
  nodeTuple[1] = null;
255
274
  if (nodeTuple[2] != null) {
256
275
  nodeTuple[2] = null;
257
276
  }
258
- // console.log("flatten", parentId, args, kwargs)
259
-
260
277
  // We keep `kwargs` as our new node definition. Then we add all positional
261
278
  // values to this object:
262
279
  args.forEach((val: string, positionalIdx: number) => {
263
280
  kwargs[positionalShort[positionalIdx]] = val;
264
281
  });
282
+ args.length = 0;
265
283
 
266
284
  // Find the parent node. `null` means 'toplevel'. PARENT_ID may be the numeric
267
285
  // index of the source.children list. If PARENT_ID is a string, we search
package/src/debounce.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  /*!
2
+ * Wunderbaum - debounce.ts
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
+ * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
+ */
6
+ /*
2
7
  * debounce & throttle, taken from https://github.com/lodash/lodash v4.17.21
3
8
  * MIT License: https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/LICENSE
4
9
  * Modified for TypeScript type annotations.
package/src/deferred.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - deferred
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - drag_observer
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - types
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -22,7 +22,7 @@ export type SortOrderType = "asc" | "desc" | undefined;
22
22
  * or a boolean value that indicates if the default icon should be used or hidden.
23
23
  */
24
24
  export type IconOption = boolean | string;
25
- /** Show/hide tooltip or display a string. */
25
+ /** Show/hide default tooltip or display a string. */
26
26
  export type TooltipOption = boolean | string;
27
27
 
28
28
  /*
@@ -93,7 +93,10 @@ export type NodeToDictCallback = (
93
93
  dict: WbNodeData,
94
94
  node: WunderbaumNode
95
95
  ) => NodeVisitResponse;
96
- /** A callback that receives a node instance and returns a string value. */
96
+ /**
97
+ * A callback that receives a node instance and may returnsa `false` to prevent
98
+ * (de)selection.
99
+ */
97
100
  export type NodeSelectCallback = (node: WunderbaumNode) => boolean | void;
98
101
 
99
102
  /**
@@ -113,23 +116,56 @@ export type DynamicTooltipOption = TooltipOption | BoolOrStringOptionResolver;
113
116
  // type WithWildcards<T> = T & { [key: string]: unknown };
114
117
  /** A plain object (dictionary) that represents a node instance. */
115
118
  export interface WbNodeData {
119
+ /** Defines if the `selected` state is displayed as checkbox, radio button,
120
+ * or hidden.
121
+ * Defaults to {@link WunderbaumOptions.checkbox}.
122
+ */
116
123
  checkbox?: CheckboxOption;
124
+ /** Optional list of child nodes.
125
+ * If `children` is an empty array, the node is considered a leaf.
126
+ * If `lazy` is true and `children is undefined or null, the node, is
127
+ * considered unloaded. Otherwise, the node is considered a leaf.
128
+ */
117
129
  children?: Array<WbNodeData>;
130
+ /** Additional classes that are added to `<div class='wb-row'>`. */
118
131
  classes?: string;
132
+ /** Only show title in a single, merged column. */
119
133
  colspan?: boolean;
134
+ /** Expand this node. */
120
135
  expanded?: boolean;
136
+ /** Defaults to standard icons (doc, folder, folderOpen, ...)
137
+ * from {@link WunderbaumOptions.iconMap}.
138
+ * Can be overridden by {@link WunderbaumOptions.icon}.
139
+ */
121
140
  icon?: IconOption;
141
+ /** Tooltip for the node icon only. Defaults to {@link WunderbaumOptions.iconTooltip}. */
122
142
  iconTooltip?: TooltipOption;
143
+ /** The node's key. Must be unique for the whole tree. Defaults to a sequence number. */
123
144
  key?: string;
145
+ /** If true (and children are undefined or null), the node is considered lazy
146
+ * and {@link WunderbaumOptions.lazyLoad} is called when expanded.
147
+ */
124
148
  lazy?: boolean;
125
149
  /** Make child nodes single-select radio buttons. */
126
150
  radiogroup?: boolean;
151
+ /** Node's reference key. Unlike {@link WunderbaumNode.key}, this value
152
+ * may be non-unique. Nodes within the tree that share the same refKey are considered
153
+ * clones.
154
+ */
127
155
  refKey?: string;
156
+ /** The node's selection status, typically displayed as a checkbox. */
128
157
  selected?: boolean;
158
+ /** The node's status, typically displayed as merged single row.
159
+ * @see {@link Wunderbaum.setStatus}
160
+ */
129
161
  statusNodeType?: NodeStatusType;
162
+ /** The node's title. Will be html escaped to prevent XSS. */
130
163
  title: string;
164
+ /** Pass true to set node tooltip to the node's title. Defaults to {@link WunderbaumOptions.tooltip}. */
131
165
  tooltip?: TooltipOption;
166
+ /** Inherit shared settings from the matching entry in {@link WunderbaumOptions.types}. */
132
167
  type?: string;
168
+ /** Set to `true` to prevent selection. Defaults to {@link WunderbaumOptions.unselectable}. */
133
169
  unselectable?: boolean;
134
170
  /** @internal */
135
171
  _treeId?: string;
@@ -531,7 +567,7 @@ export enum ChangeType {
531
567
  scroll = "scroll",
532
568
  }
533
569
 
534
- /* Internal use. */
570
+ /** @internal */
535
571
  export enum RenderFlag {
536
572
  clearMarkup = "clearMarkup",
537
573
  header = "header",
@@ -561,10 +597,14 @@ export enum NodeRegion {
561
597
 
562
598
  /** Initial navigation mode and possible transition. */
563
599
  export enum NavModeEnum {
564
- startRow = "startRow", // Start with row mode, but allow cell-nav mode
565
- cell = "cell", // Cell-nav mode only
566
- startCell = "startCell", // Start in cell-nav mode, but allow row mode
567
- row = "row", // Row mode only
600
+ /** Start with row mode, but allow cell-nav mode */
601
+ startRow = "startRow",
602
+ /** Cell-nav mode only */
603
+ cell = "cell",
604
+ /** Start in cell-nav mode, but allow row mode */
605
+ startCell = "startCell",
606
+ /** Row mode only */
607
+ row = "row",
568
608
  }
569
609
 
570
610
  /* -----------------------------------------------------------------------------
@@ -965,7 +1005,6 @@ export type InsertNodeType =
965
1005
  | "after"
966
1006
  | "prependChild"
967
1007
  | "appendChild";
968
- // export type DndModeType = "before" | "after" | "over";
969
1008
 
970
1009
  export type DropEffectType = "none" | "copy" | "link" | "move";
971
1010
  export type DropEffectAllowedType =
package/src/util.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - util
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
package/src/wb_ext_dnd.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - ext-dnd
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
  import * as util from "./util";
@@ -143,8 +143,8 @@ export class DndExtension extends WunderbaumExtension<DndOptionsType> {
143
143
  return dy < 0.25 * rowHeight
144
144
  ? "before"
145
145
  : dy > 0.75 * rowHeight
146
- ? "after"
147
- : "over";
146
+ ? "after"
147
+ : "over";
148
148
  } else if (allowed.size === 1 && allowed.has("over")) {
149
149
  return "over";
150
150
  } else {
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - ext-edit
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - ext-filter
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -177,7 +177,7 @@ export class FilterExtension extends WunderbaumExtension<FilterOptionsType> {
177
177
  }
178
178
 
179
179
  tree.filterMode = opts.mode;
180
- // eslint-disable-next-line prefer-rest-params, prefer-spread
180
+ // eslint-disable-next-line prefer-rest-params
181
181
  this.lastFilterArgs = arguments;
182
182
 
183
183
  tree.element.classList.toggle("wb-ext-filter-hide", !!hideMode);
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - ext-grid
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
  import { Wunderbaum } from "./wunderbaum";
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - ext-keynav
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - ext-logger
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - wb_extension_base
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
package/src/wb_node.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - wunderbaum_node
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -2437,7 +2437,8 @@ export class WunderbaumNode {
2437
2437
  case undefined:
2438
2438
  changed = this.selected || !this._partsel;
2439
2439
  this.selected = false;
2440
- this._partsel = true;
2440
+ // #110: end nodess cannot have a `_partsel` flag
2441
+ this._partsel = this.hasChildren() ? true : false;
2441
2442
  break;
2442
2443
  default:
2443
2444
  util.error(`Invalid state: ${state}`);
package/src/wb_options.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum - utils
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
@@ -113,6 +113,14 @@ export interface WunderbaumOptions {
113
113
  skeleton?: boolean;
114
114
  /**
115
115
  * Translation map for some system messages.
116
+ * Default:
117
+ * ```js
118
+ * strings: {
119
+ * loading: "Loading...",
120
+ * loadError: "Error",
121
+ * noData: "No data",
122
+ * }
123
+ * ```
116
124
  */
117
125
  strings?: any; //[key: string] string;
118
126
  /**
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Wunderbaum style sheet (generated from wunderbaum.scss)
3
- * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3
+ * Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
  // @use "sass:meta";
@@ -69,8 +69,8 @@ $header-height: $row-outer-height;
69
69
  // $level-rainbow: rgba(255, 255, 64, 0.07), rgba(127, 255, 127, 0.07),
70
70
  // rgba(255, 127, 255, 0.07), rgba(79, 236, 236, 0.07);
71
71
  // Slightly stronger*
72
- $level-rainbow: rgb(255, 255, 201), rgb(218, 255, 218), rgb(255, 217, 254),
73
- rgb(204, 250, 250);
72
+ $level-rainbow:
73
+ rgb(255, 255, 201), rgb(218, 255, 218), rgb(255, 217, 254), rgb(204, 250, 250);
74
74
 
75
75
  // ----------------------------------------------------------------------------
76
76
  // --- Define CSS variables with calculated default values
package/src/wunderbaum.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * A treegrid control.
5
5
  *
6
- * Copyright (c) 2021-2024, Martin Wendt (https://wwWendt.de).
6
+ * Copyright (c) 2021-2025, Martin Wendt (https://wwWendt.de).
7
7
  * https://github.com/mar10/wunderbaum
8
8
  *
9
9
  * Released under the MIT license.
@@ -125,14 +125,14 @@ export class Wunderbaum {
125
125
  protected _focusNode: WunderbaumNode | null = null;
126
126
 
127
127
  /** Currently active node if any.
128
- * Use @link {WunderbaumNode.setActive|setActive} to modify.
128
+ * Use {@link WunderbaumNode.setActive|setActive} to modify.
129
129
  */
130
130
  public get activeNode() {
131
131
  // Check for deleted node, i.e. node.tree === null
132
132
  return this._activeNode?.tree ? this._activeNode : null;
133
133
  }
134
134
  /** Current node hat has keyboard focus if any.
135
- * Use @link {WunderbaumNode.setFocus|setFocus()} to modify.
135
+ * Use {@link WunderbaumNode.setFocus|setFocus()} to modify.
136
136
  */
137
137
  public get focusNode() {
138
138
  // Check for deleted node, i.e. node.tree === null
@@ -319,7 +319,7 @@ export class Wunderbaum {
319
319
  // User existing header markup to define `this.columns`
320
320
  util.assert(
321
321
  !this.columns,
322
- "`opts.columns` must not be set if markup already contains a header"
322
+ "`opts.columns` must not be set if table markup already contains a header"
323
323
  );
324
324
  this.columns = [];
325
325
  const rowElement =
@@ -380,8 +380,7 @@ export class Wunderbaum {
380
380
  // --- Load initial data
381
381
  if (opts.source) {
382
382
  if (opts.showSpinner) {
383
- this.nodeListElement.innerHTML =
384
- "<progress class='spinner'>loading...</progress>";
383
+ this.nodeListElement.innerHTML = `<progress class='spinner'>${opts.strings.loading}</progress>`;
385
384
  }
386
385
  this.load(opts.source)
387
386
  .then(() => {
@@ -2400,8 +2399,9 @@ export class Wunderbaum {
2400
2399
  // this.debug("render", opts);
2401
2400
  const obsoleteNodes = new Set<WunderbaumNode>();
2402
2401
  this.nodeListElement.childNodes.forEach((elem) => {
2403
- const tr = elem as HTMLTableRowElement;
2404
- obsoleteNodes.add((<any>tr)._wb_node);
2402
+ if ((<any>elem)._wb_node) {
2403
+ obsoleteNodes.add((<any>elem)._wb_node);
2404
+ }
2405
2405
  });
2406
2406
 
2407
2407
  let idx = 0;