jqtree 1.7.5 → 1.8.1

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 (119) hide show
  1. package/.eslintrc +13 -3
  2. package/.github/workflows/ci.yml +6 -6
  3. package/.github/workflows/codeql-analysis.yml +4 -4
  4. package/.github/workflows/size.yml +3 -3
  5. package/.github/workflows/static.yml +1 -1
  6. package/bower.json +1 -1
  7. package/config/babel.config.json +1 -1
  8. package/config/jest.config.js +4 -0
  9. package/config/jest.polyfills.js +14 -0
  10. package/config/production +2 -0
  11. package/devserver/devserver_scroll.js +8 -0
  12. package/devserver/test_index.html +9 -0
  13. package/devserver/test_scroll.html +28 -0
  14. package/devserver/test_scroll_container.html +39 -0
  15. package/docs/.ruby-version +1 -1
  16. package/docs/_config.yml +1 -1
  17. package/docs/_entries/general/changelog.md +11 -0
  18. package/docs/_entries/multiple_selection/get-selected-nodes.md +1 -1
  19. package/docs/_entries/node/getnextnode.md +3 -6
  20. package/docs/_entries/node/getnextsibling.md +1 -1
  21. package/docs/_entries/node/getnextvisiblenode.md +8 -5
  22. package/docs/_entries/node/getpreviousnode.md +12 -0
  23. package/docs/_entries/node/getprevioussibling.md +1 -1
  24. package/docs/_entries/node/getpreviousvisiblenode.md +6 -5
  25. package/package.json +35 -29
  26. package/src/dataLoader.ts +57 -34
  27. package/src/dragAndDropHandler/dragElement.ts +54 -0
  28. package/src/dragAndDropHandler/generateHitAreas.ts +176 -0
  29. package/src/dragAndDropHandler/index.ts +454 -0
  30. package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
  31. package/src/dragAndDropHandler/types.ts +13 -0
  32. package/src/elementsRenderer.ts +75 -40
  33. package/src/jqtreeMethodTypes.ts +40 -0
  34. package/src/jqtreeOptions.ts +43 -25
  35. package/src/keyHandler.ts +59 -30
  36. package/src/mouseHandler.ts +385 -0
  37. package/src/mouseUtils.ts +23 -0
  38. package/src/node.ts +1 -29
  39. package/src/nodeElement/borderDropHint.ts +32 -0
  40. package/src/nodeElement/folderElement.ts +133 -0
  41. package/src/nodeElement/ghostDropHint.ts +69 -0
  42. package/src/nodeElement/index.ts +102 -0
  43. package/src/playwright/coverage.ts +4 -7
  44. package/src/playwright/playwright.test.ts +150 -53
  45. package/src/playwright/testUtils.ts +28 -5
  46. package/src/position.ts +28 -0
  47. package/src/saveStateHandler.ts +75 -26
  48. package/src/scrollHandler/containerScrollParent.ts +13 -23
  49. package/src/scrollHandler/createScrollParent.ts +22 -22
  50. package/src/scrollHandler/documentScrollParent.ts +16 -13
  51. package/src/scrollHandler.ts +13 -15
  52. package/src/selectNodeHandler.ts +10 -16
  53. package/src/test/jqTree/events.test.ts +97 -30
  54. package/src/test/jqTree/keyboard.test.ts +18 -23
  55. package/src/test/jqTree/loadOnDemand.test.ts +22 -15
  56. package/src/test/jqTree/methods.test.ts +40 -14
  57. package/src/test/jqTree/mouse.test.ts +82 -0
  58. package/src/test/jqTree/options.test.ts +24 -12
  59. package/src/test/node.test.ts +3 -2
  60. package/src/test/{nodeUtil.test.ts → position.test.ts} +1 -1
  61. package/src/tree.jquery.ts +314 -208
  62. package/src/util.ts +12 -0
  63. package/src/version.ts +1 -1
  64. package/tree.jquery.debug.js +2594 -3419
  65. package/tree.jquery.debug.js.map +1 -1
  66. package/tree.jquery.js +3 -3
  67. package/tree.jquery.js.map +1 -1
  68. package/tsconfig.json +5 -3
  69. package/docs/_entries/functions/get-selected-nodes.md +0 -10
  70. package/lib/dataLoader.js +0 -123
  71. package/lib/dragAndDropHandler.js +0 -588
  72. package/lib/elementsRenderer.js +0 -267
  73. package/lib/jqtreeOptions.js +0 -1
  74. package/lib/keyHandler.js +0 -111
  75. package/lib/mouse.widget.js +0 -255
  76. package/lib/node.js +0 -708
  77. package/lib/nodeElement.js +0 -274
  78. package/lib/nodeUtils.js +0 -10
  79. package/lib/playwright/coverage.js +0 -99
  80. package/lib/playwright/playwright.test.js +0 -606
  81. package/lib/playwright/testUtils.js +0 -210
  82. package/lib/saveStateHandler.js +0 -277
  83. package/lib/scrollHandler/containerScrollParent.js +0 -160
  84. package/lib/scrollHandler/createScrollParent.js +0 -57
  85. package/lib/scrollHandler/documentScrollParent.js +0 -169
  86. package/lib/scrollHandler/scrollParent.js +0 -58
  87. package/lib/scrollHandler/types.js +0 -1
  88. package/lib/scrollHandler.js +0 -71
  89. package/lib/selectNodeHandler.js +0 -128
  90. package/lib/simple.widget.js +0 -158
  91. package/lib/test/global.d.js +0 -3
  92. package/lib/test/jqTree/accessibility.test.js +0 -37
  93. package/lib/test/jqTree/create.test.js +0 -48
  94. package/lib/test/jqTree/events.test.js +0 -210
  95. package/lib/test/jqTree/keyboard.test.js +0 -225
  96. package/lib/test/jqTree/loadOnDemand.test.js +0 -218
  97. package/lib/test/jqTree/methods.test.js +0 -1348
  98. package/lib/test/jqTree/options.test.js +0 -548
  99. package/lib/test/jqTree/scrollHandler/containerScrollParent.test.js +0 -94
  100. package/lib/test/node.test.js +0 -1202
  101. package/lib/test/nodeUtil.test.js +0 -27
  102. package/lib/test/nodeUtils.test.js +0 -20
  103. package/lib/test/support/exampleData.js +0 -35
  104. package/lib/test/support/jqTreeMatchers.js +0 -70
  105. package/lib/test/support/matchers.d.js +0 -1
  106. package/lib/test/support/setupTests.js +0 -7
  107. package/lib/test/support/testUtil.js +0 -29
  108. package/lib/test/support/treeStructure.js +0 -38
  109. package/lib/test/util.test.js +0 -26
  110. package/lib/tree.jquery.d.js +0 -1
  111. package/lib/tree.jquery.js +0 -1105
  112. package/lib/types.js +0 -1
  113. package/lib/typings.d.js +0 -2
  114. package/lib/util.js +0 -15
  115. package/lib/version.js +0 -8
  116. package/src/dragAndDropHandler.ts +0 -713
  117. package/src/mouse.widget.ts +0 -266
  118. package/src/nodeElement.ts +0 -272
  119. package/src/types.ts +0 -19
