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
@@ -3,22 +3,20 @@ import { DragAndDropHandler } from "./dragAndDropHandler";
3
3
  import ElementsRenderer from "./elementsRenderer";
4
4
  import DataLoader, { HandleFinishedLoading } from "./dataLoader";
5
5
  import KeyHandler from "./keyHandler";
6
- import MouseWidget from "./mouse.widget";
7
- import { PositionInfo } from "./types";
6
+ import MouseHandler from "./mouseHandler";
7
+ import { PositionInfo } from "./mouseUtils";
8
8
  import SaveStateHandler, { SavedState } from "./saveStateHandler";
9
9
  import ScrollHandler from "./scrollHandler";
10
10
  import SelectNodeHandler from "./selectNodeHandler";
11
11
  import SimpleWidget from "./simple.widget";
12
- import { Node, getPosition } from "./node";
13
- import { isFunction } from "./util";
14
- import { FolderElement, NodeElement, OnFinishOpenNode } from "./nodeElement";
12
+ import { getOffsetTop, isFunction } from "./util";
13
+ import { Node } from "./node";
14
+ import { getPosition } from "./position";
15
+ import NodeElement from "./nodeElement";
16
+ import FolderElement from "./nodeElement/folderElement";
17
+ import { OnFinishOpenNode } from "./jqtreeMethodTypes";
15
18
  import { JQTreeOptions } from "./jqtreeOptions";
16
19
 
