tree-element 0.3.1 → 0.4.0
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 +1 -0
- package/lib/classNames.js +4 -4
- package/lib/classNames.js.map +1 -1
- package/lib/dataLoader.d.ts +0 -1
- package/lib/dataLoader.d.ts.map +1 -1
- package/lib/dataLoader.js +6 -6
- package/lib/dataLoader.js.map +1 -1
- package/lib/elementsRenderer.d.ts +4 -2
- package/lib/elementsRenderer.d.ts.map +1 -1
- package/lib/elementsRenderer.js +35 -21
- package/lib/elementsRenderer.js.map +1 -1
- package/lib/index.d.ts +10 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +75 -18
- package/lib/index.js.map +1 -1
- package/lib/keyHandler.d.ts +14 -3
- package/lib/keyHandler.d.ts.map +1 -1
- package/lib/keyHandler.js +61 -32
- package/lib/keyHandler.js.map +1 -1
- package/lib/methodTypes.d.ts +3 -0
- package/lib/methodTypes.d.ts.map +1 -1
- package/lib/nodeElement/folderElement.d.ts +1 -1
- package/lib/nodeElement/folderElement.d.ts.map +1 -1
- package/lib/nodeElement/folderElement.js +4 -4
- package/lib/nodeElement/folderElement.js.map +1 -1
- package/lib/nodeElement/index.d.ts +3 -2
- package/lib/nodeElement/index.d.ts.map +1 -1
- package/lib/nodeElement/index.js +15 -12
- package/lib/nodeElement/index.js.map +1 -1
- package/lib/options.d.ts +13 -0
- package/lib/options.d.ts.map +1 -1
- package/lib/selectNodeHandler.d.ts +3 -0
- package/lib/selectNodeHandler.d.ts.map +1 -1
- package/lib/selectNodeHandler.js +54 -22
- package/lib/selectNodeHandler.js.map +1 -1
- package/lib/setDefaultOptions.d.ts.map +1 -1
- package/lib/setDefaultOptions.js +5 -4
- package/lib/setDefaultOptions.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 +19 -19
- package/src/classNames.ts +4 -4
- package/src/dataLoader.ts +6 -9
- package/src/elementsRenderer.ts +42 -24
- package/src/index.ts +83 -24
- package/src/keyHandler.ts +84 -34
- package/src/methodTypes.ts +6 -0
- package/src/nodeElement/folderElement.ts +4 -4
- package/src/nodeElement/index.ts +20 -17
- package/src/options.ts +13 -0
- package/src/selectNodeHandler.ts +58 -25
- package/src/setDefaultOptions.ts +5 -4
- package/src/version.ts +1 -1
- package/tree_element.css +16 -0
- package/tree_element.debug.js +260 -124
- 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.
|
|
2
|
+
Tree-element 0.4.0
|
|
3
3
|
|
|
4
4
|
Copyright 2026 Marco Braak
|
|
5
5
|
|
|
@@ -29,13 +29,13 @@ var TreeElement = (function () {
|
|
|
29
29
|
*/
|
|
30
30
|
let createClassNames = ({
|
|
31
31
|
classPrefix,
|
|
32
|
-
commonClassName
|
|
33
|
-
treeClassName
|
|
32
|
+
commonClassName = `${classPrefix}-common`,
|
|
33
|
+
treeClassName = classPrefix
|
|
34
34
|
}) => ({
|
|
35
35
|
border: `${classPrefix}-border`,
|
|
36
36
|
circle: `${classPrefix}-circle`,
|
|
37
37
|
closed: `${classPrefix}-closed`,
|
|
38
|
-
common: commonClassName
|
|
38
|
+
common: commonClassName,
|
|
39
39
|
dnd: `${classPrefix}-dnd`,
|
|
40
40
|
dragging: `${classPrefix}-dragging`,
|
|
41
41
|
element: `${classPrefix}-element`,
|
|
@@ -54,7 +54,7 @@ var TreeElement = (function () {
|
|
|
54
54
|
toggler: `${classPrefix}-toggler`,
|
|
55
55
|
togglerLeft: `${classPrefix}-toggler-left`,
|
|
56
56
|
togglerRight: `${classPrefix}-toggler-right`,
|
|
57
|
-
tree: treeClassName
|
|
57
|
+
tree: treeClassName
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
class DataLoader {
|
|
@@ -80,15 +80,18 @@ var TreeElement = (function () {
|
|
|
80
80
|
element.classList.add(this._classNames.loading);
|
|
81
81
|
|
|
82
82
|
// Tell screen readers that the children of the folder are loading
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
if (node) {
|
|
84
|
+
element.setAttribute("aria-busy", "true");
|
|
85
|
+
}
|
|
85
86
|
this._triggerEvent("tree.loading_data", {
|
|
86
87
|
element,
|
|
87
88
|
node
|
|
88
89
|
});
|
|
89
90
|
let stopLoading = () => {
|
|
90
91
|
element.classList.remove(this._classNames.loading);
|
|
91
|
-
|
|
92
|
+
if (node) {
|
|
93
|
+
element.removeAttribute("aria-busy");
|
|
94
|
+
}
|
|
92
95
|
this._triggerEvent("tree.loaded_data", {
|
|
93
96
|
element,
|
|
94
97
|
node
|
|
@@ -124,9 +127,6 @@ var TreeElement = (function () {
|
|
|
124
127
|
});
|
|
125
128
|
});
|
|
126
129
|
}
|
|
127
|
-
_getTitleSpan(element) {
|
|
128
|
-
return element.querySelector(`:scope > .${this._classNames.element} > .${this._classNames.title}`);
|
|
129
|
-
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
// Get the top position of the HTML element.
|
|
@@ -672,6 +672,7 @@ var TreeElement = (function () {
|
|
|
672
672
|
_getTree: getTree,
|
|
673
673
|
_htmlElement: htmlElement,
|
|
674
674
|
_isNodeSelected: isNodeSelected,
|
|
675
|
+
_multiSelect: multiSelect,
|
|
675
676
|
_onCreateLi: onCreateLi,
|
|
676
677
|
_openedIcon: openedIcon = "+",
|
|
677
678
|
_rtl: rtl,
|
|
@@ -688,6 +689,7 @@ var TreeElement = (function () {
|
|
|
688
689
|
this._getTree = getTree;
|
|
689
690
|
this._htmlElement = htmlElement;
|
|
690
691
|
this._isNodeSelected = isNodeSelected;
|
|
692
|
+
this._multiSelect = multiSelect;
|
|
691
693
|
this._onCreateLi = onCreateLi;
|
|
692
694
|
this._rtl = rtl;
|
|
693
695
|
this._setNodeElement = setNodeElement;
|
|
@@ -713,7 +715,7 @@ var TreeElement = (function () {
|
|
|
713
715
|
* null when the folder is not rendered or has no children.
|
|
714
716
|
*/
|
|
715
717
|
_renderChildren(node) {
|
|
716
|
-
return
|
|
718
|
+
return node.element && node.hasChildren() ? this._createDomElements(node.element, node.children, false, node.getLevel() + 1) : null;
|
|
717
719
|
}
|
|
718
720
|
_renderFromNode(node) {
|
|
719
721
|
if (!node.element) {
|
|
@@ -774,10 +776,10 @@ var TreeElement = (function () {
|
|
|
774
776
|
// li > div > [toggler], title span, [toggler]
|
|
775
777
|
let div = li.firstChild;
|
|
776
778
|
let titleSpan = div.childNodes[this._buttonLeft ? 1 : 0];
|
|
777
|
-
this.
|
|
779
|
+
this._fillNode(li, titleSpan, node.name, isSelected, level);
|
|
778
780
|
if (node.is_loading) {
|
|
779
781
|
li.classList.add(this._classNames.loading);
|
|
780
|
-
|
|
782
|
+
li.setAttribute("aria-busy", "true");
|
|
781
783
|
}
|
|
782
784
|
return li;
|
|
783
785
|
}
|
|
@@ -807,11 +809,10 @@ var TreeElement = (function () {
|
|
|
807
809
|
if (this._buttonLeft) {
|
|
808
810
|
div.append(toggler);
|
|
809
811
|
}
|
|
812
|
+
li.setAttribute("aria-expanded", getBoolString(isOpen));
|
|
810
813
|
|
|
811
814
|
// title span
|
|
812
|
-
|
|
813
|
-
titleSpan.setAttribute("aria-expanded", getBoolString(isOpen));
|
|
814
|
-
div.append(titleSpan);
|
|
815
|
+
div.append(this._createTitleSpanTemplate(true));
|
|
815
816
|
if (!this._buttonLeft) {
|
|
816
817
|
div.append(toggler);
|
|
817
818
|
}
|
|
@@ -835,11 +836,22 @@ var TreeElement = (function () {
|
|
|
835
836
|
|
|
836
837
|
/*
|
|
837
838
|
Create the outer part of a <li> template: li > div
|
|
839
|
+
The li is the treeitem, so the ul of its children is inside the treeitem.
|
|
838
840
|
*/
|
|
839
841
|
_createLiTemplate(liClasses) {
|
|
840
842
|
let li = document.createElement("li");
|
|
841
843
|
li.className = liClasses;
|
|
842
|
-
li.setAttribute("role", "
|
|
844
|
+
li.setAttribute("role", "treeitem");
|
|
845
|
+
|
|
846
|
+
// Only a multiselect tree marks the nodes that are not selected
|
|
847
|
+
if (this._multiSelect) {
|
|
848
|
+
li.setAttribute("aria-selected", "false");
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Every node is focusable, but only the tab stop is in the tab order
|
|
852
|
+
if (this._tabIndex !== undefined) {
|
|
853
|
+
li.setAttribute("tabindex", "-1");
|
|
854
|
+
}
|
|
843
855
|
let div = document.createElement("div");
|
|
844
856
|
div.className = `${this._classNames.element} ${this._classNames.common}`;
|
|
845
857
|
div.setAttribute("role", "none");
|
|
@@ -855,7 +867,7 @@ var TreeElement = (function () {
|
|
|
855
867
|
// li > div > title span
|
|
856
868
|
let div = li.firstChild;
|
|
857
869
|
let titleSpan = div.firstChild;
|
|
858
|
-
this.
|
|
870
|
+
this._fillNode(li, titleSpan, node.name, isSelected, level);
|
|
859
871
|
return li;
|
|
860
872
|
}
|
|
861
873
|
|
|
@@ -876,13 +888,6 @@ var TreeElement = (function () {
|
|
|
876
888
|
}
|
|
877
889
|
classes += ` ${this._buttonLeft ? this._classNames.titleButtonLeft : this._classNames.titleButtonRight}`;
|
|
878
890
|
titleSpan.className = classes;
|
|
879
|
-
titleSpan.setAttribute("role", "treeitem");
|
|
880
|
-
titleSpan.setAttribute("aria-selected", "false");
|
|
881
|
-
|
|
882
|
-
// Every node is focusable, but only the tab stop is in the tab order
|
|
883
|
-
if (this._tabIndex !== undefined) {
|
|
884
|
-
titleSpan.setAttribute("tabindex", "-1");
|
|
885
|
-
}
|
|
886
891
|
return titleSpan;
|
|
887
892
|
}
|
|
888
893
|
_createUlTemplate(isRootNode) {
|
|
@@ -911,20 +916,25 @@ var TreeElement = (function () {
|
|
|
911
916
|
if (this._ariaLabelledBy !== undefined) {
|
|
912
917
|
ul.setAttribute("aria-labelledby", this._ariaLabelledBy);
|
|
913
918
|
}
|
|
919
|
+
if (this._multiSelect) {
|
|
920
|
+
ul.setAttribute("aria-multiselectable", "true");
|
|
921
|
+
}
|
|
914
922
|
}
|
|
915
923
|
return ul;
|
|
916
924
|
}
|
|
917
925
|
|
|
918
926
|
/*
|
|
919
|
-
Set the parts of a cloned title span that differ per node
|
|
927
|
+
Set the parts of a cloned li and title span that differ per node
|
|
920
928
|
*/
|
|
921
|
-
|
|
922
|
-
|
|
929
|
+
_fillNode(li, titleSpan, nodeName, isSelected, level) {
|
|
930
|
+
li.setAttribute("aria-level", String(level));
|
|
923
931
|
if (isSelected) {
|
|
924
|
-
|
|
932
|
+
li.setAttribute("aria-selected", "true");
|
|
925
933
|
let tabIndex = this._tabIndex;
|
|
926
|
-
|
|
927
|
-
|
|
934
|
+
|
|
935
|
+
// With multiSelect the tab stop is the active node, see updateTabStop
|
|
936
|
+
if (tabIndex !== undefined && !this._multiSelect) {
|
|
937
|
+
li.setAttribute("tabindex", String(tabIndex));
|
|
928
938
|
}
|
|
929
939
|
}
|
|
930
940
|
if (this._autoEscape) {
|
|
@@ -933,6 +943,10 @@ var TreeElement = (function () {
|
|
|
933
943
|
// eslint-disable-next-line no-unsanitized/property -- the user opted out of escaping with autoEscape: false
|
|
934
944
|
titleSpan.innerHTML = nodeName;
|
|
935
945
|
}
|
|
946
|
+
|
|
947
|
+
// The treeitem is named by its title, without the html when autoEscape
|
|
948
|
+
// is false. Otherwise the name would contain everything in the row.
|
|
949
|
+
li.setAttribute("aria-label", titleSpan.textContent);
|
|
936
950
|
}
|
|
937
951
|
_getButtonClasses(isOpen) {
|
|
938
952
|
let classes = [this._classNames.toggler, this._classNames.common];
|
|
@@ -955,24 +969,37 @@ var TreeElement = (function () {
|
|
|
955
969
|
}
|
|
956
970
|
}
|
|
957
971
|
|
|
972
|
+
/* The keys move from the selected node and select the node they move to.
|
|
973
|
+
* With multiSelect they move from the focused node and only move the focus;
|
|
974
|
+
* Space adds the focused node to the selection or removes it.
|
|
975
|
+
*/
|
|
976
|
+
|
|
958
977
|
class KeyHandler {
|
|
959
978
|
constructor({
|
|
960
979
|
_closeNode: closeNode,
|
|
980
|
+
_focusNode: focusNode,
|
|
981
|
+
_getActiveNode: getActiveNode,
|
|
961
982
|
_getFocusedNode: getFocusedNode,
|
|
962
983
|
_getSelectedNode: getSelectedNode,
|
|
963
984
|
_getTree: getTree,
|
|
964
985
|
_keyboardSupport: keyboardSupport,
|
|
986
|
+
_multiSelect: multiSelect,
|
|
965
987
|
_openNode: openNode,
|
|
966
988
|
_selectNode: selectNode,
|
|
989
|
+
_toggleNodeInSelection: toggleNodeInSelection,
|
|
967
990
|
_triggerEvent: triggerEvent
|
|
968
991
|
}) {
|
|
969
992
|
this._closeNode = closeNode;
|
|
993
|
+
this._focusNode = focusNode;
|
|
994
|
+
this._getActiveNode = getActiveNode;
|
|
970
995
|
this._getFocusedNode = getFocusedNode;
|
|
971
996
|
this._getSelectedNode = getSelectedNode;
|
|
972
997
|
this._getTree = getTree;
|
|
973
998
|
this._keyboardSupport = keyboardSupport;
|
|
999
|
+
this._multiSelect = multiSelect;
|
|
974
1000
|
this._openNode = openNode;
|
|
975
1001
|
this._originalSelectNode = selectNode;
|
|
1002
|
+
this._toggleNodeInSelection = toggleNodeInSelection;
|
|
976
1003
|
this._triggerEvent = triggerEvent;
|
|
977
1004
|
if (keyboardSupport) {
|
|
978
1005
|
document.addEventListener("keydown", this._handleKeyDown);
|
|
@@ -984,10 +1011,10 @@ var TreeElement = (function () {
|
|
|
984
1011
|
}
|
|
985
1012
|
}
|
|
986
1013
|
_moveDown() {
|
|
987
|
-
return this.
|
|
1014
|
+
return this._goToNode(this._getCurrentNode()?.getNextVisibleNode());
|
|
988
1015
|
}
|
|
989
1016
|
_moveUp() {
|
|
990
|
-
return this.
|
|
1017
|
+
return this._goToNode(this._getCurrentNode()?.getPreviousVisibleNode());
|
|
991
1018
|
}
|
|
992
1019
|
|
|
993
1020
|
// Activate the node, for example to open its edit page.
|
|
@@ -998,6 +1025,26 @@ var TreeElement = (function () {
|
|
|
998
1025
|
});
|
|
999
1026
|
return true;
|
|
1000
1027
|
}
|
|
1028
|
+
|
|
1029
|
+
// No node is selected. These keys select the focused node, which is
|
|
1030
|
+
// usually the first node, see TreeElement.updateTabStop.
|
|
1031
|
+
_getCurrentNode() {
|
|
1032
|
+
return this._multiSelect ? this._getActiveNode() : this._getSelectedNode();
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Move to the node: select it, or with multiSelect focus it.
|
|
1036
|
+
// Result: there was a node to move to.
|
|
1037
|
+
_goToNode(node) {
|
|
1038
|
+
if (!node) {
|
|
1039
|
+
return false;
|
|
1040
|
+
}
|
|
1041
|
+
if (this._multiSelect) {
|
|
1042
|
+
this._focusNode(node);
|
|
1043
|
+
} else {
|
|
1044
|
+
this._originalSelectNode(node);
|
|
1045
|
+
}
|
|
1046
|
+
return true;
|
|
1047
|
+
}
|
|
1001
1048
|
_handleArrowKey(key) {
|
|
1002
1049
|
switch (key) {
|
|
1003
1050
|
case "ArrowDown":
|
|
@@ -1022,49 +1069,53 @@ var TreeElement = (function () {
|
|
|
1022
1069
|
}
|
|
1023
1070
|
}
|
|
1024
1071
|
}
|
|
1072
|
+
_handleKey(key, focusedNode) {
|
|
1073
|
+
return this._getCurrentNode() ? this._handleArrowKey(key) : this._handleKeyWithoutSelection(key, focusedNode);
|
|
1074
|
+
}
|
|
1025
1075
|
_handleKeyDown = e => {
|
|
1026
1076
|
let focusedNode = this._getFocusedNode();
|
|
1027
1077
|
if (!focusedNode) {
|
|
1028
1078
|
return;
|
|
1029
1079
|
}
|
|
1030
1080
|
let isKeyHandled;
|
|
1031
|
-
let selectedNode = this._getSelectedNode();
|
|
1032
1081
|
switch (e.key) {
|
|
1082
|
+
case " ":
|
|
1083
|
+
{
|
|
1084
|
+
isKeyHandled = this._multiSelect ? this._toggle(focusedNode) : this._handleKey(e.key, focusedNode);
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1033
1087
|
case "End":
|
|
1034
1088
|
{
|
|
1035
|
-
isKeyHandled = this.
|
|
1089
|
+
isKeyHandled = this._goToNode(this._getTree()?.getLastChild());
|
|
1036
1090
|
break;
|
|
1037
1091
|
}
|
|
1038
1092
|
case "Enter":
|
|
1039
1093
|
{
|
|
1040
1094
|
// Without a selected node, activate the focused node
|
|
1041
|
-
isKeyHandled = this._activate(
|
|
1095
|
+
isKeyHandled = this._activate(this._multiSelect ? focusedNode : this._getSelectedNode() ?? focusedNode, e);
|
|
1042
1096
|
break;
|
|
1043
1097
|
}
|
|
1044
1098
|
case "Home":
|
|
1045
1099
|
{
|
|
1046
|
-
isKeyHandled = this.
|
|
1100
|
+
isKeyHandled = this._goToNode(this._getTree()?.children[0]);
|
|
1047
1101
|
break;
|
|
1048
1102
|
}
|
|
1049
1103
|
default:
|
|
1050
1104
|
{
|
|
1051
|
-
isKeyHandled =
|
|
1105
|
+
isKeyHandled = this._handleKey(e.key, focusedNode);
|
|
1052
1106
|
}
|
|
1053
1107
|
}
|
|
1054
1108
|
if (isKeyHandled) {
|
|
1055
1109
|
e.preventDefault();
|
|
1056
1110
|
}
|
|
1057
1111
|
};
|
|
1058
|
-
|
|
1059
|
-
// No node is selected. These keys select the focused node, which is
|
|
1060
|
-
// usually the first node, see TreeElement.updateTabStop.
|
|
1061
1112
|
_handleKeyWithoutSelection(key, focusedNode) {
|
|
1062
1113
|
switch (key) {
|
|
1063
1114
|
case " ":
|
|
1064
1115
|
case "ArrowDown":
|
|
1065
1116
|
case "ArrowRight":
|
|
1066
1117
|
{
|
|
1067
|
-
return this.
|
|
1118
|
+
return this._goToNode(focusedNode);
|
|
1068
1119
|
}
|
|
1069
1120
|
default:
|
|
1070
1121
|
{
|
|
@@ -1073,45 +1124,37 @@ var TreeElement = (function () {
|
|
|
1073
1124
|
}
|
|
1074
1125
|
}
|
|
1075
1126
|
_moveLeft() {
|
|
1076
|
-
let
|
|
1127
|
+
let currentNode = this._getCurrentNode();
|
|
1077
1128
|
|
|
1078
1129
|
/* istanbul ignore if */
|
|
1079
|
-
if (!
|
|
1130
|
+
if (!currentNode) {
|
|
1080
1131
|
return false;
|
|
1081
1132
|
}
|
|
1082
|
-
if (
|
|
1133
|
+
if (currentNode.isFolder() && currentNode.is_open) {
|
|
1083
1134
|
// Left on an open node closes the node
|
|
1084
|
-
void this._closeNode(
|
|
1135
|
+
void this._closeNode(currentNode);
|
|
1085
1136
|
return true;
|
|
1086
1137
|
}
|
|
1087
1138
|
// Left on a closed or end node moves focus to the node's parent
|
|
1088
|
-
return this.
|
|
1139
|
+
return this._goToNode(currentNode.getParent());
|
|
1089
1140
|
}
|
|
1090
1141
|
_moveRight() {
|
|
1091
|
-
let
|
|
1092
|
-
if (
|
|
1142
|
+
let currentNode = this._getCurrentNode();
|
|
1143
|
+
if (currentNode?.isFolder()) {
|
|
1093
1144
|
// folder node
|
|
1094
|
-
if (
|
|
1145
|
+
if (currentNode.is_open) {
|
|
1095
1146
|
// Right moves to the first child of an open node
|
|
1096
|
-
return this.
|
|
1147
|
+
return this._goToNode(currentNode.getNextVisibleNode());
|
|
1097
1148
|
}
|
|
1098
1149
|
// Right expands a closed node
|
|
1099
|
-
void this._openNode(
|
|
1150
|
+
void this._openNode(currentNode);
|
|
1100
1151
|
return true;
|
|
1101
1152
|
}
|
|
1102
1153
|
return false;
|
|
1103
1154
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
* Result: a different node was selected.
|
|
1108
|
-
*/
|
|
1109
|
-
_selectNode(node) {
|
|
1110
|
-
if (node) {
|
|
1111
|
-
this._originalSelectNode(node);
|
|
1112
|
-
return true;
|
|
1113
|
-
}
|
|
1114
|
-
return false;
|
|
1155
|
+
_toggle(node) {
|
|
1156
|
+
this._toggleNodeInSelection(node);
|
|
1157
|
+
return true;
|
|
1115
1158
|
}
|
|
1116
1159
|
}
|
|
1117
1160
|
|
|
@@ -2217,12 +2260,14 @@ var TreeElement = (function () {
|
|
|
2217
2260
|
constructor({
|
|
2218
2261
|
_classNames: classNames,
|
|
2219
2262
|
_getScrollLeft: getScrollLeft,
|
|
2263
|
+
_multiSelect: multiSelect = false,
|
|
2220
2264
|
_node: node,
|
|
2221
2265
|
_tabIndex: tabIndex,
|
|
2222
2266
|
_treeElement: treeElement
|
|
2223
2267
|
}) {
|
|
2224
2268
|
this._classNames = classNames;
|
|
2225
2269
|
this._getScrollLeft = getScrollLeft;
|
|
2270
|
+
this._multiSelect = multiSelect;
|
|
2226
2271
|
this._node = node;
|
|
2227
2272
|
this._tabIndex = tabIndex;
|
|
2228
2273
|
this._treeElement = treeElement;
|
|
@@ -2238,35 +2283,36 @@ var TreeElement = (function () {
|
|
|
2238
2283
|
return;
|
|
2239
2284
|
}
|
|
2240
2285
|
this._element.classList.remove(this._classNames.selected);
|
|
2241
|
-
|
|
2286
|
+
|
|
2287
|
+
// Only a multiselect tree marks the nodes that are not selected
|
|
2288
|
+
if (this._multiSelect) {
|
|
2289
|
+
this._element.setAttribute("aria-selected", "false");
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
this._element.removeAttribute("aria-selected");
|
|
2242
2293
|
|
|
2243
2294
|
// Check for null or undefined
|
|
2244
2295
|
if (this._tabIndex != null) {
|
|
2245
|
-
|
|
2296
|
+
this._element.setAttribute("tabindex", "-1");
|
|
2246
2297
|
}
|
|
2247
|
-
|
|
2248
|
-
titleSpan.blur();
|
|
2298
|
+
this._element.blur();
|
|
2249
2299
|
}
|
|
2250
2300
|
_select(mustSetFocus) {
|
|
2251
2301
|
if (!this._isRendered()) {
|
|
2252
2302
|
return;
|
|
2253
2303
|
}
|
|
2254
2304
|
this._element.classList.add(this._classNames.selected);
|
|
2255
|
-
|
|
2305
|
+
this._element.setAttribute("aria-selected", "true");
|
|
2256
2306
|
let tabIndex = this._tabIndex;
|
|
2257
2307
|
|
|
2258
2308
|
// Check for null or undefined
|
|
2259
|
-
if (tabIndex != null) {
|
|
2260
|
-
|
|
2309
|
+
if (tabIndex != null && !this._multiSelect) {
|
|
2310
|
+
this._element.setAttribute("tabindex", tabIndex.toString());
|
|
2261
2311
|
}
|
|
2262
|
-
titleSpan.setAttribute("aria-selected", "true");
|
|
2263
2312
|
if (mustSetFocus) {
|
|
2264
|
-
|
|
2313
|
+
this._element.focus();
|
|
2265
2314
|
}
|
|
2266
2315
|
}
|
|
2267
|
-
_getTitleSpan() {
|
|
2268
|
-
return this._element.querySelector(`:scope > .${this._classNames.element} > span.${this._classNames.title}`);
|
|
2269
|
-
}
|
|
2270
2316
|
_getUl() {
|
|
2271
2317
|
return this._element.querySelector(":scope > ul");
|
|
2272
2318
|
}
|
|
@@ -2328,6 +2374,7 @@ var TreeElement = (function () {
|
|
|
2328
2374
|
_classNames: classNames,
|
|
2329
2375
|
_closedIconElement: closedIconElement,
|
|
2330
2376
|
_getScrollLeft: getScrollLeft,
|
|
2377
|
+
_multiSelect: multiSelect,
|
|
2331
2378
|
_node: node,
|
|
2332
2379
|
_openedIconElement: openedIconElement,
|
|
2333
2380
|
_renderChildren: renderChildren,
|
|
@@ -2338,6 +2385,7 @@ var TreeElement = (function () {
|
|
|
2338
2385
|
super({
|
|
2339
2386
|
_classNames: classNames,
|
|
2340
2387
|
_getScrollLeft: getScrollLeft,
|
|
2388
|
+
_multiSelect: multiSelect,
|
|
2341
2389
|
_node: node,
|
|
2342
2390
|
_tabIndex: tabIndex,
|
|
2343
2391
|
_treeElement: treeElement
|
|
@@ -2375,8 +2423,7 @@ var TreeElement = (function () {
|
|
|
2375
2423
|
}
|
|
2376
2424
|
}
|
|
2377
2425
|
this._element.classList.add(this._classNames.closed);
|
|
2378
|
-
|
|
2379
|
-
titleSpan.setAttribute("aria-expanded", "false");
|
|
2426
|
+
this._element.setAttribute("aria-expanded", "false");
|
|
2380
2427
|
this._triggerEvent("tree.close", {
|
|
2381
2428
|
node: this._node
|
|
2382
2429
|
});
|
|
@@ -2412,8 +2459,7 @@ var TreeElement = (function () {
|
|
|
2412
2459
|
}
|
|
2413
2460
|
}
|
|
2414
2461
|
this._element.classList.remove(this._classNames.closed);
|
|
2415
|
-
|
|
2416
|
-
titleSpan.setAttribute("aria-expanded", "true");
|
|
2462
|
+
this._element.setAttribute("aria-expanded", "true");
|
|
2417
2463
|
this._triggerEvent("tree.open", {
|
|
2418
2464
|
node: this._node
|
|
2419
2465
|
});
|
|
@@ -2921,9 +2967,9 @@ var TreeElement = (function () {
|
|
|
2921
2967
|
} else {
|
|
2922
2968
|
this._selectedNodes.delete(node.id);
|
|
2923
2969
|
if (includeChildren) {
|
|
2924
|
-
node.iterate(
|
|
2925
|
-
if (
|
|
2926
|
-
this._selectedNodes.delete(
|
|
2970
|
+
node.iterate(child => {
|
|
2971
|
+
if (child.id != null) {
|
|
2972
|
+
this._selectedNodes.delete(child.id);
|
|
2927
2973
|
}
|
|
2928
2974
|
return true;
|
|
2929
2975
|
});
|
|
@@ -2942,6 +2988,9 @@ var TreeElement = (function () {
|
|
|
2942
2988
|
* mustToggle: support deselecting the selected node
|
|
2943
2989
|
*/
|
|
2944
2990
|
_selectSingleNode(node, optionsParam) {
|
|
2991
|
+
if (!this._canSelect(node)) {
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2945
2994
|
let defaultOptions = {
|
|
2946
2995
|
mustSetFocus: true,
|
|
2947
2996
|
mustToggle: true
|
|
@@ -2950,31 +2999,23 @@ var TreeElement = (function () {
|
|
|
2950
2999
|
...defaultOptions,
|
|
2951
3000
|
...optionsParam
|
|
2952
3001
|
};
|
|
2953
|
-
let
|
|
2954
|
-
if (!this._getSelectable()) {
|
|
2955
|
-
return false;
|
|
2956
|
-
}
|
|
2957
|
-
let onCanSelectNode = this._getOnCanSelectNode();
|
|
2958
|
-
return onCanSelectNode ? onCanSelectNode(node) : true;
|
|
2959
|
-
};
|
|
2960
|
-
if (!canSelect()) {
|
|
2961
|
-
return;
|
|
2962
|
-
}
|
|
2963
|
-
let deselectCurrentNode = deselectedNode => {
|
|
2964
|
-
this._removeFromSelection(deselectedNode);
|
|
2965
|
-
this._getNodeElementForNode(deselectedNode)._deselect();
|
|
2966
|
-
};
|
|
3002
|
+
let otherSelectedNodes = this._getSelectedNodes().filter(selectedNode => selectedNode !== node);
|
|
2967
3003
|
if (this._isNodeSelected(node)) {
|
|
2968
|
-
if (
|
|
2969
|
-
|
|
3004
|
+
if (otherSelectedNodes.length) {
|
|
3005
|
+
// Part of a multiple selection: keep only this node selected
|
|
3006
|
+
for (let otherNode of otherSelectedNodes) {
|
|
3007
|
+
this._deselectNode(otherNode);
|
|
3008
|
+
}
|
|
3009
|
+
} else if (selectOptions.mustToggle) {
|
|
3010
|
+
this._deselectNode(node);
|
|
2970
3011
|
this._triggerEvent("tree.deselect", {
|
|
2971
3012
|
node
|
|
2972
3013
|
});
|
|
2973
3014
|
}
|
|
2974
3015
|
} else {
|
|
2975
|
-
let deselectedNode =
|
|
2976
|
-
|
|
2977
|
-
|
|
3016
|
+
let deselectedNode = otherSelectedNodes[0] ?? null;
|
|
3017
|
+
for (let otherNode of otherSelectedNodes) {
|
|
3018
|
+
this._deselectNode(otherNode);
|
|
2978
3019
|
}
|
|
2979
3020
|
this._addToSelection(node);
|
|
2980
3021
|
this._openParents(node);
|
|
@@ -2987,6 +3028,43 @@ var TreeElement = (function () {
|
|
|
2987
3028
|
this._updateTabStop();
|
|
2988
3029
|
this._saveState();
|
|
2989
3030
|
}
|
|
3031
|
+
|
|
3032
|
+
/* Add a node to the selection, or remove it when it is selected, without
|
|
3033
|
+
* changing the other selected nodes.
|
|
3034
|
+
* Checks if the node is selectable and saves the state.
|
|
3035
|
+
*/
|
|
3036
|
+
_toggleNodeInSelection(node, mustSetFocus = true) {
|
|
3037
|
+
if (!this._canSelect(node)) {
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3040
|
+
if (this._isNodeSelected(node)) {
|
|
3041
|
+
this._deselectNode(node);
|
|
3042
|
+
this._triggerEvent("tree.deselect", {
|
|
3043
|
+
node
|
|
3044
|
+
});
|
|
3045
|
+
} else {
|
|
3046
|
+
this._addToSelection(node);
|
|
3047
|
+
this._openParents(node);
|
|
3048
|
+
this._getNodeElementForNode(node)._select(mustSetFocus);
|
|
3049
|
+
this._triggerEvent("tree.select", {
|
|
3050
|
+
deselectedNode: null,
|
|
3051
|
+
node
|
|
3052
|
+
});
|
|
3053
|
+
}
|
|
3054
|
+
this._updateTabStop();
|
|
3055
|
+
this._saveState();
|
|
3056
|
+
}
|
|
3057
|
+
_canSelect(node) {
|
|
3058
|
+
if (!this._getSelectable()) {
|
|
3059
|
+
return false;
|
|
3060
|
+
}
|
|
3061
|
+
let onCanSelectNode = this._getOnCanSelectNode();
|
|
3062
|
+
return onCanSelectNode ? onCanSelectNode(node) : true;
|
|
3063
|
+
}
|
|
3064
|
+
_deselectNode(node) {
|
|
3065
|
+
this._removeFromSelection(node);
|
|
3066
|
+
this._getNodeElementForNode(node)._deselect();
|
|
3067
|
+
}
|
|
2990
3068
|
}
|
|
2991
3069
|
|
|
2992
3070
|
/* The default icons are svg instead of text: the triangle characters come
|
|
@@ -2994,10 +3072,10 @@ var TreeElement = (function () {
|
|
|
2994
3072
|
* They are sized in em to follow the font size, and use currentColor to follow
|
|
2995
3073
|
* --tree-element-toggler-color.
|
|
2996
3074
|
*/
|
|
2997
|
-
let triangle = points => `<svg width="0.
|
|
2998
|
-
let triangleDown = triangle("0.5,
|
|
2999
|
-
let triangleLeft = triangle("9,0.5 9,9.5
|
|
3000
|
-
let triangleRight = triangle("
|
|
3075
|
+
let triangle = points => `<svg width="0.8em" height="0.8em" viewBox="0 0 10 10" focusable="false"><polygon points="${points}" fill="currentColor"/></svg>`;
|
|
3076
|
+
let triangleDown = triangle("0.5,0.5 9.5,0.5 5,9.5");
|
|
3077
|
+
let triangleLeft = triangle("9.5,0.5 9.5,9.5 0.5,5");
|
|
3078
|
+
let triangleRight = triangle("0.5,0.5 0.5,9.5 9.5,5");
|
|
3001
3079
|
let defaults = {
|
|
3002
3080
|
animationSpeed: "fast",
|
|
3003
3081
|
autoEscape: true,
|
|
@@ -3013,6 +3091,7 @@ var TreeElement = (function () {
|
|
|
3013
3091
|
// dataUrl: undefined,
|
|
3014
3092
|
dragAndDrop: false,
|
|
3015
3093
|
keyboardSupport: true,
|
|
3094
|
+
multiSelect: false,
|
|
3016
3095
|
nodeClass: Node,
|
|
3017
3096
|
// onCanMove: undefined, // Can this node be moved?
|
|
3018
3097
|
// onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)
|
|
@@ -3078,7 +3157,7 @@ var TreeElement = (function () {
|
|
|
3078
3157
|
};
|
|
3079
3158
|
|
|
3080
3159
|
// Generated by config/generateVersion.mjs. Do not edit.
|
|
3081
|
-
let version = "0.
|
|
3160
|
+
let version = "0.4.0";
|
|
3082
3161
|
|
|
3083
3162
|
// The types that appear in the public api. Consumers cannot import them from
|
|
3084
3163
|
// the submodules directly, because those are not exposed in package.json.
|
|
@@ -3086,6 +3165,8 @@ var TreeElement = (function () {
|
|
|
3086
3165
|
// as its global, instead of an object of named exports.
|
|
3087
3166
|
|
|
3088
3167
|
class TreeElement {
|
|
3168
|
+
// With multiSelect: the node that is the tab stop, see updateTabStop
|
|
3169
|
+
_activeNode;
|
|
3089
3170
|
_classNames;
|
|
3090
3171
|
_dataLoader;
|
|
3091
3172
|
_dndHandler;
|
|
@@ -3119,6 +3200,7 @@ var TreeElement = (function () {
|
|
|
3119
3200
|
this._tree = new Node({}, true);
|
|
3120
3201
|
this._nodeMap = new WeakMap();
|
|
3121
3202
|
this._fallbackTabStop = null;
|
|
3203
|
+
this._activeNode = null;
|
|
3122
3204
|
let {
|
|
3123
3205
|
ariaLabel,
|
|
3124
3206
|
ariaLabelledBy,
|
|
@@ -3128,6 +3210,7 @@ var TreeElement = (function () {
|
|
|
3128
3210
|
dataFilter,
|
|
3129
3211
|
dragAndDrop,
|
|
3130
3212
|
keyboardSupport,
|
|
3213
|
+
multiSelect,
|
|
3131
3214
|
onCanMove,
|
|
3132
3215
|
onCanMoveTo,
|
|
3133
3216
|
onCreateLi,
|
|
@@ -3179,6 +3262,17 @@ var TreeElement = (function () {
|
|
|
3179
3262
|
let isNodeSelected = selectNodeHandler._isNodeSelected.bind(selectNodeHandler);
|
|
3180
3263
|
let removeFromSelection = selectNodeHandler._removeFromSelection.bind(selectNodeHandler);
|
|
3181
3264
|
let selectNode = selectNodeHandler._selectSingleNode.bind(selectNodeHandler);
|
|
3265
|
+
let toggleNodeInSelection = selectNodeHandler._toggleNodeInSelection.bind(selectNodeHandler);
|
|
3266
|
+
|
|
3267
|
+
// With multiSelect, a click adds a node to the selection or removes it
|
|
3268
|
+
let onClickTitle = node => {
|
|
3269
|
+
if (this._options.multiSelect) {
|
|
3270
|
+
toggleNodeInSelection(node, false);
|
|
3271
|
+
this._focusNode(node);
|
|
3272
|
+
} else {
|
|
3273
|
+
selectNode(node);
|
|
3274
|
+
}
|
|
3275
|
+
};
|
|
3182
3276
|
let getMouseDelay = () => this._options.startDndDelay ?? 0;
|
|
3183
3277
|
let dataLoader = new DataLoader({
|
|
3184
3278
|
_classNames: classNames,
|
|
@@ -3225,12 +3319,16 @@ var TreeElement = (function () {
|
|
|
3225
3319
|
});
|
|
3226
3320
|
let keyHandler = new KeyHandler({
|
|
3227
3321
|
_closeNode: closeNode,
|
|
3322
|
+
_focusNode: this._focusNode.bind(this),
|
|
3323
|
+
_getActiveNode: this._getActiveNode.bind(this),
|
|
3228
3324
|
_getFocusedNode: getFocusedNode,
|
|
3229
3325
|
_getSelectedNode: getSelectedNode,
|
|
3230
3326
|
_getTree: getTree,
|
|
3231
3327
|
_keyboardSupport: keyboardSupport,
|
|
3328
|
+
_multiSelect: multiSelect,
|
|
3232
3329
|
_openNode: openNode,
|
|
3233
3330
|
_selectNode: selectNode,
|
|
3331
|
+
_toggleNodeInSelection: toggleNodeInSelection,
|
|
3234
3332
|
_triggerEvent: triggerEvent
|
|
3235
3333
|
});
|
|
3236
3334
|
let renderer = new ElementsRenderer({
|
|
@@ -3244,6 +3342,7 @@ var TreeElement = (function () {
|
|
|
3244
3342
|
_getTree: getTree,
|
|
3245
3343
|
_htmlElement: treeElement,
|
|
3246
3344
|
_isNodeSelected: isNodeSelected,
|
|
3345
|
+
_multiSelect: multiSelect,
|
|
3247
3346
|
_onCreateLi: onCreateLi,
|
|
3248
3347
|
_openedIcon: openedIcon,
|
|
3249
3348
|
_rtl: rtl,
|
|
@@ -3262,7 +3361,7 @@ var TreeElement = (function () {
|
|
|
3262
3361
|
_getMouseDelay: getMouseDelay,
|
|
3263
3362
|
_getNode: getNode,
|
|
3264
3363
|
_onClickButton: this.toggle.bind(this),
|
|
3265
|
-
_onClickTitle:
|
|
3364
|
+
_onClickTitle: onClickTitle,
|
|
3266
3365
|
_onMouseCapture: onMouseCapture,
|
|
3267
3366
|
_onMouseDrag: onMouseDrag,
|
|
3268
3367
|
_onMouseStart: onMouseStart,
|
|
@@ -3278,6 +3377,9 @@ var TreeElement = (function () {
|
|
|
3278
3377
|
this._saveStateHandler = saveStateHandler;
|
|
3279
3378
|
this._scrollHandler = scrollHandler;
|
|
3280
3379
|
this._selectNodeHandler = selectNodeHandler;
|
|
3380
|
+
if (multiSelect) {
|
|
3381
|
+
treeElement.addEventListener("focusin", this._handleFocusIn);
|
|
3382
|
+
}
|
|
3281
3383
|
this._initData();
|
|
3282
3384
|
}
|
|
3283
3385
|
|
|
@@ -3387,6 +3489,7 @@ var TreeElement = (function () {
|
|
|
3387
3489
|
this._dataLoader._deinit();
|
|
3388
3490
|
this._keyHandler._deinit();
|
|
3389
3491
|
this._mouseHandler._deinit();
|
|
3492
|
+
this._htmlElement.removeEventListener("focusin", this._handleFocusIn);
|
|
3390
3493
|
this._tree = new Node({}, true);
|
|
3391
3494
|
}
|
|
3392
3495
|
|
|
@@ -3574,7 +3677,8 @@ var TreeElement = (function () {
|
|
|
3574
3677
|
}
|
|
3575
3678
|
|
|
3576
3679
|
/**
|
|
3577
|
-
* Selects the next visible node, like the down arrow key.
|
|
3680
|
+
* Selects the next visible node, like the down arrow key. With
|
|
3681
|
+
* `multiSelect` it moves the focus instead.
|
|
3578
3682
|
*
|
|
3579
3683
|
* @group Selection
|
|
3580
3684
|
*/
|
|
@@ -3599,7 +3703,8 @@ var TreeElement = (function () {
|
|
|
3599
3703
|
}
|
|
3600
3704
|
|
|
3601
3705
|
/**
|
|
3602
|
-
* Selects the previous visible node, like the up arrow key.
|
|
3706
|
+
* Selects the previous visible node, like the up arrow key. With
|
|
3707
|
+
* `multiSelect` it moves the focus instead.
|
|
3603
3708
|
*
|
|
3604
3709
|
* @group Selection
|
|
3605
3710
|
*/
|
|
@@ -3729,8 +3834,8 @@ var TreeElement = (function () {
|
|
|
3729
3834
|
*/
|
|
3730
3835
|
selectNode(node, options) {
|
|
3731
3836
|
if (!node) {
|
|
3732
|
-
// Called with empty node -> deselect
|
|
3733
|
-
this.
|
|
3837
|
+
// Called with empty node -> deselect all nodes
|
|
3838
|
+
this._deselectAllNodes();
|
|
3734
3839
|
this._saveStateHandler._saveState();
|
|
3735
3840
|
return;
|
|
3736
3841
|
}
|
|
@@ -3866,6 +3971,7 @@ var TreeElement = (function () {
|
|
|
3866
3971
|
_classNames: classNames,
|
|
3867
3972
|
_closedIconElement: closedIconElement,
|
|
3868
3973
|
_getScrollLeft: getScrollLeft,
|
|
3974
|
+
_multiSelect: this._options.multiSelect,
|
|
3869
3975
|
_node: node,
|
|
3870
3976
|
_openedIconElement: openedIconElement,
|
|
3871
3977
|
_renderChildren: renderChildren,
|
|
@@ -3882,6 +3988,7 @@ var TreeElement = (function () {
|
|
|
3882
3988
|
return new NodeElement({
|
|
3883
3989
|
_classNames: classNames,
|
|
3884
3990
|
_getScrollLeft: getScrollLeft,
|
|
3991
|
+
_multiSelect: this._options.multiSelect,
|
|
3885
3992
|
_node: node,
|
|
3886
3993
|
_tabIndex: tabIndex,
|
|
3887
3994
|
_treeElement: treeElement
|
|
@@ -3911,9 +4018,8 @@ var TreeElement = (function () {
|
|
|
3911
4018
|
}
|
|
3912
4019
|
return requestUrl;
|
|
3913
4020
|
}
|
|
3914
|
-
|
|
3915
|
-
let node
|
|
3916
|
-
if (node) {
|
|
4021
|
+
_deselectAllNodes() {
|
|
4022
|
+
for (let node of this.getSelectedNodes()) {
|
|
3917
4023
|
this.removeFromSelection(node);
|
|
3918
4024
|
}
|
|
3919
4025
|
}
|
|
@@ -3926,6 +4032,20 @@ var TreeElement = (function () {
|
|
|
3926
4032
|
}
|
|
3927
4033
|
}
|
|
3928
4034
|
|
|
4035
|
+
// The treeitem of the first node, or null when the tree is empty
|
|
4036
|
+
// Move the focus to a node, without selecting it
|
|
4037
|
+
_focusNode(node) {
|
|
4038
|
+
this._activeNode = node;
|
|
4039
|
+
this._updateTabStop();
|
|
4040
|
+
node.element?.focus();
|
|
4041
|
+
}
|
|
4042
|
+
|
|
4043
|
+
// With multiSelect: the active node, if it is still rendered in the tree
|
|
4044
|
+
_getActiveNode() {
|
|
4045
|
+
let element = this._activeNode?.element;
|
|
4046
|
+
return element && this._htmlElement.contains(element) ? this._activeNode : null;
|
|
4047
|
+
}
|
|
4048
|
+
|
|
3929
4049
|
// Get the maximum level for auto open
|
|
3930
4050
|
_getAutoOpenMaxLevel() {
|
|
3931
4051
|
if (this._options.autoOpen === true) {
|
|
@@ -3941,11 +4061,8 @@ var TreeElement = (function () {
|
|
|
3941
4061
|
/* istanbul ignore next @preserve */
|
|
3942
4062
|
return 0;
|
|
3943
4063
|
}
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
_getFirstTitleSpan() {
|
|
3947
|
-
let firstElement = this._tree.children[0]?.element;
|
|
3948
|
-
return firstElement ? firstElement.querySelector(`:scope > .${this._classNames.element} > span.${this._classNames.title}`) : null;
|
|
4064
|
+
_getFirstTreeItem() {
|
|
4065
|
+
return this._tree.children[0]?.element ?? null;
|
|
3949
4066
|
}
|
|
3950
4067
|
|
|
3951
4068
|
// The node of the HTML element that has the focus, if it is in this tree
|
|
@@ -3959,7 +4076,7 @@ var TreeElement = (function () {
|
|
|
3959
4076
|
|
|
3960
4077
|
// The keyboard must still work for input elements.
|
|
3961
4078
|
let tagName = activeElement.tagName;
|
|
3962
|
-
if (tagName !== "A" && tagName !== "SPAN") {
|
|
4079
|
+
if (tagName !== "A" && tagName !== "LI" && tagName !== "SPAN") {
|
|
3963
4080
|
return null;
|
|
3964
4081
|
}
|
|
3965
4082
|
let node = this.getNode(activeElement);
|
|
@@ -3975,6 +4092,16 @@ var TreeElement = (function () {
|
|
|
3975
4092
|
_getNodeIdToBeSelected() {
|
|
3976
4093
|
return this._saveStateHandler._getNodeIdToBeSelected();
|
|
3977
4094
|
}
|
|
4095
|
+
|
|
4096
|
+
// With multiSelect, the focused node becomes the tab stop
|
|
4097
|
+
_handleFocusIn = () => {
|
|
4098
|
+
let node = this._getFocusedNode();
|
|
4099
|
+
if (!node || node === this._activeNode) {
|
|
4100
|
+
return;
|
|
4101
|
+
}
|
|
4102
|
+
this._activeNode = node;
|
|
4103
|
+
this._updateTabStop();
|
|
4104
|
+
};
|
|
3978
4105
|
_hasRenderedSelectedNode() {
|
|
3979
4106
|
return this.getSelectedNodes().some(node => Boolean(node.element));
|
|
3980
4107
|
}
|
|
@@ -4051,7 +4178,6 @@ var TreeElement = (function () {
|
|
|
4051
4178
|
}
|
|
4052
4179
|
_mouseStart(positionInfo) {
|
|
4053
4180
|
/* istanbul ignore if */
|
|
4054
|
-
// eslint-disable-next-line unicorn/prefer-ternary
|
|
4055
4181
|
if (!this._options.dragAndDrop) {
|
|
4056
4182
|
return false;
|
|
4057
4183
|
}
|
|
@@ -4161,12 +4287,22 @@ var TreeElement = (function () {
|
|
|
4161
4287
|
/* Keyboard users reach the tree through the tab stop. The selected node is
|
|
4162
4288
|
* the tab stop, see NodeElement.select. Without a selected node, the first
|
|
4163
4289
|
* node is the tab stop, so the tree can always be reached.
|
|
4290
|
+
* With multiSelect the tab stop is the active node: the node that was
|
|
4291
|
+
* focused last. Without one, it is the first node.
|
|
4164
4292
|
*/
|
|
4165
4293
|
_updateTabStop() {
|
|
4166
4294
|
let tabIndex = this._options.tabIndex;
|
|
4295
|
+
let multiSelect = this._options.multiSelect;
|
|
4167
4296
|
let previousTabStop = this._fallbackTabStop;
|
|
4168
|
-
let tabStop
|
|
4169
|
-
if (
|
|
4297
|
+
let tabStop;
|
|
4298
|
+
if (tabIndex == null) {
|
|
4299
|
+
tabStop = null;
|
|
4300
|
+
} else if (multiSelect) {
|
|
4301
|
+
tabStop = this._getActiveNode()?.element ?? this._getFirstTreeItem();
|
|
4302
|
+
} else {
|
|
4303
|
+
tabStop = this._hasRenderedSelectedNode() ? null : this._getFirstTreeItem();
|
|
4304
|
+
}
|
|
4305
|
+
if (previousTabStop && previousTabStop !== tabStop && (multiSelect || previousTabStop.getAttribute("aria-selected") !== "true")) {
|
|
4170
4306
|
previousTabStop.setAttribute("tabindex", "-1");
|
|
4171
4307
|
}
|
|
4172
4308
|
if (tabStop && tabIndex != null) {
|