@@ -0,0 +1,91 @@
1
+ import { Node } from "../node";
2
+
3
+ interface Options {
4
+ handleAfterOpenFolder: (node: Node, nextNode: Node | null) => void;
5
+ handleClosedFolder: (
6
+ node: Node,
7
+ nextNode: Node | null,
8
+ element: HTMLElement,
9
+ ) => void;
10
+ handleFirstNode: (node: Node) => void;
11
+ handleNode: (
12
+ node: Node,
13
+ nextNode: Node | null,
14
+ element: HTMLElement,
15
+ ) => void;
16
+
17
+ /*
18
+ override
19
+ return
20
+ - true: continue iterating
21
+ - false: stop iterating
22
+ */
23
+ handleOpenFolder: (node: Node, element: HTMLElement) => boolean;
24
+ }
25
+
26
+ const iterateVisibleNodes = (
27
+ tree: Node,
28
+ {
29
+ handleAfterOpenFolder,
30
+ handleClosedFolder,
31
+ handleFirstNode,
32
+ handleNode,
33
+ handleOpenFolder,
34
+ }: Options,
35
+ ) => {
36
+ let isFirstNode = true;
37
+
38
+ const iterate = (node: Node, nextNode: Node | null): void => {
39
+ let mustIterateInside =
40
+ (node.is_open || !node.element) && node.hasChildren();
41
+
42
+ let element: HTMLElement | null = null;
43
+
44
+ // Is the element visible?
45
+ if (node.element?.offsetParent) {
46
+ element = node.element;
47
+
48
+ if (isFirstNode) {
49
+ handleFirstNode(node);
50
+ isFirstNode = false;
51
+ }
52
+
53
+ if (!node.hasChildren()) {
54
+ handleNode(node, nextNode, node.element);
55
+ } else if (node.is_open) {
56
+ if (!handleOpenFolder(node, node.element)) {
57
+ mustIterateInside = false;
58
+ }
59
+ } else {
60
+ handleClosedFolder(node, nextNode, element);
61
+ }
62
+ }
63
+
64
+ if (mustIterateInside) {
65
+ const childrenLength = node.children.length;
66
+ node.children.forEach((_, i) => {
67
+ const child = node.children[i];
68
+
69
+ if (child) {
70
+ if (i === childrenLength - 1) {
71
+ iterate(child, null);
72
+ } else {
73
+ const nextChild = node.children[i + 1];
74
+
75
+ if (nextChild) {
76
+ iterate(child, nextChild);
77
+ }
78
+ }
79
+ }
80
+ });
81
+
82
+ if (node.is_open && element) {
83
+ handleAfterOpenFolder(node, nextNode);
84
+ }
85
+ }
86
+ };
87
+
88
+ iterate(tree, null);
89
+ };
90
+
91
+ export default iterateVisibleNodes;
@@ -0,0 +1,13 @@
1
+ import { Node } from "../node";
2
+ import { Position } from "../position";
3
+
4
+ export interface DropHint {
5
+ remove: () => void;
6
+ }
7
+
8
+ export interface HitArea {
9
+ top: number;
10
+ bottom: number;
11
+ node: Node;
12
+ position: Position;
13
+ }
@@ -1,23 +1,63 @@
1
1
  import { getBoolString } from "./util";
