jqtree 1.8.0 → 1.8.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.
- package/.eslintrc +13 -3
- package/.github/workflows/ci.yml +6 -6
- package/.github/workflows/codeql-analysis.yml +4 -4
- package/.github/workflows/size.yml +3 -3
- package/.github/workflows/static.yml +1 -1
- package/bower.json +1 -1
- package/config/jest.config.js +4 -0
- package/config/jest.polyfills.js +14 -0
- package/devserver/test_index.html +9 -0
- package/docs/.ruby-version +1 -1
- package/docs/_config.yml +1 -1
- package/docs/_entries/general/changelog.md +4 -0
- package/docs/_entries/multiple_selection/get-selected-nodes.md +1 -1
- package/docs/_entries/node/getnextnode.md +3 -6
- package/docs/_entries/node/getnextsibling.md +1 -1
- package/docs/_entries/node/getnextvisiblenode.md +8 -5
- package/docs/_entries/node/getpreviousnode.md +12 -0
- package/docs/_entries/node/getprevioussibling.md +1 -1
- package/docs/_entries/node/getpreviousvisiblenode.md +6 -5
- package/package.json +32 -30
- package/src/dataLoader.ts +19 -21
- package/src/dragAndDropHandler/dragElement.ts +37 -25
- package/src/dragAndDropHandler/generateHitAreas.ts +176 -0
- package/src/dragAndDropHandler/index.ts +32 -48
- package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
- package/src/dragAndDropHandler/types.ts +2 -1
- package/src/mouseHandler.ts +385 -0
- package/src/mouseUtils.ts +23 -0
- package/src/node.ts +1 -29
- package/src/nodeElement/folderElement.ts +1 -1
- package/src/nodeElement/ghostDropHint.ts +2 -1
- package/src/nodeElement/index.ts +2 -1
- package/src/playwright/coverage.ts +3 -3
- package/src/playwright/playwright.test.ts +150 -49
- package/src/playwright/testUtils.ts +28 -5
- package/src/position.ts +28 -0
- package/src/scrollHandler/containerScrollParent.ts +13 -23
- package/src/scrollHandler/createScrollParent.ts +22 -22
- package/src/scrollHandler/documentScrollParent.ts +16 -13
- package/src/scrollHandler.ts +6 -14
- package/src/test/jqTree/events.test.ts +97 -30
- package/src/test/jqTree/loadOnDemand.test.ts +22 -15
- package/src/test/jqTree/methods.test.ts +8 -11
- package/src/test/jqTree/mouse.test.ts +82 -0
- package/src/test/jqTree/options.test.ts +9 -8
- package/src/test/node.test.ts +2 -1
- package/src/test/{nodeUtil.test.ts → position.test.ts} +1 -1
- package/src/tree.jquery.ts +108 -184
- package/src/util.ts +10 -1
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +2158 -2135
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +3 -3
- package/tree.jquery.js.map +1 -1
- package/tsconfig.json +5 -3
- package/docs/_entries/functions/get-selected-nodes.md +0 -10
- package/src/dragAndDropHandler/hitAreasGenerator.ts +0 -175
- package/src/dragAndDropHandler/visibleNodeIterator.ts +0 -97
- package/src/mouse.widget.ts +0 -266
- package/src/mouseWidgetTypes.ts +0 -6
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { test, expect, Page } from "@playwright/test";
|
|
2
2
|
import {
|
|
3
|
+
boundingBox,
|
|
3
4
|
dragAndDrop,
|
|
4
5
|
findNodeElement,
|
|
6
|
+
getNodeRect,
|
|
7
|
+
getSelectedNodeName,
|
|
5
8
|
getTreeStructure,
|
|
6
9
|
moveMouseToNode,
|
|
7
10
|
selectNode,
|
|
11
|
+
sleep,
|
|
8
12
|
} from "./testUtils";
|
|
9
13
|
import { initCoverage, saveCoverage } from "./coverage";
|
|
10
14
|
|
|
@@ -70,6 +74,8 @@ test.describe("without dragAndDrop", () => {
|
|
|
70
74
|
const saurischia = await findNodeElement(page, "Saurischia");
|
|
71
75
|
await selectNode(saurischia);
|
|
72
76
|
|
|
77
|
+
expect(await getSelectedNodeName(page)).toBe("Saurischia");
|
|
78
|
+
|
|
73
79
|
const screenshot = await page.screenshot();
|
|
74
80
|
expect(screenshot).toMatchSnapshot();
|
|
75
81
|
});
|
|
@@ -112,10 +118,54 @@ test.describe("with dragAndDrop", () => {
|
|
|
112
118
|
const screenshot = await page.screenshot();
|
|
113
119
|
expect(screenshot).toMatchSnapshot();
|
|
114
120
|
});
|
|
121
|
+
|
|
122
|
+
test("moves a node with touch events", async ({ page }) => {
|
|
123
|
+
const client = await page.context().newCDPSession(page);
|
|
124
|
+
|
|
125
|
+
const box1 = await getNodeRect(page, "Herrerasaurians");
|
|
126
|
+
|
|
127
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
128
|
+
type: "touchStart",
|
|
129
|
+
touchPoints: [{ x: box1.x + 10, y: box1.y + box1.height / 2 }],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await sleep(page, 200);
|
|
133
|
+
|
|
134
|
+
const box2 = await getNodeRect(page, "Ornithischians");
|
|
135
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
136
|
+
type: "touchEnd",
|
|
137
|
+
touchPoints: [{ x: box2.x + 10, y: box2.y + box2.height / 2 }],
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const structure = await getTreeStructure(page);
|
|
141
|
+
|
|
142
|
+
expect(structure).toEqual([
|
|
143
|
+
expect.objectContaining({
|
|
144
|
+
name: "Saurischia",
|
|
145
|
+
children: [
|
|
146
|
+
expect.objectContaining({ name: "Theropods" }),
|
|
147
|
+
expect.objectContaining({ name: "Sauropodomorphs" }),
|
|
148
|
+
],
|
|
149
|
+
}),
|
|
150
|
+
expect.objectContaining({
|
|
151
|
+
name: "Ornithischians",
|
|
152
|
+
children: [
|
|
153
|
+
expect.objectContaining({ name: "Herrerasaurians" }),
|
|
154
|
+
expect.objectContaining({ name: "Heterodontosaurids" }),
|
|
155
|
+
expect.objectContaining({ name: "Thyreophorans" }),
|
|
156
|
+
expect.objectContaining({ name: "Ornithopods" }),
|
|
157
|
+
expect.objectContaining({
|
|
158
|
+
name: "Pachycephalosaurians",
|
|
159
|
+
}),
|
|
160
|
+
expect.objectContaining({ name: "Ceratopsians" }),
|
|
161
|
+
],
|
|
162
|
+
}),
|
|
163
|
+
]);
|
|
164
|
+
});
|
|
115
165
|
});
|
|
116
166
|
|
|
117
167
|
test.describe("autoscroll when the window is scrollable", () => {
|
|
118
|
-
test("it scrolls vertically when the users drags an element to the bottom
|
|
168
|
+
test("it scrolls vertically when the users drags an element to the bottom", async ({
|
|
119
169
|
baseURL,
|
|
120
170
|
page,
|
|
121
171
|
}) => {
|
|
@@ -132,12 +182,10 @@ test.describe("autoscroll when the window is scrollable", () => {
|
|
|
132
182
|
await moveMouseToNode(page, "Saurischia");
|
|
133
183
|
await page.mouse.down();
|
|
134
184
|
|
|
135
|
-
|
|
136
|
-
await page.waitForTimeout(200);
|
|
185
|
+
await sleep(page, 200);
|
|
137
186
|
|
|
138
187
|
await page.mouse.move(20, 190);
|
|
139
|
-
|
|
140
|
-
await page.waitForTimeout(50);
|
|
188
|
+
await sleep(page, 50);
|
|
141
189
|
|
|
142
190
|
expect(
|
|
143
191
|
await page
|
|
@@ -162,13 +210,10 @@ test.describe("autoscroll when the window is scrollable", () => {
|
|
|
162
210
|
|
|
163
211
|
await moveMouseToNode(page, "Saurischia");
|
|
164
212
|
await page.mouse.down();
|
|
165
|
-
|
|
166
|
-
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
167
|
-
await page.waitForTimeout(200);
|
|
213
|
+
await sleep(page, 200);
|
|
168
214
|
|
|
169
215
|
await page.mouse.move(55, 10);
|
|
170
|
-
|
|
171
|
-
await page.waitForTimeout(50);
|
|
216
|
+
await sleep(page, 50);
|
|
172
217
|
|
|
173
218
|
expect(
|
|
174
219
|
await page
|
|
@@ -202,7 +247,7 @@ test.describe("autoscroll when the window is scrollable", () => {
|
|
|
202
247
|
});
|
|
203
248
|
});
|
|
204
249
|
|
|
205
|
-
test.describe("autoscroll when the container is scrollable", () => {
|
|
250
|
+
test.describe("autoscroll when the container is scrollable vertically", () => {
|
|
206
251
|
test.beforeEach(async ({ page, baseURL }) => {
|
|
207
252
|
await initPage(page, baseURL);
|
|
208
253
|
|
|
@@ -216,7 +261,6 @@ test.describe("autoscroll when the container is scrollable", () => {
|
|
|
216
261
|
const container = document.createElement("div");
|
|
217
262
|
container.id = "container";
|
|
218
263
|
container.style.height = "200px";
|
|
219
|
-
container.style.width = "60px";
|
|
220
264
|
container.style.overflowY = "scroll";
|
|
221
265
|
|
|
222
266
|
document.body.replaceChild(container, treeElement);
|
|
@@ -229,72 +273,129 @@ test.describe("autoscroll when the container is scrollable", () => {
|
|
|
229
273
|
test("it scrolls vertically when the users drags an element to the bottom", async ({
|
|
230
274
|
page,
|
|
231
275
|
}) => {
|
|
276
|
+
const container = page.locator("#container");
|
|
277
|
+
|
|
232
278
|
expect(
|
|
233
|
-
await
|
|
234
|
-
.locator("#container")
|
|
235
|
-
.evaluate((element) => element.scrollTop),
|
|
279
|
+
await container.evaluate((element) => element.scrollTop),
|
|
236
280
|
).toEqual(0);
|
|
237
281
|
|
|
238
282
|
await moveMouseToNode(page, "Saurischia");
|
|
239
283
|
await page.mouse.down();
|
|
240
|
-
|
|
241
|
-
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
242
|
-
await page.waitForTimeout(200);
|
|
284
|
+
await sleep(page, 200);
|
|
243
285
|
|
|
244
286
|
await page.mouse.move(20, 245);
|
|
245
|
-
|
|
246
|
-
await page.waitForTimeout(50);
|
|
287
|
+
await sleep(page, 50);
|
|
247
288
|
|
|
248
289
|
expect(
|
|
249
|
-
await
|
|
250
|
-
.locator("#container")
|
|
251
|
-
.evaluate((element) => element.scrollTop),
|
|
290
|
+
await container.evaluate((element) => element.scrollTop),
|
|
252
291
|
).toBeGreaterThan(0);
|
|
253
292
|
});
|
|
254
293
|
|
|
294
|
+
test("scrollToNode scrolls to a node", async ({ page }) => {
|
|
295
|
+
const container = page.locator("#container");
|
|
296
|
+
|
|
297
|
+
expect(
|
|
298
|
+
await container.evaluate((element) => element.scrollTop),
|
|
299
|
+
).toEqual(0);
|
|
300
|
+
|
|
301
|
+
await page.evaluate(`
|
|
302
|
+
const $tree = jQuery("#tree1");
|
|
303
|
+
const node = $tree.tree("getNodeByName", "Sauropodomorphs");
|
|
304
|
+
$tree.tree("scrollToNode",node);
|
|
305
|
+
`);
|
|
306
|
+
|
|
307
|
+
expect(
|
|
308
|
+
await container.evaluate((element) => element.scrollTop),
|
|
309
|
+
).toBeGreaterThan(0);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test.describe("autoscroll when the container is scrollable horizontally", () => {
|
|
314
|
+
test.beforeEach(async ({ page, baseURL }) => {
|
|
315
|
+
await initPage(page, baseURL);
|
|
316
|
+
|
|
317
|
+
// Add a container and make it the parent of the tree element
|
|
318
|
+
await page.evaluate(`
|
|
319
|
+
document.body.style.marginLeft = "40px";
|
|
320
|
+
document.body.style.marginTop = "40px";
|
|
321
|
+
|
|
322
|
+
const treeElement = document.querySelector("#tree1");
|
|
323
|
+
|
|
324
|
+
const container = document.createElement("div");
|
|
325
|
+
container.id = "container";
|
|
326
|
+
container.style.width = "400px";
|
|
327
|
+
container.style.overflowX = "scroll";
|
|
328
|
+
container.classList.add('wide-tree');
|
|
329
|
+
|
|
330
|
+
document.body.replaceChild(container, treeElement);
|
|
331
|
+
container.appendChild(treeElement);
|
|
332
|
+
`);
|
|
333
|
+
|
|
334
|
+
await initTree(page, { autoOpen: 3, dragAndDrop: true });
|
|
335
|
+
});
|
|
336
|
+
|
|
255
337
|
test("it scrolls horizontally when the users drags an element to the right", async ({
|
|
256
338
|
page,
|
|
257
339
|
}) => {
|
|
340
|
+
const container = page.locator("#container");
|
|
341
|
+
|
|
258
342
|
expect(
|
|
259
|
-
await
|
|
260
|
-
.locator("#container")
|
|
261
|
-
.evaluate((element) => element.scrollLeft),
|
|
343
|
+
await container.evaluate((element) => element.scrollLeft),
|
|
262
344
|
).toEqual(0);
|
|
263
345
|
|
|
264
346
|
await moveMouseToNode(page, "Saurischia");
|
|
265
347
|
await page.mouse.down();
|
|
348
|
+
await sleep(page, 200);
|
|
266
349
|
|
|
267
|
-
|
|
268
|
-
await page.waitForTimeout(200);
|
|
350
|
+
const containerBox = await boundingBox(container);
|
|
269
351
|
|
|
270
|
-
await page.mouse.move(
|
|
271
|
-
|
|
272
|
-
|
|
352
|
+
await page.mouse.move(
|
|
353
|
+
containerBox.x + containerBox.width,
|
|
354
|
+
containerBox.y + 10,
|
|
355
|
+
);
|
|
356
|
+
await sleep(page, 100);
|
|
273
357
|
|
|
274
358
|
expect(
|
|
275
|
-
await
|
|
276
|
-
.locator("#container")
|
|
277
|
-
.evaluate((element) => element.scrollLeft),
|
|
359
|
+
await container.evaluate((element) => element.scrollLeft),
|
|
278
360
|
).toBeGreaterThan(0);
|
|
279
361
|
});
|
|
280
362
|
|
|
281
|
-
test("
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
.evaluate((element) => element.scrollTop),
|
|
286
|
-
).toEqual(0);
|
|
363
|
+
test("it moves a node after scrolling horizontally", async ({ page }) => {
|
|
364
|
+
await moveMouseToNode(page, "Coelophysoids");
|
|
365
|
+
await page.mouse.down();
|
|
366
|
+
await sleep(page, 200);
|
|
287
367
|
|
|
288
|
-
|
|
368
|
+
const container = page.locator("#container");
|
|
369
|
+
const containerBox = await boundingBox(container);
|
|
370
|
+
|
|
371
|
+
await page.mouse.move(
|
|
372
|
+
containerBox.x + containerBox.width,
|
|
373
|
+
containerBox.y + 10,
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
await page.waitForFunction(() => {
|
|
377
|
+
const container = document.querySelector("#container");
|
|
378
|
+
|
|
379
|
+
if (!container) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return (
|
|
384
|
+
container.scrollLeft >=
|
|
385
|
+
container.scrollWidth - container.clientWidth
|
|
386
|
+
);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
await moveMouseToNode(page, "Tyrannosauroids");
|
|
390
|
+
await page.mouse.down();
|
|
391
|
+
await sleep(page, 200);
|
|
392
|
+
|
|
393
|
+
const childrenJson = await page.evaluate<string>(`
|
|
289
394
|
const $tree = jQuery("#tree1");
|
|
290
|
-
const node = $tree.tree("getNodeByName", "
|
|
291
|
-
|
|
395
|
+
const node = $tree.tree("getNodeByName", "Tyrannosauroids");
|
|
396
|
+
const children = node.children.map(child => child.name)
|
|
397
|
+
JSON.stringify(children);
|
|
292
398
|
`);
|
|
293
|
-
|
|
294
|
-
expect(
|
|
295
|
-
await page
|
|
296
|
-
.locator("#container")
|
|
297
|
-
.evaluate((element) => element.scrollTop),
|
|
298
|
-
).toBeGreaterThan(0);
|
|
399
|
+
expect(JSON.parse(childrenJson)).toEqual(["Coelophysoids"]);
|
|
299
400
|
});
|
|
300
401
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ElementHandle, Locator, Page } from "@playwright/test";
|
|
2
2
|
|
|
3
3
|
interface BoundingBox {
|
|
4
4
|
x: number;
|
|
@@ -7,7 +7,10 @@ interface BoundingBox {
|
|
|
7
7
|
height: number;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
export const sleep = async (page: Page, timeout: number) =>
|
|
11
|
+
await page.waitForTimeout(timeout); // eslint-disable-line playwright/no-wait-for-timeout
|
|
12
|
+
|
|
13
|
+
export const locateTitle = (page: Page, title: string) =>
|
|
11
14
|
page.locator(".jqtree-title", {
|
|
12
15
|
hasText: title,
|
|
13
16
|
});
|
|
@@ -42,6 +45,16 @@ export const selectNode = async (nodeElement: ElementHandle) => {
|
|
|
42
45
|
await titleHandle.click();
|
|
43
46
|
};
|
|
44
47
|
|
|
48
|
+
export const boundingBox = async (locator: Locator) => {
|
|
49
|
+
const result = await locator.boundingBox();
|
|
50
|
+
|
|
51
|
+
if (!result) {
|
|
52
|
+
throw new Error("Empty boundingBox");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
|
|
45
58
|
const getRect = async (
|
|
46
59
|
elementHandle: ElementHandle<HTMLElement>,
|
|
47
60
|
): Promise<BoundingBox> => {
|
|
@@ -97,7 +110,10 @@ export const getTreeStructure = async (page: Page) => {
|
|
|
97
110
|
return JSON.parse(structure) as JQTreeMatchers.TreeStructure;
|
|
98
111
|
};
|
|
99
112
|
|
|
100
|
-
const getNodeRect = async (
|
|
113
|
+
export const getNodeRect = async (
|
|
114
|
+
page: Page,
|
|
115
|
+
title: string,
|
|
116
|
+
): Promise<BoundingBox> => {
|
|
101
117
|
const titleElement = await locateTitle(page, title).elementHandle();
|
|
102
118
|
|
|
103
119
|
if (!titleElement) {
|
|
@@ -122,9 +138,16 @@ export const dragAndDrop = async (
|
|
|
122
138
|
await moveMouseToNode(page, fromTitle);
|
|
123
139
|
await page.mouse.down();
|
|
124
140
|
|
|
125
|
-
|
|
126
|
-
await page.waitForTimeout(200);
|
|
141
|
+
await sleep(page, 200);
|
|
127
142
|
|
|
128
143
|
await moveMouseToNode(page, toTitle);
|
|
129
144
|
await page.mouse.up();
|
|
130
145
|
};
|
|
146
|
+
|
|
147
|
+
export const getSelectedNodeName = async (page: Page) => {
|
|
148
|
+
return await page.evaluate(`
|
|
149
|
+
const $tree = jQuery("#tree1");
|
|
150
|
+
const node = $tree.tree('getSelectedNode');
|
|
151
|
+
node?.name;
|
|
152
|
+
`);
|
|
153
|
+
};
|
package/src/position.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export enum Position {
|
|
2
|
+
Before = 1,
|
|
3
|
+
After,
|
|
4
|
+
Inside,
|
|
5
|
+
None,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const positionNames: Record<string, Position> = {
|
|
9
|
+
before: Position.Before,
|
|
10
|
+
after: Position.After,
|
|
11
|
+
inside: Position.Inside,
|
|
12
|
+
none: Position.None,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const getPositionName = (position: Position): string => {
|
|
16
|
+
for (const name in positionNames) {
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(positionNames, name)) {
|
|
18
|
+
if (positionNames[name] === position) {
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return "";
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getPosition = (name: string): Position | undefined =>
|
|
28
|
+
positionNames[name];
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { ScrollParent } from "./types";
|
|
2
|
+
import { getElementPosition, getOffsetTop } from '../util'
|
|
2
3
|
|
|
3
4
|
type HorizontalScrollDirection = "left" | "right";
|
|
4
5
|
type VerticalScrollDirection = "bottom" | "top";
|
|
5
6
|
|
|
6
7
|
interface Params {
|
|
7
|
-
|
|
8
|
+
container: HTMLElement;
|
|
8
9
|
refreshHitAreas: () => void;
|
|
9
|
-
$treeElement: JQuery<HTMLElement>;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export default class ContainerScrollParent implements ScrollParent {
|
|
13
|
-
private
|
|
13
|
+
private container: HTMLElement;
|
|
14
14
|
private horizontalScrollDirection?: HorizontalScrollDirection;
|
|
15
15
|
private horizontalScrollTimeout?: number;
|
|
16
16
|
private refreshHitAreas: () => void;
|
|
@@ -19,8 +19,8 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
19
19
|
private verticalScrollTimeout?: number;
|
|
20
20
|
private verticalScrollDirection?: VerticalScrollDirection;
|
|
21
21
|
|
|
22
|
-
constructor({
|
|
23
|
-
this
|
|
22
|
+
constructor({ container, refreshHitAreas }: Params) {
|
|
23
|
+
this.container = container;
|
|
24
24
|
this.refreshHitAreas = refreshHitAreas;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -66,12 +66,11 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
public getScrollLeft(): number {
|
|
69
|
-
return this
|
|
69
|
+
return this.container.scrollLeft;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
public scrollToY(top: number): void {
|
|
73
|
-
|
|
74
|
-
container.scrollTop = top;
|
|
73
|
+
this.container.scrollTop = top;
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
public stopScrolling() {
|
|
@@ -84,14 +83,9 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
84
83
|
private getNewHorizontalScrollDirection(
|
|
85
84
|
pageX: number,
|
|
86
85
|
): HorizontalScrollDirection | undefined {
|
|
87
|
-
const scrollParentOffset = this
|
|
88
|
-
if (!scrollParentOffset) {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const container = this.$container.get(0) as HTMLElement;
|
|
86
|
+
const scrollParentOffset = getElementPosition(this.container);
|
|
93
87
|
|
|
94
|
-
const rightEdge = scrollParentOffset.left + container.clientWidth;
|
|
88
|
+
const rightEdge = scrollParentOffset.left + this.container.clientWidth;
|
|
95
89
|
const leftEdge = scrollParentOffset.left;
|
|
96
90
|
const isNearRightEdge = pageX > rightEdge - 20;
|
|
97
91
|
const isNearLeftEdge = pageX < leftEdge + 20;
|
|
@@ -125,9 +119,8 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
125
119
|
}
|
|
126
120
|
|
|
127
121
|
const distance = this.horizontalScrollDirection === "left" ? -20 : 20;
|
|
128
|
-
const container = this.$container.get(0) as HTMLElement;
|
|
129
122
|
|
|
130
|
-
container.scrollBy({
|
|
123
|
+
this.container.scrollBy({
|
|
131
124
|
left: distance,
|
|
132
125
|
top: 0,
|
|
133
126
|
behavior: "instant",
|
|
@@ -144,9 +137,8 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
144
137
|
}
|
|
145
138
|
|
|
146
139
|
const distance = this.verticalScrollDirection === "top" ? -20 : 20;
|
|
147
|
-
const container = this.$container.get(0) as HTMLElement;
|
|
148
140
|
|
|
149
|
-
container.scrollBy({
|
|
141
|
+
this.container.scrollBy({
|
|
150
142
|
left: 0,
|
|
151
143
|
top: distance,
|
|
152
144
|
behavior: "instant",
|
|
@@ -159,7 +151,7 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
159
151
|
|
|
160
152
|
private getScrollParentTop() {
|
|
161
153
|
if (this.scrollParentTop == null) {
|
|
162
|
-
this.scrollParentTop = this
|
|
154
|
+
this.scrollParentTop = getOffsetTop(this.container)
|
|
163
155
|
}
|
|
164
156
|
|
|
165
157
|
return this.scrollParentTop;
|
|
@@ -167,9 +159,7 @@ export default class ContainerScrollParent implements ScrollParent {
|
|
|
167
159
|
|
|
168
160
|
private getScrollParentBottom() {
|
|
169
161
|
if (this.scrollParentBottom == null) {
|
|
170
|
-
this.scrollParentBottom =
|
|
171
|
-
this.getScrollParentTop() +
|
|
172
|
-
(this.$container.innerHeight() ?? 0);
|
|
162
|
+
this.scrollParentBottom = this.getScrollParentTop() + this.container.clientHeight;
|
|
173
163
|
}
|
|
174
164
|
|
|
175
165
|
return this.scrollParentBottom;
|
|
@@ -2,48 +2,48 @@ import type { ScrollParent } from "./types";
|
|
|
2
2
|
import ContainerScrollParent from "./containerScrollParent";
|
|
3
3
|
import DocumentScrollParent from "./documentScrollParent";
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
}
|
|
5
|
+
const isOverflow = (overflowValue: string) =>
|
|
6
|
+
overflowValue === "auto" || overflowValue === "scroll";
|
|
7
|
+
|
|
8
|
+
const hasOverFlow = (element: HTMLElement): boolean => {
|
|
9
|
+
const style = getComputedStyle(element);
|
|
12
10
|
|
|
13
|
-
return
|
|
11
|
+
return isOverflow(style.overflowX) || isOverflow(style.overflowY);
|
|
14
12
|
};
|
|
15
13
|
|
|
16
14
|
const getParentWithOverflow = (
|
|
17
|
-
|
|
18
|
-
):
|
|
19
|
-
if (hasOverFlow(
|
|
20
|
-
return
|
|
15
|
+
treeElement: HTMLElement,
|
|
16
|
+
): HTMLElement | null => {
|
|
17
|
+
if (hasOverFlow(treeElement)) {
|
|
18
|
+
return treeElement;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
let parent = treeElement.parentElement;
|
|
22
|
+
|
|
23
|
+
while (parent) {
|
|
24
|
+
if (hasOverFlow(parent)) {
|
|
25
|
+
return parent;
|
|
27
26
|
}
|
|
27
|
+
|
|
28
|
+
parent = parent.parentElement;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
return null;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
const createScrollParent = (
|
|
34
|
-
|
|
35
|
+
treeElement: HTMLElement,
|
|
35
36
|
refreshHitAreas: () => void,
|
|
36
37
|
): ScrollParent => {
|
|
37
|
-
const
|
|
38
|
+
const container = getParentWithOverflow(treeElement);
|
|
38
39
|
|
|
39
|
-
if (
|
|
40
|
+
if (container && container.tagName !== "HTML") {
|
|
40
41
|
return new ContainerScrollParent({
|
|
41
|
-
|
|
42
|
+
container,
|
|
42
43
|
refreshHitAreas,
|
|
43
|
-
$treeElement,
|
|
44
44
|
});
|
|
45
45
|
} else {
|
|
46
|
-
return new DocumentScrollParent(
|
|
46
|
+
return new DocumentScrollParent({ refreshHitAreas, treeElement });
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import type { ScrollParent } from "./types";
|
|
2
|
+
import { getOffsetTop } from '../util'
|
|
2
3
|
|
|
3
4
|
type HorizontalScrollDirection = "left" | "right";
|
|
4
5
|
type VerticalScrollDirection = "bottom" | "top";
|
|
5
6
|
|
|
7
|
+
interface Params {
|
|
8
|
+
refreshHitAreas: () => void;
|
|
9
|
+
treeElement: HTMLElement;
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export default class DocumentScrollParent implements ScrollParent {
|
|
7
|
-
private
|
|
13
|
+
private documentScrollHeight?: number;
|
|
14
|
+
private documentScrollWidth?: number;
|
|
8
15
|
private horizontalScrollDirection?: HorizontalScrollDirection;
|
|
9
16
|
private horizontalScrollTimeout?: number;
|
|
10
17
|
private refreshHitAreas: () => void;
|
|
18
|
+
private treeElement: HTMLElement;
|
|
11
19
|
private verticalScrollDirection?: VerticalScrollDirection;
|
|
12
20
|
private verticalScrollTimeout?: number;
|
|
13
|
-
private documentScrollHeight?: number;
|
|
14
|
-
private documentScrollWidth?: number;
|
|
15
21
|
|
|
16
|
-
constructor(
|
|
17
|
-
this.$element = $element;
|
|
22
|
+
constructor({ refreshHitAreas, treeElement }: Params) {
|
|
18
23
|
this.refreshHitAreas = refreshHitAreas;
|
|
24
|
+
this.treeElement = treeElement;
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
public checkHorizontalScrolling(pageX: number): void {
|
|
@@ -64,10 +70,9 @@ export default class DocumentScrollParent implements ScrollParent {
|
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
public scrollToY(top: number): void {
|
|
67
|
-
const
|
|
68
|
-
const treeTop = offset ? offset.top : 0;
|
|
73
|
+
const treeTop = getOffsetTop(this.treeElement);
|
|
69
74
|
|
|
70
|
-
|
|
75
|
+
document.documentElement.scrollTop = top + treeTop;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
public stopScrolling() {
|
|
@@ -80,10 +85,8 @@ export default class DocumentScrollParent implements ScrollParent {
|
|
|
80
85
|
private getNewHorizontalScrollDirection(
|
|
81
86
|
pageX: number,
|
|
82
87
|
): HorizontalScrollDirection | undefined {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
const scrollLeft = $document.scrollLeft() || 0;
|
|
86
|
-
const windowWidth = jQuery(window).width() || 0;
|
|
88
|
+
const scrollLeft = document.documentElement.scrollLeft;
|
|
89
|
+
const windowWidth = window.innerWidth;
|
|
87
90
|
|
|
88
91
|
const isNearRightEdge = pageX > windowWidth - 20;
|
|
89
92
|
const isNearLeftEdge = pageX - scrollLeft < 20;
|
|
@@ -145,7 +148,7 @@ export default class DocumentScrollParent implements ScrollParent {
|
|
|
145
148
|
return "top";
|
|
146
149
|
}
|
|
147
150
|
|
|
148
|
-
const windowHeight =
|
|
151
|
+
const windowHeight = window.innerHeight;
|
|
149
152
|
|
|
150
153
|
if (windowHeight - (pageY - scrollTop) < 20 && this.canScrollDown()) {
|
|
151
154
|
return "bottom";
|
package/src/scrollHandler.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { PositionInfo } from "./
|
|
1
|
+
import { PositionInfo } from "./mouseUtils";
|
|
2
2
|
import { ScrollParent } from "./scrollHandler/types";
|
|
3
3
|
import createScrollParent from "./scrollHandler/createScrollParent";
|
|
4
4
|
|
|
5
5
|
interface ScrollHandlerParams {
|
|
6
6
|
refreshHitAreas: () => void;
|
|
7
|
-
|
|
7
|
+
treeElement: HTMLElement;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export default class ScrollHandler {
|
|
11
11
|
private refreshHitAreas: () => void;
|
|
12
12
|
private scrollParent?: ScrollParent;
|
|
13
|
-
private
|
|
13
|
+
private treeElement: HTMLElement;
|
|
14
14
|
|
|
15
|
-
constructor({ refreshHitAreas,
|
|
15
|
+
constructor({ refreshHitAreas, treeElement }: ScrollHandlerParams) {
|
|
16
16
|
this.refreshHitAreas = refreshHitAreas;
|
|
17
17
|
this.scrollParent = undefined;
|
|
18
|
-
this
|
|
18
|
+
this.treeElement = treeElement;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
public checkScrolling(positionInfo: PositionInfo): void {
|
|
@@ -36,25 +36,17 @@ export default class ScrollHandler {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
private checkVerticalScrolling(positionInfo: PositionInfo): void {
|
|
39
|
-
if (positionInfo.pageY == null) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
39
|
this.getScrollParent().checkVerticalScrolling(positionInfo.pageY);
|
|
44
40
|
}
|
|
45
41
|
|
|
46
42
|
private checkHorizontalScrolling(positionInfo: PositionInfo): void {
|
|
47
|
-
if (positionInfo.pageX == null) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
43
|
this.getScrollParent().checkHorizontalScrolling(positionInfo.pageX);
|
|
52
44
|
}
|
|
53
45
|
|
|
54
46
|
private getScrollParent(): ScrollParent {
|
|
55
47
|
if (!this.scrollParent) {
|
|
56
48
|
this.scrollParent = createScrollParent(
|
|
57
|
-
this
|
|
49
|
+
this.treeElement,
|
|
58
50
|
this.refreshHitAreas,
|
|
59
51
|
);
|
|
60
52
|
}
|