@syncfusion/ej2-navigations 34.2.2 → 34.2.4
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/ej2-navigations.min.js +2 -2
- package/dist/ej2-navigations.umd.min.js +2 -2
- package/dist/ej2-navigations.umd.min.js.map +1 -1
- package/dist/es6/ej2-navigations.es2015.js +310 -563
- package/dist/es6/ej2-navigations.es2015.js.map +1 -1
- package/dist/es6/ej2-navigations.es5.js +312 -563
- package/dist/es6/ej2-navigations.es5.js.map +1 -1
- package/dist/global/ej2-navigations.min.js +2 -2
- package/dist/global/ej2-navigations.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/package.json +3 -3
- package/src/common/menu-base.js +14 -6
- package/src/treeview/treeview-model.d.ts +1 -0
- package/src/treeview/treeview.d.ts +7 -210
- package/src/treeview/treeview.js +298 -557
- package/styles/bds-lite.css +3 -0
- package/styles/bds.css +3 -0
- package/styles/bootstrap-dark-lite.css +3 -0
- package/styles/bootstrap-dark.css +3 -0
- package/styles/bootstrap-lite.css +3 -0
- package/styles/bootstrap.css +3 -0
- package/styles/bootstrap4-lite.css +3 -0
- package/styles/bootstrap4.css +3 -0
- package/styles/bootstrap5-dark-lite.css +3 -0
- package/styles/bootstrap5-dark.css +3 -0
- package/styles/bootstrap5-lite.css +3 -0
- package/styles/bootstrap5.3-lite.css +3 -0
- package/styles/bootstrap5.3.css +3 -0
- package/styles/bootstrap5.css +3 -0
- package/styles/fabric-dark-lite.css +3 -0
- package/styles/fabric-dark.css +3 -0
- package/styles/fabric-lite.css +3 -0
- package/styles/fabric.css +3 -0
- package/styles/fluent-dark-lite.css +3 -0
- package/styles/fluent-dark.css +3 -0
- package/styles/fluent-lite.css +3 -0
- package/styles/fluent.css +3 -0
- package/styles/fluent2-lite.css +3 -0
- package/styles/fluent2.css +3 -0
- package/styles/highcontrast-light-lite.css +3 -0
- package/styles/highcontrast-light.css +3 -0
- package/styles/highcontrast-lite.css +3 -0
- package/styles/highcontrast.css +3 -0
- package/styles/material-dark-lite.css +3 -0
- package/styles/material-dark.css +3 -0
- package/styles/material-lite.css +3 -0
- package/styles/material.css +3 -0
- package/styles/material3-dark-lite.css +3 -0
- package/styles/material3-dark.css +3 -0
- package/styles/material3-lite.css +3 -0
- package/styles/material3.css +3 -0
- package/styles/tailwind-dark-lite.css +3 -0
- package/styles/tailwind-dark.css +3 -0
- package/styles/tailwind-lite.css +3 -0
- package/styles/tailwind.css +3 -0
- package/styles/tailwind3-lite.css +3 -0
- package/styles/tailwind3.css +3 -0
- package/styles/toolbar/_layout.scss +4 -0
- package/styles/toolbar/bds.css +3 -0
- package/styles/toolbar/bootstrap-dark.css +3 -0
- package/styles/toolbar/bootstrap.css +3 -0
- package/styles/toolbar/bootstrap4.css +3 -0
- package/styles/toolbar/bootstrap5-dark.css +3 -0
- package/styles/toolbar/bootstrap5.3.css +3 -0
- package/styles/toolbar/bootstrap5.css +3 -0
- package/styles/toolbar/fabric-dark.css +3 -0
- package/styles/toolbar/fabric.css +3 -0
- package/styles/toolbar/fluent-dark.css +3 -0
- package/styles/toolbar/fluent.css +3 -0
- package/styles/toolbar/fluent2.css +3 -0
- package/styles/toolbar/highcontrast-light.css +3 -0
- package/styles/toolbar/highcontrast.css +3 -0
- package/styles/toolbar/material-dark.css +3 -0
- package/styles/toolbar/material.css +3 -0
- package/styles/toolbar/material3-dark.css +3 -0
- package/styles/toolbar/material3.css +3 -0
- package/styles/toolbar/tailwind-dark.css +3 -0
- package/styles/toolbar/tailwind.css +3 -0
- package/styles/toolbar/tailwind3.css +3 -0
|
@@ -1506,8 +1506,10 @@ var MenuBase = /** @__PURE__ @class */ (function (_super) {
|
|
|
1506
1506
|
if (!active) {
|
|
1507
1507
|
return;
|
|
1508
1508
|
}
|
|
1509
|
+
var isInputElement = active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' ||
|
|
1510
|
+
active.contentEditable === 'true';
|
|
1509
1511
|
var expanded = active.getAttribute('aria-expanded') === 'true';
|
|
1510
|
-
if (!expanded) {
|
|
1512
|
+
if (!expanded || isInputElement) {
|
|
1511
1513
|
return;
|
|
1512
1514
|
}
|
|
1513
1515
|
var ul = this.element;
|
|
@@ -1621,13 +1623,19 @@ var MenuBase = /** @__PURE__ @class */ (function (_super) {
|
|
|
1621
1623
|
var cli = cul.children[fliIdx];
|
|
1622
1624
|
fliIdx = this.isValidLI(cli, fliIdx, e.action);
|
|
1623
1625
|
cul.children[fliIdx].classList.add(FOCUSED);
|
|
1624
|
-
cul.children[fliIdx]
|
|
1626
|
+
var liToFocus = cul.children[fliIdx];
|
|
1625
1627
|
if (closest(this.element, '.e-popup')) {
|
|
1626
|
-
var
|
|
1627
|
-
var
|
|
1628
|
-
if (!
|
|
1629
|
-
|
|
1628
|
+
var focusableChild = liToFocus.querySelector('[tabindex], span[tabindex], a, button, [tabindex]:not([tabindex="-1"])');
|
|
1629
|
+
var isSpreadsheet = this.element.id.includes('_cf_menu') && this.element.parentElement.classList.contains('e-cf-menu');
|
|
1630
|
+
if (focusableChild && !isSpreadsheet) {
|
|
1631
|
+
focusableChild.focus();
|
|
1630
1632
|
}
|
|
1633
|
+
else {
|
|
1634
|
+
liToFocus.focus();
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
else {
|
|
1638
|
+
liToFocus.focus();
|
|
1631
1639
|
}
|
|
1632
1640
|
};
|
|
1633
1641
|
MenuBase.prototype.isValidLI = function (cli, index, action) {
|
|
@@ -11016,54 +11024,25 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
11016
11024
|
_this.isDropIn = false;
|
|
11017
11025
|
_this.OldCheckedData = [];
|
|
11018
11026
|
_this.isHiddenItem = false;
|
|
11019
|
-
//
|
|
11020
|
-
/** Flat ordered list of all currently-visible (non-collapsed) tree nodes. */
|
|
11027
|
+
// Virtualization state
|
|
11021
11028
|
_this.virtualFlatNodes = [];
|
|
11022
|
-
/** Maps node id → index in virtualFlatNodes for O(1) lookups. */
|
|
11023
11029
|
_this.virtualNodeMap = new Map();
|
|
11024
|
-
/** Set of expanded node IDs for O(1) lookup performance during flattening (avoids array indexOf). */
|
|
11025
11030
|
_this.virtualExpandedNodesSet = new Set();
|
|
11026
|
-
/** Set of checked node IDs for O(1) lookup performance during flattening. */
|
|
11027
11031
|
_this.virtualCheckedNodesSet = new Set();
|
|
11028
|
-
/** Set of indeterminate node IDs — persists across flattenVisibleNodes() rebuilds. */
|
|
11029
11032
|
_this.virtualIndeterminateNodesSet = new Set();
|
|
11030
|
-
/** Set of selected node IDs for O(1) lookup performance during flattening. */
|
|
11031
11033
|
_this.virtualSelectedNodesSet = new Set();
|
|
11032
|
-
/** Row height in pixels, measured from the first rendered item or set to 40 as a default. */
|
|
11033
11034
|
_this.virtualItemHeight = 40;
|
|
11034
|
-
/** Height of the scrollable container in pixels. */
|
|
11035
11035
|
_this.virtualViewportHeight = 0;
|
|
11036
|
-
/** scrollTop captured during the previous scroll handler invocation. */
|
|
11037
11036
|
_this.virtualPrevScrollTop = 0;
|
|
11038
|
-
/** Index of the first rendered row in the current window. */
|
|
11039
11037
|
_this.virtualStartIndex = 0;
|
|
11040
|
-
/** Index one past the last rendered row in the current window. */
|
|
11041
11038
|
_this.virtualEndIndex = 0;
|
|
11042
|
-
/** Extra rows rendered above and below the visible window to smooth scrolling. */
|
|
11043
11039
|
_this.virtualOverscanCount = 3;
|
|
11044
|
-
/** RequestAnimationFrame handle used for throttling scroll events. */
|
|
11045
11040
|
_this.virtualScrollRAF = null;
|
|
11046
|
-
/** The `.e-mask-parent` overlay element shown during fast scroll. */
|
|
11047
11041
|
_this.virtualMaskElement = null;
|
|
11048
|
-
/** Bound scroll handler stored for later removeEventListener. */
|
|
11049
11042
|
_this.virtualScrollBound = null;
|
|
11050
|
-
/** Skeleton component instances inside the mask overlay. */
|
|
11051
11043
|
_this.skeletonInstances = [];
|
|
11052
|
-
/** Set to true whenever the flat node list must be rebuilt on next render. */
|
|
11053
11044
|
_this.virtualTreeDirty = false;
|
|
11054
|
-
/** The data-uid of the currently keyboard-focused node in virtual mode (persists across re-renders). */
|
|
11055
11045
|
_this.virtualFocusedId = null;
|
|
11056
|
-
/**
|
|
11057
|
-
* Set to true by the document-level `keydown` handler when the user presses
|
|
11058
|
-
* the Tab key. The browser will auto-scroll the focused element into view
|
|
11059
|
-
* immediately after focus, which fires a `scroll` event on the TreeView
|
|
11060
|
-
* container. We want to skip the re-render that the virtual scroll handler
|
|
11061
|
-
* would otherwise trigger, because the element being focused is already
|
|
11062
|
-
* rendered (it is the single `<li tabindex="0">` of the current window) and
|
|
11063
|
-
* re-rendering would tear down the DOM element that is currently holding
|
|
11064
|
-
* focus. The flag is consumed (reset to `false`) inside `onVirtualScroll`
|
|
11065
|
-
* after the auto-scroll has been handled.
|
|
11066
|
-
*/
|
|
11067
11046
|
_this.virtualSkipNextScrollRender = false;
|
|
11068
11047
|
return _this;
|
|
11069
11048
|
}
|
|
@@ -11366,16 +11345,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
11366
11345
|
}
|
|
11367
11346
|
};
|
|
11368
11347
|
TreeView.prototype.renderItems = function (isSorted) {
|
|
11369
|
-
// In virtual mode (with a fixed height) create only the container <ul> —
|
|
11370
|
-
// initVirtualization will populate the items directly, avoiding the O(n)
|
|
11371
|
-
// ListBase.createList cost.
|
|
11372
|
-
// updateCheckedStateFromDS / updateParentCheckState are intentionally skipped here:
|
|
11373
|
-
// they call getCheckedNodeDetails which traverses the DOM (no DOM exists yet in
|
|
11374
|
-
// virtual mode) and would throw on empty recursion results. The initial checked
|
|
11375
|
-
// state is derived from the raw data inside flattenNodeRecursive instead.
|
|
11376
|
-
//
|
|
11377
|
-
// When enableVirtualization is true but height is NOT provided, we fall through
|
|
11378
|
-
// to the normal (non-virtualized) rendering path so the tree is still visible.
|
|
11379
11348
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
11380
11349
|
this.ulElement = this.createElement('ul', {
|
|
11381
11350
|
className: PARENTITEM + ' ' + 'e-ul',
|
|
@@ -12462,7 +12431,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12462
12431
|
this.checkDisabledState(id);
|
|
12463
12432
|
}
|
|
12464
12433
|
if (this.enableVirtualization) {
|
|
12465
|
-
// Clear any indeterminate state — node is now fully checked
|
|
12466
12434
|
this.virtualIndeterminateNodesSet.delete(id);
|
|
12467
12435
|
var actualIndex = this.virtualNodeMap.get(id);
|
|
12468
12436
|
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
@@ -12483,19 +12451,16 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12483
12451
|
var actualIndex = this.virtualNodeMap.get(id);
|
|
12484
12452
|
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
12485
12453
|
if (isIndeterminate) {
|
|
12486
|
-
// Parent is transitioning to indeterminate — preserve children states
|
|
12487
|
-
// and mark this node as 'indeterminate' so scroll/collapse re-renders correctly.
|
|
12488
12454
|
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].isChecked = 'indeterminate';
|
|
12489
|
-
// Also record it in the persistent indeterminate set so flattenVisibleNodes()
|
|
12490
|
-
// can restore this state after a full rebuild (e.g. on collapse).
|
|
12491
12455
|
this.virtualIndeterminateNodesSet.add(id);
|
|
12492
12456
|
}
|
|
12493
12457
|
else {
|
|
12494
|
-
// Node is being fully unchecked — clear indeterminate tracking too
|
|
12495
12458
|
this.virtualIndeterminateNodesSet.delete(id);
|
|
12496
12459
|
this.virtualCheckedNodesSet.delete(id);
|
|
12497
12460
|
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].isChecked = false;
|
|
12498
|
-
this.treeData
|
|
12461
|
+
if (this.treeData && this.fields && this.fields.isChecked) {
|
|
12462
|
+
this.updateField(this.treeData, this.fields, id, this.fields.isChecked, false);
|
|
12463
|
+
}
|
|
12499
12464
|
if (this.autoCheck && this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].hasChildren) {
|
|
12500
12465
|
this.setVirtualChildCheckState(id, false);
|
|
12501
12466
|
}
|
|
@@ -12540,8 +12505,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12540
12505
|
}
|
|
12541
12506
|
}
|
|
12542
12507
|
}
|
|
12543
|
-
// Collapsed children are not present in virtualFlatNodes, so walk the raw data
|
|
12544
|
-
// to keep this.treeData and checkedNodes in sync for hidden descendants too.
|
|
12545
12508
|
var collapsedChildren = this.getChildNodes(this.treeData, parentId);
|
|
12546
12509
|
if (collapsedChildren) {
|
|
12547
12510
|
for (var i = 0; i < collapsedChildren.length; i++) {
|
|
@@ -12687,7 +12650,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12687
12650
|
}
|
|
12688
12651
|
this.isLoaded = true;
|
|
12689
12652
|
this.isNodeDropped = false;
|
|
12690
|
-
// Initialise (or re-initialise) virtual mode after data binding has settled
|
|
12691
12653
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
12692
12654
|
this.initVirtualization();
|
|
12693
12655
|
}
|
|
@@ -12827,9 +12789,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12827
12789
|
};
|
|
12828
12790
|
TreeView.prototype.expandNode = function (currLi, icon, loaded, isKeyboardNav) {
|
|
12829
12791
|
var _this = this;
|
|
12830
|
-
// Virtual mode fast-path: rebuild the flat list and re-render the window.
|
|
12831
|
-
// Only engage when height is also set; without a fixed height the tree falls
|
|
12832
|
-
// back to normal rendering and the standard expand path must be used.
|
|
12833
12792
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
12834
12793
|
var id = currLi ? currLi.getAttribute('data-uid') : null;
|
|
12835
12794
|
if (id) {
|
|
@@ -12958,9 +12917,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12958
12917
|
};
|
|
12959
12918
|
TreeView.prototype.nodeCollapseAction = function (currLi, icon, colArgs, isKeyboardNav) {
|
|
12960
12919
|
var _this = this;
|
|
12961
|
-
// Virtual mode fast-path: rebuild the flat list and re-render the window.
|
|
12962
|
-
// Only engage when height is also set; without a fixed height the tree falls
|
|
12963
|
-
// back to normal rendering and the standard collapse path must be used.
|
|
12964
12920
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
12965
12921
|
var id = currLi ? currLi.getAttribute('data-uid') : null;
|
|
12966
12922
|
if (id) {
|
|
@@ -13431,7 +13387,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13431
13387
|
li.setAttribute('tabindex', '0');
|
|
13432
13388
|
EventHandler.add(li, 'blur', this.focusOut, this);
|
|
13433
13389
|
this.updateIdAttr(focusedNode, li);
|
|
13434
|
-
// Track focused id for virtual mode re-render restoration
|
|
13435
13390
|
if (this.enableVirtualization) {
|
|
13436
13391
|
this.virtualFocusedId = li.getAttribute('data-uid');
|
|
13437
13392
|
}
|
|
@@ -13444,6 +13399,13 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13444
13399
|
if (!isNullOrUndefined(id) && this.selectedNodes.indexOf(id) === -1) {
|
|
13445
13400
|
this.selectedNodes.push(id);
|
|
13446
13401
|
}
|
|
13402
|
+
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13403
|
+
this.virtualSelectedNodesSet.add(id);
|
|
13404
|
+
var actualIndex = this.virtualNodeMap.get(id);
|
|
13405
|
+
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
13406
|
+
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].selected = true;
|
|
13407
|
+
}
|
|
13408
|
+
}
|
|
13447
13409
|
};
|
|
13448
13410
|
TreeView.prototype.removeSelect = function (liEle) {
|
|
13449
13411
|
if (this.allowMultiSelection) {
|
|
@@ -13457,6 +13419,14 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13457
13419
|
if (index > -1) {
|
|
13458
13420
|
this.selectedNodes.splice(index, 1);
|
|
13459
13421
|
}
|
|
13422
|
+
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13423
|
+
var id = liEle.getAttribute('data-uid');
|
|
13424
|
+
this.virtualSelectedNodesSet.delete(id);
|
|
13425
|
+
var actualIndex = this.virtualNodeMap.get(id);
|
|
13426
|
+
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
13427
|
+
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].selected = false;
|
|
13428
|
+
}
|
|
13429
|
+
}
|
|
13460
13430
|
};
|
|
13461
13431
|
TreeView.prototype.removeSelectAll = function () {
|
|
13462
13432
|
var selectedLI = this.element.querySelectorAll('.' + ACTIVE);
|
|
@@ -13471,6 +13441,15 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13471
13441
|
}
|
|
13472
13442
|
removeClass(selectedLI, ACTIVE);
|
|
13473
13443
|
this.setProperties({ selectedNodes: [] }, true);
|
|
13444
|
+
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13445
|
+
this.virtualSelectedNodesSet.clear();
|
|
13446
|
+
for (var i = 0; i < this.virtualFlatNodes.length; i++) {
|
|
13447
|
+
var node = this.virtualFlatNodes[parseInt(i.toString(), 10)];
|
|
13448
|
+
if (node.selected) {
|
|
13449
|
+
node.selected = false;
|
|
13450
|
+
}
|
|
13451
|
+
}
|
|
13452
|
+
}
|
|
13474
13453
|
};
|
|
13475
13454
|
TreeView.prototype.getSelectEvent = function (currLi, action, e) {
|
|
13476
13455
|
var nodeData = this.getNodeData(currLi);
|
|
@@ -13539,12 +13518,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13539
13518
|
}
|
|
13540
13519
|
};
|
|
13541
13520
|
TreeView.prototype.nodeExpandAction = function (currLi, icon, expandChild, callback, isFromExpandAll, isKeyboardNav) {
|
|
13542
|
-
// In virtual mode (with a fixed height) the flat <li> never has a child <ul>
|
|
13543
|
-
// in the DOM, so the PARENTITEM check below would always fail and fall into
|
|
13544
|
-
// renderChildNodes(), which corrupts the virtual DOM.
|
|
13545
|
-
// Delegate directly to expandNode() which has the handleVirtualExpand fast-path.
|
|
13546
|
-
// When height is not provided, fall through to normal expand logic below since
|
|
13547
|
-
// the tree is rendered with a full nested DOM structure.
|
|
13548
13521
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13549
13522
|
this.expandNode(currLi, icon, undefined, isKeyboardNav);
|
|
13550
13523
|
return;
|
|
@@ -13662,9 +13635,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13662
13635
|
});
|
|
13663
13636
|
};
|
|
13664
13637
|
TreeView.prototype.navigateToFocus = function (isUp) {
|
|
13665
|
-
// In virtual mode (with a fixed height) the element itself is the scroll
|
|
13666
|
-
// container; use ensureVirtualNodeVisible. When height is not provided,
|
|
13667
|
-
// the tree uses normal rendering, so fall through to the standard scroll logic.
|
|
13668
13638
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13669
13639
|
var focusedLi = this.getFocusedNode();
|
|
13670
13640
|
if (focusedLi) {
|
|
@@ -14096,7 +14066,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14096
14066
|
};
|
|
14097
14067
|
TreeView.prototype.focusNextNode = function (li, isTowards) {
|
|
14098
14068
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
14099
|
-
// Determine the id of the node one step in the requested direction
|
|
14100
14069
|
var currentId = li ? li.getAttribute('data-uid') : null;
|
|
14101
14070
|
var currentIdx = -1;
|
|
14102
14071
|
if (!isNullOrUndefined(currentId)) {
|
|
@@ -14108,26 +14077,14 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14108
14077
|
return;
|
|
14109
14078
|
}
|
|
14110
14079
|
var targetId = this.virtualFlatNodes[parseInt(targetIdx.toString(), 10)].id;
|
|
14111
|
-
// ── Fix 1: set virtualFocusedId BEFORE calling ensureVirtualNodeVisible ──
|
|
14112
|
-
// renderVirtualItems() is called synchronously inside ensureVirtualNodeVisible
|
|
14113
|
-
// when a re-render is needed. If virtualFocusedId is still the old value at
|
|
14114
|
-
// that point, focus restoration falls back to the first item. Setting it here
|
|
14115
|
-
// ensures renderVirtualItems always restores focus to the correct target node.
|
|
14116
14080
|
this.virtualFocusedId = targetId;
|
|
14117
|
-
// ── Fix 2: clear focus classes from ALL nested list items, not just top-level ones ──
|
|
14118
|
-
// With hierarchical virtual DOM, the currently focused <li> may be nested inside
|
|
14119
|
-
// a child <ul>. Using ':scope > li' only cleans up direct children and leaves
|
|
14120
|
-
// stale e-focused / e-node-focus classes on nested nodes across re-renders.
|
|
14121
14081
|
var allLi = this.element.querySelectorAll('.' + LISTITEM + '.' + FOCUS);
|
|
14122
14082
|
for (var k = 0; k < allLi.length; k++) {
|
|
14123
14083
|
allLi[parseInt(k.toString(), 10)].classList.remove(FOCUS);
|
|
14124
14084
|
allLi[parseInt(k.toString(), 10)].classList.remove(FOCUSED$1);
|
|
14125
14085
|
allLi[parseInt(k.toString(), 10)].setAttribute('tabindex', '-1');
|
|
14126
14086
|
}
|
|
14127
|
-
// Ensure the target <li> is in the DOM window (may trigger a re-render).
|
|
14128
|
-
// virtualFocusedId is already set above so renderVirtualItems restores focus correctly.
|
|
14129
14087
|
this.ensureVirtualNodeVisible(targetId);
|
|
14130
|
-
// Re-query both nodes after the potential re-render so setFocus gets live DOM elements
|
|
14131
14088
|
var prevNode = currentId ? this.getElement(currentId) : li;
|
|
14132
14089
|
var nextNode_1 = this.getElement(targetId);
|
|
14133
14090
|
if (!isNullOrUndefined(nextNode_1)) {
|
|
@@ -14228,18 +14185,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14228
14185
|
if (!focusedElement) {
|
|
14229
14186
|
return;
|
|
14230
14187
|
}
|
|
14231
|
-
// Virtual-mode guard: when the browser moves focus into the TreeView (e.g. via
|
|
14232
|
-
// the Tab key) it always lands on the single `<li tabindex="0">`. In that
|
|
14233
|
-
// case the element is already the focusable one, FOCUS is already applied
|
|
14234
|
-
// and the only thing left to do is the keyboard focus styling. Skip the
|
|
14235
|
-
// redundant setAttribute/EventHandler.add work so we never re-render the
|
|
14236
|
-
// virtual window as a side effect of focusing the existing `tabindex="0"`
|
|
14237
|
-
// item.
|
|
14238
|
-
// ── Fix: Use document.activeElement to detect browser-focused node ──
|
|
14239
|
-
// After renderVirtualItems() restores focus, the browser-focused element is
|
|
14240
|
-
// the authoritative source, not getFocusedNode(). If they don't match, it means
|
|
14241
|
-
// renderVirtualItems already correctly set up the element, so we must not
|
|
14242
|
-
// override its setup by calling setFocus again.
|
|
14243
14188
|
var actuallyFocusedElement = document.activeElement;
|
|
14244
14189
|
var isAlreadyFocusedInVirtualMode = this.enableVirtualization
|
|
14245
14190
|
&& actuallyFocusedElement === focusedElement
|
|
@@ -14494,12 +14439,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14494
14439
|
else {
|
|
14495
14440
|
txtEle[ListBase.getDomSetter(this.listBaseOption)] = ListBase.getSanitizedText(newText, this.listBaseOption);
|
|
14496
14441
|
}
|
|
14497
|
-
// ── Virtual mode: sync the flat-node snapshot so re-renders show updated text ──
|
|
14498
|
-
// virtualFlatNodes is rebuilt from this.treeData (via flattenVisibleNodes) only on
|
|
14499
|
-
// expand/collapse/scroll. Between those events the snapshot is the single source of
|
|
14500
|
-
// truth used by createVirtualListItem. setValue() above updates this.editData (which
|
|
14501
|
-
// IS the treeData object reference), but virtualFlatNodes[idx].text still holds the
|
|
14502
|
-
// old value. Update it here so the next renderVirtualItems() call shows the new text.
|
|
14503
14442
|
if (this.enableVirtualization) {
|
|
14504
14443
|
var id = liEle.getAttribute('data-uid');
|
|
14505
14444
|
var idx = this.virtualNodeMap ? this.virtualNodeMap.get(id) : undefined;
|
|
@@ -14944,11 +14883,49 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14944
14883
|
this.fields.dataSource = this.treeData;
|
|
14945
14884
|
}
|
|
14946
14885
|
this.triggerEvent('nodeDropped', nodeData);
|
|
14886
|
+
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
14887
|
+
this.setRootData();
|
|
14888
|
+
this.rebuildVirtualCheckCache();
|
|
14889
|
+
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
14890
|
+
this.rebuildVirtualNodeMap();
|
|
14891
|
+
var scrollTopSnapshot = this.element.scrollTop;
|
|
14892
|
+
var win = this.getVirtualWindowAt(scrollTopSnapshot);
|
|
14893
|
+
this.virtualStartIndex = win.startIndex;
|
|
14894
|
+
this.virtualEndIndex = win.endIndex;
|
|
14895
|
+
this.virtualSkipNextScrollRender = true;
|
|
14896
|
+
this.renderVirtualItems();
|
|
14897
|
+
}
|
|
14947
14898
|
};
|
|
14948
14899
|
TreeView.prototype.appendNode = function (dropTarget, dragLi, dropLi, e, dragObj, offsetY) {
|
|
14949
14900
|
var checkWrapper = closest(dropTarget, '.' + CHECKBOXWRAP);
|
|
14950
14901
|
var collapse = closest(e.target, '.' + COLLAPSIBLE);
|
|
14951
14902
|
var expand = closest(e.target, '.' + EXPANDABLE);
|
|
14903
|
+
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
14904
|
+
var routesToSiblingBranch = !dragLi.classList.contains('e-disable') && !checkWrapper &&
|
|
14905
|
+
((expand && e.event.offsetY < 5) || (collapse && e.event.offsetX < 3) ||
|
|
14906
|
+
(expand && e.event.offsetY > 19) || (collapse && e.event.offsetX > 19) ||
|
|
14907
|
+
(!expand && !collapse));
|
|
14908
|
+
if (routesToSiblingBranch) {
|
|
14909
|
+
if (dropTarget.nodeName === 'LI') {
|
|
14910
|
+
this.virtualMoveAsSibling(dragLi, dropLi, e, dragObj);
|
|
14911
|
+
}
|
|
14912
|
+
else if (dropTarget.firstElementChild && dropTarget.classList.contains(ROOT)) {
|
|
14913
|
+
if (dropTarget.firstElementChild.nodeName === 'UL') {
|
|
14914
|
+
this.virtualMoveAsSibling(dragLi, dropLi, e, dragObj);
|
|
14915
|
+
}
|
|
14916
|
+
}
|
|
14917
|
+
else if ((dropTarget.classList.contains('e-icon-collapsible')) || (dropTarget.classList.contains('e-icon-expandable'))) {
|
|
14918
|
+
this.virtualMoveAsSibling(dragLi, dropLi, e, dragObj);
|
|
14919
|
+
}
|
|
14920
|
+
else {
|
|
14921
|
+
this.virtualMoveAsChild(dragLi, dropLi, dragObj, offsetY, dropTarget);
|
|
14922
|
+
}
|
|
14923
|
+
}
|
|
14924
|
+
else {
|
|
14925
|
+
this.virtualMoveAsChild(dragLi, dropLi, dragObj, offsetY, dropTarget);
|
|
14926
|
+
}
|
|
14927
|
+
return;
|
|
14928
|
+
}
|
|
14952
14929
|
if (!dragLi.classList.contains('e-disable') && !checkWrapper && ((expand && e.event.offsetY < 5) || (collapse && e.event.offsetX < 3) || (expand && e.event.offsetY > 19) || (collapse && e.event.offsetX > 19) || (!expand && !collapse))) {
|
|
14953
14930
|
if (dropTarget.nodeName === 'LI') {
|
|
14954
14931
|
this.dropAsSiblingNode(dragLi, dropLi, e, dragObj);
|
|
@@ -14972,6 +14949,62 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14972
14949
|
this.ensureIndeterminate();
|
|
14973
14950
|
}
|
|
14974
14951
|
};
|
|
14952
|
+
TreeView.prototype.virtualMoveAsSibling = function (dragLi, dropLi, e, dragObj) {
|
|
14953
|
+
var dropUl = closest(dropLi, '.' + PARENTITEM);
|
|
14954
|
+
var pre;
|
|
14955
|
+
if (e.target.offsetHeight > 0 && e.event.offsetY > e.target.offsetHeight - 2) {
|
|
14956
|
+
pre = false;
|
|
14957
|
+
}
|
|
14958
|
+
else if (e.event.offsetY < 2) {
|
|
14959
|
+
pre = true;
|
|
14960
|
+
}
|
|
14961
|
+
else if (e.target.classList.contains('e-icon-expandable') || (e.target.classList.contains('e-icon-collapsible'))) {
|
|
14962
|
+
if ((e.event.offsetY < 5) || (e.event.offsetX < 3)) {
|
|
14963
|
+
pre = true;
|
|
14964
|
+
}
|
|
14965
|
+
else if ((e.event.offsetY > 15) || (e.event.offsetX > 17)) {
|
|
14966
|
+
pre = false;
|
|
14967
|
+
}
|
|
14968
|
+
}
|
|
14969
|
+
this.moveData(dragLi, dropLi, dropUl, pre, dragObj);
|
|
14970
|
+
};
|
|
14971
|
+
TreeView.prototype.virtualMoveAsChild = function (dragLi, dropLi, dragObj, offsetY, dropTarget) {
|
|
14972
|
+
var pos = offsetY;
|
|
14973
|
+
var isSiblingMarker = dropTarget.classList.contains('e-sibling');
|
|
14974
|
+
var refLi = (pos < 7 && !isSiblingMarker) || (isSiblingMarker &&
|
|
14975
|
+
dropLi.lastChild && !dropLi.lastChild.classList.contains('e-sibling'))
|
|
14976
|
+
? dropLi : null;
|
|
14977
|
+
var dropTargetHt = dropTarget;
|
|
14978
|
+
var isAfter = (dropTargetHt.offsetHeight > 0 && pos > dropTargetHt.offsetHeight - 10);
|
|
14979
|
+
if (refLi) {
|
|
14980
|
+
var dropParentUl = closest(dropLi, '.' + PARENTITEM);
|
|
14981
|
+
this.moveData(dragLi, dropLi, dropParentUl, true, dragObj);
|
|
14982
|
+
}
|
|
14983
|
+
else if (isAfter) {
|
|
14984
|
+
var dropParentUl = closest(dropLi, '.' + PARENTITEM);
|
|
14985
|
+
this.moveData(dragLi, dropLi, dropParentUl, false, dragObj);
|
|
14986
|
+
}
|
|
14987
|
+
else {
|
|
14988
|
+
var dropIcon = select('div.' + EXPANDABLE + ', div.' + COLLAPSIBLE, dropLi);
|
|
14989
|
+
var dropIsCollapsedParent = dropIcon && dropIcon.classList.contains(EXPANDABLE);
|
|
14990
|
+
var dropIsLeaf = isNullOrUndefined(dropIcon);
|
|
14991
|
+
if (this.preventExpand !== true && (dropIsCollapsedParent || dropIsLeaf)) {
|
|
14992
|
+
var dropLiId = dropLi.getAttribute('data-uid');
|
|
14993
|
+
if (dropLiId && this.expandedNodes.indexOf(dropLiId) === -1) {
|
|
14994
|
+
this.expandedNodes.push(dropLiId);
|
|
14995
|
+
}
|
|
14996
|
+
if (this.virtualExpandedNodesSet && dropLiId) {
|
|
14997
|
+
this.virtualExpandedNodesSet.add(dropLiId);
|
|
14998
|
+
}
|
|
14999
|
+
var dropRecord = this.findNodeInTreeData(dropLiId);
|
|
15000
|
+
if (dropRecord && this.fields && this.fields.expanded) {
|
|
15001
|
+
setValue(this.fields.expanded, true, dropRecord);
|
|
15002
|
+
}
|
|
15003
|
+
}
|
|
15004
|
+
var dropUl = select('.' + PARENTITEM, dropLi) || dropLi;
|
|
15005
|
+
this.moveData(dragLi, null, dropUl, true, dragObj);
|
|
15006
|
+
}
|
|
15007
|
+
};
|
|
14975
15008
|
TreeView.prototype.dropAsSiblingNode = function (dragLi, dropLi, e, dragObj) {
|
|
14976
15009
|
var dropUl = closest(dropLi, '.' + PARENTITEM);
|
|
14977
15010
|
var dragParentUl = closest(dragLi, '.' + PARENTITEM);
|
|
@@ -15059,7 +15092,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15059
15092
|
delete removedData[0][this.fields.parentID];
|
|
15060
15093
|
}
|
|
15061
15094
|
else {
|
|
15062
|
-
var currPid = this.isNumberTypeId ? parseFloat(parentId) : parentId;
|
|
15095
|
+
var currPid = this.isNumberTypeId && parentId ? parseFloat(parentId) : parentId;
|
|
15063
15096
|
setValue(this.fields.parentID, currPid, removedData[0]);
|
|
15064
15097
|
}
|
|
15065
15098
|
this.treeData.splice(pos, 0, removedData[0]);
|
|
@@ -15201,7 +15234,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15201
15234
|
var draggedNodeData = obj ? obj.dragData : null;
|
|
15202
15235
|
var newParent = dropTarget ? this.parents(dropTarget, '.' + LISTITEM) : null;
|
|
15203
15236
|
var dragLiParent = obj.dragLi.parentElement;
|
|
15204
|
-
var dragParent = obj.dragLi ? closest(dragLiParent, '.' + LISTITEM) : null;
|
|
15237
|
+
var dragParent = obj.dragLi && dragLiParent ? closest(dragLiParent, '.' + LISTITEM) : null;
|
|
15205
15238
|
var targetParent = null;
|
|
15206
15239
|
var indexValue = null;
|
|
15207
15240
|
var iconCss = [DROPNEXT, DROPIN, DROPOUT, NODROP];
|
|
@@ -15210,7 +15243,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15210
15243
|
var index = node ? closest(node, '.e-list-parent') : null;
|
|
15211
15244
|
var i = 0;
|
|
15212
15245
|
var position = null;
|
|
15213
|
-
dragParent = (obj.dragLi && dragParent === null) ? closest(dragLiParent, '.' + ROOT) : dragParent;
|
|
15246
|
+
dragParent = (obj.dragLi && dragParent === null) && dragLiParent ? closest(dragLiParent, '.' + ROOT) : dragParent;
|
|
15214
15247
|
dragParent = (drop === true) ? this.dragParent : dragParent;
|
|
15215
15248
|
if (cloneEle) {
|
|
15216
15249
|
while (i < 4) {
|
|
@@ -15884,26 +15917,10 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15884
15917
|
TreeView.prototype.keyDownHandler = function (e) {
|
|
15885
15918
|
if (e.key === 'Tab' || e.keyCode === 9) {
|
|
15886
15919
|
this.isKeyboardFocus = true;
|
|
15887
|
-
// Mark the upcoming scroll event (if any) as Tab-induced so the
|
|
15888
|
-
// virtual scroll handler skips its re-render path. The browser
|
|
15889
|
-
// calls `Element.scrollIntoView` semantics on focus, which scrolls
|
|
15890
|
-
// a `<li tabindex="0">` in the middle of the tree into view and
|
|
15891
|
-
// therefore fires `scroll` on the container. Without this guard
|
|
15892
|
-
// the scroll handler would tear down the focused `<li>` and move
|
|
15893
|
-
// focus elsewhere.
|
|
15894
15920
|
if (this.enableVirtualization) {
|
|
15895
15921
|
this.virtualSkipNextScrollRender = true;
|
|
15896
15922
|
}
|
|
15897
15923
|
}
|
|
15898
|
-
// ── Fix: Also skip scroll render for arrow key navigation ──────────────────
|
|
15899
|
-
// Arrow Down/Up calls focusNextNode() which calls ensureVirtualNodeVisible()
|
|
15900
|
-
// to scroll the target node into view. Without this guard, the scroll event
|
|
15901
|
-
// would trigger onVirtualScroll() which re-renders the window and resets the
|
|
15902
|
-
// focus that focusNextNode() just set. This manifests as tabindex resetting
|
|
15903
|
-
// to the first item instead of staying on the arrow-navigated target.
|
|
15904
|
-
// Arrow Right/Left (expand/collapse) also calls renderVirtualItems() which
|
|
15905
|
-
// calls li.focus() in branch 2; that can trigger a scroll on an edge node,
|
|
15906
|
-
// so we consume it here to prevent a stale RAF re-render.
|
|
15907
15924
|
if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.keyCode === 40 || e.keyCode === 38
|
|
15908
15925
|
|| e.key === 'ArrowRight' || e.key === 'ArrowLeft' || e.keyCode === 39 || e.keyCode === 37) {
|
|
15909
15926
|
if (this.enableVirtualization) {
|
|
@@ -16265,10 +16282,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16265
16282
|
if (this.dataType === 1) {
|
|
16266
16283
|
this.groupedData = this.getGroupedData(this.treeData, this.fields.parentID);
|
|
16267
16284
|
}
|
|
16268
|
-
// In virtual mode (with a fixed height), rebuild the flat node list and re-render
|
|
16269
|
-
// after deletion so the removed nodes are correctly reflected in the hierarchical
|
|
16270
|
-
// virtual DOM. When height is not provided, the tree uses normal rendering and
|
|
16271
|
-
// the DOM is already updated by removeNode() above.
|
|
16272
16285
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
16273
16286
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
16274
16287
|
this.rebuildVirtualNodeMap();
|
|
@@ -16337,16 +16350,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16337
16350
|
}
|
|
16338
16351
|
return parentsID;
|
|
16339
16352
|
};
|
|
16340
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
16341
|
-
// VIRTUALIZATION — private helpers
|
|
16342
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
16343
|
-
/**
|
|
16344
|
-
* Parses the `height` property (string like '400px' or number) to a pixel value.
|
|
16345
|
-
* Returns 0 if the value cannot be determined.
|
|
16346
|
-
*
|
|
16347
|
-
* @returns {number} Pixel height.
|
|
16348
|
-
* @private
|
|
16349
|
-
*/
|
|
16350
16353
|
TreeView.prototype.parseHeightToPixels = function () {
|
|
16351
16354
|
var h = this.height;
|
|
16352
16355
|
if (isNullOrUndefined(h)) {
|
|
@@ -16358,13 +16361,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16358
16361
|
var parsed = parseFloat(h);
|
|
16359
16362
|
return isNaN(parsed) ? 0 : parsed;
|
|
16360
16363
|
};
|
|
16361
|
-
/**
|
|
16362
|
-
* Measures the height of the first rendered list item so subsequent calculations
|
|
16363
|
-
* use real layout values. Falls back to the stored `virtualItemHeight` default (40).
|
|
16364
|
-
*
|
|
16365
|
-
* @returns {number} Row height in pixels.
|
|
16366
|
-
* @private
|
|
16367
|
-
*/
|
|
16368
16364
|
TreeView.prototype.measureVirtualItemHeight = function () {
|
|
16369
16365
|
var firstLi = select('.' + LISTITEM, this.element);
|
|
16370
16366
|
if (firstLi && firstLi.offsetHeight > 0) {
|
|
@@ -16372,13 +16368,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16372
16368
|
}
|
|
16373
16369
|
return this.virtualItemHeight;
|
|
16374
16370
|
};
|
|
16375
|
-
/**
|
|
16376
|
-
* Rebuilds the cached Sets for checked/selected nodes to enable O(1) lookup
|
|
16377
|
-
* during the flatten operation instead of O(n) array indexOf calls.
|
|
16378
|
-
*
|
|
16379
|
-
* @returns {void}
|
|
16380
|
-
* @private
|
|
16381
|
-
*/
|
|
16382
16371
|
TreeView.prototype.rebuildVirtualCheckCache = function () {
|
|
16383
16372
|
this.virtualExpandedNodesSet.clear();
|
|
16384
16373
|
this.virtualCheckedNodesSet.clear();
|
|
@@ -16399,20 +16388,10 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16399
16388
|
}
|
|
16400
16389
|
}
|
|
16401
16390
|
};
|
|
16402
|
-
/**
|
|
16403
|
-
* Recursively walks the treeData (or groupedData for flat lists) and builds
|
|
16404
|
-
* `virtualFlatNodes` — an ordered list of every node that is currently visible
|
|
16405
|
-
* (i.e. its ancestors are all expanded). Uses cached Sets for O(1) state lookups.
|
|
16406
|
-
*
|
|
16407
|
-
* @returns {VirtualNodeData[]} Ordered flat list of visible nodes.
|
|
16408
|
-
* @private
|
|
16409
|
-
*/
|
|
16410
16391
|
TreeView.prototype.flattenVisibleNodes = function () {
|
|
16411
|
-
// Build cached Sets for fast lookups
|
|
16412
16392
|
this.rebuildVirtualCheckCache();
|
|
16413
16393
|
var result = [];
|
|
16414
16394
|
if (this.dataType === 1) {
|
|
16415
|
-
// Flat data with parentID field — use getChildGroup to find root nodes
|
|
16416
16395
|
var rootNodes = [];
|
|
16417
16396
|
if (this.groupedData) {
|
|
16418
16397
|
rootNodes = this.getChildGroup(this.groupedData, null, true);
|
|
@@ -16420,39 +16399,29 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16420
16399
|
if (!rootNodes || rootNodes.length === 0) {
|
|
16421
16400
|
rootNodes = this.rootData;
|
|
16422
16401
|
}
|
|
16423
|
-
// Apply sortOrder to root-level nodes for flat data (same as hierarchical path below)
|
|
16424
16402
|
rootNodes = this.getSortedData(rootNodes);
|
|
16425
16403
|
this.flattenNodeRecursive(rootNodes, 1, null, result);
|
|
16426
16404
|
}
|
|
16427
16405
|
else {
|
|
16428
|
-
// Hierarchical data
|
|
16429
16406
|
var sorted = this.getSortedData(this.rootData);
|
|
16430
16407
|
this.flattenNodeRecursive(sorted, 1, null, result);
|
|
16431
16408
|
}
|
|
16432
16409
|
return result;
|
|
16433
16410
|
};
|
|
16434
|
-
/**
|
|
16435
|
-
* Recursive helper for `flattenVisibleNodes`.
|
|
16436
|
-
*
|
|
16437
|
-
* @param {Object[]} nodes - Array of raw data objects at this level.
|
|
16438
|
-
* @param {number} level - 1-based depth level.
|
|
16439
|
-
* @param {string | null} parentId - The parent node id, or null for root.
|
|
16440
|
-
* @param {VirtualNodeData[]} result - Accumulator array.
|
|
16441
|
-
* @returns {void}
|
|
16442
|
-
* @private
|
|
16443
|
-
*/
|
|
16444
16411
|
TreeView.prototype.flattenNodeRecursive = function (nodes, level, parentId, result) {
|
|
16445
16412
|
if (!nodes || nodes.length === 0) {
|
|
16446
16413
|
return;
|
|
16447
16414
|
}
|
|
16448
|
-
|
|
16449
|
-
var childFieldName =
|
|
16450
|
-
var expandedFieldName =
|
|
16451
|
-
var isCheckedFieldName =
|
|
16452
|
-
var iconCssFieldName =
|
|
16453
|
-
var imageUrlFieldName =
|
|
16454
|
-
var idFieldName =
|
|
16455
|
-
var textFieldName =
|
|
16415
|
+
var levelMapper = level === 1 ? this.fields : this.getChildFields(this.fields, level, 1);
|
|
16416
|
+
var childFieldName = levelMapper.child && levelMapper.child.toString();
|
|
16417
|
+
var expandedFieldName = levelMapper.expanded;
|
|
16418
|
+
var isCheckedFieldName = levelMapper.isChecked;
|
|
16419
|
+
var iconCssFieldName = levelMapper.iconCss;
|
|
16420
|
+
var imageUrlFieldName = levelMapper.imageUrl;
|
|
16421
|
+
var idFieldName = levelMapper.id;
|
|
16422
|
+
var textFieldName = levelMapper.text;
|
|
16423
|
+
var selectedFieldName = levelMapper.selected;
|
|
16424
|
+
var hasChildrenFieldName = levelMapper.hasChildren;
|
|
16456
16425
|
var needsSorting = this.sortOrder !== 'None';
|
|
16457
16426
|
var isDataTypeFlat = this.dataType === 1;
|
|
16458
16427
|
var enableVirtualization = this.enableVirtualization;
|
|
@@ -16460,70 +16429,93 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16460
16429
|
var raw = nodes[i];
|
|
16461
16430
|
var id = isNullOrUndefined(raw[idFieldName]) ? '' : raw[idFieldName].toString();
|
|
16462
16431
|
var text = isNullOrUndefined(raw[textFieldName]) ? '' : raw[textFieldName].toString();
|
|
16463
|
-
// Use expandedNodes as the single source of truth.
|
|
16464
16432
|
var inExpandedNodes = this.virtualExpandedNodesSet.has(id);
|
|
16465
|
-
var rawExpanded = !inExpandedNodes && getValue(expandedFieldName, raw) === true;
|
|
16466
|
-
var
|
|
16433
|
+
var rawExpanded = !inExpandedNodes && expandedFieldName && getValue(expandedFieldName, raw) === true;
|
|
16434
|
+
var expanded = inExpandedNodes || rawExpanded;
|
|
16467
16435
|
if (rawExpanded && id) {
|
|
16468
16436
|
this.expandedNodes.push(id);
|
|
16469
16437
|
this.virtualExpandedNodesSet.add(id);
|
|
16470
16438
|
}
|
|
16471
|
-
// Inline hasChildRecords check to avoid function call (optimization)
|
|
16472
16439
|
var hasChildren = false;
|
|
16473
|
-
|
|
16440
|
+
var explicitHasChildren = hasChildrenFieldName ? getValue(hasChildrenFieldName, raw) : null;
|
|
16441
|
+
if (levelMapper.dataSource instanceof DataManager && !isNullOrUndefined(explicitHasChildren) && explicitHasChildren) {
|
|
16442
|
+
hasChildren = true;
|
|
16443
|
+
}
|
|
16444
|
+
else if (isDataTypeFlat) {
|
|
16474
16445
|
if (this.groupedData) {
|
|
16475
16446
|
var groupedChild = this.getChildGroup(this.groupedData, id, false);
|
|
16476
16447
|
hasChildren = !isNullOrUndefined(groupedChild) && groupedChild.length > 0;
|
|
16477
16448
|
}
|
|
16478
16449
|
}
|
|
16479
16450
|
else {
|
|
16480
|
-
var childrenObj = getValue(childFieldName, raw);
|
|
16451
|
+
var childrenObj = childFieldName ? getValue(childFieldName, raw) : null;
|
|
16481
16452
|
hasChildren = !isNullOrUndefined(childrenObj) && Array.isArray(childrenObj) && childrenObj.length > 0;
|
|
16482
16453
|
}
|
|
16483
|
-
|
|
16484
|
-
if (
|
|
16485
|
-
|
|
16486
|
-
|
|
16454
|
+
var parentChecked = null;
|
|
16455
|
+
if (levelMapper.dataSource instanceof DataManager && level > 1 && this.autoCheck && parentId) {
|
|
16456
|
+
if (this.virtualCheckedNodesSet.has(parentId) ||
|
|
16457
|
+
(this.checkedNodes && this.checkedNodes.indexOf(parentId) !== -1)) {
|
|
16458
|
+
parentChecked = true;
|
|
16459
|
+
}
|
|
16460
|
+
else {
|
|
16461
|
+
parentChecked = false;
|
|
16462
|
+
}
|
|
16463
|
+
}
|
|
16464
|
+
var rawChecked = isCheckedFieldName && getValue(isCheckedFieldName, raw);
|
|
16465
|
+
if (enableVirtualization && id && !this.virtualCheckedNodesSet.has(id)) {
|
|
16466
|
+
if ((!isNullOrUndefined(rawChecked) && rawChecked.toString() === 'true') ||
|
|
16467
|
+
(levelMapper.dataSource instanceof DataManager && parentChecked === true)) {
|
|
16487
16468
|
this.virtualCheckedNodesSet.add(id);
|
|
16488
16469
|
if (this.checkedNodes && this.checkedNodes.indexOf(id) === -1) {
|
|
16489
16470
|
this.checkedNodes.push(id);
|
|
16490
16471
|
}
|
|
16491
16472
|
}
|
|
16492
16473
|
}
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16474
|
+
else if (enableVirtualization && id && this.virtualCheckedNodesSet.has(id) && levelMapper.dataSource instanceof DataManager) {
|
|
16475
|
+
if (level > 1 && !this.virtualIndeterminateNodesSet.has(parentId) && this.autoCheck &&
|
|
16476
|
+
((!isNullOrUndefined(rawChecked) && rawChecked.toString() === 'false') || parentChecked === false)) {
|
|
16477
|
+
this.virtualCheckedNodesSet.delete(id);
|
|
16478
|
+
if (this.checkedNodes && this.checkedNodes.indexOf(id) === -1) {
|
|
16479
|
+
this.checkedNodes.splice(this.checkedNodes.indexOf(id), 1);
|
|
16480
|
+
}
|
|
16481
|
+
}
|
|
16482
|
+
}
|
|
16483
|
+
if (this.initialRender && enableVirtualization && id && selectedFieldName && !this.virtualSelectedNodesSet.has(id)) {
|
|
16484
|
+
var rawSelected = getValue(selectedFieldName, raw);
|
|
16485
|
+
if (!isNullOrUndefined(rawSelected) && rawSelected.toString() === 'true') {
|
|
16486
|
+
this.virtualSelectedNodesSet.add(id);
|
|
16487
|
+
if (this.selectedNodes && this.selectedNodes.indexOf(id) === -1) {
|
|
16488
|
+
this.selectedNodes.push(id);
|
|
16489
|
+
}
|
|
16490
|
+
}
|
|
16491
|
+
}
|
|
16492
|
+
var selected = this.virtualSelectedNodesSet.has(id);
|
|
16497
16493
|
var isChecked = (enableVirtualization && this.virtualIndeterminateNodesSet.has(id))
|
|
16498
16494
|
? 'indeterminate'
|
|
16499
16495
|
: this.virtualCheckedNodesSet.has(id);
|
|
16500
|
-
var isDisabled = false; // TODO: Check if any per-node disabled field exists
|
|
16501
16496
|
var iconCssVal = raw[iconCssFieldName];
|
|
16502
16497
|
var iconCss = isNullOrUndefined(iconCssVal) ? '' : iconCssVal.toString();
|
|
16503
16498
|
var imageUrlVal = raw[imageUrlFieldName];
|
|
16504
16499
|
var imageUrl = isNullOrUndefined(imageUrlVal) ? '' : imageUrlVal.toString();
|
|
16505
16500
|
var node = {
|
|
16506
|
-
id: id, text: text, level: level, parentId: parentId, hasChildren: hasChildren,
|
|
16507
|
-
|
|
16501
|
+
id: id, text: text, level: level, parentId: parentId, hasChildren: hasChildren, expanded: expanded,
|
|
16502
|
+
selected: selected, isChecked: isChecked, iconCss: iconCss, imageUrl: imageUrl
|
|
16508
16503
|
};
|
|
16509
16504
|
result.push(node);
|
|
16510
|
-
if (
|
|
16511
|
-
// Determine children list
|
|
16505
|
+
if (expanded && hasChildren) {
|
|
16512
16506
|
var children = [];
|
|
16513
16507
|
if (isDataTypeFlat) {
|
|
16514
16508
|
if (this.groupedData) {
|
|
16515
16509
|
children = this.getChildGroup(this.groupedData, id, false);
|
|
16516
|
-
// Apply sortOrder to flat-data children (same as hierarchical path)
|
|
16517
16510
|
if (needsSorting) {
|
|
16518
16511
|
children = ListBase.getDataSource(children, ListBase.addSorting(this.sortOrder, this.fields.text));
|
|
16519
16512
|
}
|
|
16520
16513
|
}
|
|
16521
16514
|
}
|
|
16522
16515
|
else {
|
|
16523
|
-
var rawChildren = getValue(childFieldName, raw);
|
|
16516
|
+
var rawChildren = childFieldName ? getValue(childFieldName, raw) : null;
|
|
16524
16517
|
if (!isNullOrUndefined(rawChildren) && Array.isArray(rawChildren)) {
|
|
16525
16518
|
children = rawChildren;
|
|
16526
|
-
// Only sort if needed
|
|
16527
16519
|
if (needsSorting) {
|
|
16528
16520
|
children = ListBase.getDataSource(children, ListBase.addSorting(this.sortOrder, this.fields.text));
|
|
16529
16521
|
}
|
|
@@ -16533,35 +16525,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16533
16525
|
}
|
|
16534
16526
|
}
|
|
16535
16527
|
};
|
|
16536
|
-
/**
|
|
16537
|
-
* Checks whether a raw datasource node has child records.
|
|
16538
|
-
*
|
|
16539
|
-
* @param {Object} raw - Raw datasource object.
|
|
16540
|
-
* @returns {boolean} True if children exist.
|
|
16541
|
-
* @private
|
|
16542
|
-
*/
|
|
16543
|
-
TreeView.prototype.hasChildRecords = function (raw) {
|
|
16544
|
-
if (this.dataType === 1) {
|
|
16545
|
-
if (!this.groupedData) {
|
|
16546
|
-
return false;
|
|
16547
|
-
}
|
|
16548
|
-
var rawId = raw[this.fields.id];
|
|
16549
|
-
if (isNullOrUndefined(rawId)) {
|
|
16550
|
-
return false;
|
|
16551
|
-
}
|
|
16552
|
-
var groupedChild = this.getChildGroup(this.groupedData, rawId.toString(), false);
|
|
16553
|
-
return !isNullOrUndefined(groupedChild) && groupedChild.length > 0;
|
|
16554
|
-
}
|
|
16555
|
-
var childField = this.fields.child.toString();
|
|
16556
|
-
var children = getValue(childField, raw);
|
|
16557
|
-
return !isNullOrUndefined(children) && Array.isArray(children) && children.length > 0;
|
|
16558
|
-
};
|
|
16559
|
-
/**
|
|
16560
|
-
* Rebuilds `virtualNodeMap` (id → index) from the current `virtualFlatNodes`.
|
|
16561
|
-
*
|
|
16562
|
-
* @returns {void}
|
|
16563
|
-
* @private
|
|
16564
|
-
*/
|
|
16565
16528
|
TreeView.prototype.rebuildVirtualNodeMap = function () {
|
|
16566
16529
|
this.virtualNodeMap.clear();
|
|
16567
16530
|
for (var i = 0; i < this.virtualFlatNodes.length; i++) {
|
|
@@ -16594,49 +16557,12 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16594
16557
|
var paddingBottom = Math.max(0, (total - end) * itemH);
|
|
16595
16558
|
return { paddingTop: paddingTop, paddingBottom: paddingBottom };
|
|
16596
16559
|
};
|
|
16597
|
-
/**
|
|
16598
|
-
* Renders the virtual window into a **nested** `<ul>/<li>` hierarchy identical to
|
|
16599
|
-
* the non-virtualized DOM structure.
|
|
16600
|
-
*
|
|
16601
|
-
* ## Scroll math
|
|
16602
|
-
* The flat-index ↔ pixel mapping stays unchanged: every entry in
|
|
16603
|
-
* `virtualFlatNodes` represents exactly one `itemHeight` row.
|
|
16604
|
-
* `paddingTop = startIndex * itemHeight` and
|
|
16605
|
-
* `paddingBottom = (total - endIndex) * itemHeight` keep the scrollbar
|
|
16606
|
-
* thumb in the correct position.
|
|
16607
|
-
*
|
|
16608
|
-
* ## Ancestor injection
|
|
16609
|
-
* When `startIndex` points at a child node whose ancestor(s) have already
|
|
16610
|
-
* scrolled above the viewport (their flat indices are < startIndex), the
|
|
16611
|
-
* ancestors would normally be missing from the DOM, forcing the children to
|
|
16612
|
-
* fall back to the root `<ul>` as flat siblings — producing wrong HTML.
|
|
16613
|
-
*
|
|
16614
|
-
* To fix this, before rendering the window we walk the ancestor chain of the
|
|
16615
|
-
* first visible node and collect every ancestor that lies **outside** the
|
|
16616
|
-
* window. Those ancestors are injected as real `<li>` containers at the
|
|
16617
|
-
* very top of the root `<ul>`. To compensate for their presence, `paddingTop`
|
|
16618
|
-
* is reduced by `injectedCount * itemHeight` so the total scroll height
|
|
16619
|
-
* remains the same.
|
|
16620
|
-
*
|
|
16621
|
-
* Once the ancestors are in the DOM they are registered in `renderedParentMap`
|
|
16622
|
-
* so the normal window-rendering loop can nest children inside them exactly
|
|
16623
|
-
* as it does when both parent and child are in the same window.
|
|
16624
|
-
*
|
|
16625
|
-
* @returns {void}
|
|
16626
|
-
* @private
|
|
16627
|
-
*/
|
|
16628
16560
|
TreeView.prototype.renderVirtualItems = function () {
|
|
16629
16561
|
if (!this.ulElement) {
|
|
16630
16562
|
return;
|
|
16631
16563
|
}
|
|
16632
16564
|
var ul = this.ulElement;
|
|
16633
|
-
// ── Snapshot focused ID BEFORE clearing the DOM ───────────────────────────
|
|
16634
|
-
// Removing a focused <li> from the DOM triggers a synchronous `blur` event,
|
|
16635
|
-
// which calls focusOut() and sets virtualFocusedId = null. Capturing the id
|
|
16636
|
-
// here (before any removeChild) ensures focus is correctly restored to the
|
|
16637
|
-
// same node after re-render even when keyboard navigation was in progress.
|
|
16638
16565
|
var focusedUid = this.virtualFocusedId || null;
|
|
16639
|
-
// ── Clear previous render (direct children only) ─────────────────────────
|
|
16640
16566
|
var existingItems = ul.querySelectorAll(':scope > li');
|
|
16641
16567
|
for (var i = existingItems.length - 1; i >= 0; i--) {
|
|
16642
16568
|
ul.removeChild(existingItems[parseInt(i.toString(), 10)]);
|
|
@@ -16647,26 +16573,22 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16647
16573
|
if (this.virtualStartIndex < this.virtualFlatNodes.length) {
|
|
16648
16574
|
var firstNode = this.virtualFlatNodes[this.virtualStartIndex];
|
|
16649
16575
|
if (firstNode.parentId) {
|
|
16650
|
-
// Build the ancestor chain from root down to the immediate parent
|
|
16651
16576
|
var ancestors = [];
|
|
16652
16577
|
var searchId = firstNode.parentId;
|
|
16653
16578
|
while (searchId) {
|
|
16654
16579
|
var ancestorIdx = this.virtualNodeMap.get(searchId);
|
|
16655
16580
|
if (!isNullOrUndefined(ancestorIdx) && ancestorIdx < this.virtualStartIndex) {
|
|
16656
16581
|
var ancestor = this.virtualFlatNodes[parseInt(ancestorIdx.toString(), 10)];
|
|
16657
|
-
ancestors.unshift(ancestor);
|
|
16582
|
+
ancestors.unshift(ancestor);
|
|
16658
16583
|
searchId = ancestor.parentId;
|
|
16659
16584
|
}
|
|
16660
16585
|
else {
|
|
16661
16586
|
break;
|
|
16662
16587
|
}
|
|
16663
16588
|
}
|
|
16664
|
-
// Inject each ancestor as a real <li> into the root <ul>
|
|
16665
|
-
// and register it in renderedParentMap for child-nesting below.
|
|
16666
16589
|
for (var a = 0; a < ancestors.length; a++) {
|
|
16667
16590
|
var ancestor = ancestors[parseInt(a.toString(), 10)];
|
|
16668
16591
|
var ancestorLi = this.createVirtualListItem(ancestor, false);
|
|
16669
|
-
// Find the correct container: root or a previously injected ancestor's <ul>
|
|
16670
16592
|
var targetUl = ul;
|
|
16671
16593
|
if (ancestor.parentId && renderedParentMap.has(ancestor.parentId)) {
|
|
16672
16594
|
var pe = renderedParentMap.get(ancestor.parentId);
|
|
@@ -16685,26 +16607,20 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16685
16607
|
}
|
|
16686
16608
|
}
|
|
16687
16609
|
}
|
|
16688
|
-
// ── Scroll-space padding (adjusted for injected ancestors) ────────────────
|
|
16689
16610
|
var total = this.virtualFlatNodes.length;
|
|
16690
16611
|
var start = this.virtualStartIndex;
|
|
16691
16612
|
var end = this.virtualEndIndex;
|
|
16692
16613
|
var rawPaddingTop = start * itemH;
|
|
16693
|
-
// Subtract the height of injected ancestors so the scroll position is
|
|
16694
|
-
// exact: those ancestor rows are now real DOM elements, not hidden space.
|
|
16695
16614
|
var adjustedPaddingTop = Math.max(0, rawPaddingTop - injectedCount * itemH);
|
|
16696
16615
|
ul.style.paddingTop = adjustedPaddingTop + 'px';
|
|
16697
16616
|
ul.style.paddingBottom = Math.max(0, (total - end) * itemH) + 'px';
|
|
16698
|
-
// ── Render window items (nested via renderedParentMap) ────────────────────
|
|
16699
16617
|
var liListBuf = [];
|
|
16700
16618
|
for (var i = start; i < end; i++) {
|
|
16701
16619
|
var node = this.virtualFlatNodes[parseInt(i.toString(), 10)];
|
|
16702
16620
|
var li = this.createVirtualListItem(node, i === start);
|
|
16703
|
-
// Find the correct parent container
|
|
16704
16621
|
var targetUl = ul;
|
|
16705
16622
|
if (node.parentId && renderedParentMap.has(node.parentId)) {
|
|
16706
16623
|
var parentEntry = renderedParentMap.get(node.parentId);
|
|
16707
|
-
// Lazily create the child <ul> the first time a child needs it
|
|
16708
16624
|
if (!parentEntry.childUl) {
|
|
16709
16625
|
parentEntry.childUl = this.createElement('ul', {
|
|
16710
16626
|
className: PARENTITEM + ' e-ul',
|
|
@@ -16716,30 +16632,11 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16716
16632
|
}
|
|
16717
16633
|
targetUl.appendChild(li);
|
|
16718
16634
|
liListBuf.push(li);
|
|
16719
|
-
|
|
16720
|
-
if (node.isExpanded && node.hasChildren) {
|
|
16635
|
+
if (node.expanded && node.hasChildren) {
|
|
16721
16636
|
renderedParentMap.set(node.id, { li: li, childUl: null });
|
|
16722
16637
|
}
|
|
16723
16638
|
}
|
|
16724
|
-
// ── Restore focus / tabindex ──────────────────────────────────────────────
|
|
16725
|
-
// In virtual mode only the li that carries the 'e-active' class should be
|
|
16726
|
-
// focusable (tabindex='0'). All other rendered li elements must be set
|
|
16727
|
-
// to tabindex='-1' so the tab order remains unambiguous as the window
|
|
16728
|
-
// changes during scrolling.
|
|
16729
16639
|
var focusRestored = false;
|
|
16730
|
-
// 1. Prefer the currently active node if it is in the rendered window.
|
|
16731
|
-
for (var k = 0; k < liListBuf.length; k++) {
|
|
16732
|
-
var li = liListBuf[parseInt(k.toString(), 10)];
|
|
16733
|
-
if (li.classList.contains(ACTIVE)) {
|
|
16734
|
-
li.setAttribute('tabindex', '0');
|
|
16735
|
-
// ── Fix: ensure FOCUS class set on active node too ──
|
|
16736
|
-
// This ensures focusIn() guard condition is met: tabindex='0' && FOCUS class
|
|
16737
|
-
addClass([li], FOCUS);
|
|
16738
|
-
focusRestored = true;
|
|
16739
|
-
break;
|
|
16740
|
-
}
|
|
16741
|
-
}
|
|
16742
|
-
// 2. Otherwise fall back to the previously focused node (if it is in window).
|
|
16743
16640
|
if (!focusRestored && focusedUid) {
|
|
16744
16641
|
for (var k = 0; k < liListBuf.length; k++) {
|
|
16745
16642
|
var li = liListBuf[parseInt(k.toString(), 10)];
|
|
@@ -16747,22 +16644,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16747
16644
|
li.setAttribute('tabindex', '0');
|
|
16748
16645
|
addClass([li], FOCUS);
|
|
16749
16646
|
addClass([li], FOCUSED$1);
|
|
16750
|
-
// ── Fix: restore actual browser focus so keyboard events keep working ──
|
|
16751
|
-
// After renderVirtualItems() replaces all <li> elements the old element
|
|
16752
|
-
// is gone from the DOM and document.activeElement falls back to
|
|
16753
|
-
// document.body. Setting tabindex + classes is not enough — the new
|
|
16754
|
-
// element also needs a programmatic .focus() call so subsequent keyboard
|
|
16755
|
-
// events (Arrow keys, Home, End, etc.) are delivered to the TreeView.
|
|
16756
|
-
// Re-attach the blur→focusOut handler so virtualFocusedId is cleared
|
|
16757
|
-
// correctly when the user tabs away.
|
|
16758
|
-
// ── Use preventScroll:true ────────────────────────────────────────────
|
|
16759
|
-
// Without preventScroll the browser scrolls the container to bring this
|
|
16760
|
-
// node into view during the re-render, changing scrollTop AFTER the
|
|
16761
|
-
// correct paddingTop has been applied. This is the root cause of the
|
|
16762
|
-
// KBN expand position-jump bug: the render is correct but the browser
|
|
16763
|
-
// silently scrolls the viewport, making the parent node appear to jump.
|
|
16764
|
-
// ensureVirtualNodeVisible() handles any legitimate scroll-into-view
|
|
16765
|
-
// needs before renderVirtualItems() is called, so scroll here is wrong.
|
|
16766
16647
|
EventHandler.add(li, 'blur', this.focusOut, this);
|
|
16767
16648
|
li.focus({ preventScroll: true });
|
|
16768
16649
|
focusRestored = true;
|
|
@@ -16770,53 +16651,36 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16770
16651
|
}
|
|
16771
16652
|
}
|
|
16772
16653
|
}
|
|
16773
|
-
// 3. Finally default to the first item in the window.
|
|
16774
16654
|
if (!focusRestored && liListBuf.length > 0) {
|
|
16775
16655
|
var firstLi = liListBuf[0];
|
|
16776
16656
|
firstLi.setAttribute('tabindex', '0');
|
|
16777
16657
|
}
|
|
16778
|
-
// ── Fix: Ensure all other rendered nodes have tabindex="-1" ──
|
|
16779
|
-
// This prevents stale tabindex="0" on multiple nodes which breaks Tab order
|
|
16780
16658
|
for (var k = 0; k < liListBuf.length; k++) {
|
|
16781
16659
|
var li = liListBuf[parseInt(k.toString(), 10)];
|
|
16782
16660
|
if (li.getAttribute('tabindex') !== '0') {
|
|
16783
16661
|
li.setAttribute('tabindex', '-1');
|
|
16784
16662
|
}
|
|
16785
16663
|
}
|
|
16786
|
-
// Keep liList in sync so keyboard-navigation helpers stay functional.
|
|
16787
16664
|
this.liList = liListBuf;
|
|
16788
16665
|
};
|
|
16789
|
-
/**
|
|
16790
|
-
* Creates a single `<li>` element for the virtual window representing `node`.
|
|
16791
|
-
*
|
|
16792
|
-
* @param {VirtualNodeData} node - The node data.
|
|
16793
|
-
* @param {boolean} _isFirst - True if this is the first rendered item (unused here but kept for potential override).
|
|
16794
|
-
* @returns {HTMLElement} The constructed `<li>` element.
|
|
16795
|
-
* @private
|
|
16796
|
-
*/
|
|
16797
16666
|
TreeView.prototype.createVirtualListItem = function (node, _isFirst) {
|
|
16798
16667
|
var li = this.createElement('li', { className: LISTITEM });
|
|
16799
|
-
// Level class for CSS indentation
|
|
16800
16668
|
li.classList.add('e-level-' + node.level);
|
|
16801
16669
|
li.setAttribute('data-uid', node.id);
|
|
16802
16670
|
li.setAttribute('aria-level', node.level.toString());
|
|
16803
16671
|
li.setAttribute('role', 'treeitem');
|
|
16804
16672
|
li.setAttribute('tabindex', '-1');
|
|
16805
|
-
// Full-row overlay (required for fullRowSelect mode)
|
|
16806
16673
|
if (this.fullRowSelect) {
|
|
16807
16674
|
var fullRow = this.createElement('div', { className: FULLROW });
|
|
16808
16675
|
li.appendChild(fullRow);
|
|
16809
16676
|
}
|
|
16810
|
-
// Text/icon wrapper
|
|
16811
16677
|
var textWrap = this.createElement('div', { className: TEXTWRAP });
|
|
16812
|
-
// Expand/collapse icon
|
|
16813
16678
|
if (node.hasChildren) {
|
|
16814
16679
|
var iconSpan = this.createElement('div', {
|
|
16815
|
-
className: ICON + ' ' + (node.
|
|
16680
|
+
className: ICON + ' ' + (node.expanded ? COLLAPSIBLE : EXPANDABLE)
|
|
16816
16681
|
});
|
|
16817
16682
|
textWrap.appendChild(iconSpan);
|
|
16818
16683
|
}
|
|
16819
|
-
// Checkbox
|
|
16820
16684
|
if (this.showCheckBox) {
|
|
16821
16685
|
var checkWrap = createCheckBox(this.createElement, false, {
|
|
16822
16686
|
checked: node.isChecked === true,
|
|
@@ -16830,29 +16694,32 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16830
16694
|
}
|
|
16831
16695
|
textWrap.appendChild(checkWrap);
|
|
16832
16696
|
}
|
|
16833
|
-
// Icon
|
|
16834
16697
|
if (node.iconCss) {
|
|
16835
16698
|
var iconEl = this.createElement('span', {
|
|
16836
16699
|
className: ICON + ' ' + node.iconCss
|
|
16837
16700
|
});
|
|
16838
16701
|
textWrap.appendChild(iconEl);
|
|
16839
16702
|
}
|
|
16840
|
-
// Image
|
|
16841
16703
|
if (node.imageUrl) {
|
|
16842
16704
|
var img = document.createElement('img');
|
|
16843
16705
|
img.src = node.imageUrl;
|
|
16844
16706
|
img.classList.add(IMAGE);
|
|
16845
16707
|
textWrap.appendChild(img);
|
|
16846
16708
|
}
|
|
16847
|
-
// Text anchor
|
|
16848
16709
|
var anchor = this.createElement('span', {
|
|
16849
16710
|
className: 'e-list-text',
|
|
16850
16711
|
innerHTML: node.text
|
|
16851
16712
|
});
|
|
16852
16713
|
textWrap.appendChild(anchor);
|
|
16853
16714
|
li.appendChild(textWrap);
|
|
16854
|
-
|
|
16855
|
-
|
|
16715
|
+
if (!isNullOrUndefined(this.nodeTemplateFn)) {
|
|
16716
|
+
var rawData = this.findNodeInTreeData(node.id);
|
|
16717
|
+
if (!isNullOrUndefined(rawData)) {
|
|
16718
|
+
anchor.innerHTML = '';
|
|
16719
|
+
this.renderNodeTemplate(rawData, anchor, node.id);
|
|
16720
|
+
}
|
|
16721
|
+
}
|
|
16722
|
+
if (node.expanded) {
|
|
16856
16723
|
li.classList.add(EXPANDED);
|
|
16857
16724
|
li.setAttribute('aria-expanded', 'true');
|
|
16858
16725
|
}
|
|
@@ -16860,91 +16727,50 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16860
16727
|
li.classList.add(NODECOLLAPSED);
|
|
16861
16728
|
li.setAttribute('aria-expanded', 'false');
|
|
16862
16729
|
}
|
|
16863
|
-
if (node.
|
|
16730
|
+
if (node.selected) {
|
|
16864
16731
|
li.classList.add(ACTIVE);
|
|
16865
16732
|
li.setAttribute('aria-selected', 'true');
|
|
16866
16733
|
}
|
|
16867
|
-
if (node.isDisabled) {
|
|
16868
|
-
li.classList.add(DISABLED$1);
|
|
16869
|
-
li.setAttribute('aria-disabled', 'true');
|
|
16870
|
-
}
|
|
16871
16734
|
if (node.hasChildren) {
|
|
16872
16735
|
li.classList.add(CHILD);
|
|
16873
16736
|
}
|
|
16874
|
-
// Wire the focus event so `focusIn()` fires when the user Tabs into this
|
|
16875
|
-
// item. The non-virtualized path registers this in `beforeNodeCreate()`,
|
|
16876
|
-
// but virtual items never go through that callback, so we must register
|
|
16877
|
-
// it here to keep focus styling (e.g. `e-focused`) consistent between
|
|
16878
|
-
// virtual and non-virtual modes. `unWireEvents()` already removes this
|
|
16879
|
-
// handler during teardown by iterating over the rendered `<li>`s.
|
|
16880
16737
|
EventHandler.add(li, 'focus', this.focusIn, this);
|
|
16881
16738
|
return li;
|
|
16882
16739
|
};
|
|
16883
|
-
/**
|
|
16884
|
-
* Initialises the virtual-scrolling layout:
|
|
16885
|
-
* 1. Adds the `e-virtualization` CSS class and applies a fixed `height` + `overflow-y`.
|
|
16886
|
-
* 2. Flattens all visible nodes into `virtualFlatNodes`.
|
|
16887
|
-
* 3. Measures item height and viewport height.
|
|
16888
|
-
* 4. Computes the initial window and renders it.
|
|
16889
|
-
* 5. Wires the scroll event handler.
|
|
16890
|
-
*
|
|
16891
|
-
* @returns {void}
|
|
16892
|
-
* @private
|
|
16893
|
-
*/
|
|
16894
16740
|
TreeView.prototype.initVirtualization = function () {
|
|
16895
16741
|
addClass([this.element], VIRTUALIZATION);
|
|
16896
|
-
// Apply container height
|
|
16897
16742
|
var px = this.parseHeightToPixels();
|
|
16898
16743
|
if (px > 0) {
|
|
16899
16744
|
this.element.style.height = px + 'px';
|
|
16900
16745
|
this.element.style.overflowY = 'auto';
|
|
16901
16746
|
}
|
|
16902
|
-
// Ensure the inner UL is ready
|
|
16903
16747
|
if (!this.ulElement) {
|
|
16904
16748
|
this.ulElement = select('.' + PARENTITEM, this.element);
|
|
16905
16749
|
}
|
|
16906
16750
|
if (!this.ulElement) {
|
|
16907
16751
|
return;
|
|
16908
16752
|
}
|
|
16909
|
-
// Make the UL position-relative for the absolute spacers
|
|
16910
16753
|
this.ulElement.style.position = 'relative';
|
|
16911
|
-
// Rebuild flat list
|
|
16912
16754
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
16913
16755
|
this.rebuildVirtualNodeMap();
|
|
16914
|
-
// Measure dimensions
|
|
16915
16756
|
this.virtualViewportHeight = px > 0 ? px : this.element.offsetHeight;
|
|
16916
|
-
// Render a single probe item to measure the real item height before the full render
|
|
16917
16757
|
if (this.virtualFlatNodes.length > 0) {
|
|
16918
16758
|
var probe = this.createVirtualListItem(this.virtualFlatNodes[0], true);
|
|
16919
16759
|
this.ulElement.appendChild(probe);
|
|
16920
16760
|
this.virtualItemHeight = probe.offsetHeight > 0 ? probe.offsetHeight : this.virtualItemHeight;
|
|
16921
16761
|
this.ulElement.removeChild(probe);
|
|
16922
16762
|
}
|
|
16923
|
-
// Compute window and render all items in the initial viewport
|
|
16924
16763
|
var win = this.getVirtualWindow();
|
|
16925
16764
|
this.virtualStartIndex = win.startIndex;
|
|
16926
16765
|
this.virtualEndIndex = win.endIndex;
|
|
16927
16766
|
this.renderVirtualItems();
|
|
16928
|
-
// Wire scroll
|
|
16929
16767
|
this.wireVirtualScrollEvents();
|
|
16930
16768
|
};
|
|
16931
|
-
/**
|
|
16932
|
-
* Wires the scroll event listener on the TreeView element.
|
|
16933
|
-
*
|
|
16934
|
-
* @returns {void}
|
|
16935
|
-
* @private
|
|
16936
|
-
*/
|
|
16937
16769
|
TreeView.prototype.wireVirtualScrollEvents = function () {
|
|
16938
16770
|
this.unwireVirtualScrollEvents();
|
|
16939
16771
|
this.virtualScrollBound = this.onVirtualScroll.bind(this);
|
|
16940
16772
|
this.element.addEventListener('scroll', this.virtualScrollBound, { passive: true });
|
|
16941
16773
|
};
|
|
16942
|
-
/**
|
|
16943
|
-
* Removes the scroll event listener previously wired by `wireVirtualScrollEvents`.
|
|
16944
|
-
*
|
|
16945
|
-
* @returns {void}
|
|
16946
|
-
* @private
|
|
16947
|
-
*/
|
|
16948
16774
|
TreeView.prototype.unwireVirtualScrollEvents = function () {
|
|
16949
16775
|
if (this.virtualScrollBound) {
|
|
16950
16776
|
this.element.removeEventListener('scroll', this.virtualScrollBound);
|
|
@@ -16955,29 +16781,13 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16955
16781
|
this.virtualScrollRAF = null;
|
|
16956
16782
|
}
|
|
16957
16783
|
};
|
|
16958
|
-
/**
|
|
16959
|
-
* Scroll handler for the virtual TreeView. Throttled via `requestAnimationFrame`.
|
|
16960
|
-
* Shows the loading mask during fast scrolls, re-renders the window, then hides the mask.
|
|
16961
|
-
*
|
|
16962
|
-
* @returns {void}
|
|
16963
|
-
* @private
|
|
16964
|
-
*/
|
|
16965
16784
|
TreeView.prototype.onVirtualScroll = function () {
|
|
16966
16785
|
var _this = this;
|
|
16967
16786
|
if (this.virtualScrollRAF !== null) {
|
|
16968
16787
|
cancelAnimationFrame(this.virtualScrollRAF);
|
|
16969
16788
|
}
|
|
16970
|
-
// ── Tab-induced focus guard ────────────────────────────────────────────────
|
|
16971
|
-
// When the user Tabs into a `<li tabindex="0">` that is in the middle of
|
|
16972
|
-
// the treeview, the browser auto-scrolls the container so the focused
|
|
16973
|
-
// element becomes visible. That fires a `scroll` event here, but the
|
|
16974
|
-
// virtual window already contains the focused element — re-rendering
|
|
16975
|
-
// would destroy the focused `<li>` and break focus. Detect this case
|
|
16976
|
-
// via the flag set in `keyDownHandler` and skip the re-render entirely.
|
|
16977
16789
|
if (this.virtualSkipNextScrollRender) {
|
|
16978
16790
|
this.virtualSkipNextScrollRender = false;
|
|
16979
|
-
// Update prev scrollTop so a subsequent user-driven scroll still
|
|
16980
|
-
// calculates the correct delta.
|
|
16981
16791
|
this.virtualPrevScrollTop = this.element.scrollTop;
|
|
16982
16792
|
return;
|
|
16983
16793
|
}
|
|
@@ -16994,30 +16804,16 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16994
16804
|
_this.virtualStartIndex = win.startIndex;
|
|
16995
16805
|
_this.virtualEndIndex = win.endIndex;
|
|
16996
16806
|
_this.renderVirtualItems();
|
|
16997
|
-
// Hide the skeleton mask after a short delay so it stays visible long enough
|
|
16998
|
-
// for the user to perceive the loading indicator even on short scrolls.
|
|
16999
16807
|
setTimeout(function () {
|
|
17000
16808
|
_this.hideVirtualMask();
|
|
17001
|
-
// Keep the (now hidden) mask's coords fresh for the next show.
|
|
17002
16809
|
_this.updateMaskPosition();
|
|
17003
16810
|
}, 200);
|
|
17004
16811
|
});
|
|
17005
16812
|
};
|
|
17006
|
-
/**
|
|
17007
|
-
* Creates the skeleton mask overlay used to indicate loading during fast scrolls.
|
|
17008
|
-
* Skeleton instances are stored in `skeletonInstances` for later disposal.
|
|
17009
|
-
*
|
|
17010
|
-
* @returns {void}
|
|
17011
|
-
* @private
|
|
17012
|
-
*/
|
|
17013
16813
|
TreeView.prototype.createVirtualMask = function () {
|
|
17014
16814
|
if (this.virtualMaskElement) {
|
|
17015
16815
|
return;
|
|
17016
16816
|
}
|
|
17017
|
-
// Use position:fixed so the mask is anchored to the visible viewport (not to the
|
|
17018
|
-
// scrolling container). Width/height/left/top are set/refreshed by
|
|
17019
|
-
// updateMaskPosition() so the mask always covers the TreeView's visible area
|
|
17020
|
-
// regardless of how the page itself is scrolled.
|
|
17021
16817
|
var rect = this.element.getBoundingClientRect();
|
|
17022
16818
|
var scrollBarWidth = this.element.offsetWidth - this.element.clientWidth;
|
|
17023
16819
|
var maskParent = this.createElement('div', {
|
|
@@ -17030,20 +16826,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17030
16826
|
className: VIRTUAL_MASK_ITEM,
|
|
17031
16827
|
styles: "display:flex;align-items:center;height:" + this.virtualItemHeight + "px;padding:0 12px;gap:8px;"
|
|
17032
16828
|
});
|
|
17033
|
-
// Skeleton circle for icon placeholder
|
|
17034
|
-
// const iconHolder: HTMLElement = this.createElement('span', {
|
|
17035
|
-
// styles: `width:20px;height:20px;`
|
|
17036
|
-
// });
|
|
17037
|
-
// maskItem.appendChild(iconHolder);
|
|
17038
|
-
// const iconSkel: Skeleton = new Skeleton({
|
|
17039
|
-
// shape: 'Circle',
|
|
17040
|
-
// width: '20px',
|
|
17041
|
-
// height: '20px',
|
|
17042
|
-
// cssClass: 'e-virtual-skel-icon'
|
|
17043
|
-
// });
|
|
17044
|
-
// iconSkel.appendTo(iconHolder);
|
|
17045
|
-
// this.skeletonInstances.push(iconSkel);
|
|
17046
|
-
// Skeleton text bar
|
|
17047
16829
|
var textHolder = this.createElement('span');
|
|
17048
16830
|
textHolder.style.flex = '1';
|
|
17049
16831
|
textHolder.style.height = '14px';
|
|
@@ -17061,14 +16843,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17061
16843
|
this.virtualMaskElement = maskParent;
|
|
17062
16844
|
this.element.appendChild(maskParent);
|
|
17063
16845
|
};
|
|
17064
|
-
/**
|
|
17065
|
-
* Refreshes the mask position so it always overlays the TreeView's viewport.
|
|
17066
|
-
* Called on every show / scroll, since `position:fixed` is relative to the
|
|
17067
|
-
* page viewport, not to the TreeView scroll container.
|
|
17068
|
-
*
|
|
17069
|
-
* @returns {void}
|
|
17070
|
-
* @private
|
|
17071
|
-
*/
|
|
17072
16846
|
TreeView.prototype.updateMaskPosition = function () {
|
|
17073
16847
|
if (!this.virtualMaskElement) {
|
|
17074
16848
|
return;
|
|
@@ -17080,12 +16854,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17080
16854
|
this.virtualMaskElement.style.width = (rect.width - scrollBarWidth) + 'px';
|
|
17081
16855
|
this.virtualMaskElement.style.height = rect.height + 'px';
|
|
17082
16856
|
};
|
|
17083
|
-
/**
|
|
17084
|
-
* Destroys all skeleton instances and removes the mask overlay from the DOM.
|
|
17085
|
-
*
|
|
17086
|
-
* @returns {void}
|
|
17087
|
-
* @private
|
|
17088
|
-
*/
|
|
17089
16857
|
TreeView.prototype.destroyVirtualMask = function () {
|
|
17090
16858
|
for (var i = this.skeletonInstances.length - 1; i >= 0; i--) {
|
|
17091
16859
|
this.skeletonInstances[parseInt(i.toString(), 10)].destroy();
|
|
@@ -17098,52 +16866,26 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17098
16866
|
this.virtualMaskElement = null;
|
|
17099
16867
|
}
|
|
17100
16868
|
};
|
|
17101
|
-
/**
|
|
17102
|
-
* Positions and shows the skeleton mask at the current `scrollTop` position.
|
|
17103
|
-
*
|
|
17104
|
-
* @param {number} _scrollTop - Current scrollTop of the container.
|
|
17105
|
-
* @returns {void}
|
|
17106
|
-
* @private
|
|
17107
|
-
*/
|
|
17108
16869
|
TreeView.prototype.showVirtualMask = function (_scrollTop) {
|
|
17109
16870
|
if (!this.virtualMaskElement) {
|
|
17110
16871
|
this.createVirtualMask();
|
|
17111
16872
|
}
|
|
17112
16873
|
if (this.virtualMaskElement) {
|
|
17113
|
-
// Refresh the fixed-position coords in case the TreeView was moved/resized
|
|
17114
|
-
// since the last time the mask was shown.
|
|
17115
16874
|
this.updateMaskPosition();
|
|
17116
16875
|
this.virtualMaskElement.style.display = 'block';
|
|
17117
|
-
// Visually hide the real list while the skeleton is shown
|
|
17118
16876
|
if (this.ulElement) {
|
|
17119
16877
|
this.ulElement.style.visibility = 'hidden';
|
|
17120
16878
|
}
|
|
17121
16879
|
}
|
|
17122
16880
|
};
|
|
17123
|
-
/**
|
|
17124
|
-
* Hides the skeleton mask overlay after the virtual window has been rendered.
|
|
17125
|
-
*
|
|
17126
|
-
* @returns {void}
|
|
17127
|
-
* @private
|
|
17128
|
-
*/
|
|
17129
16881
|
TreeView.prototype.hideVirtualMask = function () {
|
|
17130
16882
|
if (this.virtualMaskElement) {
|
|
17131
16883
|
this.virtualMaskElement.style.display = 'none';
|
|
17132
|
-
// Restore real list visibility
|
|
17133
16884
|
if (this.ulElement) {
|
|
17134
16885
|
this.ulElement.style.visibility = '';
|
|
17135
16886
|
}
|
|
17136
16887
|
}
|
|
17137
16888
|
};
|
|
17138
|
-
/**
|
|
17139
|
-
* Ensures the node identified by `id` is scrolled into view inside the virtual container.
|
|
17140
|
-
* If the node falls outside the rendered window, the container's `scrollTop` is adjusted so
|
|
17141
|
-
* that the node becomes visible, the window is re-computed and `renderVirtualItems` is called.
|
|
17142
|
-
*
|
|
17143
|
-
* @param {string} id - The `data-uid` of the target node.
|
|
17144
|
-
* @returns {void}
|
|
17145
|
-
* @private
|
|
17146
|
-
*/
|
|
17147
16889
|
TreeView.prototype.ensureVirtualNodeVisible = function (id) {
|
|
17148
16890
|
var idx = this.virtualNodeMap.get(id);
|
|
17149
16891
|
if (isNullOrUndefined(idx)) {
|
|
@@ -17162,20 +16904,53 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17162
16904
|
this.element.scrollTop = nodeBottom - vpH;
|
|
17163
16905
|
}
|
|
17164
16906
|
else {
|
|
17165
|
-
return;
|
|
16907
|
+
return;
|
|
17166
16908
|
}
|
|
17167
|
-
// Re-render the new window synchronously so the <li> is in the DOM
|
|
17168
16909
|
var win = this.getVirtualWindow();
|
|
17169
16910
|
this.virtualStartIndex = win.startIndex;
|
|
17170
16911
|
this.virtualEndIndex = win.endIndex;
|
|
17171
16912
|
this.renderVirtualItems();
|
|
17172
16913
|
};
|
|
16914
|
+
TreeView.prototype.findNodeInTreeData = function (id) {
|
|
16915
|
+
if (!this.treeData) {
|
|
16916
|
+
return null;
|
|
16917
|
+
}
|
|
16918
|
+
var idFieldName = this.fields.id.toString();
|
|
16919
|
+
var childFieldName = this.fields.child.toString();
|
|
16920
|
+
var findRecursive = function (nodes) {
|
|
16921
|
+
if (!nodes || nodes.length === 0) {
|
|
16922
|
+
return null;
|
|
16923
|
+
}
|
|
16924
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
16925
|
+
var node = nodes[i];
|
|
16926
|
+
if (node[idFieldName] && node[idFieldName].toString() === id) {
|
|
16927
|
+
return node;
|
|
16928
|
+
}
|
|
16929
|
+
var children = getValue(childFieldName, node);
|
|
16930
|
+
if (children && Array.isArray(children)) {
|
|
16931
|
+
var found = findRecursive(children);
|
|
16932
|
+
if (found) {
|
|
16933
|
+
return found;
|
|
16934
|
+
}
|
|
16935
|
+
}
|
|
16936
|
+
}
|
|
16937
|
+
return null;
|
|
16938
|
+
};
|
|
16939
|
+
return findRecursive(this.treeData);
|
|
16940
|
+
};
|
|
16941
|
+
TreeView.prototype.getNodeLevel = function (id) {
|
|
16942
|
+
if (!this.virtualFlatNodes) {
|
|
16943
|
+
return 1;
|
|
16944
|
+
}
|
|
16945
|
+
for (var i = 0; i < this.virtualFlatNodes.length; i++) {
|
|
16946
|
+
if (this.virtualFlatNodes[parseInt(i.toString(), 10)].id === id) {
|
|
16947
|
+
return this.virtualFlatNodes[parseInt(i.toString(), 10)].level;
|
|
16948
|
+
}
|
|
16949
|
+
}
|
|
16950
|
+
return 1;
|
|
16951
|
+
};
|
|
17173
16952
|
TreeView.prototype.handleVirtualExpand = function (id, isKeyboardNav) {
|
|
17174
|
-
|
|
17175
|
-
// A scroll RAF queued before the expand click would run asynchronously after
|
|
17176
|
-
// this synchronous expand completes, re-rendering the window from a stale
|
|
17177
|
-
// scrollTop and moving the parent node to the wrong position. Cancel it now
|
|
17178
|
-
// so the expand render is authoritative.
|
|
16953
|
+
var _this = this;
|
|
17179
16954
|
if (this.virtualScrollRAF !== null) {
|
|
17180
16955
|
cancelAnimationFrame(this.virtualScrollRAF);
|
|
17181
16956
|
this.virtualScrollRAF = null;
|
|
@@ -17183,64 +16958,85 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17183
16958
|
if (this.expandedNodes.indexOf(id) === -1) {
|
|
17184
16959
|
this.expandedNodes.push(id);
|
|
17185
16960
|
}
|
|
17186
|
-
// Also update virtualExpandedNodesSet to keep it in sync
|
|
17187
16961
|
if (this.virtualExpandedNodesSet) {
|
|
17188
16962
|
this.virtualExpandedNodesSet.add(id);
|
|
17189
16963
|
}
|
|
17190
|
-
if (this.
|
|
17191
|
-
var acutalRootData = this.
|
|
17192
|
-
acutalRootData.
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
// (`id` comes from currLi.getAttribute('data-uid') in expandNode, where currLi
|
|
17197
|
-
// is getFocusedNode()). Set unconditionally — the old conditional guard
|
|
17198
|
-
// `!this.virtualFocusedId` could leave a stale or null value if a previous
|
|
17199
|
-
// RAF render (from arrow-key scroll) hadn't yet completed, causing branch 3
|
|
17200
|
-
// (first item) to fire in renderVirtualItems() instead of branch 2.
|
|
17201
|
-
// For mouse clicks (isKeyboardNav=false), clear virtualFocusedId so that
|
|
17202
|
-
// renderVirtualItems() Branch 2 does NOT apply the FOCUS/FOCUSED classes —
|
|
17203
|
-
// mouse-based expand/collapse should never add the e-focused class.
|
|
16964
|
+
if (this.treeData) {
|
|
16965
|
+
var acutalRootData = this.findNodeInTreeData(id);
|
|
16966
|
+
if (acutalRootData && this.fields && this.fields.expanded) {
|
|
16967
|
+
setValue(this.fields.expanded, true, acutalRootData);
|
|
16968
|
+
}
|
|
16969
|
+
}
|
|
17204
16970
|
if (isKeyboardNav) {
|
|
17205
16971
|
this.virtualFocusedId = id;
|
|
17206
16972
|
}
|
|
17207
16973
|
else {
|
|
17208
16974
|
this.virtualFocusedId = null;
|
|
17209
16975
|
}
|
|
16976
|
+
if (this.fields.dataSource instanceof DataManager && !this.isOffline) {
|
|
16977
|
+
var parentNode = this.findNodeInTreeData(id);
|
|
16978
|
+
if (parentNode && !isNullOrUndefined(parentNode)) {
|
|
16979
|
+
var childFieldName = this.fields.child.toString();
|
|
16980
|
+
var childrenObj = getValue(childFieldName, parentNode);
|
|
16981
|
+
var childrenNotLoaded = isNullOrUndefined(childrenObj) || !Array.isArray(childrenObj) ||
|
|
16982
|
+
childrenObj.length === 0;
|
|
16983
|
+
if (childrenNotLoaded) {
|
|
16984
|
+
this.loadVirtualChildData(id, parentNode, function () {
|
|
16985
|
+
_this.completeVirtualExpand(id, isKeyboardNav);
|
|
16986
|
+
});
|
|
16987
|
+
return;
|
|
16988
|
+
}
|
|
16989
|
+
}
|
|
16990
|
+
}
|
|
16991
|
+
this.completeVirtualExpand(id, isKeyboardNav);
|
|
16992
|
+
};
|
|
16993
|
+
TreeView.prototype.loadVirtualChildData = function (parentId, parentNode, callback) {
|
|
16994
|
+
var _this = this;
|
|
16995
|
+
var level = this.getNodeLevel(parentId);
|
|
16996
|
+
var mapper = this.getChildFields(this.fields, level + 1, 1);
|
|
16997
|
+
if (isNullOrUndefined(mapper) || isNullOrUndefined(mapper.dataSource)) {
|
|
16998
|
+
if (callback) {
|
|
16999
|
+
callback();
|
|
17000
|
+
}
|
|
17001
|
+
return;
|
|
17002
|
+
}
|
|
17003
|
+
mapper.dataSource.executeQuery(this.getQuery(mapper, parentId)).then(function (e) {
|
|
17004
|
+
var childItems = e.result;
|
|
17005
|
+
if (!isNullOrUndefined(childItems) && childItems.length > 0) {
|
|
17006
|
+
var childFieldName = _this.fields.child.toString();
|
|
17007
|
+
setValue(childFieldName, childItems, parentNode);
|
|
17008
|
+
if (_this.dataType === 2) {
|
|
17009
|
+
var nodeInTree = _this.findNodeInTreeData(parentId);
|
|
17010
|
+
if (nodeInTree) {
|
|
17011
|
+
setValue(childFieldName, childItems, nodeInTree);
|
|
17012
|
+
}
|
|
17013
|
+
}
|
|
17014
|
+
}
|
|
17015
|
+
if (callback) {
|
|
17016
|
+
callback();
|
|
17017
|
+
}
|
|
17018
|
+
}).catch(function (e) {
|
|
17019
|
+
_this.trigger('actionFailure', { error: e });
|
|
17020
|
+
if (callback) {
|
|
17021
|
+
callback();
|
|
17022
|
+
}
|
|
17023
|
+
});
|
|
17024
|
+
};
|
|
17025
|
+
TreeView.prototype.completeVirtualExpand = function (id, isKeyboardNav) {
|
|
17210
17026
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
17211
17027
|
this.rebuildVirtualNodeMap();
|
|
17212
|
-
// ── Snapshot scrollTop before computing the window ────────────────────────
|
|
17213
|
-
// Read scrollTop once here and pass it into getVirtualWindow so that any
|
|
17214
|
-
// browser scroll-anchoring adjustment that happens when the padding values
|
|
17215
|
-
// change cannot affect which window we render.
|
|
17216
17028
|
var scrollTopSnapshot = this.element.scrollTop;
|
|
17217
17029
|
var win = this.getVirtualWindowAt(scrollTopSnapshot);
|
|
17218
17030
|
this.virtualStartIndex = win.startIndex;
|
|
17219
17031
|
this.virtualEndIndex = win.endIndex;
|
|
17220
|
-
// ── Block ALL scroll-triggered re-renders during this expand ─────────────
|
|
17221
|
-
// renderVirtualItems() calls li.focus() in branch 2 (keyboard focus restore).
|
|
17222
|
-
// The post-render focus() call below can also trigger browser scroll. Both
|
|
17223
|
-
// can fire the 'scroll' event and cause onVirtualScroll() to queue a RAF.
|
|
17224
|
-
// We set the skip flag ONCE here; it is consumed by the first scroll event.
|
|
17225
|
-
// To cover the second potential scroll (from the focus() call below) we use
|
|
17226
|
-
// preventScroll:true on that call so it never moves the container at all.
|
|
17227
17032
|
this.virtualSkipNextScrollRender = true;
|
|
17228
17033
|
this.renderVirtualItems();
|
|
17229
|
-
// renderVirtualItems() replaces all <li> elements so the old icon element that
|
|
17230
|
-
// had the PROCESS class is gone. Remove PROCESS from the newly rendered icon
|
|
17231
|
-
// so the node can be collapsed/expanded again without being blocked.
|
|
17232
17034
|
var newLi = this.getElement(id);
|
|
17233
17035
|
if (newLi) {
|
|
17234
17036
|
var icon = select('.' + ICON, newLi);
|
|
17235
17037
|
if (icon) {
|
|
17236
17038
|
removeClass([icon], PROCESS);
|
|
17237
17039
|
}
|
|
17238
|
-
// ── Use preventScroll:true ────────────────────────────────────────────
|
|
17239
|
-
// Without preventScroll the browser scrolls the container to bring this
|
|
17240
|
-
// node into view, which fires a second 'scroll' event. The first scroll
|
|
17241
|
-
// was already consumed by virtualSkipNextScrollRender (set above), so the
|
|
17242
|
-
// second scroll would queue a new RAF that re-renders from the
|
|
17243
|
-
// focus-adjusted scrollTop — moving the parent node to the wrong position.
|
|
17244
17040
|
newLi.focus({ preventScroll: true });
|
|
17245
17041
|
}
|
|
17246
17042
|
if (this.isLoaded) {
|
|
@@ -17253,9 +17049,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17253
17049
|
}
|
|
17254
17050
|
};
|
|
17255
17051
|
TreeView.prototype.handleVirtualCollapse = function (id, isKeyboardNav) {
|
|
17256
|
-
// ── Cancel any pending scroll RAF ─────────────────────────────────────────
|
|
17257
|
-
// Mirrors handleVirtualExpand: a queued RAF from a previous scroll event
|
|
17258
|
-
// must not override the collapse render with a stale window.
|
|
17259
17052
|
if (this.virtualScrollRAF !== null) {
|
|
17260
17053
|
cancelAnimationFrame(this.virtualScrollRAF);
|
|
17261
17054
|
this.virtualScrollRAF = null;
|
|
@@ -17264,21 +17057,15 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17264
17057
|
if (idx !== -1) {
|
|
17265
17058
|
this.expandedNodes.splice(idx, 1);
|
|
17266
17059
|
}
|
|
17267
|
-
// Also update virtualExpandedNodesSet to keep it in sync
|
|
17268
17060
|
if (this.virtualExpandedNodesSet) {
|
|
17269
17061
|
this.virtualExpandedNodesSet.delete(id);
|
|
17270
17062
|
}
|
|
17271
|
-
if (this.
|
|
17272
|
-
var acutalRootData = this.
|
|
17273
|
-
acutalRootData.
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
// definitively the focused node. Set unconditionally to avoid the stale/null
|
|
17278
|
-
// state that could cause the RAF re-render to fall through to branch 3.
|
|
17279
|
-
// For mouse clicks (isKeyboardNav=false), clear virtualFocusedId so that
|
|
17280
|
-
// renderVirtualItems() Branch 2 does NOT apply the FOCUS/FOCUSED classes —
|
|
17281
|
-
// mouse-based expand/collapse should never add the e-focused class.
|
|
17063
|
+
if (this.treeData) {
|
|
17064
|
+
var acutalRootData = this.findNodeInTreeData(id);
|
|
17065
|
+
if (acutalRootData && this.fields && this.fields.expanded) {
|
|
17066
|
+
setValue(this.fields.expanded, false, acutalRootData);
|
|
17067
|
+
}
|
|
17068
|
+
}
|
|
17282
17069
|
if (isKeyboardNav) {
|
|
17283
17070
|
this.virtualFocusedId = id;
|
|
17284
17071
|
}
|
|
@@ -17287,28 +17074,18 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17287
17074
|
}
|
|
17288
17075
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
17289
17076
|
this.rebuildVirtualNodeMap();
|
|
17290
|
-
// ── Snapshot scrollTop before computing the window ────────────────────────
|
|
17291
|
-
// Same rationale as handleVirtualExpand: capture scrollTop before any focus()
|
|
17292
|
-
// call or padding change can cause the browser to auto-scroll.
|
|
17293
17077
|
var scrollTopSnapshot = this.element.scrollTop;
|
|
17294
17078
|
var win = this.getVirtualWindowAt(scrollTopSnapshot);
|
|
17295
17079
|
this.virtualStartIndex = win.startIndex;
|
|
17296
17080
|
this.virtualEndIndex = win.endIndex;
|
|
17297
|
-
// ── Block ALL scroll-triggered re-renders during this collapse ────────────
|
|
17298
|
-
// Same as handleVirtualExpand: use preventScroll:true on the focus() call
|
|
17299
|
-
// below so the second potential scroll event is never fired.
|
|
17300
17081
|
this.virtualSkipNextScrollRender = true;
|
|
17301
17082
|
this.renderVirtualItems();
|
|
17302
|
-
// renderVirtualItems() replaces all <li> elements so the old icon element that
|
|
17303
|
-
// had the PROCESS class is gone. Remove PROCESS from the newly rendered icon
|
|
17304
|
-
// so the node can be expanded/collapsed again without being blocked.
|
|
17305
17083
|
var newLi = this.getElement(id);
|
|
17306
17084
|
if (newLi) {
|
|
17307
17085
|
var icon = select('.' + ICON, newLi);
|
|
17308
17086
|
if (icon) {
|
|
17309
17087
|
removeClass([icon], PROCESS);
|
|
17310
17088
|
}
|
|
17311
|
-
// ── Use preventScroll:true to avoid consuming virtualSkipNextScrollRender ─
|
|
17312
17089
|
newLi.focus({ preventScroll: true });
|
|
17313
17090
|
}
|
|
17314
17091
|
if (this.isLoaded) {
|
|
@@ -17320,36 +17097,18 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17320
17097
|
}
|
|
17321
17098
|
}
|
|
17322
17099
|
};
|
|
17323
|
-
|
|
17324
|
-
* Updates the selected state of a node in `virtualFlatNodes` and re-renders the window.
|
|
17325
|
-
*
|
|
17326
|
-
* @param {string} id - The `data-uid` of the target node.
|
|
17327
|
-
* @param {boolean} isSelected - Whether the node is now selected.
|
|
17328
|
-
* @returns {void}
|
|
17329
|
-
* @private
|
|
17330
|
-
*/
|
|
17331
|
-
TreeView.prototype.updateVirtualNodeSelection = function (id, isSelected) {
|
|
17100
|
+
TreeView.prototype.updateVirtualNodeSelection = function (id, selected) {
|
|
17332
17101
|
var idx = this.virtualNodeMap.get(id);
|
|
17333
17102
|
if (!isNullOrUndefined(idx)) {
|
|
17334
|
-
this.virtualFlatNodes[parseInt(idx.toString(), 10)].
|
|
17103
|
+
this.virtualFlatNodes[parseInt(idx.toString(), 10)].selected = selected;
|
|
17335
17104
|
this.renderVirtualItems();
|
|
17336
17105
|
}
|
|
17337
17106
|
};
|
|
17338
|
-
/**
|
|
17339
|
-
* Updates the checkbox state of a node in `virtualFlatNodes` and re-renders the window.
|
|
17340
|
-
*
|
|
17341
|
-
* @param {string} id - The `data-uid` of the target node.
|
|
17342
|
-
* @param {'check' | 'uncheck' | 'indeterminate'} state - The new check state.
|
|
17343
|
-
* @returns {void}
|
|
17344
|
-
* @private
|
|
17345
|
-
*/
|
|
17346
17107
|
TreeView.prototype.updateVirtualNodeCheckState = function (id, state) {
|
|
17347
17108
|
var idx = this.virtualNodeMap.get(id);
|
|
17348
17109
|
if (!isNullOrUndefined(idx)) {
|
|
17349
17110
|
this.virtualFlatNodes[parseInt(idx.toString(), 10)].isChecked =
|
|
17350
17111
|
state === 'check' ? true : state === 'indeterminate' ? 'indeterminate' : false;
|
|
17351
|
-
// Keep the persistent indeterminate set in sync so flattenVisibleNodes()
|
|
17352
|
-
// correctly restores state after any full list rebuild (e.g. collapse).
|
|
17353
17112
|
if (state === 'indeterminate') {
|
|
17354
17113
|
this.virtualIndeterminateNodesSet.add(id);
|
|
17355
17114
|
}
|
|
@@ -17359,9 +17118,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17359
17118
|
this.renderVirtualItems();
|
|
17360
17119
|
}
|
|
17361
17120
|
};
|
|
17362
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17363
|
-
// END VIRTUALIZATION
|
|
17364
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17365
17121
|
/**
|
|
17366
17122
|
* Called internally if any of the property value changed.
|
|
17367
17123
|
*
|
|
@@ -17506,7 +17262,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17506
17262
|
}
|
|
17507
17263
|
}
|
|
17508
17264
|
else {
|
|
17509
|
-
// Tear down virtualization and do a full re-render
|
|
17510
17265
|
this.unwireVirtualScrollEvents();
|
|
17511
17266
|
this.destroyVirtualMask();
|
|
17512
17267
|
removeClass([this.element], VIRTUALIZATION);
|
|
@@ -17517,7 +17272,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17517
17272
|
break;
|
|
17518
17273
|
case 'height':
|
|
17519
17274
|
if (this.enableVirtualization) {
|
|
17520
|
-
// Re-initialise so the new height takes effect
|
|
17521
17275
|
this.unwireVirtualScrollEvents();
|
|
17522
17276
|
this.initVirtualization();
|
|
17523
17277
|
}
|
|
@@ -17535,7 +17289,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17535
17289
|
* @returns {void}
|
|
17536
17290
|
*/
|
|
17537
17291
|
TreeView.prototype.destroy = function () {
|
|
17538
|
-
// Tear down virtualization before standard cleanup
|
|
17539
17292
|
if (this.enableVirtualization) {
|
|
17540
17293
|
this.unwireVirtualScrollEvents();
|
|
17541
17294
|
this.destroyVirtualMask();
|
|
@@ -17626,10 +17379,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17626
17379
|
if (isNullOrUndefined(fNode)) {
|
|
17627
17380
|
this.setNodeFocusable();
|
|
17628
17381
|
}
|
|
17629
|
-
// In virtual mode (with a fixed height), rebuild the flat node list and re-render
|
|
17630
|
-
// the window so the newly added nodes appear in the correct hierarchical position.
|
|
17631
|
-
// When height is not provided, the tree uses normal rendering and the DOM is
|
|
17632
|
-
// already updated by addGivenNodes() above.
|
|
17633
17382
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
17634
17383
|
this.setRootData();
|
|
17635
17384
|
this.rebuildVirtualCheckCache();
|
|
@@ -17699,7 +17448,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17699
17448
|
}
|
|
17700
17449
|
for (var i = 0; i < nodes.length; i++) {
|
|
17701
17450
|
var node = nodes[parseInt(i.toString(), 10)];
|
|
17702
|
-
node['
|
|
17451
|
+
node['expanded'] = false;
|
|
17703
17452
|
var children = getValue(_this.fields.child.toString(), node);
|
|
17704
17453
|
if (children && Array.isArray(children)) {
|
|
17705
17454
|
setAllCollapsed_1(children);
|
|
@@ -17799,7 +17548,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17799
17548
|
var nodeId = getValue(idFieldName_1, node);
|
|
17800
17549
|
if (node.hasChild) {
|
|
17801
17550
|
allParentIds_1.push(nodeId);
|
|
17802
|
-
node.
|
|
17551
|
+
node.expanded = true;
|
|
17803
17552
|
}
|
|
17804
17553
|
}
|
|
17805
17554
|
};
|