tree-element 0.2.0 → 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 (121) hide show
  1. package/README.md +12 -4
  2. package/lib/animation.d.ts +2 -2
  3. package/lib/animation.d.ts.map +1 -1
  4. package/lib/animation.js +13 -9
  5. package/lib/animation.js.map +1 -1
  6. package/lib/dataLoader.d.ts +1 -0
  7. package/lib/dataLoader.d.ts.map +1 -1
  8. package/lib/dataLoader.js +8 -0
  9. package/lib/dataLoader.js.map +1 -1
  10. package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -1
  11. package/lib/dragAndDropHandler/dragElement.js +2 -1
  12. package/lib/dragAndDropHandler/dragElement.js.map +1 -1
  13. package/lib/dragAndDropHandler/index.d.ts.map +1 -1
  14. package/lib/dragAndDropHandler/index.js +56 -65
  15. package/lib/dragAndDropHandler/index.js.map +1 -1
  16. package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -1
  17. package/lib/dragAndDropHandler/iterateVisibleNodes.js +16 -15
  18. package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -1
  19. package/lib/elementsRenderer.d.ts +5 -1
  20. package/lib/elementsRenderer.d.ts.map +1 -1
  21. package/lib/elementsRenderer.js +62 -39
  22. package/lib/elementsRenderer.js.map +1 -1
  23. package/lib/events.d.ts +44 -11
  24. package/lib/events.d.ts.map +1 -1
  25. package/lib/index.d.ts +31 -8
  26. package/lib/index.d.ts.map +1 -1
  27. package/lib/index.js +162 -122
  28. package/lib/index.js.map +1 -1
  29. package/lib/keyHandler.d.ts +11 -5
  30. package/lib/keyHandler.d.ts.map +1 -1
  31. package/lib/keyHandler.js +87 -33
  32. package/lib/keyHandler.js.map +1 -1
  33. package/lib/methodTypes.d.ts +2 -2
  34. package/lib/methodTypes.d.ts.map +1 -1
  35. package/lib/mouseHandler.d.ts +1 -1
  36. package/lib/mouseHandler.d.ts.map +1 -1
  37. package/lib/mouseHandler.js +10 -7
  38. package/lib/mouseHandler.js.map +1 -1
  39. package/lib/node.d.ts +45 -15
  40. package/lib/node.d.ts.map +1 -1
  41. package/lib/node.js +136 -139
  42. package/lib/node.js.map +1 -1
  43. package/lib/nodeElement/folderElement.d.ts +1 -1
  44. package/lib/nodeElement/folderElement.d.ts.map +1 -1
  45. package/lib/nodeElement/folderElement.js +46 -57
  46. package/lib/nodeElement/folderElement.js.map +1 -1
  47. package/lib/nodeElement/ghostDropHint.d.ts.map +1 -1
  48. package/lib/nodeElement/ghostDropHint.js +8 -4
  49. package/lib/nodeElement/ghostDropHint.js.map +1 -1
  50. package/lib/nodeElement/index.d.ts.map +1 -1
  51. package/lib/nodeElement/index.js +6 -6
  52. package/lib/nodeElement/index.js.map +1 -1
  53. package/lib/nodeUtils.d.ts.map +1 -1
  54. package/lib/nodeUtils.js +1 -1
  55. package/lib/nodeUtils.js.map +1 -1
  56. package/lib/options.d.ts +19 -3
  57. package/lib/options.d.ts.map +1 -1
  58. package/lib/requestUrl.d.ts.map +1 -1
  59. package/lib/requestUrl.js +2 -11
  60. package/lib/requestUrl.js.map +1 -1
  61. package/lib/saveStateHandler.d.ts.map +1 -1
  62. package/lib/saveStateHandler.js +21 -41
  63. package/lib/saveStateHandler.js.map +1 -1
  64. package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -1
  65. package/lib/scrollHandler/containerScrollParent.js +3 -8
  66. package/lib/scrollHandler/containerScrollParent.js.map +1 -1
  67. package/lib/scrollHandler/createScrollParent.d.ts.map +1 -1
  68. package/lib/scrollHandler/createScrollParent.js +4 -5
  69. package/lib/scrollHandler/createScrollParent.js.map +1 -1
  70. package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -1
  71. package/lib/scrollHandler/documentScrollParent.js +3 -9
  72. package/lib/scrollHandler/documentScrollParent.js.map +1 -1
  73. package/lib/scrollHandler/scrollParent.d.ts.map +1 -1
  74. package/lib/scrollHandler/scrollParent.js +19 -17
  75. package/lib/scrollHandler/scrollParent.js.map +1 -1
  76. package/lib/selectNodeHandler.d.ts +3 -1
  77. package/lib/selectNodeHandler.d.ts.map +1 -1
  78. package/lib/selectNodeHandler.js +27 -37
  79. package/lib/selectNodeHandler.js.map +1 -1
  80. package/lib/setDefaultOptions.d.ts.map +1 -1
  81. package/lib/setDefaultOptions.js +11 -10
  82. package/lib/setDefaultOptions.js.map +1 -1
  83. package/lib/util.d.ts.map +1 -1
  84. package/lib/util.js +1 -1
  85. package/lib/util.js.map +1 -1
  86. package/lib/version.d.ts +1 -1
  87. package/lib/version.js +1 -1
  88. package/lib/version.js.map +1 -1
  89. package/package.json +42 -33
  90. package/src/animation.ts +13 -11
  91. package/src/dataLoader.ts +11 -0
  92. package/src/dragAndDropHandler/dragElement.ts +2 -1
  93. package/src/dragAndDropHandler/index.ts +70 -75
  94. package/src/dragAndDropHandler/iterateVisibleNodes.ts +18 -16
  95. package/src/elementsRenderer.ts +76 -46
  96. package/src/events.ts +44 -11
  97. package/src/index.ts +210 -150
  98. package/src/keyHandler.ts +95 -41
  99. package/src/methodTypes.ts +3 -3
  100. package/src/mouseHandler.ts +10 -7
  101. package/src/node.ts +155 -148
  102. package/src/nodeElement/folderElement.ts +54 -63
  103. package/src/nodeElement/ghostDropHint.ts +4 -2
  104. package/src/nodeElement/index.ts +9 -15
  105. package/src/nodeUtils.ts +1 -1
  106. package/src/options.ts +19 -3
  107. package/src/requestUrl.ts +4 -11
  108. package/src/saveStateHandler.ts +29 -43
  109. package/src/scrollHandler/containerScrollParent.ts +3 -9
  110. package/src/scrollHandler/createScrollParent.ts +1 -2
  111. package/src/scrollHandler/documentScrollParent.ts +5 -11
  112. package/src/scrollHandler/scrollParent.ts +29 -25
  113. package/src/selectNodeHandler.ts +34 -38
  114. package/src/setDefaultOptions.ts +19 -10
  115. package/src/util.ts +1 -2
  116. package/src/version.ts +1 -1
  117. package/tree_element.css +87 -69
  118. package/tree_element.debug.js +706 -639
  119. package/tree_element.debug.js.map +1 -1
  120. package/tree_element.js +2 -2
  121. package/tree_element.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tree_element.js","sources":["src/dataLoader.ts","src/positionUtils.ts","src/dragAndDropHandler/dragElement.ts","src/dragAndDropHandler/iterateVisibleNodes.ts","src/dragAndDropHandler/generateHitAreas.ts","src/dragAndDropHandler/index.ts","src/dragAndDropHandler/binarySearch.ts","src/elementsRenderer.ts","src/util.ts","src/keyHandler.ts","src/mouseUtils.ts","src/mouseHandler.ts","src/nodeUtils.ts","src/node.ts","src/nodeElement/borderDropHint.ts","src/nodeElement/ghostDropHint.ts","src/nodeElement/index.ts","src/animation.ts","src/nodeElement/folderElement.ts","src/requestUrl.ts","src/saveStateHandler.ts","src/scrollHandler/scrollParent.ts","src/scrollHandler/containerScrollParent.ts","src/scrollHandler/documentScrollParent.ts","src/scrollHandler/createScrollParent.ts","src/scrollHandler.ts","src/selectNodeHandler.ts","src/setDefaultOptions.ts","src/classNames.ts","src/triggerCustomEvent.ts","src/index.ts","src/version.ts"],"sourcesContent":["import type { ClassNames } from \"./classNames\";\nimport type { LoadData, TriggerEvent } from \"./methodTypes\";\nimport type { Node, NodeData } from \"./node\";\nimport type { DataFilter } from \"./options\";\nimport type RequestUrl from \"./requestUrl\";\n\ninterface DataLoaderParams {\n classNames: ClassNames;\n dataFilter?: DataFilter;\n loadData: LoadData;\n treeElement: HTMLElement;\n triggerEvent: TriggerEvent;\n}\n\nexport default class DataLoader {\n private abortController: AbortController;\n private classNames: ClassNames;\n private dataFilter?: DataFilter;\n private loadData: LoadData;\n private treeElement: HTMLElement;\n private triggerEvent: TriggerEvent;\n\n constructor({\n classNames,\n dataFilter,\n loadData,\n treeElement,\n triggerEvent,\n }: DataLoaderParams) {\n this.abortController = new AbortController();\n this.classNames = classNames;\n this.dataFilter = dataFilter;\n this.loadData = loadData;\n this.treeElement = treeElement;\n this.triggerEvent = triggerEvent;\n }\n\n public deinit(): void {\n this.abortController.abort();\n }\n\n public async loadFromUrl(url: RequestUrl, node?: Node): Promise<void> {\n const element = node?.element ?? this.treeElement;\n element.classList.add(this.classNames.loading);\n\n this.triggerEvent(\"tree.loading_data\", {\n element,\n node,\n });\n\n const stopLoading = (): void => {\n element.classList.remove(this.classNames.loading);\n this.triggerEvent(\"tree.loaded_data\", {\n element,\n node,\n });\n };\n\n const handleResponse = async (response: Response): Promise<void> => {\n if (response.ok) {\n const data = (await response.json()) as NodeData[];\n\n stopLoading();\n this.loadData(this.dataFilter ? this.dataFilter(data) : data, node);\n } else {\n stopLoading();\n\n this.triggerEvent(\"tree.load_failed\", { response });\n }\n };\n\n const signal = this.abortController.signal;\n url.setSearchParam(\"_\", Date.now().toString());\n\n return fetch(url.value(), {\n headers: { \"Content-Type\": \"application/json\" },\n signal,\n })\n .then(handleResponse)\n .catch((error: unknown) => {\n if (this.abortController.signal.aborted) {\n // The request was aborted by deinit.\n return;\n }\n\n stopLoading();\n this.triggerEvent(\"tree.load_failed\", { error });\n });\n }\n}\n","interface TopLeftPosition {\n left: number;\n top: number;\n}\n\n// Get the top position of the HTML element.\nexport const getOffsetTop = (element: HTMLElement): number =>\n getElementPosition(element).top;\n\n// Get the top left position of the HTML element.\nexport const getElementPosition = (element: HTMLElement): TopLeftPosition => {\n const rect = element.getBoundingClientRect();\n\n return {\n left: rect.x + window.scrollX,\n top: rect.y + window.scrollY,\n };\n};\n","import type { ClassNames } from \"../classNames\";\n\ninterface DragElementParams {\n autoEscape: boolean;\n classNames: ClassNames;\n nodeName: string;\n offsetX: number;\n offsetY: number;\n treeElement: HTMLElement;\n}\n\nclass DragElement {\n private element: HTMLElement;\n private offsetX: number;\n private offsetY: number;\n\n constructor({\n autoEscape,\n classNames,\n nodeName,\n offsetX,\n offsetY,\n treeElement,\n }: DragElementParams) {\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n\n this.element = this.createElement(nodeName, autoEscape, classNames);\n\n treeElement.appendChild(this.element);\n }\n\n public move(pageX: number, pageY: number): void {\n this.element.style.left = `${pageX - this.offsetX}px`;\n this.element.style.top = `${pageY - this.offsetY}px`;\n }\n\n public remove(): void {\n this.element.remove();\n }\n\n private createElement(\n nodeName: string,\n autoEscape: boolean,\n classNames: ClassNames,\n ) {\n const element = document.createElement(\"span\");\n element.classList.add(classNames.title, classNames.dragging);\n\n if (autoEscape) {\n element.textContent = nodeName;\n } else {\n element.innerHTML = nodeName;\n }\n\n element.style.position = \"absolute\";\n\n return element;\n }\n}\n\nexport default DragElement;\n","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 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","import type { Node, Position } from \"../node\";\nimport type { HitArea } from \"./types\";\n\nimport { getOffsetTop } from \"../positionUtils\";\nimport iterateVisibleNodes from \"./iterateVisibleNodes\";\n\ninterface HitPosition {\n node: Node;\n position: null | Position;\n top: number;\n}\n\nexport const generateHitPositions = (\n tree: Node,\n currentNode: Node,\n): HitPosition[] => {\n const hitPositions: HitPosition[] = [];\n let lastTop = 0;\n\n const addHitPosition = (\n node: Node,\n position: null | Position,\n top: number,\n ) => {\n hitPositions.push({\n node,\n position,\n top,\n });\n lastTop = top;\n };\n\n const handleAfterOpenFolder = (node: Node, nextNode: Node | null) => {\n if (node === currentNode || nextNode === currentNode) {\n // Cannot move before or after current item\n addHitPosition(node, null, lastTop);\n } else {\n addHitPosition(node, \"after\", lastTop);\n }\n };\n\n const handleClosedFolder = (\n node: Node,\n nextNode: Node | null,\n element: HTMLElement,\n ) => {\n const top = getOffsetTop(element);\n\n if (node === currentNode) {\n // Cannot move after current item\n addHitPosition(node, null, top);\n } else {\n addHitPosition(node, \"inside\", top);\n\n // Cannot move before current item\n if (nextNode !== currentNode) {\n addHitPosition(node, \"after\", top);\n }\n }\n };\n\n const handleFirstNode = (node: Node) => {\n if (node !== currentNode && node.element) {\n addHitPosition(node, \"before\", getOffsetTop(node.element));\n }\n };\n\n const handleNode = (\n node: Node,\n nextNode: Node | null,\n element: HTMLElement,\n ) => {\n const top = getOffsetTop(element);\n\n if (node === currentNode) {\n // Cannot move inside current item\n addHitPosition(node, null, top);\n } else {\n addHitPosition(node, \"inside\", top);\n }\n\n if (nextNode === currentNode || node === currentNode) {\n // Cannot move before or after current item\n addHitPosition(node, null, top);\n } else {\n addHitPosition(node, \"after\", top);\n }\n };\n\n const handleOpenFolder = (node: Node, element: HTMLElement) => {\n if (node === currentNode) {\n // Cannot move inside current item\n\n // Dnd over the current element is not possible: add a position with type None for the top and the bottom.\n const top = getOffsetTop(element);\n const height = element.clientHeight;\n addHitPosition(node, null, top);\n\n if (height > 5) {\n // Subtract 5 pixels to allow more space for the next element.\n addHitPosition(node, null, top + height - 5);\n }\n\n // Stop iterating\n return false;\n }\n\n // Cannot move before current item\n if (node.children[0] !== currentNode) {\n addHitPosition(node, \"inside\", getOffsetTop(element));\n }\n\n // Continue iterating\n return true;\n };\n\n iterateVisibleNodes(tree, {\n handleAfterOpenFolder,\n handleClosedFolder,\n handleFirstNode,\n handleNode,\n handleOpenFolder,\n });\n\n return hitPositions;\n};\n\nexport const generateHitAreasForGroup = (\n hitAreas: HitArea[],\n positionsInGroup: HitPosition[],\n top: number,\n bottom: number,\n) => {\n // limit positions in group\n const positionCount = Math.min(positionsInGroup.length, 4);\n\n const areaHeight = Math.round((bottom - top) / positionCount);\n let areaTop = top;\n\n for (let i = 0; i < positionCount; i++) {\n const position = positionsInGroup[i] as HitPosition;\n\n if (position.position) {\n hitAreas.push({\n bottom: areaTop + areaHeight,\n node: position.node,\n position: position.position,\n top: areaTop,\n });\n }\n\n areaTop += areaHeight;\n }\n};\n\nexport const generateHitAreasFromPositions = (\n hitPositions: HitPosition[],\n treeBottom: number,\n): HitArea[] => {\n if (!hitPositions.length) {\n return [];\n }\n\n let previousTop = (hitPositions[0] as HitPosition).top;\n let group: HitPosition[] = [];\n const hitAreas: HitArea[] = [];\n\n for (const position of hitPositions) {\n if (position.top !== previousTop && group.length) {\n generateHitAreasForGroup(hitAreas, group, previousTop, position.top);\n\n previousTop = position.top;\n group = [];\n }\n\n group.push(position);\n }\n\n generateHitAreasForGroup(hitAreas, group, previousTop, treeBottom);\n\n return hitAreas;\n};\n\nconst generateHitAreas = (tree: Node, currentNode: Node, treeBottom: number) =>\n generateHitAreasFromPositions(\n generateHitPositions(tree, currentNode),\n treeBottom,\n );\n\nexport default generateHitAreas;\n","import type { ClassNames } from \"../classNames\";\nimport type {\n GetScrollLeft,\n GetTree,\n OpenNode,\n RefreshElements,\n TriggerEvent,\n} from \"../methodTypes\";\nimport type { PositionInfo } from \"../mouseUtils\";\nimport type { Node } from \"../node\";\nimport type NodeElement from \"../nodeElement\";\nimport type {\n DragMethod,\n OnCanMove,\n OnCanMoveTo,\n OnIsMoveHandle,\n} from \"../options\";\nimport type { DropHint, HitArea } from \"./types\";\n\nimport { getElementPosition } from \"../positionUtils\";\nimport binarySearch from \"./binarySearch\";\nimport DragElement from \"./dragElement\";\nimport generateHitAreas from \"./generateHitAreas\";\n\ninterface Dimensions {\n bottom: number;\n left: number;\n right: number;\n top: number;\n}\n\ninterface DragAndDropHandlerParams {\n autoEscape?: boolean;\n classNames: ClassNames;\n getNodeElement: GetNodeElement;\n getNodeElementForNode: GetNodeElementForNode;\n getScrollLeft: GetScrollLeft;\n getTree: GetTree;\n onCanMove?: OnCanMove;\n onCanMoveTo?: OnCanMoveTo;\n onDragMove?: DragMethod;\n onDragStop?: DragMethod;\n onIsMoveHandle?: OnIsMoveHandle;\n openFolderDelay: false | number;\n openNode: OpenNode;\n refreshElements: RefreshElements;\n slide: boolean;\n treeElement: HTMLElement;\n triggerEvent: TriggerEvent;\n}\ntype GetNodeElement = (element: HTMLElement) => NodeElement | null;\n\ntype GetNodeElementForNode = (node: Node) => NodeElement;\n\nexport class DragAndDropHandler {\n public currentItem: NodeElement | null;\n public hitAreas: HitArea[];\n public hoveredArea: HitArea | null;\n public isDragging: boolean;\n\n private autoEscape?: boolean;\n private classNames: ClassNames;\n private dragElement: DragElement | null;\n private getNodeElement: GetNodeElement;\n private getNodeElementForNode: GetNodeElementForNode;\n private getScrollLeft: GetScrollLeft;\n private getTree: GetTree;\n private onCanMove?: OnCanMove;\n private onCanMoveTo?: OnCanMoveTo;\n private onDragMove?: DragMethod;\n private onDragStop?: DragMethod;\n private onIsMoveHandle?: OnIsMoveHandle;\n private openFolderDelay: false | number;\n private openFolderTimer: null | number;\n private openNode: OpenNode;\n private previousGhost: DropHint | null;\n private refreshElements: RefreshElements;\n private slide: boolean;\n private treeElement: HTMLElement;\n private triggerEvent: TriggerEvent;\n\n constructor({\n autoEscape,\n classNames,\n getNodeElement,\n getNodeElementForNode,\n getScrollLeft,\n getTree,\n onCanMove,\n onCanMoveTo,\n onDragMove,\n onDragStop,\n onIsMoveHandle,\n openFolderDelay,\n openNode,\n refreshElements,\n slide,\n treeElement,\n triggerEvent,\n }: DragAndDropHandlerParams) {\n this.autoEscape = autoEscape;\n this.classNames = classNames;\n this.getNodeElement = getNodeElement;\n this.getNodeElementForNode = getNodeElementForNode;\n this.getScrollLeft = getScrollLeft;\n this.getTree = getTree;\n this.onCanMove = onCanMove;\n this.onCanMoveTo = onCanMoveTo;\n this.onDragMove = onDragMove;\n this.onDragStop = onDragStop;\n this.onIsMoveHandle = onIsMoveHandle;\n this.openFolderDelay = openFolderDelay;\n this.openNode = openNode;\n this.refreshElements = refreshElements;\n this.slide = slide;\n this.treeElement = treeElement;\n this.triggerEvent = triggerEvent;\n\n this.hoveredArea = null;\n this.hitAreas = [];\n this.isDragging = false;\n this.currentItem = null;\n\n this.dragElement = null;\n this.openFolderTimer = null;\n this.previousGhost = null;\n }\n\n public mouseCapture(positionInfo: PositionInfo): boolean | null {\n const element = positionInfo.target;\n\n if (!this.mustCaptureElement(element)) {\n return null;\n }\n\n if (this.onIsMoveHandle && !this.onIsMoveHandle(element)) {\n return null;\n }\n\n let nodeElement = this.getNodeElement(element);\n\n if (nodeElement && this.onCanMove) {\n if (!this.onCanMove(nodeElement.node)) {\n nodeElement = null;\n }\n }\n\n this.currentItem = nodeElement;\n return this.currentItem != null;\n }\n\n public mouseDrag(positionInfo: PositionInfo): boolean {\n if (!this.currentItem || !this.dragElement) {\n return false;\n }\n\n this.dragElement.move(positionInfo.pageX, positionInfo.pageY);\n\n const area = this.findHoveredArea(positionInfo.pageX, positionInfo.pageY);\n\n if (area && this.canMoveToArea(area, this.currentItem)) {\n if (!area.node.isFolder()) {\n this.stopOpenFolderTimer();\n }\n\n if (this.hoveredArea !== area) {\n this.hoveredArea = area;\n\n // If this is a closed folder, start timer to open it\n if (this.mustOpenFolderTimer(area)) {\n this.startOpenFolderTimer(area.node);\n } else {\n this.stopOpenFolderTimer();\n }\n\n this.updateDropHint();\n }\n } else {\n this.removeDropHint();\n this.stopOpenFolderTimer();\n this.hoveredArea = area;\n }\n\n if (!area) {\n if (this.onDragMove) {\n this.onDragMove(this.currentItem.node, positionInfo.originalEvent);\n }\n }\n\n return true;\n }\n\n public mouseStart(positionInfo: PositionInfo): boolean {\n if (!this.currentItem) {\n return false;\n }\n\n this.refresh();\n\n const { left, top } = getElementPosition(positionInfo.target);\n\n const node = this.currentItem.node;\n\n this.dragElement = new DragElement({\n autoEscape: this.autoEscape ?? true,\n classNames: this.classNames,\n nodeName: node.name,\n offsetX: positionInfo.pageX - left,\n offsetY: positionInfo.pageY - top,\n treeElement: this.treeElement,\n });\n\n this.isDragging = true;\n this.currentItem.element.classList.add(this.classNames.moving);\n\n return true;\n }\n\n public mouseStop(positionInfo: PositionInfo): boolean {\n this.moveItem(positionInfo);\n this.clear();\n this.removeHover();\n this.removeDropHint();\n this.removeHitAreas();\n\n const currentItem = this.currentItem;\n\n if (this.currentItem) {\n this.currentItem.element.classList.remove(this.classNames.moving);\n this.currentItem = null;\n }\n\n this.isDragging = false;\n\n if (!this.hoveredArea && currentItem) {\n if (this.onDragStop) {\n this.onDragStop(currentItem.node, positionInfo.originalEvent);\n }\n }\n\n return false;\n }\n\n public refresh(): void {\n this.removeHitAreas();\n\n if (this.currentItem) {\n const currentNode = this.currentItem.node;\n this.generateHitAreas(currentNode);\n this.currentItem = this.getNodeElementForNode(currentNode);\n\n if (this.isDragging) {\n this.currentItem.element.classList.add(this.classNames.moving);\n }\n }\n }\n\n private canMoveToArea(area: HitArea, currentItem: NodeElement): boolean {\n if (!this.onCanMoveTo) {\n return true;\n }\n\n return this.onCanMoveTo(currentItem.node, area.node, area.position);\n }\n\n private clear(): void {\n if (this.dragElement) {\n this.dragElement.remove();\n this.dragElement = null;\n }\n }\n\n private findHoveredArea(x: number, y: number): HitArea | null {\n const dimensions = this.getTreeDimensions();\n\n if (\n x < dimensions.left ||\n y < dimensions.top ||\n x > dimensions.right ||\n y > dimensions.bottom\n ) {\n return null;\n }\n\n return binarySearch<HitArea>(this.hitAreas, (area) => {\n if (y < area.top) {\n return 1;\n } else if (y > area.bottom) {\n return -1;\n } else {\n return 0;\n }\n });\n }\n\n private generateHitAreas(currentNode: Node): void {\n const tree = this.getTree();\n\n if (!tree) {\n this.hitAreas = [];\n } else {\n this.hitAreas = generateHitAreas(\n tree,\n currentNode,\n this.getTreeDimensions().bottom,\n );\n }\n }\n\n private getTreeDimensions(): Dimensions {\n // Return the dimensions of the tree. Add a margin to the bottom to allow\n // to drag-and-drop after the last element.\n const treePosition = getElementPosition(this.treeElement);\n const left = treePosition.left + this.getScrollLeft();\n const top = treePosition.top;\n\n return {\n bottom: top + this.treeElement.clientHeight + 16,\n left,\n right: left + this.treeElement.clientWidth,\n top,\n };\n }\n\n /* Move the dragged node to the selected position in the tree. */\n private moveItem(positionInfo: PositionInfo): void {\n if (\n this.currentItem &&\n this.hoveredArea?.position &&\n this.canMoveToArea(this.hoveredArea, this.currentItem)\n ) {\n const movedNode = this.currentItem.node;\n const targetNode = this.hoveredArea.node;\n const position = this.hoveredArea.position;\n const previousParent = movedNode.parent;\n\n if (position === \"inside\") {\n this.hoveredArea.node.is_open = true;\n }\n\n const doMove = (): void => {\n const tree = this.getTree();\n\n if (tree) {\n tree.moveNode(movedNode, targetNode, position);\n\n this.treeElement.textContent = \"\";\n this.refreshElements(null);\n }\n };\n\n if (\n this.triggerEvent(\"tree.move\", {\n moveInfo: {\n doMove,\n movedNode,\n originalEvent: positionInfo.originalEvent,\n position,\n previousParent,\n targetNode,\n },\n })\n ) {\n doMove();\n }\n }\n }\n\n private mustCaptureElement(element: HTMLElement): boolean {\n const nodeName = element.nodeName;\n\n return (\n nodeName !== \"INPUT\" && nodeName !== \"SELECT\" && nodeName !== \"TEXTAREA\"\n );\n }\n\n private mustOpenFolderTimer(area: HitArea): boolean {\n const node = area.node;\n\n return node.isFolder() && !node.is_open && area.position === \"inside\";\n }\n\n private removeDropHint(): void {\n if (this.previousGhost) {\n this.previousGhost.remove();\n }\n }\n\n private removeHitAreas(): void {\n this.hitAreas = [];\n }\n\n private removeHover(): void {\n this.hoveredArea = null;\n }\n\n private startOpenFolderTimer(folder: Node): void {\n const openFolder = (): void => {\n void this.openNode(folder, this.slide).then(() => {\n this.refresh();\n this.updateDropHint();\n });\n };\n\n this.stopOpenFolderTimer();\n\n const openFolderDelay = this.openFolderDelay;\n\n if (openFolderDelay !== false) {\n this.openFolderTimer = window.setTimeout(openFolder, openFolderDelay);\n }\n }\n\n private stopOpenFolderTimer(): void {\n if (this.openFolderTimer) {\n clearTimeout(this.openFolderTimer);\n this.openFolderTimer = null;\n }\n }\n\n private updateDropHint(): void {\n if (!this.hoveredArea) {\n return;\n }\n\n // remove previous drop hint\n this.removeDropHint();\n\n // add new drop hint\n const nodeElement = this.getNodeElementForNode(this.hoveredArea.node);\n this.previousGhost = nodeElement.addDropHint(this.hoveredArea.position);\n }\n}\n","function binarySearch<T>(items: T[], compareFn: (a: T) => number): null | T {\n let low = 0;\n let high = items.length;\n\n while (low < high) {\n const mid = (low + high) >> 1;\n const item = items[mid];\n\n if (item === undefined) {\n return null;\n }\n\n const compareResult = compareFn(item);\n\n if (compareResult > 0) {\n high = mid;\n } else if (compareResult < 0) {\n low = mid + 1;\n } else {\n return item;\n }\n }\n\n return null;\n}\n\nexport default binarySearch;\n","import type { ClassNames } from \"./classNames\";\nimport type { GetTree, IsNodeSelected } from \"./methodTypes\";\nimport type { Node } from \"./node\";\nimport type { IconElement, OnCreateLi } from \"./options\";\n\nimport { getBoolString } from \"./util\";\n\ninterface ElementsRendererParams {\n autoEscape: boolean;\n buttonLeft: boolean;\n classNames: ClassNames;\n closedIcon?: IconElement;\n dragAndDrop: boolean;\n getTree: GetTree;\n htmlElement: HTMLElement;\n isNodeSelected: IsNodeSelected;\n onCreateLi?: OnCreateLi;\n openedIcon?: IconElement;\n rtl?: boolean;\n setNodeElement: (element: HTMLElement, node: Node) => void;\n showEmptyFolder: boolean;\n tabIndex?: number;\n}\n\n/* Renders the tree to html.\n *\n * The children of a closed folder are not rendered. They are rendered when\n * the folder is opened, see renderChildren.\n *\n * The elements are created by cloning templates. A template is a fully\n * built <li> or <ul> with everything that is the same for every node\n * (structure, roles, static classes, the toggler icon). Per node only the\n * parts that differ are set: the title, the aria attributes and the\n * selected and loading classes.\n */\nexport default class ElementsRenderer {\n public closedIconElement?: globalThis.Node;\n public openedIconElement?: globalThis.Node;\n private autoEscape: boolean;\n private buttonLeft: boolean;\n private classNames: ClassNames;\n private closedFolderTemplate: HTMLLIElement;\n private dragAndDrop: boolean;\n private getTree: GetTree;\n private groupUlTemplate: HTMLUListElement;\n private htmlElement: HTMLElement;\n private isNodeSelected: IsNodeSelected;\n private nodeTemplate: HTMLLIElement;\n private onCreateLi?: OnCreateLi;\n private openedFolderTemplate: HTMLLIElement;\n private rootUlTemplate: HTMLUListElement;\n private rtl?: boolean;\n private setNodeElement: (element: HTMLElement, node: Node) => void;\n private showEmptyFolder: boolean;\n private tabIndex?: number;\n\n constructor({\n autoEscape,\n buttonLeft,\n classNames,\n closedIcon,\n dragAndDrop,\n getTree,\n htmlElement,\n isNodeSelected,\n onCreateLi,\n openedIcon,\n rtl,\n setNodeElement,\n showEmptyFolder,\n tabIndex,\n }: ElementsRendererParams) {\n this.autoEscape = autoEscape;\n this.buttonLeft = buttonLeft;\n this.classNames = classNames;\n this.dragAndDrop = dragAndDrop;\n this.getTree = getTree;\n this.htmlElement = htmlElement;\n this.isNodeSelected = isNodeSelected;\n this.onCreateLi = onCreateLi;\n this.rtl = rtl;\n this.setNodeElement = setNodeElement;\n this.showEmptyFolder = showEmptyFolder;\n this.tabIndex = tabIndex;\n this.openedIconElement = this.createButtonElement(openedIcon ?? \"+\");\n this.closedIconElement = this.createButtonElement(closedIcon ?? \"-\");\n\n this.rootUlTemplate = this.createUlTemplate(true);\n this.groupUlTemplate = this.createUlTemplate(false);\n this.nodeTemplate = this.createNodeTemplate();\n this.openedFolderTemplate = this.createFolderTemplate(true);\n this.closedFolderTemplate = this.createFolderTemplate(false);\n }\n\n public render(fromNode: Node | null): void {\n if (fromNode?.parent) {\n this.renderFromNode(fromNode);\n } else {\n this.renderFromRoot();\n }\n }\n\n /* Render the children of a rendered folder. Returns the new <ul>, or\n * null when the folder is not rendered or has no children.\n */\n public renderChildren(node: Node): HTMLUListElement | null {\n if (!node.element || !node.hasChildren()) {\n return null;\n }\n\n return this.createDomElements(\n node.element,\n node.children,\n false,\n node.getLevel() + 1,\n );\n }\n\n public renderFromNode(node: Node): void {\n if (!node.element) {\n return;\n }\n\n const currentLi = node.element;\n const newLi = this.createLi(node, node.getLevel());\n currentLi.replaceWith(newLi);\n\n if (this.mustRenderChildren(node)) {\n this.createDomElements(newLi, node.children, false, node.getLevel() + 1);\n }\n }\n\n public renderFromRoot(): void {\n this.htmlElement.textContent = \"\";\n\n const tree = this.getTree();\n\n if (tree) {\n this.createDomElements(this.htmlElement, tree.children, true, 1);\n }\n }\n\n private attachNodeData(node: Node, li: HTMLElement): void {\n node.element = li;\n this.setNodeElement(li, node);\n }\n\n /* Returns the template of a toggler icon; it is cloned for every folder.\n * A string is parsed as html and becomes a fragment, so it can hold\n * entities, text and elements.\n */\n private createButtonElement(value: IconElement): globalThis.Node | undefined {\n if (typeof value === \"string\") {\n const template = document.createElement(\"template\");\n template.innerHTML = value;\n\n return template.content;\n } else if (value.nodeType) {\n return value;\n } else {\n return undefined;\n }\n }\n\n private createDomElements(\n element: Element,\n children: Node[],\n isRootNode: boolean,\n level: number,\n ): HTMLUListElement {\n const template = isRootNode ? this.rootUlTemplate : this.groupUlTemplate;\n const ul = template.cloneNode() as HTMLUListElement;\n element.appendChild(ul);\n\n for (const child of children) {\n const li = this.createLi(child, level);\n ul.appendChild(li);\n\n if (this.mustRenderChildren(child)) {\n this.createDomElements(li, child.children, false, level + 1);\n }\n }\n\n return ul;\n }\n\n private createFolderLi(\n node: Node,\n level: number,\n isSelected: boolean,\n ): HTMLLIElement {\n const template = node.is_open\n ? this.openedFolderTemplate\n : this.closedFolderTemplate;\n const li = template.cloneNode(true) as HTMLLIElement;\n\n if (isSelected) {\n li.classList.add(this.classNames.selected);\n }\n\n if (node.is_loading) {\n li.classList.add(this.classNames.loading);\n }\n\n // li > div > [button link], title span, [button link]\n const div = li.firstChild as HTMLDivElement;\n const titleSpan = div.childNodes[\n this.buttonLeft ? 1 : 0\n ] as HTMLSpanElement;\n\n this.fillTitleSpan(titleSpan, node.name, isSelected, level);\n\n return li;\n }\n\n /* Template for a folder <li>:\n * li > div > [button link], title span, [button link]\n * The toggler icon and the aria-expanded attribute depend on the open\n * state, so there is a template for each.\n */\n private createFolderTemplate(isOpen: boolean): HTMLLIElement {\n const liClasses = [this.classNames.common, this.classNames.folder];\n\n if (!isOpen) {\n liClasses.push(this.classNames.closed);\n }\n\n const li = this.createLiTemplate(liClasses.join(\" \"));\n const div = li.firstChild as HTMLDivElement;\n\n // button link\n const buttonLink = document.createElement(\"a\");\n buttonLink.className = this.getButtonClasses(isOpen);\n\n const iconElement = isOpen\n ? this.openedIconElement\n : this.closedIconElement;\n\n if (iconElement) {\n buttonLink.appendChild(iconElement.cloneNode(true));\n }\n\n if (this.buttonLeft) {\n div.appendChild(buttonLink);\n }\n\n // title span\n const titleSpan = this.createTitleSpanTemplate(true);\n titleSpan.setAttribute(\"aria-expanded\", getBoolString(isOpen));\n div.appendChild(titleSpan);\n\n if (!this.buttonLeft) {\n div.appendChild(buttonLink);\n }\n\n return li;\n }\n\n /* Create the <li> element\n * Attach it to node.element.\n * Call onCreateLi\n */\n private createLi(node: Node, level: number): HTMLLIElement {\n const isSelected = this.isNodeSelected(node);\n\n const mustShowFolder =\n node.isFolder() || (node.isEmptyFolder && this.showEmptyFolder);\n\n const li = mustShowFolder\n ? this.createFolderLi(node, level, isSelected)\n : this.createNodeLi(node, level, isSelected);\n\n this.attachNodeData(node, li);\n\n if (this.onCreateLi) {\n this.onCreateLi(node, li, isSelected);\n }\n\n return li;\n }\n\n /* Create the outer part of a <li> template: li > div */\n private createLiTemplate(liClasses: string): HTMLLIElement {\n const li = document.createElement(\"li\");\n li.className = liClasses;\n li.setAttribute(\"role\", \"none\");\n\n const div = document.createElement(\"div\");\n div.className = `${this.classNames.element} ${this.classNames.common}`;\n div.setAttribute(\"role\", \"none\");\n\n li.appendChild(div);\n\n return li;\n }\n\n private createNodeLi(\n node: Node,\n level: number,\n isSelected: boolean,\n ): HTMLLIElement {\n const li = this.nodeTemplate.cloneNode(true) as HTMLLIElement;\n\n if (isSelected) {\n li.classList.add(this.classNames.selected);\n }\n\n // li > div > title span\n const div = li.firstChild as HTMLDivElement;\n const titleSpan = div.firstChild as HTMLSpanElement;\n\n this.fillTitleSpan(titleSpan, node.name, isSelected, level);\n\n return li;\n }\n\n /* Template for a <li> without children: li > div > title span */\n private createNodeTemplate(): HTMLLIElement {\n const li = this.createLiTemplate(this.classNames.common);\n const div = li.firstChild as HTMLDivElement;\n\n div.appendChild(this.createTitleSpanTemplate(false));\n\n return li;\n }\n\n private createTitleSpanTemplate(isFolder: boolean): HTMLSpanElement {\n const titleSpan = document.createElement(\"span\");\n\n let classes = `${this.classNames.title} ${this.classNames.common}`;\n\n if (isFolder) {\n classes += ` ${this.classNames.titleFolder}`;\n }\n\n classes += ` ${this.buttonLeft ? this.classNames.titleButtonLeft : this.classNames.titleButtonRight}`;\n\n titleSpan.className = classes;\n titleSpan.setAttribute(\"role\", \"treeitem\");\n titleSpan.setAttribute(\"aria-selected\", \"false\");\n\n return titleSpan;\n }\n\n private createUlTemplate(isRootNode: boolean): HTMLUListElement {\n let classString;\n let role;\n\n if (!isRootNode) {\n classString = \"\";\n role = \"group\";\n } else {\n classString = this.classNames.tree;\n role = \"tree\";\n\n if (this.rtl) {\n classString += ` ${this.classNames.rtl}`;\n }\n }\n\n if (this.dragAndDrop) {\n classString += ` ${this.classNames.dnd}`;\n }\n\n const ul = document.createElement(\"ul\");\n ul.className = `${this.classNames.common} ${classString}`;\n\n ul.setAttribute(\"role\", role);\n\n return ul;\n }\n\n /* Set the parts of a cloned title span that differ per node */\n private fillTitleSpan(\n titleSpan: HTMLSpanElement,\n nodeName: string,\n isSelected: boolean,\n level: number,\n ): void {\n titleSpan.setAttribute(\"aria-label\", nodeName);\n titleSpan.setAttribute(\"aria-level\", `${level}`);\n\n if (isSelected) {\n titleSpan.setAttribute(\"aria-selected\", \"true\");\n\n const tabIndex = this.tabIndex;\n\n if (tabIndex !== undefined) {\n titleSpan.setAttribute(\"tabindex\", `${tabIndex}`);\n }\n }\n\n if (this.autoEscape) {\n titleSpan.textContent = nodeName;\n } else {\n titleSpan.innerHTML = nodeName;\n }\n }\n\n private getButtonClasses(isOpen: boolean): string {\n const classes = [this.classNames.toggler, this.classNames.common];\n\n if (!isOpen) {\n classes.push(this.classNames.closed);\n }\n\n if (this.buttonLeft) {\n classes.push(this.classNames.togglerLeft);\n } else {\n classes.push(this.classNames.togglerRight);\n }\n\n return classes.join(\" \");\n }\n\n /* The children of a closed folder are rendered when it is opened */\n private mustRenderChildren(node: Node): boolean {\n return node.hasChildren() && node.is_open === true;\n }\n}\n","export const isInt = (n: unknown): boolean =>\n typeof n === \"number\" && n % 1 === 0;\n\nexport const getBoolString = (value: unknown): string =>\n value ? \"true\" : \"false\";\n","import type {\n CloseNode,\n GetSelectedNode,\n IsFocusOnTree,\n OpenNode,\n SelectNode,\n} from \"./methodTypes\";\nimport type { Node } from \"./node\";\n\ninterface KeyHandlerParams {\n closeNode: CloseNode;\n getSelectedNode: GetSelectedNode;\n isFocusOnTree: IsFocusOnTree;\n keyboardSupport: boolean;\n openNode: OpenNode;\n selectNode: SelectNode;\n}\n\nexport default class KeyHandler {\n private closeNode: CloseNode;\n private getSelectedNode: GetSelectedNode;\n\n private isFocusOnTree: IsFocusOnTree;\n\n private keyboardSupport: boolean;\n private openNode: OpenNode;\n private originalSelectNode: SelectNode;\n\n constructor({\n closeNode,\n getSelectedNode,\n isFocusOnTree,\n keyboardSupport,\n openNode,\n selectNode,\n }: KeyHandlerParams) {\n this.closeNode = closeNode;\n this.getSelectedNode = getSelectedNode;\n this.isFocusOnTree = isFocusOnTree;\n this.keyboardSupport = keyboardSupport;\n this.openNode = openNode;\n this.originalSelectNode = selectNode;\n\n if (keyboardSupport) {\n document.addEventListener(\"keydown\", this.handleKeyDown);\n }\n }\n\n public deinit(): void {\n if (this.keyboardSupport) {\n document.removeEventListener(\"keydown\", this.handleKeyDown);\n }\n }\n\n public moveDown(): boolean {\n return this.selectNode(this.getSelectedNode()?.getNextVisibleNode());\n }\n\n public moveUp(): boolean {\n return this.selectNode(this.getSelectedNode()?.getPreviousVisibleNode());\n }\n\n private canHandleKeyboard(): boolean {\n return this.keyboardSupport && this.isFocusOnTree();\n }\n\n private handleKeyDown = (e: KeyboardEvent): void => {\n if (!this.canHandleKeyboard()) {\n return;\n }\n\n let isKeyHandled = false;\n\n const selectedNode = this.getSelectedNode();\n if (selectedNode) {\n switch (e.key) {\n case \"ArrowDown\":\n isKeyHandled = this.moveDown();\n break;\n\n case \"ArrowLeft\":\n isKeyHandled = this.moveLeft();\n break;\n\n case \"ArrowRight\":\n isKeyHandled = this.moveRight();\n break;\n\n case \"ArrowUp\":\n isKeyHandled = this.moveUp();\n break;\n }\n }\n\n if (isKeyHandled) {\n e.preventDefault();\n }\n };\n\n private moveLeft(): boolean {\n const selectedNode = this.getSelectedNode();\n\n /* istanbul ignore if */\n if (!selectedNode) {\n return false;\n }\n\n if (selectedNode.isFolder() && selectedNode.is_open) {\n // Left on an open node closes the node\n this.closeNode(selectedNode);\n return true;\n } else {\n // Left on a closed or end node moves focus to the node's parent\n return this.selectNode(selectedNode.getParent());\n }\n }\n\n private moveRight(): boolean {\n const selectedNode = this.getSelectedNode();\n\n if (!selectedNode?.isFolder()) {\n return false;\n } else {\n // folder node\n if (selectedNode.is_open) {\n // Right moves to the first child of an open node\n return this.selectNode(selectedNode.getNextVisibleNode());\n } else {\n // Right expands a closed node\n void this.openNode(selectedNode);\n return true;\n }\n }\n }\n\n /* Select the node.\n * Don't do anything if the node is null.\n * Result: a different node was selected.\n */\n private selectNode(node?: Node | null): boolean {\n if (!node) {\n return false;\n } else {\n this.originalSelectNode(node);\n\n return true;\n }\n }\n}\n","export interface PositionInfo {\n originalEvent: Event;\n pageX: number;\n pageY: number;\n target: HTMLElement;\n}\n\nexport const getPositionInfoFromMouseEvent = (e: MouseEvent): PositionInfo => ({\n originalEvent: e,\n pageX: e.pageX,\n pageY: e.pageY,\n target: e.target as HTMLElement,\n});\n\nexport const getPositionInfoFromTouch = (\n touch: Touch,\n e: TouchEvent,\n): PositionInfo => ({\n originalEvent: e,\n pageX: touch.pageX,\n pageY: touch.pageY,\n target: touch.target as HTMLElement,\n});\n","import type { ClassNames } from \"./classNames\";\nimport type { TriggerEvent } from \"./methodTypes\";\nimport type { PositionInfo } from \"./mouseUtils\";\nimport type { Node } from \"./node\";\n\nimport {\n getPositionInfoFromMouseEvent,\n getPositionInfoFromTouch,\n} from \"./mouseUtils\";\n\nexport type GetMouseDelay = () => number;\nexport type GetNode = (element: HTMLElement) => Node | null;\nexport type MouseCapture = (positionInfo: PositionInfo) => boolean | null;\nexport type MouseStart = (positionInfo: PositionInfo) => boolean;\n\ninterface ClickTarget {\n node: Node;\n type: \"button\" | \"label\";\n}\n\ninterface MouseHandlerParams {\n classNames: ClassNames;\n element: HTMLElement;\n getMouseDelay: () => number;\n getNode: GetNode;\n onClickButton: (node: Node) => void;\n onClickTitle: (node: Node) => void;\n onMouseCapture: MouseCapture;\n onMouseDrag: (positionInfo: PositionInfo) => void;\n onMouseStart: MouseStart;\n onMouseStop: (positionInfo: PositionInfo) => void;\n triggerEvent: TriggerEvent;\n useContextMenu: boolean;\n}\n\nclass MouseHandler {\n private classNames: ClassNames;\n private element: HTMLElement;\n private getMouseDelay: GetMouseDelay;\n private getNode: GetNode;\n\n private isMouseDelayMet: boolean;\n\n private isMouseStarted: boolean;\n\n private mouseDelayTimer: null | number;\n\n private mouseDownInfo: null | PositionInfo;\n private onClickButton: (node: Node) => void;\n private onClickTitle: (node: Node) => void;\n\n private onMouseCapture: MouseCapture;\n\n private onMouseDrag: (positionInfo: PositionInfo) => void;\n\n private onMouseStart: MouseStart;\n\n private onMouseStop: (positionInfo: PositionInfo) => void;\n\n private triggerEvent: TriggerEvent;\n private useContextMenu: boolean;\n constructor({\n classNames,\n element,\n getMouseDelay,\n getNode,\n onClickButton,\n onClickTitle,\n onMouseCapture,\n onMouseDrag,\n onMouseStart,\n onMouseStop,\n triggerEvent,\n useContextMenu,\n }: MouseHandlerParams) {\n this.classNames = classNames;\n this.element = element;\n this.getMouseDelay = getMouseDelay;\n this.getNode = getNode;\n this.onClickButton = onClickButton;\n this.onClickTitle = onClickTitle;\n this.onMouseCapture = onMouseCapture;\n this.onMouseDrag = onMouseDrag;\n this.onMouseStart = onMouseStart;\n this.onMouseStop = onMouseStop;\n this.triggerEvent = triggerEvent;\n this.useContextMenu = useContextMenu;\n\n element.addEventListener(\"click\", this.handleClick);\n element.addEventListener(\"dblclick\", this.handleDblclick);\n element.addEventListener(\"mousedown\", this.mouseDown, {\n passive: false,\n });\n element.addEventListener(\"touchstart\", this.touchStart, {\n passive: false,\n });\n\n if (useContextMenu) {\n element.addEventListener(\"contextmenu\", this.handleContextmenu);\n }\n\n this.isMouseStarted = false;\n this.mouseDelayTimer = null;\n this.isMouseDelayMet = false;\n this.mouseDownInfo = null;\n }\n public deinit(): void {\n this.element.removeEventListener(\"click\", this.handleClick);\n this.element.removeEventListener(\"dblclick\", this.handleDblclick);\n\n if (this.useContextMenu) {\n this.element.removeEventListener(\"contextmenu\", this.handleContextmenu);\n }\n\n this.element.removeEventListener(\"mousedown\", this.mouseDown);\n this.element.removeEventListener(\"touchstart\", this.touchStart);\n this.removeMouseMoveEventListeners();\n }\n private getClickTarget(element: HTMLElement): ClickTarget | null {\n const button = element.closest<HTMLElement>(`.${this.classNames.toggler}`);\n\n if (button) {\n const node = this.getNode(button);\n\n if (node) {\n return {\n node,\n type: \"button\",\n };\n }\n } else {\n const treeElement = element.closest<HTMLElement>(\n `.${this.classNames.element}`,\n );\n\n if (treeElement) {\n const node = this.getNode(treeElement);\n if (node) {\n return {\n node,\n type: \"label\",\n };\n }\n }\n }\n\n return null;\n }\n private handleClick = (e: MouseEvent): void => {\n if (!e.target) {\n return;\n }\n\n const clickTarget = this.getClickTarget(e.target as HTMLElement);\n\n if (!clickTarget) {\n return;\n }\n\n switch (clickTarget.type) {\n case \"button\":\n this.onClickButton(clickTarget.node);\n\n e.preventDefault();\n e.stopPropagation();\n break;\n\n case \"label\": {\n if (\n this.triggerEvent(\"tree.click\", {\n node: clickTarget.node,\n originalEvent: e,\n })\n ) {\n this.onClickTitle(clickTarget.node);\n }\n break;\n }\n }\n };\n\n private handleContextmenu = (e: MouseEvent) => {\n if (!e.target) {\n return;\n }\n\n const div = (e.target as HTMLElement).closest<HTMLElement>(\n `ul.${this.classNames.tree} .${this.classNames.element}`,\n );\n\n if (div) {\n const node = this.getNode(div);\n if (node) {\n e.preventDefault();\n e.stopPropagation();\n\n this.triggerEvent(\"tree.contextmenu\", {\n node,\n originalEvent: e,\n });\n return false;\n }\n }\n\n return null;\n };\n\n private handleDblclick = (e: MouseEvent): void => {\n if (!e.target) {\n return;\n }\n\n const clickTarget = this.getClickTarget(e.target as HTMLElement);\n\n if (clickTarget?.type === \"label\") {\n this.triggerEvent(\"tree.dblclick\", {\n node: clickTarget.node,\n originalEvent: e,\n });\n }\n };\n\n private handleMouseDown(positionInfo: PositionInfo): boolean {\n // We may have missed mouseup (out of window)\n if (this.isMouseStarted) {\n this.handleMouseUp(positionInfo);\n }\n\n this.mouseDownInfo = positionInfo;\n\n if (!this.onMouseCapture(positionInfo)) {\n return false;\n }\n\n this.handleStartMouse();\n\n return true;\n }\n\n private handleMouseMove(\n e: MouseEvent | TouchEvent,\n positionInfo: PositionInfo,\n ): void {\n if (this.isMouseStarted) {\n this.onMouseDrag(positionInfo);\n\n if (e.cancelable) {\n e.preventDefault();\n }\n return;\n }\n\n if (!this.isMouseDelayMet) {\n return;\n }\n\n if (this.mouseDownInfo) {\n this.isMouseStarted = this.onMouseStart(this.mouseDownInfo);\n }\n\n if (this.isMouseStarted) {\n this.onMouseDrag(positionInfo);\n\n if (e.cancelable) {\n e.preventDefault();\n }\n } else {\n this.handleMouseUp(positionInfo);\n }\n }\n private handleMouseUp(positionInfo: PositionInfo): void {\n this.removeMouseMoveEventListeners();\n this.isMouseDelayMet = false;\n this.mouseDownInfo = null;\n\n if (this.isMouseStarted) {\n this.isMouseStarted = false;\n this.onMouseStop(positionInfo);\n }\n }\n\n private handleStartMouse(): void {\n document.addEventListener(\"mousemove\", this.mouseMove, {\n passive: false,\n });\n document.addEventListener(\"touchmove\", this.touchMove, {\n passive: false,\n });\n document.addEventListener(\"mouseup\", this.mouseUp, { passive: false });\n document.addEventListener(\"touchend\", this.touchEnd, {\n passive: false,\n });\n\n const mouseDelay = this.getMouseDelay();\n\n if (mouseDelay) {\n this.startMouseDelayTimer(mouseDelay);\n } else {\n this.isMouseDelayMet = true;\n }\n }\n\n private mouseDown = (e: MouseEvent): void => {\n // Left mouse button?\n if (e.button !== 0) {\n return;\n }\n\n const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));\n\n if (result && e.cancelable) {\n e.preventDefault();\n }\n };\n\n private mouseMove = (e: MouseEvent): void => {\n this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));\n };\n\n private mouseUp = (e: MouseEvent): void => {\n this.handleMouseUp(getPositionInfoFromMouseEvent(e));\n };\n\n private removeMouseMoveEventListeners() {\n document.removeEventListener(\"mousemove\", this.mouseMove);\n document.removeEventListener(\"touchmove\", this.touchMove);\n document.removeEventListener(\"mouseup\", this.mouseUp);\n document.removeEventListener(\"touchend\", this.touchEnd);\n }\n\n private startMouseDelayTimer(mouseDelay: number): void {\n if (this.mouseDelayTimer) {\n clearTimeout(this.mouseDelayTimer);\n }\n\n this.mouseDelayTimer = window.setTimeout(() => {\n if (this.mouseDownInfo) {\n this.isMouseDelayMet = true;\n }\n }, mouseDelay);\n\n this.isMouseDelayMet = false;\n }\n\n private touchEnd = (e: TouchEvent): void => {\n if (e.touches.length > 1) {\n return;\n }\n\n const touch = e.touches[0];\n\n if (!touch) {\n return;\n }\n\n this.handleMouseUp(getPositionInfoFromTouch(touch, e));\n };\n\n private touchMove = (e: TouchEvent): void => {\n if (e.touches.length > 1) {\n return;\n }\n\n const touch = e.touches[0];\n\n if (!touch) {\n return;\n }\n\n this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));\n };\n\n private touchStart = (e: TouchEvent): void => {\n if (e.touches.length > 1) {\n return;\n }\n\n const touch = e.touches[0];\n\n if (!touch) {\n return;\n }\n\n this.handleMouseDown(getPositionInfoFromTouch(touch, e));\n };\n}\n\nexport default MouseHandler;\n","import type { NodeData, NodeRecord } from \"./node\";\n\ninterface NodeRecordWithChildren extends NodeRecord {\n children: NodeData[];\n}\n\nexport const isNodeRecordWithChildren = (\n data: NodeData,\n): data is NodeRecordWithChildren =>\n typeof data === \"object\" &&\n \"children\" in data &&\n data.children instanceof Array;\n","/*\nA node reads and writes the private members of other nodes (node.setParent),\nso the `_` prefix that the build adds cannot be limited to `this.`:\n\nprefix-private-members: all\n*/\n\nimport { isNodeRecordWithChildren } from \"./nodeUtils\";\n\nexport type NodeData = NodeRecord | string;\n\nexport type NodeId = number | string;\n\nexport interface NodeRecord {\n [key: string]: unknown;\n children?: NodeData[];\n id?: NodeId;\n}\n\nexport type Position = \"after\" | \"before\" | \"inside\";\n\ntype IterateCallback = (node: Node, level: number) => boolean;\n\n/**\n * @groupDescription Properties\n * Any other key in the node data is copied onto the node, so\n * `{ name: \"node1\", color: \"green\" }` gives you `node.color`.\n *\n * @groupDescription Searching\n * These work on any node, and search that node's subtree. Called on the root\n * node, they search the whole tree — which is what the tree's own methods of\n * the same name do.\n *\n * @groupDescription Changing the tree\n * ::: warning\n * These methods change the data without re-rendering. The tree's\n * [methods](/reference/methods) — `appendNode`, `removeNode`, `moveNode` and\n * friends — do the same and refresh the display, so prefer those. If you do\n * use these, call `tree.refresh()` afterwards.\n * :::\n */\nexport class Node {\n /** @hidden */\n [key: string]: unknown;\n\n /** The child nodes. */\n public children: Node[];\n /** The `li` element, once the node is rendered. Nodes inside a closed\n * folder are rendered when the folder is opened. */\n public element?: HTMLElement;\n /** The id from the node data. */\n public id?: NodeId;\n /** @hidden */\n public idMapping?: Map<NodeId, Node>;\n /** Whether the node's children are being fetched. */\n public is_loading?: boolean;\n /** Whether the folder is open. */\n public is_open?: boolean;\n /** Whether the node data had an empty `children` array. */\n public isEmptyFolder: boolean;\n /** Whether the children still have to be fetched. */\n public load_on_demand: boolean;\n /** The label. Also settable from the `label` key in node data. */\n public name: string;\n /** @hidden */\n public nodeClass?: typeof Node;\n /** The parent; `null` for the root node. */\n public parent: Node | null;\n /** The root node. */\n public tree?: Node;\n\n /** @hidden */\n constructor(\n nodeData: NodeData | null = null,\n isRoot = false,\n nodeClass = Node,\n ) {\n this.name = \"\";\n this.load_on_demand = false;\n\n this.isEmptyFolder =\n nodeData != null &&\n isNodeRecordWithChildren(nodeData) &&\n nodeData.children.length === 0;\n\n this.setData(nodeData);\n\n this.children = [];\n this.parent = null;\n this.is_loading = undefined;\n this.is_open ??= undefined;\n\n if (isRoot) {\n this.idMapping = new Map<NodeId, Node>();\n this.tree = this;\n this.nodeClass = nodeClass;\n } else {\n this.idMapping = undefined;\n }\n }\n\n /**\n * Adds a sibling after this node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addAfter(nodeInfo: NodeData): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const node = this.createNode(nodeInfo);\n\n const childIndex = this.parent.getChildIndex(this);\n this.parent.addChildAtPosition(node, childIndex + 1);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n }\n\n /**\n * Adds a sibling before this node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addBefore(nodeInfo: NodeData): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const node = this.createNode(nodeInfo);\n\n const childIndex = this.parent.getChildIndex(this);\n this.parent.addChildAtPosition(node, childIndex);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n }\n\n /**\n * Adds an existing `Node` object as the last child.\n *\n * @group Changing the tree\n */\n public addChild(node: Node): void {\n this.children.push(node);\n node.setParent(this);\n }\n\n /**\n * Adds an existing `Node` object as a child, at this position in\n * `children`. The index starts at `0`.\n *\n * @group Changing the tree\n */\n public addChildAtPosition(node: Node, index: number): void {\n this.children.splice(index, 0, node);\n node.setParent(this);\n }\n\n /** @hidden */\n public addNodeToIndex(node: Node): void {\n if (node.id != null) {\n this.idMapping?.set(node.id, node);\n }\n }\n\n /**\n * Inserts a new parent between this node and its current parent.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addParent(nodeInfo: NodeData): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const newParent = this.createNode(nodeInfo);\n\n if (this.tree) {\n newParent.setParent(this.tree);\n }\n const originalParent = this.parent;\n\n for (const child of originalParent.children) {\n newParent.addChild(child);\n }\n\n originalParent.children = [];\n originalParent.addChild(newParent);\n return newParent;\n }\n }\n\n /**\n * Adds a child at the end.\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public append(nodeInfo: NodeData): Node {\n const node = this.createNode(nodeInfo);\n this.addChild(node);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n\n /**\n * Returns all nodes in the subtree for which the callback returns\n * `true`.\n *\n * @example\n * ```js\n * const folders = tree.getTree().filter((node) => node.isFolder());\n * ```\n *\n * @group Searching\n */\n public filter(f: (node: Node) => boolean): Node[] {\n const result: Node[] = [];\n\n this.iterate((node: Node) => {\n if (f(node)) {\n result.push(node);\n }\n\n return true;\n });\n\n return result;\n }\n\n /**\n * Returns the position of a child in `children`, or `-1`.\n *\n * @group Inspecting a node\n */\n public getChildIndex(node: Node): number {\n return this.children.indexOf(node);\n }\n\n /**\n * Returns the subtree as plain data, ready for `JSON.stringify`.\n * Internal properties (`parent`, `children`, `element`, `tree`,\n * `idMapping`, `nodeClass`, `load_on_demand`, `isEmptyFolder`) are left\n * out; your own properties are kept.\n *\n * ```js\n * tree.getTree().getData();\n * // [{ name: \"node1\", id: 1, children: [{ name: \"child1\", id: 2 }] }]\n * ```\n *\n * @param includeParent - Make the result the node itself rather than its\n * children. Default `false`.\n * @group Reading data back\n */\n public getData(includeParent = false): NodeRecord[] {\n const getDataFromNodes = (nodes: Node[]): Record<string, unknown>[] => {\n return nodes.map((node) => {\n const tmpNode: Record<string, unknown> = {};\n\n for (const k in node) {\n if (\n [\n \"parent\",\n \"children\",\n \"element\",\n \"idMapping\",\n \"load_on_demand\",\n \"nodeClass\",\n \"tree\",\n \"isEmptyFolder\",\n ].indexOf(k) === -1 &&\n Object.prototype.hasOwnProperty.call(node, k)\n ) {\n const v = node[k];\n tmpNode[k] = v;\n }\n }\n\n if (node.hasChildren()) {\n tmpNode.children = getDataFromNodes(node.children);\n }\n\n return tmpNode;\n });\n };\n\n if (includeParent) {\n return getDataFromNodes([this]);\n } else {\n return getDataFromNodes(this.children);\n }\n }\n\n /**\n * Returns the last child, or `null`. When that child is an open folder,\n * its own last child, and so on.\n *\n * @group Moving around the tree\n */\n public getLastChild(): Node | null {\n if (!this.hasChildren()) {\n return null;\n } else {\n const lastChild = this.children[this.children.length - 1] as Node;\n\n if (!(lastChild.hasChildren() && lastChild.is_open)) {\n return lastChild;\n } else {\n return lastChild.getLastChild();\n }\n }\n }\n\n /**\n * Returns the depth of the node, counting the top level as `1`.\n *\n * @group Inspecting a node\n */\n public getLevel(): number {\n let level = 0;\n let node: Node = this; // eslint-disable-line @typescript-eslint/no-this-alias\n\n while (node.parent) {\n level += 1;\n node = node.parent;\n }\n\n return level;\n }\n\n /**\n * Returns the next node in the tree, regardless of whether it is\n * visible. `getNextNode(false)` skips the node's own children.\n *\n * @group Moving around the tree\n */\n public getNextNode(includeChildren = true): Node | null {\n if (includeChildren && this.hasChildren()) {\n return this.children[0] ?? null;\n } else if (!this.parent) {\n return null;\n } else {\n const nextSibling = this.getNextSibling();\n\n if (nextSibling) {\n return nextSibling;\n } else {\n return this.parent.getNextNode(false);\n }\n }\n }\n\n /**\n * Returns the next sibling, or `null`.\n *\n * @group Moving around the tree\n */\n public getNextSibling(): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const nextIndex = this.parent.getChildIndex(this) + 1;\n if (nextIndex < this.parent.children.length) {\n return this.parent.children[nextIndex] ?? null;\n } else {\n return null;\n }\n }\n }\n\n /**\n * Like `getNextNode`, but skipping nodes inside closed folders — this is\n * what the arrow keys use.\n *\n * @group Moving around the tree\n */\n public getNextVisibleNode(): Node | null {\n if (this.hasChildren() && this.is_open) {\n // First child\n return this.children[0] ?? null;\n } else {\n if (!this.parent) {\n return null;\n } else {\n const nextSibling = this.getNextSibling();\n if (nextSibling) {\n // Next sibling\n return nextSibling;\n } else {\n // Next node of parent\n return this.parent.getNextNode(false);\n }\n }\n }\n }\n\n /**\n * Returns the first node for which the callback returns `true`.\n *\n * @group Searching\n */\n public getNodeByCallback(callback: (node: Node) => boolean): Node | null {\n let result: Node | null = null;\n\n this.iterate((node: Node) => {\n if (result) {\n return false;\n } else if (callback(node)) {\n result = node;\n return false;\n } else {\n return true;\n }\n });\n\n return result;\n }\n\n /**\n * Returns the node with this id. Only available on the root node, which\n * keeps the id index.\n *\n * @group Searching\n */\n public getNodeById(nodeId: NodeId): Node | null {\n return this.idMapping?.get(nodeId) ?? null;\n }\n\n /**\n * Returns the first node with this name.\n *\n * @group Searching\n */\n public getNodeByName(name: string): Node | null {\n return this.getNodeByCallback((node: Node) => node.name === name);\n }\n\n /**\n * Like `getNodeByName`, but throws when there is no such node.\n *\n * @group Searching\n */\n public getNodeByNameMustExist(name: string): Node {\n const node = this.getNodeByCallback((n: Node) => n.name === name);\n\n if (!node) {\n throw new Error(`Node with name ${name} not found`);\n }\n\n return node;\n }\n\n /**\n * Returns all nodes with this property value.\n *\n * @group Searching\n */\n public getNodesByProperty(key: string, value: unknown): Node[] {\n return this.filter((node: Node) => node[key] === value);\n }\n\n /**\n * Returns the parent: `null` for a top-level node — the root node is not\n * returned.\n *\n * @group Moving around the tree\n */\n public getParent(): Node | null {\n // Return parent except if it is the root node\n if (!this.parent) {\n return null;\n } else if (!this.parent.parent) {\n // Root node -> null\n return null;\n } else {\n return this.parent;\n }\n }\n\n /**\n * Returns the previous node in the tree, regardless of whether it is\n * visible.\n *\n * @group Moving around the tree\n */\n public getPreviousNode(): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const previousSibling = this.getPreviousSibling();\n\n if (!previousSibling) {\n return this.getParent();\n } else if (previousSibling.hasChildren()) {\n return previousSibling.getLastChild();\n } else {\n return previousSibling;\n }\n }\n }\n\n /**\n * Returns the previous sibling, or `null`.\n *\n * @group Moving around the tree\n */\n public getPreviousSibling(): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const previousIndex = this.parent.getChildIndex(this) - 1;\n if (previousIndex >= 0) {\n return this.parent.children[previousIndex] ?? null;\n } else {\n return null;\n }\n }\n }\n\n /**\n * Like `getPreviousNode`, but skipping nodes inside closed folders —\n * this is what the arrow keys use.\n *\n * @group Moving around the tree\n */\n public getPreviousVisibleNode(): Node | null {\n if (!this.parent) {\n return null;\n } else {\n const previousSibling = this.getPreviousSibling();\n\n if (!previousSibling) {\n return this.getParent();\n } else if (!previousSibling.hasChildren() || !previousSibling.is_open) {\n // Previous sibling\n return previousSibling;\n } else {\n // Last child of previous sibling\n return previousSibling.getLastChild();\n }\n }\n }\n\n /**\n * Whether the node has children.\n *\n * @group Inspecting a node\n */\n public hasChildren(): boolean {\n return this.children.length !== 0;\n }\n\n /**\n * Init Node from data without making it the root of the tree.\n *\n * @hidden\n */\n public initFromData(data: NodeData): void {\n const addNode = (nodeData: NodeData): void => {\n this.setData(nodeData);\n\n if (isNodeRecordWithChildren(nodeData) && nodeData.children.length) {\n addChildren(nodeData.children);\n }\n };\n\n const addChildren = (childrenData: NodeData[]): void => {\n for (const child of childrenData) {\n const node = this.createNode();\n node.initFromData(child);\n this.addChild(node);\n }\n };\n\n addNode(data);\n }\n\n /**\n * `true` when the node has children, or is marked `load_on_demand`.\n *\n * @group Inspecting a node\n */\n public isFolder(): boolean {\n return this.hasChildren() || this.load_on_demand;\n }\n\n /**\n * Whether this node is an ancestor of the other node.\n *\n * @group Inspecting a node\n */\n public isParentOf(node: Node): boolean {\n let parent = node.parent;\n\n while (parent) {\n if (parent === this) {\n return true;\n }\n\n parent = parent.parent;\n }\n\n return false;\n }\n\n /**\n * Walks the subtree, calling the callback with `(node, level)`. Return\n * `false` from the callback to stop descending into that node:\n *\n * ```js\n * tree.getTree().iterate((node, level) => {\n * console.log(\" \".repeat(level) + node.name);\n * return level <= 2; // don't go deeper than level 2\n * });\n * ```\n *\n * @group Searching\n */\n public iterate(callback: IterateCallback): void {\n const _iterate = (node: Node, level: number): void => {\n for (const child of node.children) {\n const result = callback(child, level);\n\n if (result && child.hasChildren()) {\n _iterate(child, level + 1);\n }\n }\n };\n\n _iterate(this, 0);\n }\n\n /**\n * Replaces the children with new node data.\n *\n * @group Changing the tree\n */\n public loadFromData(data: NodeData[]): this {\n this.removeChildren();\n\n for (const childData of data) {\n const node = this.createNode(childData);\n this.addChild(node);\n\n if (isNodeRecordWithChildren(childData)) {\n node.loadFromData(childData.children);\n }\n }\n\n return this;\n }\n\n /**\n * Moves a node relative to another node. Called on the root node.\n *\n * @param position - `\"before\"`, `\"after\"` or `\"inside\"`.\n * @returns `false` when the move is impossible, for instance moving a\n * node into its own subtree.\n * @group Changing the tree\n */\n public moveNode(\n movedNode: Node,\n targetNode: Node,\n position: Position,\n ): boolean {\n if (!movedNode.parent || movedNode.isParentOf(targetNode)) {\n // - Node is parent of target node\n // - Or, parent is empty\n return false;\n } else {\n movedNode.parent.doRemoveChild(movedNode);\n\n switch (position) {\n case \"after\": {\n if (targetNode.parent) {\n targetNode.parent.addChildAtPosition(\n movedNode,\n targetNode.parent.getChildIndex(targetNode) + 1,\n );\n return true;\n }\n return false;\n }\n\n case \"before\": {\n if (targetNode.parent) {\n targetNode.parent.addChildAtPosition(\n movedNode,\n targetNode.parent.getChildIndex(targetNode),\n );\n return true;\n }\n return false;\n }\n\n case \"inside\": {\n // move inside as first child\n targetNode.addChildAtPosition(movedNode, 0);\n return true;\n }\n }\n }\n }\n\n /**\n * Adds a child at the start.\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public prepend(nodeInfo: NodeData): Node {\n const node = this.createNode(nodeInfo);\n this.addChildAtPosition(node, 0);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n\n /**\n * Removes this node from its parent.\n *\n * @group Changing the tree\n */\n public remove(): void {\n if (this.parent) {\n this.parent.removeChild(this);\n this.parent = null;\n }\n }\n\n /**\n * Removes a child and its children.\n *\n * @group Changing the tree\n */\n public removeChild(node: Node): void {\n // remove children from the index\n node.removeChildren();\n\n this.doRemoveChild(node);\n }\n\n /**\n * Removes all children.\n *\n * @group Changing the tree\n */\n public removeChildren(): void {\n this.iterate((child: Node) => {\n this.tree?.removeNodeFromIndex(child);\n return true;\n });\n\n this.children = [];\n }\n\n /** @hidden */\n public removeNodeFromIndex(node: Node): void {\n if (node.id != null) {\n this.idMapping?.delete(node.id);\n }\n }\n\n /**\n * Updates the node's properties from node data. `children` and `parent`\n * are ignored. A string sets the name. Existing node values are not\n * removed.\n *\n * @group Changing the tree\n */\n public setData(o: NodeData | null): void {\n if (!o) {\n return;\n } else if (typeof o === \"string\") {\n this.name = o;\n } else if (typeof o === \"object\") {\n for (const key in o) {\n if (Object.prototype.hasOwnProperty.call(o, key)) {\n const value = o[key];\n\n if (key === \"label\" || key === \"name\") {\n // You can use the 'label' key instead of 'name'; this is a legacy feature\n if (typeof value === \"string\") {\n this.name = value;\n }\n } else if (key !== \"children\" && key !== \"parent\") {\n // You can't update the children or the parent using this function\n this[key] = value;\n }\n }\n }\n }\n }\n\n private createNode(nodeData?: NodeData): Node {\n const nodeClass = this.getNodeClass();\n return new nodeClass(nodeData);\n }\n\n private doRemoveChild(node: Node): void {\n this.children.splice(this.getChildIndex(node), 1);\n this.tree?.removeNodeFromIndex(node);\n }\n\n private getNodeClass(): typeof Node {\n return this.nodeClass ?? this.tree?.nodeClass ?? Node;\n }\n\n // Load children data from nodeInfo if it has children\n private loadChildrenFromData(nodeInfo: NodeData) {\n if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {\n this.loadFromData(nodeInfo.children);\n }\n }\n\n private setParent(parent: Node): void {\n this.parent = parent;\n this.tree = parent.tree;\n this.tree?.addNodeToIndex(this);\n }\n}\n","import type { ClassNames } from \"../classNames\";\nimport type { DropHint } from \"../dragAndDropHandler/types\";\n\nclass BorderDropHint implements DropHint {\n private hint?: HTMLElement;\n\n constructor(\n element: HTMLElement,\n scrollLeft: number,\n classNames: ClassNames,\n ) {\n const div = element.querySelector(`:scope > .${classNames.element}`);\n\n if (!div) {\n this.hint = undefined;\n return;\n }\n\n const width = Math.max(element.offsetWidth + scrollLeft - 4, 0);\n const height = Math.max(element.clientHeight - 4, 0);\n\n const hint = document.createElement(\"span\");\n hint.className = classNames.border;\n hint.style.width = `${width}px`;\n hint.style.height = `${height}px`;\n\n this.hint = hint;\n\n div.append(this.hint);\n }\n\n public remove(): void {\n this.hint?.remove();\n }\n}\n\nexport default BorderDropHint;\n","import type { ClassNames } from \"../classNames\";\nimport type { DropHint } from \"../dragAndDropHandler/types\";\nimport type { Node, Position } from \"../node\";\n\nclass GhostDropHint implements DropHint {\n private classNames: ClassNames;\n private element: HTMLElement;\n private ghost: HTMLElement;\n private node: Node;\n\n constructor(\n node: Node,\n element: HTMLElement,\n position: Position,\n classNames: ClassNames,\n ) {\n this.classNames = classNames;\n this.element = element;\n this.node = node;\n this.ghost = this.createGhostElement();\n\n switch (position) {\n case \"after\":\n this.moveAfter();\n break;\n\n case \"before\":\n this.moveBefore();\n break;\n\n case \"inside\": {\n if (node.isFolder() && node.is_open) {\n this.moveInsideOpenFolder();\n } else {\n this.moveInside();\n }\n }\n }\n }\n\n public remove(): void {\n this.ghost.remove();\n }\n\n private createGhostElement() {\n const { circle, common, ghost: ghostClass, line } = this.classNames;\n\n const ghost = document.createElement(\"li\");\n ghost.className = `${common} ${ghostClass}`;\n\n const circleSpan = document.createElement(\"span\");\n circleSpan.className = `${common} ${circle}`;\n ghost.append(circleSpan);\n\n const lineSpan = document.createElement(\"span\");\n lineSpan.className = `${common} ${line}`;\n ghost.append(lineSpan);\n\n return ghost;\n }\n\n private moveAfter(): void {\n this.element.after(this.ghost);\n }\n\n private moveBefore(): void {\n this.element.before(this.ghost);\n }\n\n private moveInside(): void {\n this.element.after(this.ghost);\n this.ghost.classList.add(this.classNames.inside);\n }\n\n private moveInsideOpenFolder(): void {\n const childElement = this.node.children[0]?.element;\n\n if (childElement) {\n childElement.before(this.ghost);\n }\n }\n}\n\nexport default GhostDropHint;\n","import type { ClassNames } from \"../classNames\";\nimport type { DropHint } from \"../dragAndDropHandler/types\";\nimport type { GetScrollLeft } from \"../methodTypes\";\nimport type { Node, Position } from \"../node\";\n\nimport BorderDropHint from \"./borderDropHint\";\nimport GhostDropHint from \"./ghostDropHint\";\n\nexport interface NodeElementParams {\n classNames: ClassNames;\n getScrollLeft: GetScrollLeft;\n node: Node;\n tabIndex?: number;\n treeElement: HTMLElement;\n}\n\nclass NodeElement {\n public element: HTMLElement;\n public node: Node;\n protected classNames: ClassNames;\n private getScrollLeft: GetScrollLeft;\n private tabIndex?: number;\n private treeElement: HTMLElement;\n\n constructor({\n classNames,\n getScrollLeft,\n node,\n tabIndex,\n treeElement,\n }: NodeElementParams) {\n this.classNames = classNames;\n this.getScrollLeft = getScrollLeft;\n this.node = node;\n this.tabIndex = tabIndex;\n this.treeElement = treeElement;\n\n // The root node has no element of its own; it uses the tree element.\n this.element = node.element ?? this.treeElement;\n }\n\n public addDropHint(position: Position): DropHint {\n if (this.mustShowBorderDropHint(position)) {\n return new BorderDropHint(\n this.element,\n this.getScrollLeft(),\n this.classNames,\n );\n } else {\n return new GhostDropHint(\n this.node,\n this.element,\n position,\n this.classNames,\n );\n }\n }\n\n public deselect(): void {\n if (!this.isRendered()) {\n return;\n }\n\n this.element.classList.remove(this.classNames.selected);\n\n const titleSpan = this.getTitleSpan();\n titleSpan.removeAttribute(\"tabindex\");\n titleSpan.setAttribute(\"aria-selected\", \"false\");\n\n titleSpan.blur();\n }\n\n public select(mustSetFocus: boolean): void {\n if (!this.isRendered()) {\n return;\n }\n\n this.element.classList.add(this.classNames.selected);\n\n const titleSpan = this.getTitleSpan();\n const tabIndex = this.tabIndex;\n\n // Check for null or undefined\n if (tabIndex != null) {\n titleSpan.setAttribute(\"tabindex\", tabIndex.toString());\n }\n\n titleSpan.setAttribute(\"aria-selected\", \"true\");\n\n if (mustSetFocus) {\n titleSpan.focus();\n }\n }\n\n protected getTitleSpan(): HTMLSpanElement {\n return this.element.querySelector(\n `:scope > .${this.classNames.element} > span.${this.classNames.title}`,\n ) as HTMLSpanElement;\n }\n\n protected getUl(): HTMLUListElement | null {\n return this.element.querySelector(\":scope > ul\");\n }\n\n /* A node inside a closed folder is not rendered. Its selected and open\n * state is applied when it is rendered.\n */\n protected isRendered(): boolean {\n return Boolean(this.node.element);\n }\n\n protected mustShowBorderDropHint(position: Position): boolean {\n return position === \"inside\";\n }\n}\n\nexport default NodeElement;\n","export type AnimationSpeed = \"fast\" | \"slow\" | number;\n\nexport const getAnimationDuration = (duration: AnimationSpeed): number => {\n if (typeof duration === \"number\") {\n return duration;\n }\n\n return duration === \"slow\" ? 600 : 200;\n};\n\nexport const slideDown = (\n element: HTMLElement,\n animationSpeed: AnimationSpeed,\n onFinished: () => void,\n): void => {\n element.style.display = \"block\";\n\n const animation = element.animate(\n [\n { height: \"0\", overflow: \"hidden\" },\n { height: `${element.scrollHeight}px`, overflow: \"hidden\" },\n ],\n { duration: getAnimationDuration(animationSpeed) },\n );\n\n animation.onfinish = () => {\n onFinished();\n };\n};\n\nexport const slideUp = (\n element: HTMLElement,\n animationSpeed: AnimationSpeed,\n onFinished: () => void,\n): void => {\n const animation = element.animate(\n [\n { height: `${element.scrollHeight}px`, overflow: \"hidden\" },\n { height: \"0\", overflow: \"hidden\" },\n ],\n { duration: getAnimationDuration(animationSpeed) },\n );\n\n animation.onfinish = () => {\n element.style.display = \"none\";\n onFinished();\n };\n};\n","import type { AnimationSpeed } from \"../animation\";\nimport type { TriggerEvent } from \"../methodTypes\";\nimport type { Node, Position } from \"../node\";\nimport type { NodeElementParams } from \"./index\";\n\nimport { slideDown, slideUp } from \"../animation\";\nimport NodeElement from \"./index\";\n\nexport type RenderChildren = (node: Node) => HTMLUListElement | null;\n\ninterface FolderElementParams extends NodeElementParams {\n closedIconElement?: globalThis.Node;\n openedIconElement?: globalThis.Node;\n renderChildren: RenderChildren;\n triggerEvent: TriggerEvent;\n}\n\nclass FolderElement extends NodeElement {\n private closedIconElement?: globalThis.Node;\n private openedIconElement?: globalThis.Node;\n private renderChildren: RenderChildren;\n private triggerEvent: TriggerEvent;\n\n constructor({\n classNames,\n closedIconElement,\n getScrollLeft,\n node,\n openedIconElement,\n renderChildren,\n tabIndex,\n treeElement,\n triggerEvent,\n }: FolderElementParams) {\n super({\n classNames,\n getScrollLeft,\n node,\n tabIndex,\n treeElement,\n });\n\n this.closedIconElement = closedIconElement;\n this.openedIconElement = openedIconElement;\n this.renderChildren = renderChildren;\n this.triggerEvent = triggerEvent;\n }\n\n public close(slide: boolean, animationSpeed: AnimationSpeed): void {\n if (!this.node.is_open) {\n return;\n }\n\n this.node.is_open = false;\n\n if (!this.isRendered()) {\n this.triggerEvent(\"tree.close\", { node: this.node });\n return;\n }\n\n const button = this.getButton();\n button.classList.add(this.classNames.closed);\n button.innerHTML = \"\";\n\n const closedIconElement = this.closedIconElement;\n\n if (closedIconElement) {\n const icon = closedIconElement.cloneNode(true);\n button.appendChild(icon);\n }\n\n const doClose = (): void => {\n this.element.classList.add(this.classNames.closed);\n\n const titleSpan = this.getTitleSpan();\n titleSpan.setAttribute(\"aria-expanded\", \"false\");\n\n this.triggerEvent(\"tree.close\", {\n node: this.node,\n });\n };\n\n const ul = this.getUl();\n\n if (!ul) {\n doClose();\n } else if (slide) {\n slideUp(ul, animationSpeed, doClose);\n } else {\n ul.style.display = \"none\";\n doClose();\n }\n }\n\n public async open(\n slide: boolean,\n animationSpeed: AnimationSpeed,\n ): Promise<void> {\n return new Promise((resolve) => {\n if (this.node.is_open) {\n resolve();\n return;\n }\n\n this.node.is_open = true;\n\n if (!this.isRendered()) {\n // The folder is rendered open when its parent is opened\n this.triggerEvent(\"tree.open\", { node: this.node });\n resolve();\n return;\n }\n\n const button = this.getButton();\n button.classList.remove(this.classNames.closed);\n button.innerHTML = \"\";\n\n const openedIconElement = this.openedIconElement;\n\n if (openedIconElement) {\n const icon = openedIconElement.cloneNode(true);\n button.appendChild(icon);\n }\n\n const doOpen = (): void => {\n this.element.classList.remove(this.classNames.closed);\n\n const titleSpan = this.getTitleSpan();\n titleSpan.setAttribute(\"aria-expanded\", \"true\");\n\n this.triggerEvent(\"tree.open\", {\n node: this.node,\n });\n\n resolve();\n };\n\n // The children are rendered the first time the folder is opened\n const ul = this.getUl() ?? this.renderChildren(this.node);\n\n if (!ul) {\n doOpen();\n } else if (slide) {\n slideDown(ul, animationSpeed, doOpen);\n } else {\n ul.style.display = \"block\";\n doOpen();\n }\n });\n }\n\n protected mustShowBorderDropHint(position: Position): boolean {\n return !this.node.is_open && position === \"inside\";\n }\n\n private getButton(): HTMLLinkElement {\n return this.element.querySelector(\n `:scope > .${this.classNames.element} > a.${this.classNames.toggler}`,\n ) as HTMLLinkElement;\n }\n}\n\nexport default FolderElement;\n","// Url class for absolute and relative urls.\n\nconst isAbsoluteUrl = (inputUrl: string) => {\n try {\n new URL(inputUrl);\n return true;\n } catch {\n return false;\n }\n};\n\nconst LOCALHOST = \"http://localhost\";\n\nclass RequestUrl {\n private isAbsolute: boolean;\n private url: URL;\n\n constructor(inputUrl: string) {\n if (isAbsoluteUrl(inputUrl)) {\n this.url = new URL(inputUrl);\n this.isAbsolute = true;\n } else {\n this.url = new URL(inputUrl, LOCALHOST);\n this.isAbsolute = false;\n }\n }\n\n setSearchParam(key: string, value: string) {\n this.url.searchParams.set(key, value);\n }\n\n value() {\n if (this.isAbsolute) {\n return this.url.href;\n } else {\n return this.url.href.slice(LOCALHOST.length);\n }\n }\n}\n\nexport default RequestUrl;\n","import type {\n AddToSelection,\n GetNodeById,\n GetSelectedNodes,\n GetTree,\n OpenNode,\n RefreshElements,\n RemoveFromSelection,\n} from \"./methodTypes\";\nimport type { Node, NodeId } from \"./node\";\nimport type { OnGetStateFromStorage, OnSetStateFromStorage } from \"./options\";\n\nimport { isInt } from \"./util\";\n\nexport interface SavedState {\n open_nodes?: NodeId[];\n selected_node?: NodeId[];\n}\n\ninterface SaveStateHandlerParams {\n addToSelection: AddToSelection;\n getNodeById: GetNodeById;\n getSelectedNodes: GetSelectedNodes;\n getTree: GetTree;\n onGetStateFromStorage?: OnGetStateFromStorage;\n onSetStateFromStorage?: OnSetStateFromStorage;\n openNode: OpenNode;\n refreshElements: RefreshElements;\n removeFromSelection: RemoveFromSelection;\n saveState: boolean | string;\n}\n\nexport default class SaveStateHandler {\n private addToSelection: AddToSelection;\n private getNodeById: GetNodeById;\n private getSelectedNodes: GetSelectedNodes;\n private getTree: GetTree;\n private onGetStateFromStorage?: OnGetStateFromStorage;\n private onSetStateFromStorage?: OnSetStateFromStorage;\n private openNode: OpenNode;\n private refreshElements: RefreshElements;\n private removeFromSelection: RemoveFromSelection;\n private saveStateOption: boolean | string;\n\n constructor({\n addToSelection,\n getNodeById,\n getSelectedNodes,\n getTree,\n onGetStateFromStorage,\n onSetStateFromStorage,\n openNode,\n refreshElements,\n removeFromSelection,\n saveState,\n }: SaveStateHandlerParams) {\n this.addToSelection = addToSelection;\n this.getNodeById = getNodeById;\n this.getSelectedNodes = getSelectedNodes;\n this.getTree = getTree;\n this.onGetStateFromStorage = onGetStateFromStorage;\n this.onSetStateFromStorage = onSetStateFromStorage;\n this.openNode = openNode;\n this.refreshElements = refreshElements;\n this.removeFromSelection = removeFromSelection;\n this.saveStateOption = saveState;\n }\n\n public getNodeIdToBeSelected(): NodeId | null {\n if (!this.saveStateOption) {\n return null;\n }\n\n const state = this.getStateFromStorage();\n\n if (state?.selected_node) {\n return state.selected_node[0] ?? null;\n } else {\n return null;\n }\n }\n\n public getState(): SavedState {\n const getOpenNodeIds = (): NodeId[] => {\n const openNodes: NodeId[] = [];\n\n this.getTree()?.iterate((node: Node) => {\n if (node.is_open && node.id && node.hasChildren()) {\n openNodes.push(node.id);\n }\n return true;\n });\n\n return openNodes;\n };\n\n const getSelectedNodeIds = (): NodeId[] => {\n const selectedNodeIds: NodeId[] = [];\n\n this.getSelectedNodes().forEach((node) => {\n if (node.id != null) {\n selectedNodeIds.push(node.id);\n }\n });\n\n return selectedNodeIds;\n };\n\n return {\n open_nodes: getOpenNodeIds(),\n selected_node: getSelectedNodeIds(),\n };\n }\n\n public getStateFromStorage(): null | SavedState {\n if (!this.saveStateOption) {\n return null;\n }\n\n const jsonData = this.loadFromStorage();\n\n if (jsonData) {\n return this.parseState(jsonData);\n } else {\n return null;\n }\n }\n\n public saveState(): void {\n if (!this.saveStateOption) {\n return;\n }\n\n const state = JSON.stringify(this.getState());\n\n if (this.onSetStateFromStorage) {\n this.onSetStateFromStorage(state);\n } else {\n localStorage.setItem(this.getKeyName(), state);\n }\n }\n\n /*\n Set initial state\n Don't handle nodes that are loaded on demand\n\n result: must load on demand (boolean)\n */\n public setInitialState(state: SavedState): boolean {\n let mustLoadOnDemand = false;\n\n if (state.open_nodes) {\n mustLoadOnDemand = this.openInitialNodes(state.open_nodes);\n }\n\n this.resetSelection();\n\n if (state.selected_node) {\n this.selectInitialNodes(state.selected_node);\n }\n\n return mustLoadOnDemand;\n }\n\n public async setInitialStateOnDemand(state: SavedState): Promise<void> {\n let nodeIds = state.open_nodes;\n\n const openNodes = async () => {\n if (!nodeIds) {\n return;\n }\n\n const newNodesIds = [];\n\n for (const nodeId of nodeIds) {\n const node = this.getNodeById(nodeId);\n\n if (!node) {\n newNodesIds.push(nodeId);\n } else {\n if (!node.is_loading) {\n if (node.load_on_demand) {\n await loadAndOpenNode(node);\n } else {\n await this.openNode(node, false);\n }\n }\n }\n }\n\n nodeIds = newNodesIds;\n\n if (state.selected_node) {\n if (this.selectInitialNodes(state.selected_node)) {\n this.refreshElements(null);\n }\n }\n };\n\n const loadAndOpenNode = async (node: Node) => {\n await this.openNode(node, false);\n await openNodes();\n };\n\n await openNodes();\n }\n\n private getKeyName(): string {\n if (typeof this.saveStateOption === \"string\") {\n return this.saveStateOption;\n } else {\n return \"tree\";\n }\n }\n\n private loadFromStorage(): null | string {\n if (this.onGetStateFromStorage) {\n return this.onGetStateFromStorage();\n } else {\n return localStorage.getItem(this.getKeyName());\n }\n }\n\n private openInitialNodes(nodeIds: NodeId[]): boolean {\n let mustLoadOnDemand = false;\n\n for (const nodeId of nodeIds) {\n const node = this.getNodeById(nodeId);\n\n if (node) {\n if (!node.load_on_demand) {\n node.is_open = true;\n } else {\n mustLoadOnDemand = true;\n }\n }\n }\n\n return mustLoadOnDemand;\n }\n\n private parseState(jsonData: string): SavedState {\n const state = JSON.parse(jsonData) as Record<string, unknown>;\n\n // Check if selected_node is an int (instead of an array)\n if (state.selected_node && isInt(state.selected_node)) {\n // Convert to array\n state.selected_node = [state.selected_node];\n }\n\n return state;\n }\n\n private resetSelection(): void {\n const selectedNodes = this.getSelectedNodes();\n\n selectedNodes.forEach((node) => {\n this.removeFromSelection(node);\n });\n }\n\n private selectInitialNodes(nodeIds: NodeId[]): boolean {\n let selectCount = 0;\n\n for (const nodeId of nodeIds) {\n const node = this.getNodeById(nodeId);\n\n if (node) {\n selectCount += 1;\n\n this.addToSelection(node);\n }\n }\n\n return selectCount !== 0;\n }\n}\n","export type HorizontalScrollDirection = \"left\" | \"right\";\nexport type VerticalScrollDirection = \"bottom\" | \"top\";\n\ninterface ConstructorParams {\n container: HTMLElement;\n refreshHitAreas: () => void;\n}\n\nexport abstract class ScrollParent {\n protected container: HTMLElement;\n protected horizontalScrollDirection?: HorizontalScrollDirection;\n protected horizontalScrollTimeout?: number;\n\n protected refreshHitAreas: () => void;\n protected verticalScrollDirection?: VerticalScrollDirection;\n protected verticalScrollTimeout?: number;\n\n constructor({ container, refreshHitAreas }: ConstructorParams) {\n this.container = container;\n this.refreshHitAreas = refreshHitAreas;\n }\n\n public checkHorizontalScrolling(pageX: number): void {\n const newHorizontalScrollDirection =\n this.getNewHorizontalScrollDirection(pageX);\n\n if (this.horizontalScrollDirection !== newHorizontalScrollDirection) {\n this.horizontalScrollDirection = newHorizontalScrollDirection;\n\n if (this.horizontalScrollTimeout != null) {\n window.clearTimeout(this.horizontalScrollTimeout);\n }\n\n if (newHorizontalScrollDirection) {\n this.horizontalScrollTimeout = window.setTimeout(\n this.scrollHorizontally.bind(this),\n 40,\n );\n }\n }\n }\n\n public checkVerticalScrolling(pageY: number) {\n const newVerticalScrollDirection =\n this.getNewVerticalScrollDirection(pageY);\n\n if (this.verticalScrollDirection !== newVerticalScrollDirection) {\n this.verticalScrollDirection = newVerticalScrollDirection;\n\n if (this.verticalScrollTimeout != null) {\n window.clearTimeout(this.verticalScrollTimeout);\n this.verticalScrollTimeout = undefined;\n }\n\n if (newVerticalScrollDirection) {\n this.verticalScrollTimeout = window.setTimeout(\n this.scrollVertically.bind(this),\n 40,\n );\n }\n }\n }\n\n public getScrollLeft(): number {\n return this.container.scrollLeft;\n }\n\n public scrollToY(top: number): void {\n this.container.scrollTop = top;\n }\n\n public stopScrolling() {\n this.horizontalScrollDirection = undefined;\n this.verticalScrollDirection = undefined;\n }\n\n protected abstract getNewHorizontalScrollDirection(\n pageX: number,\n ): HorizontalScrollDirection | undefined;\n protected abstract getNewVerticalScrollDirection(\n pageY: number,\n ): undefined | VerticalScrollDirection;\n\n protected scrollHorizontally() {\n if (!this.horizontalScrollDirection) {\n return;\n }\n\n const distance = this.horizontalScrollDirection === \"left\" ? -20 : 20;\n this.container.scrollBy({\n behavior: \"instant\",\n left: distance,\n top: 0,\n });\n\n this.refreshHitAreas();\n\n setTimeout(this.scrollHorizontally.bind(this), 40);\n }\n\n protected scrollVertically() {\n if (!this.verticalScrollDirection) {\n return;\n }\n\n const distance = this.verticalScrollDirection === \"top\" ? -20 : 20;\n this.container.scrollBy({\n behavior: \"instant\",\n left: 0,\n top: distance,\n });\n\n this.refreshHitAreas();\n\n setTimeout(this.scrollVertically.bind(this), 40);\n }\n}\n","import type {\n HorizontalScrollDirection,\n VerticalScrollDirection,\n} from \"./scrollParent\";\n\nimport { getElementPosition, getOffsetTop } from \"../positionUtils\";\nimport { ScrollParent } from \"./scrollParent\";\n\nexport default class ContainerScrollParent extends ScrollParent {\n private scrollParentBottom?: number;\n private scrollParentTop?: number;\n\n public stopScrolling() {\n super.stopScrolling();\n\n this.horizontalScrollDirection = undefined;\n this.verticalScrollDirection = undefined;\n }\n\n protected getNewHorizontalScrollDirection(\n pageX: number,\n ): HorizontalScrollDirection | undefined {\n const scrollParentOffset = getElementPosition(this.container);\n const containerWidth = this.container.getBoundingClientRect().width;\n\n const rightEdge = scrollParentOffset.left + containerWidth;\n const leftEdge = scrollParentOffset.left;\n const isNearRightEdge = pageX > rightEdge - 20;\n const isNearLeftEdge = pageX < leftEdge + 20;\n\n if (isNearRightEdge) {\n return \"right\";\n } else if (isNearLeftEdge) {\n return \"left\";\n }\n\n return undefined;\n }\n\n protected getNewVerticalScrollDirection(\n pageY: number,\n ): undefined | VerticalScrollDirection {\n if (pageY < this.getScrollParentTop()) {\n return \"top\";\n }\n\n if (pageY > this.getScrollParentBottom()) {\n return \"bottom\";\n }\n\n return undefined;\n }\n\n private getScrollParentBottom() {\n if (this.scrollParentBottom == null) {\n const containerHeight = this.container.getBoundingClientRect().height;\n this.scrollParentBottom = this.getScrollParentTop() + containerHeight;\n }\n\n return this.scrollParentBottom;\n }\n\n private getScrollParentTop() {\n this.scrollParentTop ??= getOffsetTop(this.container);\n\n return this.scrollParentTop;\n }\n}\n","import type {\n HorizontalScrollDirection,\n VerticalScrollDirection,\n} from \"./scrollParent\";\n\nimport { getOffsetTop } from \"../positionUtils\";\nimport { ScrollParent } from \"./scrollParent\";\n\ninterface Params {\n refreshHitAreas: () => void;\n treeElement: HTMLElement;\n}\n\nexport default class DocumentScrollParent extends ScrollParent {\n private documentScrollHeight?: number;\n private documentScrollWidth?: number;\n private treeElement: HTMLElement;\n\n constructor({ refreshHitAreas, treeElement }: Params) {\n super({ container: document.documentElement, refreshHitAreas });\n\n this.treeElement = treeElement;\n }\n\n public scrollToY(top: number): void {\n const treeTop = getOffsetTop(this.treeElement);\n\n super.scrollToY(top + treeTop);\n }\n\n public stopScrolling() {\n super.stopScrolling();\n\n this.documentScrollHeight = undefined;\n this.documentScrollWidth = undefined;\n }\n\n protected getNewHorizontalScrollDirection(\n pageX: number,\n ): HorizontalScrollDirection | undefined {\n const scrollLeft = this.container.scrollLeft;\n const windowWidth = window.innerWidth;\n\n const isNearRightEdge = pageX > windowWidth - 20;\n const isNearLeftEdge = pageX - scrollLeft < 20;\n\n if (isNearRightEdge && this.canScrollRight()) {\n return \"right\";\n }\n\n if (isNearLeftEdge) {\n return \"left\";\n }\n\n return undefined;\n }\n\n protected getNewVerticalScrollDirection(\n pageY: number,\n ): undefined | VerticalScrollDirection {\n const scrollTop = this.container.scrollTop;\n const distanceTop = pageY - scrollTop;\n\n if (distanceTop < 20) {\n return \"top\";\n }\n\n const windowHeight = window.innerHeight;\n\n if (windowHeight - (pageY - scrollTop) < 20 && this.canScrollDown()) {\n return \"bottom\";\n }\n\n return undefined;\n }\n\n private canScrollDown() {\n return (\n this.container.scrollTop + this.container.clientHeight <\n this.getDocumentScrollHeight()\n );\n }\n\n private canScrollRight() {\n return (\n this.container.scrollLeft + this.container.clientWidth <\n this.getDocumentScrollWidth()\n );\n }\n\n private getDocumentScrollHeight() {\n // Store the original scroll height because the scroll height can increase when the drag element is moved beyond the scroll height.\n this.documentScrollHeight ??= this.container.scrollHeight;\n\n return this.documentScrollHeight;\n }\n\n private getDocumentScrollWidth() {\n // Store the original scroll width because the scroll width can increase when the drag element is moved beyond the scroll width.\n this.documentScrollWidth ??= this.container.scrollWidth;\n\n return this.documentScrollWidth;\n }\n}\n","import type { ScrollParent } from \"./scrollParent\";\n\nimport ContainerScrollParent from \"./containerScrollParent\";\nimport DocumentScrollParent from \"./documentScrollParent\";\n\nconst isOverflow = (overflowValue: string) =>\n overflowValue === \"auto\" || overflowValue === \"scroll\";\n\nconst hasOverFlow = (element: HTMLElement): boolean => {\n const style = getComputedStyle(element);\n\n return isOverflow(style.overflowX) || isOverflow(style.overflowY);\n};\n\nconst getParentWithOverflow = (\n treeElement: HTMLElement,\n): HTMLElement | null => {\n if (hasOverFlow(treeElement)) {\n return treeElement;\n }\n\n let parent = treeElement.parentElement;\n\n while (parent) {\n if (hasOverFlow(parent)) {\n return parent;\n }\n\n parent = parent.parentElement;\n }\n\n return null;\n};\n\nconst createScrollParent = (\n treeElement: HTMLElement,\n refreshHitAreas: () => void,\n): ScrollParent => {\n const container = getParentWithOverflow(treeElement);\n\n if (container && container.tagName !== \"HTML\") {\n return new ContainerScrollParent({\n container,\n refreshHitAreas,\n });\n } else {\n return new DocumentScrollParent({ refreshHitAreas, treeElement });\n }\n};\n\nexport default createScrollParent;\n","import type { PositionInfo } from \"./mouseUtils\";\nimport type { ScrollParent } from \"./scrollHandler/scrollParent\";\n\nimport createScrollParent from \"./scrollHandler/createScrollParent\";\n\ninterface ScrollHandlerParams {\n refreshHitAreas: () => void;\n treeElement: HTMLElement;\n}\n\nexport default class ScrollHandler {\n private refreshHitAreas: () => void;\n private scrollParent?: ScrollParent;\n private treeElement: HTMLElement;\n\n constructor({ refreshHitAreas, treeElement }: ScrollHandlerParams) {\n this.refreshHitAreas = refreshHitAreas;\n this.scrollParent = undefined;\n this.treeElement = treeElement;\n }\n\n public checkScrolling(positionInfo: PositionInfo): void {\n this.checkVerticalScrolling(positionInfo);\n this.checkHorizontalScrolling(positionInfo);\n }\n\n public getScrollLeft(): number {\n return this.getScrollParent().getScrollLeft();\n }\n\n public scrollToY(top: number): void {\n this.getScrollParent().scrollToY(top);\n }\n\n public stopScrolling() {\n this.getScrollParent().stopScrolling();\n }\n\n private checkHorizontalScrolling(positionInfo: PositionInfo): void {\n this.getScrollParent().checkHorizontalScrolling(positionInfo.pageX);\n }\n\n private checkVerticalScrolling(positionInfo: PositionInfo): void {\n this.getScrollParent().checkVerticalScrolling(positionInfo.pageY);\n }\n\n private getScrollParent(): ScrollParent {\n this.scrollParent ??= createScrollParent(\n this.treeElement,\n this.refreshHitAreas,\n );\n\n return this.scrollParent;\n }\n}\n","import type {\n GetNodeById,\n GetNodeElementForNode,\n OpenParents,\n TriggerEvent,\n} from \"./methodTypes\";\nimport type { Node, NodeId } from \"./node\";\nimport type { OnCanSelectNode } from \"./options\";\n\nexport interface SelectNodeOptions {\n mustSetFocus?: boolean;\n mustToggle?: boolean;\n}\n\ninterface SelectNodeHandlerParameters {\n getNodeById: GetNodeById;\n getNodeElementForNode: GetNodeElementForNode;\n getOnCanSelectNode: () => OnCanSelectNode | undefined;\n getSelectable: () => boolean;\n openParents: OpenParents;\n saveState: () => void;\n triggerEvent: TriggerEvent;\n}\n\nexport default class SelectNodeHandler {\n private getNodeById: GetNodeById;\n private getNodeElementForNode: GetNodeElementForNode;\n private getOnCanSelectNode: () => OnCanSelectNode | undefined;\n private getSelectable: () => boolean;\n private openParents: OpenParents;\n private saveState: () => void;\n private selectedNodes: Set<NodeId>;\n private selectedSingleNode: Node | null;\n private triggerEvent: TriggerEvent;\n\n constructor({\n getNodeById,\n getNodeElementForNode,\n getOnCanSelectNode,\n getSelectable,\n openParents,\n saveState,\n triggerEvent,\n }: SelectNodeHandlerParameters) {\n this.getNodeById = getNodeById;\n this.getNodeElementForNode = getNodeElementForNode;\n this.getOnCanSelectNode = getOnCanSelectNode;\n this.getSelectable = getSelectable;\n this.openParents = openParents;\n this.saveState = saveState;\n this.selectedNodes = new Set<NodeId>();\n this.selectedSingleNode = null;\n this.triggerEvent = triggerEvent;\n }\n\n public addToSelection(node: Node): void {\n if (node.id != null) {\n this.selectedNodes.add(node.id);\n } else {\n this.selectedSingleNode = node;\n }\n }\n\n public clear(): void {\n this.selectedNodes.clear();\n this.selectedSingleNode = null;\n }\n\n public getSelectedNode(): Node | null {\n const selectedNodes = this.getSelectedNodes();\n\n if (selectedNodes.length) {\n return selectedNodes[0] ?? null;\n } else {\n return null;\n }\n }\n\n public getSelectedNodes(): Node[] {\n if (this.selectedSingleNode) {\n return [this.selectedSingleNode];\n } else {\n const selectedNodes: Node[] = [];\n\n this.selectedNodes.forEach((id) => {\n const node = this.getNodeById(id);\n if (node) {\n selectedNodes.push(node);\n }\n });\n\n return selectedNodes;\n }\n }\n\n public getSelectedNodesUnder(parent: Node): Node[] {\n if (this.selectedSingleNode) {\n if (parent.isParentOf(this.selectedSingleNode)) {\n return [this.selectedSingleNode];\n } else {\n return [];\n }\n } else {\n const selectedNodes: Node[] = [];\n\n this.selectedNodes.forEach((id) => {\n const node = this.getNodeById(id);\n if (node && parent.isParentOf(node)) {\n selectedNodes.push(node);\n }\n });\n\n return selectedNodes;\n }\n }\n\n public isNodeSelected(node: Node): boolean {\n if (node.id != null) {\n return this.selectedNodes.has(node.id);\n } else if (this.selectedSingleNode) {\n return this.selectedSingleNode === node;\n } else {\n return false;\n }\n }\n\n public removeFromSelection(node: Node, includeChildren = false): void {\n if (node.id == null) {\n if (this.selectedSingleNode === node) {\n this.selectedSingleNode = null;\n }\n } else {\n this.selectedNodes.delete(node.id);\n\n if (includeChildren) {\n node.iterate(() => {\n if (node.id != null) {\n this.selectedNodes.delete(node.id);\n }\n return true;\n });\n }\n }\n }\n\n /* Select a single node.\n * Renders the changed elements.\n * Deselects if the node is currently selected (if the mustToggle is on).\n * Deselects the previously selected node.\n * Check if the node is selectable.\n * Saves the state.\n * Options:\n * mustSetFocus: set the focus to the selected node\n * mustToggle: support deselecting the selected node\n */\n public selectSingleNode(node: Node, optionsParam?: SelectNodeOptions) {\n const defaultOptions = { mustSetFocus: true, mustToggle: true };\n const selectOptions = { ...defaultOptions, ...(optionsParam ?? {}) };\n\n const canSelect = (): boolean => {\n if (!this.getSelectable()) {\n return false;\n }\n\n const onCanSelectNode = this.getOnCanSelectNode();\n return onCanSelectNode ? onCanSelectNode(node) : true;\n };\n\n if (!canSelect()) {\n return;\n }\n\n const deselectCurrentNode = (deselectedNode: Node) => {\n this.removeFromSelection(deselectedNode);\n this.getNodeElementForNode(deselectedNode).deselect();\n };\n\n if (this.isNodeSelected(node)) {\n if (selectOptions.mustToggle) {\n deselectCurrentNode(node);\n this.triggerEvent(\"tree.deselect\", { node });\n }\n } else {\n const deselectedNode = this.getSelectedNode();\n\n if (deselectedNode) {\n deselectCurrentNode(deselectedNode);\n }\n\n this.addToSelection(node);\n this.openParents(node);\n this.getNodeElementForNode(node).select(selectOptions.mustSetFocus);\n\n this.triggerEvent(\"tree.select\", {\n deselectedNode,\n node,\n });\n }\n\n this.saveState();\n }\n}\n","import type { TreeElementOptions } from \"./options\";\n\nimport { DEFAULT_CLASS_PREFIX } from \"./classNames\";\nimport { Node } from \"./node\";\n\nconst defaults: TreeElementOptions = {\n animationSpeed: \"fast\",\n autoEscape: true,\n autoOpen: false, // true / false / int (open n levels starting at 0)\n buttonLeft: true,\n classPrefix: DEFAULT_CLASS_PREFIX, // the prefix of all css classes\n // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER\n // http://www.fileformat.info/info/unicode/char/25ba/index.htm\n // closedIcon: undefined,\n // commonClassName: undefined, // the class of every element; the default is \"<classPrefix>-common\"\n // data: undefined,\n // dataFilter: undefined,\n // dataUrl: undefined,\n dragAndDrop: false,\n keyboardSupport: true,\n nodeClass: Node,\n // onCanMove: undefined, // Can this node be moved?\n // onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)\n // onCanSelectNode: undefined,\n // onCreateLi: undefined,\n // onDragMove: undefined,\n // onDragStop: undefined,\n // onGetStateFromStorage: undefined,\n // onIsMoveHandle: undefined,\n // onSetStateFromStorage: undefined,\n // openedIcon: undefined,\n openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds\n // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE\n // http://www.fileformat.info/info/unicode/char/25bc/index.htm\n // rtl: undefined, // right-to-left support; true / false (default)\n saveState: false, // true / false / string (local storage key; the default key is \"tree\")\n selectable: true,\n showEmptyFolder: false,\n slide: true, // must display slide animation?\n startDndDelay: 300, // The delay for starting dnd (in milliseconds)\n tabIndex: 0,\n // treeClassName: undefined, // the class of the root element; the default is classPrefix\n useContextMenu: true,\n};\n\nconst setDefaultOptions = (\n htmlElement: HTMLElement,\n inputOptions: Partial<TreeElementOptions>,\n): TreeElementOptions => {\n const options = { ...defaults, ...inputOptions };\n\n options.dataUrl ??= htmlElement.dataset.url;\n options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);\n options.closedIcon ??= getDefaultClosedIcon(options);\n options.openedIcon ??= \"&#x25bc;\";\n\n return options;\n};\n\nconst getDefaultClosedIcon = (options: TreeElementOptions): string => {\n if (options.rtl) {\n // triangle to the left\n return \"&#x25c0;\";\n } else {\n // triangle to the right\n return \"&#x25ba;\";\n }\n};\n\nconst getRtlOptionFromHTMLElement = (htmlElement: HTMLElement): boolean => {\n const dataRtl = htmlElement.dataset.rtl;\n\n if (dataRtl == \"\") {\n return true;\n } else if (dataRtl === \"false\") {\n return false;\n } else {\n return Boolean(dataRtl);\n }\n};\n\nexport default setDefaultOptions;\n","export interface ClassNames {\n border: string;\n circle: string;\n closed: string;\n common: string;\n dnd: string;\n dragging: string;\n element: string;\n folder: string;\n ghost: string;\n inside: string;\n line: string;\n loading: string;\n moving: string;\n rtl: string;\n selected: string;\n title: string;\n titleButtonLeft: string;\n titleButtonRight: string;\n titleFolder: string;\n toggler: string;\n togglerLeft: string;\n togglerRight: string;\n tree: string;\n}\n\nexport interface ClassNamesOptions {\n classPrefix: string;\n commonClassName?: string;\n treeClassName?: string;\n}\n\nexport const DEFAULT_CLASS_PREFIX = \"tree-element\";\n\n/* Create the class names that the widget puts on the elements it creates.\n * They are all derived from classPrefix, except for the class of the root\n * element and the class that every element gets, which have an option of\n * their own.\n */\nconst createClassNames = ({\n classPrefix,\n commonClassName,\n treeClassName,\n}: ClassNamesOptions): ClassNames => ({\n border: `${classPrefix}-border`,\n circle: `${classPrefix}-circle`,\n closed: `${classPrefix}-closed`,\n common: commonClassName ?? `${classPrefix}-common`,\n dnd: `${classPrefix}-dnd`,\n dragging: `${classPrefix}-dragging`,\n element: `${classPrefix}-element`,\n folder: `${classPrefix}-folder`,\n ghost: `${classPrefix}-ghost`,\n inside: `${classPrefix}-inside`,\n line: `${classPrefix}-line`,\n loading: `${classPrefix}-loading`,\n moving: `${classPrefix}-moving`,\n rtl: `${classPrefix}-rtl`,\n selected: `${classPrefix}-selected`,\n title: `${classPrefix}-title`,\n titleButtonLeft: `${classPrefix}-title-button-left`,\n titleButtonRight: `${classPrefix}-title-button-right`,\n titleFolder: `${classPrefix}-title-folder`,\n toggler: `${classPrefix}-toggler`,\n togglerLeft: `${classPrefix}-toggler-left`,\n togglerRight: `${classPrefix}-toggler-right`,\n tree: treeClassName ?? classPrefix,\n});\n\nexport default createClassNames;\n","// Trigger a CustomEvent. Return if the event is processed (true) or cancelled (false).\nconst triggerCustomEvent = (\n element: HTMLElement,\n eventName: string,\n values?: Record<string, unknown>,\n): boolean => {\n const event = new CustomEvent(eventName, {\n bubbles: true,\n cancelable: true,\n detail: values,\n });\n\n element.dispatchEvent(event);\n\n return !event.defaultPrevented;\n};\n\nexport default triggerCustomEvent;\n","import type { ClassNames } from \"./classNames\";\nimport type { MoveInfo, TreeEvent, TreeEventName, TreeEvents } from \"./events\";\nimport type { PositionInfo } from \"./mouseUtils\";\nimport type { NodeData, NodeId, Position } from \"./node\";\nimport type { TreeElementOptions } from \"./options\";\nimport type { SavedState } from \"./saveStateHandler\";\nimport type { SelectNodeOptions } from \"./selectNodeHandler\";\n\nimport createClassNames from \"./classNames\";\nimport DataLoader from \"./dataLoader\";\nimport { DragAndDropHandler } from \"./dragAndDropHandler\";\nimport ElementsRenderer from \"./elementsRenderer\";\nimport KeyHandler from \"./keyHandler\";\nimport MouseHandler from \"./mouseHandler\";\nimport { Node } from \"./node\";\nimport NodeElement from \"./nodeElement\";\nimport FolderElement from \"./nodeElement/folderElement\";\nimport { getOffsetTop } from \"./positionUtils\";\nimport RequestUrl from \"./requestUrl\";\nimport SaveStateHandler from \"./saveStateHandler\";\nimport ScrollHandler from \"./scrollHandler\";\nimport SelectNodeHandler from \"./selectNodeHandler\";\nimport setDefaultOptions from \"./setDefaultOptions\";\nimport triggerCustomEvent from \"./triggerCustomEvent\";\nimport __version__ from \"./version\";\n\n// The types that appear in the public api. Consumers cannot import them from\n// the submodules directly, because those are not exposed in package.json.\n// Type only, so that the iife build keeps exposing the TreeElement class itself\n// as its global, instead of an object of named exports.\nexport type {\n MoveInfo,\n Node,\n NodeData,\n NodeId,\n Position,\n SavedState,\n SelectNodeOptions,\n TreeElementOptions,\n TreeEvent,\n TreeEventName,\n TreeEvents,\n};\n\nexport type TriggerEventProvider = (\n element: HTMLElement,\n eventName: TreeEventName,\n values?: TreeEvents[TreeEventName],\n) => boolean;\n\ninterface TreeElementParams extends Partial<TreeElementOptions> {\n /** The element the tree is rendered into. Its content is replaced. */\n htmlElement: HTMLElement;\n /** Replaces how events are dispatched. It must return whether the event\n * was not cancelled. This exists for tests and for integrating with\n * another event system. */\n overrideTriggerEventProvider?: TriggerEventProvider;\n}\n\nexport default class TreeElement {\n private classNames: ClassNames;\n private dataLoader: DataLoader;\n private dndHandler: DragAndDropHandler;\n private htmlElement: HTMLElement;\n private isInitialized: boolean;\n private keyHandler: KeyHandler;\n private mouseHandler: MouseHandler;\n private nodeMap: WeakMap<HTMLElement, Node>;\n private options: TreeElementOptions;\n private renderer: ElementsRenderer;\n private saveStateHandler: SaveStateHandler;\n private scrollHandler: ScrollHandler;\n private selectNodeHandler: SelectNodeHandler;\n private tree: Node;\n private triggerEventProvider: TriggerEventProvider;\n\n /** @hidden */\n constructor({\n htmlElement,\n overrideTriggerEventProvider,\n ...options\n }: TreeElementParams) {\n this.htmlElement = htmlElement;\n this.options = setDefaultOptions(htmlElement, options);\n this.classNames = createClassNames(this.options);\n this.triggerEventProvider =\n overrideTriggerEventProvider ?? triggerCustomEvent;\n\n this.isInitialized = false;\n this.tree = new Node({}, true);\n this.nodeMap = new WeakMap();\n\n const {\n autoEscape,\n buttonLeft,\n closedIcon,\n dataFilter,\n dragAndDrop,\n keyboardSupport,\n onCanMove,\n onCanMoveTo,\n onCreateLi,\n onDragMove,\n onDragStop,\n onGetStateFromStorage,\n onIsMoveHandle,\n onSetStateFromStorage,\n openedIcon,\n openFolderDelay,\n rtl,\n saveState: saveStateOption,\n showEmptyFolder,\n slide,\n tabIndex,\n } = this.options;\n\n const classNames = this.classNames;\n const closeNode = this.closeNode.bind(this);\n const getNodeElement = this.getNodeElement.bind(this);\n const getNodeElementForNode = this.getNodeElementForNode.bind(this);\n const getNodeById = this.getNodeById.bind(this);\n const getSelectedNode = this.getSelectedNode.bind(this);\n const getTree = this.getTree.bind(this);\n const isFocusOnTree = this.isFocusOnTree.bind(this);\n const loadData = this.loadData.bind(this);\n const openNode = this.openNode.bind(this);\n const openParents = this.openParents.bind(this);\n const refreshElements = this.refreshElements.bind(this);\n const refreshHitAreas = this.refreshHitAreas.bind(this);\n const setNodeElement = this.setNodeElement.bind(this);\n const treeElement = this.htmlElement;\n const triggerEvent = this.triggerEvent.bind(this);\n\n const saveState = () => {\n saveStateHandler.saveState();\n };\n\n const selectNodeHandler = new SelectNodeHandler({\n getNodeById,\n getNodeElementForNode,\n getOnCanSelectNode: () => this.options.onCanSelectNode,\n getSelectable: () => this.options.selectable,\n openParents,\n saveState,\n triggerEvent,\n });\n\n const addToSelection =\n selectNodeHandler.addToSelection.bind(selectNodeHandler);\n const getSelectedNodes =\n selectNodeHandler.getSelectedNodes.bind(selectNodeHandler);\n const isNodeSelected =\n selectNodeHandler.isNodeSelected.bind(selectNodeHandler);\n const removeFromSelection =\n selectNodeHandler.removeFromSelection.bind(selectNodeHandler);\n const selectNode =\n selectNodeHandler.selectSingleNode.bind(selectNodeHandler);\n\n const getMouseDelay = () => this.options.startDndDelay ?? 0;\n\n const dataLoader = new DataLoader({\n classNames,\n dataFilter,\n loadData,\n treeElement,\n triggerEvent,\n });\n\n const saveStateHandler = new SaveStateHandler({\n addToSelection,\n getNodeById,\n getSelectedNodes,\n getTree,\n onGetStateFromStorage,\n onSetStateFromStorage,\n openNode,\n refreshElements,\n removeFromSelection,\n saveState: saveStateOption,\n });\n\n const scrollHandler = new ScrollHandler({\n refreshHitAreas,\n treeElement,\n });\n\n const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);\n\n const dndHandler = new DragAndDropHandler({\n autoEscape,\n classNames,\n getNodeElement,\n getNodeElementForNode,\n getScrollLeft,\n getTree,\n onCanMove,\n onCanMoveTo,\n onDragMove,\n onDragStop,\n onIsMoveHandle,\n openFolderDelay,\n openNode,\n refreshElements,\n slide,\n treeElement,\n triggerEvent,\n });\n\n const keyHandler = new KeyHandler({\n closeNode,\n getSelectedNode,\n isFocusOnTree,\n keyboardSupport,\n openNode,\n selectNode,\n });\n\n const renderer = new ElementsRenderer({\n autoEscape,\n buttonLeft,\n classNames,\n closedIcon,\n dragAndDrop,\n getTree,\n htmlElement: treeElement,\n isNodeSelected,\n onCreateLi,\n openedIcon,\n rtl,\n setNodeElement,\n showEmptyFolder,\n tabIndex,\n });\n\n const getNode = this.getNode.bind(this);\n const onMouseCapture = this.mouseCapture.bind(this);\n const onMouseDrag = this.mouseDrag.bind(this);\n const onMouseStart = this.mouseStart.bind(this);\n const onMouseStop = this.mouseStop.bind(this);\n\n const mouseHandler = new MouseHandler({\n classNames,\n element: treeElement,\n getMouseDelay,\n getNode,\n onClickButton: this.toggle.bind(this),\n onClickTitle: selectNode,\n onMouseCapture,\n onMouseDrag,\n onMouseStart,\n onMouseStop,\n triggerEvent,\n useContextMenu: this.options.useContextMenu,\n });\n\n this.dataLoader = dataLoader;\n this.dndHandler = dndHandler;\n this.keyHandler = keyHandler;\n this.mouseHandler = mouseHandler;\n this.renderer = renderer;\n this.saveStateHandler = saveStateHandler;\n this.scrollHandler = scrollHandler;\n this.selectNodeHandler = selectNodeHandler;\n\n this.initData();\n }\n\n /**\n * Adds a sibling after a node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addNodeAfter(nodeData: NodeData, existingNode: Node): Node | null {\n const newNode = existingNode.addAfter(nodeData);\n\n if (newNode) {\n this.refreshElements(existingNode.parent);\n }\n\n return newNode;\n }\n\n /**\n * Adds a sibling before a node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addNodeBefore(nodeData: NodeData, existingNode: Node): Node | null {\n const newNode = existingNode.addBefore(nodeData);\n\n if (newNode) {\n this.refreshElements(existingNode.parent);\n }\n\n return newNode;\n }\n\n /**\n * Inserts a new node between a node and its parent, taking the node as its\n * child.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addParentNode(nodeData: NodeData, existingNode: Node): Node | null {\n const newNode = existingNode.addParent(nodeData);\n\n if (newNode) {\n this.refreshElements(newNode.parent);\n }\n\n return newNode;\n }\n\n /**\n * Adds a node to the selection instead of replacing it.\n *\n * @param mustSetFocus - Move the focus to the node. Default `true`.\n * @group Selection\n */\n public addToSelection(node: Node, mustSetFocus?: boolean) {\n this.selectNodeHandler.addToSelection(node);\n this.openParents(node);\n\n this.getNodeElementForNode(node).select(mustSetFocus ?? true);\n\n this.saveState();\n }\n\n /**\n * Adds a node as the last child of a parent.\n *\n * @example\n * ```js\n * tree.appendNode({ name: \"child\", id: 5 }, tree.getNodeById(1));\n * ```\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public appendNode(nodeData: NodeData, parentNode: Node): Node {\n const node = parentNode.append(nodeData);\n\n this.refreshElements(parentNode);\n\n return node;\n }\n\n /**\n * Closes a folder.\n *\n * @param slide - Override the `slide` option for this call.\n * @group Opening and closing\n */\n public closeNode(node: Node, slide?: boolean): void {\n if (node.isFolder() || node.isEmptyFolder) {\n this.createFolderElement(node).close(\n slide ?? this.options.slide,\n this.options.animationSpeed,\n );\n\n this.saveState();\n }\n }\n\n /**\n * Empties the element and removes the tree's document-level keyboard\n * listener. Call it when you remove the tree from the page.\n *\n * @group Other\n */\n public deinit(): void {\n this.htmlElement.textContent = \"\";\n\n this.dataLoader.deinit();\n this.keyHandler.deinit();\n this.mouseHandler.deinit();\n\n this.tree = new Node({}, true);\n }\n\n /**\n * Returns the node that belongs to a `li` element the tree rendered.\n *\n * @group Finding nodes\n */\n public getNode(element: HTMLElement): Node | null {\n const liElement = element.closest<HTMLElement>(\n `li.${this.classNames.common}`,\n );\n\n if (liElement) {\n return this.nodeMap.get(liElement) ?? null;\n } else {\n return null;\n }\n }\n\n /**\n * Returns the first node for which the callback returns `true`.\n *\n * @example\n * ```js\n * const node = tree.getNodeByCallback((node) => node.children.length > 3);\n * ```\n *\n * @group Finding nodes\n */\n public getNodeByCallback(callback: (node: Node) => boolean): Node | null {\n return this.tree.getNodeByCallback(callback);\n }\n\n /**\n * Returns the node with this id.\n *\n * @example\n * ```js\n * const node = tree.getNodeById(1);\n * ```\n *\n * @group Finding nodes\n */\n public getNodeById(id: NodeId): Node | null {\n return this.tree.getNodeById(id);\n }\n\n /**\n * Returns the first node with this name.\n *\n * @group Finding nodes\n */\n public getNodeByName(name: string): Node | null {\n return this.tree.getNodeByName(name);\n }\n\n /**\n * Like `getNodeByName`, but throws when there is no such node. Convenient\n * in tests and when a missing node is a bug.\n *\n * @group Finding nodes\n */\n public getNodeByNameMustExist(name: string): Node {\n return this.tree.getNodeByNameMustExist(name);\n }\n\n /**\n * Returns all nodes with this property value.\n *\n * @example\n * ```js\n * tree.getNodesByProperty(\"color\", \"green\");\n * ```\n *\n * @group Finding nodes\n */\n public getNodesByProperty(key: string, value: unknown): Node[] {\n return this.tree.getNodesByProperty(key, value);\n }\n\n /**\n * Returns the selected node, or `null` when nothing is selected.\n *\n * @group Selection\n */\n public getSelectedNode(): Node | null {\n return this.selectNodeHandler.getSelectedNode();\n }\n\n /**\n * Returns the selected nodes.\n *\n * @group Selection\n */\n public getSelectedNodes(): Node[] {\n return this.selectNodeHandler.getSelectedNodes();\n }\n\n /**\n * Returns the current state — `open_nodes` and `selected_node` — whether or\n * not `saveState` is enabled.\n *\n * @group State\n */\n public getState(): null | SavedState {\n return this.saveStateHandler.getState();\n }\n\n /**\n * Returns the state as it is stored.\n *\n * @group State\n */\n public getStateFromStorage(): null | SavedState {\n return this.saveStateHandler.getStateFromStorage();\n }\n\n /**\n * Returns the root node. It is not rendered; its `children` are the\n * top-level nodes. Also available as the `tree` property.\n *\n * @group Finding nodes\n */\n public getTree(): Node {\n return this.tree;\n }\n\n /**\n * Returns the version of tree-element.\n *\n * @group Other\n */\n public getVersion(): string {\n return __version__;\n }\n\n /**\n * Returns whether the user is dragging a node.\n *\n * @group Other\n */\n public isDragging(): boolean {\n return this.dndHandler.isDragging;\n }\n\n /**\n * Returns whether the node is selected.\n *\n * @group Selection\n */\n public isNodeSelected(node: Node): boolean {\n return this.selectNodeHandler.isNodeSelected(node);\n }\n\n /**\n * Loads data into the tree.\n *\n * @param parentNode - Replace this node's children instead of the whole\n * tree.\n * @group Loading data\n */\n public loadData(data: NodeData[] | null, parentNode?: Node): void {\n if (data) {\n if (parentNode) {\n this.deselectNodes(parentNode);\n this.loadSubtree(data, parentNode);\n } else {\n this.initTree(data);\n }\n\n if (this.isDragging()) {\n this.dndHandler.refresh();\n }\n }\n\n this.triggerEvent(\"tree.set_data\", {\n node: parentNode,\n treeData: data ?? undefined,\n });\n }\n\n /**\n * Fetches data and loads it into the tree, or into `parentNode`.\n *\n * @param url - Defaults to the `dataUrl` option.\n * @group Loading data\n */\n public async loadDataFromUrl(url?: string, parentNode?: Node): Promise<void> {\n const requestUrl = url\n ? new RequestUrl(url)\n : this.createRequestUrl(parentNode);\n\n if (requestUrl) {\n await this.dataLoader.loadFromUrl(requestUrl, parentNode);\n }\n }\n\n /**\n * Selects the next visible node, like the down arrow key.\n *\n * @group Selection\n */\n public moveDown() {\n this.keyHandler.moveDown();\n }\n\n /**\n * Moves a node inside the tree.\n *\n * @example\n * ```js\n * tree.moveNode(tree.getNodeById(2), tree.getNodeById(1), \"inside\");\n * ```\n *\n * @param position - `\"before\"`, `\"after\"` or `\"inside\"`.\n * @group Changing the tree\n */\n public moveNode(node: Node, targetNode: Node, position: Position): void {\n this.tree.moveNode(node, targetNode, position);\n this.refreshElements(null);\n }\n\n /**\n * Selects the previous visible node, like the up arrow key.\n *\n * @group Selection\n */\n public moveUp() {\n this.keyHandler.moveUp();\n }\n\n /**\n * Opens a folder, and the folders above it. A node marked `load_on_demand`\n * is fetched first, so await the promise when you need to know it is really\n * open.\n *\n * @example\n * ```js\n * await tree.openNode(node);\n * console.log(\"open\");\n * ```\n *\n * @param slide - Override the `slide` option for this call.\n * @group Opening and closing\n */\n public async openNode(node: Node, slide?: boolean): Promise<void> {\n const mustSlide = slide ?? this.options.slide;\n\n const doOpenNode = async (\n openedNode: Node,\n slideOption: boolean,\n ): Promise<void> => {\n if (!node.children.length) {\n return;\n }\n\n const folderElement = this.createFolderElement(openedNode);\n\n await folderElement.open(slideOption, this.options.animationSpeed);\n };\n\n if (node.isFolder() || node.isEmptyFolder) {\n if (node.load_on_demand) {\n await this.loadFolderOnDemand(node, mustSlide);\n } else {\n let parent = node.parent;\n\n while (parent) {\n // nb: do not open root element\n if (parent.parent) {\n await doOpenNode(parent, false);\n }\n parent = parent.parent;\n }\n\n await doOpenNode(node, mustSlide);\n\n this.saveState();\n }\n }\n }\n\n /**\n * Adds a node as the first child of a parent.\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public prependNode(nodeData: NodeData, parentNode: Node): Node {\n const node = parentNode.prepend(nodeData);\n\n this.refreshElements(parentNode);\n\n return node;\n }\n\n /**\n * Re-renders the whole tree. Needed after changing node data directly\n * instead of through these methods.\n *\n * @group Changing the tree\n */\n public refresh() {\n this.refreshElements(null);\n }\n\n /**\n * Recomputes the drop targets. Call this if the layout changes during a\n * drag.\n *\n * @group Other\n */\n public refreshHitAreas() {\n this.dndHandler.refresh();\n }\n\n /**\n * Removes a node from the selection.\n *\n * @group Selection\n */\n public removeFromSelection(node: Node) {\n this.selectNodeHandler.removeFromSelection(node);\n\n this.getNodeElementForNode(node).deselect();\n this.saveState();\n }\n\n /**\n * Removes a node and its children.\n *\n * @group Changing the tree\n */\n public removeNode(node: Node): void {\n this.selectNodeHandler.removeFromSelection(node, true); // including children\n\n const parent = node.parent;\n node.remove();\n this.refreshElements(parent);\n }\n\n /**\n * Scrolls the node into view.\n *\n * @group Selection\n */\n public scrollToNode(node: Node) {\n if (!node.element) {\n return;\n }\n\n const top = getOffsetTop(node.element) - getOffsetTop(this.htmlElement);\n\n this.scrollHandler.scrollToY(top);\n }\n\n /**\n * Replaces the selection, and opens the parents of the node.\n *\n * @param node - `null` clears the selection.\n * @param options - `mustSetFocus`: move focus to the node, default `true`.\n * `mustToggle`: deselect the node if it is already selected, default\n * `false`.\n * @group Selection\n */\n public selectNode(node: Node | null, options?: SelectNodeOptions): void {\n if (!node) {\n // Called with empty node -> deselect current node\n this.deselectCurrentNode();\n this.saveStateHandler.saveState();\n return;\n }\n\n this.selectNodeHandler.selectSingleNode(node, options);\n }\n\n /**\n * Changes an option after construction. See\n * [Options](/reference/options#changing-an-option-later) for the caveats.\n *\n * @group Other\n */\n public setOption(option: string, value: unknown) {\n (this.options as unknown as Record<string, unknown>)[option] = value;\n }\n\n /**\n * Applies a state to the tree, and saves it to storage when `saveState` is\n * enabled.\n *\n * @group State\n */\n public setState(state: SavedState) {\n this.saveStateHandler.setInitialState(state);\n this.refreshElements(null);\n this.saveState();\n }\n\n /**\n * Closes an open node and opens a closed one.\n *\n * @param slide - Override the `slide` option for this call.\n * @group Opening and closing\n */\n public toggle(node: Node, slide: boolean | null = null) {\n const mustSlide = slide ?? this.options.slide;\n\n if (node.is_open) {\n this.closeNode(node, mustSlide);\n } else {\n void this.openNode(node, mustSlide);\n }\n }\n\n /**\n * Returns the tree as a json string, including changes made through the\n * api.\n *\n * @group Other\n */\n public toJson(): string {\n return JSON.stringify(this.tree.getData());\n }\n\n /**\n * Updates the data of a node and re-renders it. A string updates just the\n * name.\n *\n * Changing the `id` re-indexes the node. `children` and `parent` are\n * ignored — use `loadData` or `moveNode` for those.\n *\n * @example\n * ```js\n * tree.updateNode(node, \"new name\");\n * tree.updateNode(node, { name: \"new name\", color: \"red\" });\n * ```\n *\n * @group Changing the tree\n */\n public updateNode(node: Node, data: NodeData): void {\n const idIsChanged =\n typeof data === \"object\" && data.id && data.id !== node.id;\n\n if (idIsChanged) {\n this.tree.removeNodeFromIndex(node);\n }\n\n node.setData(data);\n\n if (idIsChanged) {\n this.tree.addNodeToIndex(node);\n }\n\n if (\n typeof data === \"object\" &&\n data.children &&\n data.children instanceof Array\n ) {\n node.removeChildren();\n\n if (data.children.length) {\n node.loadFromData(data.children);\n }\n }\n\n this.refreshElements(node);\n }\n\n private createFolderElement(node: Node) {\n const classNames = this.classNames;\n const closedIconElement = this.renderer.closedIconElement;\n const getScrollLeft = this.scrollHandler.getScrollLeft.bind(\n this.scrollHandler,\n );\n const openedIconElement = this.renderer.openedIconElement;\n const renderChildren = this.renderer.renderChildren.bind(this.renderer);\n const tabIndex = this.options.tabIndex;\n const treeElement = this.htmlElement;\n const triggerEvent = this.triggerEvent.bind(this);\n\n return new FolderElement({\n classNames,\n closedIconElement,\n getScrollLeft,\n node,\n openedIconElement,\n renderChildren,\n tabIndex,\n treeElement,\n triggerEvent,\n });\n }\n\n private createNodeElement(node: Node) {\n const classNames = this.classNames;\n const getScrollLeft = this.scrollHandler.getScrollLeft.bind(\n this.scrollHandler,\n );\n const tabIndex = this.options.tabIndex;\n const treeElement = this.htmlElement;\n\n return new NodeElement({\n classNames,\n getScrollLeft,\n node,\n tabIndex,\n treeElement,\n });\n }\n\n /* Create a RequestUrl based on the url in the options.\n * Add a 'node' query parameter for loading on demand\n * Add a 'selected_node' query parameter if a node is selected.\n */\n private createRequestUrl(node?: Node): null | RequestUrl {\n const dataUrl = this.options.dataUrl;\n\n let url;\n\n if (typeof dataUrl === \"function\") {\n url = dataUrl(node);\n } else {\n url = dataUrl;\n }\n\n if (!url) {\n return null;\n }\n\n const requestUrl = new RequestUrl(url);\n\n if (node?.id) {\n // Load on demand of a subtree; add node parameter\n requestUrl.setSearchParam(\"node\", node.id.toString());\n } else {\n // Add selected_node parameter\n const selectedNodeId = this.getNodeIdToBeSelected();\n if (selectedNodeId) {\n requestUrl.setSearchParam(\"selected_node\", selectedNodeId.toString());\n }\n }\n\n return requestUrl;\n }\n\n private deselectCurrentNode(): void {\n const node = this.getSelectedNode();\n if (node) {\n this.removeFromSelection(node);\n }\n }\n\n // Deselect the children of the node.\n private deselectNodes(parentNode: Node): void {\n const selectedNodesUnderParent =\n this.selectNodeHandler.getSelectedNodesUnder(parentNode);\n for (const n of selectedNodesUnderParent) {\n this.selectNodeHandler.removeFromSelection(n);\n }\n }\n\n // Get the maximum level for auto open\n private getAutoOpenMaxLevel(): number {\n if (this.options.autoOpen === true) {\n return -1;\n } else if (typeof this.options.autoOpen === \"number\") {\n return this.options.autoOpen;\n } else if (typeof this.options.autoOpen === \"string\") {\n return parseInt(this.options.autoOpen, 10);\n }\n\n /* istanbul ignore next @preserve */\n return 0;\n }\n\n private getNodeElement(element: HTMLElement): NodeElement | null {\n const node = this.getNode(element);\n if (node) {\n return this.getNodeElementForNode(node);\n } else {\n return null;\n }\n }\n\n private getNodeElementForNode(node: Node): NodeElement {\n if (node.isFolder()) {\n return this.createFolderElement(node);\n } else {\n return this.createNodeElement(node);\n }\n }\n\n private getNodeIdToBeSelected(): NodeId | null {\n return this.saveStateHandler.getNodeIdToBeSelected();\n }\n\n private initData(): void {\n if (this.options.data) {\n this.loadData(this.options.data);\n } else {\n const dataUrl = this.createRequestUrl();\n\n if (dataUrl) {\n void this.loadDataFromUrl();\n } else {\n this.loadData([]);\n }\n }\n }\n\n private initTree(data: NodeData[]): void {\n const doInit = (): void => {\n if (!this.isInitialized) {\n this.isInitialized = true;\n this.triggerEvent(\"tree.init\");\n }\n };\n\n this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);\n\n this.selectNodeHandler.clear();\n\n this.tree.loadFromData(data);\n\n const mustLoadOnDemand = this.setInitialState();\n\n this.refreshElements(null);\n\n if (mustLoadOnDemand) {\n // Load data on demand and then init the tree\n void this.setInitialStateOnDemand().then(doInit);\n } else {\n doInit();\n }\n }\n\n // Does an HTML element of the tree have the focus?\n private isFocusOnTree(): boolean {\n const activeElement = document.activeElement;\n\n /* istanbul ignore if */\n if (!activeElement) {\n return false;\n }\n\n // The keyboard must still work for input elements.\n const tagName = activeElement.tagName;\n if (tagName !== \"A\" && tagName !== \"SPAN\") {\n return false;\n }\n\n const node = this.getNode(activeElement as HTMLElement);\n return node?.tree === this.tree;\n }\n\n private isSelectedNodeInSubtree(subtree: Node): boolean {\n const selectedNode = this.getSelectedNode();\n\n if (!selectedNode) {\n return false;\n } else {\n return subtree === selectedNode || subtree.isParentOf(selectedNode);\n }\n }\n\n private async loadFolderOnDemand(node: Node, slide: boolean): Promise<void> {\n node.is_loading = true;\n\n await this.loadDataFromUrl(undefined, node);\n\n await this.openNode(node, slide);\n }\n\n private loadSubtree(data: NodeData[], parentNode: Node): void {\n parentNode.loadFromData(data);\n\n parentNode.load_on_demand = false;\n parentNode.is_loading = false;\n\n this.refreshElements(parentNode);\n }\n\n private mouseCapture(positionInfo: PositionInfo): boolean | null {\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n return this.dndHandler.mouseCapture(positionInfo);\n }\n\n private mouseDrag(positionInfo: PositionInfo): boolean {\n /* istanbul ignore if */\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n const result = this.dndHandler.mouseDrag(positionInfo);\n this.scrollHandler.checkScrolling(positionInfo);\n return result;\n }\n\n private mouseStart(positionInfo: PositionInfo): boolean {\n /* istanbul ignore if */\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n return this.dndHandler.mouseStart(positionInfo);\n }\n\n private mouseStop(positionInfo: PositionInfo): boolean {\n /* istanbul ignore if */\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n this.scrollHandler.stopScrolling();\n return this.dndHandler.mouseStop(positionInfo);\n }\n\n private openParents(node: Node) {\n const parent = node.parent;\n\n if (parent?.parent && !parent.is_open) {\n void this.openNode(parent, false);\n }\n }\n\n /*\n Redraw the tree or part of the tree.\n from_node: redraw this subtree\n */\n private refreshElements(fromNode: Node | null): void {\n const mustSetFocus = this.isFocusOnTree();\n const mustSelect = fromNode\n ? this.isSelectedNodeInSubtree(fromNode)\n : false;\n\n this.renderer.render(fromNode);\n\n if (mustSelect) {\n this.selectCurrentNode(mustSetFocus);\n }\n\n this.triggerEvent(\"tree.refresh\");\n }\n\n private saveState(): void {\n this.saveStateHandler.saveState();\n }\n\n private selectCurrentNode(mustSetFocus: boolean): void {\n const node = this.getSelectedNode();\n if (node) {\n const nodeElement = this.getNodeElementForNode(node);\n nodeElement.select(mustSetFocus);\n }\n }\n\n // Set initial state, either by restoring the state or auto-opening nodes\n // result: must load nodes on demand?\n private setInitialState(): boolean {\n const restoreState = (): [boolean, boolean] => {\n // result: is state restored, must load on demand?\n const state = this.saveStateHandler.getStateFromStorage();\n\n if (!state) {\n return [false, false];\n } else {\n const mustLoadOnDemand = this.saveStateHandler.setInitialState(state);\n\n // return true: the state is restored\n return [true, mustLoadOnDemand];\n }\n };\n\n const autoOpenNodes = (): boolean => {\n // result: must load on demand?\n if (this.options.autoOpen === false) {\n return false;\n }\n\n const maxLevel = this.getAutoOpenMaxLevel();\n let mustLoadOnDemand = false;\n\n this.tree.iterate((node: Node, level: number) => {\n if (node.load_on_demand) {\n mustLoadOnDemand = true;\n return false;\n } else if (!node.hasChildren()) {\n return false;\n } else {\n node.is_open = true;\n return level !== maxLevel;\n }\n });\n\n return mustLoadOnDemand;\n };\n\n let [isRestored, mustLoadOnDemand] = restoreState(); // eslint-disable-line prefer-const\n\n if (!isRestored) {\n mustLoadOnDemand = autoOpenNodes();\n }\n\n return mustLoadOnDemand;\n }\n\n // Set the initial state for nodes that are loaded on demand\n private async setInitialStateOnDemand(): Promise<void> {\n return new Promise((resolve) => {\n const restoreState = (): boolean => {\n const state = this.saveStateHandler.getStateFromStorage();\n\n if (!state) {\n return false;\n } else {\n void this.saveStateHandler.setInitialStateOnDemand(state).then(() => {\n resolve();\n });\n\n return true;\n }\n };\n\n const autoOpenNodes = (): void => {\n const maxLevel = this.getAutoOpenMaxLevel();\n let loadingCount = 0;\n\n const loadAndOpenNode = (node: Node): void => {\n loadingCount += 1;\n void this.openNode(node, false).then(() => {\n loadingCount -= 1;\n openNodes();\n });\n };\n\n const openNodes = (): void => {\n this.tree.iterate((node: Node, level: number) => {\n if (node.load_on_demand) {\n if (!node.is_loading) {\n loadAndOpenNode(node);\n }\n\n return false;\n } else {\n void this.openNode(node, false);\n\n return level !== maxLevel;\n }\n });\n\n if (loadingCount === 0) {\n resolve();\n }\n };\n\n openNodes();\n };\n\n if (!restoreState()) {\n autoOpenNodes();\n }\n });\n }\n\n // Set this HTML element to this node in the node map.\n private setNodeElement(element: HTMLElement, node: Node) {\n this.nodeMap.set(element, node);\n }\n\n private triggerEvent<Name extends TreeEventName>(\n eventName: Name,\n values?: TreeEvents[Name],\n ): boolean {\n return this.triggerEventProvider(this.htmlElement, eventName, values);\n }\n}\n","// Generated by config/generateVersion.mjs. Do not edit.\nconst version = \"0.2.0\";\n\nexport default version;\n"],"names":["DataLoader","constructor","_classNames","classNames","_dataFilter","dataFilter","_loadData","loadData","_treeElement","treeElement","_triggerEvent","triggerEvent","this","abortController","AbortController","deinit","abort","loadFromUrl","url","node","element","classList","add","loading","stopLoading","remove","signal","setSearchParam","Date","now","toString","fetch","value","headers","then","async","response","ok","data","json","catch","error","aborted","getOffsetTop","getElementPosition","top","rect","getBoundingClientRect","left","x","window","scrollX","y","scrollY","DragElement","_autoEscape","autoEscape","_nodeName","nodeName","_offsetX","offsetX","_offsetY","offsetY","createElement","appendChild","move","pageX","pageY","style","document","title","dragging","textContent","innerHTML","position","generateHitAreasForGroup","hitAreas","positionsInGroup","bottom","positionCount","Math","min","length","areaHeight","round","areaTop","i","push","DragAndDropHandler","_getNodeElement","getNodeElement","_getNodeElementForNode","getNodeElementForNode","_getScrollLeft","getScrollLeft","_getTree","getTree","_onCanMove","onCanMove","_onCanMoveTo","onCanMoveTo","_onDragMove","onDragMove","_onDragStop","onDragStop","_onIsMoveHandle","onIsMoveHandle","_openFolderDelay","openFolderDelay","_openNode","openNode","_refreshElements","refreshElements","_slide","slide","hoveredArea","isDragging","currentItem","dragElement","openFolderTimer","previousGhost","mouseCapture","positionInfo","target","mustCaptureElement","nodeElement","mouseDrag","area","findHoveredArea","canMoveToArea","isFolder","stopOpenFolderTimer","mustOpenFolderTimer","startOpenFolderTimer","updateDropHint","removeDropHint","originalEvent","mouseStart","refresh","name","moving","mouseStop","moveItem","clear","removeHover","removeHitAreas","currentNode","generateHitAreas","dimensions","getTreeDimensions","right","items","compareFn","low","high","mid","item","undefined","compareResult","binarySearch","tree","treeBottom","hitPositions","previousTop","group","generateHitAreasFromPositions","lastTop","addHitPosition","_handleAfterOpenFolder","handleAfterOpenFolder","_handleClosedFolder","handleClosedFolder","_handleFirstNode","handleFirstNode","_handleNode","handleNode","_handleOpenFolder","handleOpenFolder","isFirstNode","iterate","nextNode","mustIterateInside","is_open","hasChildren","offsetParent","childrenLength","children","forEach","_","child","nextChild","iterateVisibleNodes","height","clientHeight","generateHitPositions","treePosition","clientWidth","movedNode","targetNode","previousParent","parent","doMove","moveNode","moveInfo","folder","setTimeout","clearTimeout","addDropHint","ElementsRenderer","_buttonLeft","buttonLeft","_closedIcon","closedIcon","_dragAndDrop","dragAndDrop","_htmlElement","htmlElement","_isNodeSelected","isNodeSelected","_onCreateLi","onCreateLi","_openedIcon","openedIcon","_rtl","rtl","_setNodeElement","setNodeElement","_showEmptyFolder","showEmptyFolder","_tabIndex","tabIndex","openedIconElement","createButtonElement","closedIconElement","rootUlTemplate","createUlTemplate","groupUlTemplate","nodeTemplate","createNodeTemplate","openedFolderTemplate","createFolderTemplate","closedFolderTemplate","render","fromNode","renderFromNode","renderFromRoot","renderChildren","createDomElements","getLevel","currentLi","newLi","createLi","replaceWith","mustRenderChildren","attachNodeData","li","template","content","nodeType","isRootNode","level","ul","cloneNode","createFolderLi","isSelected","selected","is_loading","fillTitleSpan","firstChild","childNodes","isOpen","liClasses","common","closed","createLiTemplate","join","div","buttonLink","className","getButtonClasses","iconElement","titleSpan","createTitleSpanTemplate","setAttribute","isEmptyFolder","createNodeLi","classes","titleFolder","titleButtonLeft","titleButtonRight","classString","role","dnd","toggler","togglerLeft","togglerRight","KeyHandler","_closeNode","closeNode","_getSelectedNode","getSelectedNode","_isFocusOnTree","isFocusOnTree","_keyboardSupport","keyboardSupport","_selectNode","selectNode","originalSelectNode","addEventListener","handleKeyDown","removeEventListener","moveDown","getNextVisibleNode","moveUp","getPreviousVisibleNode","canHandleKeyboard","e","isKeyHandled","key","moveLeft","moveRight","preventDefault","selectedNode","getParent","getPositionInfoFromMouseEvent","getPositionInfoFromTouch","touch","MouseHandler","_element","_getMouseDelay","getMouseDelay","_getNode","getNode","_onClickButton","onClickButton","_onClickTitle","onClickTitle","_onMouseCapture","onMouseCapture","_onMouseDrag","onMouseDrag","_onMouseStart","onMouseStart","_onMouseStop","onMouseStop","_useContextMenu","useContextMenu","handleClick","handleDblclick","mouseDown","passive","touchStart","handleContextmenu","isMouseStarted","mouseDelayTimer","isMouseDelayMet","mouseDownInfo","removeMouseMoveEventListeners","getClickTarget","button","closest","type","clickTarget","stopPropagation","handleMouseDown","handleMouseUp","handleStartMouse","handleMouseMove","cancelable","mouseMove","touchMove","mouseUp","touchEnd","mouseDelay","startMouseDelayTimer","touches","isNodeRecordWithChildren","Array","Node","id","idMapping","load_on_demand","nodeClass","nodeData","isRoot","setData","Map","addAfter","nodeInfo","createNode","childIndex","getChildIndex","addChildAtPosition","loadChildrenFromData","addBefore","addChild","setParent","index","splice","addNodeToIndex","set","addParent","newParent","originalParent","append","filter","f","result","indexOf","getData","includeParent","getDataFromNodes","nodes","map","tmpNode","k","Object","prototype","hasOwnProperty","call","getLastChild","lastChild","getNextNode","includeChildren","getNextSibling","nextIndex","getNodeByCallback","callback","getNodeById","nodeId","get","getNodeByName","getNodeByNameMustExist","n","Error","getNodesByProperty","getPreviousNode","previousSibling","getPreviousSibling","previousIndex","initFromData","addChildren","childrenData","addNode","isParentOf","_iterate","loadFromData","removeChildren","childData","doRemoveChild","prepend","removeChild","removeNodeFromIndex","delete","o","getNodeClass","BorderDropHint","scrollLeft","querySelector","hint","width","max","offsetWidth","border","GhostDropHint","ghost","createGhostElement","moveAfter","moveBefore","moveInsideOpenFolder","moveInside","circle","ghostClass","line","circleSpan","lineSpan","after","before","inside","childElement","NodeElement","_node","mustShowBorderDropHint","deselect","isRendered","getTitleSpan","removeAttribute","blur","select","mustSetFocus","focus","getUl","Boolean","getAnimationDuration","duration","FolderElement","_closedIconElement","_openedIconElement","_renderChildren","super","close","animationSpeed","getButton","icon","doClose","onFinished","animate","scrollHeight","overflow","onfinish","display","slideUp","open","Promise","resolve","doOpen","slideDown","RequestUrl","inputUrl","URL","isAbsoluteUrl","isAbsolute","searchParams","href","slice","LOCALHOST","SaveStateHandler","_addToSelection","addToSelection","_getNodeById","_getSelectedNodes","getSelectedNodes","_onGetStateFromStorage","onGetStateFromStorage","_onSetStateFromStorage","onSetStateFromStorage","_removeFromSelection","removeFromSelection","_saveState","saveState","saveStateOption","getNodeIdToBeSelected","state","getStateFromStorage","selected_node","getState","open_nodes","openNodes","getOpenNodeIds","selectedNodeIds","getSelectedNodeIds","jsonData","loadFromStorage","parseState","JSON","stringify","localStorage","setItem","getKeyName","setInitialState","mustLoadOnDemand","openInitialNodes","resetSelection","selectInitialNodes","setInitialStateOnDemand","nodeIds","newNodesIds","loadAndOpenNode","getItem","parse","selectCount","ScrollParent","_container","container","_refreshHitAreas","refreshHitAreas","checkHorizontalScrolling","newHorizontalScrollDirection","getNewHorizontalScrollDirection","horizontalScrollDirection","horizontalScrollTimeout","scrollHorizontally","bind","checkVerticalScrolling","newVerticalScrollDirection","getNewVerticalScrollDirection","verticalScrollDirection","verticalScrollTimeout","scrollVertically","scrollToY","scrollTop","stopScrolling","scrollBy","behavior","ContainerScrollParent","scrollParentOffset","containerWidth","getScrollParentTop","getScrollParentBottom","scrollParentBottom","containerHeight","scrollParentTop","DocumentScrollParent","documentElement","treeTop","documentScrollHeight","documentScrollWidth","isNearLeftEdge","innerWidth","canScrollRight","innerHeight","canScrollDown","getDocumentScrollHeight","getDocumentScrollWidth","scrollWidth","isOverflow","overflowValue","hasOverFlow","getComputedStyle","overflowX","overflowY","ScrollHandler","scrollParent","checkScrolling","getScrollParent","parentElement","getParentWithOverflow","tagName","createScrollParent","SelectNodeHandler","_getOnCanSelectNode","getOnCanSelectNode","_getSelectable","getSelectable","_openParents","openParents","selectedNodes","Set","selectedSingleNode","getSelectedNodesUnder","has","selectSingleNode","optionsParam","selectOptions","mustToggle","onCanSelectNode","canSelect","deselectCurrentNode","deselectedNode","defaults","autoOpen","classPrefix","selectable","startDndDelay","triggerCustomEvent","eventName","values","event","CustomEvent","bubbles","detail","dispatchEvent","defaultPrevented","dataLoader","dndHandler","isInitialized","keyHandler","mouseHandler","nodeMap","options","renderer","saveStateHandler","scrollHandler","selectNodeHandler","triggerEventProvider","overrideTriggerEventProvider","inputOptions","dataUrl","dataset","dataRtl","getRtlOptionFromHTMLElement","getDefaultClosedIcon","setDefaultOptions","commonClassName","treeClassName","createClassNames","WeakMap","toggle","initData","addNodeAfter","existingNode","newNode","addNodeBefore","addParentNode","appendNode","parentNode","createFolderElement","liElement","getVersion","deselectNodes","loadSubtree","initTree","treeData","loadDataFromUrl","requestUrl","createRequestUrl","mustSlide","doOpenNode","openedNode","slideOption","folderElement","loadFolderOnDemand","prependNode","removeNode","scrollToNode","setOption","option","setState","toJson","updateNode","idIsChanged","createNodeElement","selectedNodeId","selectedNodesUnderParent","getAutoOpenMaxLevel","parseInt","doInit","activeElement","isSelectedNodeInSubtree","subtree","mustSelect","selectCurrentNode","isRestored","restoreState","maxLevel","autoOpenNodes","loadingCount"],"mappings":"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"}
