jqtree 1.8.0 → 1.8.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 (60) hide show
  1. package/.eslintrc +13 -3
  2. package/.github/workflows/ci.yml +6 -6
  3. package/.github/workflows/codeql-analysis.yml +4 -4
  4. package/.github/workflows/size.yml +3 -3
  5. package/.github/workflows/static.yml +1 -1
  6. package/bower.json +1 -1
  7. package/config/jest.config.js +4 -0
  8. package/config/jest.polyfills.js +14 -0
  9. package/devserver/test_index.html +9 -0
  10. package/docs/.ruby-version +1 -1
  11. package/docs/_config.yml +1 -1
  12. package/docs/_entries/general/changelog.md +8 -0
  13. package/docs/_entries/multiple_selection/get-selected-nodes.md +1 -1
  14. package/docs/_entries/node/getnextnode.md +3 -6
  15. package/docs/_entries/node/getnextsibling.md +1 -1
  16. package/docs/_entries/node/getnextvisiblenode.md +8 -5
  17. package/docs/_entries/node/getpreviousnode.md +12 -0
  18. package/docs/_entries/node/getprevioussibling.md +1 -1
  19. package/docs/_entries/node/getpreviousvisiblenode.md +6 -5
  20. package/package.json +32 -30
  21. package/src/dataLoader.ts +19 -21
  22. package/src/dragAndDropHandler/dragElement.ts +37 -25
  23. package/src/dragAndDropHandler/generateHitAreas.ts +187 -0
  24. package/src/dragAndDropHandler/index.ts +32 -48
  25. package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
  26. package/src/dragAndDropHandler/types.ts +2 -1
  27. package/src/mouseHandler.ts +385 -0
  28. package/src/mouseUtils.ts +23 -0
  29. package/src/node.ts +1 -29
  30. package/src/nodeElement/folderElement.ts +1 -1
  31. package/src/nodeElement/ghostDropHint.ts +2 -1
  32. package/src/nodeElement/index.ts +2 -1
  33. package/src/playwright/coverage.ts +3 -3
  34. package/src/playwright/playwright.test.ts +150 -49
  35. package/src/playwright/testUtils.ts +28 -5
  36. package/src/position.ts +28 -0
  37. package/src/scrollHandler/containerScrollParent.ts +13 -23
  38. package/src/scrollHandler/createScrollParent.ts +22 -22
  39. package/src/scrollHandler/documentScrollParent.ts +16 -13
  40. package/src/scrollHandler.ts +6 -14
  41. package/src/test/jqTree/events.test.ts +97 -30
  42. package/src/test/jqTree/loadOnDemand.test.ts +22 -15
  43. package/src/test/jqTree/methods.test.ts +8 -11
  44. package/src/test/jqTree/mouse.test.ts +82 -0
  45. package/src/test/jqTree/options.test.ts +9 -8
  46. package/src/test/node.test.ts +2 -1
  47. package/src/test/{nodeUtil.test.ts → position.test.ts} +1 -1
  48. package/src/tree.jquery.ts +108 -184
  49. package/src/util.ts +10 -1
  50. package/src/version.ts +1 -1
  51. package/tree.jquery.debug.js +2167 -2134
  52. package/tree.jquery.debug.js.map +1 -1
  53. package/tree.jquery.js +3 -3
  54. package/tree.jquery.js.map +1 -1
  55. package/tsconfig.json +5 -3
  56. package/docs/_entries/functions/get-selected-nodes.md +0 -10
  57. package/src/dragAndDropHandler/hitAreasGenerator.ts +0 -175
  58. package/src/dragAndDropHandler/visibleNodeIterator.ts +0 -97
  59. package/src/mouse.widget.ts +0 -266
  60. package/src/mouseWidgetTypes.ts +0 -6
package/tsconfig.json CHANGED
@@ -4,8 +4,9 @@
4
4
  "include": ["src/**/*"],