17
- interface ClickTarget {
18
- node: Node;
19
- type: "button" | "label";
20
- }
21
-
22
20
  interface SelectNodeOptions {
23
21
  mustToggle?: boolean;
24
22
  mustSetFocus?: boolean;
@@ -27,7 +25,7 @@ interface SelectNodeOptions {
27
25
  const NODE_PARAM_IS_EMPTY = "Node parameter is empty";
28
26
  const PARAM_IS_EMPTY = "Parameter is empty: ";
29
27
 
30
- export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
28
+ export class JqTreeWidget extends SimpleWidget<JQTreeOptions> {
31
29
  protected static defaults: JQTreeOptions = {
32
30
  animationSpeed: "fast",
33
31
  autoEscape: true,
@@ -67,17 +65,18 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
67
65
  useContextMenu: true,
68
66
  };
69
67
 
70
- public element: JQuery;
71
- public tree: Node;
72
- public dndHandler: DragAndDropHandler;
73
- public renderer: ElementsRenderer;
74
- public dataLoader: DataLoader;
75
- public scrollHandler: ScrollHandler;
76
- public selectNodeHandler: SelectNodeHandler;
77
-
68
+ private element: JQuery;
78
69
  private isInitialized: boolean;
79
- private saveStateHandler: SaveStateHandler;
70
+ private tree: Node;
71
+
72
+ private dataLoader: DataLoader;
73
+ private dndHandler: DragAndDropHandler;
80
74
  private keyHandler: KeyHandler;
75
+ private mouseHandler: MouseHandler;
76
+ private renderer: ElementsRenderer;
77
+ private saveStateHandler: SaveStateHandler;
78
+ private scrollHandler: ScrollHandler;
79
+ private selectNodeHandler: SelectNodeHandler;
81
80
 
82
81
  public toggle(node: Node, slideParam: null | boolean = null): JQuery {
83
82
  if (!node) {
@@ -164,7 +163,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
164
163
  }
165
164
 
166
165
  public refresh(): JQuery {
167
- this._refreshElements(null);
166
+ this.refreshElements(null);
168
167
  return this.element;
169
168
  }
170
169
 
@@ -185,9 +184,18 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
185
184
  }
186
185
 
187
186
  public getNodeByHtmlElement(
188
- element: HTMLElement | JQuery<HTMLElement>,
187
+ inputElement: HTMLElement | JQuery<HTMLElement>,
189
188
  ): Node | null {
190
- return this.getNode(jQuery(element));
189
+ const element =
190
+ inputElement instanceof HTMLElement
191
+ ? inputElement
192
+ : inputElement[0];
193
+
194
+ if (!element) {
195
+ return null;
196
+ }
197
+
198
+ return this.getNode(element);
191
199
  }
192
200
 
193
201
  public getNodeByCallback(callback: (node: Node) => boolean): Node | null {
@@ -203,12 +211,12 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
203
211
  throw Error(NODE_PARAM_IS_EMPTY);
204
212
  }
205
213
 
206
- const parseParams = (): [boolean, OnFinishOpenNode | null] => {
214
+ const parseParams = (): [boolean, OnFinishOpenNode | undefined] => {
207
215
  let onFinished: OnFinishOpenNode | null;
208
216
  let slide: boolean | null;
209
217
 
210
218
  if (isFunction(param1)) {
211
- onFinished = param1 as OnFinishOpenNode | null;
219
+ onFinished = param1 as OnFinishOpenNode;
212
220
  slide = null;
213
221
  } else {
214
222
  slide = param1 as boolean;
@@ -224,7 +232,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
224
232
 
225
233
  const [slide, onFinished] = parseParams();
226
234
 
227
- this._openNode(node, slide, onFinished);
235
+ this.openNodeInternal(node, slide, onFinished);
228
236
  return this.element;
229
237
  }
230
238
 
@@ -236,7 +244,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
236
244
  const slide = slideParam ?? this.options.slide;
237
245
 
238
246
  if (node.isFolder() || node.isEmptyFolder) {
239
- new FolderElement(node, this).close(
247
+ this.createFolderElement(node).close(
240
248
  slide,
241
249
  this.options.animationSpeed,
242
250
  );
@@ -263,7 +271,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
263
271
  const newNode = existingNode.addAfter(newNodeInfo);
264
272
 
265
273
  if (newNode) {
266
- this._refreshElements(existingNode.parent);
274
+ this.refreshElements(existingNode.parent);
267
275
  }
268
276
 
269
277
  return newNode;
@@ -280,7 +288,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
280
288
  const newNode = existingNode.addBefore(newNodeInfo);
281
289
 
282
290
  if (newNode) {
283
- this._refreshElements(existingNode.parent);
291
+ this.refreshElements(existingNode.parent);
284
292
  }
285
293
 
286
294
  return newNode;
@@ -297,7 +305,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
297
305
  const newNode = existingNode.addParent(newNodeInfo);
298
306
 
299
307
  if (newNode) {
300
- this._refreshElements(newNode.parent);
308
+ this.refreshElements(newNode.parent);
301
309
  }
302
310
 
303
311
  return newNode;
@@ -316,7 +324,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
316
324
 
317
325
  const parent = node.parent;
318
326
  node.remove();
319
- this._refreshElements(parent);
327
+ this.refreshElements(parent);
320
328
 
321
329
  return this.element;
322
330
  }
@@ -326,7 +334,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
326
334
 
327
335
  const node = parentNode.append(newNodeInfo);
328
336
 
329
- this._refreshElements(parentNode);
337
+ this.refreshElements(parentNode);
330
338
 
331
339
  return node;
332
340
  }
@@ -336,7 +344,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
336
344
 
337
345
  const node = parentNode.prepend(newNodeInfo);
338
346
 
339
- this._refreshElements(parentNode);
347
+ this.refreshElements(parentNode);
340
348
 
341
349
  return node;
342
350
  }
@@ -371,7 +379,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
371
379
  }
372
380
  }
373
381
 
374
- this._refreshElements(node);
382
+ this.refreshElements(node);
375
383
 
376
384
  return this.element;
377
385
  }
@@ -399,7 +407,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
399
407
 
400
408
  if (positionIndex !== undefined) {
401
409
  this.tree.moveNode(node, targetNode, positionIndex);
402
- this._refreshElements(null);
410
+ this.refreshElements(null);
403
411
  }
404
412
 
405
413
  return this.element;
@@ -415,8 +423,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
415
423
  }
416
424
 
417
425
  this.selectNodeHandler.addToSelection(node);
426
+ this.openParents(node);
418
427
 
