jqtree 1.6.3 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.github/workflows/ci.yml +15 -21
  2. package/.github/workflows/codeql-analysis.yml +2 -2
  3. package/README.md +1 -1
  4. package/bower.json +10 -3
  5. package/config/production +2 -2
  6. package/config/{rollup.config.js → rollup.config.mjs} +3 -8
  7. package/docs/Gemfile.lock +34 -37
  8. package/docs/_config.yml +1 -1
  9. package/docs/_entries/10_changelog.md +13 -0
  10. package/docs/_entries/93_getnextnode.md +4 -1
  11. package/docs/_entries/{95_getpreviousnode.md → 95_getnextvisiblenode.md} +1 -1
  12. package/docs/_entries/96_getpreviousnode.md +0 -0
  13. package/docs/_entries/98_getpreviousvisiblenode.md +14 -0
  14. package/docs/package.json +7 -7
  15. package/docs/pnpm-lock.yaml +413 -265
  16. package/docs/static/bower.json +2 -2
  17. package/docs/static/bower_components/fontawesome/css/all.min.css +6 -2
  18. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  19. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  20. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  21. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  22. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  23. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  24. package/docs/static/bower_components/fontawesome/webfonts/fa-v4compatibility.ttf +0 -0
  25. package/docs/static/bower_components/fontawesome/webfonts/fa-v4compatibility.woff2 +0 -0
  26. package/docs/static/bower_components/jquery/dist/jquery.js +944 -1121
  27. package/docs/static/bower_components/jquery/dist/jquery.min.js +2 -2
  28. package/docs/static/documentation.css +181 -159
  29. package/docs/static/example.css +0 -1
  30. package/docs/tree.jquery.js +3 -3
  31. package/lib/dataLoader.js +5 -31
  32. package/lib/dragAndDropHandler.js +40 -142
  33. package/lib/elementsRenderer.js +52 -72
  34. package/lib/keyHandler.js +8 -32
  35. package/lib/mouse.widget.js +24 -74
  36. package/lib/node.js +72 -134
  37. package/lib/nodeElement.js +24 -84
  38. package/lib/playwright/coverage.js +58 -97
  39. package/lib/playwright/playwright.test.js +148 -210
  40. package/lib/playwright/testUtils.js +116 -182
  41. package/lib/saveStateHandler.js +13 -62
  42. package/lib/scrollHandler.js +24 -77
  43. package/lib/selectNodeHandler.js +6 -25
  44. package/lib/simple.widget.js +20 -53
  45. package/lib/test/jqTree/accessibility.test.js +37 -0
  46. package/lib/test/jqTree/create.test.js +0 -4
  47. package/lib/test/jqTree/events.test.js +73 -84
  48. package/lib/test/jqTree/keyboard.test.js +0 -6
  49. package/lib/test/jqTree/loadOnDemand.test.js +84 -121
  50. package/lib/test/jqTree/methods.test.js +107 -150
  51. package/lib/test/jqTree/options.test.js +32 -54
  52. package/lib/test/node.test.js +134 -76
  53. package/lib/test/nodeUtil.test.js +0 -1
  54. package/lib/test/support/jqTreeMatchers.js +4 -9
  55. package/lib/test/support/setupTests.js +0 -4
  56. package/lib/test/support/testUtil.js +2 -11
  57. package/lib/test/support/treeStructure.js +0 -6
  58. package/lib/test/util.test.js +0 -1
  59. package/lib/tree.jquery.js +28 -239
  60. package/lib/util.js +0 -6
  61. package/lib/version.js +1 -1
  62. package/package.json +44 -47
  63. package/src/dragAndDropHandler.ts +24 -10
  64. package/src/elementsRenderer.ts +49 -42
  65. package/src/jqtreeOptions.ts +3 -3
  66. package/src/keyHandler.ts +3 -3
  67. package/src/mouse.widget.ts +12 -0
  68. package/src/node.ts +52 -16
  69. package/src/nodeElement.ts +27 -21
  70. package/src/saveStateHandler.ts +1 -1
  71. package/src/scrollHandler.ts +6 -2
  72. package/src/selectNodeHandler.ts +1 -1
  73. package/src/simple.widget.ts +2 -0
  74. package/src/test/.eslintrc +3 -1
  75. package/src/test/jqTree/accessibility.test.ts +25 -0
  76. package/src/test/jqTree/events.test.ts +79 -93
  77. package/src/test/jqTree/methods.test.ts +1 -1
  78. package/src/test/node.test.ts +152 -58
  79. package/src/test/nodeUtil.test.ts +1 -1
  80. package/src/tree.jquery.ts +7 -6
  81. package/src/version.ts +1 -1
  82. package/tree.jquery.debug.js +297 -904
  83. package/tree.jquery.debug.js.map +1 -1
  84. package/tree.jquery.js +3 -3
  85. package/tree.jquery.js.map +1 -1
  86. package/tsconfig.json +1 -0
  87. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.eot +0 -0
  88. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.svg +0 -3717
  89. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.woff +0 -0
  90. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.eot +0 -0
  91. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.svg +0 -801
  92. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.woff +0 -0
  93. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.eot +0 -0
  94. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.svg +0 -5028
  95. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.woff +0 -0
  96. /package/docs/_entries/{96_getprevioussibling.md → 97_getprevioussibling.md} +0 -0
  97. /package/docs/_entries/{97_parent.md → 99_parent.md} +0 -0
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.1";
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.3",
3
+ "version": "1.7.1",
4
4
  "description": "Tree widget for jQuery",
