jqtree 1.8.8 → 1.8.10

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,7 +1,7 @@
1
1
  /*
2
- JqTree 1.8.8
2
+ JqTree 1.8.10
3
3
 
4
- Copyright 2024 Marco Braak
4
+ Copyright 2025 Marco Braak
5
5
 
6
6
  Licensed under the Apache License, Version 2.0 (the "License");
7
7
  you may not use this file except in compliance with the License.
@@ -37,6 +37,32 @@ var jqtree = (function (exports) {
37
37
  this.treeElement = treeElement;
38
38
  this.triggerEvent = triggerEvent;
39
39
  }
40
+ loadFromUrl(urlInfo, parentNode, onFinished) {
41
+ if (!urlInfo) {
42
+ return;
43
+ }
44
+ const element = this.getDomElement(parentNode);
45
+ this.addLoadingClass(element);
46
+ this.notifyLoading(true, parentNode, element);
47
+ const stopLoading = () => {
48
+ this.removeLoadingClass(element);
49
+ this.notifyLoading(false, parentNode, element);
50
+ };
51
+ const handleSuccess = data => {
52
+ stopLoading();
53
+ this.loadData(this.parseData(data), parentNode);
54
+ if (onFinished && typeof onFinished === "function") {
55
+ onFinished();
56
+ }
57
+ };
58
+ const handleError = jqXHR => {
59
+ stopLoading();
60
+ if (this.onLoadFailed) {
61
+ this.onLoadFailed(jqXHR);
62
+ }
63
+ };
64
+ this.submitRequest(urlInfo, handleSuccess, handleError);
65
+ }
40
66
  addLoadingClass(element) {
41
67
  element.classList.add("jqtree-loading");
42
68
  }
@@ -91,59 +117,8 @@ var jqtree = (function (exports) {
91
117
  ajaxSettings.method = ajaxSettings.method?.toUpperCase() ?? "GET";
92
118
  void jQuery.ajax(ajaxSettings);
93
119
  }
94
- loadFromUrl(urlInfo, parentNode, onFinished) {
95
- if (!urlInfo) {
96
- return;
97
- }
98
- const element = this.getDomElement(parentNode);
99
- this.addLoadingClass(element);
100
- this.notifyLoading(true, parentNode, element);
101
- const stopLoading = () => {
102
- this.removeLoadingClass(element);
103
- this.notifyLoading(false, parentNode, element);
104
- };
105
- const handleSuccess = data => {
106
- stopLoading();
107
- this.loadData(this.parseData(data), parentNode);
108
- if (onFinished && typeof onFinished === "function") {
109
- onFinished();
110
- }
111
- };
112
- const handleError = jqXHR => {
113
- stopLoading();
114
- if (this.onLoadFailed) {
115
- this.onLoadFailed(jqXHR);
116
- }
117
- };
118
- this.submitRequest(urlInfo, handleSuccess, handleError);
119
- }
120
120
  }
121
121
 
122
- let Position = /*#__PURE__*/function (Position) {
123
- Position[Position["Before"] = 1] = "Before";
124
- Position[Position["After"] = 2] = "After";
125
- Position[Position["Inside"] = 3] = "Inside";
126
- Position[Position["None"] = 4] = "None";
127
- return Position;
128
- }({});
129
- const positionNames = {
130
- after: Position.After,
131
- before: Position.Before,
132
- inside: Position.Inside,
133
- none: Position.None
134
- };
135
- const getPositionName = position => {
136
- for (const name in positionNames) {
137
- if (Object.prototype.hasOwnProperty.call(positionNames, name)) {
138
- if (positionNames[name] === position) {
139
- return name;
140
- }
141
- }
142
- }
143
- return "";
144
- };
145
- const getPosition = name => positionNames[name];
146
-
147
122
  const isInt = n => typeof n === "number" && n % 1 === 0;
148
123
  const isFunction = v => typeof v === "function";
149
124
  const getBoolString = value => value ? "true" : "false";
@@ -156,6 +131,27 @@ var jqtree = (function (exports) {
156
131
  };
157
132
  };
158
133
 
