jqtree 1.6.2 → 1.7.0

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 (276) hide show
  1. package/.eslintrc +3 -12
  2. package/.github/workflows/ci.yml +57 -30
  3. package/.github/workflows/codeql-analysis.yml +9 -5
  4. package/.prettier +3 -0
  5. package/.tool-versions +1 -0
  6. package/README.md +12 -9
  7. package/bower.json +10 -3
  8. package/{.postcssrc → config/.postcssrc} +0 -0
  9. package/{babel.config.json → config/babel.config.json} +0 -0
  10. package/{babel.coverage.config.json → config/babel.coverage.config.json} +0 -0
  11. package/{jest-jsdom.config.js → config/jest.config.js} +8 -3
  12. package/config/playwright.config.js +18 -0
  13. package/config/production +4 -0
  14. package/{rollup.config.js → config/rollup.config.mjs} +3 -8
  15. package/{jqtree.postcss → css/jqtree.postcss} +0 -0
  16. package/devserver/index.html +1 -9
  17. package/docs/Gemfile +2 -0
  18. package/docs/Gemfile.lock +263 -0
  19. package/{_config.yml → docs/_config.yml} +8 -1
  20. package/{_entries → docs/_entries}/01_general.md +0 -0
  21. package/{_entries → docs/_entries}/02_introduction.md +0 -0
  22. package/{_entries → docs/_entries}/03_features.md +1 -1
  23. package/{_entries → docs/_entries}/04_demo.html +1 -7
  24. package/{_entries → docs/_entries}/05_requirements.md +0 -0
  25. package/{_entries → docs/_entries}/06_downloads.md +0 -0
  26. package/{_entries → docs/_entries}/07_tutorial.md +0 -0
  27. package/{_entries → docs/_entries}/08_examples.md +0 -0
  28. package/{_entries → docs/_entries}/09_usecases.md +0 -0
  29. package/{_entries → docs/_entries}/10_changelog.md +13 -0
  30. package/{_entries → docs/_entries}/11_options.md +0 -0
  31. package/{_entries → docs/_entries}/12_animationspeed.md +0 -0
  32. package/{_entries → docs/_entries}/13_autoescape.md +0 -0
  33. package/{_entries → docs/_entries}/14_autoopen.md +0 -0
  34. package/{_entries → docs/_entries}/15_buttonleft.md +0 -0
  35. package/{_entries → docs/_entries}/16_closedicon.md +0 -0
  36. package/{_entries → docs/_entries}/17_data.md +0 -0
  37. package/{_entries → docs/_entries}/18_datafilter.md +0 -0
  38. package/{_entries → docs/_entries}/19_data-url.md +0 -0
  39. package/{_entries → docs/_entries}/20_draganddrop.md +0 -0
  40. package/{_entries → docs/_entries}/21_keyboardsupport.md +0 -0
  41. package/{_entries → docs/_entries}/22_oncanmove.md +0 -0
  42. package/{_entries → docs/_entries}/23_oncanmoveto.md +2 -2
  43. package/{_entries → docs/_entries}/24_oncanselectnode.md +0 -0
  44. package/{_entries → docs/_entries}/25_oncreateli.md +2 -2
  45. package/{_entries → docs/_entries}/26_ondragmove.md +0 -0
  46. package/{_entries → docs/_entries}/27_ondragstop.md +0 -0
  47. package/{_entries → docs/_entries}/28_onismovehandle.md +0 -0
  48. package/{_entries → docs/_entries}/29_onloadfailed.md +0 -0
  49. package/{_entries → docs/_entries}/30_onloading.md +2 -2
  50. package/{_entries → docs/_entries}/31_openedicon.md +0 -0
  51. package/{_entries → docs/_entries}/32_openfolderdelay.md +2 -0
  52. package/{_entries → docs/_entries}/33_rtl.md +0 -0
  53. package/{_entries → docs/_entries}/34_savestate.md +0 -0
  54. package/{_entries → docs/_entries}/35_selectable.md +0 -0
  55. package/{_entries → docs/_entries}/36_showemptyfolder.md +0 -0
  56. package/{_entries → docs/_entries}/37_slide.md +0 -0
  57. package/{_entries → docs/_entries}/38_start_dnd_delay.md +0 -0
  58. package/{_entries → docs/_entries}/39_tabindex.md +0 -0
  59. package/{_entries → docs/_entries}/40_usecontextmenu.md +0 -0
  60. package/{_entries → docs/_entries}/41_functions.md +0 -0
  61. package/{_entries → docs/_entries}/42_addparentnode.md +1 -1
  62. package/{_entries → docs/_entries}/43_addnodeafter.md +1 -1
  63. package/{_entries → docs/_entries}/44_addnodebefore.md +1 -1
  64. package/{_entries → docs/_entries}/45_appendnode.md +5 -5
  65. package/{_entries → docs/_entries}/46_closenode.md +0 -0
  66. package/{_entries → docs/_entries}/47_destroy.md +0 -0
  67. package/{_entries → docs/_entries}/48_getnodebycallback.md +0 -0
  68. package/{_entries → docs/_entries}/49_getnodebyid.md +0 -0
  69. package/{_entries → docs/_entries}/50_getnodebyhtmlelement.md +2 -2
  70. package/{_entries → docs/_entries}/51_getselectednode.md +0 -0
  71. package/{_entries → docs/_entries}/52_getstate.md +0 -0
  72. package/{_entries → docs/_entries}/53_gettree.md +1 -1
  73. package/{_entries → docs/_entries}/54_isdragging.md +1 -1
  74. package/{_entries → docs/_entries}/55_loaddata.md +3 -3
  75. package/{_entries → docs/_entries}/56_loaddatafromurl.md +4 -4
  76. package/{_entries → docs/_entries}/57_movedown.md +0 -0
  77. package/{_entries → docs/_entries}/58_movenode.md +3 -3
  78. package/{_entries → docs/_entries}/59_moveup.md +0 -0
  79. package/{_entries → docs/_entries}/60_opennode.md +3 -3
  80. package/docs/_entries/61_prependnode.md +21 -0
  81. package/{_entries → docs/_entries}/62_refresh.md +0 -0
  82. package/{_entries → docs/_entries}/63_reload.md +2 -2
  83. package/{_entries → docs/_entries}/64_removenode.md +0 -0
  84. package/{_entries → docs/_entries}/65_selectnode.md +0 -0
  85. package/{_entries → docs/_entries}/66_scrolltonode.md +0 -0
  86. package/{_entries → docs/_entries}/67_setoption.md +0 -0
  87. package/{_entries → docs/_entries}/68_setstate.md +0 -0
  88. package/{_entries → docs/_entries}/69_toggle.md +0 -0
  89. package/{_entries → docs/_entries}/70_tojson.md +0 -0
  90. package/{_entries → docs/_entries}/71_updatenode.md +1 -1
  91. package/{_entries → docs/_entries}/72_events.md +0 -0
  92. package/{_entries → docs/_entries}/73_tree-click.md +0 -0
  93. package/{_entries → docs/_entries}/74_tree-close.md +0 -0
  94. package/{_entries → docs/_entries}/75_tree-contextmenu.md +0 -0
  95. package/{_entries → docs/_entries}/76_tree-dblclick.md +0 -0
  96. package/{_entries → docs/_entries}/77_tree-init.md +0 -0
  97. package/{_entries → docs/_entries}/78_tree-load-data.md +0 -0
  98. package/{_entries → docs/_entries}/79_tree-loading-data.md +0 -0
  99. package/{_entries → docs/_entries}/80_tree-move.md +0 -0
  100. package/{_entries → docs/_entries}/81_tree-refresh.md +0 -0
  101. package/{_entries → docs/_entries}/82_tree-open.md +0 -0
  102. package/{_entries → docs/_entries}/83_tree-select.md +0 -0
  103. package/{_entries → docs/_entries}/84_multiple-selection.md +0 -0
  104. package/{_entries → docs/_entries}/85_add-to-selection.md +0 -0
  105. package/{_entries → docs/_entries}/86_get-selected-nodes.md +0 -0
  106. package/{_entries → docs/_entries}/87_is-node-selected.md +1 -1
  107. package/{_entries → docs/_entries}/88_remove-from-selection.md +0 -0
  108. package/{_entries → docs/_entries}/89_node-functions.md +0 -0
  109. package/{_entries → docs/_entries}/90_children.md +0 -0
  110. package/{_entries → docs/_entries}/91_getdata.md +2 -2
  111. package/{_entries → docs/_entries}/92_getlevel.md +0 -0
  112. package/docs/_entries/93_getnextnode.md +15 -0
  113. package/{_entries → docs/_entries}/94_getnextsibling.md +0 -0
  114. package/{_entries/95_getpreviousnode.md → docs/_entries/95_getnextvisiblenode.md} +1 -1
  115. package/docs/_entries/96_getpreviousnode.md +0 -0
  116. package/{_entries/96_getprevioussibling.md → docs/_entries/97_getprevioussibling.md} +0 -0
  117. package/docs/_entries/98_getpreviousvisiblenode.md +14 -0
  118. package/{_entries/97_parent.md → docs/_entries/99_parent.md} +1 -1
  119. package/{_entries → docs/_entries}/insert.py +0 -0
  120. package/{_entries → docs/_entries}/renumber.py +0 -0
  121. package/{_examples → docs/_examples}/01_load_json_data.html +3 -5
  122. package/{_examples → docs/_examples}/02_load_json_data_from_server.html +3 -5
  123. package/{_examples → docs/_examples}/03_drag_and_drop.html +3 -5
  124. package/{_examples → docs/_examples}/04_save_state.html +3 -5
  125. package/{_examples → docs/_examples}/05_load_on_demand.html +3 -5
  126. package/{_examples → docs/_examples}/06_autoescape.html +3 -5
  127. package/{_examples → docs/_examples}/07_autoscroll.html +3 -5
  128. package/{_examples → docs/_examples}/08_multiple_select.html +3 -5
  129. package/{_examples → docs/_examples}/09_custom_html.html +3 -5
  130. package/{_examples → docs/_examples}/10_icon_buttons.html +3 -5
  131. package/{_examples → docs/_examples}/11_right-to-left.html +3 -5
  132. package/{_examples → docs/_examples}/12_button_on_right.html +3 -5
  133. package/docs/_examples/13_drag_outside.html +48 -0
  134. package/{_examples → docs/_examples}/14_filter.html +7 -9
  135. package/docs/_layouts/example.html +7 -0
  136. package/{_layouts/base.html → docs/_layouts/page.html} +4 -11
  137. package/docs/documentation.css +3 -0
  138. package/docs/index.html +65 -0
  139. package/docs/jqtree.css +189 -0
  140. package/docs/package.json +22 -0
  141. package/docs/pnpm-lock.yaml +798 -0
  142. package/docs/postcss.config.js +7 -0
  143. package/{static → docs/static}/bower.json +1 -2
  144. package/{static → docs/static}/bower_components/fontawesome/css/all.min.css +0 -0
  145. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.eot +0 -0
  146. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.svg +0 -0
  147. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  148. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.woff +0 -0
  149. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  150. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.eot +0 -0
  151. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.svg +0 -0
  152. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  153. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.woff +0 -0
  154. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  155. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.eot +0 -0
  156. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.svg +0 -0
  157. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  158. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.woff +0 -0
  159. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  160. package/{static → docs/static}/bower_components/jquery/dist/jquery.js +209 -97
  161. package/docs/static/bower_components/jquery/dist/jquery.min.js +2 -0
  162. package/{static → docs/static}/bower_components/jquery-mockjax/dist/jquery.mockjax.js +0 -0
  163. package/docs/static/documentation.css +1453 -0
  164. package/docs/static/documentation.js +26 -0
  165. package/{static → docs/static}/example.css +5 -38
  166. package/{static → docs/static}/example.postcss +5 -35
  167. package/{static → docs/static}/example_data.js +0 -0
  168. package/{static → docs/static}/examples/autoescape.js +0 -0
  169. package/{static → docs/static}/examples/autoscroll.js +0 -0
  170. package/{static → docs/static}/examples/button-on-right.js +0 -0
  171. package/{static → docs/static}/examples/custom_html.js +5 -9
  172. package/{static → docs/static}/examples/drag-outside.js +0 -0
  173. package/{static → docs/static}/examples/drag_and_drop.js +0 -0
  174. package/{static → docs/static}/examples/filter.js +2 -2
  175. package/{static → docs/static}/examples/icon_buttons.js +0 -0
  176. package/{static → docs/static}/examples/load_json_data.js +0 -0
  177. package/{static → docs/static}/examples/load_json_data_from_server.js +0 -0
  178. package/{static → docs/static}/examples/load_on_demand.js +0 -0
  179. package/{static → docs/static}/examples/multiple_select.js +0 -0
  180. package/{static → docs/static}/examples/right-to-left.js +0 -0
  181. package/{static → docs/static}/examples/save_state.js +0 -0
  182. package/{static → docs/static}/monokai.css +0 -0
  183. package/{static → docs/static}/spinner.gif +0 -0
  184. package/docs/tailwind.config.js +16 -0
  185. package/docs/tree.jquery.js +21 -0
  186. package/lib/dataLoader.js +5 -31
  187. package/lib/dragAndDropHandler.js +26 -135
  188. package/lib/elementsRenderer.js +29 -59
  189. package/lib/keyHandler.js +8 -32
  190. package/lib/mouse.widget.js +16 -77
  191. package/lib/node.js +60 -125
  192. package/lib/nodeElement.js +8 -75
  193. package/lib/playwright/coverage.js +101 -0
  194. package/lib/playwright/playwright.test.js +212 -182
  195. package/lib/playwright/testUtils.js +201 -0
  196. package/lib/saveStateHandler.js +12 -61
  197. package/lib/scrollHandler.js +17 -74
  198. package/lib/selectNodeHandler.js +5 -24
  199. package/lib/simple.widget.js +18 -53
  200. package/lib/test/jqTree/create.test.js +0 -4
  201. package/lib/test/jqTree/events.test.js +10 -16
  202. package/lib/test/jqTree/keyboard.test.js +0 -6
  203. package/lib/test/jqTree/loadOnDemand.test.js +107 -139
  204. package/lib/test/jqTree/methods.test.js +136 -159
  205. package/lib/test/jqTree/options.test.js +53 -63
  206. package/lib/test/node.test.js +127 -72
  207. package/lib/test/nodeUtil.test.js +0 -1
  208. package/lib/test/support/jqTreeMatchers.js +4 -9
  209. package/lib/test/support/setupTests.js +0 -4
  210. package/lib/test/support/testUtil.js +2 -11
  211. package/lib/test/support/treeStructure.js +0 -6
  212. package/lib/test/util.test.js +0 -1
  213. package/lib/tree.jquery.js +32 -243
  214. package/lib/util.js +0 -6
  215. package/lib/version.js +1 -1
  216. package/package.json +54 -54
  217. package/src/dragAndDropHandler.ts +8 -4
  218. package/src/jqtreeOptions.ts +1 -1
  219. package/src/keyHandler.ts +3 -3
  220. package/src/node.ts +43 -12
  221. package/src/playwright/.eslintrc +2 -2
  222. package/src/playwright/coverage.ts +41 -0
  223. package/src/playwright/playwright.test.ts +50 -52
  224. package/src/playwright/playwright.test.ts-snapshots/with-dragAndDrop-moves-a-node-1-Chromium-darwin.png +0 -0
  225. package/src/playwright/playwright.test.ts-snapshots/with-dragAndDrop-moves-a-node-1-Chromium-linux.png +0 -0
  226. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-displays-a-tree-1-Chromium-darwin.png +0 -0
  227. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-displays-a-tree-1-Chromium-linux.png +0 -0
  228. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-selects-a-node-1-Chromium-darwin.png +0 -0
  229. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-selects-a-node-1-Chromium-linux.png +0 -0
  230. package/src/playwright/testUtils.ts +122 -0
  231. package/src/test/.eslintrc +15 -3
  232. package/src/test/jqTree/events.test.ts +10 -9
  233. package/src/test/jqTree/loadOnDemand.test.ts +10 -10
  234. package/src/test/jqTree/methods.test.ts +37 -45
  235. package/src/test/jqTree/options.test.ts +26 -28
  236. package/src/test/node.test.ts +146 -54
  237. package/src/tree.jquery.d.ts +1 -1
  238. package/src/tree.jquery.ts +6 -5
  239. package/src/version.ts +1 -1
  240. package/tree.jquery.debug.js +217 -867
  241. package/tree.jquery.debug.js.map +1 -1
  242. package/tree.jquery.js +3 -3
  243. package/tree.jquery.js.map +1 -1
  244. package/_entries/61_prependnode.md +0 -21
  245. package/_entries/93_getnextnode.md +0 -12
  246. package/_examples/13_drag_outside.html +0 -26
  247. package/_layouts/frontpage.html +0 -20
  248. package/_layouts/page.html +0 -7
  249. package/index.html +0 -48
  250. package/jest-browser.config.js +0 -15
  251. package/jest-playwright.config.js +0 -21
  252. package/jest.config.js +0 -8
  253. package/lib/playwright/testUtil.js +0 -459
  254. package/lib/playwright/visualRegression.js +0 -193
  255. package/production +0 -5
  256. package/src/playwright/screenshots/displays_a_tree_Desktop.png +0 -0
  257. package/src/playwright/screenshots/displays_a_tree_iPhone 6.png +0 -0
  258. package/src/playwright/screenshots/moves_a_node_Desktop.png +0 -0
  259. package/src/playwright/screenshots/moves_a_node_iPhone 6.png +0 -0
  260. package/src/playwright/screenshots/opens_a_node_Desktop.png +0 -0
  261. package/src/playwright/screenshots/opens_a_node_iPhone 6.png +0 -0
  262. package/src/playwright/screenshots/selects_a_node_Desktop.png +0 -0
  263. package/src/playwright/screenshots/selects_a_node_iPhone 6.png +0 -0
  264. package/src/playwright/testUtil.ts +0 -170
  265. package/src/playwright/visualRegression.ts +0 -88
  266. package/static/bower_components/bootstrap/dist/css/bootstrap-theme.min.css +0 -6
  267. package/static/bower_components/bootstrap/dist/css/bootstrap.min.css +0 -6
  268. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  269. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg +0 -288
  270. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  271. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  272. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  273. package/static/bower_components/bootstrap/dist/js/bootstrap.min.js +0 -6
  274. package/static/bower_components/jquery/dist/jquery.min.js +0 -2
  275. package/static/documentation.css +0 -171
  276. package/static/documentation.js +0 -48
