tree-element 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +221 -0
  3. package/lib/animation.d.ts +5 -0
  4. package/lib/animation.d.ts.map +1 -0
  5. package/lib/animation.js +39 -0
  6. package/lib/animation.js.map +1 -0
  7. package/lib/classNames.d.ts +34 -0
  8. package/lib/classNames.d.ts.map +1 -0
  9. package/lib/classNames.js +39 -0
  10. package/lib/classNames.js.map +1 -0
  11. package/lib/dataLoader.d.ts +25 -0
  12. package/lib/dataLoader.d.ts.map +1 -0
  13. package/lib/dataLoader.js +69 -0
  14. package/lib/dataLoader.js.map +1 -0
  15. package/lib/dragAndDropHandler/binarySearch.d.ts +3 -0
  16. package/lib/dragAndDropHandler/binarySearch.d.ts.map +1 -0
  17. package/lib/dragAndDropHandler/binarySearch.js +23 -0
  18. package/lib/dragAndDropHandler/binarySearch.js.map +1 -0
  19. package/lib/dragAndDropHandler/dragElement.d.ts +20 -0
  20. package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -0
  21. package/lib/dragAndDropHandler/dragElement.js +39 -0
  22. package/lib/dragAndDropHandler/dragElement.js.map +1 -0
  23. package/lib/dragAndDropHandler/generateHitAreas.d.ts +13 -0
  24. package/lib/dragAndDropHandler/generateHitAreas.d.ts.map +1 -0
  25. package/lib/dragAndDropHandler/generateHitAreas.js +130 -0
  26. package/lib/dragAndDropHandler/generateHitAreas.js.map +1 -0
  27. package/lib/dragAndDropHandler/index.d.ts +76 -0
  28. package/lib/dragAndDropHandler/index.d.ts.map +1 -0
  29. package/lib/dragAndDropHandler/index.js +311 -0
  30. package/lib/dragAndDropHandler/index.js.map +1 -0
  31. package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts +11 -0
  32. package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -0
  33. package/lib/dragAndDropHandler/iterateVisibleNodes.js +54 -0
  34. package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -0
  35. package/lib/dragAndDropHandler/types.d.ts +11 -0
  36. package/lib/dragAndDropHandler/types.d.ts.map +1 -0
  37. package/lib/elementsRenderer.d.ts +53 -0
  38. package/lib/elementsRenderer.d.ts.map +1 -0
  39. package/lib/elementsRenderer.js +251 -0
  40. package/lib/elementsRenderer.js.map +1 -0
  41. package/lib/events.d.ts +224 -0
  42. package/lib/events.d.ts.map +1 -0
  43. package/lib/index.d.ts +367 -0
  44. package/lib/index.d.ts.map +1 -0
  45. package/lib/index.js +1098 -0
  46. package/lib/index.js.map +1 -0
  47. package/lib/keyHandler.d.ts +29 -0
  48. package/lib/keyHandler.d.ts.map +1 -0
  49. package/lib/keyHandler.js +107 -0
  50. package/lib/keyHandler.js.map +1 -0
  51. package/lib/methodTypes.d.ts +21 -0
  52. package/lib/methodTypes.d.ts.map +1 -0
  53. package/lib/mouseHandler.d.ts +60 -0
  54. package/lib/mouseHandler.d.ts.map +1 -0
  55. package/lib/mouseHandler.js +283 -0
  56. package/lib/mouseHandler.js.map +1 -0
  57. package/lib/mouseUtils.d.ts +9 -0
  58. package/lib/mouseUtils.d.ts.map +1 -0
  59. package/lib/mouseUtils.js +15 -0
  60. package/lib/mouseUtils.js.map +1 -0
  61. package/lib/node.d.ts +320 -0
  62. package/lib/node.d.ts.map +1 -0
  63. package/lib/node.js +737 -0
  64. package/lib/node.js.map +1 -0
  65. package/lib/nodeElement/borderDropHint.d.ts +9 -0
  66. package/lib/nodeElement/borderDropHint.d.ts.map +1 -0
  67. package/lib/nodeElement/borderDropHint.js +24 -0
  68. package/lib/nodeElement/borderDropHint.js.map +1 -0
  69. package/lib/nodeElement/folderElement.d.ts +22 -0
  70. package/lib/nodeElement/folderElement.d.ts.map +1 -0
  71. package/lib/nodeElement/folderElement.js +100 -0
  72. package/lib/nodeElement/folderElement.js.map +1 -0
  73. package/lib/nodeElement/ghostDropHint.d.ts +18 -0
  74. package/lib/nodeElement/ghostDropHint.d.ts.map +1 -0
  75. package/lib/nodeElement/ghostDropHint.js +67 -0
  76. package/lib/nodeElement/ghostDropHint.js.map +1 -0
  77. package/lib/nodeElement/index.d.ts +28 -0
  78. package/lib/nodeElement/index.d.ts.map +1 -0
  79. package/lib/nodeElement/index.js +66 -0
  80. package/lib/nodeElement/index.js.map +1 -0
  81. package/lib/nodeUtils.d.ts +7 -0
  82. package/lib/nodeUtils.d.ts.map +1 -0
  83. package/lib/nodeUtils.js +4 -0
  84. package/lib/nodeUtils.js.map +1 -0
  85. package/lib/options.d.ts +310 -0
  86. package/lib/options.d.ts.map +1 -0
  87. package/lib/package.json +3 -0
  88. package/lib/positionUtils.d.ts +8 -0
  89. package/lib/positionUtils.d.ts.map +1 -0
  90. package/lib/positionUtils.js +14 -0
  91. package/lib/positionUtils.js.map +1 -0
  92. package/lib/requestUrl.d.ts +9 -0
  93. package/lib/requestUrl.d.ts.map +1 -0
  94. package/lib/requestUrl.js +37 -0
  95. package/lib/requestUrl.js.map +1 -0
  96. package/lib/saveStateHandler.d.ts +46 -0
  97. package/lib/saveStateHandler.d.ts.map +1 -0
  98. package/lib/saveStateHandler.js +204 -0
  99. package/lib/saveStateHandler.js.map +1 -0
  100. package/lib/scrollHandler/containerScrollParent.d.ts +12 -0
  101. package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -0
  102. package/lib/scrollHandler/containerScrollParent.js +49 -0
  103. package/lib/scrollHandler/containerScrollParent.js.map +1 -0
  104. package/lib/scrollHandler/createScrollParent.d.ts +4 -0
  105. package/lib/scrollHandler/createScrollParent.d.ts.map +1 -0
  106. package/lib/scrollHandler/createScrollParent.js +38 -0
  107. package/lib/scrollHandler/createScrollParent.js.map +1 -0
  108. package/lib/scrollHandler/documentScrollParent.d.ts +22 -0
  109. package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -0
  110. package/lib/scrollHandler/documentScrollParent.js +71 -0
  111. package/lib/scrollHandler/documentScrollParent.js.map +1 -0
  112. package/lib/scrollHandler/scrollParent.d.ts +26 -0
  113. package/lib/scrollHandler/scrollParent.d.ts.map +1 -0
  114. package/lib/scrollHandler/scrollParent.js +79 -0
  115. package/lib/scrollHandler/scrollParent.js.map +1 -0
  116. package/lib/scrollHandler.d.ts +20 -0
  117. package/lib/scrollHandler.d.ts.map +1 -0
  118. package/lib/scrollHandler.js +41 -0
  119. package/lib/scrollHandler.js.map +1 -0
  120. package/lib/selectNodeHandler.d.ts +38 -0
  121. package/lib/selectNodeHandler.d.ts.map +1 -0
  122. package/lib/selectNodeHandler.js +166 -0
  123. package/lib/selectNodeHandler.js.map +1 -0
  124. package/lib/setDefaultOptions.d.ts +4 -0
  125. package/lib/setDefaultOptions.d.ts.map +1 -0
  126. package/lib/setDefaultOptions.js +86 -0
  127. package/lib/setDefaultOptions.js.map +1 -0
  128. package/lib/triggerCustomEvent.d.ts +3 -0
  129. package/lib/triggerCustomEvent.d.ts.map +1 -0
  130. package/lib/triggerCustomEvent.js +13 -0
  131. package/lib/triggerCustomEvent.js.map +1 -0
  132. package/lib/util.d.ts +3 -0
  133. package/lib/util.d.ts.map +1 -0
  134. package/lib/util.js +5 -0
  135. package/lib/util.js.map +1 -0
  136. package/lib/version.d.ts +3 -0
  137. package/lib/version.d.ts.map +1 -0
  138. package/lib/version.js +5 -0
  139. package/lib/version.js.map +1 -0
  140. package/package.json +110 -0
  141. package/src/animation.ts +48 -0
  142. package/src/classNames.ts +70 -0
  143. package/src/dataLoader.ts +92 -0
  144. package/src/dragAndDropHandler/binarySearch.ts +27 -0
  145. package/src/dragAndDropHandler/dragElement.ts +62 -0
  146. package/src/dragAndDropHandler/generateHitAreas.ts +195 -0
  147. package/src/dragAndDropHandler/index.ts +442 -0
  148. package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
  149. package/src/dragAndDropHandler/types.ts +12 -0
  150. package/src/elementsRenderer.ts +367 -0
  151. package/src/events.ts +237 -0
  152. package/src/header.txt +16 -0
  153. package/src/index.ts +1290 -0
  154. package/src/keyHandler.ts +139 -0
  155. package/src/methodTypes.ts +44 -0
  156. package/src/mouseHandler.ts +391 -0
  157. package/src/mouseUtils.ts +23 -0
  158. package/src/node.ts +831 -0
  159. package/src/nodeElement/borderDropHint.ts +37 -0
  160. package/src/nodeElement/folderElement.ts +140 -0
  161. package/src/nodeElement/ghostDropHint.ts +84 -0
  162. package/src/nodeElement/index.ts +103 -0
  163. package/src/nodeUtils.ts +12 -0
  164. package/src/options.ts +325 -0
  165. package/src/positionUtils.ts +18 -0
  166. package/src/requestUrl.ts +41 -0
  167. package/src/saveStateHandler.ts +279 -0
  168. package/src/scrollHandler/containerScrollParent.ts +71 -0
  169. package/src/scrollHandler/createScrollParent.ts +51 -0
  170. package/src/scrollHandler/documentScrollParent.ts +104 -0
  171. package/src/scrollHandler/scrollParent.ts +117 -0
  172. package/src/scrollHandler.ts +55 -0
  173. package/src/selectNodeHandler.ts +192 -0
  174. package/src/setDefaultOptions.ts +79 -0
  175. package/src/triggerCustomEvent.ts +14 -0
  176. package/src/util.ts +5 -0
  177. package/src/version.ts +4 -0
  178. package/tree_element.css +195 -0
  179. package/tree_element.debug.js +4153 -0
  180. package/tree_element.debug.js.map +1 -0
  181. package/tree_element.js +21 -0
  182. package/tree_element.js.map +1 -0