1
+ {"version":3,"file":"tree_element.js","sources":["src/dataLoader.ts","src/positionUtils.ts","src/dragAndDropHandler/dragElement.ts","src/dragAndDropHandler/iterateVisibleNodes.ts","src/dragAndDropHandler/generateHitAreas.ts","src/dragAndDropHandler/index.ts","src/dragAndDropHandler/binarySearch.ts","src/elementsRenderer.ts","src/util.ts","src/keyHandler.ts","src/mouseUtils.ts","src/mouseHandler.ts","src/nodeUtils.ts","src/node.ts","src/nodeElement/borderDropHint.ts","src/nodeElement/ghostDropHint.ts","src/nodeElement/index.ts","src/animation.ts","src/nodeElement/folderElement.ts","src/requestUrl.ts","src/saveStateHandler.ts","src/scrollHandler/scrollParent.ts","src/scrollHandler/containerScrollParent.ts","src/scrollHandler/documentScrollParent.ts","src/scrollHandler/createScrollParent.ts","src/scrollHandler.ts","src/selectNodeHandler.ts","src/setDefaultOptions.ts","src/classNames.ts","src/triggerCustomEvent.ts","src/index.ts","src/version.ts"],"sourcesContent":["import type { ClassNames } from \"./classNames\";\nimport type { LoadData, TriggerEvent } from \"./methodTypes\";\nimport type { Node, NodeData } from \"./node\";\nimport type { DataFilter } from \"./options\";\nimport type RequestUrl from \"./requestUrl\";\n\ninterface DataLoaderParams {\n classNames: ClassNames;\n dataFilter?: DataFilter;\n loadData: LoadData;\n treeElement: HTMLElement;\n triggerEvent: TriggerEvent;\n}\n\nexport default class DataLoader {\n private abortController: AbortController;\n private classNames: ClassNames;\n private dataFilter?: DataFilter;\n private loadData: LoadData;\n private treeElement: HTMLElement;\n private triggerEvent: TriggerEvent;\n\n constructor({\n classNames,\n dataFilter,\n loadData,\n treeElement,\n triggerEvent,\n }: DataLoaderParams) {\n this.abortController = new AbortController();\n this.classNames = classNames;\n this.dataFilter = dataFilter;\n this.loadData = loadData;\n this.treeElement = treeElement;\n this.triggerEvent = triggerEvent;\n }\n\n public deinit(): void {\n this.abortController.abort();\n }\n\n public async loadFromUrl(url: RequestUrl, node?: Node): Promise<void> {\n const element = node?.element ?? this.treeElement;\n element.classList.add(this.classNames.loading);\n\n // Tell screen readers that the children of the folder are loading\n const titleSpan = node ? this.getTitleSpan(element) : null;\n titleSpan?.setAttribute(\"aria-busy\", \"true\");\n\n this.triggerEvent(\"tree.loading_data\", {\n element,\n node,\n });\n\n const stopLoading = (): void => {\n element.classList.remove(this.classNames.loading);\n titleSpan?.removeAttribute(\"aria-busy\");\n this.triggerEvent(\"tree.loaded_data\", {\n element,\n node,\n });\n };\n\n const handleResponse = async (response: Response): Promise<void> => {\n if (response.ok) {\n const data = (await response.json()) as NodeData[];\n\n stopLoading();\n this.loadData(this.dataFilter ? this.dataFilter(data) : data, node);\n } else {\n stopLoading();\n\n this.triggerEvent(\"tree.load_failed\", { response });\n }\n };\n\n const signal = this.abortController.signal;\n url.setSearchParam(\"_\", Date.now().toString());\n\n return fetch(url.value(), {\n headers: { \"Content-Type\": \"application/json\" },\n signal,\n })\n .then(handleResponse)\n .catch((error: unknown) => {\n if (this.abortController.signal.aborted) {\n // The request was aborted by deinit.\n return;\n }\n\n stopLoading();\n this.triggerEvent(\"tree.load_failed\", { error });\n });\n }\n\n private getTitleSpan(element: HTMLElement): HTMLElement | null {\n return element.querySelector<HTMLElement>(\n `:scope > .${this.classNames.element} > .${this.classNames.title}`,\n );\n }\n}\n","interface TopLeftPosition {\n left: number;\n top: number;\n}\n\n// Get the top position of the HTML element.\nexport const getOffsetTop = (element: HTMLElement): number =>\n getElementPosition(element).top;\n\n// Get the top left position of the HTML element.\nexport const getElementPosition = (element: HTMLElement): TopLeftPosition => {\n const rect = element.getBoundingClientRect();\n\n return {\n left: rect.x + window.scrollX,\n top: rect.y + window.scrollY,\n };\n};\n","import type { ClassNames } from \"../classNames\";\n\ninterface DragElementParams {\n autoEscape: boolean;\n classNames: ClassNames;\n nodeName: string;\n offsetX: number;\n offsetY: number;\n treeElement: HTMLElement;\n}\n\nclass DragElement {\n private element: HTMLElement;\n private offsetX: number;\n private offsetY: number;\n\n constructor({\n autoEscape,\n classNames,\n nodeName,\n offsetX,\n offsetY,\n treeElement,\n }: DragElementParams) {\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n\n this.element = this.createElement(nodeName, autoEscape, classNames);\n\n treeElement.append(this.element);\n }\n\n public move(pageX: number, pageY: number): void {\n this.element.style.left = `${pageX - this.offsetX}px`;\n this.element.style.top = `${pageY - this.offsetY}px`;\n }\n\n public remove(): void {\n this.element.remove();\n }\n\n private createElement(\n nodeName: string,\n autoEscape: boolean,\n classNames: ClassNames,\n ) {\n const element = document.createElement(\"span\");\n element.classList.add(classNames.title, classNames.dragging);\n\n if (autoEscape) {\n element.textContent = nodeName;\n } else {\n // eslint-disable-next-line no-unsanitized/property -- the user opted out of escaping with autoEscape: false\n element.innerHTML = nodeName;\n }\n\n element.style.position = \"absolute\";\n\n return element;\n }\n}\n\nexport default DragElement;\n","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","import type { Node, Position } from \"../node\";\nimport type { HitArea } from \"./types\";\n\nimport { getOffsetTop } from \"../positionUtils\";\nimport iterateVisibleNodes from \"./iterateVisibleNodes\";\n\ninterface HitPosition {\n node: Node;\n position: null | Position;\n top: number;\n}\n\nexport const generateHitPositions = (\n tree: Node,\n currentNode: Node,\n): HitPosition[] => {\n const hitPositions: HitPosition[] = [];\n let lastTop = 0;\n\n const addHitPosition = (\n node: Node,\n position: null | Position,\n top: number,\n ) => {\n hitPositions.push({\n node,\n position,\n top,\n });\n lastTop = top;\n };\n\n const handleAfterOpenFolder = (node: Node, nextNode: Node | null) => {\n if (node === currentNode || nextNode === currentNode) {\n // Cannot move before or after current item\n addHitPosition(node, null, lastTop);\n } else {\n addHitPosition(node, \"after\", lastTop);\n }\n };\n\n const handleClosedFolder = (\n node: Node,\n nextNode: Node | null,\n element: HTMLElement,\n ) => {\n const top = getOffsetTop(element);\n\n if (node === currentNode) {\n // Cannot move after current item\n addHitPosition(node, null, top);\n } else {\n addHitPosition(node, \"inside\", top);\n\n // Cannot move before current item\n if (nextNode !== currentNode) {\n addHitPosition(node, \"after\", top);\n }\n }\n };\n\n const handleFirstNode = (node: Node) => {\n if (node !== currentNode && node.element) {\n addHitPosition(node, \"before\", getOffsetTop(node.element));\n }\n };\n\n const handleNode = (\n node: Node,\n nextNode: Node | null,\n element: HTMLElement,\n ) => {\n const top = getOffsetTop(element);\n\n if (node === currentNode) {\n // Cannot move inside current item\n addHitPosition(node, null, top);\n } else {\n addHitPosition(node, \"inside\", top);\n }\n\n if (nextNode === currentNode || node === currentNode) {\n // Cannot move before or after current item\n addHitPosition(node, null, top);\n } else {\n addHitPosition(node, \"after\", top);\n }\n };\n\n const handleOpenFolder = (node: Node, element: HTMLElement) => {\n if (node === currentNode) {\n // Cannot move inside current item\n\n // Dnd over the current element is not possible: add a position with type None for the top and the bottom.\n const top = getOffsetTop(element);\n const height = element.clientHeight;\n addHitPosition(node, null, top);\n\n if (height > 5) {\n // Subtract 5 pixels to allow more space for the next element.\n addHitPosition(node, null, top + height - 5);\n }\n\n // Stop iterating\n return false;\n }\n\n // Cannot move before current item\n if (node.children[0] !== currentNode) {\n addHitPosition(node, \"inside\", getOffsetTop(element));\n }\n\n // Continue iterating\n return true;\n };\n\n iterateVisibleNodes(tree, {\n handleAfterOpenFolder,\n handleClosedFolder,\n handleFirstNode,\n handleNode,\n handleOpenFolder,\n });\n\n return hitPositions;\n};\n\nexport const generateHitAreasForGroup = (\n hitAreas: HitArea[],\n positionsInGroup: HitPosition[],\n top: number,\n bottom: number,\n) => {\n // limit positions in group\n const positionCount = Math.min(positionsInGroup.length, 4);\n\n const areaHeight = Math.round((bottom - top) / positionCount);\n let areaTop = top;\n\n for (let i = 0; i < positionCount; i++) {\n const position = positionsInGroup[i] as HitPosition;\n\n if (position.position) {\n hitAreas.push({\n bottom: areaTop + areaHeight,\n node: position.node,\n position: position.position,\n top: areaTop,\n });\n }\n\n areaTop += areaHeight;\n }\n};\n\nexport const generateHitAreasFromPositions = (\n hitPositions: HitPosition[],\n treeBottom: number,\n): HitArea[] => {\n if (!hitPositions.length) {\n return [];\n }\n\n let previousTop = (hitPositions[0] as HitPosition).top;\n let group: HitPosition[] = [];\n const hitAreas: HitArea[] = [];\n\n for (const position of hitPositions) {\n if (position.top !== previousTop && group.length) {\n generateHitAreasForGroup(hitAreas, group, previousTop, position.top);\n\n previousTop = position.top;\n group = [];\n }\n\n group.push(position);\n }\n\n generateHitAreasForGroup(hitAreas, group, previousTop, treeBottom);\n\n return hitAreas;\n};\n\nconst generateHitAreas = (tree: Node, currentNode: Node, treeBottom: number) =>\n generateHitAreasFromPositions(\n generateHitPositions(tree, currentNode),\n treeBottom,\n );\n\nexport default generateHitAreas;\n","import type { ClassNames } from \"../classNames\";\nimport type {\n GetScrollLeft,\n GetTree,\n OpenNode,\n RefreshElements,\n TriggerEvent,\n} from \"../methodTypes\";\nimport type { PositionInfo } from \"../mouseUtils\";\nimport type { Node } from \"../node\";\nimport type NodeElement from \"../nodeElement\";\nimport type {\n DragMethod,\n OnCanMove,\n OnCanMoveTo,\n OnIsMoveHandle,\n} from \"../options\";\nimport type { DropHint, HitArea } from \"./types\";\n\nimport { getElementPosition } from \"../positionUtils\";\nimport binarySearch from \"./binarySearch\";\nimport DragElement from \"./dragElement\";\nimport generateHitAreas from \"./generateHitAreas\";\n\ninterface Dimensions {\n bottom: number;\n left: number;\n right: number;\n top: number;\n}\n\ninterface DragAndDropHandlerParams {\n autoEscape?: boolean;\n classNames: ClassNames;\n getNodeElement: GetNodeElement;\n getNodeElementForNode: GetNodeElementForNode;\n getScrollLeft: GetScrollLeft;\n getTree: GetTree;\n onCanMove?: OnCanMove;\n onCanMoveTo?: OnCanMoveTo;\n onDragMove?: DragMethod;\n onDragStop?: DragMethod;\n onIsMoveHandle?: OnIsMoveHandle;\n openFolderDelay: false | number;\n openNode: OpenNode;\n refreshElements: RefreshElements;\n slide: boolean;\n treeElement: HTMLElement;\n triggerEvent: TriggerEvent;\n}\ntype GetNodeElement = (element: HTMLElement) => NodeElement | null;\n\ntype GetNodeElementForNode = (node: Node) => NodeElement;\n\nexport class DragAndDropHandler {\n public currentItem: NodeElement | null;\n public hitAreas: HitArea[];\n public hoveredArea: HitArea | null;\n public isDragging: boolean;\n\n private autoEscape?: boolean;\n private classNames: ClassNames;\n private dragElement: DragElement | null;\n private getNodeElement: GetNodeElement;\n private getNodeElementForNode: GetNodeElementForNode;\n private getScrollLeft: GetScrollLeft;\n private getTree: GetTree;\n private onCanMove?: OnCanMove;\n private onCanMoveTo?: OnCanMoveTo;\n private onDragMove?: DragMethod;\n private onDragStop?: DragMethod;\n private onIsMoveHandle?: OnIsMoveHandle;\n private openFolderDelay: false | number;\n private openFolderTimer: null | number;\n private openNode: OpenNode;\n private previousGhost: DropHint | null;\n private refreshElements: RefreshElements;\n private slide: boolean;\n private treeElement: HTMLElement;\n private triggerEvent: TriggerEvent;\n\n constructor({\n autoEscape,\n classNames,\n getNodeElement,\n getNodeElementForNode,\n getScrollLeft,\n getTree,\n onCanMove,\n onCanMoveTo,\n onDragMove,\n onDragStop,\n onIsMoveHandle,\n openFolderDelay,\n openNode,\n refreshElements,\n slide,\n treeElement,\n triggerEvent,\n }: DragAndDropHandlerParams) {\n this.autoEscape = autoEscape;\n this.classNames = classNames;\n this.getNodeElement = getNodeElement;\n this.getNodeElementForNode = getNodeElementForNode;\n this.getScrollLeft = getScrollLeft;\n this.getTree = getTree;\n this.onCanMove = onCanMove;\n this.onCanMoveTo = onCanMoveTo;\n this.onDragMove = onDragMove;\n this.onDragStop = onDragStop;\n this.onIsMoveHandle = onIsMoveHandle;\n this.openFolderDelay = openFolderDelay;\n this.openNode = openNode;\n this.refreshElements = refreshElements;\n this.slide = slide;\n this.treeElement = treeElement;\n this.triggerEvent = triggerEvent;\n\n this.hoveredArea = null;\n this.hitAreas = [];\n this.isDragging = false;\n this.currentItem = null;\n\n this.dragElement = null;\n this.openFolderTimer = null;\n this.previousGhost = null;\n }\n\n public mouseCapture(positionInfo: PositionInfo): boolean | null {\n const element = positionInfo.target;\n\n if (!this.mustCaptureElement(element)) {\n return null;\n }\n\n if (this.onIsMoveHandle && !this.onIsMoveHandle(element)) {\n return null;\n }\n\n let nodeElement = this.getNodeElement(element);\n\n if (nodeElement && this.onCanMove && !this.onCanMove(nodeElement.node)) {\n nodeElement = null;\n }\n\n this.currentItem = nodeElement;\n return this.currentItem != null;\n }\n\n public mouseDrag(positionInfo: PositionInfo): boolean {\n if (!this.currentItem || !this.dragElement) {\n return false;\n }\n\n this.dragElement.move(positionInfo.pageX, positionInfo.pageY);\n\n const area = this.findHoveredArea(positionInfo.pageX, positionInfo.pageY);\n\n if (area && this.canMoveToArea(area, this.currentItem)) {\n if (!area.node.isFolder()) {\n this.stopOpenFolderTimer();\n }\n\n if (this.hoveredArea !== area) {\n this.hoveredArea = area;\n\n // If this is a closed folder, start timer to open it\n if (this.mustOpenFolderTimer(area)) {\n this.startOpenFolderTimer(area.node);\n } else {\n this.stopOpenFolderTimer();\n }\n\n this.updateDropHint();\n }\n } else {\n this.removeDropHint();\n this.stopOpenFolderTimer();\n this.hoveredArea = area;\n }\n\n if (!area && this.onDragMove) {\n this.onDragMove(this.currentItem.node, positionInfo.originalEvent);\n }\n\n return true;\n }\n\n public mouseStart(positionInfo: PositionInfo): boolean {\n if (!this.currentItem) {\n return false;\n }\n\n this.refresh();\n\n const { left, top } = getElementPosition(positionInfo.target);\n\n const node = this.currentItem.node;\n\n this.dragElement = new DragElement({\n autoEscape: this.autoEscape ?? true,\n classNames: this.classNames,\n nodeName: node.name,\n offsetX: positionInfo.pageX - left,\n offsetY: positionInfo.pageY - top,\n treeElement: this.treeElement,\n });\n\n this.isDragging = true;\n this.currentItem.element.classList.add(this.classNames.moving);\n\n return true;\n }\n\n public mouseStop(positionInfo: PositionInfo): boolean {\n this.moveItem(positionInfo);\n this.clear();\n this.removeHover();\n this.removeDropHint();\n this.removeHitAreas();\n\n const currentItem = this.currentItem;\n\n if (this.currentItem) {\n this.currentItem.element.classList.remove(this.classNames.moving);\n this.currentItem = null;\n }\n\n this.isDragging = false;\n\n if (!this.hoveredArea && currentItem && this.onDragStop) {\n this.onDragStop(currentItem.node, positionInfo.originalEvent);\n }\n\n return false;\n }\n\n public refresh(): void {\n this.removeHitAreas();\n\n if (!this.currentItem) {\n return;\n }\n\n const currentNode = this.currentItem.node;\n this.generateHitAreas(currentNode);\n this.currentItem = this.getNodeElementForNode(currentNode);\n\n if (this.isDragging) {\n this.currentItem.element.classList.add(this.classNames.moving);\n }\n }\n\n private canMoveToArea(area: HitArea, currentItem: NodeElement): boolean {\n return this.onCanMoveTo\n ? this.onCanMoveTo(currentItem.node, area.node, area.position)\n : true;\n }\n\n private clear(): void {\n if (!this.dragElement) {\n return;\n }\n\n this.dragElement.remove();\n this.dragElement = null;\n }\n\n private findHoveredArea(x: number, y: number): HitArea | null {\n const dimensions = this.getTreeDimensions();\n\n if (\n x < dimensions.left ||\n y < dimensions.top ||\n x > dimensions.right ||\n y > dimensions.bottom\n ) {\n return null;\n }\n\n return binarySearch<HitArea>(this.hitAreas, (area) => {\n if (y < area.top) {\n return 1;\n }\n return y > area.bottom ? -1 : 0;\n });\n }\n\n private generateHitAreas(currentNode: Node): void {\n const tree = this.getTree();\n\n this.hitAreas = tree\n ? generateHitAreas(tree, currentNode, this.getTreeDimensions().bottom)\n : [];\n }\n\n private getTreeDimensions(): Dimensions {\n // Return the dimensions of the tree. Add a margin to the bottom to allow\n // to drag-and-drop after the last element.\n const treePosition = getElementPosition(this.treeElement);\n const left = treePosition.left + this.getScrollLeft();\n const top = treePosition.top;\n\n return {\n bottom: top + this.treeElement.clientHeight + 16,\n left,\n right: left + this.treeElement.clientWidth,\n top,\n };\n }\n\n /*\n Move the dragged node to the selected position in the tree.\n */\n private moveItem(positionInfo: PositionInfo): void {\n if (!(\n this.currentItem &&\n this.hoveredArea?.position &&\n this.canMoveToArea(this.hoveredArea, this.currentItem)\n )) {\n return;\n }\n\n const movedNode = this.currentItem.node;\n const targetNode = this.hoveredArea.node;\n const position = this.hoveredArea.position;\n const previousParent = movedNode.parent;\n\n if (position === \"inside\") {\n this.hoveredArea.node.is_open = true;\n }\n\n const doMove = (): void => {\n const tree = this.getTree();\n\n if (!tree) {\n return;\n }\n\n tree.moveNode(movedNode, targetNode, position);\n\n this.treeElement.textContent = \"\";\n this.refreshElements(null);\n };\n\n if (\n this.triggerEvent(\"tree.move\", {\n moveInfo: {\n doMove,\n movedNode,\n originalEvent: positionInfo.originalEvent,\n position,\n previousParent,\n targetNode,\n },\n })\n ) {\n doMove();\n }\n }\n\n private mustCaptureElement(element: HTMLElement): boolean {\n const nodeName = element.nodeName;\n\n return (\n nodeName !== \"INPUT\" && nodeName !== \"SELECT\" && nodeName !== \"TEXTAREA\"\n );\n }\n\n private mustOpenFolderTimer(area: HitArea): boolean {\n const node = area.node;\n\n return node.isFolder() && !node.is_open && area.position === \"inside\";\n }\n\n private removeDropHint(): void {\n if (this.previousGhost) {\n this.previousGhost.remove();\n }\n }\n\n private removeHitAreas(): void {\n this.hitAreas = [];\n }\n\n private removeHover(): void {\n this.hoveredArea = null;\n }\n\n private startOpenFolderTimer(folder: Node): void {\n const openFolder = (): void => {\n void this.openNode(folder, this.slide).then(() => {\n this.refresh();\n this.updateDropHint();\n });\n };\n\n this.stopOpenFolderTimer();\n\n const openFolderDelay = this.openFolderDelay;\n\n if (openFolderDelay !== false) {\n this.openFolderTimer = window.setTimeout(openFolder, openFolderDelay);\n }\n }\n\n private stopOpenFolderTimer(): void {\n if (!this.openFolderTimer) {\n return;\n }\n\n clearTimeout(this.openFolderTimer);\n this.openFolderTimer = null;\n }\n\n private updateDropHint(): void {\n if (!this.hoveredArea) {\n return;\n }\n\n // remove previous drop hint\n this.removeDropHint();\n\n // add new drop hint\n const nodeElement = this.getNodeElementForNode(this.hoveredArea.node);\n this.previousGhost = nodeElement.addDropHint(this.hoveredArea.position);\n }\n}\n","function binarySearch<T>(items: T[], compareFn: (a: T) => number): null | T {\n let low = 0;\n let high = items.length;\n\n while (low < high) {\n const mid = (low + high) >> 1;\n const item = items[mid];\n\n if (item === undefined) {\n return null;\n }\n\n const compareResult = compareFn(item);\n\n if (compareResult > 0) {\n high = mid;\n } else if (compareResult < 0) {\n low = mid + 1;\n } else {\n return item;\n }\n }\n\n return null;\n}\n\nexport default binarySearch;\n","import type { ClassNames } from \"./classNames\";\nimport type { GetTree, IsNodeSelected } from \"./methodTypes\";\nimport type { Node } from \"./node\";\nimport type { IconElement, OnCreateLi } from \"./options\";\n\nimport { getBoolString } from \"./util\";\n\ninterface ElementsRendererParams {\n ariaLabel?: string;\n ariaLabelledBy?: string;\n autoEscape: boolean;\n buttonLeft: boolean;\n classNames: ClassNames;\n closedIcon?: IconElement;\n dragAndDrop: boolean;\n getTree: GetTree;\n htmlElement: HTMLElement;\n isNodeSelected: IsNodeSelected;\n onCreateLi?: OnCreateLi;\n openedIcon?: IconElement;\n rtl?: boolean;\n setNodeElement: (element: HTMLElement, node: Node) => void;\n showEmptyFolder: boolean;\n tabIndex?: number;\n}\n\n/* Renders the tree to html.\n *\n * The children of a closed folder are not rendered. They are rendered when\n * the folder is opened, see renderChildren.\n *\n * The elements are created by cloning templates. A template is a fully\n * built <li> or <ul> with everything that is the same for every node\n * (structure, roles, static classes, the toggler icon). Per node only the\n * parts that differ are set: the title, the aria attributes and the\n * selected and loading classes.\n */\nexport default class ElementsRenderer {\n public closedIconElement?: globalThis.Node;\n public openedIconElement?: globalThis.Node;\n private ariaLabel?: string;\n private ariaLabelledBy?: string;\n private autoEscape: boolean;\n private buttonLeft: boolean;\n private classNames: ClassNames;\n private closedFolderTemplate: HTMLLIElement;\n private dragAndDrop: boolean;\n private getTree: GetTree;\n private groupUlTemplate: HTMLUListElement;\n private htmlElement: HTMLElement;\n private isNodeSelected: IsNodeSelected;\n private nodeTemplate: HTMLLIElement;\n private onCreateLi?: OnCreateLi;\n private openedFolderTemplate: HTMLLIElement;\n private rootUlTemplate: HTMLUListElement;\n private rtl?: boolean;\n private setNodeElement: (element: HTMLElement, node: Node) => void;\n private showEmptyFolder: boolean;\n private tabIndex?: number;\n\n constructor({\n ariaLabel,\n ariaLabelledBy,\n autoEscape,\n buttonLeft,\n classNames,\n closedIcon = \"-\",\n dragAndDrop,\n getTree,\n htmlElement,\n isNodeSelected,\n onCreateLi,\n openedIcon = \"+\",\n rtl,\n setNodeElement,\n showEmptyFolder,\n tabIndex,\n }: ElementsRendererParams) {\n this.ariaLabel = ariaLabel;\n this.ariaLabelledBy = ariaLabelledBy;\n this.autoEscape = autoEscape;\n this.buttonLeft = buttonLeft;\n this.classNames = classNames;\n this.dragAndDrop = dragAndDrop;\n this.getTree = getTree;\n this.htmlElement = htmlElement;\n this.isNodeSelected = isNodeSelected;\n this.onCreateLi = onCreateLi;\n this.rtl = rtl;\n this.setNodeElement = setNodeElement;\n this.showEmptyFolder = showEmptyFolder;\n this.tabIndex = tabIndex;\n this.openedIconElement = this.createButtonElement(openedIcon);\n this.closedIconElement = this.createButtonElement(closedIcon);\n\n this.rootUlTemplate = this.createUlTemplate(true);\n this.groupUlTemplate = this.createUlTemplate(false);\n this.nodeTemplate = this.createNodeTemplate();\n this.openedFolderTemplate = this.createFolderTemplate(true);\n this.closedFolderTemplate = this.createFolderTemplate(false);\n }\n\n public render(fromNode: Node | null): void {\n if (fromNode?.parent) {\n this.renderFromNode(fromNode);\n } else {\n this.renderFromRoot();\n }\n }\n\n /* Render the children of a rendered folder. Returns the new <ul>, or\n * null when the folder is not rendered or has no children.\n */\n public renderChildren(node: Node): HTMLUListElement | null {\n return !node.element || !node.hasChildren()\n ? null\n : this.createDomElements(\n node.element,\n node.children,\n false,\n node.getLevel() + 1,\n );\n }\n\n public renderFromNode(node: Node): void {\n if (!node.element) {\n return;\n }\n\n const currentLi = node.element;\n const newLi = this.createLi(node, node.getLevel());\n currentLi.replaceWith(newLi);\n\n if (this.mustRenderChildren(node)) {\n this.createDomElements(newLi, node.children, false, node.getLevel() + 1);\n }\n }\n\n public renderFromRoot(): void {\n this.htmlElement.textContent = \"\";\n\n const tree = this.getTree();\n\n if (tree) {\n this.createDomElements(this.htmlElement, tree.children, true, 1);\n }\n }\n\n private attachNodeData(node: Node, li: HTMLElement): void {\n node.element = li;\n this.setNodeElement(li, node);\n }\n\n /* Returns the template of a toggler icon; it is cloned for every folder.\n * A string is parsed as html and becomes a fragment, so it can hold\n * entities, text and elements.\n */\n private createButtonElement(value: IconElement): globalThis.Node | undefined {\n if (typeof value === \"string\") {\n const template = document.createElement(\"template\");\n // eslint-disable-next-line no-unsanitized/property -- icon options are documented to accept html\n template.innerHTML = value;\n\n return template.content;\n }\n return value.nodeType ? value : undefined;\n }\n\n private createDomElements(\n element: Element,\n children: Node[],\n isRootNode: boolean,\n level: number,\n ): HTMLUListElement {\n const template = isRootNode ? this.rootUlTemplate : this.groupUlTemplate;\n const ul = template.cloneNode() as HTMLUListElement;\n element.append(ul);\n\n for (const child of children) {\n const li = this.createLi(child, level);\n ul.append(li);\n\n if (this.mustRenderChildren(child)) {\n this.createDomElements(li, child.children, false, level + 1);\n }\n }\n\n return ul;\n }\n\n private createFolderLi(\n node: Node,\n level: number,\n isSelected: boolean,\n ): HTMLLIElement {\n const template = node.is_open\n ? this.openedFolderTemplate\n : this.closedFolderTemplate;\n const li = template.cloneNode(true) as HTMLLIElement;\n\n if (isSelected) {\n li.classList.add(this.classNames.selected);\n }\n\n // li > div > [toggler], title span, [toggler]\n const div = li.firstChild as HTMLDivElement;\n const titleSpan = div.childNodes[\n this.buttonLeft ? 1 : 0\n ] as HTMLSpanElement;\n\n this.fillTitleSpan(titleSpan, node.name, isSelected, level);\n\n if (node.is_loading) {\n li.classList.add(this.classNames.loading);\n titleSpan.setAttribute(\"aria-busy\", \"true\");\n }\n\n return li;\n }\n\n /* Template for a folder <li>:\n * li > div > [toggler], title span, [toggler]\n * The toggler icon and the aria-expanded attribute depend on the open\n * state, so there is a template for each.\n */\n private createFolderTemplate(isOpen: boolean): HTMLLIElement {\n const liClasses = [this.classNames.common, this.classNames.folder];\n\n if (!isOpen) {\n liClasses.push(this.classNames.closed);\n }\n\n const li = this.createLiTemplate(liClasses.join(\" \"));\n const div = li.firstChild as HTMLDivElement;\n\n // The toggler is hidden from screen readers: the icon is decoration, and\n // aria-expanded on the treeitem has the open state.\n const toggler = document.createElement(\"span\");\n toggler.className = this.getButtonClasses(isOpen);\n toggler.setAttribute(\"aria-hidden\", \"true\");\n\n const iconElement = isOpen\n ? this.openedIconElement\n : this.closedIconElement;\n\n if (iconElement) {\n toggler.append(iconElement.cloneNode(true));\n }\n\n if (this.buttonLeft) {\n div.append(toggler);\n }\n\n // title span\n const titleSpan = this.createTitleSpanTemplate(true);\n titleSpan.setAttribute(\"aria-expanded\", getBoolString(isOpen));\n div.append(titleSpan);\n\n if (!this.buttonLeft) {\n div.append(toggler);\n }\n\n return li;\n }\n\n /* Create the <li> element\n * Attach it to node.element.\n * Call onCreateLi\n */\n private createLi(node: Node, level: number): HTMLLIElement {\n const isSelected = this.isNodeSelected(node);\n\n const mustShowFolder =\n node.isFolder() || (node.isEmptyFolder && this.showEmptyFolder);\n\n const li = mustShowFolder\n ? this.createFolderLi(node, level, isSelected)\n : this.createNodeLi(node, level, isSelected);\n\n this.attachNodeData(node, li);\n\n if (this.onCreateLi) {\n this.onCreateLi(node, li, isSelected);\n }\n\n return li;\n }\n\n /*\n Create the outer part of a <li> template: li > div\n */\n private createLiTemplate(liClasses: string): HTMLLIElement {\n const li = document.createElement(\"li\");\n li.className = liClasses;\n li.setAttribute(\"role\", \"none\");\n\n const div = document.createElement(\"div\");\n div.className = `${this.classNames.element} ${this.classNames.common}`;\n div.setAttribute(\"role\", \"none\");\n\n li.append(div);\n\n return li;\n }\n\n private createNodeLi(\n node: Node,\n level: number,\n isSelected: boolean,\n ): HTMLLIElement {\n const li = this.nodeTemplate.cloneNode(true) as HTMLLIElement;\n\n if (isSelected) {\n li.classList.add(this.classNames.selected);\n }\n\n // li > div > title span\n const div = li.firstChild as HTMLDivElement;\n const titleSpan = div.firstChild as HTMLSpanElement;\n\n this.fillTitleSpan(titleSpan, node.name, isSelected, level);\n\n return li;\n }\n\n /*\n Template for a <li> without children: li > div > title span\n */\n private createNodeTemplate(): HTMLLIElement {\n const li = this.createLiTemplate(this.classNames.common);\n const div = li.firstChild as HTMLDivElement;\n\n div.append(this.createTitleSpanTemplate(false));\n\n return li;\n }\n\n private createTitleSpanTemplate(isFolder: boolean): HTMLSpanElement {\n const titleSpan = document.createElement(\"span\");\n\n let classes = `${this.classNames.title} ${this.classNames.common}`;\n\n if (isFolder) {\n classes += ` ${this.classNames.titleFolder}`;\n }\n\n classes += ` ${this.buttonLeft ? this.classNames.titleButtonLeft : this.classNames.titleButtonRight}`;\n\n titleSpan.className = classes;\n titleSpan.setAttribute(\"role\", \"treeitem\");\n titleSpan.setAttribute(\"aria-selected\", \"false\");\n\n // Every node is focusable, but only the tab stop is in the tab order\n if (this.tabIndex !== undefined) {\n titleSpan.setAttribute(\"tabindex\", \"-1\");\n }\n\n return titleSpan;\n }\n\n private createUlTemplate(isRootNode: boolean): HTMLUListElement {\n let classString;\n let role;\n\n if (isRootNode) {\n classString = this.classNames.tree;\n role = \"tree\";\n\n if (this.rtl) {\n classString += ` ${this.classNames.rtl}`;\n }\n } else {\n classString = \"\";\n role = \"group\";\n }\n\n if (this.dragAndDrop) {\n classString += ` ${this.classNames.dnd}`;\n }\n\n const ul = document.createElement(\"ul\");\n ul.className = `${this.classNames.common} ${classString}`;\n\n ul.setAttribute(\"role\", role);\n\n if (isRootNode) {\n if (this.ariaLabel !== undefined) {\n ul.setAttribute(\"aria-label\", this.ariaLabel);\n }\n\n if (this.ariaLabelledBy !== undefined) {\n ul.setAttribute(\"aria-labelledby\", this.ariaLabelledBy);\n }\n }\n\n return ul;\n }\n\n /*\n Set the parts of a cloned title span that differ per node\n */\n private fillTitleSpan(\n titleSpan: HTMLSpanElement,\n nodeName: string,\n isSelected: boolean,\n level: number,\n ): void {\n titleSpan.setAttribute(\"aria-level\", String(level));\n\n if (isSelected) {\n titleSpan.setAttribute(\"aria-selected\", \"true\");\n\n const tabIndex = this.tabIndex;\n\n if (tabIndex !== undefined) {\n titleSpan.setAttribute(\"tabindex\", String(tabIndex));\n }\n }\n\n if (this.autoEscape) {\n titleSpan.textContent = nodeName;\n } else {\n // eslint-disable-next-line no-unsanitized/property -- the user opted out of escaping with autoEscape: false\n titleSpan.innerHTML = nodeName;\n }\n }\n\n private getButtonClasses(isOpen: boolean): string {\n const classes = [this.classNames.toggler, this.classNames.common];\n\n if (!isOpen) {\n classes.push(this.classNames.closed);\n }\n\n if (this.buttonLeft) {\n classes.push(this.classNames.togglerLeft);\n } else {\n classes.push(this.classNames.togglerRight);\n }\n\n return classes.join(\" \");\n }\n\n /*\n The children of a closed folder are rendered when it is opened\n */\n private mustRenderChildren(node: Node): boolean {\n return node.hasChildren() && node.is_open === true;\n }\n}\n","export const isInt = (n: unknown): boolean => Number.isInteger(n);\n\nexport const getBoolString = (value: unknown): string =>\n value ? \"true\" : \"false\";\n","import type {\n CloseNode,\n GetFocusedNode,\n GetSelectedNode,\n GetTree,\n OpenNode,\n SelectNode,\n TriggerEvent,\n} from \"./methodTypes\";\nimport type { Node } from \"./node\";\n\ninterface KeyHandlerParams {\n closeNode: CloseNode;\n getFocusedNode: GetFocusedNode;\n getSelectedNode: GetSelectedNode;\n getTree: GetTree;\n keyboardSupport: boolean;\n openNode: OpenNode;\n selectNode: SelectNode;\n triggerEvent: TriggerEvent;\n}\n\nexport default class KeyHandler {\n private closeNode: CloseNode;\n private getFocusedNode: GetFocusedNode;\n private getSelectedNode: GetSelectedNode;\n private getTree: GetTree;\n\n private keyboardSupport: boolean;\n private openNode: OpenNode;\n private originalSelectNode: SelectNode;\n private triggerEvent: TriggerEvent;\n\n constructor({\n closeNode,\n getFocusedNode,\n getSelectedNode,\n getTree,\n keyboardSupport,\n openNode,\n selectNode,\n triggerEvent,\n }: KeyHandlerParams) {\n this.closeNode = closeNode;\n this.getFocusedNode = getFocusedNode;\n this.getSelectedNode = getSelectedNode;\n this.getTree = getTree;\n this.keyboardSupport = keyboardSupport;\n this.openNode = openNode;\n this.originalSelectNode = selectNode;\n this.triggerEvent = triggerEvent;\n\n if (keyboardSupport) {\n document.addEventListener(\"keydown\", this.handleKeyDown);\n }\n }\n\n public deinit(): void {\n if (this.keyboardSupport) {\n document.removeEventListener(\"keydown\", this.handleKeyDown);\n }\n }\n\n public moveDown(): boolean {\n return this.selectNode(this.getSelectedNode()?.getNextVisibleNode());\n }\n\n public moveUp(): boolean {\n return this.selectNode(this.getSelectedNode()?.getPreviousVisibleNode());\n }\n\n // Activate the node, for example to open its edit page.\n private activate(node: Node, originalEvent: KeyboardEvent): boolean {\n this.triggerEvent(\"tree.activate\", { node, originalEvent });\n return true;\n }\n\n private handleArrowKey(key: string): boolean {\n switch (key) {\n case \"ArrowDown\": {\n return this.moveDown();\n }\n\n case \"ArrowLeft\": {\n return this.moveLeft();\n }\n\n case \"ArrowRight\": {\n return this.moveRight();\n }\n\n case \"ArrowUp\": {\n return this.moveUp();\n }\n\n default: {\n return false;\n }\n }\n }\n\n private handleKeyDown = (e: KeyboardEvent): void => {\n const focusedNode = this.getFocusedNode();\n\n if (!focusedNode) {\n return;\n }\n\n let isKeyHandled: boolean;\n\n const selectedNode = this.getSelectedNode();\n\n switch (e.key) {\n case \"End\": {\n isKeyHandled = this.selectNode(this.getTree()?.getLastChild());\n break;\n }\n\n case \"Enter\": {\n // Without a selected node, activate the focused node\n isKeyHandled = this.activate(selectedNode ?? focusedNode, e);\n break;\n }\n\n case \"Home\": {\n isKeyHandled = this.selectNode(this.getTree()?.children[0]);\n break;\n }\n\n default: {\n isKeyHandled = selectedNode\n ? this.handleArrowKey(e.key)\n : this.handleKeyWithoutSelection(e.key, focusedNode);\n }\n }\n\n if (isKeyHandled) {\n e.preventDefault();\n }\n };\n\n // No node is selected. These keys select the focused node, which is\n // usually the first node, see TreeElement.updateTabStop.\n private handleKeyWithoutSelection(key: string, focusedNode: Node): boolean {\n switch (key) {\n case \" \":\n case \"ArrowDown\":\n case \"ArrowRight\": {\n return this.selectNode(focusedNode);\n }\n\n default: {\n return false;\n }\n }\n }\n\n private moveLeft(): boolean {\n const selectedNode = this.getSelectedNode();\n\n /* istanbul ignore if */\n if (!selectedNode) {\n return false;\n }\n\n if (selectedNode.isFolder() && selectedNode.is_open) {\n // Left on an open node closes the node\n void this.closeNode(selectedNode);\n return true;\n }\n // Left on a closed or end node moves focus to the node's parent\n return this.selectNode(selectedNode.getParent());\n }\n\n private moveRight(): boolean {\n const selectedNode = this.getSelectedNode();\n\n if (selectedNode?.isFolder()) {\n // folder node\n if (selectedNode.is_open) {\n // Right moves to the first child of an open node\n return this.selectNode(selectedNode.getNextVisibleNode());\n }\n // Right expands a closed node\n void this.openNode(selectedNode);\n return true;\n }\n return false;\n }\n\n /* Select the node.\n * Don't do anything if the node is null.\n * Result: a different node was selected.\n */\n private selectNode(node?: Node | null): boolean {\n if (node) {\n this.originalSelectNode(node);\n\n return true;\n }\n return false;\n }\n}\n","export interface PositionInfo {\n originalEvent: Event;\n pageX: number;\n pageY: number;\n target: HTMLElement;\n}\n\nexport const getPositionInfoFromMouseEvent = (e: MouseEvent): PositionInfo => ({\n originalEvent: e,\n pageX: e.pageX,\n pageY: e.pageY,\n target: e.target as HTMLElement,\n});\n\nexport const getPositionInfoFromTouch = (\n touch: Touch,\n e: TouchEvent,\n): PositionInfo => ({\n originalEvent: e,\n pageX: touch.pageX,\n pageY: touch.pageY,\n target: touch.target as HTMLElement,\n});\n","import type { ClassNames } from \"./classNames\";\nimport type { TriggerEvent } from \"./methodTypes\";\nimport type { PositionInfo } from \"./mouseUtils\";\nimport type { Node } from \"./node\";\n\nimport {\n getPositionInfoFromMouseEvent,\n getPositionInfoFromTouch,\n} from \"./mouseUtils\";\n\nexport type GetMouseDelay = () => number;\nexport type GetNode = (element: HTMLElement) => Node | null;\nexport type MouseCapture = (positionInfo: PositionInfo) => boolean | null;\nexport type MouseStart = (positionInfo: PositionInfo) => boolean;\n\ninterface ClickTarget {\n node: Node;\n type: \"button\" | \"label\";\n}\n\ninterface MouseHandlerParams {\n classNames: ClassNames;\n element: HTMLElement;\n getMouseDelay: () => number;\n getNode: GetNode;\n onClickButton: (node: Node) => Promise<void>;\n onClickTitle: (node: Node) => void;\n onMouseCapture: MouseCapture;\n onMouseDrag: (positionInfo: PositionInfo) => void;\n onMouseStart: MouseStart;\n onMouseStop: (positionInfo: PositionInfo) => void;\n triggerEvent: TriggerEvent;\n useContextMenu: boolean;\n}\n\nclass MouseHandler {\n private classNames: ClassNames;\n private element: HTMLElement;\n private getMouseDelay: GetMouseDelay;\n private getNode: GetNode;\n\n private isMouseDelayMet: boolean;\n\n private isMouseStarted: boolean;\n\n private mouseDelayTimer: null | number;\n\n private mouseDownInfo: null | PositionInfo;\n private onClickButton: (node: Node) => Promise<void>;\n private onClickTitle: (node: Node) => void;\n\n private onMouseCapture: MouseCapture;\n\n private onMouseDrag: (positionInfo: PositionInfo) => void;\n\n private onMouseStart: MouseStart;\n\n private onMouseStop: (positionInfo: PositionInfo) => void;\n\n private triggerEvent: TriggerEvent;\n private useContextMenu: boolean;\n constructor({\n classNames,\n element,\n getMouseDelay,\n getNode,\n onClickButton,\n onClickTitle,\n onMouseCapture,\n onMouseDrag,\n onMouseStart,\n onMouseStop,\n triggerEvent,\n useContextMenu,\n }: MouseHandlerParams) {\n this.classNames = classNames;\n this.element = element;\n this.getMouseDelay = getMouseDelay;\n this.getNode = getNode;\n this.onClickButton = onClickButton;\n this.onClickTitle = onClickTitle;\n this.onMouseCapture = onMouseCapture;\n this.onMouseDrag = onMouseDrag;\n this.onMouseStart = onMouseStart;\n this.onMouseStop = onMouseStop;\n this.triggerEvent = triggerEvent;\n this.useContextMenu = useContextMenu;\n\n element.addEventListener(\"click\", this.handleClick);\n element.addEventListener(\"dblclick\", this.handleDblclick);\n element.addEventListener(\"mousedown\", this.mouseDown, {\n passive: false,\n });\n element.addEventListener(\"touchstart\", this.touchStart, {\n passive: false,\n });\n\n if (useContextMenu) {\n element.addEventListener(\"contextmenu\", this.handleContextmenu);\n }\n\n this.isMouseStarted = false;\n this.mouseDelayTimer = null;\n this.isMouseDelayMet = false;\n this.mouseDownInfo = null;\n }\n public deinit(): void {\n this.element.removeEventListener(\"click\", this.handleClick);\n this.element.removeEventListener(\"dblclick\", this.handleDblclick);\n\n if (this.useContextMenu) {\n this.element.removeEventListener(\"contextmenu\", this.handleContextmenu);\n }\n\n this.element.removeEventListener(\"mousedown\", this.mouseDown);\n this.element.removeEventListener(\"touchstart\", this.touchStart);\n this.removeMouseMoveEventListeners();\n }\n private getClickTarget(element: HTMLElement): ClickTarget | null {\n const button = element.closest<HTMLElement>(`.${this.classNames.toggler}`);\n\n if (button) {\n const node = this.getNode(button);\n\n if (node) {\n return {\n node,\n type: \"button\",\n };\n }\n } else {\n const treeElement = element.closest<HTMLElement>(\n `.${this.classNames.element}`,\n );\n\n if (treeElement) {\n const node = this.getNode(treeElement);\n if (node) {\n return {\n node,\n type: \"label\",\n };\n }\n }\n }\n\n return null;\n }\n private handleClick = (e: MouseEvent): void => {\n if (!e.target) {\n return;\n }\n\n const clickTarget = this.getClickTarget(e.target as HTMLElement);\n\n if (!clickTarget) {\n return;\n }\n\n switch (clickTarget.type) {\n case \"button\": {\n void this.onClickButton(clickTarget.node);\n\n e.preventDefault();\n e.stopPropagation();\n break;\n }\n\n case \"label\": {\n if (\n this.triggerEvent(\"tree.click\", {\n node: clickTarget.node,\n originalEvent: e,\n })\n ) {\n this.onClickTitle(clickTarget.node);\n }\n break;\n }\n }\n };\n\n private handleContextmenu = (e: MouseEvent) => {\n if (!e.target) {\n return;\n }\n\n const div = (e.target as HTMLElement).closest<HTMLElement>(\n `ul.${this.classNames.tree} .${this.classNames.element}`,\n );\n\n if (div) {\n const node = this.getNode(div);\n if (node) {\n e.preventDefault();\n e.stopPropagation();\n\n this.triggerEvent(\"tree.contextmenu\", {\n node,\n originalEvent: e,\n });\n return false;\n }\n }\n\n return null;\n };\n\n private handleDblclick = (e: MouseEvent): void => {\n if (!e.target) {\n return;\n }\n\n const clickTarget = this.getClickTarget(e.target as HTMLElement);\n\n if (clickTarget?.type === \"label\") {\n this.triggerEvent(\"tree.dblclick\", {\n node: clickTarget.node,\n originalEvent: e,\n });\n }\n };\n\n private handleMouseDown(positionInfo: PositionInfo): boolean {\n // We may have missed mouseup (out of window)\n if (this.isMouseStarted) {\n this.handleMouseUp(positionInfo);\n }\n\n this.mouseDownInfo = positionInfo;\n\n if (!this.onMouseCapture(positionInfo)) {\n return false;\n }\n\n this.handleStartMouse();\n\n return true;\n }\n\n private handleMouseMove(\n e: MouseEvent | TouchEvent,\n positionInfo: PositionInfo,\n ): void {\n if (this.isMouseStarted) {\n this.onMouseDrag(positionInfo);\n\n if (e.cancelable) {\n e.preventDefault();\n }\n return;\n }\n\n if (!this.isMouseDelayMet) {\n return;\n }\n\n if (this.mouseDownInfo) {\n this.isMouseStarted = this.onMouseStart(this.mouseDownInfo);\n }\n\n if (this.isMouseStarted) {\n this.onMouseDrag(positionInfo);\n\n if (e.cancelable) {\n e.preventDefault();\n }\n } else {\n this.handleMouseUp(positionInfo);\n }\n }\n private handleMouseUp(positionInfo: PositionInfo): void {\n this.removeMouseMoveEventListeners();\n this.isMouseDelayMet = false;\n this.mouseDownInfo = null;\n\n if (!this.isMouseStarted) {\n return;\n }\n\n this.isMouseStarted = false;\n this.onMouseStop(positionInfo);\n }\n\n private handleStartMouse(): void {\n document.addEventListener(\"mousemove\", this.mouseMove, {\n passive: false,\n });\n document.addEventListener(\"touchmove\", this.touchMove, {\n passive: false,\n });\n document.addEventListener(\"mouseup\", this.mouseUp, { passive: false });\n document.addEventListener(\"touchend\", this.touchEnd, {\n passive: false,\n });\n\n const mouseDelay = this.getMouseDelay();\n\n if (mouseDelay) {\n this.startMouseDelayTimer(mouseDelay);\n } else {\n this.isMouseDelayMet = true;\n }\n }\n\n private mouseDown = (e: MouseEvent): void => {\n // Left mouse button?\n if (e.button !== 0) {\n return;\n }\n\n const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));\n\n if (result && e.cancelable) {\n e.preventDefault();\n }\n };\n\n private mouseMove = (e: MouseEvent): void => {\n this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));\n };\n\n private mouseUp = (e: MouseEvent): void => {\n this.handleMouseUp(getPositionInfoFromMouseEvent(e));\n };\n\n private removeMouseMoveEventListeners() {\n document.removeEventListener(\"mousemove\", this.mouseMove);\n document.removeEventListener(\"touchmove\", this.touchMove);\n document.removeEventListener(\"mouseup\", this.mouseUp);\n document.removeEventListener(\"touchend\", this.touchEnd);\n }\n\n private startMouseDelayTimer(mouseDelay: number): void {\n if (this.mouseDelayTimer) {\n clearTimeout(this.mouseDelayTimer);\n }\n\n this.mouseDelayTimer = window.setTimeout(() => {\n if (this.mouseDownInfo) {\n this.isMouseDelayMet = true;\n }\n }, mouseDelay);\n\n this.isMouseDelayMet = false;\n }\n\n private touchEnd = (e: TouchEvent): void => {\n if (e.touches.length > 1) {\n return;\n }\n\n const touch = e.touches[0];\n\n if (!touch) {\n return;\n }\n\n this.handleMouseUp(getPositionInfoFromTouch(touch, e));\n };\n\n private touchMove = (e: TouchEvent): void => {\n if (e.touches.length > 1) {\n return;\n }\n\n const touch = e.touches[0];\n\n if (!touch) {\n return;\n }\n\n this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));\n };\n\n private touchStart = (e: TouchEvent): void => {\n if (e.touches.length > 1) {\n return;\n }\n\n const touch = e.touches[0];\n\n if (!touch) {\n return;\n }\n\n this.handleMouseDown(getPositionInfoFromTouch(touch, e));\n };\n}\n\nexport default MouseHandler;\n","import type { NodeData, NodeRecord } from \"./node\";\n\ninterface NodeRecordWithChildren extends NodeRecord {\n children: NodeData[];\n}\n\nexport const isNodeRecordWithChildren = (\n data: NodeData,\n): data is NodeRecordWithChildren =>\n typeof data === \"object\" &&\n \"children\" in data &&\n Array.isArray(data.children);\n","/*\nA node reads and writes the private members of other nodes (node.setParent),\nso the `_` prefix that the build adds cannot be limited to `this.`:\n\nprefix-private-members: all\n*/\n\nimport { isNodeRecordWithChildren } from \"./nodeUtils\";\n\nexport type NodeData = NodeRecord | string;\n\nexport type NodeId = number | string;\n\nexport interface NodeRecord {\n [key: string]: unknown;\n children?: NodeData[];\n id?: NodeId;\n}\n\nexport type Position = \"after\" | \"before\" | \"inside\";\n\ntype IterateCallback = (node: Node, level: number) => boolean;\n\n/**\n * @groupDescription Properties\n * Any other key in the node data is copied onto the node, so\n * `{ name: \"node1\", color: \"green\" }` gives you `node.color`.\n *\n * @groupDescription Searching\n * These work on any node, and search that node's subtree. Called on the root\n * node, they search the whole tree — which is what the tree's own methods of\n * the same name do.\n *\n * @groupDescription Changing the tree\n * ::: warning\n * These methods change the data without re-rendering. The tree's\n * [methods](/reference/methods) — `appendNode`, `removeNode`, `moveNode` and\n * friends — do the same and refresh the display, so prefer those. If you do\n * use these, call `tree.refresh()` afterwards.\n * :::\n */\nexport class Node {\n /**\n @hidden\n */\n [key: string]: unknown;\n\n /**\n The child nodes.\n */\n public children: Node[];\n /** The `li` element, once the node is rendered. Nodes inside a closed\n * folder are rendered when the folder is opened. */\n public element?: HTMLElement;\n /**\n The id from the node data.\n */\n public id?: NodeId;\n /**\n @hidden\n */\n public idMapping?: Map<NodeId, Node>;\n /**\n Whether the node's children are being fetched.\n */\n public is_loading?: boolean;\n /**\n Whether the folder is open.\n */\n public is_open?: boolean;\n /**\n Whether the node data had an empty `children` array.\n */\n public isEmptyFolder: boolean;\n /**\n Whether the children still have to be fetched.\n */\n public load_on_demand = false;\n /**\n The label. Also settable from the `label` key in node data.\n */\n public name = \"\";\n /**\n @hidden\n */\n public nodeClass?: typeof Node;\n /**\n The parent; `null` for the root node.\n */\n public parent: Node | null;\n /**\n The root node.\n */\n public tree?: Node;\n\n /**\n @hidden\n */\n constructor(\n nodeData: NodeData | null = null,\n isRoot = false,\n nodeClass = Node,\n ) {\n this.isEmptyFolder =\n nodeData != null &&\n isNodeRecordWithChildren(nodeData) &&\n nodeData.children.length === 0;\n\n this.setData(nodeData);\n\n this.children = [];\n this.parent = null;\n this.is_loading = undefined;\n this.is_open ??= undefined;\n\n if (isRoot) {\n this.idMapping = new Map<NodeId, Node>();\n this.tree = this;\n this.nodeClass = nodeClass;\n } else {\n this.idMapping = undefined;\n }\n }\n\n /**\n * Adds a sibling after this node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addAfter(nodeInfo: NodeData): Node | null {\n if (this.parent) {\n const node = this.createNode(nodeInfo);\n\n const childIndex = this.parent.getChildIndex(this);\n this.parent.addChildAtPosition(node, childIndex + 1);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n return null;\n }\n\n /**\n * Adds a sibling before this node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addBefore(nodeInfo: NodeData): Node | null {\n if (this.parent) {\n const node = this.createNode(nodeInfo);\n\n const childIndex = this.parent.getChildIndex(this);\n this.parent.addChildAtPosition(node, childIndex);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n return null;\n }\n\n /**\n * Adds an existing `Node` object as the last child.\n *\n * @group Changing the tree\n */\n public addChild(node: Node): void {\n this.children.push(node);\n node.setParent(this);\n }\n\n /**\n * Adds an existing `Node` object as a child, at this position in\n * `children`. The index starts at `0`.\n *\n * @group Changing the tree\n */\n public addChildAtPosition(node: Node, index: number): void {\n this.children.splice(index, 0, node);\n node.setParent(this);\n }\n\n /**\n @hidden\n */\n public addNodeToIndex(node: Node): void {\n if (node.id != null) {\n this.idMapping?.set(node.id, node);\n }\n }\n\n /**\n * Inserts a new parent between this node and its current parent.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addParent(nodeInfo: NodeData): Node | null {\n if (this.parent) {\n const newParent = this.createNode(nodeInfo);\n\n if (this.tree) {\n newParent.setParent(this.tree);\n }\n const originalParent = this.parent;\n\n for (const child of originalParent.children) {\n newParent.addChild(child);\n }\n\n originalParent.children = [];\n originalParent.addChild(newParent);\n return newParent;\n }\n return null;\n }\n\n /**\n * Adds a child at the end.\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public append(nodeInfo: NodeData): Node {\n const node = this.createNode(nodeInfo);\n this.addChild(node);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n\n /**\n * Returns all nodes in the subtree for which the callback returns\n * `true`.\n *\n * @example\n * ```js\n * const folders = tree.getTree().filter((node) => node.isFolder());\n * ```\n *\n * @group Searching\n */\n public filter(f: (node: Node) => boolean): Node[] {\n const result: Node[] = [];\n\n this.iterate((node: Node) => {\n if (f(node)) {\n result.push(node);\n }\n\n return true;\n });\n\n return result;\n }\n\n /**\n * Returns the position of a child in `children`, or `-1`.\n *\n * @group Inspecting a node\n */\n public getChildIndex(node: Node): number {\n return this.children.indexOf(node);\n }\n\n /**\n * Returns the subtree as plain data, ready for `JSON.stringify`.\n * Internal properties (`parent`, `children`, `element`, `tree`,\n * `idMapping`, `nodeClass`, `load_on_demand`, `isEmptyFolder`) are left\n * out; your own properties are kept.\n *\n * ```js\n * tree.getTree().getData();\n * // [{ name: \"node1\", id: 1, children: [{ name: \"child1\", id: 2 }] }]\n * ```\n *\n * @param includeParent - Make the result the node itself rather than its\n * children. Default `false`.\n * @group Reading data back\n */\n public getData(includeParent = false): NodeRecord[] {\n const getDataFromNodes = (nodes: Node[]): Record<string, unknown>[] => {\n return nodes.map((node) => {\n const tmpNode: Record<string, unknown> = {};\n\n for (const k in node) {\n if (\n [\n \"children\",\n \"element\",\n \"idMapping\",\n \"isEmptyFolder\",\n \"load_on_demand\",\n \"nodeClass\",\n \"parent\",\n \"tree\",\n ].includes(k) ||\n !Object.prototype.hasOwnProperty.call(node, k)\n ) {\n continue;\n }\n\n const v = node[k];\n tmpNode[k] = v;\n }\n\n if (node.hasChildren()) {\n tmpNode.children = getDataFromNodes(node.children);\n }\n\n return tmpNode;\n });\n };\n\n return getDataFromNodes(includeParent ? [this] : this.children);\n }\n\n /**\n * Returns the last child, or `null`. When that child is an open folder,\n * its own last child, and so on.\n *\n * @group Moving around the tree\n */\n public getLastChild(): Node | null {\n if (this.hasChildren()) {\n const lastChild = this.children[this.children.length - 1] as Node;\n\n return lastChild.hasChildren() && lastChild.is_open\n ? lastChild.getLastChild()\n : lastChild;\n }\n return null;\n }\n\n /**\n * Returns the depth of the node, counting the top level as `1`.\n *\n * @group Inspecting a node\n */\n public getLevel(): number {\n let level = 0;\n let node: Node = this; // eslint-disable-line @typescript-eslint/no-this-alias, unicorn/no-this-assignment\n\n while (node.parent) {\n level += 1;\n node = node.parent;\n }\n\n return level;\n }\n\n /**\n * Returns the next node in the tree, regardless of whether it is\n * visible. `getNextNode(false)` skips the node's own children.\n *\n * @group Moving around the tree\n */\n public getNextNode(includeChildren = true): Node | null {\n if (includeChildren && this.hasChildren()) {\n return this.children[0] ?? null;\n }\n if (this.parent) {\n const nextSibling = this.getNextSibling();\n\n return nextSibling ?? this.parent.getNextNode(false);\n }\n return null;\n }\n\n /**\n * Returns the next sibling, or `null`.\n *\n * @group Moving around the tree\n */\n public getNextSibling(): Node | null {\n if (this.parent) {\n const nextIndex = this.parent.getChildIndex(this) + 1;\n return nextIndex < this.parent.children.length\n ? (this.parent.children[nextIndex] ?? null)\n : null;\n }\n return null;\n }\n\n /**\n * Like `getNextNode`, but skipping nodes inside closed folders — this is\n * what the arrow keys use.\n *\n * @group Moving around the tree\n */\n public getNextVisibleNode(): Node | null {\n if (this.hasChildren() && this.is_open) {\n // First child\n return this.children[0] ?? null;\n }\n if (this.parent) {\n const nextSibling = this.getNextSibling();\n if (nextSibling) {\n // Next sibling\n return nextSibling;\n }\n // Next node of parent\n return this.parent.getNextNode(false);\n }\n return null;\n }\n\n /**\n * Returns the first node for which the callback returns `true`.\n *\n * @group Searching\n */\n public getNodeByCallback(callback: (node: Node) => boolean): Node | null {\n let result: Node | null = null;\n\n this.iterate((node: Node) => {\n if (result) {\n return false;\n }\n if (callback(node)) {\n result = node;\n return false;\n }\n return true;\n });\n\n return result;\n }\n\n /**\n * Returns the node with this id. Only available on the root node, which\n * keeps the id index.\n *\n * @group Searching\n */\n public getNodeById(nodeId: NodeId): Node | null {\n return this.idMapping?.get(nodeId) ?? null;\n }\n\n /**\n * Returns the first node with this name.\n *\n * @group Searching\n */\n public getNodeByName(name: string): Node | null {\n return this.getNodeByCallback((node: Node) => node.name === name);\n }\n\n /**\n * Like `getNodeByName`, but throws when there is no such node.\n *\n * @group Searching\n */\n public getNodeByNameMustExist(name: string): Node {\n const node = this.getNodeByCallback((n: Node) => n.name === name);\n\n if (!node) {\n throw new Error(`Node with name ${name} not found`);\n }\n\n return node;\n }\n\n /**\n * Returns all nodes with this property value.\n *\n * @group Searching\n */\n public getNodesByProperty(key: string, value: unknown): Node[] {\n return this.filter((node: Node) => node[key] === value);\n }\n\n /**\n * Returns the parent: `null` for a top-level node — the root node is not\n * returned.\n *\n * @group Moving around the tree\n */\n public getParent(): Node | null {\n // Return parent except if it is the root node\n if (!this.parent) {\n return null;\n }\n if (this.parent.parent) {\n return this.parent;\n }\n // Root node -> null\n return null;\n }\n\n /**\n * Returns the previous node in the tree, regardless of whether it is\n * visible.\n *\n * @group Moving around the tree\n */\n public getPreviousNode(): Node | null {\n if (this.parent) {\n const previousSibling = this.getPreviousSibling();\n\n if (!previousSibling) {\n return this.getParent();\n }\n return previousSibling.hasChildren()\n ? previousSibling.getLastChild()\n : previousSibling;\n }\n return null;\n }\n\n /**\n * Returns the previous sibling, or `null`.\n *\n * @group Moving around the tree\n */\n public getPreviousSibling(): Node | null {\n if (this.parent) {\n const previousIndex = this.parent.getChildIndex(this) - 1;\n return previousIndex >= 0\n ? (this.parent.children[previousIndex] ?? null)\n : null;\n }\n return null;\n }\n\n /**\n * Like `getPreviousNode`, but skipping nodes inside closed folders —\n * this is what the arrow keys use.\n *\n * @group Moving around the tree\n */\n public getPreviousVisibleNode(): Node | null {\n if (this.parent) {\n const previousSibling = this.getPreviousSibling();\n\n if (!previousSibling) {\n return this.getParent();\n }\n if (!previousSibling.hasChildren() || !previousSibling.is_open) {\n // Previous sibling\n return previousSibling;\n }\n // Last child of previous sibling\n return previousSibling.getLastChild();\n }\n return null;\n }\n\n /**\n * Whether the node has children.\n *\n * @group Inspecting a node\n */\n public hasChildren(): boolean {\n return this.children.length !== 0;\n }\n\n /**\n * Init Node from data without making it the root of the tree.\n *\n * @hidden\n */\n public initFromData(data: NodeData): void {\n const addNode = (nodeData: NodeData): void => {\n this.setData(nodeData);\n\n if (isNodeRecordWithChildren(nodeData) && nodeData.children.length) {\n addChildren(nodeData.children);\n }\n };\n\n const addChildren = (childrenData: NodeData[]): void => {\n for (const child of childrenData) {\n const node = this.createNode();\n node.initFromData(child);\n this.addChild(node);\n }\n };\n\n addNode(data);\n }\n\n /**\n * `true` when the node has children, or is marked `load_on_demand`.\n *\n * @group Inspecting a node\n */\n public isFolder(): boolean {\n return this.hasChildren() || this.load_on_demand;\n }\n\n /**\n * Whether this node is an ancestor of the other node.\n *\n * @group Inspecting a node\n */\n public isParentOf(node: Node): boolean {\n let parent = node.parent;\n\n while (parent) {\n if (parent === this) {\n return true;\n }\n\n parent = parent.parent;\n }\n\n return false;\n }\n\n /**\n * Walks the subtree, calling the callback with `(node, level)`. Return\n * `false` from the callback to stop descending into that node:\n *\n * ```js\n * tree.getTree().iterate((node, level) => {\n * console.log(\" \".repeat(level) + node.name);\n * return level <= 2; // don't go deeper than level 2\n * });\n * ```\n *\n * @group Searching\n */\n public iterate(callback: IterateCallback): void {\n const _iterate = (node: Node, level: number): void => {\n for (const child of node.children) {\n const result = callback(child, level);\n\n if (result && child.hasChildren()) {\n _iterate(child, level + 1);\n }\n }\n };\n\n _iterate(this, 0);\n }\n\n /**\n * Replaces the children with new node data.\n *\n * @group Changing the tree\n */\n public loadFromData(data: NodeData[]): this {\n this.removeChildren();\n\n for (const childData of data) {\n const node = this.createNode(childData);\n this.addChild(node);\n\n if (isNodeRecordWithChildren(childData)) {\n node.loadFromData(childData.children);\n }\n }\n\n return this;\n }\n\n /**\n * Moves a node relative to another node. Called on the root node.\n *\n * @param position - `\"before\"`, `\"after\"` or `\"inside\"`.\n * @returns `false` when the move is impossible, for instance moving a\n * node into its own subtree.\n * @group Changing the tree\n */\n public moveNode(\n movedNode: Node,\n targetNode: Node,\n position: Position,\n ): boolean {\n if (!movedNode.parent || movedNode.isParentOf(targetNode)) {\n // - Node is parent of target node\n // - Or, parent is empty\n return false;\n }\n movedNode.parent.doRemoveChild(movedNode);\n\n switch (position) {\n case \"after\": {\n if (targetNode.parent) {\n targetNode.parent.addChildAtPosition(\n movedNode,\n targetNode.parent.getChildIndex(targetNode) + 1,\n );\n return true;\n }\n return false;\n }\n\n case \"before\": {\n if (targetNode.parent) {\n targetNode.parent.addChildAtPosition(\n movedNode,\n targetNode.parent.getChildIndex(targetNode),\n );\n return true;\n }\n return false;\n }\n\n case \"inside\": {\n // move inside as first child\n targetNode.addChildAtPosition(movedNode, 0);\n return true;\n }\n }\n }\n\n /**\n * Adds a child at the start.\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public prepend(nodeInfo: NodeData): Node {\n const node = this.createNode(nodeInfo);\n this.addChildAtPosition(node, 0);\n\n node.loadChildrenFromData(nodeInfo);\n return node;\n }\n\n /**\n * Removes this node from its parent.\n *\n * @group Changing the tree\n */\n public remove(): void {\n if (!this.parent) {\n return;\n }\n\n this.parent.removeChild(this);\n this.parent = null;\n }\n\n /**\n * Removes a child and its children.\n *\n * @group Changing the tree\n */\n public removeChild(node: Node): void {\n // remove children from the index\n node.removeChildren();\n\n this.doRemoveChild(node);\n }\n\n /**\n * Removes all children.\n *\n * @group Changing the tree\n */\n public removeChildren(): void {\n this.iterate((child: Node) => {\n this.tree?.removeNodeFromIndex(child);\n return true;\n });\n\n this.children = [];\n }\n\n /**\n @hidden\n */\n public removeNodeFromIndex(node: Node): void {\n if (node.id != null) {\n this.idMapping?.delete(node.id);\n }\n }\n\n /**\n * Updates the node's properties from node data. `children` and `parent`\n * are ignored. A string sets the name. Existing node values are not\n * removed.\n *\n * @group Changing the tree\n */\n public setData(o: NodeData | null): void {\n if (!o) {\n return;\n }\n if (typeof o === \"string\") {\n this.name = o;\n } else if (typeof o === \"object\") {\n for (const key in o) {\n if (!Object.prototype.hasOwnProperty.call(o, key)) {\n continue;\n }\n\n const value = o[key];\n\n if (key === \"label\" || key === \"name\") {\n // You can use the 'label' key instead of 'name'; this is a legacy feature\n if (typeof value === \"string\") {\n this.name = value;\n }\n } else if (key !== \"children\" && key !== \"parent\") {\n // You can't update the children or the parent using this function\n this[key] = value;\n }\n }\n }\n }\n\n private createNode(nodeData?: NodeData): Node {\n const nodeClass = this.getNodeClass();\n return new nodeClass(nodeData);\n }\n\n private doRemoveChild(node: Node): void {\n this.children.splice(this.getChildIndex(node), 1);\n this.tree?.removeNodeFromIndex(node);\n }\n\n private getNodeClass(): typeof Node {\n return this.nodeClass ?? this.tree?.nodeClass ?? Node;\n }\n\n // Load children data from nodeInfo if it has children\n private loadChildrenFromData(nodeInfo: NodeData) {\n if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {\n this.loadFromData(nodeInfo.children);\n }\n }\n\n private setParent(parent: Node): void {\n this.parent = parent;\n this.tree = parent.tree;\n this.tree?.addNodeToIndex(this);\n }\n}\n","import type { ClassNames } from \"../classNames\";\nimport type { DropHint } from \"../dragAndDropHandler/types\";\n\nclass BorderDropHint implements DropHint {\n private hint?: HTMLElement;\n\n constructor(\n element: HTMLElement,\n scrollLeft: number,\n classNames: ClassNames,\n ) {\n const div = element.querySelector(`:scope > .${classNames.element}`);\n\n if (!div) {\n this.hint = undefined;\n return;\n }\n\n const width = Math.max(element.offsetWidth + scrollLeft - 4, 0);\n const height = Math.max(element.clientHeight - 4, 0);\n\n const hint = document.createElement(\"span\");\n hint.className = classNames.border;\n hint.style.width = `${width}px`;\n hint.style.height = `${height}px`;\n\n this.hint = hint;\n\n div.append(this.hint);\n }\n\n public remove(): void {\n this.hint?.remove();\n }\n}\n\nexport default BorderDropHint;\n","import type { ClassNames } from \"../classNames\";\nimport type { DropHint } from \"../dragAndDropHandler/types\";\nimport type { Node, Position } from \"../node\";\n\nclass GhostDropHint implements DropHint {\n private classNames: ClassNames;\n private element: HTMLElement;\n private ghost: HTMLElement;\n private node: Node;\n\n constructor(\n node: Node,\n element: HTMLElement,\n position: Position,\n classNames: ClassNames,\n ) {\n this.classNames = classNames;\n this.element = element;\n this.node = node;\n this.ghost = this.createGhostElement();\n\n switch (position) {\n case \"after\": {\n this.moveAfter();\n break;\n }\n\n case \"before\": {\n this.moveBefore();\n break;\n }\n\n case \"inside\": {\n if (node.isFolder() && node.is_open) {\n this.moveInsideOpenFolder();\n } else {\n this.moveInside();\n }\n }\n }\n }\n\n public remove(): void {\n this.ghost.remove();\n }\n\n private createGhostElement() {\n const { circle, common, ghost: ghostClass, line } = this.classNames;\n\n const ghost = document.createElement(\"li\");\n ghost.className = `${common} ${ghostClass}`;\n\n const circleSpan = document.createElement(\"span\");\n circleSpan.className = `${common} ${circle}`;\n ghost.append(circleSpan);\n\n const lineSpan = document.createElement(\"span\");\n lineSpan.className = `${common} ${line}`;\n ghost.append(lineSpan);\n\n return ghost;\n }\n\n private moveAfter(): void {\n this.element.after(this.ghost);\n }\n\n private moveBefore(): void {\n this.element.before(this.ghost);\n }\n\n private moveInside(): void {\n this.element.after(this.ghost);\n this.ghost.classList.add(this.classNames.inside);\n }\n\n private moveInsideOpenFolder(): void {\n const childElement = this.node.children[0]?.element;\n\n if (childElement) {\n childElement.before(this.ghost);\n }\n }\n}\n\nexport default GhostDropHint;\n","import type { ClassNames } from \"../classNames\";\nimport type { DropHint } from \"../dragAndDropHandler/types\";\nimport type { GetScrollLeft } from \"../methodTypes\";\nimport type { Node, Position } from \"../node\";\n\nimport BorderDropHint from \"./borderDropHint\";\nimport GhostDropHint from \"./ghostDropHint\";\n\nexport interface NodeElementParams {\n classNames: ClassNames;\n getScrollLeft: GetScrollLeft;\n node: Node;\n tabIndex?: number;\n treeElement: HTMLElement;\n}\n\nclass NodeElement {\n public element: HTMLElement;\n public node: Node;\n protected classNames: ClassNames;\n private getScrollLeft: GetScrollLeft;\n private tabIndex?: number;\n private treeElement: HTMLElement;\n\n constructor({\n classNames,\n getScrollLeft,\n node,\n tabIndex,\n treeElement,\n }: NodeElementParams) {\n this.classNames = classNames;\n this.getScrollLeft = getScrollLeft;\n this.node = node;\n this.tabIndex = tabIndex;\n this.treeElement = treeElement;\n\n // The root node has no element of its own; it uses the tree element.\n this.element = node.element ?? this.treeElement;\n }\n\n public addDropHint(position: Position): DropHint {\n return this.mustShowBorderDropHint(position)\n ? new BorderDropHint(this.element, this.getScrollLeft(), this.classNames)\n : new GhostDropHint(this.node, this.element, position, this.classNames);\n }\n\n public deselect(): void {\n if (!this.isRendered()) {\n return;\n }\n\n this.element.classList.remove(this.classNames.selected);\n\n const titleSpan = this.getTitleSpan();\n\n // Check for null or undefined\n if (this.tabIndex != null) {\n titleSpan.setAttribute(\"tabindex\", \"-1\");\n }\n\n titleSpan.setAttribute(\"aria-selected\", \"false\");\n\n titleSpan.blur();\n }\n\n public select(mustSetFocus: boolean): void {\n if (!this.isRendered()) {\n return;\n }\n\n this.element.classList.add(this.classNames.selected);\n\n const titleSpan = this.getTitleSpan();\n const tabIndex = this.tabIndex;\n\n // Check for null or undefined\n if (tabIndex != null) {\n titleSpan.setAttribute(\"tabindex\", tabIndex.toString());\n }\n\n titleSpan.setAttribute(\"aria-selected\", \"true\");\n\n if (mustSetFocus) {\n titleSpan.focus();\n }\n }\n\n protected getTitleSpan(): HTMLSpanElement {\n return this.element.querySelector(\n `:scope > .${this.classNames.element} > span.${this.classNames.title}`,\n ) as HTMLSpanElement;\n }\n\n protected getUl(): HTMLUListElement | null {\n return this.element.querySelector(\":scope > ul\");\n }\n\n /* A node inside a closed folder is not rendered. Its selected and open\n * state is applied when it is rendered.\n */\n protected isRendered(): boolean {\n return Boolean(this.node.element);\n }\n\n protected mustShowBorderDropHint(position: Position): boolean {\n return position === \"inside\";\n }\n}\n\nexport default NodeElement;\n","export type AnimationSpeed = \"fast\" | \"slow\" | number;\n\nexport const getAnimationDuration = (duration: AnimationSpeed): number => {\n if (typeof duration === \"number\") {\n return duration;\n }\n\n return duration === \"slow\" ? 600 : 200;\n};\n\nexport const slideDown = (\n element: HTMLElement,\n animationSpeed: AnimationSpeed,\n): Promise<void> => {\n element.style.display = \"block\";\n\n const animation = element.animate(\n [\n { height: \"0\", overflow: \"hidden\" },\n { height: `${element.scrollHeight}px`, overflow: \"hidden\" },\n ],\n { duration: getAnimationDuration(animationSpeed) },\n );\n\n return new Promise((resolve) => {\n animation.onfinish = () => {\n resolve();\n };\n });\n};\n\nexport const slideUp = (\n element: HTMLElement,\n animationSpeed: AnimationSpeed,\n): Promise<void> => {\n const animation = element.animate(\n [\n { height: `${element.scrollHeight}px`, overflow: \"hidden\" },\n { height: \"0\", overflow: \"hidden\" },\n ],\n { duration: getAnimationDuration(animationSpeed) },\n );\n\n return new Promise((resolve) => {\n animation.onfinish = () => {\n element.style.display = \"none\";\n resolve();\n };\n });\n};\n","import type { AnimationSpeed } from \"../animation\";\nimport type { TriggerEvent } from \"../methodTypes\";\nimport type { Node, Position } from \"../node\";\nimport type { NodeElementParams } from \"./index\";\n\nimport { slideDown, slideUp } from \"../animation\";\nimport NodeElement from \"./index\";\n\nexport type RenderChildren = (node: Node) => HTMLUListElement | null;\n\ninterface FolderElementParams extends NodeElementParams {\n closedIconElement?: globalThis.Node;\n openedIconElement?: globalThis.Node;\n renderChildren: RenderChildren;\n triggerEvent: TriggerEvent;\n}\n\nclass FolderElement extends NodeElement {\n private closedIconElement?: globalThis.Node;\n private openedIconElement?: globalThis.Node;\n private renderChildren: RenderChildren;\n private triggerEvent: TriggerEvent;\n\n constructor({\n classNames,\n closedIconElement,\n getScrollLeft,\n node,\n openedIconElement,\n renderChildren,\n tabIndex,\n treeElement,\n triggerEvent,\n }: FolderElementParams) {\n super({\n classNames,\n getScrollLeft,\n node,\n tabIndex,\n treeElement,\n });\n\n this.closedIconElement = closedIconElement;\n this.openedIconElement = openedIconElement;\n this.renderChildren = renderChildren;\n this.triggerEvent = triggerEvent;\n }\n\n public async close(\n slide: boolean,\n animationSpeed: AnimationSpeed,\n ): Promise<void> {\n if (!this.node.is_open) {\n return;\n }\n\n this.node.is_open = false;\n\n if (!this.isRendered()) {\n this.triggerEvent(\"tree.close\", { node: this.node });\n return;\n }\n\n const button = this.getButton();\n button.classList.add(this.classNames.closed);\n button.replaceChildren();\n\n const closedIconElement = this.closedIconElement;\n\n if (closedIconElement) {\n const icon = closedIconElement.cloneNode(true);\n button.append(icon);\n }\n\n const ul = this.getUl();\n\n if (ul) {\n if (slide) {\n await slideUp(ul, animationSpeed);\n } else {\n ul.style.display = \"none\";\n }\n }\n\n this.element.classList.add(this.classNames.closed);\n\n const titleSpan = this.getTitleSpan();\n titleSpan.setAttribute(\"aria-expanded\", \"false\");\n\n this.triggerEvent(\"tree.close\", {\n node: this.node,\n });\n }\n\n public async open(\n slide: boolean,\n animationSpeed: AnimationSpeed,\n ): Promise<void> {\n if (this.node.is_open) {\n return;\n }\n\n this.node.is_open = true;\n\n if (!this.isRendered()) {\n // The folder is rendered open when its parent is opened\n this.triggerEvent(\"tree.open\", { node: this.node });\n return;\n }\n\n const button = this.getButton();\n button.classList.remove(this.classNames.closed);\n button.replaceChildren();\n\n const openedIconElement = this.openedIconElement;\n\n if (openedIconElement) {\n const icon = openedIconElement.cloneNode(true);\n button.append(icon);\n }\n\n // The children are rendered the first time the folder is opened\n const ul = this.getUl() ?? this.renderChildren(this.node);\n\n if (ul) {\n if (slide) {\n await slideDown(ul, animationSpeed);\n } else {\n ul.style.display = \"block\";\n }\n }\n\n this.element.classList.remove(this.classNames.closed);\n\n const titleSpan = this.getTitleSpan();\n titleSpan.setAttribute(\"aria-expanded\", \"true\");\n\n this.triggerEvent(\"tree.open\", {\n node: this.node,\n });\n }\n\n protected mustShowBorderDropHint(position: Position): boolean {\n return !this.node.is_open && position === \"inside\";\n }\n\n private getButton(): HTMLElement {\n return this.element.querySelector(\n `:scope > .${this.classNames.element} > .${this.classNames.toggler}`,\n ) as HTMLElement;\n }\n}\n\nexport default FolderElement;\n","// Url class for absolute and relative urls.\n\nconst isAbsoluteUrl = (inputUrl: string) => {\n return URL.canParse(inputUrl);\n};\n\nconst LOCALHOST = \"http://localhost\";\n\nclass RequestUrl {\n private isAbsolute: boolean;\n private url: URL;\n\n constructor(inputUrl: string) {\n if (isAbsoluteUrl(inputUrl)) {\n this.url = new URL(inputUrl);\n this.isAbsolute = true;\n } else {\n this.url = new URL(inputUrl, LOCALHOST);\n this.isAbsolute = false;\n }\n }\n\n setSearchParam(key: string, value: string) {\n this.url.searchParams.set(key, value);\n }\n\n value() {\n return this.isAbsolute\n ? this.url.href\n : this.url.href.slice(LOCALHOST.length);\n }\n}\n\nexport default RequestUrl;\n","import type {\n AddToSelection,\n GetNodeById,\n GetSelectedNodes,\n GetTree,\n OpenNode,\n RefreshElements,\n RemoveFromSelection,\n} from \"./methodTypes\";\nimport type { Node, NodeId } from \"./node\";\nimport type { OnGetStateFromStorage, OnSetStateFromStorage } from \"./options\";\n\nimport { isInt } from \"./util\";\n\nexport interface SavedState {\n open_nodes?: NodeId[];\n selected_node?: NodeId[];\n}\n\ninterface SaveStateHandlerParams {\n addToSelection: AddToSelection;\n getNodeById: GetNodeById;\n getSelectedNodes: GetSelectedNodes;\n getTree: GetTree;\n onGetStateFromStorage?: OnGetStateFromStorage;\n onSetStateFromStorage?: OnSetStateFromStorage;\n openNode: OpenNode;\n refreshElements: RefreshElements;\n removeFromSelection: RemoveFromSelection;\n saveState: boolean | string;\n}\n\nexport default class SaveStateHandler {\n private addToSelection: AddToSelection;\n private getNodeById: GetNodeById;\n private getSelectedNodes: GetSelectedNodes;\n private getTree: GetTree;\n private onGetStateFromStorage?: OnGetStateFromStorage;\n private onSetStateFromStorage?: OnSetStateFromStorage;\n private openNode: OpenNode;\n private refreshElements: RefreshElements;\n private removeFromSelection: RemoveFromSelection;\n private saveStateOption: boolean | string;\n\n constructor({\n addToSelection,\n getNodeById,\n getSelectedNodes,\n getTree,\n onGetStateFromStorage,\n onSetStateFromStorage,\n openNode,\n refreshElements,\n removeFromSelection,\n saveState,\n }: SaveStateHandlerParams) {\n this.addToSelection = addToSelection;\n this.getNodeById = getNodeById;\n this.getSelectedNodes = getSelectedNodes;\n this.getTree = getTree;\n this.onGetStateFromStorage = onGetStateFromStorage;\n this.onSetStateFromStorage = onSetStateFromStorage;\n this.openNode = openNode;\n this.refreshElements = refreshElements;\n this.removeFromSelection = removeFromSelection;\n this.saveStateOption = saveState;\n }\n\n public getNodeIdToBeSelected(): NodeId | null {\n if (!this.saveStateOption) {\n return null;\n }\n\n const state = this.getStateFromStorage();\n\n return state?.selected_node ? (state.selected_node[0] ?? null) : null;\n }\n\n public getState(): SavedState {\n const getOpenNodeIds = (): NodeId[] => {\n const openNodes: NodeId[] = [];\n\n this.getTree()?.iterate((node: Node) => {\n if (node.is_open && node.id && node.hasChildren()) {\n openNodes.push(node.id);\n }\n return true;\n });\n\n return openNodes;\n };\n\n const getSelectedNodeIds = (): NodeId[] => {\n const selectedNodeIds: NodeId[] = [];\n\n for (const node of this.getSelectedNodes()) {\n if (node.id != null) {\n selectedNodeIds.push(node.id);\n }\n }\n\n return selectedNodeIds;\n };\n\n return {\n open_nodes: getOpenNodeIds(),\n selected_node: getSelectedNodeIds(),\n };\n }\n\n public getStateFromStorage(): null | SavedState {\n if (!this.saveStateOption) {\n return null;\n }\n\n const jsonData = this.loadFromStorage();\n\n return jsonData ? this.parseState(jsonData) : null;\n }\n\n public saveState(): void {\n if (!this.saveStateOption) {\n return;\n }\n\n const state = JSON.stringify(this.getState());\n\n if (this.onSetStateFromStorage) {\n this.onSetStateFromStorage(state);\n } else {\n localStorage.setItem(this.getKeyName(), state);\n }\n }\n\n /*\n Set initial state\n Don't handle nodes that are loaded on demand\n\n result: must load on demand (boolean)\n */\n public setInitialState(state: SavedState): boolean {\n const mustLoadOnDemand = state.open_nodes\n ? this.openInitialNodes(state.open_nodes)\n : false;\n\n this.resetSelection();\n\n if (state.selected_node) {\n this.selectInitialNodes(state.selected_node);\n }\n\n return mustLoadOnDemand;\n }\n\n public async setInitialStateOnDemand(state: SavedState): Promise<void> {\n let nodeIds = state.open_nodes;\n\n const openNodes = async () => {\n if (!nodeIds) {\n return;\n }\n\n const newNodesIds = [];\n\n for (const nodeId of nodeIds) {\n const node = this.getNodeById(nodeId);\n\n if (node) {\n if (!node.is_loading) {\n if (node.load_on_demand) {\n await loadAndOpenNode(node);\n } else {\n await this.openNode(node, false);\n }\n }\n } else {\n newNodesIds.push(nodeId);\n }\n }\n\n nodeIds = newNodesIds;\n\n if (state.selected_node && this.selectInitialNodes(state.selected_node)) {\n this.refreshElements(null);\n }\n };\n\n const loadAndOpenNode = async (node: Node) => {\n await this.openNode(node, false);\n await openNodes();\n };\n\n await openNodes();\n }\n\n private getKeyName(): string {\n return typeof this.saveStateOption === \"string\"\n ? this.saveStateOption\n : \"tree\";\n }\n\n private loadFromStorage(): null | string {\n return this.onGetStateFromStorage\n ? this.onGetStateFromStorage()\n : localStorage.getItem(this.getKeyName());\n }\n\n private openInitialNodes(nodeIds: NodeId[]): boolean {\n let mustLoadOnDemand = false;\n\n for (const nodeId of nodeIds) {\n const node = this.getNodeById(nodeId);\n\n if (node) {\n if (node.load_on_demand) {\n mustLoadOnDemand = true;\n } else {\n node.is_open = true;\n }\n }\n }\n\n return mustLoadOnDemand;\n }\n\n private parseState(jsonData: string): SavedState {\n const state = JSON.parse(jsonData) as Record<string, unknown>;\n\n // Check if selected_node is an int (instead of an array)\n if (state.selected_node && isInt(state.selected_node)) {\n // Convert to array\n state.selected_node = [state.selected_node];\n }\n\n return state;\n }\n\n private resetSelection(): void {\n const selectedNodes = this.getSelectedNodes();\n\n for (const node of selectedNodes) {\n this.removeFromSelection(node);\n }\n }\n\n private selectInitialNodes(nodeIds: NodeId[]): boolean {\n let selectCount = 0;\n\n for (const nodeId of nodeIds) {\n const node = this.getNodeById(nodeId);\n\n if (!node) {\n continue;\n }\n\n selectCount += 1;\n\n this.addToSelection(node);\n }\n\n return selectCount !== 0;\n }\n}\n","export type HorizontalScrollDirection = \"left\" | \"right\";\nexport type VerticalScrollDirection = \"bottom\" | \"top\";\n\ninterface ConstructorParams {\n container: HTMLElement;\n refreshHitAreas: () => void;\n}\n\nexport abstract class ScrollParent {\n protected container: HTMLElement;\n protected horizontalScrollDirection?: HorizontalScrollDirection;\n protected horizontalScrollTimeout?: number;\n\n protected refreshHitAreas: () => void;\n protected verticalScrollDirection?: VerticalScrollDirection;\n protected verticalScrollTimeout?: number;\n\n constructor({ container, refreshHitAreas }: ConstructorParams) {\n this.container = container;\n this.refreshHitAreas = refreshHitAreas;\n }\n\n public checkHorizontalScrolling(pageX: number): void {\n const newHorizontalScrollDirection =\n this.getNewHorizontalScrollDirection(pageX);\n\n if (this.horizontalScrollDirection === newHorizontalScrollDirection) {\n return;\n }\n\n this.horizontalScrollDirection = newHorizontalScrollDirection;\n\n if (this.horizontalScrollTimeout != null) {\n window.clearTimeout(this.horizontalScrollTimeout);\n }\n\n if (newHorizontalScrollDirection) {\n this.horizontalScrollTimeout = window.setTimeout(\n this.scrollHorizontally.bind(this),\n 40,\n );\n }\n }\n\n public checkVerticalScrolling(pageY: number) {\n const newVerticalScrollDirection =\n this.getNewVerticalScrollDirection(pageY);\n\n if (this.verticalScrollDirection === newVerticalScrollDirection) {\n return;\n }\n\n this.verticalScrollDirection = newVerticalScrollDirection;\n\n if (this.verticalScrollTimeout != null) {\n window.clearTimeout(this.verticalScrollTimeout);\n this.verticalScrollTimeout = undefined;\n }\n\n if (newVerticalScrollDirection) {\n this.verticalScrollTimeout = window.setTimeout(\n this.scrollVertically.bind(this),\n 40,\n );\n }\n }\n\n public getScrollLeft(): number {\n return this.container.scrollLeft;\n }\n\n public scrollToY(top: number): void {\n this.container.scrollTop = top;\n }\n\n public stopScrolling() {\n this.horizontalScrollDirection = undefined;\n this.verticalScrollDirection = undefined;\n }\n\n protected abstract getNewHorizontalScrollDirection(\n pageX: number,\n ): HorizontalScrollDirection | undefined;\n protected abstract getNewVerticalScrollDirection(\n pageY: number,\n ): undefined | VerticalScrollDirection;\n\n protected scrollHorizontally() {\n if (!this.horizontalScrollDirection) {\n return;\n }\n\n const distance = this.horizontalScrollDirection === \"left\" ? -20 : 20;\n this.container.scrollBy({\n behavior: \"instant\",\n left: distance,\n top: 0,\n });\n\n this.refreshHitAreas();\n\n setTimeout(this.scrollHorizontally.bind(this), 40);\n }\n\n protected scrollVertically() {\n if (!this.verticalScrollDirection) {\n return;\n }\n\n const distance = this.verticalScrollDirection === \"top\" ? -20 : 20;\n this.container.scrollBy({\n behavior: \"instant\",\n left: 0,\n top: distance,\n });\n\n this.refreshHitAreas();\n\n setTimeout(this.scrollVertically.bind(this), 40);\n }\n}\n","import type {\n HorizontalScrollDirection,\n VerticalScrollDirection,\n} from \"./scrollParent\";\n\nimport { getElementPosition, getOffsetTop } from \"../positionUtils\";\nimport { ScrollParent } from \"./scrollParent\";\n\nexport default class ContainerScrollParent extends ScrollParent {\n private scrollParentBottom?: number;\n private scrollParentTop?: number;\n\n public stopScrolling() {\n super.stopScrolling();\n\n this.horizontalScrollDirection = undefined;\n this.verticalScrollDirection = undefined;\n }\n\n protected getNewHorizontalScrollDirection(\n pageX: number,\n ): HorizontalScrollDirection | undefined {\n const scrollParentOffset = getElementPosition(this.container);\n const containerWidth = this.container.getBoundingClientRect().width;\n\n const rightEdge = scrollParentOffset.left + containerWidth;\n const leftEdge = scrollParentOffset.left;\n const isNearRightEdge = pageX > rightEdge - 20;\n\n if (isNearRightEdge) {\n return \"right\";\n }\n\n const isNearLeftEdge = pageX < leftEdge + 20;\n return isNearLeftEdge ? \"left\" : undefined;\n }\n\n protected getNewVerticalScrollDirection(\n pageY: number,\n ): undefined | VerticalScrollDirection {\n if (pageY < this.getScrollParentTop()) {\n return \"top\";\n }\n\n return pageY > this.getScrollParentBottom() ? \"bottom\" : undefined;\n }\n\n private getScrollParentBottom() {\n if (this.scrollParentBottom == null) {\n const containerHeight = this.container.getBoundingClientRect().height;\n this.scrollParentBottom = this.getScrollParentTop() + containerHeight;\n }\n\n return this.scrollParentBottom;\n }\n\n private getScrollParentTop() {\n this.scrollParentTop ??= getOffsetTop(this.container);\n\n return this.scrollParentTop;\n }\n}\n","import type {\n HorizontalScrollDirection,\n VerticalScrollDirection,\n} from \"./scrollParent\";\n\nimport { getOffsetTop } from \"../positionUtils\";\nimport { ScrollParent } from \"./scrollParent\";\n\ninterface Params {\n refreshHitAreas: () => void;\n treeElement: HTMLElement;\n}\n\nexport default class DocumentScrollParent extends ScrollParent {\n private documentScrollHeight?: number;\n private documentScrollWidth?: number;\n private treeElement: HTMLElement;\n\n constructor({ refreshHitAreas, treeElement }: Params) {\n super({ container: document.documentElement, refreshHitAreas });\n\n this.treeElement = treeElement;\n }\n\n public scrollToY(top: number): void {\n const treeTop = getOffsetTop(this.treeElement);\n\n super.scrollToY(top + treeTop);\n }\n\n public stopScrolling() {\n super.stopScrolling();\n\n this.documentScrollHeight = undefined;\n this.documentScrollWidth = undefined;\n }\n\n protected getNewHorizontalScrollDirection(\n pageX: number,\n ): HorizontalScrollDirection | undefined {\n const scrollLeft = this.container.scrollLeft;\n const windowWidth = window.innerWidth;\n\n const isNearRightEdge = pageX > windowWidth - 20;\n\n if (isNearRightEdge && this.canScrollRight()) {\n return \"right\";\n }\n\n const isNearLeftEdge = pageX - scrollLeft < 20;\n return isNearLeftEdge ? \"left\" : undefined;\n }\n\n protected getNewVerticalScrollDirection(\n pageY: number,\n ): undefined | VerticalScrollDirection {\n const scrollTop = this.container.scrollTop;\n const distanceTop = pageY - scrollTop;\n\n if (distanceTop < 20) {\n return \"top\";\n }\n\n const windowHeight = window.innerHeight;\n\n return windowHeight - (pageY - scrollTop) < 20 && this.canScrollDown()\n ? \"bottom\"\n : undefined;\n }\n\n private canScrollDown() {\n return (\n this.container.scrollTop + this.container.clientHeight <\n this.getDocumentScrollHeight()\n );\n }\n\n private canScrollRight() {\n return (\n this.container.scrollLeft + this.container.clientWidth <\n this.getDocumentScrollWidth()\n );\n }\n\n private getDocumentScrollHeight() {\n // Store the original scroll height because the scroll height can increase when the drag element is moved beyond the scroll height.\n this.documentScrollHeight ??= this.container.scrollHeight;\n\n return this.documentScrollHeight;\n }\n\n private getDocumentScrollWidth() {\n // Store the original scroll width because the scroll width can increase when the drag element is moved beyond the scroll width.\n this.documentScrollWidth ??= this.container.scrollWidth;\n\n return this.documentScrollWidth;\n }\n}\n","import type { ScrollParent } from \"./scrollParent\";\n\nimport ContainerScrollParent from \"./containerScrollParent\";\nimport DocumentScrollParent from \"./documentScrollParent\";\n\nconst isOverflow = (overflowValue: string) =>\n overflowValue === \"auto\" || overflowValue === \"scroll\";\n\nconst hasOverFlow = (element: HTMLElement): boolean => {\n const style = getComputedStyle(element);\n\n return isOverflow(style.overflowX) || isOverflow(style.overflowY);\n};\n\nconst getParentWithOverflow = (\n treeElement: HTMLElement,\n): HTMLElement | null => {\n if (hasOverFlow(treeElement)) {\n return treeElement;\n }\n\n let parent = treeElement.parentElement;\n\n while (parent) {\n if (hasOverFlow(parent)) {\n return parent;\n }\n\n parent = parent.parentElement;\n }\n\n return null;\n};\n\nconst createScrollParent = (\n treeElement: HTMLElement,\n refreshHitAreas: () => void,\n): ScrollParent => {\n const container = getParentWithOverflow(treeElement);\n\n if (container && container.tagName !== \"HTML\") {\n return new ContainerScrollParent({\n container,\n refreshHitAreas,\n });\n }\n return new DocumentScrollParent({ refreshHitAreas, treeElement });\n};\n\nexport default createScrollParent;\n","import type { PositionInfo } from \"./mouseUtils\";\nimport type { ScrollParent } from \"./scrollHandler/scrollParent\";\n\nimport createScrollParent from \"./scrollHandler/createScrollParent\";\n\ninterface ScrollHandlerParams {\n refreshHitAreas: () => void;\n treeElement: HTMLElement;\n}\n\nexport default class ScrollHandler {\n private refreshHitAreas: () => void;\n private scrollParent?: ScrollParent;\n private treeElement: HTMLElement;\n\n constructor({ refreshHitAreas, treeElement }: ScrollHandlerParams) {\n this.refreshHitAreas = refreshHitAreas;\n this.scrollParent = undefined;\n this.treeElement = treeElement;\n }\n\n public checkScrolling(positionInfo: PositionInfo): void {\n this.checkVerticalScrolling(positionInfo);\n this.checkHorizontalScrolling(positionInfo);\n }\n\n public getScrollLeft(): number {\n return this.getScrollParent().getScrollLeft();\n }\n\n public scrollToY(top: number): void {\n this.getScrollParent().scrollToY(top);\n }\n\n public stopScrolling() {\n this.getScrollParent().stopScrolling();\n }\n\n private checkHorizontalScrolling(positionInfo: PositionInfo): void {\n this.getScrollParent().checkHorizontalScrolling(positionInfo.pageX);\n }\n\n private checkVerticalScrolling(positionInfo: PositionInfo): void {\n this.getScrollParent().checkVerticalScrolling(positionInfo.pageY);\n }\n\n private getScrollParent(): ScrollParent {\n this.scrollParent ??= createScrollParent(\n this.treeElement,\n this.refreshHitAreas,\n );\n\n return this.scrollParent;\n }\n}\n","import type {\n GetNodeById,\n GetNodeElementForNode,\n OpenParents,\n TriggerEvent,\n} from \"./methodTypes\";\nimport type { Node, NodeId } from \"./node\";\nimport type { OnCanSelectNode } from \"./options\";\n\nexport interface SelectNodeOptions {\n mustSetFocus?: boolean;\n mustToggle?: boolean;\n}\n\ninterface SelectNodeHandlerParameters {\n getNodeById: GetNodeById;\n getNodeElementForNode: GetNodeElementForNode;\n getOnCanSelectNode: () => OnCanSelectNode | undefined;\n getSelectable: () => boolean;\n openParents: OpenParents;\n saveState: () => void;\n triggerEvent: TriggerEvent;\n updateTabStop: () => void;\n}\n\nexport default class SelectNodeHandler {\n private getNodeById: GetNodeById;\n private getNodeElementForNode: GetNodeElementForNode;\n private getOnCanSelectNode: () => OnCanSelectNode | undefined;\n private getSelectable: () => boolean;\n private openParents: OpenParents;\n private saveState: () => void;\n private selectedNodes: Set<NodeId>;\n private selectedSingleNode: Node | null;\n private triggerEvent: TriggerEvent;\n private updateTabStop: () => void;\n\n constructor({\n getNodeById,\n getNodeElementForNode,\n getOnCanSelectNode,\n getSelectable,\n openParents,\n saveState,\n triggerEvent,\n updateTabStop,\n }: SelectNodeHandlerParameters) {\n this.getNodeById = getNodeById;\n this.getNodeElementForNode = getNodeElementForNode;\n this.getOnCanSelectNode = getOnCanSelectNode;\n this.getSelectable = getSelectable;\n this.openParents = openParents;\n this.saveState = saveState;\n this.selectedNodes = new Set<NodeId>();\n this.selectedSingleNode = null;\n this.triggerEvent = triggerEvent;\n this.updateTabStop = updateTabStop;\n }\n\n public addToSelection(node: Node): void {\n if (node.id == null) {\n this.selectedSingleNode = node;\n } else {\n this.selectedNodes.add(node.id);\n }\n }\n\n public clear(): void {\n this.selectedNodes.clear();\n this.selectedSingleNode = null;\n }\n\n public getSelectedNode(): Node | null {\n const selectedNodes = this.getSelectedNodes();\n\n return selectedNodes.length ? (selectedNodes[0] ?? null) : null;\n }\n\n public getSelectedNodes(): Node[] {\n if (this.selectedSingleNode) {\n return [this.selectedSingleNode];\n }\n\n const selectedNodes: Node[] = [];\n\n this.selectedNodes.forEach((id) => {\n const node = this.getNodeById(id);\n if (node) {\n selectedNodes.push(node);\n }\n });\n\n return selectedNodes;\n }\n\n public getSelectedNodesUnder(parent: Node): Node[] {\n if (this.selectedSingleNode) {\n return parent.isParentOf(this.selectedSingleNode)\n ? [this.selectedSingleNode]\n : [];\n }\n\n const selectedNodes: Node[] = [];\n\n this.selectedNodes.forEach((id) => {\n const node = this.getNodeById(id);\n if (node && parent.isParentOf(node)) {\n selectedNodes.push(node);\n }\n });\n\n return selectedNodes;\n }\n\n public isNodeSelected(node: Node): boolean {\n if (node.id != null) {\n return this.selectedNodes.has(node.id);\n }\n return this.selectedSingleNode ? this.selectedSingleNode === node : false;\n }\n\n public removeFromSelection(node: Node, includeChildren = false): void {\n if (node.id == null) {\n if (this.selectedSingleNode === node) {\n this.selectedSingleNode = null;\n }\n } else {\n this.selectedNodes.delete(node.id);\n\n if (includeChildren) {\n node.iterate(() => {\n if (node.id != null) {\n this.selectedNodes.delete(node.id);\n }\n return true;\n });\n }\n }\n }\n\n /* Select a single node.\n * Renders the changed elements.\n * Deselects if the node is currently selected (if the mustToggle is on).\n * Deselects the previously selected node.\n * Check if the node is selectable.\n * Saves the state.\n * Options:\n * mustSetFocus: set the focus to the selected node\n * mustToggle: support deselecting the selected node\n */\n public selectSingleNode(node: Node, optionsParam?: SelectNodeOptions) {\n const defaultOptions = { mustSetFocus: true, mustToggle: true };\n const selectOptions = { ...defaultOptions, ...optionsParam };\n\n const canSelect = (): boolean => {\n if (!this.getSelectable()) {\n return false;\n }\n\n const onCanSelectNode = this.getOnCanSelectNode();\n return onCanSelectNode ? onCanSelectNode(node) : true;\n };\n\n if (!canSelect()) {\n return;\n }\n\n const deselectCurrentNode = (deselectedNode: Node) => {\n this.removeFromSelection(deselectedNode);\n this.getNodeElementForNode(deselectedNode).deselect();\n };\n\n if (this.isNodeSelected(node)) {\n if (selectOptions.mustToggle) {\n deselectCurrentNode(node);\n this.triggerEvent(\"tree.deselect\", { node });\n }\n } else {\n const deselectedNode = this.getSelectedNode();\n\n if (deselectedNode) {\n deselectCurrentNode(deselectedNode);\n }\n\n this.addToSelection(node);\n this.openParents(node);\n this.getNodeElementForNode(node).select(selectOptions.mustSetFocus);\n\n this.triggerEvent(\"tree.select\", {\n deselectedNode,\n node,\n });\n }\n\n this.updateTabStop();\n this.saveState();\n }\n}\n","import type { AnimationSpeed } from \"./animation\";\nimport type { TreeElementOptions } from \"./options\";\n\nimport { DEFAULT_CLASS_PREFIX } from \"./classNames\";\nimport { Node } from \"./node\";\n\nconst defaults: TreeElementOptions = {\n animationSpeed: \"fast\",\n autoEscape: true,\n autoOpen: false, // true / false / int (open n levels starting at 0)\n buttonLeft: true,\n classPrefix: DEFAULT_CLASS_PREFIX, // the prefix of all css classes\n // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER\n // https://www.fileformat.info/info/unicode/char/25ba/index.htm\n // closedIcon: undefined,\n // commonClassName: undefined, // the class of every element; the default is \"<classPrefix>-common\"\n // data: undefined,\n // dataFilter: undefined,\n // dataUrl: undefined,\n dragAndDrop: false,\n keyboardSupport: true,\n nodeClass: Node,\n // onCanMove: undefined, // Can this node be moved?\n // onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)\n // onCanSelectNode: undefined,\n // onCreateLi: undefined,\n // onDragMove: undefined,\n // onDragStop: undefined,\n // onGetStateFromStorage: undefined,\n // onIsMoveHandle: undefined,\n // onSetStateFromStorage: undefined,\n // openedIcon: undefined,\n openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds\n // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE\n // https://www.fileformat.info/info/unicode/char/25bc/index.htm\n // rtl: undefined, // right-to-left support; true / false (default)\n saveState: false, // true / false / string (local storage key; the default key is \"tree\")\n selectable: true,\n showEmptyFolder: false,\n slide: true, // must display slide animation?\n startDndDelay: 300, // The delay for starting dnd (in milliseconds)\n tabIndex: 0,\n // treeClassName: undefined, // the class of the root element; the default is classPrefix\n useContextMenu: true,\n};\n\nconst setDefaultOptions = (\n htmlElement: HTMLElement,\n inputOptions: Partial<TreeElementOptions>,\n): TreeElementOptions => {\n const options = {\n ...defaults,\n ...inputOptions,\n animationSpeed: inputOptions.animationSpeed ?? getDefaultAnimationSpeed(),\n };\n\n options.dataUrl ??= htmlElement.dataset.url;\n options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);\n options.closedIcon ??= getDefaultClosedIcon(options);\n options.openedIcon ??= \"&#x25bc;\";\n\n return options;\n};\n\n// No animation when the user asked the system for reduced motion\nconst getDefaultAnimationSpeed = (): AnimationSpeed =>\n prefersReducedMotion() ? 0 : defaults.animationSpeed;\n\nconst prefersReducedMotion = (): boolean =>\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\nconst getDefaultClosedIcon = (options: TreeElementOptions): string => {\n if (options.rtl) {\n // triangle to the left\n return \"&#x25c0;\";\n }\n // triangle to the right\n return \"&#x25ba;\";\n};\n\nconst getRtlOptionFromHTMLElement = (htmlElement: HTMLElement): boolean => {\n const dataRtl = htmlElement.dataset.rtl;\n\n if (dataRtl == \"\") {\n return true;\n }\n return dataRtl === \"false\" ? false : Boolean(dataRtl);\n};\n\nexport default setDefaultOptions;\n","export interface ClassNames {\n border: string;\n circle: string;\n closed: string;\n common: string;\n dnd: string;\n dragging: string;\n element: string;\n folder: string;\n ghost: string;\n inside: string;\n line: string;\n loading: string;\n moving: string;\n rtl: string;\n selected: string;\n title: string;\n titleButtonLeft: string;\n titleButtonRight: string;\n titleFolder: string;\n toggler: string;\n togglerLeft: string;\n togglerRight: string;\n tree: string;\n}\n\nexport interface ClassNamesOptions {\n classPrefix: string;\n commonClassName?: string;\n treeClassName?: string;\n}\n\nexport const DEFAULT_CLASS_PREFIX = \"tree-element\";\n\n/* Create the class names that the widget puts on the elements it creates.\n * They are all derived from classPrefix, except for the class of the root\n * element and the class that every element gets, which have an option of\n * their own.\n */\nconst createClassNames = ({\n classPrefix,\n commonClassName,\n treeClassName,\n}: ClassNamesOptions): ClassNames => ({\n border: `${classPrefix}-border`,\n circle: `${classPrefix}-circle`,\n closed: `${classPrefix}-closed`,\n common: commonClassName ?? `${classPrefix}-common`,\n dnd: `${classPrefix}-dnd`,\n dragging: `${classPrefix}-dragging`,\n element: `${classPrefix}-element`,\n folder: `${classPrefix}-folder`,\n ghost: `${classPrefix}-ghost`,\n inside: `${classPrefix}-inside`,\n line: `${classPrefix}-line`,\n loading: `${classPrefix}-loading`,\n moving: `${classPrefix}-moving`,\n rtl: `${classPrefix}-rtl`,\n selected: `${classPrefix}-selected`,\n title: `${classPrefix}-title`,\n titleButtonLeft: `${classPrefix}-title-button-left`,\n titleButtonRight: `${classPrefix}-title-button-right`,\n titleFolder: `${classPrefix}-title-folder`,\n toggler: `${classPrefix}-toggler`,\n togglerLeft: `${classPrefix}-toggler-left`,\n togglerRight: `${classPrefix}-toggler-right`,\n tree: treeClassName ?? classPrefix,\n});\n\nexport default createClassNames;\n","// Trigger a CustomEvent. Return if the event is processed (true) or cancelled (false).\nconst triggerCustomEvent = (\n element: HTMLElement,\n eventName: string,\n values?: Record<string, unknown>,\n): boolean => {\n const event = new CustomEvent(eventName, {\n bubbles: true,\n cancelable: true,\n detail: values,\n });\n\n element.dispatchEvent(event);\n\n return !event.defaultPrevented;\n};\n\nexport default triggerCustomEvent;\n","import type { ClassNames } from \"./classNames\";\nimport type { TreeEventName, TreeEvents } from \"./events\";\nimport type { PositionInfo } from \"./mouseUtils\";\nimport type { NodeData, NodeId, Position } from \"./node\";\nimport type { TreeElementOptions } from \"./options\";\nimport type { SavedState } from \"./saveStateHandler\";\nimport type { SelectNodeOptions } from \"./selectNodeHandler\";\n\nimport createClassNames from \"./classNames\";\nimport DataLoader from \"./dataLoader\";\nimport { DragAndDropHandler } from \"./dragAndDropHandler\";\nimport ElementsRenderer from \"./elementsRenderer\";\nimport KeyHandler from \"./keyHandler\";\nimport MouseHandler from \"./mouseHandler\";\nimport { Node } from \"./node\";\nimport NodeElement from \"./nodeElement\";\nimport FolderElement from \"./nodeElement/folderElement\";\nimport { getOffsetTop } from \"./positionUtils\";\nimport RequestUrl from \"./requestUrl\";\nimport SaveStateHandler from \"./saveStateHandler\";\nimport ScrollHandler from \"./scrollHandler\";\nimport SelectNodeHandler from \"./selectNodeHandler\";\nimport setDefaultOptions from \"./setDefaultOptions\";\nimport triggerCustomEvent from \"./triggerCustomEvent\";\nimport __version__ from \"./version\";\n\n// The types that appear in the public api. Consumers cannot import them from\n// the submodules directly, because those are not exposed in package.json.\n// Type only, so that the iife build keeps exposing the TreeElement class itself\n// as its global, instead of an object of named exports.\n\nexport type TriggerEventProvider = (\n element: HTMLElement,\n eventName: TreeEventName,\n values?: TreeEvents[TreeEventName],\n) => boolean;\n\ninterface TreeElementParams extends Partial<TreeElementOptions> {\n /**\n The element the tree is rendered into. Its content is replaced.\n */\n htmlElement: HTMLElement;\n /** Replaces how events are dispatched. It must return whether the event\n * was not cancelled. This exists for tests and for integrating with\n * another event system. */\n overrideTriggerEventProvider?: TriggerEventProvider;\n}\n\nexport default class TreeElement {\n private classNames: ClassNames;\n private dataLoader: DataLoader;\n private dndHandler: DragAndDropHandler;\n private fallbackTabStop: HTMLElement | null;\n private htmlElement: HTMLElement;\n private isInitialized: boolean;\n private keyHandler: KeyHandler;\n private mouseHandler: MouseHandler;\n private nodeMap: WeakMap<HTMLElement, Node>;\n private options: TreeElementOptions;\n private renderer: ElementsRenderer;\n private saveStateHandler: SaveStateHandler;\n private scrollHandler: ScrollHandler;\n private selectNodeHandler: SelectNodeHandler;\n private tree: Node;\n private triggerEventProvider: TriggerEventProvider;\n\n /**\n @hidden\n */\n constructor({\n htmlElement,\n overrideTriggerEventProvider,\n ...options\n }: TreeElementParams) {\n this.htmlElement = htmlElement;\n this.options = setDefaultOptions(htmlElement, options);\n this.classNames = createClassNames(this.options);\n this.triggerEventProvider =\n overrideTriggerEventProvider ?? triggerCustomEvent;\n\n this.isInitialized = false;\n this.tree = new Node({}, true);\n this.nodeMap = new WeakMap();\n this.fallbackTabStop = null;\n\n const {\n ariaLabel,\n ariaLabelledBy,\n autoEscape,\n buttonLeft,\n closedIcon,\n dataFilter,\n dragAndDrop,\n keyboardSupport,\n onCanMove,\n onCanMoveTo,\n onCreateLi,\n onDragMove,\n onDragStop,\n onGetStateFromStorage,\n onIsMoveHandle,\n onSetStateFromStorage,\n openedIcon,\n openFolderDelay,\n rtl,\n saveState: saveStateOption,\n showEmptyFolder,\n slide,\n tabIndex,\n } = this.options;\n\n const classNames = this.classNames;\n const closeNode = this.closeNode.bind(this);\n const getNodeElement = this.getNodeElement.bind(this);\n const getNodeElementForNode = this.getNodeElementForNode.bind(this);\n const getFocusedNode = this.getFocusedNode.bind(this);\n const getNodeById = this.getNodeById.bind(this);\n const getSelectedNode = this.getSelectedNode.bind(this);\n const getTree = this.getTree.bind(this);\n const loadData = this.loadData.bind(this);\n const openNode = this.openNode.bind(this);\n const openParents = this.openParents.bind(this);\n const refreshElements = this.refreshElements.bind(this);\n const refreshHitAreas = this.refreshHitAreas.bind(this);\n const setNodeElement = this.setNodeElement.bind(this);\n const treeElement = this.htmlElement;\n const triggerEvent = this.triggerEvent.bind(this);\n const updateTabStop = this.updateTabStop.bind(this);\n\n const saveState = () => {\n saveStateHandler.saveState();\n };\n\n const selectNodeHandler = new SelectNodeHandler({\n getNodeById,\n getNodeElementForNode,\n getOnCanSelectNode: () => this.options.onCanSelectNode,\n getSelectable: () => this.options.selectable,\n openParents,\n saveState,\n triggerEvent,\n updateTabStop,\n });\n\n const addToSelection =\n selectNodeHandler.addToSelection.bind(selectNodeHandler);\n const getSelectedNodes =\n selectNodeHandler.getSelectedNodes.bind(selectNodeHandler);\n const isNodeSelected =\n selectNodeHandler.isNodeSelected.bind(selectNodeHandler);\n const removeFromSelection =\n selectNodeHandler.removeFromSelection.bind(selectNodeHandler);\n const selectNode =\n selectNodeHandler.selectSingleNode.bind(selectNodeHandler);\n\n const getMouseDelay = () => this.options.startDndDelay ?? 0;\n\n const dataLoader = new DataLoader({\n classNames,\n dataFilter,\n loadData,\n treeElement,\n triggerEvent,\n });\n\n const saveStateHandler = new SaveStateHandler({\n addToSelection,\n getNodeById,\n getSelectedNodes,\n getTree,\n onGetStateFromStorage,\n onSetStateFromStorage,\n openNode,\n refreshElements,\n removeFromSelection,\n saveState: saveStateOption,\n });\n\n const scrollHandler = new ScrollHandler({\n refreshHitAreas,\n treeElement,\n });\n\n const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);\n\n const dndHandler = new DragAndDropHandler({\n autoEscape,\n classNames,\n getNodeElement,\n getNodeElementForNode,\n getScrollLeft,\n getTree,\n onCanMove,\n onCanMoveTo,\n onDragMove,\n onDragStop,\n onIsMoveHandle,\n openFolderDelay,\n openNode,\n refreshElements,\n slide,\n treeElement,\n triggerEvent,\n });\n\n const keyHandler = new KeyHandler({\n closeNode,\n getFocusedNode,\n getSelectedNode,\n getTree,\n keyboardSupport,\n openNode,\n selectNode,\n triggerEvent,\n });\n\n const renderer = new ElementsRenderer({\n ariaLabel,\n ariaLabelledBy,\n autoEscape,\n buttonLeft,\n classNames,\n closedIcon,\n dragAndDrop,\n getTree,\n htmlElement: treeElement,\n isNodeSelected,\n onCreateLi,\n openedIcon,\n rtl,\n setNodeElement,\n showEmptyFolder,\n tabIndex,\n });\n\n const getNode = this.getNode.bind(this);\n const onMouseCapture = this.mouseCapture.bind(this);\n const onMouseDrag = this.mouseDrag.bind(this);\n const onMouseStart = this.mouseStart.bind(this);\n const onMouseStop = this.mouseStop.bind(this);\n\n const mouseHandler = new MouseHandler({\n classNames,\n element: treeElement,\n getMouseDelay,\n getNode,\n onClickButton: this.toggle.bind(this),\n onClickTitle: selectNode,\n onMouseCapture,\n onMouseDrag,\n onMouseStart,\n onMouseStop,\n triggerEvent,\n useContextMenu: this.options.useContextMenu,\n });\n\n this.dataLoader = dataLoader;\n this.dndHandler = dndHandler;\n this.keyHandler = keyHandler;\n this.mouseHandler = mouseHandler;\n this.renderer = renderer;\n this.saveStateHandler = saveStateHandler;\n this.scrollHandler = scrollHandler;\n this.selectNodeHandler = selectNodeHandler;\n\n this.initData();\n }\n\n /**\n * Adds a sibling after a node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addNodeAfter(nodeData: NodeData, existingNode: Node): Node | null {\n const newNode = existingNode.addAfter(nodeData);\n\n if (newNode) {\n this.refreshElements(existingNode.parent);\n }\n\n return newNode;\n }\n\n /**\n * Adds a sibling before a node.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addNodeBefore(nodeData: NodeData, existingNode: Node): Node | null {\n const newNode = existingNode.addBefore(nodeData);\n\n if (newNode) {\n this.refreshElements(existingNode.parent);\n }\n\n return newNode;\n }\n\n /**\n * Inserts a new node between a node and its parent, taking the node as its\n * child.\n *\n * @returns The new node, or `null` when the node has no parent.\n * @group Changing the tree\n */\n public addParentNode(nodeData: NodeData, existingNode: Node): Node | null {\n const newNode = existingNode.addParent(nodeData);\n\n if (newNode) {\n this.refreshElements(newNode.parent);\n }\n\n return newNode;\n }\n\n /**\n * Adds a node to the selection instead of replacing it.\n *\n * @param mustSetFocus - Move the focus to the node. Default `true`.\n * @group Selection\n */\n public addToSelection(node: Node, mustSetFocus = true) {\n this.selectNodeHandler.addToSelection(node);\n this.openParents(node);\n\n this.getNodeElementForNode(node).select(mustSetFocus);\n\n this.updateTabStop();\n this.saveState();\n }\n\n /**\n * Adds a node as the last child of a parent.\n *\n * @example\n * ```js\n * tree.appendNode({ name: \"child\", id: 5 }, tree.getNodeById(1));\n * ```\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public appendNode(nodeData: NodeData, parentNode: Node): Node {\n const node = parentNode.append(nodeData);\n\n this.refreshElements(parentNode);\n\n return node;\n }\n\n /**\n * Closes a folder. Await the promise when you need to know the closing\n * animation has finished.\n *\n * @example\n * ```js\n * await tree.closeNode(node);\n * console.log(\"closed\");\n * ```\n *\n * @param slide - Override the `slide` option for this call.\n * @group Opening and closing\n */\n public async closeNode(node: Node, slide?: boolean): Promise<void> {\n if (!(node.isFolder() || node.isEmptyFolder)) {\n return;\n }\n\n await this.createFolderElement(node).close(\n slide ?? this.options.slide,\n this.options.animationSpeed,\n );\n\n this.saveState();\n }\n\n /**\n * Empties the element and removes the tree's document-level keyboard\n * listener. Call it when you remove the tree from the page.\n *\n * @group Other\n */\n public deinit(): void {\n this.htmlElement.textContent = \"\";\n\n this.dataLoader.deinit();\n this.keyHandler.deinit();\n this.mouseHandler.deinit();\n\n this.tree = new Node({}, true);\n }\n\n /**\n * Returns the node that belongs to a `li` element the tree rendered.\n *\n * @group Finding nodes\n */\n public getNode(element: HTMLElement): Node | null {\n const liElement = element.closest<HTMLElement>(\n `li.${this.classNames.common}`,\n );\n\n return liElement ? (this.nodeMap.get(liElement) ?? null) : null;\n }\n\n /**\n * Returns the first node for which the callback returns `true`.\n *\n * @example\n * ```js\n * const node = tree.getNodeByCallback((node) => node.children.length > 3);\n * ```\n *\n * @group Finding nodes\n */\n public getNodeByCallback(callback: (node: Node) => boolean): Node | null {\n return this.tree.getNodeByCallback(callback);\n }\n\n /**\n * Returns the node with this id.\n *\n * @example\n * ```js\n * const node = tree.getNodeById(1);\n * ```\n *\n * @group Finding nodes\n */\n public getNodeById(id: NodeId): Node | null {\n return this.tree.getNodeById(id);\n }\n\n /**\n * Returns the first node with this name.\n *\n * @group Finding nodes\n */\n public getNodeByName(name: string): Node | null {\n return this.tree.getNodeByName(name);\n }\n\n /**\n * Like `getNodeByName`, but throws when there is no such node. Convenient\n * in tests and when a missing node is a bug.\n *\n * @group Finding nodes\n */\n public getNodeByNameMustExist(name: string): Node {\n return this.tree.getNodeByNameMustExist(name);\n }\n\n /**\n * Returns all nodes with this property value.\n *\n * @example\n * ```js\n * tree.getNodesByProperty(\"color\", \"green\");\n * ```\n *\n * @group Finding nodes\n */\n public getNodesByProperty(key: string, value: unknown): Node[] {\n return this.tree.getNodesByProperty(key, value);\n }\n\n /**\n * Returns the selected node, or `null` when nothing is selected.\n *\n * @group Selection\n */\n public getSelectedNode(): Node | null {\n return this.selectNodeHandler.getSelectedNode();\n }\n\n /**\n * Returns the selected nodes.\n *\n * @group Selection\n */\n public getSelectedNodes(): Node[] {\n return this.selectNodeHandler.getSelectedNodes();\n }\n\n /**\n * Returns the current state — `open_nodes` and `selected_node` — whether or\n * not `saveState` is enabled.\n *\n * @group State\n */\n public getState(): null | SavedState {\n return this.saveStateHandler.getState();\n }\n\n /**\n * Returns the state as it is stored.\n *\n * @group State\n */\n public getStateFromStorage(): null | SavedState {\n return this.saveStateHandler.getStateFromStorage();\n }\n\n /**\n * Returns the root node. It is not rendered; its `children` are the\n * top-level nodes. Also available as the `tree` property.\n *\n * @group Finding nodes\n */\n public getTree(): Node {\n return this.tree;\n }\n\n /**\n * Returns the version of tree-element.\n *\n * @group Other\n */\n public getVersion(): string {\n return __version__;\n }\n\n /**\n * Returns whether the user is dragging a node.\n *\n * @group Other\n */\n public isDragging(): boolean {\n return this.dndHandler.isDragging;\n }\n\n /**\n * Returns whether the node is selected.\n *\n * @group Selection\n */\n public isNodeSelected(node: Node): boolean {\n return this.selectNodeHandler.isNodeSelected(node);\n }\n\n /**\n * Loads data into the tree.\n *\n * @param parentNode - Replace this node's children instead of the whole\n * tree.\n * @group Loading data\n */\n public loadData(data: NodeData[] | null, parentNode?: Node): void {\n if (data) {\n if (parentNode) {\n this.deselectNodes(parentNode);\n this.loadSubtree(data, parentNode);\n } else {\n this.initTree(data);\n }\n\n if (this.isDragging()) {\n this.dndHandler.refresh();\n }\n }\n\n this.triggerEvent(\"tree.set_data\", {\n node: parentNode,\n treeData: data ?? undefined,\n });\n }\n\n /**\n * Fetches data and loads it into the tree, or into `parentNode`.\n *\n * @param url - Defaults to the `dataUrl` option.\n * @group Loading data\n */\n public async loadDataFromUrl(url?: string, parentNode?: Node): Promise<void> {\n const requestUrl = url\n ? new RequestUrl(url)\n : this.createRequestUrl(parentNode);\n\n if (requestUrl) {\n await this.dataLoader.loadFromUrl(requestUrl, parentNode);\n }\n }\n\n /**\n * Selects the next visible node, like the down arrow key.\n *\n * @group Selection\n */\n public moveDown() {\n this.keyHandler.moveDown();\n }\n\n /**\n * Moves a node inside the tree.\n *\n * @example\n * ```js\n * tree.moveNode(tree.getNodeById(2), tree.getNodeById(1), \"inside\");\n * ```\n *\n * @param position - `\"before\"`, `\"after\"` or `\"inside\"`.\n * @group Changing the tree\n */\n public moveNode(node: Node, targetNode: Node, position: Position): void {\n this.tree.moveNode(node, targetNode, position);\n this.refreshElements(null);\n }\n\n /**\n * Selects the previous visible node, like the up arrow key.\n *\n * @group Selection\n */\n public moveUp() {\n this.keyHandler.moveUp();\n }\n\n /**\n * Opens a folder, and the folders above it. A node marked `load_on_demand`\n * is fetched first, so await the promise when you need to know it is really\n * open.\n *\n * @example\n * ```js\n * await tree.openNode(node);\n * console.log(\"open\");\n * ```\n *\n * @param slide - Override the `slide` option for this call.\n * @group Opening and closing\n */\n public async openNode(node: Node, slide?: boolean): Promise<void> {\n const mustSlide = slide ?? this.options.slide;\n\n const doOpenNode = async (\n openedNode: Node,\n slideOption: boolean,\n ): Promise<void> => {\n if (!node.children.length) {\n return;\n }\n\n const folderElement = this.createFolderElement(openedNode);\n\n await folderElement.open(slideOption, this.options.animationSpeed);\n };\n\n if (node.isFolder() || node.isEmptyFolder) {\n if (node.load_on_demand) {\n await this.loadFolderOnDemand(node, mustSlide);\n } else {\n let parent = node.parent;\n\n while (parent) {\n // nb: do not open root element\n if (parent.parent) {\n await doOpenNode(parent, false);\n }\n parent = parent.parent;\n }\n\n await doOpenNode(node, mustSlide);\n\n this.saveState();\n }\n }\n }\n\n /**\n * Adds a node as the first child of a parent.\n *\n * @returns The new node.\n * @group Changing the tree\n */\n public prependNode(nodeData: NodeData, parentNode: Node): Node {\n const node = parentNode.prepend(nodeData);\n\n this.refreshElements(parentNode);\n\n return node;\n }\n\n /**\n * Re-renders the whole tree. Needed after changing node data directly\n * instead of through these methods.\n *\n * @group Changing the tree\n */\n public refresh() {\n this.refreshElements(null);\n }\n\n /**\n * Recomputes the drop targets. Call this if the layout changes during a\n * drag.\n *\n * @group Other\n */\n public refreshHitAreas() {\n this.dndHandler.refresh();\n }\n\n /**\n * Removes a node from the selection.\n *\n * @group Selection\n */\n public removeFromSelection(node: Node) {\n this.selectNodeHandler.removeFromSelection(node);\n\n this.getNodeElementForNode(node).deselect();\n this.updateTabStop();\n this.saveState();\n }\n\n /**\n * Removes a node and its children.\n *\n * @group Changing the tree\n */\n public removeNode(node: Node): void {\n this.selectNodeHandler.removeFromSelection(node, true); // including children\n\n const parent = node.parent;\n node.remove();\n this.refreshElements(parent);\n }\n\n /**\n * Scrolls the node into view.\n *\n * @group Selection\n */\n public scrollToNode(node: Node) {\n if (!node.element) {\n return;\n }\n\n const top = getOffsetTop(node.element) - getOffsetTop(this.htmlElement);\n\n this.scrollHandler.scrollToY(top);\n }\n\n /**\n * Replaces the selection, and opens the parents of the node.\n *\n * @param node - `null` clears the selection.\n * @param options - `mustSetFocus`: move focus to the node, default `true`.\n * `mustToggle`: deselect the node if it is already selected, default\n * `false`.\n * @group Selection\n */\n public selectNode(node: Node | null, options?: SelectNodeOptions): void {\n if (!node) {\n // Called with empty node -> deselect current node\n this.deselectCurrentNode();\n this.saveStateHandler.saveState();\n return;\n }\n\n // Unlike a click, selecting the selected node again keeps it selected\n this.selectNodeHandler.selectSingleNode(node, {\n mustToggle: false,\n ...options,\n });\n }\n\n /**\n * Changes an option after construction. See\n * [Options](/reference/options#changing-an-option-later) for the caveats.\n *\n * @group Other\n */\n public setOption(option: string, value: unknown) {\n (this.options as unknown as Record<string, unknown>)[option] = value;\n }\n\n /**\n * Applies a state to the tree, and saves it to storage when `saveState` is\n * enabled.\n *\n * @group State\n */\n public setState(state: SavedState) {\n this.saveStateHandler.setInitialState(state);\n this.refreshElements(null);\n this.saveState();\n }\n\n /**\n * Closes an open node and opens a closed one. Await the promise when you\n * need to know the node is really open or closed, like with `openNode` and\n * `closeNode`.\n *\n * @param slide - Override the `slide` option for this call.\n * @group Opening and closing\n */\n public async toggle(node: Node, slide: boolean | null = null): Promise<void> {\n const mustSlide = slide ?? this.options.slide;\n\n if (node.is_open) {\n await this.closeNode(node, mustSlide);\n } else {\n await this.openNode(node, mustSlide);\n }\n }\n\n /**\n * Returns the tree as a json string, including changes made through the\n * api.\n *\n * @group Other\n */\n public toJson(): string {\n return JSON.stringify(this.tree.getData());\n }\n\n /**\n * Updates the data of a node and re-renders it. A string updates just the\n * name.\n *\n * Changing the `id` re-indexes the node. `children` and `parent` are\n * ignored — use `loadData` or `moveNode` for those.\n *\n * @example\n * ```js\n * tree.updateNode(node, \"new name\");\n * tree.updateNode(node, { name: \"new name\", color: \"red\" });\n * ```\n *\n * @group Changing the tree\n */\n public updateNode(node: Node, data: NodeData): void {\n const idIsChanged =\n typeof data === \"object\" && data.id && data.id !== node.id;\n\n if (idIsChanged) {\n this.tree.removeNodeFromIndex(node);\n }\n\n node.setData(data);\n\n if (idIsChanged) {\n this.tree.addNodeToIndex(node);\n }\n\n if (\n typeof data === \"object\" &&\n data.children &&\n Array.isArray(data.children)\n ) {\n node.removeChildren();\n\n if (data.children.length) {\n node.loadFromData(data.children);\n }\n }\n\n this.refreshElements(node);\n }\n\n // Open the nodes up to the autoOpen level. A folder that is loaded on\n // demand is fetched first, and its children are opened when the data has\n // arrived.\n private async autoOpenNodesOnDemand(): Promise<void> {\n const maxLevel = this.getAutoOpenMaxLevel();\n\n const openNodes = async (): Promise<void> => {\n const loading: Promise<void>[] = [];\n\n this.tree.iterate((node: Node, level: number) => {\n if (node.load_on_demand) {\n if (!node.is_loading) {\n loading.push(this.openNode(node, false).then(openNodes));\n }\n\n return false;\n }\n void this.openNode(node, false);\n\n return level !== maxLevel;\n });\n\n await Promise.all(loading);\n };\n\n await openNodes();\n }\n\n private createFolderElement(node: Node) {\n const classNames = this.classNames;\n const closedIconElement = this.renderer.closedIconElement;\n const getScrollLeft = this.scrollHandler.getScrollLeft.bind(\n this.scrollHandler,\n );\n const openedIconElement = this.renderer.openedIconElement;\n const tabIndex = this.options.tabIndex;\n const treeElement = this.htmlElement;\n const triggerEvent = this.triggerEvent.bind(this);\n\n // A selected node in a closed folder is rendered when the folder is\n // opened, which can be after it was selected. It becomes the tab stop\n // then, so the fallback tab stop must go.\n const renderChildren = (folder: Node) => {\n const ul = this.renderer.renderChildren(folder);\n this.updateTabStop();\n return ul;\n };\n\n return new FolderElement({\n classNames,\n closedIconElement,\n getScrollLeft,\n node,\n openedIconElement,\n renderChildren,\n tabIndex,\n treeElement,\n triggerEvent,\n });\n }\n\n private createNodeElement(node: Node) {\n const classNames = this.classNames;\n const getScrollLeft = this.scrollHandler.getScrollLeft.bind(\n this.scrollHandler,\n );\n const tabIndex = this.options.tabIndex;\n const treeElement = this.htmlElement;\n\n return new NodeElement({\n classNames,\n getScrollLeft,\n node,\n tabIndex,\n treeElement,\n });\n }\n\n /* Create a RequestUrl based on the url in the options.\n * Add a 'node' query parameter for loading on demand\n * Add a 'selected_node' query parameter if a node is selected.\n */\n private createRequestUrl(node?: Node): null | RequestUrl {\n const dataUrl = this.options.dataUrl;\n\n const url = typeof dataUrl === \"function\" ? dataUrl(node) : dataUrl;\n\n if (!url) {\n return null;\n }\n\n const requestUrl = new RequestUrl(url);\n\n if (node?.id) {\n // Load on demand of a subtree; add node parameter\n requestUrl.setSearchParam(\"node\", node.id.toString());\n } else {\n // Add selected_node parameter\n const selectedNodeId = this.getNodeIdToBeSelected();\n if (selectedNodeId) {\n requestUrl.setSearchParam(\"selected_node\", selectedNodeId.toString());\n }\n }\n\n return requestUrl;\n }\n\n private deselectCurrentNode(): void {\n const node = this.getSelectedNode();\n if (node) {\n this.removeFromSelection(node);\n }\n }\n\n // Deselect the children of the node.\n private deselectNodes(parentNode: Node): void {\n const selectedNodesUnderParent =\n this.selectNodeHandler.getSelectedNodesUnder(parentNode);\n for (const n of selectedNodesUnderParent) {\n this.selectNodeHandler.removeFromSelection(n);\n }\n }\n\n // Get the maximum level for auto open\n private getAutoOpenMaxLevel(): number {\n if (this.options.autoOpen === true) {\n return -1;\n }\n if (typeof this.options.autoOpen === \"number\") {\n return this.options.autoOpen;\n }\n if (typeof this.options.autoOpen === \"string\") {\n return parseInt(this.options.autoOpen, 10);\n }\n\n /* istanbul ignore next @preserve */\n return 0;\n }\n\n // The title span of the first node, or null when the tree is empty\n private getFirstTitleSpan(): HTMLElement | null {\n const firstElement = this.tree.children[0]?.element;\n\n return firstElement\n ? firstElement.querySelector<HTMLElement>(\n `:scope > .${this.classNames.element} > span.${this.classNames.title}`,\n )\n : null;\n }\n\n // The node of the HTML element that has the focus, if it is in this tree\n private getFocusedNode(): Node | null {\n const activeElement = document.activeElement;\n\n /* istanbul ignore if */\n if (!activeElement) {\n return null;\n }\n\n // The keyboard must still work for input elements.\n const tagName = activeElement.tagName;\n if (tagName !== \"A\" && tagName !== \"SPAN\") {\n return null;\n }\n\n const node = this.getNode(activeElement as HTMLElement);\n return node?.tree === this.tree ? node : null;\n }\n\n private getNodeElement(element: HTMLElement): NodeElement | null {\n const node = this.getNode(element);\n return node ? this.getNodeElementForNode(node) : null;\n }\n\n private getNodeElementForNode(node: Node): NodeElement {\n return node.isFolder()\n ? this.createFolderElement(node)\n : this.createNodeElement(node);\n }\n\n private getNodeIdToBeSelected(): NodeId | null {\n return this.saveStateHandler.getNodeIdToBeSelected();\n }\n\n private hasRenderedSelectedNode(): boolean {\n return this.getSelectedNodes().some((node) => Boolean(node.element));\n }\n\n private initData(): void {\n if (this.options.data) {\n this.loadData(this.options.data);\n } else {\n const dataUrl = this.createRequestUrl();\n\n if (dataUrl) {\n void this.loadDataFromUrl();\n } else {\n this.loadData([]);\n }\n }\n }\n\n private initTree(data: NodeData[]): void {\n const doInit = (): void => {\n if (this.isInitialized) {\n return;\n }\n\n this.isInitialized = true;\n this.triggerEvent(\"tree.init\");\n };\n\n this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);\n\n this.selectNodeHandler.clear();\n\n this.tree.loadFromData(data);\n\n const mustLoadOnDemand = this.setInitialState();\n\n this.refreshElements(null);\n\n if (mustLoadOnDemand) {\n // Load data on demand and then init the tree\n void this.setInitialStateOnDemand().then(doInit);\n } else {\n doInit();\n }\n }\n\n // Does an HTML element of the tree have the focus?\n private isFocusOnTree(): boolean {\n return this.getFocusedNode() !== null;\n }\n\n private isSelectedNodeInSubtree(subtree: Node): boolean {\n const selectedNode = this.getSelectedNode();\n\n return selectedNode\n ? subtree === selectedNode || subtree.isParentOf(selectedNode)\n : false;\n }\n\n private async loadFolderOnDemand(node: Node, slide: boolean): Promise<void> {\n node.is_loading = true;\n\n await this.loadDataFromUrl(undefined, node);\n\n // Loading failed, or there is no url. Opening the node now would load it\n // again, without end. Leave it closed so the user can try again.\n if (node.load_on_demand) {\n node.is_loading = false;\n return;\n }\n\n await this.openNode(node, slide);\n }\n\n private loadSubtree(data: NodeData[], parentNode: Node): void {\n parentNode.loadFromData(data);\n\n parentNode.load_on_demand = false;\n parentNode.is_loading = false;\n\n this.refreshElements(parentNode);\n }\n\n private mouseCapture(positionInfo: PositionInfo): boolean | null {\n return this.options.dragAndDrop\n ? this.dndHandler.mouseCapture(positionInfo)\n : false;\n }\n\n private mouseDrag(positionInfo: PositionInfo): boolean {\n /* istanbul ignore if */\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n const result = this.dndHandler.mouseDrag(positionInfo);\n this.scrollHandler.checkScrolling(positionInfo);\n return result;\n }\n\n private mouseStart(positionInfo: PositionInfo): boolean {\n /* istanbul ignore if */\n // eslint-disable-next-line unicorn/prefer-ternary\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n return this.dndHandler.mouseStart(positionInfo);\n }\n\n private mouseStop(positionInfo: PositionInfo): boolean {\n /* istanbul ignore if */\n if (!this.options.dragAndDrop) {\n return false;\n }\n\n this.scrollHandler.stopScrolling();\n return this.dndHandler.mouseStop(positionInfo);\n }\n\n private openParents(node: Node) {\n const parent = node.parent;\n\n if (parent?.parent && !parent.is_open) {\n void this.openNode(parent, false);\n }\n }\n\n /*\n Redraw the tree or part of the tree.\n from_node: redraw this subtree\n */\n private refreshElements(fromNode: Node | null): void {\n const mustSetFocus = this.isFocusOnTree();\n const mustSelect = fromNode\n ? this.isSelectedNodeInSubtree(fromNode)\n : false;\n\n this.renderer.render(fromNode);\n\n if (mustSelect) {\n this.selectCurrentNode(mustSetFocus);\n }\n\n this.updateTabStop();\n\n this.triggerEvent(\"tree.refresh\");\n }\n\n private saveState(): void {\n this.saveStateHandler.saveState();\n }\n\n private selectCurrentNode(mustSetFocus: boolean): void {\n const node = this.getSelectedNode();\n if (!node) {\n return;\n }\n\n const nodeElement = this.getNodeElementForNode(node);\n nodeElement.select(mustSetFocus);\n }\n\n // Set initial state, either by restoring the state or auto-opening nodes\n // result: must load nodes on demand?\n private setInitialState(): boolean {\n const restoreState = (): [boolean, boolean] => {\n // result: is state restored, must load on demand?\n const state = this.saveStateHandler.getStateFromStorage();\n\n if (state) {\n const mustLoadOnDemand = this.saveStateHandler.setInitialState(state);\n\n // return true: the state is restored\n return [true, mustLoadOnDemand];\n }\n return [false, false];\n };\n\n const autoOpenNodes = (): boolean => {\n // result: must load on demand?\n if (this.options.autoOpen === false) {\n return false;\n }\n\n const maxLevel = this.getAutoOpenMaxLevel();\n let mustLoadOnDemand = false;\n\n this.tree.iterate((node: Node, level: number) => {\n if (node.load_on_demand) {\n mustLoadOnDemand = true;\n return false;\n }\n if (node.hasChildren()) {\n node.is_open = true;\n return level !== maxLevel;\n }\n return false;\n });\n\n return mustLoadOnDemand;\n };\n\n let [isRestored, mustLoadOnDemand] = restoreState(); // eslint-disable-line prefer-const\n\n if (!isRestored) {\n mustLoadOnDemand = autoOpenNodes();\n }\n\n return mustLoadOnDemand;\n }\n\n // Set the initial state for nodes that are loaded on demand\n private async setInitialStateOnDemand(): Promise<void> {\n const state = this.saveStateHandler.getStateFromStorage();\n\n if (state) {\n await this.saveStateHandler.setInitialStateOnDemand(state);\n } else {\n await this.autoOpenNodesOnDemand();\n }\n }\n\n // Set this HTML element to this node in the node map.\n private setNodeElement(element: HTMLElement, node: Node) {\n this.nodeMap.set(element, node);\n }\n\n private triggerEvent<Name extends TreeEventName>(\n eventName: Name,\n values?: TreeEvents[Name],\n ): boolean {\n return this.triggerEventProvider(this.htmlElement, eventName, values);\n }\n\n /* Keyboard users reach the tree through the tab stop. The selected node is\n * the tab stop, see NodeElement.select. Without a selected node, the first\n * node is the tab stop, so the tree can always be reached.\n */\n private updateTabStop(): void {\n const tabIndex = this.options.tabIndex;\n const previousTabStop = this.fallbackTabStop;\n const tabStop =\n tabIndex == null || this.hasRenderedSelectedNode()\n ? null\n : this.getFirstTitleSpan();\n\n if (\n previousTabStop &&\n previousTabStop !== tabStop &&\n previousTabStop.getAttribute(\"aria-selected\") !== \"true\"\n ) {\n previousTabStop.setAttribute(\"tabindex\", \"-1\");\n }\n\n if (tabStop && tabIndex != null) {\n tabStop.setAttribute(\"tabindex\", String(tabIndex));\n }\n\n this.fallbackTabStop = tabStop;\n }\n}\n\nexport {\n type MoveInfo,\n type TreeEvent,\n type TreeEventName,\n type TreeEvents,\n} from \"./events\";\nexport { type Node, type NodeData, type NodeId, type Position } from \"./node\";\nexport { type TreeElementOptions } from \"./options\";\nexport { type SavedState } from \"./saveStateHandler\";\nexport { type SelectNodeOptions } from \"./selectNodeHandler\";\n","// Generated by config/generateVersion.mjs. Do not edit.\nconst version = \"0.3.0\";\n\nexport default version;\n"],"names":["DataLoader","constructor","_classNames","classNames","_dataFilter","dataFilter","_loadData","loadData","_treeElement","treeElement","_triggerEvent","triggerEvent","this","abortController","AbortController","deinit","abort","loadFromUrl","url","node","element","classList","add","loading","titleSpan","getTitleSpan","setAttribute","stopLoading","remove","removeAttribute","signal","setSearchParam","Date","now","toString","fetch","value","headers","then","async","response","ok","data","json","catch","error","aborted","querySelector","title","getOffsetTop","getElementPosition","top","rect","getBoundingClientRect","left","x","window","scrollX","y","scrollY","DragElement","_autoEscape","autoEscape","_nodeName","nodeName","_offsetX","offsetX","_offsetY","offsetY","createElement","append","move","pageX","pageY","style","document","dragging","textContent","innerHTML","position","generateHitAreasForGroup","hitAreas","positionsInGroup","bottom","positionCount","Math","min","length","areaHeight","round","areaTop","i","push","DragAndDropHandler","_getNodeElement","getNodeElement","_getNodeElementForNode","getNodeElementForNode","_getScrollLeft","getScrollLeft","_getTree","getTree","_onCanMove","onCanMove","_onCanMoveTo","onCanMoveTo","_onDragMove","onDragMove","_onDragStop","onDragStop","_onIsMoveHandle","onIsMoveHandle","_openFolderDelay","openFolderDelay","_openNode","openNode","_refreshElements","refreshElements","_slide","slide","hoveredArea","isDragging","currentItem","dragElement","openFolderTimer","previousGhost","mouseCapture","positionInfo","target","mustCaptureElement","nodeElement","mouseDrag","area","findHoveredArea","canMoveToArea","isFolder","stopOpenFolderTimer","mustOpenFolderTimer","startOpenFolderTimer","updateDropHint","removeDropHint","originalEvent","mouseStart","refresh","name","moving","mouseStop","moveItem","clear","removeHover","removeHitAreas","currentNode","generateHitAreas","dimensions","getTreeDimensions","right","items","compareFn","low","high","mid","item","undefined","compareResult","binarySearch","tree","treeBottom","hitPositions","previousTop","group","generateHitAreasFromPositions","lastTop","addHitPosition","_handleAfterOpenFolder","handleAfterOpenFolder","_handleClosedFolder","handleClosedFolder","_handleFirstNode","handleFirstNode","_handleNode","handleNode","_handleOpenFolder","handleOpenFolder","isFirstNode","iterate","nextNode","mustIterateInside","is_open","hasChildren","offsetParent","childrenLength","children","keys","child","nextChild","iterateVisibleNodes","height","clientHeight","generateHitPositions","treePosition","clientWidth","movedNode","targetNode","previousParent","parent","doMove","moveNode","moveInfo","folder","setTimeout","clearTimeout","addDropHint","ElementsRenderer","_ariaLabel","ariaLabel","_ariaLabelledBy","ariaLabelledBy","_buttonLeft","buttonLeft","_closedIcon","closedIcon","_dragAndDrop","dragAndDrop","_htmlElement","htmlElement","_isNodeSelected","isNodeSelected","_onCreateLi","onCreateLi","_openedIcon","openedIcon","_rtl","rtl","_setNodeElement","setNodeElement","_showEmptyFolder","showEmptyFolder","_tabIndex","tabIndex","openedIconElement","createButtonElement","closedIconElement","rootUlTemplate","createUlTemplate","groupUlTemplate","nodeTemplate","createNodeTemplate","openedFolderTemplate","createFolderTemplate","closedFolderTemplate","render","fromNode","renderFromNode","renderFromRoot","renderChildren","createDomElements","getLevel","currentLi","newLi","createLi","replaceWith","mustRenderChildren","attachNodeData","li","template","content","nodeType","isRootNode","level","ul","cloneNode","createFolderLi","isSelected","selected","firstChild","childNodes","fillTitleSpan","is_loading","isOpen","liClasses","common","closed","createLiTemplate","join","div","toggler","className","getButtonClasses","iconElement","createTitleSpanTemplate","isEmptyFolder","createNodeLi","classes","titleFolder","titleButtonLeft","titleButtonRight","classString","role","dnd","String","togglerLeft","togglerRight","KeyHandler","_closeNode","closeNode","_getFocusedNode","getFocusedNode","_getSelectedNode","getSelectedNode","_keyboardSupport","keyboardSupport","_selectNode","selectNode","originalSelectNode","addEventListener","handleKeyDown","removeEventListener","moveDown","getNextVisibleNode","moveUp","getPreviousVisibleNode","activate","handleArrowKey","key","moveLeft","moveRight","e","isKeyHandled","focusedNode","selectedNode","getLastChild","handleKeyWithoutSelection","preventDefault","getParent","getPositionInfoFromMouseEvent","getPositionInfoFromTouch","touch","MouseHandler","_element","_getMouseDelay","getMouseDelay","_getNode","getNode","_onClickButton","onClickButton","_onClickTitle","onClickTitle","_onMouseCapture","onMouseCapture","_onMouseDrag","onMouseDrag","_onMouseStart","onMouseStart","_onMouseStop","onMouseStop","_useContextMenu","useContextMenu","handleClick","handleDblclick","mouseDown","passive","touchStart","handleContextmenu","isMouseStarted","mouseDelayTimer","isMouseDelayMet","mouseDownInfo","removeMouseMoveEventListeners","getClickTarget","button","closest","type","clickTarget","stopPropagation","handleMouseDown","handleMouseUp","handleStartMouse","handleMouseMove","cancelable","mouseMove","touchMove","mouseUp","touchEnd","mouseDelay","startMouseDelayTimer","touches","isNodeRecordWithChildren","Array","isArray","Node","id","idMapping","load_on_demand","nodeClass","nodeData","isRoot","setData","Map","addAfter","nodeInfo","createNode","childIndex","getChildIndex","addChildAtPosition","loadChildrenFromData","addBefore","addChild","setParent","index","splice","addNodeToIndex","set","addParent","newParent","originalParent","filter","f","result","indexOf","getData","includeParent","getDataFromNodes","nodes","map","tmpNode","k","includes","Object","prototype","hasOwnProperty","call","lastChild","getNextNode","includeChildren","getNextSibling","nextIndex","getNodeByCallback","callback","getNodeById","nodeId","get","getNodeByName","getNodeByNameMustExist","n","Error","getNodesByProperty","getPreviousNode","previousSibling","getPreviousSibling","previousIndex","initFromData","addChildren","childrenData","addNode","isParentOf","_iterate","loadFromData","removeChildren","childData","doRemoveChild","prepend","removeChild","removeNodeFromIndex","delete","o","getNodeClass","BorderDropHint","scrollLeft","hint","width","max","offsetWidth","border","GhostDropHint","ghost","createGhostElement","moveAfter","moveBefore","moveInsideOpenFolder","moveInside","circle","ghostClass","line","circleSpan","lineSpan","after","before","inside","childElement","NodeElement","_node","mustShowBorderDropHint","deselect","isRendered","blur","select","mustSetFocus","focus","getUl","Boolean","getAnimationDuration","duration","FolderElement","_closedIconElement","_openedIconElement","_renderChildren","super","close","animationSpeed","getButton","replaceChildren","icon","animation","animate","scrollHeight","overflow","Promise","resolve","onfinish","display","slideUp","open","slideDown","RequestUrl","inputUrl","URL","canParse","isAbsoluteUrl","isAbsolute","searchParams","href","slice","LOCALHOST","SaveStateHandler","_addToSelection","addToSelection","_getNodeById","_getSelectedNodes","getSelectedNodes","_onGetStateFromStorage","onGetStateFromStorage","_onSetStateFromStorage","onSetStateFromStorage","_removeFromSelection","removeFromSelection","_saveState","saveState","saveStateOption","getNodeIdToBeSelected","state","getStateFromStorage","selected_node","getState","open_nodes","openNodes","getOpenNodeIds","selectedNodeIds","getSelectedNodeIds","jsonData","loadFromStorage","parseState","JSON","stringify","localStorage","setItem","getKeyName","setInitialState","mustLoadOnDemand","openInitialNodes","resetSelection","selectInitialNodes","setInitialStateOnDemand","nodeIds","newNodesIds","loadAndOpenNode","getItem","parse","Number","isInteger","selectedNodes","selectCount","ScrollParent","_container","container","_refreshHitAreas","refreshHitAreas","checkHorizontalScrolling","newHorizontalScrollDirection","getNewHorizontalScrollDirection","horizontalScrollDirection","horizontalScrollTimeout","scrollHorizontally","bind","checkVerticalScrolling","newVerticalScrollDirection","getNewVerticalScrollDirection","verticalScrollDirection","verticalScrollTimeout","scrollVertically","scrollToY","scrollTop","stopScrolling","scrollBy","behavior","ContainerScrollParent","scrollParentOffset","containerWidth","getScrollParentTop","getScrollParentBottom","scrollParentBottom","containerHeight","scrollParentTop","DocumentScrollParent","documentElement","treeTop","documentScrollHeight","documentScrollWidth","innerWidth","canScrollRight","innerHeight","canScrollDown","getDocumentScrollHeight","getDocumentScrollWidth","scrollWidth","isOverflow","overflowValue","hasOverFlow","getComputedStyle","overflowX","overflowY","ScrollHandler","scrollParent","checkScrolling","getScrollParent","parentElement","getParentWithOverflow","tagName","createScrollParent","SelectNodeHandler","_getOnCanSelectNode","getOnCanSelectNode","_getSelectable","getSelectable","_openParents","openParents","_updateTabStop","updateTabStop","Set","selectedSingleNode","forEach","getSelectedNodesUnder","has","selectSingleNode","optionsParam","selectOptions","mustToggle","onCanSelectNode","canSelect","deselectCurrentNode","deselectedNode","defaults","autoOpen","classPrefix","selectable","startDndDelay","triggerCustomEvent","eventName","values","event","CustomEvent","bubbles","detail","dispatchEvent","defaultPrevented","dataLoader","dndHandler","fallbackTabStop","isInitialized","keyHandler","mouseHandler","nodeMap","options","renderer","saveStateHandler","scrollHandler","selectNodeHandler","triggerEventProvider","overrideTriggerEventProvider","inputOptions","matchMedia","matches","dataUrl","dataset","dataRtl","getRtlOptionFromHTMLElement","getDefaultClosedIcon","setDefaultOptions","commonClassName","treeClassName","createClassNames","WeakMap","toggle","initData","addNodeAfter","existingNode","newNode","addNodeBefore","addParentNode","appendNode","parentNode","createFolderElement","liElement","getVersion","deselectNodes","loadSubtree","initTree","treeData","loadDataFromUrl","requestUrl","createRequestUrl","mustSlide","doOpenNode","openedNode","slideOption","folderElement","loadFolderOnDemand","prependNode","removeNode","scrollToNode","setOption","option","setState","toJson","updateNode","idIsChanged","autoOpenNodesOnDemand","maxLevel","getAutoOpenMaxLevel","all","createNodeElement","selectedNodeId","selectedNodesUnderParent","parseInt","getFirstTitleSpan","firstElement","activeElement","hasRenderedSelectedNode","some","doInit","isFocusOnTree","isSelectedNodeInSubtree","subtree","mustSelect","selectCurrentNode","isRestored","restoreState","autoOpenNodes","previousTabStop","tabStop","getAttribute"],"mappings":"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"}