@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.
- package/dist/ej2-navigations.min.js +1 -10
- package/dist/ej2-navigations.umd.min.js +1 -10
- package/dist/ej2-navigations.umd.min.js.map +1 -1
- package/dist/es6/ej2-navigations.es2015.js +368 -553
- package/dist/es6/ej2-navigations.es2015.js.map +1 -1
- package/dist/es6/ej2-navigations.es5.js +373 -556
- package/dist/es6/ej2-navigations.es5.js.map +1 -1
- package/dist/global/ej2-navigations.min.js +1 -10
- package/dist/global/ej2-navigations.min.js.map +1 -1
- package/dist/global/index.d.ts +0 -9
- package/package.json +3 -3
- package/src/toolbar/toolbar.d.ts +2 -0
- package/src/toolbar/toolbar.js +16 -0
- package/src/treeview/treeview.d.ts +8 -221
- package/src/treeview/treeview.js +357 -556
|
@@ -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
|
-
//
|
|
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') &&
|
|
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
|
|
12018
|
-
var
|
|
12019
|
-
var
|
|
12020
|
-
|
|
12021
|
-
|
|
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(
|
|
12027
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16483
|
-
var childFieldName =
|
|
16484
|
-
var expandedFieldName =
|
|
16485
|
-
var isCheckedFieldName =
|
|
16486
|
-
var iconCssFieldName =
|
|
16487
|
-
var imageUrlFieldName =
|
|
16488
|
-
var idFieldName =
|
|
16489
|
-
var textFieldName =
|
|
16490
|
-
var selectedFieldName =
|
|
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
|
-
|
|
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
|
-
|
|
16519
|
-
if (
|
|
16520
|
-
|
|
16521
|
-
|
|
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);
|
|
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;
|
|
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
|
-
|
|
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();
|