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.
Files changed (155) hide show
  1. package/README.md +43 -31
  2. package/lib/animation.d.ts +2 -2
  3. package/lib/animation.d.ts.map +1 -1
  4. package/lib/animation.js +16 -12
  5. package/lib/animation.js.map +1 -1
  6. package/lib/classNames.d.ts.map +1 -1
  7. package/lib/classNames.js +2 -2
  8. package/lib/classNames.js.map +1 -1
  9. package/lib/dataLoader.d.ts +1 -0
  10. package/lib/dataLoader.d.ts.map +1 -1
  11. package/lib/dataLoader.js +22 -20
  12. package/lib/dataLoader.js.map +1 -1
  13. package/lib/dragAndDropHandler/binarySearch.js +3 -3
  14. package/lib/dragAndDropHandler/binarySearch.js.map +1 -1
  15. package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -1
  16. package/lib/dragAndDropHandler/dragElement.js +11 -13
  17. package/lib/dragAndDropHandler/dragElement.js.map +1 -1
  18. package/lib/dragAndDropHandler/generateHitAreas.d.ts.map +1 -1
  19. package/lib/dragAndDropHandler/generateHitAreas.js +25 -25
  20. package/lib/dragAndDropHandler/generateHitAreas.js.map +1 -1
  21. package/lib/dragAndDropHandler/index.d.ts.map +1 -1
  22. package/lib/dragAndDropHandler/index.js +125 -158
  23. package/lib/dragAndDropHandler/index.js.map +1 -1
  24. package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -1
  25. package/lib/dragAndDropHandler/iterateVisibleNodes.js +23 -22
  26. package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -1
  27. package/lib/dragAndDropHandler/types.d.ts.map +1 -1
  28. package/lib/elementsRenderer.d.ts +20 -7
  29. package/lib/elementsRenderer.d.ts.map +1 -1
  30. package/lib/elementsRenderer.js +195 -136
  31. package/lib/elementsRenderer.js.map +1 -1
  32. package/lib/events.d.ts +44 -11
  33. package/lib/events.d.ts.map +1 -1
  34. package/lib/index.d.ts +36 -13
  35. package/lib/index.d.ts.map +1 -1
  36. package/lib/index.js +386 -349
  37. package/lib/index.js.map +1 -1
  38. package/lib/keyHandler.d.ts +13 -8
  39. package/lib/keyHandler.d.ts.map +1 -1
  40. package/lib/keyHandler.js +106 -51
  41. package/lib/keyHandler.js.map +1 -1
  42. package/lib/methodTypes.d.ts +3 -3
  43. package/lib/methodTypes.d.ts.map +1 -1
  44. package/lib/mouseHandler.d.ts +1 -1
  45. package/lib/mouseHandler.d.ts.map +1 -1
  46. package/lib/mouseHandler.js +36 -49
  47. package/lib/mouseHandler.js.map +1 -1
  48. package/lib/mouseUtils.d.ts.map +1 -1
  49. package/lib/mouseUtils.js +2 -2
  50. package/lib/mouseUtils.js.map +1 -1
  51. package/lib/node.d.ts +47 -16
  52. package/lib/node.d.ts.map +1 -1
  53. package/lib/node.js +169 -171
  54. package/lib/node.js.map +1 -1
  55. package/lib/nodeElement/borderDropHint.d.ts.map +1 -1
  56. package/lib/nodeElement/borderDropHint.js +4 -5
  57. package/lib/nodeElement/borderDropHint.js.map +1 -1
  58. package/lib/nodeElement/folderElement.d.ts +8 -5
  59. package/lib/nodeElement/folderElement.d.ts.map +1 -1
  60. package/lib/nodeElement/folderElement.js +75 -67
  61. package/lib/nodeElement/folderElement.js.map +1 -1
  62. package/lib/nodeElement/ghostDropHint.d.ts.map +1 -1
  63. package/lib/nodeElement/ghostDropHint.js +13 -13
  64. package/lib/nodeElement/ghostDropHint.js.map +1 -1
  65. package/lib/nodeElement/index.d.ts +2 -1
  66. package/lib/nodeElement/index.d.ts.map +1 -1
  67. package/lib/nodeElement/index.js +38 -30
  68. package/lib/nodeElement/index.js.map +1 -1
  69. package/lib/nodeUtils.d.ts.map +1 -1
  70. package/lib/nodeUtils.js +1 -1
  71. package/lib/nodeUtils.js.map +1 -1
  72. package/lib/options.d.ts +19 -3
  73. package/lib/options.d.ts.map +1 -1
  74. package/lib/positionUtils.js +3 -3
  75. package/lib/positionUtils.js.map +1 -1
  76. package/lib/requestUrl.d.ts +1 -1
  77. package/lib/requestUrl.d.ts.map +1 -1
  78. package/lib/requestUrl.js +6 -17
  79. package/lib/requestUrl.js.map +1 -1
  80. package/lib/saveStateHandler.d.ts.map +1 -1
  81. package/lib/saveStateHandler.js +59 -89
  82. package/lib/saveStateHandler.js.map +1 -1
  83. package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -1
  84. package/lib/scrollHandler/containerScrollParent.js +11 -18
  85. package/lib/scrollHandler/containerScrollParent.js.map +1 -1
  86. package/lib/scrollHandler/createScrollParent.d.ts.map +1 -1
  87. package/lib/scrollHandler/createScrollParent.js +12 -13
  88. package/lib/scrollHandler/createScrollParent.js.map +1 -1
  89. package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -1
  90. package/lib/scrollHandler/documentScrollParent.js +18 -27
  91. package/lib/scrollHandler/documentScrollParent.js.map +1 -1
  92. package/lib/scrollHandler/scrollParent.d.ts.map +1 -1
  93. package/lib/scrollHandler/scrollParent.js +30 -34
  94. package/lib/scrollHandler/scrollParent.js.map +1 -1
  95. package/lib/scrollHandler.d.ts.map +1 -1
  96. package/lib/scrollHandler.js +11 -14
  97. package/lib/scrollHandler.js.map +1 -1
  98. package/lib/selectNodeHandler.d.ts +4 -2
  99. package/lib/selectNodeHandler.d.ts.map +1 -1
  100. package/lib/selectNodeHandler.js +64 -83
  101. package/lib/selectNodeHandler.js.map +1 -1
  102. package/lib/setDefaultOptions.d.ts.map +1 -1
  103. package/lib/setDefaultOptions.js +34 -38
  104. package/lib/setDefaultOptions.js.map +1 -1
  105. package/lib/triggerCustomEvent.d.ts.map +1 -1
  106. package/lib/triggerCustomEvent.js +2 -2
  107. package/lib/triggerCustomEvent.js.map +1 -1
  108. package/lib/util.d.ts.map +1 -1
  109. package/lib/util.js +2 -2
  110. package/lib/util.js.map +1 -1
  111. package/lib/version.d.ts +1 -1
  112. package/lib/version.js +1 -1
  113. package/lib/version.js.map +1 -1
  114. package/package.json +43 -32
  115. package/src/animation.ts +14 -12
  116. package/src/classNames.ts +52 -52
  117. package/src/dataLoader.ts +79 -71
  118. package/src/dragAndDropHandler/binarySearch.ts +17 -17
  119. package/src/dragAndDropHandler/dragElement.ts +51 -50
  120. package/src/dragAndDropHandler/generateHitAreas.ts +156 -161
  121. package/src/dragAndDropHandler/index.ts +334 -348
  122. package/src/dragAndDropHandler/iterateVisibleNodes.ts +61 -63
  123. package/src/dragAndDropHandler/types.ts +5 -5
  124. package/src/elementsRenderer.ts +377 -294
  125. package/src/events.ts +241 -208
  126. package/src/header.txt +1 -1
  127. package/src/index.ts +259 -229
  128. package/src/keyHandler.ts +179 -115
  129. package/src/methodTypes.ts +7 -10
  130. package/src/mouseHandler.ts +316 -316
  131. package/src/mouseUtils.ts +14 -14
  132. package/src/node.ts +773 -771
  133. package/src/nodeElement/borderDropHint.ts +25 -25
  134. package/src/nodeElement/folderElement.ts +116 -102
  135. package/src/nodeElement/ghostDropHint.ts +64 -62
  136. package/src/nodeElement/index.ts +81 -73
  137. package/src/nodeUtils.ts +5 -5
  138. package/src/options.ts +25 -5
  139. package/src/requestUrl.ts +7 -14
  140. package/src/saveStateHandler.ts +191 -207
  141. package/src/scrollHandler/containerScrollParent.ts +40 -49
  142. package/src/scrollHandler/createScrollParent.ts +26 -27
  143. package/src/scrollHandler/documentScrollParent.ts +66 -72
  144. package/src/scrollHandler/scrollParent.ts +90 -86
  145. package/src/scrollHandler.ts +45 -45
  146. package/src/selectNodeHandler.ts +171 -165
  147. package/src/setDefaultOptions.ts +44 -32
  148. package/src/triggerCustomEvent.ts +7 -3
  149. package/src/util.ts +2 -3
  150. package/src/version.ts +1 -1
  151. package/tree_element.css +87 -69
  152. package/tree_element.debug.js +3866 -3831
  153. package/tree_element.debug.js.map +1 -1
  154. package/tree_element.js +2 -2
  155. package/tree_element.js.map +1 -1
