jqtree 1.7.5 → 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/babel.config.json +1 -1
- package/config/jest.config.js +4 -0
- package/config/jest.polyfills.js +14 -0
- package/config/production +2 -0
- package/devserver/devserver_scroll.js +8 -0
- package/devserver/test_index.html +9 -0
- package/devserver/test_scroll.html +28 -0
- package/devserver/test_scroll_container.html +39 -0
- package/docs/.ruby-version +1 -1
- package/docs/_config.yml +1 -1
- package/docs/_entries/general/changelog.md +11 -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 +35 -29
- package/src/dataLoader.ts +57 -34
- package/src/dragAndDropHandler/dragElement.ts +54 -0
- package/src/dragAndDropHandler/generateHitAreas.ts +176 -0
- package/src/dragAndDropHandler/index.ts +454 -0
- package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
- package/src/dragAndDropHandler/types.ts +13 -0
- package/src/elementsRenderer.ts +75 -40
- package/src/jqtreeMethodTypes.ts +40 -0
- package/src/jqtreeOptions.ts +43 -25
- package/src/keyHandler.ts +59 -30
- package/src/mouseHandler.ts +385 -0
- package/src/mouseUtils.ts +23 -0
- package/src/node.ts +1 -29
- package/src/nodeElement/borderDropHint.ts +32 -0
- package/src/nodeElement/folderElement.ts +133 -0
- package/src/nodeElement/ghostDropHint.ts +69 -0
- package/src/nodeElement/index.ts +102 -0
- package/src/playwright/coverage.ts +4 -7
- package/src/playwright/playwright.test.ts +150 -53
- package/src/playwright/testUtils.ts +28 -5
- package/src/position.ts +28 -0
- package/src/saveStateHandler.ts +75 -26
- 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 +13 -15
- package/src/selectNodeHandler.ts +10 -16
- package/src/test/jqTree/events.test.ts +97 -30
- package/src/test/jqTree/keyboard.test.ts +18 -23
- package/src/test/jqTree/loadOnDemand.test.ts +22 -15
- package/src/test/jqTree/methods.test.ts +40 -14
- package/src/test/jqTree/mouse.test.ts +82 -0
- package/src/test/jqTree/options.test.ts +24 -12
- package/src/test/node.test.ts +3 -2
- package/src/test/{nodeUtil.test.ts → position.test.ts} +1 -1
- package/src/tree.jquery.ts +314 -208
- package/src/util.ts +12 -0
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +2594 -3419
- 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/lib/dataLoader.js +0 -123
- package/lib/dragAndDropHandler.js +0 -588
- package/lib/elementsRenderer.js +0 -267
- package/lib/jqtreeOptions.js +0 -1
- package/lib/keyHandler.js +0 -111
- package/lib/mouse.widget.js +0 -255
- package/lib/node.js +0 -708
- package/lib/nodeElement.js +0 -274
- package/lib/nodeUtils.js +0 -10
- package/lib/playwright/coverage.js +0 -99
- package/lib/playwright/playwright.test.js +0 -606
- package/lib/playwright/testUtils.js +0 -210
- package/lib/saveStateHandler.js +0 -277
- package/lib/scrollHandler/containerScrollParent.js +0 -160
- package/lib/scrollHandler/createScrollParent.js +0 -57
- package/lib/scrollHandler/documentScrollParent.js +0 -169
- package/lib/scrollHandler/scrollParent.js +0 -58
- package/lib/scrollHandler/types.js +0 -1
- package/lib/scrollHandler.js +0 -71
- package/lib/selectNodeHandler.js +0 -128
- package/lib/simple.widget.js +0 -158
- package/lib/test/global.d.js +0 -3
- package/lib/test/jqTree/accessibility.test.js +0 -37
- package/lib/test/jqTree/create.test.js +0 -48
- package/lib/test/jqTree/events.test.js +0 -210
- package/lib/test/jqTree/keyboard.test.js +0 -225
- package/lib/test/jqTree/loadOnDemand.test.js +0 -218
- package/lib/test/jqTree/methods.test.js +0 -1348
- package/lib/test/jqTree/options.test.js +0 -548
- package/lib/test/jqTree/scrollHandler/containerScrollParent.test.js +0 -94
- package/lib/test/node.test.js +0 -1202
- package/lib/test/nodeUtil.test.js +0 -27
- package/lib/test/nodeUtils.test.js +0 -20
- package/lib/test/support/exampleData.js +0 -35
- package/lib/test/support/jqTreeMatchers.js +0 -70
- package/lib/test/support/matchers.d.js +0 -1
- package/lib/test/support/setupTests.js +0 -7
- package/lib/test/support/testUtil.js +0 -29
- package/lib/test/support/treeStructure.js +0 -38
- package/lib/test/util.test.js +0 -26
- package/lib/tree.jquery.d.js +0 -1
- package/lib/tree.jquery.js +0 -1105
- package/lib/types.js +0 -1
- package/lib/typings.d.js +0 -2
- package/lib/util.js +0 -15
- package/lib/version.js +0 -8
- package/src/dragAndDropHandler.ts +0 -713
- package/src/mouse.widget.ts +0 -266
- package/src/nodeElement.ts +0 -272
- package/src/types.ts +0 -19
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Node } from "../node";
|
|
2
|
+
import { Position } from "../position";
|
|
3
|
+
import { DropHint } from "../dragAndDropHandler/types";
|
|
4
|
+
import BorderDropHint from "./borderDropHint";
|
|
5
|
+
import GhostDropHint from "./ghostDropHint";
|
|
6
|
+
import { GetScrollLeft } from "../jqtreeMethodTypes";
|
|
7
|
+
|
|
8
|
+
export interface NodeElementParams {
|
|
9
|
+
getScrollLeft: GetScrollLeft;
|
|
10
|
+
node: Node;
|
|
11
|
+
tabIndex?: number;
|
|
12
|
+
$treeElement: JQuery<HTMLElement>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class NodeElement {
|
|
16
|
+
public node: Node;
|
|
17
|
+
public element: HTMLElement;
|
|
18
|
+
private getScrollLeft: GetScrollLeft;
|
|
19
|
+
private tabIndex?: number;
|
|
20
|
+
private $treeElement: JQuery<HTMLElement>;
|
|
21
|
+
|
|
22
|
+
constructor({
|
|
23
|
+
getScrollLeft,
|
|
24
|
+
node,
|
|
25
|
+
tabIndex,
|
|
26
|
+
$treeElement,
|
|
27
|
+
}: NodeElementParams) {
|
|
28
|
+
this.getScrollLeft = getScrollLeft;
|
|
29
|
+
this.tabIndex = tabIndex;
|
|
30
|
+
this.$treeElement = $treeElement;
|
|
31
|
+
|
|
32
|
+
this.init(node);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public init(node: Node): void {
|
|
36
|
+
this.node = node;
|
|
37
|
+
|
|
38
|
+
if (!node.element) {
|
|
39
|
+
const element = this.$treeElement.get(0);
|
|
40
|
+
|
|
41
|
+
if (element) {
|
|
42
|
+
node.element = element;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (node.element) {
|
|
47
|
+
this.element = node.element;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public addDropHint(position: number): DropHint {
|
|
52
|
+
if (this.mustShowBorderDropHint(position)) {
|
|
53
|
+
return new BorderDropHint(this.element, this.getScrollLeft());
|
|
54
|
+
} else {
|
|
55
|
+
return new GhostDropHint(this.node, this.element, position);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public select(mustSetFocus: boolean): void {
|
|
60
|
+
this.element.classList.add("jqtree-selected");
|
|
61
|
+
|
|
62
|
+
const titleSpan = this.getTitleSpan();
|
|
63
|
+
const tabIndex = this.tabIndex;
|
|
64
|
+
|
|
65
|
+
// Check for null or undefined
|
|
66
|
+
if (tabIndex != null) {
|
|
67
|
+
titleSpan.setAttribute("tabindex", tabIndex.toString());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
titleSpan.setAttribute("aria-selected", "true");
|
|
71
|
+
|
|
72
|
+
if (mustSetFocus) {
|
|
73
|
+
titleSpan.focus();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public deselect(): void {
|
|
78
|
+
this.element.classList.remove("jqtree-selected");
|
|
79
|
+
|
|
80
|
+
const titleSpan = this.getTitleSpan();
|
|
81
|
+
titleSpan.removeAttribute("tabindex");
|
|
82
|
+
titleSpan.setAttribute("aria-selected", "false");
|
|
83
|
+
|
|
84
|
+
titleSpan.blur();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected getUl(): HTMLUListElement {
|
|
88
|
+
return this.element.querySelector(":scope > ul") as HTMLUListElement;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected getTitleSpan(): HTMLSpanElement {
|
|
92
|
+
return this.element.querySelector(
|
|
93
|
+
":scope > .jqtree-element > span.jqtree-title",
|
|
94
|
+
) as HTMLSpanElement;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected mustShowBorderDropHint(position: Position): boolean {
|
|
98
|
+
return position === Position.Inside;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default NodeElement;
|
|
@@ -13,17 +13,14 @@ export const initCoverage = async (context: BrowserContext) => {
|
|
|
13
13
|
await context.exposeFunction(
|
|
14
14
|
"collectIstanbulCoverage",
|
|
15
15
|
(coverageJSON: string) => {
|
|
16
|
-
if (
|
|
17
|
-
console.log("No coverage");
|
|
18
|
-
} else {
|
|
16
|
+
if (coverageJSON) {
|
|
19
17
|
const filename = path.join(
|
|
20
18
|
istanbulCLIOutput,
|
|
21
|
-
`playwright_coverage_${generateUUID()}.json
|
|
19
|
+
`playwright_coverage_${generateUUID()}.json`,
|
|
22
20
|
);
|
|
23
|
-
console.log(`Writing coverage to ${filename}`);
|
|
24
21
|
fs.writeFileSync(filename, coverageJSON);
|
|
25
22
|
}
|
|
26
|
-
}
|
|
23
|
+
},
|
|
27
24
|
);
|
|
28
25
|
};
|
|
29
26
|
|
|
@@ -34,7 +31,7 @@ export const saveCoverage = async (context: BrowserContext) => {
|
|
|
34
31
|
const anyWindow = window as any;
|
|
35
32
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
36
33
|
const coverageData = anyWindow.__coverage__;
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, playwright/no-unsafe-references
|
|
38
35
|
anyWindow.collectIstanbulCoverage(JSON.stringify(coverageData));
|
|
39
36
|
});
|
|
40
37
|
}
|
|
@@ -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
|
|
|
@@ -17,10 +21,6 @@ const initPage = async (page: Page, baseURL: string | undefined) => {
|
|
|
17
21
|
await page.waitForLoadState("domcontentloaded");
|
|
18
22
|
|
|
19
23
|
page.on("console", (msg) => console.log(`console: ${msg.text()}`));
|
|
20
|
-
|
|
21
|
-
await page.evaluate(`
|
|
22
|
-
console.log(window.__coverage__ ? 'Coverage enabled' : 'Coverage not enabled');
|
|
23
|
-
`);
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
interface InitTreeOptions {
|
|
@@ -74,6 +74,8 @@ test.describe("without dragAndDrop", () => {
|
|
|
74
74
|
const saurischia = await findNodeElement(page, "Saurischia");
|
|
75
75
|
await selectNode(saurischia);
|
|
76
76
|
|
|
77
|
+
expect(await getSelectedNodeName(page)).toBe("Saurischia");
|
|
78
|
+
|
|
77
79
|
const screenshot = await page.screenshot();
|
|
78
80
|
expect(screenshot).toMatchSnapshot();
|
|
79
81
|
});
|
|
@@ -116,10 +118,54 @@ test.describe("with dragAndDrop", () => {
|
|
|
116
118
|
const screenshot = await page.screenshot();
|
|
117
119
|
expect(screenshot).toMatchSnapshot();
|
|
118
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
|
+
});
|
|
119
165
|
});
|
|
120
166
|
|
|
121
167
|
test.describe("autoscroll when the window is scrollable", () => {
|
|
122
|
-
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 ({
|
|
123
169
|
baseURL,
|
|
124
170
|
page,
|
|
125
171
|
}) => {
|
|
@@ -136,12 +182,10 @@ test.describe("autoscroll when the window is scrollable", () => {
|
|
|
136
182
|
await moveMouseToNode(page, "Saurischia");
|
|
137
183
|
await page.mouse.down();
|
|
138
184
|
|
|
139
|
-
|
|
140
|
-
await page.waitForTimeout(200);
|
|
185
|
+
await sleep(page, 200);
|
|
141
186
|
|
|
142
187
|
await page.mouse.move(20, 190);
|
|
143
|
-
|
|
144
|
-
await page.waitForTimeout(50);
|
|
188
|
+
await sleep(page, 50);
|
|
145
189
|
|
|
146
190
|
expect(
|
|
147
191
|
await page
|
|
@@ -166,13 +210,10 @@ test.describe("autoscroll when the window is scrollable", () => {
|
|
|
166
210
|
|
|
167
211
|
await moveMouseToNode(page, "Saurischia");
|
|
168
212
|
await page.mouse.down();
|
|
169
|
-
|
|
170
|
-
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
171
|
-
await page.waitForTimeout(200);
|
|
213
|
+
await sleep(page, 200);
|
|
172
214
|
|
|
173
215
|
await page.mouse.move(55, 10);
|
|
174
|
-
|
|
175
|
-
await page.waitForTimeout(50);
|
|
216
|
+
await sleep(page, 50);
|
|
176
217
|
|
|
177
218
|
expect(
|
|
178
219
|
await page
|
|
@@ -206,7 +247,7 @@ test.describe("autoscroll when the window is scrollable", () => {
|
|
|
206
247
|
});
|
|
207
248
|
});
|
|
208
249
|
|
|
209
|
-
test.describe("autoscroll when the container is scrollable", () => {
|
|
250
|
+
test.describe("autoscroll when the container is scrollable vertically", () => {
|
|
210
251
|
test.beforeEach(async ({ page, baseURL }) => {
|
|
211
252
|
await initPage(page, baseURL);
|
|
212
253
|
|
|
@@ -220,7 +261,6 @@ test.describe("autoscroll when the container is scrollable", () => {
|
|
|
220
261
|
const container = document.createElement("div");
|
|
221
262
|
container.id = "container";
|
|
222
263
|
container.style.height = "200px";
|
|
223
|
-
container.style.width = "60px";
|
|
224
264
|
container.style.overflowY = "scroll";
|
|
225
265
|
|
|
226
266
|
document.body.replaceChild(container, treeElement);
|
|
@@ -233,72 +273,129 @@ test.describe("autoscroll when the container is scrollable", () => {
|
|
|
233
273
|
test("it scrolls vertically when the users drags an element to the bottom", async ({
|
|
234
274
|
page,
|
|
235
275
|
}) => {
|
|
276
|
+
const container = page.locator("#container");
|
|
277
|
+
|
|
236
278
|
expect(
|
|
237
|
-
await
|
|
238
|
-
.locator("#container")
|
|
239
|
-
.evaluate((element) => element.scrollTop),
|
|
279
|
+
await container.evaluate((element) => element.scrollTop),
|
|
240
280
|
).toEqual(0);
|
|
241
281
|
|
|
242
282
|
await moveMouseToNode(page, "Saurischia");
|
|
243
283
|
await page.mouse.down();
|
|
244
|
-
|
|
245
|
-
// eslint-disable-next-line playwright/no-wait-for-timeout
|
|
246
|
-
await page.waitForTimeout(200);
|
|
284
|
+
await sleep(page, 200);
|
|
247
285
|
|
|
248
286
|
await page.mouse.move(20, 245);
|
|
249
|
-
|
|
250
|
-
await page.waitForTimeout(50);
|
|
287
|
+
await sleep(page, 50);
|
|
251
288
|
|
|
252
289
|
expect(
|
|
253
|
-
await
|
|
254
|
-
|
|
255
|
-
|
|
290
|
+
await container.evaluate((element) => element.scrollTop),
|
|
291
|
+
).toBeGreaterThan(0);
|
|
292
|
+
});
|
|
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),
|
|
256
309
|
).toBeGreaterThan(0);
|
|
257
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
|
+
});
|
|
258
336
|
|
|
259
337
|
test("it scrolls horizontally when the users drags an element to the right", async ({
|
|
260
338
|
page,
|
|
261
339
|
}) => {
|
|
340
|
+
const container = page.locator("#container");
|
|
341
|
+
|
|
262
342
|
expect(
|
|
263
|
-
await
|
|
264
|
-
.locator("#container")
|
|
265
|
-
.evaluate((element) => element.scrollLeft),
|
|
343
|
+
await container.evaluate((element) => element.scrollLeft),
|
|
266
344
|
).toEqual(0);
|
|
267
345
|
|
|
268
346
|
await moveMouseToNode(page, "Saurischia");
|
|
269
347
|
await page.mouse.down();
|
|
348
|
+
await sleep(page, 200);
|
|
270
349
|
|
|
271
|
-
|
|
272
|
-
await page.waitForTimeout(200);
|
|
350
|
+
const containerBox = await boundingBox(container);
|
|
273
351
|
|
|
274
|
-
await page.mouse.move(
|
|
275
|
-
|
|
276
|
-
|
|
352
|
+
await page.mouse.move(
|
|
353
|
+
containerBox.x + containerBox.width,
|
|
354
|
+
containerBox.y + 10,
|
|
355
|
+
);
|
|
356
|
+
await sleep(page, 100);
|
|
277
357
|
|
|
278
358
|
expect(
|
|
279
|
-
await
|
|
280
|
-
.locator("#container")
|
|
281
|
-
.evaluate((element) => element.scrollLeft),
|
|
359
|
+
await container.evaluate((element) => element.scrollLeft),
|
|
282
360
|
).toBeGreaterThan(0);
|
|
283
361
|
});
|
|
284
362
|
|
|
285
|
-
test("
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
.evaluate((element) => element.scrollTop),
|
|
290
|
-
).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);
|
|
291
367
|
|
|
292
|
-
|
|
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>(`
|
|
293
394
|
const $tree = jQuery("#tree1");
|
|
294
|
-
const node = $tree.tree("getNodeByName", "
|
|
295
|
-
|
|
395
|
+
const node = $tree.tree("getNodeByName", "Tyrannosauroids");
|
|
396
|
+
const children = node.children.map(child => child.name)
|
|
397
|
+
JSON.stringify(children);
|
|
296
398
|
`);
|
|
297
|
-
|
|
298
|
-
expect(
|
|
299
|
-
await page
|
|
300
|
-
.locator("#container")
|
|
301
|
-
.evaluate((element) => element.scrollTop),
|
|
302
|
-
).toBeGreaterThan(0);
|
|
399
|
+
expect(JSON.parse(childrenJson)).toEqual(["Coelophysoids"]);
|
|
303
400
|
});
|
|
304
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];
|