package/lib/util.js CHANGED
@@ -4,21 +4,15 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.isInt = exports.isFunction = exports.getBoolString = void 0;
7
-
8
7
  var isInt = function isInt(n) {
9
8
  return typeof n === "number" && n % 1 === 0;
10
9
  };
11
-
12
10
  exports.isInt = isInt;
13
-
14
11
  var isFunction = function isFunction(v) {
15
12
  return typeof v === "function";
16
13
  };
17
-
18
14
  exports.isFunction = isFunction;
19
-
20
15
  var getBoolString = function getBoolString(value) {
21
16
  return value ? "true" : "false";
22
17
  };
23
-
24
18
  exports.getBoolString = getBoolString;
package/lib/version.js CHANGED
@@ -4,6 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports["default"] = void 0;
7
- var version = "1.6.2";
7
+ var version = "1.7.0";
8
8
  var _default = version;
9
9
  exports["default"] = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jqtree",
3
- "version": "1.6.2",
3
+ "version": "1.7.0",
4
4
  "description": "Tree widget for jQuery",
5
5
  "keywords": [
6
6
  "jquery-plugin",
@@ -14,69 +14,69 @@
14
14
  "url": "https://github.com/mbraak/jqtree"
15
15
  },
16
16
  "scripts": {
17
- "ci": "pnpm run lint && yarn run tsc && pnpm run test",
18
- "test": "start-server-and-test 'yarn devserver-with-coverage' http://localhost:8080 'jest --runInBand --coverage --no-cache --verbose'",
19
- "test-with-server": "jest --runInBand --coverage",
20
- "test-watch": "jest --watch",
17
+ "ci": "pnpm lint && pnpm tsc && pnpm test",
18
+ "jest": "jest --coverage --no-cache --verbose --config ./config/jest.config.js",
19
+ "jest-watch": "jest --watch --config ./config/jest.config.js",
21
20
  "lint": "eslint src/ --ext .ts,.tsx",
22
- "production": "./production",
23
- "jekyll-build": "bundle exec jekyll build",
24
- "jekyll-serve": "bundle exec jekyll serve",
25
- "devserver": "SERVE=true rollup -c -w rollup.config.js",
26
- "devserver-with-coverage": "COVERAGE=true SERVE=true rollup -c rollup.config.js",
27
- "prettier": "prettier src/*.ts src_test/*.ts --write --tab-width 4",
28
- "coveralls": "nyc report --reporter=text-lcov | coveralls",
21
+ "production": "./config/production",
22
+ "devserver": "SERVE=true rollup --config config/rollup.config.mjs --watch",
23
+ "devserver-with-coverage": "COVERAGE=true SERVE=true rollup --config config/rollup.config.mjs",
24
+ "build-with-coverage": "COVERAGE=true rollup --config config/rollup.config.mjs",
25
+ "prettier": "prettier src/*.ts --write --tab-width 4",
26
+ "write-coverage": "nyc report --reporter=text-lcov > lcov.info",
29
27
  "tsc": "tsc --noEmit --project tsconfig.json",
30
28
  "merge-coverage": "cp jest-coverage/coverage-final.json .nyc_output/coverage_jsdom.json",
31
- "clean-coverage": "rm -rf coverage jest-coverage .nyc_output && jest --clearCache",
32
- "print-coverage": "nyc report"
29
+ "clean-coverage": "rm -rf .nyc_output && jest --clearCache",
30
+ "print-coverage": "nyc report",
31
+ "playwright": "pnpm build-with-coverage && playwright test --config config/playwright.config.js",
32
+ "test": "pnpm jest && pnpm playwright"
33
33
  },
