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,17 +1,3 @@
1
- import { Node } from "../node";
2
- import { getPositionName, Position } from "../position";
3
- import { DropHint, HitArea } from "./types";
4
- import { PositionInfo } from "../mouseUtils";
5
- import NodeElement from "../nodeElement";
6
- import DragElement from "./dragElement";
7
- import generateHitAreas from "./generateHitAreas";
8
- import { getElementPosition } from "../util";
9
- import {
10
- OnCanMove,
11
- OnCanMoveTo,
12
- OnIsMoveHandle,
13
- DragMethod,
14
- } from "../jqtreeOptions";
15
1
  import {
16
2
  GetScrollLeft,
17
3
  GetTree,
@@ -19,12 +5,26 @@ import {
19
5
  RefreshElements,
20
6
  TriggerEvent,
21
7
  } from "../jqtreeMethodTypes";
8
+ import {
9
+ DragMethod,
10
+ OnCanMove,
11
+ OnCanMoveTo,
12
+ OnIsMoveHandle,
13
+ } from "../jqtreeOptions";
14
+ import { PositionInfo } from "../mouseUtils";
15
+ import { Node } from "../node";
16
+ import NodeElement from "../nodeElement";
17
+ import { getPositionName, Position } from "../position";
18
+ import { getElementPosition } from "../util";
19
+ import DragElement from "./dragElement";
20
+ import generateHitAreas from "./generateHitAreas";
21
+ import { DropHint, HitArea } from "./types";
22
22
 
23
23
  interface Dimensions {
24
+ bottom: number;
24
25
  left: number;
25
- top: number;
26
26
  right: number;
27
- bottom: number;
27
+ top: number;
28
28
  }
29
29
 
30
30
  type GetNodeElement = (element: HTMLElement) => NodeElement | null;
@@ -41,7 +41,7 @@ interface DragAndDropHandlerParams {
41
41
  onDragMove?: DragMethod;
42
42
  onDragStop?: DragMethod;
43
43
  onIsMoveHandle?: OnIsMoveHandle;
44
- openFolderDelay: number | false;
44
+ openFolderDelay: false | number;
45
45
  openNode: OpenNode;
46
46
  refreshElements: RefreshElements;
47
47
  slide: boolean;
@@ -50,15 +50,11 @@ interface DragAndDropHandlerParams {
50
50
  }
51
51
 
52
52
  export class DragAndDropHandler {
53
- public hitAreas: HitArea[];
54
- public isDragging: boolean;
55
- public currentItem: NodeElement | null;
56
- public hoveredArea: HitArea | null;
57
-
58
53
  private autoEscape?: boolean;
59
54
  private dragElement: DragElement | null;
60
55
  private getNodeElement: GetNodeElement;
61
56
  private getNodeElementForNode: GetNodeElementForNode;
57
+
62
58
  private getScrollLeft: GetScrollLeft;
63
59
  private getTree: GetTree;
64
60
  private onCanMove?: OnCanMove;
@@ -66,14 +62,18 @@ export class DragAndDropHandler {
66
62
  private onDragMove?: DragMethod;
67
63
  private onDragStop?: DragMethod;
68
64
  private onIsMoveHandle?: OnIsMoveHandle;
69
- private openFolderDelay: number | false;
70
- private openFolderTimer: number | null;
65
+ private openFolderDelay: false | number;
66
+ private openFolderTimer: null | number;
71
67
  private openNode: OpenNode;
72
68
  private previousGhost: DropHint | null;
73
69
  private refreshElements: RefreshElements;
74
70
  private slide: boolean;
75
71
  private treeElement: HTMLElement;
76
72
  private triggerEvent: TriggerEvent;
73
+ public currentItem: NodeElement | null;
74
+ public hitAreas: HitArea[];
75
+ public hoveredArea: HitArea | null;
76
+ public isDragging: boolean;
77
77
 
78
78
  constructor({
79
79
  autoEscape,
@@ -114,166 +114,6 @@ export class DragAndDropHandler {
114
114
  this.currentItem = null;
115
115
  }
116
116
 
117
- public mouseCapture(positionInfo: PositionInfo): boolean | null {
118
- const element = positionInfo.target;
119
-
120
- if (!this.mustCaptureElement(element)) {
121
- return null;
122
- }
123
-
124
- if (this.onIsMoveHandle && !this.onIsMoveHandle(jQuery(element))) {
125
- return null;
126
- }
127
-
128
- let nodeElement = this.getNodeElement(element);
129
-
130
- if (nodeElement && this.onCanMove) {
131
- if (!this.onCanMove(nodeElement.node)) {
132
- nodeElement = null;
133
- }
134
- }
135
-
136
- this.currentItem = nodeElement;
137
- return this.currentItem != null;
138
- }
139
-
140
- public mouseStart(positionInfo: PositionInfo): boolean {
141
- if (!this.currentItem) {
142
- return false;
143
- }
144
-
145
- this.refresh();
146
-
147
- const { left, top } = getElementPosition(positionInfo.target);
148
-
149
- const node = this.currentItem.node;
150
-
151
- this.dragElement = new DragElement({
152
- autoEscape: this.autoEscape ?? true,
153
- nodeName: node.name,
154
- offsetX: positionInfo.pageX - left,
155
- offsetY: positionInfo.pageY - top,
156
- treeElement: this.treeElement,
157
- });
158
-
159
- this.isDragging = true;
160
- this.currentItem.element.classList.add("jqtree-moving");
161
-
162
- return true;
163
- }
164
-
165
- public mouseDrag(positionInfo: PositionInfo): boolean {
166
- if (!this.currentItem || !this.dragElement) {
167
- return false;
168
- }
169
-
170
- this.dragElement.move(positionInfo.pageX, positionInfo.pageY);
171
-
172
- const area = this.findHoveredArea(
173
- positionInfo.pageX,
174
- positionInfo.pageY,
175
- );
176
-
177
- if (area && this.canMoveToArea(area)) {
178
- if (!area.node.isFolder()) {
179
- this.stopOpenFolderTimer();
180
- }
181
-
182
- if (this.hoveredArea !== area) {
183
- this.hoveredArea = area;
184
-
185
- // If this is a closed folder, start timer to open it
186
- if (this.mustOpenFolderTimer(area)) {
187
- this.startOpenFolderTimer(area.node);
188
- } else {
189
- this.stopOpenFolderTimer();
190
- }
191
-
192
- this.updateDropHint();
193
- }
194
- } else {
195
- this.removeDropHint();
196
- this.stopOpenFolderTimer();
197
- this.hoveredArea = area;
198
- }
199
-
200
- if (!area) {
201
- if (this.onDragMove) {
202
- this.onDragMove(
203
- this.currentItem.node,
204
- positionInfo.originalEvent,
205
- );
206
- }
207
- }
208
-
209
- return true;
210
- }
211
-
212
- public mouseStop(positionInfo: PositionInfo): boolean {
213
- this.moveItem(positionInfo);
214
- this.clear();
215
- this.removeHover();
216
- this.removeDropHint();
217
- this.removeHitAreas();
218
-
219
- const currentItem = this.currentItem;
220
-
221
- if (this.currentItem) {
222
- this.currentItem.element.classList.remove("jqtree-moving");
223
- this.currentItem = null;
224
- }
225
-
226
- this.isDragging = false;
227
-
228
- if (!this.hoveredArea && currentItem) {
229
- if (this.onDragStop) {
230
- this.onDragStop(currentItem.node, positionInfo.originalEvent);
231
- }
232
- }
233
-
234
- return false;
235
- }
236
-
237
- public refresh(): void {
238
- this.removeHitAreas();
239
-
240
- if (this.currentItem) {
241
- this.generateHitAreas();
242
-
243
- this.currentItem = this.getNodeElementForNode(
244
- this.currentItem.node,
245
- );
246
-
247
- if (this.isDragging) {
248
- this.currentItem.element.classList.add("jqtree-moving");
249
- }
250
- }
251
- }
252
-
253
- private generateHitAreas(): void {
254
- const tree = this.getTree();
255
-
256
- if (!this.currentItem || !tree) {
257
- this.hitAreas = [];
258
- } else {
259
- this.hitAreas = generateHitAreas(
260
- tree,
261
- this.currentItem.node,
262
- this.getTreeDimensions().bottom,
263
- );
264
- }
265
- }
266
-
267
- private mustCaptureElement(element: HTMLElement): boolean {
268
- const nodeName = element.nodeName;
269
-
270
- return (
271
- nodeName !== "INPUT" &&
272
- nodeName !== "SELECT" &&
273
- nodeName !== "TEXTAREA"
274
- );
275
- }
276
-
277
117
  private canMoveToArea(area: HitArea): boolean {
278
118
  if (!this.onCanMoveTo) {
279
119
  return true;
@@ -288,10 +128,6 @@ export class DragAndDropHandler {
288
128
  return this.onCanMoveTo(this.currentItem.node, area.node, positionName);
289
129
  }
290
130
 
291
- private removeHitAreas(): void {
292
- this.hitAreas = [];
293
- }
294
-
295
131
  private clear(): void {
296
132
  if (this.dragElement) {
297
133
  this.dragElement.remove();
@@ -299,16 +135,6 @@ export class DragAndDropHandler {
299
135
  }
300
136
  }
301
137
 
302
- private removeDropHint(): void {
303
- if (this.previousGhost) {
304
- this.previousGhost.remove();
305
- }
306
- }
307
-
308
- private removeHover(): void {
309
- this.hoveredArea = null;
310
- }
311
-
312
138
  private findHoveredArea(x: number, y: number): HitArea | null {
313
139
  const dimensions = this.getTreeDimensions();
314
140
 
@@ -343,6 +169,89 @@ export class DragAndDropHandler {
343
169
  return null;
344
170
  }
345
171
 
172
+ private generateHitAreas(): void {
173
+ const tree = this.getTree();
174
+
175
+ if (!this.currentItem || !tree) {
176
+ this.hitAreas = [];
177
+ } else {
178
+ this.hitAreas = generateHitAreas(
179
+ tree,
180
+ this.currentItem.node,
181
+ this.getTreeDimensions().bottom,
182
+ );
183
+ }
184
+ }
185
+
186
+ private getTreeDimensions(): Dimensions {
187
+ // Return the dimensions of the tree. Add a margin to the bottom to allow
188
+ // to drag-and-drop after the last element.
189
+ const treePosition = getElementPosition(this.treeElement);
190
+ const left = treePosition.left + this.getScrollLeft();
191
+ const top = treePosition.top;
192
+
193
+ return {
194
+ bottom: top + this.treeElement.clientHeight + 16,
195
+ left,
196
+ right: left + this.treeElement.clientWidth,
197
+ top,
198
+ };
199
+ }
200
+
201
+ private moveItem(positionInfo: PositionInfo): void {
202
+ if (
203
+ this.currentItem &&
204
+ this.hoveredArea &&
205
+ this.hoveredArea.position !== Position.None &&
206
+ this.canMoveToArea(this.hoveredArea)
207
+ ) {
208
+ const movedNode = this.currentItem.node;
209
+ const targetNode = this.hoveredArea.node;
210
+ const position = this.hoveredArea.position;
211
+ const previousParent = movedNode.parent;
212
+
213
+ if (position === Position.Inside) {
214
+ this.hoveredArea.node.is_open = true;
215
+ }
216
+
217
+ const doMove = (): void => {
218
+ const tree = this.getTree();
219
+
220
+ if (tree) {
221
+ tree.moveNode(movedNode, targetNode, position);
222
+
223
+ this.treeElement.textContent = "";
224
+ this.refreshElements(null);
225
+ }
226
+ };
227
+
228
+ const event = this.triggerEvent("tree.move", {
229
+ move_info: {
230
+ do_move: doMove,
231
+ moved_node: movedNode,
232
+ original_event: positionInfo.originalEvent,
233
+ position: getPositionName(position),
234
+ previous_parent: previousParent,
235
+ target_node: targetNode,
236
+ },
237
+ });
238
+
239
+ if (!event.isDefaultPrevented()) {
240
+ doMove();
241
+ }
242
+ }
243
+ }
244
+
245
+ private mustCaptureElement(element: HTMLElement): boolean {
246
+ const nodeName = element.nodeName;
247
+
248
+ return (
249
+ nodeName !== "INPUT" &&
250
+ nodeName !== "SELECT" &&
251
+ nodeName !== "TEXTAREA"
252
+ );
253
+ }
254
+
346
255
  private mustOpenFolderTimer(area: HitArea): boolean {
347
256
  const node = area.node;
348
257
 
@@ -353,17 +262,18 @@ export class DragAndDropHandler {
353
262
  );
354
263
  }
355
264
 
356
- private updateDropHint(): void {
357
- if (!this.hoveredArea) {
358
- return;
265
+ private removeDropHint(): void {
266
+ if (this.previousGhost) {
267
+ this.previousGhost.remove();
359
268
  }
269
+ }
360
270
 
361
- // remove previous drop hint
362
- this.removeDropHint();
271
+ private removeHitAreas(): void {
272
+ this.hitAreas = [];
273
+ }
363
274
 
364
- // add new drop hint
365
- const nodeElement = this.getNodeElementForNode(this.hoveredArea.node);
366
- this.previousGhost = nodeElement.addDropHint(this.hoveredArea.position);
275
+ private removeHover(): void {
276
+ this.hoveredArea = null;
367
277
  }
368
278
 
369
279
  private startOpenFolderTimer(folder: Node): void {
@@ -393,62 +303,152 @@ export class DragAndDropHandler {
393
303
  }
394
304
  }
395
305
 
396
- private moveItem(positionInfo: PositionInfo): void {
397
- if (
398
- this.currentItem &&
399
- this.hoveredArea &&
400
- this.hoveredArea.position !== Position.None &&
401
- this.canMoveToArea(this.hoveredArea)
402
- ) {
403
- const movedNode = this.currentItem.node;
404
- const targetNode = this.hoveredArea.node;
405
- const position = this.hoveredArea.position;
406
- const previousParent = movedNode.parent;
306
+ private updateDropHint(): void {
307
+ if (!this.hoveredArea) {
308
+ return;
309
+ }
407
310
 
408
- if (position === Position.Inside) {
409
- this.hoveredArea.node.is_open = true;
311
+ // remove previous drop hint
312
+ this.removeDropHint();
313
+
314
+ // add new drop hint
315
+ const nodeElement = this.getNodeElementForNode(this.hoveredArea.node);
316
+ this.previousGhost = nodeElement.addDropHint(this.hoveredArea.position);
317
+ }
318
+
319
+ public mouseCapture(positionInfo: PositionInfo): boolean | null {
320
+ const element = positionInfo.target;
321
+
322
+ if (!this.mustCaptureElement(element)) {
323
+ return null;
324
+ }
325
+
326
+ if (this.onIsMoveHandle && !this.onIsMoveHandle(jQuery(element))) {
327
+ return null;
328
+ }
329
+
330
+ let nodeElement = this.getNodeElement(element);
331
+
332
+ if (nodeElement && this.onCanMove) {
333
+ if (!this.onCanMove(nodeElement.node)) {
334
+ nodeElement = null;
410
335
  }
336
+ }
411
337
 
412
- const doMove = (): void => {
413
- const tree = this.getTree();
338
+ this.currentItem = nodeElement;
339
+ return this.currentItem != null;
340
+ }
414
341
 
415
- if (tree) {
416
- tree.moveNode(movedNode, targetNode, position);
342
+ public mouseDrag(positionInfo: PositionInfo): boolean {
343
+ if (!this.currentItem || !this.dragElement) {
344
+ return false;
345
+ }
417
346
 
418
- this.treeElement.textContent = "";
419
- this.refreshElements(null);
347
+ this.dragElement.move(positionInfo.pageX, positionInfo.pageY);
348
+
349
+ const area = this.findHoveredArea(
350
+ positionInfo.pageX,
351
+ positionInfo.pageY,
352
+ );
353
+
354
+ if (area && this.canMoveToArea(area)) {
355
+ if (!area.node.isFolder()) {
356
+ this.stopOpenFolderTimer();
357
+ }
358
+
359
+ if (this.hoveredArea !== area) {
360
+ this.hoveredArea = area;
361
+
362
+ // If this is a closed folder, start timer to open it
363
+ if (this.mustOpenFolderTimer(area)) {
364
+ this.startOpenFolderTimer(area.node);
365
+ } else {
366
+ this.stopOpenFolderTimer();
420
367
  }
421
- };
422
368
 
423
- const event = this.triggerEvent("tree.move", {
424
- move_info: {
425
- moved_node: movedNode,
426
- target_node: targetNode,
427
- position: getPositionName(position),
428
- previous_parent: previousParent,
429
- do_move: doMove,
430
- original_event: positionInfo.originalEvent,
431
- },
432
- });
369
+ this.updateDropHint();
370
+ }
371
+ } else {
372
+ this.removeDropHint();
373
+ this.stopOpenFolderTimer();
374
+ this.hoveredArea = area;
375
+ }
433
376
 
434
- if (!event.isDefaultPrevented()) {
435
- doMove();
377
+ if (!area) {
378
+ if (this.onDragMove) {
379
+ this.onDragMove(
380
+ this.currentItem.node,
381
+ positionInfo.originalEvent,
382
+ );
436
383
  }
437
384
  }
385
+
386
+ return true;
438
387
  }
439
388
 
440
- private getTreeDimensions(): Dimensions {
441
- // Return the dimensions of the tree. Add a margin to the bottom to allow
442
- // to drag-and-drop after the last element.
443
- const treePosition = getElementPosition(this.treeElement);
444
- const left = treePosition.left + this.getScrollLeft();
445
- const top = treePosition.top;
389
+ public mouseStart(positionInfo: PositionInfo): boolean {
390
+ if (!this.currentItem) {
391
+ return false;
392
+ }
446
393
 
447
- return {
448
- left,
449
- top,
450
- right: left + this.treeElement.clientWidth,
451
- bottom: top + this.treeElement.clientHeight + 16,
452
- };
394
+ this.refresh();
395
+
396
+ const { left, top } = getElementPosition(positionInfo.target);
397
+
398
+ const node = this.currentItem.node;
399
+
400
+ this.dragElement = new DragElement({
401
+ autoEscape: this.autoEscape ?? true,
402
+ nodeName: node.name,
403
+ offsetX: positionInfo.pageX - left,
404
+ offsetY: positionInfo.pageY - top,
405
+ treeElement: this.treeElement,
406
+ });
407
+
408
+ this.isDragging = true;
409
+ this.currentItem.element.classList.add("jqtree-moving");
410
+
411
+ return true;
412
+ }
413
+
414
+ public mouseStop(positionInfo: PositionInfo): boolean {
415
+ this.moveItem(positionInfo);
416
+ this.clear();
417
+ this.removeHover();
418
+ this.removeDropHint();
419
+ this.removeHitAreas();
420
+
421
+ const currentItem = this.currentItem;
422
+
423
+ if (this.currentItem) {
424
+ this.currentItem.element.classList.remove("jqtree-moving");
425
+ this.currentItem = null;
426
+ }
427
+
428
+ this.isDragging = false;
429
+
430
+ if (!this.hoveredArea && currentItem) {
431
+ if (this.onDragStop) {
432
+ this.onDragStop(currentItem.node, positionInfo.originalEvent);
433
+ }
434
+ }
435
+
436
+ return false;
437
+ }
438
+
439
+ public refresh(): void {
440
+ this.removeHitAreas();
441
+
442
+ if (this.currentItem) {
443
+ this.generateHitAreas();
444
+
445
+ this.currentItem = this.getNodeElementForNode(
446
+ this.currentItem.node,
447
+ );
448
+
449
+ if (this.isDragging) {
450
+ this.currentItem.element.classList.add("jqtree-moving");
451
+ }
452
+ }
453
453
  }
454
454
  }
@@ -6,8 +6,8 @@ export interface DropHint {
6
6
  }
7
7
 
8
8
  export interface HitArea {
9
- top: number;
10
9
  bottom: number;
11
10
  node: Node;
12
11
  position: Position;
12
+ top: number;
13
13
  }