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
@@ -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 { screen } from "@testing-library/dom";
4
3
  import { rest } from "msw";
@@ -106,6 +105,52 @@ context("when a node has load_on_demand in the data", () => {
106
105
  }),
107
106
  ]);
108
107
  });
108
+
109
+ context("when the node is selected and has the focus", () => {
110
+ beforeEach(() => {
111
+ given.$tree.tree("selectNode", given.node);
112
+ });
113
+
114
+ it("keeps the node selected and focused", async () => {
115
+ expect(given.node.element).toBeSelected();
116
+ expect(given.node.element).toBeFocused();
117
+
118
+ togglerLink(given.node.element).trigger("click");
119
+ await screen.findByText("loaded-on-demand");
120
+
121
+ expect(given.node.element).toBeSelected();
122
+ expect(given.node.element).toBeFocused();
123
+ });
124
+ });
125
+
126
+ context("when the node is not selected", () => {
127
+ it("doesn't select the node", async () => {
128
+ expect(given.node.element).not.toBeSelected();
129
+
130
+ togglerLink(given.node.element).trigger("click");
131
+ await screen.findByText("loaded-on-demand");
132
+
133
+ expect(given.node.element).not.toBeSelected();
134
+ });
135
+ });
136
+
137
+ context("when the node is selected and doesn't have the focus", () => {
138
+ beforeEach(() => {
139
+ given.$tree.tree("selectNode", given.node);
140
+ (document.activeElement as HTMLElement).blur();
141
+ });
142
+
143
+ it("keeps the node selected and not focused", async () => {
144
+ expect(given.node.element).toBeSelected();
145
+ expect(given.node.element).not.toBeFocused();
146
+
147
+ togglerLink(given.node.element).trigger("click");
148
+ await screen.findByText("loaded-on-demand");
149
+
150
+ expect(given.node.element).toBeSelected();
151
+ expect(given.node.element).not.toBeFocused();
152
+ });
153
+ });
109
154
  });
110
155
 