34
34
  "dependencies": {
35
- "jquery": "^3.6.0"
35
+ "jquery": "^3.6.3"
36
36
  },
37
37
  "devDependencies": {
38
- "@babel/cli": "^7.16.0",
39
- "@babel/core": "^7.16.5",
40
- "@babel/preset-env": "^7.16.5",
41
- "@babel/preset-typescript": "^7.16.5",
42
- "@rollup/plugin-babel": "^5.3.0",
43
- "@rollup/plugin-node-resolve": "^13.1.1",
44
- "@testing-library/dom": "^8.11.1",
45
- "@types/jest": "^27.0.3",
46
- "@types/jquery": "^3.5.10",
47
- "@types/pngjs": "^6.0.1",
48
- "@typescript-eslint/eslint-plugin": "^5.7.0",
49
- "@typescript-eslint/parser": "^5.7.0",
50
- "autoprefixer": "^10.4.0",
51
- "babel-jest": "^27.4.5",
38
+ "@babel/cli": "^7.20.7",
39
+ "@babel/core": "^7.20.7",
40
+ "@babel/preset-env": "^7.20.2",
41
+ "@babel/preset-typescript": "^7.18.6",
42
+ "@playwright/test": "^1.29.1",
43
+ "@rollup/plugin-babel": "^6.0.3",
44
+ "@rollup/plugin-node-resolve": "^15.0.1",
45
+ "@rollup/plugin-terser": "^0.1.0",
46
+ "@testing-library/dom": "^8.19.0",
47
+ "@types/debug": "^4.1.7",
48
+ "@types/jest": "^29.2.4",
49
+ "@types/jquery": "^3.5.14",
50
+ "@types/node": "^18.11.17",
51
+ "@typescript-eslint/eslint-plugin": "^5.47.0",
52
+ "@typescript-eslint/parser": "^5.47.0",
53
+ "autoprefixer": "^10.4.13",
54
+ "babel-jest": "^29.3.1",
52
55
  "babel-plugin-istanbul": "^6.1.1",
53
- "coveralls": "^3.1.1",
54
- "eslint": "^8.4.1",
55
- "eslint-plugin-import": "^2.25.3",
56
- "eslint-plugin-jest": "^25.3.0",
57
- "eslint-plugin-playwright": "^0.6.0",
58
- "eslint-plugin-testing-library": "^5.0.1",
59
- "expect-playwright": "^0.8.0",
56
+ "eslint": "^8.30.0",
57
+ "eslint-plugin-import": "^2.26.0",
58
+ "eslint-plugin-jest": "^27.1.7",
59
+ "eslint-plugin-playwright": "^0.11.2",
60
+ "eslint-plugin-testing-library": "^5.9.1",
60
61
  "givens": "^1.3.9",
61
- "jest": "^27.4.5",
62
- "jest-extended": "^1.2.0",
63
- "jest-playwright-preset": "^1.7.0",
62
+ "graphql": "^16.6.0",
63
+ "jest": "^29.3.1",
64
+ "jest-environment-jsdom": "^29.3.1",
65
+ "jest-extended": "^3.2.0",
64
66
  "jsonfile": "^6.1.0",
65
67
  "lodash.template": "^4.5.0",
66
- "msw": "^0.36.3",
67
- "pixelmatch": "^5.2.1",
68
- "playwright": "^1.17.1",
69
- "pngjs": "^6.0.0",
70
- "postcss": "^8.4.5",
71
- "postcss-cli": "^9.1.0",
72
- "postcss-load-config": "^3.1.0",
73
- "postcss-nested": "^5.0.6",
74
- "prettier": "^2.5.1",
75
- "rollup": "^2.61.1",
76
- "rollup-plugin-serve": "^1.1.0",
77
- "rollup-plugin-terser": "^7.0.2",
78
- "start-server-and-test": "^1.14.0",
79
- "tslib": "^2.3.1",
80
- "typescript": "^4.5.4"
68
+ "msw": "^0.49.2",
69
+ "nyc": "^15.1.0",
70
+ "playwright": "^1.29.1",
71
+ "postcss": "^8.4.20",
72
+ "postcss-cli": "^10.1.0",
73
+ "postcss-import": "^15.1.0",
74
+ "postcss-load-config": "^4.0.1",
75
+ "postcss-nested": "^6.0.0",
76
+ "prettier": "^2.8.1",
77
+ "rollup": "^3.8.1",
78
+ "rollup-plugin-serve": "^2.0.2",
79
+ "tslib": "^2.4.1",
80
+ "typescript": "~4.9.4"
81
81
  }
