jqtree 1.8.8 → 1.8.9

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/src/keyHandler.ts CHANGED
@@ -20,6 +20,49 @@ export default class KeyHandler {
20
20
  private closeNode: CloseNode;
21
21
  private getSelectedNode: GetSelectedNode;
22
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
+
23
66
  private handleKeyDown = (e: KeyboardEvent): void => {
24
67
  if (!this.canHandleKeyboard()) {
25
68
  return;
@@ -53,35 +96,6 @@ export default class KeyHandler {
53
96
  }
54
97
  };
55
98
 
56
- private isFocusOnTree: IsFocusOnTree;
57
- private keyboardSupport: boolean;
58
- private openNode: OpenNode;
59
- private originalSelectNode: SelectNode;
60
-
61
- constructor({
62
- closeNode,
63
- getSelectedNode,
64
- isFocusOnTree,
65
- keyboardSupport,
66
- openNode,
67
- selectNode,
68
- }: KeyHandlerParams) {
69
- this.closeNode = closeNode;
70
- this.getSelectedNode = getSelectedNode;
71
- this.isFocusOnTree = isFocusOnTree;
72
- this.keyboardSupport = keyboardSupport;
73
- this.openNode = openNode;
74
- this.originalSelectNode = selectNode;
75
-
76
- if (keyboardSupport) {
77
- document.addEventListener("keydown", this.handleKeyDown);
78
- }
79
- }
80
-
81
- private canHandleKeyboard(): boolean {
82
- return this.keyboardSupport && this.isFocusOnTree();
83
- }
84
-
85
99
  private moveLeft(selectedNode: Node): boolean {
86
100
  if (selectedNode.isFolder() && selectedNode.is_open) {
87
101
  // Left on an open node closes the node
@@ -122,18 +136,4 @@ export default class KeyHandler {
122
136
  return true;
123
137
  }
124
138
  }
125
-
126
- public deinit(): void {
127
- if (this.keyboardSupport) {
128
- document.removeEventListener("keydown", this.handleKeyDown);
129
- }
130
- }
131
-
132
- public moveDown(selectedNode: Node): boolean {
133
- return this.selectNode(selectedNode.getNextVisibleNode());
134
- }
135
-
136
- public moveUp(selectedNode: Node): boolean {
137
- return this.selectNode(selectedNode.getPreviousVisibleNode());
138
- }
139
139
  }
@@ -32,159 +32,26 @@ class MouseHandler {
32
32
  private getMouseDelay: () => number;
33
33
  private getNode: GetNode;
34
34
 
35
- private handleClick = (e: MouseEvent): void => {
36
- if (!e.target) {
37
- return;
38
- }
39
-
40
- const clickTarget = this.getClickTarget(e.target as HTMLElement);
41
-
42
- if (!clickTarget) {
43
- return;
44
- }
45
-
46
- switch (clickTarget.type) {
47
- case "button":
48
- this.onClickButton(clickTarget.node);
49
-
50
- e.preventDefault();
51
- e.stopPropagation();
52
- break;
53
-
54
- case "label": {
55
- const event = this.triggerEvent("tree.click", {
56
- click_event: e,
57
- node: clickTarget.node,
58
- });
59
-
60
- if (!event.isDefaultPrevented()) {
61
- this.onClickTitle(clickTarget.node);
62
- }
63
- break;
64
- }
65
- }
66
- };
67
-
68
- private handleContextmenu = (e: MouseEvent) => {
69
- if (!e.target) {
70
- return;
71
- }
72
-
73
- const div = (e.target as HTMLElement).closest<HTMLElement>(
74
- "ul.jqtree-tree .jqtree-element",
75
- );
76
-
77
- if (div) {
78
- const node = this.getNode(div);
79
- if (node) {
80
- e.preventDefault();
81
- e.stopPropagation();
82
-
83
- this.triggerEvent("tree.contextmenu", {
84
- click_event: e,
85
- node,
86
- });
87
- return false;
88
- }
89
- }
90
-
91
- return null;
92
- };
93
-
94
- private handleDblclick = (e: MouseEvent): void => {
95
- if (!e.target) {
96
- return;
97
- }
98
-
99
- const clickTarget = this.getClickTarget(e.target as HTMLElement);
100
-
101
- if (clickTarget?.type === "label") {
102
- this.triggerEvent("tree.dblclick", {
103
- click_event: e,
104
- node: clickTarget.node,
105
- });
106
- }
107
- };
108
-
109
35
  private isMouseDelayMet: boolean;
110
- private isMouseStarted: boolean;
111
- private mouseDelayTimer: null | number;
112
36
 
113
- private mouseDown = (e: MouseEvent): void => {
114
- // Left mouse button?
115
- if (e.button !== 0) {
116
- return;
117
- }
118
-
119
- const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));
37
+ private isMouseStarted: boolean;
120
38
 
121
- if (result && e.cancelable) {
122
- e.preventDefault();
123
- }
124
- };
39
+ private mouseDelayTimer: null | number;
125
40
 
126
41
  private mouseDownInfo: null | PositionInfo;
127
-
128
- private mouseMove = (e: MouseEvent): void => {
129
- this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));
130
- };
131
-
132
- private mouseUp = (e: MouseEvent): void => {
133
- this.handleMouseUp(getPositionInfoFromMouseEvent(e));
134
- };
135
-
136
42
  private onClickButton: (node: Node) => void;
