@syncfusion/ej2-navigations 34.2.3 → 34.2.5

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.
@@ -3955,6 +3955,7 @@ var Toolbar = /** @__PURE__ @class */ (function (_super) {
3955
3955
  var _this = _super.call(this, options, element) || this;
3956
3956
  _this.resizeContext = _this.resize.bind(_this);
3957
3957
  _this.orientationChangeContext = _this.orientationChange.bind(_this);
3958
+ _this.lastObservedWidth = 0;
3958
3959
  /**
3959
3960
  * Contains the keyboard configuration of the Toolbar.
3960
3961
  */
@@ -3988,6 +3989,10 @@ var Toolbar = /** @__PURE__ @class */ (function (_super) {
3988
3989
  }
3989
3990
  });
3990
3991
  this.unwireEvents();
3992
+ this.lastObservedWidth = 0;
3993
+ if (this.resizeObserver && this.element.closest('.e-splitter')) {
3994
+ this.resizeObserver.disconnect();
3995
+ }
3991
3996
  this.tempId.forEach(function (ele) {
3992
3997
  if (!isNullOrUndefined(_this.element.querySelector(ele))) {
3993
3998
  document.body.appendChild(_this.element.querySelector(ele)).style.display = 'none';
@@ -4572,6 +4577,17 @@ var Toolbar = /** @__PURE__ @class */ (function (_super) {
4572
4577
  this.scrollEvent = this.docEvent.bind(this);
4573
4578
  this.renderControl();
4574
4579
  this.wireEvents();
4580
+ if (this.element.closest('.e-splitter')) {
4581
+ this.lastObservedWidth = this.element.offsetWidth;
4582
+ this.resizeObserver = new window.ResizeObserver(function () {
4583
+ if (_this.element.offsetWidth === _this.lastObservedWidth) {
4584
+ return;
4585
+ }
4586
+ _this.lastObservedWidth = _this.element.offsetWidth;
4587
+ _this.refreshOverflow();
4588
+ });
4589
+ this.resizeObserver.observe(this.element);
4590
+ }
4575
4591
  this.renderComplete();
4576
4592
  if (this.isReact && this.portals && this.portals.length > 0) {
4577
4593
  this.renderReactTemplates(function () {
@@ -11024,55 +11040,28 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
11024
11040
  _this.isDropIn = false;
11025
11041
  _this.OldCheckedData = [];
11026
11042
  _this.isHiddenItem = false;
11027
- // ── Virtualization state ──────────────────────────────────────────────────────────────
11028
- /** Flat ordered list of all currently-visible (non-collapsed) tree nodes. */
11043
+ // Virtualization state
11029
11044
  _this.virtualFlatNodes = [];
11030
- /** Maps node id → index in virtualFlatNodes for O(1) lookups. */
11031
11045
  _this.virtualNodeMap = new Map();
11032
- /** Set of expanded node IDs for O(1) lookup performance during flattening (avoids array indexOf). */
11033
11046
  _this.virtualExpandedNodesSet = new Set();
11034
- /** Set of checked node IDs for O(1) lookup performance during flattening. */
11035
11047
  _this.virtualCheckedNodesSet = new Set();
11036
- /** Set of indeterminate node IDs — persists across flattenVisibleNodes() rebuilds. */
11037
11048
  _this.virtualIndeterminateNodesSet = new Set();
11038
- /** Set of selected node IDs for O(1) lookup performance during flattening. */
11039
11049
  _this.virtualSelectedNodesSet = new Set();
11040
- /** Row height in pixels, measured from the first rendered item or set to 40 as a default. */
11041
11050
  _this.virtualItemHeight = 40;
11042
- /** Height of the scrollable container in pixels. */
11043
11051
  _this.virtualViewportHeight = 0;
11044
- /** scrollTop captured during the previous scroll handler invocation. */
11045
11052
  _this.virtualPrevScrollTop = 0;
11046
- /** Index of the first rendered row in the current window. */
11047
11053
  _this.virtualStartIndex = 0;
11048
- /** Index one past the last rendered row in the current window. */
11049
11054
  _this.virtualEndIndex = 0;
11050
- /** Extra rows rendered above and below the visible window to smooth scrolling. */
11051
11055
  _this.virtualOverscanCount = 3;
11052
- /** RequestAnimationFrame handle used for throttling scroll events. */
11053
11056
  _this.virtualScrollRAF = null;
11054
- /** The `.e-mask-parent` overlay element shown during fast scroll. */
11055
11057
  _this.virtualMaskElement = null;
11056
- /** Bound scroll handler stored for later removeEventListener. */
11057
11058
  _this.virtualScrollBound = null;
11058
- /** Skeleton component instances inside the mask overlay. */
11059
11059
  _this.skeletonInstances = [];
11060
- /** Set to true whenever the flat node list must be rebuilt on next render. */
11061
11060
  _this.virtualTreeDirty = false;
11062
- /** The data-uid of the currently keyboard-focused node in virtual mode (persists across re-renders). */
11063
11061
  _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
11062
  _this.virtualSkipNextScrollRender = false;
11063
+ _this.filterCheckedNodes = [];
11064
+ _this.filterIndeterminateNodes = [];
11076
11065
  return _this;
11077
11066
  }
11078
11067
  TreeView_1 = TreeView;
@@ -11373,17 +11362,12 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
11373
11362
  return false;
11374
11363
  }
11375
11364
  };
11365
+ TreeView.prototype.isRemoteDataLoadOnDemand = function () {
11366
+ var remoteDataSource = (this.fields.dataSource instanceof DataManager) ||
11367
+ (this.fields.child && this.fields.child.dataSource instanceof DataManager ? true : false);
11368
+ return !remoteDataSource && !this.loadOnDemand;
11369
+ };
11376
11370
  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
11371
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
11388
11372
  this.ulElement = this.createElement('ul', {
11389
11373
  className: PARENTITEM + ' ' + 'e-ul',
@@ -11571,7 +11555,9 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
11571
11555
  if (this_1.checkedNodes.indexOf(childId) !== -1) {
11572
11556
  count++;
11573
11557
  }
11574
- else if (this_1.element.classList.contains('e-filtering') && OldCheckedNodes.findIndex(function (e) { return e['id'] === childId; }) !== -1) {
11558
+ else if (this_1.element.classList.contains('e-filtering') && (this_1.isRemoteDataLoadOnDemand() ?
11559
+ this_1.filterCheckedNodes.findIndex(function (id) { return id === childId; }) !== -1 :
11560
+ OldCheckedNodes.findIndex(function (e) { return e['id'] === childId; }) !== -1)) {
11575
11561
  count++;
11576
11562
  }
11577
11563
  };
@@ -11890,6 +11876,23 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
11890
11876
  }
11891
11877
  });
11892
11878
  var parentNodeChecked = false;
11879
+ if (this.isRemoteDataLoadOnDemand() && this.element.classList.contains('e-filtering') && this.autoCheck) {
11880
+ if (this.filterCheckedNodes.indexOf(dataUid_1) !== -1) {
11881
+ this.changeState(checkBoxEle, 'check', null, true, true);
11882
+ }
11883
+ else if (this.filterIndeterminateNodes.indexOf(dataUid_1) !== -1) {
11884
+ this.changeState(checkBoxEle, 'indeterminate', null, true, true);
11885
+ }
11886
+ else {
11887
+ this.changeState(checkBoxEle, 'uncheck', null, true, true);
11888
+ }
11889
+ var parentUL_1 = closest(element, '.' + PARENTITEM);
11890
+ if (!isNullOrUndefined(parentUL_1)) {
11891
+ var currentParent = closest(parentUL_1, '.' + LISTITEM);
11892
+ this.ensureParentCheckState(currentParent);
11893
+ }
11894
+ return;
11895
+ }
11893
11896
  if (this.element.classList.contains('e-filtering')) {
11894
11897
  var oldCheckedNodes = new DataManager(this.OldCheckedData).executeLocal(new Query().where('parentID', 'equal', dataUid_1, true));
11895
11898
  checkedCount = oldCheckedNodes.length;
@@ -11997,7 +12000,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
11997
12000
  }
11998
12001
  });
11999
12002
  };
12000
- TreeView.prototype.getAllChildNodes = function (data, parentId) {
12003
+ TreeView.prototype.getAllChildNodes = function (data, parentId, includeAllDescendants) {
12001
12004
  if (isNullOrUndefined(data) || isNullOrUndefined(parentId)) {
12002
12005
  return [];
12003
12006
  }
@@ -12014,17 +12017,55 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12014
12017
  }
12015
12018
  if (this.dataType === 2) {
12016
12019
  var parentFieldId_1 = this.fields.id;
12017
- var childField = this.fields.child.toString();
12018
- var target_2 = parentId.toString();
12019
- var node = data.find(function (n) {
12020
- var idVal = getValue(parentFieldId_1, n);
12021
- return !isNullOrUndefined(idVal) && idVal.toString() === target_2;
12022
- });
12020
+ var childField_1 = this.fields.child.toString();
12021
+ var target = parentId.toString();
12022
+ var findNodeInTree_1 = function (nodes, id) {
12023
+ if (!Array.isArray(nodes)) {
12024
+ return undefined;
12025
+ }
12026
+ for (var i = 0; i < nodes.length; i++) {
12027
+ var n = nodes[parseInt(i.toString(), 10)];
12028
+ var idVal = getValue(parentFieldId_1, n);
12029
+ if (!isNullOrUndefined(idVal) && idVal.toString() === id) {
12030
+ return n;
12031
+ }
12032
+ var subs = getValue(childField_1, n);
12033
+ var found = findNodeInTree_1(subs, id);
12034
+ if (found) {
12035
+ return found;
12036
+ }
12037
+ }
12038
+ return undefined;
12039
+ };
12040
+ var node = findNodeInTree_1(data, target);
12023
12041
  if (!node) {
12024
12042
  return [];
12025
12043
  }
12026
- var children = getValue(childField, node);
12027
- return Array.isArray(children) ? children : [];
12044
+ var children = getValue(childField_1, node);
12045
+ if (!Array.isArray(children)) {
12046
+ return [];
12047
+ }
12048
+ if (!includeAllDescendants) {
12049
+ return children;
12050
+ }
12051
+ var result_1 = children.slice();
12052
+ var collectNested_1 = function (nodes) {
12053
+ if (!Array.isArray(nodes)) {
12054
+ return;
12055
+ }
12056
+ for (var i = 0; i < nodes.length; i++) {
12057
+ var n = nodes[parseInt(i.toString(), 10)];
12058
+ var grandChildren = getValue(childField_1, n);
12059
+ if (Array.isArray(grandChildren) && grandChildren.length) {
12060
+ for (var j = 0; j < grandChildren.length; j++) {
12061
+ result_1.push(grandChildren[parseInt(j.toString(), 10)]);
12062
+ }
12063
+ collectNested_1(grandChildren);
12064
+ }
12065
+ }
12066
+ };
12067
+ collectNested_1(children);
12068
+ return result_1;
12028
12069
  }
12029
12070
  return [];
12030
12071
  };
@@ -12470,7 +12511,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12470
12511
  this.checkDisabledState(id);
12471
12512
  }
12472
12513
  if (this.enableVirtualization) {
12473
- // Clear any indeterminate state — node is now fully checked
12474
12514
  this.virtualIndeterminateNodesSet.delete(id);
12475
12515
  var actualIndex = this.virtualNodeMap.get(id);
12476
12516
  if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
@@ -12491,20 +12531,15 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12491
12531
  var actualIndex = this.virtualNodeMap.get(id);
12492
12532
  if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
12493
12533
  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
12534
  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
12535
  this.virtualIndeterminateNodesSet.add(id);
12500
12536
  }
12501
12537
  else {
12502
- // Node is being fully unchecked — clear indeterminate tracking too
12503
12538
  this.virtualIndeterminateNodesSet.delete(id);
12504
12539
  this.virtualCheckedNodesSet.delete(id);
12505
12540
  this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].isChecked = false;
12506
12541
  if (this.treeData && this.fields && this.fields.isChecked) {
12507
- setValue(this.fields.isChecked, false, this.treeData[parseInt(id.toString(), 10) - 1]);
12542
+ this.updateField(this.treeData, this.fields, id, this.fields.isChecked, false);
12508
12543
  }
12509
12544
  if (this.autoCheck && this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].hasChildren) {
12510
12545
  this.setVirtualChildCheckState(id, false);
@@ -12550,8 +12585,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12550
12585
  }