134
+ function binarySearch(items, compareFn) {
135
+ let low = 0;
136
+ let high = items.length;
137
+ while (low < high) {
138
+ const mid = low + high >> 1;
139
+ const item = items[mid];
140
+ if (item === undefined) {
141
+ return null;
142
+ }
143
+ const compareResult = compareFn(item);
144
+ if (compareResult > 0) {
145
+ high = mid;
146
+ } else if (compareResult < 0) {
147
+ low = mid + 1;
148
+ } else {
149
+ return item;
150
+ }
151
+ }
152
+ return null;
153
+ }
154
+
159
155
  class DragElement {
160
156
  constructor(_ref) {
161
157
  let {
@@ -170,6 +166,13 @@ var jqtree = (function (exports) {
170
166
  this.element = this.createElement(nodeName, autoEscape);
171
167
  treeElement.appendChild(this.element);
172
168
  }
169
+ move(pageX, pageY) {
170
+ this.element.style.left = `${pageX - this.offsetX}px`;
171
+ this.element.style.top = `${pageY - this.offsetY}px`;
172
+ }
173
+ remove() {
174
+ this.element.remove();
175
+ }
173
176
  createElement(nodeName, autoEscape) {
174
177
  const element = document.createElement("span");
175
178
  element.classList.add("jqtree-title", "jqtree-dragging");
@@ -181,13 +184,6 @@ var jqtree = (function (exports) {
181
184
  element.style.position = "absolute";
182
185
  return element;
183
186
  }
184
- move(pageX, pageY) {
185
- this.element.style.left = `${pageX - this.offsetX}px`;
186
- this.element.style.top = `${pageY - this.offsetY}px`;
187
- }
188
- remove() {
189
- this.element.remove();
190
- }
191
187
  }
192
188
 
193
189
  const iterateVisibleNodes = (tree, _ref) => {
@@ -257,43 +253,43 @@ var jqtree = (function (exports) {
257
253
  const handleAfterOpenFolder = (node, nextNode) => {
258
254
  if (node === currentNode || nextNode === currentNode) {
259
255
  // Cannot move before or after current item
260
- addHitPosition(node, Position.None, lastTop);
256
+ addHitPosition(node, null, lastTop);
261
257
  } else {
262
- addHitPosition(node, Position.After, lastTop);
258
+ addHitPosition(node, "after", lastTop);
263
259
  }
264
260
  };
265
261
  const handleClosedFolder = (node, nextNode, element) => {
266
262
  const top = getOffsetTop(element);
267
263
  if (node === currentNode) {
268
264
  // Cannot move after current item
269
- addHitPosition(node, Position.None, top);
265
+ addHitPosition(node, null, top);
270
266
  } else {
271
- addHitPosition(node, Position.Inside, top);
267
+ addHitPosition(node, "inside", top);
272
268
 
273
269
  // Cannot move before current item
274
270
  if (nextNode !== currentNode) {
275
- addHitPosition(node, Position.After, top);
271
+ addHitPosition(node, "after", top);
276
272
  }
277
273
  }
278
274
  };
279
275
  const handleFirstNode = node => {
280
276
  if (node !== currentNode && node.element) {
281
- addHitPosition(node, Position.Before, getOffsetTop(node.element));
277
+ addHitPosition(node, "before", getOffsetTop(node.element));
282
278
  }
283
279
  };
284
280
  const handleNode = (node, nextNode, element) => {
285
281
  const top = getOffsetTop(element);
286
282
  if (node === currentNode) {
287
283
  // Cannot move inside current item
288
- addHitPosition(node, Position.None, top);
284
+ addHitPosition(node, null, top);
289
285
  } else {
290
- addHitPosition(node, Position.Inside, top);
286
+ addHitPosition(node, "inside", top);
291
287
  }
292
288
  if (nextNode === currentNode || node === currentNode) {
293
289
  // Cannot move before or after current item
294
- addHitPosition(node, Position.None, top);
290
+ addHitPosition(node, null, top);
295
291
  } else {
296
- addHitPosition(node, Position.After, top);
292
+ addHitPosition(node, "after", top);
297
293
  }
298
294
  };
299
295
  const handleOpenFolder = (node, element) => {
@@ -303,10 +299,10 @@ var jqtree = (function (exports) {
303
299
  // Dnd over the current element is not possible: add a position with type None for the top and the bottom.
304
300
  const top = getOffsetTop(element);
305
301
  const height = element.clientHeight;
306
- addHitPosition(node, Position.None, top);
302
+ addHitPosition(node, null, top);
307
303
  if (height > 5) {
308
304
  // Subtract 5 pixels to allow more space for the next element.
309
- addHitPosition(node, Position.None, top + height - 5);
305
+ addHitPosition(node, null, top + height - 5);
310
306
  }
311
307
 
312
308
  // Stop iterating
@@ -315,7 +311,7 @@ var jqtree = (function (exports) {
315
311
 
316
312
  // Cannot move before current item
317
313
  if (node.children[0] !== currentNode) {
318
- addHitPosition(node, Position.Inside, getOffsetTop(element));
314
+ addHitPosition(node, "inside", getOffsetTop(element));
319
315
  }
320
316
 
321
317
  // Continue iterating
@@ -337,7 +333,7 @@ var jqtree = (function (exports) {
337
333
  let areaTop = top;
338
334
  for (let i = 0; i < positionCount; i++) {
339
335
  const position = positionsInGroup[i];
340
- if (position.position !== Position.None) {
336
+ if (position.position) {
341
337
  hitAreas.push({
342
338
  bottom: areaTop + areaHeight,
343
339
  node: position.node,
@@ -381,6 +377,7 @@ var jqtree = (function (exports) {
381
377
  onDragMove,
382
378
  onDragStop,
383
379
  onIsMoveHandle,
380
+ openFolderDelay,
384
381
  openNode,
385
382
  refreshElements,
386
383
  slide,
@@ -397,6 +394,7 @@ var jqtree = (function (exports) {
397
394
  this.onDragMove = onDragMove;
398
395
  this.onDragStop = onDragStop;
399
396
  this.onIsMoveHandle = onIsMoveHandle;
397
+ this.openFolderDelay = openFolderDelay;
400
398
  this.openNode = openNode;
401
399
  this.refreshElements = refreshElements;
402
400
  this.slide = slide;
@@ -407,15 +405,112 @@ var jqtree = (function (exports) {
407
405
  this.isDragging = false;
408
406
  this.currentItem = null;
409
407
  }
410
- canMoveToArea(area) {
411
- if (!this.onCanMoveTo) {
412
- return true;
408
+ mouseCapture(positionInfo) {
409
+ const element = positionInfo.target;
410
+ if (!this.mustCaptureElement(element)) {
411
+ return null;
412
+ }
413
+ if (this.onIsMoveHandle && !this.onIsMoveHandle(jQuery(element))) {
414
+ return null;
415
+ }
416
+ let nodeElement = this.getNodeElement(element);
417
+ if (nodeElement && this.onCanMove) {
418
+ if (!this.onCanMove(nodeElement.node)) {
419
+ nodeElement = null;
420
+ }
421
+ }
422
+ this.currentItem = nodeElement;
423
+ return this.currentItem != null;
424
+ }
425
+ mouseDrag(positionInfo) {
426
+ if (!this.currentItem || !this.dragElement) {
427
+ return false;
428
+ }
429
+ this.dragElement.move(positionInfo.pageX, positionInfo.pageY);
430
+ const area = this.findHoveredArea(positionInfo.pageX, positionInfo.pageY);
431
+ if (area && this.canMoveToArea(area, this.currentItem)) {
432
+ if (!area.node.isFolder()) {
433
+ this.stopOpenFolderTimer();
434
+ }
435
+ if (this.hoveredArea !== area) {
436
+ this.hoveredArea = area;
437
+
438
+ // If this is a closed folder, start timer to open it
439
+ if (this.mustOpenFolderTimer(area)) {
440
+ this.startOpenFolderTimer(area.node);
441
+ } else {
442
+ this.stopOpenFolderTimer();
443
+ }
444
+ this.updateDropHint();
445
+ }
446
+ } else {
447
+ this.removeDropHint();
448
+ this.stopOpenFolderTimer();
449
+ this.hoveredArea = area;
450
+ }
451
+ if (!area) {
452
+ if (this.onDragMove) {
453
+ this.onDragMove(this.currentItem.node, positionInfo.originalEvent);
454
+ }
413
455
  }
456
+ return true;
457
+ }
458
+ mouseStart(positionInfo) {
414
459
  if (!this.currentItem) {
415
460
  return false;
416
461
  }
417
- const positionName = getPositionName(area.position);
418
- return this.onCanMoveTo(this.currentItem.node, area.node, positionName);
462
+ this.refresh();
463
+ const {
464
+ left,
465
+ top
466
+ } = getElementPosition(positionInfo.target);
467
+ const node = this.currentItem.node;
468
+ this.dragElement = new DragElement({
469
+ autoEscape: this.autoEscape ?? true,
470
+ nodeName: node.name,
471
+ offsetX: positionInfo.pageX - left,
472
+ offsetY: positionInfo.pageY - top,
473
+ treeElement: this.treeElement
474
+ });
475
+ this.isDragging = true;
476
+ this.currentItem.element.classList.add("jqtree-moving");
477
+ return true;
478
+ }
479
+ mouseStop(positionInfo) {
480
+ this.moveItem(positionInfo);
481
+ this.clear();
482
+ this.removeHover();
483
+ this.removeDropHint();
484
+ this.removeHitAreas();
485
+ const currentItem = this.currentItem;
486
+ if (this.currentItem) {
487
+ this.currentItem.element.classList.remove("jqtree-moving");
488
+ this.currentItem = null;
489
+ }
490
+ this.isDragging = false;
491
+ if (!this.hoveredArea && currentItem) {
492
+ if (this.onDragStop) {
493
+ this.onDragStop(currentItem.node, positionInfo.originalEvent);
494
+ }
495
+ }
496
+ return false;
497
+ }
498
+ refresh() {
499
+ this.removeHitAreas();
500
+ if (this.currentItem) {
501
+ const currentNode = this.currentItem.node;
502
+ this.generateHitAreas(currentNode);
503
+ this.currentItem = this.getNodeElementForNode(currentNode);
504
+ if (this.isDragging) {
505
+ this.currentItem.element.classList.add("jqtree-moving");
506
+ }
507
+ }
508
+ }
509
+ canMoveToArea(area, currentItem) {
510
+ if (!this.onCanMoveTo) {
511
+ return true;
512
+ }
513
+ return this.onCanMoveTo(currentItem.node, area.node, area.position);
419
514
  }
420
515
  clear() {
421
516
  if (this.dragElement) {
@@ -428,30 +523,22 @@ var jqtree = (function (exports) {
428
523
  if (x < dimensions.left || y < dimensions.top || x > dimensions.right || y > dimensions.bottom) {
429
524
  return null;
430
525
  }
431
- let low = 0;
432
- let high = this.hitAreas.length;
433
- while (low < high) {
434
- const mid = low + high >> 1;
435
- const area = this.hitAreas[mid];
436
- if (!area) {
437
- return null;
438
- }
526
+ return binarySearch(this.hitAreas, area => {
439
527
  if (y < area.top) {
440
- high = mid;
528
+ return 1;
441
529
  } else if (y > area.bottom) {
442
- low = mid + 1;
530
+ return -1;
443
531
  } else {
444
- return area;
532
+ return 0;
445
533
  }
446
- }
447
- return null;
534
+ });
448
535
  }
449
- generateHitAreas() {
536
+ generateHitAreas(currentNode) {
450
537
  const tree = this.getTree();
451
- if (!this.currentItem || !tree) {
538
+ if (!tree) {
452
539
  this.hitAreas = [];
453
540
  } else {
454
- this.hitAreas = generateHitAreas(tree, this.currentItem.node, this.getTreeDimensions().bottom);
541
+ this.hitAreas = generateHitAreas(tree, currentNode, this.getTreeDimensions().bottom);
455
542
  }
456
543
  }
457
544
  getTreeDimensions() {
@@ -467,13 +554,15 @@ var jqtree = (function (exports) {
467
554
  top
468
555
  };
469
556
  }
557
+
558
+ /* Move the dragged node to the selected position in the tree. */
470
559
  moveItem(positionInfo) {
471
- if (this.currentItem && this.hoveredArea && this.hoveredArea.position !== Position.None && this.canMoveToArea(this.hoveredArea)) {
560
+ if (this.currentItem && this.hoveredArea?.position && this.canMoveToArea(this.hoveredArea, this.currentItem)) {
472
561
  const movedNode = this.currentItem.node;
473
562
  const targetNode = this.hoveredArea.node;
474
563
  const position = this.hoveredArea.position;
475
564
  const previousParent = movedNode.parent;
476
- if (position === Position.Inside) {
565
+ if (position === "inside") {
477
566
  this.hoveredArea.node.is_open = true;
478
567
  }
479
568
  const doMove = () => {
@@ -489,7 +578,7 @@ var jqtree = (function (exports) {
489
578
  do_move: doMove,
490
579
  moved_node: movedNode,
491
580
  original_event: positionInfo.originalEvent,
492
- position: getPositionName(position),
581
+ position,
493
582
  previous_parent: previousParent,
494
583
  target_node: targetNode
495
584
  }
@@ -505,7 +594,7 @@ var jqtree = (function (exports) {
505
594
  }
506
595
  mustOpenFolderTimer(area) {
507
596
  const node = area.node;
508
- return node.isFolder() && !node.is_open && area.position === Position.Inside;
597
+ return node.isFolder() && !node.is_open && area.position === "inside";
509
598
  }
510
599
  removeDropHint() {
511
600
  if (this.previousGhost) {
@@ -549,137 +638,71 @@ var jqtree = (function (exports) {
549
638
  const nodeElement = this.getNodeElementForNode(this.hoveredArea.node);
550
639
  this.previousGhost = nodeElement.addDropHint(this.hoveredArea.position);
551
640
  }
552
- mouseCapture(positionInfo) {
553
- const element = positionInfo.target;
554
- if (!this.mustCaptureElement(element)) {
555
- return null;
556
- }
557
- if (this.onIsMoveHandle && !this.onIsMoveHandle(jQuery(element))) {
558
- return null;
559
- }
560
- let nodeElement = this.getNodeElement(element);
561
- if (nodeElement && this.onCanMove) {
562
- if (!this.onCanMove(nodeElement.node)) {
563
- nodeElement = null;
564
- }
641
+ }
642
+
643
+ class ElementsRenderer {
644
+ constructor(_ref) {
645
+ let {
646
+ $element,
647
+ autoEscape,
648
+ buttonLeft,
649
+ closedIcon,
650
+ dragAndDrop,
651
+ getTree,
652
+ isNodeSelected,
653
+ onCreateLi,
654
+ openedIcon,
655
+ rtl,
656
+ showEmptyFolder,
657
+ tabIndex
658
+ } = _ref;
659
+ this.autoEscape = autoEscape;
660
+ this.buttonLeft = buttonLeft;
661
+ this.dragAndDrop = dragAndDrop;
662
+ this.$element = $element;
663
+ this.getTree = getTree;
664
+ this.isNodeSelected = isNodeSelected;
665
+ this.onCreateLi = onCreateLi;
666
+ this.rtl = rtl;
667
+ this.showEmptyFolder = showEmptyFolder;
668
+ this.tabIndex = tabIndex;
669
+ this.openedIconElement = this.createButtonElement(openedIcon ?? "+");
670
+ this.closedIconElement = this.createButtonElement(closedIcon ?? "-");
671
+ }
672
+ render(fromNode) {
673
+ if (fromNode?.parent) {
674
+ this.renderFromNode(fromNode);
675
+ } else {
676
+ this.renderFromRoot();
565
677
  }
566
- this.currentItem = nodeElement;
567
- return this.currentItem != null;
568
678
  }
569
- mouseDrag(positionInfo) {
570
- if (!this.currentItem || !this.dragElement) {
571
- return false;
679
+ renderFromNode(node) {
680
+ if (!node.element) {
681
+ return;
572
682
  }
573
- this.dragElement.move(positionInfo.pageX, positionInfo.pageY);
574
- const area = this.findHoveredArea(positionInfo.pageX, positionInfo.pageY);
575
- if (area && this.canMoveToArea(area)) {
576
- if (!area.node.isFolder()) {
577
- this.stopOpenFolderTimer();
578
- }
579
- if (this.hoveredArea !== area) {
580
- this.hoveredArea = area;
581
683
 
582
- // If this is a closed folder, start timer to open it
583
- if (this.mustOpenFolderTimer(area)) {
584
- this.startOpenFolderTimer(area.node);
585
- } else {
586
- this.stopOpenFolderTimer();
587
- }
588
- this.updateDropHint();
589
- }
590
- } else {
591
- this.removeDropHint();
592
- this.stopOpenFolderTimer();
593
- this.hoveredArea = area;
594
- }
595
- if (!area) {
596
- if (this.onDragMove) {
597
- this.onDragMove(this.currentItem.node, positionInfo.originalEvent);
598
- }
599
- }
600
- return true;
601
- }
602
- mouseStart(positionInfo) {
603
- if (!this.currentItem) {
604
- return false;
605
- }
606
- this.refresh();
607
- const {
608
- left,
609
- top
610
- } = getElementPosition(positionInfo.target);
611
- const node = this.currentItem.node;
612
- this.dragElement = new DragElement({
613
- autoEscape: this.autoEscape ?? true,
614
- nodeName: node.name,
615
- offsetX: positionInfo.pageX - left,
616
- offsetY: positionInfo.pageY - top,
617
- treeElement: this.treeElement
618
- });
619
- this.isDragging = true;
620
- this.currentItem.element.classList.add("jqtree-moving");
621
- return true;
622
- }
623
- mouseStop(positionInfo) {
624
- this.moveItem(positionInfo);
625
- this.clear();
626
- this.removeHover();
627
- this.removeDropHint();
628
- this.removeHitAreas();
629
- const currentItem = this.currentItem;
630
- if (this.currentItem) {
631
- this.currentItem.element.classList.remove("jqtree-moving");
632
- this.currentItem = null;
633
- }
634
- this.isDragging = false;
635
- if (!this.hoveredArea && currentItem) {
636
- if (this.onDragStop) {
637
- this.onDragStop(currentItem.node, positionInfo.originalEvent);
638
- }
639
- }
640
- return false;
684
+ // remember current li
685
+ const $previousLi = jQuery(node.element);
686
+
687
+ // create element
688
+ const li = this.createLi(node, node.getLevel());
689
+
690
+ // add element to dom
691
+ $previousLi.after(li);
692
+
693
+ // remove previous li
694
+ $previousLi.remove();
695
+
696
+ // create children
697
+ this.createDomElements(li, node.children, false, node.getLevel() + 1);
641
698
  }
642
- refresh() {
643
- this.removeHitAreas();
644
- if (this.currentItem) {
645
- this.generateHitAreas();
646
- this.currentItem = this.getNodeElementForNode(this.currentItem.node);
647
- if (this.isDragging) {
648
- this.currentItem.element.classList.add("jqtree-moving");
649
- }
699
+ renderFromRoot() {
700
+ this.$element.empty();
701
+ const tree = this.getTree();
702
+ if (this.$element[0] && tree) {
703
+ this.createDomElements(this.$element[0], tree.children, true, 1);
650
704
  }
651
705
  }
652
- }
653
-
654
- class ElementsRenderer {
655
- constructor(_ref) {
656
- let {
657
- $element,
658
- autoEscape,
659
- buttonLeft,
660
- closedIcon,
661
- dragAndDrop,
662
- getTree,
663
- isNodeSelected,
664
- onCreateLi,
665
- openedIcon,
666
- rtl,
667
- showEmptyFolder,
668
- tabIndex
669
- } = _ref;
670
- this.autoEscape = autoEscape;
671
- this.buttonLeft = buttonLeft;
672
- this.dragAndDrop = dragAndDrop;
673
- this.$element = $element;
674
- this.getTree = getTree;
675
- this.isNodeSelected = isNodeSelected;
676
- this.onCreateLi = onCreateLi;
677
- this.rtl = rtl;
678
- this.showEmptyFolder = showEmptyFolder;
679
- this.tabIndex = tabIndex;
680
- this.openedIconElement = this.createButtonElement(openedIcon ?? "+");
681
- this.closedIconElement = this.createButtonElement(closedIcon ?? "-");
682
- }
683
706
  attachNodeData(node, li) {
684
707
  node.element = li;
685
708
  jQuery(li).data("node", node);
@@ -854,43 +877,42 @@ var jqtree = (function (exports) {
854
877
  element.setAttribute("aria-selected", getBoolString(isSelected));
855
878
  element.setAttribute("role", "treeitem");
856
879
  }
857
- render(fromNode) {
858
- if (fromNode?.parent) {
859
- this.renderFromNode(fromNode);
860
- } else {
861
- this.renderFromRoot();
880
+ }
881
+
882
+ class KeyHandler {
883
+ constructor(_ref) {
884
+ let {
885
+ closeNode,
886
+ getSelectedNode,
887
+ isFocusOnTree,
888
+ keyboardSupport,
889
+ openNode,
890
+ selectNode
891
+ } = _ref;
892
+ this.closeNode = closeNode;
893
+ this.getSelectedNode = getSelectedNode;
894
+ this.isFocusOnTree = isFocusOnTree;
895
+ this.keyboardSupport = keyboardSupport;
896
+ this.openNode = openNode;
897
+ this.originalSelectNode = selectNode;
898
+ if (keyboardSupport) {
899
+ document.addEventListener("keydown", this.handleKeyDown);
862
900
  }
863
901
  }
864
- renderFromNode(node) {
865
- if (!node.element) {
866
- return;
902
+ deinit() {
903
+ if (this.keyboardSupport) {
904
+ document.removeEventListener("keydown", this.handleKeyDown);
867
905
  }
868
-
869
- // remember current li
870
- const $previousLi = jQuery(node.element);
871
-
872
- // create element
873
- const li = this.createLi(node, node.getLevel());
874
-
875
- // add element to dom
876
- $previousLi.after(li);
877
-
878
- // remove previous li
879
- $previousLi.remove();
880
-
881
- // create children
882
- this.createDomElements(li, node.children, false, node.getLevel() + 1);
883
906
  }
884
- renderFromRoot() {
885
- this.$element.empty();
886
- const tree = this.getTree();
887
- if (this.$element[0] && tree) {
888
- this.createDomElements(this.$element[0], tree.children, true, 1);
889
- }
907
+ moveDown(selectedNode) {
908
+ return this.selectNode(selectedNode.getNextVisibleNode());
909
+ }
910
+ moveUp(selectedNode) {
911
+ return this.selectNode(selectedNode.getPreviousVisibleNode());
912
+ }
913
+ canHandleKeyboard() {
914
+ return this.keyboardSupport && this.isFocusOnTree();
890
915
  }
891
- }
892
-
893
- class KeyHandler {
894
916
  handleKeyDown = e => {
895
917
  if (!this.canHandleKeyboard()) {
896
918
  return;
@@ -917,28 +939,6 @@ var jqtree = (function (exports) {
917
939
  e.preventDefault();
918
940
  }
919
941
  };
920
- constructor(_ref) {
921
- let {
922
- closeNode,
923
- getSelectedNode,
924
- isFocusOnTree,
925
- keyboardSupport,
926
- openNode,
927
- selectNode
928
- } = _ref;
929
- this.closeNode = closeNode;
930
- this.getSelectedNode = getSelectedNode;
931
- this.isFocusOnTree = isFocusOnTree;
932
- this.keyboardSupport = keyboardSupport;
933
- this.openNode = openNode;
934
- this.originalSelectNode = selectNode;
935
- if (keyboardSupport) {
936
- document.addEventListener("keydown", this.handleKeyDown);
937
- }
938
- }
939
- canHandleKeyboard() {
940
- return this.keyboardSupport && this.isFocusOnTree();
941
- }
942
942
  moveLeft(selectedNode) {
943
943
  if (selectedNode.isFolder() && selectedNode.is_open) {
944
944
  // Left on an open node closes the node
@@ -977,17 +977,6 @@ var jqtree = (function (exports) {
977
977
  return true;
978
978
  }
979
979
  }
980
- deinit() {
981
- if (this.keyboardSupport) {
982
- document.removeEventListener("keydown", this.handleKeyDown);
983
- }
984
- }
985
- moveDown(selectedNode) {
986
- return this.selectNode(selectedNode.getNextVisibleNode());
987
- }
988
- moveUp(selectedNode) {
989
- return this.selectNode(selectedNode.getPreviousVisibleNode());
990
- }
991
980
  }
992
981
 
993
982
  const getPositionInfoFromMouseEvent = e => ({
@@ -1004,15 +993,90 @@ var jqtree = (function (exports) {
1004
993
  });
1005
994
 
1006
995
  class MouseHandler {
1007
- handleClick = e => {
1008
- if (!e.target) {
1009
- return;
996
+ constructor(_ref) {
997
+ let {
998
+ element,
999
+ getMouseDelay,
1000
+ getNode,
1001
+ onClickButton,
1002
+ onClickTitle,
1003
+ onMouseCapture,
1004
+ onMouseDrag,
1005
+ onMouseStart,
1006
+ onMouseStop,
1007
+ triggerEvent,
1008
+ useContextMenu
1009
+ } = _ref;
1010
+ this.element = element;
1011
+ this.getMouseDelay = getMouseDelay;
1012
+ this.getNode = getNode;
1013
+ this.onClickButton = onClickButton;
1014
+ this.onClickTitle = onClickTitle;
1015
+ this.onMouseCapture = onMouseCapture;
1016
+ this.onMouseDrag = onMouseDrag;
1017
+ this.onMouseStart = onMouseStart;
1018
+ this.onMouseStop = onMouseStop;
1019
+ this.triggerEvent = triggerEvent;
1020
+ this.useContextMenu = useContextMenu;
1021
+ element.addEventListener("click", this.handleClick);
1022
+ element.addEventListener("dblclick", this.handleDblclick);
1023
+ element.addEventListener("mousedown", this.mouseDown, {
1024
+ passive: false
1025
+ });
1026
+ element.addEventListener("touchstart", this.touchStart, {
1027
+ passive: false
1028
+ });
1029
+ if (useContextMenu) {
1030
+ element.addEventListener("contextmenu", this.handleContextmenu);
1010
1031
  }
1011
- const clickTarget = this.getClickTarget(e.target);
1012
- if (!clickTarget) {
1013
- return;
1032
+ this.isMouseStarted = false;
1033
+ this.mouseDelayTimer = null;
1034
+ this.isMouseDelayMet = false;
1035
+ this.mouseDownInfo = null;
1036
+ }
1037
+ deinit() {
1038
+ this.element.removeEventListener("click", this.handleClick);
1039
+ this.element.removeEventListener("dblclick", this.handleDblclick);
1040
+ if (this.useContextMenu) {
1041
+ this.element.removeEventListener("contextmenu", this.handleContextmenu);
1014
1042
  }
1015
- switch (clickTarget.type) {
1043
+ this.element.removeEventListener("mousedown", this.mouseDown);
1044
+ this.element.removeEventListener("touchstart", this.touchStart);
1045
+ this.removeMouseMoveEventListeners();
1046
+ }
1047
+ getClickTarget(element) {
1048
+ const button = element.closest(".jqtree-toggler");
1049
+ if (button) {
1050
+ const node = this.getNode(button);
1051
+ if (node) {
1052
+ return {
1053
+ node,
1054
+ type: "button"
1055
+ };
1056
+ }
1057
+ } else {
1058
+ const jqTreeElement = element.closest(".jqtree-element");
1059
+ if (jqTreeElement) {
1060
+ const node = this.getNode(jqTreeElement);
1061
+ if (node) {
1062
+ return {
1063
+ node,
1064
+ type: "label"
1065
+ };
1066
+ }
1067
+ }
1068
+ }
1069
+ return null;
1070
+ }
1071
+ handleClick = e => {
1072
+ if (!e.target) {
1073
+ return;
1074
+ }
1075
+ const clickTarget = this.getClickTarget(e.target);
1076
+ if (!clickTarget) {
1077
+ return;
1078
+ }
1079
+ switch (clickTarget.type) {
1016
1080
  case "button":
1017
1081
  this.onClickButton(clickTarget.node);
1018
1082
  e.preventDefault();
@@ -1062,117 +1126,6 @@ var jqtree = (function (exports) {
1062
1126
  });
1063
1127
  }
1064
1128
  };
1065
- mouseDown = e => {
1066
- // Left mouse button?
1067
- if (e.button !== 0) {
1068
- return;
1069
- }
1070
- const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));
1071
- if (result && e.cancelable) {
1072
- e.preventDefault();
1073
- }
1074
- };
1075
- mouseMove = e => {
1076
- this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));
1077
- };
1078
- mouseUp = e => {
1079
- this.handleMouseUp(getPositionInfoFromMouseEvent(e));
1080
- };
1081
- touchEnd = e => {
1082
- if (e.touches.length > 1) {
1083
- return;
1084
- }
1085
- const touch = e.touches[0];
1086
- if (!touch) {
1087
- return;
1088
- }
1089
- this.handleMouseUp(getPositionInfoFromTouch(touch, e));
1090
- };
1091
- touchMove = e => {
1092
- if (e.touches.length > 1) {
1093
- return;
1094
- }
1095
- const touch = e.touches[0];
1096
- if (!touch) {
1097
- return;
1098
- }
1099
- this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
1100
- };
1101
- touchStart = e => {
1102
- if (e.touches.length > 1) {
1103
- return;
1104
- }
1105
- const touch = e.touches[0];
1106
- if (!touch) {
1107
- return;
1108
- }
1109
- this.handleMouseDown(getPositionInfoFromTouch(touch, e));
1110
- };
1111
- constructor(_ref) {
1112
- let {
1113
- element,
1114
- getMouseDelay,
1115
- getNode,
1116
- onClickButton,
1117
- onClickTitle,
1118
- onMouseCapture,
1119
- onMouseDrag,
1120
- onMouseStart,
1121
- onMouseStop,
1122
- triggerEvent,
1123
- useContextMenu
1124
- } = _ref;
1125
- this.element = element;
1126
- this.getMouseDelay = getMouseDelay;
1127
- this.getNode = getNode;
1128
- this.onClickButton = onClickButton;
1129
- this.onClickTitle = onClickTitle;
1130
- this.onMouseCapture = onMouseCapture;
1131
- this.onMouseDrag = onMouseDrag;
1132
- this.onMouseStart = onMouseStart;
1133
- this.onMouseStop = onMouseStop;
1134
- this.triggerEvent = triggerEvent;
1135
- this.useContextMenu = useContextMenu;
1136
- element.addEventListener("click", this.handleClick);
1137
- element.addEventListener("dblclick", this.handleDblclick);
1138
- element.addEventListener("mousedown", this.mouseDown, {
1139
- passive: false
1140
- });
1141
- element.addEventListener("touchstart", this.touchStart, {
1142
- passive: false
1143
- });
1144
- if (useContextMenu) {
1145
- element.addEventListener("contextmenu", this.handleContextmenu);
1146
- }
1147
- this.isMouseStarted = false;
1148
- this.mouseDelayTimer = null;
1149
- this.isMouseDelayMet = false;
1150
- this.mouseDownInfo = null;
1151
- }
1152
- getClickTarget(element) {
1153
- const button = element.closest(".jqtree-toggler");
1154
- if (button) {
1155
- const node = this.getNode(button);
1156
- if (node) {
1157
- return {
1158
- node,
1159
- type: "button"
1160
- };
1161
- }
1162
- } else {
1163
- const jqTreeElement = element.closest(".jqtree-element");
1164
- if (jqTreeElement) {
1165
- const node = this.getNode(jqTreeElement);
1166
- if (node) {
1167
- return {
1168
- node,
1169
- type: "label"
1170
- };
1171
- }
1172
- }
1173
- }
1174
- return null;
1175
- }
1176
1129
  handleMouseDown(positionInfo) {
1177
1130
  // We may have missed mouseup (out of window)
1178
1131
  if (this.isMouseStarted) {
@@ -1237,6 +1190,22 @@ var jqtree = (function (exports) {
1237
1190
  this.isMouseDelayMet = true;
1238
1191
  }
1239
1192
  }
1193
+ mouseDown = e => {
1194
+ // Left mouse button?
1195
+ if (e.button !== 0) {
1196
+ return;
1197
+ }
1198
+ const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));
1199
+ if (result && e.cancelable) {
1200
+ e.preventDefault();
1201
+ }
1202
+ };
1203
+ mouseMove = e => {
1204
+ this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));
1205
+ };
1206
+ mouseUp = e => {
1207
+ this.handleMouseUp(getPositionInfoFromMouseEvent(e));
1208
+ };
1240
1209
  removeMouseMoveEventListeners() {
1241
1210
  document.removeEventListener("mousemove", this.mouseMove);
1242
1211
  document.removeEventListener("touchmove", this.touchMove);
@@ -1254,16 +1223,36 @@ var jqtree = (function (exports) {
1254
1223
  }, mouseDelay);
1255
1224
  this.isMouseDelayMet = false;
1256
1225
  }
1257
- deinit() {
1258
- this.element.removeEventListener("click", this.handleClick);
1259
- this.element.removeEventListener("dblclick", this.handleDblclick);
1260
- if (this.useContextMenu) {
1261
- this.element.removeEventListener("contextmenu", this.handleContextmenu);
1226
+ touchEnd = e => {
1227
+ if (e.touches.length > 1) {
1228
+ return;
1262
1229
  }
1263
- this.element.removeEventListener("mousedown", this.mouseDown);
1264
- this.element.removeEventListener("touchstart", this.touchStart);
1265
- this.removeMouseMoveEventListeners();
1266
- }
1230
+ const touch = e.touches[0];
1231
+ if (!touch) {
1232
+ return;
1233
+ }
1234
+ this.handleMouseUp(getPositionInfoFromTouch(touch, e));
1235
+ };
1236
+ touchMove = e => {
1237
+ if (e.touches.length > 1) {
1238
+ return;
1239
+ }
1240
+ const touch = e.touches[0];
1241
+ if (!touch) {
1242
+ return;
1243
+ }
1244
+ this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
1245
+ };
1246
+ touchStart = e => {
1247
+ if (e.touches.length > 1) {
1248
+ return;
1249
+ }
1250
+ const touch = e.touches[0];
1251
+ if (!touch) {
1252
+ return;
1253
+ }
1254
+ this.handleMouseDown(getPositionInfoFromTouch(touch, e));
1255
+ };
1267
1256
  }
1268
1257
 
1269
1258
  const isNodeRecordWithChildren = data => typeof data === "object" && "children" in data && data.children instanceof Array;
@@ -1285,29 +1274,6 @@ var jqtree = (function (exports) {
1285
1274
  this.nodeClass = nodeClass;
1286
1275
  }
1287
1276
  }
1288
- createNode(nodeData) {
1289
- const nodeClass = this.getNodeClass();
1290
- return new nodeClass(nodeData);
1291
- }
1292
- doRemoveChild(node) {
1293
- this.children.splice(this.getChildIndex(node), 1);
1294
- this.tree?.removeNodeFromIndex(node);
1295
- }
1296
- getNodeClass() {
1297
- return this.nodeClass ?? this.tree?.nodeClass ?? Node;
1298
- }
1299
-
1300
- // Load children data from nodeInfo if it has children
1301
- loadChildrenFromData(nodeInfo) {
1302
- if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
1303
- this.loadFromData(nodeInfo.children);
1304
- }
1305
- }
1306
- setParent(parent) {
1307
- this.parent = parent;
1308
- this.tree = parent.tree;
1309
- this.tree?.addNodeToIndex(this);
1310
- }
1311
1277
  addAfter(nodeInfo) {
1312
1278
  if (!this.parent) {
1313
1279
  return null;
@@ -1688,7 +1654,7 @@ var jqtree = (function (exports) {
1688
1654
  } else {
1689
1655
  movedNode.parent.doRemoveChild(movedNode);
1690
1656
  switch (position) {
1691
- case Position.After:
1657
+ case "after":
1692
1658
  {
1693
1659
  if (targetNode.parent) {
1694
1660
  targetNode.parent.addChildAtPosition(movedNode, targetNode.parent.getChildIndex(targetNode) + 1);
@@ -1696,7 +1662,7 @@ var jqtree = (function (exports) {
1696
1662
  }
1697
1663
  return false;
1698
1664
  }
1699
- case Position.Before:
1665
+ case "before":
1700
1666
  {
1701
1667
  if (targetNode.parent) {
1702
1668
  targetNode.parent.addChildAtPosition(movedNode, targetNode.parent.getChildIndex(targetNode));
@@ -1704,14 +1670,12 @@ var jqtree = (function (exports) {
1704
1670
  }
1705
1671
  return false;
1706
1672
  }
1707
- case Position.Inside:
1673
+ case "inside":
1708
1674
  {
1709
1675
  // move inside as first child
1710
1676
  targetNode.addChildAtPosition(movedNode, 0);
1711
1677
  return true;
1712
1678
  }
1713
- default:
1714
- return false;
1715
1679
  }
1716
1680
  }
1717
1681
  }
@@ -1783,6 +1747,29 @@ var jqtree = (function (exports) {
1783
1747
  }
1784
1748
  }
1785
1749
  }
1750
+ createNode(nodeData) {
1751
+ const nodeClass = this.getNodeClass();
1752
+ return new nodeClass(nodeData);
1753
+ }
1754
+ doRemoveChild(node) {
1755
+ this.children.splice(this.getChildIndex(node), 1);
1756
+ this.tree?.removeNodeFromIndex(node);
1757
+ }
1758
+ getNodeClass() {
1759
+ return this.nodeClass ?? this.tree?.nodeClass ?? Node;
1760
+ }
1761
+
1762
+ // Load children data from nodeInfo if it has children
1763
+ loadChildrenFromData(nodeInfo) {
1764
+ if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
1765
+ this.loadFromData(nodeInfo.children);
1766
+ }
1767
+ }
1768
+ setParent(parent) {
1769
+ this.parent = parent;
1770
+ this.tree = parent.tree;
1771
+ this.tree?.addNodeToIndex(this);
1772
+ }
1786
1773
  }
1787
1774
 
1788
1775
  class BorderDropHint {
@@ -1812,13 +1799,13 @@ var jqtree = (function (exports) {
1812
1799
  this.node = node;
1813
1800
  this.ghost = this.createGhostElement();
1814
1801
  switch (position) {
1815
- case Position.After:
1802
+ case "after":
1816
1803
  this.moveAfter();
1817
1804
  break;
1818
- case Position.Before:
1805
+ case "before":
1819
1806
  this.moveBefore();
1820
1807
  break;
1821
- case Position.Inside:
1808
+ case "inside":
1822
1809
  {
1823
1810
  if (node.isFolder() && node.is_open) {
1824
1811
  this.moveInsideOpenFolder();
@@ -1828,6 +1815,9 @@ var jqtree = (function (exports) {
1828
1815
  }
1829
1816
  }
1830
1817
  }
1818
+ remove() {
1819
+ this.ghost.remove();
1820
+ }
1831
1821
  createGhostElement() {
1832
1822
  const ghost = document.createElement("li");
1833
1823
  ghost.className = "jqtree_common jqtree-ghost";
@@ -1855,9 +1845,6 @@ var jqtree = (function (exports) {
1855
1845
  childElement.before(this.ghost);
1856
1846
  }
1857
1847
  }
1858
- remove() {
1859
- this.ghost.remove();
1860
- }
1861
1848
  }
1862
1849
 
1863
1850
  class NodeElement {
@@ -1873,15 +1860,6 @@ var jqtree = (function (exports) {
1873
1860
  this.treeElement = treeElement;
1874
1861
  this.init(node);
1875
1862
  }
1876
- getTitleSpan() {
1877
- return this.element.querySelector(":scope > .jqtree-element > span.jqtree-title");
1878
- }
1879
- getUl() {
1880
- return this.element.querySelector(":scope > ul");
1881
- }
1882
- mustShowBorderDropHint(position) {
1883
- return position === Position.Inside;
1884
- }
1885
1863
  addDropHint(position) {
1886
1864
  if (this.mustShowBorderDropHint(position)) {
1887
1865
  return new BorderDropHint(this.element, this.getScrollLeft());
@@ -1917,6 +1895,15 @@ var jqtree = (function (exports) {
1917
1895
  titleSpan.focus();
1918
1896
  }
1919
1897
  }
1898
+ getTitleSpan() {
1899
+ return this.element.querySelector(":scope > .jqtree-element > span.jqtree-title");
1900
+ }
1901
+ getUl() {
1902
+ return this.element.querySelector(":scope > ul");
1903
+ }
1904
+ mustShowBorderDropHint(position) {
1905
+ return position === "inside";
1906
+ }
1920
1907
  }
1921
1908
 
1922
1909
  class FolderElement extends NodeElement {
@@ -1940,12 +1927,6 @@ var jqtree = (function (exports) {
1940
1927
  this.openedIconElement = openedIconElement;
1941
1928
  this.triggerEvent = triggerEvent;
1942
1929
  }
1943
- mustShowBorderDropHint(position) {
1944
- return !this.node.is_open && position === Position.Inside;
1945
- }
1946
- getButton() {
1947
- return this.element.querySelector(":scope > .jqtree-element > a.jqtree-toggler");
1948
- }
1949
1930
  close(slide, animationSpeed) {
1950
1931
  if (!this.node.is_open) {
1951
1932
  return;
@@ -2005,6 +1986,12 @@ var jqtree = (function (exports) {
2005
1986
  doOpen();
2006
1987
  }
2007
1988
  }
1989
+ mustShowBorderDropHint(position) {
1990
+ return !this.node.is_open && position === "inside";
1991
+ }
1992
+ getButton() {
1993
+ return this.element.querySelector(":scope > .jqtree-element > a.jqtree-toggler");
1994
+ }
2008
1995
  }
2009
1996
 
2010
1997
  class SaveStateHandler {
@@ -2032,61 +2019,6 @@ var jqtree = (function (exports) {
2032
2019
  this.removeFromSelection = removeFromSelection;
2033
2020
  this.saveStateOption = saveState;
2034
2021
  }
2035
- getKeyName() {
2036
- if (typeof this.saveStateOption === "string") {
2037
- return this.saveStateOption;
2038
- } else {
2039
- return "tree";
2040
- }
2041
- }
2042
- loadFromStorage() {
2043
- if (this.onGetStateFromStorage) {
2044
- return this.onGetStateFromStorage();
2045
- } else {
2046
- return localStorage.getItem(this.getKeyName());
2047
- }
2048
- }
2049
- openInitialNodes(nodeIds) {
2050
- let mustLoadOnDemand = false;
2051
- for (const nodeId of nodeIds) {
2052
- const node = this.getNodeById(nodeId);
2053
- if (node) {
2054
- if (!node.load_on_demand) {
2055
- node.is_open = true;
2056
- } else {
2057
- mustLoadOnDemand = true;
2058
- }
2059
- }
2060
- }
2061
- return mustLoadOnDemand;
2062
- }
2063
- parseState(jsonData) {
2064
- const state = JSON.parse(jsonData);
2065
-
2066
- // Check if selected_node is an int (instead of an array)
2067
- if (state.selected_node && isInt(state.selected_node)) {
2068
- // Convert to array
2069
- state.selected_node = [state.selected_node];
2070
- }
2071
- return state;
2072
- }
2073
- resetSelection() {
2074
- const selectedNodes = this.getSelectedNodes();
2075
- selectedNodes.forEach(node => {
2076
- this.removeFromSelection(node);
2077
- });
2078
- }
2079
- selectInitialNodes(nodeIds) {
2080
- let selectCount = 0;
2081
- for (const nodeId of nodeIds) {
2082
- const node = this.getNodeById(nodeId);
2083
- if (node) {
2084
- selectCount += 1;
2085
- this.addToSelection(node);
2086
- }
2087
- }
2088
- return selectCount !== 0;
2089
- }
2090
2022
  getNodeIdToBeSelected() {
2091
2023
  const state = this.getStateFromStorage();
2092
2024
  if (state?.selected_node) {
@@ -2194,6 +2126,61 @@ var jqtree = (function (exports) {
2194
2126
  };
2195
2127
  openNodes();
2196
2128
  }
2129
+ getKeyName() {
2130
+ if (typeof this.saveStateOption === "string") {
2131
+ return this.saveStateOption;
2132
+ } else {
2133
+ return "tree";
2134
+ }
2135
+ }
2136
+ loadFromStorage() {
2137
+ if (this.onGetStateFromStorage) {
2138
+ return this.onGetStateFromStorage();
2139
+ } else {
2140
+ return localStorage.getItem(this.getKeyName());
2141
+ }
2142
+ }
2143
+ openInitialNodes(nodeIds) {
2144
+ let mustLoadOnDemand = false;
2145
+ for (const nodeId of nodeIds) {
2146
+ const node = this.getNodeById(nodeId);
2147
+ if (node) {
2148
+ if (!node.load_on_demand) {
2149
+ node.is_open = true;
2150
+ } else {
2151
+ mustLoadOnDemand = true;
2152
+ }
2153
+ }
2154
+ }
2155
+ return mustLoadOnDemand;
2156
+ }
2157
+ parseState(jsonData) {
2158
+ const state = JSON.parse(jsonData);
2159
+
2160
+ // Check if selected_node is an int (instead of an array)
2161
+ if (state.selected_node && isInt(state.selected_node)) {
2162
+ // Convert to array
2163
+ state.selected_node = [state.selected_node];
2164
+ }
2165
+ return state;
2166
+ }
2167
+ resetSelection() {
2168
+ const selectedNodes = this.getSelectedNodes();
2169
+ selectedNodes.forEach(node => {
2170
+ this.removeFromSelection(node);
2171
+ });
2172
+ }
2173
+ selectInitialNodes(nodeIds) {
2174
+ let selectCount = 0;
2175
+ for (const nodeId of nodeIds) {
2176
+ const node = this.getNodeById(nodeId);
2177
+ if (node) {
2178
+ selectCount += 1;
2179
+ this.addToSelection(node);
2180
+ }
2181
+ }
2182
+ return selectCount !== 0;
2183
+ }
2197
2184
  }
2198
2185
 
2199
2186
  class ContainerScrollParent {
@@ -2205,6 +2192,43 @@ var jqtree = (function (exports) {
2205
2192
  this.container = container;
2206
2193
  this.refreshHitAreas = refreshHitAreas;
2207
2194
  }
2195
+ checkHorizontalScrolling(pageX) {
2196
+ const newHorizontalScrollDirection = this.getNewHorizontalScrollDirection(pageX);
2197
+ if (this.horizontalScrollDirection !== newHorizontalScrollDirection) {
2198
+ this.horizontalScrollDirection = newHorizontalScrollDirection;
2199
+ if (this.horizontalScrollTimeout != null) {
2200
+ window.clearTimeout(this.verticalScrollTimeout);
2201
+ }
2202
+ if (newHorizontalScrollDirection) {
2203
+ this.horizontalScrollTimeout = window.setTimeout(this.scrollHorizontally.bind(this), 40);
2204
+ }
2205
+ }
2206
+ }
2207
+ checkVerticalScrolling(pageY) {
2208
+ const newVerticalScrollDirection = this.getNewVerticalScrollDirection(pageY);
2209
+ if (this.verticalScrollDirection !== newVerticalScrollDirection) {
2210
+ this.verticalScrollDirection = newVerticalScrollDirection;
2211
+ if (this.verticalScrollTimeout != null) {
2212
+ window.clearTimeout(this.verticalScrollTimeout);
2213
+ this.verticalScrollTimeout = undefined;
2214
+ }
2215
+ if (newVerticalScrollDirection) {
2216
+ this.verticalScrollTimeout = window.setTimeout(this.scrollVertically.bind(this), 40);
2217
+ }
2218
+ }
2219
+ }
2220
+ getScrollLeft() {
2221
+ return this.container.scrollLeft;
2222
+ }
2223
+ scrollToY(top) {
2224
+ this.container.scrollTop = top;
2225
+ }
2226
+ stopScrolling() {
2227
+ this.horizontalScrollDirection = undefined;
2228
+ this.verticalScrollDirection = undefined;
2229
+ this.scrollParentTop = undefined;
2230
+ this.scrollParentBottom = undefined;
2231
+ }
2208
2232
  getNewHorizontalScrollDirection(pageX) {
2209
2233
  const scrollParentOffset = getElementPosition(this.container);
2210
2234
  const rightEdge = scrollParentOffset.left + this.container.clientWidth;
@@ -2265,12 +2289,23 @@ var jqtree = (function (exports) {
2265
2289
  this.refreshHitAreas();
2266
2290
  setTimeout(this.scrollVertically.bind(this), 40);
2267
2291
  }
2292
+ }
2293
+
2294
+ class DocumentScrollParent {
2295
+ constructor(_ref) {
2296
+ let {
2297
+ refreshHitAreas,
2298
+ treeElement
2299
+ } = _ref;
2300
+ this.refreshHitAreas = refreshHitAreas;
2301
+ this.treeElement = treeElement;
2302
+ }
2268
2303
  checkHorizontalScrolling(pageX) {
2269
2304
  const newHorizontalScrollDirection = this.getNewHorizontalScrollDirection(pageX);
2270
2305
  if (this.horizontalScrollDirection !== newHorizontalScrollDirection) {
2271
2306
  this.horizontalScrollDirection = newHorizontalScrollDirection;
2272
2307
  if (this.horizontalScrollTimeout != null) {
2273
- window.clearTimeout(this.verticalScrollTimeout);
2308
+ window.clearTimeout(this.horizontalScrollTimeout);
2274
2309
  }
2275
2310
  if (newHorizontalScrollDirection) {
2276
2311
  this.horizontalScrollTimeout = window.setTimeout(this.scrollHorizontally.bind(this), 40);
@@ -2291,27 +2326,17 @@ var jqtree = (function (exports) {
2291
2326
  }
2292
2327
  }
2293
2328
  getScrollLeft() {
2294
- return this.container.scrollLeft;
2329
+ return document.documentElement.scrollLeft;
2295
2330
  }
2296
2331
  scrollToY(top) {
2297
- this.container.scrollTop = top;
2332
+ const treeTop = getOffsetTop(this.treeElement);
2333
+ document.documentElement.scrollTop = top + treeTop;
2298
2334
  }
2299
2335
  stopScrolling() {
2300
2336
  this.horizontalScrollDirection = undefined;
2301
2337
  this.verticalScrollDirection = undefined;
2302
- this.scrollParentTop = undefined;
2303
- this.scrollParentBottom = undefined;
2304
- }
2305
- }
2306
-
2307
- class DocumentScrollParent {
2308
- constructor(_ref) {
2309
- let {
2310
- refreshHitAreas,
2311
- treeElement
2312
- } = _ref;
2313
- this.refreshHitAreas = refreshHitAreas;
2314
- this.treeElement = treeElement;
2338
+ this.documentScrollHeight = undefined;
2339
+ this.documentScrollWidth = undefined;
2315
2340
  }
2316
2341
  canScrollDown() {
2317
2342
  const documentElement = document.documentElement;
@@ -2386,44 +2411,6 @@ var jqtree = (function (exports) {
2386
2411
  this.refreshHitAreas();
2387
2412
  setTimeout(this.scrollVertically.bind(this), 40);
2388
2413
  }
2389
- checkHorizontalScrolling(pageX) {
2390
- const newHorizontalScrollDirection = this.getNewHorizontalScrollDirection(pageX);
2391
- if (this.horizontalScrollDirection !== newHorizontalScrollDirection) {
2392
- this.horizontalScrollDirection = newHorizontalScrollDirection;
2393
- if (this.horizontalScrollTimeout != null) {
2394
- window.clearTimeout(this.horizontalScrollTimeout);
2395
- }
2396
- if (newHorizontalScrollDirection) {
2397
- this.horizontalScrollTimeout = window.setTimeout(this.scrollHorizontally.bind(this), 40);
2398
- }
2399
- }
2400
- }
2401
- checkVerticalScrolling(pageY) {
2402
- const newVerticalScrollDirection = this.getNewVerticalScrollDirection(pageY);
2403
- if (this.verticalScrollDirection !== newVerticalScrollDirection) {
2404
- this.verticalScrollDirection = newVerticalScrollDirection;
2405
- if (this.verticalScrollTimeout != null) {
2406
- window.clearTimeout(this.verticalScrollTimeout);
2407
- this.verticalScrollTimeout = undefined;
2408
- }
2409
- if (newVerticalScrollDirection) {
2410
- this.verticalScrollTimeout = window.setTimeout(this.scrollVertically.bind(this), 40);
2411
- }
2412
- }
2413
- }
2414
- getScrollLeft() {
2415
- return document.documentElement.scrollLeft;
2416
- }
2417
- scrollToY(top) {
2418
- const treeTop = getOffsetTop(this.treeElement);
2419
- document.documentElement.scrollTop = top + treeTop;
2420
- }
2421
- stopScrolling() {
2422
- this.horizontalScrollDirection = undefined;
2423
- this.verticalScrollDirection = undefined;
2424
- this.documentScrollHeight = undefined;
2425
- this.documentScrollWidth = undefined;
2426
- }
2427
2414
  }
2428
2415
 
2429
2416
  const isOverflow = overflowValue => overflowValue === "auto" || overflowValue === "scroll";
@@ -2469,18 +2456,6 @@ var jqtree = (function (exports) {
2469
2456
  this.scrollParent = undefined;
2470
2457
  this.treeElement = treeElement;
2471
2458
  }
2472
- checkHorizontalScrolling(positionInfo) {
2473
- this.getScrollParent().checkHorizontalScrolling(positionInfo.pageX);
2474
- }
2475
- checkVerticalScrolling(positionInfo) {
2476
- this.getScrollParent().checkVerticalScrolling(positionInfo.pageY);
2477
- }
2478
- getScrollParent() {
2479
- if (!this.scrollParent) {
2480
- this.scrollParent = createScrollParent(this.treeElement, this.refreshHitAreas);
2481
- }
2482
- return this.scrollParent;
2483
- }
2484
2459
  checkScrolling(positionInfo) {
2485
2460
  this.checkVerticalScrolling(positionInfo);
2486
2461
  this.checkHorizontalScrolling(positionInfo);
@@ -2494,7 +2469,19 @@ var jqtree = (function (exports) {
2494
2469
  stopScrolling() {
2495
2470
  this.getScrollParent().stopScrolling();
2496
2471
  }
2497
- }
2472
+ checkHorizontalScrolling(positionInfo) {
2473
+ this.getScrollParent().checkHorizontalScrolling(positionInfo.pageX);
2474
+ }
2475
+ checkVerticalScrolling(positionInfo) {
2476
+ this.getScrollParent().checkVerticalScrolling(positionInfo.pageY);
2477
+ }
2478
+ getScrollParent() {
2479
+ if (!this.scrollParent) {
2480
+ this.scrollParent = createScrollParent(this.treeElement, this.refreshHitAreas);
2481
+ }
2482
+ return this.scrollParent;
2483
+ }
2484
+ }
2498
2485
 
2499
2486
  class SelectNodeHandler {
2500
2487
  constructor(_ref) {
@@ -2688,7 +2675,7 @@ var jqtree = (function (exports) {
2688
2675
  }
2689
2676
  }
2690
2677
 
2691
- const version = "1.8.8";
2678
+ const version = "1.8.10";
2692
2679
 
2693
2680
  const NODE_PARAM_IS_EMPTY = "Node parameter is empty";
2694
2681
  const PARAM_IS_EMPTY = "Parameter is empty: ";
@@ -2739,838 +2726,231 @@ var jqtree = (function (exports) {
2739
2726
  tabIndex: 0,
2740
2727
  useContextMenu: true
2741
2728
  }))();
2742
- connectHandlers() {
2743
- const {
2744
- autoEscape,
2745
- buttonLeft,
2746
- closedIcon,
2747
- dataFilter,
2748
- dragAndDrop,
2749
- keyboardSupport,
2750
- onCanMove,
2751
- onCanMoveTo,
2752
- onCreateLi,
2753
- onDragMove,
2754
- onDragStop,
2755
- onGetStateFromStorage,
2756
- onIsMoveHandle,
2757
- onLoadFailed,
2758
- onLoading,
2759
- onSetStateFromStorage,
2760
- openedIcon,
2761
- openFolderDelay,
2762
- rtl,
2763
- saveState,
2764
- showEmptyFolder,
2765
- slide,
2766
- tabIndex
2767
- } = this.options;
2768
- const closeNode = this.closeNode.bind(this);
2769
- const getNodeElement = this.getNodeElement.bind(this);
2770
- const getNodeElementForNode = this.getNodeElementForNode.bind(this);
2771
- const getNodeById = this.getNodeById.bind(this);
2772
- const getSelectedNode = this.getSelectedNode.bind(this);
2773
- const getTree = this.getTree.bind(this);
2774
- const isFocusOnTree = this.isFocusOnTree.bind(this);
2775
- const loadData = this.loadData.bind(this);
2776
- const openNode = this.openNodeInternal.bind(this);
2777
- const refreshElements = this.refreshElements.bind(this);
2778
- const refreshHitAreas = this.refreshHitAreas.bind(this);
2779
- const selectNode = this.selectNode.bind(this);
2780
- const $treeElement = this.element;
2781
- const treeElement = this.element.get(0);
2782
- const triggerEvent = this.triggerEvent.bind(this);
2783
- const selectNodeHandler = new SelectNodeHandler({
2784
- getNodeById
2785
- });
2786
- const addToSelection = selectNodeHandler.addToSelection.bind(selectNodeHandler);
2787
- const getSelectedNodes = selectNodeHandler.getSelectedNodes.bind(selectNodeHandler);
2788
- const isNodeSelected = selectNodeHandler.isNodeSelected.bind(selectNodeHandler);
2789
- const removeFromSelection = selectNodeHandler.removeFromSelection.bind(selectNodeHandler);
2790
- const getMouseDelay = () => this.options.startDndDelay ?? 0;
2791
- const dataLoader = new DataLoader({
2792
- dataFilter,
2793
- loadData,
2794
- onLoadFailed,
2795
- onLoading,
2796
- treeElement,
2797
- triggerEvent
2798
- });
2799
- const saveStateHandler = new SaveStateHandler({
2800
- addToSelection,
2801
- getNodeById,
2802
- getSelectedNodes,
2803
- getTree,
2804
- onGetStateFromStorage,
2805
- onSetStateFromStorage,
2806
- openNode,
2807
- refreshElements,
2808
- removeFromSelection,
2809
- saveState
2810
- });
2811
- const scrollHandler = new ScrollHandler({
2812
- refreshHitAreas,
2813
- treeElement
2814
- });
2815
- const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);
2816
- const dndHandler = new DragAndDropHandler({
2817
- autoEscape,
2818
- getNodeElement,
2819
- getNodeElementForNode,
2820
- getScrollLeft,
2821
- getTree,
2822
- onCanMove,
2823
- onCanMoveTo,
2824
- onDragMove,
2825
- onDragStop,
2826
- onIsMoveHandle,
2827
- openFolderDelay,
2828
- openNode,
2829
- refreshElements,
2830
- slide,
2831
- treeElement,
2832
- triggerEvent
2833
- });
2834
- const keyHandler = new KeyHandler({
2835
- closeNode,
2836
- getSelectedNode,
2837
- isFocusOnTree,
2838
- keyboardSupport,
2839
- openNode,
2840
- selectNode
2841
- });
2842
- const renderer = new ElementsRenderer({
2843
- $element: $treeElement,
2844
- autoEscape,
2845
- buttonLeft,
2846
- closedIcon,
2847
- dragAndDrop,
2848
- getTree,
2849
- isNodeSelected,
2850
- onCreateLi,
2851
- openedIcon,
2852
- rtl,
2853
- showEmptyFolder,
2854
- tabIndex
2855
- });
2856
- const getNode = this.getNode.bind(this);
2857
- const onMouseCapture = this.mouseCapture.bind(this);
2858
- const onMouseDrag = this.mouseDrag.bind(this);
2859
- const onMouseStart = this.mouseStart.bind(this);
2860
- const onMouseStop = this.mouseStop.bind(this);
2861
- const mouseHandler = new MouseHandler({
2862
- element: treeElement,
2863
- getMouseDelay,
2864
- getNode,
2865
- onClickButton: this.toggle.bind(this),
2866
- onClickTitle: this.doSelectNode.bind(this),
2867
- onMouseCapture,
2868
- onMouseDrag,
2869
- onMouseStart,
2870
- onMouseStop,
2871
- triggerEvent,
2872
- useContextMenu: this.options.useContextMenu
2873
- });
2874
- this.dataLoader = dataLoader;
2875
- this.dndHandler = dndHandler;
2876
- this.keyHandler = keyHandler;
2877
- this.mouseHandler = mouseHandler;
2878
- this.renderer = renderer;
2879
- this.saveStateHandler = saveStateHandler;
2880
- this.scrollHandler = scrollHandler;
2881
- this.selectNodeHandler = selectNodeHandler;
2882
- }
2883
- containsElement(element) {
2884
- const node = this.getNode(element);
2885
- return node != null && node.tree === this.tree;
2886
- }
2887
- createFolderElement(node) {
2888
- const closedIconElement = this.renderer.closedIconElement;
2889
- const getScrollLeft = this.scrollHandler.getScrollLeft.bind(this.scrollHandler);
2890
- const openedIconElement = this.renderer.openedIconElement;
2891
- const tabIndex = this.options.tabIndex;
2892
- const treeElement = this.element.get(0);
2893
- const triggerEvent = this.triggerEvent.bind(this);
2894
- return new FolderElement({
2895
- closedIconElement,
2896
- getScrollLeft,
2897
- node,
2898
- openedIconElement,
2899
- tabIndex,
2900
- treeElement,
2901
- triggerEvent
2902
- });
2903
- }
2904
- createNodeElement(node) {
2905
- const getScrollLeft = this.scrollHandler.getScrollLeft.bind(this.scrollHandler);
2906
- const tabIndex = this.options.tabIndex;
2907
- const treeElement = this.element.get(0);
2908
- return new NodeElement({
2909
- getScrollLeft,
2910
- node,
2911
- tabIndex,
2912
- treeElement
2913
- });
2729
+ addNodeAfter(newNodeInfo, existingNode) {
2730
+ const newNode = existingNode.addAfter(newNodeInfo);
2731
+ if (newNode) {
2732
+ this.refreshElements(existingNode.parent);
2733
+ }
2734
+ return newNode;
2914
2735
  }
2915
- deselectCurrentNode() {
2916
- const node = this.getSelectedNode();
2917
- if (node) {
2918
- this.removeFromSelection(node);
2736
+ addNodeBefore(newNodeInfo, existingNode) {
2737
+ if (!existingNode) {
2738
+ throw Error(PARAM_IS_EMPTY + "existingNode");
2739
+ }
2740
+ const newNode = existingNode.addBefore(newNodeInfo);
2741
+ if (newNode) {
2742
+ this.refreshElements(existingNode.parent);
2919
2743
  }
2744
+ return newNode;
2920
2745
  }
2921
- deselectNodes(parentNode) {
2922
- const selectedNodesUnderParent = this.selectNodeHandler.getSelectedNodesUnder(parentNode);
2923
- for (const n of selectedNodesUnderParent) {
2924
- this.selectNodeHandler.removeFromSelection(n);
2746
+ addParentNode(newNodeInfo, existingNode) {
2747
+ if (!existingNode) {
2748
+ throw Error(PARAM_IS_EMPTY + "existingNode");
2749
+ }
2750
+ const newNode = existingNode.addParent(newNodeInfo);
2751
+ if (newNode) {
2752
+ this.refreshElements(newNode.parent);
2925
2753
  }
2754
+ return newNode;
2926
2755
  }
2927
- doLoadData(data, parentNode) {
2928
- if (data) {
2929
- if (parentNode) {
2930
- this.deselectNodes(parentNode);
2931
- this.loadSubtree(data, parentNode);
2932
- } else {
2933
- this.initTree(data);
2934
- }
2935
- if (this.isDragging()) {
2936
- this.dndHandler.refresh();
2937
- }
2756
+ addToSelection(node, mustSetFocus) {
2757
+ if (!node) {
2758
+ throw Error(NODE_PARAM_IS_EMPTY);
2938
2759
  }
2939
- this.triggerEvent("tree.load_data", {
2940
- parent_node: parentNode,
2941
- tree_data: data
2942
- });
2760
+ this.selectNodeHandler.addToSelection(node);
2761
+ this.openParents(node);
2762
+ this.getNodeElementForNode(node).select(mustSetFocus ?? true);
2763
+ this.saveState();
2764
+ return this.element;
2943
2765
  }
2944
- doLoadDataFromUrl(urlInfoParam, parentNode, onFinished) {
2945
- const urlInfo = urlInfoParam ?? this.getDataUrlInfo(parentNode);
2946
- this.dataLoader.loadFromUrl(urlInfo, parentNode, onFinished);
2766
+ appendNode(newNodeInfo, parentNodeParam) {
2767
+ const parentNode = parentNodeParam ?? this.tree;
2768
+ const node = parentNode.append(newNodeInfo);
2769
+ this.refreshElements(parentNode);
2770
+ return node;
2947
2771
  }
2948
- doSelectNode(node, optionsParam) {
2949
- const saveState = () => {
2950
- if (this.options.saveState) {
2951
- this.saveStateHandler.saveState();
2952
- }
2953
- };
2772
+ closeNode(node, slideParam) {
2954
2773
  if (!node) {
2955
- // Called with empty node -> deselect current node
2956
- this.deselectCurrentNode();
2957
- saveState();
2958
- return;
2959
- }
2960
- const defaultOptions = {
2961
- mustSetFocus: true,
2962
- mustToggle: true
2963
- };
2964
- const selectOptions = {
2965
- ...defaultOptions,
2966
- ...(optionsParam ?? {})
2967
- };
2968
- const canSelect = () => {
2969
- if (this.options.onCanSelectNode) {
2970
- return this.options.selectable && this.options.onCanSelectNode(node);
2971
- } else {
2972
- return this.options.selectable;
2973
- }
2974
- };
2975
- if (!canSelect()) {
2976
- return;
2977
- }
2978
- if (this.selectNodeHandler.isNodeSelected(node)) {
2979
- if (selectOptions.mustToggle) {
2980
- this.deselectCurrentNode();
2981
- this.triggerEvent("tree.select", {
2982
- node: null,
2983
- previous_node: node
2984
- });
2985
- }
2986
- } else {
2987
- const deselectedNode = this.getSelectedNode() || null;
2988
- this.deselectCurrentNode();
2989
- this.addToSelection(node, selectOptions.mustSetFocus);
2990
- this.triggerEvent("tree.select", {
2991
- deselected_node: deselectedNode,
2992
- node
2993
- });
2994
- this.openParents(node);
2774
+ throw Error(NODE_PARAM_IS_EMPTY);
2995
2775
  }
2996
- saveState();
2997
- }
2998
- getAutoOpenMaxLevel() {
2999
- if (this.options.autoOpen === true) {
3000
- return -1;
3001
- } else if (typeof this.options.autoOpen === "number") {
3002
- return this.options.autoOpen;
3003
- } else if (typeof this.options.autoOpen === "string") {
3004
- return parseInt(this.options.autoOpen, 10);
3005
- } else {
3006
- return 0;
2776
+ const slide = slideParam ?? this.options.slide;
2777
+ if (node.isFolder() || node.isEmptyFolder) {
2778
+ this.createFolderElement(node).close(slide, this.options.animationSpeed);
2779
+ this.saveState();
3007
2780
  }
2781
+ return this.element;
3008
2782
  }
3009
- getDataUrlInfo(node) {
3010
- const dataUrl = this.options.dataUrl ?? this.element.data("url");
3011
- const getUrlFromString = url => {
3012
- const urlInfo = {
3013
- url
3014
- };
3015
- setUrlInfoData(urlInfo);
3016
- return urlInfo;
3017
- };
3018
- const setUrlInfoData = urlInfo => {
3019
- if (node?.id) {
3020
- // Load on demand of a subtree; add node parameter
3021
- const data = {
3022
- node: node.id
3023
- };
3024
- urlInfo.data = data;
3025
- } else {
3026
- // Add selected_node parameter
3027
- const selectedNodeId = this.getNodeIdToBeSelected();
3028
- if (selectedNodeId) {
3029
- const data = {
3030
- selected_node: selectedNodeId
3031
- };
3032
- urlInfo.data = data;
3033
- }
3034
- }
3035
- };
3036
- if (typeof dataUrl === "function") {
3037
- return dataUrl(node);
3038
- } else if (typeof dataUrl === "string") {
3039
- return getUrlFromString(dataUrl);
3040
- } else if (dataUrl && typeof dataUrl === "object") {
3041
- setUrlInfoData(dataUrl);
3042
- return dataUrl;
3043
- } else {
3044
- return null;
3045
- }
2783
+ deinit() {
2784
+ this.element.empty();
2785
+ this.element.off();
2786
+ this.keyHandler.deinit();
2787
+ this.mouseHandler.deinit();
2788
+ this.tree = new Node({}, true);
2789
+ super.deinit();
3046
2790
  }
3047
- getDefaultClosedIcon() {
3048
- if (this.options.rtl) {
3049
- // triangle to the left
3050
- return "&#x25c0;";
3051
- } else {
3052
- // triangle to the right
3053
- return "&#x25ba;";
3054
- }
2791
+ getNodeByCallback(callback) {
2792
+ return this.tree.getNodeByCallback(callback);
3055
2793
  }
3056
- getNode(element) {
3057
- const liElement = element.closest("li.jqtree_common");
3058
- if (liElement) {
3059
- return jQuery(liElement).data("node");
3060
- } else {
2794
+ getNodeByHtmlElement(inputElement) {
2795
+ const element = inputElement instanceof HTMLElement ? inputElement : inputElement[0];
2796
+ if (!element) {
3061
2797
  return null;
3062
2798
  }
2799
+ return this.getNode(element);
3063
2800
  }
3064
- getNodeElement(element) {
3065
- const node = this.getNode(element);
3066
- if (node) {
3067
- return this.getNodeElementForNode(node);
3068
- } else {
3069
- return null;
3070
- }
2801
+ getNodeById(nodeId) {
2802
+ return this.tree.getNodeById(nodeId);
3071
2803
  }
3072
- getNodeElementForNode(node) {
3073
- if (node.isFolder()) {
3074
- return this.createFolderElement(node);
3075
- } else {
3076
- return this.createNodeElement(node);
3077
- }
2804
+ getNodeByName(name) {
2805
+ return this.tree.getNodeByName(name);
3078
2806
  }
3079
- getNodeIdToBeSelected() {
3080
- if (this.options.saveState) {
3081
- return this.saveStateHandler.getNodeIdToBeSelected();
3082
- } else {
3083
- return null;
3084
- }
2807
+ getNodeByNameMustExist(name) {
2808
+ return this.tree.getNodeByNameMustExist(name);
3085
2809
  }
3086
- getRtlOption() {
3087
- if (this.options.rtl != null) {
3088
- return this.options.rtl;
3089
- } else {
3090
- const dataRtl = this.element.data("rtl");
3091
- if (dataRtl !== null && dataRtl !== false && dataRtl !== undefined) {
3092
- return true;
3093
- } else {
3094
- return false;
3095
- }
3096
- }
2810
+ getNodesByProperty(key, value) {
2811
+ return this.tree.getNodesByProperty(key, value);
3097
2812
  }
3098
- initData() {
3099
- if (this.options.data) {
3100
- this.doLoadData(this.options.data, null);
3101
- } else {
3102
- const dataUrl = this.getDataUrlInfo(null);
3103
- if (dataUrl) {
3104
- this.doLoadDataFromUrl(null, null, null);
3105
- } else {
3106
- this.doLoadData([], null);
3107
- }
3108
- }
2813
+ getSelectedNode() {
2814
+ return this.selectNodeHandler.getSelectedNode();
3109
2815
  }
3110
- initTree(data) {
3111
- const doInit = () => {
3112
- if (!this.isInitialized) {
3113
- this.isInitialized = true;
3114
- this.triggerEvent("tree.init");
3115
- }
3116
- };
3117
- this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);
3118
- this.selectNodeHandler.clear();
3119
- this.tree.loadFromData(data);
3120
- const mustLoadOnDemand = this.setInitialState();
3121
- this.refreshElements(null);
3122
- if (!mustLoadOnDemand) {
3123
- doInit();
3124
- } else {
3125
- // Load data on demand and then init the tree
3126
- this.setInitialStateOnDemand(doInit);
3127
- }
2816
+ getSelectedNodes() {
2817
+ return this.selectNodeHandler.getSelectedNodes();
3128
2818
  }
3129
- isFocusOnTree() {
3130
- const activeElement = document.activeElement;
3131
- return Boolean(activeElement && activeElement.tagName === "SPAN" && this.containsElement(activeElement));
2819
+ getState() {
2820
+ return this.saveStateHandler.getState();
3132
2821
  }
3133
- isSelectedNodeInSubtree(subtree) {
3134
- const selectedNode = this.getSelectedNode();
3135
- if (!selectedNode) {
3136
- return false;
3137
- } else {
3138
- return subtree === selectedNode || subtree.isParentOf(selectedNode);
3139
- }
2822
+ getStateFromStorage() {
2823
+ return this.saveStateHandler.getStateFromStorage();
3140
2824
  }
3141
- loadFolderOnDemand(node) {
3142
- let slide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
3143
- let onFinished = arguments.length > 2 ? arguments[2] : undefined;
3144
- node.is_loading = true;
3145
- this.doLoadDataFromUrl(null, node, () => {
3146
- this.openNodeInternal(node, slide, onFinished);
3147
- });
2825
+ getTree() {
2826
+ return this.tree;
3148
2827
  }
3149
- loadSubtree(data, parentNode) {
3150
- parentNode.loadFromData(data);
3151
- parentNode.load_on_demand = false;
3152
- parentNode.is_loading = false;
3153
- this.refreshElements(parentNode);
2828
+ getVersion() {
2829
+ return version;
3154
2830
  }
3155
- mouseCapture(positionInfo) {
3156
- if (this.options.dragAndDrop) {
3157
- return this.dndHandler.mouseCapture(positionInfo);
3158
- } else {
3159
- return false;
2831
+ init() {
2832
+ super.init();
2833
+ this.element = this.$el;
2834
+ this.isInitialized = false;
2835
+ this.options.rtl = this.getRtlOption();
2836
+ if (this.options.closedIcon == null) {
2837
+ this.options.closedIcon = this.getDefaultClosedIcon();
3160
2838
  }
2839
+ this.connectHandlers();
2840
+ this.initData();
3161
2841
  }
3162
- mouseDrag(positionInfo) {
3163
- if (this.options.dragAndDrop) {
3164
- const result = this.dndHandler.mouseDrag(positionInfo);
3165
- this.scrollHandler.checkScrolling(positionInfo);
3166
- return result;
3167
- } else {
3168
- return false;
3169
- }
2842
+ isDragging() {
2843
+ return this.dndHandler.isDragging;
3170
2844
  }
3171
- mouseStart(positionInfo) {
3172
- if (this.options.dragAndDrop) {
3173
- return this.dndHandler.mouseStart(positionInfo);
3174
- } else {
3175
- return false;
2845
+ isNodeSelected(node) {
2846
+ if (!node) {
2847
+ throw Error(NODE_PARAM_IS_EMPTY);
3176
2848
  }
2849
+ return this.selectNodeHandler.isNodeSelected(node);
3177
2850
  }
3178
- mouseStop(positionInfo) {
3179
- if (this.options.dragAndDrop) {
3180
- this.scrollHandler.stopScrolling();
3181
- return this.dndHandler.mouseStop(positionInfo);
3182
- } else {
3183
- return false;
3184
- }
3185
- }
3186
- openNodeInternal(node) {
3187
- let slide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
3188
- let onFinished = arguments.length > 2 ? arguments[2] : undefined;
3189
- const doOpenNode = (_node, _slide, _onFinished) => {
3190
- if (!node.children.length) {
3191
- return;
3192
- }
3193
- const folderElement = this.createFolderElement(_node);
3194
- folderElement.open(_onFinished, _slide, this.options.animationSpeed);
3195
- };
3196
- if (node.isFolder() || node.isEmptyFolder) {
3197
- if (node.load_on_demand) {
3198
- this.loadFolderOnDemand(node, slide, onFinished);
3199
- } else {
3200
- let parent = node.parent;
3201
- while (parent) {
3202
- // nb: do not open root element
3203
- if (parent.parent) {
3204
- doOpenNode(parent, false);
3205
- }
3206
- parent = parent.parent;
3207
- }
3208
- doOpenNode(node, slide, onFinished);
3209
- this.saveState();
3210
- }
3211
- }
3212
- }
3213
- openParents(node) {
3214
- const parent = node.parent;
3215
- if (parent?.parent && !parent.is_open) {
3216
- this.openNode(parent, false);
3217
- }
2851
+ loadData(data, parentNode) {
2852
+ this.doLoadData(data, parentNode);
2853
+ return this.element;
3218
2854
  }
3219
2855
 
3220
2856
  /*
3221
- Redraw the tree or part of the tree.
3222
- from_node: redraw this subtree
2857
+ signatures:
2858
+ - loadDataFromUrl(url, parent_node=null, on_finished=null)
2859
+ loadDataFromUrl('/my_data');
2860
+ loadDataFromUrl('/my_data', node1);
2861
+ loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
2862
+ loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
2863
+ - loadDataFromUrl(parent_node=null, on_finished=null)
2864
+ loadDataFromUrl();
2865
+ loadDataFromUrl(node1);
2866
+ loadDataFromUrl(null, function() { console.log('finished'); });
2867
+ loadDataFromUrl(node1, function() { console.log('finished'); });
3223
2868
  */
3224
- refreshElements(fromNode) {
3225
- const mustSetFocus = this.isFocusOnTree();
3226
- const mustSelect = fromNode ? this.isSelectedNodeInSubtree(fromNode) : false;
3227
- this.renderer.render(fromNode);
3228
- if (mustSelect) {
3229
- this.selectCurrentNode(mustSetFocus);
2869
+ loadDataFromUrl(param1, param2, param3) {
2870
+ if (typeof param1 === "string") {
2871
+ // first parameter is url
2872
+ this.doLoadDataFromUrl(param1, param2, param3 ?? null);
2873
+ } else {
2874
+ // first parameter is not url
2875
+ this.doLoadDataFromUrl(null, param1, param2);
3230
2876
  }
3231
- this.triggerEvent("tree.refresh");
2877
+ return this.element;
3232
2878
  }
3233
- saveState() {
3234
- if (this.options.saveState) {
3235
- this.saveStateHandler.saveState();
2879
+ moveDown() {
2880
+ const selectedNode = this.getSelectedNode();
2881
+ if (selectedNode) {
2882
+ this.keyHandler.moveDown(selectedNode);
3236
2883
  }
2884
+ return this.element;
3237
2885
  }
3238
- selectCurrentNode(mustSetFocus) {
3239
- const node = this.getSelectedNode();
3240
- if (node) {
3241
- const nodeElement = this.getNodeElementForNode(node);
3242
- nodeElement.select(mustSetFocus);
2886
+ moveNode(node, targetNode, position) {
2887
+ if (!node) {
2888
+ throw Error(NODE_PARAM_IS_EMPTY);
2889
+ }
2890
+ if (!targetNode) {
2891
+ throw Error(PARAM_IS_EMPTY + "targetNode");
2892
+ }
2893
+ if (!position) {
2894
+ throw Error(PARAM_IS_EMPTY + "position");
3243
2895
  }
2896
+ this.tree.moveNode(node, targetNode, position);
2897
+ this.refreshElements(null);
2898
+ return this.element;
3244
2899
  }
3245
-
3246
- // Set initial state, either by restoring the state or auto-opening nodes
3247
- // result: must load nodes on demand?
3248
- setInitialState() {
3249
- const restoreState = () => {
3250
- // result: is state restored, must load on demand?
3251
- if (!this.options.saveState) {
3252
- return [false, false];
3253
- } else {
3254
- const state = this.saveStateHandler.getStateFromStorage();
3255
- if (!state) {
3256
- return [false, false];
3257
- } else {
3258
- const mustLoadOnDemand = this.saveStateHandler.setInitialState(state);
3259
-
3260
- // return true: the state is restored
3261
- return [true, mustLoadOnDemand];
3262
- }
3263
- }
3264
- };
3265
- const autoOpenNodes = () => {
3266
- // result: must load on demand?
3267
- if (this.options.autoOpen === false) {
3268
- return false;
3269
- }
3270
- const maxLevel = this.getAutoOpenMaxLevel();
3271
- let mustLoadOnDemand = false;
3272
- this.tree.iterate((node, level) => {
3273
- if (node.load_on_demand) {
3274
- mustLoadOnDemand = true;
3275
- return false;
3276
- } else if (!node.hasChildren()) {
3277
- return false;
3278
- } else {
3279
- node.is_open = true;
3280
- return level !== maxLevel;
3281
- }
3282
- });
3283
- return mustLoadOnDemand;
3284
- };
3285
- let [isRestored, mustLoadOnDemand] = restoreState(); // eslint-disable-line prefer-const
3286
-
3287
- if (!isRestored) {
3288
- mustLoadOnDemand = autoOpenNodes();
2900
+ moveUp() {
2901
+ const selectedNode = this.getSelectedNode();
2902
+ if (selectedNode) {
2903
+ this.keyHandler.moveUp(selectedNode);
3289
2904
  }
3290
- return mustLoadOnDemand;
2905
+ return this.element;
3291
2906
  }
3292
-
3293
- // Set the initial state for nodes that are loaded on demand
3294
- // Call cb_finished when done
3295
- setInitialStateOnDemand(cbFinished) {
3296
- const restoreState = () => {
3297
- if (!this.options.saveState) {
3298
- return false;
2907
+ openNode(node, param1, param2) {
2908
+ if (!node) {
2909
+ throw Error(NODE_PARAM_IS_EMPTY);
2910
+ }
2911
+ const parseParams = () => {
2912
+ let onFinished;
2913
+ let slide;
2914
+ if (isFunction(param1)) {
2915
+ onFinished = param1;
2916
+ slide = null;
3299
2917
  } else {
3300
- const state = this.saveStateHandler.getStateFromStorage();
3301
- if (!state) {
3302
- return false;
3303
- } else {
3304
- this.saveStateHandler.setInitialStateOnDemand(state, cbFinished);
3305
- return true;
3306
- }
2918
+ slide = param1;
2919
+ onFinished = param2;
3307
2920
  }
2921
+ if (slide == null) {
2922
+ slide = this.options.slide;
2923
+ }
2924
+ return [slide, onFinished];
3308
2925
  };
3309
- const autoOpenNodes = () => {
3310
- const maxLevel = this.getAutoOpenMaxLevel();
3311
- let loadingCount = 0;
3312
- const loadAndOpenNode = node => {
3313
- loadingCount += 1;
3314
- this.openNodeInternal(node, false, () => {
3315
- loadingCount -= 1;
3316
- openNodes();
3317
- });
3318
- };
3319
- const openNodes = () => {
3320
- this.tree.iterate((node, level) => {
3321
- if (node.load_on_demand) {
3322
- if (!node.is_loading) {
3323
- loadAndOpenNode(node);
3324
- }
3325
- return false;
3326
- } else {
3327
- this.openNodeInternal(node, false);
3328
- return level !== maxLevel;
3329
- }
3330
- });
3331
- if (loadingCount === 0) {
3332
- cbFinished();
3333
- }
3334
- };
3335
- openNodes();
3336
- };
3337
- if (!restoreState()) {
3338
- autoOpenNodes();
3339
- }
2926
+ const [slide, onFinished] = parseParams();
2927
+ this.openNodeInternal(node, slide, onFinished);
2928
+ return this.element;
3340
2929
  }
3341
- triggerEvent(eventName, values) {
3342
- const event = jQuery.Event(eventName, values);
3343
- this.element.trigger(event);
3344
- return event;
2930
+ prependNode(newNodeInfo, parentNodeParam) {
2931
+ const parentNode = parentNodeParam ?? this.tree;
2932
+ const node = parentNode.prepend(newNodeInfo);
2933
+ this.refreshElements(parentNode);
2934
+ return node;
3345
2935
  }
3346
- addNodeAfter(newNodeInfo, existingNode) {
3347
- const newNode = existingNode.addAfter(newNodeInfo);
3348
- if (newNode) {
3349
- this.refreshElements(existingNode.parent);
3350
- }
3351
- return newNode;
2936
+ refresh() {
2937
+ this.refreshElements(null);
2938
+ return this.element;
3352
2939
  }
3353
- addNodeBefore(newNodeInfo, existingNode) {
3354
- if (!existingNode) {
3355
- throw Error(PARAM_IS_EMPTY + "existingNode");
3356
- }
3357
- const newNode = existingNode.addBefore(newNodeInfo);
3358
- if (newNode) {
3359
- this.refreshElements(existingNode.parent);
3360
- }
3361
- return newNode;
2940
+ refreshHitAreas() {
2941
+ this.dndHandler.refresh();
2942
+ return this.element;
3362
2943
  }
3363
- addParentNode(newNodeInfo, existingNode) {
3364
- if (!existingNode) {
3365
- throw Error(PARAM_IS_EMPTY + "existingNode");
3366
- }
3367
- const newNode = existingNode.addParent(newNodeInfo);
3368
- if (newNode) {
3369
- this.refreshElements(newNode.parent);
3370
- }
3371
- return newNode;
2944
+ reload(onFinished) {
2945
+ this.doLoadDataFromUrl(null, null, onFinished);
2946
+ return this.element;
3372
2947
  }
3373
- addToSelection(node, mustSetFocus) {
2948
+ removeFromSelection(node) {
3374
2949
  if (!node) {
3375
2950
  throw Error(NODE_PARAM_IS_EMPTY);
3376
2951
  }
3377
- this.selectNodeHandler.addToSelection(node);
3378
- this.openParents(node);
3379
- this.getNodeElementForNode(node).select(mustSetFocus ?? true);
3380
- this.saveState();
3381
- return this.element;
3382
- }
3383
- appendNode(newNodeInfo, parentNodeParam) {
3384
- const parentNode = parentNodeParam ?? this.tree;
3385
- const node = parentNode.append(newNodeInfo);
3386
- this.refreshElements(parentNode);
3387
- return node;
3388
- }
3389
- closeNode(node, slideParam) {
3390
- if (!node) {
3391
- throw Error(NODE_PARAM_IS_EMPTY);
3392
- }
3393
- const slide = slideParam ?? this.options.slide;
3394
- if (node.isFolder() || node.isEmptyFolder) {
3395
- this.createFolderElement(node).close(slide, this.options.animationSpeed);
3396
- this.saveState();
3397
- }
3398
- return this.element;
3399
- }
3400
- deinit() {
3401
- this.element.empty();
3402
- this.element.off();
3403
- this.keyHandler.deinit();
3404
- this.mouseHandler.deinit();
3405
- this.tree = new Node({}, true);
3406
- super.deinit();
3407
- }
3408
- getNodeByCallback(callback) {
3409
- return this.tree.getNodeByCallback(callback);
3410
- }
3411
- getNodeByHtmlElement(inputElement) {
3412
- const element = inputElement instanceof HTMLElement ? inputElement : inputElement[0];
3413
- if (!element) {
3414
- return null;
3415
- }
3416
- return this.getNode(element);
3417
- }
3418
- getNodeById(nodeId) {
3419
- return this.tree.getNodeById(nodeId);
3420
- }
3421
- getNodeByName(name) {
3422
- return this.tree.getNodeByName(name);
3423
- }
3424
- getNodeByNameMustExist(name) {
3425
- return this.tree.getNodeByNameMustExist(name);
3426
- }
3427
- getNodesByProperty(key, value) {
3428
- return this.tree.getNodesByProperty(key, value);
3429
- }
3430
- getSelectedNode() {
3431
- return this.selectNodeHandler.getSelectedNode();
3432
- }
3433
- getSelectedNodes() {
3434
- return this.selectNodeHandler.getSelectedNodes();
3435
- }
3436
- getState() {
3437
- return this.saveStateHandler.getState();
3438
- }
3439
- getStateFromStorage() {
3440
- return this.saveStateHandler.getStateFromStorage();
3441
- }
3442
- getTree() {
3443
- return this.tree;
3444
- }
3445
- getVersion() {
3446
- return version;
3447
- }
3448
- init() {
3449
- super.init();
3450
- this.element = this.$el;
3451
- this.isInitialized = false;
3452
- this.options.rtl = this.getRtlOption();
3453
- if (this.options.closedIcon == null) {
3454
- this.options.closedIcon = this.getDefaultClosedIcon();
3455
- }
3456
- this.connectHandlers();
3457
- this.initData();
3458
- }
3459
- isDragging() {
3460
- return this.dndHandler.isDragging;
3461
- }
3462
- isNodeSelected(node) {
3463
- if (!node) {
3464
- throw Error(NODE_PARAM_IS_EMPTY);
3465
- }
3466
- return this.selectNodeHandler.isNodeSelected(node);
3467
- }
3468
- loadData(data, parentNode) {
3469
- this.doLoadData(data, parentNode);
3470
- return this.element;
3471
- }
3472
-
3473
- /*
3474
- signatures:
3475
- - loadDataFromUrl(url, parent_node=null, on_finished=null)
3476
- loadDataFromUrl('/my_data');
3477
- loadDataFromUrl('/my_data', node1);
3478
- loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
3479
- loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
3480
- - loadDataFromUrl(parent_node=null, on_finished=null)
3481
- loadDataFromUrl();
3482
- loadDataFromUrl(node1);
3483
- loadDataFromUrl(null, function() { console.log('finished'); });
3484
- loadDataFromUrl(node1, function() { console.log('finished'); });
3485
- */
3486
- loadDataFromUrl(param1, param2, param3) {
3487
- if (typeof param1 === "string") {
3488
- // first parameter is url
3489
- this.doLoadDataFromUrl(param1, param2, param3 ?? null);
3490
- } else {
3491
- // first parameter is not url
3492
- this.doLoadDataFromUrl(null, param1, param2);
3493
- }
3494
- return this.element;
3495
- }
3496
- moveDown() {
3497
- const selectedNode = this.getSelectedNode();
3498
- if (selectedNode) {
3499
- this.keyHandler.moveDown(selectedNode);
3500
- }
3501
- return this.element;
3502
- }
3503
- moveNode(node, targetNode, position) {
3504
- if (!node) {
3505
- throw Error(NODE_PARAM_IS_EMPTY);
3506
- }
3507
- if (!targetNode) {
3508
- throw Error(PARAM_IS_EMPTY + "targetNode");
3509
- }
3510
- if (!position) {
3511
- throw Error(PARAM_IS_EMPTY + "position");
3512
- }
3513
- const positionIndex = getPosition(position);
3514
- if (positionIndex !== undefined) {
3515
- this.tree.moveNode(node, targetNode, positionIndex);
3516
- this.refreshElements(null);
3517
- }
3518
- return this.element;
3519
- }
3520
- moveUp() {
3521
- const selectedNode = this.getSelectedNode();
3522
- if (selectedNode) {
3523
- this.keyHandler.moveUp(selectedNode);
3524
- }
3525
- return this.element;
3526
- }
3527
- openNode(node, param1, param2) {
3528
- if (!node) {
3529
- throw Error(NODE_PARAM_IS_EMPTY);
3530
- }
3531
- const parseParams = () => {
3532
- let onFinished;
3533
- let slide;
3534
- if (isFunction(param1)) {
3535
- onFinished = param1;
3536
- slide = null;
3537
- } else {
3538
- slide = param1;
3539
- onFinished = param2;
3540
- }
3541
- if (slide == null) {
3542
- slide = this.options.slide;
3543
- }
3544
- return [slide, onFinished];
3545
- };
3546
- const [slide, onFinished] = parseParams();
3547
- this.openNodeInternal(node, slide, onFinished);
3548
- return this.element;
3549
- }
3550
- prependNode(newNodeInfo, parentNodeParam) {
3551
- const parentNode = parentNodeParam ?? this.tree;
3552
- const node = parentNode.prepend(newNodeInfo);
3553
- this.refreshElements(parentNode);
3554
- return node;
3555
- }
3556
- refresh() {
3557
- this.refreshElements(null);
3558
- return this.element;
3559
- }
3560
- refreshHitAreas() {
3561
- this.dndHandler.refresh();
3562
- return this.element;
3563
- }
3564
- reload(onFinished) {
3565
- this.doLoadDataFromUrl(null, null, onFinished);
3566
- return this.element;
3567
- }
3568
- removeFromSelection(node) {
3569
- if (!node) {
3570
- throw Error(NODE_PARAM_IS_EMPTY);
3571
- }
3572
- this.selectNodeHandler.removeFromSelection(node);
3573
- this.getNodeElementForNode(node).deselect();
2952
+ this.selectNodeHandler.removeFromSelection(node);
2953
+ this.getNodeElementForNode(node).deselect();
3574
2954
  this.saveState();
3575
2955
  return this.element;
3576
2956
  }
@@ -3654,6 +3034,610 @@ var jqtree = (function (exports) {
3654
3034
  this.refreshElements(node);
3655
3035
  return this.element;
3656
3036
  }
3037
+ connectHandlers() {
3038
+ const {
3039
+ autoEscape,
3040
+ buttonLeft,
3041
+ closedIcon,
3042
+ dataFilter,
3043
+ dragAndDrop,
3044
+ keyboardSupport,
3045
+ onCanMove,
3046
+ onCanMoveTo,
3047
+ onCreateLi,
3048
+ onDragMove,
3049
+ onDragStop,
3050
+ onGetStateFromStorage,
3051
+ onIsMoveHandle,
3052
+ onLoadFailed,
3053
+ onLoading,
3054
+ onSetStateFromStorage,
3055
+ openedIcon,
3056
+ openFolderDelay,
3057
+ rtl,
3058
+ saveState,
3059
+ showEmptyFolder,
3060
+ slide,
3061
+ tabIndex
3062
+ } = this.options;
3063
+ const closeNode = this.closeNode.bind(this);
3064
+ const getNodeElement = this.getNodeElement.bind(this);
3065
+ const getNodeElementForNode = this.getNodeElementForNode.bind(this);
3066
+ const getNodeById = this.getNodeById.bind(this);
3067
+ const getSelectedNode = this.getSelectedNode.bind(this);
3068
+ const getTree = this.getTree.bind(this);
3069
+ const isFocusOnTree = this.isFocusOnTree.bind(this);
3070
+ const loadData = this.loadData.bind(this);
3071
+ const openNode = this.openNodeInternal.bind(this);
3072
+ const refreshElements = this.refreshElements.bind(this);
3073
+ const refreshHitAreas = this.refreshHitAreas.bind(this);
3074
+ const selectNode = this.selectNode.bind(this);
3075
+ const $treeElement = this.element;
3076
+ const treeElement = this.element.get(0);
3077
+ const triggerEvent = this.triggerEvent.bind(this);
3078
+ const selectNodeHandler = new SelectNodeHandler({
3079
+ getNodeById
3080
+ });
3081
+ const addToSelection = selectNodeHandler.addToSelection.bind(selectNodeHandler);
3082
+ const getSelectedNodes = selectNodeHandler.getSelectedNodes.bind(selectNodeHandler);
3083
+ const isNodeSelected = selectNodeHandler.isNodeSelected.bind(selectNodeHandler);
3084
+ const removeFromSelection = selectNodeHandler.removeFromSelection.bind(selectNodeHandler);
3085
+ const getMouseDelay = () => this.options.startDndDelay ?? 0;
3086
+ const dataLoader = new DataLoader({
3087
+ dataFilter,
3088
+ loadData,
3089
+ onLoadFailed,
3090
+ onLoading,
3091
+ treeElement,
3092
+ triggerEvent
3093
+ });
3094
+ const saveStateHandler = new SaveStateHandler({
3095
+ addToSelection,
3096
+ getNodeById,
3097
+ getSelectedNodes,
3098
+ getTree,
3099
+ onGetStateFromStorage,
3100
+ onSetStateFromStorage,
3101
+ openNode,
3102
+ refreshElements,
3103
+ removeFromSelection,
3104
+ saveState
3105
+ });
3106
+ const scrollHandler = new ScrollHandler({
3107
+ refreshHitAreas,
3108
+ treeElement
3109
+ });
3110
+ const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);
3111
+ const dndHandler = new DragAndDropHandler({
3112
+ autoEscape,
3113
+ getNodeElement,
3114
+ getNodeElementForNode,
3115
+ getScrollLeft,
3116
+ getTree,
3117
+ onCanMove,
3118
+ onCanMoveTo,
3119
+ onDragMove,
3120
+ onDragStop,
3121
+ onIsMoveHandle,
3122
+ openFolderDelay,
3123
+ openNode,
3124
+ refreshElements,
3125
+ slide,
3126
+ treeElement,
3127
+ triggerEvent
3128
+ });
3129
+ const keyHandler = new KeyHandler({
3130
+ closeNode,
3131
+ getSelectedNode,
3132
+ isFocusOnTree,
3133
+ keyboardSupport,
3134
+ openNode,
3135
+ selectNode
3136
+ });
3137
+ const renderer = new ElementsRenderer({
3138
+ $element: $treeElement,
3139
+ autoEscape,
3140
+ buttonLeft,
3141
+ closedIcon,
3142
+ dragAndDrop,
3143
+ getTree,
3144
+ isNodeSelected,
3145
+ onCreateLi,
3146
+ openedIcon,
3147
+ rtl,
3148
+ showEmptyFolder,
3149
+ tabIndex
3150
+ });
3151
+ const getNode = this.getNode.bind(this);
3152
+ const onMouseCapture = this.mouseCapture.bind(this);
3153
+ const onMouseDrag = this.mouseDrag.bind(this);
3154
+ const onMouseStart = this.mouseStart.bind(this);
3155
+ const onMouseStop = this.mouseStop.bind(this);
3156
+ const mouseHandler = new MouseHandler({
3157
+ element: treeElement,
3158
+ getMouseDelay,
3159
+ getNode,
3160
+ onClickButton: this.toggle.bind(this),
3161
+ onClickTitle: this.doSelectNode.bind(this),
3162
+ onMouseCapture,
3163
+ onMouseDrag,
3164
+ onMouseStart,
3165
+ onMouseStop,
3166
+ triggerEvent,
3167
+ useContextMenu: this.options.useContextMenu
3168
+ });
3169
+ this.dataLoader = dataLoader;
3170
+ this.dndHandler = dndHandler;
3171
+ this.keyHandler = keyHandler;
3172
+ this.mouseHandler = mouseHandler;
3173
+ this.renderer = renderer;
3174
+ this.saveStateHandler = saveStateHandler;
3175
+ this.scrollHandler = scrollHandler;
3176
+ this.selectNodeHandler = selectNodeHandler;
3177
+ }
3178
+ containsElement(element) {
3179
+ const node = this.getNode(element);
3180
+ return node != null && node.tree === this.tree;
3181
+ }
3182
+ createFolderElement(node) {
3183
+ const closedIconElement = this.renderer.closedIconElement;
3184
+ const getScrollLeft = this.scrollHandler.getScrollLeft.bind(this.scrollHandler);
3185
+ const openedIconElement = this.renderer.openedIconElement;
3186
+ const tabIndex = this.options.tabIndex;
3187
+ const treeElement = this.element.get(0);
3188
+ const triggerEvent = this.triggerEvent.bind(this);
3189
+ return new FolderElement({
3190
+ closedIconElement,
3191
+ getScrollLeft,
3192
+ node,
3193
+ openedIconElement,
3194
+ tabIndex,
3195
+ treeElement,
3196
+ triggerEvent
3197
+ });
3198
+ }
3199
+ createNodeElement(node) {
3200
+ const getScrollLeft = this.scrollHandler.getScrollLeft.bind(this.scrollHandler);
3201
+ const tabIndex = this.options.tabIndex;
3202
+ const treeElement = this.element.get(0);
3203
+ return new NodeElement({
3204
+ getScrollLeft,
3205
+ node,
3206
+ tabIndex,
3207
+ treeElement
3208
+ });
3209
+ }
3210
+ deselectCurrentNode() {
3211
+ const node = this.getSelectedNode();
3212
+ if (node) {
3213
+ this.removeFromSelection(node);
3214
+ }
3215
+ }
3216
+ deselectNodes(parentNode) {
3217
+ const selectedNodesUnderParent = this.selectNodeHandler.getSelectedNodesUnder(parentNode);
3218
+ for (const n of selectedNodesUnderParent) {
3219
+ this.selectNodeHandler.removeFromSelection(n);
3220
+ }
3221
+ }
3222
+ doLoadData(data, parentNode) {
3223
+ if (data) {
3224
+ if (parentNode) {
3225
+ this.deselectNodes(parentNode);
3226
+ this.loadSubtree(data, parentNode);
3227
+ } else {
3228
+ this.initTree(data);
3229
+ }
3230
+ if (this.isDragging()) {
3231
+ this.dndHandler.refresh();
3232
+ }
3233
+ }
3234
+ this.triggerEvent("tree.load_data", {
3235
+ parent_node: parentNode,
3236
+ tree_data: data
3237
+ });
3238
+ }
3239
+ doLoadDataFromUrl(urlInfoParam, parentNode, onFinished) {
3240
+ const urlInfo = urlInfoParam ?? this.getDataUrlInfo(parentNode);
3241
+ this.dataLoader.loadFromUrl(urlInfo, parentNode, onFinished);
3242
+ }
3243
+ doSelectNode(node, optionsParam) {
3244
+ const saveState = () => {
3245
+ if (this.options.saveState) {
3246
+ this.saveStateHandler.saveState();
3247
+ }
3248
+ };
3249
+ if (!node) {
3250
+ // Called with empty node -> deselect current node
3251
+ this.deselectCurrentNode();
3252
+ saveState();
3253
+ return;
3254
+ }
3255
+ const defaultOptions = {
3256
+ mustSetFocus: true,
3257
+ mustToggle: true
3258
+ };
3259
+ const selectOptions = {
3260
+ ...defaultOptions,
3261
+ ...(optionsParam ?? {})
3262
+ };
3263
+ const canSelect = () => {
3264
+ if (this.options.onCanSelectNode) {
3265
+ return this.options.selectable && this.options.onCanSelectNode(node);
3266
+ } else {
3267
+ return this.options.selectable;
3268
+ }
3269
+ };
3270
+ if (!canSelect()) {
3271
+ return;
3272
+ }
3273
+ if (this.selectNodeHandler.isNodeSelected(node)) {
3274
+ if (selectOptions.mustToggle) {
3275
+ this.deselectCurrentNode();
3276
+ this.triggerEvent("tree.select", {
3277
+ node: null,
3278
+ previous_node: node
3279
+ });
3280
+ }
3281
+ } else {
3282
+ const deselectedNode = this.getSelectedNode() || null;
3283
+ this.deselectCurrentNode();
3284
+ this.addToSelection(node, selectOptions.mustSetFocus);
3285
+ this.triggerEvent("tree.select", {
3286
+ deselected_node: deselectedNode,
3287
+ node
3288
+ });
3289
+ this.openParents(node);
3290
+ }
3291
+ saveState();
3292
+ }
3293
+ getAutoOpenMaxLevel() {
3294
+ if (this.options.autoOpen === true) {
3295
+ return -1;
3296
+ } else if (typeof this.options.autoOpen === "number") {
3297
+ return this.options.autoOpen;
3298
+ } else if (typeof this.options.autoOpen === "string") {
3299
+ return parseInt(this.options.autoOpen, 10);
3300
+ } else {
3301
+ return 0;
3302
+ }
3303
+ }
3304
+ getDataUrlInfo(node) {
3305
+ const dataUrl = this.options.dataUrl ?? this.element.data("url");
3306
+ const getUrlFromString = url => {
3307
+ const urlInfo = {
3308
+ url
3309
+ };
3310
+ setUrlInfoData(urlInfo);
3311
+ return urlInfo;
3312
+ };
3313
+ const setUrlInfoData = urlInfo => {
3314
+ if (node?.id) {
3315
+ // Load on demand of a subtree; add node parameter
3316
+ const data = {
3317
+ node: node.id
3318
+ };
3319
+ urlInfo.data = data;
3320
+ } else {
3321
+ // Add selected_node parameter
3322
+ const selectedNodeId = this.getNodeIdToBeSelected();
3323
+ if (selectedNodeId) {
3324
+ const data = {
3325
+ selected_node: selectedNodeId
3326
+ };
3327
+ urlInfo.data = data;
3328
+ }
3329
+ }
3330
+ };
3331
+ if (typeof dataUrl === "function") {
3332
+ return dataUrl(node);
3333
+ } else if (typeof dataUrl === "string") {
3334
+ return getUrlFromString(dataUrl);
3335
+ } else if (dataUrl && typeof dataUrl === "object") {
3336
+ setUrlInfoData(dataUrl);
3337
+ return dataUrl;
3338
+ } else {
3339
+ return null;
3340
+ }
3341
+ }
3342
+ getDefaultClosedIcon() {
3343
+ if (this.options.rtl) {
3344
+ // triangle to the left
3345
+ return "&#x25c0;";
3346
+ } else {
3347
+ // triangle to the right
3348
+ return "&#x25ba;";
3349
+ }
3350
+ }
3351
+ getNode(element) {
3352
+ const liElement = element.closest("li.jqtree_common");
3353
+ if (liElement) {
3354
+ return jQuery(liElement).data("node");
3355
+ } else {
3356
+ return null;
3357
+ }
3358
+ }
3359
+ getNodeElement(element) {
3360
+ const node = this.getNode(element);
3361
+ if (node) {
3362
+ return this.getNodeElementForNode(node);
3363
+ } else {
3364
+ return null;
3365
+ }
3366
+ }
3367
+ getNodeElementForNode(node) {
3368
+ if (node.isFolder()) {
3369
+ return this.createFolderElement(node);
3370
+ } else {
3371
+ return this.createNodeElement(node);
3372
+ }
3373
+ }
3374
+ getNodeIdToBeSelected() {
3375
+ if (this.options.saveState) {
3376
+ return this.saveStateHandler.getNodeIdToBeSelected();
3377
+ } else {
3378
+ return null;
3379
+ }
3380
+ }
3381
+ getRtlOption() {
3382
+ if (this.options.rtl != null) {
3383
+ return this.options.rtl;
3384
+ } else {
3385
+ const dataRtl = this.element.data("rtl");
3386
+ if (dataRtl !== null && dataRtl !== false && dataRtl !== undefined) {
3387
+ return true;
3388
+ } else {
3389
+ return false;
3390
+ }
3391
+ }
3392
+ }
3393
+ initData() {
3394
+ if (this.options.data) {
3395
+ this.doLoadData(this.options.data, null);
3396
+ } else {
3397
+ const dataUrl = this.getDataUrlInfo(null);
3398
+ if (dataUrl) {
3399
+ this.doLoadDataFromUrl(null, null, null);
3400
+ } else {
3401
+ this.doLoadData([], null);
3402
+ }
3403
+ }
3404
+ }
3405
+ initTree(data) {
3406
+ const doInit = () => {
3407
+ if (!this.isInitialized) {
3408
+ this.isInitialized = true;
3409
+ this.triggerEvent("tree.init");
3410
+ }
3411
+ };
3412
+ this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);
3413
+ this.selectNodeHandler.clear();
3414
+ this.tree.loadFromData(data);
3415
+ const mustLoadOnDemand = this.setInitialState();
3416
+ this.refreshElements(null);
3417
+ if (!mustLoadOnDemand) {
3418
+ doInit();
3419
+ } else {
3420
+ // Load data on demand and then init the tree
3421
+ this.setInitialStateOnDemand(doInit);
3422
+ }
3423
+ }
3424
+ isFocusOnTree() {
3425
+ const activeElement = document.activeElement;
3426
+ return Boolean(activeElement && activeElement.tagName === "SPAN" && this.containsElement(activeElement));
3427
+ }
3428
+ isSelectedNodeInSubtree(subtree) {
3429
+ const selectedNode = this.getSelectedNode();
3430
+ if (!selectedNode) {
3431
+ return false;
3432
+ } else {
3433
+ return subtree === selectedNode || subtree.isParentOf(selectedNode);
3434
+ }
3435
+ }
3436
+ loadFolderOnDemand(node) {
3437
+ let slide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
3438
+ let onFinished = arguments.length > 2 ? arguments[2] : undefined;
3439
+ node.is_loading = true;
3440
+ this.doLoadDataFromUrl(null, node, () => {
3441
+ this.openNodeInternal(node, slide, onFinished);
3442
+ });
3443
+ }
3444
+ loadSubtree(data, parentNode) {
3445
+ parentNode.loadFromData(data);
3446
+ parentNode.load_on_demand = false;
3447
+ parentNode.is_loading = false;
3448
+ this.refreshElements(parentNode);
3449
+ }
3450
+ mouseCapture(positionInfo) {
3451
+ if (this.options.dragAndDrop) {
3452
+ return this.dndHandler.mouseCapture(positionInfo);
3453
+ } else {
3454
+ return false;
3455
+ }
3456
+ }
3457
+ mouseDrag(positionInfo) {
3458
+ if (this.options.dragAndDrop) {
3459
+ const result = this.dndHandler.mouseDrag(positionInfo);
3460
+ this.scrollHandler.checkScrolling(positionInfo);
3461
+ return result;
3462
+ } else {
3463
+ return false;
3464
+ }
3465
+ }
3466
+ mouseStart(positionInfo) {
3467
+ if (this.options.dragAndDrop) {
3468
+ return this.dndHandler.mouseStart(positionInfo);
3469
+ } else {
3470
+ return false;
3471
+ }
3472
+ }
3473
+ mouseStop(positionInfo) {
3474
+ if (this.options.dragAndDrop) {
3475
+ this.scrollHandler.stopScrolling();
3476
+ return this.dndHandler.mouseStop(positionInfo);
3477
+ } else {
3478
+ return false;
3479
+ }
3480
+ }
3481
+ openNodeInternal(node) {
3482
+ let slide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
3483
+ let onFinished = arguments.length > 2 ? arguments[2] : undefined;
3484
+ const doOpenNode = (_node, _slide, _onFinished) => {
3485
+ if (!node.children.length) {
3486
+ return;
3487
+ }
3488
+ const folderElement = this.createFolderElement(_node);
3489
+ folderElement.open(_onFinished, _slide, this.options.animationSpeed);
3490
+ };
3491
+ if (node.isFolder() || node.isEmptyFolder) {
3492
+ if (node.load_on_demand) {
3493
+ this.loadFolderOnDemand(node, slide, onFinished);
3494
+ } else {
3495
+ let parent = node.parent;
3496
+ while (parent) {
3497
+ // nb: do not open root element
3498
+ if (parent.parent) {
3499
+ doOpenNode(parent, false);
3500
+ }
3501
+ parent = parent.parent;
3502
+ }
3503
+ doOpenNode(node, slide, onFinished);
3504
+ this.saveState();
3505
+ }
3506
+ }
3507
+ }
3508
+ openParents(node) {
3509
+ const parent = node.parent;
3510
+ if (parent?.parent && !parent.is_open) {
3511
+ this.openNode(parent, false);
3512
+ }
3513
+ }
3514
+
3515
+ /*
3516
+ Redraw the tree or part of the tree.
3517
+ from_node: redraw this subtree
3518
+ */
3519
+ refreshElements(fromNode) {
3520
+ const mustSetFocus = this.isFocusOnTree();
3521
+ const mustSelect = fromNode ? this.isSelectedNodeInSubtree(fromNode) : false;
3522
+ this.renderer.render(fromNode);
3523
+ if (mustSelect) {
3524
+ this.selectCurrentNode(mustSetFocus);
3525
+ }
3526
+ this.triggerEvent("tree.refresh");
3527
+ }
3528
+ saveState() {
3529
+ if (this.options.saveState) {
3530
+ this.saveStateHandler.saveState();
3531
+ }
3532
+ }
3533
+ selectCurrentNode(mustSetFocus) {
3534
+ const node = this.getSelectedNode();
3535
+ if (node) {
3536
+ const nodeElement = this.getNodeElementForNode(node);
3537
+ nodeElement.select(mustSetFocus);
3538
+ }
3539
+ }
3540
+
3541
+ // Set initial state, either by restoring the state or auto-opening nodes
3542
+ // result: must load nodes on demand?
3543
+ setInitialState() {
3544
+ const restoreState = () => {
3545
+ // result: is state restored, must load on demand?
3546
+ if (!this.options.saveState) {
3547
+ return [false, false];
3548
+ } else {
3549
+ const state = this.saveStateHandler.getStateFromStorage();
3550
+ if (!state) {
3551
+ return [false, false];
3552
+ } else {
3553
+ const mustLoadOnDemand = this.saveStateHandler.setInitialState(state);
3554
+
3555
+ // return true: the state is restored
3556
+ return [true, mustLoadOnDemand];
3557
+ }
3558
+ }
3559
+ };
3560
+ const autoOpenNodes = () => {
3561
+ // result: must load on demand?
3562
+ if (this.options.autoOpen === false) {
3563
+ return false;
3564
+ }
3565
+ const maxLevel = this.getAutoOpenMaxLevel();
3566
+ let mustLoadOnDemand = false;
3567
+ this.tree.iterate((node, level) => {
3568
+ if (node.load_on_demand) {
3569
+ mustLoadOnDemand = true;
3570
+ return false;
3571
+ } else if (!node.hasChildren()) {
3572
+ return false;
3573
+ } else {
3574
+ node.is_open = true;
3575
+ return level !== maxLevel;
3576
+ }
3577
+ });
3578
+ return mustLoadOnDemand;
3579
+ };
3580
+ let [isRestored, mustLoadOnDemand] = restoreState(); // eslint-disable-line prefer-const
3581
+
3582
+ if (!isRestored) {
3583
+ mustLoadOnDemand = autoOpenNodes();
3584
+ }
3585
+ return mustLoadOnDemand;
3586
+ }
3587
+
3588
+ // Set the initial state for nodes that are loaded on demand
3589
+ // Call cb_finished when done
3590
+ setInitialStateOnDemand(cbFinished) {
3591
+ const restoreState = () => {
3592
+ if (!this.options.saveState) {
3593
+ return false;
3594
+ } else {
3595
+ const state = this.saveStateHandler.getStateFromStorage();
3596
+ if (!state) {
3597
+ return false;
3598
+ } else {
3599
+ this.saveStateHandler.setInitialStateOnDemand(state, cbFinished);
3600
+ return true;
3601
+ }
3602
+ }
3603
+ };
3604
+ const autoOpenNodes = () => {
3605
+ const maxLevel = this.getAutoOpenMaxLevel();
3606
+ let loadingCount = 0;
3607
+ const loadAndOpenNode = node => {
3608
+ loadingCount += 1;
3609
+ this.openNodeInternal(node, false, () => {
3610
+ loadingCount -= 1;
3611
+ openNodes();
3612
+ });
3613
+ };
3614
+ const openNodes = () => {
3615
+ this.tree.iterate((node, level) => {
3616
+ if (node.load_on_demand) {
3617
+ if (!node.is_loading) {
3618
+ loadAndOpenNode(node);
3619
+ }
3620
+ return false;
3621
+ } else {
3622
+ this.openNodeInternal(node, false);
3623
+ return level !== maxLevel;
3624
+ }
3625
+ });
3626
+ if (loadingCount === 0) {
3627
+ cbFinished();
3628
+ }
3629
+ };
3630
+ openNodes();
3631
+ };
3632
+ if (!restoreState()) {
3633
+ autoOpenNodes();
3634
+ }
3635
+ }
3636
+ triggerEvent(eventName, values) {
3637
+ const event = jQuery.Event(eventName, values);
3638
+ this.element.trigger(event);
3639
+ return event;
3640
+ }
3657
3641
  }
3658
3642
  SimpleWidget.register(JqTreeWidget, "tree");
3659
3643