137
43
  private onClickTitle: (node: Node) => void;
138
- private onMouseCapture: (positionInfo: PositionInfo) => boolean | null;
139
- private onMouseDrag: (positionInfo: PositionInfo) => void;
140
- private onMouseStart: (positionInfo: PositionInfo) => boolean;
141
- private onMouseStop: (positionInfo: PositionInfo) => void;
142
-
143
- private touchEnd = (e: TouchEvent): void => {
144
- if (e.touches.length > 1) {
145
- return;
146
- }
147
-
148
- const touch = e.touches[0];
149
-
150
- if (!touch) {
151
- return;
152
- }
153
-
154
- this.handleMouseUp(getPositionInfoFromTouch(touch, e));
155
- };
156
-
157
- private touchMove = (e: TouchEvent): void => {
158
- if (e.touches.length > 1) {
159
- return;
160
- }
161
44
 
162
- const touch = e.touches[0];
163
-
164
- if (!touch) {
165
- return;
166
- }
167
-
168
- this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
169
- };
170
-
171
- private touchStart = (e: TouchEvent): void => {
172
- if (e.touches.length > 1) {
173
- return;
174
- }
45
+ private onMouseCapture: (positionInfo: PositionInfo) => boolean | null;
175
46
 
176
- const touch = e.touches[0];
47
+ private onMouseDrag: (positionInfo: PositionInfo) => void;
177
48
 
178
- if (!touch) {
179
- return;
180
- }
49
+ private onMouseStart: (positionInfo: PositionInfo) => boolean;
181
50
 
182
- this.handleMouseDown(getPositionInfoFromTouch(touch, e));
183
- };
51
+ private onMouseStop: (positionInfo: PositionInfo) => void;
184
52
 
185
53
  private triggerEvent: TriggerEvent;
186
54
  private useContextMenu: boolean;
