wunderbaum 0.0.9 → 0.1.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/dist/wunderbaum.css +2 -2
- package/dist/wunderbaum.d.ts +192 -77
- package/dist/wunderbaum.esm.js +171 -143
- package/dist/wunderbaum.esm.min.js +22 -22
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +171 -143
- package/dist/wunderbaum.umd.min.js +25 -25
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/types.ts +170 -37
- package/src/wb_ext_dnd.ts +1 -1
- package/src/wb_ext_edit.ts +11 -9
- package/src/wb_ext_filter.ts +17 -7
- package/src/wb_ext_keynav.ts +40 -21
- package/src/wb_node.ts +47 -24
- package/src/wb_options.ts +31 -17
- package/src/wunderbaum.scss +62 -21
- package/src/wunderbaum.ts +83 -73
package/src/wunderbaum.ts
CHANGED
|
@@ -26,15 +26,20 @@ import {
|
|
|
26
26
|
ExpandAllOptions,
|
|
27
27
|
FilterModeType,
|
|
28
28
|
MatcherCallback,
|
|
29
|
-
|
|
29
|
+
NavModeEnum,
|
|
30
30
|
NodeStatusType,
|
|
31
31
|
NodeStringCallback,
|
|
32
|
-
|
|
32
|
+
NodeTypeDefinitionMap,
|
|
33
33
|
ScrollToOptions,
|
|
34
34
|
SetActiveOptions,
|
|
35
35
|
SetModifiedOptions,
|
|
36
36
|
SetStatusOptions,
|
|
37
|
-
|
|
37
|
+
NodeRegion,
|
|
38
|
+
WbEventInfo,
|
|
39
|
+
ApplyCommandOptions,
|
|
40
|
+
AddChildrenOptions,
|
|
41
|
+
UpdateColumnsOptions,
|
|
42
|
+
VisitRowsOptions,
|
|
38
43
|
} from "./types";
|
|
39
44
|
import {
|
|
40
45
|
DEFAULT_DEBUGLEVEL,
|
|
@@ -79,8 +84,8 @@ export class Wunderbaum {
|
|
|
79
84
|
public readonly element: HTMLDivElement;
|
|
80
85
|
/** The `div.wb-header` element if any. */
|
|
81
86
|
public readonly headerElement: HTMLDivElement;
|
|
82
|
-
/** The `div.wb-
|
|
83
|
-
public readonly
|
|
87
|
+
/** The `div.wb-list-container` element that contains the `nodeListElement`. */
|
|
88
|
+
public readonly listContainerElement: HTMLDivElement;
|
|
84
89
|
/** The `div.wb-node-list` element that contains all visible div.wb-row child elements. */
|
|
85
90
|
public readonly nodeListElement: HTMLDivElement;
|
|
86
91
|
/** Contains additional data that was sent as response to an Ajax source load request. */
|
|
@@ -104,7 +109,7 @@ export class Wunderbaum {
|
|
|
104
109
|
public focusNode: WunderbaumNode | null = null;
|
|
105
110
|
|
|
106
111
|
/** Shared properties, referenced by `node.type`. */
|
|
107
|
-
public types:
|
|
112
|
+
public types: NodeTypeDefinitionMap = {};
|
|
108
113
|
/** List of column definitions. */
|
|
109
114
|
public columns: ColumnDefinitionList = []; // any[] = [];
|
|
110
115
|
|
|
@@ -160,7 +165,7 @@ export class Wunderbaum {
|
|
|
160
165
|
skeleton: false,
|
|
161
166
|
connectTopBreadcrumb: null, // HTMLElement that receives the top nodes breadcrumb
|
|
162
167
|
// --- KeyNav ---
|
|
163
|
-
navigationModeOption: null, //
|
|
168
|
+
navigationModeOption: null, // NavModeEnum.startRow,
|
|
164
169
|
quicksearch: true,
|
|
165
170
|
// --- Events ---
|
|
166
171
|
change: util.noop,
|
|
@@ -293,13 +298,13 @@ export class Wunderbaum {
|
|
|
293
298
|
|
|
294
299
|
//
|
|
295
300
|
this.element.innerHTML += `
|
|
296
|
-
<div class="wb-
|
|
301
|
+
<div class="wb-list-container">
|
|
297
302
|
<div class="wb-node-list"></div>
|
|
298
303
|
</div>`;
|
|
299
|
-
this.
|
|
300
|
-
"div.wb-
|
|
304
|
+
this.listContainerElement = this.element.querySelector(
|
|
305
|
+
"div.wb-list-container"
|
|
301
306
|
) as HTMLDivElement;
|
|
302
|
-
this.nodeListElement = this.
|
|
307
|
+
this.nodeListElement = this.listContainerElement.querySelector(
|
|
303
308
|
"div.wb-node-list"
|
|
304
309
|
) as HTMLDivElement;
|
|
305
310
|
this.headerElement = this.element.querySelector(
|
|
@@ -328,9 +333,9 @@ export class Wunderbaum {
|
|
|
328
333
|
// The source may have defined columns, so we may adjust the nav mode
|
|
329
334
|
if (opts.navigationModeOption == null) {
|
|
330
335
|
if (this.isGrid()) {
|
|
331
|
-
this.setNavigationOption(
|
|
336
|
+
this.setNavigationOption(NavModeEnum.cell);
|
|
332
337
|
} else {
|
|
333
|
-
this.setNavigationOption(
|
|
338
|
+
this.setNavigationOption(NavModeEnum.row);
|
|
334
339
|
}
|
|
335
340
|
} else {
|
|
336
341
|
this.setNavigationOption(opts.navigationModeOption);
|
|
@@ -354,13 +359,9 @@ export class Wunderbaum {
|
|
|
354
359
|
|
|
355
360
|
// --- Bind listeners
|
|
356
361
|
this.element.addEventListener("scroll", (e: Event) => {
|
|
357
|
-
// this.log(
|
|
362
|
+
// this.log(`scroll, scrollTop:${e.target.scrollTop}`, e);
|
|
358
363
|
this.setModified(ChangeType.vscroll);
|
|
359
364
|
});
|
|
360
|
-
// this.scrollContainerElement.addEventListener("scroll", (e: Event) => {
|
|
361
|
-
// this.log("scroll", e)
|
|
362
|
-
// this.setModified(ChangeType.vscroll);
|
|
363
|
-
// });
|
|
364
365
|
|
|
365
366
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
366
367
|
this.setModified(ChangeType.vscroll);
|
|
@@ -373,16 +374,6 @@ export class Wunderbaum {
|
|
|
373
374
|
const node = info.node;
|
|
374
375
|
// this.log("click", info, e);
|
|
375
376
|
|
|
376
|
-
// if( (e.target as HTMLElement).matches("input[type=checkbox]")){
|
|
377
|
-
// // Click on an embedded checkbox triggers a change event.
|
|
378
|
-
// // We return here, before the `setActive()` performs a render
|
|
379
|
-
// this.log("click - cb", info, e);
|
|
380
|
-
// // e.preventDefault()
|
|
381
|
-
// setTimeout(()=>{
|
|
382
|
-
// // (e.target as HTMLElement).click()
|
|
383
|
-
// }, 50)
|
|
384
|
-
// // return
|
|
385
|
-
// }
|
|
386
377
|
if (
|
|
387
378
|
this._callEvent("click", { event: e, node: node, info: info }) === false
|
|
388
379
|
) {
|
|
@@ -417,6 +408,22 @@ export class Wunderbaum {
|
|
|
417
408
|
this.lastClickTime = Date.now();
|
|
418
409
|
});
|
|
419
410
|
|
|
411
|
+
util.onEvent(this.nodeListElement, "dblclick", "div.wb-row", (e) => {
|
|
412
|
+
const info = Wunderbaum.getEventInfo(e);
|
|
413
|
+
const node = info.node;
|
|
414
|
+
// this.log("dblclick", info, e);
|
|
415
|
+
|
|
416
|
+
if (
|
|
417
|
+
this._callEvent("dblclick", { event: e, node: node, info: info }) ===
|
|
418
|
+
false
|
|
419
|
+
) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
if (node && info.colIdx === 0 && node.isExpandable()) {
|
|
423
|
+
node.setExpanded(!node.isExpanded());
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
420
427
|
util.onEvent(this.element, "keydown", (e) => {
|
|
421
428
|
const info = Wunderbaum.getEventInfo(e);
|
|
422
429
|
const eventName = util.eventToString(e);
|
|
@@ -724,20 +731,24 @@ export class Wunderbaum {
|
|
|
724
731
|
*
|
|
725
732
|
* @see {@link WunderbaumNode.addChildren}
|
|
726
733
|
*/
|
|
727
|
-
addChildren(nodeData: any, options?:
|
|
734
|
+
addChildren(nodeData: any, options?: AddChildrenOptions): WunderbaumNode {
|
|
728
735
|
return this.root.addChildren(nodeData, options);
|
|
729
736
|
}
|
|
730
737
|
|
|
731
738
|
/**
|
|
732
739
|
* Apply a modification (or navigation) operation on the **tree or active node**.
|
|
733
740
|
*/
|
|
734
|
-
applyCommand(cmd: ApplyCommandType, options?:
|
|
741
|
+
applyCommand(cmd: ApplyCommandType, options?: ApplyCommandOptions): any;
|
|
735
742
|
|
|
736
743
|
/**
|
|
737
744
|
* Apply a modification (or navigation) operation on a **node**.
|
|
738
745
|
* @see {@link WunderbaumNode.applyCommand}
|
|
739
746
|
*/
|
|
740
|
-
applyCommand(
|
|
747
|
+
applyCommand(
|
|
748
|
+
cmd: ApplyCommandType,
|
|
749
|
+
node: WunderbaumNode,
|
|
750
|
+
options?: ApplyCommandOptions
|
|
751
|
+
): any;
|
|
741
752
|
|
|
742
753
|
/**
|
|
743
754
|
* Apply a modification or navigation operation.
|
|
@@ -758,7 +769,7 @@ export class Wunderbaum {
|
|
|
758
769
|
applyCommand(
|
|
759
770
|
cmd: ApplyCommandType,
|
|
760
771
|
nodeOrOpts?: WunderbaumNode | any,
|
|
761
|
-
options?:
|
|
772
|
+
options?: ApplyCommandOptions
|
|
762
773
|
): any {
|
|
763
774
|
let // clipboard,
|
|
764
775
|
node,
|
|
@@ -1112,7 +1123,7 @@ export class Wunderbaum {
|
|
|
1112
1123
|
findRelatedNode(node: WunderbaumNode, where: string, includeHidden = false) {
|
|
1113
1124
|
let res = null;
|
|
1114
1125
|
const pageSize = Math.floor(
|
|
1115
|
-
this.
|
|
1126
|
+
this.listContainerElement.clientHeight / ROW_HEIGHT
|
|
1116
1127
|
);
|
|
1117
1128
|
|
|
1118
1129
|
switch (where) {
|
|
@@ -1270,14 +1281,14 @@ export class Wunderbaum {
|
|
|
1270
1281
|
* @returns {object} Return a {node: WunderbaumNode, region: TYPE} object
|
|
1271
1282
|
* TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined
|
|
1272
1283
|
*/
|
|
1273
|
-
static getEventInfo(event: Event) {
|
|
1284
|
+
static getEventInfo(event: Event): WbEventInfo {
|
|
1274
1285
|
let target = <Element>event.target,
|
|
1275
1286
|
cl = target.classList,
|
|
1276
1287
|
parentCol = target.closest("span.wb-col") as HTMLSpanElement,
|
|
1277
1288
|
node = Wunderbaum.getNode(target),
|
|
1278
1289
|
tree = node ? node.tree : Wunderbaum.getTree(event),
|
|
1279
|
-
res = {
|
|
1280
|
-
tree: tree
|
|
1290
|
+
res: WbEventInfo = {
|
|
1291
|
+
tree: tree!,
|
|
1281
1292
|
node: node,
|
|
1282
1293
|
region: NodeRegion.unknown,
|
|
1283
1294
|
colDef: undefined,
|
|
@@ -1324,15 +1335,6 @@ export class Wunderbaum {
|
|
|
1324
1335
|
return res;
|
|
1325
1336
|
}
|
|
1326
1337
|
|
|
1327
|
-
// /** Return a string describing the affected node region for a mouse event.
|
|
1328
|
-
// *
|
|
1329
|
-
// * @param {Event} event Mouse event, e.g. click, mousemove, ...
|
|
1330
|
-
// * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined
|
|
1331
|
-
// */
|
|
1332
|
-
// getEventNodeRegion(event: Event) {
|
|
1333
|
-
// return this.getEventInfo(event).region;
|
|
1334
|
-
// }
|
|
1335
|
-
|
|
1336
1338
|
/**
|
|
1337
1339
|
* Return readable string representation for this instance.
|
|
1338
1340
|
* @internal
|
|
@@ -1445,7 +1447,8 @@ export class Wunderbaum {
|
|
|
1445
1447
|
const vpRowBottom = vpRowTop + ROW_HEIGHT;
|
|
1446
1448
|
const topNode = options?.topNode;
|
|
1447
1449
|
|
|
1448
|
-
// this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts );
|
|
1450
|
+
// this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts , options);
|
|
1451
|
+
|
|
1449
1452
|
let newScrollTop: number | null = null;
|
|
1450
1453
|
if (vpRowTop >= vpTop) {
|
|
1451
1454
|
if (vpRowBottom <= vpHeight) {
|
|
@@ -1481,9 +1484,6 @@ export class Wunderbaum {
|
|
|
1481
1484
|
const fixedWidth = this.columns[0]._widthPx!;
|
|
1482
1485
|
const vpWidth = this.element.clientWidth;
|
|
1483
1486
|
const scrollLeft = this.element.scrollLeft;
|
|
1484
|
-
// if (scrollLeft <= 0) {
|
|
1485
|
-
// return; // Not scrolled horizontally: Nothing to do
|
|
1486
|
-
// }
|
|
1487
1487
|
const colElem = this.getActiveColElem()!;
|
|
1488
1488
|
const colLeft = Number.parseInt(colElem?.style.left, 10);
|
|
1489
1489
|
const colRight = colLeft + Number.parseInt(colElem?.style.width, 10);
|
|
@@ -1496,13 +1496,13 @@ export class Wunderbaum {
|
|
|
1496
1496
|
// The current column is scrolled outside the right side
|
|
1497
1497
|
newLeft = colRight - vpWidth;
|
|
1498
1498
|
}
|
|
1499
|
+
newLeft = Math.max(0, newLeft);
|
|
1499
1500
|
// util.assert(node._rowIdx != null);
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1501
|
+
this.log(
|
|
1502
|
+
`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`
|
|
1503
|
+
);
|
|
1503
1504
|
this.element.scrollLeft = newLeft;
|
|
1504
1505
|
// this.setModified(ChangeType.vscroll);
|
|
1505
|
-
// }
|
|
1506
1506
|
}
|
|
1507
1507
|
/**
|
|
1508
1508
|
* Set column #colIdx to 'active'.
|
|
@@ -1555,12 +1555,16 @@ export class Wunderbaum {
|
|
|
1555
1555
|
}
|
|
1556
1556
|
|
|
1557
1557
|
/** Schedule an update request to reflect a tree change. */
|
|
1558
|
-
setModified(change: ChangeType, options?:
|
|
1558
|
+
setModified(change: ChangeType, options?: SetModifiedOptions): void;
|
|
1559
1559
|
|
|
1560
1560
|
/** Schedule an update request to reflect a single node modification.
|
|
1561
1561
|
* @see {@link WunderbaumNode.setModified}
|
|
1562
1562
|
*/
|
|
1563
|
-
setModified(
|
|
1563
|
+
setModified(
|
|
1564
|
+
change: ChangeType,
|
|
1565
|
+
node: WunderbaumNode,
|
|
1566
|
+
options?: SetModifiedOptions
|
|
1567
|
+
): void;
|
|
1564
1568
|
|
|
1565
1569
|
setModified(
|
|
1566
1570
|
change: ChangeType,
|
|
@@ -1662,26 +1666,26 @@ export class Wunderbaum {
|
|
|
1662
1666
|
}
|
|
1663
1667
|
|
|
1664
1668
|
/** Set the tree's navigation mode option. */
|
|
1665
|
-
setNavigationOption(mode:
|
|
1666
|
-
if (!this.isGrid() && mode !==
|
|
1669
|
+
setNavigationOption(mode: NavModeEnum, reset = false) {
|
|
1670
|
+
if (!this.isGrid() && mode !== NavModeEnum.row) {
|
|
1667
1671
|
this.logWarn("Plain trees only support row navigation mode.");
|
|
1668
1672
|
return;
|
|
1669
1673
|
}
|
|
1670
1674
|
this.options.navigationModeOption = mode;
|
|
1671
1675
|
|
|
1672
1676
|
switch (mode) {
|
|
1673
|
-
case
|
|
1677
|
+
case NavModeEnum.cell:
|
|
1674
1678
|
this.setCellNav(true);
|
|
1675
1679
|
break;
|
|
1676
|
-
case
|
|
1680
|
+
case NavModeEnum.row:
|
|
1677
1681
|
this.setCellNav(false);
|
|
1678
1682
|
break;
|
|
1679
|
-
case
|
|
1683
|
+
case NavModeEnum.startCell:
|
|
1680
1684
|
if (reset) {
|
|
1681
1685
|
this.setCellNav(true);
|
|
1682
1686
|
}
|
|
1683
1687
|
break;
|
|
1684
|
-
case
|
|
1688
|
+
case NavModeEnum.startRow:
|
|
1685
1689
|
if (reset) {
|
|
1686
1690
|
this.setCellNav(false);
|
|
1687
1691
|
}
|
|
@@ -1714,7 +1718,7 @@ export class Wunderbaum {
|
|
|
1714
1718
|
}
|
|
1715
1719
|
}
|
|
1716
1720
|
/** Update column headers and width. */
|
|
1717
|
-
updateColumns(options?:
|
|
1721
|
+
updateColumns(options?: UpdateColumnsOptions) {
|
|
1718
1722
|
options = Object.assign({ calculateCols: true, updateRows: true }, options);
|
|
1719
1723
|
const defaultMinWidth = 4;
|
|
1720
1724
|
const vpWidth = this.element.clientWidth;
|
|
@@ -1789,7 +1793,7 @@ export class Wunderbaum {
|
|
|
1789
1793
|
// 'position: fixed' requires that the content has the correct size
|
|
1790
1794
|
const tw = `${totalWidth}px`;
|
|
1791
1795
|
this.headerElement.style.width = tw;
|
|
1792
|
-
this.
|
|
1796
|
+
this.listContainerElement!.style.width = tw;
|
|
1793
1797
|
// }
|
|
1794
1798
|
|
|
1795
1799
|
// Every column has now a calculated `_ofsPx` and `_widthPx`
|
|
@@ -1837,6 +1841,9 @@ export class Wunderbaum {
|
|
|
1837
1841
|
resizer = '<span class="wb-col-resizer"></span>';
|
|
1838
1842
|
}
|
|
1839
1843
|
colElem.innerHTML = `<span class="wb-col-title"${tooltip}>${title}</span>${resizer}`;
|
|
1844
|
+
if (this.isCellNav()) {
|
|
1845
|
+
colElem.classList.toggle("wb-active", i === this.activeColIdx);
|
|
1846
|
+
}
|
|
1840
1847
|
}
|
|
1841
1848
|
}
|
|
1842
1849
|
|
|
@@ -1879,7 +1886,7 @@ export class Wunderbaum {
|
|
|
1879
1886
|
this.changeRedrawRequestPending = false;
|
|
1880
1887
|
this.changeScrollRequestPending = false;
|
|
1881
1888
|
|
|
1882
|
-
let height = this.
|
|
1889
|
+
let height = this.listContainerElement.clientHeight;
|
|
1883
1890
|
// We cannot get the height for absolute positioned parent, so look at first col
|
|
1884
1891
|
// let headerHeight = this.headerElement.clientHeight
|
|
1885
1892
|
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
@@ -1890,7 +1897,7 @@ export class Wunderbaum {
|
|
|
1890
1897
|
|
|
1891
1898
|
if (Math.abs(height - wantHeight) > 1.0) {
|
|
1892
1899
|
// this.log("resize", height, wantHeight);
|
|
1893
|
-
this.
|
|
1900
|
+
this.listContainerElement.style.height = wantHeight + "px";
|
|
1894
1901
|
height = wantHeight;
|
|
1895
1902
|
}
|
|
1896
1903
|
// console.profile(`_updateViewportImmediately()`)
|
|
@@ -2028,7 +2035,7 @@ export class Wunderbaum {
|
|
|
2028
2035
|
// Resize tree container
|
|
2029
2036
|
this.nodeListElement.style.height = `${top}px`;
|
|
2030
2037
|
// this.log(
|
|
2031
|
-
// `
|
|
2038
|
+
// `_updateRows(scrollOfs:${ofs}, ${startIdx}..${endIdx})`,
|
|
2032
2039
|
// this.nodeListElement.style.height
|
|
2033
2040
|
// );
|
|
2034
2041
|
// this.logTimeEnd(label);
|
|
@@ -2065,7 +2072,10 @@ export class Wunderbaum {
|
|
|
2065
2072
|
* {start: First tree node, reverse: false, includeSelf: true, includeHidden: false, wrap: false}
|
|
2066
2073
|
* @returns {boolean} false if iteration was canceled
|
|
2067
2074
|
*/
|
|
2068
|
-
visitRows(
|
|
2075
|
+
visitRows(
|
|
2076
|
+
callback: (node: WunderbaumNode) => any,
|
|
2077
|
+
options?: VisitRowsOptions
|
|
2078
|
+
): boolean {
|
|
2069
2079
|
if (!this.root.hasChildren()) {
|
|
2070
2080
|
return false;
|
|
2071
2081
|
}
|
|
@@ -2146,7 +2156,7 @@ export class Wunderbaum {
|
|
|
2146
2156
|
if (!parent && options.wrap) {
|
|
2147
2157
|
this.logDebug("visitRows(): wrap around");
|
|
2148
2158
|
util.assert(options.start, "`wrap` option requires `start`");
|
|
2149
|
-
stopNode = options.start
|
|
2159
|
+
stopNode = options.start!;
|
|
2150
2160
|
options.wrap = false;
|
|
2151
2161
|
parent = this.root;
|
|
2152
2162
|
siblingOfs = 0;
|
|
@@ -2161,22 +2171,22 @@ export class Wunderbaum {
|
|
|
2161
2171
|
*/
|
|
2162
2172
|
protected _visitRowsUp(
|
|
2163
2173
|
callback: (node: WunderbaumNode) => any,
|
|
2164
|
-
|
|
2174
|
+
options: VisitRowsOptions
|
|
2165
2175
|
): boolean {
|
|
2166
2176
|
let children,
|
|
2167
2177
|
idx,
|
|
2168
2178
|
parent,
|
|
2169
|
-
includeHidden = !!
|
|
2170
|
-
node =
|
|
2179
|
+
includeHidden = !!options.includeHidden,
|
|
2180
|
+
node = options.start || this.root.children![0];
|
|
2171
2181
|
|
|
2172
|
-
if (
|
|
2182
|
+
if (options.includeSelf !== false) {
|
|
2173
2183
|
if (callback(node) === false) {
|
|
2174
2184
|
return false;
|
|
2175
2185
|
}
|
|
2176
2186
|
}
|
|
2177
2187
|
while (true) {
|
|
2178
2188
|
parent = node.parent;
|
|
2179
|
-
children = parent.children
|
|
2189
|
+
children = parent.children!;
|
|
2180
2190
|
|
|
2181
2191
|
if (children[0] === node) {
|
|
2182
2192
|
// If this is already the first sibling, goto parent
|