12551
12586
  }
12552
12587
  }
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
12588
  var collapsedChildren = this.getChildNodes(this.treeData, parentId);
12556
12589
  if (collapsedChildren) {
12557
12590
  for (var i = 0; i < collapsedChildren.length; i++) {
@@ -12697,7 +12730,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12697
12730
  }
12698
12731
  this.isLoaded = true;
12699
12732
  this.isNodeDropped = false;
12700
- // Initialise (or re-initialise) virtual mode after data binding has settled
12701
12733
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
12702
12734
  this.initVirtualization();
12703
12735
  }
@@ -12837,9 +12869,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12837
12869
  };
12838
12870
  TreeView.prototype.expandNode = function (currLi, icon, loaded, isKeyboardNav) {
12839
12871
  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
12872
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
12844
12873
  var id = currLi ? currLi.getAttribute('data-uid') : null;
12845
12874
  if (id) {
@@ -12968,9 +12997,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
12968
12997
  };
12969
12998
  TreeView.prototype.nodeCollapseAction = function (currLi, icon, colArgs, isKeyboardNav) {
12970
12999
  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
13000
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
12975
13001
  var id = currLi ? currLi.getAttribute('data-uid') : null;
12976
13002
  if (id) {
@@ -13441,7 +13467,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
13441
13467
  li.setAttribute('tabindex', '0');
13442
13468
  EventHandler.add(li, 'blur', this.focusOut, this);
13443
13469
  this.updateIdAttr(focusedNode, li);
13444
- // Track focused id for virtual mode re-render restoration
13445
13470
  if (this.enableVirtualization) {
13446
13471
  this.virtualFocusedId = li.getAttribute('data-uid');
13447
13472
  }
@@ -13457,7 +13482,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
13457
13482
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
13458
13483
  this.virtualSelectedNodesSet.add(id);
13459
13484
  var actualIndex = this.virtualNodeMap.get(id);
13460
- if (actualIndex && actualIndex > -1) {
13485
+ if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
13461
13486
  this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].selected = true;
13462
13487
  }
13463
13488
  }
@@ -13478,7 +13503,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
13478
13503
  var id = liEle.getAttribute('data-uid');
13479
13504
  this.virtualSelectedNodesSet.delete(id);
13480
13505
  var actualIndex = this.virtualNodeMap.get(id);
13481
- if (actualIndex && actualIndex > -1) {
13506
+ if (!isNullOrUndefined(actualIndex) && actualIndex > -1) {
13482
13507
  this.virtualFlatNodes[parseInt(actualIndex.toString(), 10)].selected = false;
13483
13508
  }
13484
13509
  }
@@ -13573,12 +13598,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
13573
13598
  }
13574
13599
  };
13575
13600
  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
13601
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
13583
13602
  this.expandNode(currLi, icon, undefined, isKeyboardNav);
13584
13603
  return;
@@ -13696,9 +13715,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
13696
13715
  });
13697
13716
  };
13698
13717
  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
13718
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
13703
13719
  var focusedLi = this.getFocusedNode();
13704
13720
  if (focusedLi) {
@@ -13794,6 +13810,83 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
13794
13810
  }
13795
13811
  }
13796
13812
  }
