wunderbaum 0.0.1-0 → 0.0.3

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.
@@ -0,0 +1,45 @@
1
+ /*!
2
+ * Wunderbaum - ext-grid
3
+ * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
4
+ * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
+ */
6
+ import { Wunderbaum } from "./wunderbaum";
7
+ import { WunderbaumExtension } from "./wb_extension_base";
8
+ import { DragCallbackArgType, DragObserver } from "./drag_observer";
9
+
10
+ export class GridExtension extends WunderbaumExtension {
11
+ protected observer: DragObserver;
12
+
13
+ constructor(tree: Wunderbaum) {
14
+ super(tree, "grid", {
15
+ // throttle: 200,
16
+ });
17
+
18
+ this.observer = new DragObserver({
19
+ root: window.document,
20
+ selector: "span.wb-col-resizer",
21
+ thresh: 4,
22
+ // throttle: 400,
23
+ dragstart: (e) => {
24
+ return this.tree.element.contains(e.dragElem);
25
+ },
26
+ drag: (e) => {
27
+ // TODO: throttle
28
+ return this.handleDrag(e);
29
+ },
30
+ dragstop: (e) => {
31
+ return this.handleDrag(e);
32
+ },
33
+ });
34
+ }
35
+
36
+ init() {
37
+ super.init();
38
+ }
39
+
40
+ protected handleDrag(e: DragCallbackArgType): void {
41
+ const info = Wunderbaum.getEventInfo(e.event);
42
+ // this.tree.options.
43
+ this.tree.log(`${e.type}(${e.dx})`, e, info);
44
+ }
45
+ }
@@ -94,7 +94,7 @@ export class KeynavExtension extends WunderbaumExtension {
94
94
  if (!node.expanded && (node.children || node.lazy)) {
95
95
  eventName = "Add"; // expand
96
96
  } else if (navModeOption === NavigationModeOption.startRow) {
97
- tree.setCellMode(NavigationMode.cellNav);
97
+ tree.setNavigationMode(NavigationMode.cellNav);
98
98
  return;
99
99
  }
100
100
  break;
@@ -133,6 +133,8 @@ export class KeynavExtension extends WunderbaumExtension {
133
133
  case "Home":
134
134
  case "Control+End":
135
135
  case "Control+Home":
136
+ case "Meta+ArrowDown":
137
+ case "Meta+ArrowUp":
136
138
  case "PageDown":
137
139
  case "PageUp":
138
140
  node.navigate(eventName, { activate: activate, event: event });
@@ -164,10 +166,10 @@ export class KeynavExtension extends WunderbaumExtension {
164
166
  break;
165
167
  case "Escape":
166
168
  if (tree.navMode === NavigationMode.cellEdit) {
167
- tree.setCellMode(NavigationMode.cellNav);
169
+ tree.setNavigationMode(NavigationMode.cellNav);
168
170
  handled = true;
169
171
  } else if (tree.navMode === NavigationMode.cellNav) {
170
- tree.setCellMode(NavigationMode.row);
172
+ tree.setNavigationMode(NavigationMode.row);
171
173
  handled = true;
172
174
  }
173
175
  break;
@@ -176,7 +178,7 @@ export class KeynavExtension extends WunderbaumExtension {
176
178
  tree.setColumn(tree.activeColIdx - 1);
177
179
  handled = true;
178
180
  } else if (navModeOption !== NavigationModeOption.cell) {
179
- tree.setCellMode(NavigationMode.row);
181
+ tree.setNavigationMode(NavigationMode.row);
180
182
  handled = true;
181
183
  }
182
184
  break;
@@ -193,6 +195,8 @@ export class KeynavExtension extends WunderbaumExtension {
193
195
  case "Home":
194
196
  case "Control+End":
195
197
  case "Control+Home":
198
+ case "Meta+ArrowDown":
199
+ case "Meta+ArrowUp":
196
200
  case "PageDown":
197
201
  case "PageUp":
198
202
  node.navigate(eventName, { activate: activate, event: event });
package/src/wb_node.ts CHANGED
@@ -25,6 +25,9 @@ import {
25
25
  TEST_IMG,
26
26
  ApplyCommandType,
27
27
  AddNodeType,
28
+ SetActiveOptions,
29
+ SetExpandedOptions,
30
+ SetSelectedOptions,
28
31
  } from "./common";
29
32
  import { Deferred } from "./deferred";
30
33
  import { WbNodeData } from "./wb_options";
@@ -66,6 +69,13 @@ const NODE_ATTRS = new Set<string>([
66
69
  "unselectableStatus",
67
70
  ]);
68
71
 
72
+ /**
73
+ * A single tree node.
74
+ *
75
+ * **NOTE:** <br>
76
+ * Generally you should not modify properties directly, since this may break
77
+ * the internal bookkeeping.
78
+ */
69
79
  export class WunderbaumNode {
70
80
  static sequence = 0;
71
81
 
@@ -73,19 +83,32 @@ export class WunderbaumNode {
73
83
  public tree: Wunderbaum;
74
84
  /** Parent node (null for the invisible root node `tree.root`). */
75
85
  public parent: WunderbaumNode;
86
+ /** Name of the node.
87
+ * @see Use {@link setTitle} to modify. */
76
88
  public title: string;
89
+ /** Unique key. Passed with constructor or defaults to `SEQUENCE`.
90
+ * @see Use {@link setKey} to modify. */
77
91
  public readonly key: string;
92
+ /** Reference key. Unlike {@link key}, a `refKey` may occur multiple
93
+ * times within a tree (in this case we have 'clone nodes').
94
+ * @see Use {@link setKey} to modify.
95
+ */
78
96
  public readonly refKey: string | undefined = undefined;
79
97
  public children: WunderbaumNode[] | null = null;
80
98
  public checkbox?: boolean;
81
99
  public colspan?: boolean;
82
100
  public icon?: boolean | string;
83
101
  public lazy: boolean = false;
102
+ /** Expansion state.
103
+ * @see {@link isExpandable}, {@link isExpanded}, {@link setExpanded}. */
84
104
  public expanded: boolean = false;
105
+ /** Selection state.
106
+ * @see {@link isSelected}, {@link setSelected}. */
85
107
  public selected: boolean = false;
86
108
  public type?: string;
87
109
  public tooltip?: string;
88
- /** Additional classes added to `div.wb-row`. */
110
+ /** Additional classes added to `div.wb-row`.
111
+ * @see {@link addClass}, {@link removeClass}, {@link toggleClass}. */
89
112
  public extraClasses = new Set<string>();
90
113
  /** Custom data that was passed to the constructor */
91
114
  public data: any = {};
@@ -100,6 +123,7 @@ export class WunderbaumNode {
100
123
  public match?: boolean; // Added and removed by filter code
101
124
  public subMatchCount?: number = 0;
102
125
  public subMatchBadge?: HTMLElement;
126
+ /** @internal */
103
127
  public titleWithHighlight?: string;
104
128
  public _filterAutoExpanded?: boolean;
105
129
 
@@ -236,7 +260,7 @@ export class WunderbaumNode {
236
260
  // this.fixSelection3FromEndNodes();
237
261
  // }
238
262
  // this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null);
239
- this.tree.setModified(ChangeType.structure, this);
263
+ this.tree.setModified(ChangeType.structure);
240
264
  return nodeList[0];
241
265
  } finally {
242
266
  this.tree.enableUpdate(true);
@@ -276,7 +300,8 @@ export class WunderbaumNode {
276
300
 
277
301
  /**
278
302
  * Apply a modification (or navigation) operation.
279
- * @see Wunderbaum#applyCommand
303
+ *
304
+ * @see {@link Wunderbaum.applyCommand}
280
305
  */
281
306
  applyCommand(cmd: ApplyCommandType, opts: any): any {
282
307
  return this.tree.applyCommand(cmd, this, opts);
@@ -374,8 +399,7 @@ export class WunderbaumNode {
374
399
 
375
400
  /** Find a node relative to self.
376
401
  *
377
- * @param where The keyCode that would normally trigger this move,
378
- * or a keyword ('down', 'first', 'last', 'left', 'parent', 'right', 'up').
402
+ * @see {@link Wunderbaum.findRelatedNode|tree.findRelatedNode()}
379
403
  */
380
404
  findRelatedNode(where: string, includeHidden = false) {
381
405
  return this.tree.findRelatedNode(this, where, includeHidden);
@@ -739,7 +763,7 @@ export class WunderbaumNode {
739
763
  util.assert(!this.parent);
740
764
  tree.columns = data.columns;
741
765
  delete data.columns;
742
- tree.renderHeader();
766
+ tree.updateColumns({ calculateCols: false });
743
767
  }
744
768
  this._loadSourceObject(data);
745
769
  }
@@ -777,20 +801,21 @@ export class WunderbaumNode {
777
801
  }
778
802
  util.assert(
779
803
  util.isArray(source) || (source && source.url),
780
- "The lazyLoad event must return a node list, `{url: ...}` or false."
804
+ "The lazyLoad event must return a node list, `{url: ...}`, or false."
781
805
  );
782
806
 
783
807
  await this.load(source); // also calls setStatus('ok')
784
808
 
785
809
  if (wasExpanded) {
786
810
  this.expanded = true;
787
- this.tree.updateViewport();
811
+ this.tree.setModified(ChangeType.structure);
788
812
  } else {
789
- this.render(); // Fix expander icon to 'loaded'
813
+ this.setModified(); // Fix expander icon to 'loaded'
790
814
  }
791
815
  } catch (e) {
816
+ this.logError("Error during loadLazy()", e);
817
+ this._callEvent("error", { error: e });
792
818
  this.setStatus(NodeStatusType.error, "" + e);
793
- // } finally {
794
819
  }
795
820
  return;
796
821
  }
@@ -956,7 +981,7 @@ export class WunderbaumNode {
956
981
  }, true);
957
982
  }
958
983
 
959
- tree.updateViewport();
984
+ tree.setModified(ChangeType.structure);
960
985
  // TODO: fix selection state
961
986
  // TODO: fix active state
962
987
  }
@@ -978,31 +1003,33 @@ export class WunderbaumNode {
978
1003
  where = KEY_TO_ACTION_DICT[where] || where;
979
1004
 
980
1005
  // Otherwise activate or focus the related node
981
- let node = this.findRelatedNode(where);
982
- if (node) {
983
- // setFocus/setActive will scroll later (if autoScroll is specified)
984
- try {
985
- node.makeVisible({ scrollIntoView: false });
986
- } catch (e) {} // #272
987
- node.setFocus();
988
- if (options?.activate === false) {
989
- return Promise.resolve(this);
990
- }
991
- return node.setActive(true, { event: options?.event });
1006
+ const node = this.findRelatedNode(where);
1007
+ if (!node) {
1008
+ this.logWarn(`Could not find related node '${where}'.`);
1009
+ return Promise.resolve(this);
1010
+ }
1011
+ // setFocus/setActive will scroll later (if autoScroll is specified)
1012
+ try {
1013
+ node.makeVisible({ scrollIntoView: false });
1014
+ } catch (e) {} // #272
1015
+ node.setFocus();
1016
+ if (options?.activate === false) {
1017
+ return Promise.resolve(this);
992
1018
  }
993
- this.logWarn("Could not find related node '" + where + "'.");
994
- return Promise.resolve(this);
1019
+ return node.setActive(true, { event: options?.event });
995
1020
  }
996
1021
 
997
1022
  /** Delete this node and all descendants. */
998
1023
  remove() {
999
1024
  const tree = this.tree;
1000
1025
  const pos = this.parent.children!.indexOf(this);
1026
+ this.triggerModify("remove");
1001
1027
  this.parent.children!.splice(pos, 1);
1002
1028
  this.visit((n) => {
1003
1029
  n.removeMarkup();
1004
1030
  tree._unregisterNode(n);
1005
1031
  }, true);
1032
+ tree.setModified(ChangeType.structure);
1006
1033
  }
1007
1034
 
1008
1035
  /** Remove all descendants of this node. */
@@ -1035,7 +1062,7 @@ export class WunderbaumNode {
1035
1062
  if (!this.isRootNode()) {
1036
1063
  this.expanded = false;
1037
1064
  }
1038
- this.tree.updateViewport();
1065
+ this.tree.setModified(ChangeType.structure);
1039
1066
  }
1040
1067
 
1041
1068
  /** Remove all HTML markup from the DOM. */
@@ -1135,6 +1162,10 @@ export class WunderbaumNode {
1135
1162
  tree.navMode === NavigationMode.row ? null : tree.activeColIdx;
1136
1163
  // let colElems: HTMLElement[];
1137
1164
  const isNew = !rowDiv;
1165
+ util.assert(
1166
+ !isNew || (opts && opts.after),
1167
+ "opts.after expected, unless updating"
1168
+ );
1138
1169
 
1139
1170
  util.assert(!this.isRootNode());
1140
1171
  //
@@ -1194,7 +1225,7 @@ export class WunderbaumNode {
1194
1225
  ofsTitlePx += ICON_WIDTH;
1195
1226
  }
1196
1227
 
1197
- if (level > treeOptions.minExpandLevel) {
1228
+ if (!treeOptions.minExpandLevel || level > treeOptions.minExpandLevel) {
1198
1229
  expanderSpan = document.createElement("i");
1199
1230
  nodeElem.appendChild(expanderSpan);
1200
1231
  ofsTitlePx += ICON_WIDTH;
@@ -1214,7 +1245,7 @@ export class WunderbaumNode {
1214
1245
  // Store the width of leading icons with the node, so we can calculate
1215
1246
  // the width of the embedded title span later
1216
1247
  (<any>nodeElem)._ofsTitlePx = ofsTitlePx;
1217
- if (tree.options.dnd.dragStart) {
1248
+ if (tree.options.dnd!.dragStart) {
1218
1249
  nodeElem.draggable = true;
1219
1250
  }
1220
1251
 
@@ -1290,10 +1321,11 @@ export class WunderbaumNode {
1290
1321
 
1291
1322
  if (this.titleWithHighlight) {
1292
1323
  titleSpan.innerHTML = this.titleWithHighlight;
1293
- } else if (tree.options.escapeTitles) {
1294
- titleSpan.textContent = this.title;
1295
1324
  } else {
1296
- titleSpan.innerHTML = this.title;
1325
+ // } else if (tree.options.escapeTitles) {
1326
+ titleSpan.textContent = this.title;
1327
+ // } else {
1328
+ // titleSpan.innerHTML = this.title;
1297
1329
  }
1298
1330
  // Set the width of the title span, so overflow ellipsis work
1299
1331
  if (!treeOptions.skeleton) {
@@ -1328,9 +1360,19 @@ export class WunderbaumNode {
1328
1360
  }
1329
1361
 
1330
1362
  // Attach to DOM as late as possible
1331
- // if (!this._rowElem) {
1332
- tree.nodeListElement.appendChild(rowDiv);
1333
- // }
1363
+ if (isNew) {
1364
+ const after = opts ? opts.after : "last";
1365
+ switch (after) {
1366
+ case "first":
1367
+ tree.nodeListElement.prepend(rowDiv);
1368
+ break;
1369
+ case "last":
1370
+ tree.nodeListElement.appendChild(rowDiv);
1371
+ break;
1372
+ default:
1373
+ opts.after.after(rowDiv);
1374
+ }
1375
+ }
1334
1376
  }
1335
1377
 
1336
1378
  /**
@@ -1342,7 +1384,7 @@ export class WunderbaumNode {
1342
1384
  this.expanded = false;
1343
1385
  this.lazy = true;
1344
1386
  this.children = null;
1345
- this.tree.updateViewport();
1387
+ this.tree.setModified(ChangeType.structure);
1346
1388
  }
1347
1389
 
1348
1390
  /** Convert node (or whole branch) into a plain object.
@@ -1408,14 +1450,15 @@ export class WunderbaumNode {
1408
1450
  *
1409
1451
  * Evaluation sequence:
1410
1452
  *
1411
- * If `tree.options.<name>` is a callback that returns something, use that.
1412
- * Else if `node.<name>` is defined, use that.
1413
- * Else if `tree.types[<node.type>]` is a value, use that.
1414
- * Else if `tree.options.<name>` is a value, use that.
1415
- * Else use `defaultValue`.
1453
+ * - If `tree.options.<name>` is a callback that returns something, use that.
1454
+ * - Else if `node.<name>` is defined, use that.
1455
+ * - Else if `tree.types[<node.type>]` is a value, use that.
1456
+ * - Else if `tree.options.<name>` is a value, use that.
1457
+ * - Else use `defaultValue`.
1416
1458
  *
1417
1459
  * @param name name of the option property (on node and tree)
1418
1460
  * @param defaultValue return this if nothing else matched
1461
+ * {@link Wunderbaum.getOption|Wunderbaum.getOption()}
1419
1462
  */
1420
1463
  getOption(name: string, defaultValue?: any) {
1421
1464
  let tree = this.tree;
@@ -1453,17 +1496,23 @@ export class WunderbaumNode {
1453
1496
  return value ?? defaultValue;
1454
1497
  }
1455
1498
 
1499
+ /** Make sure that this node is visible in the viewport.
1500
+ * @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo()}
1501
+ */
1456
1502
  async scrollIntoView(options?: any) {
1457
1503
  return this.tree.scrollTo(this);
1458
1504
  }
1459
1505
 
1460
- async setActive(flag: boolean = true, options?: any) {
1506
+ /**
1507
+ * Activate this node, deactivate previous, send events, activate column and scroll int viewport.
1508
+ */
1509
+ async setActive(flag: boolean = true, options?: SetActiveOptions) {
1461
1510
  const tree = this.tree;
1462
1511
  const prev = tree.activeNode;
1463
1512
  const retrigger = options?.retrigger;
1464
- const noEvent = options?.noEvent;
1513
+ const noEvents = options?.noEvents;
1465
1514
 
1466
- if (!noEvent) {
1515
+ if (!noEvents) {
1467
1516
  let orgEvent = options?.event;
1468
1517
  if (flag) {
1469
1518
  if (prev !== this || retrigger) {
@@ -1482,7 +1531,7 @@ export class WunderbaumNode {
1482
1531
  }) === false
1483
1532
  ) {
1484
1533
  tree.activeNode = null;
1485
- prev?.setDirty(ChangeType.status);
1534
+ prev?.setModified();
1486
1535
  return;
1487
1536
  }
1488
1537
  }
@@ -1493,8 +1542,8 @@ export class WunderbaumNode {
1493
1542
 
1494
1543
  if (prev !== this) {
1495
1544
  tree.activeNode = this;
1496
- prev?.setDirty(ChangeType.status);
1497
- this.setDirty(ChangeType.status);
1545
+ prev?.setModified();
1546
+ this.setModified();
1498
1547
  }
1499
1548
  if (
1500
1549
  options &&
@@ -1507,22 +1556,13 @@ export class WunderbaumNode {
1507
1556
  // requestAnimationFrame(() => {
1508
1557
  // this.scrollIntoView();
1509
1558
  // })
1510
- this.scrollIntoView();
1511
- }
1512
-
1513
- setDirty(type: ChangeType) {
1514
- if (this.tree._disableUpdate) {
1515
- return;
1516
- }
1517
- if (type === ChangeType.structure) {
1518
- this.tree.updateViewport();
1519
- } else if (this._rowElem) {
1520
- // otherwise not in viewport, so no need to render
1521
- this.render();
1522
- }
1559
+ return this.scrollIntoView();
1523
1560
  }
1524
1561
 
1525
- async setExpanded(flag: boolean = true, options?: any) {
1562
+ /**
1563
+ * Expand or collapse this node.
1564
+ */
1565
+ async setExpanded(flag: boolean = true, options?: SetExpandedOptions) {
1526
1566
  // alert("" + this.getLevel() + ", "+ this.getOption("minExpandLevel");
1527
1567
  if (
1528
1568
  !flag &&
@@ -1530,45 +1570,61 @@ export class WunderbaumNode {
1530
1570
  this.getLevel() < this.getOption("minExpandLevel") &&
1531
1571
  !util.getOption(options, "force")
1532
1572
  ) {
1533
- this.logDebug("Ignored collapse request.");
1573
+ this.logDebug("Ignored collapse request below expandLevel.");
1534
1574
  return;
1535
1575
  }
1536
1576
  if (flag && this.lazy && this.children == null) {
1537
1577
  await this.loadLazy();
1538
1578
  }
1539
1579
  this.expanded = flag;
1540
- this.setDirty(ChangeType.structure);
1580
+ this.tree.setModified(ChangeType.structure);
1581
+ }
1582
+
1583
+ /**
1584
+ * Set keyboard focus here.
1585
+ * @see {@link setActive}
1586
+ */
1587
+ setFocus(flag: boolean = true, options?: any) {
1588
+ const prev = this.tree.focusNode;
1589
+ this.tree.focusNode = this;
1590
+ prev?.setModified();
1591
+ this.setModified();
1541
1592
  }
1542
1593
 
1594
+ /** Set a new icon path or class. */
1543
1595
  setIcon() {
1544
1596
  throw new Error("Not yet implemented");
1545
- // this.setDirty(ChangeType.status);
1597
+ // this.setModified();
1546
1598
  }
1547
1599
 
1548
- setFocus(flag: boolean = true, options?: any) {
1549
- const prev = this.tree.focusNode;
1550
- this.tree.focusNode = this;
1551
- prev?.setDirty(ChangeType.status);
1552
- this.setDirty(ChangeType.status);
1600
+ /** Change node's {@link key} and/or {@link refKey}. */
1601
+ setKey(key: string | null, refKey: string | null) {
1602
+ throw new Error("Not yet implemented");
1603
+ }
1604
+
1605
+ /** Schedule a render, typically called to update after a status or data change. */
1606
+ setModified(change: ChangeType = ChangeType.status) {
1607
+ util.assert(change === ChangeType.status);
1608
+ this.tree.setModified(ChangeType.row, this);
1553
1609
  }
1554
1610
 
1555
- setSelected(flag: boolean = true, options?: any) {
1611
+ /** Modify the check/uncheck state. */
1612
+ setSelected(flag: boolean = true, options?: SetSelectedOptions) {
1556
1613
  const prev = this.selected;
1557
1614
  if (!!flag !== prev) {
1558
1615
  this._callEvent("select", { flag: flag });
1559
1616
  }
1560
1617
  this.selected = !!flag;
1561
- this.setDirty(ChangeType.status);
1618
+ this.setModified();
1562
1619
  }
1563
1620
 
1564
- /** Show node status (ok, loading, error, noData) using styles and a dummy child node.
1565
- */
1621
+ /** Display node status (ok, loading, error, noData) using styles and a dummy child node. */
1566
1622
  setStatus(
1567
1623
  status: NodeStatusType,
1568
1624
  message?: string,
1569
1625
  details?: string
1570
1626
  ): WunderbaumNode | null {
1571
- let tree = this.tree;
1627
+ const tree = this.tree;
1572
1628
  let statusNode: WunderbaumNode | null = null;
1573
1629
 
1574
1630
  const _clearStatusNode = () => {
@@ -1649,13 +1705,14 @@ export class WunderbaumNode {
1649
1705
  default:
1650
1706
  util.error("invalid node status " + status);
1651
1707
  }
1652
- tree.updateViewport();
1708
+ tree.setModified(ChangeType.structure);
1653
1709
  return statusNode;
1654
1710
  }
1655
1711
 
1712
+ /** Rename this node. */
1656
1713
  setTitle(title: string): void {
1657
1714
  this.title = title;
1658
- this.setDirty(ChangeType.status);
1715
+ this.setModified();
1659
1716
  // this.triggerModify("rename"); // TODO
1660
1717
  }
1661
1718
 
@@ -1684,12 +1741,18 @@ export class WunderbaumNode {
1684
1741
  * @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
1685
1742
  * @param {object} [extra]
1686
1743
  */
1687
- triggerModify(operation: string, extra: any) {
1744
+ triggerModify(operation: string, extra?: any) {
1745
+ if (!this.parent) {
1746
+ return;
1747
+ }
1688
1748
  this.parent.triggerModifyChild(operation, this, extra);
1689
1749
  }
1690
1750
 
1691
- /** Call fn(node) for all child nodes in hierarchical order (depth-first).<br>
1692
- * Stop iteration, if fn() returns false. Skip current branch, if fn() returns "skip".<br>
1751
+ /**
1752
+ * Call fn(node) for all child nodes in hierarchical order (depth-first).
1753
+ *
1754
+ * Stop iteration, if fn() returns false. Skip current branch, if fn()
1755
+ * returns "skip".<br>
1693
1756
  * Return false if iteration was stopped.
1694
1757
  *
1695
1758
  * @param {function} callback the callback function.
@@ -1745,7 +1808,8 @@ export class WunderbaumNode {
1745
1808
  return true;
1746
1809
  }
1747
1810
 
1748
- /** Call fn(node) for all sibling nodes.<br>
1811
+ /**
1812
+ * Call fn(node) for all sibling nodes.<br>
1749
1813
  * Stop iteration, if fn() returns false.<br>
1750
1814
  * Return false if iteration was stopped.
1751
1815
  *