jqtree 1.8.5 → 1.8.7

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.
@@ -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
- public openedIconElement?: HTMLElement | Text;
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
- public renderFromRoot(): void {
72
- this.$element.empty();
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
- public renderFromNode(node: Node): void {
82
- // remember current li
83
- const $previousLi = jQuery(node.element);
84
-
85
- // create element
86
- const li = this.createLi(node, node.getLevel());
87
- this.attachNodeData(node, li);
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
- // create children
96
- if (node.children) {
97
- this.createDomElements(
98
- li,
99
- node.children,
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 createButtonElement(
351
- value: IconElement,
352
- ): HTMLElement | Text | undefined {
353
- if (typeof value === "string") {
354
- // convert value to html
355
- const div = document.createElement("div");
356
- div.innerHTML = value;
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
- 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
+ public render(fromNode: Node | null): void {
329
+ if (fromNode?.parent) {
330
+ this.renderFromNode(fromNode);
363
331
  } else {
364
- return jQuery(value)[0];
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
  }
@@ -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 = () => Node | false;
11
+ export type GetSelectedNode = () => false | Node;
12
12
 
13
13
  export type GetSelectedNodes = () => Node[];
14
14
 
@@ -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 = string | JQuery.AjaxSettings | DataUrlFunction;
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 = string | HTMLElement | JQuery<HTMLElement>;
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: number | false;
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: number;
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
- this.handleKeyDownHandler = this.handleKeyDown.bind(this);
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
- public moveDown(selectedNode: Node): boolean {
59
- return this.selectNode(selectedNode.getNextVisibleNode());
84
+ private canHandleKeyboard(): boolean {
85
+ return this.keyboardSupport && this.isFocusOnTree();
60
86
  }
61
87
 
62
- public moveUp(selectedNode: Node): boolean {
63
- return this.selectNode(selectedNode.getPreviousVisibleNode());
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
- public moveRight(selectedNode: Node): boolean {
99
+ private moveRight(selectedNode: Node): boolean {
67
100
  if (!selectedNode.isFolder()) {
68
- return true;
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 false;
110
+ return true;
78
111
  }
79
112
  }
80
113
  }
81
114
 
82
- public moveLeft(selectedNode: Node): boolean {
83
- if (selectedNode.isFolder() && selectedNode.is_open) {
84
- // Left on an open node closes the node
85
- this.closeNode(selectedNode);
86
- return false;
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 true;
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
- const selectedNode = this.getSelectedNode();
109
- if (!selectedNode) {
110
- return true;
129
+ public deinit(): void {
130
+ if (this.handleKeyDownHandler) {
131
+ document.removeEventListener("keydown", this.handleKeyDownHandler);
111
132
  }
133
+ }
112
134
 
113
- switch (e.key) {
114
- case "ArrowDown":
115
- return this.moveDown(selectedNode);
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
- private canHandleKeyboard(): boolean {
132
- return this.keyboardSupport && this.isFocusOnTree();
139
+ public moveUp(selectedNode: Node): boolean {
140
+ return this.selectNode(selectedNode.getPreviousVisibleNode());
133
141
  }
134
142
  }