2
2
  import { Node } from "./node";
3
- import { JqTreeWidget } from "./tree.jquery";
4
-
5
- type IconElement = string | HTMLElement | JQuery<HTMLElement>;
3
+ import { IconElement, OnCreateLi } from "./jqtreeOptions";
4
+ import { GetTree, IsNodeSelected } from "./jqtreeMethodTypes";
5
+
6
+ interface ElementsRendererParams {
7
+ autoEscape: boolean;
8
+ buttonLeft: boolean;
9
+ closedIcon?: IconElement;
10
+ dragAndDrop: boolean;
11
+ $element: JQuery<HTMLElement>;
12
+ getTree: GetTree;
13
+ isNodeSelected: IsNodeSelected;
14
+ onCreateLi?: OnCreateLi;
15
+ openedIcon?: IconElement;
16
+ rtl?: boolean;
17
+ showEmptyFolder: boolean;
18
+ tabIndex?: number;
19
+ }
6
20
 
7
21
  export default class ElementsRenderer {
8
22
  public openedIconElement?: HTMLElement | Text;
9
23
  public closedIconElement?: HTMLElement | Text;
10
- private treeWidget: JqTreeWidget;
11
-
12
- constructor(treeWidget: JqTreeWidget) {
13
- this.treeWidget = treeWidget;
14
-
15
- this.openedIconElement = this.createButtonElement(
16
- treeWidget.options.openedIcon || "+",
17
- );
18
- this.closedIconElement = this.createButtonElement(
19
- treeWidget.options.closedIcon || "-",
20
- );
24
+ private autoEscape: boolean;
25
+ private buttonLeft: boolean;
26
+ private dragAndDrop: boolean;
27
+ private $element: JQuery<HTMLElement>;
28
+ private getTree: GetTree;
29
+ private isNodeSelected: IsNodeSelected;
30
+ private onCreateLi?: OnCreateLi;
31
+ private rtl?: boolean;
32
+ private showEmptyFolder: boolean;
33
+ private tabIndex?: number;
34
+
35
+ constructor({
36
+ autoEscape,
37
+ buttonLeft,
38
+ closedIcon,
39
+ onCreateLi,
40
+ dragAndDrop,
41
+ $element,
42
+ getTree,
43
+ isNodeSelected,
44
+ openedIcon,
45
+ rtl,
46
+ showEmptyFolder,
47
+ tabIndex,
48
+ }: ElementsRendererParams) {
49
+ this.autoEscape = autoEscape;
50
+ this.buttonLeft = buttonLeft;
51
+ this.dragAndDrop = dragAndDrop;
52
+ this.$element = $element;
53
+ this.getTree = getTree;
54
+ this.isNodeSelected = isNodeSelected;
55
+ this.onCreateLi = onCreateLi;
56
+ this.rtl = rtl;
57
+ this.showEmptyFolder = showEmptyFolder;
58
+ this.tabIndex = tabIndex;
59
+ this.openedIconElement = this.createButtonElement(openedIcon || "+");
60
+ this.closedIconElement = this.createButtonElement(closedIcon || "-");
21
61
  }
22
62
 
23
63
  public render(fromNode: Node | null): void {
@@ -29,16 +69,12 @@ export default class ElementsRenderer {
29
69
  }
30
70
 
31
71
  public renderFromRoot(): void {
32
- const $element = this.treeWidget.element;
33
- $element.empty();
72
+ this.$element.empty();
34
73
 
35
- if ($element[0]) {
36
- this.createDomElements(
37
- $element[0],
38
- this.treeWidget.tree.children,
39
- true,
40
- 1,
41
- );
74
+ const tree = this.getTree();
75
+
76
+ if (this.$element[0] && tree) {
77
+ this.createDomElements(this.$element[0], tree.children, true, 1);
42
78
  }
43
79
  }
44
80
 
@@ -104,12 +140,12 @@ export default class ElementsRenderer {
104
140
  classString = "jqtree-tree";
105
141
  role = "tree";
106
142
 
107
- if (this.treeWidget.options.rtl) {
143
+ if (this.rtl) {
108
144
  classString += " jqtree-rtl";
109
145
  }
110
146
  }
111
147
 
112
- if (this.treeWidget.options.dragAndDrop) {
148
+ if (this.dragAndDrop) {
113
149
  classString += " jqtree-dnd";
114
150
  }
115
151
 
@@ -122,20 +158,17 @@ export default class ElementsRenderer {
122
158
  }
123
159
 
124
160
  private createLi(node: Node, level: number): HTMLLIElement {
125
- const isSelected = Boolean(
126
- this.treeWidget.selectNodeHandler.isNodeSelected(node),
127
- );
161
+ const isSelected = Boolean(this.isNodeSelected(node));
128
162
 
129
163
  const mustShowFolder =
130
- node.isFolder() ||
131
- (node.isEmptyFolder && this.treeWidget.options.showEmptyFolder);
164
+ node.isFolder() || (node.isEmptyFolder && this.showEmptyFolder);
132
165
 
133
166
  const li = mustShowFolder
134
167
  ? this.createFolderLi(node, level, isSelected)
135
168
  : this.createNodeLi(node, level, isSelected);
136
169
 
137
- if (this.treeWidget.options.onCreateLi) {
138
- this.treeWidget.options.onCreateLi(node, jQuery(li), isSelected);
170
+ if (this.onCreateLi) {
171
+ this.onCreateLi(node, jQuery(li), isSelected);
139
172
  }
140
173
 
141
174
  return li;
@@ -185,7 +218,7 @@ export default class ElementsRenderer {
185
218
  buttonLink.appendChild(iconElement.cloneNode(true));
186
219
  }
187
220
 
188
- if (this.treeWidget.options.buttonLeft) {
221
+ if (this.buttonLeft) {
189
222
  div.appendChild(buttonLink);
190
223
  }
191
224
 
@@ -199,7 +232,7 @@ export default class ElementsRenderer {
199
232
  titleSpan.setAttribute("aria-expanded", getBoolString(node.is_open));
200
233
  div.appendChild(titleSpan);
201
234
 
202
- if (!this.treeWidget.options.buttonLeft) {
235
+ if (!this.buttonLeft) {
203
236
  div.appendChild(buttonLink);
204
237
  }
205
238
 
@@ -257,14 +290,12 @@ export default class ElementsRenderer {
257
290
  classes += " jqtree-title-folder";
258
291
  }
259
292
 
260
- classes += ` jqtree-title-button-${
261
- this.treeWidget.options.buttonLeft ? "left" : "right"
262
- }`;
293
+ classes += ` jqtree-title-button-${this.buttonLeft ? "left" : "right"}`;
263
294
 
264
295
  titleSpan.className = classes;
265
296
 
266
297
  if (isSelected) {
267
- const tabIndex = this.treeWidget.options.tabIndex;
298
+ const tabIndex = this.tabIndex;
268
299
 
269
300
  if (tabIndex !== undefined) {
270
301
  titleSpan.setAttribute("tabindex", `${tabIndex}`);
@@ -273,7 +304,7 @@ export default class ElementsRenderer {
273
304
 
274
305
  this.setTreeItemAriaAttributes(titleSpan, nodeName, level, isSelected);
275
306
 
276
- if (this.treeWidget.options.autoEscape) {
307
+ if (this.autoEscape) {
277
308
  titleSpan.textContent = nodeName;
278
309
  } else {
279
310
  titleSpan.innerHTML = nodeName;
@@ -289,7 +320,7 @@ export default class ElementsRenderer {
289
320
  classes.push("jqtree-closed");
290
321
  }
291
322
 
292
- if (this.treeWidget.options.buttonLeft) {
323
+ if (this.buttonLeft) {
293
324
  classes.push("jqtree-toggler-left");
294
325
  } else {
295
326
  classes.push("jqtree-toggler-right");
@@ -325,6 +356,10 @@ export default class ElementsRenderer {
325
356
  div.innerHTML = value;
326
357
 
327
358
  return document.createTextNode(div.innerHTML);
359
+ } else if (value == null) {
360
+ return undefined;
361
+ } else if ((value as HTMLElement).nodeType) {
362
+ return value as HTMLElement;
328
363
  } else {
329
364
  return jQuery(value)[0];
330
365
  }
@@ -0,0 +1,40 @@
1
+ import { Node } from "./node";
2
+
3
+ export type AddToSelection = (node: Node) => void;
4
+
5
+ export type CloseNode = (node: Node) => void;
6
+
7
+ export type GetNodeById = (nodeId: NodeId) => Node | null;
8
+
9
+ export type GetScrollLeft = () => number;
10
+
11
+ export type GetSelectedNode = () => Node | false;
12
+
13
+ export type GetSelectedNodes = () => Node[];
14
+
15
+ export type GetTree = () => Node | null;
16
+
17
+ export type IsFocusOnTree = () => boolean;
18
+
19
+ export type IsNodeSelected = (node: Node) => boolean;
20
+
21
+ export type LoadData = (data: NodeData[], parentNode: Node | null) => void;
22
+
23
+ export type OnFinishOpenNode = (node: Node) => void;
24
+
25
+ export type OpenNode = (
26
+ node: Node,
27
+ slide?: boolean,
28
+ onFinished?: OnFinishOpenNode,
29
+ ) => void;
30
+
31
+ export type RefreshElements = (fromNode: Node | null) => void;
32
+
33
+ export type RemoveFromSelection = (node: Node) => void;
34
+
35
+ export type SelectNode = (node: Node) => void;
36
+
37
+ export type TriggerEvent = (
38
+ eventName: string,
39
+ values?: Record<string, unknown>,
40
+ ) => JQuery.Event;
@@ -1,16 +1,34 @@
1
1
  import { Node } from "./node";
2
2
 
3
- type CanMoveNodeTo = (
3
+ export type OnCanMove = ((node: Node) => boolean) | undefined;
4
+
5
+ type DataUrlFunction = (node: Node | null) => JQuery.AjaxSettings;
6
+
7
+ export type DataUrl = string | JQuery.AjaxSettings | DataUrlFunction;
8
+
9
+ export type DragMethod = (node: Node, event: Event | Touch) => void;
10
+
11
+ export type OnCanMoveTo = (
4
12
  node: Node,
5
13
  targetNode: Node,
6
14
  positionName: string,
7
15
  ) => boolean;
8
- type CreateLi = (node: Node, el: JQuery, isSelected: boolean) => void;
9
- type DataFilter = (data: unknown) => NodeData[];
10
- type DataUrlFunction = (node: Node | null) => JQuery.AjaxSettings;
11
- type DataUrl = string | JQuery.AjaxSettings | DataUrlFunction;
12
- type DragMethod = (node: Node, event: Event | Touch) => void;
13
- type HandleLoadingMethod = (
16
+
17
+ export type OnGetStateFromStorage = (() => string) | undefined;
18
+
19
+ export type OnIsMoveHandle = (el: JQuery) => boolean;
20
+
21
+ export type OnLoadFailed = (response: JQuery.jqXHR) => void;
22
+
23
+ export type OnSetStateFromStorage = ((data: string) => void) | undefined;
24
+
25
+ export type DataFilter = (data: unknown) => NodeData[];
26
+
27
+ export type IconElement = string | HTMLElement | JQuery<HTMLElement>;
28
+
29
+ export type OnCreateLi = (node: Node, el: JQuery, isSelected: boolean) => void;
30
+
31
+ export type OnLoading = (
14
32
  isLoading: boolean,
15
33
  node: Node | null,
16
34
  $el: JQuery,
@@ -21,32 +39,32 @@ export interface JQTreeOptions {
21
39
  autoEscape: boolean;
22
40
  autoOpen: boolean | number;
23
41
  buttonLeft: boolean;
24
- closedIcon?: string | HTMLElement | JQuery<HTMLElement>;
25
- data: NodeData[] | undefined;
26
- dataFilter: DataFilter | undefined;
27
- dataUrl: DataUrl | undefined;
42
+ closedIcon?: IconElement;
43
+ data?: NodeData[];
44
+ dataFilter?: DataFilter;
45
+ dataUrl?: DataUrl;
28
46
  dragAndDrop: boolean;
29
47
  keyboardSupport: boolean;
30
48
  nodeClass: typeof Node;
31
- onCanMove: ((node: Node) => boolean) | undefined;
32
- onCanMoveTo: CanMoveNodeTo | undefined;
33
- onCanSelectNode: ((node: Node) => boolean) | undefined;
34
- onCreateLi: CreateLi | undefined;
35
- onDragMove: DragMethod | undefined;
36
- onDragStop: DragMethod | undefined;
37
- onGetStateFromStorage: (() => string) | undefined;
38
- onIsMoveHandle: ((el: JQuery) => boolean) | undefined;
39
- onLoadFailed: ((response: JQuery.jqXHR) => void) | undefined;
40
- onLoading: HandleLoadingMethod | undefined;
41
- onSetStateFromStorage: ((data: string) => void) | undefined;
42
- openedIcon?: string | HTMLElement | JQuery<HTMLElement>;
49
+ onCanMove?: OnCanMove;
50
+ onCanMoveTo?: OnCanMoveTo;
51
+ onCanSelectNode?: (node: Node) => boolean;
52
+ onCreateLi?: OnCreateLi;
53
+ onDragMove?: DragMethod;
54
+ onDragStop?: DragMethod;
55
+ onGetStateFromStorage?: OnGetStateFromStorage;
56
+ onIsMoveHandle?: OnIsMoveHandle;
57
+ onLoadFailed?: OnLoadFailed;
58
+ onLoading?: OnLoading;
59
+ onSetStateFromStorage?: OnSetStateFromStorage;
60
+ openedIcon?: IconElement;
43
61
  openFolderDelay: number | false;
44
- rtl: boolean | undefined;
62
+ rtl?: boolean;
45
63
  selectable: boolean;
46
64
  saveState: boolean | string;
47
65
  showEmptyFolder: boolean;
48
66
  slide: boolean;
49
67
  startDndDelay: number;
50
- tabIndex: number;
68
+ tabIndex?: number;
51
69
  useContextMenu: boolean;
52
70
  }
package/src/keyHandler.ts CHANGED
@@ -1,24 +1,58 @@
1
1
  import { Node } from "./node";
2
- import { JqTreeWidget } from "./tree.jquery";
2
+ import {
3
+ CloseNode,
4
+ GetSelectedNode,
5
+ IsFocusOnTree,
6
+ OpenNode,
7
+ SelectNode,
8
+ } from "./jqtreeMethodTypes";
9
+
10
+ type KeyboardEventHandler = (event: KeyboardEvent) => boolean;
11
+
12
+ interface KeyHandlerParams {
13
+ closeNode: CloseNode;
14
+ getSelectedNode: GetSelectedNode;
15
+ isFocusOnTree: IsFocusOnTree;
16
+ keyboardSupport: boolean;
17
+ openNode: OpenNode;
18
+ selectNode: SelectNode;
19
+ }
3
20
 
4
21
  export default class KeyHandler {
5
- private static LEFT = 37;
6
- private static UP = 38;
7
- private static RIGHT = 39;
8
- private static DOWN = 40;
9
-
10
- private treeWidget: JqTreeWidget;
11
-
12
- constructor(treeWidget: JqTreeWidget) {
13
- this.treeWidget = treeWidget;
14
-
15
- if (treeWidget.options.keyboardSupport) {
16
- jQuery(document).on("keydown.jqtree", this.handleKeyDown);
22
+ private closeNode: CloseNode;
23
+ private getSelectedNode: GetSelectedNode;
24
+ private handleKeyDownHandler?: KeyboardEventHandler;
25
+ private isFocusOnTree: IsFocusOnTree;
26
+ private keyboardSupport: boolean;
27
+ private openNode: OpenNode;
28
+ private originalSelectNode: SelectNode;
29
+
30
+ constructor({
31
+ closeNode,
32
+ getSelectedNode,
33
+ isFocusOnTree,
34
+ keyboardSupport,
35
+ openNode,
36
+ selectNode,
37
+ }: KeyHandlerParams) {
38
+ this.closeNode = closeNode;
39
+ this.getSelectedNode = getSelectedNode;
40
+ this.isFocusOnTree = isFocusOnTree;
41
+ this.keyboardSupport = keyboardSupport;
42
+ this.openNode = openNode;
43
+ this.originalSelectNode = selectNode;
44
+
45
+ if (keyboardSupport) {
46
+ this.handleKeyDownHandler = this.handleKeyDown.bind(this);
47
+
48
+ document.addEventListener("keydown", this.handleKeyDownHandler);
17
49
  }
18
50
  }
19
51
 
20
52
  public deinit(): void {
21
- jQuery(document).off("keydown.jqtree");
53
+ if (this.handleKeyDownHandler) {
54
+ document.removeEventListener("keydown", this.handleKeyDownHandler);
55
+ }
22
56
  }
23
57
 
24
58
  public moveDown(selectedNode: Node): boolean {
@@ -39,7 +73,7 @@ export default class KeyHandler {
39
73
  return this.selectNode(selectedNode.getNextVisibleNode());
40
74
  } else {
41
75
  // Right expands a closed node
42
- this.treeWidget.openNode(selectedNode);
76
+ this.openNode(selectedNode);
43
77
  return false;
44
78
  }
45
79
  }
@@ -48,7 +82,7 @@ export default class KeyHandler {
48
82
  public moveLeft(selectedNode: Node): boolean {
49
83
  if (selectedNode.isFolder() && selectedNode.is_open) {
50
84
  // Left on an open node closes the node
51
- this.treeWidget.closeNode(selectedNode);
85
+ this.closeNode(selectedNode);
52
86
  return false;
53
87
  } else {
54
88
  // Left on a closed or end node moves focus to the node's parent
@@ -60,35 +94,33 @@ export default class KeyHandler {
60
94
  if (!node) {
61
95
  return true;
62
96
  } else {
63
- this.treeWidget.selectNode(node);
97
+ this.originalSelectNode(node);
64
98
 
65
99
  return false;
66
100
  }
67
101
  }
68
102
 
69
- private handleKeyDown = (e: JQuery.Event): boolean => {
103
+ private handleKeyDown = (e: KeyboardEvent): boolean => {
70
104
  if (!this.canHandleKeyboard()) {
71
105
  return true;
72
106
  }
73
107
 
74
- const selectedNode = this.treeWidget.getSelectedNode();
108
+ const selectedNode = this.getSelectedNode();
75
109
  if (!selectedNode) {
76
110
  return true;
77
111
  }
78
112
 
79
- const key = e.which;
80
-
81
- switch (key) {
82
- case KeyHandler.DOWN:
113
+ switch (e.key) {
114
+ case "ArrowDown":
83
115
  return this.moveDown(selectedNode);
84
116
 
85
- case KeyHandler.UP:
117
+ case "ArrowUp":
86
118
  return this.moveUp(selectedNode);
87
119
 
88
- case KeyHandler.RIGHT:
120
+ case "ArrowRight":
89
121
  return this.moveRight(selectedNode);
90
122
 
91
- case KeyHandler.LEFT:
123
+ case "ArrowLeft":
92
124
  return this.moveLeft(selectedNode);
93
125
 
94
126
  default:
@@ -97,9 +129,6 @@ export default class KeyHandler {
97
129
  };
98
130
 
99
131
  private canHandleKeyboard(): boolean {
100
- return (
101
- (this.treeWidget.options.keyboardSupport || false) &&
102
- this.treeWidget.selectNodeHandler.isFocusOnTree()
103
- );
132
+ return this.keyboardSupport && this.isFocusOnTree();
104
133
  }
105
134
  }