187
-
188
55
  constructor({
189
56
  element,
190
57
  getMouseDelay,
@@ -228,7 +95,21 @@ class MouseHandler {
228
95
  this.isMouseDelayMet = false;
229
96
  this.mouseDownInfo = null;
230
97
  }
98
+ public deinit(): void {
99
+ this.element.removeEventListener("click", this.handleClick);
100
+ this.element.removeEventListener("dblclick", this.handleDblclick);
101
+
102
+ if (this.useContextMenu) {
103
+ this.element.removeEventListener(
104
+ "contextmenu",
105
+ this.handleContextmenu,
106
+ );
107
+ }
231
108
 
109
+ this.element.removeEventListener("mousedown", this.mouseDown);
110
+ this.element.removeEventListener("touchstart", this.touchStart);
111
+ this.removeMouseMoveEventListeners();
112
+ }
232
113
  private getClickTarget(element: HTMLElement): ClickTarget | null {
233
114
  const button = element.closest<HTMLElement>(".jqtree-toggler");
234
115
 
@@ -258,6 +139,79 @@ class MouseHandler {
258
139
 
259
140
  return null;
260
141
  }
142
+ private handleClick = (e: MouseEvent): void => {
143
+ if (!e.target) {
144
+ return;
145
+ }
146
+
147
+ const clickTarget = this.getClickTarget(e.target as HTMLElement);
148
+
149
+ if (!clickTarget) {
150
+ return;
151
+ }
152
+
153
+ switch (clickTarget.type) {
154
+ case "button":
155
+ this.onClickButton(clickTarget.node);
156
+
157
+ e.preventDefault();
158
+ e.stopPropagation();
159
+ break;
160
+
161
+ case "label": {
162
+ const event = this.triggerEvent("tree.click", {
163
+ click_event: e,
164
+ node: clickTarget.node,
165
+ });
166
+
167
+ if (!event.isDefaultPrevented()) {
168
+ this.onClickTitle(clickTarget.node);
169
+ }
170
+ break;
171
+ }
172
+ }
173
+ };
174
+
175
+ private handleContextmenu = (e: MouseEvent) => {
176
+ if (!e.target) {
177
+ return;
178
+ }
179
+
180
+ const div = (e.target as HTMLElement).closest<HTMLElement>(
181
+ "ul.jqtree-tree .jqtree-element",
182
+ );
183
+
184
+ if (div) {
185
+ const node = this.getNode(div);
186
+ if (node) {
187
+ e.preventDefault();
188
+ e.stopPropagation();
189
+
190
+ this.triggerEvent("tree.contextmenu", {
191
+ click_event: e,
192
+ node,
193
+ });
194
+ return false;
195
+ }
196
+ }
197
+
198
+ return null;
199
+ };
200
+
201
+ private handleDblclick = (e: MouseEvent): void => {
202
+ if (!e.target) {
203
+ return;
204
+ }
205
+
206
+ const clickTarget = this.getClickTarget(e.target as HTMLElement);
207
+
208
+ if (clickTarget?.type === "label") {
209
+ this.triggerEvent("tree.dblclick", {
210
+ click_event: e,
211
+ node: clickTarget.node,
212
+ });
213
+ }
214
+ };
261
215
 
262
216
  private handleMouseDown(positionInfo: PositionInfo): boolean {
263
217
  // We may have missed mouseup (out of window)
@@ -307,7 +261,6 @@ class MouseHandler {
307
261
  this.handleMouseUp(positionInfo);
308
262
  }
309
263
  }
310
-
311
264
  private handleMouseUp(positionInfo: PositionInfo): void {
312
265
  this.removeMouseMoveEventListeners();
313
266
  this.isMouseDelayMet = false;
@@ -340,6 +293,27 @@ class MouseHandler {
340
293
  }
341
294
  }
342
295
 
296
+ private mouseDown = (e: MouseEvent): void => {
297
+ // Left mouse button?
298
+ if (e.button !== 0) {
299
+ return;
300
+ }
301
+
302
+ const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));
303
+
304
+ if (result && e.cancelable) {
305
+ e.preventDefault();
306
+ }
307
+ };
308
+
309
+ private mouseMove = (e: MouseEvent): void => {
310
+ this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));
311
+ };
312
+
313
+ private mouseUp = (e: MouseEvent): void => {
314
+ this.handleMouseUp(getPositionInfoFromMouseEvent(e));
315
+ };
316
+
343
317
  private removeMouseMoveEventListeners() {
344
318
  document.removeEventListener("mousemove", this.mouseMove);
345
319
  document.removeEventListener("touchmove", this.touchMove);
@@ -361,21 +335,47 @@ class MouseHandler {
361
335
  this.isMouseDelayMet = false;
362
336
  }
363
337
 
364
- public deinit(): void {
365
- this.element.removeEventListener("click", this.handleClick);
366
- this.element.removeEventListener("dblclick", this.handleDblclick);
338
+ private touchEnd = (e: TouchEvent): void => {
339
+ if (e.touches.length > 1) {
340
+ return;
341
+ }
367
342
 
368
- if (this.useContextMenu) {
369
- this.element.removeEventListener(
370
- "contextmenu",
371
- this.handleContextmenu,
372
- );
343
+ const touch = e.touches[0];
344
+
345
+ if (!touch) {
346
+ return;
373
347
  }
374
348
 
375
- this.element.removeEventListener("mousedown", this.mouseDown);
376
- this.element.removeEventListener("touchstart", this.touchStart);
377
- this.removeMouseMoveEventListeners();
378
- }
349
+ this.handleMouseUp(getPositionInfoFromTouch(touch, e));
350
+ };
351
+
352
+ private touchMove = (e: TouchEvent): void => {
353
+ if (e.touches.length > 1) {
354
+ return;
355
+ }
356
+
357
+ const touch = e.touches[0];
358
+
359
+ if (!touch) {
360
+ return;
361
+ }
362
+
363
+ this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
364
+ };
365
+
366
+ private touchStart = (e: TouchEvent): void => {
367
+ if (e.touches.length > 1) {
368
+ return;
369
+ }
370
+
371
+ const touch = e.touches[0];
372
+
373
+ if (!touch) {
374
+ return;
375
+ }
376
+
377
+ this.handleMouseDown(getPositionInfoFromTouch(touch, e));
378
+ };
379
379
  }
380
380
 
381
381
  export default MouseHandler;
package/src/node.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { isNodeRecordWithChildren } from "./nodeUtils";
2
- import { Position } from "./position";
2
+
3
+ export type Position = "after" | "before" | "inside";
3
4
 
4
5
  type IterateCallback = (node: Node, level: number) => boolean;
5
6
 
@@ -44,33 +45,6 @@ export class Node implements INode {
44
45
  }
45
46
  }
