wunderbaum 0.2.0 → 0.3.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/LICENSE +1 -1
- package/README.md +1 -7
- package/dist/wunderbaum.css +3 -3
- package/dist/wunderbaum.d.ts +190 -101
- package/dist/wunderbaum.esm.js +422 -206
- package/dist/wunderbaum.esm.min.js +35 -35
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +422 -206
- package/dist/wunderbaum.umd.min.js +44 -44
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/common.ts +9 -1
- package/src/deferred.ts +1 -1
- package/src/drag_observer.ts +1 -1
- package/src/types.ts +99 -70
- package/src/util.ts +61 -10
- package/src/wb_ext_dnd.ts +27 -7
- package/src/wb_ext_edit.ts +3 -3
- package/src/wb_ext_filter.ts +1 -1
- package/src/wb_ext_grid.ts +1 -1
- package/src/wb_ext_keynav.ts +1 -1
- package/src/wb_ext_logger.ts +1 -1
- package/src/wb_extension_base.ts +1 -1
- package/src/wb_node.ts +130 -30
- package/src/wb_options.ts +9 -3
- package/src/wunderbaum.scss +6 -3
- package/src/wunderbaum.ts +199 -143
package/src/wunderbaum.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A treegrid control.
|
|
5
5
|
*
|
|
6
|
-
* Copyright (c) 2021-
|
|
6
|
+
* Copyright (c) 2021-2023, Martin Wendt (https://wwWendt.de).
|
|
7
7
|
* https://github.com/mar10/wunderbaum
|
|
8
8
|
*
|
|
9
9
|
* Released under the MIT license.
|
|
@@ -38,14 +38,17 @@ import {
|
|
|
38
38
|
WbEventInfo,
|
|
39
39
|
ApplyCommandOptions,
|
|
40
40
|
AddChildrenOptions,
|
|
41
|
-
UpdateColumnsOptions,
|
|
42
41
|
VisitRowsOptions,
|
|
43
42
|
NodeFilterCallback,
|
|
44
43
|
FilterNodesOptions,
|
|
44
|
+
RenderFlag,
|
|
45
|
+
NodeVisitCallback,
|
|
46
|
+
SortCallback,
|
|
45
47
|
} from "./types";
|
|
46
48
|
import {
|
|
47
49
|
DEFAULT_DEBUGLEVEL,
|
|
48
50
|
makeNodeTitleStartMatcher,
|
|
51
|
+
nodeTitleSorter,
|
|
49
52
|
RENDER_MAX_PREFETCH,
|
|
50
53
|
ROW_HEIGHT,
|
|
51
54
|
} from "./common";
|
|
@@ -104,6 +107,7 @@ export class Wunderbaum {
|
|
|
104
107
|
protected refKeyMap = new Map<string, Set<WunderbaumNode>>();
|
|
105
108
|
protected treeRowCount = 0;
|
|
106
109
|
protected _disableUpdateCount = 0;
|
|
110
|
+
protected _disableUpdateIgnoreCount = 0;
|
|
107
111
|
|
|
108
112
|
/** Currently active node if any. */
|
|
109
113
|
public activeNode: WunderbaumNode | null = null;
|
|
@@ -119,8 +123,7 @@ export class Wunderbaum {
|
|
|
119
123
|
protected resizeObserver: ResizeObserver;
|
|
120
124
|
|
|
121
125
|
// Modification Status
|
|
122
|
-
protected
|
|
123
|
-
protected changeScrollRequestPending = false;
|
|
126
|
+
protected pendingChangeTypes: Set<RenderFlag> = new Set();
|
|
124
127
|
|
|
125
128
|
/** A Promise that is resolved when the tree was initialized (similar to `init(e)` event). */
|
|
126
129
|
public readonly ready: Promise<any>;
|
|
@@ -163,6 +166,7 @@ export class Wunderbaum {
|
|
|
163
166
|
showSpinner: false,
|
|
164
167
|
checkbox: false,
|
|
165
168
|
minExpandLevel: 0,
|
|
169
|
+
emptyChildListExpandable: false,
|
|
166
170
|
updateThrottleWait: 200,
|
|
167
171
|
skeleton: false,
|
|
168
172
|
connectTopBreadcrumb: null, // HTMLElement that receives the top nodes breadcrumb
|
|
@@ -362,12 +366,12 @@ export class Wunderbaum {
|
|
|
362
366
|
// --- Bind listeners
|
|
363
367
|
this.element.addEventListener("scroll", (e: Event) => {
|
|
364
368
|
// this.log(`scroll, scrollTop:${e.target.scrollTop}`, e);
|
|
365
|
-
this.setModified(ChangeType.
|
|
369
|
+
this.setModified(ChangeType.scroll);
|
|
366
370
|
});
|
|
367
371
|
|
|
368
372
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
369
|
-
this.setModified(ChangeType.vscroll);
|
|
370
373
|
// this.log("ResizeObserver: Size changed", entries);
|
|
374
|
+
this.setModified(ChangeType.resize);
|
|
371
375
|
});
|
|
372
376
|
this.resizeObserver.observe(this.element);
|
|
373
377
|
|
|
@@ -978,7 +982,7 @@ export class Wunderbaum {
|
|
|
978
982
|
(this.options as any)[name] = value;
|
|
979
983
|
switch (name) {
|
|
980
984
|
case "checkbox":
|
|
981
|
-
this.setModified(ChangeType.any
|
|
985
|
+
this.setModified(ChangeType.any);
|
|
982
986
|
break;
|
|
983
987
|
case "enabled":
|
|
984
988
|
this.setEnabled(!!value);
|
|
@@ -1312,8 +1316,9 @@ export class Wunderbaum {
|
|
|
1312
1316
|
if (cl.contains("wb-title")) {
|
|
1313
1317
|
res.region = NodeRegion.title;
|
|
1314
1318
|
} else if (cl.contains("wb-expander")) {
|
|
1315
|
-
res.region =
|
|
1316
|
-
|
|
1319
|
+
res.region = node!.isExpandable()
|
|
1320
|
+
? NodeRegion.expander
|
|
1321
|
+
: NodeRegion.prefix;
|
|
1317
1322
|
} else if (cl.contains("wb-checkbox")) {
|
|
1318
1323
|
res.region = NodeRegion.checkbox;
|
|
1319
1324
|
} else if (cl.contains("wb-icon")) {
|
|
@@ -1483,7 +1488,7 @@ export class Wunderbaum {
|
|
|
1483
1488
|
// Make sure the topNode is always visible
|
|
1484
1489
|
this.scrollTo(topNode);
|
|
1485
1490
|
}
|
|
1486
|
-
// this.setModified(ChangeType.
|
|
1491
|
+
// this.setModified(ChangeType.scroll);
|
|
1487
1492
|
}
|
|
1488
1493
|
}
|
|
1489
1494
|
|
|
@@ -1514,7 +1519,7 @@ export class Wunderbaum {
|
|
|
1514
1519
|
`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`
|
|
1515
1520
|
);
|
|
1516
1521
|
this.element.scrollLeft = newLeft;
|
|
1517
|
-
// this.setModified(ChangeType.
|
|
1522
|
+
// this.setModified(ChangeType.scroll);
|
|
1518
1523
|
}
|
|
1519
1524
|
/**
|
|
1520
1525
|
* Set column #colIdx to 'active'.
|
|
@@ -1566,11 +1571,19 @@ export class Wunderbaum {
|
|
|
1566
1571
|
}
|
|
1567
1572
|
}
|
|
1568
1573
|
|
|
1569
|
-
/**
|
|
1574
|
+
/**
|
|
1575
|
+
* Schedule an update request to reflect a tree change.
|
|
1576
|
+
* The render operation is async and debounced unless the `immediate` option
|
|
1577
|
+
* is set.
|
|
1578
|
+
* Use {@link WunderbaumNode.setModified()} if only a single node has changed,
|
|
1579
|
+
* or {@link WunderbaumNode.render()}) to pass special options.
|
|
1580
|
+
*/
|
|
1570
1581
|
setModified(change: ChangeType, options?: SetModifiedOptions): void;
|
|
1571
1582
|
|
|
1572
|
-
/**
|
|
1573
|
-
*
|
|
1583
|
+
/**
|
|
1584
|
+
* Update a row to reflect a single node's modification.
|
|
1585
|
+
*
|
|
1586
|
+
* @see {@link WunderbaumNode.setModified()}, {@link WunderbaumNode.render()}
|
|
1574
1587
|
*/
|
|
1575
1588
|
setModified(
|
|
1576
1589
|
change: ChangeType,
|
|
@@ -1588,35 +1601,41 @@ export class Wunderbaum {
|
|
|
1588
1601
|
// this.log(
|
|
1589
1602
|
// `IGNORED setModified(${change}) node=${node} (disable level ${this._disableUpdateCount})`
|
|
1590
1603
|
// );
|
|
1604
|
+
this._disableUpdateIgnoreCount++;
|
|
1591
1605
|
return;
|
|
1592
1606
|
}
|
|
1593
1607
|
// this.log(`setModified(${change}) node=${node}`);
|
|
1594
1608
|
if (!(node instanceof WunderbaumNode)) {
|
|
1595
1609
|
options = node;
|
|
1610
|
+
node = null;
|
|
1596
1611
|
}
|
|
1597
1612
|
const immediate = !!util.getOption(options, "immediate");
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1600
|
-
this.visit((n) => {
|
|
1601
|
-
n.removeMarkup();
|
|
1602
|
-
});
|
|
1603
|
-
}
|
|
1613
|
+
const RF = RenderFlag;
|
|
1614
|
+
const pending = this.pendingChangeTypes;
|
|
1604
1615
|
|
|
1605
|
-
let callUpdate = false;
|
|
1606
1616
|
switch (change) {
|
|
1607
1617
|
case ChangeType.any:
|
|
1618
|
+
case ChangeType.colStructure:
|
|
1619
|
+
pending.add(RF.header);
|
|
1620
|
+
pending.add(RF.clearMarkup);
|
|
1621
|
+
pending.add(RF.redraw);
|
|
1622
|
+
pending.add(RF.scroll);
|
|
1623
|
+
break;
|
|
1624
|
+
case ChangeType.resize:
|
|
1625
|
+
// case ChangeType.colWidth:
|
|
1626
|
+
pending.add(RF.header);
|
|
1627
|
+
pending.add(RF.redraw);
|
|
1628
|
+
break;
|
|
1608
1629
|
case ChangeType.structure:
|
|
1609
|
-
|
|
1610
|
-
this.changeRedrawRequestPending = true;
|
|
1611
|
-
callUpdate = true;
|
|
1630
|
+
pending.add(RF.redraw);
|
|
1612
1631
|
break;
|
|
1613
|
-
case ChangeType.
|
|
1614
|
-
|
|
1615
|
-
callUpdate = true;
|
|
1632
|
+
case ChangeType.scroll:
|
|
1633
|
+
pending.add(RF.scroll);
|
|
1616
1634
|
break;
|
|
1617
1635
|
case ChangeType.row:
|
|
1618
1636
|
case ChangeType.data:
|
|
1619
1637
|
case ChangeType.status:
|
|
1638
|
+
util.assert(node, `Option '${change}' requires a node.`);
|
|
1620
1639
|
// Single nodes are immediately updated if already inside the viewport
|
|
1621
1640
|
// (otherwise we can ignore)
|
|
1622
1641
|
if (node._rowElem) {
|
|
@@ -1624,9 +1643,18 @@ export class Wunderbaum {
|
|
|
1624
1643
|
}
|
|
1625
1644
|
break;
|
|
1626
1645
|
default:
|
|
1627
|
-
util.error(`Invalid change type ${change}
|
|
1646
|
+
util.error(`Invalid change type '${change}'.`);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
if (change === ChangeType.colStructure) {
|
|
1650
|
+
const isGrid = this.isGrid();
|
|
1651
|
+
this.element.classList.toggle("wb-grid", isGrid);
|
|
1652
|
+
if (!isGrid && this.isCellNav()) {
|
|
1653
|
+
this.setCellNav(false);
|
|
1654
|
+
}
|
|
1628
1655
|
}
|
|
1629
|
-
|
|
1656
|
+
|
|
1657
|
+
if (pending.size > 0) {
|
|
1630
1658
|
if (immediate) {
|
|
1631
1659
|
this._updateViewportImmediately();
|
|
1632
1660
|
} else {
|
|
@@ -1703,7 +1731,7 @@ export class Wunderbaum {
|
|
|
1703
1731
|
}
|
|
1704
1732
|
break;
|
|
1705
1733
|
default:
|
|
1706
|
-
util.error(`Invalid mode '${mode}'
|
|
1734
|
+
util.error(`Invalid mode '${mode}'.`);
|
|
1707
1735
|
}
|
|
1708
1736
|
}
|
|
1709
1737
|
|
|
@@ -1714,6 +1742,7 @@ export class Wunderbaum {
|
|
|
1714
1742
|
): WunderbaumNode | null {
|
|
1715
1743
|
return this.root.setStatus(status, options);
|
|
1716
1744
|
}
|
|
1745
|
+
|
|
1717
1746
|
/** Add or redefine node type definitions. */
|
|
1718
1747
|
setTypes(types: any, replace = true) {
|
|
1719
1748
|
util.assert(util.isPlainObject(types));
|
|
@@ -1729,14 +1758,29 @@ export class Wunderbaum {
|
|
|
1729
1758
|
}
|
|
1730
1759
|
}
|
|
1731
1760
|
}
|
|
1732
|
-
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* Sort nodes list by title or custom criteria.
|
|
1764
|
+
* @param {function} cmp custom compare function(a, b) that returns -1, 0, or 1
|
|
1765
|
+
* (defaults to sorting by title).
|
|
1766
|
+
* @param {boolean} deep pass true to sort all descendant nodes recursively
|
|
1767
|
+
*/
|
|
1768
|
+
sortChildren(
|
|
1769
|
+
cmp: SortCallback | null = nodeTitleSorter,
|
|
1770
|
+
deep: boolean = false
|
|
1771
|
+
): void {
|
|
1772
|
+
this.root.sortChildren(cmp, deep);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
/**
|
|
1776
|
+
* Update column headers and column width.
|
|
1733
1777
|
* Return true if at least one column width changed.
|
|
1734
1778
|
*/
|
|
1735
|
-
|
|
1736
|
-
|
|
1779
|
+
// _updateColumnWidths(options?: UpdateColumnsOptions): boolean {
|
|
1780
|
+
_updateColumnWidths(): boolean {
|
|
1781
|
+
// options = Object.assign({ updateRows: true, renderMarkup: false }, options);
|
|
1737
1782
|
const defaultMinWidth = 4;
|
|
1738
1783
|
const vpWidth = this.element.clientWidth;
|
|
1739
|
-
const isGrid = this.isGrid();
|
|
1740
1784
|
// Shorten last column width to avoid h-scrollbar
|
|
1741
1785
|
const FIX_ADJUST_LAST_COL = 2;
|
|
1742
1786
|
const columns = this.columns;
|
|
@@ -1747,76 +1791,74 @@ export class Wunderbaum {
|
|
|
1747
1791
|
let fixedWidth = 0;
|
|
1748
1792
|
let modified = false;
|
|
1749
1793
|
|
|
1750
|
-
this.element.classList.toggle("wb-grid", isGrid);
|
|
1751
|
-
if (!isGrid && this.isCellNav()) {
|
|
1752
|
-
|
|
1753
|
-
}
|
|
1794
|
+
// this.element.classList.toggle("wb-grid", isGrid);
|
|
1795
|
+
// if (!isGrid && this.isCellNav()) {
|
|
1796
|
+
// this.setCellNav(false);
|
|
1797
|
+
// }
|
|
1754
1798
|
|
|
1755
|
-
if (options.calculateCols) {
|
|
1756
|
-
|
|
1757
|
-
|
|
1799
|
+
// if (options.calculateCols) {
|
|
1800
|
+
if (col0.id !== "*") {
|
|
1801
|
+
throw new Error(`First column must have id '*': got '${col0.id}'.`);
|
|
1802
|
+
}
|
|
1803
|
+
// Gather width definitions
|
|
1804
|
+
this._columnsById = {};
|
|
1805
|
+
for (let col of columns) {
|
|
1806
|
+
this._columnsById[<string>col.id] = col;
|
|
1807
|
+
let cw = col.width;
|
|
1808
|
+
if (col.id === "*" && col !== col0) {
|
|
1809
|
+
throw new Error(
|
|
1810
|
+
`Column id '*' must be defined only once: '${col.title}'.`
|
|
1811
|
+
);
|
|
1758
1812
|
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1813
|
+
|
|
1814
|
+
if (!cw || cw === "*") {
|
|
1815
|
+
col._weight = 1.0;
|
|
1816
|
+
totalWeight += 1.0;
|
|
1817
|
+
} else if (typeof cw === "number") {
|
|
1818
|
+
col._weight = cw;
|
|
1819
|
+
totalWeight += cw;
|
|
1820
|
+
} else if (typeof cw === "string" && cw.endsWith("px")) {
|
|
1821
|
+
col._weight = 0;
|
|
1822
|
+
let px = parseFloat(cw.slice(0, -2));
|
|
1823
|
+
if (col._widthPx != px) {
|
|
1824
|
+
modified = true;
|
|
1825
|
+
col._widthPx = px;
|
|
1768
1826
|
}
|
|
1827
|
+
fixedWidth += px;
|
|
1828
|
+
} else {
|
|
1829
|
+
util.error(
|
|
1830
|
+
`Invalid column width: ${cw} (expected string ending with 'px' or number, e.g. "<num>px" or <int>).`
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
// Share remaining space between non-fixed columns
|
|
1835
|
+
const restPx = Math.max(0, vpWidth - fixedWidth);
|
|
1836
|
+
let ofsPx = 0;
|
|
1769
1837
|
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
if (col._widthPx != px) {
|
|
1780
|
-
modified = true;
|
|
1781
|
-
col._widthPx = px;
|
|
1782
|
-
}
|
|
1783
|
-
fixedWidth += px;
|
|
1838
|
+
for (let col of columns) {
|
|
1839
|
+
let minWidth: number;
|
|
1840
|
+
|
|
1841
|
+
if (col._weight) {
|
|
1842
|
+
const cmw = col.minWidth;
|
|
1843
|
+
if (typeof cmw === "number") {
|
|
1844
|
+
minWidth = cmw;
|
|
1845
|
+
} else if (typeof cmw === "string" && cmw.endsWith("px")) {
|
|
1846
|
+
minWidth = parseFloat(cmw.slice(0, -2));
|
|
1784
1847
|
} else {
|
|
1785
|
-
|
|
1786
|
-
`Invalid column width: ${cw} (expected string ending with 'px' or number, e.g. "<num>px" or <int>)`
|
|
1787
|
-
);
|
|
1848
|
+
minWidth = defaultMinWidth;
|
|
1788
1849
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
for (let col of columns) {
|
|
1795
|
-
let minWidth: number;
|
|
1796
|
-
|
|
1797
|
-
if (col._weight) {
|
|
1798
|
-
const cmw = col.minWidth;
|
|
1799
|
-
if (typeof cmw === "number") {
|
|
1800
|
-
minWidth = cmw;
|
|
1801
|
-
} else if (typeof cmw === "string" && cmw.endsWith("px")) {
|
|
1802
|
-
minWidth = parseFloat(cmw.slice(0, -2));
|
|
1803
|
-
} else {
|
|
1804
|
-
minWidth = defaultMinWidth;
|
|
1805
|
-
}
|
|
1806
|
-
const px = Math.max(minWidth, (restPx * col._weight) / totalWeight);
|
|
1807
|
-
if (col._widthPx != px) {
|
|
1808
|
-
modified = true;
|
|
1809
|
-
col._widthPx = px;
|
|
1810
|
-
}
|
|
1850
|
+
const px = Math.max(minWidth, (restPx * col._weight) / totalWeight);
|
|
1851
|
+
if (col._widthPx != px) {
|
|
1852
|
+
modified = true;
|
|
1853
|
+
col._widthPx = px;
|
|
1811
1854
|
}
|
|
1812
|
-
col._ofsPx = ofsPx;
|
|
1813
|
-
ofsPx += col._widthPx!;
|
|
1814
1855
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1856
|
+
col._ofsPx = ofsPx;
|
|
1857
|
+
ofsPx += col._widthPx!;
|
|
1817
1858
|
}
|
|
1818
|
-
|
|
1819
|
-
|
|
1859
|
+
columns[columns.length - 1]._widthPx! -= FIX_ADJUST_LAST_COL;
|
|
1860
|
+
totalWidth = ofsPx - FIX_ADJUST_LAST_COL;
|
|
1861
|
+
|
|
1820
1862
|
const tw = `${totalWidth}px`;
|
|
1821
1863
|
this.headerElement.style.width = tw;
|
|
1822
1864
|
this.listContainerElement!.style.width = tw;
|
|
@@ -1826,12 +1868,14 @@ export class Wunderbaum {
|
|
|
1826
1868
|
// this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element);
|
|
1827
1869
|
// console.trace();
|
|
1828
1870
|
// util.error("BREAK");
|
|
1829
|
-
if (modified) {
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1871
|
+
// if (modified) {
|
|
1872
|
+
// this._renderHeaderMarkup();
|
|
1873
|
+
// if (options.renderMarkup) {
|
|
1874
|
+
// this.setModified(ChangeType.header, { removeMarkup: true });
|
|
1875
|
+
// } else if (options.updateRows) {
|
|
1876
|
+
// this._updateRows();
|
|
1877
|
+
// }
|
|
1878
|
+
// }
|
|
1835
1879
|
return modified;
|
|
1836
1880
|
}
|
|
1837
1881
|
|
|
@@ -1885,7 +1929,7 @@ export class Wunderbaum {
|
|
|
1885
1929
|
* pending async changes if any.
|
|
1886
1930
|
*/
|
|
1887
1931
|
updatePendingModifications() {
|
|
1888
|
-
if (this.
|
|
1932
|
+
if (this.pendingChangeTypes.size > 0) {
|
|
1889
1933
|
this._updateViewportImmediately();
|
|
1890
1934
|
}
|
|
1891
1935
|
}
|
|
@@ -1900,40 +1944,58 @@ export class Wunderbaum {
|
|
|
1900
1944
|
* @internal
|
|
1901
1945
|
*/
|
|
1902
1946
|
protected _updateViewportImmediately() {
|
|
1903
|
-
// Shorten container height to avoid v-scrollbar
|
|
1904
|
-
const FIX_ADJUST_HEIGHT = 1;
|
|
1905
|
-
|
|
1906
1947
|
if (this._disableUpdateCount) {
|
|
1907
1948
|
this.log(
|
|
1908
|
-
`
|
|
1949
|
+
`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount})`
|
|
1909
1950
|
);
|
|
1951
|
+
this._disableUpdateIgnoreCount++;
|
|
1910
1952
|
return;
|
|
1911
1953
|
}
|
|
1912
|
-
const newNodesOnly = !this.changeRedrawRequestPending;
|
|
1913
|
-
this.changeRedrawRequestPending = false;
|
|
1914
|
-
this.changeScrollRequestPending = false;
|
|
1915
1954
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
1920
|
-
// const headerHeight = this.options.headerHeightPx;
|
|
1921
|
-
const headerHeight = this.headerElement.clientHeight; // May be 0
|
|
1922
|
-
const wantHeight =
|
|
1923
|
-
this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
|
|
1955
|
+
// Shorten container height to avoid v-scrollbar
|
|
1956
|
+
const FIX_ADJUST_HEIGHT = 1;
|
|
1957
|
+
const RF = RenderFlag;
|
|
1924
1958
|
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
this.listContainerElement.style.height = wantHeight + "px";
|
|
1928
|
-
height = wantHeight;
|
|
1929
|
-
}
|
|
1930
|
-
// console.profile(`_updateViewportImmediately()`)
|
|
1959
|
+
const pending = new Set(this.pendingChangeTypes);
|
|
1960
|
+
this.pendingChangeTypes.clear();
|
|
1931
1961
|
|
|
1932
|
-
const
|
|
1962
|
+
const scrollOnly = pending.has(RF.scroll) && pending.size === 1;
|
|
1963
|
+
if (scrollOnly) {
|
|
1964
|
+
this._updateRows({ newNodesOnly: true });
|
|
1965
|
+
// this.log("_updateViewportImmediately(): scroll only.");
|
|
1966
|
+
} else {
|
|
1967
|
+
this.log("_updateViewportImmediately():", pending);
|
|
1968
|
+
let height = this.listContainerElement.clientHeight;
|
|
1969
|
+
// We cannot get the height for absolute positioned parent, so look at first col
|
|
1970
|
+
// let headerHeight = this.headerElement.clientHeight
|
|
1971
|
+
// let headerHeight = this.headerElement.children[0].children[0].clientHeight;
|
|
1972
|
+
// const headerHeight = this.options.headerHeightPx;
|
|
1973
|
+
const headerHeight = this.headerElement.clientHeight; // May be 0
|
|
1974
|
+
const wantHeight =
|
|
1975
|
+
this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
|
|
1976
|
+
|
|
1977
|
+
if (Math.abs(height - wantHeight) > 1.0) {
|
|
1978
|
+
// this.log("resize", height, wantHeight);
|
|
1979
|
+
this.listContainerElement.style.height = wantHeight + "px";
|
|
1980
|
+
height = wantHeight;
|
|
1981
|
+
}
|
|
1982
|
+
// console.profile(`_updateViewportImmediately()`)
|
|
1933
1983
|
|
|
1934
|
-
|
|
1984
|
+
if (pending.has(RF.clearMarkup)) {
|
|
1985
|
+
this.visit((n) => {
|
|
1986
|
+
n.removeMarkup();
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1935
1989
|
|
|
1936
|
-
|
|
1990
|
+
// let widthModified = false;
|
|
1991
|
+
if (pending.has(RF.header)) {
|
|
1992
|
+
// widthModified = this._updateColumnWidths();
|
|
1993
|
+
this._updateColumnWidths();
|
|
1994
|
+
this._renderHeaderMarkup();
|
|
1995
|
+
}
|
|
1996
|
+
this._updateRows();
|
|
1997
|
+
// console.profileEnd(`_updateViewportImmediately()`)
|
|
1998
|
+
}
|
|
1937
1999
|
|
|
1938
2000
|
if (this.options.connectTopBreadcrumb) {
|
|
1939
2001
|
let path = this.getTopmostVpNode(true)?.getPath(false, "title", " > ");
|
|
@@ -2084,25 +2146,17 @@ export class Wunderbaum {
|
|
|
2084
2146
|
}
|
|
2085
2147
|
|
|
2086
2148
|
/**
|
|
2087
|
-
* Call
|
|
2149
|
+
* Call callback(node) for all nodes in vertical order, top down (or bottom up).
|
|
2088
2150
|
*
|
|
2089
|
-
* Note that this considers expansion state, i.e.
|
|
2090
|
-
* are skipped.
|
|
2151
|
+
* Note that this considers expansion state, i.e. filtered nodes and children
|
|
2152
|
+
* of collapsed nodes are skipped, unless `includeHidden` is set.
|
|
2091
2153
|
*
|
|
2092
|
-
* Stop iteration
|
|
2154
|
+
* Stop iteration if callback() returns false.<br>
|
|
2093
2155
|
* Return false if iteration was stopped.
|
|
2094
2156
|
*
|
|
2095
|
-
* @param callback the callback function.
|
|
2096
|
-
* Return false to stop iteration, return "skip" to skip this node and children only.
|
|
2097
|
-
* @param [options]
|
|
2098
|
-
* Defaults:
|
|
2099
|
-
* {start: First tree node, reverse: false, includeSelf: true, includeHidden: false, wrap: false}
|
|
2100
2157
|
* @returns {boolean} false if iteration was canceled
|
|
2101
2158
|
*/
|
|
2102
|
-
visitRows(
|
|
2103
|
-
callback: (node: WunderbaumNode) => any,
|
|
2104
|
-
options?: VisitRowsOptions
|
|
2105
|
-
): boolean {
|
|
2159
|
+
visitRows(callback: NodeVisitCallback, options?: VisitRowsOptions): boolean {
|
|
2106
2160
|
if (!this.root.hasChildren()) {
|
|
2107
2161
|
return false;
|
|
2108
2162
|
}
|
|
@@ -2130,7 +2184,7 @@ export class Wunderbaum {
|
|
|
2130
2184
|
nextIdx = siblings.indexOf(node) + siblingOfs;
|
|
2131
2185
|
util.assert(
|
|
2132
2186
|
nextIdx >= 0,
|
|
2133
|
-
|
|
2187
|
+
`Could not find ${node} in parent's children: ${parent}`
|
|
2134
2188
|
);
|
|
2135
2189
|
|
|
2136
2190
|
for (i = nextIdx; i < siblings.length; i++) {
|
|
@@ -2197,7 +2251,7 @@ export class Wunderbaum {
|
|
|
2197
2251
|
* @internal
|
|
2198
2252
|
*/
|
|
2199
2253
|
protected _visitRowsUp(
|
|
2200
|
-
callback:
|
|
2254
|
+
callback: NodeVisitCallback,
|
|
2201
2255
|
options: VisitRowsOptions
|
|
2202
2256
|
): boolean {
|
|
2203
2257
|
let children,
|
|
@@ -2291,8 +2345,10 @@ export class Wunderbaum {
|
|
|
2291
2345
|
// `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...`
|
|
2292
2346
|
// );
|
|
2293
2347
|
if (this._disableUpdateCount === 0) {
|
|
2294
|
-
|
|
2295
|
-
|
|
2348
|
+
this.logDebug(
|
|
2349
|
+
`enableUpdate(): active again. Re-painting to catch up with ${this._disableUpdateIgnoreCount} ignored update requests...`
|
|
2350
|
+
);
|
|
2351
|
+
this._disableUpdateIgnoreCount = 0;
|
|
2296
2352
|
this.setModified(ChangeType.any, { immediate: true });
|
|
2297
2353
|
}
|
|
2298
2354
|
} else {
|