jqtree 1.5.2 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/.eslintrc +1 -0
  2. package/.github/workflows/ci.yml +54 -0
  3. package/.github/workflows/codeql-analysis.yml +28 -0
  4. package/README.md +1 -1
  5. package/_config.yml +1 -1
  6. package/_entries/10_changelog.md +20 -0
  7. package/_entries/{36_showemptynode.md → 36_showemptyfolder.md} +5 -5
  8. package/_entries/38_start_dnd_delay.md +13 -0
  9. package/_entries/{38_tabindex.md → 39_tabindex.md} +0 -0
  10. package/_entries/{39_usecontextmenu.md → 40_usecontextmenu.md} +0 -0
  11. package/_entries/{40_functions.md → 41_functions.md} +0 -0
  12. package/_entries/{41_addparentnode.md → 42_addparentnode.md} +0 -0
  13. package/_entries/{42_addnodeafter.md → 43_addnodeafter.md} +0 -0
  14. package/_entries/{43_addnodebefore.md → 44_addnodebefore.md} +0 -0
  15. package/_entries/{44_appendnode.md → 45_appendnode.md} +0 -0
  16. package/_entries/{45_closenode.md → 46_closenode.md} +0 -0
  17. package/_entries/{46_destroy.md → 47_destroy.md} +0 -0
  18. package/_entries/{47_getnodebycallback.md → 48_getnodebycallback.md} +0 -0
  19. package/_entries/{48_getnodebyid.md → 49_getnodebyid.md} +0 -0
  20. package/_entries/{49_getnodebyhtmlelement.md → 50_getnodebyhtmlelement.md} +0 -0
  21. package/_entries/{50_getselectednode.md → 51_getselectednode.md} +0 -0
  22. package/_entries/{51_getstate.md → 52_getstate.md} +0 -0
  23. package/_entries/{52_gettree.md → 53_gettree.md} +0 -0
  24. package/_entries/{53_isdragging.md → 54_isdragging.md} +0 -0
  25. package/_entries/{54_loaddata.md → 55_loaddata.md} +0 -0
  26. package/_entries/{55_loaddatafromurl.md → 56_loaddatafromurl.md} +0 -0
  27. package/_entries/{56_movedown.md → 57_movedown.md} +0 -0
  28. package/_entries/{57_movenode.md → 58_movenode.md} +0 -0
  29. package/_entries/{58_moveup.md → 59_moveup.md} +0 -0
  30. package/_entries/{59_opennode.md → 60_opennode.md} +0 -0
  31. package/_entries/{60_prependnode.md → 61_prependnode.md} +0 -0
  32. package/_entries/62_refresh.md +12 -0
  33. package/_entries/{61_reload.md → 63_reload.md} +0 -0
  34. package/_entries/{62_removenode.md → 64_removenode.md} +0 -0
  35. package/_entries/{63_selectnode.md → 65_selectnode.md} +0 -0
  36. package/_entries/{64_scrolltonode.md → 66_scrolltonode.md} +0 -0
  37. package/_entries/{65_setoption.md → 67_setoption.md} +0 -0
  38. package/_entries/{66_setstate.md → 68_setstate.md} +0 -0
  39. package/_entries/{67_toggle.md → 69_toggle.md} +0 -0
  40. package/_entries/{68_tojson.md → 70_tojson.md} +0 -0
  41. package/_entries/{69_updatenode.md → 71_updatenode.md} +0 -0
  42. package/_entries/{70_events.md → 72_events.md} +0 -0
  43. package/_entries/{71_tree-click.md → 73_tree-click.md} +0 -0
  44. package/_entries/{72_tree-close.md → 74_tree-close.md} +0 -0
  45. package/_entries/{73_tree-contextmenu.md → 75_tree-contextmenu.md} +0 -0
  46. package/_entries/{74_tree-dblclick.md → 76_tree-dblclick.md} +0 -0
  47. package/_entries/{75_tree-init.md → 77_tree-init.md} +0 -0
  48. package/_entries/{76_tree-load-data.md → 78_tree-load-data.md} +0 -0
  49. package/_entries/{77_tree-loading-data.md → 79_tree-loading-data.md} +0 -0
  50. package/_entries/{78_tree-move.md → 80_tree-move.md} +0 -0
  51. package/_entries/{79_tree-refresh.md → 81_tree-refresh.md} +0 -0
  52. package/_entries/{80_tree-open.md → 82_tree-open.md} +0 -0
  53. package/_entries/{81_tree-select.md → 83_tree-select.md} +0 -0
  54. package/_entries/{82_multiple-selection.md → 84_multiple-selection.md} +0 -0
  55. package/_entries/{83_add-to-selection.md → 85_add-to-selection.md} +0 -0
  56. package/_entries/{84_get-selected-nodes.md → 86_get-selected-nodes.md} +0 -0
  57. package/_entries/{85_is-node-selected.md → 87_is-node-selected.md} +0 -0
  58. package/_entries/{86_remove-from-selection.md → 88_remove-from-selection.md} +0 -0
  59. package/_entries/{87_node-functions.md → 89_node-functions.md} +0 -0
  60. package/_entries/{88_children.md → 90_children.md} +0 -0
  61. package/_entries/{89_getdata.md → 91_getdata.md} +0 -0
  62. package/_entries/{90_getlevel.md → 92_getlevel.md} +0 -0
  63. package/_entries/{91_getnextnode.md → 93_getnextnode.md} +0 -0
  64. package/_entries/{92_getnextsibling.md → 94_getnextsibling.md} +0 -0
  65. package/_entries/{93_getpreviousnode.md → 95_getpreviousnode.md} +0 -0
  66. package/_entries/{94_getprevioussibling.md → 96_getprevioussibling.md} +0 -0
  67. package/_entries/{95_parent.md → 97_parent.md} +0 -0
  68. package/_examples/13_drag_outside.html +2 -1
  69. package/_examples/14_filter.html +113 -0
  70. package/_layouts/base.html +1 -23
  71. package/babel.config.json +11 -0
  72. package/babel.coverage.config.json +4 -0
  73. package/bower.json +1 -1
  74. package/jest-browser.config.js +0 -3
  75. package/jest-jsdom.config.js +1 -2
  76. package/jqtree.css +4 -1
  77. package/jqtree.postcss +3 -0
  78. package/lib/dataLoader.js +146 -98
  79. package/lib/dragAndDropHandler.js +668 -470
  80. package/lib/elementsRenderer.js +282 -197
  81. package/lib/jqtreeOptions.js +1 -2
  82. package/lib/keyHandler.js +134 -87
  83. package/lib/mouse.widget.js +288 -165
  84. package/lib/node.js +693 -505
  85. package/lib/nodeElement.js +329 -205
  86. package/lib/playwright/playwright.test.js +216 -189
  87. package/lib/playwright/testUtil.js +437 -192
  88. package/lib/playwright/visualRegression.js +183 -117
  89. package/lib/saveStateHandler.js +311 -204
  90. package/lib/scrollHandler.js +293 -199
  91. package/lib/selectNodeHandler.js +140 -105
  92. package/lib/simple.widget.js +184 -109
  93. package/lib/test/global.d.js +3 -0
  94. package/lib/test/jqTree/create.test.js +44 -40
  95. package/lib/test/jqTree/events.test.js +185 -138
  96. package/lib/test/jqTree/keyboard.test.js +216 -199
  97. package/lib/test/jqTree/loadOnDemand.test.js +233 -157
  98. package/lib/test/jqTree/methods.test.js +1269 -1000
  99. package/lib/test/jqTree/options.test.js +467 -398
  100. package/lib/test/node.test.js +1036 -873
  101. package/lib/test/nodeUtil.test.js +21 -20
  102. package/lib/test/support/exampleData.js +35 -23
  103. package/lib/test/support/jqTreeMatchers.js +72 -54
  104. package/lib/test/support/matchers.d.js +1 -0
  105. package/lib/test/support/setupTests.js +9 -3
  106. package/lib/test/support/testUtil.js +38 -15
  107. package/lib/test/support/treeStructure.js +41 -32
  108. package/lib/test/util.test.js +21 -20
  109. package/lib/tree.jquery.d.js +1 -0
  110. package/lib/tree.jquery.js +1264 -883
  111. package/lib/types.js +1 -2
  112. package/lib/typings.d.js +2 -0
  113. package/lib/util.js +21 -7
  114. package/lib/version.js +8 -3
  115. package/package.json +43 -36
  116. package/production +4 -4
  117. package/rollup.config.js +16 -11
  118. package/src/dataLoader.ts +6 -6
  119. package/src/dragAndDropHandler.ts +0 -4
  120. package/src/elementsRenderer.ts +4 -0
  121. package/src/jqtreeOptions.ts +33 -32
  122. package/src/mouse.widget.ts +58 -29
  123. package/src/node.ts +32 -46
  124. package/src/nodeElement.ts +17 -9
  125. package/src/playwright/.eslintrc +5 -0
  126. package/src/playwright/playwright.test.ts +30 -30
  127. package/src/playwright/testUtil.ts +36 -37
  128. package/src/saveStateHandler.ts +11 -6
  129. package/src/selectNodeHandler.ts +14 -21
  130. package/src/simple.widget.ts +1 -1
  131. package/src/test/.eslintrc +4 -0
  132. package/src/test/jqTree/create.test.ts +0 -1
  133. package/src/test/jqTree/events.test.ts +12 -13
  134. package/src/test/jqTree/keyboard.test.ts +0 -1
  135. package/src/test/jqTree/loadOnDemand.test.ts +46 -1
  136. package/src/test/jqTree/methods.test.ts +67 -18
  137. package/src/test/jqTree/options.test.ts +5 -6
  138. package/src/test/node.test.ts +2 -2
  139. package/src/test/support/jqTreeMatchers.ts +8 -9
  140. package/src/test/support/matchers.d.ts +2 -4
  141. package/src/test/support/setupTests.ts +2 -1
  142. package/src/tree.jquery.d.ts +19 -13
  143. package/src/tree.jquery.ts +63 -57
  144. package/src/version.ts +1 -1
  145. package/static/bower.json +3 -3
  146. package/static/bower_components/fontawesome/css/all.min.css +2 -2
  147. package/static/bower_components/fontawesome/webfonts/fa-brands-400.eot +0 -0
  148. package/static/bower_components/fontawesome/webfonts/fa-brands-400.svg +774 -627
  149. package/static/bower_components/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  150. package/static/bower_components/fontawesome/webfonts/fa-brands-400.woff +0 -0
  151. package/static/bower_components/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  152. package/static/bower_components/fontawesome/webfonts/fa-regular-400.eot +0 -0
  153. package/static/bower_components/fontawesome/webfonts/fa-regular-400.svg +93 -95
  154. package/static/bower_components/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  155. package/static/bower_components/fontawesome/webfonts/fa-regular-400.woff +0 -0
  156. package/static/bower_components/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  157. package/static/bower_components/fontawesome/webfonts/fa-solid-900.eot +0 -0
  158. package/static/bower_components/fontawesome/webfonts/fa-solid-900.svg +1164 -1074
  159. package/static/bower_components/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  160. package/static/bower_components/fontawesome/webfonts/fa-solid-900.woff +0 -0
  161. package/static/bower_components/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  162. package/static/bower_components/jquery/dist/jquery.js +118 -109
  163. package/static/bower_components/jquery/dist/jquery.min.js +2 -2
  164. package/static/bower_components/jquery-mockjax/dist/jquery.mockjax.js +15 -9
  165. package/static/example.css +13 -0
  166. package/static/example.postcss +13 -0
  167. package/static/example_data.js +33 -36
  168. package/static/examples/filter.js +63 -0
  169. package/tree.jquery.debug.js +4809 -3305
  170. package/tree.jquery.debug.js.map +1 -1
  171. package/tree.jquery.js +3 -3
  172. package/tree.jquery.js.map +1 -1
  173. package/tsconfig.json +1 -0
  174. package/.travis.yml +0 -18
