tree-element 0.4.0 → 0.4.1
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/README.md +22 -20
- package/lib/dataLoader.d.ts.map +1 -1
- package/lib/dataLoader.js +4 -1
- package/lib/dataLoader.js.map +1 -1
- package/lib/dragAndDropHandler/generateHitAreas.d.ts.map +1 -1
- package/lib/dragAndDropHandler/generateHitAreas.js +3 -2
- package/lib/dragAndDropHandler/generateHitAreas.js.map +1 -1
- package/lib/dragAndDropHandler/index.d.ts +2 -4
- package/lib/dragAndDropHandler/index.d.ts.map +1 -1
- package/lib/dragAndDropHandler/index.js +2 -9
- package/lib/dragAndDropHandler/index.js.map +1 -1
- package/lib/elementsRenderer.d.ts +7 -2
- package/lib/elementsRenderer.d.ts.map +1 -1
- package/lib/elementsRenderer.js +70 -23
- package/lib/elementsRenderer.js.map +1 -1
- package/lib/events.d.ts +13 -7
- package/lib/events.d.ts.map +1 -1
- package/lib/folderOpenState.d.ts +8 -0
- package/lib/folderOpenState.d.ts.map +1 -0
- package/lib/folderOpenState.js +22 -0
- package/lib/folderOpenState.js.map +1 -0
- package/lib/index.d.ts +17 -16
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +93 -49
- package/lib/index.js.map +1 -1
- package/lib/keyHandler.d.ts +2 -0
- package/lib/keyHandler.d.ts.map +1 -1
- package/lib/keyHandler.js +18 -0
- package/lib/keyHandler.js.map +1 -1
- package/lib/mouseHandler.d.ts.map +1 -1
- package/lib/mouseHandler.js +12 -12
- package/lib/mouseHandler.js.map +1 -1
- package/lib/node.d.ts +12 -10
- package/lib/node.d.ts.map +1 -1
- package/lib/node.js +12 -10
- package/lib/node.js.map +1 -1
- package/lib/nodeElement/folderElement.d.ts +7 -5
- package/lib/nodeElement/folderElement.d.ts.map +1 -1
- package/lib/nodeElement/folderElement.js +33 -53
- package/lib/nodeElement/folderElement.js.map +1 -1
- package/lib/options.d.ts +19 -17
- package/lib/options.d.ts.map +1 -1
- package/lib/options.js +12 -0
- package/lib/options.js.map +1 -0
- package/lib/saveStateHandler.d.ts.map +1 -1
- package/lib/saveStateHandler.js +6 -6
- package/lib/saveStateHandler.js.map +1 -1
- package/lib/selectNodeHandler.d.ts.map +1 -1
- package/lib/selectNodeHandler.js +13 -1
- package/lib/selectNodeHandler.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +35 -29
- package/src/dataLoader.ts +3 -1
- package/src/dragAndDropHandler/generateHitAreas.ts +3 -2
- package/src/dragAndDropHandler/index.ts +3 -17
- package/src/elementsRenderer.ts +84 -33
- package/src/events.ts +13 -7
- package/src/folderOpenState.ts +38 -0
- package/src/index.ts +109 -59
- package/src/keyHandler.ts +20 -0
- package/src/mouseHandler.ts +15 -13
- package/src/node.ts +12 -10
- package/src/nodeElement/folderElement.ts +45 -70
- package/src/options.ts +36 -17
- package/src/saveStateHandler.ts +5 -8
- package/src/selectNodeHandler.ts +12 -1
- package/src/version.ts +1 -1
- package/tree_element.css +32 -5
- package/tree_element.debug.js +291 -165
- package/tree_element.debug.js.map +1 -1
- package/tree_element.js +2 -2
- package/tree_element.js.map +1 -1
package/tree_element.debug.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Tree-element 0.4.
|
|
2
|
+
Tree-element 0.4.1
|
|
3
3
|
|
|
4
4
|
Copyright 2026 Marco Braak
|
|
5
5
|
|
|
@@ -111,9 +111,12 @@ var TreeElement = (function () {
|
|
|
111
111
|
};
|
|
112
112
|
let signal = this._abortController.signal;
|
|
113
113
|
url._setSearchParam("_", Date.now().toString());
|
|
114
|
+
|
|
115
|
+
// Accept, not Content-Type: the request has no body. A cross-origin request
|
|
116
|
+
// with only an Accept header also needs no CORS preflight.
|
|
114
117
|
return fetch(url._value(), {
|
|
115
118
|
headers: {
|
|
116
|
-
|
|
119
|
+
Accept: "application/json"
|
|
117
120
|
},
|
|
118
121
|
signal
|
|
119
122
|
}).then(handleResponse).catch(error => {
|
|
@@ -262,8 +265,9 @@ var TreeElement = (function () {
|
|
|
262
265
|
lastTop = top;
|
|
263
266
|
};
|
|
264
267
|
let handleAfterOpenFolder = (node, nextNode) => {
|
|
265
|
-
|
|
266
|
-
|
|
268
|
+
// Not called for the current node: handleOpenFolder stops iterating there
|
|
269
|
+
if (nextNode === currentNode) {
|
|
270
|
+
// Dropping the current node after this folder would leave it where it is
|
|
267
271
|
addHitPosition(node, null, lastTop);
|
|
268
272
|
} else {
|
|
269
273
|
addHitPosition(node, "after", lastTop);
|
|
@@ -391,7 +395,6 @@ var TreeElement = (function () {
|
|
|
391
395
|
_openFolderDelay: openFolderDelay,
|
|
392
396
|
_openNode: openNode,
|
|
393
397
|
_refreshElements: refreshElements,
|
|
394
|
-
_slide: slide,
|
|
395
398
|
_treeElement: treeElement,
|
|
396
399
|
_triggerEvent: triggerEvent
|
|
397
400
|
}) {
|
|
@@ -409,7 +412,6 @@ var TreeElement = (function () {
|
|
|
409
412
|
this._openFolderDelay = openFolderDelay;
|
|
410
413
|
this._openNode = openNode;
|
|
411
414
|
this._refreshElements = refreshElements;
|
|
412
|
-
this._slide = slide;
|
|
413
415
|
this._treeElement = treeElement;
|
|
414
416
|
this._triggerEvent = triggerEvent;
|
|
415
417
|
this._hoveredArea = null;
|
|
@@ -442,9 +444,6 @@ var TreeElement = (function () {
|
|
|
442
444
|
this._dragElement._move(positionInfo.pageX, positionInfo.pageY);
|
|
443
445
|
let area = this._findHoveredArea(positionInfo.pageX, positionInfo.pageY);
|
|
444
446
|
if (area && this._canMoveToArea(area, this._currentItem)) {
|
|
445
|
-
if (!area.node.isFolder()) {
|
|
446
|
-
this._stopOpenFolderTimer();
|
|
447
|
-
}
|
|
448
447
|
if (this._hoveredArea !== area) {
|
|
449
448
|
this._hoveredArea = area;
|
|
450
449
|
|
|
@@ -503,7 +502,6 @@ var TreeElement = (function () {
|
|
|
503
502
|
if (!this._hoveredArea && currentItem && this._onDragStop) {
|
|
504
503
|
this._onDragStop(currentItem._node, positionInfo.originalEvent);
|
|
505
504
|
}
|
|
506
|
-
return false;
|
|
507
505
|
}
|
|
508
506
|
_refresh() {
|
|
509
507
|
this._removeHitAreas();
|
|
@@ -594,8 +592,7 @@ var TreeElement = (function () {
|
|
|
594
592
|
}
|
|
595
593
|
}
|
|
596
594
|
_mustCaptureElement(element) {
|
|
597
|
-
|
|
598
|
-
return nodeName !== "INPUT" && nodeName !== "SELECT" && nodeName !== "TEXTAREA";
|
|
595
|
+
return !["INPUT", "SELECT", "TEXTAREA"].includes(element.nodeName);
|
|
599
596
|
}
|
|
600
597
|
_mustOpenFolderTimer(area) {
|
|
601
598
|
let node = area.node;
|
|
@@ -614,7 +611,7 @@ var TreeElement = (function () {
|
|
|
614
611
|
}
|
|
615
612
|
_startOpenFolderTimer(folder) {
|
|
616
613
|
let openFolder = () => {
|
|
617
|
-
void this._openNode(folder
|
|
614
|
+
void this._openNode(folder).then(() => {
|
|
618
615
|
this._refresh();
|
|
619
616
|
this._updateDropHint();
|
|
620
617
|
});
|
|
@@ -649,6 +646,24 @@ var TreeElement = (function () {
|
|
|
649
646
|
let isInt = n => Number.isInteger(n);
|
|
650
647
|
let getBoolString = value => value ? "true" : "false";
|
|
651
648
|
|
|
649
|
+
/* The open state of a folder is shown on the toggler and on the <li>.
|
|
650
|
+
* These are used both when a folder is rendered and when it is opened or
|
|
651
|
+
* closed, so a rendered folder looks the same as a toggled one.
|
|
652
|
+
*/
|
|
653
|
+
|
|
654
|
+
let setTogglerOpenState = (toggler, isOpen, classNames, icons) => {
|
|
655
|
+
toggler.classList.toggle(classNames.closed, !isOpen);
|
|
656
|
+
toggler.replaceChildren();
|
|
657
|
+
let iconElement = isOpen ? icons.opened : icons.closed;
|
|
658
|
+
if (iconElement) {
|
|
659
|
+
toggler.append(iconElement.cloneNode(true));
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
let setFolderLiOpenState = (li, isOpen, classNames) => {
|
|
663
|
+
li.classList.toggle(classNames.closed, !isOpen);
|
|
664
|
+
li.setAttribute("aria-expanded", getBoolString(isOpen));
|
|
665
|
+
};
|
|
666
|
+
|
|
652
667
|
/* Renders the tree to html.
|
|
653
668
|
*
|
|
654
669
|
* The children of a closed folder are not rendered. They are rendered when
|
|
@@ -695,13 +710,16 @@ var TreeElement = (function () {
|
|
|
695
710
|
this._setNodeElement = setNodeElement;
|
|
696
711
|
this._showEmptyFolder = showEmptyFolder;
|
|
697
712
|
this._tabIndex = tabIndex;
|
|
698
|
-
this.
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
this.
|
|
704
|
-
this.
|
|
713
|
+
this._icons = {
|
|
714
|
+
closed: this._createButtonElement(closedIcon),
|
|
715
|
+
opened: this._createButtonElement(openedIcon)
|
|
716
|
+
};
|
|
717
|
+
let templates = this._createTemplates();
|
|
718
|
+
this._closedFolderTemplate = templates.closedFolderTemplate;
|
|
719
|
+
this._groupUlTemplate = templates.groupUlTemplate;
|
|
720
|
+
this._nodeTemplate = templates.nodeTemplate;
|
|
721
|
+
this._openedFolderTemplate = templates.openedFolderTemplate;
|
|
722
|
+
this._rootUlTemplate = templates.rootUlTemplate;
|
|
705
723
|
}
|
|
706
724
|
_render(fromNode) {
|
|
707
725
|
if (fromNode?.parent) {
|
|
@@ -735,6 +753,43 @@ var TreeElement = (function () {
|
|
|
735
753
|
this._createDomElements(this._htmlElement, tree.children, true, 1);
|
|
736
754
|
}
|
|
737
755
|
}
|
|
756
|
+
|
|
757
|
+
/* Change dragAndDrop after construction. The rendered lists and the
|
|
758
|
+
* templates for new lists get or lose the dnd class.
|
|
759
|
+
*/
|
|
760
|
+
_setDragAndDrop(dragAndDrop) {
|
|
761
|
+
this._dragAndDrop = dragAndDrop;
|
|
762
|
+
this._updateTemplates();
|
|
763
|
+
for (let ul of this._htmlElement.querySelectorAll(`ul.${this._classNames.common}`)) {
|
|
764
|
+
ul.classList.toggle(this._classNames.dnd, dragAndDrop);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/* Change multiSelect after construction. Only the templates are updated;
|
|
769
|
+
* the tree must be rendered again.
|
|
770
|
+
*/
|
|
771
|
+
_setMultiSelect(multiSelect) {
|
|
772
|
+
this._multiSelect = multiSelect;
|
|
773
|
+
this._updateTemplates();
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/* Change tabIndex after construction. The rendered nodes and the
|
|
777
|
+
* templates for new nodes get the new tabindex. The tab stop is updated by
|
|
778
|
+
* TreeElement.updateTabStop.
|
|
779
|
+
*/
|
|
780
|
+
_setTabIndex(tabIndex) {
|
|
781
|
+
this._tabIndex = tabIndex;
|
|
782
|
+
this._updateTemplates();
|
|
783
|
+
for (let li of this._htmlElement.querySelectorAll("li[role=treeitem]")) {
|
|
784
|
+
if (tabIndex === undefined) {
|
|
785
|
+
li.removeAttribute("tabindex");
|
|
786
|
+
} else if (!this._multiSelect && li.getAttribute("aria-selected") === "true") {
|
|
787
|
+
li.setAttribute("tabindex", String(tabIndex));
|
|
788
|
+
} else {
|
|
789
|
+
li.setAttribute("tabindex", "-1");
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
738
793
|
_attachNodeData(node, li) {
|
|
739
794
|
node.element = li;
|
|
740
795
|
this._setNodeElement(li, node);
|
|
@@ -790,26 +845,19 @@ var TreeElement = (function () {
|
|
|
790
845
|
* state, so there is a template for each.
|
|
791
846
|
*/
|
|
792
847
|
_createFolderTemplate(isOpen) {
|
|
793
|
-
let
|
|
794
|
-
|
|
795
|
-
liClasses.push(this._classNames.closed);
|
|
796
|
-
}
|
|
797
|
-
let li = this._createLiTemplate(liClasses.join(" "));
|
|
848
|
+
let li = this._createLiTemplate(`${this._classNames.common} ${this._classNames.folder}`);
|
|
849
|
+
setFolderLiOpenState(li, isOpen, this._classNames);
|
|
798
850
|
let div = li.firstChild;
|
|
799
851
|
|
|
800
852
|
// The toggler is hidden from screen readers: the icon is decoration, and
|
|
801
853
|
// aria-expanded on the treeitem has the open state.
|
|
802
854
|
let toggler = document.createElement("span");
|
|
803
|
-
toggler.className = this._getButtonClasses(
|
|
855
|
+
toggler.className = this._getButtonClasses();
|
|
804
856
|
toggler.setAttribute("aria-hidden", "true");
|
|
805
|
-
|
|
806
|
-
if (iconElement) {
|
|
807
|
-
toggler.append(iconElement.cloneNode(true));
|
|
808
|
-
}
|
|
857
|
+
setTogglerOpenState(toggler, isOpen, this._classNames, this._icons);
|
|
809
858
|
if (this._buttonLeft) {
|
|
810
859
|
div.append(toggler);
|
|
811
860
|
}
|
|
812
|
-
li.setAttribute("aria-expanded", getBoolString(isOpen));
|
|
813
861
|
|
|
814
862
|
// title span
|
|
815
863
|
div.append(this._createTitleSpanTemplate(true));
|
|
@@ -880,6 +928,15 @@ var TreeElement = (function () {
|
|
|
880
928
|
div.append(this._createTitleSpanTemplate(false));
|
|
881
929
|
return li;
|
|
882
930
|
}
|
|
931
|
+
_createTemplates() {
|
|
932
|
+
return {
|
|
933
|
+
closedFolderTemplate: this._createFolderTemplate(false),
|
|
934
|
+
groupUlTemplate: this._createUlTemplate(false),
|
|
935
|
+
nodeTemplate: this._createNodeTemplate(),
|
|
936
|
+
openedFolderTemplate: this._createFolderTemplate(true),
|
|
937
|
+
rootUlTemplate: this._createUlTemplate(true)
|
|
938
|
+
};
|
|
939
|
+
}
|
|
883
940
|
_createTitleSpanTemplate(isFolder) {
|
|
884
941
|
let titleSpan = document.createElement("span");
|
|
885
942
|
let classes = `${this._classNames.title} ${this._classNames.common}`;
|
|
@@ -948,11 +1005,8 @@ var TreeElement = (function () {
|
|
|
948
1005
|
// is false. Otherwise the name would contain everything in the row.
|
|
949
1006
|
li.setAttribute("aria-label", titleSpan.textContent);
|
|
950
1007
|
}
|
|
951
|
-
_getButtonClasses(
|
|
1008
|
+
_getButtonClasses() {
|
|
952
1009
|
let classes = [this._classNames.toggler, this._classNames.common];
|
|
953
|
-
if (!isOpen) {
|
|
954
|
-
classes.push(this._classNames.closed);
|
|
955
|
-
}
|
|
956
1010
|
if (this._buttonLeft) {
|
|
957
1011
|
classes.push(this._classNames.togglerLeft);
|
|
958
1012
|
} else {
|
|
@@ -967,6 +1021,14 @@ var TreeElement = (function () {
|
|
|
967
1021
|
_mustRenderChildren(node) {
|
|
968
1022
|
return node.hasChildren() && node.is_open === true;
|
|
969
1023
|
}
|
|
1024
|
+
_updateTemplates() {
|
|
1025
|
+
let templates = this._createTemplates();
|
|
1026
|
+
this._closedFolderTemplate = templates.closedFolderTemplate;
|
|
1027
|
+
this._groupUlTemplate = templates.groupUlTemplate;
|
|
1028
|
+
this._nodeTemplate = templates.nodeTemplate;
|
|
1029
|
+
this._openedFolderTemplate = templates.openedFolderTemplate;
|
|
1030
|
+
this._rootUlTemplate = templates.rootUlTemplate;
|
|
1031
|
+
}
|
|
970
1032
|
}
|
|
971
1033
|
|
|
972
1034
|
/* The keys move from the selected node and select the node they move to.
|
|
@@ -1017,6 +1079,24 @@ var TreeElement = (function () {
|
|
|
1017
1079
|
return this._goToNode(this._getCurrentNode()?.getPreviousVisibleNode());
|
|
1018
1080
|
}
|
|
1019
1081
|
|
|
1082
|
+
// Change keyboardSupport after construction
|
|
1083
|
+
_setKeyboardSupport(keyboardSupport) {
|
|
1084
|
+
if (keyboardSupport === this._keyboardSupport) {
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
this._keyboardSupport = keyboardSupport;
|
|
1088
|
+
if (keyboardSupport) {
|
|
1089
|
+
document.addEventListener("keydown", this._handleKeyDown);
|
|
1090
|
+
} else {
|
|
1091
|
+
document.removeEventListener("keydown", this._handleKeyDown);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// Change multiSelect after construction
|
|
1096
|
+
_setMultiSelect(multiSelect) {
|
|
1097
|
+
this._multiSelect = multiSelect;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1020
1100
|
// Activate the node, for example to open its edit page.
|
|
1021
1101
|
_activate(node, originalEvent) {
|
|
1022
1102
|
this._triggerEvent("tree.activate", {
|
|
@@ -1281,19 +1361,19 @@ var TreeElement = (function () {
|
|
|
1281
1361
|
return;
|
|
1282
1362
|
}
|
|
1283
1363
|
let div = e.target.closest(`ul.${this._classNames.tree} .${this._classNames.element}`);
|
|
1284
|
-
if (div) {
|
|
1285
|
-
|
|
1286
|
-
if (node) {
|
|
1287
|
-
e.preventDefault();
|
|
1288
|
-
e.stopPropagation();
|
|
1289
|
-
this._triggerEvent("tree.contextmenu", {
|
|
1290
|
-
node,
|
|
1291
|
-
originalEvent: e
|
|
1292
|
-
});
|
|
1293
|
-
return false;
|
|
1294
|
-
}
|
|
1364
|
+
if (!div) {
|
|
1365
|
+
return;
|
|
1295
1366
|
}
|
|
1296
|
-
|
|
1367
|
+
let node = this._getNode(div);
|
|
1368
|
+
if (!node) {
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
e.preventDefault();
|
|
1372
|
+
e.stopPropagation();
|
|
1373
|
+
this._triggerEvent("tree.contextmenu", {
|
|
1374
|
+
node,
|
|
1375
|
+
originalEvent: e
|
|
1376
|
+
});
|
|
1297
1377
|
};
|
|
1298
1378
|
_handleDblclick = e => {
|
|
1299
1379
|
if (!e.target) {
|
|
@@ -1453,14 +1533,14 @@ var TreeElement = (function () {
|
|
|
1453
1533
|
*
|
|
1454
1534
|
* @groupDescription Searching
|
|
1455
1535
|
* These work on any node, and search that node's subtree. Called on the root
|
|
1456
|
-
* node, they search the whole tree
|
|
1536
|
+
* node, they search the whole tree—which is what the tree's own methods of
|
|
1457
1537
|
* the same name do.
|
|
1458
1538
|
*
|
|
1459
1539
|
* @groupDescription Changing the tree
|
|
1460
1540
|
* ::: warning
|
|
1461
1541
|
* These methods change the data without re-rendering. The tree's
|
|
1462
|
-
* [methods](/reference/methods)
|
|
1463
|
-
* friends
|
|
1542
|
+
* [methods](/reference/methods)—`appendNode`, `removeNode`, `moveNode` and
|
|
1543
|
+
* friends—do the same and refresh the display, so prefer those. If you do
|
|
1464
1544
|
* use these, call `tree.refresh()` afterwards.
|
|
1465
1545
|
* :::
|
|
1466
1546
|
*/
|
|
@@ -1509,7 +1589,7 @@ var TreeElement = (function () {
|
|
|
1509
1589
|
*/
|
|
1510
1590
|
nodeClass;
|
|
1511
1591
|
/**
|
|
1512
|
-
The parent
|
|
1592
|
+
The parent, or `null` for the root node.
|
|
1513
1593
|
*/
|
|
1514
1594
|
parent;
|
|
1515
1595
|
/**
|
|
@@ -1601,7 +1681,9 @@ var TreeElement = (function () {
|
|
|
1601
1681
|
}
|
|
1602
1682
|
|
|
1603
1683
|
/**
|
|
1604
|
-
* Inserts a new parent between this node and its current parent.
|
|
1684
|
+
* Inserts a new parent between this node and its current parent. Its
|
|
1685
|
+
* siblings move along: the new node takes all children of the current
|
|
1686
|
+
* parent, and becomes its only child.
|
|
1605
1687
|
*
|
|
1606
1688
|
* @returns The new node, or `null` when the node has no parent.
|
|
1607
1689
|
* @group Changing the tree
|
|
@@ -1671,7 +1753,7 @@ var TreeElement = (function () {
|
|
|
1671
1753
|
* Returns the subtree as plain data, ready for `JSON.stringify`.
|
|
1672
1754
|
* Internal properties (`parent`, `children`, `element`, `tree`,
|
|
1673
1755
|
* `idMapping`, `nodeClass`, `load_on_demand`, `isEmptyFolder`) are left
|
|
1674
|
-
* out
|
|
1756
|
+
* out. Your own properties are kept.
|
|
1675
1757
|
*
|
|
1676
1758
|
* ```js
|
|
1677
1759
|
* tree.getTree().getData();
|
|
@@ -1763,7 +1845,7 @@ var TreeElement = (function () {
|
|
|
1763
1845
|
}
|
|
1764
1846
|
|
|
1765
1847
|
/**
|
|
1766
|
-
* Like `getNextNode`, but skipping nodes inside closed folders
|
|
1848
|
+
* Like `getNextNode`, but skipping nodes inside closed folders. This is
|
|
1767
1849
|
* what the arrow keys use.
|
|
1768
1850
|
*
|
|
1769
1851
|
* @group Moving around the tree
|
|
@@ -1847,7 +1929,7 @@ var TreeElement = (function () {
|
|
|
1847
1929
|
}
|
|
1848
1930
|
|
|
1849
1931
|
/**
|
|
1850
|
-
* Returns the parent
|
|
1932
|
+
* Returns the parent, or `null` for a top-level node: the root node is not
|
|
1851
1933
|
* returned.
|
|
1852
1934
|
*
|
|
1853
1935
|
* @group Moving around the tree
|
|
@@ -1895,8 +1977,8 @@ var TreeElement = (function () {
|
|
|
1895
1977
|
}
|
|
1896
1978
|
|
|
1897
1979
|
/**
|
|
1898
|
-
* Like `getPreviousNode`, but skipping nodes inside closed folders
|
|
1899
|
-
*
|
|
1980
|
+
* Like `getPreviousNode`, but skipping nodes inside closed folders.
|
|
1981
|
+
* This is what the arrow keys use.
|
|
1900
1982
|
*
|
|
1901
1983
|
* @group Moving around the tree
|
|
1902
1984
|
*/
|
|
@@ -2372,11 +2454,10 @@ var TreeElement = (function () {
|
|
|
2372
2454
|
class FolderElement extends NodeElement {
|
|
2373
2455
|
constructor({
|
|
2374
2456
|
_classNames: classNames,
|
|
2375
|
-
_closedIconElement: closedIconElement,
|
|
2376
2457
|
_getScrollLeft: getScrollLeft,
|
|
2458
|
+
_icons: icons,
|
|
2377
2459
|
_multiSelect: multiSelect,
|
|
2378
2460
|
_node: node,
|
|
2379
|
-
_openedIconElement: openedIconElement,
|
|
2380
2461
|
_renderChildren: renderChildren,
|
|
2381
2462
|
_tabIndex: tabIndex,
|
|
2382
2463
|
_treeElement: treeElement,
|
|
@@ -2390,8 +2471,7 @@ var TreeElement = (function () {
|
|
|
2390
2471
|
_tabIndex: tabIndex,
|
|
2391
2472
|
_treeElement: treeElement
|
|
2392
2473
|
});
|
|
2393
|
-
this.
|
|
2394
|
-
this._openedIconElement = openedIconElement;
|
|
2474
|
+
this._icons = icons;
|
|
2395
2475
|
this._renderChildren = renderChildren;
|
|
2396
2476
|
this._triggerEvent = triggerEvent;
|
|
2397
2477
|
}
|
|
@@ -2400,30 +2480,11 @@ var TreeElement = (function () {
|
|
|
2400
2480
|
return;
|
|
2401
2481
|
}
|
|
2402
2482
|
this._node.is_open = false;
|
|
2403
|
-
if (
|
|
2404
|
-
this.
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
return;
|
|
2408
|
-
}
|
|
2409
|
-
let button = this._getButton();
|
|
2410
|
-
button.classList.add(this._classNames.closed);
|
|
2411
|
-
button.replaceChildren();
|
|
2412
|
-
let closedIconElement = this._closedIconElement;
|
|
2413
|
-
if (closedIconElement) {
|
|
2414
|
-
let icon = closedIconElement.cloneNode(true);
|
|
2415
|
-
button.append(icon);
|
|
2416
|
-
}
|
|
2417
|
-
let ul = this._getUl();
|
|
2418
|
-
if (ul) {
|
|
2419
|
-
if (slide) {
|
|
2420
|
-
await slideUp(ul, animationSpeed);
|
|
2421
|
-
} else {
|
|
2422
|
-
ul.style.display = "none";
|
|
2423
|
-
}
|
|
2483
|
+
if (this._isRendered()) {
|
|
2484
|
+
this._setButtonState(false);
|
|
2485
|
+
await this._setUlState(this._getUl(), false, slide, animationSpeed);
|
|
2486
|
+
this._setElementState(false);
|
|
2424
2487
|
}
|
|
2425
|
-
this._element.classList.add(this._classNames.closed);
|
|
2426
|
-
this._element.setAttribute("aria-expanded", "false");
|
|
2427
2488
|
this._triggerEvent("tree.close", {
|
|
2428
2489
|
node: this._node
|
|
2429
2490
|
});
|
|
@@ -2433,33 +2494,17 @@ var TreeElement = (function () {
|
|
|
2433
2494
|
return;
|
|
2434
2495
|
}
|
|
2435
2496
|
this._node.is_open = true;
|
|
2436
|
-
if (!this._isRendered()) {
|
|
2437
|
-
// The folder is rendered open when its parent is opened
|
|
2438
|
-
this._triggerEvent("tree.open", {
|
|
2439
|
-
node: this._node
|
|
2440
|
-
});
|
|
2441
|
-
return;
|
|
2442
|
-
}
|
|
2443
|
-
let button = this._getButton();
|
|
2444
|
-
button.classList.remove(this._classNames.closed);
|
|
2445
|
-
button.replaceChildren();
|
|
2446
|
-
let openedIconElement = this._openedIconElement;
|
|
2447
|
-
if (openedIconElement) {
|
|
2448
|
-
let icon = openedIconElement.cloneNode(true);
|
|
2449
|
-
button.append(icon);
|
|
2450
|
-
}
|
|
2451
2497
|
|
|
2452
|
-
//
|
|
2453
|
-
|
|
2454
|
-
if (
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2498
|
+
// A folder that is not rendered is rendered open when its parent is
|
|
2499
|
+
// opened
|
|
2500
|
+
if (this._isRendered()) {
|
|
2501
|
+
this._setButtonState(true);
|
|
2502
|
+
|
|
2503
|
+
// The children are rendered the first time the folder is opened
|
|
2504
|
+
let ul = this._getUl() ?? this._renderChildren(this._node);
|
|
2505
|
+
await this._setUlState(ul, true, slide, animationSpeed);
|
|
2506
|
+
this._setElementState(true);
|
|
2460
2507
|
}
|
|
2461
|
-
this._element.classList.remove(this._classNames.closed);
|
|
2462
|
-
this._element.setAttribute("aria-expanded", "true");
|
|
2463
2508
|
this._triggerEvent("tree.open", {
|
|
2464
2509
|
node: this._node
|
|
2465
2510
|
});
|
|
@@ -2470,8 +2515,34 @@ var TreeElement = (function () {
|
|
|
2470
2515
|
_getButton() {
|
|
2471
2516
|
return this._element.querySelector(`:scope > .${this._classNames.element} > .${this._classNames.toggler}`);
|
|
2472
2517
|
}
|
|
2518
|
+
_setButtonState(isOpen) {
|
|
2519
|
+
setTogglerOpenState(this._getButton(), isOpen, this._classNames, this._icons);
|
|
2520
|
+
}
|
|
2521
|
+
_setElementState(isOpen) {
|
|
2522
|
+
setFolderLiOpenState(this._element, isOpen, this._classNames);
|
|
2523
|
+
}
|
|
2524
|
+
async _setUlState(ul, isOpen, slide, animationSpeed) {
|
|
2525
|
+
if (!ul) {
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
if (slide) {
|
|
2529
|
+
await (isOpen ? slideDown : slideUp)(ul, animationSpeed);
|
|
2530
|
+
} else {
|
|
2531
|
+
ul.style.display = isOpen ? "block" : "none";
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2473
2534
|
}
|
|
2474
2535
|
|
|
2536
|
+
/* The options that setOption can change. The others are read once, in the
|
|
2537
|
+
* constructor, so changing them later would have no effect or leave the tree
|
|
2538
|
+
* in an inconsistent state.
|
|
2539
|
+
*/
|
|
2540
|
+
let changeableOptions = ["animationSpeed", "dataUrl", "dragAndDrop", "keyboardSupport", "multiSelect", "onCanSelectNode", "selectable", "slide", "startDndDelay", "tabIndex"];
|
|
2541
|
+
|
|
2542
|
+
/**
|
|
2543
|
+
* The options that `setOption` can change.
|
|
2544
|
+
*/
|
|
2545
|
+
|
|
2475
2546
|
// Url of a request. A relative url is resolved against the page, like a link
|
|
2476
2547
|
// or `fetch` would, so it also works when the page is in a subdirectory.
|
|
2477
2548
|
|
|
@@ -2512,9 +2583,7 @@ var TreeElement = (function () {
|
|
|
2512
2583
|
this._saveStateOption = saveState;
|
|
2513
2584
|
}
|
|
2514
2585
|
_getNodeIdToBeSelected() {
|
|
2515
|
-
|
|
2516
|
-
return null;
|
|
2517
|
-
}
|
|
2586
|
+
// Without the saveState option there is no state
|
|
2518
2587
|
let state = this._getStateFromStorage();
|
|
2519
2588
|
return state?.selected_node ? state.selected_node[0] ?? null : null;
|
|
2520
2589
|
}
|
|
@@ -2643,17 +2712,19 @@ var TreeElement = (function () {
|
|
|
2643
2712
|
this._removeFromSelection(node);
|
|
2644
2713
|
}
|
|
2645
2714
|
}
|
|
2715
|
+
|
|
2716
|
+
// result: is a node selected?
|
|
2646
2717
|
_selectInitialNodes(nodeIds) {
|
|
2647
|
-
let
|
|
2718
|
+
let isNodeSelected = false;
|
|
2648
2719
|
for (let nodeId of nodeIds) {
|
|
2649
2720
|
let node = this._getNodeById(nodeId);
|
|
2650
2721
|
if (!node) {
|
|
2651
2722
|
continue;
|
|
2652
2723
|
}
|
|
2653
|
-
selectCount += 1;
|
|
2654
2724
|
this._addToSelection(node);
|
|
2725
|
+
isNodeSelected = true;
|
|
2655
2726
|
}
|
|
2656
|
-
return
|
|
2727
|
+
return isNodeSelected;
|
|
2657
2728
|
}
|
|
2658
2729
|
}
|
|
2659
2730
|
|
|
@@ -3006,6 +3077,11 @@ var TreeElement = (function () {
|
|
|
3006
3077
|
for (let otherNode of otherSelectedNodes) {
|
|
3007
3078
|
this._deselectNode(otherNode);
|
|
3008
3079
|
}
|
|
3080
|
+
for (let otherNode of otherSelectedNodes) {
|
|
3081
|
+
this._triggerEvent("tree.deselect", {
|
|
3082
|
+
node: otherNode
|
|
3083
|
+
});
|
|
3084
|
+
}
|
|
3009
3085
|
} else if (selectOptions.mustToggle) {
|
|
3010
3086
|
this._deselectNode(node);
|
|
3011
3087
|
this._triggerEvent("tree.deselect", {
|
|
@@ -3013,13 +3089,20 @@ var TreeElement = (function () {
|
|
|
3013
3089
|
});
|
|
3014
3090
|
}
|
|
3015
3091
|
} else {
|
|
3016
|
-
|
|
3092
|
+
// tree.select reports the first deselected node; the others, from a
|
|
3093
|
+
// multiple selection, get a tree.deselect.
|
|
3094
|
+
let [deselectedNode = null, ...alsoDeselectedNodes] = otherSelectedNodes;
|
|
3017
3095
|
for (let otherNode of otherSelectedNodes) {
|
|
3018
3096
|
this._deselectNode(otherNode);
|
|
3019
3097
|
}
|
|
3020
3098
|
this._addToSelection(node);
|
|
3021
3099
|
this._openParents(node);
|
|
3022
3100
|
this._getNodeElementForNode(node)._select(selectOptions.mustSetFocus);
|
|
3101
|
+
for (let otherNode of alsoDeselectedNodes) {
|
|
3102
|
+
this._triggerEvent("tree.deselect", {
|
|
3103
|
+
node: otherNode
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3023
3106
|
this._triggerEvent("tree.select", {
|
|
3024
3107
|
deselectedNode,
|
|
3025
3108
|
node
|
|
@@ -3157,7 +3240,7 @@ var TreeElement = (function () {
|
|
|
3157
3240
|
};
|
|
3158
3241
|
|
|
3159
3242
|
// Generated by config/generateVersion.mjs. Do not edit.
|
|
3160
|
-
let version = "0.4.
|
|
3243
|
+
let version = "0.4.1";
|
|
3161
3244
|
|
|
3162
3245
|
// The types that appear in the public api. Consumers cannot import them from
|
|
3163
3246
|
// the submodules directly, because those are not exposed in package.json.
|
|
@@ -3224,7 +3307,6 @@ var TreeElement = (function () {
|
|
|
3224
3307
|
rtl,
|
|
3225
3308
|
saveState: saveStateOption,
|
|
3226
3309
|
showEmptyFolder,
|
|
3227
|
-
slide,
|
|
3228
3310
|
tabIndex
|
|
3229
3311
|
} = this._options;
|
|
3230
3312
|
let classNames = this._classNames;
|
|
@@ -3313,7 +3395,6 @@ var TreeElement = (function () {
|
|
|
3313
3395
|
_openFolderDelay: openFolderDelay,
|
|
3314
3396
|
_openNode: openNode,
|
|
3315
3397
|
_refreshElements: refreshElements,
|
|
3316
|
-
_slide: slide,
|
|
3317
3398
|
_treeElement: treeElement,
|
|
3318
3399
|
_triggerEvent: triggerEvent
|
|
3319
3400
|
});
|
|
@@ -3412,8 +3493,9 @@ var TreeElement = (function () {
|
|
|
3412
3493
|
}
|
|
3413
3494
|
|
|
3414
3495
|
/**
|
|
3415
|
-
* Inserts a new node between a node and its parent
|
|
3416
|
-
*
|
|
3496
|
+
* Inserts a new node between a node and its parent. The siblings of the node
|
|
3497
|
+
* move along: the new node takes all children of the parent, and becomes its
|
|
3498
|
+
* only child.
|
|
3417
3499
|
*
|
|
3418
3500
|
* @returns The new node, or `null` when the node has no parent.
|
|
3419
3501
|
* @group Changing the tree
|
|
@@ -3583,7 +3665,7 @@ var TreeElement = (function () {
|
|
|
3583
3665
|
}
|
|
3584
3666
|
|
|
3585
3667
|
/**
|
|
3586
|
-
* Returns the current state
|
|
3668
|
+
* Returns the current state—`open_nodes` and `selected_node`—whether or
|
|
3587
3669
|
* not `saveState` is enabled.
|
|
3588
3670
|
*
|
|
3589
3671
|
* @group State
|
|
@@ -3602,7 +3684,7 @@ var TreeElement = (function () {
|
|
|
3602
3684
|
}
|
|
3603
3685
|
|
|
3604
3686
|
/**
|
|
3605
|
-
* Returns the root node. It is not rendered
|
|
3687
|
+
* Returns the root node. It is not rendered, and its `children` are the
|
|
3606
3688
|
* top-level nodes. Also available as the `tree` property.
|
|
3607
3689
|
*
|
|
3608
3690
|
* @group Finding nodes
|
|
@@ -3713,7 +3795,7 @@ var TreeElement = (function () {
|
|
|
3713
3795
|
}
|
|
3714
3796
|
|
|
3715
3797
|
/**
|
|
3716
|
-
* Opens a folder, and the folders
|
|
3798
|
+
* Opens a folder, and the folders that contain it. A node marked `load_on_demand`
|
|
3717
3799
|
* is fetched first, so await the promise when you need to know it is really
|
|
3718
3800
|
* open.
|
|
3719
3801
|
*
|
|
@@ -3729,7 +3811,7 @@ var TreeElement = (function () {
|
|
|
3729
3811
|
async openNode(node, slide) {
|
|
3730
3812
|
let mustSlide = slide ?? this._options.slide;
|
|
3731
3813
|
let doOpenNode = async (openedNode, slideOption) => {
|
|
3732
|
-
if (!
|
|
3814
|
+
if (!openedNode.children.length) {
|
|
3733
3815
|
return;
|
|
3734
3816
|
}
|
|
3735
3817
|
let folderElement = this._createFolderElement(openedNode);
|
|
@@ -3848,13 +3930,43 @@ var TreeElement = (function () {
|
|
|
3848
3930
|
}
|
|
3849
3931
|
|
|
3850
3932
|
/**
|
|
3851
|
-
* Changes an option after construction.
|
|
3852
|
-
*
|
|
3933
|
+
* Changes an option after construction. Only some options can be changed:
|
|
3934
|
+
* the others throw an error. See
|
|
3935
|
+
* [Options](/reference/options#changing-an-option-later).
|
|
3853
3936
|
*
|
|
3854
3937
|
* @group Other
|
|
3855
3938
|
*/
|
|
3856
3939
|
setOption(option, value) {
|
|
3940
|
+
if (!changeableOptions.includes(option)) {
|
|
3941
|
+
throw new Error(`The option ${option} can only be set in the constructor`);
|
|
3942
|
+
}
|
|
3857
3943
|
this._options[option] = value;
|
|
3944
|
+
switch (option) {
|
|
3945
|
+
case "dragAndDrop":
|
|
3946
|
+
{
|
|
3947
|
+
this._renderer._setDragAndDrop(Boolean(value));
|
|
3948
|
+
break;
|
|
3949
|
+
}
|
|
3950
|
+
case "keyboardSupport":
|
|
3951
|
+
{
|
|
3952
|
+
this._keyHandler._setKeyboardSupport(Boolean(value));
|
|
3953
|
+
break;
|
|
3954
|
+
}
|
|
3955
|
+
case "multiSelect":
|
|
3956
|
+
{
|
|
3957
|
+
this._setMultiSelect(Boolean(value));
|
|
3958
|
+
break;
|
|
3959
|
+
}
|
|
3960
|
+
case "tabIndex":
|
|
3961
|
+
{
|
|
3962
|
+
this._options.tabIndex = value ?? undefined;
|
|
3963
|
+
this._renderer._setTabIndex(this._options.tabIndex);
|
|
3964
|
+
this._fallbackTabStop = null;
|
|
3965
|
+
this._updateTabStop();
|
|
3966
|
+
break;
|
|
3967
|
+
}
|
|
3968
|
+
// No default
|
|
3969
|
+
}
|
|
3858
3970
|
}
|
|
3859
3971
|
|
|
3860
3972
|
/**
|
|
@@ -3887,8 +3999,8 @@ var TreeElement = (function () {
|
|
|
3887
3999
|
}
|
|
3888
4000
|
|
|
3889
4001
|
/**
|
|
3890
|
-
* Returns the tree as a
|
|
3891
|
-
*
|
|
4002
|
+
* Returns the tree as a JSON string, including changes made through the
|
|
4003
|
+
* API.
|
|
3892
4004
|
*
|
|
3893
4005
|
* @group Other
|
|
3894
4006
|
*/
|
|
@@ -3901,7 +4013,7 @@ var TreeElement = (function () {
|
|
|
3901
4013
|
* name.
|
|
3902
4014
|
*
|
|
3903
4015
|
* Changing the `id` re-indexes the node. `children` and `parent` are
|
|
3904
|
-
* ignored
|
|
4016
|
+
* ignored—use `loadData` or `moveNode` for those.
|
|
3905
4017
|
*
|
|
3906
4018
|
* @example
|
|
3907
4019
|
* ```js
|
|
@@ -3952,9 +4064,7 @@ var TreeElement = (function () {
|
|
|
3952
4064
|
}
|
|
3953
4065
|
_createFolderElement(node) {
|
|
3954
4066
|
let classNames = this._classNames;
|
|
3955
|
-
let closedIconElement = this._renderer._closedIconElement;
|
|
3956
4067
|
let getScrollLeft = this._scrollHandler._getScrollLeft.bind(this._scrollHandler);
|
|
3957
|
-
let openedIconElement = this._renderer._openedIconElement;
|
|
3958
4068
|
let tabIndex = this._options.tabIndex;
|
|
3959
4069
|
let treeElement = this._htmlElement;
|
|
3960
4070
|
let triggerEvent = this._triggerEvent.bind(this);
|
|
@@ -3969,11 +4079,10 @@ var TreeElement = (function () {
|
|
|
3969
4079
|
};
|
|
3970
4080
|
return new FolderElement({
|
|
3971
4081
|
_classNames: classNames,
|
|
3972
|
-
_closedIconElement: closedIconElement,
|
|
3973
4082
|
_getScrollLeft: getScrollLeft,
|
|
4083
|
+
_icons: this._renderer._icons,
|
|
3974
4084
|
_multiSelect: this._options.multiSelect,
|
|
3975
4085
|
_node: node,
|
|
3976
|
-
_openedIconElement: openedIconElement,
|
|
3977
4086
|
_renderChildren: renderChildren,
|
|
3978
4087
|
_tabIndex: tabIndex,
|
|
3979
4088
|
_treeElement: treeElement,
|
|
@@ -4069,14 +4178,8 @@ var TreeElement = (function () {
|
|
|
4069
4178
|
_getFocusedNode() {
|
|
4070
4179
|
let activeElement = document.activeElement;
|
|
4071
4180
|
|
|
4072
|
-
|
|
4073
|
-
if (!activeElement) {
|
|
4074
|
-
return null;
|
|
4075
|
-
}
|
|
4076
|
-
|
|
4077
|
-
// The keyboard must still work for input elements.
|
|
4078
|
-
let tagName = activeElement.tagName;
|
|
4079
|
-
if (tagName !== "A" && tagName !== "LI" && tagName !== "SPAN") {
|
|
4181
|
+
// An active element must exist and the keyboard must still work for input elements.
|
|
4182
|
+
if (!activeElement || !["A", "LI", "SPAN"].includes(activeElement.tagName)) {
|
|
4080
4183
|
return null;
|
|
4081
4184
|
}
|
|
4082
4185
|
let node = this.getNode(activeElement);
|
|
@@ -4125,11 +4228,17 @@ var TreeElement = (function () {
|
|
|
4125
4228
|
this._isInitialized = true;
|
|
4126
4229
|
this._triggerEvent("tree.init");
|
|
4127
4230
|
};
|
|
4231
|
+
|
|
4232
|
+
// Before the tree is replaced: then the focused node is no longer in it
|
|
4233
|
+
let focusedNode = this._getFocusedNode();
|
|
4128
4234
|
this._tree = new this._options.nodeClass(null, true, this._options.nodeClass);
|
|
4129
4235
|
this._selectNodeHandler._clear();
|
|
4130
4236
|
this._tree.loadFromData(data);
|
|
4131
4237
|
let mustLoadOnDemand = this._setInitialState();
|
|
4132
4238
|
this._refreshElements(null);
|
|
4239
|
+
if (focusedNode) {
|
|
4240
|
+
this._restoreFocus(focusedNode);
|
|
4241
|
+
}
|
|
4133
4242
|
if (mustLoadOnDemand) {
|
|
4134
4243
|
// Load data on demand and then init the tree
|
|
4135
4244
|
void this._setInitialStateOnDemand().then(doInit);
|
|
@@ -4137,15 +4246,6 @@ var TreeElement = (function () {
|
|
|
4137
4246
|
doInit();
|
|
4138
4247
|
}
|
|
4139
4248
|
}
|
|
4140
|
-
|
|
4141
|
-
// Does an HTML element of the tree have the focus?
|
|
4142
|
-
_isFocusOnTree() {
|
|
4143
|
-
return this._getFocusedNode() !== null;
|
|
4144
|
-
}
|
|
4145
|
-
_isSelectedNodeInSubtree(subtree) {
|
|
4146
|
-
let selectedNode = this.getSelectedNode();
|
|
4147
|
-
return selectedNode ? subtree === selectedNode || subtree.isParentOf(selectedNode) : false;
|
|
4148
|
-
}
|
|
4149
4249
|
async _loadFolderOnDemand(node, slide) {
|
|
4150
4250
|
node.is_loading = true;
|
|
4151
4251
|
await this.loadDataFromUrl(undefined, node);
|
|
@@ -4186,10 +4286,10 @@ var TreeElement = (function () {
|
|
|
4186
4286
|
_mouseStop(positionInfo) {
|
|
4187
4287
|
/* istanbul ignore if */
|
|
4188
4288
|
if (!this._options.dragAndDrop) {
|
|
4189
|
-
return
|
|
4289
|
+
return;
|
|
4190
4290
|
}
|
|
4191
4291
|
this._scrollHandler._stopScrolling();
|
|
4192
|
-
|
|
4292
|
+
this._dndHandler._mouseStop(positionInfo);
|
|
4193
4293
|
}
|
|
4194
4294
|
_openParents(node) {
|
|
4195
4295
|
let parent = node.parent;
|
|
@@ -4203,25 +4303,32 @@ var TreeElement = (function () {
|
|
|
4203
4303
|
from_node: redraw this subtree
|
|
4204
4304
|
*/
|
|
4205
4305
|
_refreshElements(fromNode) {
|
|
4206
|
-
let
|
|
4207
|
-
|
|
4306
|
+
let focusedNode = this._getFocusedNode();
|
|
4307
|
+
|
|
4308
|
+
// The renderer marks the selected nodes, so only the focus needs restoring
|
|
4208
4309
|
this._renderer._render(fromNode);
|
|
4209
|
-
if (
|
|
4210
|
-
this.
|
|
4310
|
+
if (focusedNode) {
|
|
4311
|
+
this._restoreFocus(focusedNode);
|
|
4211
4312
|
}
|
|
4212
4313
|
this._updateTabStop();
|
|
4213
4314
|
this._triggerEvent("tree.refresh");
|
|
4214
4315
|
}
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
if (
|
|
4316
|
+
|
|
4317
|
+
// Rendering replaces the elements of the nodes, so a focused element can be
|
|
4318
|
+
// gone. Then move the focus to the new element of the same node. After
|
|
4319
|
+
// loadData the nodes are new objects, so look the node up by its id.
|
|
4320
|
+
_restoreFocus(focusedNode) {
|
|
4321
|
+
if (this._htmlElement.contains(document.activeElement)) {
|
|
4221
4322
|
return;
|
|
4222
4323
|
}
|
|
4223
|
-
let
|
|
4224
|
-
|
|
4324
|
+
let node = (focusedNode.id == null ? null : this.getNodeById(focusedNode.id)) ?? focusedNode;
|
|
4325
|
+
let element = node.element;
|
|
4326
|
+
if (element && this._htmlElement.contains(element)) {
|
|
4327
|
+
element.focus();
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
_saveState() {
|
|
4331
|
+
this._saveStateHandler._saveState();
|
|
4225
4332
|
}
|
|
4226
4333
|
|
|
4227
4334
|
// Set initial state, either by restoring the state or auto-opening nodes
|
|
@@ -4276,6 +4383,25 @@ var TreeElement = (function () {
|
|
|
4276
4383
|
}
|
|
4277
4384
|
}
|
|
4278
4385
|
|
|
4386
|
+
/* Change multiSelect after construction. The attributes of the nodes
|
|
4387
|
+
* depend on it, so the tree is rendered again. The selection is kept: a
|
|
4388
|
+
* tree without multiSelect can also have several selected nodes, see
|
|
4389
|
+
* addToSelection.
|
|
4390
|
+
*/
|
|
4391
|
+
_setMultiSelect(multiSelect) {
|
|
4392
|
+
let focusedNode = this._getFocusedNode();
|
|
4393
|
+
this._keyHandler._setMultiSelect(multiSelect);
|
|
4394
|
+
this._renderer._setMultiSelect(multiSelect);
|
|
4395
|
+
if (multiSelect) {
|
|
4396
|
+
this._htmlElement.addEventListener("focusin", this._handleFocusIn);
|
|
4397
|
+
} else {
|
|
4398
|
+
this._htmlElement.removeEventListener("focusin", this._handleFocusIn);
|
|
4399
|
+
}
|
|
4400
|
+
this._activeNode = multiSelect ? focusedNode : null;
|
|
4401
|
+
this._fallbackTabStop = null;
|
|
4402
|
+
this._refreshElements(null);
|
|
4403
|
+
}
|
|
4404
|
+
|
|
4279
4405
|
// Set this HTML element to this node in the node map.
|
|
4280
4406
|
_setNodeElement(element, node) {
|
|
4281
4407
|
this._nodeMap.set(element, node);
|