13813
+ if (this.isRemoteDataLoadOnDemand() && this.element.classList.contains('e-filtering') && this.autoCheck) {
13814
+ var nodeUid = li.getAttribute('data-uid');
13815
+ if (isNullOrUndefined(nodeUid)) {
13816
+ return;
13817
+ }
13818
+ var checkedIndex = this.filterCheckedNodes.indexOf(nodeUid);
13819
+ var indeterminateIndex = this.filterIndeterminateNodes.indexOf(nodeUid);
13820
+ var shouldCheck = !isCheck;
13821
+ if (shouldCheck) {
13822
+ if (checkedIndex === -1) {
13823
+ this.filterCheckedNodes.push(nodeUid);
13824
+ }
13825
+ if (indeterminateIndex !== -1) {
13826
+ this.filterIndeterminateNodes.splice(indeterminateIndex, 1);
13827
+ }
13828
+ }
13829
+ else {
13830
+ if (checkedIndex !== -1) {
13831
+ this.filterCheckedNodes.splice(checkedIndex, 1);
13832
+ }
13833
+ }
13834
+ var parentLi = closest(closest(li, '.' + PARENTITEM), '.' + LISTITEM);
13835
+ while (!isNullOrUndefined(parentLi)) {
13836
+ var parentUid = parentLi.getAttribute('data-uid');
13837
+ if (!isNullOrUndefined(parentUid)) {
13838
+ var parentChildren = this.getAllChildNodes(this.DDTTreeData, parentUid, true);
13839
+ if (parentChildren && parentChildren.length > 0) {
13840
+ var firstChildState = void 0;
13841
+ var mismatchFound = false;
13842
+ for (var i = 0; i < parentChildren.length; i++) {
13843
+ var childData = parentChildren[parseInt(i.toString(), 10)];
13844
+ var childId = childData && childData[this.fields.id]
13845
+ ? childData[this.fields.id].toString()
13846
+ : null;
13847
+ if (isNullOrUndefined(childId)) {
13848
+ continue;
13849
+ }
13850
+ var childCheckedState = this.filterIndeterminateNodes.indexOf(childId) !== -1
13851
+ ? null
13852
+ : this.filterCheckedNodes.indexOf(childId) !== -1;
13853
+ if (firstChildState === void 0) {
13854
+ firstChildState = childCheckedState;
13855
+ }
13856
+ else if (childCheckedState !== firstChildState) {
13857
+ mismatchFound = true;
13858
+ break;
13859
+ }
13860
+ }
13861
+ if (mismatchFound || firstChildState === null) {
13862
+ if (this.filterIndeterminateNodes.indexOf(parentUid) === -1) {
13863
+ this.filterIndeterminateNodes.push(parentUid);
13864
+ }
13865
+ var parentCheckedIndex = this.filterCheckedNodes.indexOf(parentUid);
13866
+ if (parentCheckedIndex !== -1) {
13867
+ this.filterCheckedNodes.splice(parentCheckedIndex, 1);
13868
+ }
13869
+ }
13870
+ else {
13871
+ var parentIndeterminateIndex = this.filterIndeterminateNodes.indexOf(parentUid);
13872
+ if (parentIndeterminateIndex !== -1) {
13873
+ this.filterIndeterminateNodes.splice(parentIndeterminateIndex, 1);
13874
+ }
13875
+ var parentCheckedIndex = this.filterCheckedNodes.indexOf(parentUid);
13876
+ if (firstChildState === true) {
13877
+ if (parentCheckedIndex === -1) {
13878
+ this.filterCheckedNodes.push(parentUid);
13879
+ }
13880
+ }
13881
+ else if (parentCheckedIndex !== -1) {
13882
+ this.filterCheckedNodes.splice(parentCheckedIndex, 1);
13883
+ }
13884
+ }
13885
+ }
13886
+ }
13887
+ parentLi = closest(closest(parentLi, '.' + PARENTITEM), '.' + LISTITEM);
13888
+ }
13889
+ }
13797
13890
  this.changeState(checkWrap, isCheck ? 'uncheck' : 'check', e, true);
13798
13891
  this.updateActiveClass(li, isCheck);
13799
13892
  if (this.autoCheck) {
@@ -14130,7 +14223,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
14130
14223
  };
14131
14224
  TreeView.prototype.focusNextNode = function (li, isTowards) {
14132
14225
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
14133
- // Determine the id of the node one step in the requested direction
14134
14226
  var currentId = li ? li.getAttribute('data-uid') : null;
14135
14227
  var currentIdx = -1;
14136
14228
  if (!isNullOrUndefined(currentId)) {
@@ -14142,26 +14234,14 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
14142
14234
  return;
14143
14235
  }
14144
14236
  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
14237
  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
14238
  var allLi = this.element.querySelectorAll('.' + LISTITEM + '.' + FOCUS);
14156
14239
  for (var k = 0; k < allLi.length; k++) {
14157
14240
  allLi[parseInt(k.toString(), 10)].classList.remove(FOCUS);
14158
14241
  allLi[parseInt(k.toString(), 10)].classList.remove(FOCUSED$1);
14159
14242
  allLi[parseInt(k.toString(), 10)].setAttribute('tabindex', '-1');
14160
14243
  }
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
14244
  this.ensureVirtualNodeVisible(targetId);
14164
- // Re-query both nodes after the potential re-render so setFocus gets live DOM elements
14165
14245
  var prevNode = currentId ? this.getElement(currentId) : li;
14166
14246
  var nextNode_1 = this.getElement(targetId);
14167
14247
  if (!isNullOrUndefined(nextNode_1)) {
@@ -14262,18 +14342,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
14262
14342
  if (!focusedElement) {
14263
14343
  return;
14264
14344
  }
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
14345
  var actuallyFocusedElement = document.activeElement;
14278
14346
  var isAlreadyFocusedInVirtualMode = this.enableVirtualization
14279
14347
  && actuallyFocusedElement === focusedElement
@@ -14528,12 +14596,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
14528
14596
  else {
14529
14597
  txtEle[ListBase.getDomSetter(this.listBaseOption)] = ListBase.getSanitizedText(newText, this.listBaseOption);
14530
14598
  }
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
14599
  if (this.enableVirtualization) {
14538
14600
  var id = liEle.getAttribute('data-uid');
14539
14601
  var idx = this.virtualNodeMap ? this.virtualNodeMap.get(id) : undefined;
@@ -14978,11 +15040,49 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
14978
15040
  this.fields.dataSource = this.treeData;
14979
15041
  }
14980
15042
  this.triggerEvent('nodeDropped', nodeData);
15043
+ if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
15044
+ this.setRootData();
15045
+ this.rebuildVirtualCheckCache();
15046
+ this.virtualFlatNodes = this.flattenVisibleNodes();
15047
+ this.rebuildVirtualNodeMap();
15048
+ var scrollTopSnapshot = this.element.scrollTop;
15049
+ var win = this.getVirtualWindowAt(scrollTopSnapshot);
15050
+ this.virtualStartIndex = win.startIndex;
15051
+ this.virtualEndIndex = win.endIndex;
15052
+ this.virtualSkipNextScrollRender = true;
15053
+ this.renderVirtualItems();
15054
+ }
14981
15055
  };
14982
15056
  TreeView.prototype.appendNode = function (dropTarget, dragLi, dropLi, e, dragObj, offsetY) {
14983
15057
  var checkWrapper = closest(dropTarget, '.' + CHECKBOXWRAP);
14984
15058
  var collapse = closest(e.target, '.' + COLLAPSIBLE);
14985
15059
  var expand = closest(e.target, '.' + EXPANDABLE);
15060
+ if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
15061
+ var routesToSiblingBranch = !dragLi.classList.contains('e-disable') && !checkWrapper &&
15062
+ ((expand && e.event.offsetY < 5) || (collapse && e.event.offsetX < 3) ||
15063
+ (expand && e.event.offsetY > 19) || (collapse && e.event.offsetX > 19) ||
15064
+ (!expand && !collapse));
15065
+ if (routesToSiblingBranch) {
15066
+ if (dropTarget.nodeName === 'LI') {
15067
+ this.virtualMoveAsSibling(dragLi, dropLi, e, dragObj);
15068
+ }
15069
+ else if (dropTarget.firstElementChild && dropTarget.classList.contains(ROOT)) {
15070
+ if (dropTarget.firstElementChild.nodeName === 'UL') {
15071
+ this.virtualMoveAsSibling(dragLi, dropLi, e, dragObj);
15072
+ }
15073
+ }
15074
+ else if ((dropTarget.classList.contains('e-icon-collapsible')) || (dropTarget.classList.contains('e-icon-expandable'))) {
15075
+ this.virtualMoveAsSibling(dragLi, dropLi, e, dragObj);
15076
+ }
15077
+ else {
15078
+ this.virtualMoveAsChild(dragLi, dropLi, dragObj, offsetY, dropTarget);
15079
+ }
15080
+ }
15081
+ else {
15082
+ this.virtualMoveAsChild(dragLi, dropLi, dragObj, offsetY, dropTarget);
15083
+ }
15084
+ return;
15085
+ }
14986
15086
  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
15087
  if (dropTarget.nodeName === 'LI') {
14988
15088
  this.dropAsSiblingNode(dragLi, dropLi, e, dragObj);
@@ -15006,6 +15106,62 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
15006
15106
  this.ensureIndeterminate();
15007
15107
  }
15008
15108
  };