@@ -0,0 +1,139 @@
1
+ import type {
2
+ CloseNode,
3
+ GetSelectedNode,
4
+ IsFocusOnTree,
5
+ OpenNode,
6
+ SelectNode,
7
+ } from "./methodTypes";
8
+ import type { Node } from "./node";
9
+
10
+ interface KeyHandlerParams {
11
+ closeNode: CloseNode;
12
+ getSelectedNode: GetSelectedNode;
13
+ isFocusOnTree: IsFocusOnTree;
14
+ keyboardSupport: boolean;
15
+ openNode: OpenNode;
16
+ selectNode: SelectNode;
17
+ }
18
+
19
+ export default class KeyHandler {
20
+ private closeNode: CloseNode;
21
+ private getSelectedNode: GetSelectedNode;
22
+
23
+ private isFocusOnTree: IsFocusOnTree;
24
+
25
+ private keyboardSupport: boolean;
26
+ private openNode: OpenNode;
27
+ private originalSelectNode: SelectNode;
28
+ constructor({
29
+ closeNode,
30
+ getSelectedNode,
31
+ isFocusOnTree,
32
+ keyboardSupport,
33
+ openNode,
34
+ selectNode,
35
+ }: KeyHandlerParams) {
36
+ this.closeNode = closeNode;
37
+ this.getSelectedNode = getSelectedNode;
38
+ this.isFocusOnTree = isFocusOnTree;
39
+ this.keyboardSupport = keyboardSupport;
40
+ this.openNode = openNode;
41
+ this.originalSelectNode = selectNode;
42
+
43
+ if (keyboardSupport) {
44
+ document.addEventListener("keydown", this.handleKeyDown);
45
+ }
46
+ }
47
+
48
+ public deinit(): void {
49
+ if (this.keyboardSupport) {
50
+ document.removeEventListener("keydown", this.handleKeyDown);
51
+ }
52
+ }
53
+
54
+ public moveDown(selectedNode: Node): boolean {
55
+ return this.selectNode(selectedNode.getNextVisibleNode());
56
+ }
57
+
58
+ public moveUp(selectedNode: Node): boolean {
59
+ return this.selectNode(selectedNode.getPreviousVisibleNode());
60
+ }
61
+
62
+ private canHandleKeyboard(): boolean {
63
+ return this.keyboardSupport && this.isFocusOnTree();
64
+ }
65
+
66
+ private handleKeyDown = (e: KeyboardEvent): void => {
67
+ if (!this.canHandleKeyboard()) {
68
+ return;
69
+ }
70
+
71
+ let isKeyHandled = false;
72
+
73
+ const selectedNode = this.getSelectedNode();
74
+ if (selectedNode) {
75
+ switch (e.key) {
76
+ case "ArrowDown":
77
+ isKeyHandled = this.moveDown(selectedNode);
78
+ break;
79
+
80
+ case "ArrowLeft":
81
+ isKeyHandled = this.moveLeft(selectedNode);
82
+ break;
83
+
84
+ case "ArrowRight":
85
+ isKeyHandled = this.moveRight(selectedNode);
86
+ break;
87
+
88
+ case "ArrowUp":
89
+ isKeyHandled = this.moveUp(selectedNode);
90
+ break;
91
+ }
92
+ }
93
+
94
+ if (isKeyHandled) {
95
+ e.preventDefault();
96
+ }
97
+ };
98
+
99
+ private moveLeft(selectedNode: Node): boolean {
100
+ if (selectedNode.isFolder() && selectedNode.is_open) {
101
+ // Left on an open node closes the node
102
+ this.closeNode(selectedNode);
103
+ return true;
104
+ } else {
105
+ // Left on a closed or end node moves focus to the node's parent
106
+ return this.selectNode(selectedNode.getParent());
107
+ }
108
+ }
109
+
110
+ private moveRight(selectedNode: Node): boolean {
111
+ if (!selectedNode.isFolder()) {
112
+ return false;
113
+ } else {
114
+ // folder node
115
+ if (selectedNode.is_open) {
116
+ // Right moves to the first child of an open node
117
+ return this.selectNode(selectedNode.getNextVisibleNode());
118
+ } else {
119
+ // Right expands a closed node
120
+ void this.openNode(selectedNode);
121
+ return true;
122
+ }
123
+ }
124
+ }
125
+
126
+ /* Select the node.
127
+ * Don't do anything if the node is null.
128
+ * Result: a different node was selected.
129
+ */
130
+ private selectNode(node: Node | null): boolean {
131
+ if (!node) {
132
+ return false;
133
+ } else {
134
+ this.originalSelectNode(node);
135
+
136
+ return true;
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,44 @@
1
+ import type { TreeEventName, TreeEvents } from "./events";
2
+ import type { Node, NodeData, NodeId } from "./node";
3
+ import type NodeElement from "./nodeElement";
4
+
5
+ export type AddToSelection = (node: Node) => void;
6
+
7
+ export type CloseNode = (node: Node) => void;
8
+
9
+ export type GetNodeById = (nodeId: NodeId) => Node | null;
10
+
11
+ export type GetNodeElementForNode = (node: Node) => NodeElement;
12
+
13
+ export type GetScrollLeft = () => number;
14
+
15
+ export type GetSelectedNode = () => false | Node;
16
+
17
+ export type GetSelectedNodes = () => Node[];
18
+
19
+ export type GetTree = () => Node | null;
20
+
21
+ export type IsFocusOnTree = () => boolean;
22
+
23
+ export type IsNodeSelected = (node: Node) => boolean;
24
+
25
+ export type LoadData = (data: NodeData[], parentNode?: Node) => void;
26
+
27
+ export type OpenNode = (
28
+ node: Node,
29
+ slide?: boolean,
30
+ ) => Promise<void>;
31
+
32
+ export type OpenParents = (node: Node) => void;
33
+
34
+ export type RefreshElements = (fromNode: Node | null) => void;
35
+
36
+ export type RemoveFromSelection = (node: Node) => void;
37
+
38
+ export type SelectNode = (node: Node) => void;
39
+
40
+ // Trigger an event. Return if the event is processed (true) or cancelled (false).
41
+ export type TriggerEvent = <Name extends TreeEventName>(
42
+ eventName: Name,
43
+ values?: TreeEvents[Name],
44
+ ) => boolean;
@@ -0,0 +1,391 @@
1
+ import type { ClassNames } from "./classNames";
2
+ import type { TriggerEvent } from "./methodTypes";
3
+ import type { PositionInfo } from "./mouseUtils";
4
+ import type { Node } from "./node";
5
+
6
+ import {
7
+ getPositionInfoFromMouseEvent,
8
+ getPositionInfoFromTouch,
9
+ } from "./mouseUtils";
10
+
11
+ export type GetMouseDelay = () => number;
12
+ export type GetNode = (element: HTMLElement) => Node | null;
13
+ export type MouseCapture = (positionInfo: PositionInfo) => boolean | null;
14
+ export type MouseStart = (positionInfo: PositionInfo) => boolean;
15
+
16
+ interface ClickTarget {
17
+ node: Node;
18
+ type: "button" | "label";
19
+ }
20
+
21
+ interface MouseHandlerParams {
22
+ classNames: ClassNames;
23
+ element: HTMLElement;
24
+ getMouseDelay: () => number;
25
+ getNode: GetNode;
26
+ onClickButton: (node: Node) => void;
27
+ onClickTitle: (node: Node) => void;
28
+ onMouseCapture: MouseCapture;
29
+ onMouseDrag: (positionInfo: PositionInfo) => void;
30
+ onMouseStart: MouseStart;
31
+ onMouseStop: (positionInfo: PositionInfo) => void;
32
+ triggerEvent: TriggerEvent;
33
+ useContextMenu: boolean;
34
+ }
35
+
36
+ class MouseHandler {
37
+ private classNames: ClassNames;
38
+ private element: HTMLElement;
39
+ private getMouseDelay: GetMouseDelay;
40
+ private getNode: GetNode;
41
+
42
+ private isMouseDelayMet: boolean;
43
+
44
+ private isMouseStarted: boolean;
45
+
46
+ private mouseDelayTimer: null | number;
47
+
48
+ private mouseDownInfo: null | PositionInfo;
49
+ private onClickButton: (node: Node) => void;
50
+ private onClickTitle: (node: Node) => void;
51
+
52
+ private onMouseCapture: MouseCapture;
53
+
54
+ private onMouseDrag: (positionInfo: PositionInfo) => void;
55
+
56
+ private onMouseStart: MouseStart;
57
+
58
+ private onMouseStop: (positionInfo: PositionInfo) => void;
59
+
60
+ private triggerEvent: TriggerEvent;
61
+ private useContextMenu: boolean;
62
+ constructor({
63
+ classNames,
64
+ element,
65
+ getMouseDelay,
66
+ getNode,
67
+ onClickButton,
68
+ onClickTitle,
69
+ onMouseCapture,
70
+ onMouseDrag,
71
+ onMouseStart,
72
+ onMouseStop,
73
+ triggerEvent,
74
+ useContextMenu,
75
+ }: MouseHandlerParams) {
76
+ this.classNames = classNames;
77
+ this.element = element;
78
+ this.getMouseDelay = getMouseDelay;
79
+ this.getNode = getNode;
80
+ this.onClickButton = onClickButton;
81
+ this.onClickTitle = onClickTitle;
82
+ this.onMouseCapture = onMouseCapture;
83
+ this.onMouseDrag = onMouseDrag;
84
+ this.onMouseStart = onMouseStart;
85
+ this.onMouseStop = onMouseStop;
86
+ this.triggerEvent = triggerEvent;
87
+ this.useContextMenu = useContextMenu;
88
+
89
+ element.addEventListener("click", this.handleClick);
90
+ element.addEventListener("dblclick", this.handleDblclick);
91
+ element.addEventListener("mousedown", this.mouseDown, {
92
+ passive: false,
93
+ });
94
+ element.addEventListener("touchstart", this.touchStart, {
95
+ passive: false,
96
+ });
97
+
98
+ if (useContextMenu) {
99
+ element.addEventListener("contextmenu", this.handleContextmenu);
100
+ }
101
+
102
+ this.isMouseStarted = false;
103
+ this.mouseDelayTimer = null;
104
+ this.isMouseDelayMet = false;
105
+ this.mouseDownInfo = null;
106
+ }
107
+ public deinit(): void {
108
+ this.element.removeEventListener("click", this.handleClick);
109
+ this.element.removeEventListener("dblclick", this.handleDblclick);
110
+
111
+ if (this.useContextMenu) {
112
+ this.element.removeEventListener(
113
+ "contextmenu",
114
+ this.handleContextmenu,
115
+ );
116
+ }
117
+
118
+ this.element.removeEventListener("mousedown", this.mouseDown);
119
+ this.element.removeEventListener("touchstart", this.touchStart);
120
+ this.removeMouseMoveEventListeners();
121
+ }
122
+ private getClickTarget(element: HTMLElement): ClickTarget | null {
123
+ const button = element.closest<HTMLElement>(
124
+ `.${this.classNames.toggler}`,
125
+ );
126
+
127
+ if (button) {
128
+ const node = this.getNode(button);
129
+
130
+ if (node) {
131
+ return {
132
+ node,
133
+ type: "button",
134
+ };
135
+ }
136
+ } else {
137
+ const treeElement = element.closest<HTMLElement>(
138
+ `.${this.classNames.element}`,
139
+ );
140
+
141
+ if (treeElement) {
142
+ const node = this.getNode(treeElement);
143
+ if (node) {
144
+ return {
145
+ node,
146
+ type: "label",
147
+ };
148
+ }
149
+ }
150
+ }
151
+
152
+ return null;
153
+ }
154
+ private handleClick = (e: MouseEvent): void => {
155
+ if (!e.target) {
156
+ return;
157
+ }
158
+
159
+ const clickTarget = this.getClickTarget(e.target as HTMLElement);
160
+
161
+ if (!clickTarget) {
162
+ return;
163
+ }
164
+
165
+ switch (clickTarget.type) {
166
+ case "button":
167
+ this.onClickButton(clickTarget.node);
168
+
169
+ e.preventDefault();
170
+ e.stopPropagation();
171
+ break;
172
+
173
+ case "label": {
174
+ if (this.triggerEvent("tree.click", {
175
+ node: clickTarget.node,
176
+ originalEvent: e,
177
+ })) {
178
+ this.onClickTitle(clickTarget.node);
179
+ }
180
+ break;
181
+ }
182
+ }
183
+ };
184
+
185
+ private handleContextmenu = (e: MouseEvent) => {
186
+ if (!e.target) {
187
+ return;
188
+ }
189
+
190
+ const div = (e.target as HTMLElement).closest<HTMLElement>(
191
+ `ul.${this.classNames.tree} .${this.classNames.element}`,
192
+ );
193
+
194
+ if (div) {
195
+ const node = this.getNode(div);
196
+ if (node) {
197
+ e.preventDefault();
198
+ e.stopPropagation();
199
+
200
+ this.triggerEvent("tree.contextmenu", {
201
+ node,
202
+ originalEvent: e,
203
+ });
204
+ return false;
205
+ }
206
+ }
207
+
208
+ return null;
209
+ };
210
+
211
+ private handleDblclick = (e: MouseEvent): void => {
212
+ if (!e.target) {
213
+ return;
214
+ }
215
+
216
+ const clickTarget = this.getClickTarget(e.target as HTMLElement);
217
+
218
+ if (clickTarget?.type === "label") {
219
+ this.triggerEvent("tree.dblclick", {
220
+ node: clickTarget.node,
221
+ originalEvent: e,
222
+ });
223
+ }
224
+ };
225
+
226
+ private handleMouseDown(positionInfo: PositionInfo): boolean {
227
+ // We may have missed mouseup (out of window)
228
+ if (this.isMouseStarted) {
229
+ this.handleMouseUp(positionInfo);
230
+ }
231
+
232
+ this.mouseDownInfo = positionInfo;
233
+
234
+ if (!this.onMouseCapture(positionInfo)) {
235
+ return false;
236
+ }
237
+
238
+ this.handleStartMouse();
239
+
240
+ return true;
241
+ }
242
+
243
+ private handleMouseMove(
244
+ e: MouseEvent | TouchEvent,
245
+ positionInfo: PositionInfo,
246
+ ): void {
247
+ if (this.isMouseStarted) {
248
+ this.onMouseDrag(positionInfo);
249
+
250
+ if (e.cancelable) {
251
+ e.preventDefault();
252
+ }
253
+ return;
254
+ }
255
+
256
+ if (!this.isMouseDelayMet) {
257
+ return;
258
+ }
259
+
260
+ if (this.mouseDownInfo) {
261
+ this.isMouseStarted = this.onMouseStart(this.mouseDownInfo);
262
+ }
263
+
264
+ if (this.isMouseStarted) {
265
+ this.onMouseDrag(positionInfo);
266
+
267
+ if (e.cancelable) {
268
+ e.preventDefault();
269
+ }
270
+ } else {
271
+ this.handleMouseUp(positionInfo);
272
+ }
273
+ }
274
+ private handleMouseUp(positionInfo: PositionInfo): void {
275
+ this.removeMouseMoveEventListeners();
276
+ this.isMouseDelayMet = false;
277
+ this.mouseDownInfo = null;
278
+
279
+ if (this.isMouseStarted) {
280
+ this.isMouseStarted = false;
281
+ this.onMouseStop(positionInfo);
282
+ }
283
+ }
284
+
285
+ private handleStartMouse(): void {
286
+ document.addEventListener("mousemove", this.mouseMove, {
287
+ passive: false,
288
+ });
289
+ document.addEventListener("touchmove", this.touchMove, {
290
+ passive: false,
291
+ });
292
+ document.addEventListener("mouseup", this.mouseUp, { passive: false });
293
+ document.addEventListener("touchend", this.touchEnd, {
294
+ passive: false,
295
+ });
296
+
297
+ const mouseDelay = this.getMouseDelay();
298
+
299
+ if (mouseDelay) {
300
+ this.startMouseDelayTimer(mouseDelay);
301
+ } else {
302
+ this.isMouseDelayMet = true;
303
+ }
304
+ }
305
+
306
+ private mouseDown = (e: MouseEvent): void => {
307
+ // Left mouse button?
308
+ if (e.button !== 0) {
309
+ return;
310
+ }
311
+
312
+ const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));
313
+
314
+ if (result && e.cancelable) {
315
+ e.preventDefault();
316
+ }
317
+ };
318
+
319
+ private mouseMove = (e: MouseEvent): void => {
320
+ this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));
321
+ };
322
+
323
+ private mouseUp = (e: MouseEvent): void => {
324
+ this.handleMouseUp(getPositionInfoFromMouseEvent(e));
325
+ };
326
+
327
+ private removeMouseMoveEventListeners() {
328
+ document.removeEventListener("mousemove", this.mouseMove);
329
+ document.removeEventListener("touchmove", this.touchMove);
330
+ document.removeEventListener("mouseup", this.mouseUp);
331
+ document.removeEventListener("touchend", this.touchEnd);
332
+ }
333
+
334
+ private startMouseDelayTimer(mouseDelay: number): void {
335
+ if (this.mouseDelayTimer) {
336
+ clearTimeout(this.mouseDelayTimer);
337
+ }
338
+
339
+ this.mouseDelayTimer = window.setTimeout(() => {
340
+ if (this.mouseDownInfo) {
341
+ this.isMouseDelayMet = true;
342
+ }
343
+ }, mouseDelay);
344
+
345
+ this.isMouseDelayMet = false;
346
+ }
347
+
348
+ private touchEnd = (e: TouchEvent): void => {
349
+ if (e.touches.length > 1) {
350
+ return;
351
+ }
352
+
353
+ const touch = e.touches[0];
354
+
355
+ if (!touch) {
356
+ return;
357
+ }
358
+
359
+ this.handleMouseUp(getPositionInfoFromTouch(touch, e));
360
+ };
361
+
362
+ private touchMove = (e: TouchEvent): void => {
363
+ if (e.touches.length > 1) {
364
+ return;
365
+ }
366
+
367
+ const touch = e.touches[0];
368
+
369
+ if (!touch) {
370
+ return;
371
+ }
372
+
373
+ this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
374
+ };
375
+
376
+ private touchStart = (e: TouchEvent): void => {
377
+ if (e.touches.length > 1) {
378
+ return;
379
+ }
380
+
381
+ const touch = e.touches[0];
382
+
383
+ if (!touch) {
384
+ return;
385
+ }
386
+
387
+ this.handleMouseDown(getPositionInfoFromTouch(touch, e));
388
+ };
389
+ }
390
+
391
+ export default MouseHandler;
@@ -0,0 +1,23 @@
1
+ export interface PositionInfo {
2
+ originalEvent: Event;
3
+ pageX: number;
4
+ pageY: number;
5
+ target: HTMLElement;
6
+ }
7
+
8
+ export const getPositionInfoFromMouseEvent = (e: MouseEvent): PositionInfo => ({
9
+ originalEvent: e,
10
+ pageX: e.pageX,
11
+ pageY: e.pageY,
12
+ target: e.target as HTMLElement,
13
+ });
14
+
15
+ export const getPositionInfoFromTouch = (
16
+ touch: Touch,
17
+ e: TouchEvent,
18
+ ): PositionInfo => ({
19
+ originalEvent: e,
20
+ pageX: touch.pageX,
21
+ pageY: touch.pageY,
22
+ target: touch.target as HTMLElement,
23
+ });