5
5
  "keywords": [
6
6
  "jquery-plugin",
@@ -16,66 +16,63 @@
16
16
  "scripts": {
17
17
  "ci": "pnpm lint && pnpm tsc && pnpm test",
18
18
  "jest": "jest --coverage --no-cache --verbose --config ./config/jest.config.js",
19
- "jest-watch": "jest --watch",
19
+ "jest-watch": "jest --watch --config ./config/jest.config.js",
20
20
  "lint": "eslint src/ --ext .ts,.tsx",
21
21
  "production": "./config/production",
22
- "devserver": "SERVE=true rollup --config config/rollup.config.js --watch",
23
- "devserver-with-coverage": "COVERAGE=true SERVE=true rollup --config config/rollup.config.js",
24
- "build-with-coverage": "COVERAGE=true rollup --config config/rollup.config.js",
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
25
  "prettier": "prettier src/*.ts --write --tab-width 4",
26
- "coveralls": "nyc report --reporter=text-lcov | coveralls",
27
26
  "tsc": "tsc --noEmit --project tsconfig.json",
28
- "merge-coverage": "cp jest-coverage/coverage-final.json .nyc_output/coverage_jsdom.json",
29
- "clean-coverage": "rm -rf .nyc_output && jest --clearCache",
30
- "print-coverage": "nyc report",
31
27
  "playwright": "pnpm build-with-coverage && playwright test --config config/playwright.config.js",
32
28
  "test": "pnpm jest && pnpm playwright"
33
29
  },
34
30
  "dependencies": {
35
- "jquery": "^3.6.0"
31
+ "jquery": "^3.7.0"
36
32
  },
37
33
  "devDependencies": {
38
- "@babel/cli": "^7.18.10",
39
- "@babel/core": "^7.18.10",
40
- "@babel/preset-env": "^7.18.10",
41
- "@babel/preset-typescript": "^7.18.6",
42
- "@playwright/test": "^1.24.2",
43
- "@rollup/plugin-babel": "^5.3.1",
44
- "@rollup/plugin-node-resolve": "^13.3.0",
45
- "@testing-library/dom": "^8.16.1",
46
- "@types/debug": "^4.1.7",
47
- "@types/jest": "^28.1.6",
48
- "@types/jquery": "^3.5.14",
49
- "@typescript-eslint/eslint-plugin": "^5.32.0",
50
- "@typescript-eslint/parser": "^5.32.0",
51
- "autoprefixer": "^10.4.8",
52
- "babel-jest": "^28.1.3",
34
+ "@babel/cli": "^7.22.9",
35
+ "@babel/core": "^7.22.9",
36
+ "@babel/preset-env": "^7.22.9",
37
+ "@babel/preset-typescript": "^7.22.5",
38
+ "@playwright/test": "^1.36.2",
39
+ "@rollup/plugin-babel": "^6.0.3",
40
+ "@rollup/plugin-node-resolve": "^15.1.0",
41
+ "@rollup/plugin-terser": "^0.4.3",
42
+ "@testing-library/dom": "^9.3.1",
43
+ "@types/debug": "^4.1.8",
44
+ "@types/jest": "^29.5.3",
45
+ "@types/jest-axe": "^3.5.5",
46
+ "@types/jquery": "^3.5.16",
47
+ "@types/node": "^20.4.7",
48
+ "@typescript-eslint/eslint-plugin": "^6.2.1",
49
+ "@typescript-eslint/parser": "^6.2.1",
50
+ "autoprefixer": "^10.4.14",
51
+ "babel-jest": "^29.6.2",
53
52
  "babel-plugin-istanbul": "^6.1.1",
54
- "coveralls": "^3.1.1",
55
- "eslint": "^8.21.0",
56
- "eslint-plugin-import": "^2.26.0",
57
- "eslint-plugin-jest": "^26.7.0",
58
- "eslint-plugin-playwright": "^0.10.0",
59
- "eslint-plugin-testing-library": "^5.6.0",
53
+ "eslint": "^8.46.0",
54
+ "eslint-plugin-import": "^2.28.0",
55
+ "eslint-plugin-jest": "^27.2.3",
56
+ "eslint-plugin-playwright": "^0.15.3",
57
+ "eslint-plugin-testing-library": "^5.11.0",
60
58
  "givens": "^1.3.9",
61
- "jest": "^28.1.3",
62
- "jest-environment-jsdom": "^28.1.3",
63
- "jest-extended": "^3.0.2",
59
+ "graphql": "^16.7.1",
60
+ "jest": "^29.6.2",
61
+ "jest-axe": "^8.0.0",
62
+ "jest-environment-jsdom": "^29.6.2",
63
+ "jest-extended": "^4.0.1",
64
64
  "jsonfile": "^6.1.0",
65
65
  "lodash.template": "^4.5.0",
66
- "msw": "^0.44.2",
67
- "nyc": "^15.1.0",
68
- "playwright": "^1.24.2",
69
- "postcss": "^8.4.16",
70
- "postcss-cli": "^10.0.0",
71
- "postcss-import": "^14.1.0",
66
+ "msw": "^1.2.3",
67
+ "postcss": "^8.4.27",
68
+ "postcss-cli": "^10.1.0",
69
+ "postcss-import": "^15.1.0",
72
70
  "postcss-load-config": "^4.0.1",
73
- "postcss-nested": "^5.0.6",
74
- "prettier": "^2.7.1",
75
- "rollup": "^2.77.2",
76
- "rollup-plugin-serve": "^2.0.0",
77
- "rollup-plugin-terser": "^7.0.2",
78
- "tslib": "^2.4.0",
79
- "typescript": "^4.7.4"
71
+ "postcss-nested": "^6.0.1",
72
+ "prettier": "^3.0.1",
73
+ "rollup": "^3.27.2",
74
+ "rollup-plugin-serve": "^2.0.2",
75
+ "tslib": "^2.6.1",
76
+ "typescript": "~5.1.6"
80
77
  }
81
78
  }
