jqtree 1.8.5 → 1.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.tool-versions +2 -0
- package/README.md +1 -1
- package/bower.json +1 -1
- package/eslint.config.mjs +69 -0
- package/package.json +27 -28
- package/src/dataLoader.ts +62 -62
- package/src/dragAndDropHandler/dragElement.ts +10 -10
- package/src/dragAndDropHandler/generateHitAreas.ts +5 -5
- package/src/dragAndDropHandler/index.ts +250 -250
- package/src/dragAndDropHandler/types.ts +1 -1
- package/src/elementsRenderer.ts +124 -125
- package/src/jqtreeMethodTypes.ts +1 -1
- package/src/jqtreeOptions.ts +5 -5
- package/src/keyHandler.ts +66 -58
- package/src/mouseHandler.ts +211 -215
- package/src/node.ts +390 -392
- package/src/nodeElement/folderElement.ts +48 -48
- package/src/nodeElement/ghostDropHint.ts +4 -4
- package/src/nodeElement/index.ts +39 -39
- package/src/nodeUtils.ts +1 -1
- package/src/position.ts +1 -1
- package/src/saveStateHandler.ts +135 -137
- package/src/scrollHandler/containerScrollParent.ts +70 -69
- package/src/scrollHandler/createScrollParent.ts +1 -0
- package/src/scrollHandler/documentScrollParent.ts +88 -87
- package/src/scrollHandler.ts +20 -20
- package/src/selectNodeHandler.ts +16 -16
- package/src/simple.widget.ts +16 -15
- package/src/tree.jquery.d.ts +25 -27
- package/src/tree.jquery.ts +849 -843
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +2533 -2523
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +2 -2
- package/tree.jquery.js.map +1 -1
package/src/elementsRenderer.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { getBoolString } from "./util";
|
|
2
|
-
import { Node } from "./node";
|
|
3
|
-
import { IconElement, OnCreateLi } from "./jqtreeOptions";
|
|
4
1
|
import { GetTree, IsNodeSelected } from "./jqtreeMethodTypes";
|
|
2
|
+
import { IconElement, OnCreateLi } from "./jqtreeOptions";
|
|
3
|
+
import { Node } from "./node";
|
|
4
|
+
import { getBoolString } from "./util";
|
|
5
5
|
|
|
6
6
|
interface ElementsRendererParams {
|
|
7
|
+
$element: JQuery;
|
|
7
8
|
autoEscape: boolean;
|
|
8
9
|
buttonLeft: boolean;
|
|
9
10
|
closedIcon?: IconElement;
|
|
10
11
|
dragAndDrop: boolean;
|
|
11
|
-
$element: JQuery<HTMLElement>;
|
|
12
12
|
getTree: GetTree;
|
|
13
13
|
isNodeSelected: IsNodeSelected;
|
|
14
14
|
onCreateLi?: OnCreateLi;
|
|
@@ -19,12 +19,10 @@ interface ElementsRendererParams {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export default class ElementsRenderer {
|
|
22
|
-
|
|
23
|
-
public closedIconElement?: HTMLElement | Text;
|
|
22
|
+
private $element: JQuery;
|
|
24
23
|
private autoEscape: boolean;
|
|
25
24
|
private buttonLeft: boolean;
|
|
26
25
|
private dragAndDrop: boolean;
|
|
27
|
-
private $element: JQuery<HTMLElement>;
|
|
28
26
|
private getTree: GetTree;
|
|
29
27
|
private isNodeSelected: IsNodeSelected;
|
|
30
28
|
private onCreateLi?: OnCreateLi;
|
|
@@ -32,15 +30,18 @@ export default class ElementsRenderer {
|
|
|
32
30
|
private showEmptyFolder: boolean;
|
|
33
31
|
private tabIndex?: number;
|
|
34
32
|
|
|
33
|
+
public closedIconElement?: HTMLElement | Text;
|
|
34
|
+
public openedIconElement?: HTMLElement | Text;
|
|
35
|
+
|
|
35
36
|
constructor({
|
|
37
|
+
$element,
|
|
36
38
|
autoEscape,
|
|
37
39
|
buttonLeft,
|
|
38
40
|
closedIcon,
|
|
39
|
-
onCreateLi,
|
|
40
41
|
dragAndDrop,
|
|
41
|
-
$element,
|
|
42
42
|
getTree,
|
|
43
43
|
isNodeSelected,
|
|
44
|
+
onCreateLi,
|
|
44
45
|
openedIcon,
|
|
45
46
|
rtl,
|
|
46
47
|
showEmptyFolder,
|
|
@@ -56,50 +57,28 @@ export default class ElementsRenderer {
|
|
|
56
57
|
this.rtl = rtl;
|
|
57
58
|
this.showEmptyFolder = showEmptyFolder;
|
|
58
59
|
this.tabIndex = tabIndex;
|
|
59
|
-
this.openedIconElement = this.createButtonElement(openedIcon
|
|
60
|
-
this.closedIconElement = this.createButtonElement(closedIcon
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public render(fromNode: Node | null): void {
|
|
64
|
-
if (fromNode && fromNode.parent) {
|
|
65
|
-
this.renderFromNode(fromNode);
|
|
66
|
-
} else {
|
|
67
|
-
this.renderFromRoot();
|
|
68
|
-
}
|
|
60
|
+
this.openedIconElement = this.createButtonElement(openedIcon ?? "+");
|
|
61
|
+
this.closedIconElement = this.createButtonElement(closedIcon ?? "-");
|
|
69
62
|
}
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const tree = this.getTree();
|
|
75
|
-
|
|
76
|
-
if (this.$element[0] && tree) {
|
|
77
|
-
this.createDomElements(this.$element[0], tree.children, true, 1);
|
|
78
|
-
}
|
|
64
|
+
private attachNodeData(node: Node, li: HTMLElement): void {
|
|
65
|
+
node.element = li;
|
|
66
|
+
jQuery(li).data("node", node);
|
|
79
67
|
}
|
|
80
68
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// add element to dom
|
|
90
|
-
$previousLi.after(li);
|
|
91
|
-
|
|
92
|
-
// remove previous li
|
|
93
|
-
$previousLi.remove();
|
|
69
|
+
private createButtonElement(
|
|
70
|
+
value: IconElement,
|
|
71
|
+
): HTMLElement | Text | undefined {
|
|
72
|
+
if (typeof value === "string") {
|
|
73
|
+
// convert value to html
|
|
74
|
+
const div = document.createElement("div");
|
|
75
|
+
div.innerHTML = value;
|
|
94
76
|
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
false,
|
|
101
|
-
node.getLevel() + 1,
|
|
102
|
-
);
|
|
77
|
+
return document.createTextNode(div.innerHTML);
|
|
78
|
+
} else if ((value as HTMLElement).nodeType) {
|
|
79
|
+
return value as HTMLElement;
|
|
80
|
+
} else {
|
|
81
|
+
return jQuery(value)[0];
|
|
103
82
|
}
|
|
104
83
|
}
|
|
105
84
|
|
|
@@ -116,76 +95,12 @@ export default class ElementsRenderer {
|
|
|
116
95
|
const li = this.createLi(child, level);
|
|
117
96
|
ul.appendChild(li);
|
|
118
97
|
|
|
119
|
-
this.attachNodeData(child, li);
|
|
120
|
-
|
|
121
98
|
if (child.hasChildren()) {
|
|
122
99
|
this.createDomElements(li, child.children, false, level + 1);
|
|
123
100
|
}
|
|
124
101
|
}
|
|
125
102
|
}
|
|
126
103
|
|
|
127
|
-
private attachNodeData(node: Node, li: HTMLElement): void {
|
|
128
|
-
node.element = li;
|
|
129
|
-
jQuery(li).data("node", node);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private createUl(isRootNode: boolean): HTMLUListElement {
|
|
133
|
-
let classString;
|
|
134
|
-
let role;
|
|
135
|
-
|
|
136
|
-
if (!isRootNode) {
|
|
137
|
-
classString = "";
|
|
138
|
-
role = "group";
|
|
139
|
-
} else {
|
|
140
|
-
classString = "jqtree-tree";
|
|
141
|
-
role = "tree";
|
|
142
|
-
|
|
143
|
-
if (this.rtl) {
|
|
144
|
-
classString += " jqtree-rtl";
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (this.dragAndDrop) {
|
|
149
|
-
classString += " jqtree-dnd";
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const ul = document.createElement("ul");
|
|
153
|
-
ul.className = `jqtree_common ${classString}`;
|
|
154
|
-
|
|
155
|
-
ul.setAttribute("role", role);
|
|
156
|
-
|
|
157
|
-
return ul;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private createLi(node: Node, level: number): HTMLLIElement {
|
|
161
|
-
const isSelected = Boolean(this.isNodeSelected(node));
|
|
162
|
-
|
|
163
|
-
const mustShowFolder =
|
|
164
|
-
node.isFolder() || (node.isEmptyFolder && this.showEmptyFolder);
|
|
165
|
-
|
|
166
|
-
const li = mustShowFolder
|
|
167
|
-
? this.createFolderLi(node, level, isSelected)
|
|
168
|
-
: this.createNodeLi(node, level, isSelected);
|
|
169
|
-
|
|
170
|
-
if (this.onCreateLi) {
|
|
171
|
-
this.onCreateLi(node, jQuery(li), isSelected);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return li;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private setTreeItemAriaAttributes(
|
|
178
|
-
element: HTMLElement,
|
|
179
|
-
name: string,
|
|
180
|
-
level: number,
|
|
181
|
-
isSelected: boolean,
|
|
182
|
-
) {
|
|
183
|
-
element.setAttribute("aria-label", name);
|
|
184
|
-
element.setAttribute("aria-level", `${level}`);
|
|
185
|
-
element.setAttribute("aria-selected", getBoolString(isSelected));
|
|
186
|
-
element.setAttribute("role", "treeitem");
|
|
187
|
-
}
|
|
188
|
-
|
|
189
104
|
private createFolderLi(
|
|
190
105
|
node: Node,
|
|
191
106
|
level: number,
|
|
@@ -239,6 +154,29 @@ export default class ElementsRenderer {
|
|
|
239
154
|
return li;
|
|
240
155
|
}
|
|
241
156
|
|
|
157
|
+
/* Create the <li> element
|
|
158
|
+
* Attach it to node.element.
|
|
159
|
+
* Call onCreateLi
|
|
160
|
+
*/
|
|
161
|
+
private createLi(node: Node, level: number): HTMLLIElement {
|
|
162
|
+
const isSelected = Boolean(this.isNodeSelected(node));
|
|
163
|
+
|
|
164
|
+
const mustShowFolder =
|
|
165
|
+
node.isFolder() || (node.isEmptyFolder && this.showEmptyFolder);
|
|
166
|
+
|
|
167
|
+
const li = mustShowFolder
|
|
168
|
+
? this.createFolderLi(node, level, isSelected)
|
|
169
|
+
: this.createNodeLi(node, level, isSelected);
|
|
170
|
+
|
|
171
|
+
this.attachNodeData(node, li);
|
|
172
|
+
|
|
173
|
+
if (this.onCreateLi) {
|
|
174
|
+
this.onCreateLi(node, jQuery(li), isSelected);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return li;
|
|
178
|
+
}
|
|
179
|
+
|
|
242
180
|
private createNodeLi(
|
|
243
181
|
node: Node,
|
|
244
182
|
level: number,
|
|
@@ -313,6 +251,34 @@ export default class ElementsRenderer {
|
|
|
313
251
|
return titleSpan;
|
|
314
252
|
}
|
|
315
253
|
|
|
254
|
+
private createUl(isRootNode: boolean): HTMLUListElement {
|
|
255
|
+
let classString;
|
|
256
|
+
let role;
|
|
257
|
+
|
|
258
|
+
if (!isRootNode) {
|
|
259
|
+
classString = "";
|
|
260
|
+
role = "group";
|
|
261
|
+
} else {
|
|
262
|
+
classString = "jqtree-tree";
|
|
263
|
+
role = "tree";
|
|
264
|
+
|
|
265
|
+
if (this.rtl) {
|
|
266
|
+
classString += " jqtree-rtl";
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (this.dragAndDrop) {
|
|
271
|
+
classString += " jqtree-dnd";
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const ul = document.createElement("ul");
|
|
275
|
+
ul.className = `jqtree_common ${classString}`;
|
|
276
|
+
|
|
277
|
+
ul.setAttribute("role", role);
|
|
278
|
+
|
|
279
|
+
return ul;
|
|
280
|
+
}
|
|
281
|
+
|
|
316
282
|
private getButtonClasses(node: Node): string {
|
|
317
283
|
const classes = ["jqtree-toggler", "jqtree_common"];
|
|
318
284
|
|
|
@@ -347,21 +313,54 @@ export default class ElementsRenderer {
|
|
|
347
313
|
return classes.join(" ");
|
|
348
314
|
}
|
|
349
315
|
|
|
350
|
-
private
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
316
|
+
private setTreeItemAriaAttributes(
|
|
317
|
+
element: HTMLElement,
|
|
318
|
+
name: string,
|
|
319
|
+
level: number,
|
|
320
|
+
isSelected: boolean,
|
|
321
|
+
) {
|
|
322
|
+
element.setAttribute("aria-label", name);
|
|
323
|
+
element.setAttribute("aria-level", `${level}`);
|
|
324
|
+
element.setAttribute("aria-selected", getBoolString(isSelected));
|
|
325
|
+
element.setAttribute("role", "treeitem");
|
|
326
|
+
}
|
|
357
327
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
} else if ((value as HTMLElement).nodeType) {
|
|
362
|
-
return value as HTMLElement;
|
|
328
|
+
public render(fromNode: Node | null): void {
|
|
329
|
+
if (fromNode?.parent) {
|
|
330
|
+
this.renderFromNode(fromNode);
|
|
363
331
|
} else {
|
|
364
|
-
|
|
332
|
+
this.renderFromRoot();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
public renderFromNode(node: Node): void {
|
|
337
|
+
if (!node.element) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// remember current li
|
|
342
|
+
const $previousLi = jQuery(node.element);
|
|
343
|
+
|
|
344
|
+
// create element
|
|
345
|
+
const li = this.createLi(node, node.getLevel());
|
|
346
|
+
|
|
347
|
+
// add element to dom
|
|
348
|
+
$previousLi.after(li);
|
|
349
|
+
|
|
350
|
+
// remove previous li
|
|
351
|
+
$previousLi.remove();
|
|
352
|
+
|
|
353
|
+
// create children
|
|
354
|
+
this.createDomElements(li, node.children, false, node.getLevel() + 1);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
public renderFromRoot(): void {
|
|
358
|
+
this.$element.empty();
|
|
359
|
+
|
|
360
|
+
const tree = this.getTree();
|
|
361
|
+
|
|
362
|
+
if (this.$element[0] && tree) {
|
|
363
|
+
this.createDomElements(this.$element[0], tree.children, true, 1);
|
|
365
364
|
}
|
|
366
365
|
}
|
|
367
366
|
}
|
package/src/jqtreeMethodTypes.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type GetNodeById = (nodeId: NodeId) => Node | null;
|
|
|
8
8
|
|
|
9
9
|
export type GetScrollLeft = () => number;
|
|
10
10
|
|
|
11
|
-
export type GetSelectedNode = () =>
|
|
11
|
+
export type GetSelectedNode = () => false | Node;
|
|
12
12
|
|
|
13
13
|
export type GetSelectedNodes = () => Node[];
|
|
14
14
|
|
package/src/jqtreeOptions.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type OnCanMove = ((node: Node) => boolean) | undefined;
|
|
|
4
4
|
|
|
5
5
|
type DataUrlFunction = (node: Node | null) => JQuery.AjaxSettings;
|
|
6
6
|
|
|
7
|
-
export type DataUrl =
|
|
7
|
+
export type DataUrl = DataUrlFunction | JQuery.AjaxSettings | string;
|
|
8
8
|
|
|
9
9
|
export type DragMethod = (node: Node, event: Event | Touch) => void;
|
|
10
10
|
|
|
@@ -24,7 +24,7 @@ export type OnSetStateFromStorage = ((data: string) => void) | undefined;
|
|
|
24
24
|
|
|
25
25
|
export type DataFilter = (data: unknown) => NodeData[];
|
|
26
26
|
|
|
27
|
-
export type IconElement =
|
|
27
|
+
export type IconElement = HTMLElement | JQuery | string;
|
|
28
28
|
|
|
29
29
|
export type OnCreateLi = (node: Node, el: JQuery, isSelected: boolean) => void;
|
|
30
30
|
|
|
@@ -58,13 +58,13 @@ export interface JQTreeOptions {
|
|
|
58
58
|
onLoading?: OnLoading;
|
|
59
59
|
onSetStateFromStorage?: OnSetStateFromStorage;
|
|
60
60
|
openedIcon?: IconElement;
|
|
61
|
-
openFolderDelay:
|
|
61
|
+
openFolderDelay: false | number;
|
|
62
62
|
rtl?: boolean;
|
|
63
|
-
selectable: boolean;
|
|
64
63
|
saveState: boolean | string;
|
|
64
|
+
selectable: boolean;
|
|
65
65
|
showEmptyFolder: boolean;
|
|
66
66
|
slide: boolean;
|
|
67
|
-
startDndDelay
|
|
67
|
+
startDndDelay?: number;
|
|
68
68
|
tabIndex?: number;
|
|
69
69
|
useContextMenu: boolean;
|
|
70
70
|
}
|
package/src/keyHandler.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Node } from "./node";
|
|
2
1
|
import {
|
|
3
2
|
CloseNode,
|
|
4
3
|
GetSelectedNode,
|
|
@@ -6,6 +5,7 @@ import {
|
|
|
6
5
|
OpenNode,
|
|
7
6
|
SelectNode,
|
|
8
7
|
} from "./jqtreeMethodTypes";
|
|
8
|
+
import { Node } from "./node";
|
|
9
9
|
|
|
10
10
|
type KeyboardEventHandler = (event: KeyboardEvent) => boolean;
|
|
11
11
|
|
|
@@ -21,6 +21,40 @@ interface KeyHandlerParams {
|
|
|
21
21
|
export default class KeyHandler {
|
|
22
22
|
private closeNode: CloseNode;
|
|
23
23
|
private getSelectedNode: GetSelectedNode;
|
|
24
|
+
|
|
25
|
+
private handleKeyDown = (e: KeyboardEvent): void => {
|
|
26
|
+
if (!this.canHandleKeyboard()) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let isKeyHandled = false;
|
|
31
|
+
|
|
32
|
+
const selectedNode = this.getSelectedNode();
|
|
33
|
+
if (selectedNode) {
|
|
34
|
+
switch (e.key) {
|
|
35
|
+
case "ArrowDown":
|
|
36
|
+
isKeyHandled = this.moveDown(selectedNode);
|
|
37
|
+
break;
|
|
38
|
+
|
|
39
|
+
case "ArrowUp":
|
|
40
|
+
isKeyHandled = this.moveUp(selectedNode);
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
case "ArrowRight":
|
|
44
|
+
isKeyHandled = this.moveRight(selectedNode);
|
|
45
|
+
break;
|
|
46
|
+
|
|
47
|
+
case "ArrowLeft":
|
|
48
|
+
isKeyHandled = this.moveLeft(selectedNode);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isKeyHandled) {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
24
58
|
private handleKeyDownHandler?: KeyboardEventHandler;
|
|
25
59
|
private isFocusOnTree: IsFocusOnTree;
|
|
26
60
|
private keyboardSupport: boolean;
|
|
@@ -43,29 +77,28 @@ export default class KeyHandler {
|
|
|
43
77
|
this.originalSelectNode = selectNode;
|
|
44
78
|
|
|
45
79
|
if (keyboardSupport) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
document.addEventListener("keydown", this.handleKeyDownHandler);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public deinit(): void {
|
|
53
|
-
if (this.handleKeyDownHandler) {
|
|
54
|
-
document.removeEventListener("keydown", this.handleKeyDownHandler);
|
|
80
|
+
document.addEventListener("keydown", this.handleKeyDown);
|
|
55
81
|
}
|
|
56
82
|
}
|
|
57
83
|
|
|
58
|
-
|
|
59
|
-
return this.
|
|
84
|
+
private canHandleKeyboard(): boolean {
|
|
85
|
+
return this.keyboardSupport && this.isFocusOnTree();
|
|
60
86
|
}
|
|
61
87
|
|
|
62
|
-
|
|
63
|
-
|
|
88
|
+
private moveLeft(selectedNode: Node): boolean {
|
|
89
|
+
if (selectedNode.isFolder() && selectedNode.is_open) {
|
|
90
|
+
// Left on an open node closes the node
|
|
91
|
+
this.closeNode(selectedNode);
|
|
92
|
+
return true;
|
|
93
|
+
} else {
|
|
94
|
+
// Left on a closed or end node moves focus to the node's parent
|
|
95
|
+
return this.selectNode(selectedNode.getParent());
|
|
96
|
+
}
|
|
64
97
|
}
|
|
65
98
|
|
|
66
|
-
|
|
99
|
+
private moveRight(selectedNode: Node): boolean {
|
|
67
100
|
if (!selectedNode.isFolder()) {
|
|
68
|
-
return
|
|
101
|
+
return false;
|
|
69
102
|
} else {
|
|
70
103
|
// folder node
|
|
71
104
|
if (selectedNode.is_open) {
|
|
@@ -74,61 +107,36 @@ export default class KeyHandler {
|
|
|
74
107
|
} else {
|
|
75
108
|
// Right expands a closed node
|
|
76
109
|
this.openNode(selectedNode);
|
|
77
|
-
return
|
|
110
|
+
return true;
|
|
78
111
|
}
|
|
79
112
|
}
|
|
80
113
|
}
|
|
81
114
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} else {
|
|
88
|
-
// Left on a closed or end node moves focus to the node's parent
|
|
89
|
-
return this.selectNode(selectedNode.getParent());
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
public selectNode(node: Node | null): boolean {
|
|
115
|
+
/* Select the node.
|
|
116
|
+
* Don't do anything if the node is null.
|
|
117
|
+
* Result: a different node was selected.
|
|
118
|
+
*/
|
|
119
|
+
private selectNode(node: Node | null): boolean {
|
|
94
120
|
if (!node) {
|
|
95
|
-
return
|
|
121
|
+
return false;
|
|
96
122
|
} else {
|
|
97
123
|
this.originalSelectNode(node);
|
|
98
124
|
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private handleKeyDown = (e: KeyboardEvent): boolean => {
|
|
104
|
-
if (!this.canHandleKeyboard()) {
|
|
105
125
|
return true;
|
|
106
126
|
}
|
|
127
|
+
}
|
|
107
128
|
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
|
|
129
|
+
public deinit(): void {
|
|
130
|
+
if (this.handleKeyDownHandler) {
|
|
131
|
+
document.removeEventListener("keydown", this.handleKeyDownHandler);
|
|
111
132
|
}
|
|
133
|
+
}
|
|
112
134
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
case "ArrowUp":
|
|
118
|
-
return this.moveUp(selectedNode);
|
|
119
|
-
|
|
120
|
-
case "ArrowRight":
|
|
121
|
-
return this.moveRight(selectedNode);
|
|
122
|
-
|
|
123
|
-
case "ArrowLeft":
|
|
124
|
-
return this.moveLeft(selectedNode);
|
|
125
|
-
|
|
126
|
-
default:
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
135
|
+
public moveDown(selectedNode: Node): boolean {
|
|
136
|
+
return this.selectNode(selectedNode.getNextVisibleNode());
|
|
137
|
+
}
|
|
130
138
|
|
|
131
|
-
|
|
132
|
-
return this.
|
|
139
|
+
public moveUp(selectedNode: Node): boolean {
|
|
140
|
+
return this.selectNode(selectedNode.getPreviousVisibleNode());
|
|
133
141
|
}
|
|
134
142
|
}
|