@syncfusion/ej2-navigations 34.2.3 → 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 +204 -546
- package/dist/es6/ej2-navigations.es2015.js.map +1 -1
- package/dist/es6/ej2-navigations.es5.js +206 -546
- 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/treeview/treeview.d.ts +5 -221
- package/src/treeview/treeview.js +206 -546
|
@@ -11024,54 +11024,25 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
11024
11024
|
_this.isDropIn = false;
|
|
11025
11025
|
_this.OldCheckedData = [];
|
|
11026
11026
|
_this.isHiddenItem = false;
|
|
11027
|
-
//
|
|
11028
|
-
/** Flat ordered list of all currently-visible (non-collapsed) tree nodes. */
|
|
11027
|
+
// Virtualization state
|
|
11029
11028
|
_this.virtualFlatNodes = [];
|
|
11030
|
-
/** Maps node id → index in virtualFlatNodes for O(1) lookups. */
|
|
11031
11029
|
_this.virtualNodeMap = new Map();
|
|
11032
|
-
/** Set of expanded node IDs for O(1) lookup performance during flattening (avoids array indexOf). */
|
|
11033
11030
|
_this.virtualExpandedNodesSet = new Set();
|
|
11034
|
-
/** Set of checked node IDs for O(1) lookup performance during flattening. */
|
|
11035
11031
|
_this.virtualCheckedNodesSet = new Set();
|
|
11036
|
-
/** Set of indeterminate node IDs — persists across flattenVisibleNodes() rebuilds. */
|
|
11037
11032
|
_this.virtualIndeterminateNodesSet = new Set();
|
|
11038
|
-
/** Set of selected node IDs for O(1) lookup performance during flattening. */
|
|
11039
11033
|
_this.virtualSelectedNodesSet = new Set();
|
|
11040
|
-
/** Row height in pixels, measured from the first rendered item or set to 40 as a default. */
|
|
11041
11034
|
_this.virtualItemHeight = 40;
|
|
11042
|
-
/** Height of the scrollable container in pixels. */
|
|
11043
11035
|
_this.virtualViewportHeight = 0;
|
|
11044
|
-
/** scrollTop captured during the previous scroll handler invocation. */
|
|
11045
11036
|
_this.virtualPrevScrollTop = 0;
|
|
11046
|
-
/** Index of the first rendered row in the current window. */
|
|
11047
11037
|
_this.virtualStartIndex = 0;
|
|
11048
|
-
/** Index one past the last rendered row in the current window. */
|
|
11049
11038
|
_this.virtualEndIndex = 0;
|
|
11050
|
-
/** Extra rows rendered above and below the visible window to smooth scrolling. */
|
|
11051
11039
|
_this.virtualOverscanCount = 3;
|
|
11052
|
-
/** RequestAnimationFrame handle used for throttling scroll events. */
|
|
11053
11040
|
_this.virtualScrollRAF = null;
|
|
11054
|
-
/** The `.e-mask-parent` overlay element shown during fast scroll. */
|
|
11055
11041
|
_this.virtualMaskElement = null;
|
|
11056
|
-
/** Bound scroll handler stored for later removeEventListener. */
|
|
11057
11042
|
_this.virtualScrollBound = null;
|
|
11058
|
-
/** Skeleton component instances inside the mask overlay. */
|
|
11059
11043
|
_this.skeletonInstances = [];
|
|
11060
|
-
/** Set to true whenever the flat node list must be rebuilt on next render. */
|
|
11061
11044
|
_this.virtualTreeDirty = false;
|
|
11062
|
-
/** The data-uid of the currently keyboard-focused node in virtual mode (persists across re-renders). */
|
|
11063
11045
|
_this.virtualFocusedId = null;
|
|
11064
|
-
/**
|
|
11065
|
-
* Set to true by the document-level `keydown` handler when the user presses
|
|
11066
|
-
* the Tab key. The browser will auto-scroll the focused element into view
|
|
11067
|
-
* immediately after focus, which fires a `scroll` event on the TreeView
|
|
11068
|
-
* container. We want to skip the re-render that the virtual scroll handler
|
|
11069
|
-
* would otherwise trigger, because the element being focused is already
|
|
11070
|
-
* rendered (it is the single `<li tabindex="0">` of the current window) and
|
|
11071
|
-
* re-rendering would tear down the DOM element that is currently holding
|
|
11072
|
-
* focus. The flag is consumed (reset to `false`) inside `onVirtualScroll`
|
|
11073
|
-
* after the auto-scroll has been handled.
|
|
11074
|
-
*/
|
|
11075
11046
|
_this.virtualSkipNextScrollRender = false;
|
|
11076
11047
|
return _this;
|
|
11077
11048
|
}
|
|
@@ -11374,16 +11345,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
11374
11345
|
}
|
|
11375
11346
|
};
|
|
11376
11347
|
TreeView.prototype.renderItems = function (isSorted) {
|
|
11377
|
-
// In virtual mode (with a fixed height) create only the container <ul> —
|
|
11378
|
-
// initVirtualization will populate the items directly, avoiding the O(n)
|
|
11379
|
-
// ListBase.createList cost.
|
|
11380
|
-
// updateCheckedStateFromDS / updateParentCheckState are intentionally skipped here:
|
|
11381
|
-
// they call getCheckedNodeDetails which traverses the DOM (no DOM exists yet in
|
|
11382
|
-
// virtual mode) and would throw on empty recursion results. The initial checked
|
|
11383
|
-
// state is derived from the raw data inside flattenNodeRecursive instead.
|
|
11384
|
-
//
|
|
11385
|
-
// When enableVirtualization is true but height is NOT provided, we fall through
|
|
11386
|
-
// to the normal (non-virtualized) rendering path so the tree is still visible.
|
|
11387
11348
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
11388
11349
|
this.ulElement = this.createElement('ul', {
|
|
11389
11350
|
className: PARENTITEM + ' ' + 'e-ul',
|
|
@@ -12470,7 +12431,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12470
12431
|
this.checkDisabledState(id);
|
|
12471
12432
|
}
|
|
12472
12433
|
if (this.enableVirtualization) {
|
|
12473
|
-
// Clear any indeterminate state — node is now fully checked
|
|
12474
12434
|
this.virtualIndeterminateNodesSet.delete(id);
|
|
12475
12435
|
var actualIndex = this.virtualNodeMap.get(id);
|
|
12476
12436
|
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
@@ -12491,20 +12451,15 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12491
12451
|
var actualIndex = this.virtualNodeMap.get(id);
|
|
12492
12452
|
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
12493
12453
|
if (isIndeterminate) {
|
|
12494
|
-
// Parent is transitioning to indeterminate — preserve children states
|
|
12495
|
-
// and mark this node as 'indeterminate' so scroll/collapse re-renders correctly.
|
|
12496
12454
|
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].isChecked = 'indeterminate';
|
|
12497
|
-
// Also record it in the persistent indeterminate set so flattenVisibleNodes()
|
|
12498
|
-
// can restore this state after a full rebuild (e.g. on collapse).
|
|
12499
12455
|
this.virtualIndeterminateNodesSet.add(id);
|
|
12500
12456
|
}
|
|
12501
12457
|
else {
|
|
12502
|
-
// Node is being fully unchecked — clear indeterminate tracking too
|
|
12503
12458
|
this.virtualIndeterminateNodesSet.delete(id);
|
|
12504
12459
|
this.virtualCheckedNodesSet.delete(id);
|
|
12505
12460
|
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].isChecked = false;
|
|
12506
12461
|
if (this.treeData && this.fields && this.fields.isChecked) {
|
|
12507
|
-
|
|
12462
|
+
this.updateField(this.treeData, this.fields, id, this.fields.isChecked, false);
|
|
12508
12463
|
}
|
|
12509
12464
|
if (this.autoCheck && this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].hasChildren) {
|
|
12510
12465
|
this.setVirtualChildCheckState(id, false);
|
|
@@ -12550,8 +12505,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12550
12505
|
}
|
|
12551
12506
|
}
|
|
12552
12507
|
}
|
|
12553
|
-
// Collapsed children are not present in virtualFlatNodes, so walk the raw data
|
|
12554
|
-
// to keep this.treeData and checkedNodes in sync for hidden descendants too.
|
|
12555
12508
|
var collapsedChildren = this.getChildNodes(this.treeData, parentId);
|
|
12556
12509
|
if (collapsedChildren) {
|
|
12557
12510
|
for (var i = 0; i < collapsedChildren.length; i++) {
|
|
@@ -12697,7 +12650,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12697
12650
|
}
|
|
12698
12651
|
this.isLoaded = true;
|
|
12699
12652
|
this.isNodeDropped = false;
|
|
12700
|
-
// Initialise (or re-initialise) virtual mode after data binding has settled
|
|
12701
12653
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
12702
12654
|
this.initVirtualization();
|
|
12703
12655
|
}
|
|
@@ -12837,9 +12789,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12837
12789
|
};
|
|
12838
12790
|
TreeView.prototype.expandNode = function (currLi, icon, loaded, isKeyboardNav) {
|
|
12839
12791
|
var _this = this;
|
|
12840
|
-
// Virtual mode fast-path: rebuild the flat list and re-render the window.
|
|
12841
|
-
// Only engage when height is also set; without a fixed height the tree falls
|
|
12842
|
-
// back to normal rendering and the standard expand path must be used.
|
|
12843
12792
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
12844
12793
|
var id = currLi ? currLi.getAttribute('data-uid') : null;
|
|
12845
12794
|
if (id) {
|
|
@@ -12968,9 +12917,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
12968
12917
|
};
|
|
12969
12918
|
TreeView.prototype.nodeCollapseAction = function (currLi, icon, colArgs, isKeyboardNav) {
|
|
12970
12919
|
var _this = this;
|
|
12971
|
-
// Virtual mode fast-path: rebuild the flat list and re-render the window.
|
|
12972
|
-
// Only engage when height is also set; without a fixed height the tree falls
|
|
12973
|
-
// back to normal rendering and the standard collapse path must be used.
|
|
12974
12920
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
12975
12921
|
var id = currLi ? currLi.getAttribute('data-uid') : null;
|
|
12976
12922
|
if (id) {
|
|
@@ -13441,7 +13387,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13441
13387
|
li.setAttribute('tabindex', '0');
|
|
13442
13388
|
EventHandler.add(li, 'blur', this.focusOut, this);
|
|
13443
13389
|
this.updateIdAttr(focusedNode, li);
|
|
13444
|
-
// Track focused id for virtual mode re-render restoration
|
|
13445
13390
|
if (this.enableVirtualization) {
|
|
13446
13391
|
this.virtualFocusedId = li.getAttribute('data-uid');
|
|
13447
13392
|
}
|
|
@@ -13457,7 +13402,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13457
13402
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13458
13403
|
this.virtualSelectedNodesSet.add(id);
|
|
13459
13404
|
var actualIndex = this.virtualNodeMap.get(id);
|
|
13460
|
-
if (actualIndex && actualIndex > -1) {
|
|
13405
|
+
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
13461
13406
|
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].selected = true;
|
|
13462
13407
|
}
|
|
13463
13408
|
}
|
|
@@ -13478,7 +13423,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13478
13423
|
var id = liEle.getAttribute('data-uid');
|
|
13479
13424
|
this.virtualSelectedNodesSet.delete(id);
|
|
13480
13425
|
var actualIndex = this.virtualNodeMap.get(id);
|
|
13481
|
-
if (actualIndex && actualIndex > -1) {
|
|
13426
|
+
if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
|
|
13482
13427
|
this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].selected = false;
|
|
13483
13428
|
}
|
|
13484
13429
|
}
|
|
@@ -13573,12 +13518,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13573
13518
|
}
|
|
13574
13519
|
};
|
|
13575
13520
|
TreeView.prototype.nodeExpandAction = function (currLi, icon, expandChild, callback, isFromExpandAll, isKeyboardNav) {
|
|
13576
|
-
// In virtual mode (with a fixed height) the flat <li> never has a child <ul>
|
|
13577
|
-
// in the DOM, so the PARENTITEM check below would always fail and fall into
|
|
13578
|
-
// renderChildNodes(), which corrupts the virtual DOM.
|
|
13579
|
-
// Delegate directly to expandNode() which has the handleVirtualExpand fast-path.
|
|
13580
|
-
// When height is not provided, fall through to normal expand logic below since
|
|
13581
|
-
// the tree is rendered with a full nested DOM structure.
|
|
13582
13521
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13583
13522
|
this.expandNode(currLi, icon, undefined, isKeyboardNav);
|
|
13584
13523
|
return;
|
|
@@ -13696,9 +13635,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
13696
13635
|
});
|
|
13697
13636
|
};
|
|
13698
13637
|
TreeView.prototype.navigateToFocus = function (isUp) {
|
|
13699
|
-
// In virtual mode (with a fixed height) the element itself is the scroll
|
|
13700
|
-
// container; use ensureVirtualNodeVisible. When height is not provided,
|
|
13701
|
-
// the tree uses normal rendering, so fall through to the standard scroll logic.
|
|
13702
13638
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
13703
13639
|
var focusedLi = this.getFocusedNode();
|
|
13704
13640
|
if (focusedLi) {
|
|
@@ -14130,7 +14066,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14130
14066
|
};
|
|
14131
14067
|
TreeView.prototype.focusNextNode = function (li, isTowards) {
|
|
14132
14068
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
14133
|
-
// Determine the id of the node one step in the requested direction
|
|
14134
14069
|
var currentId = li ? li.getAttribute('data-uid') : null;
|
|
14135
14070
|
var currentIdx = -1;
|
|
14136
14071
|
if (!isNullOrUndefined(currentId)) {
|
|
@@ -14142,26 +14077,14 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14142
14077
|
return;
|
|
14143
14078
|
}
|
|
14144
14079
|
var targetId = this.virtualFlatNodes[parseInt(targetIdx.toString(), 10)].id;
|
|
14145
|
-
// ── Fix 1: set virtualFocusedId BEFORE calling ensureVirtualNodeVisible ──
|
|
14146
|
-
// renderVirtualItems() is called synchronously inside ensureVirtualNodeVisible
|
|
14147
|
-
// when a re-render is needed. If virtualFocusedId is still the old value at
|
|
14148
|
-
// that point, focus restoration falls back to the first item. Setting it here
|
|
14149
|
-
// ensures renderVirtualItems always restores focus to the correct target node.
|
|
14150
14080
|
this.virtualFocusedId = targetId;
|
|
14151
|
-
// ── Fix 2: clear focus classes from ALL nested list items, not just top-level ones ──
|
|
14152
|
-
// With hierarchical virtual DOM, the currently focused <li> may be nested inside
|
|
14153
|
-
// a child <ul>. Using ':scope > li' only cleans up direct children and leaves
|
|
14154
|
-
// stale e-focused / e-node-focus classes on nested nodes across re-renders.
|
|
14155
14081
|
var allLi = this.element.querySelectorAll('.' + LISTITEM + '.' + FOCUS);
|
|
14156
14082
|
for (var k = 0; k < allLi.length; k++) {
|
|
14157
14083
|
allLi[parseInt(k.toString(), 10)].classList.remove(FOCUS);
|
|
14158
14084
|
allLi[parseInt(k.toString(), 10)].classList.remove(FOCUSED$1);
|
|
14159
14085
|
allLi[parseInt(k.toString(), 10)].setAttribute('tabindex', '-1');
|
|
14160
14086
|
}
|
|
14161
|
-
// Ensure the target <li> is in the DOM window (may trigger a re-render).
|
|
14162
|
-
// virtualFocusedId is already set above so renderVirtualItems restores focus correctly.
|
|
14163
14087
|
this.ensureVirtualNodeVisible(targetId);
|
|
14164
|
-
// Re-query both nodes after the potential re-render so setFocus gets live DOM elements
|
|
14165
14088
|
var prevNode = currentId ? this.getElement(currentId) : li;
|
|
14166
14089
|
var nextNode_1 = this.getElement(targetId);
|
|
14167
14090
|
if (!isNullOrUndefined(nextNode_1)) {
|
|
@@ -14262,18 +14185,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14262
14185
|
if (!focusedElement) {
|
|
14263
14186
|
return;
|
|
14264
14187
|
}
|
|
14265
|
-
// Virtual-mode guard: when the browser moves focus into the TreeView (e.g. via
|
|
14266
|
-
// the Tab key) it always lands on the single `<li tabindex="0">`. In that
|
|
14267
|
-
// case the element is already the focusable one, FOCUS is already applied
|
|
14268
|
-
// and the only thing left to do is the keyboard focus styling. Skip the
|
|
14269
|
-
// redundant setAttribute/EventHandler.add work so we never re-render the
|
|
14270
|
-
// virtual window as a side effect of focusing the existing `tabindex="0"`
|
|
14271
|
-
// item.
|
|
14272
|
-
// ── Fix: Use document.activeElement to detect browser-focused node ──
|
|
14273
|
-
// After renderVirtualItems() restores focus, the browser-focused element is
|
|
14274
|
-
// the authoritative source, not getFocusedNode(). If they don't match, it means
|
|
14275
|
-
// renderVirtualItems already correctly set up the element, so we must not
|
|
14276
|
-
// override its setup by calling setFocus again.
|
|
14277
14188
|
var actuallyFocusedElement = document.activeElement;
|
|
14278
14189
|
var isAlreadyFocusedInVirtualMode = this.enableVirtualization
|
|
14279
14190
|
&& actuallyFocusedElement === focusedElement
|
|
@@ -14528,12 +14439,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14528
14439
|
else {
|
|
14529
14440
|
txtEle[ListBase.getDomSetter(this.listBaseOption)] = ListBase.getSanitizedText(newText, this.listBaseOption);
|
|
14530
14441
|
}
|
|
14531
|
-
// ── Virtual mode: sync the flat-node snapshot so re-renders show updated text ──
|
|
14532
|
-
// virtualFlatNodes is rebuilt from this.treeData (via flattenVisibleNodes) only on
|
|
14533
|
-
// expand/collapse/scroll. Between those events the snapshot is the single source of
|
|
14534
|
-
// truth used by createVirtualListItem. setValue() above updates this.editData (which
|
|
14535
|
-
// IS the treeData object reference), but virtualFlatNodes[idx].text still holds the
|
|
14536
|
-
// old value. Update it here so the next renderVirtualItems() call shows the new text.
|
|
14537
14442
|
if (this.enableVirtualization) {
|
|
14538
14443
|
var id = liEle.getAttribute('data-uid');
|
|
14539
14444
|
var idx = this.virtualNodeMap ? this.virtualNodeMap.get(id) : undefined;
|
|
@@ -14978,11 +14883,49 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
14978
14883
|
this.fields.dataSource = this.treeData;
|
|
14979
14884
|
}
|
|
14980
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
|
+
}
|
|
14981
14898
|
};
|
|
14982
14899
|
TreeView.prototype.appendNode = function (dropTarget, dragLi, dropLi, e, dragObj, offsetY) {
|
|
14983
14900
|
var checkWrapper = closest(dropTarget, '.' + CHECKBOXWRAP);
|
|
14984
14901
|
var collapse = closest(e.target, '.' + COLLAPSIBLE);
|
|
14985
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
|
+
}
|
|
14986
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))) {
|
|
14987
14930
|
if (dropTarget.nodeName === 'LI') {
|
|
14988
14931
|
this.dropAsSiblingNode(dragLi, dropLi, e, dragObj);
|
|
@@ -15006,6 +14949,62 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15006
14949
|
this.ensureIndeterminate();
|
|
15007
14950
|
}
|
|
15008
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
|
+
};
|
|
15009
15008
|
TreeView.prototype.dropAsSiblingNode = function (dragLi, dropLi, e, dragObj) {
|
|
15010
15009
|
var dropUl = closest(dropLi, '.' + PARENTITEM);
|
|
15011
15010
|
var dragParentUl = closest(dragLi, '.' + PARENTITEM);
|
|
@@ -15093,7 +15092,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15093
15092
|
delete removedData[0][this.fields.parentID];
|
|
15094
15093
|
}
|
|
15095
15094
|
else {
|
|
15096
|
-
var currPid = this.isNumberTypeId ? parseFloat(parentId) : parentId;
|
|
15095
|
+
var currPid = this.isNumberTypeId && parentId ? parseFloat(parentId) : parentId;
|
|
15097
15096
|
setValue(this.fields.parentID, currPid, removedData[0]);
|
|
15098
15097
|
}
|
|
15099
15098
|
this.treeData.splice(pos, 0, removedData[0]);
|
|
@@ -15235,7 +15234,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15235
15234
|
var draggedNodeData = obj ? obj.dragData : null;
|
|
15236
15235
|
var newParent = dropTarget ? this.parents(dropTarget, '.' + LISTITEM) : null;
|
|
15237
15236
|
var dragLiParent = obj.dragLi.parentElement;
|
|
15238
|
-
var dragParent = obj.dragLi ? closest(dragLiParent, '.' + LISTITEM) : null;
|
|
15237
|
+
var dragParent = obj.dragLi && dragLiParent ? closest(dragLiParent, '.' + LISTITEM) : null;
|
|
15239
15238
|
var targetParent = null;
|
|
15240
15239
|
var indexValue = null;
|
|
15241
15240
|
var iconCss = [DROPNEXT, DROPIN, DROPOUT, NODROP];
|
|
@@ -15244,7 +15243,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15244
15243
|
var index = node ? closest(node, '.e-list-parent') : null;
|
|
15245
15244
|
var i = 0;
|
|
15246
15245
|
var position = null;
|
|
15247
|
-
dragParent = (obj.dragLi && dragParent === null) ? closest(dragLiParent, '.' + ROOT) : dragParent;
|
|
15246
|
+
dragParent = (obj.dragLi && dragParent === null) && dragLiParent ? closest(dragLiParent, '.' + ROOT) : dragParent;
|
|
15248
15247
|
dragParent = (drop === true) ? this.dragParent : dragParent;
|
|
15249
15248
|
if (cloneEle) {
|
|
15250
15249
|
while (i < 4) {
|
|
@@ -15918,26 +15917,10 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
15918
15917
|
TreeView.prototype.keyDownHandler = function (e) {
|
|
15919
15918
|
if (e.key === 'Tab' || e.keyCode === 9) {
|
|
15920
15919
|
this.isKeyboardFocus = true;
|
|
15921
|
-
// Mark the upcoming scroll event (if any) as Tab-induced so the
|
|
15922
|
-
// virtual scroll handler skips its re-render path. The browser
|
|
15923
|
-
// calls `Element.scrollIntoView` semantics on focus, which scrolls
|
|
15924
|
-
// a `<li tabindex="0">` in the middle of the tree into view and
|
|
15925
|
-
// therefore fires `scroll` on the container. Without this guard
|
|
15926
|
-
// the scroll handler would tear down the focused `<li>` and move
|
|
15927
|
-
// focus elsewhere.
|
|
15928
15920
|
if (this.enableVirtualization) {
|
|
15929
15921
|
this.virtualSkipNextScrollRender = true;
|
|
15930
15922
|
}
|
|
15931
15923
|
}
|
|
15932
|
-
// ── Fix: Also skip scroll render for arrow key navigation ──────────────────
|
|
15933
|
-
// Arrow Down/Up calls focusNextNode() which calls ensureVirtualNodeVisible()
|
|
15934
|
-
// to scroll the target node into view. Without this guard, the scroll event
|
|
15935
|
-
// would trigger onVirtualScroll() which re-renders the window and resets the
|
|
15936
|
-
// focus that focusNextNode() just set. This manifests as tabindex resetting
|
|
15937
|
-
// to the first item instead of staying on the arrow-navigated target.
|
|
15938
|
-
// Arrow Right/Left (expand/collapse) also calls renderVirtualItems() which
|
|
15939
|
-
// calls li.focus() in branch 2; that can trigger a scroll on an edge node,
|
|
15940
|
-
// so we consume it here to prevent a stale RAF re-render.
|
|
15941
15924
|
if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.keyCode === 40 || e.keyCode === 38
|
|
15942
15925
|
|| e.key === 'ArrowRight' || e.key === 'ArrowLeft' || e.keyCode === 39 || e.keyCode === 37) {
|
|
15943
15926
|
if (this.enableVirtualization) {
|
|
@@ -16299,10 +16282,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16299
16282
|
if (this.dataType === 1) {
|
|
16300
16283
|
this.groupedData = this.getGroupedData(this.treeData, this.fields.parentID);
|
|
16301
16284
|
}
|
|
16302
|
-
// In virtual mode (with a fixed height), rebuild the flat node list and re-render
|
|
16303
|
-
// after deletion so the removed nodes are correctly reflected in the hierarchical
|
|
16304
|
-
// virtual DOM. When height is not provided, the tree uses normal rendering and
|
|
16305
|
-
// the DOM is already updated by removeNode() above.
|
|
16306
16285
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
16307
16286
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
16308
16287
|
this.rebuildVirtualNodeMap();
|
|
@@ -16371,16 +16350,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16371
16350
|
}
|
|
16372
16351
|
return parentsID;
|
|
16373
16352
|
};
|
|
16374
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
16375
|
-
// VIRTUALIZATION — private helpers
|
|
16376
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
16377
|
-
/**
|
|
16378
|
-
* Parses the `height` property (string like '400px' or number) to a pixel value.
|
|
16379
|
-
* Returns 0 if the value cannot be determined.
|
|
16380
|
-
*
|
|
16381
|
-
* @returns {number} Pixel height.
|
|
16382
|
-
* @private
|
|
16383
|
-
*/
|
|
16384
16353
|
TreeView.prototype.parseHeightToPixels = function () {
|
|
16385
16354
|
var h = this.height;
|
|
16386
16355
|
if (isNullOrUndefined(h)) {
|
|
@@ -16392,13 +16361,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16392
16361
|
var parsed = parseFloat(h);
|
|
16393
16362
|
return isNaN(parsed) ? 0 : parsed;
|
|
16394
16363
|
};
|
|
16395
|
-
/**
|
|
16396
|
-
* Measures the height of the first rendered list item so subsequent calculations
|
|
16397
|
-
* use real layout values. Falls back to the stored `virtualItemHeight` default (40).
|
|
16398
|
-
*
|
|
16399
|
-
* @returns {number} Row height in pixels.
|
|
16400
|
-
* @private
|
|
16401
|
-
*/
|
|
16402
16364
|
TreeView.prototype.measureVirtualItemHeight = function () {
|
|
16403
16365
|
var firstLi = select('.' + LISTITEM, this.element);
|
|
16404
16366
|
if (firstLi && firstLi.offsetHeight > 0) {
|
|
@@ -16406,13 +16368,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16406
16368
|
}
|
|
16407
16369
|
return this.virtualItemHeight;
|
|
16408
16370
|
};
|
|
16409
|
-
/**
|
|
16410
|
-
* Rebuilds the cached Sets for checked/selected nodes to enable O(1) lookup
|
|
16411
|
-
* during the flatten operation instead of O(n) array indexOf calls.
|
|
16412
|
-
*
|
|
16413
|
-
* @returns {void}
|
|
16414
|
-
* @private
|
|
16415
|
-
*/
|
|
16416
16371
|
TreeView.prototype.rebuildVirtualCheckCache = function () {
|
|
16417
16372
|
this.virtualExpandedNodesSet.clear();
|
|
16418
16373
|
this.virtualCheckedNodesSet.clear();
|
|
@@ -16433,20 +16388,10 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16433
16388
|
}
|
|
16434
16389
|
}
|
|
16435
16390
|
};
|
|
16436
|
-
/**
|
|
16437
|
-
* Recursively walks the treeData (or groupedData for flat lists) and builds
|
|
16438
|
-
* `virtualFlatNodes` — an ordered list of every node that is currently visible
|
|
16439
|
-
* (i.e. its ancestors are all expanded). Uses cached Sets for O(1) state lookups.
|
|
16440
|
-
*
|
|
16441
|
-
* @returns {VirtualNodeData[]} Ordered flat list of visible nodes.
|
|
16442
|
-
* @private
|
|
16443
|
-
*/
|
|
16444
16391
|
TreeView.prototype.flattenVisibleNodes = function () {
|
|
16445
|
-
// Build cached Sets for fast lookups
|
|
16446
16392
|
this.rebuildVirtualCheckCache();
|
|
16447
16393
|
var result = [];
|
|
16448
16394
|
if (this.dataType === 1) {
|
|
16449
|
-
// Flat data with parentID field — use getChildGroup to find root nodes
|
|
16450
16395
|
var rootNodes = [];
|
|
16451
16396
|
if (this.groupedData) {
|
|
16452
16397
|
rootNodes = this.getChildGroup(this.groupedData, null, true);
|
|
@@ -16454,40 +16399,29 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16454
16399
|
if (!rootNodes || rootNodes.length === 0) {
|
|
16455
16400
|
rootNodes = this.rootData;
|
|
16456
16401
|
}
|
|
16457
|
-
// Apply sortOrder to root-level nodes for flat data (same as hierarchical path below)
|
|
16458
16402
|
rootNodes = this.getSortedData(rootNodes);
|
|
16459
16403
|
this.flattenNodeRecursive(rootNodes, 1, null, result);
|
|
16460
16404
|
}
|
|
16461
16405
|
else {
|
|
16462
|
-
// Hierarchical data
|
|
16463
16406
|
var sorted = this.getSortedData(this.rootData);
|
|
16464
16407
|
this.flattenNodeRecursive(sorted, 1, null, result);
|
|
16465
16408
|
}
|
|
16466
16409
|
return result;
|
|
16467
16410
|
};
|
|
16468
|
-
/**
|
|
16469
|
-
* Recursive helper for `flattenVisibleNodes`.
|
|
16470
|
-
*
|
|
16471
|
-
* @param {Object[]} nodes - Array of raw data objects at this level.
|
|
16472
|
-
* @param {number} level - 1-based depth level.
|
|
16473
|
-
* @param {string | null} parentId - The parent node id, or null for root.
|
|
16474
|
-
* @param {VirtualNodeData[]} result - Accumulator array.
|
|
16475
|
-
* @returns {void}
|
|
16476
|
-
* @private
|
|
16477
|
-
*/
|
|
16478
16411
|
TreeView.prototype.flattenNodeRecursive = function (nodes, level, parentId, result) {
|
|
16479
16412
|
if (!nodes || nodes.length === 0) {
|
|
16480
16413
|
return;
|
|
16481
16414
|
}
|
|
16482
|
-
|
|
16483
|
-
var childFieldName =
|
|
16484
|
-
var expandedFieldName =
|
|
16485
|
-
var isCheckedFieldName =
|
|
16486
|
-
var iconCssFieldName =
|
|
16487
|
-
var imageUrlFieldName =
|
|
16488
|
-
var idFieldName =
|
|
16489
|
-
var textFieldName =
|
|
16490
|
-
var selectedFieldName =
|
|
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;
|
|
16491
16425
|
var needsSorting = this.sortOrder !== 'None';
|
|
16492
16426
|
var isDataTypeFlat = this.dataType === 1;
|
|
16493
16427
|
var enableVirtualization = this.enableVirtualization;
|
|
@@ -16495,36 +16429,57 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16495
16429
|
var raw = nodes[i];
|
|
16496
16430
|
var id = isNullOrUndefined(raw[idFieldName]) ? '' : raw[idFieldName].toString();
|
|
16497
16431
|
var text = isNullOrUndefined(raw[textFieldName]) ? '' : raw[textFieldName].toString();
|
|
16498
|
-
// Use expandedNodes as the single source of truth.
|
|
16499
16432
|
var inExpandedNodes = this.virtualExpandedNodesSet.has(id);
|
|
16500
|
-
var rawExpanded = !inExpandedNodes && getValue(expandedFieldName, raw) === true;
|
|
16433
|
+
var rawExpanded = !inExpandedNodes && expandedFieldName && getValue(expandedFieldName, raw) === true;
|
|
16501
16434
|
var expanded = inExpandedNodes || rawExpanded;
|
|
16502
16435
|
if (rawExpanded && id) {
|
|
16503
16436
|
this.expandedNodes.push(id);
|
|
16504
16437
|
this.virtualExpandedNodesSet.add(id);
|
|
16505
16438
|
}
|
|
16506
|
-
// Inline hasChildRecords check to avoid function call (optimization)
|
|
16507
16439
|
var hasChildren = false;
|
|
16508
|
-
|
|
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) {
|
|
16509
16445
|
if (this.groupedData) {
|
|
16510
16446
|
var groupedChild = this.getChildGroup(this.groupedData, id, false);
|
|
16511
16447
|
hasChildren = !isNullOrUndefined(groupedChild) && groupedChild.length > 0;
|
|
16512
16448
|
}
|
|
16513
16449
|
}
|
|
16514
16450
|
else {
|
|
16515
|
-
var childrenObj = getValue(childFieldName, raw);
|
|
16451
|
+
var childrenObj = childFieldName ? getValue(childFieldName, raw) : null;
|
|
16516
16452
|
hasChildren = !isNullOrUndefined(childrenObj) && Array.isArray(childrenObj) && childrenObj.length > 0;
|
|
16517
16453
|
}
|
|
16518
|
-
|
|
16519
|
-
if (
|
|
16520
|
-
|
|
16521
|
-
|
|
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)) {
|
|
16522
16468
|
this.virtualCheckedNodesSet.add(id);
|
|
16523
16469
|
if (this.checkedNodes && this.checkedNodes.indexOf(id) === -1) {
|
|
16524
16470
|
this.checkedNodes.push(id);
|
|
16525
16471
|
}
|
|
16526
16472
|
}
|
|
16527
16473
|
}
|
|
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
|
+
}
|
|
16528
16483
|
if (this.initialRender && enableVirtualization && id && selectedFieldName && !this.virtualSelectedNodesSet.has(id)) {
|
|
16529
16484
|
var rawSelected = getValue(selectedFieldName, raw);
|
|
16530
16485
|
if (!isNullOrUndefined(rawSelected) && rawSelected.toString() === 'true') {
|
|
@@ -16534,10 +16489,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16534
16489
|
}
|
|
16535
16490
|
}
|
|
16536
16491
|
}
|
|
16537
|
-
// Use cached Sets for O(1) lookup
|
|
16538
16492
|
var selected = this.virtualSelectedNodesSet.has(id);
|
|
16539
|
-
// Resolve checkbox state: indeterminate takes precedence over the checked set,
|
|
16540
|
-
// because a node can be in the indeterminate state without being in checkedNodes.
|
|
16541
16493
|
var isChecked = (enableVirtualization && this.virtualIndeterminateNodesSet.has(id))
|
|
16542
16494
|
? 'indeterminate'
|
|
16543
16495
|
: this.virtualCheckedNodesSet.has(id);
|
|
@@ -16551,22 +16503,19 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16551
16503
|
};
|
|
16552
16504
|
result.push(node);
|
|
16553
16505
|
if (expanded && hasChildren) {
|
|
16554
|
-
// Determine children list
|
|
16555
16506
|
var children = [];
|
|
16556
16507
|
if (isDataTypeFlat) {
|
|
16557
16508
|
if (this.groupedData) {
|
|
16558
16509
|
children = this.getChildGroup(this.groupedData, id, false);
|
|
16559
|
-
// Apply sortOrder to flat-data children (same as hierarchical path)
|
|
16560
16510
|
if (needsSorting) {
|
|
16561
16511
|
children = ListBase.getDataSource(children, ListBase.addSorting(this.sortOrder, this.fields.text));
|
|
16562
16512
|
}
|
|
16563
16513
|
}
|
|
16564
16514
|
}
|
|
16565
16515
|
else {
|
|
16566
|
-
var rawChildren = getValue(childFieldName, raw);
|
|
16516
|
+
var rawChildren = childFieldName ? getValue(childFieldName, raw) : null;
|
|
16567
16517
|
if (!isNullOrUndefined(rawChildren) && Array.isArray(rawChildren)) {
|
|
16568
16518
|
children = rawChildren;
|
|
16569
|
-
// Only sort if needed
|
|
16570
16519
|
if (needsSorting) {
|
|
16571
16520
|
children = ListBase.getDataSource(children, ListBase.addSorting(this.sortOrder, this.fields.text));
|
|
16572
16521
|
}
|
|
@@ -16576,35 +16525,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16576
16525
|
}
|
|
16577
16526
|
}
|
|
16578
16527
|
};
|
|
16579
|
-
/**
|
|
16580
|
-
* Checks whether a raw datasource node has child records.
|
|
16581
|
-
*
|
|
16582
|
-
* @param {Object} raw - Raw datasource object.
|
|
16583
|
-
* @returns {boolean} True if children exist.
|
|
16584
|
-
* @private
|
|
16585
|
-
*/
|
|
16586
|
-
TreeView.prototype.hasChildRecords = function (raw) {
|
|
16587
|
-
if (this.dataType === 1) {
|
|
16588
|
-
if (!this.groupedData) {
|
|
16589
|
-
return false;
|
|
16590
|
-
}
|
|
16591
|
-
var rawId = raw[this.fields.id];
|
|
16592
|
-
if (isNullOrUndefined(rawId)) {
|
|
16593
|
-
return false;
|
|
16594
|
-
}
|
|
16595
|
-
var groupedChild = this.getChildGroup(this.groupedData, rawId.toString(), false);
|
|
16596
|
-
return !isNullOrUndefined(groupedChild) && groupedChild.length > 0;
|
|
16597
|
-
}
|
|
16598
|
-
var childField = this.fields.child.toString();
|
|
16599
|
-
var children = getValue(childField, raw);
|
|
16600
|
-
return !isNullOrUndefined(children) && Array.isArray(children) && children.length > 0;
|
|
16601
|
-
};
|
|
16602
|
-
/**
|
|
16603
|
-
* Rebuilds `virtualNodeMap` (id → index) from the current `virtualFlatNodes`.
|
|
16604
|
-
*
|
|
16605
|
-
* @returns {void}
|
|
16606
|
-
* @private
|
|
16607
|
-
*/
|
|
16608
16528
|
TreeView.prototype.rebuildVirtualNodeMap = function () {
|
|
16609
16529
|
this.virtualNodeMap.clear();
|
|
16610
16530
|
for (var i = 0; i < this.virtualFlatNodes.length; i++) {
|
|
@@ -16637,49 +16557,12 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16637
16557
|
var paddingBottom = Math.max(0, (total - end) * itemH);
|
|
16638
16558
|
return { paddingTop: paddingTop, paddingBottom: paddingBottom };
|
|
16639
16559
|
};
|
|
16640
|
-
/**
|
|
16641
|
-
* Renders the virtual window into a **nested** `<ul>/<li>` hierarchy identical to
|
|
16642
|
-
* the non-virtualized DOM structure.
|
|
16643
|
-
*
|
|
16644
|
-
* ## Scroll math
|
|
16645
|
-
* The flat-index ↔ pixel mapping stays unchanged: every entry in
|
|
16646
|
-
* `virtualFlatNodes` represents exactly one `itemHeight` row.
|
|
16647
|
-
* `paddingTop = startIndex * itemHeight` and
|
|
16648
|
-
* `paddingBottom = (total - endIndex) * itemHeight` keep the scrollbar
|
|
16649
|
-
* thumb in the correct position.
|
|
16650
|
-
*
|
|
16651
|
-
* ## Ancestor injection
|
|
16652
|
-
* When `startIndex` points at a child node whose ancestor(s) have already
|
|
16653
|
-
* scrolled above the viewport (their flat indices are < startIndex), the
|
|
16654
|
-
* ancestors would normally be missing from the DOM, forcing the children to
|
|
16655
|
-
* fall back to the root `<ul>` as flat siblings — producing wrong HTML.
|
|
16656
|
-
*
|
|
16657
|
-
* To fix this, before rendering the window we walk the ancestor chain of the
|
|
16658
|
-
* first visible node and collect every ancestor that lies **outside** the
|
|
16659
|
-
* window. Those ancestors are injected as real `<li>` containers at the
|
|
16660
|
-
* very top of the root `<ul>`. To compensate for their presence, `paddingTop`
|
|
16661
|
-
* is reduced by `injectedCount * itemHeight` so the total scroll height
|
|
16662
|
-
* remains the same.
|
|
16663
|
-
*
|
|
16664
|
-
* Once the ancestors are in the DOM they are registered in `renderedParentMap`
|
|
16665
|
-
* so the normal window-rendering loop can nest children inside them exactly
|
|
16666
|
-
* as it does when both parent and child are in the same window.
|
|
16667
|
-
*
|
|
16668
|
-
* @returns {void}
|
|
16669
|
-
* @private
|
|
16670
|
-
*/
|
|
16671
16560
|
TreeView.prototype.renderVirtualItems = function () {
|
|
16672
16561
|
if (!this.ulElement) {
|
|
16673
16562
|
return;
|
|
16674
16563
|
}
|
|
16675
16564
|
var ul = this.ulElement;
|
|
16676
|
-
// ── Snapshot focused ID BEFORE clearing the DOM ───────────────────────────
|
|
16677
|
-
// Removing a focused <li> from the DOM triggers a synchronous `blur` event,
|
|
16678
|
-
// which calls focusOut() and sets virtualFocusedId = null. Capturing the id
|
|
16679
|
-
// here (before any removeChild) ensures focus is correctly restored to the
|
|
16680
|
-
// same node after re-render even when keyboard navigation was in progress.
|
|
16681
16565
|
var focusedUid = this.virtualFocusedId || null;
|
|
16682
|
-
// ── Clear previous render (direct children only) ─────────────────────────
|
|
16683
16566
|
var existingItems = ul.querySelectorAll(':scope > li');
|
|
16684
16567
|
for (var i = existingItems.length - 1; i >= 0; i--) {
|
|
16685
16568
|
ul.removeChild(existingItems[parseInt(i.toString(), 10)]);
|
|
@@ -16690,26 +16573,22 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16690
16573
|
if (this.virtualStartIndex < this.virtualFlatNodes.length) {
|
|
16691
16574
|
var firstNode = this.virtualFlatNodes[this.virtualStartIndex];
|
|
16692
16575
|
if (firstNode.parentId) {
|
|
16693
|
-
// Build the ancestor chain from root down to the immediate parent
|
|
16694
16576
|
var ancestors = [];
|
|
16695
16577
|
var searchId = firstNode.parentId;
|
|
16696
16578
|
while (searchId) {
|
|
16697
16579
|
var ancestorIdx = this.virtualNodeMap.get(searchId);
|
|
16698
16580
|
if (!isNullOrUndefined(ancestorIdx) && ancestorIdx < this.virtualStartIndex) {
|
|
16699
16581
|
var ancestor = this.virtualFlatNodes[parseInt(ancestorIdx.toString(), 10)];
|
|
16700
|
-
ancestors.unshift(ancestor);
|
|
16582
|
+
ancestors.unshift(ancestor);
|
|
16701
16583
|
searchId = ancestor.parentId;
|
|
16702
16584
|
}
|
|
16703
16585
|
else {
|
|
16704
16586
|
break;
|
|
16705
16587
|
}
|
|
16706
16588
|
}
|
|
16707
|
-
// Inject each ancestor as a real <li> into the root <ul>
|
|
16708
|
-
// and register it in renderedParentMap for child-nesting below.
|
|
16709
16589
|
for (var a = 0; a < ancestors.length; a++) {
|
|
16710
16590
|
var ancestor = ancestors[parseInt(a.toString(), 10)];
|
|
16711
16591
|
var ancestorLi = this.createVirtualListItem(ancestor, false);
|
|
16712
|
-
// Find the correct container: root or a previously injected ancestor's <ul>
|
|
16713
16592
|
var targetUl = ul;
|
|
16714
16593
|
if (ancestor.parentId && renderedParentMap.has(ancestor.parentId)) {
|
|
16715
16594
|
var pe = renderedParentMap.get(ancestor.parentId);
|
|
@@ -16728,26 +16607,20 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16728
16607
|
}
|
|
16729
16608
|
}
|
|
16730
16609
|
}
|
|
16731
|
-
// ── Scroll-space padding (adjusted for injected ancestors) ────────────────
|
|
16732
16610
|
var total = this.virtualFlatNodes.length;
|
|
16733
16611
|
var start = this.virtualStartIndex;
|
|
16734
16612
|
var end = this.virtualEndIndex;
|
|
16735
16613
|
var rawPaddingTop = start * itemH;
|
|
16736
|
-
// Subtract the height of injected ancestors so the scroll position is
|
|
16737
|
-
// exact: those ancestor rows are now real DOM elements, not hidden space.
|
|
16738
16614
|
var adjustedPaddingTop = Math.max(0, rawPaddingTop - injectedCount * itemH);
|
|
16739
16615
|
ul.style.paddingTop = adjustedPaddingTop + 'px';
|
|
16740
16616
|
ul.style.paddingBottom = Math.max(0, (total - end) * itemH) + 'px';
|
|
16741
|
-
// ── Render window items (nested via renderedParentMap) ────────────────────
|
|
16742
16617
|
var liListBuf = [];
|
|
16743
16618
|
for (var i = start; i < end; i++) {
|
|
16744
16619
|
var node = this.virtualFlatNodes[parseInt(i.toString(), 10)];
|
|
16745
16620
|
var li = this.createVirtualListItem(node, i === start);
|
|
16746
|
-
// Find the correct parent container
|
|
16747
16621
|
var targetUl = ul;
|
|
16748
16622
|
if (node.parentId && renderedParentMap.has(node.parentId)) {
|
|
16749
16623
|
var parentEntry = renderedParentMap.get(node.parentId);
|
|
16750
|
-
// Lazily create the child <ul> the first time a child needs it
|
|
16751
16624
|
if (!parentEntry.childUl) {
|
|
16752
16625
|
parentEntry.childUl = this.createElement('ul', {
|
|
16753
16626
|
className: PARENTITEM + ' e-ul',
|
|
@@ -16759,30 +16632,11 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16759
16632
|
}
|
|
16760
16633
|
targetUl.appendChild(li);
|
|
16761
16634
|
liListBuf.push(li);
|
|
16762
|
-
// Register this node so its children in the same window can nest under it
|
|
16763
16635
|
if (node.expanded && node.hasChildren) {
|
|
16764
16636
|
renderedParentMap.set(node.id, { li: li, childUl: null });
|
|
16765
16637
|
}
|
|
16766
16638
|
}
|
|
16767
|
-
// ── Restore focus / tabindex ──────────────────────────────────────────────
|
|
16768
|
-
// In virtual mode only the li that carries the 'e-active' class should be
|
|
16769
|
-
// focusable (tabindex='0'). All other rendered li elements must be set
|
|
16770
|
-
// to tabindex='-1' so the tab order remains unambiguous as the window
|
|
16771
|
-
// changes during scrolling.
|
|
16772
16639
|
var focusRestored = false;
|
|
16773
|
-
// 1. Prefer the currently active node if it is in the rendered window.
|
|
16774
|
-
for (var k = 0; k < liListBuf.length; k++) {
|
|
16775
|
-
var li = liListBuf[parseInt(k.toString(), 10)];
|
|
16776
|
-
if (li.classList.contains(ACTIVE)) {
|
|
16777
|
-
li.setAttribute('tabindex', '0');
|
|
16778
|
-
// ── Fix: ensure FOCUS class set on active node too ──
|
|
16779
|
-
// This ensures focusIn() guard condition is met: tabindex='0' && FOCUS class
|
|
16780
|
-
addClass([li], FOCUS);
|
|
16781
|
-
focusRestored = true;
|
|
16782
|
-
break;
|
|
16783
|
-
}
|
|
16784
|
-
}
|
|
16785
|
-
// 2. Otherwise fall back to the previously focused node (if it is in window).
|
|
16786
16640
|
if (!focusRestored && focusedUid) {
|
|
16787
16641
|
for (var k = 0; k < liListBuf.length; k++) {
|
|
16788
16642
|
var li = liListBuf[parseInt(k.toString(), 10)];
|
|
@@ -16790,22 +16644,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16790
16644
|
li.setAttribute('tabindex', '0');
|
|
16791
16645
|
addClass([li], FOCUS);
|
|
16792
16646
|
addClass([li], FOCUSED$1);
|
|
16793
|
-
// ── Fix: restore actual browser focus so keyboard events keep working ──
|
|
16794
|
-
// After renderVirtualItems() replaces all <li> elements the old element
|
|
16795
|
-
// is gone from the DOM and document.activeElement falls back to
|
|
16796
|
-
// document.body. Setting tabindex + classes is not enough — the new
|
|
16797
|
-
// element also needs a programmatic .focus() call so subsequent keyboard
|
|
16798
|
-
// events (Arrow keys, Home, End, etc.) are delivered to the TreeView.
|
|
16799
|
-
// Re-attach the blur→focusOut handler so virtualFocusedId is cleared
|
|
16800
|
-
// correctly when the user tabs away.
|
|
16801
|
-
// ── Use preventScroll:true ────────────────────────────────────────────
|
|
16802
|
-
// Without preventScroll the browser scrolls the container to bring this
|
|
16803
|
-
// node into view during the re-render, changing scrollTop AFTER the
|
|
16804
|
-
// correct paddingTop has been applied. This is the root cause of the
|
|
16805
|
-
// KBN expand position-jump bug: the render is correct but the browser
|
|
16806
|
-
// silently scrolls the viewport, making the parent node appear to jump.
|
|
16807
|
-
// ensureVirtualNodeVisible() handles any legitimate scroll-into-view
|
|
16808
|
-
// needs before renderVirtualItems() is called, so scroll here is wrong.
|
|
16809
16647
|
EventHandler.add(li, 'blur', this.focusOut, this);
|
|
16810
16648
|
li.focus({ preventScroll: true });
|
|
16811
16649
|
focusRestored = true;
|
|
@@ -16813,53 +16651,36 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16813
16651
|
}
|
|
16814
16652
|
}
|
|
16815
16653
|
}
|
|
16816
|
-
// 3. Finally default to the first item in the window.
|
|
16817
16654
|
if (!focusRestored && liListBuf.length > 0) {
|
|
16818
16655
|
var firstLi = liListBuf[0];
|
|
16819
16656
|
firstLi.setAttribute('tabindex', '0');
|
|
16820
16657
|
}
|
|
16821
|
-
// ── Fix: Ensure all other rendered nodes have tabindex="-1" ──
|
|
16822
|
-
// This prevents stale tabindex="0" on multiple nodes which breaks Tab order
|
|
16823
16658
|
for (var k = 0; k < liListBuf.length; k++) {
|
|
16824
16659
|
var li = liListBuf[parseInt(k.toString(), 10)];
|
|
16825
16660
|
if (li.getAttribute('tabindex') !== '0') {
|
|
16826
16661
|
li.setAttribute('tabindex', '-1');
|
|
16827
16662
|
}
|
|
16828
16663
|
}
|
|
16829
|
-
// Keep liList in sync so keyboard-navigation helpers stay functional.
|
|
16830
16664
|
this.liList = liListBuf;
|
|
16831
16665
|
};
|
|
16832
|
-
/**
|
|
16833
|
-
* Creates a single `<li>` element for the virtual window representing `node`.
|
|
16834
|
-
*
|
|
16835
|
-
* @param {VirtualNodeData} node - The node data.
|
|
16836
|
-
* @param {boolean} _isFirst - True if this is the first rendered item (unused here but kept for potential override).
|
|
16837
|
-
* @returns {HTMLElement} The constructed `<li>` element.
|
|
16838
|
-
* @private
|
|
16839
|
-
*/
|
|
16840
16666
|
TreeView.prototype.createVirtualListItem = function (node, _isFirst) {
|
|
16841
16667
|
var li = this.createElement('li', { className: LISTITEM });
|
|
16842
|
-
// Level class for CSS indentation
|
|
16843
16668
|
li.classList.add('e-level-' + node.level);
|
|
16844
16669
|
li.setAttribute('data-uid', node.id);
|
|
16845
16670
|
li.setAttribute('aria-level', node.level.toString());
|
|
16846
16671
|
li.setAttribute('role', 'treeitem');
|
|
16847
16672
|
li.setAttribute('tabindex', '-1');
|
|
16848
|
-
// Full-row overlay (required for fullRowSelect mode)
|
|
16849
16673
|
if (this.fullRowSelect) {
|
|
16850
16674
|
var fullRow = this.createElement('div', { className: FULLROW });
|
|
16851
16675
|
li.appendChild(fullRow);
|
|
16852
16676
|
}
|
|
16853
|
-
// Text/icon wrapper
|
|
16854
16677
|
var textWrap = this.createElement('div', { className: TEXTWRAP });
|
|
16855
|
-
// Expand/collapse icon
|
|
16856
16678
|
if (node.hasChildren) {
|
|
16857
16679
|
var iconSpan = this.createElement('div', {
|
|
16858
16680
|
className: ICON + ' ' + (node.expanded ? COLLAPSIBLE : EXPANDABLE)
|
|
16859
16681
|
});
|
|
16860
16682
|
textWrap.appendChild(iconSpan);
|
|
16861
16683
|
}
|
|
16862
|
-
// Checkbox
|
|
16863
16684
|
if (this.showCheckBox) {
|
|
16864
16685
|
var checkWrap = createCheckBox(this.createElement, false, {
|
|
16865
16686
|
checked: node.isChecked === true,
|
|
@@ -16873,28 +16694,24 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16873
16694
|
}
|
|
16874
16695
|
textWrap.appendChild(checkWrap);
|
|
16875
16696
|
}
|
|
16876
|
-
// Icon
|
|
16877
16697
|
if (node.iconCss) {
|
|
16878
16698
|
var iconEl = this.createElement('span', {
|
|
16879
16699
|
className: ICON + ' ' + node.iconCss
|
|
16880
16700
|
});
|
|
16881
16701
|
textWrap.appendChild(iconEl);
|
|
16882
16702
|
}
|
|
16883
|
-
// Image
|
|
16884
16703
|
if (node.imageUrl) {
|
|
16885
16704
|
var img = document.createElement('img');
|
|
16886
16705
|
img.src = node.imageUrl;
|
|
16887
16706
|
img.classList.add(IMAGE);
|
|
16888
16707
|
textWrap.appendChild(img);
|
|
16889
16708
|
}
|
|
16890
|
-
// Text anchor
|
|
16891
16709
|
var anchor = this.createElement('span', {
|
|
16892
16710
|
className: 'e-list-text',
|
|
16893
16711
|
innerHTML: node.text
|
|
16894
16712
|
});
|
|
16895
16713
|
textWrap.appendChild(anchor);
|
|
16896
16714
|
li.appendChild(textWrap);
|
|
16897
|
-
// nodeTemplate
|
|
16898
16715
|
if (!isNullOrUndefined(this.nodeTemplateFn)) {
|
|
16899
16716
|
var rawData = this.findNodeInTreeData(node.id);
|
|
16900
16717
|
if (!isNullOrUndefined(rawData)) {
|
|
@@ -16902,7 +16719,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16902
16719
|
this.renderNodeTemplate(rawData, anchor, node.id);
|
|
16903
16720
|
}
|
|
16904
16721
|
}
|
|
16905
|
-
// State classes
|
|
16906
16722
|
if (node.expanded) {
|
|
16907
16723
|
li.classList.add(EXPANDED);
|
|
16908
16724
|
li.setAttribute('aria-expanded', 'true');
|
|
@@ -16918,80 +16734,43 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
16918
16734
|
if (node.hasChildren) {
|
|
16919
16735
|
li.classList.add(CHILD);
|
|
16920
16736
|
}
|
|
16921
|
-
// Wire the focus event so `focusIn()` fires when the user Tabs into this
|
|
16922
|
-
// item. The non-virtualized path registers this in `beforeNodeCreate()`,
|
|
16923
|
-
// but virtual items never go through that callback, so we must register
|
|
16924
|
-
// it here to keep focus styling (e.g. `e-focused`) consistent between
|
|
16925
|
-
// virtual and non-virtual modes. `unWireEvents()` already removes this
|
|
16926
|
-
// handler during teardown by iterating over the rendered `<li>`s.
|
|
16927
16737
|
EventHandler.add(li, 'focus', this.focusIn, this);
|
|
16928
16738
|
return li;
|
|
16929
16739
|
};
|
|
16930
|
-
/**
|
|
16931
|
-
* Initialises the virtual-scrolling layout:
|
|
16932
|
-
* 1. Adds the `e-virtualization` CSS class and applies a fixed `height` + `overflow-y`.
|
|
16933
|
-
* 2. Flattens all visible nodes into `virtualFlatNodes`.
|
|
16934
|
-
* 3. Measures item height and viewport height.
|
|
16935
|
-
* 4. Computes the initial window and renders it.
|
|
16936
|
-
* 5. Wires the scroll event handler.
|
|
16937
|
-
*
|
|
16938
|
-
* @returns {void}
|
|
16939
|
-
* @private
|
|
16940
|
-
*/
|
|
16941
16740
|
TreeView.prototype.initVirtualization = function () {
|
|
16942
16741
|
addClass([this.element], VIRTUALIZATION);
|
|
16943
|
-
// Apply container height
|
|
16944
16742
|
var px = this.parseHeightToPixels();
|
|
16945
16743
|
if (px > 0) {
|
|
16946
16744
|
this.element.style.height = px + 'px';
|
|
16947
16745
|
this.element.style.overflowY = 'auto';
|
|
16948
16746
|
}
|
|
16949
|
-
// Ensure the inner UL is ready
|
|
16950
16747
|
if (!this.ulElement) {
|
|
16951
16748
|
this.ulElement = select('.' + PARENTITEM, this.element);
|
|
16952
16749
|
}
|
|
16953
16750
|
if (!this.ulElement) {
|
|
16954
16751
|
return;
|
|
16955
16752
|
}
|
|
16956
|
-
// Make the UL position-relative for the absolute spacers
|
|
16957
16753
|
this.ulElement.style.position = 'relative';
|
|
16958
|
-
// Rebuild flat list
|
|
16959
16754
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
16960
16755
|
this.rebuildVirtualNodeMap();
|
|
16961
|
-
// Measure dimensions
|
|
16962
16756
|
this.virtualViewportHeight = px > 0 ? px : this.element.offsetHeight;
|
|
16963
|
-
// Render a single probe item to measure the real item height before the full render
|
|
16964
16757
|
if (this.virtualFlatNodes.length > 0) {
|
|
16965
16758
|
var probe = this.createVirtualListItem(this.virtualFlatNodes[0], true);
|
|
16966
16759
|
this.ulElement.appendChild(probe);
|
|
16967
16760
|
this.virtualItemHeight = probe.offsetHeight > 0 ? probe.offsetHeight : this.virtualItemHeight;
|
|
16968
16761
|
this.ulElement.removeChild(probe);
|
|
16969
16762
|
}
|
|
16970
|
-
// Compute window and render all items in the initial viewport
|
|
16971
16763
|
var win = this.getVirtualWindow();
|
|
16972
16764
|
this.virtualStartIndex = win.startIndex;
|
|
16973
16765
|
this.virtualEndIndex = win.endIndex;
|
|
16974
16766
|
this.renderVirtualItems();
|
|
16975
|
-
// Wire scroll
|
|
16976
16767
|
this.wireVirtualScrollEvents();
|
|
16977
16768
|
};
|
|
16978
|
-
/**
|
|
16979
|
-
* Wires the scroll event listener on the TreeView element.
|
|
16980
|
-
*
|
|
16981
|
-
* @returns {void}
|
|
16982
|
-
* @private
|
|
16983
|
-
*/
|
|
16984
16769
|
TreeView.prototype.wireVirtualScrollEvents = function () {
|
|
16985
16770
|
this.unwireVirtualScrollEvents();
|
|
16986
16771
|
this.virtualScrollBound = this.onVirtualScroll.bind(this);
|
|
16987
16772
|
this.element.addEventListener('scroll', this.virtualScrollBound, { passive: true });
|
|
16988
16773
|
};
|
|
16989
|
-
/**
|
|
16990
|
-
* Removes the scroll event listener previously wired by `wireVirtualScrollEvents`.
|
|
16991
|
-
*
|
|
16992
|
-
* @returns {void}
|
|
16993
|
-
* @private
|
|
16994
|
-
*/
|
|
16995
16774
|
TreeView.prototype.unwireVirtualScrollEvents = function () {
|
|
16996
16775
|
if (this.virtualScrollBound) {
|
|
16997
16776
|
this.element.removeEventListener('scroll', this.virtualScrollBound);
|
|
@@ -17002,29 +16781,13 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17002
16781
|
this.virtualScrollRAF = null;
|
|
17003
16782
|
}
|
|
17004
16783
|
};
|
|
17005
|
-
/**
|
|
17006
|
-
* Scroll handler for the virtual TreeView. Throttled via `requestAnimationFrame`.
|
|
17007
|
-
* Shows the loading mask during fast scrolls, re-renders the window, then hides the mask.
|
|
17008
|
-
*
|
|
17009
|
-
* @returns {void}
|
|
17010
|
-
* @private
|
|
17011
|
-
*/
|
|
17012
16784
|
TreeView.prototype.onVirtualScroll = function () {
|
|
17013
16785
|
var _this = this;
|
|
17014
16786
|
if (this.virtualScrollRAF !== null) {
|
|
17015
16787
|
cancelAnimationFrame(this.virtualScrollRAF);
|
|
17016
16788
|
}
|
|
17017
|
-
// ── Tab-induced focus guard ────────────────────────────────────────────────
|
|
17018
|
-
// When the user Tabs into a `<li tabindex="0">` that is in the middle of
|
|
17019
|
-
// the treeview, the browser auto-scrolls the container so the focused
|
|
17020
|
-
// element becomes visible. That fires a `scroll` event here, but the
|
|
17021
|
-
// virtual window already contains the focused element — re-rendering
|
|
17022
|
-
// would destroy the focused `<li>` and break focus. Detect this case
|
|
17023
|
-
// via the flag set in `keyDownHandler` and skip the re-render entirely.
|
|
17024
16789
|
if (this.virtualSkipNextScrollRender) {
|
|
17025
16790
|
this.virtualSkipNextScrollRender = false;
|
|
17026
|
-
// Update prev scrollTop so a subsequent user-driven scroll still
|
|
17027
|
-
// calculates the correct delta.
|
|
17028
16791
|
this.virtualPrevScrollTop = this.element.scrollTop;
|
|
17029
16792
|
return;
|
|
17030
16793
|
}
|
|
@@ -17041,30 +16804,16 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17041
16804
|
_this.virtualStartIndex = win.startIndex;
|
|
17042
16805
|
_this.virtualEndIndex = win.endIndex;
|
|
17043
16806
|
_this.renderVirtualItems();
|
|
17044
|
-
// Hide the skeleton mask after a short delay so it stays visible long enough
|
|
17045
|
-
// for the user to perceive the loading indicator even on short scrolls.
|
|
17046
16807
|
setTimeout(function () {
|
|
17047
16808
|
_this.hideVirtualMask();
|
|
17048
|
-
// Keep the (now hidden) mask's coords fresh for the next show.
|
|
17049
16809
|
_this.updateMaskPosition();
|
|
17050
16810
|
}, 200);
|
|
17051
16811
|
});
|
|
17052
16812
|
};
|
|
17053
|
-
/**
|
|
17054
|
-
* Creates the skeleton mask overlay used to indicate loading during fast scrolls.
|
|
17055
|
-
* Skeleton instances are stored in `skeletonInstances` for later disposal.
|
|
17056
|
-
*
|
|
17057
|
-
* @returns {void}
|
|
17058
|
-
* @private
|
|
17059
|
-
*/
|
|
17060
16813
|
TreeView.prototype.createVirtualMask = function () {
|
|
17061
16814
|
if (this.virtualMaskElement) {
|
|
17062
16815
|
return;
|
|
17063
16816
|
}
|
|
17064
|
-
// Use position:fixed so the mask is anchored to the visible viewport (not to the
|
|
17065
|
-
// scrolling container). Width/height/left/top are set/refreshed by
|
|
17066
|
-
// updateMaskPosition() so the mask always covers the TreeView's visible area
|
|
17067
|
-
// regardless of how the page itself is scrolled.
|
|
17068
16817
|
var rect = this.element.getBoundingClientRect();
|
|
17069
16818
|
var scrollBarWidth = this.element.offsetWidth - this.element.clientWidth;
|
|
17070
16819
|
var maskParent = this.createElement('div', {
|
|
@@ -17077,20 +16826,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17077
16826
|
className: VIRTUAL_MASK_ITEM,
|
|
17078
16827
|
styles: "display:flex;align-items:center;height:" + this.virtualItemHeight + "px;padding:0 12px;gap:8px;"
|
|
17079
16828
|
});
|
|
17080
|
-
// Skeleton circle for icon placeholder
|
|
17081
|
-
// const iconHolder: HTMLElement = this.createElement('span', {
|
|
17082
|
-
// styles: `width:20px;height:20px;`
|
|
17083
|
-
// });
|
|
17084
|
-
// maskItem.appendChild(iconHolder);
|
|
17085
|
-
// const iconSkel: Skeleton = new Skeleton({
|
|
17086
|
-
// shape: 'Circle',
|
|
17087
|
-
// width: '20px',
|
|
17088
|
-
// height: '20px',
|
|
17089
|
-
// cssClass: 'e-virtual-skel-icon'
|
|
17090
|
-
// });
|
|
17091
|
-
// iconSkel.appendTo(iconHolder);
|
|
17092
|
-
// this.skeletonInstances.push(iconSkel);
|
|
17093
|
-
// Skeleton text bar
|
|
17094
16829
|
var textHolder = this.createElement('span');
|
|
17095
16830
|
textHolder.style.flex = '1';
|
|
17096
16831
|
textHolder.style.height = '14px';
|
|
@@ -17108,14 +16843,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17108
16843
|
this.virtualMaskElement = maskParent;
|
|
17109
16844
|
this.element.appendChild(maskParent);
|
|
17110
16845
|
};
|
|
17111
|
-
/**
|
|
17112
|
-
* Refreshes the mask position so it always overlays the TreeView's viewport.
|
|
17113
|
-
* Called on every show / scroll, since `position:fixed` is relative to the
|
|
17114
|
-
* page viewport, not to the TreeView scroll container.
|
|
17115
|
-
*
|
|
17116
|
-
* @returns {void}
|
|
17117
|
-
* @private
|
|
17118
|
-
*/
|
|
17119
16846
|
TreeView.prototype.updateMaskPosition = function () {
|
|
17120
16847
|
if (!this.virtualMaskElement) {
|
|
17121
16848
|
return;
|
|
@@ -17127,12 +16854,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17127
16854
|
this.virtualMaskElement.style.width = (rect.width - scrollBarWidth) + 'px';
|
|
17128
16855
|
this.virtualMaskElement.style.height = rect.height + 'px';
|
|
17129
16856
|
};
|
|
17130
|
-
/**
|
|
17131
|
-
* Destroys all skeleton instances and removes the mask overlay from the DOM.
|
|
17132
|
-
*
|
|
17133
|
-
* @returns {void}
|
|
17134
|
-
* @private
|
|
17135
|
-
*/
|
|
17136
16857
|
TreeView.prototype.destroyVirtualMask = function () {
|
|
17137
16858
|
for (var i = this.skeletonInstances.length - 1; i >= 0; i--) {
|
|
17138
16859
|
this.skeletonInstances[parseInt(i.toString(), 10)].destroy();
|
|
@@ -17145,52 +16866,26 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17145
16866
|
this.virtualMaskElement = null;
|
|
17146
16867
|
}
|
|
17147
16868
|
};
|
|
17148
|
-
/**
|
|
17149
|
-
* Positions and shows the skeleton mask at the current `scrollTop` position.
|
|
17150
|
-
*
|
|
17151
|
-
* @param {number} _scrollTop - Current scrollTop of the container.
|
|
17152
|
-
* @returns {void}
|
|
17153
|
-
* @private
|
|
17154
|
-
*/
|
|
17155
16869
|
TreeView.prototype.showVirtualMask = function (_scrollTop) {
|
|
17156
16870
|
if (!this.virtualMaskElement) {
|
|
17157
16871
|
this.createVirtualMask();
|
|
17158
16872
|
}
|
|
17159
16873
|
if (this.virtualMaskElement) {
|
|
17160
|
-
// Refresh the fixed-position coords in case the TreeView was moved/resized
|
|
17161
|
-
// since the last time the mask was shown.
|
|
17162
16874
|
this.updateMaskPosition();
|
|
17163
16875
|
this.virtualMaskElement.style.display = 'block';
|
|
17164
|
-
// Visually hide the real list while the skeleton is shown
|
|
17165
16876
|
if (this.ulElement) {
|
|
17166
16877
|
this.ulElement.style.visibility = 'hidden';
|
|
17167
16878
|
}
|
|
17168
16879
|
}
|
|
17169
16880
|
};
|
|
17170
|
-
/**
|
|
17171
|
-
* Hides the skeleton mask overlay after the virtual window has been rendered.
|
|
17172
|
-
*
|
|
17173
|
-
* @returns {void}
|
|
17174
|
-
* @private
|
|
17175
|
-
*/
|
|
17176
16881
|
TreeView.prototype.hideVirtualMask = function () {
|
|
17177
16882
|
if (this.virtualMaskElement) {
|
|
17178
16883
|
this.virtualMaskElement.style.display = 'none';
|
|
17179
|
-
// Restore real list visibility
|
|
17180
16884
|
if (this.ulElement) {
|
|
17181
16885
|
this.ulElement.style.visibility = '';
|
|
17182
16886
|
}
|
|
17183
16887
|
}
|
|
17184
16888
|
};
|
|
17185
|
-
/**
|
|
17186
|
-
* Ensures the node identified by `id` is scrolled into view inside the virtual container.
|
|
17187
|
-
* If the node falls outside the rendered window, the container's `scrollTop` is adjusted so
|
|
17188
|
-
* that the node becomes visible, the window is re-computed and `renderVirtualItems` is called.
|
|
17189
|
-
*
|
|
17190
|
-
* @param {string} id - The `data-uid` of the target node.
|
|
17191
|
-
* @returns {void}
|
|
17192
|
-
* @private
|
|
17193
|
-
*/
|
|
17194
16889
|
TreeView.prototype.ensureVirtualNodeVisible = function (id) {
|
|
17195
16890
|
var idx = this.virtualNodeMap.get(id);
|
|
17196
16891
|
if (isNullOrUndefined(idx)) {
|
|
@@ -17209,25 +16904,13 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17209
16904
|
this.element.scrollTop = nodeBottom - vpH;
|
|
17210
16905
|
}
|
|
17211
16906
|
else {
|
|
17212
|
-
return;
|
|
16907
|
+
return;
|
|
17213
16908
|
}
|
|
17214
|
-
// Re-render the new window synchronously so the <li> is in the DOM
|
|
17215
16909
|
var win = this.getVirtualWindow();
|
|
17216
16910
|
this.virtualStartIndex = win.startIndex;
|
|
17217
16911
|
this.virtualEndIndex = win.endIndex;
|
|
17218
16912
|
this.renderVirtualItems();
|
|
17219
16913
|
};
|
|
17220
|
-
/**
|
|
17221
|
-
* Recursively walks the treeData (and any nested `childFieldName` arrays) to
|
|
17222
|
-
* find the node whose `idFieldName` matches the given `id` (compared as
|
|
17223
|
-
* strings). Used by the virtual-mode expand/collapse handlers so they can
|
|
17224
|
-
* locate nodes at any depth — not just the root level — before writing the
|
|
17225
|
-
* `expanded` flag back to the datasource.
|
|
17226
|
-
*
|
|
17227
|
-
* @param {string} id - The id (as a string) of the node to locate.
|
|
17228
|
-
* @returns {Object | null} The matching raw datasource node, or null if not found.
|
|
17229
|
-
* @private
|
|
17230
|
-
*/
|
|
17231
16914
|
TreeView.prototype.findNodeInTreeData = function (id) {
|
|
17232
16915
|
if (!this.treeData) {
|
|
17233
16916
|
return null;
|
|
@@ -17255,12 +16938,19 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17255
16938
|
};
|
|
17256
16939
|
return findRecursive(this.treeData);
|
|
17257
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
|
+
};
|
|
17258
16952
|
TreeView.prototype.handleVirtualExpand = function (id, isKeyboardNav) {
|
|
17259
|
-
|
|
17260
|
-
// A scroll RAF queued before the expand click would run asynchronously after
|
|
17261
|
-
// this synchronous expand completes, re-rendering the window from a stale
|
|
17262
|
-
// scrollTop and moving the parent node to the wrong position. Cancel it now
|
|
17263
|
-
// so the expand render is authoritative.
|
|
16953
|
+
var _this = this;
|
|
17264
16954
|
if (this.virtualScrollRAF !== null) {
|
|
17265
16955
|
cancelAnimationFrame(this.virtualScrollRAF);
|
|
17266
16956
|
this.virtualScrollRAF = null;
|
|
@@ -17268,7 +16958,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17268
16958
|
if (this.expandedNodes.indexOf(id) === -1) {
|
|
17269
16959
|
this.expandedNodes.push(id);
|
|
17270
16960
|
}
|
|
17271
|
-
// Also update virtualExpandedNodesSet to keep it in sync
|
|
17272
16961
|
if (this.virtualExpandedNodesSet) {
|
|
17273
16962
|
this.virtualExpandedNodesSet.add(id);
|
|
17274
16963
|
}
|
|
@@ -17278,56 +16967,76 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17278
16967
|
setValue(this.fields.expanded, true, acutalRootData);
|
|
17279
16968
|
}
|
|
17280
16969
|
}
|
|
17281
|
-
// ── Fix: Pin focused ID to the expanding node for keyboard navigation ──
|
|
17282
|
-
// When keyboard-triggered, the expanded node IS definitively the focused node
|
|
17283
|
-
// (`id` comes from currLi.getAttribute('data-uid') in expandNode, where currLi
|
|
17284
|
-
// is getFocusedNode()). Set unconditionally — the old conditional guard
|
|
17285
|
-
// `!this.virtualFocusedId` could leave a stale or null value if a previous
|
|
17286
|
-
// RAF render (from arrow-key scroll) hadn't yet completed, causing branch 3
|
|
17287
|
-
// (first item) to fire in renderVirtualItems() instead of branch 2.
|
|
17288
|
-
// For mouse clicks (isKeyboardNav=false), clear virtualFocusedId so that
|
|
17289
|
-
// renderVirtualItems() Branch 2 does NOT apply the FOCUS/FOCUSED classes —
|
|
17290
|
-
// mouse-based expand/collapse should never add the e-focused class.
|
|
17291
16970
|
if (isKeyboardNav) {
|
|
17292
16971
|
this.virtualFocusedId = id;
|
|
17293
16972
|
}
|
|
17294
16973
|
else {
|
|
17295
16974
|
this.virtualFocusedId = null;
|
|
17296
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) {
|
|
17297
17026
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
17298
17027
|
this.rebuildVirtualNodeMap();
|
|
17299
|
-
// ── Snapshot scrollTop before computing the window ────────────────────────
|
|
17300
|
-
// Read scrollTop once here and pass it into getVirtualWindow so that any
|
|
17301
|
-
// browser scroll-anchoring adjustment that happens when the padding values
|
|
17302
|
-
// change cannot affect which window we render.
|
|
17303
17028
|
var scrollTopSnapshot = this.element.scrollTop;
|
|
17304
17029
|
var win = this.getVirtualWindowAt(scrollTopSnapshot);
|
|
17305
17030
|
this.virtualStartIndex = win.startIndex;
|
|
17306
17031
|
this.virtualEndIndex = win.endIndex;
|
|
17307
|
-
// ── Block ALL scroll-triggered re-renders during this expand ─────────────
|
|
17308
|
-
// renderVirtualItems() calls li.focus() in branch 2 (keyboard focus restore).
|
|
17309
|
-
// The post-render focus() call below can also trigger browser scroll. Both
|
|
17310
|
-
// can fire the 'scroll' event and cause onVirtualScroll() to queue a RAF.
|
|
17311
|
-
// We set the skip flag ONCE here; it is consumed by the first scroll event.
|
|
17312
|
-
// To cover the second potential scroll (from the focus() call below) we use
|
|
17313
|
-
// preventScroll:true on that call so it never moves the container at all.
|
|
17314
17032
|
this.virtualSkipNextScrollRender = true;
|
|
17315
17033
|
this.renderVirtualItems();
|
|
17316
|
-
// renderVirtualItems() replaces all <li> elements so the old icon element that
|
|
17317
|
-
// had the PROCESS class is gone. Remove PROCESS from the newly rendered icon
|
|
17318
|
-
// so the node can be collapsed/expanded again without being blocked.
|
|
17319
17034
|
var newLi = this.getElement(id);
|
|
17320
17035
|
if (newLi) {
|
|
17321
17036
|
var icon = select('.' + ICON, newLi);
|
|
17322
17037
|
if (icon) {
|
|
17323
17038
|
removeClass([icon], PROCESS);
|
|
17324
17039
|
}
|
|
17325
|
-
// ── Use preventScroll:true ────────────────────────────────────────────
|
|
17326
|
-
// Without preventScroll the browser scrolls the container to bring this
|
|
17327
|
-
// node into view, which fires a second 'scroll' event. The first scroll
|
|
17328
|
-
// was already consumed by virtualSkipNextScrollRender (set above), so the
|
|
17329
|
-
// second scroll would queue a new RAF that re-renders from the
|
|
17330
|
-
// focus-adjusted scrollTop — moving the parent node to the wrong position.
|
|
17331
17040
|
newLi.focus({ preventScroll: true });
|
|
17332
17041
|
}
|
|
17333
17042
|
if (this.isLoaded) {
|
|
@@ -17340,9 +17049,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17340
17049
|
}
|
|
17341
17050
|
};
|
|
17342
17051
|
TreeView.prototype.handleVirtualCollapse = function (id, isKeyboardNav) {
|
|
17343
|
-
// ── Cancel any pending scroll RAF ─────────────────────────────────────────
|
|
17344
|
-
// Mirrors handleVirtualExpand: a queued RAF from a previous scroll event
|
|
17345
|
-
// must not override the collapse render with a stale window.
|
|
17346
17052
|
if (this.virtualScrollRAF !== null) {
|
|
17347
17053
|
cancelAnimationFrame(this.virtualScrollRAF);
|
|
17348
17054
|
this.virtualScrollRAF = null;
|
|
@@ -17351,7 +17057,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17351
17057
|
if (idx !== -1) {
|
|
17352
17058
|
this.expandedNodes.splice(idx, 1);
|
|
17353
17059
|
}
|
|
17354
|
-
// Also update virtualExpandedNodesSet to keep it in sync
|
|
17355
17060
|
if (this.virtualExpandedNodesSet) {
|
|
17356
17061
|
this.virtualExpandedNodesSet.delete(id);
|
|
17357
17062
|
}
|
|
@@ -17361,13 +17066,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17361
17066
|
setValue(this.fields.expanded, false, acutalRootData);
|
|
17362
17067
|
}
|
|
17363
17068
|
}
|
|
17364
|
-
// ── Fix: Pin focused ID to the collapsing node for keyboard navigation ──
|
|
17365
|
-
// Same reasoning as handleVirtualExpand: when keyboard-triggered, `id` is
|
|
17366
|
-
// definitively the focused node. Set unconditionally to avoid the stale/null
|
|
17367
|
-
// state that could cause the RAF re-render to fall through to branch 3.
|
|
17368
|
-
// For mouse clicks (isKeyboardNav=false), clear virtualFocusedId so that
|
|
17369
|
-
// renderVirtualItems() Branch 2 does NOT apply the FOCUS/FOCUSED classes —
|
|
17370
|
-
// mouse-based expand/collapse should never add the e-focused class.
|
|
17371
17069
|
if (isKeyboardNav) {
|
|
17372
17070
|
this.virtualFocusedId = id;
|
|
17373
17071
|
}
|
|
@@ -17376,28 +17074,18 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17376
17074
|
}
|
|
17377
17075
|
this.virtualFlatNodes = this.flattenVisibleNodes();
|
|
17378
17076
|
this.rebuildVirtualNodeMap();
|
|
17379
|
-
// ── Snapshot scrollTop before computing the window ────────────────────────
|
|
17380
|
-
// Same rationale as handleVirtualExpand: capture scrollTop before any focus()
|
|
17381
|
-
// call or padding change can cause the browser to auto-scroll.
|
|
17382
17077
|
var scrollTopSnapshot = this.element.scrollTop;
|
|
17383
17078
|
var win = this.getVirtualWindowAt(scrollTopSnapshot);
|
|
17384
17079
|
this.virtualStartIndex = win.startIndex;
|
|
17385
17080
|
this.virtualEndIndex = win.endIndex;
|
|
17386
|
-
// ── Block ALL scroll-triggered re-renders during this collapse ────────────
|
|
17387
|
-
// Same as handleVirtualExpand: use preventScroll:true on the focus() call
|
|
17388
|
-
// below so the second potential scroll event is never fired.
|
|
17389
17081
|
this.virtualSkipNextScrollRender = true;
|
|
17390
17082
|
this.renderVirtualItems();
|
|
17391
|
-
// renderVirtualItems() replaces all <li> elements so the old icon element that
|
|
17392
|
-
// had the PROCESS class is gone. Remove PROCESS from the newly rendered icon
|
|
17393
|
-
// so the node can be expanded/collapsed again without being blocked.
|
|
17394
17083
|
var newLi = this.getElement(id);
|
|
17395
17084
|
if (newLi) {
|
|
17396
17085
|
var icon = select('.' + ICON, newLi);
|
|
17397
17086
|
if (icon) {
|
|
17398
17087
|
removeClass([icon], PROCESS);
|
|
17399
17088
|
}
|
|
17400
|
-
// ── Use preventScroll:true to avoid consuming virtualSkipNextScrollRender ─
|
|
17401
17089
|
newLi.focus({ preventScroll: true });
|
|
17402
17090
|
}
|
|
17403
17091
|
if (this.isLoaded) {
|
|
@@ -17409,14 +17097,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17409
17097
|
}
|
|
17410
17098
|
}
|
|
17411
17099
|
};
|
|
17412
|
-
/**
|
|
17413
|
-
* Updates the selected state of a node in `virtualFlatNodes` and re-renders the window.
|
|
17414
|
-
*
|
|
17415
|
-
* @param {string} id - The `data-uid` of the target node.
|
|
17416
|
-
* @param {boolean} selected - Whether the node is now selected.
|
|
17417
|
-
* @returns {void}
|
|
17418
|
-
* @private
|
|
17419
|
-
*/
|
|
17420
17100
|
TreeView.prototype.updateVirtualNodeSelection = function (id, selected) {
|
|
17421
17101
|
var idx = this.virtualNodeMap.get(id);
|
|
17422
17102
|
if (!isNullOrUndefined(idx)) {
|
|
@@ -17424,21 +17104,11 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17424
17104
|
this.renderVirtualItems();
|
|
17425
17105
|
}
|
|
17426
17106
|
};
|
|
17427
|
-
/**
|
|
17428
|
-
* Updates the checkbox state of a node in `virtualFlatNodes` and re-renders the window.
|
|
17429
|
-
*
|
|
17430
|
-
* @param {string} id - The `data-uid` of the target node.
|
|
17431
|
-
* @param {'check' | 'uncheck' | 'indeterminate'} state - The new check state.
|
|
17432
|
-
* @returns {void}
|
|
17433
|
-
* @private
|
|
17434
|
-
*/
|
|
17435
17107
|
TreeView.prototype.updateVirtualNodeCheckState = function (id, state) {
|
|
17436
17108
|
var idx = this.virtualNodeMap.get(id);
|
|
17437
17109
|
if (!isNullOrUndefined(idx)) {
|
|
17438
17110
|
this.virtualFlatNodes[parseInt(idx.toString(), 10)].isChecked =
|
|
17439
17111
|
state === 'check' ? true : state === 'indeterminate' ? 'indeterminate' : false;
|
|
17440
|
-
// Keep the persistent indeterminate set in sync so flattenVisibleNodes()
|
|
17441
|
-
// correctly restores state after any full list rebuild (e.g. collapse).
|
|
17442
17112
|
if (state === 'indeterminate') {
|
|
17443
17113
|
this.virtualIndeterminateNodesSet.add(id);
|
|
17444
17114
|
}
|
|
@@ -17448,9 +17118,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17448
17118
|
this.renderVirtualItems();
|
|
17449
17119
|
}
|
|
17450
17120
|
};
|
|
17451
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17452
|
-
// END VIRTUALIZATION
|
|
17453
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17454
17121
|
/**
|
|
17455
17122
|
* Called internally if any of the property value changed.
|
|
17456
17123
|
*
|
|
@@ -17595,7 +17262,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17595
17262
|
}
|
|
17596
17263
|
}
|
|
17597
17264
|
else {
|
|
17598
|
-
// Tear down virtualization and do a full re-render
|
|
17599
17265
|
this.unwireVirtualScrollEvents();
|
|
17600
17266
|
this.destroyVirtualMask();
|
|
17601
17267
|
removeClass([this.element], VIRTUALIZATION);
|
|
@@ -17606,7 +17272,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17606
17272
|
break;
|
|
17607
17273
|
case 'height':
|
|
17608
17274
|
if (this.enableVirtualization) {
|
|
17609
|
-
// Re-initialise so the new height takes effect
|
|
17610
17275
|
this.unwireVirtualScrollEvents();
|
|
17611
17276
|
this.initVirtualization();
|
|
17612
17277
|
}
|
|
@@ -17624,7 +17289,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17624
17289
|
* @returns {void}
|
|
17625
17290
|
*/
|
|
17626
17291
|
TreeView.prototype.destroy = function () {
|
|
17627
|
-
// Tear down virtualization before standard cleanup
|
|
17628
17292
|
if (this.enableVirtualization) {
|
|
17629
17293
|
this.unwireVirtualScrollEvents();
|
|
17630
17294
|
this.destroyVirtualMask();
|
|
@@ -17715,10 +17379,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
|
|
|
17715
17379
|
if (isNullOrUndefined(fNode)) {
|
|
17716
17380
|
this.setNodeFocusable();
|
|
17717
17381
|
}
|
|
17718
|
-
// In virtual mode (with a fixed height), rebuild the flat node list and re-render
|
|
17719
|
-
// the window so the newly added nodes appear in the correct hierarchical position.
|
|
17720
|
-
// When height is not provided, the tree uses normal rendering and the DOM is
|
|
17721
|
-
// already updated by addGivenNodes() above.
|
|
17722
17382
|
if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
|
|
17723
17383
|
this.setRootData();
|
|
17724
17384
|
this.rebuildVirtualCheckCache();
|