15109
+ TreeView.prototype.virtualMoveAsSibling = function (dragLi, dropLi, e, dragObj) {
15110
+ var dropUl = closest(dropLi, '.' + PARENTITEM);
15111
+ var pre;
15112
+ if (e.target.offsetHeight > 0 && e.event.offsetY > e.target.offsetHeight - 2) {
15113
+ pre = false;
15114
+ }
15115
+ else if (e.event.offsetY < 2) {
15116
+ pre = true;
15117
+ }
15118
+ else if (e.target.classList.contains('e-icon-expandable') || (e.target.classList.contains('e-icon-collapsible'))) {
15119
+ if ((e.event.offsetY < 5) || (e.event.offsetX < 3)) {
15120
+ pre = true;
15121
+ }
15122
+ else if ((e.event.offsetY > 15) || (e.event.offsetX > 17)) {
15123
+ pre = false;
15124
+ }
15125
+ }
15126
+ this.moveData(dragLi, dropLi, dropUl, pre, dragObj);
15127
+ };
15128
+ TreeView.prototype.virtualMoveAsChild = function (dragLi, dropLi, dragObj, offsetY, dropTarget) {
15129
+ var pos = offsetY;
15130
+ var isSiblingMarker = dropTarget.classList.contains('e-sibling');
15131
+ var refLi = (pos < 7 && !isSiblingMarker) || (isSiblingMarker &&
15132
+ dropLi.lastChild && !dropLi.lastChild.classList.contains('e-sibling'))
15133
+ ? dropLi : null;
15134
+ var dropTargetHt = dropTarget;
15135
+ var isAfter = (dropTargetHt.offsetHeight > 0 && pos > dropTargetHt.offsetHeight - 10);
15136
+ if (refLi) {
15137
+ var dropParentUl = closest(dropLi, '.' + PARENTITEM);
15138
+ this.moveData(dragLi, dropLi, dropParentUl, true, dragObj);
15139
+ }
15140
+ else if (isAfter) {
15141
+ var dropParentUl = closest(dropLi, '.' + PARENTITEM);
15142
+ this.moveData(dragLi, dropLi, dropParentUl, false, dragObj);
15143
+ }
15144
+ else {
15145
+ var dropIcon = select('div.' + EXPANDABLE + ', div.' + COLLAPSIBLE, dropLi);
15146
+ var dropIsCollapsedParent = dropIcon && dropIcon.classList.contains(EXPANDABLE);
15147
+ var dropIsLeaf = isNullOrUndefined(dropIcon);
15148
+ if (this.preventExpand !== true && (dropIsCollapsedParent || dropIsLeaf)) {
15149
+ var dropLiId = dropLi.getAttribute('data-uid');
15150
+ if (dropLiId && this.expandedNodes.indexOf(dropLiId) === -1) {
15151
+ this.expandedNodes.push(dropLiId);
15152
+ }
15153
+ if (this.virtualExpandedNodesSet && dropLiId) {
15154
+ this.virtualExpandedNodesSet.add(dropLiId);
15155
+ }
15156
+ var dropRecord = this.findNodeInTreeData(dropLiId);
15157
+ if (dropRecord && this.fields && this.fields.expanded) {
15158
+ setValue(this.fields.expanded, true, dropRecord);
15159
+ }
15160
+ }
15161
+ var dropUl = select('.' + PARENTITEM, dropLi) || dropLi;
15162
+ this.moveData(dragLi, null, dropUl, true, dragObj);
15163
+ }
15164
+ };
15009
15165
  TreeView.prototype.dropAsSiblingNode = function (dragLi, dropLi, e, dragObj) {
15010
15166
  var dropUl = closest(dropLi, '.' + PARENTITEM);
15011
15167
  var dragParentUl = closest(dragLi, '.' + PARENTITEM);
@@ -15093,7 +15249,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
15093
15249
  delete removedData[0][this.fields.parentID];
15094
15250
  }
15095
15251
  else {
15096
- var currPid = this.isNumberTypeId ? parseFloat(parentId) : parentId;
15252
+ var currPid = this.isNumberTypeId && parentId ? parseFloat(parentId) : parentId;
15097
15253
  setValue(this.fields.parentID, currPid, removedData[0]);
15098
15254
  }
15099
15255
  this.treeData.splice(pos, 0, removedData[0]);
@@ -15235,7 +15391,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
15235
15391
  var draggedNodeData = obj ? obj.dragData : null;
15236
15392
  var newParent = dropTarget ? this.parents(dropTarget, '.' + LISTITEM) : null;
15237
15393
  var dragLiParent = obj.dragLi.parentElement;
15238
- var dragParent = obj.dragLi ? closest(dragLiParent, '.' + LISTITEM) : null;
15394
+ var dragParent = obj.dragLi && dragLiParent ? closest(dragLiParent, '.' + LISTITEM) : null;
15239
15395
  var targetParent = null;
15240
15396
  var indexValue = null;
15241
15397
  var iconCss = [DROPNEXT, DROPIN, DROPOUT, NODROP];
@@ -15244,7 +15400,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
15244
15400
  var index = node ? closest(node, '.e-list-parent') : null;
15245
15401
  var i = 0;
15246
15402
  var position = null;
15247
- dragParent = (obj.dragLi && dragParent === null) ? closest(dragLiParent, '.' + ROOT) : dragParent;
15403
+ dragParent = (obj.dragLi && dragParent === null) && dragLiParent ? closest(dragLiParent, '.' + ROOT) : dragParent;
15248
15404
  dragParent = (drop === true) ? this.dragParent : dragParent;
