tree-element 0.1.1 → 0.3.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 +43 -31
- package/lib/animation.d.ts +2 -2
- package/lib/animation.d.ts.map +1 -1
- package/lib/animation.js +16 -12
- package/lib/animation.js.map +1 -1
- package/lib/classNames.d.ts.map +1 -1
- package/lib/classNames.js +2 -2
- package/lib/classNames.js.map +1 -1
- package/lib/dataLoader.d.ts +1 -0
- package/lib/dataLoader.d.ts.map +1 -1
- package/lib/dataLoader.js +22 -20
- package/lib/dataLoader.js.map +1 -1
- package/lib/dragAndDropHandler/binarySearch.js +3 -3
- package/lib/dragAndDropHandler/binarySearch.js.map +1 -1
- package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -1
- package/lib/dragAndDropHandler/dragElement.js +11 -13
- package/lib/dragAndDropHandler/dragElement.js.map +1 -1
- package/lib/dragAndDropHandler/generateHitAreas.d.ts.map +1 -1
- package/lib/dragAndDropHandler/generateHitAreas.js +25 -25
- package/lib/dragAndDropHandler/generateHitAreas.js.map +1 -1
- package/lib/dragAndDropHandler/index.d.ts.map +1 -1
- package/lib/dragAndDropHandler/index.js +125 -158
- package/lib/dragAndDropHandler/index.js.map +1 -1
- package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -1
- package/lib/dragAndDropHandler/iterateVisibleNodes.js +23 -22
- package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -1
- package/lib/dragAndDropHandler/types.d.ts.map +1 -1
- package/lib/elementsRenderer.d.ts +20 -7
- package/lib/elementsRenderer.d.ts.map +1 -1
- package/lib/elementsRenderer.js +195 -136
- package/lib/elementsRenderer.js.map +1 -1
- package/lib/events.d.ts +44 -11
- package/lib/events.d.ts.map +1 -1
- package/lib/index.d.ts +36 -13
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +386 -349
- package/lib/index.js.map +1 -1
- package/lib/keyHandler.d.ts +13 -8
- package/lib/keyHandler.d.ts.map +1 -1
- package/lib/keyHandler.js +106 -51
- package/lib/keyHandler.js.map +1 -1
- package/lib/methodTypes.d.ts +3 -3
- package/lib/methodTypes.d.ts.map +1 -1
- package/lib/mouseHandler.d.ts +1 -1
- package/lib/mouseHandler.d.ts.map +1 -1
- package/lib/mouseHandler.js +36 -49
- package/lib/mouseHandler.js.map +1 -1
- package/lib/mouseUtils.d.ts.map +1 -1
- package/lib/mouseUtils.js +2 -2
- package/lib/mouseUtils.js.map +1 -1
- package/lib/node.d.ts +47 -16
- package/lib/node.d.ts.map +1 -1
- package/lib/node.js +169 -171
- package/lib/node.js.map +1 -1
- package/lib/nodeElement/borderDropHint.d.ts.map +1 -1
- package/lib/nodeElement/borderDropHint.js +4 -5
- package/lib/nodeElement/borderDropHint.js.map +1 -1
- package/lib/nodeElement/folderElement.d.ts +8 -5
- package/lib/nodeElement/folderElement.d.ts.map +1 -1
- package/lib/nodeElement/folderElement.js +75 -67
- package/lib/nodeElement/folderElement.js.map +1 -1
- package/lib/nodeElement/ghostDropHint.d.ts.map +1 -1
- package/lib/nodeElement/ghostDropHint.js +13 -13
- package/lib/nodeElement/ghostDropHint.js.map +1 -1
- package/lib/nodeElement/index.d.ts +2 -1
- package/lib/nodeElement/index.d.ts.map +1 -1
- package/lib/nodeElement/index.js +38 -30
- package/lib/nodeElement/index.js.map +1 -1
- package/lib/nodeUtils.d.ts.map +1 -1
- package/lib/nodeUtils.js +1 -1
- package/lib/nodeUtils.js.map +1 -1
- package/lib/options.d.ts +19 -3
- package/lib/options.d.ts.map +1 -1
- package/lib/positionUtils.js +3 -3
- package/lib/positionUtils.js.map +1 -1
- package/lib/requestUrl.d.ts +1 -1
- package/lib/requestUrl.d.ts.map +1 -1
- package/lib/requestUrl.js +6 -17
- package/lib/requestUrl.js.map +1 -1
- package/lib/saveStateHandler.d.ts.map +1 -1
- package/lib/saveStateHandler.js +59 -89
- package/lib/saveStateHandler.js.map +1 -1
- package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -1
- package/lib/scrollHandler/containerScrollParent.js +11 -18
- package/lib/scrollHandler/containerScrollParent.js.map +1 -1
- package/lib/scrollHandler/createScrollParent.d.ts.map +1 -1
- package/lib/scrollHandler/createScrollParent.js +12 -13
- package/lib/scrollHandler/createScrollParent.js.map +1 -1
- package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -1
- package/lib/scrollHandler/documentScrollParent.js +18 -27
- package/lib/scrollHandler/documentScrollParent.js.map +1 -1
- package/lib/scrollHandler/scrollParent.d.ts.map +1 -1
- package/lib/scrollHandler/scrollParent.js +30 -34
- package/lib/scrollHandler/scrollParent.js.map +1 -1
- package/lib/scrollHandler.d.ts.map +1 -1
- package/lib/scrollHandler.js +11 -14
- package/lib/scrollHandler.js.map +1 -1
- package/lib/selectNodeHandler.d.ts +4 -2
- package/lib/selectNodeHandler.d.ts.map +1 -1
- package/lib/selectNodeHandler.js +64 -83
- package/lib/selectNodeHandler.js.map +1 -1
- package/lib/setDefaultOptions.d.ts.map +1 -1
- package/lib/setDefaultOptions.js +34 -38
- package/lib/setDefaultOptions.js.map +1 -1
- package/lib/triggerCustomEvent.d.ts.map +1 -1
- package/lib/triggerCustomEvent.js +2 -2
- package/lib/triggerCustomEvent.js.map +1 -1
- package/lib/util.d.ts.map +1 -1
- package/lib/util.js +2 -2
- package/lib/util.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 +43 -32
- package/src/animation.ts +14 -12
- package/src/classNames.ts +52 -52
- package/src/dataLoader.ts +79 -71
- package/src/dragAndDropHandler/binarySearch.ts +17 -17
- package/src/dragAndDropHandler/dragElement.ts +51 -50
- package/src/dragAndDropHandler/generateHitAreas.ts +156 -161
- package/src/dragAndDropHandler/index.ts +334 -348
- package/src/dragAndDropHandler/iterateVisibleNodes.ts +61 -63
- package/src/dragAndDropHandler/types.ts +5 -5
- package/src/elementsRenderer.ts +377 -294
- package/src/events.ts +241 -208
- package/src/header.txt +1 -1
- package/src/index.ts +259 -229
- package/src/keyHandler.ts +179 -115
- package/src/methodTypes.ts +7 -10
- package/src/mouseHandler.ts +316 -316
- package/src/mouseUtils.ts +14 -14
- package/src/node.ts +773 -771
- package/src/nodeElement/borderDropHint.ts +25 -25
- package/src/nodeElement/folderElement.ts +116 -102
- package/src/nodeElement/ghostDropHint.ts +64 -62
- package/src/nodeElement/index.ts +81 -73
- package/src/nodeUtils.ts +5 -5
- package/src/options.ts +25 -5
- package/src/requestUrl.ts +7 -14
- package/src/saveStateHandler.ts +191 -207
- package/src/scrollHandler/containerScrollParent.ts +40 -49
- package/src/scrollHandler/createScrollParent.ts +26 -27
- package/src/scrollHandler/documentScrollParent.ts +66 -72
- package/src/scrollHandler/scrollParent.ts +90 -86
- package/src/scrollHandler.ts +45 -45
- package/src/selectNodeHandler.ts +171 -165
- package/src/setDefaultOptions.ts +44 -32
- package/src/triggerCustomEvent.ts +7 -3
- package/src/util.ts +2 -3
- package/src/version.ts +1 -1
- package/tree_element.css +87 -69
- package/tree_element.debug.js +3866 -3831
- package/tree_element.debug.js.map +1 -1
- package/tree_element.js +2 -2
- package/tree_element.js.map +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
handleAfterOpenFolder,
|
|
3
|
-
handleClosedFolder,
|
|
4
|
-
handleFirstNode,
|
|
5
|
-
handleNode,
|
|
6
|
-
handleOpenFolder
|
|
1
|
+
let iterateVisibleNodes = (tree, {
|
|
2
|
+
_handleAfterOpenFolder: handleAfterOpenFolder,
|
|
3
|
+
_handleClosedFolder: handleClosedFolder,
|
|
4
|
+
_handleFirstNode: handleFirstNode,
|
|
5
|
+
_handleNode: handleNode,
|
|
6
|
+
_handleOpenFolder: handleOpenFolder
|
|
7
7
|
}) => {
|
|
8
8
|
let isFirstNode = true;
|
|
9
|
-
|
|
9
|
+
let iterate = (node, nextNode) => {
|
|
10
10
|
let mustIterateInside = (node.is_open === true || !node.element) && node.hasChildren();
|
|
11
11
|
let element = null;
|
|
12
12
|
|
|
@@ -27,25 +27,26 @@ const iterateVisibleNodes = (tree, {
|
|
|
27
27
|
handleClosedFolder(node, nextNode, element);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
if (mustIterateInside) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
if (!mustIterateInside) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let childrenLength = node.children.length;
|
|
34
|
+
for (let i of node.children.keys()) {
|
|
35
|
+
let child = node.children[i];
|
|
36
|
+
if (child) {
|
|
37
|
+
if (i === childrenLength - 1) {
|
|
38
|
+
iterate(child, null);
|
|
39
|
+
} else {
|
|
40
|
+
let nextChild = node.children[i + 1];
|
|
41
|
+
if (nextChild) {
|
|
42
|
+
iterate(child, nextChild);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
});
|
|
45
|
-
if (node.is_open && element) {
|
|
46
|
-
handleAfterOpenFolder(node, nextNode);
|
|
47
45
|
}
|
|
48
46
|
}
|
|
47
|
+
if (node.is_open && element) {
|
|
48
|
+
handleAfterOpenFolder(node, nextNode);
|
|
49
|
+
}
|
|
49
50
|
};
|
|
50
51
|
iterate(tree, null);
|
|
51
52
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iterateVisibleNodes.js","sources":["../../src/dragAndDropHandler/iterateVisibleNodes.ts"],"sourcesContent":["import type { Node } from \"../node\";\n\ninterface Options {\n
|
|
1
|
+
{"version":3,"file":"iterateVisibleNodes.js","sources":["../../src/dragAndDropHandler/iterateVisibleNodes.ts"],"sourcesContent":["import type { Node } from \"../node\";\n\ninterface Options {\n handleAfterOpenFolder: (node: Node, nextNode: Node | null) => void;\n handleClosedFolder: (\n node: Node,\n nextNode: Node | null,\n element: HTMLElement,\n ) => void;\n handleFirstNode: (node: Node) => void;\n handleNode: (node: Node, nextNode: Node | null, element: HTMLElement) => void;\n\n /*\n override\n return\n - true: continue iterating\n - false: stop iterating\n */\n handleOpenFolder: (node: Node, element: HTMLElement) => boolean;\n}\n\nconst iterateVisibleNodes = (\n tree: Node,\n {\n handleAfterOpenFolder,\n handleClosedFolder,\n handleFirstNode,\n handleNode,\n handleOpenFolder,\n }: Options,\n) => {\n let isFirstNode = true;\n\n const iterate = (node: Node, nextNode: Node | null): void => {\n let mustIterateInside =\n (node.is_open === true || !node.element) && node.hasChildren();\n\n let element: HTMLElement | null = null;\n\n // Is the element visible?\n if (node.element?.offsetParent) {\n element = node.element;\n\n if (isFirstNode) {\n handleFirstNode(node);\n isFirstNode = false;\n }\n\n if (!node.hasChildren()) {\n handleNode(node, nextNode, node.element);\n } else if (node.is_open) {\n if (!handleOpenFolder(node, node.element)) {\n mustIterateInside = false;\n }\n } else {\n handleClosedFolder(node, nextNode, element);\n }\n }\n\n if (!mustIterateInside) {\n return;\n }\n\n const childrenLength = node.children.length;\n for (const i of node.children.keys()) {\n const child = node.children[i];\n\n if (child) {\n if (i === childrenLength - 1) {\n iterate(child, null);\n } else {\n const nextChild = node.children[i + 1];\n\n if (nextChild) {\n iterate(child, nextChild);\n }\n }\n }\n }\n\n if (node.is_open && element) {\n handleAfterOpenFolder(node, nextNode);\n }\n };\n\n iterate(tree, null);\n};\n\nexport default iterateVisibleNodes;\n"],"names":[],"mappings":"AAqBA,IAAM,mBAAmB,GAAG,CAC1B,IAAU,EACV;EACE,sBAAA,EAAA,qBAAqB;EACrB,mBAAA,EAAA,kBAAkB;EAClB,gBAAA,EAAA,eAAe;EACf,WAAA,EAAA,UAAU;AACV,EAAA,iBAAA,EAAA;AACO,CAAC,KACP;EACH,IAAI,WAAW,GAAG,IAAI;AAEtB,EAAA,IAAM,OAAO,GAAG,CAAC,IAAU,EAAE,QAAqB,KAAW;AAC3D,IAAA,IAAI,iBAAiB,GACnB,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,WAAW,EAAE;IAEhE,IAAI,OAA2B,GAAG,IAAI;;AAEtC;AACA,IAAA,IAAI,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE;MAC9B,OAAO,GAAG,IAAI,CAAC,OAAO;AAEtB,MAAA,IAAI,WAAW,EAAE;QACf,eAAe,CAAC,IAAI,CAAC;AACrB,QAAA,WAAW,GAAG,KAAK;AACrB,MAAA;AAEA,MAAA,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE;QACvB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC;AAC1C,MAAA,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE;QACvB,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE;AACzC,UAAA,iBAAiB,GAAG,KAAK;AAC3B,QAAA;AACF,MAAA,CAAC,MAAM;AACL,QAAA,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC;AAC7C,MAAA;AACF,IAAA;IAEA,IAAI,CAAC,iBAAiB,EAAE;AACtB,MAAA;AACF,IAAA;AAEA,IAAA,IAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM;IAC3C,KAAK,IAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE;AACpC,MAAA,IAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE9B,MAAA,IAAI,KAAK,EAAE;AACT,QAAA,IAAI,CAAC,KAAK,cAAc,GAAG,CAAC,EAAE;AAC5B,UAAA,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;AACtB,QAAA,CAAC,MAAM;UACL,IAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;AAEtC,UAAA,IAAI,SAAS,EAAE;AACb,YAAA,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC;AAC3B,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AAEA,IAAA,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,EAAE;AAC3B,MAAA,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC;AACvC,IAAA;EACF,CAAC;AAED,EAAA,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;AACrB;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dragAndDropHandler/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,QAAQ;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dragAndDropHandler/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb"}
|
|
@@ -3,6 +3,8 @@ import type { GetTree, IsNodeSelected } from "./methodTypes.js";
|
|
|
3
3
|
import type { Node } from "./node.js";
|
|
4
4
|
import type { IconElement, OnCreateLi } from "./options.js";
|
|
5
5
|
interface ElementsRendererParams {
|
|
6
|
+
ariaLabel?: string;
|
|
7
|
+
ariaLabelledBy?: string;
|
|
6
8
|
autoEscape: boolean;
|
|
7
9
|
buttonLeft: boolean;
|
|
8
10
|
classNames: ClassNames;
|
|
@@ -19,35 +21,46 @@ interface ElementsRendererParams {
|
|
|
19
21
|
tabIndex?: number;
|
|
20
22
|
}
|
|
21
23
|
export default class ElementsRenderer {
|
|
22
|
-
closedIconElement?:
|
|
23
|
-
openedIconElement?:
|
|
24
|
+
closedIconElement?: globalThis.Node;
|
|
25
|
+
openedIconElement?: globalThis.Node;
|
|
26
|
+
private ariaLabel?;
|
|
27
|
+
private ariaLabelledBy?;
|
|
24
28
|
private autoEscape;
|
|
25
29
|
private buttonLeft;
|
|
26
30
|
private classNames;
|
|
31
|
+
private closedFolderTemplate;
|
|
27
32
|
private dragAndDrop;
|
|
28
33
|
private getTree;
|
|
34
|
+
private groupUlTemplate;
|
|
29
35
|
private htmlElement;
|
|
30
36
|
private isNodeSelected;
|
|
37
|
+
private nodeTemplate;
|
|
31
38
|
private onCreateLi?;
|
|
39
|
+
private openedFolderTemplate;
|
|
40
|
+
private rootUlTemplate;
|
|
32
41
|
private rtl?;
|
|
33
42
|
private setNodeElement;
|
|
34
43
|
private showEmptyFolder;
|
|
35
44
|
private tabIndex?;
|
|
36
|
-
constructor({ autoEscape, buttonLeft, classNames, closedIcon, dragAndDrop, getTree, htmlElement, isNodeSelected, onCreateLi, openedIcon, rtl, setNodeElement, showEmptyFolder, tabIndex, }: ElementsRendererParams);
|
|
45
|
+
constructor({ ariaLabel, ariaLabelledBy, autoEscape, buttonLeft, classNames, closedIcon, dragAndDrop, getTree, htmlElement, isNodeSelected, onCreateLi, openedIcon, rtl, setNodeElement, showEmptyFolder, tabIndex, }: ElementsRendererParams);
|
|
37
46
|
render(fromNode: Node | null): void;
|
|
47
|
+
renderChildren(node: Node): HTMLUListElement | null;
|
|
38
48
|
renderFromNode(node: Node): void;
|
|
39
49
|
renderFromRoot(): void;
|
|
40
50
|
private attachNodeData;
|
|
41
51
|
private createButtonElement;
|
|
42
52
|
private createDomElements;
|
|
43
53
|
private createFolderLi;
|
|
54
|
+
private createFolderTemplate;
|
|
44
55
|
private createLi;
|
|
56
|
+
private createLiTemplate;
|
|
45
57
|
private createNodeLi;
|
|
46
|
-
private
|
|
47
|
-
private
|
|
58
|
+
private createNodeTemplate;
|
|
59
|
+
private createTitleSpanTemplate;
|
|
60
|
+
private createUlTemplate;
|
|
61
|
+
private fillTitleSpan;
|
|
48
62
|
private getButtonClasses;
|
|
49
|
-
private
|
|
50
|
-
private setTreeItemAriaAttributes;
|
|
63
|
+
private mustRenderChildren;
|
|
51
64
|
}
|
|
52
65
|
export {};
|
|
53
66
|
//# sourceMappingURL=elementsRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elementsRenderer.d.ts","sourceRoot":"","sources":["../src/elementsRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIzD,UAAU,sBAAsB;
|
|
1
|
+
{"version":3,"file":"elementsRenderer.d.ts","sourceRoot":"","sources":["../src/elementsRenderer.ts"],"names":[],"mappings":"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"}
|
package/lib/elementsRenderer.js
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
import { getBoolString } from './util.js';
|
|
2
2
|
|
|
3
|
+
/* Renders the tree to html.
|
|
4
|
+
*
|
|
5
|
+
* The children of a closed folder are not rendered. They are rendered when
|
|
6
|
+
* the folder is opened, see renderChildren.
|
|
7
|
+
*
|
|
8
|
+
* The elements are created by cloning templates. A template is a fully
|
|
9
|
+
* built <li> or <ul> with everything that is the same for every node
|
|
10
|
+
* (structure, roles, static classes, the toggler icon). Per node only the
|
|
11
|
+
* parts that differ are set: the title, the aria attributes and the
|
|
12
|
+
* selected and loading classes.
|
|
13
|
+
*/
|
|
3
14
|
class ElementsRenderer {
|
|
4
|
-
closedIconElement;
|
|
5
|
-
openedIconElement;
|
|
6
|
-
_autoEscape;
|
|
7
|
-
_buttonLeft;
|
|
8
|
-
_classNames;
|
|
9
|
-
_dragAndDrop;
|
|
10
|
-
_getTree;
|
|
11
|
-
_htmlElement;
|
|
12
|
-
_isNodeSelected;
|
|
13
|
-
_onCreateLi;
|
|
14
|
-
_rtl;
|
|
15
|
-
_setNodeElement;
|
|
16
|
-
_showEmptyFolder;
|
|
17
|
-
_tabIndex;
|
|
18
15
|
constructor({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
_ariaLabel: ariaLabel,
|
|
17
|
+
_ariaLabelledBy: ariaLabelledBy,
|
|
18
|
+
_autoEscape: autoEscape,
|
|
19
|
+
_buttonLeft: buttonLeft,
|
|
20
|
+
_classNames: classNames,
|
|
21
|
+
_closedIcon: closedIcon = "-",
|
|
22
|
+
_dragAndDrop: dragAndDrop,
|
|
23
|
+
_getTree: getTree,
|
|
24
|
+
_htmlElement: htmlElement,
|
|
25
|
+
_isNodeSelected: isNodeSelected,
|
|
26
|
+
_onCreateLi: onCreateLi,
|
|
27
|
+
_openedIcon: openedIcon = "+",
|
|
28
|
+
_rtl: rtl,
|
|
29
|
+
_setNodeElement: setNodeElement,
|
|
30
|
+
_showEmptyFolder: showEmptyFolder,
|
|
31
|
+
_tabIndex: tabIndex
|
|
33
32
|
}) {
|
|
33
|
+
this._ariaLabel = ariaLabel;
|
|
34
|
+
this._ariaLabelledBy = ariaLabelledBy;
|
|
34
35
|
this._autoEscape = autoEscape;
|
|
35
36
|
this._buttonLeft = buttonLeft;
|
|
36
37
|
this._classNames = classNames;
|
|
@@ -43,30 +44,42 @@ class ElementsRenderer {
|
|
|
43
44
|
this._setNodeElement = setNodeElement;
|
|
44
45
|
this._showEmptyFolder = showEmptyFolder;
|
|
45
46
|
this._tabIndex = tabIndex;
|
|
46
|
-
this.
|
|
47
|
-
this.
|
|
47
|
+
this._openedIconElement = this._createButtonElement(openedIcon);
|
|
48
|
+
this._closedIconElement = this._createButtonElement(closedIcon);
|
|
49
|
+
this._rootUlTemplate = this._createUlTemplate(true);
|
|
50
|
+
this._groupUlTemplate = this._createUlTemplate(false);
|
|
51
|
+
this._nodeTemplate = this._createNodeTemplate();
|
|
52
|
+
this._openedFolderTemplate = this._createFolderTemplate(true);
|
|
53
|
+
this._closedFolderTemplate = this._createFolderTemplate(false);
|
|
48
54
|
}
|
|
49
|
-
|
|
55
|
+
_render(fromNode) {
|
|
50
56
|
if (fromNode?.parent) {
|
|
51
|
-
this.
|
|
57
|
+
this._renderFromNode(fromNode);
|
|
52
58
|
} else {
|
|
53
|
-
this.
|
|
59
|
+
this._renderFromRoot();
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
|
-
|
|
62
|
+
|
|
63
|
+
/* Render the children of a rendered folder. Returns the new <ul>, or
|
|
64
|
+
* null when the folder is not rendered or has no children.
|
|
65
|
+
*/
|
|
66
|
+
_renderChildren(node) {
|
|
67
|
+
return !node.element || !node.hasChildren() ? null : this._createDomElements(node.element, node.children, false, node.getLevel() + 1);
|
|
68
|
+
}
|
|
69
|
+
_renderFromNode(node) {
|
|
57
70
|
if (!node.element) {
|
|
58
71
|
return;
|
|
59
72
|
}
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
let currentLi = node.element;
|
|
74
|
+
let newLi = this._createLi(node, node.getLevel());
|
|
62
75
|
currentLi.replaceWith(newLi);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
if (this._mustRenderChildren(node)) {
|
|
77
|
+
this._createDomElements(newLi, node.children, false, node.getLevel() + 1);
|
|
78
|
+
}
|
|
66
79
|
}
|
|
67
|
-
|
|
68
|
-
this._htmlElement.textContent =
|
|
69
|
-
|
|
80
|
+
_renderFromRoot() {
|
|
81
|
+
this._htmlElement.textContent = "";
|
|
82
|
+
let tree = this._getTree();
|
|
70
83
|
if (tree) {
|
|
71
84
|
this._createDomElements(this._htmlElement, tree.children, true, 1);
|
|
72
85
|
}
|
|
@@ -75,61 +88,83 @@ class ElementsRenderer {
|
|
|
75
88
|
node.element = li;
|
|
76
89
|
this._setNodeElement(li, node);
|
|
77
90
|
}
|
|
91
|
+
|
|
92
|
+
/* Returns the template of a toggler icon; it is cloned for every folder.
|
|
93
|
+
* A string is parsed as html and becomes a fragment, so it can hold
|
|
94
|
+
* entities, text and elements.
|
|
95
|
+
*/
|
|
78
96
|
_createButtonElement(value) {
|
|
79
97
|
if (typeof value === "string") {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return
|
|
84
|
-
} else if (value.nodeType) {
|
|
85
|
-
return value;
|
|
86
|
-
} else {
|
|
87
|
-
return undefined;
|
|
98
|
+
let template = document.createElement("template");
|
|
99
|
+
// eslint-disable-next-line no-unsanitized/property -- icon options are documented to accept html
|
|
100
|
+
template.innerHTML = value;
|
|
101
|
+
return template.content;
|
|
88
102
|
}
|
|
103
|
+
return value.nodeType ? value : undefined;
|
|
89
104
|
}
|
|
90
105
|
_createDomElements(element, children, isRootNode, level) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
106
|
+
let template = isRootNode ? this._rootUlTemplate : this._groupUlTemplate;
|
|
107
|
+
let ul = template.cloneNode();
|
|
108
|
+
element.append(ul);
|
|
109
|
+
for (let child of children) {
|
|
110
|
+
let li = this._createLi(child, level);
|
|
111
|
+
ul.append(li);
|
|
112
|
+
if (this._mustRenderChildren(child)) {
|
|
97
113
|
this._createDomElements(li, child.children, false, level + 1);
|
|
98
114
|
}
|
|
99
115
|
}
|
|
116
|
+
return ul;
|
|
100
117
|
}
|
|
101
118
|
_createFolderLi(node, level, isSelected) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
let template = node.is_open ? this._openedFolderTemplate : this._closedFolderTemplate;
|
|
120
|
+
let li = template.cloneNode(true);
|
|
121
|
+
if (isSelected) {
|
|
122
|
+
li.classList.add(this._classNames.selected);
|
|
123
|
+
}
|
|
105
124
|
|
|
106
|
-
// li
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
// li > div > [toggler], title span, [toggler]
|
|
126
|
+
let div = li.firstChild;
|
|
127
|
+
let titleSpan = div.childNodes[this._buttonLeft ? 1 : 0];
|
|
128
|
+
this._fillTitleSpan(titleSpan, node.name, isSelected, level);
|
|
129
|
+
if (node.is_loading) {
|
|
130
|
+
li.classList.add(this._classNames.loading);
|
|
131
|
+
titleSpan.setAttribute("aria-busy", "true");
|
|
132
|
+
}
|
|
133
|
+
return li;
|
|
134
|
+
}
|
|
110
135
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
136
|
+
/* Template for a folder <li>:
|
|
137
|
+
* li > div > [toggler], title span, [toggler]
|
|
138
|
+
* The toggler icon and the aria-expanded attribute depend on the open
|
|
139
|
+
* state, so there is a template for each.
|
|
140
|
+
*/
|
|
141
|
+
_createFolderTemplate(isOpen) {
|
|
142
|
+
let liClasses = [this._classNames.common, this._classNames.folder];
|
|
143
|
+
if (!isOpen) {
|
|
144
|
+
liClasses.push(this._classNames.closed);
|
|
145
|
+
}
|
|
146
|
+
let li = this._createLiTemplate(liClasses.join(" "));
|
|
147
|
+
let div = li.firstChild;
|
|
116
148
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
149
|
+
// The toggler is hidden from screen readers: the icon is decoration, and
|
|
150
|
+
// aria-expanded on the treeitem has the open state.
|
|
151
|
+
let toggler = document.createElement("span");
|
|
152
|
+
toggler.className = this._getButtonClasses(isOpen);
|
|
153
|
+
toggler.setAttribute("aria-hidden", "true");
|
|
154
|
+
let iconElement = isOpen ? this._openedIconElement : this._closedIconElement;
|
|
120
155
|
if (iconElement) {
|
|
121
|
-
|
|
156
|
+
toggler.append(iconElement.cloneNode(true));
|
|
122
157
|
}
|
|
123
158
|
if (this._buttonLeft) {
|
|
124
|
-
div.
|
|
159
|
+
div.append(toggler);
|
|
125
160
|
}
|
|
126
161
|
|
|
127
162
|
// title span
|
|
128
|
-
|
|
129
|
-
titleSpan.setAttribute("aria-expanded", getBoolString(
|
|
130
|
-
div.
|
|
163
|
+
let titleSpan = this._createTitleSpanTemplate(true);
|
|
164
|
+
titleSpan.setAttribute("aria-expanded", getBoolString(isOpen));
|
|
165
|
+
div.append(titleSpan);
|
|
131
166
|
if (!this._buttonLeft) {
|
|
132
|
-
div.
|
|
167
|
+
div.append(toggler);
|
|
133
168
|
}
|
|
134
169
|
return li;
|
|
135
170
|
}
|
|
@@ -139,111 +174,135 @@ class ElementsRenderer {
|
|
|
139
174
|
* Call onCreateLi
|
|
140
175
|
*/
|
|
141
176
|
_createLi(node, level) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
177
|
+
let isSelected = this._isNodeSelected(node);
|
|
178
|
+
let mustShowFolder = node.isFolder() || node.isEmptyFolder && this._showEmptyFolder;
|
|
179
|
+
let li = mustShowFolder ? this._createFolderLi(node, level, isSelected) : this._createNodeLi(node, level, isSelected);
|
|
145
180
|
this._attachNodeData(node, li);
|
|
146
181
|
if (this._onCreateLi) {
|
|
147
182
|
this._onCreateLi(node, li, isSelected);
|
|
148
183
|
}
|
|
149
184
|
return li;
|
|
150
185
|
}
|
|
151
|
-
_createNodeLi(node, level, isSelected) {
|
|
152
|
-
const liClasses = [this._classNames.common];
|
|
153
|
-
if (isSelected) {
|
|
154
|
-
liClasses.push(this._classNames.selected);
|
|
155
|
-
}
|
|
156
|
-
const classString = liClasses.join(" ");
|
|
157
186
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
187
|
+
/*
|
|
188
|
+
Create the outer part of a <li> template: li > div
|
|
189
|
+
*/
|
|
190
|
+
_createLiTemplate(liClasses) {
|
|
191
|
+
let li = document.createElement("li");
|
|
192
|
+
li.className = liClasses;
|
|
161
193
|
li.setAttribute("role", "none");
|
|
162
|
-
|
|
163
|
-
// div
|
|
164
|
-
const div = document.createElement("div");
|
|
194
|
+
let div = document.createElement("div");
|
|
165
195
|
div.className = `${this._classNames.element} ${this._classNames.common}`;
|
|
166
196
|
div.setAttribute("role", "none");
|
|
167
|
-
li.
|
|
197
|
+
li.append(div);
|
|
198
|
+
return li;
|
|
199
|
+
}
|
|
200
|
+
_createNodeLi(node, level, isSelected) {
|
|
201
|
+
let li = this._nodeTemplate.cloneNode(true);
|
|
202
|
+
if (isSelected) {
|
|
203
|
+
li.classList.add(this._classNames.selected);
|
|
204
|
+
}
|
|
168
205
|
|
|
169
|
-
// title span
|
|
170
|
-
|
|
171
|
-
div.
|
|
206
|
+
// li > div > title span
|
|
207
|
+
let div = li.firstChild;
|
|
208
|
+
let titleSpan = div.firstChild;
|
|
209
|
+
this._fillTitleSpan(titleSpan, node.name, isSelected, level);
|
|
172
210
|
return li;
|
|
173
211
|
}
|
|
174
|
-
|
|
175
|
-
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
Template for a <li> without children: li > div > title span
|
|
215
|
+
*/
|
|
216
|
+
_createNodeTemplate() {
|
|
217
|
+
let li = this._createLiTemplate(this._classNames.common);
|
|
218
|
+
let div = li.firstChild;
|
|
219
|
+
div.append(this._createTitleSpanTemplate(false));
|
|
220
|
+
return li;
|
|
221
|
+
}
|
|
222
|
+
_createTitleSpanTemplate(isFolder) {
|
|
223
|
+
let titleSpan = document.createElement("span");
|
|
176
224
|
let classes = `${this._classNames.title} ${this._classNames.common}`;
|
|
177
225
|
if (isFolder) {
|
|
178
226
|
classes += ` ${this._classNames.titleFolder}`;
|
|
179
227
|
}
|
|
180
228
|
classes += ` ${this._buttonLeft ? this._classNames.titleButtonLeft : this._classNames.titleButtonRight}`;
|
|
181
229
|
titleSpan.className = classes;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
this._setTreeItemAriaAttributes(titleSpan, nodeName, level, isSelected);
|
|
189
|
-
if (this._autoEscape) {
|
|
190
|
-
titleSpan.textContent = nodeName;
|
|
191
|
-
} else {
|
|
192
|
-
titleSpan.innerHTML = nodeName;
|
|
230
|
+
titleSpan.setAttribute("role", "treeitem");
|
|
231
|
+
titleSpan.setAttribute("aria-selected", "false");
|
|
232
|
+
|
|
233
|
+
// Every node is focusable, but only the tab stop is in the tab order
|
|
234
|
+
if (this._tabIndex !== undefined) {
|
|
235
|
+
titleSpan.setAttribute("tabindex", "-1");
|
|
193
236
|
}
|
|
194
237
|
return titleSpan;
|
|
195
238
|
}
|
|
196
|
-
|
|
239
|
+
_createUlTemplate(isRootNode) {
|
|
197
240
|
let classString;
|
|
198
241
|
let role;
|
|
199
|
-
if (
|
|
200
|
-
classString = "";
|
|
201
|
-
role = "group";
|
|
202
|
-
} else {
|
|
242
|
+
if (isRootNode) {
|
|
203
243
|
classString = this._classNames.tree;
|
|
204
244
|
role = "tree";
|
|
205
245
|
if (this._rtl) {
|
|
206
246
|
classString += ` ${this._classNames.rtl}`;
|
|
207
247
|
}
|
|
248
|
+
} else {
|
|
249
|
+
classString = "";
|
|
250
|
+
role = "group";
|
|
208
251
|
}
|
|
209
252
|
if (this._dragAndDrop) {
|
|
210
253
|
classString += ` ${this._classNames.dnd}`;
|
|
211
254
|
}
|
|
212
|
-
|
|
255
|
+
let ul = document.createElement("ul");
|
|
213
256
|
ul.className = `${this._classNames.common} ${classString}`;
|
|
214
257
|
ul.setAttribute("role", role);
|
|
258
|
+
if (isRootNode) {
|
|
259
|
+
if (this._ariaLabel !== undefined) {
|
|
260
|
+
ul.setAttribute("aria-label", this._ariaLabel);
|
|
261
|
+
}
|
|
262
|
+
if (this._ariaLabelledBy !== undefined) {
|
|
263
|
+
ul.setAttribute("aria-labelledby", this._ariaLabelledBy);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
215
266
|
return ul;
|
|
216
267
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
268
|
+
|
|
269
|
+
/*
|
|
270
|
+
Set the parts of a cloned title span that differ per node
|
|
271
|
+
*/
|
|
272
|
+
_fillTitleSpan(titleSpan, nodeName, isSelected, level) {
|
|
273
|
+
titleSpan.setAttribute("aria-level", String(level));
|
|
274
|
+
if (isSelected) {
|
|
275
|
+
titleSpan.setAttribute("aria-selected", "true");
|
|
276
|
+
let tabIndex = this._tabIndex;
|
|
277
|
+
if (tabIndex !== undefined) {
|
|
278
|
+
titleSpan.setAttribute("tabindex", String(tabIndex));
|
|
279
|
+
}
|
|
221
280
|
}
|
|
222
|
-
if (this.
|
|
223
|
-
|
|
281
|
+
if (this._autoEscape) {
|
|
282
|
+
titleSpan.textContent = nodeName;
|
|
224
283
|
} else {
|
|
225
|
-
|
|
284
|
+
// eslint-disable-next-line no-unsanitized/property -- the user opted out of escaping with autoEscape: false
|
|
285
|
+
titleSpan.innerHTML = nodeName;
|
|
226
286
|
}
|
|
227
|
-
return classes.join(" ");
|
|
228
287
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (!
|
|
288
|
+
_getButtonClasses(isOpen) {
|
|
289
|
+
let classes = [this._classNames.toggler, this._classNames.common];
|
|
290
|
+
if (!isOpen) {
|
|
232
291
|
classes.push(this._classNames.closed);
|
|
233
292
|
}
|
|
234
|
-
if (
|
|
235
|
-
classes.push(this._classNames.
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
classes.push(this._classNames.loading);
|
|
293
|
+
if (this._buttonLeft) {
|
|
294
|
+
classes.push(this._classNames.togglerLeft);
|
|
295
|
+
} else {
|
|
296
|
+
classes.push(this._classNames.togglerRight);
|
|
239
297
|
}
|
|
240
298
|
return classes.join(" ");
|
|
241
299
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
The children of a closed folder are rendered when it is opened
|
|
303
|
+
*/
|
|
304
|
+
_mustRenderChildren(node) {
|
|
305
|
+
return node.hasChildren() && node.is_open === true;
|
|
247
306
|
}
|
|
248
307
|
}
|
|
249
308
|
|