package/src/node.ts CHANGED
@@ -1,7 +1,6 @@
1
- export type NodeId = number | string;
2
-
3
- export type DefaultRecord = Record<string, unknown>;
4
- export type NodeData = string | DefaultRecord;
1
+ interface NodeRecordWithChildren extends NodeRecord {
2
+ children: NodeData[];
3
+ }
5
4
 
6
5
  export enum Position {
7
6
  Before = 1,
@@ -34,12 +33,19 @@ export const getPositionName = (position: Position): string => {
34
33
  export const getPosition = (name: string): Position | undefined =>
35
34
  positionNames[name];
36
35
 
36
+ const isNodeRecordWithChildren = (
37
+ data: NodeData
38
+ ): data is NodeRecordWithChildren =>
39
+ typeof data === "object" &&
40
+ "children" in data &&
41
+ data["children"] instanceof Array;
42
+
37
43
  export class Node implements INode {
38
44
  public id?: NodeId;
39
45
  public name: string;
40
46
  public children: Node[];
41
47
  public parent: Node | null;
42
- public idMapping: Record<NodeId, Node>;
48
+ public idMapping: Map<NodeId, Node>;
43
49
  public tree?: Node;
44
50
  public nodeClass?: typeof Node;
45
51
  public load_on_demand: boolean;
@@ -61,7 +67,7 @@ export class Node implements INode {
61
67
  this.parent = null;
62
68
 
63
69
  if (isRoot) {
64
- this.idMapping = {};
70
+ this.idMapping = new Map<NodeId, Node>();
65
71
  this.tree = this;
66
72
  this.nodeClass = nodeClass;
67
73
  }
@@ -131,15 +137,11 @@ export class Node implements INode {
131
137
  const node = this.createNode(o);
132
138
  this.addChild(node);
133
139
 
134
- if (
135
- typeof o === "object" &&
136
- o["children"] &&
137
- o["children"] instanceof Array
138
- ) {
139
- if (o["children"].length === 0) {
140
+ if (isNodeRecordWithChildren(o)) {
141
+ if (o.children.length === 0) {
140
142
  node.isEmptyFolder = true;
141
143
  } else {
142
- node.loadFromData(o["children"]);
144
+ node.loadFromData(o.children);
143
145
  }
144
146
  }
145
147
  }
@@ -299,7 +301,7 @@ export class Node implements INode {
299
301
  /*
300
302
  Get the tree as data.
301
303
  */
302
- public getData(includeParent = false): DefaultRecord[] {
304
+ public getData(includeParent = false): NodeRecord[] {
303
305
  const getDataFromNodes = (nodes: Node[]): Record<string, unknown>[] => {
304
306
  return nodes.map((node) => {
305
307
  const tmpNode: Record<string, unknown> = {};
@@ -379,12 +381,10 @@ export class Node implements INode {
379
381
  this.parent.addChildAtPosition(node, childIndex + 1);
380
382
 
381
383
  if (
382
- typeof nodeInfo === "object" &&
383
- nodeInfo["children"] &&
384
- nodeInfo["children"] instanceof Array &&
385
- nodeInfo["children"].length
384
+ isNodeRecordWithChildren(nodeInfo) &&
385
+ nodeInfo.children.length
386
386
  ) {
387
- node.loadFromData(nodeInfo["children"]);
387
+ node.loadFromData(nodeInfo.children);
388
388
  }
389
389
 
390
390
  return node;
@@ -401,12 +401,10 @@ export class Node implements INode {
401
401
  this.parent.addChildAtPosition(node, childIndex);
402
402
 
403
403
  if (
404
- typeof nodeInfo === "object" &&
405
- nodeInfo["children"] &&
406
- nodeInfo["children"] instanceof Array &&
407
- nodeInfo["children"].length
404
+ isNodeRecordWithChildren(nodeInfo) &&
405
+ nodeInfo.children.length
408
406
  ) {
409
- node.loadFromData(nodeInfo["children"]);
407
+ node.loadFromData(nodeInfo.children);
410
408
  }
411
409
 
412
410
  return node;
@@ -445,13 +443,8 @@ export class Node implements INode {
445
443
  const node = this.createNode(nodeInfo);
446
444
  this.addChild(node);
447
445
 
448
- if (
449
- typeof nodeInfo === "object" &&
450
- nodeInfo["children"] &&
451
- nodeInfo["children"] instanceof Array &&
452
- nodeInfo["children"].length
453
- ) {
454
- node.loadFromData(nodeInfo["children"]);
446
+ if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
447
+ node.loadFromData(nodeInfo.children);
455
448
  }
456
449
 
457
450
  return node;
@@ -461,13 +454,8 @@ export class Node implements INode {
461
454
  const node = this.createNode(nodeInfo);
462
455
  this.addChildAtPosition(node, 0);
463
456
 
464
- if (
465
- typeof nodeInfo === "object" &&
466
- nodeInfo["children"] &&
467
- nodeInfo["children"] instanceof Array &&
468
- nodeInfo["children"].length
469
- ) {
470
- node.loadFromData(nodeInfo["children"]);
457
+ if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
458
+ node.loadFromData(nodeInfo.children);
471
459
  }
472
460
 
473
461
  return node;
@@ -500,18 +488,18 @@ export class Node implements INode {
500
488
  }
501
489
 
502
490
  public getNodeById(nodeId: NodeId): Node | null {
503
- return this.idMapping[nodeId] || null;
491
+ return this.idMapping.get(nodeId) || null;
504
492
  }
505
493
 
506
494
  public addNodeToIndex(node: Node): void {
507
495
  if (node.id != null) {
508
- this.idMapping[node.id] = node;
496
+ this.idMapping.set(node.id, node);
509
497
  }
510
498
  }
511
499
 
512
500
  public removeNodeFromIndex(node: Node): void {
513
501
  if (node.id != null) {
514
- delete this.idMapping[node.id];
502
+ this.idMapping.delete(node.id);
515
503
  }
516
504
  }
517
505
 
@@ -641,12 +629,10 @@ export class Node implements INode {
641
629
  this.setData(nodeData);
642
630
 
643
631
  if (
644
- typeof nodeData === "object" &&
645
- nodeData["children"] &&
646
- nodeData["children"] instanceof Array &&
647
- nodeData["children"].length
632
+ isNodeRecordWithChildren(nodeData) &&
633
+ nodeData.children.length
648
634
  ) {
649
- addChildren(nodeData["children"]);
635
+ addChildren(nodeData.children);
650
636
  }
651
637
  };
652
638
 
@@ -18,10 +18,16 @@ export class NodeElement {
18
18
  this.treeWidget = treeWidget;
19
19
 
20
20
  if (!node.element) {
21
- node.element = this.treeWidget.element.get(0);
21
+ const element = this.treeWidget.element.get(0);
22
+
23
+ if (element) {
24
+ node.element = element;
25
+ }
22
26
  }
23
27
 
24
- this.$element = jQuery(node.element);
28
+ if (node.element) {
29
+ this.$element = jQuery(node.element);
30
+ }
25
31
  }
26
32
 
27
33
  public addDropHint(position: number): DropHint {
@@ -99,9 +105,8 @@ export class FolderElement extends NodeElement {
99
105
  const buttonEl = $button.get(0);
100
106
 
101
107
  if (buttonEl) {
102
- const icon = this.treeWidget.renderer.openedIconElement.cloneNode(
103
- true
104
- );
108
+ const icon =
109
+ this.treeWidget.renderer.openedIconElement.cloneNode(true);
105
110
 
106
111
  buttonEl.appendChild(icon);
107
112
  }
@@ -147,9 +152,8 @@ export class FolderElement extends NodeElement {
147
152
  const buttonEl = $button.get(0);
148
153
 
149
154
  if (buttonEl) {
150
- const icon = this.treeWidget.renderer.closedIconElement.cloneNode(
151
- true
152
- );
155
+ const icon =
156
+ this.treeWidget.renderer.closedIconElement.cloneNode(true);
153
157
 
154
158
  buttonEl.appendChild(icon);
155
159
  }
@@ -248,7 +252,11 @@ class GhostDropHint implements DropHint {
248
252
  }
249
253
 
250
254
  public moveInsideOpenFolder(): void {
251
- jQuery(this.node.children[0].element).before(this.$ghost);
255
+ const childElement = this.node.children[0].element;
256
+
257
+ if (childElement) {
258
+ jQuery(childElement).before(this.$ghost);
259
+ }
252
260
  }
253
261
 
254
262
  public moveInside(): void {
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": [
3
+ "plugin:playwright/jest-playwright"
4
+ ]
5
+ }
@@ -41,8 +41,8 @@ beforeEach(async () => {
41
41
  autoOpen: 0,
42
42
  data: ExampleData.exampleData,
43
43
  dragAndDrop: ${given.dragAndDrop},
44
+ startDndDelay: 100,
44
45
  });
45
- $tree.tree("setMouseDelay", 100);
46
46
  `);
47
47
  });
48
48
 
@@ -51,15 +51,15 @@ afterEach(async () => {
51
51
  });
52
52
 
53
53
  it("displays a tree", async () => {
54
- await expect(page).toHaveText("Saurischia");
55
- await expect(page).toHaveText("Ornithischians");
56
- await expect(page).toHaveText("Coelophysoids");
54
+ await expect(page).toMatchText(/.*Saurischia.*/);
55
+ await expect(page).toMatchText(/.*Ornithischians.*/);
56
+ await expect(page).toMatchText(/.*Coelophysoids.*/);
57
57
 
58
58
  await matchScreenshot("displays_a_tree");
59
59
  });
60
60
 
61
61
  it("selects a node", async () => {
62
- await expect(page).toHaveText("Saurischia");
62
+ await expect(page).toMatchText(/.*Saurischia.*/);
63
63
  const saurischia = await findNodeElement("Saurischia");
64
64
  await selectNode(saurischia);
65
65
  await expectToBeSelected(saurischia);
@@ -68,7 +68,7 @@ it("selects a node", async () => {
68
68
  });
69
69
 
70
70
  it("opens a node", async () => {
71
- await expect(page).toHaveText("Saurischia");
71
+ await expect(page).toMatchText(/.*Saurischia.*/);
72
72
 
73
73
  const theropods = await findNodeElement("Theropods");
74
74
  await expectToBeClosed(theropods);
@@ -84,30 +84,30 @@ describe("dragAndDrop", () => {
84
84
  it("moves a node", async () => {
85
85
  await dragAndDrop("Herrerasaurians", "Ornithischians");
86
86
 
87
- await getTreeStructure().then((structure) => {
88
- expect(structure).toEqual([
89
- expect.objectContaining({
90
- name: "Saurischia",
91
- children: [
92
- expect.objectContaining({ name: "Theropods" }),
93
- expect.objectContaining({ name: "Sauropodomorphs" }),
94
- ],
95
- }),
96
- expect.objectContaining({
97
- name: "Ornithischians",
98
- children: [
99
- expect.objectContaining({ name: "Herrerasaurians" }),
100
- expect.objectContaining({ name: "Heterodontosaurids" }),
101
- expect.objectContaining({ name: "Thyreophorans" }),
102
- expect.objectContaining({ name: "Ornithopods" }),
103
- expect.objectContaining({
104
- name: "Pachycephalosaurians",
105
- }),
106
- expect.objectContaining({ name: "Ceratopsians" }),
107
- ],
108
- }),
109
- ]);
110
- });
87
+ const structure = await getTreeStructure();
88
+
89
+ expect(structure).toEqual([
90
+ expect.objectContaining({
91
+ name: "Saurischia",
92
+ children: [
93
+ expect.objectContaining({ name: "Theropods" }),
94
+ expect.objectContaining({ name: "Sauropodomorphs" }),
95
+ ],
96
+ }),
97
+ expect.objectContaining({
98
+ name: "Ornithischians",
99
+ children: [
100
+ expect.objectContaining({ name: "Herrerasaurians" }),
101
+ expect.objectContaining({ name: "Heterodontosaurids" }),
102
+ expect.objectContaining({ name: "Thyreophorans" }),
103
+ expect.objectContaining({ name: "Ornithopods" }),
104
+ expect.objectContaining({
105
+ name: "Pachycephalosaurians",
106
+ }),
107
+ expect.objectContaining({ name: "Ceratopsians" }),
108
+ ],
109
+ }),
110
+ ]);
111
111
 
112
112
  await matchScreenshot("moves_a_node");
113
113
  });
@@ -96,47 +96,46 @@ export const selectNode = async (
96
96
  await titleHandle?.click();
97
97
  };
98
98
 
99
- export const getTreeStructure = async (): Promise<
100
- JQTreeMatchers.TreeStructure
101
- > =>
99
+ export const getTreeStructure = async (): Promise<JQTreeMatchers.TreeStructure> =>
102
100
  await page
103
101
  .evaluate(
104
102
  `
105
- function getTreeNode($li) {
106
- const $div = $li.children("div.jqtree-element");
107
- const $span = $div.children("span.jqtree-title");
108
- const name = $span.text();
109
- const selected = $li.hasClass("jqtree-selected");
110
-
111
- if ($li.hasClass("jqtree-folder")) {
112
- const $ul = $li.children("ul.jqtree_common");
113
-
114
- return {
115
- nodeType: "folder",
116
- children: getChildren($ul),
117
- name,
118
- open: !$li.hasClass("jqtree-closed"),
119
- selected,
120
- };
121
- } else {
122
- return {
123
- nodeType: "child",
124
- name,
125
- selected,
126
- };
103
+ ;
104
+ function getTreeNode($li) {
105
+ const $div = $li.children("div.jqtree-element");
106
+ const $span = $div.children("span.jqtree-title");
107
+ const name = $span.text();
108
+ const selected = $li.hasClass("jqtree-selected");
109
+
110
+ if ($li.hasClass("jqtree-folder")) {
111
+ const $ul = $li.children("ul.jqtree_common");
112
+
113
+ return {
114
+ nodeType: "folder",
115
+ children: getChildren($ul),
116
+ name,
117
+ open: !$li.hasClass("jqtree-closed"),
118
+ selected,
119
+ };
120
+ } else {
121
+ return {
122
+ nodeType: "child",
123
+ name,
124
+ selected,
125
+ };
126
+ }
127
127
  }
128
- };
129
-
130
- function getChildren($ul) {
131
- return $ul
132
- .children("li.jqtree_common")
133
- .map((_, li) => {
134
- return getTreeNode(jQuery(li))
135
- })
136
- .get();
137
- };
138
-
139
- JSON.stringify(window.getChildren(jQuery("ul.jqtree-tree")))
128
+
129
+ function getChildren($ul) {
130
+ return $ul
131
+ .children("li.jqtree_common")
132
+ .map((_, li) => {
133
+ return getTreeNode(jQuery(li));
134
+ })
135
+ .get();
136
+ }
137
+
138
+ JSON.stringify(window.getChildren(jQuery("ul.jqtree-tree")));
140
139
  `
141
140
  )
142
141
  .then((s) => JSON.parse(s as string) as JQTreeMatchers.TreeStructure);
@@ -1,6 +1,11 @@
1
1
  import { isInt } from "./util";
2
2
  import { JqTreeWidget } from "./tree.jquery";
3
- import { Node, NodeId } from "./node";
3
+ import { Node } from "./node";
4
+
5
+ export interface SavedState {
6
+ open_nodes: NodeId[];
7
+ selected_node: NodeId[];
8
+ }
4
9
 
5
10
  export default class SaveStateHandler {
6
11
  private treeWidget: JqTreeWidget;
@@ -24,7 +29,7 @@ export default class SaveStateHandler {
24
29
  const jsonData = this.loadFromStorage();
25
30
 
26
31
  if (jsonData) {
27
- return (this.parseState(jsonData) as unknown) as SavedState;
32
+ return this.parseState(jsonData) as unknown as SavedState;
28
33
  } else {
29
34
  return null;
30
35
  }
@@ -121,7 +126,7 @@ export default class SaveStateHandler {
121
126
  state.selected_node = [state.selected_node];
122
127
  }
123
128
 
124
- return (state as unknown) as SavedState;
129
+ return state as unknown as SavedState;
125
130
  }
126
131
 
127
132
  private loadFromStorage(): string | null {
@@ -134,11 +139,11 @@ export default class SaveStateHandler {
134
139
  }
135
140
  }
136
141
 
137
- private openInitialNodes(nodeIds: any[]): boolean {
142
+ private openInitialNodes(nodeIds: NodeId[]): boolean {
138
143
  let mustLoadOnDemand = false;
139
144
 
140
- for (const nodeDd of nodeIds) {
141
- const node = this.treeWidget.getNodeById(nodeDd);
145
+ for (const nodeId of nodeIds) {
146
+ const node = this.treeWidget.getNodeById(nodeId);
142
147
 
143
148
  if (node) {
144
149
  if (!node.load_on_demand) {
@@ -1,13 +1,14 @@
1
- import { Node, NodeId } from "./node";
1
+ import { Node } from "./node";
2
2
  import { JqTreeWidget } from "./tree.jquery";
3
3
 
4
4
  export default class SelectNodeHandler {
5
5
  private treeWidget: JqTreeWidget;
6
- private selectedNodes: Record<NodeId, boolean>;
6
+ private selectedNodes: Set<NodeId>;
7
7
  private selectedSingleNode: Node | null;
8
8
 
9
9
  constructor(treeWidget: JqTreeWidget) {
10
10
  this.treeWidget = treeWidget;
11
+ this.selectedNodes = new Set<NodeId>();
11
12
  this.clear();
12
13
  }
13
14
 
@@ -25,18 +26,14 @@ export default class SelectNodeHandler {
25
26
  if (this.selectedSingleNode) {
26
27
  return [this.selectedSingleNode];
27
28
  } else {
28
- const selectedNodes = [];
29
+ const selectedNodes: Node[] = [];
29
30
 
30
- for (const id in this.selectedNodes) {
31
- if (
32
- Object.prototype.hasOwnProperty.call(this.selectedNodes, id)
33
- ) {
34
- const node = this.treeWidget.getNodeById(id);
35
- if (node) {
36
- selectedNodes.push(node);
37
- }
31
+ this.selectedNodes.forEach((id) => {
32
+ const node = this.treeWidget.getNodeById(id);
33
+ if (node) {
34
+ selectedNodes.push(node);
38
35
  }
39
- }
36
+ });
40
37
 
41
38
  return selectedNodes;
42
39
  }
@@ -69,11 +66,7 @@ export default class SelectNodeHandler {
69
66
 
70
67
  public isNodeSelected(node: Node): boolean {
71
68
  if (node.id != null) {
72
- if (this.selectedNodes[node.id]) {
73
- return true;
74
- } else {
75
- return false;
76
- }
69
+ return this.selectedNodes.has(node.id);
77
70
  } else if (this.selectedSingleNode) {
78
71
  return this.selectedSingleNode.element === node.element;
79
72
  } else {
@@ -82,7 +75,7 @@ export default class SelectNodeHandler {
82
75
  }
83
76
 
84
77
  public clear(): void {
85
- this.selectedNodes = {};
78
+ this.selectedNodes.clear();
86
79
  this.selectedSingleNode = null;
87
80
  }
88
81
 
@@ -95,12 +88,12 @@ export default class SelectNodeHandler {
95
88
  this.selectedSingleNode = null;
96
89
  }
97
90
  } else {
98
- delete this.selectedNodes[node.id];
91
+ this.selectedNodes.delete(node.id);
99
92
 
100
93
  if (includeChildren) {
101
94
  node.iterate(() => {
102
95
  if (node.id != null) {
103
- delete this.selectedNodes[node.id];
96
+ this.selectedNodes.delete(node.id);
104
97
  }
105
98
  return true;
106
99
  });
@@ -110,7 +103,7 @@ export default class SelectNodeHandler {
110
103
 
111
104
  public addToSelection(node: Node): void {
112
105
  if (node.id != null) {
113
- this.selectedNodes[node.id] = true;
106
+ this.selectedNodes.add(node.id);
114
107
  } else {
115
108
  this.selectedSingleNode = node;
116
109
  }
@@ -109,7 +109,7 @@ export default class SimpleWidget<WidgetOptions> {
109
109
 
110
110
  public options: WidgetOptions;
111
111
 
112
- protected $el: JQuery<HTMLElement>;
112
+ public $el: JQuery<HTMLElement>;
113
113
 
114
114
  constructor(el: HTMLElement, options: WidgetOptions) {
115
115
  this.$el = jQuery(el);
@@ -0,0 +1,4 @@
1
+ {
2
+ "plugins": ["testing-library"],
3
+ "extends": ["plugin:testing-library/dom"]
4
+ }
@@ -1,4 +1,3 @@
1
- import * as $ from "jquery";
2
1
  import getGiven from "givens";
3
2
  import "../../tree.jquery";
4
3
  import exampleData from "../support/exampleData";
@@ -1,4 +1,3 @@
1
- import * as $ from "jquery";
2
1
  import getGiven from "givens";
3
2
  import { rest } from "msw";
4
3
  import { setupServer } from "msw/node";
@@ -35,7 +34,7 @@ describe("tree.click", () => {
35
34
  });
36
35
 
37
36
  it("fires tree.click", () =>
38
- new Promise((done) => {
37
+ new Promise<void>((done) => {
39
38
  given.$tree.on("tree.click", (e: unknown) => {
40
39
  const treeClickEvent = e as ClickNodeEvent;
41
40
 
@@ -43,7 +42,7 @@ describe("tree.click", () => {
43
42
  done();
44
43
  });
45
44
 
46
- given.titleSpan.click();
45
+ given.titleSpan.trigger("click");
47
46
  }));
48
47
  });
49
48
 
@@ -64,7 +63,7 @@ describe("tree.contextmenu", () => {
64
63
  });
65
64
 
66
65
  it("fires tree.contextmenu", () =>
67
- new Promise((done) => {
66
+ new Promise<void>((done) => {
68
67
  given.$tree.on("tree.contextmenu", (e: unknown) => {
69
68
  const treeClickEvent = e as ClickNodeEvent;
70
69
 
@@ -93,7 +92,7 @@ describe("tree.dblclick", () => {
93
92
  });
94
93
 
95
94
  it("fires tree.dblclick", () =>
96
- new Promise((done) => {
95
+ new Promise<void>((done) => {
97
96
  given.$tree.on("tree.dblclick", (e: unknown) => {
98
97
  const treeClickEvent = e as ClickNodeEvent;
99
98
 
@@ -101,7 +100,7 @@ describe("tree.dblclick", () => {
101
100
  done();
102
101
  });
103
102
 
104
- given.titleSpan.dblclick();
103
+ given.titleSpan.trigger("dblclick");
105
104
  }));
106
105
  });
107
106
 
@@ -114,7 +113,7 @@ describe("tree.init", () => {
114
113
 
115
114
  context("with json data", () => {
116
115
  it("is called", () =>
117
- new Promise((done) => {
116
+ new Promise<void>((done) => {
118
117
  given.$tree.on("tree.init", () => {
119
118
  expect(
120
119
  given.$tree.tree("getNodeByName", "node2")
@@ -148,7 +147,7 @@ describe("tree.init", () => {
148
147
  });
149
148
 
150
149
  it("is called", () =>
151
- new Promise((done) => {
150
+ new Promise<void>((done) => {
152
151
  given.$tree.on("tree.init", () => {
153
152
  expect(
154
153
  given.$tree.tree("getNodeByName", "node2")
@@ -173,7 +172,7 @@ describe("tree.load_data", () => {
173
172
 
174
173
  context("when the tree is initialized with data", () => {
175
174
  it("fires tree.load_data", () =>
176
- new Promise((resolve) => {
175
+ new Promise<void>((resolve) => {
177
176
  given.$tree.on("tree.load_data", (e: any) => {
178
177
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
179
178
  expect(e.tree_data).toEqual(exampleData);
@@ -204,7 +203,7 @@ describe("tree.select", () => {
204
203
  });
205
204
 
206
205
  it("fires tree.click", () =>
207
- new Promise((done) => {
206
+ new Promise<void>((done) => {
208
207
  given.$tree.on("tree.select", (e: unknown) => {
209
208
  const treeClickEvent = e as ClickNodeEvent;
210
209
 
@@ -213,7 +212,7 @@ describe("tree.select", () => {
213
212
  done();
214
213
  });
215
214
 
216
- given.titleSpan.click();
215
+ given.titleSpan.trigger("click");
217
216
  }));
218
217
 
219
218
  context("when the node was selected", () => {
@@ -222,7 +221,7 @@ describe("tree.select", () => {
222
221
  });
223
222
 
224
223
  it("fires tree.select with node is null", () =>
225
- new Promise((done) => {
224
+ new Promise<void>((done) => {
226
225
  given.$tree.on("tree.select", (e: unknown) => {
227
226
  const treeClickEvent = e as ClickNodeEvent;
228
227
 
@@ -231,7 +230,7 @@ describe("tree.select", () => {
231
230
  done();
232
231
  });
233
232
 
234
- given.titleSpan.click();
233
+ given.titleSpan.trigger("click");
235
234
  }));
236
235
  });
237
236
  });