15249
15405
  if (cloneEle) {
15250
15406
  while (i < 4) {
@@ -15918,26 +16074,10 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
15918
16074
  TreeView.prototype.keyDownHandler = function (e) {
15919
16075
  if (e.key === 'Tab' || e.keyCode === 9) {
15920
16076
  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
16077
  if (this.enableVirtualization) {
15929
16078
  this.virtualSkipNextScrollRender = true;
15930
16079
  }
15931
16080
  }
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
16081
  if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.keyCode === 40 || e.keyCode === 38
15942
16082
  || e.key === 'ArrowRight' || e.key === 'ArrowLeft' || e.keyCode === 39 || e.keyCode === 37) {
15943
16083
  if (this.enableVirtualization) {
@@ -16299,10 +16439,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16299
16439
  if (this.dataType === 1) {
16300
16440
  this.groupedData = this.getGroupedData(this.treeData, this.fields.parentID);
16301
16441
  }
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
16442
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
16307
16443
  this.virtualFlatNodes = this.flattenVisibleNodes();
16308
16444
  this.rebuildVirtualNodeMap();
@@ -16371,16 +16507,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16371
16507
  }
16372
16508
  return parentsID;
16373
16509
  };
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
16510
  TreeView.prototype.parseHeightToPixels = function () {
16385
16511
  var h = this.height;
16386
16512
  if (isNullOrUndefined(h)) {
@@ -16392,13 +16518,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16392
16518
  var parsed = parseFloat(h);
16393
16519
  return isNaN(parsed) ? 0 : parsed;
16394
16520
  };
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
16521
  TreeView.prototype.measureVirtualItemHeight = function () {
16403
16522
  var firstLi = select('.' + LISTITEM, this.element);
16404
16523
  if (firstLi && firstLi.offsetHeight > 0) {
@@ -16406,13 +16525,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16406
16525
  }
16407
16526
  return this.virtualItemHeight;
16408
16527
  };
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
16528
  TreeView.prototype.rebuildVirtualCheckCache = function () {
16417
16529
  this.virtualExpandedNodesSet.clear();
16418
16530
  this.virtualCheckedNodesSet.clear();
@@ -16433,20 +16545,10 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16433
16545
  }
16434
16546
  }
16435
16547
  };
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
16548
  TreeView.prototype.flattenVisibleNodes = function () {
16445
- // Build cached Sets for fast lookups
16446
16549
  this.rebuildVirtualCheckCache();
16447
16550
  var result = [];
16448
16551
  if (this.dataType === 1) {
16449
- // Flat data with parentID field — use getChildGroup to find root nodes
16450
16552
  var rootNodes = [];
16451
16553
  if (this.groupedData) {
16452
16554
  rootNodes = this.getChildGroup(this.groupedData, null, true);
@@ -16454,40 +16556,29 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16454
16556
  if (!rootNodes || rootNodes.length === 0) {
16455
16557
  rootNodes = this.rootData;
16456
16558
  }
16457
- // Apply sortOrder to root-level nodes for flat data (same as hierarchical path below)
16458
16559
  rootNodes = this.getSortedData(rootNodes);
16459
16560
  this.flattenNodeRecursive(rootNodes, 1, null, result);
16460
16561
  }
16461
16562
  else {
16462
- // Hierarchical data
16463
16563
  var sorted = this.getSortedData(this.rootData);
16464
16564
  this.flattenNodeRecursive(sorted, 1, null, result);
16465
16565
  }
16466
16566
  return result;
16467
16567
  };
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
16568
  TreeView.prototype.flattenNodeRecursive = function (nodes, level, parentId, result) {
16479
16569
  if (!nodes || nodes.length === 0) {
16480
16570
  return;
16481
16571
  }
16482
- // Cache field names and settings outside the loop to avoid repeated conversions
16483
- var childFieldName = this.fields.child.toString();
16484
- var expandedFieldName = this.fields.expanded;
16485
- var isCheckedFieldName = this.fields.isChecked;
16486
- var iconCssFieldName = this.fields.iconCss;
16487
- var imageUrlFieldName = this.fields.imageUrl;
16488
- var idFieldName = this.fields.id;
16489
- var textFieldName = this.fields.text;
16490
- var selectedFieldName = this.fields.selected;
16572
+ var levelMapper = level === 1 ? this.fields : this.getChildFields(this.fields, level, 1);
16573
+ var childFieldName = levelMapper.child && levelMapper.child.toString();
16574
+ var expandedFieldName = levelMapper.expanded;
16575
+ var isCheckedFieldName = levelMapper.isChecked;
16576
+ var iconCssFieldName = levelMapper.iconCss;
16577
+ var imageUrlFieldName = levelMapper.imageUrl;
16578
+ var idFieldName = levelMapper.id;
16579
+ var textFieldName = levelMapper.text;
16580
+ var selectedFieldName = levelMapper.selected;
16581
+ var hasChildrenFieldName = levelMapper.hasChildren;
16491
16582
  var needsSorting = this.sortOrder !== 'None';
16492
16583
  var isDataTypeFlat = this.dataType === 1;
16493
16584
  var enableVirtualization = this.enableVirtualization;
@@ -16495,36 +16586,57 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16495
16586
  var raw = nodes[i];
16496
16587
  var id = isNullOrUndefined(raw[idFieldName]) ? '' : raw[idFieldName].toString();
16497
16588
  var text = isNullOrUndefined(raw[textFieldName]) ? '' : raw[textFieldName].toString();
16498
- // Use expandedNodes as the single source of truth.
16499
16589
  var inExpandedNodes = this.virtualExpandedNodesSet.has(id);
16500
- var rawExpanded = !inExpandedNodes && getValue(expandedFieldName, raw) === true;
16590
+ var rawExpanded = !inExpandedNodes && expandedFieldName && getValue(expandedFieldName, raw) === true;
16501
16591
  var expanded = inExpandedNodes || rawExpanded;
16502
16592
  if (rawExpanded && id) {
16503
16593
  this.expandedNodes.push(id);
16504
16594
  this.virtualExpandedNodesSet.add(id);
16505
16595
  }
16506
- // Inline hasChildRecords check to avoid function call (optimization)
16507
16596
  var hasChildren = false;
16508
- if (isDataTypeFlat) {
16597
+ var explicitHasChildren = hasChildrenFieldName ? getValue(hasChildrenFieldName, raw) : null;
16598
+ if (levelMapper.dataSource instanceof DataManager && !isNullOrUndefined(explicitHasChildren) && explicitHasChildren) {
16599
+ hasChildren = true;
16600
+ }
16601
+ else if (isDataTypeFlat) {
16509
16602
  if (this.groupedData) {
16510
16603
  var groupedChild = this.getChildGroup(this.groupedData, id, false);
16511
16604
  hasChildren = !isNullOrUndefined(groupedChild) && groupedChild.length > 0;
16512
16605
  }
16513
16606
  }
16514
16607
  else {
16515
- var childrenObj = getValue(childFieldName, raw);
16608
+ var childrenObj = childFieldName ? getValue(childFieldName, raw) : null;
16516
16609
  hasChildren = !isNullOrUndefined(childrenObj) && Array.isArray(childrenObj) && childrenObj.length > 0;
16517
16610
  }
16518
- // Virtual-mode only: honour fields.isChecked === true on initial render
16519
- if (enableVirtualization && id && isCheckedFieldName && !this.virtualCheckedNodesSet.has(id)) {
16520
- var rawChecked = getValue(isCheckedFieldName, raw);
16521
- if (!isNullOrUndefined(rawChecked) && rawChecked.toString() === 'true') {
16611
+ var parentChecked = null;
16612
+ if (levelMapper.dataSource instanceof DataManager && level > 1 && this.autoCheck && parentId) {
16613
+ if (this.virtualCheckedNodesSet.has(parentId) ||
16614
+ (this.checkedNodes && this.checkedNodes.indexOf(parentId) !== -1)) {
16615
+ parentChecked = true;
16616
+ }
16617
+ else {
16618
+ parentChecked = false;
16619
+ }
16620
+ }
16621
+ var rawChecked = isCheckedFieldName && getValue(isCheckedFieldName, raw);
16622
+ if (enableVirtualization && id && !this.virtualCheckedNodesSet.has(id)) {
16623
+ if ((!isNullOrUndefined(rawChecked) && rawChecked.toString() === 'true') ||
16624
+ (levelMapper.dataSource instanceof DataManager && parentChecked === true)) {
16522
16625
  this.virtualCheckedNodesSet.add(id);
16523
16626
  if (this.checkedNodes && this.checkedNodes.indexOf(id) === -1) {
16524
16627
  this.checkedNodes.push(id);
16525
16628
  }
16526
16629
  }
16527
16630
  }
16631
+ else if (enableVirtualization && id && this.virtualCheckedNodesSet.has(id) && levelMapper.dataSource instanceof DataManager) {
16632
+ if (level > 1 && !this.virtualIndeterminateNodesSet.has(parentId) && this.autoCheck &&
16633
+ ((!isNullOrUndefined(rawChecked) && rawChecked.toString() === 'false') || parentChecked === false)) {
16634
+ this.virtualCheckedNodesSet.delete(id);
16635
+ if (this.checkedNodes && this.checkedNodes.indexOf(id) === -1) {
16636
+ this.checkedNodes.splice(this.checkedNodes.indexOf(id), 1);
16637
+ }
16638
+ }
16639
+ }
16528
16640
  if (this.initialRender && enableVirtualization && id && selectedFieldName && !this.virtualSelectedNodesSet.has(id)) {
16529
16641
  var rawSelected = getValue(selectedFieldName, raw);
16530
16642
  if (!isNullOrUndefined(rawSelected) && rawSelected.toString() === 'true') {
@@ -16534,10 +16646,7 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16534
16646
  }
16535
16647
  }
16536
16648
  }
16537
- // Use cached Sets for O(1) lookup
16538
16649
  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
16650
  var isChecked = (enableVirtualization && this.virtualIndeterminateNodesSet.has(id))
16542
16651
  ? 'indeterminate'
16543
16652
  : this.virtualCheckedNodesSet.has(id);
@@ -16551,22 +16660,19 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16551
16660
  };
16552
16661
  result.push(node);
16553
16662
  if (expanded && hasChildren) {
16554
- // Determine children list
16555
16663
  var children = [];
16556
16664
  if (isDataTypeFlat) {
16557
16665
  if (this.groupedData) {
16558
16666
  children = this.getChildGroup(this.groupedData, id, false);
16559
- // Apply sortOrder to flat-data children (same as hierarchical path)
16560
16667
  if (needsSorting) {
16561
16668
  children = ListBase.getDataSource(children, ListBase.addSorting(this.sortOrder, this.fields.text));
16562
16669
  }
16563
16670
  }
16564
16671
  }
16565
16672
  else {
16566
- var rawChildren = getValue(childFieldName, raw);
16673
+ var rawChildren = childFieldName ? getValue(childFieldName, raw) : null;
16567
16674
  if (!isNullOrUndefined(rawChildren) && Array.isArray(rawChildren)) {
16568
16675
  children = rawChildren;
16569
- // Only sort if needed
16570
16676
  if (needsSorting) {
16571
16677
  children = ListBase.getDataSource(children, ListBase.addSorting(this.sortOrder, this.fields.text));
16572
16678
  }
@@ -16576,35 +16682,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16576
16682
  }
16577
16683
  }
16578
16684
  };
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
16685
  TreeView.prototype.rebuildVirtualNodeMap = function () {
16609
16686
  this.virtualNodeMap.clear();
16610
16687
  for (var i = 0; i < this.virtualFlatNodes.length; i++) {
@@ -16637,49 +16714,12 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16637
16714
  var paddingBottom = Math.max(0, (total - end) * itemH);
16638
16715
  return { paddingTop: paddingTop, paddingBottom: paddingBottom };
16639
16716
  };
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
16717
  TreeView.prototype.renderVirtualItems = function () {
16672
16718
  if (!this.ulElement) {
16673
16719
  return;
16674
16720
  }
16675
16721
  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
16722
  var focusedUid = this.virtualFocusedId || null;
16682
- // ── Clear previous render (direct children only) ─────────────────────────
16683
16723
  var existingItems = ul.querySelectorAll(':scope > li');
16684
16724
  for (var i = existingItems.length - 1; i >= 0; i--) {
16685
16725
  ul.removeChild(existingItems[parseInt(i.toString(), 10)]);
@@ -16690,26 +16730,22 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16690
16730
  if (this.virtualStartIndex < this.virtualFlatNodes.length) {
16691
16731
  var firstNode = this.virtualFlatNodes[this.virtualStartIndex];
16692
16732
  if (firstNode.parentId) {
16693
- // Build the ancestor chain from root down to the immediate parent
16694
16733
  var ancestors = [];
16695
16734
  var searchId = firstNode.parentId;
16696
16735
  while (searchId) {
16697
16736
  var ancestorIdx = this.virtualNodeMap.get(searchId);
16698
16737
  if (!isNullOrUndefined(ancestorIdx) && ancestorIdx < this.virtualStartIndex) {
16699
16738
  var ancestor = this.virtualFlatNodes[parseInt(ancestorIdx.toString(), 10)];
16700
- ancestors.unshift(ancestor); // prepend so root comes first
16739
+ ancestors.unshift(ancestor);
16701
16740
  searchId = ancestor.parentId;
16702
16741
  }
16703
16742
  else {
16704
16743
  break;
16705
16744
  }
16706
16745
  }
16707
- // Inject each ancestor as a real <li> into the root <ul>
16708
- // and register it in renderedParentMap for child-nesting below.
16709
16746
  for (var a = 0; a < ancestors.length; a++) {
16710
16747
  var ancestor = ancestors[parseInt(a.toString(), 10)];
16711
16748
  var ancestorLi = this.createVirtualListItem(ancestor, false);
16712
- // Find the correct container: root or a previously injected ancestor's <ul>
16713
16749
  var targetUl = ul;
16714
16750
  if (ancestor.parentId && renderedParentMap.has(ancestor.parentId)) {
16715
16751
  var pe = renderedParentMap.get(ancestor.parentId);
@@ -16728,26 +16764,20 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16728
16764
  }
16729
16765
  }
16730
16766
  }
16731
- // ── Scroll-space padding (adjusted for injected ancestors) ────────────────
16732
16767
  var total = this.virtualFlatNodes.length;
16733
16768
  var start = this.virtualStartIndex;
16734
16769
  var end = this.virtualEndIndex;
16735
16770
  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
16771
  var adjustedPaddingTop = Math.max(0, rawPaddingTop - injectedCount * itemH);
16739
16772
  ul.style.paddingTop = adjustedPaddingTop + 'px';
16740
16773
  ul.style.paddingBottom = Math.max(0, (total - end) * itemH) + 'px';
16741
- // ── Render window items (nested via renderedParentMap) ────────────────────
16742
16774
  var liListBuf = [];
16743
16775
  for (var i = start; i < end; i++) {
16744
16776
  var node = this.virtualFlatNodes[parseInt(i.toString(), 10)];
16745
16777
  var li = this.createVirtualListItem(node, i === start);
16746
- // Find the correct parent container
16747
16778
  var targetUl = ul;
16748
16779
  if (node.parentId && renderedParentMap.has(node.parentId)) {
16749
16780
  var parentEntry = renderedParentMap.get(node.parentId);
16750
- // Lazily create the child <ul> the first time a child needs it
16751
16781
  if (!parentEntry.childUl) {
16752
16782
  parentEntry.childUl = this.createElement('ul', {
16753
16783
  className: PARENTITEM + ' e-ul',
@@ -16759,30 +16789,11 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16759
16789
  }
16760
16790
  targetUl.appendChild(li);
16761
16791
  liListBuf.push(li);
16762
- // Register this node so its children in the same window can nest under it
16763
16792
  if (node.expanded && node.hasChildren) {
16764
16793
  renderedParentMap.set(node.id, { li: li, childUl: null });
16765
16794
  }
16766
16795
  }
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
16796
  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
16797
  if (!focusRestored && focusedUid) {
16787
16798
  for (var k = 0; k < liListBuf.length; k++) {
16788
16799
  var li = liListBuf[parseInt(k.toString(), 10)];
@@ -16790,22 +16801,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16790
16801
  li.setAttribute('tabindex', '0');
16791
16802
  addClass([li], FOCUS);
16792
16803
  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
16804
  EventHandler.add(li, 'blur', this.focusOut, this);
16810
16805
  li.focus({ preventScroll: true });
16811
16806
  focusRestored = true;
@@ -16813,53 +16808,36 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16813
16808
  }
16814
16809
  }
16815
16810
  }
16816
- // 3. Finally default to the first item in the window.
16817
16811
  if (!focusRestored && liListBuf.length > 0) {
16818
16812
  var firstLi = liListBuf[0];
16819
16813
  firstLi.setAttribute('tabindex', '0');
16820
16814
  }
16821
- // ── Fix: Ensure all other rendered nodes have tabindex="-1" ──
16822
- // This prevents stale tabindex="0" on multiple nodes which breaks Tab order
16823
16815
  for (var k = 0; k < liListBuf.length; k++) {
16824
16816
  var li = liListBuf[parseInt(k.toString(), 10)];
16825
16817
  if (li.getAttribute('tabindex') !== '0') {
16826
16818
  li.setAttribute('tabindex', '-1');
16827
16819
  }
16828
16820
  }
16829
- // Keep liList in sync so keyboard-navigation helpers stay functional.
16830
16821
  this.liList = liListBuf;
16831
16822
  };
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
16823
  TreeView.prototype.createVirtualListItem = function (node, _isFirst) {
16841
16824
  var li = this.createElement('li', { className: LISTITEM });
16842
- // Level class for CSS indentation
16843
16825
  li.classList.add('e-level-' + node.level);
16844
16826
  li.setAttribute('data-uid', node.id);
16845
16827
  li.setAttribute('aria-level', node.level.toString());
16846
16828
  li.setAttribute('role', 'treeitem');
16847
16829
  li.setAttribute('tabindex', '-1');
16848
- // Full-row overlay (required for fullRowSelect mode)
16849
16830
  if (this.fullRowSelect) {
16850
16831
  var fullRow = this.createElement('div', { className: FULLROW });
16851
16832
  li.appendChild(fullRow);
16852
16833
  }
16853
- // Text/icon wrapper
16854
16834
  var textWrap = this.createElement('div', { className: TEXTWRAP });
16855
- // Expand/collapse icon
16856
16835
  if (node.hasChildren) {
16857
16836
  var iconSpan = this.createElement('div', {
16858
16837
  className: ICON + ' ' + (node.expanded ? COLLAPSIBLE : EXPANDABLE)
16859
16838
  });
16860
16839
  textWrap.appendChild(iconSpan);
16861
16840
  }
16862
- // Checkbox
16863
16841
  if (this.showCheckBox) {
16864
16842
  var checkWrap = createCheckBox(this.createElement, false, {
16865
16843
  checked: node.isChecked === true,
@@ -16873,28 +16851,24 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16873
16851
  }
16874
16852
  textWrap.appendChild(checkWrap);
16875
16853
  }
16876
- // Icon
16877
16854
  if (node.iconCss) {
16878
16855
  var iconEl = this.createElement('span', {
16879
16856
  className: ICON + ' ' + node.iconCss
16880
16857
  });
16881
16858
  textWrap.appendChild(iconEl);
16882
16859
  }
16883
- // Image
16884
16860
  if (node.imageUrl) {
16885
16861
  var img = document.createElement('img');
16886
16862
  img.src = node.imageUrl;
16887
16863
  img.classList.add(IMAGE);
16888
16864
  textWrap.appendChild(img);
16889
16865
  }
16890
- // Text anchor
16891
16866
  var anchor = this.createElement('span', {
16892
16867
  className: 'e-list-text',
16893
16868
  innerHTML: node.text
16894
16869
  });
16895
16870
  textWrap.appendChild(anchor);
16896
16871
  li.appendChild(textWrap);
16897
- // nodeTemplate
16898
16872
  if (!isNullOrUndefined(this.nodeTemplateFn)) {
16899
16873
  var rawData = this.findNodeInTreeData(node.id);
16900
16874
  if (!isNullOrUndefined(rawData)) {
@@ -16902,7 +16876,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16902
16876
  this.renderNodeTemplate(rawData, anchor, node.id);
16903
16877
  }
16904
16878
  }
16905
- // State classes
16906
16879
  if (node.expanded) {
16907
16880
  li.classList.add(EXPANDED);
16908
16881
  li.setAttribute('aria-expanded', 'true');
@@ -16918,80 +16891,43 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
16918
16891
  if (node.hasChildren) {
16919
16892
  li.classList.add(CHILD);
16920
16893
  }
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
16894
  EventHandler.add(li, 'focus', this.focusIn, this);
16928
16895
  return li;
16929
16896
  };
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
16897
  TreeView.prototype.initVirtualization = function () {
16942
16898
  addClass([this.element], VIRTUALIZATION);
16943
- // Apply container height
16944
16899
  var px = this.parseHeightToPixels();
16945
16900
  if (px > 0) {
16946
16901
  this.element.style.height = px + 'px';
16947
16902
  this.element.style.overflowY = 'auto';
16948
16903
  }
16949
- // Ensure the inner UL is ready
16950
16904
  if (!this.ulElement) {
16951
16905
  this.ulElement = select('.' + PARENTITEM, this.element);
16952
16906
  }
16953
16907
  if (!this.ulElement) {
16954
16908
  return;
16955
16909
  }
16956
- // Make the UL position-relative for the absolute spacers
16957
16910
  this.ulElement.style.position = 'relative';
16958
- // Rebuild flat list
16959
16911
  this.virtualFlatNodes = this.flattenVisibleNodes();
16960
16912
  this.rebuildVirtualNodeMap();
16961
- // Measure dimensions
16962
16913
  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
16914
  if (this.virtualFlatNodes.length > 0) {
16965
16915
  var probe = this.createVirtualListItem(this.virtualFlatNodes[0], true);
16966
16916
  this.ulElement.appendChild(probe);
16967
16917
  this.virtualItemHeight = probe.offsetHeight > 0 ? probe.offsetHeight : this.virtualItemHeight;
16968
16918
  this.ulElement.removeChild(probe);
16969
16919
  }
16970
- // Compute window and render all items in the initial viewport
16971
16920
  var win = this.getVirtualWindow();
16972
16921
  this.virtualStartIndex = win.startIndex;
16973
16922
  this.virtualEndIndex = win.endIndex;
16974
16923
  this.renderVirtualItems();
16975
- // Wire scroll
16976
16924
  this.wireVirtualScrollEvents();
16977
16925
  };
16978
- /**
16979
- * Wires the scroll event listener on the TreeView element.
16980
- *
16981
- * @returns {void}
16982
- * @private
16983
- */
16984
16926
  TreeView.prototype.wireVirtualScrollEvents = function () {
16985
16927
  this.unwireVirtualScrollEvents();
16986
16928
  this.virtualScrollBound = this.onVirtualScroll.bind(this);
16987
16929
  this.element.addEventListener('scroll', this.virtualScrollBound, { passive: true });
16988
16930
  };
16989
- /**
16990
- * Removes the scroll event listener previously wired by `wireVirtualScrollEvents`.
16991
- *
16992
- * @returns {void}
16993
- * @private
16994
- */
16995
16931
  TreeView.prototype.unwireVirtualScrollEvents = function () {
16996
16932
  if (this.virtualScrollBound) {
16997
16933
  this.element.removeEventListener('scroll', this.virtualScrollBound);
@@ -17002,29 +16938,13 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17002
16938
  this.virtualScrollRAF = null;
17003
16939
  }
17004
16940
  };
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
16941
  TreeView.prototype.onVirtualScroll = function () {
17013
16942
  var _this = this;
17014
16943
  if (this.virtualScrollRAF !== null) {
17015
16944
  cancelAnimationFrame(this.virtualScrollRAF);
17016
16945
  }
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
16946
  if (this.virtualSkipNextScrollRender) {
17025
16947
  this.virtualSkipNextScrollRender = false;
17026
- // Update prev scrollTop so a subsequent user-driven scroll still
17027
- // calculates the correct delta.
17028
16948
  this.virtualPrevScrollTop = this.element.scrollTop;
17029
16949
  return;
17030
16950
  }
@@ -17041,30 +16961,16 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17041
16961
  _this.virtualStartIndex = win.startIndex;
17042
16962
  _this.virtualEndIndex = win.endIndex;
17043
16963
  _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
16964
  setTimeout(function () {
17047
16965
  _this.hideVirtualMask();
17048
- // Keep the (now hidden) mask's coords fresh for the next show.
17049
16966
  _this.updateMaskPosition();
17050
16967
  }, 200);
17051
16968
  });
17052
16969
  };
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
16970
  TreeView.prototype.createVirtualMask = function () {
17061
16971
  if (this.virtualMaskElement) {
17062
16972
  return;
17063
16973
  }
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
16974
  var rect = this.element.getBoundingClientRect();
17069
16975
  var scrollBarWidth = this.element.offsetWidth - this.element.clientWidth;
17070
16976
  var maskParent = this.createElement('div', {
@@ -17077,20 +16983,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17077
16983
  className: VIRTUAL_MASK_ITEM,
17078
16984
  styles: "display:flex;align-items:center;height:" + this.virtualItemHeight + "px;padding:0 12px;gap:8px;"
17079
16985
  });
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
16986
  var textHolder = this.createElement('span');
17095
16987
  textHolder.style.flex = '1';
17096
16988
  textHolder.style.height = '14px';
@@ -17108,14 +17000,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17108
17000
  this.virtualMaskElement = maskParent;
17109
17001
  this.element.appendChild(maskParent);
17110
17002
  };
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
17003
  TreeView.prototype.updateMaskPosition = function () {
17120
17004
  if (!this.virtualMaskElement) {
17121
17005
  return;
@@ -17127,12 +17011,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17127
17011
  this.virtualMaskElement.style.width = (rect.width - scrollBarWidth) + 'px';
17128
17012
  this.virtualMaskElement.style.height = rect.height + 'px';
17129
17013
  };
17130
- /**
17131
- * Destroys all skeleton instances and removes the mask overlay from the DOM.
17132
- *
17133
- * @returns {void}
17134
- * @private
17135
- */
17136
17014
  TreeView.prototype.destroyVirtualMask = function () {
17137
17015
  for (var i = this.skeletonInstances.length - 1; i >= 0; i--) {
17138
17016
  this.skeletonInstances[parseInt(i.toString(), 10)].destroy();
@@ -17145,52 +17023,26 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17145
17023
  this.virtualMaskElement = null;
17146
17024
  }
17147
17025
  };
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
17026
  TreeView.prototype.showVirtualMask = function (_scrollTop) {
17156
17027
  if (!this.virtualMaskElement) {
17157
17028
  this.createVirtualMask();
17158
17029
  }
17159
17030
  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
17031
  this.updateMaskPosition();
17163
17032
  this.virtualMaskElement.style.display = 'block';
17164
- // Visually hide the real list while the skeleton is shown
17165
17033
  if (this.ulElement) {
17166
17034
  this.ulElement.style.visibility = 'hidden';
17167
17035
  }
17168
17036
  }
17169
17037
  };
17170
- /**
17171
- * Hides the skeleton mask overlay after the virtual window has been rendered.
17172
- *
17173
- * @returns {void}
17174
- * @private
17175
- */
17176
17038
  TreeView.prototype.hideVirtualMask = function () {
17177
17039
  if (this.virtualMaskElement) {
17178
17040
  this.virtualMaskElement.style.display = 'none';
17179
- // Restore real list visibility
17180
17041
  if (this.ulElement) {
17181
17042
  this.ulElement.style.visibility = '';
17182
17043
  }
17183
17044
  }
17184
17045
  };
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
17046
  TreeView.prototype.ensureVirtualNodeVisible = function (id) {
17195
17047
  var idx = this.virtualNodeMap.get(id);
17196
17048
  if (isNullOrUndefined(idx)) {
@@ -17209,25 +17061,13 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17209
17061
  this.element.scrollTop = nodeBottom - vpH;
17210
17062
  }
17211
17063
  else {
17212
- return; // already visible, no re-render needed
17064
+ return;
17213
17065
  }
17214
- // Re-render the new window synchronously so the <li> is in the DOM
17215
17066
  var win = this.getVirtualWindow();
17216
17067
  this.virtualStartIndex = win.startIndex;
17217
17068
  this.virtualEndIndex = win.endIndex;
17218
17069
  this.renderVirtualItems();
17219
17070
  };
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
17071
  TreeView.prototype.findNodeInTreeData = function (id) {
17232
17072
  if (!this.treeData) {
17233
17073
  return null;
@@ -17255,12 +17095,19 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17255
17095
  };
17256
17096
  return findRecursive(this.treeData);
17257
17097
  };
17098
+ TreeView.prototype.getNodeLevel = function (id) {
17099
+ if (!this.virtualFlatNodes) {
17100
+ return 1;
17101
+ }
17102
+ for (var i = 0; i < this.virtualFlatNodes.length; i++) {
17103
+ if (this.virtualFlatNodes[parseInt(i.toString(), 10)].id === id) {
17104
+ return this.virtualFlatNodes[parseInt(i.toString(), 10)].level;
17105
+ }
17106
+ }
17107
+ return 1;
17108
+ };
17258
17109
  TreeView.prototype.handleVirtualExpand = function (id, isKeyboardNav) {
17259
- // ── Cancel any pending scroll RAF ─────────────────────────────────────────
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.
17110
+ var _this = this;
17264
17111
  if (this.virtualScrollRAF !== null) {
17265
17112
  cancelAnimationFrame(this.virtualScrollRAF);
17266
17113
  this.virtualScrollRAF = null;
@@ -17268,7 +17115,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17268
17115
  if (this.expandedNodes.indexOf(id) === -1) {
17269
17116
  this.expandedNodes.push(id);
17270
17117
  }
17271
- // Also update virtualExpandedNodesSet to keep it in sync
17272
17118
  if (this.virtualExpandedNodesSet) {
17273
17119
  this.virtualExpandedNodesSet.add(id);
17274
17120
  }
@@ -17278,56 +17124,76 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17278
17124
  setValue(this.fields.expanded, true, acutalRootData);
17279
17125
  }
17280
17126
  }
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
17127
  if (isKeyboardNav) {
17292
17128
  this.virtualFocusedId = id;
17293
17129
  }
17294
17130
  else {
17295
17131
  this.virtualFocusedId = null;
17296
17132
  }
17133
+ if (this.fields.dataSource instanceof DataManager && !this.isOffline) {
17134
+ var parentNode = this.findNodeInTreeData(id);
17135
+ if (parentNode && !isNullOrUndefined(parentNode)) {
17136
+ var childFieldName = this.fields.child.toString();
17137
+ var childrenObj = getValue(childFieldName, parentNode);
17138
+ var childrenNotLoaded = isNullOrUndefined(childrenObj) || !Array.isArray(childrenObj) ||
17139
+ childrenObj.length === 0;
17140
+ if (childrenNotLoaded) {
17141
+ this.loadVirtualChildData(id, parentNode, function () {
17142
+ _this.completeVirtualExpand(id, isKeyboardNav);
17143
+ });
17144
+ return;
17145
+ }
17146
+ }
17147
+ }
17148
+ this.completeVirtualExpand(id, isKeyboardNav);
17149
+ };
17150
+ TreeView.prototype.loadVirtualChildData = function (parentId, parentNode, callback) {
17151
+ var _this = this;
17152
+ var level = this.getNodeLevel(parentId);
17153
+ var mapper = this.getChildFields(this.fields, level + 1, 1);
17154
+ if (isNullOrUndefined(mapper) || isNullOrUndefined(mapper.dataSource)) {
17155
+ if (callback) {
17156
+ callback();
17157
+ }
17158
+ return;
17159
+ }
17160
+ mapper.dataSource.executeQuery(this.getQuery(mapper, parentId)).then(function (e) {
17161
+ var childItems = e.result;
17162
+ if (!isNullOrUndefined(childItems) && childItems.length > 0) {
17163
+ var childFieldName = _this.fields.child.toString();
17164
+ setValue(childFieldName, childItems, parentNode);
17165
+ if (_this.dataType === 2) {
17166
+ var nodeInTree = _this.findNodeInTreeData(parentId);
17167
+ if (nodeInTree) {
17168
+ setValue(childFieldName, childItems, nodeInTree);
17169
+ }
17170
+ }
17171
+ }
17172
+ if (callback) {
17173
+ callback();
17174
+ }
17175
+ }).catch(function (e) {
17176
+ _this.trigger('actionFailure', { error: e });
17177
+ if (callback) {
17178
+ callback();
17179
+ }
17180
+ });
17181
+ };
17182
+ TreeView.prototype.completeVirtualExpand = function (id, isKeyboardNav) {
17297
17183
  this.virtualFlatNodes = this.flattenVisibleNodes();
17298
17184
  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
17185
  var scrollTopSnapshot = this.element.scrollTop;
17304
17186
  var win = this.getVirtualWindowAt(scrollTopSnapshot);
17305
17187
  this.virtualStartIndex = win.startIndex;
17306
17188
  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
17189
  this.virtualSkipNextScrollRender = true;
17315
17190
  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
17191
  var newLi = this.getElement(id);
17320
17192
  if (newLi) {
17321
17193
  var icon = select('.' + ICON, newLi);
17322
17194
  if (icon) {
17323
17195
  removeClass([icon], PROCESS);
17324
17196
  }
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
17197
  newLi.focus({ preventScroll: true });
17332
17198
  }
17333
17199
  if (this.isLoaded) {
@@ -17340,9 +17206,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17340
17206
  }
17341
17207
  };
17342
17208
  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
17209
  if (this.virtualScrollRAF !== null) {
17347
17210
  cancelAnimationFrame(this.virtualScrollRAF);
17348
17211
  this.virtualScrollRAF = null;
@@ -17351,7 +17214,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17351
17214
  if (idx !== -1) {
17352
17215
  this.expandedNodes.splice(idx, 1);
17353
17216
  }
17354
- // Also update virtualExpandedNodesSet to keep it in sync
17355
17217
  if (this.virtualExpandedNodesSet) {
17356
17218
  this.virtualExpandedNodesSet.delete(id);
17357
17219
  }
@@ -17361,13 +17223,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17361
17223
  setValue(this.fields.expanded, false, acutalRootData);
17362
17224
  }
17363
17225
  }
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
17226
  if (isKeyboardNav) {
17372
17227
  this.virtualFocusedId = id;
17373
17228
  }
@@ -17376,28 +17231,18 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17376
17231
  }
17377
17232
  this.virtualFlatNodes = this.flattenVisibleNodes();
17378
17233
  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
17234
  var scrollTopSnapshot = this.element.scrollTop;
17383
17235
  var win = this.getVirtualWindowAt(scrollTopSnapshot);
17384
17236
  this.virtualStartIndex = win.startIndex;
17385
17237
  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
17238
  this.virtualSkipNextScrollRender = true;
17390
17239
  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
17240
  var newLi = this.getElement(id);
17395
17241
  if (newLi) {
17396
17242
  var icon = select('.' + ICON, newLi);
17397
17243
  if (icon) {
17398
17244
  removeClass([icon], PROCESS);
17399
17245
  }
17400
- // ── Use preventScroll:true to avoid consuming virtualSkipNextScrollRender ─
17401
17246
  newLi.focus({ preventScroll: true });
17402
17247
  }
17403
17248
  if (this.isLoaded) {
@@ -17409,14 +17254,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17409
17254
  }
17410
17255
  }
17411
17256
  };
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
17257
  TreeView.prototype.updateVirtualNodeSelection = function (id, selected) {
17421
17258
  var idx = this.virtualNodeMap.get(id);
17422
17259
  if (!isNullOrUndefined(idx)) {
@@ -17424,21 +17261,11 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17424
17261
  this.renderVirtualItems();
17425
17262
  }
17426
17263
  };
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
17264
  TreeView.prototype.updateVirtualNodeCheckState = function (id, state) {
17436
17265
  var idx = this.virtualNodeMap.get(id);
17437
17266
  if (!isNullOrUndefined(idx)) {
17438
17267
  this.virtualFlatNodes[parseInt(idx.toString(), 10)].isChecked =
17439
17268
  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
17269
  if (state === 'indeterminate') {
17443
17270
  this.virtualIndeterminateNodesSet.add(id);
17444
17271
  }
@@ -17448,9 +17275,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17448
17275
  this.renderVirtualItems();
17449
17276
  }
17450
17277
  };
17451
- // ═══════════════════════════════════════════════════════════════════════════════
17452
- // END VIRTUALIZATION
17453
- // ═══════════════════════════════════════════════════════════════════════════════
17454
17278
  /**
17455
17279
  * Called internally if any of the property value changed.
17456
17280
  *
@@ -17595,7 +17419,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17595
17419
  }
17596
17420
  }
17597
17421
  else {
17598
- // Tear down virtualization and do a full re-render
17599
17422
  this.unwireVirtualScrollEvents();
17600
17423
  this.destroyVirtualMask();
17601
17424
  removeClass([this.element], VIRTUALIZATION);
@@ -17606,7 +17429,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17606
17429
  break;
17607
17430
  case 'height':
17608
17431
  if (this.enableVirtualization) {
17609
- // Re-initialise so the new height takes effect
17610
17432
  this.unwireVirtualScrollEvents();
17611
17433
  this.initVirtualization();
17612
17434
  }
@@ -17624,7 +17446,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17624
17446
  * @returns {void}
17625
17447
  */
17626
17448
  TreeView.prototype.destroy = function () {
17627
- // Tear down virtualization before standard cleanup
17628
17449
  if (this.enableVirtualization) {
17629
17450
  this.unwireVirtualScrollEvents();
17630
17451
  this.destroyVirtualMask();
@@ -17715,10 +17536,6 @@ var TreeView = /** @__PURE__ @class */ (function (_super) {
17715
17536
  if (isNullOrUndefined(fNode)) {
17716
17537
  this.setNodeFocusable();
17717
17538
  }
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
17539
  if (this.enableVirtualization && !isNullOrUndefined(this.height)) {
17723
17540
  this.setRootData();
17724
17541
  this.rebuildVirtualCheckCache();