82
82
  }
@@ -312,10 +312,14 @@ export class DragAndDropHandler {
312
312
 
313
313
  this.stopOpenFolderTimer();
314
314
 
315
- this.openFolderTimer = window.setTimeout(
316
- openFolder,
317
- this.treeWidget.options.openFolderDelay
318
- );
315
+ const openFolderDelay = this.treeWidget.options.openFolderDelay;
316
+
317
+ if (openFolderDelay !== false) {
318
+ this.openFolderTimer = window.setTimeout(
319
+ openFolder,
320
+ openFolderDelay
321
+ );
322
+ }
319
323
  }
320
324
 
321
325
  private stopOpenFolderTimer(): void {
@@ -40,7 +40,7 @@ export interface JQTreeOptions {
40
40
  onLoading: HandleLoadingMethod | undefined;
41
41
  onSetStateFromStorage: ((data: string) => void) | undefined;
42
42
  openedIcon: string | Element;
43
- openFolderDelay: number;
43
+ openFolderDelay: number | false;
44
44
  rtl: boolean | undefined;
45
45
  selectable: boolean;
46
46
  saveState: boolean | string;
package/src/keyHandler.ts CHANGED
@@ -22,11 +22,11 @@ export default class KeyHandler {
22
22
  }
23
23
 
24
24
  public moveDown(selectedNode: Node): boolean {
25
- return this.selectNode(selectedNode.getNextNode());
25
+ return this.selectNode(selectedNode.getNextVisibleNode());
26
26
  }
27
27
 
28
28
  public moveUp(selectedNode: Node): boolean {
29
- return this.selectNode(selectedNode.getPreviousNode());
29
+ return this.selectNode(selectedNode.getPreviousVisibleNode());
30
30
  }
31
31
 
32
32
  public moveRight(selectedNode: Node): boolean {
@@ -36,7 +36,7 @@ export default class KeyHandler {
36
36
  // folder node
37
37
  if (selectedNode.is_open) {
38
38
  // Right moves to the first child of an open node
39
- return this.selectNode(selectedNode.getNextNode());
39
+ return this.selectNode(selectedNode.getNextVisibleNode());
40
40
  } else {
41
41
  // Right expands a closed node
42
42
  this.treeWidget.openNode(selectedNode);
package/src/node.ts CHANGED
@@ -557,7 +557,23 @@ export class Node implements INode {
557
557
  }
558
558
 
559
559
  public getNextNode(includeChildren = true): Node | null {
560
- if (includeChildren && this.hasChildren() && this.is_open) {
560
+ if (includeChildren && this.hasChildren()) {
561
+ return this.children[0];
562
+ } else if (!this.parent) {
563
+ return null;
564
+ } else {
565
+ const nextSibling = this.getNextSibling();
566
+
567
+ if (nextSibling) {
568
+ return nextSibling;
569
+ } else {
570
+ return this.parent.getNextNode(false);
571
+ }
572
+ }
573
+ }
574
+
575
+ public getNextVisibleNode(): Node | null {
576
+ if (this.hasChildren() && this.is_open) {
561
577
  // First child
562
578
  return this.children[0];
563
579
  } else {
@@ -581,19 +597,34 @@ export class Node implements INode {
581
597
  return null;
582
598
  } else {
583
599
  const previousSibling = this.getPreviousSibling();
584
- if (previousSibling) {
585
- if (
586
- !previousSibling.hasChildren() ||
587
- !previousSibling.is_open
588
- ) {
589
- // Previous sibling
590
- return previousSibling;
591
- } else {
592
- // Last child of previous sibling
593
- return previousSibling.getLastChild();
594
- }
600
+
601
+ if (!previousSibling) {
602
+ return this.getParent();
603
+ } else if (previousSibling.hasChildren()) {
604
+ return previousSibling.getLastChild();
595
605
  } else {
606
+ return previousSibling;
607
+ }
608
+ }
609
+ }
610
+
611
+ public getPreviousVisibleNode(): Node | null {
612
+ if (!this.parent) {
613
+ return null;
614
+ } else {
615
+ const previousSibling = this.getPreviousSibling();
616
+
617
+ if (!previousSibling) {
596
618
  return this.getParent();
619
+ } else if (
620
+ !previousSibling.hasChildren() ||
621
+ !previousSibling.is_open
622
+ ) {
623
+ // Previous sibling
624
+ return previousSibling;
625
+ } else {
626
+ // Last child of previous sibling
627
+ return previousSibling.getLastChild();
597
628
  }
598
629
  }
599
630
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "extends": [
3
- "plugin:playwright/jest-playwright"
3
+ "plugin:playwright/playwright-test"
4
4
  ]
5
- }
5
+ }
@@ -0,0 +1,41 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import crypto from "crypto";
4
+ import { BrowserContext } from "@playwright/test";
5
+
6
+ const istanbulCLIOutput = path.join(process.cwd(), ".nyc_output");
7
+
8
+ const generateUUID = () => crypto.randomBytes(16).toString("hex");
9
+
10
+ export const initCoverage = async (context: BrowserContext) => {
11
+ await fs.promises.mkdir(istanbulCLIOutput, { recursive: true });
12
+
13
+ await context.exposeFunction(
14
+ "collectIstanbulCoverage",
15
+ (coverageJSON: string) => {
16
+ if (!coverageJSON) {
17
+ console.log("No coverage");
18
+ } else {
19
+ const filename = path.join(
20
+ istanbulCLIOutput,
21
+ `playwright_coverage_${generateUUID()}.json`
22
+ );
23
+ console.log(`Writing coverage to ${filename}`);
24
+ fs.writeFileSync(filename, coverageJSON);
25
+ }
26
+ }
27
+ );
28
+ };
29
+
30
+ export const saveCoverage = async (context: BrowserContext) => {
31
+ for (const page of context.pages()) {
32
+ await page.evaluate(() => {
33
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
34
+ const anyWindow = window as any;
35
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
36
+ const coverageData = anyWindow.__coverage__;
37
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
38
+ anyWindow.collectIstanbulCoverage(JSON.stringify(coverageData));
39
+ });
40
+ }
41
+ };
@@ -1,37 +1,27 @@
1
- /// <reference types="jest-playwright-preset" />
2
- /// <reference types="expect-playwright" />
3
-
4
- import getGiven from "givens";
1
+ import { test, expect, Page } from "@playwright/test";
5
2
  import {
6
3
  dragAndDrop,
7
- expectToBeClosed,
8
- expectToBeOpen,
9
- expectToBeSelected,
10
4
  findNodeElement,
11
5
  getTreeStructure,
12
- openNode,
13
6
  selectNode,
14
- } from "./testUtil";
15
- import { matchScreenshot } from "./visualRegression";
7
+ } from "./testUtils";
8
+ import { initCoverage, saveCoverage } from "./coverage";
16
9
 
17
- interface Vars {
10
+ interface InitPageParameters {
11
+ baseURL?: string;
18
12
  dragAndDrop: boolean;
13
+ page: Page;
19
14
  }
20
15
 
21
- const given = getGiven<Vars>();
22
- given("dragAndDrop", () => false);
23
-
24
- beforeEach(async () => {
25
- await jestPlaywright.resetPage();
16
+ const initPage = async ({ baseURL, dragAndDrop, page }: InitPageParameters) => {
17
+ if (!baseURL) {
18
+ throw new Error("Missing baseURL");
19
+ }
26
20
 
27
- await page.goto("http://localhost:8080/test_index.html");
21
+ await page.goto(`${baseURL}/test_index.html`);
28
22
  await page.waitForLoadState("domcontentloaded");
29
23
 
30
- // Fix error on iphone6 device when collecting coverage
31
- await page.evaluate(() => {
32
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
33
- (window as any)["reportCodeCoverage"] = () => null;
34
- });
24
+ page.on("console", (msg) => console.log(`console: ${msg.text()}`));
35
25
 
36
26
  await page.evaluate(`
37
27
  const $tree = jQuery("#tree1");
@@ -40,51 +30,58 @@ beforeEach(async () => {
40
30
  animationSpeed: 0,
41
31
  autoOpen: 0,
42
32
  data: ExampleData.exampleData,
43
- dragAndDrop: ${given.dragAndDrop},
33
+ dragAndDrop: ${dragAndDrop},
44
34
  startDndDelay: 100,
45
35
  });
46
36
  `);
47
- });
48
37
 
49
- afterEach(async () => {
50
- await jestPlaywright.saveCoverage(page);
51
- });
38
+ await page.evaluate(`
39
+ console.log(window.__coverage__ ? 'Coverage enabled' : 'Coverage not enabled');
40
+ `);
41
+ };
52
42
 
53
- it("displays a tree", async () => {
54
- await expect(page).toMatchText(/.*Saurischia.*/);
55
- await expect(page).toMatchText(/.*Ornithischians.*/);
56
- await expect(page).toMatchText(/.*Coelophysoids.*/);
43
+ test.beforeEach(async ({ context }) => {
44
+ await initCoverage(context);
45
+ });
57
46
 
58
- await matchScreenshot("displays_a_tree");
47
+ test.afterEach(async ({ context }) => {
48
+ await saveCoverage(context);
59
49
  });
60
50
 
61
- it("selects a node", async () => {
62
- await expect(page).toMatchText(/.*Saurischia.*/);
63
- const saurischia = await findNodeElement("Saurischia");
64
- await selectNode(saurischia);
65
- await expectToBeSelected(saurischia);
51
+ test.describe("without dragAndDrop", () => {
52
+ test.beforeEach(async ({ baseURL, page }) => {
53
+ await initPage({ baseURL, page, dragAndDrop: false });
54
+ });
66
55
 
67
- await matchScreenshot("selects_a_node");
68
- });
56
+ test("displays a tree", async ({ page }) => {
57
+ await expect(page.locator("body")).toHaveText(/.*Saurischia.*/);
58
+ await expect(page.locator("body")).toHaveText(/.*Ornithischians.*/);
59
+ await expect(page.locator("body")).toHaveText(/.*Coelophysoids.*/);
69
60
 
70
- it("opens a node", async () => {
71
- await expect(page).toMatchText(/.*Saurischia.*/);
61
+ const screenshot = await page.screenshot();
62
+ expect(screenshot).toMatchSnapshot();
63
+ });
72
64
 
73
- const theropods = await findNodeElement("Theropods");
74
- await expectToBeClosed(theropods);
75
- await openNode(theropods);
76
- await expectToBeOpen(theropods);
65
+ test("selects a node", async ({ page }) => {
66
+ await expect(page.locator("body")).toHaveText(/.*Saurischia.*/);
77
67
 
78
- await matchScreenshot("opens_a_node");
68
+ const saurischia = await findNodeElement(page, "Saurischia");
69
+ await selectNode(saurischia);
70
+
71
+ const screenshot = await page.screenshot();
72
+ expect(screenshot).toMatchSnapshot();
73
+ });
79
74
  });
80
75
 
81
- describe("dragAndDrop", () => {
82
- given("dragAndDrop", () => true);
76
+ test.describe("with dragAndDrop", () => {
77
+ test.beforeEach(async ({ baseURL, page }) => {
78
+ await initPage({ baseURL, page, dragAndDrop: true });
79
+ });
83
80
 
84
- it("moves a node", async () => {
85
- await dragAndDrop("Herrerasaurians", "Ornithischians");
81
+ test("moves a node", async ({ page }) => {
82
+ await dragAndDrop(page, "Herrerasaurians", "Ornithischians");
86
83
 
87
- const structure = await getTreeStructure();
84
+ const structure = await getTreeStructure(page);
88
85
 
89
86
  expect(structure).toEqual([
90
87
  expect.objectContaining({
@@ -109,6 +106,7 @@ describe("dragAndDrop", () => {
109
106
  }),
110
107
  ]);
111
108
 
112
- await matchScreenshot("moves_a_node");
109
+ const screenshot = await page.screenshot();
110
+ expect(screenshot).toMatchSnapshot();
113
111
  });
114
112
  });
@@ -0,0 +1,122 @@
1
+ import { Page, ElementHandle } from "@playwright/test";
2
+
3
+ const locateTitle = (page: Page, title: string) =>
4
+ page.locator(".jqtree-title", {
5
+ hasText: title,
6
+ });
7
+
8
+ export const findNodeElement = async (page: Page, title: string) => {
9
+ const titleElement = await locateTitle(page, title).elementHandle();
10
+
11
+ if (!titleElement) {
12
+ throw new Error(`Title element not found: ${title}`);
13
+ }
14
+
15
+ const nodeElement = await titleElement.evaluateHandle((el) => {
16
+ const li = el.closest("li");
17
+
18
+ if (!li) {
19
+ throw Error("Node element not found");
20
+ }
21
+
22
+ return li;
23
+ });
24
+
25
+ return nodeElement;
26
+ };
27
+
28
+ export const selectNode = async (nodeElement: ElementHandle) => {
29
+ const titleHandle = await nodeElement.$(".jqtree-title");
30
+
31
+ if (!titleHandle) {
32
+ throw new Error("Could not select: title element not found");
33
+ }
34
+
35
+ await titleHandle.click();
36
+ };
37
+
38
+ const getRect = async (elementHandle: ElementHandle<HTMLElement>) => {
39
+ const boundingBox = await elementHandle.boundingBox();
40
+
41
+ if (!boundingBox) {
42
+ throw "No bounding box";
43
+ }
44
+
45
+ return boundingBox;
46
+ };
47
+
48
+ export const getTreeStructure = async (page: Page) => {
49
+ const structure = await page.evaluate<string>(`
50
+ ;
51
+ function getTreeNode($li) {
52
+ const $div = $li.children("div.jqtree-element");
53
+ const $span = $div.children("span.jqtree-title");
54
+ const name = $span.text();
55
+ const selected = $li.hasClass("jqtree-selected");
56
+
57
+ if ($li.hasClass("jqtree-folder")) {
58
+ const $ul = $li.children("ul.jqtree_common");
59
+
60
+ return {
61
+ nodeType: "folder",
62
+ children: getChildren($ul),
63
+ name,
64
+ open: !$li.hasClass("jqtree-closed"),
65
+ selected,
66
+ };
67
+ } else {
68
+ return {
69
+ nodeType: "child",
70
+ name,
71
+ selected,
72
+ };
73
+ }
74
+ }
75
+
76
+ function getChildren($ul) {
77
+ return $ul
78
+ .children("li.jqtree_common")
79
+ .map((_, li) => {
80
+ return getTreeNode(jQuery(li));
81
+ })
82
+ .get();
83
+ }
84
+
85
+ JSON.stringify(window.getChildren(jQuery("ul.jqtree-tree")));
86
+ `);
87
+
88
+ return JSON.parse(structure) as JQTreeMatchers.TreeStructure;
89
+ };
90
+
91
+ const getNodeRect = async (page: Page, title: string) => {
92
+ const titleElement = await locateTitle(page, title).elementHandle();
93
+
94
+ if (!titleElement) {
95
+ throw Error("Element not found");
96
+ }
97
+
98
+ const rect = await getRect(titleElement as ElementHandle<HTMLElement>);
99
+ return rect;
100
+ };
101
+
102
+ export const dragAndDrop = async (
103
+ page: Page,
104
+ from: string,
105
+ to: string
106
+ ): Promise<void> => {
107
+ const fromRect = await getNodeRect(page, from);
108
+ const toRect = await getNodeRect(page, to);
109
+
110
+ await page.mouse.move(
111
+ fromRect.x + fromRect.width / 2,
112
+ fromRect.y + fromRect.height / 2
113
+ );
114
+ await page.mouse.down();
115
+ // eslint-disable-next-line playwright/no-wait-for-timeout
116
+ await page.waitForTimeout(200);
117
+ await page.mouse.move(
118
+ toRect.x + toRect.width / 2,
119
+ toRect.y + toRect.height / 2
120
+ );
121
+ await page.mouse.up();
122
+ };
@@ -1,4 +1,16 @@
1
1
  {
2
- "plugins": ["testing-library"],
3
- "extends": ["plugin:testing-library/dom"]
4
- }
2
+ "plugins": ["jest", "testing-library"],
3
+ "extends": ["plugin:jest/all", "plugin:testing-library/dom"],
4
+ "rules": {
5
+ "jest/consistent-test-it": "off",
6
+ "jest/max-expects": ["off"],
7
+ "jest/no-duplicate-hooks": "off",
8
+ "jest/no-hooks": "off",
9
+ "jest/no-identical-title": "off",
10
+ "jest/no-standalone-expect": "off",
11
+ "jest/prefer-expect-assertions": "off",
12
+ "jest/prefer-strict-equal": "off",
13
+ "jest/require-hook": "off",
14
+ "jest/require-top-level-describe": "off"
15
+ }
16
+ }