419
- this._getNodeElementForNode(node).select(
428
+ this.getNodeElementForNode(node).select(
420
429
  mustSetFocus === undefined ? true : mustSetFocus,
421
430
  );
422
431
 
@@ -444,7 +453,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
444
453
 
445
454
  this.selectNodeHandler.removeFromSelection(node);
446
455
 
447
- this._getNodeElementForNode(node).deselect();
456
+ this.getNodeElementForNode(node).deselect();
448
457
  this.saveState();
449
458
 
450
459
  return this.element;
@@ -455,9 +464,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
455
464
  throw Error(NODE_PARAM_IS_EMPTY);
456
465
  }
457
466
 
458
- const nodeTop = jQuery(node.element).offset()?.top ?? 0;
459
- const treeTop = this.$el.offset()?.top ?? 0;
460
- const top = nodeTop - treeTop;
467
+ const top =
468
+ getOffsetTop(node.element) -
469
+ getOffsetTop(this.$el.get(0) as HTMLElement);
461
470
 
462
471
  this.scrollHandler.scrollToY(top);
463
472
 
@@ -470,7 +479,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
470
479
 
471
480
  public setState(state: SavedState): JQuery {
472
481
  this.saveStateHandler.setInitialState(state);
473
- this._refreshElements(null);
482
+ this.refreshElements(null);
474
483
 
475
484
  return this.element;
476
485
  }
@@ -502,26 +511,17 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
502
511
  return __version__;
503
512
  }
504
513
 
