jqtree 1.7.4 → 1.7.5
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.
- package/.eslintrc +5 -1
- package/bower.json +1 -1
- package/docs/_config.yml +1 -1
- package/docs/_entries/general/changelog.md +5 -0
- package/docs/package.json +1 -1
- package/docs/pnpm-lock.yaml +30 -30
- package/lib/dataLoader.js +2 -3
- package/lib/dragAndDropHandler.js +5 -13
- package/lib/elementsRenderer.js +2 -3
- package/lib/keyHandler.js +1 -5
- package/lib/mouse.widget.js +1 -2
- package/lib/node.js +30 -39
- package/lib/nodeElement.js +3 -6
- package/lib/nodeUtils.js +10 -0
- package/lib/playwright/coverage.js +14 -11
- package/lib/playwright/playwright.test.js +482 -104
- package/lib/playwright/testUtils.js +75 -49
- package/lib/saveStateHandler.js +2 -3
- package/lib/scrollHandler/containerScrollParent.js +160 -0
- package/lib/scrollHandler/createScrollParent.js +57 -0
- package/lib/scrollHandler/documentScrollParent.js +169 -0
- package/lib/scrollHandler/scrollParent.js +58 -0
- package/lib/scrollHandler/types.js +1 -0
- package/lib/scrollHandler.js +28 -207
- package/lib/selectNodeHandler.js +2 -3
- package/lib/simple.widget.js +1 -2
- package/lib/test/jqTree/loadOnDemand.test.js +3 -3
- package/lib/test/jqTree/methods.test.js +2 -1
- package/lib/test/jqTree/scrollHandler/containerScrollParent.test.js +94 -0
- package/lib/test/node.test.js +49 -7
- package/lib/test/nodeUtils.test.js +20 -0
- package/lib/test/support/exampleData.js +1 -2
- package/lib/test/support/testUtil.js +3 -6
- package/lib/test/support/treeStructure.js +1 -2
- package/lib/tree.jquery.js +6 -7
- package/lib/util.js +4 -7
- package/lib/version.js +2 -3
- package/package.json +27 -27
- package/src/dragAndDropHandler.ts +27 -33
- package/src/keyHandler.ts +0 -8
- package/src/node.ts +32 -48
- package/src/nodeUtils.ts +10 -0
- package/src/playwright/playwright.test.ts +207 -15
- package/src/playwright/testUtils.ts +23 -15
- package/src/scrollHandler/containerScrollParent.ts +177 -0
- package/src/scrollHandler/createScrollParent.ts +50 -0
- package/src/scrollHandler/documentScrollParent.ts +182 -0
- package/src/scrollHandler/types.ts +7 -0
- package/src/scrollHandler.ts +25 -243
- package/src/test/jqTree/loadOnDemand.test.ts +2 -3
- package/src/test/jqTree/methods.test.ts +1 -1
- package/src/test/node.test.ts +84 -25
- package/src/test/nodeUtils.test.ts +21 -0
- package/src/tree.jquery.ts +27 -30
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +391 -229
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +2 -2
- package/tree.jquery.js.map +1 -1
|
@@ -3,17 +3,12 @@ import {
|
|
|
3
3
|
dragAndDrop,
|
|
4
4
|
findNodeElement,
|
|
5
5
|
getTreeStructure,
|
|
6
|
+
moveMouseToNode,
|
|
6
7
|
selectNode,
|
|
7
8
|
} from "./testUtils";
|
|
8
9
|
import { initCoverage, saveCoverage } from "./coverage";
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
baseURL?: string;
|
|
12
|
-
dragAndDrop: boolean;
|
|
13
|
-
page: Page;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const initPage = async ({ baseURL, dragAndDrop, page }: InitPageParameters) => {
|
|
11
|
+
const initPage = async (page: Page, baseURL: string | undefined) => {
|
|
17
12
|
if (!baseURL) {
|
|
18
13
|
throw new Error("Missing baseURL");
|
|
19
14
|
}
|
|
@@ -23,21 +18,31 @@ const initPage = async ({ baseURL, dragAndDrop, page }: InitPageParameters) => {
|
|
|
23
18
|
|
|
24
19
|
page.on("console", (msg) => console.log(`console: ${msg.text()}`));
|
|
25
20
|
|
|
21
|
+
await page.evaluate(`
|
|
22
|
+
console.log(window.__coverage__ ? 'Coverage enabled' : 'Coverage not enabled');
|
|
23
|
+
`);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
interface InitTreeOptions {
|
|
27
|
+
autoOpen?: number;
|
|
28
|
+
dragAndDrop?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const initTree = async (
|
|
32
|
+
page: Page,
|
|
33
|
+
{ autoOpen, dragAndDrop }: InitTreeOptions,
|
|
34
|
+
) => {
|
|
26
35
|
await page.evaluate(`
|
|
27
36
|
const $tree = jQuery("#tree1");
|
|
28
37
|
|
|
29
38
|
$tree.tree({
|
|
30
39
|
animationSpeed: 0,
|
|
31
|
-
autoOpen: 0,
|
|
40
|
+
autoOpen: ${autoOpen || 0},
|
|
32
41
|
data: ExampleData.exampleData,
|
|
33
|
-
dragAndDrop: ${dragAndDrop},
|
|
42
|
+
dragAndDrop: ${dragAndDrop || false},
|
|
34
43
|
startDndDelay: 100,
|
|
35
44
|
});
|
|
36
45
|
`);
|
|
37
|
-
|
|
38
|
-
await page.evaluate(`
|
|
39
|
-
console.log(window.__coverage__ ? 'Coverage enabled' : 'Coverage not enabled');
|
|
40
|
-
`);
|
|
41
46
|
};
|
|
42
47
|
|
|
43
48
|
test.beforeEach(async ({ context }) => {
|
|
@@ -50,7 +55,8 @@ test.afterEach(async ({ context }) => {
|
|
|
50
55
|
|
|
51
56
|
test.describe("without dragAndDrop", () => {
|
|
52
57
|
test.beforeEach(async ({ baseURL, page }) => {
|
|
53
|
-
await initPage(
|
|
58
|
+
await initPage(page, baseURL);
|
|
59
|
+
await initTree(page, { dragAndDrop: false });
|
|
54
60
|
});
|
|
55
61
|
|
|
56
62
|
test("displays a tree", async ({ page }) => {
|
|
@@ -75,7 +81,8 @@ test.describe("without dragAndDrop", () => {
|
|
|
75
81
|
|
|
76
82
|
test.describe("with dragAndDrop", () => {
|
|
77
83
|
test.beforeEach(async ({ baseURL, page }) => {
|
|
78
|
-
await initPage(
|
|
84
|
+
await initPage(page, baseURL);
|
|
85
|
+
await initTree(page, { dragAndDrop: true });
|
|
79
86
|
});
|
|
80
87
|
|
|
81
88
|
test("moves a node", async ({ page }) => {
|
|
@@ -110,3 +117,188 @@ test.describe("with dragAndDrop", () => {
|
|
|
110
117
|
expect(screenshot).toMatchSnapshot();
|
|
111
118
|
});
|
|
112
119
|
});
|
|
120
|
+
|
|
121
|
+
test.describe("autoscroll when the window is scrollable", () => {
|
|
122
|
+
test("it scrolls vertically when the users drags an element to the bottom ", async ({
|
|
123
|
+
baseURL,
|
|
124
|
+
page,
|
|
125
|
+
}) => {
|
|
126
|
+
await page.setViewportSize({ width: 200, height: 100 });
|
|
127
|
+
await initPage(page, baseURL);
|
|
128
|
+
await initTree(page, { autoOpen: 3, dragAndDrop: true });
|
|
129
|
+
|
|
130
|
+
expect(
|
|
131
|
+
await page
|
|
132
|
+
.getByRole("document")
|
|
133
|
+
.evaluate((element) => element.scrollTop),
|
|
134
|
+
).toEqual(0);
|
|
135
|
+
|
|
136
|
+
await moveMouseToNode(page, "Saurischia");
|
|
137
|
+
await page.mouse.down();
|
|
138
|
+
|
|
139
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
140
|
+
await page.waitForTimeout(200);
|
|
141
|
+
|
|
142
|
+
await page.mouse.move(20, 190);
|
|
143
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
144
|
+
await page.waitForTimeout(50);
|
|
145
|
+
|
|
146
|
+
expect(
|
|
147
|
+
await page
|
|
148
|
+
.getByRole("document")
|
|
149
|
+
.evaluate((element) => element.scrollTop),
|
|
150
|
+
).toBeGreaterThan(0);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("it scrolls horizontally when the users drags an element to the right", async ({
|
|
154
|
+
baseURL,
|
|
155
|
+
page,
|
|
156
|
+
}) => {
|
|
157
|
+
await page.setViewportSize({ width: 60, height: 400 });
|
|
158
|
+
await initPage(page, baseURL);
|
|
159
|
+
await initTree(page, { autoOpen: 3, dragAndDrop: true });
|
|
160
|
+
|
|
161
|
+
expect(
|
|
162
|
+
await page
|
|
163
|
+
.getByRole("document")
|
|
164
|
+
.evaluate((element) => element.scrollLeft),
|
|
165
|
+
).toEqual(0);
|
|
166
|
+
|
|
167
|
+
await moveMouseToNode(page, "Saurischia");
|
|
168
|
+
await page.mouse.down();
|
|
169
|
+
|
|
170
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
171
|
+
await page.waitForTimeout(200);
|
|
172
|
+
|
|
173
|
+
await page.mouse.move(55, 10);
|
|
174
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
175
|
+
await page.waitForTimeout(50);
|
|
176
|
+
|
|
177
|
+
expect(
|
|
178
|
+
await page
|
|
179
|
+
.getByRole("document")
|
|
180
|
+
.evaluate((element) => element.scrollLeft),
|
|
181
|
+
).toBeGreaterThan(0);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("scrollToNode scrolls to a node", async ({ baseURL, page }) => {
|
|
185
|
+
await page.setViewportSize({ width: 200, height: 100 });
|
|
186
|
+
await initPage(page, baseURL);
|
|
187
|
+
await initTree(page, { autoOpen: 3, dragAndDrop: true });
|
|
188
|
+
|
|
189
|
+
expect(
|
|
190
|
+
await page
|
|
191
|
+
.getByRole("document")
|
|
192
|
+
.evaluate((element) => element.scrollTop),
|
|
193
|
+
).toEqual(0);
|
|
194
|
+
|
|
195
|
+
await page.evaluate(`
|
|
196
|
+
const $tree = jQuery("#tree1");
|
|
197
|
+
const node = $tree.tree("getNodeByName", "Sauropodomorphs");
|
|
198
|
+
$tree.tree("scrollToNode",node);
|
|
199
|
+
`);
|
|
200
|
+
|
|
201
|
+
expect(
|
|
202
|
+
await page
|
|
203
|
+
.getByRole("document")
|
|
204
|
+
.evaluate((element) => element.scrollTop),
|
|
205
|
+
).toBeGreaterThan(0);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test.describe("autoscroll when the container is scrollable", () => {
|
|
210
|
+
test.beforeEach(async ({ page, baseURL }) => {
|
|
211
|
+
await initPage(page, baseURL);
|
|
212
|
+
|
|
213
|
+
// Add a container and make it the parent of the tree element
|
|
214
|
+
await page.evaluate(`
|
|
215
|
+
document.body.style.marginLeft = "40px";
|
|
216
|
+
document.body.style.marginTop = "40px";
|
|
217
|
+
|
|
218
|
+
const treeElement = document.querySelector("#tree1");
|
|
219
|
+
|
|
220
|
+
const container = document.createElement("div");
|
|
221
|
+
container.id = "container";
|
|
222
|
+
container.style.height = "200px";
|
|
223
|
+
container.style.width = "60px";
|
|
224
|
+
container.style.overflowY = "scroll";
|
|
225
|
+
|
|
226
|
+
document.body.replaceChild(container, treeElement);
|
|
227
|
+
container.appendChild(treeElement);
|
|
228
|
+
`);
|
|
229
|
+
|
|
230
|
+
await initTree(page, { autoOpen: 3, dragAndDrop: true });
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("it scrolls vertically when the users drags an element to the bottom", async ({
|
|
234
|
+
page,
|
|
235
|
+
}) => {
|
|
236
|
+
expect(
|
|
237
|
+
await page
|
|
238
|
+
.locator("#container")
|
|
239
|
+
.evaluate((element) => element.scrollTop),
|
|
240
|
+
).toEqual(0);
|
|
241
|
+
|
|
242
|
+
await moveMouseToNode(page, "Saurischia");
|
|
243
|
+
await page.mouse.down();
|
|
244
|
+
|
|
245
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
246
|
+
await page.waitForTimeout(200);
|
|
247
|
+
|
|
248
|
+
await page.mouse.move(20, 245);
|
|
249
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
250
|
+
await page.waitForTimeout(50);
|
|
251
|
+
|
|
252
|
+
expect(
|
|
253
|
+
await page
|
|
254
|
+
.locator("#container")
|
|
255
|
+
.evaluate((element) => element.scrollTop),
|
|
256
|
+
).toBeGreaterThan(0);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test("it scrolls horizontally when the users drags an element to the right", async ({
|
|
260
|
+
page,
|
|
261
|
+
}) => {
|
|
262
|
+
expect(
|
|
263
|
+
await page
|
|
264
|
+
.locator("#container")
|
|
265
|
+
.evaluate((element) => element.scrollLeft),
|
|
266
|
+
).toEqual(0);
|
|
267
|
+
|
|
268
|
+
await moveMouseToNode(page, "Saurischia");
|
|
269
|
+
await page.mouse.down();
|
|
270
|
+
|
|
271
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
272
|
+
await page.waitForTimeout(200);
|
|
273
|
+
|
|
274
|
+
await page.mouse.move(100, 50);
|
|
275
|
+
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
276
|
+
await page.waitForTimeout(50);
|
|
277
|
+
|
|
278
|
+
expect(
|
|
279
|
+
await page
|
|
280
|
+
.locator("#container")
|
|
281
|
+
.evaluate((element) => element.scrollLeft),
|
|
282
|
+
).toBeGreaterThan(0);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("scrollToNode scrolls to a node", async ({ page }) => {
|
|
286
|
+
expect(
|
|
287
|
+
await page
|
|
288
|
+
.locator("#container")
|
|
289
|
+
.evaluate((element) => element.scrollTop),
|
|
290
|
+
).toEqual(0);
|
|
291
|
+
|
|
292
|
+
await page.evaluate(`
|
|
293
|
+
const $tree = jQuery("#tree1");
|
|
294
|
+
const node = $tree.tree("getNodeByName", "Sauropodomorphs");
|
|
295
|
+
$tree.tree("scrollToNode",node);
|
|
296
|
+
`);
|
|
297
|
+
|
|
298
|
+
expect(
|
|
299
|
+
await page
|
|
300
|
+
.locator("#container")
|
|
301
|
+
.evaluate((element) => element.scrollTop),
|
|
302
|
+
).toBeGreaterThan(0);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Page, ElementHandle } from "@playwright/test";
|
|
2
2
|
|
|
3
|
+
interface BoundingBox {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
const locateTitle = (page: Page, title: string) =>
|
|
4
11
|
page.locator(".jqtree-title", {
|
|
5
12
|
hasText: title,
|
|
@@ -35,7 +42,9 @@ export const selectNode = async (nodeElement: ElementHandle) => {
|
|
|
35
42
|
await titleHandle.click();
|
|
36
43
|
};
|
|
37
44
|
|
|
38
|
-
const getRect = async (
|
|
45
|
+
const getRect = async (
|
|
46
|
+
elementHandle: ElementHandle<HTMLElement>,
|
|
47
|
+
): Promise<BoundingBox> => {
|
|
39
48
|
const boundingBox = await elementHandle.boundingBox();
|
|
40
49
|
|
|
41
50
|
if (!boundingBox) {
|
|
@@ -88,7 +97,7 @@ export const getTreeStructure = async (page: Page) => {
|
|
|
88
97
|
return JSON.parse(structure) as JQTreeMatchers.TreeStructure;
|
|
89
98
|
};
|
|
90
99
|
|
|
91
|
-
const getNodeRect = async (page: Page, title: string) => {
|
|
100
|
+
const getNodeRect = async (page: Page, title: string): Promise<BoundingBox> => {
|
|
92
101
|
const titleElement = await locateTitle(page, title).elementHandle();
|
|
93
102
|
|
|
94
103
|
if (!titleElement) {
|
|
@@ -99,24 +108,23 @@ const getNodeRect = async (page: Page, title: string) => {
|
|
|
99
108
|
return rect;
|
|
100
109
|
};
|
|
101
110
|
|
|
111
|
+
export const moveMouseToNode = async (page: Page, title: string) => {
|
|
112
|
+
const rect = await getNodeRect(page, title);
|
|
113
|
+
|
|
114
|
+
await page.mouse.move(rect.x + 10, rect.y + rect.height / 2);
|
|
115
|
+
};
|
|
116
|
+
|
|
102
117
|
export const dragAndDrop = async (
|
|
103
118
|
page: Page,
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
fromTitle: string,
|
|
120
|
+
toTitle: string,
|
|
106
121
|
): Promise<void> => {
|
|
107
|
-
|
|
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
|
-
);
|
|
122
|
+
await moveMouseToNode(page, fromTitle);
|
|
114
123
|
await page.mouse.down();
|
|
124
|
+
|
|
115
125
|
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
116
126
|
await page.waitForTimeout(200);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
toRect.y + toRect.height / 2
|
|
120
|
-
);
|
|
127
|
+
|
|
128
|
+
await moveMouseToNode(page, toTitle);
|
|
121
129
|
await page.mouse.up();
|
|
122
130
|
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { ScrollParent } from "./types";
|
|
2
|
+
|
|
3
|
+
type HorizontalScrollDirection = "left" | "right";
|
|
4
|
+
type VerticalScrollDirection = "bottom" | "top";
|
|
5
|
+
|
|
6
|
+
interface Params {
|
|
7
|
+
$container: JQuery<HTMLElement>;
|
|
8
|
+
refreshHitAreas: () => void;
|
|
9
|
+
$treeElement: JQuery<HTMLElement>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default class ContainerScrollParent implements ScrollParent {
|
|
13
|
+
private $container: JQuery<HTMLElement>;
|
|
14
|
+
private horizontalScrollDirection?: HorizontalScrollDirection;
|
|
15
|
+
private horizontalScrollTimeout?: number;
|
|
16
|
+
private refreshHitAreas: () => void;
|
|
17
|
+
private scrollParentBottom?: number;
|
|
18
|
+
private scrollParentTop?: number;
|
|
19
|
+
private verticalScrollTimeout?: number;
|
|
20
|
+
private verticalScrollDirection?: VerticalScrollDirection;
|
|
21
|
+
|
|
22
|
+
constructor({ $container, refreshHitAreas }: Params) {
|
|
23
|
+
this.$container = $container;
|
|
24
|
+
this.refreshHitAreas = refreshHitAreas;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public checkHorizontalScrolling(pageX: number): void {
|
|
28
|
+
const newHorizontalScrollDirection =
|
|
29
|
+
this.getNewHorizontalScrollDirection(pageX);
|
|
30
|
+
|
|
31
|
+
if (this.horizontalScrollDirection !== newHorizontalScrollDirection) {
|
|
32
|
+
this.horizontalScrollDirection = newHorizontalScrollDirection;
|
|
33
|
+
|
|
34
|
+
if (this.horizontalScrollTimeout != null) {
|
|
35
|
+
window.clearTimeout(this.verticalScrollTimeout);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (newHorizontalScrollDirection) {
|
|
39
|
+
this.horizontalScrollTimeout = window.setTimeout(
|
|
40
|
+
this.scrollHorizontally.bind(this),
|
|
41
|
+
40,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public checkVerticalScrolling(pageY: number) {
|
|
48
|
+
const newVerticalScrollDirection =
|
|
49
|
+
this.getNewVerticalScrollDirection(pageY);
|
|
50
|
+
|
|
51
|
+
if (this.verticalScrollDirection !== newVerticalScrollDirection) {
|
|
52
|
+
this.verticalScrollDirection = newVerticalScrollDirection;
|
|
53
|
+
|
|
54
|
+
if (this.verticalScrollTimeout != null) {
|
|
55
|
+
window.clearTimeout(this.verticalScrollTimeout);
|
|
56
|
+
this.verticalScrollTimeout = undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (newVerticalScrollDirection) {
|
|
60
|
+
this.verticalScrollTimeout = window.setTimeout(
|
|
61
|
+
this.scrollVertically.bind(this),
|
|
62
|
+
40,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public getScrollLeft(): number {
|
|
69
|
+
return this.$container.scrollLeft() || 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public scrollToY(top: number): void {
|
|
73
|
+
const container = this.$container.get(0) as HTMLElement;
|
|
74
|
+
container.scrollTop = top;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public stopScrolling() {
|
|
78
|
+
this.horizontalScrollDirection = undefined;
|
|
79
|
+
this.verticalScrollDirection = undefined;
|
|
80
|
+
this.scrollParentTop = undefined;
|
|
81
|
+
this.scrollParentBottom = undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private getNewHorizontalScrollDirection(
|
|
85
|
+
pageX: number,
|
|
86
|
+
): HorizontalScrollDirection | undefined {
|
|
87
|
+
const scrollParentOffset = this.$container.offset();
|
|
88
|
+
if (!scrollParentOffset) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const container = this.$container.get(0) as HTMLElement;
|
|
93
|
+
|
|
94
|
+
const rightEdge = scrollParentOffset.left + container.clientWidth;
|
|
95
|
+
const leftEdge = scrollParentOffset.left;
|
|
96
|
+
const isNearRightEdge = pageX > rightEdge - 20;
|
|
97
|
+
const isNearLeftEdge = pageX < leftEdge + 20;
|
|
98
|
+
|
|
99
|
+
if (isNearRightEdge) {
|
|
100
|
+
return "right";
|
|
101
|
+
} else if (isNearLeftEdge) {
|
|
102
|
+
return "left";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private getNewVerticalScrollDirection(
|
|
109
|
+
pageY: number,
|
|
110
|
+
): VerticalScrollDirection | undefined {
|
|
111
|
+
if (pageY < this.getScrollParentTop()) {
|
|
112
|
+
return "top";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (pageY > this.getScrollParentBottom()) {
|
|
116
|
+
return "bottom";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private scrollHorizontally() {
|
|
123
|
+
if (!this.horizontalScrollDirection) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const distance = this.horizontalScrollDirection === "left" ? -20 : 20;
|
|
128
|
+
const container = this.$container.get(0) as HTMLElement;
|
|
129
|
+
|
|
130
|
+
container.scrollBy({
|
|
131
|
+
left: distance,
|
|
132
|
+
top: 0,
|
|
133
|
+
behavior: "instant",
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
this.refreshHitAreas();
|
|
137
|
+
|
|
138
|
+
setTimeout(this.scrollHorizontally.bind(this), 40);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private scrollVertically() {
|
|
142
|
+
if (!this.verticalScrollDirection) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const distance = this.verticalScrollDirection === "top" ? -20 : 20;
|
|
147
|
+
const container = this.$container.get(0) as HTMLElement;
|
|
148
|
+
|
|
149
|
+
container.scrollBy({
|
|
150
|
+
left: 0,
|
|
151
|
+
top: distance,
|
|
152
|
+
behavior: "instant",
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
this.refreshHitAreas();
|
|
156
|
+
|
|
157
|
+
setTimeout(this.scrollVertically.bind(this), 40);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private getScrollParentTop() {
|
|
161
|
+
if (this.scrollParentTop == null) {
|
|
162
|
+
this.scrollParentTop = this.$container.offset()?.top || 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return this.scrollParentTop;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private getScrollParentBottom() {
|
|
169
|
+
if (this.scrollParentBottom == null) {
|
|
170
|
+
this.scrollParentBottom =
|
|
171
|
+
this.getScrollParentTop() +
|
|
172
|
+
(this.$container.innerHeight() ?? 0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return this.scrollParentBottom;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ScrollParent } from "./types";
|
|
2
|
+
import ContainerScrollParent from "./containerScrollParent";
|
|
3
|
+
import DocumentScrollParent from "./documentScrollParent";
|
|
4
|
+
|
|
5
|
+
const hasOverFlow = ($element: JQuery<HTMLElement>): boolean => {
|
|
6
|
+
for (const attr of ["overflow", "overflow-y"]) {
|
|
7
|
+
const overflowValue = $element.css(attr);
|
|
8
|
+
if (overflowValue === "auto" || overflowValue === "scroll") {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return false;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getParentWithOverflow = (
|
|
17
|
+
$treeElement: JQuery<HTMLElement>,
|
|
18
|
+
): JQuery<HTMLElement> | null => {
|
|
19
|
+
if (hasOverFlow($treeElement)) {
|
|
20
|
+
return $treeElement;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const element of $treeElement.parents().get()) {
|
|
24
|
+
const $element = jQuery(element);
|
|
25
|
+
if (hasOverFlow($element)) {
|
|
26
|
+
return $element;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const createScrollParent = (
|
|
34
|
+
$treeElement: JQuery<HTMLElement>,
|
|
35
|
+
refreshHitAreas: () => void,
|
|
36
|
+
): ScrollParent => {
|
|
37
|
+
const $container = getParentWithOverflow($treeElement);
|
|
38
|
+
|
|
39
|
+
if ($container?.length && $container[0]?.tagName !== "HTML") {
|
|
40
|
+
return new ContainerScrollParent({
|
|
41
|
+
$container,
|
|
42
|
+
refreshHitAreas,
|
|
43
|
+
$treeElement,
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
return new DocumentScrollParent($treeElement, refreshHitAreas);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default createScrollParent;
|