46
47
 
47
- private createNode(nodeData?: NodeData): Node {
48
- const nodeClass = this.getNodeClass();
49
- return new nodeClass(nodeData);
50
- }
51
-
52
- private doRemoveChild(node: Node): void {
53
- this.children.splice(this.getChildIndex(node), 1);
54
- this.tree?.removeNodeFromIndex(node);
55
- }
56
-
57
- private getNodeClass(): typeof Node {
58
- return this.nodeClass ?? this.tree?.nodeClass ?? Node;
59
- }
60
-
61
- // Load children data from nodeInfo if it has children
62
- private loadChildrenFromData(nodeInfo: NodeData) {
63
- if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
64
- this.loadFromData(nodeInfo.children);
65
- }
66
- }
67
-
68
- private setParent(parent: Node): void {
69
- this.parent = parent;
70
- this.tree = parent.tree;
71
- this.tree?.addNodeToIndex(this);
72
- }
73
-
74
48
  public addAfter(nodeInfo: NodeData): Node | null {
75
49
  if (!this.parent) {
76
50
  return null;
@@ -541,7 +515,7 @@ export class Node implements INode {
541
515
  movedNode.parent.doRemoveChild(movedNode);
542
516
 
543
517
  switch (position) {
544
- case Position.After: {
518
+ case "after": {
545
519
  if (targetNode.parent) {
546
520
  targetNode.parent.addChildAtPosition(
547
521
  movedNode,
@@ -552,7 +526,7 @@ export class Node implements INode {
552
526
  return false;
553
527
  }
554
528
 
555
- case Position.Before: {
529
+ case "before": {
556
530
  if (targetNode.parent) {
557
531
  targetNode.parent.addChildAtPosition(
558
532
  movedNode,
@@ -563,14 +537,11 @@ export class Node implements INode {
563
537
  return false;
564
538
  }
565
539
 
566
- case Position.Inside: {
540
+ case "inside": {
567
541
  // move inside as first child
568
542
  targetNode.addChildAtPosition(movedNode, 0);
569
543
  return true;
570
544
  }
571
-
572
- default:
573
- return false;
574
545
  }
575
546
  }
576
547
  }
@@ -656,4 +627,31 @@ export class Node implements INode {
656
627
  }
657
628
  }
658
629
  }
630
+
631
+ private createNode(nodeData?: NodeData): Node {
632
+ const nodeClass = this.getNodeClass();
633
+ return new nodeClass(nodeData);
634
+ }
635
+
636
+ private doRemoveChild(node: Node): void {
637
+ this.children.splice(this.getChildIndex(node), 1);
638
+ this.tree?.removeNodeFromIndex(node);
639
+ }
640
+
641
+ private getNodeClass(): typeof Node {
642
+ return this.nodeClass ?? this.tree?.nodeClass ?? Node;
643
+ }
644
+
645
+ // Load children data from nodeInfo if it has children
646
+ private loadChildrenFromData(nodeInfo: NodeData) {
647
+ if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
648
+ this.loadFromData(nodeInfo.children);
649
+ }
650
+ }
651
+
652
+ private setParent(parent: Node): void {
653
+ this.parent = parent;
654
+ this.tree = parent.tree;
655
+ this.tree?.addNodeToIndex(this);
656
+ }
659
657
  }
@@ -1,5 +1,5 @@
1
1
  import { OnFinishOpenNode, TriggerEvent } from "../jqtreeMethodTypes";
2
- import { Position } from "../position";
2
+ import { Position } from "../node";
3
3
  import NodeElement, { NodeElementParams } from "./index";
4
4
 
5
5
  interface FolderElementParams extends NodeElementParams {
@@ -34,16 +34,6 @@ class FolderElement extends NodeElement {
34
34
  this.triggerEvent = triggerEvent;
35
35
  }
36
36
 
37
- protected mustShowBorderDropHint(position: Position): boolean {
38
- return !this.node.is_open && position === Position.Inside;
39
- }
40
-
41
- private getButton(): HTMLLinkElement {
42
- return this.element.querySelector(
43
- ":scope > .jqtree-element > a.jqtree-toggler",
44
- ) as HTMLLinkElement;
45
- }
46
-
47
37
  public close(slide: boolean, animationSpeed: JQuery.Duration): void {
48
38
  if (!this.node.is_open) {
49
39
  return;
@@ -125,6 +115,16 @@ class FolderElement extends NodeElement {
125
115
  doOpen();
126
116
  }
127
117
  }
118
+
119
+ protected mustShowBorderDropHint(position: Position): boolean {
120
+ return !this.node.is_open && position === "inside";
121
+ }
122
+
123
+ private getButton(): HTMLLinkElement {
124
+ return this.element.querySelector(
125
+ ":scope > .jqtree-element > a.jqtree-toggler",
126
+ ) as HTMLLinkElement;
127
+ }
128
128
  }
129
129
 
130
130
  export default FolderElement;
@@ -1,6 +1,5 @@
1
1
  import { DropHint } from "../dragAndDropHandler/types";
2
- import { Node } from "../node";
3
- import { Position } from "../position";
2
+ import { Node, Position } from "../node";
4
3
 
5
4
  class GhostDropHint implements DropHint {
6
5
  private element: HTMLElement;
@@ -13,15 +12,15 @@ class GhostDropHint implements DropHint {
13
12
  this.ghost = this.createGhostElement();
14
13
 
15
14
  switch (position) {
16
- case Position.After:
15
+ case "after":
17
16
  this.moveAfter();
18
17
  break;
19
18
 
20
- case Position.Before:
19
+ case "before":
21
20
  this.moveBefore();
22
21
  break;
23
22
 
24
- case Position.Inside: {
23
+ case "inside": {
25
24
  if (node.isFolder() && node.is_open) {
26
25
  this.moveInsideOpenFolder();
27
26
  } else {
@@ -31,6 +30,10 @@ class GhostDropHint implements DropHint {
31
30
  }
32
31
  }
33
32
 
33
+ public remove(): void {
34
+ this.ghost.remove();
35
+ }
36
+
34
37
  private createGhostElement() {
35
38
  const ghost = document.createElement("li");
36
39
  ghost.className = "jqtree_common jqtree-ghost";
@@ -66,10 +69,6 @@ class GhostDropHint implements DropHint {
66
69
  childElement.before(this.ghost);
67
70
  }
68
71
  }
69
-
70
- public remove(): void {
71
- this.ghost.remove();
72
- }
73
72
  }
74
73
 
75
74
  export default GhostDropHint;