111
156
  context("with autoOpen is true", () => {
@@ -1,4 +1,3 @@
1
- import * as $ from "jquery";
2
1
  import getGiven from "givens";
3
2
  import { screen } from "@testing-library/dom";
4
3
  import { rest } from "msw";
@@ -312,15 +311,17 @@ describe("getNodeByHtmlElement", () => {
312
311
 
313
312
  describe("getNodeById", () => {
314
313
  interface Vars {
314
+ data: NodeData[];
315
315
  $tree: JQuery<HTMLElement>;
316
316
  }
317
317
 
318
318
  const given = getGiven<Vars>();
319
+ given("data", () => exampleData);
319
320
  given("$tree", () => $("#tree1"));
320
321
 
321
322
  beforeEach(() => {
322
323
  given.$tree.tree({
323
- data: exampleData,
324
+ data: given.data,
324
325
  });
325
326
  });
326
327
 
@@ -331,18 +332,40 @@ describe("getNodeById", () => {
331
332
  });
332
333
 
333
334
  context("with a string parameter", () => {
334
- it("returns the node", () => {
335
- expect(given.$tree.tree("getNodeById", "127")).toMatchObject({
336
- name: "node3",
337
- });
335
+ it("doesn't return the node", () => {
336
+ expect(given.$tree.tree("getNodeById", "127")).toBeNull();
338
337
  });
339
338
  });
340
339
 
341
340
  context("when the node doesn't exist", () => {
342
- it("returns undefined", () => {
341
+ it("returns null", () => {
343
342
  expect(given.$tree.tree("getNodeById", 99999)).toBeNull();
344
343
  });
345
344
  });
345
+
346
+ context("when the data has string ids", () => {
347
+ given("data", () => [{ id: "123", name: "node1" }]);
348
+
349
+ context("with a string parameter", () => {
350
+ it("returns the node", () => {
351
+ expect(given.$tree.tree("getNodeById", "123")).toMatchObject({
352
+ name: "node1",
353
+ });
354
+ });
355
+ });
356
+
357
+ context("with a number parameter", () => {
358
+ it("doesn't return the node", () => {
359
+ expect(given.$tree.tree("getNodeById", 123)).toBeNull();
360
+ });
361
+ });
362
+
363
+ context("when the node doesn't exist", () => {
364
+ it("returns null", () => {
365
+ expect(given.$tree.tree("getNodeById", "abc")).toBeNull();
366
+ });
367
+ });
368
+ });
346
369
  });
347
370
 
348
371
  describe("getNodesByProperty", () => {
@@ -943,6 +966,38 @@ describe("prependNode", () => {
943
966
  });
944
967
  });
945
968
 
969
+ describe("refresh", () => {
970
+ interface Vars {
971
+ $tree: JQuery<HTMLElement>;
972
+ }
973
+
974
+ const given = getGiven<Vars>();
975
+ given("$tree", () => $("#tree1"));
976
+
977
+ beforeEach(() => {
978
+ given.$tree.tree({
979
+ data: exampleData,
980
+ });
981
+ });
982
+
983
+ it("rerenders the tree", () => {
984
+ const tree = given.$tree.tree("getTree");
985
+ tree.children[0].name = "node1a";
986
+
987
+ expect(given.$tree).toHaveTreeStructure([
988
+ expect.objectContaining({ name: "node1" }),
989
+ expect.objectContaining({ name: "node2" }),
990
+ ]);
991
+
992
+ given.$tree.tree("refresh");
993
+
994
+ expect(given.$tree).toHaveTreeStructure([
995
+ expect.objectContaining({ name: "node1a" }),
996
+ expect.objectContaining({ name: "node2" }),
997
+ ]);
998
+ });
999
+ });
1000
+
946
1001
  describe("reload", () => {
947
1002
  interface Vars {
948
1003
  node1: INode;
@@ -991,7 +1046,7 @@ describe("reload", () => {
991
1046
 
992
1047
  context("with a onFinished parameter", () => {
993
1048
  it("calls onFinished", () =>
994
- new Promise((resolve) => {
1049
+ new Promise<void>((resolve) => {
995
1050
  const handleFinished = () => {
996
1051
  expect(given.$tree).toHaveTreeStructure([
997
1052
  expect.objectContaining({ name: "node1" }),
@@ -1125,7 +1180,7 @@ describe("selectNode", () => {
1125
1180
 
1126
1181
  it("selects the node and deselects the previous node", () => {
1127
1182
  expect(given.node1.element).toBeSelected();
1128
- expect(given.node2.element).notToBeSelected();
1183
+ expect(given.node2.element).not.toBeSelected();
1129
1184
  });
1130
1185
  });
1131
1186
 
@@ -1146,7 +1201,7 @@ describe("selectNode", () => {
1146
1201
 
1147
1202
  it("deselects the node", () => {
1148
1203
  given.$tree.tree("selectNode", given.node1);
1149
- expect(given.node1.element).notToBeSelected();
1204
+ expect(given.node1.element).not.toBeSelected();
1150
1205
  });
1151
1206
  });
1152
1207
 
@@ -1181,7 +1236,7 @@ describe("setOption", () => {
1181
1236
 
1182
1237
  it("sets an option", () => {
1183
1238
  given.$tree.tree("setOption", "selectable", true);
1184
- titleSpan(given.node1.element).click();
1239
+ titleSpan(given.node1.element).trigger("click");
1185
1240
  expect(given.$tree.tree("getSelectedNode")).toMatchObject({
1186
1241
  name: "node1",
1187
1242
  });
@@ -1412,13 +1467,7 @@ describe("updateNode", () => {
1412
1467
  });
1413
1468
 
1414
1469
  it("keeps the focus on the node", () => {
1415
- expect(document.activeElement).not.toBeNil();
1416
- expect(
1417
- given.$tree.tree(
1418
- "getNodeByHtmlElement",
1419
- document.activeElement as HTMLElement
1420
- )
1421
- ).not.toBeNil();
1470
+ expect(given.node.element).toBeFocused();
1422
1471
  });
1423
1472
  });
1424
1473
  });
@@ -1,4 +1,3 @@
1
- import * as $ from "jquery";
2
1
  import getGiven from "givens";
3
2
  import { screen } from "@testing-library/dom";
4
3
  import { rest } from "msw";
@@ -364,7 +363,7 @@ describe("onLoadFailed", () => {
364
363
  });
365
364
 
366
365
  it("calls onLoadFailed", () =>
367
- new Promise((done) => {
366
+ new Promise<void>((done) => {
368
367
  given.$tree.tree({
369
368
  dataUrl: "/tree/",
370
369
  onLoadFailed: (jqXHR) => {
@@ -391,7 +390,7 @@ describe("rtl", () => {
391
390
  });
392
391
 
393
392
  it("has a different closed icon", () => {
394
- expect(togglerLink(given.node1.element).text()).toEqual("◀");
393
+ expect(togglerLink(given.node1.element).text()).toBe("◀");
395
394
  });
396
395
  });
397
396
 
@@ -402,7 +401,7 @@ describe("rtl", () => {
402
401
  });
403
402
 
404
403
  it("has a different closed icon", () => {
405
- expect(togglerLink(given.node1.element).text()).toEqual("◀");
404
+ expect(togglerLink(given.node1.element).text()).toBe("◀");
406
405
  });
407
406
  });
408
407
  });
@@ -434,7 +433,7 @@ describe("saveState", () => {
434
433
  given("saveState", () => true);
435
434
 
436
435
  it("saves the state to local storage", () => {
437
- expect(localStorage.getItem("tree")).toEqual(
436
+ expect(localStorage.getItem("tree")).toBe(
438
437
  '{"open_nodes":[123],"selected_node":[123]}'
439
438
  );
440
439
  });
@@ -444,7 +443,7 @@ describe("saveState", () => {
444
443
  given("saveState", () => "my-state");
445
444
 
446
445
  it("uses the string as a key", () => {
447
- expect(localStorage.getItem("my-state")).toEqual(
446
+ expect(localStorage.getItem("my-state")).toBe(
448
447
  '{"open_nodes":[123],"selected_node":[123]}'
449
448
  );
450
449
  });
@@ -855,13 +855,13 @@ describe("hasChildren", () => {
855
855
  });
856
856
 
857
857
  it("returns true", () => {
858
- expect(given.node.hasChildren()).toEqual(true);
858
+ expect(given.node.hasChildren()).toBe(true);
859
859
  });
860
860
  });
861
861
 
862
862
  context("when a node doesn't have children", () => {
863
863
  it("returns false", () => {
864
- expect(given.node.hasChildren()).toEqual(false);
864
+ expect(given.node.hasChildren()).toBe(false);
865
865
  });
866
866
  });
867
867
  });
@@ -1,4 +1,5 @@
1
1
  import treeStructure from "./treeStructure";
2
+ import { titleSpan } from "./testUtil";
2
3
 
3
4
  const assertJqTreeFolder = ($el: JQuery<HTMLElement>) => {
4
5
  /* istanbul ignore if */
@@ -8,15 +9,6 @@ const assertJqTreeFolder = ($el: JQuery<HTMLElement>) => {
8
9
  };
9
10
 
10
11
  expect.extend({
11
- notToBeSelected(el: HTMLElement | JQuery<HTMLElement>) {
12
- const $el = jQuery(el);
13
-
14
- /* istanbul ignore next */
15
- return {
16
- message: () => "The node is selected",
17
- pass: !$el.hasClass("jqtree-selected"),
18
- };
19
- },
20
12
  toBeClosed(el: HTMLElement | JQuery<HTMLElement>) {
21
13
  const $el = jQuery(el);
22
14
  assertJqTreeFolder($el);
@@ -27,6 +19,13 @@ expect.extend({
27
19
  pass: $el.hasClass("jqtree-closed"),
28
20
  };
29
21
  },
22
+ toBeFocused(el: HTMLElement | JQuery<HTMLElement>) {
23
+ /* istanbul ignore next */
24
+ return {
25
+ message: () => "The is node is not focused",
26
+ pass: document.activeElement === titleSpan(el)[0],
27
+ };
28
+ },
30
29
  toBeOpen(el: HTMLElement | JQuery<HTMLElement>) {
31
30
  const $el = jQuery(el);
32
31
  assertJqTreeFolder($el);
@@ -22,12 +22,10 @@ declare namespace JQTreeMatchers {
22
22
  declare namespace jest {
23
23
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
24
  interface Matchers<R> {
25
- notToBeSelected(): boolean;
26
25
  toBeClosed(): boolean;
26
+ toBeFocused(): boolean;
27
27
  toBeOpen(): boolean;
28
28
  toBeSelected(): boolean;
29
- toHaveTreeStructure(
30
- treeStructure: JQTreeMatchers.TreeStructure
31
- ): boolean;
29
+ toHaveTreeStructure(treeStructure: any): boolean;
32
30
  }
33
31
  }
@@ -1,4 +1,5 @@
1
- import * as jQuery from "jquery";
1
+ import jQuery from "jquery";
2
2
  import "./jqTreeMatchers";
3
3
 
4
+ (window as any).$ = jQuery; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
4
5
  (window as any).jQuery = jQuery; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
@@ -1,21 +1,26 @@
1
1
  type NodeId = number | string;
2
2
 
3
- type DefaultRecord = Record<string, unknown>;
4
- type NodeData = string | DefaultRecord;
3
+ interface NodeRecord {
4
+ [key: string]: unknown;
5
+ id?: NodeId;
6
+ children?: NodeData[];
7
+ }
8
+
9
+ type NodeData = string | NodeRecord;
5
10
 
6
11
  type IterateCallback = (node: INode, level: number) => boolean;
7
12
 
8
- declare class INode {
9
- public id?: NodeId;
10
- public name: string;
11
- public children: INode[];
12
- public element: HTMLElement;
13
- public is_open: boolean;
14
- public parent: INode | null;
13
+ interface INode {
14
+ id?: NodeId;
15
+ name: string;
16
+ children: INode[];
17
+ element: HTMLElement;
18
+ is_open: boolean;
19
+ parent: INode | null;
15
20
 
16
21
  [key: string]: unknown;
17
22
 
18
- public iterate(callback: IterateCallback): void;
23
+ iterate(callback: IterateCallback): void;
19
24
  }
20
25
 
21
26
  type DataUrlFunction = (node?: Node) => JQuery.AjaxSettings;
@@ -41,7 +46,7 @@ interface IJQTreeOptions {
41
46
  buttonLeft?: boolean;
42
47
  closedIcon?: string | Element;
43
48
  data?: NodeData[];
44
- dataFilter?: (data: unknown) => NodeData[];
49
+ dataFilter?: (data: NodeData[]) => NodeData[];
45
50
  dataUrl?: DataUrl;
46
51
  dragAndDrop?: boolean;
47
52
  nodeClass?: any;
@@ -63,6 +68,7 @@ interface IJQTreeOptions {
63
68
  saveState?: boolean | string;
64
69
  slide?: boolean;
65
70
  showEmptyFolder?: boolean;
71
+ startDndDelay?: number;
66
72
  tabIndex?: number;
67
73
  useContextMenu?: boolean;
68
74
  }
@@ -134,14 +140,14 @@ interface IJQTreePlugin {
134
140
  onFinished?: (node: INode) => void
135
141
  ): JQuery;
136
142
  (behavior: "prependNode", newNodeInfo: NodeData, parentNode?: INode): INode;
143
+ (behavior: "refresh"): JQuery;
137
144
  (behavior: "reload", onFinished?: () => void): JQuery;
138
145
  (behavior: "removeFromSelection", node: INode): JQuery;
139
146
  (behavior: "removeNode", node: INode): JQuery;
140
147
  (behavior: "scrollToNode", node: INode): JQuery;
141
148
  (behavior: "selectNode", node: INode | null): JQuery;
142
- (behavior: "setMouseDelay", delay: number): void;
143
149
  (behavior: "setOption", option: string, value: unknown): JQuery;
144
- (behavior: "setState", options: DefaultRecord): JQuery;
150
+ (behavior: "setState", options: Record<string, unknown>): JQuery;
145
151
  (behavior: "toggle", node: INode, slideParam?: boolean): JQuery;
146
152
  (behavior: "toJson"): string;
147
153
  (behavior: "updateNode", node: INode, data: NodeData): JQuery;
@@ -1,23 +1,19 @@
1
1
  import __version__ from "./version";
2
- import * as jQueryProxy from "jquery";
3
2
  import { DragAndDropHandler } from "./dragAndDropHandler";
4
3
  import ElementsRenderer from "./elementsRenderer";
5
4
  import DataLoader, { HandleFinishedLoading } from "./dataLoader";
6
5
  import KeyHandler from "./keyHandler";
7
6
  import MouseWidget from "./mouse.widget";
8
7
  import { PositionInfo } from "./types";
9
- import SaveStateHandler from "./saveStateHandler";
8
+ import SaveStateHandler, { SavedState } from "./saveStateHandler";
10
9
  import ScrollHandler from "./scrollHandler";
11
10
  import SelectNodeHandler from "./selectNodeHandler";
12
11
  import SimpleWidget from "./simple.widget";
13
- import { Node, NodeId, getPosition, NodeData } from "./node";
12
+ import { Node, getPosition } from "./node";
14
13
  import { isFunction } from "./util";
15
14
  import { FolderElement, NodeElement, OnFinishOpenNode } from "./nodeElement";
16
15
  import { JQTreeOptions } from "./jqtreeOptions";
17
16
 
18
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
19
- const jQuery: JQueryStatic = (<any>jQueryProxy).default || jQueryProxy;
20
-
21
17
  interface ClickTarget {
22
18
  node: Node;
23
19
  type: "button" | "label";
@@ -34,45 +30,41 @@ const PARAM_IS_EMPTY = "Parameter is empty: ";
34
30
  export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
35
31
  protected static defaults: JQTreeOptions = {
36
32
  animationSpeed: "fast",
37
- autoOpen: false, // true / false / int (open n levels starting at 0)
38
- saveState: false, // true / false / string (cookie name)
39
- dragAndDrop: false,
40
- selectable: true,
41
- useContextMenu: true,
42
- onCanSelectNode: undefined,
43
- onSetStateFromStorage: undefined,
44
- onGetStateFromStorage: undefined,
45
- onCreateLi: undefined,
46
- onIsMoveHandle: undefined,
47
-
48
- // Can this node be moved?
49
- onCanMove: undefined,
50
-
51
- // Can this node be moved to this position? function(moved_node, target_node, position)
52
- onCanMoveTo: undefined,
53
- onLoadFailed: undefined,
54
33
  autoEscape: true,
55
- dataUrl: undefined,
56
-
34
+ autoOpen: false, // true / false / int (open n levels starting at 0)
35
+ buttonLeft: true,
57
36
  // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER
58
37
  // http://www.fileformat.info/info/unicode/char/25ba/index.htm
59
38
  closedIcon: undefined,
60
-
61
- // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
62
- // http://www.fileformat.info/info/unicode/char/25bc/index.htm
63
- openedIcon: "&#x25bc;",
64
- slide: true, // must display slide animation?
65
- nodeClass: Node,
39
+ data: undefined,
66
40
  dataFilter: undefined,
41
+ dataUrl: undefined,
42
+ dragAndDrop: false,
67
43
  keyboardSupport: true,
68
- openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds
69
- rtl: undefined, // right-to-left support; true / false (default)
44
+ nodeClass: Node,
45
+ onCanMove: undefined, // Can this node be moved?
46
+ onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)
47
+ onCanSelectNode: undefined,
48
+ onCreateLi: undefined,
70
49
  onDragMove: undefined,
71
50
  onDragStop: undefined,
72
- buttonLeft: true,
51
+ onGetStateFromStorage: undefined,
52
+ onIsMoveHandle: undefined,
53
+ onLoadFailed: undefined,
73
54
  onLoading: undefined,
55
+ onSetStateFromStorage: undefined,
56
+ openedIcon: "&#x25bc;",
57
+ openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds
58
+ // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
59
+ // http://www.fileformat.info/info/unicode/char/25bc/index.htm
60
+ rtl: undefined, // right-to-left support; true / false (default)
61
+ saveState: false, // true / false / string (cookie name)
62
+ selectable: true,
74
63
  showEmptyFolder: false,
64
+ slide: true, // must display slide animation?
65
+ startDndDelay: 300, // The delay for starting dnd (in milliseconds)
75
66
  tabIndex: 0,
67
+ useContextMenu: true,
76
68
  };
77
69
 
78
70
  public element: JQuery;
@@ -171,6 +163,11 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
171
163
  return this.element;
172
164
  }
173
165
 
166
+ public refresh(): JQuery {
167
+ this._refreshElements(null);
168
+ return this.element;
169
+ }
170
+
174
171
  public getNodeById(nodeId: NodeId): Node | null {
175
172
  return this.tree.getNodeById(nodeId);
176
173
  }
@@ -370,19 +367,12 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
370
367
  node.removeChildren();
371
368
 
372
369
  if (data.children.length) {
373
- node.loadFromData(data.children);
370
+ node.loadFromData(data.children as Node[]);
374
371
  }
375
372
  }
376
373
 
377
- const mustSetFocus = this.selectNodeHandler.isFocusOnTree();
378
- const mustSelect = this.isSelectedNodeInSubtree(node);
379
-
380
374
  this._refreshElements(node);
381
375
 
382
- if (mustSelect) {
383
- this.selectCurrentNode(mustSetFocus);
384
- }
385
-
386
376
  return this.element;
387
377
  }
388
378
 
@@ -490,7 +480,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
490
480
  }
491
481
 
492
482
  public setOption(option: string, value: unknown): JQuery {
493
- (this.options as Record<string, unknown>)[option] = value;
483
+ (this.options as unknown as Record<string, unknown>)[option] = value;
494
484
  return this.element;
495
485
  }
496
486
 
@@ -518,7 +508,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
518
508
 
519
509
  public _triggerEvent(
520
510
  eventName: string,
521
- values?: DefaultRecord
511
+ values?: Record<string, unknown>
522
512
  ): JQuery.Event {
523
513
  const event = jQuery.Event(eventName, values);
524
514
  this.element.trigger(event);
@@ -532,7 +522,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
532
522
  ): void {
533
523
  const doOpenNode = (
534
524
  _node: Node,
535
- _slide: any,
525
+ _slide: boolean,
536
526
  _onFinished: OnFinishOpenNode | null
537
527
  ): void => {
538
528
  const folderElement = new FolderElement(_node, this);
@@ -568,8 +558,17 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
568
558
  from_node: redraw this subtree
569
559
  */
570
560
  public _refreshElements(fromNode: Node | null): void {
561
+ const mustSetFocus = this.selectNodeHandler.isFocusOnTree();
562
+ const mustSelect = fromNode
563
+ ? this.isSelectedNodeInSubtree(fromNode)
564
+ : false;
565
+
571
566
  this.renderer.render(fromNode);
572
567
 
568
+ if (mustSelect) {
569
+ this.selectCurrentNode(mustSetFocus);
570
+ }
571
+
573
572
  this._triggerEvent("tree.refresh");
574
573
  }
575
574
 
@@ -604,7 +603,6 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
604
603
  super.init();
605
604
 
606
605
  this.element = this.$el;
607
- this.mouseDelay = 300;
608
606
  this.isInitialized = false;
609
607
 
610
608
  this.options.rtl = this.getRtlOption();
@@ -677,6 +675,10 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
677
675
  }
678
676
  }
679
677
 
678
+ protected getMouseDelay(): number {
679
+ return this.options.startDndDelay ?? 0;
680
+ }
681
+
680
682
  private initData(): void {
681
683
  if (this.options.data) {
682
684
  this.doLoadData(this.options.data, null);
@@ -738,7 +740,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
738
740
  }
739
741
  }
740
742
 
741
- private initTree(data: any): void {
743
+ private initTree(data: NodeData[]): void {
742
744
  const doInit = (): void => {
743
745
  if (!this.isInitialized) {
744
746
  this.isInitialized = true;
@@ -785,9 +787,8 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
785
787
  if (!state) {
786
788
  return [false, false];
787
789
  } else {
788
- const mustLoadOnDemand = this.saveStateHandler.setInitialState(
789
- state
790
- );
790
+ const mustLoadOnDemand =
791
+ this.saveStateHandler.setInitialState(state);
791
792
 
792
793
  // return true: the state is restored
793
794
  return [true, mustLoadOnDemand];
@@ -902,7 +903,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
902
903
  }
903
904
  }
904
905
 
905
- private handleClick = (e: JQuery.ClickEvent): void => {
906
+ private handleClick = (
907
+ e: JQuery.ClickEvent<HTMLElement, any, HTMLElement, HTMLElement>
908
+ ): void => {
906
909
  const clickTarget = this.getClickTarget(e.target);
907
910
 
908
911
  if (clickTarget) {
@@ -925,7 +928,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
925
928
  }
926
929
  };
927
930
 
928
- private handleDblclick = (e: JQuery.DoubleClickEvent): void => {
931
+ private handleDblclick = (
932
+ e: JQuery.DoubleClickEvent<HTMLElement, any, HTMLElement, HTMLElement>
933
+ ): void => {
929
934
  const clickTarget = this.getClickTarget(e.target);
930
935
 
931
936
  if (clickTarget?.type === "label") {
@@ -975,7 +980,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
975
980
  }
976
981
  }
977
982
 
978
- private handleContextmenu = (e: JQuery.ContextMenuEvent) => {
983
+ private handleContextmenu = (
984
+ e: JQuery.ContextMenuEvent<HTMLElement, any, HTMLElement, HTMLElement>
985
+ ) => {
979
986
  const $div = jQuery(e.target).closest("ul.jqtree-tree .jqtree-element");
980
987
  if ($div.length) {
981
988
  const node = this.getNode($div);
@@ -1130,15 +1137,14 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
1130
1137
  }
1131
1138
 
1132
1139
  private deselectNodes(parentNode: Node): void {
1133
- const selectedNodesUnderParent = this.selectNodeHandler.getSelectedNodesUnder(
1134
- parentNode
1135
- );
1140
+ const selectedNodesUnderParent =
1141
+ this.selectNodeHandler.getSelectedNodesUnder(parentNode);
1136
1142
  for (const n of selectedNodesUnderParent) {
1137
1143
  this.selectNodeHandler.removeFromSelection(n);
1138
1144
  }
1139
1145
  }
1140
1146
 
1141
- private loadSubtree(data: any[], parentNode: Node): void {
1147
+ private loadSubtree(data: NodeData[], parentNode: Node): void {
1142
1148
  parentNode.loadFromData(data);
1143
1149
 
1144
1150
  parentNode.load_on_demand = false;
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
- const version = "1.5.2";
1
+ const version = "1.6.2";
2
2
 
3
3
  export default version;