@@ -261,6 +261,10 @@ export class DragAndDropHandler {
261
261
  const mid = (low + high) >> 1;
262
262
  const area = this.hitAreas[mid];
263
263
 
264
+ if (!area) {
265
+ return null;
266
+ }
267
+
264
268
  if (y < area.top) {
265
269
  high = mid;
266
270
  } else if (y > area.bottom) {
@@ -433,10 +437,18 @@ abstract class VisibleNodeIterator {
433
437
  if (mustIterateInside) {
434
438
  const childrenLength = node.children.length;
435
439
  node.children.forEach((_, i) => {
436
- if (i === childrenLength - 1) {
437
- _iterateNode(node.children[i], null);
438
- } else {
439
- _iterateNode(node.children[i], node.children[i + 1]);
440
+ const child = node.children[i];
441
+
442
+ if (child) {
443
+ if (i === childrenLength - 1) {
444
+ _iterateNode(child, null);
445
+ } else {
446
+ const nextChild = node.children[i + 1];
447
+
448
+ if (nextChild) {
449
+ _iterateNode(child, nextChild);
450
+ }
451
+ }
440
452
  }
441
453
  });
442
454
 
@@ -639,12 +651,14 @@ export class HitAreasGenerator extends VisibleNodeIterator {
639
651
  while (i < positionCount) {
640
652
  const position = positionsInGroup[i];
641
653
 
642
- hitAreas.push({
643
- top: areaTop,
644
- bottom: areaTop + areaHeight,
645
- node: position.node,
646
- position: position.position,
647
- });
654
+ if (position) {
655
+ hitAreas.push({
656
+ top: areaTop,
657
+ bottom: areaTop + areaHeight,
658
+ node: position.node,
659
+ position: position.position,
660
+ });
661
+ }
648
662
 
649
663
  areaTop += areaHeight;
650
664
  i += 1;
@@ -5,8 +5,8 @@ import { JqTreeWidget } from "./tree.jquery";
5
5
  type IconElement = Text | Element;
6
6
 
7
7
  export default class ElementsRenderer {
8
- public openedIconElement: IconElement;
9
- public closedIconElement: IconElement;
8
+ public openedIconElement?: IconElement;
9
+ public closedIconElement?: IconElement;
10
10
  private treeWidget: JqTreeWidget;
11
11
 
12
12
  constructor(treeWidget: JqTreeWidget) {
@@ -32,12 +32,14 @@ export default class ElementsRenderer {
32
32
  const $element = this.treeWidget.element;
33
33
  $element.empty();
34
34
 
35
- this.createDomElements(
36
- $element[0],
37
- this.treeWidget.tree.children,
38
- true,
39
- 1
40
- );
35
+ if ($element[0]) {
36
+ this.createDomElements(
37
+ $element[0],
38
+ this.treeWidget.tree.children,
39
+ true,
40
+ 1
41
+ );
42
+ }
41
43
  }
42
44
 
43
45
  public renderFromNode(node: Node): void {
@@ -139,6 +141,18 @@ export default class ElementsRenderer {
139
141
  return li;
140
142
  }
141
143
 
144
+ private setTreeItemAriaAttributes(
145
+ element: HTMLElement,
146
+ name: string,
147
+ level: number,
148
+ isSelected: boolean
149
+ ) {
150
+ element.setAttribute("aria-label", name);
151
+ element.setAttribute("aria-level", `${level}`);
152
+ element.setAttribute("aria-selected", getBoolString(isSelected));
153
+ element.setAttribute("role", "treeitem");
154
+ }
155
+
142
156
  private createFolderLi(
143
157
  node: Node,
144
158
  level: number,
@@ -154,12 +168,12 @@ export default class ElementsRenderer {
154
168
  // li
155
169
  const li = document.createElement("li");
156
170
  li.className = `jqtree_common ${folderClasses}`;
157
- li.setAttribute("role", "presentation");
171
+ li.setAttribute("role", "none");
158
172
 
159
173
  // div
160
174
  const div = document.createElement("div");
161
175
  div.className = "jqtree-element jqtree_common";
162
- div.setAttribute("role", "presentation");
176
+ div.setAttribute("role", "none");
163
177
 
164
178
  li.appendChild(div);
165
179
 
@@ -167,25 +181,23 @@ export default class ElementsRenderer {
167
181
  const buttonLink = document.createElement("a");
168
182
  buttonLink.className = buttonClasses;
169
183
 
170
- buttonLink.appendChild(iconElement.cloneNode(true));
171
-
172
- buttonLink.setAttribute("role", "presentation");
173
- buttonLink.setAttribute("aria-hidden", "true");
184
+ if (iconElement) {
185
+ buttonLink.appendChild(iconElement.cloneNode(true));
186
+ }
174
187
 
175
188
  if (this.treeWidget.options.buttonLeft) {
176
189
  div.appendChild(buttonLink);
177
190
  }
178
191
 
179
192
  // title span
180
- div.appendChild(
181
- this.createTitleSpan(
182
- node.name,
183
- level,
184
- isSelected,
185
- node.is_open,
186
- true
187
- )
193
+ const titleSpan = this.createTitleSpan(
194
+ node.name,
195
+ isSelected,
196
+ true,
197
+ level
188
198
  );
199
+ titleSpan.setAttribute("aria-expanded", getBoolString(node.is_open));
200
+ div.appendChild(titleSpan);
189
201
 
190
202
  if (!this.treeWidget.options.buttonLeft) {
191
203
  div.appendChild(buttonLink);
@@ -210,35 +222,32 @@ export default class ElementsRenderer {
210
222
  // li
211
223
  const li = document.createElement("li");
212
224
  li.className = classString;
213
- li.setAttribute("role", "presentation");
225
+ li.setAttribute("role", "none");
214
226
 
215
227
  // div
216
228
  const div = document.createElement("div");
217
229
  div.className = "jqtree-element jqtree_common";
218
- div.setAttribute("role", "presentation");
230
+ div.setAttribute("role", "none");
219
231
 
220
232
  li.appendChild(div);
221
233
 
222
234
  // title span
223
- div.appendChild(
224
- this.createTitleSpan(
225
- node.name,
226
- level,
227
- isSelected,
228
- node.is_open,
229
- false
230
- )
235
+ const titleSpan = this.createTitleSpan(
236
+ node.name,
237
+ isSelected,
238
+ false,
239
+ level
231
240
  );
241
+ div.appendChild(titleSpan);
232
242
 
233
243
  return li;
234
244
  }
235
245
 
236
246
  private createTitleSpan(
237
247
  nodeName: string,
238
- level: number,
239
248
  isSelected: boolean,
240
- isOpen: boolean,
241
- isFolder: boolean
249
+ isFolder: boolean,
250
+ level: number
242
251
  ): HTMLSpanElement {
243
252
  const titleSpan = document.createElement("span");
244
253
 
@@ -254,12 +263,6 @@ export default class ElementsRenderer {
254
263
 
255
264
  titleSpan.className = classes;
256
265
 
257
- titleSpan.setAttribute("role", "treeitem");
258
- titleSpan.setAttribute("aria-level", `${level}`);
259
-
260
- titleSpan.setAttribute("aria-selected", getBoolString(isSelected));
261
- titleSpan.setAttribute("aria-expanded", getBoolString(isOpen));
262
-
263
266
  if (isSelected) {
264
267
  const tabIndex = this.treeWidget.options.tabIndex;
265
268
 
@@ -268,6 +271,8 @@ export default class ElementsRenderer {
268
271
  }
269
272
  }
270
273
 
274
+ this.setTreeItemAriaAttributes(titleSpan, nodeName, level, isSelected);
275
+
271
276
  if (this.treeWidget.options.autoEscape) {
272
277
  titleSpan.textContent = nodeName;
273
278
  } else {
@@ -311,7 +316,9 @@ export default class ElementsRenderer {
311
316
  return classes.join(" ");
312
317
  }
313
318
 
314
- private createButtonElement(value: string | Element): IconElement {
319
+ private createButtonElement(
320
+ value: string | Element
321
+ ): IconElement | undefined {
315
322
  if (typeof value === "string") {
316
323
  // convert value to html
317
324
  const div = document.createElement("div");
@@ -3,7 +3,7 @@ import { Node } from "./node";
3
3
  type CanMoveNodeTo = (
4
4
  node: Node,
5
5
  targetNode: Node,
6
- positionName: string
6
+ positionName: string,
7
7
  ) => boolean;
8
8
  type CreateLi = (node: Node, el: JQuery, isSelected: boolean) => void;
9
9
  type DataFilter = (data: unknown) => NodeData[];
@@ -13,11 +13,11 @@ type DragMethod = (node: Node, event: Event | Touch) => void;
13
13
  type HandleLoadingMethod = (
14
14
  isLoading: boolean,
15
15
  node: Node | null,
16
- $el: JQuery
16
+ $el: JQuery,
17
17
  ) => void;
18
18
 
19
19
  export interface JQTreeOptions {
20
- animationSpeed: string | number;
20
+ animationSpeed: JQuery.Duration;
21
21
  autoEscape: boolean;
22
22
  autoOpen: boolean | number;
23
23
  buttonLeft: boolean;
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);
@@ -219,6 +219,10 @@ abstract class MouseWidget<WidgetOptions> extends SimpleWidget<WidgetOptions> {
219
219
 
220
220
  const touch = e.changedTouches[0];
221
221
 
222
+ if (!touch) {
223
+ return;
224
+ }
225
+
222
226
  this.handleMouseDown(getPositionInfoFromTouch(touch, e));
223
227
  };
224
228
 
@@ -233,6 +237,10 @@ abstract class MouseWidget<WidgetOptions> extends SimpleWidget<WidgetOptions> {
233
237
 
234
238
  const touch = e.changedTouches[0];
235
239
 
240
+ if (!touch) {
241
+ return;
242
+ }
243
+
236
244
  this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
237
245
  };
238
246
 
@@ -247,6 +255,10 @@ abstract class MouseWidget<WidgetOptions> extends SimpleWidget<WidgetOptions> {
247
255
 
248
256
  const touch = e.changedTouches[0];
249
257
 
258
+ if (!touch) {
259
+ return;
260
+ }
261
+
250
262
  this.handleMouseUp(getPositionInfoFromTouch(touch, e));
251
263
  };
252
264
  }
package/src/node.ts CHANGED
@@ -518,7 +518,7 @@ export class Node implements INode {
518
518
  } else {
519
519
  const previousIndex = this.parent.getChildIndex(this) - 1;
520
520
  if (previousIndex >= 0) {
521
- return this.parent.children[previousIndex];
521
+ return this.parent.children[previousIndex] || null;
522
522
  } else {
523
523
  return null;
524
524
  }
@@ -531,7 +531,7 @@ export class Node implements INode {
531
531
  } else {
532
532
  const nextIndex = this.parent.getChildIndex(this) + 1;
533
533
  if (nextIndex < this.parent.children.length) {
534
- return this.parent.children[nextIndex];
534
+ return this.parent.children[nextIndex] || null;
535
535
  } else {
536
536
  return null;
537
537
  }
@@ -557,9 +557,25 @@ 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] || null;
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
- return this.children[0];
578
+ return this.children[0] || null;
563
579
  } else {
564
580
  if (!this.parent) {
565
581
  return null;
@@ -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
  }
@@ -615,10 +646,15 @@ export class Node implements INode {
615
646
  return null;
616
647
  } else {
617
648
  const lastChild = this.children[this.children.length - 1];
649
+
650
+ if (!lastChild) {
651
+ return null;
652
+ }
653
+
618
654
  if (!(lastChild.hasChildren() && lastChild.is_open)) {
619
655
  return lastChild;
620
656
  } else {
621
- return lastChild.getLastChild();
657
+ return lastChild?.getLastChild();
622
658
  }
623
659
  }
624
660
  }