tree-element 0.1.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/LICENSE +201 -0
- package/README.md +221 -0
- package/lib/animation.d.ts +5 -0
- package/lib/animation.d.ts.map +1 -0
- package/lib/animation.js +39 -0
- package/lib/animation.js.map +1 -0
- package/lib/classNames.d.ts +34 -0
- package/lib/classNames.d.ts.map +1 -0
- package/lib/classNames.js +39 -0
- package/lib/classNames.js.map +1 -0
- package/lib/dataLoader.d.ts +25 -0
- package/lib/dataLoader.d.ts.map +1 -0
- package/lib/dataLoader.js +69 -0
- package/lib/dataLoader.js.map +1 -0
- package/lib/dragAndDropHandler/binarySearch.d.ts +3 -0
- package/lib/dragAndDropHandler/binarySearch.d.ts.map +1 -0
- package/lib/dragAndDropHandler/binarySearch.js +23 -0
- package/lib/dragAndDropHandler/binarySearch.js.map +1 -0
- package/lib/dragAndDropHandler/dragElement.d.ts +20 -0
- package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -0
- package/lib/dragAndDropHandler/dragElement.js +39 -0
- package/lib/dragAndDropHandler/dragElement.js.map +1 -0
- package/lib/dragAndDropHandler/generateHitAreas.d.ts +13 -0
- package/lib/dragAndDropHandler/generateHitAreas.d.ts.map +1 -0
- package/lib/dragAndDropHandler/generateHitAreas.js +130 -0
- package/lib/dragAndDropHandler/generateHitAreas.js.map +1 -0
- package/lib/dragAndDropHandler/index.d.ts +76 -0
- package/lib/dragAndDropHandler/index.d.ts.map +1 -0
- package/lib/dragAndDropHandler/index.js +311 -0
- package/lib/dragAndDropHandler/index.js.map +1 -0
- package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts +11 -0
- package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -0
- package/lib/dragAndDropHandler/iterateVisibleNodes.js +54 -0
- package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -0
- package/lib/dragAndDropHandler/types.d.ts +11 -0
- package/lib/dragAndDropHandler/types.d.ts.map +1 -0
- package/lib/elementsRenderer.d.ts +53 -0
- package/lib/elementsRenderer.d.ts.map +1 -0
- package/lib/elementsRenderer.js +251 -0
- package/lib/elementsRenderer.js.map +1 -0
- package/lib/events.d.ts +224 -0
- package/lib/events.d.ts.map +1 -0
- package/lib/index.d.ts +367 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1098 -0
- package/lib/index.js.map +1 -0
- package/lib/keyHandler.d.ts +29 -0
- package/lib/keyHandler.d.ts.map +1 -0
- package/lib/keyHandler.js +107 -0
- package/lib/keyHandler.js.map +1 -0
- package/lib/methodTypes.d.ts +21 -0
- package/lib/methodTypes.d.ts.map +1 -0
- package/lib/mouseHandler.d.ts +60 -0
- package/lib/mouseHandler.d.ts.map +1 -0
- package/lib/mouseHandler.js +283 -0
- package/lib/mouseHandler.js.map +1 -0
- package/lib/mouseUtils.d.ts +9 -0
- package/lib/mouseUtils.d.ts.map +1 -0
- package/lib/mouseUtils.js +15 -0
- package/lib/mouseUtils.js.map +1 -0
- package/lib/node.d.ts +320 -0
- package/lib/node.d.ts.map +1 -0
- package/lib/node.js +737 -0
- package/lib/node.js.map +1 -0
- package/lib/nodeElement/borderDropHint.d.ts +9 -0
- package/lib/nodeElement/borderDropHint.d.ts.map +1 -0
- package/lib/nodeElement/borderDropHint.js +24 -0
- package/lib/nodeElement/borderDropHint.js.map +1 -0
- package/lib/nodeElement/folderElement.d.ts +22 -0
- package/lib/nodeElement/folderElement.d.ts.map +1 -0
- package/lib/nodeElement/folderElement.js +100 -0
- package/lib/nodeElement/folderElement.js.map +1 -0
- package/lib/nodeElement/ghostDropHint.d.ts +18 -0
- package/lib/nodeElement/ghostDropHint.d.ts.map +1 -0
- package/lib/nodeElement/ghostDropHint.js +67 -0
- package/lib/nodeElement/ghostDropHint.js.map +1 -0
- package/lib/nodeElement/index.d.ts +28 -0
- package/lib/nodeElement/index.d.ts.map +1 -0
- package/lib/nodeElement/index.js +66 -0
- package/lib/nodeElement/index.js.map +1 -0
- package/lib/nodeUtils.d.ts +7 -0
- package/lib/nodeUtils.d.ts.map +1 -0
- package/lib/nodeUtils.js +4 -0
- package/lib/nodeUtils.js.map +1 -0
- package/lib/options.d.ts +310 -0
- package/lib/options.d.ts.map +1 -0
- package/lib/package.json +3 -0
- package/lib/positionUtils.d.ts +8 -0
- package/lib/positionUtils.d.ts.map +1 -0
- package/lib/positionUtils.js +14 -0
- package/lib/positionUtils.js.map +1 -0
- package/lib/requestUrl.d.ts +9 -0
- package/lib/requestUrl.d.ts.map +1 -0
- package/lib/requestUrl.js +37 -0
- package/lib/requestUrl.js.map +1 -0
- package/lib/saveStateHandler.d.ts +46 -0
- package/lib/saveStateHandler.d.ts.map +1 -0
- package/lib/saveStateHandler.js +204 -0
- package/lib/saveStateHandler.js.map +1 -0
- package/lib/scrollHandler/containerScrollParent.d.ts +12 -0
- package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -0
- package/lib/scrollHandler/containerScrollParent.js +49 -0
- package/lib/scrollHandler/containerScrollParent.js.map +1 -0
- package/lib/scrollHandler/createScrollParent.d.ts +4 -0
- package/lib/scrollHandler/createScrollParent.d.ts.map +1 -0
- package/lib/scrollHandler/createScrollParent.js +38 -0
- package/lib/scrollHandler/createScrollParent.js.map +1 -0
- package/lib/scrollHandler/documentScrollParent.d.ts +22 -0
- package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -0
- package/lib/scrollHandler/documentScrollParent.js +71 -0
- package/lib/scrollHandler/documentScrollParent.js.map +1 -0
- package/lib/scrollHandler/scrollParent.d.ts +26 -0
- package/lib/scrollHandler/scrollParent.d.ts.map +1 -0
- package/lib/scrollHandler/scrollParent.js +79 -0
- package/lib/scrollHandler/scrollParent.js.map +1 -0
- package/lib/scrollHandler.d.ts +20 -0
- package/lib/scrollHandler.d.ts.map +1 -0
- package/lib/scrollHandler.js +41 -0
- package/lib/scrollHandler.js.map +1 -0
- package/lib/selectNodeHandler.d.ts +38 -0
- package/lib/selectNodeHandler.d.ts.map +1 -0
- package/lib/selectNodeHandler.js +166 -0
- package/lib/selectNodeHandler.js.map +1 -0
- package/lib/setDefaultOptions.d.ts +4 -0
- package/lib/setDefaultOptions.d.ts.map +1 -0
- package/lib/setDefaultOptions.js +86 -0
- package/lib/setDefaultOptions.js.map +1 -0
- package/lib/triggerCustomEvent.d.ts +3 -0
- package/lib/triggerCustomEvent.d.ts.map +1 -0
- package/lib/triggerCustomEvent.js +13 -0
- package/lib/triggerCustomEvent.js.map +1 -0
- package/lib/util.d.ts +3 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +5 -0
- package/lib/util.js.map +1 -0
- package/lib/version.d.ts +3 -0
- package/lib/version.d.ts.map +1 -0
- package/lib/version.js +5 -0
- package/lib/version.js.map +1 -0
- package/package.json +110 -0
- package/src/animation.ts +48 -0
- package/src/classNames.ts +70 -0
- package/src/dataLoader.ts +92 -0
- package/src/dragAndDropHandler/binarySearch.ts +27 -0
- package/src/dragAndDropHandler/dragElement.ts +62 -0
- package/src/dragAndDropHandler/generateHitAreas.ts +195 -0
- package/src/dragAndDropHandler/index.ts +442 -0
- package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
- package/src/dragAndDropHandler/types.ts +12 -0
- package/src/elementsRenderer.ts +367 -0
- package/src/events.ts +237 -0
- package/src/header.txt +16 -0
- package/src/index.ts +1290 -0
- package/src/keyHandler.ts +139 -0
- package/src/methodTypes.ts +44 -0
- package/src/mouseHandler.ts +391 -0
- package/src/mouseUtils.ts +23 -0
- package/src/node.ts +831 -0
- package/src/nodeElement/borderDropHint.ts +37 -0
- package/src/nodeElement/folderElement.ts +140 -0
- package/src/nodeElement/ghostDropHint.ts +84 -0
- package/src/nodeElement/index.ts +103 -0
- package/src/nodeUtils.ts +12 -0
- package/src/options.ts +325 -0
- package/src/positionUtils.ts +18 -0
- package/src/requestUrl.ts +41 -0
- package/src/saveStateHandler.ts +279 -0
- package/src/scrollHandler/containerScrollParent.ts +71 -0
- package/src/scrollHandler/createScrollParent.ts +51 -0
- package/src/scrollHandler/documentScrollParent.ts +104 -0
- package/src/scrollHandler/scrollParent.ts +117 -0
- package/src/scrollHandler.ts +55 -0
- package/src/selectNodeHandler.ts +192 -0
- package/src/setDefaultOptions.ts +79 -0
- package/src/triggerCustomEvent.ts +14 -0
- package/src/util.ts +5 -0
- package/src/version.ts +4 -0
- package/tree_element.css +195 -0
- package/tree_element.debug.js +4153 -0
- package/tree_element.debug.js.map +1 -0
- package/tree_element.js +21 -0
- package/tree_element.js.map +1 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import type { ClassNames } from "./classNames";
|
|
2
|
+
import type { GetTree, IsNodeSelected } from "./methodTypes";
|
|
3
|
+
import type { Node } from "./node";
|
|
4
|
+
import type { IconElement, OnCreateLi } from "./options";
|
|
5
|
+
|
|
6
|
+
import { getBoolString } from "./util";
|
|
7
|
+
|
|
8
|
+
interface ElementsRendererParams {
|
|
9
|
+
autoEscape: boolean;
|
|
10
|
+
buttonLeft: boolean;
|
|
11
|
+
classNames: ClassNames;
|
|
12
|
+
closedIcon?: IconElement;
|
|
13
|
+
dragAndDrop: boolean;
|
|
14
|
+
getTree: GetTree;
|
|
15
|
+
htmlElement: HTMLElement;
|
|
16
|
+
isNodeSelected: IsNodeSelected;
|
|
17
|
+
onCreateLi?: OnCreateLi;
|
|
18
|
+
openedIcon?: IconElement;
|
|
19
|
+
rtl?: boolean;
|
|
20
|
+
setNodeElement: (element: HTMLElement, node: Node) => void;
|
|
21
|
+
showEmptyFolder: boolean;
|
|
22
|
+
tabIndex?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default class ElementsRenderer {
|
|
26
|
+
public closedIconElement?: HTMLElement | Text;
|
|
27
|
+
public openedIconElement?: HTMLElement | Text;
|
|
28
|
+
private autoEscape: boolean;
|
|
29
|
+
private buttonLeft: boolean;
|
|
30
|
+
private classNames: ClassNames;
|
|
31
|
+
private dragAndDrop: boolean;
|
|
32
|
+
private getTree: GetTree;
|
|
33
|
+
private htmlElement: HTMLElement;
|
|
34
|
+
private isNodeSelected: IsNodeSelected;
|
|
35
|
+
private onCreateLi?: OnCreateLi;
|
|
36
|
+
private rtl?: boolean;
|
|
37
|
+
private setNodeElement: (element: HTMLElement, node: Node) => void;
|
|
38
|
+
private showEmptyFolder: boolean;
|
|
39
|
+
private tabIndex?: number;
|
|
40
|
+
|
|
41
|
+
constructor({
|
|
42
|
+
autoEscape,
|
|
43
|
+
buttonLeft,
|
|
44
|
+
classNames,
|
|
45
|
+
closedIcon,
|
|
46
|
+
dragAndDrop,
|
|
47
|
+
getTree,
|
|
48
|
+
htmlElement,
|
|
49
|
+
isNodeSelected,
|
|
50
|
+
onCreateLi,
|
|
51
|
+
openedIcon,
|
|
52
|
+
rtl,
|
|
53
|
+
setNodeElement,
|
|
54
|
+
showEmptyFolder,
|
|
55
|
+
tabIndex,
|
|
56
|
+
}: ElementsRendererParams) {
|
|
57
|
+
this.autoEscape = autoEscape;
|
|
58
|
+
this.buttonLeft = buttonLeft;
|
|
59
|
+
this.classNames = classNames;
|
|
60
|
+
this.dragAndDrop = dragAndDrop;
|
|
61
|
+
this.getTree = getTree;
|
|
62
|
+
this.htmlElement = htmlElement;
|
|
63
|
+
this.isNodeSelected = isNodeSelected;
|
|
64
|
+
this.onCreateLi = onCreateLi;
|
|
65
|
+
this.rtl = rtl;
|
|
66
|
+
this.setNodeElement = setNodeElement;
|
|
67
|
+
this.showEmptyFolder = showEmptyFolder;
|
|
68
|
+
this.tabIndex = tabIndex;
|
|
69
|
+
this.openedIconElement = this.createButtonElement(openedIcon ?? "+");
|
|
70
|
+
this.closedIconElement = this.createButtonElement(closedIcon ?? "-");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public render(fromNode: Node | null): void {
|
|
74
|
+
if (fromNode?.parent) {
|
|
75
|
+
this.renderFromNode(fromNode);
|
|
76
|
+
} else {
|
|
77
|
+
this.renderFromRoot();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public renderFromNode(node: Node): void {
|
|
82
|
+
if (!node.element) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const currentLi = node.element;
|
|
87
|
+
const newLi = this.createLi(node, node.getLevel());
|
|
88
|
+
currentLi.replaceWith(newLi);
|
|
89
|
+
|
|
90
|
+
// create children
|
|
91
|
+
this.createDomElements(newLi, node.children, false, node.getLevel() + 1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public renderFromRoot(): void {
|
|
95
|
+
this.htmlElement.textContent = '';
|
|
96
|
+
|
|
97
|
+
const tree = this.getTree();
|
|
98
|
+
|
|
99
|
+
if (tree) {
|
|
100
|
+
this.createDomElements(this.htmlElement, tree.children, true, 1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private attachNodeData(node: Node, li: HTMLElement): void {
|
|
105
|
+
node.element = li;
|
|
106
|
+
this.setNodeElement(li, node);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private createButtonElement(
|
|
110
|
+
value: IconElement,
|
|
111
|
+
): HTMLElement | Text | undefined {
|
|
112
|
+
if (typeof value === "string") {
|
|
113
|
+
// convert value to html
|
|
114
|
+
const div = document.createElement("div");
|
|
115
|
+
div.innerHTML = value;
|
|
116
|
+
|
|
117
|
+
return document.createTextNode(div.innerHTML);
|
|
118
|
+
} else if (value.nodeType) {
|
|
119
|
+
return value;
|
|
120
|
+
} else {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private createDomElements(
|
|
126
|
+
element: Element,
|
|
127
|
+
children: Node[],
|
|
128
|
+
isRootNode: boolean,
|
|
129
|
+
level: number,
|
|
130
|
+
): void {
|
|
131
|
+
const ul = this.createUl(isRootNode);
|
|
132
|
+
element.appendChild(ul);
|
|
133
|
+
|
|
134
|
+
for (const child of children) {
|
|
135
|
+
const li = this.createLi(child, level);
|
|
136
|
+
ul.appendChild(li);
|
|
137
|
+
|
|
138
|
+
if (child.hasChildren()) {
|
|
139
|
+
this.createDomElements(li, child.children, false, level + 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private createFolderLi(
|
|
145
|
+
node: Node,
|
|
146
|
+
level: number,
|
|
147
|
+
isSelected: boolean,
|
|
148
|
+
): HTMLLIElement {
|
|
149
|
+
const buttonClasses = this.getButtonClasses(node);
|
|
150
|
+
const folderClasses = this.getFolderClasses(node, isSelected);
|
|
151
|
+
|
|
152
|
+
const iconElement = node.is_open
|
|
153
|
+
? this.openedIconElement
|
|
154
|
+
: this.closedIconElement;
|
|
155
|
+
|
|
156
|
+
// li
|
|
157
|
+
const li = document.createElement("li");
|
|
158
|
+
li.className = `${this.classNames.common} ${folderClasses}`;
|
|
159
|
+
li.setAttribute("role", "none");
|
|
160
|
+
|
|
161
|
+
// div
|
|
162
|
+
const div = document.createElement("div");
|
|
163
|
+
div.className = `${this.classNames.element} ${this.classNames.common}`;
|
|
164
|
+
div.setAttribute("role", "none");
|
|
165
|
+
|
|
166
|
+
li.appendChild(div);
|
|
167
|
+
|
|
168
|
+
// button link
|
|
169
|
+
const buttonLink = document.createElement("a");
|
|
170
|
+
buttonLink.className = buttonClasses;
|
|
171
|
+
|
|
172
|
+
if (iconElement) {
|
|
173
|
+
buttonLink.appendChild(iconElement.cloneNode(true));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (this.buttonLeft) {
|
|
177
|
+
div.appendChild(buttonLink);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// title span
|
|
181
|
+
const titleSpan = this.createTitleSpan(
|
|
182
|
+
node.name,
|
|
183
|
+
isSelected,
|
|
184
|
+
true,
|
|
185
|
+
level,
|
|
186
|
+
);
|
|
187
|
+
titleSpan.setAttribute("aria-expanded", getBoolString(node.is_open));
|
|
188
|
+
div.appendChild(titleSpan);
|
|
189
|
+
|
|
190
|
+
if (!this.buttonLeft) {
|
|
191
|
+
div.appendChild(buttonLink);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return li;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Create the <li> element
|
|
198
|
+
* Attach it to node.element.
|
|
199
|
+
* Call onCreateLi
|
|
200
|
+
*/
|
|
201
|
+
private createLi(node: Node, level: number): HTMLLIElement {
|
|
202
|
+
const isSelected = this.isNodeSelected(node);
|
|
203
|
+
|
|
204
|
+
const mustShowFolder =
|
|
205
|
+
node.isFolder() || (node.isEmptyFolder && this.showEmptyFolder);
|
|
206
|
+
|
|
207
|
+
const li = mustShowFolder
|
|
208
|
+
? this.createFolderLi(node, level, isSelected)
|
|
209
|
+
: this.createNodeLi(node, level, isSelected);
|
|
210
|
+
|
|
211
|
+
this.attachNodeData(node, li);
|
|
212
|
+
|
|
213
|
+
if (this.onCreateLi) {
|
|
214
|
+
this.onCreateLi(node, li, isSelected);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return li;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private createNodeLi(
|
|
221
|
+
node: Node,
|
|
222
|
+
level: number,
|
|
223
|
+
isSelected: boolean,
|
|
224
|
+
): HTMLLIElement {
|
|
225
|
+
const liClasses = [this.classNames.common];
|
|
226
|
+
|
|
227
|
+
if (isSelected) {
|
|
228
|
+
liClasses.push(this.classNames.selected);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const classString = liClasses.join(" ");
|
|
232
|
+
|
|
233
|
+
// li
|
|
234
|
+
const li = document.createElement("li");
|
|
235
|
+
li.className = classString;
|
|
236
|
+
li.setAttribute("role", "none");
|
|
237
|
+
|
|
238
|
+
// div
|
|
239
|
+
const div = document.createElement("div");
|
|
240
|
+
div.className = `${this.classNames.element} ${this.classNames.common}`;
|
|
241
|
+
div.setAttribute("role", "none");
|
|
242
|
+
|
|
243
|
+
li.appendChild(div);
|
|
244
|
+
|
|
245
|
+
// title span
|
|
246
|
+
const titleSpan = this.createTitleSpan(
|
|
247
|
+
node.name,
|
|
248
|
+
isSelected,
|
|
249
|
+
false,
|
|
250
|
+
level,
|
|
251
|
+
);
|
|
252
|
+
div.appendChild(titleSpan);
|
|
253
|
+
|
|
254
|
+
return li;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private createTitleSpan(
|
|
258
|
+
nodeName: string,
|
|
259
|
+
isSelected: boolean,
|
|
260
|
+
isFolder: boolean,
|
|
261
|
+
level: number,
|
|
262
|
+
): HTMLSpanElement {
|
|
263
|
+
const titleSpan = document.createElement("span");
|
|
264
|
+
|
|
265
|
+
let classes = `${this.classNames.title} ${this.classNames.common}`;
|
|
266
|
+
|
|
267
|
+
if (isFolder) {
|
|
268
|
+
classes += ` ${this.classNames.titleFolder}`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
classes += ` ${this.buttonLeft ? this.classNames.titleButtonLeft : this.classNames.titleButtonRight}`;
|
|
272
|
+
|
|
273
|
+
titleSpan.className = classes;
|
|
274
|
+
|
|
275
|
+
if (isSelected) {
|
|
276
|
+
const tabIndex = this.tabIndex;
|
|
277
|
+
|
|
278
|
+
if (tabIndex !== undefined) {
|
|
279
|
+
titleSpan.setAttribute("tabindex", `${tabIndex}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
this.setTreeItemAriaAttributes(titleSpan, nodeName, level, isSelected);
|
|
284
|
+
|
|
285
|
+
if (this.autoEscape) {
|
|
286
|
+
titleSpan.textContent = nodeName;
|
|
287
|
+
} else {
|
|
288
|
+
titleSpan.innerHTML = nodeName;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return titleSpan;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private createUl(isRootNode: boolean): HTMLUListElement {
|
|
295
|
+
let classString;
|
|
296
|
+
let role;
|
|
297
|
+
|
|
298
|
+
if (!isRootNode) {
|
|
299
|
+
classString = "";
|
|
300
|
+
role = "group";
|
|
301
|
+
} else {
|
|
302
|
+
classString = this.classNames.tree;
|
|
303
|
+
role = "tree";
|
|
304
|
+
|
|
305
|
+
if (this.rtl) {
|
|
306
|
+
classString += ` ${this.classNames.rtl}`;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (this.dragAndDrop) {
|
|
311
|
+
classString += ` ${this.classNames.dnd}`;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const ul = document.createElement("ul");
|
|
315
|
+
ul.className = `${this.classNames.common} ${classString}`;
|
|
316
|
+
|
|
317
|
+
ul.setAttribute("role", role);
|
|
318
|
+
|
|
319
|
+
return ul;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private getButtonClasses(node: Node): string {
|
|
323
|
+
const classes = [this.classNames.toggler, this.classNames.common];
|
|
324
|
+
|
|
325
|
+
if (!node.is_open) {
|
|
326
|
+
classes.push(this.classNames.closed);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (this.buttonLeft) {
|
|
330
|
+
classes.push(this.classNames.togglerLeft);
|
|
331
|
+
} else {
|
|
332
|
+
classes.push(this.classNames.togglerRight);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return classes.join(" ");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
private getFolderClasses(node: Node, isSelected: boolean): string {
|
|
339
|
+
const classes = [this.classNames.folder];
|
|
340
|
+
|
|
341
|
+
if (!node.is_open) {
|
|
342
|
+
classes.push(this.classNames.closed);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (isSelected) {
|
|
346
|
+
classes.push(this.classNames.selected);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (node.is_loading) {
|
|
350
|
+
classes.push(this.classNames.loading);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return classes.join(" ");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private setTreeItemAriaAttributes(
|
|
357
|
+
element: HTMLElement,
|
|
358
|
+
name: string,
|
|
359
|
+
level: number,
|
|
360
|
+
isSelected: boolean,
|
|
361
|
+
) {
|
|
362
|
+
element.setAttribute("aria-label", name);
|
|
363
|
+
element.setAttribute("aria-level", `${level}`);
|
|
364
|
+
element.setAttribute("aria-selected", getBoolString(isSelected));
|
|
365
|
+
element.setAttribute("role", "treeitem");
|
|
366
|
+
}
|
|
367
|
+
}
|
package/src/events.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { Node, NodeData, Position } from "./node";
|
|
2
|
+
|
|
3
|
+
export interface MoveInfo {
|
|
4
|
+
doMove: () => void;
|
|
5
|
+
movedNode: Node;
|
|
6
|
+
originalEvent: Event;
|
|
7
|
+
position: Position;
|
|
8
|
+
previousParent: Node | null;
|
|
9
|
+
targetNode: Node;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// The CustomEvent of a tree event, for example `TreeEvent<"tree.select">`.
|
|
13
|
+
export type TreeEvent<Name extends TreeEventName = TreeEventName> = CustomEvent<
|
|
14
|
+
TreeEvents[Name]
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
export type TreeEventName = keyof TreeEvents;
|
|
18
|
+
|
|
19
|
+
// The events that the tree dispatches, and the type of their `detail`.
|
|
20
|
+
// `undefined` means that the event has no `detail`.
|
|
21
|
+
// The events reference in the docs is generated from this interface, so the
|
|
22
|
+
// events are ordered chronologically instead of alphabetically.
|
|
23
|
+
/* eslint-disable perfectionist/sort-interfaces */
|
|
24
|
+
export interface TreeEvents {
|
|
25
|
+
/**
|
|
26
|
+
* Dispatched once, after the tree is rendered for the first time. With
|
|
27
|
+
* `dataUrl` this is after the data has arrived, so it is the moment the
|
|
28
|
+
* api is safe to use:
|
|
29
|
+
*
|
|
30
|
+
* ```js
|
|
31
|
+
* element.addEventListener("tree.init", () => {
|
|
32
|
+
* tree.selectNode(tree.getNodeByName("node1"));
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* No `detail`.
|
|
37
|
+
*
|
|
38
|
+
* With inline `data`, the tree is rendered inside the constructor, so
|
|
39
|
+
* this event has already fired by the time the constructor returns. Add
|
|
40
|
+
* the listener to the element _before_ creating the tree:
|
|
41
|
+
*
|
|
42
|
+
* ```js
|
|
43
|
+
* const element = document.getElementById("tree1");
|
|
44
|
+
*
|
|
45
|
+
* element.addEventListener("tree.init", () => {
|
|
46
|
+
* // ...
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* const tree = new TreeElement({ data, htmlElement: element });
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @group Lifecycle
|
|
53
|
+
*/
|
|
54
|
+
"tree.init": undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Dispatched after the tree has been re-rendered. No `detail`.
|
|
57
|
+
*
|
|
58
|
+
* @group Lifecycle
|
|
59
|
+
*/
|
|
60
|
+
"tree.refresh": undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Dispatched when a node title is clicked. Call `preventDefault()` to
|
|
63
|
+
* stop the tree from selecting the node:
|
|
64
|
+
*
|
|
65
|
+
* ```js
|
|
66
|
+
* element.addEventListener("tree.click", (e) => {
|
|
67
|
+
* e.preventDefault();
|
|
68
|
+
* console.log("clicked", e.detail.node.name, "but not selected");
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @group Mouse
|
|
73
|
+
*/
|
|
74
|
+
"tree.click": {
|
|
75
|
+
node: Node;
|
|
76
|
+
originalEvent: MouseEvent;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Dispatched when a node title is double clicked.
|
|
80
|
+
*
|
|
81
|
+
* @group Mouse
|
|
82
|
+
*/
|
|
83
|
+
"tree.dblclick": {
|
|
84
|
+
node: Node;
|
|
85
|
+
originalEvent: MouseEvent;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Dispatched on a right click on a node, unless `useContextMenu` is
|
|
89
|
+
* `false`. The browser's own menu is suppressed.
|
|
90
|
+
*
|
|
91
|
+
* @group Mouse
|
|
92
|
+
*/
|
|
93
|
+
"tree.contextmenu": {
|
|
94
|
+
node: Node;
|
|
95
|
+
originalEvent: MouseEvent;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Dispatched when a folder is opened, after the animation.
|
|
99
|
+
*
|
|
100
|
+
* @group Opening and closing
|
|
101
|
+
*/
|
|
102
|
+
"tree.open": {
|
|
103
|
+
node: Node;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Dispatched when a folder is closed, after the animation.
|
|
107
|
+
*
|
|
108
|
+
* @group Opening and closing
|
|
109
|
+
*/
|
|
110
|
+
"tree.close": {
|
|
111
|
+
node: Node;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Dispatched when a node is selected. A deselection is
|
|
115
|
+
* [`tree.deselect`](#tree-deselect) instead, so `node` is always a node
|
|
116
|
+
* here.
|
|
117
|
+
*
|
|
118
|
+
* ```js
|
|
119
|
+
* element.addEventListener("tree.select", (e) => {
|
|
120
|
+
* console.log("selected", e.detail.node.name);
|
|
121
|
+
* });
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @group Selection
|
|
125
|
+
*/
|
|
126
|
+
"tree.select": {
|
|
127
|
+
/** The node that was selected before, if any. */
|
|
128
|
+
deselectedNode: Node | null;
|
|
129
|
+
/** The node that is now selected. */
|
|
130
|
+
node: Node;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Dispatched when the selected node is deselected, which happens when it
|
|
134
|
+
* is clicked again or passed to `selectNode` again. No `tree.select` is
|
|
135
|
+
* dispatched for it.
|
|
136
|
+
*
|
|
137
|
+
* ```js
|
|
138
|
+
* element.addEventListener("tree.deselect", (e) => {
|
|
139
|
+
* console.log("deselected", e.detail.node.name);
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* Selecting another node does not dispatch it — that is a `tree.select`
|
|
144
|
+
* with the previous node in `deselectedNode`. It is also not dispatched
|
|
145
|
+
* with `mustToggle: false`, or by `selectNode(null)`,
|
|
146
|
+
* `removeFromSelection`, `removeNode`, `loadData` and restoring a saved
|
|
147
|
+
* state.
|
|
148
|
+
*
|
|
149
|
+
* @group Selection
|
|
150
|
+
*/
|
|
151
|
+
"tree.deselect": {
|
|
152
|
+
node: Node;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Dispatched when a node is dropped after a drag.
|
|
156
|
+
*
|
|
157
|
+
* | `detail` | Type |
|
|
158
|
+
* | ------------------------- | --------------------------------- |
|
|
159
|
+
* | `moveInfo.movedNode` | `Node` |
|
|
160
|
+
* | `moveInfo.targetNode` | `Node` |
|
|
161
|
+
* | `moveInfo.position` | `"before" \| "after" \| "inside"` |
|
|
162
|
+
* | `moveInfo.previousParent` | `Node \| null` |
|
|
163
|
+
* | `moveInfo.originalEvent` | `Event` |
|
|
164
|
+
* | `moveInfo.doMove` | `() => void` |
|
|
165
|
+
*
|
|
166
|
+
* Call `preventDefault()` to keep the tree as it is, and
|
|
167
|
+
* `moveInfo.doMove()` to apply the move later. See
|
|
168
|
+
* [Drag and drop](/guide/drag-and-drop#reacting-to-a-move).
|
|
169
|
+
*
|
|
170
|
+
* @group Drag and drop
|
|
171
|
+
*/
|
|
172
|
+
"tree.move": {
|
|
173
|
+
/** @hidden The fields are in the table above. */
|
|
174
|
+
moveInfo: MoveInfo;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Dispatched when data is set on the tree, both from the `data` option
|
|
178
|
+
* and from a url.
|
|
179
|
+
*
|
|
180
|
+
* @group Loading data
|
|
181
|
+
*/
|
|
182
|
+
"tree.set_data": {
|
|
183
|
+
/** The node whose children were replaced, if it was a subtree. */
|
|
184
|
+
node?: Node;
|
|
185
|
+
treeData?: NodeData[];
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Dispatched when a request starts.
|
|
189
|
+
*
|
|
190
|
+
* @group Loading data
|
|
191
|
+
*/
|
|
192
|
+
"tree.loading_data": {
|
|
193
|
+
element: HTMLElement;
|
|
194
|
+
/** The node whose children are loading, if it is a subtree. */
|
|
195
|
+
node?: Node;
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Dispatched when a request finishes. It is dispatched when the request
|
|
199
|
+
* fails too; a [`tree.load_failed`](#tree-load-failed) follows it.
|
|
200
|
+
*
|
|
201
|
+
* @group Loading data
|
|
202
|
+
*/
|
|
203
|
+
"tree.loaded_data": {
|
|
204
|
+
element: HTMLElement;
|
|
205
|
+
/** The node whose children were loaded, if it was a subtree. */
|
|
206
|
+
node?: Node;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Dispatched when a request returns an error status, after
|
|
210
|
+
* `tree.loaded_data`:
|
|
211
|
+
*
|
|
212
|
+
* ```js
|
|
213
|
+
* element.addEventListener("tree.load_failed", (e) => {
|
|
214
|
+
* console.error("loading the tree failed", e.detail.response.status);
|
|
215
|
+
* });
|
|
216
|
+
* ```
|
|
217
|
+
*
|
|
218
|
+
* @group Loading data
|
|
219
|
+
*/
|
|
220
|
+
"tree.load_failed": {
|
|
221
|
+
response: Response;
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/* eslint-enable perfectionist/sort-interfaces */
|
|
225
|
+
|
|
226
|
+
type TreeEventMap = {
|
|
227
|
+
[Name in TreeEventName]: TreeEvent<Name>;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Type `addEventListener("tree.select", ...)` on elements, the document and the window.
|
|
231
|
+
declare global {
|
|
232
|
+
interface DocumentEventMap extends TreeEventMap { }
|
|
233
|
+
|
|
234
|
+
interface HTMLElementEventMap extends TreeEventMap { }
|
|
235
|
+
|
|
236
|
+
interface WindowEventMap extends TreeEventMap { }
|
|
237
|
+
}
|
package/src/header.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Html-tree <%= version %>
|
|
2
|
+
|
|
3
|
+
Copyright <%= year %> Marco Braak
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
@license
|