@@ -1,12 +1,12 @@
1
- const iterateVisibleNodes = (tree, {
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
- const iterate = (node, nextNode) => {
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
- const childrenLength = node.children.length;
32
- node.children.forEach((_, i) => {
33
- const child = node.children[i];
34
- if (child) {
35
- if (i === childrenLength - 1) {
36
- iterate(child, null);
37
- } else {
38
- const nextChild = node.children[i + 1];
39
- if (nextChild) {
40
- iterate(child, nextChild);
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 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: (\n node: Node,\n nextNode: Node | null,\n element: HTMLElement,\n ) => 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 const childrenLength = node.children.length;\n node.children.forEach((_, i) => {\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\n iterate(tree, null);\n};\n\nexport default iterateVisibleNodes;\n"],"names":[],"mappings":"AAyBA,MAAM,mBAAmB,GAAG,CACxB,IAAU,EACV;EACI,qBAAqB;EACrB,kBAAkB;EAClB,eAAe;EACf,UAAU;AACV,EAAA;AACK,CAAC,KACT;EACD,IAAI,WAAW,GAAG,IAAI;AAEtB,EAAA,MAAM,OAAO,GAAG,CAAC,IAAU,EAAE,QAAqB,KAAW;AACzD,IAAA,IAAI,iBAAiB,GACjB,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,WAAW,EAAE;IAElE,IAAI,OAA2B,GAAG,IAAI;;AAEtC;AACA,IAAA,IAAI,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE;MAC5B,OAAO,GAAG,IAAI,CAAC,OAAO;AAEtB,MAAA,IAAI,WAAW,EAAE;QACb,eAAe,CAAC,IAAI,CAAC;AACrB,QAAA,WAAW,GAAG,KAAK;AACvB,MAAA;AAEA,MAAA,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE;QACrB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC;AAC5C,MAAA,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE;QACrB,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE;AACvC,UAAA,iBAAiB,GAAG,KAAK;AAC7B,QAAA;AACJ,MAAA,CAAC,MAAM;AACH,QAAA,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC;AAC/C,MAAA;AACJ,IAAA;AAEA,IAAA,IAAI,iBAAiB,EAAE;AACnB,MAAA,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM;MAC3C,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AAC5B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE9B,QAAA,IAAI,KAAK,EAAE;AACP,UAAA,IAAI,CAAC,KAAK,cAAc,GAAG,CAAC,EAAE;AAC1B,YAAA,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;AACxB,UAAA,CAAC,MAAM;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;AAEtC,YAAA,IAAI,SAAS,EAAE;AACX,cAAA,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC;AAC7B,YAAA;AACJ,UAAA;AACJ,QAAA;AACJ,MAAA,CAAC,CAAC;AAEF,MAAA,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,EAAE;AACzB,QAAA,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC;AACzC,MAAA;AACJ,IAAA;EACJ,CAAC;AAED,EAAA,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;AACvB;;"}
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;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACf"}
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?: HTMLElement | Text;
23
- openedIconElement?: HTMLElement | Text;
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 createTitleSpan;
47
- private createUl;
58
+ private createNodeTemplate;
59
+ private createTitleSpanTemplate;
60
+ private createUlTemplate;
61
+ private fillTitleSpan;
48
62
  private getButtonClasses;
49
- private getFolderClasses;
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;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC3D,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,CAAC,OAAO,OAAO,gBAAgB;IAC1B,iBAAiB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACvC,iBAAiB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9C,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,GAAG,CAAC,CAAU;IACtB,OAAO,CAAC,cAAc,CAA6C;IACnE,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,CAAS;gBAEd,EACR,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,OAAO,EACP,WAAW,EACX,cAAc,EACd,UAAU,EACV,UAAU,EACV,GAAG,EACH,cAAc,EACd,eAAe,EACf,QAAQ,GACX,EAAE,sBAAsB;IAiBlB,MAAM,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI;IAQnC,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAahC,cAAc,IAAI,IAAI;IAU7B,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,cAAc;IAyDtB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,YAAY;IAqCpB,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,QAAQ;IA4BhB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,yBAAyB;CAWpC"}
1
+ {"version":3,"file":"elementsRenderer.d.ts","sourceRoot":"","sources":["../src/elementsRenderer.ts"],"names":[],"mappings":"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"}
@@ -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
- autoEscape,
20
- buttonLeft,
21
- classNames,
22
- closedIcon,
23
- dragAndDrop,
24
- getTree,
25
- htmlElement,
26
- isNodeSelected,
27
- onCreateLi,
28
- openedIcon,
29
- rtl,
30
- setNodeElement,
31
- showEmptyFolder,
32
- tabIndex
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.openedIconElement = this._createButtonElement(openedIcon ?? "+");
47
- this.closedIconElement = this._createButtonElement(closedIcon ?? "-");
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
- render(fromNode) {
55
+ _render(fromNode) {
50
56
  if (fromNode?.parent) {
51
- this.renderFromNode(fromNode);
57
+ this._renderFromNode(fromNode);
52
58
  } else {
53
- this.renderFromRoot();
59
+ this._renderFromRoot();
54
60
  }
55
61
  }
56
- renderFromNode(node) {
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
- const currentLi = node.element;
61
- const newLi = this._createLi(node, node.getLevel());
73
+ let currentLi = node.element;
74
+ let newLi = this._createLi(node, node.getLevel());
62
75
  currentLi.replaceWith(newLi);
63
-
64
- // create children
65
- this._createDomElements(newLi, node.children, false, node.getLevel() + 1);
76
+ if (this._mustRenderChildren(node)) {
77
+ this._createDomElements(newLi, node.children, false, node.getLevel() + 1);
78
+ }
66
79
  }
67
- renderFromRoot() {
68
- this._htmlElement.textContent = '';
69
- const tree = this._getTree();
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
- // convert value to html
81
- const div = document.createElement("div");
82
- div.innerHTML = value;
83
- return document.createTextNode(div.innerHTML);
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
- const ul = this._createUl(isRootNode);
92
- element.appendChild(ul);
93
- for (const child of children) {
94
- const li = this._createLi(child, level);
95
- ul.appendChild(li);
96
- if (child.hasChildren()) {
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
- const buttonClasses = this._getButtonClasses(node);
103
- const folderClasses = this._getFolderClasses(node, isSelected);
104
- const iconElement = node.is_open ? this.openedIconElement : this.closedIconElement;
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
- const li = document.createElement("li");
108
- li.className = `${this._classNames.common} ${folderClasses}`;
109
- li.setAttribute("role", "none");
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
- // div
112
- const div = document.createElement("div");
113
- div.className = `${this._classNames.element} ${this._classNames.common}`;
114
- div.setAttribute("role", "none");
115
- li.appendChild(div);
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
- // button link
118
- const buttonLink = document.createElement("a");
119
- buttonLink.className = buttonClasses;
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
- buttonLink.appendChild(iconElement.cloneNode(true));
156
+ toggler.append(iconElement.cloneNode(true));
122
157
  }
123
158
  if (this._buttonLeft) {
124
- div.appendChild(buttonLink);
159
+ div.append(toggler);
125
160
  }
126
161
 
127
162
  // title span
128
- const titleSpan = this._createTitleSpan(node.name, isSelected, true, level);
129
- titleSpan.setAttribute("aria-expanded", getBoolString(node.is_open));
130
- div.appendChild(titleSpan);
163
+ let titleSpan = this._createTitleSpanTemplate(true);
164
+ titleSpan.setAttribute("aria-expanded", getBoolString(isOpen));
165
+ div.append(titleSpan);
131
166
  if (!this._buttonLeft) {
132
- div.appendChild(buttonLink);
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
- const isSelected = this._isNodeSelected(node);
143
- const mustShowFolder = node.isFolder() || node.isEmptyFolder && this._showEmptyFolder;
144
- const li = mustShowFolder ? this._createFolderLi(node, level, isSelected) : this._createNodeLi(node, level, isSelected);
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
- // li
159
- const li = document.createElement("li");
160
- li.className = classString;
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.appendChild(div);
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
- const titleSpan = this._createTitleSpan(node.name, isSelected, false, level);
171
- div.appendChild(titleSpan);
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
- _createTitleSpan(nodeName, isSelected, isFolder, level) {
175
- const titleSpan = document.createElement("span");
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
- if (isSelected) {
183
- const tabIndex = this._tabIndex;
184
- if (tabIndex !== undefined) {
185
- titleSpan.setAttribute("tabindex", `${tabIndex}`);
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
- _createUl(isRootNode) {
239
+ _createUlTemplate(isRootNode) {
197
240
  let classString;
198
241
  let role;
199
- if (!isRootNode) {
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
- const ul = document.createElement("ul");
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
- _getButtonClasses(node) {
218
- const classes = [this._classNames.toggler, this._classNames.common];
219
- if (!node.is_open) {
220
- classes.push(this._classNames.closed);
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._buttonLeft) {
223
- classes.push(this._classNames.togglerLeft);
281
+ if (this._autoEscape) {
282
+ titleSpan.textContent = nodeName;
224
283
  } else {
225
- classes.push(this._classNames.togglerRight);
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
- _getFolderClasses(node, isSelected) {
230
- const classes = [this._classNames.folder];
231
- if (!node.is_open) {
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 (isSelected) {
235
- classes.push(this._classNames.selected);
236
- }
237
- if (node.is_loading) {
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
- _setTreeItemAriaAttributes(element, name, level, isSelected) {
243
- element.setAttribute("aria-label", name);
244
- element.setAttribute("aria-level", `${level}`);
245
- element.setAttribute("aria-selected", getBoolString(isSelected));
246
- element.setAttribute("role", "treeitem");
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