505
- public _triggerEvent(
506
- eventName: string,
507
- values?: Record<string, unknown>,
508
- ): JQuery.Event {
509
- const event = jQuery.Event(eventName, values);
510
- this.element.trigger(event);
511
- return event;
512
- }
513
-
514
- public _openNode(
514
+ private openNodeInternal(
515
515
  node: Node,
516
516
  slide = true,
517
- onFinished: OnFinishOpenNode | null,
517
+ onFinished?: OnFinishOpenNode,
518
518
  ): void {
519
519
  const doOpenNode = (
520
520
  _node: Node,
521
521
  _slide: boolean,
522
- _onFinished: OnFinishOpenNode | null,
522
+ _onFinished?: OnFinishOpenNode,
523
523
  ): void => {
524
- const folderElement = new FolderElement(_node, this);
524
+ const folderElement = this.createFolderElement(_node);
525
525
  folderElement.open(
526
526
  _onFinished,
527
527
  _slide,
@@ -538,7 +538,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
538
538
  while (parent) {
539
539
  // nb: do not open root element
540
540
  if (parent.parent) {
541
- doOpenNode(parent, false, null);
541
+ doOpenNode(parent, false);
542
542
  }
543
543
  parent = parent.parent;
544
544
  }
@@ -553,8 +553,8 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
553
553
  Redraw the tree or part of the tree.
554
554
  from_node: redraw this subtree
555
555
  */
556
- public _refreshElements(fromNode: Node | null): void {
557
- const mustSetFocus = this.selectNodeHandler.isFocusOnTree();
556
+ private refreshElements(fromNode: Node | null): void {
557
+ const mustSetFocus = this.isFocusOnTree();
558
558
  const mustSelect = fromNode
559
559
  ? this.isSelectedNodeInSubtree(fromNode)
560
560
  : false;
@@ -565,36 +565,26 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
565
565
  this.selectCurrentNode(mustSetFocus);
566
566
  }
567
567
 
568
- this._triggerEvent("tree.refresh");
568
+ this.triggerEvent("tree.refresh");
569
569
  }
570
570
 
571
- public _getNodeElementForNode(node: Node): NodeElement {
571
+ private getNodeElementForNode(node: Node): NodeElement {
572
572
  if (node.isFolder()) {
573
- return new FolderElement(node, this);
573
+ return this.createFolderElement(node);
574
574
  } else {
575
- return new NodeElement(node, this);
575
+ return this.createNodeElement(node);
576
576
  }
577
577
  }
578
578
 
579
- public _getNodeElement($element: JQuery<HTMLElement>): NodeElement | null {
580
- const node = this.getNode($element);
579
+ private getNodeElement(element: HTMLElement): NodeElement | null {
580
+ const node = this.getNode(element);
581
581
  if (node) {
582
- return this._getNodeElementForNode(node);
582
+ return this.getNodeElementForNode(node);
583
583
  } else {
584
584
  return null;
585
585
  }
586
586
  }
587
587
 
588
- public _containsElement(element: HTMLElement): boolean {
589
- const node = this.getNode(jQuery(element));
590
-
591
- return node != null && node.tree === this.tree;
592
- }
593
-
594
- public _getScrollLeft(): number {
595
- return this.scrollHandler.getScrollLeft();
596
- }
597
-
598
588
  public init(): void {
599
589
  super.init();
600
590
 
@@ -607,22 +597,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
607
597
  this.options.closedIcon = this.getDefaultClosedIcon();
608
598
  }
609
599
 
610
- this.renderer = new ElementsRenderer(this);
611
- this.dataLoader = new DataLoader(this);
612
- this.saveStateHandler = new SaveStateHandler(this);
613
- this.selectNodeHandler = new SelectNodeHandler(this);
614
- this.dndHandler = new DragAndDropHandler(this);
615
- this.scrollHandler = new ScrollHandler(this);
616
- this.keyHandler = new KeyHandler(this);
600
+ this.connectHandlers();
617
601
 
618
602
  this.initData();
619
-
620
- this.element.on("click", this.handleClick);
621
- this.element.on("dblclick", this.handleDblclick);
622
-
623
- if (this.options.useContextMenu) {
624
- this.element.on("contextmenu", this.handleContextmenu);
625
- }
626
603
  }
627
604
 
628
605
  public deinit(): void {
@@ -630,13 +607,23 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
630
607
  this.element.off();
631
608
 
632
609
  this.keyHandler.deinit();
610
+ this.mouseHandler.deinit();
633
611
 
634
612
  this.tree = new Node({}, true);
635
613
 
636
614
  super.deinit();
637
615
  }
638
616
 
639
- protected mouseCapture(positionInfo: PositionInfo): boolean | null {
617
+ private triggerEvent(
618
+ eventName: string,
619
+ values?: Record<string, unknown>,
620
+ ): JQuery.Event {
621
+ const event = jQuery.Event(eventName, values);
622
+ this.element.trigger(event);
623
+ return event;
624
+ }
625
+
626
+ private mouseCapture(positionInfo: PositionInfo): boolean | null {
640
627
  if (this.options.dragAndDrop) {
641
628
  return this.dndHandler.mouseCapture(positionInfo);
642
629
  } else {
@@ -644,7 +631,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
644
631
  }
645
632
  }
646
633
 
647
- protected mouseStart(positionInfo: PositionInfo): boolean {
634
+ private mouseStart(positionInfo: PositionInfo): boolean {
648
635
  if (this.options.dragAndDrop) {
649
636
  return this.dndHandler.mouseStart(positionInfo);
650
637
  } else {
@@ -652,7 +639,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
652
639
  }
653
640
  }
654
641
 
655
- protected mouseDrag(positionInfo: PositionInfo): boolean {
642
+ private mouseDrag(positionInfo: PositionInfo): boolean {
656
643
  if (this.options.dragAndDrop) {
657
644
  const result = this.dndHandler.mouseDrag(positionInfo);
658
645
 
@@ -663,7 +650,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
663
650
  }
664
651
  }
665
652
 
666
- protected mouseStop(positionInfo: PositionInfo): boolean {
653
+ private mouseStop(positionInfo: PositionInfo): boolean {
667
654
  if (this.options.dragAndDrop) {
668
655
  this.scrollHandler.stopScrolling();
669
656
  return this.dndHandler.mouseStop(positionInfo);
@@ -672,10 +659,6 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
672
659
  }
673
660
  }
674
661
 
675
- protected getMouseDelay(): number {
676
- return this.options.startDndDelay ?? 0;
677
- }
678
-
679
662
  private initData(): void {
680
663
  if (this.options.data) {
681
664
  this.doLoadData(this.options.data, null);
@@ -741,7 +724,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
741
724
  const doInit = (): void => {
742
725
  if (!this.isInitialized) {
743
726
  this.isInitialized = true;
744
- this._triggerEvent("tree.init");
727
+ this.triggerEvent("tree.init");
745
728
  }
746
729
  };
747
730
 
@@ -761,7 +744,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
761
744
 
762
745
  const mustLoadOnDemand = this.setInitialState();
763
746
 
764
- this._refreshElements(null);
747
+ this.refreshElements(null);
765
748
 
766
749
  if (!mustLoadOnDemand) {
767
750
  doInit();
@@ -854,7 +837,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
854
837
 
855
838
  const loadAndOpenNode = (node: Node): void => {
856
839
  loadingCount += 1;
857
- this._openNode(node, false, () => {
840
+ this.openNodeInternal(node, false, () => {
858
841
  loadingCount -= 1;
859
842
  openNodes();
860
843
  });
@@ -869,7 +852,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
869
852
 
870
853
  return false;
871
854
  } else {
872
- this._openNode(node, false, null);
855
+ this.openNodeInternal(node, false);
873
856
 
874
857
  return level !== maxLevel;
875
858
  }
@@ -900,104 +883,16 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
900
883
  }
901
884
  }
902
885
 
903
- private handleClick = (
904
- e: JQuery.ClickEvent<HTMLElement, any, HTMLElement, HTMLElement>,
905
- ): void => {
906
- const clickTarget = this.getClickTarget(e.target);
907
-
908
- if (clickTarget) {
909
- if (clickTarget.type === "button") {
910
- this.toggle(clickTarget.node, this.options.slide);
911
-
912
- e.preventDefault();
913
- e.stopPropagation();
914
- } else if (clickTarget.type === "label") {
915
- const node = clickTarget.node;
916
- const event = this._triggerEvent("tree.click", {
917
- node,
918
- click_event: e,
919
- });
920
-
921
- if (!event.isDefaultPrevented()) {
922
- this.doSelectNode(node);
923
- }
924
- }
925
- }
926
- };
927
-
928
- private handleDblclick = (
929
- e: JQuery.DoubleClickEvent<HTMLElement, any, HTMLElement, HTMLElement>,
930
- ): void => {
931
- const clickTarget = this.getClickTarget(e.target);
932
-
933
- if (clickTarget?.type === "label") {
934
- this._triggerEvent("tree.dblclick", {
935
- node: clickTarget.node,
936
- click_event: e,
937
- });
938
- }
939
- };
940
-
941
- private getClickTarget(element: EventTarget): ClickTarget | null {
942
- const $target = jQuery(element);
943
-
944
- const $button = $target.closest(".jqtree-toggler");
945
-
946
- if ($button.length) {
947
- const node = this.getNode($button as JQuery<HTMLElement>);
886
+ private getNode(element: HTMLElement): null | Node {
887
+ const liElement = element.closest("li.jqtree_common");
948
888
 
949
- if (node) {
950
- return {
951
- type: "button",
952
- node,
953
- };
954
- }
889
+ if (liElement) {
890
+ return jQuery(liElement).data("node") as Node;
955
891
  } else {
956
- const $el = $target.closest(".jqtree-element");
957
- if ($el.length) {
958
- const node = this.getNode($el as JQuery<HTMLElement>);
959
- if (node) {
960
- return {
961
- type: "label",
962
- node,
963
- };
964
- }
965
- }
966
- }
967
-
968
- return null;
969
- }
970
-
971
- private getNode($element: JQuery<HTMLElement>): null | Node {
972
- const $li = $element.closest("li.jqtree_common");
973
- if ($li.length === 0) {
974
892
  return null;
975
- } else {
976
- return $li.data("node") as Node;
977
893
  }
978
894
  }
979
895
 
980
- private handleContextmenu = (
981
- e: JQuery.ContextMenuEvent<HTMLElement, any, HTMLElement, HTMLElement>,
982
- ) => {
983
- const $div = jQuery(e.target).closest("ul.jqtree-tree .jqtree-element");
984
- if ($div.length) {
985
- const node = this.getNode($div);
986
- if (node) {
987
- e.preventDefault();
988
- e.stopPropagation();
989
-
990
- this._triggerEvent("tree.contextmenu", {
991
- node,
992
- click_event: e,
993
- });
994
- return false;
995
- }
996
- }
997
-
998
- return null;
999
- };
1000
-
1001
896
  private saveState(): void {
1002
897
  if (this.options.saveState) {
1003
898
  this.saveStateHandler.saveState();
@@ -1007,7 +902,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1007
902
  private selectCurrentNode(mustSetFocus: boolean): void {
1008
903
  const node = this.getSelectedNode();
1009
904
  if (node) {
1010
- const nodeElement = this._getNodeElementForNode(node);
905
+ const nodeElement = this.getNodeElementForNode(node);
1011
906
  if (nodeElement) {
1012
907
  nodeElement.select(mustSetFocus);
1013
908
  }
@@ -1079,14 +974,6 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1079
974
  }
1080
975
  };
1081
976
 
1082
- const openParents = (): void => {
1083
- const parent = node.parent;
1084
-
1085
- if (parent && parent.parent && !parent.is_open) {
1086
- this.openNode(parent, false);
1087
- }
1088
- };
1089
-
1090
977
  if (!canSelect()) {
1091
978
  return;
1092
979
  }
@@ -1094,7 +981,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1094
981
  if (this.selectNodeHandler.isNodeSelected(node)) {
1095
982
  if (selectOptions.mustToggle) {
1096
983
  this.deselectCurrentNode();
1097
- this._triggerEvent("tree.select", {
984
+ this.triggerEvent("tree.select", {
1098
985
  node: null,
1099
986
  previous_node: node,
1100
987
  });
@@ -1104,11 +991,11 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1104
991
  this.deselectCurrentNode();
1105
992
  this.addToSelection(node, selectOptions.mustSetFocus);
1106
993
 
1107
- this._triggerEvent("tree.select", {
994
+ this.triggerEvent("tree.select", {
1108
995
  node,
1109
996
  deselected_node: deselectedNode,
1110
997
  });
1111
- openParents();
998
+ this.openParents(node);
1112
999
  }
1113
1000
 
1114
1001
  saveState();
@@ -1128,7 +1015,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1128
1015
  }
1129
1016
  }
1130
1017
 
1131
- this._triggerEvent("tree.load_data", {
1018
+ this.triggerEvent("tree.load_data", {
1132
1019
  tree_data: data,
1133
1020
  parent_node: parentNode,
1134
1021
  });
@@ -1148,7 +1035,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1148
1035
  parentNode.load_on_demand = false;
1149
1036
  parentNode.is_loading = false;
1150
1037
 
1151
- this._refreshElements(parentNode);
1038
+ this.refreshElements(parentNode);
1152
1039
  }
1153
1040
 
1154
1041
  private doLoadDataFromUrl(
@@ -1164,13 +1051,232 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1164
1051
  private loadFolderOnDemand(
1165
1052
  node: Node,
1166
1053
  slide = true,
1167
- onFinished: OnFinishOpenNode | null,
1054
+ onFinished?: OnFinishOpenNode,
1168
1055
  ): void {
1169
1056
  node.is_loading = true;
1170
1057
 
1171
1058
  this.doLoadDataFromUrl(null, node, () => {
1172
- this._openNode(node, slide, onFinished);
1059
+ this.openNodeInternal(node, slide, onFinished);
1060
+ });
1061
+ }
1062
+
1063
+ private containsElement(element: HTMLElement): boolean {
1064
+ const node = this.getNode(element);
1065
+
1066
+ return node != null && node.tree === this.tree;
1067
+ }
1068
+
1069
+ private isFocusOnTree(): boolean {
1070
+ const activeElement = document.activeElement;
1071
+
1072
+ return Boolean(
1073
+ activeElement &&
1074
+ activeElement.tagName === "SPAN" &&
1075
+ this.containsElement(activeElement as HTMLElement),
1076
+ );
1077
+ }
1078
+
1079
+ private connectHandlers() {
1080
+ const {
1081
+ autoEscape,
1082
+ buttonLeft,
1083
+ closedIcon,
1084
+ dataFilter,
1085
+ dragAndDrop,
1086
+ keyboardSupport,
1087
+ onCanMove,
1088
+ onCanMoveTo,
1089
+ onCreateLi,
1090
+ onDragMove,
1091
+ onDragStop,
1092
+ onGetStateFromStorage,
1093
+ onIsMoveHandle,
1094
+ onLoadFailed,
1095
+ onLoading,
1096
+ onSetStateFromStorage,
1097
+ openedIcon,
1098
+ openFolderDelay,
1099
+ rtl,
1100
+ saveState,
1101
+ showEmptyFolder,
1102
+ slide,
1103
+ tabIndex,
1104
+ } = this.options;
1105
+
1106
+ const closeNode = this.closeNode.bind(this);
1107
+ const getNodeElement = this.getNodeElement.bind(this);
1108
+ const getNodeElementForNode = this.getNodeElementForNode.bind(this);
1109
+ const getNodeById = this.getNodeById.bind(this);
1110
+ const getSelectedNode = this.getSelectedNode.bind(this);
1111
+ const getTree = this.getTree.bind(this);
1112
+ const isFocusOnTree = this.isFocusOnTree.bind(this);
1113
+ const loadData = this.loadData.bind(this);
1114
+ const openNode = this.openNodeInternal.bind(this);
1115
+ const refreshElements = this.refreshElements.bind(this);
1116
+ const refreshHitAreas = this.refreshHitAreas.bind(this);
1117
+ const selectNode = this.selectNode.bind(this);
1118
+ const $treeElement = this.element;
1119
+ const treeElement = this.element.get(0) as HTMLElement;
1120
+ const triggerEvent = this.triggerEvent.bind(this);
1121
+
1122
+ const selectNodeHandler = new SelectNodeHandler({
1123
+ getNodeById,
1173
1124
  });
1125
+
1126
+ const addToSelection =
1127
+ selectNodeHandler.addToSelection.bind(selectNodeHandler);
1128
+ const getSelectedNodes =
1129
+ selectNodeHandler.getSelectedNodes.bind(selectNodeHandler);
1130
+ const isNodeSelected =
1131
+ selectNodeHandler.isNodeSelected.bind(selectNodeHandler);
1132
+ const removeFromSelection =
1133
+ selectNodeHandler.removeFromSelection.bind(selectNodeHandler);
1134
+ const getMouseDelay = () => this.options.startDndDelay ?? 0;
1135
+
1136
+ const dataLoader = new DataLoader({
1137
+ dataFilter,
1138
+ loadData,
1139
+ onLoadFailed,
1140
+ onLoading,
1141
+ treeElement,
1142
+ triggerEvent,
1143
+ });
1144
+
1145
+ const saveStateHandler = new SaveStateHandler({
1146
+ addToSelection,
1147
+ getNodeById,
1148
+ getSelectedNodes,
1149
+ getTree,
1150
+ onGetStateFromStorage,
1151
+ onSetStateFromStorage,
1152
+ openNode,
1153
+ refreshElements,
1154
+ removeFromSelection,
1155
+ saveState,
1156
+ });
1157
+
1158
+ const scrollHandler = new ScrollHandler({
1159
+ refreshHitAreas,
1160
+ treeElement,
1161
+ });
1162
+
1163
+ const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);
1164
+
1165
+ const dndHandler = new DragAndDropHandler({
1166
+ autoEscape,
1167
+ getNodeElement,
1168
+ getNodeElementForNode,
1169
+ getScrollLeft,
1170
+ getTree,
1171
+ onCanMove,
1172
+ onCanMoveTo,
1173
+ onDragMove,
1174
+ onDragStop,
1175
+ onIsMoveHandle,
1176
+ openFolderDelay,
1177
+ openNode,
1178
+ refreshElements,
1179
+ slide,
1180
+ treeElement,
1181
+ triggerEvent,
1182
+ });
1183
+
1184
+ const keyHandler = new KeyHandler({
1185
+ closeNode,
1186
+ getSelectedNode,
1187
+ isFocusOnTree,
1188
+ keyboardSupport,
1189
+ openNode,
1190
+ selectNode,
1191
+ });
1192
+
1193
+ const renderer = new ElementsRenderer({
1194
+ autoEscape,
1195
+ buttonLeft,
1196
+ closedIcon,
1197
+ dragAndDrop,
1198
+ $element: $treeElement,
1199
+ getTree,
1200
+ isNodeSelected,
1201
+ onCreateLi,
1202
+ openedIcon,
1203
+ rtl,
1204
+ showEmptyFolder,
1205
+ tabIndex,
1206
+ });
1207
+
1208
+ const getNode = this.getNode.bind(this);
1209
+ const onMouseCapture = this.mouseCapture.bind(this);
1210
+ const onMouseDrag = this.mouseDrag.bind(this);
1211
+ const onMouseStart = this.mouseStart.bind(this);
1212
+ const onMouseStop = this.mouseStop.bind(this);
1213
+
1214
+ const mouseHandler = new MouseHandler({
1215
+ element: treeElement,
1216
+ getMouseDelay,
1217
+ getNode,
1218
+ onClickButton: this.toggle.bind(this),
1219
+ onClickTitle: this.doSelectNode.bind(this),
1220
+ onMouseCapture,
1221
+ onMouseDrag,
1222
+ onMouseStart,
1223
+ onMouseStop,
1224
+ triggerEvent,
1225
+ useContextMenu: this.options.useContextMenu,
1226
+ });
1227
+
1228
+ this.dataLoader = dataLoader;
1229
+ this.dndHandler = dndHandler;
1230
+ this.keyHandler = keyHandler;
1231
+ this.mouseHandler = mouseHandler;
1232
+ this.renderer = renderer;
1233
+ this.saveStateHandler = saveStateHandler;
1234
+ this.scrollHandler = scrollHandler;
1235
+ this.selectNodeHandler = selectNodeHandler;
1236
+ }
1237
+
1238
+ private createFolderElement(node: Node) {
1239
+ const closedIconElement = this.renderer.closedIconElement;
1240
+ const getScrollLeft = this.scrollHandler.getScrollLeft.bind(
1241
+ this.scrollHandler,
1242
+ );
1243
+ const openedIconElement = this.renderer.openedIconElement;
1244
+ const tabIndex = this.options.tabIndex;
1245
+ const $treeElement = this.element;
1246
+ const triggerEvent = this.triggerEvent.bind(this);
1247
+
1248
+ return new FolderElement({
1249
+ closedIconElement,
1250
+ getScrollLeft,
1251
+ node,
1252
+ openedIconElement,
1253
+ tabIndex,
1254
+ $treeElement,
1255
+ triggerEvent,
1256
+ });
1257
+ }
1258
+
1259
+ private createNodeElement(node: Node) {
1260
+ const getScrollLeft = this.scrollHandler.getScrollLeft.bind(
1261
+ this.scrollHandler,
1262
+ );
1263
+ const tabIndex = this.options.tabIndex;
1264
+ const $treeElement = this.element;
1265
+
1266
+ return new NodeElement({
1267
+ getScrollLeft,
1268
+ node,
1269
+ tabIndex,
1270
+ $treeElement,
1271
+ });
1272
+ }
1273
+
1274
+ private openParents(node: Node) {
1275
+ const parent = node.parent;
1276
+
1277
+ if (parent && parent.parent && !parent.is_open) {
1278
+ this.openNode(parent, false);
1279
+ }
1174
1280
  }
1175
1281
  }
1176
1282