5
5
  "compilerOptions": {
6
6
  "esModuleInterop": true,
7
- "lib": ["es2015", "es2015.iterable", "dom"],
8
- "moduleResolution": "node",
7
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
8
+ "module": "ESNext",
9
+ "moduleResolution": "bundler",
9
10
  "noEmit": true,
10
11
  "noFallthroughCasesInSwitch": true,
11
12
  "noImplicitAny": true,
@@ -17,6 +18,7 @@
17
18
  "rootDir": "src",
18
19
  "strictNullChecks": true,
19
20
  "strictPropertyInitialization": false,
20
- "strict": true
21
+ "strict": true,
22
+ "target": "ES2022",
21
23
  }
22
24
  }
@@ -1,10 +0,0 @@
1
- ---
2
- title: getSelectedNodes
3
- name: multiple-selection-get-selected-nodes
4
- ---
5
-
6
- Return a list of selected nodes.
7
-
8
- {% highlight js %}
9
- var nodes = $('#tree1').tree('getSelectedNodes');
10
- {% endhighlight %}
@@ -1,175 +0,0 @@
1
- import { HitArea } from "./types";
2
- import { Node, Position } from "../node";
3
- import { getOffsetTop } from "../util";
4
- import VisibleNodeIterator from "./visibleNodeIterator";
5
-
6
- class HitAreasGenerator extends VisibleNodeIterator {
7
- private currentNode: Node;
8
- private treeBottom: number;
9
- private positions: HitArea[];
10
- private lastTop: number;
11
-
12
- constructor(tree: Node, currentNode: Node, treeBottom: number) {
13
- super(tree);
14
-
15
- this.currentNode = currentNode;
16
- this.treeBottom = treeBottom;
17
- }
18
-
19
- public generate(): HitArea[] {
20
- this.positions = [];
21
- this.lastTop = 0;
22
-
23
- this.iterate();
24
-
25
- return this.generateHitAreas(this.positions);
26
- }
27
-
28
- protected generateHitAreas(positions: HitArea[]): HitArea[] {
29
- let previousTop = positions[0]?.top ?? 0;
30
- let group = [];
31
- const hitAreas: HitArea[] = [];
32
-
33
- for (const position of positions) {
34
- if (position.top !== previousTop && group.length) {
35
- this.generateHitAreasForGroup(
36
- hitAreas,
37
- group,
38
- previousTop,
39
- position.top,
40
- );
41
-
42
- previousTop = position.top;
43
- group = [];
44
- }
45
-
46
- group.push(position);
47
- }
48
-
49
- this.generateHitAreasForGroup(
50
- hitAreas,
51
- group,
52
- previousTop,
53
- this.treeBottom,
54
- );
55
-
56
- return hitAreas;
57
- }
58
-
59
- protected handleOpenFolder(node: Node, element: HTMLElement): boolean {
60
- if (node === this.currentNode) {
61
- // Cannot move inside current item
62
- // Stop iterating
63
- return false;
64
- }
65
-
66
- // Cannot move before current item
67
- if (node.children[0] !== this.currentNode) {
68
- this.addPosition(node, Position.Inside, getOffsetTop(element));
69
- }
70
-
71
- // Continue iterating
72
- return true;
73
- }
74
-
75
- protected handleClosedFolder(
76
- node: Node,
77
- nextNode: Node,
78
- element: HTMLElement,
79
- ): void {
80
- const top = getOffsetTop(element);
81
-
82
- if (node === this.currentNode) {
83
- // Cannot move after current item
84
- this.addPosition(node, Position.None, top);
85
- } else {
86
- this.addPosition(node, Position.Inside, top);
87
-
88
- // Cannot move before current item
89
- if (nextNode !== this.currentNode) {
90
- this.addPosition(node, Position.After, top);
91
- }
92
- }
93
- }
94
-
95
- protected handleFirstNode(node: Node): void {
96
- if (node !== this.currentNode) {
97
- this.addPosition(node, Position.Before, getOffsetTop(node.element));
98
- }
99
- }
100
-
101
- protected handleAfterOpenFolder(node: Node, nextNode: Node): void {
102
- if (node === this.currentNode || nextNode === this.currentNode) {
103
- // Cannot move before or after current item
104
- this.addPosition(node, Position.None, this.lastTop);
105
- } else {
106
- this.addPosition(node, Position.After, this.lastTop);
107
- }
108
- }
109
-
110
- protected handleNode(
111
- node: Node,
112
- nextNode: Node,
113
- element: HTMLElement,
114
- ): void {
115
- const top = getOffsetTop(element);
116
-
117
- if (node === this.currentNode) {
118
- // Cannot move inside current item
119
- this.addPosition(node, Position.None, top);
120
- } else {
121
- this.addPosition(node, Position.Inside, top);
122
- }
123
-
124
- if (nextNode === this.currentNode || node === this.currentNode) {
125
- // Cannot move before or after current item
126
- this.addPosition(node, Position.None, top);
127
- } else {
128
- this.addPosition(node, Position.After, top);
129
- }
130
- }
131
-
132
- private addPosition(node: Node, position: number, top: number): void {
133
- const area = {
134
- top,
135
- bottom: 0,
136
- node,
137
- position,
138
- };
139
-
140
- this.positions.push(area);
141
- this.lastTop = top;
142
- }
143
-
144
- private generateHitAreasForGroup(
145
- hitAreas: HitArea[],
146
- positionsInGroup: HitArea[],
147
- top: number,
148
- bottom: number,
149
- ): void {
150
- // limit positions in group
151
- const positionCount = Math.min(positionsInGroup.length, 4);
152
-
153
- const areaHeight = Math.round((bottom - top) / positionCount);
154
- let areaTop = top;
155
-
156
- let i = 0;
157
- while (i < positionCount) {
158
- const position = positionsInGroup[i];
159
-
160
- if (position) {
161
- hitAreas.push({
162
- top: areaTop,
163
- bottom: areaTop + areaHeight,
164
- node: position.node,
165
- position: position.position,
166
- });
167
- }
168
-
169
- areaTop += areaHeight;
170
- i += 1;
171
- }
172
- }
173
- }
174
-
175
- export default HitAreasGenerator;
@@ -1,97 +0,0 @@
1
- import { Node } from "../node";
2
-
3
- abstract class VisibleNodeIterator {
4
- private tree: Node;
5
-
6
- constructor(tree: Node) {
7
- this.tree = tree;
8
- }
9
-
10
- protected iterate(): void {
11
- let isFirstNode = true;
12
-
13
- const _iterateNode = (node: Node, nextNode: Node | null): void => {
14
- let mustIterateInside =
15
- (node.is_open || !node.element) && node.hasChildren();
16
-
17
- let element: HTMLElement | null = null;
18
-
19
- // Is the element visible?
20
- if (node.element?.offsetParent) {
21
- element = node.element;
22
-
23
- if (isFirstNode) {
24
- this.handleFirstNode(node);
25
- isFirstNode = false;
26
- }
27
-
28
- if (!node.hasChildren()) {
29
- this.handleNode(node, nextNode, node.element);
30
- } else if (node.is_open) {
31
- if (!this.handleOpenFolder(node, node.element)) {
32
- mustIterateInside = false;
33
- }
34
- } else {
35
- this.handleClosedFolder(node, nextNode, element);
36
- }
37
- }
38
-
39
- if (mustIterateInside) {
40
- const childrenLength = node.children.length;
41
- node.children.forEach((_, i) => {
42
- const child = node.children[i];
43
-
44
- if (child) {
45
- if (i === childrenLength - 1) {
46
- _iterateNode(child, null);
47
- } else {
48
- const nextChild = node.children[i + 1];
49
-
50
- if (nextChild) {
51
- _iterateNode(child, nextChild);
52
- }
53
- }
54
- }
55
- });
56
-
57
- if (node.is_open && element) {
58
- this.handleAfterOpenFolder(node, nextNode);
59
- }
60
- }
61
- };
62
-
63
- _iterateNode(this.tree, null);
64
- }
65
-
66
- protected abstract handleNode(
67
- node: Node,
68
- nextNode: Node | null,
69
- element: HTMLElement,
70
- ): void;
71
-
72
- /*
73
- override
74
- return
75
- - true: continue iterating
76
- - false: stop iterating
77
- */
78
- protected abstract handleOpenFolder(
79
- node: Node,
80
- element: HTMLElement,
81
- ): boolean;
82
-
83
- protected abstract handleClosedFolder(
84
- node: Node,
85
- nextNode: Node | null,
86
- element: HTMLElement,
87
- ): void;
88
-
89
- protected abstract handleAfterOpenFolder(
90
- node: Node,
91
- nextNode: Node | null,
92
- ): void;
93
-
94
- protected abstract handleFirstNode(node: Node): void;
95
- }
96
-
97
- export default VisibleNodeIterator;
@@ -1,266 +0,0 @@
1
- /*
2
- This widget does the same a the mouse widget in jqueryui.
3
- */
4
- import SimpleWidget from "./simple.widget";
5
- import { PositionInfo } from "./mouseWidgetTypes";
6
-
7
- const getPositionInfoFromMouseEvent = (e: MouseEvent): PositionInfo => ({
8
- pageX: e.pageX,
9
- pageY: e.pageY,
10
- target: e.target as HTMLElement,
11
- originalEvent: e,
12
- });
13
-
14
- const getPositionInfoFromTouch = (
15
- touch: Touch,
16
- e: TouchEvent,
17
- ): PositionInfo => ({
18
- pageX: touch.pageX,
19
- pageY: touch.pageY,
20
- target: touch.target as HTMLElement,
21
- originalEvent: e,
22
- });
23
-
24
- abstract class MouseWidget<WidgetOptions> extends SimpleWidget<WidgetOptions> {
25
- protected isMouseStarted: boolean;
26
- protected mouseDownInfo: PositionInfo | null;
27
- private mouseDelayTimer: number | null;
28
- private isMouseDelayMet: boolean;
29
-
30
- public init(): void {
31
- const element = this.$el.get(0);
32
-
33
- if (element) {
34
- element.addEventListener("mousedown", this.mouseDown, {
35
- passive: false,
36
- });
37
- element.addEventListener("touchstart", this.touchStart, {
38
- passive: false,
39
- });
40
- }
41
-
42
- this.isMouseStarted = false;
43
- this.mouseDelayTimer = null;
44
- this.isMouseDelayMet = false;
45
- this.mouseDownInfo = null;
46
- }
47
-
48
- public deinit(): void {
49
- const el = this.$el.get(0);
50
-
51
- if (el) {
52
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
53
- (el as any).removeEventListener("mousedown", this.mouseDown, {
54
- passive: false,
55
- });
56
-
57
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
58
- (el as any).removeEventListener("touchstart", this.touchStart, {
59
- passive: false,
60
- });
61
- }
62
-
63
- this.removeMouseMoveEventListeners();
64
- }
65
-
66
- protected abstract mouseCapture(positionInfo: PositionInfo): boolean | null;
67
-
68
- protected abstract mouseStart(positionInfo: PositionInfo): boolean;
69
-
70
- protected abstract mouseDrag(positionInfo: PositionInfo): void;
71
-
72
- protected abstract mouseStop(positionInfo: PositionInfo): void;
73
-
74
- protected abstract getMouseDelay(): number;
75
-
76
- private mouseDown = (e: MouseEvent): void => {
77
- // Left mouse button?
78
- if (e.button !== 0) {
79
- return;
80
- }
81
-
82
- const result = this.handleMouseDown(getPositionInfoFromMouseEvent(e));
83
-
84
- if (result && e.cancelable) {
85
- e.preventDefault();
86
- }
87
- };
88
-
89
- private handleMouseDown(positionInfo: PositionInfo): boolean {
90
- // We may have missed mouseup (out of window)
91
- if (this.isMouseStarted) {
92
- this.handleMouseUp(positionInfo);
93
- }
94
-
95
- this.mouseDownInfo = positionInfo;
96
-
97
- if (!this.mouseCapture(positionInfo)) {
98
- return false;
99
- }
100
-
101
- this.handleStartMouse();
102
-
103
- return true;
104
- }
105
-
106
- private handleStartMouse(): void {
107
- document.addEventListener("mousemove", this.mouseMove, {
108
- passive: false,
109
- });
110
- document.addEventListener("touchmove", this.touchMove, {
111
- passive: false,
112
- });
113
- document.addEventListener("mouseup", this.mouseUp, { passive: false });
114
- document.addEventListener("touchend", this.touchEnd, {
115
- passive: false,
116
- });
117
-
118
- const mouseDelay = this.getMouseDelay();
119
-
120
- if (mouseDelay) {
121
- this.startMouseDelayTimer(mouseDelay);
122
- } else {
123
- this.isMouseDelayMet = true;
124
- }
125
- }
126
-
127
- private startMouseDelayTimer(mouseDelay: number): void {
128
- if (this.mouseDelayTimer) {
129
- clearTimeout(this.mouseDelayTimer);
130
- }
131
-
132
- this.mouseDelayTimer = window.setTimeout(() => {
133
- if (this.mouseDownInfo) {
134
- this.isMouseDelayMet = true;
135
- }
136
- }, mouseDelay);
137
-
138
- this.isMouseDelayMet = false;
139
- }
140
-
141
- private mouseMove = (e: MouseEvent): void => {
142
- this.handleMouseMove(e, getPositionInfoFromMouseEvent(e));
143
- };
144
-
145
- private handleMouseMove(
146
- e: MouseEvent | TouchEvent,
147
- positionInfo: PositionInfo,
148
- ): void {
149
- if (this.isMouseStarted) {
150
- this.mouseDrag(positionInfo);
151
-
152
- if (e.cancelable) {
153
- e.preventDefault();
154
- }
155
- return;
156
- }
157
-
158
- if (!this.isMouseDelayMet) {
159
- return;
160
- }
161
-
162
- if (this.mouseDownInfo) {
163
- this.isMouseStarted = this.mouseStart(this.mouseDownInfo) !== false;
164
- }
165
-
166
- if (this.isMouseStarted) {
167
- this.mouseDrag(positionInfo);
168
-
169
- if (e.cancelable) {
170
- e.preventDefault();
171
- }
172
- } else {
173
- this.handleMouseUp(positionInfo);
174
- }
175
- }
176
-
177
- private mouseUp = (e: MouseEvent): void => {
178
- this.handleMouseUp(getPositionInfoFromMouseEvent(e));
179
- };
180
-
181
- private handleMouseUp(positionInfo: PositionInfo): void {
182
- this.removeMouseMoveEventListeners();
183
- this.isMouseDelayMet = false;
184
- this.mouseDownInfo = null;
185
-
186
- if (this.isMouseStarted) {
187
- this.isMouseStarted = false;
188
- this.mouseStop(positionInfo);
189
- }
190
- }
191
-
192
- private removeMouseMoveEventListeners() {
193
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
194
- (document as any).removeEventListener("mousemove", this.mouseMove, {
195
- passive: false,
196
- });
197
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
198
- (document as any).removeEventListener("touchmove", this.touchMove, {
199
- passive: false,
200
- });
201
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
202
- (document as any).removeEventListener("mouseup", this.mouseUp, {
203
- passive: false,
204
- });
205
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
206
- (document as any).removeEventListener("touchend", this.touchEnd, {
207
- passive: false,
208
- });
209
- }
210
-
211
- private touchStart = (e: TouchEvent): void => {
212
- if (!e) {
213
- return;
214
- }
215
-
216
- if (e.touches.length > 1) {
217
- return;
218
- }
219
-
220
- const touch = e.changedTouches[0];
221
-
222
- if (!touch) {
223
- return;
224
- }
225
-
226
- this.handleMouseDown(getPositionInfoFromTouch(touch, e));
227
- };
228
-
229
- private touchMove = (e: TouchEvent): void => {
230
- if (!e) {
231
- return;
232
- }
233
-
234
- if (e.touches.length > 1) {
235
- return;
236
- }
237
-
238
- const touch = e.changedTouches[0];
239
-
240
- if (!touch) {
241
- return;
242
- }
243
-
244
- this.handleMouseMove(e, getPositionInfoFromTouch(touch, e));
245
- };
246
-
247
- private touchEnd = (e: TouchEvent): void => {
248
- if (!e) {
249
- return;
250
- }
251
-
252
- if (e.touches.length > 1) {
253
- return;
254
- }
255
-
256
- const touch = e.changedTouches[0];
257
-
258
- if (!touch) {
259
- return;
260
- }
261
-
262
- this.handleMouseUp(getPositionInfoFromTouch(touch, e));
263
- };
264
- }
265
-
266
- export default MouseWidget;
@@ -1,6 +0,0 @@
1
- export interface PositionInfo {
2
- pageX: number | undefined;
3
- pageY: number | undefined;
4
- target: HTMLElement;
5
- originalEvent: Event;
6
- }