jqtree 1.7.4 → 1.8.0
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/config/babel.config.json +1 -1
- package/config/production +2 -0
- package/devserver/devserver_scroll.js +8 -0
- package/devserver/test_scroll.html +28 -0
- package/devserver/test_scroll_container.html +39 -0
- package/docs/_config.yml +1 -1
- package/docs/_entries/general/changelog.md +12 -0
- package/docs/package.json +1 -1
- package/docs/pnpm-lock.yaml +30 -30
- package/package.json +31 -27
- package/src/dataLoader.ts +44 -19
- package/src/dragAndDropHandler/dragElement.ts +42 -0
- package/src/dragAndDropHandler/hitAreasGenerator.ts +175 -0
- package/src/dragAndDropHandler/index.ts +470 -0
- package/src/dragAndDropHandler/types.ts +12 -0
- package/src/dragAndDropHandler/visibleNodeIterator.ts +97 -0
- package/src/elementsRenderer.ts +75 -40
- package/src/jqtreeMethodTypes.ts +40 -0
- package/src/jqtreeOptions.ts +43 -25
- package/src/keyHandler.ts +59 -38
- package/src/mouse.widget.ts +3 -3
- package/src/mouseWidgetTypes.ts +6 -0
- package/src/node.ts +32 -48
- package/src/nodeElement/borderDropHint.ts +32 -0
- package/src/nodeElement/folderElement.ts +133 -0
- package/src/nodeElement/ghostDropHint.ts +68 -0
- package/src/nodeElement/index.ts +101 -0
- package/src/nodeUtils.ts +10 -0
- package/src/playwright/coverage.ts +1 -4
- package/src/playwright/playwright.test.ts +203 -15
- package/src/playwright/testUtils.ts +23 -15
- package/src/saveStateHandler.ts +75 -26
- 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 +36 -248
- package/src/selectNodeHandler.ts +10 -16
- package/src/test/jqTree/keyboard.test.ts +18 -23
- package/src/test/jqTree/loadOnDemand.test.ts +2 -3
- package/src/test/jqTree/methods.test.ts +33 -4
- package/src/test/jqTree/options.test.ts +15 -4
- package/src/test/node.test.ts +85 -26
- package/src/test/nodeUtils.test.ts +21 -0
- package/src/tree.jquery.ts +262 -83
- package/src/util.ts +3 -0
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +1922 -2608
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +2 -2
- package/tree.jquery.js.map +1 -1
- package/lib/dataLoader.js +0 -124
- package/lib/dragAndDropHandler.js +0 -596
- package/lib/elementsRenderer.js +0 -268
- package/lib/jqtreeOptions.js +0 -1
- package/lib/keyHandler.js +0 -115
- package/lib/mouse.widget.js +0 -256
- package/lib/node.js +0 -717
- package/lib/nodeElement.js +0 -277
- package/lib/playwright/coverage.js +0 -96
- package/lib/playwright/playwright.test.js +0 -228
- package/lib/playwright/testUtils.js +0 -184
- package/lib/saveStateHandler.js +0 -278
- package/lib/scrollHandler.js +0 -250
- package/lib/selectNodeHandler.js +0 -129
- package/lib/simple.widget.js +0 -159
- 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 -1347
- package/lib/test/jqTree/options.test.js +0 -548
- package/lib/test/node.test.js +0 -1160
- package/lib/test/nodeUtil.test.js +0 -27
- package/lib/test/support/exampleData.js +0 -36
- 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 -32
- package/lib/test/support/treeStructure.js +0 -39
- package/lib/test/util.test.js +0 -26
- package/lib/tree.jquery.d.js +0 -1
- package/lib/tree.jquery.js +0 -1106
- package/lib/types.js +0 -1
- package/lib/typings.d.js +0 -2
- package/lib/util.js +0 -18
- package/lib/version.js +0 -9
- package/src/dragAndDropHandler.ts +0 -719
- package/src/nodeElement.ts +0 -272
- package/src/types.ts +0 -19
package/src/node.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
children: NodeData[];
|
|
3
|
-
}
|
|
1
|
+
import { isNodeRecordWithChildren } from "./nodeUtils";
|
|
4
2
|
|
|
5
3
|
export enum Position {
|
|
6
4
|
Before = 1,
|
|
@@ -33,13 +31,6 @@ export const getPositionName = (position: Position): string => {
|
|
|
33
31
|
export const getPosition = (name: string): Position | undefined =>
|
|
34
32
|
positionNames[name];
|
|
35
33
|
|
|
36
|
-
const isNodeRecordWithChildren = (
|
|
37
|
-
data: NodeData
|
|
38
|
-
): data is NodeRecordWithChildren =>
|
|
39
|
-
typeof data === "object" &&
|
|
40
|
-
"children" in data &&
|
|
41
|
-
data["children"] instanceof Array;
|
|
42
|
-
|
|
43
34
|
export class Node implements INode {
|
|
44
35
|
public id?: NodeId;
|
|
45
36
|
public name: string;
|
|
@@ -56,12 +47,20 @@ export class Node implements INode {
|
|
|
56
47
|
|
|
57
48
|
[key: string]: unknown;
|
|
58
49
|
|
|
59
|
-
constructor(
|
|
50
|
+
constructor(
|
|
51
|
+
nodeData: NodeData | null = null,
|
|
52
|
+
isRoot = false,
|
|
53
|
+
nodeClass = Node,
|
|
54
|
+
) {
|
|
60
55
|
this.name = "";
|
|
61
|
-
this.isEmptyFolder = false;
|
|
62
56
|
this.load_on_demand = false;
|
|
63
57
|
|
|
64
|
-
this.
|
|
58
|
+
this.isEmptyFolder =
|
|
59
|
+
nodeData != null &&
|
|
60
|
+
isNodeRecordWithChildren(nodeData) &&
|
|
61
|
+
nodeData.children.length === 0;
|
|
62
|
+
|
|
63
|
+
this.setData(nodeData);
|
|
65
64
|
|
|
66
65
|
this.children = [];
|
|
67
66
|
this.parent = null;
|
|
@@ -77,10 +76,10 @@ export class Node implements INode {
|
|
|
77
76
|
Set the data of this node.
|
|
78
77
|
|
|
79
78
|
setData(string): set the name of the node
|
|
80
|
-
|
|
79
|
+
setData(object): set attributes of the node
|
|
81
80
|
|
|
82
81
|
Examples:
|
|
83
|
-
|
|
82
|
+
setData('node1')
|
|
84
83
|
|
|
85
84
|
setData({ name: 'node1', id: 1});
|
|
86
85
|
|
|
@@ -133,16 +132,12 @@ export class Node implements INode {
|
|
|
133
132
|
public loadFromData(data: NodeData[]): Node {
|
|
134
133
|
this.removeChildren();
|
|
135
134
|
|
|
136
|
-
for (const
|
|
137
|
-
const node = this.createNode(
|
|
135
|
+
for (const childData of data) {
|
|
136
|
+
const node = this.createNode(childData);
|
|
138
137
|
this.addChild(node);
|
|
139
138
|
|
|
140
|
-
if (isNodeRecordWithChildren(
|
|
141
|
-
|
|
142
|
-
node.isEmptyFolder = true;
|
|
143
|
-
} else {
|
|
144
|
-
node.loadFromData(o.children);
|
|
145
|
-
}
|
|
139
|
+
if (isNodeRecordWithChildren(childData)) {
|
|
140
|
+
node.loadFromData(childData.children);
|
|
146
141
|
}
|
|
147
142
|
}
|
|
148
143
|
|
|
@@ -254,7 +249,7 @@ export class Node implements INode {
|
|
|
254
249
|
public moveNode(
|
|
255
250
|
movedNode: Node,
|
|
256
251
|
targetNode: Node,
|
|
257
|
-
position: Position
|
|
252
|
+
position: Position,
|
|
258
253
|
): boolean {
|
|
259
254
|
if (!movedNode.parent || movedNode.isParentOf(targetNode)) {
|
|
260
255
|
// - Node is parent of target node
|
|
@@ -268,7 +263,7 @@ export class Node implements INode {
|
|
|
268
263
|
if (targetNode.parent) {
|
|
269
264
|
targetNode.parent.addChildAtPosition(
|
|
270
265
|
movedNode,
|
|
271
|
-
targetNode.parent.getChildIndex(targetNode) + 1
|
|
266
|
+
targetNode.parent.getChildIndex(targetNode) + 1,
|
|
272
267
|
);
|
|
273
268
|
return true;
|
|
274
269
|
}
|
|
@@ -279,7 +274,7 @@ export class Node implements INode {
|
|
|
279
274
|
if (targetNode.parent) {
|
|
280
275
|
targetNode.parent.addChildAtPosition(
|
|
281
276
|
movedNode,
|
|
282
|
-
targetNode.parent.getChildIndex(targetNode)
|
|
277
|
+
targetNode.parent.getChildIndex(targetNode),
|
|
283
278
|
);
|
|
284
279
|
return true;
|
|
285
280
|
}
|
|
@@ -380,13 +375,7 @@ export class Node implements INode {
|
|
|
380
375
|
const childIndex = this.parent.getChildIndex(this);
|
|
381
376
|
this.parent.addChildAtPosition(node, childIndex + 1);
|
|
382
377
|
|
|
383
|
-
|
|
384
|
-
isNodeRecordWithChildren(nodeInfo) &&
|
|
385
|
-
nodeInfo.children.length
|
|
386
|
-
) {
|
|
387
|
-
node.loadFromData(nodeInfo.children);
|
|
388
|
-
}
|
|
389
|
-
|
|
378
|
+
node.loadChildrenFromData(nodeInfo);
|
|
390
379
|
return node;
|
|
391
380
|
}
|
|
392
381
|
}
|
|
@@ -400,13 +389,7 @@ export class Node implements INode {
|
|
|
400
389
|
const childIndex = this.parent.getChildIndex(this);
|
|
401
390
|
this.parent.addChildAtPosition(node, childIndex);
|
|
402
391
|
|
|
403
|
-
|
|
404
|
-
isNodeRecordWithChildren(nodeInfo) &&
|
|
405
|
-
nodeInfo.children.length
|
|
406
|
-
) {
|
|
407
|
-
node.loadFromData(nodeInfo.children);
|
|
408
|
-
}
|
|
409
|
-
|
|
392
|
+
node.loadChildrenFromData(nodeInfo);
|
|
410
393
|
return node;
|
|
411
394
|
}
|
|
412
395
|
}
|
|
@@ -443,10 +426,7 @@ export class Node implements INode {
|
|
|
443
426
|
const node = this.createNode(nodeInfo);
|
|
444
427
|
this.addChild(node);
|
|
445
428
|
|
|
446
|
-
|
|
447
|
-
node.loadFromData(nodeInfo.children);
|
|
448
|
-
}
|
|
449
|
-
|
|
429
|
+
node.loadChildrenFromData(nodeInfo);
|
|
450
430
|
return node;
|
|
451
431
|
}
|
|
452
432
|
|
|
@@ -454,10 +434,7 @@ export class Node implements INode {
|
|
|
454
434
|
const node = this.createNode(nodeInfo);
|
|
455
435
|
this.addChildAtPosition(node, 0);
|
|
456
436
|
|
|
457
|
-
|
|
458
|
-
node.loadFromData(nodeInfo.children);
|
|
459
|
-
}
|
|
460
|
-
|
|
437
|
+
node.loadChildrenFromData(nodeInfo);
|
|
461
438
|
return node;
|
|
462
439
|
}
|
|
463
440
|
|
|
@@ -702,4 +679,11 @@ export class Node implements INode {
|
|
|
702
679
|
const nodeClass = this.getNodeClass();
|
|
703
680
|
return new nodeClass(nodeData);
|
|
704
681
|
}
|
|
682
|
+
|
|
683
|
+
// Load children data from nodeInfo if it has children
|
|
684
|
+
private loadChildrenFromData(nodeInfo: NodeData) {
|
|
685
|
+
if (isNodeRecordWithChildren(nodeInfo) && nodeInfo.children.length) {
|
|
686
|
+
this.loadFromData(nodeInfo.children);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
705
689
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DropHint } from "../dragAndDropHandler/types";
|
|
2
|
+
|
|
3
|
+
class BorderDropHint implements DropHint {
|
|
4
|
+
private hint?: HTMLElement;
|
|
5
|
+
|
|
6
|
+
constructor(element: HTMLElement, scrollLeft: number) {
|
|
7
|
+
const div = element.querySelector(":scope > .jqtree-element");
|
|
8
|
+
|
|
9
|
+
if (!div) {
|
|
10
|
+
this.hint = undefined;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const width = Math.max(element.offsetWidth + scrollLeft - 4, 0);
|
|
15
|
+
const height = Math.max(element.clientHeight - 4, 0);
|
|
16
|
+
|
|
17
|
+
const hint = document.createElement("span");
|
|
18
|
+
hint.className = "jqtree-border";
|
|
19
|
+
hint.style.width = `${width}px`;
|
|
20
|
+
hint.style.height = `${height}px`;
|
|
21
|
+
|
|
22
|
+
this.hint = hint;
|
|
23
|
+
|
|
24
|
+
div.append(this.hint);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public remove(): void {
|
|
28
|
+
this.hint?.remove();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default BorderDropHint;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Position } from "../node";
|
|
2
|
+
import NodeElement, { NodeElementParams } from "./index";
|
|
3
|
+
import { OnFinishOpenNode, TriggerEvent } from "../jqtreeMethodTypes";
|
|
4
|
+
|
|
5
|
+
interface FolderElementParams extends NodeElementParams {
|
|
6
|
+
closedIconElement?: HTMLElement | Text;
|
|
7
|
+
openedIconElement?: HTMLElement | Text;
|
|
8
|
+
triggerEvent: TriggerEvent;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class FolderElement extends NodeElement {
|
|
12
|
+
private closedIconElement?: HTMLElement | Text;
|
|
13
|
+
private openedIconElement?: HTMLElement | Text;
|
|
14
|
+
private triggerEvent: TriggerEvent;
|
|
15
|
+
|
|
16
|
+
constructor({
|
|
17
|
+
closedIconElement,
|
|
18
|
+
getScrollLeft,
|
|
19
|
+
node,
|
|
20
|
+
openedIconElement,
|
|
21
|
+
tabIndex,
|
|
22
|
+
$treeElement,
|
|
23
|
+
triggerEvent,
|
|
24
|
+
}: FolderElementParams) {
|
|
25
|
+
super({
|
|
26
|
+
getScrollLeft,
|
|
27
|
+
node,
|
|
28
|
+
tabIndex,
|
|
29
|
+
$treeElement,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
this.closedIconElement = closedIconElement;
|
|
33
|
+
this.openedIconElement = openedIconElement;
|
|
34
|
+
this.triggerEvent = triggerEvent;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public open(
|
|
38
|
+
onFinished: OnFinishOpenNode | undefined,
|
|
39
|
+
slide = true,
|
|
40
|
+
animationSpeed: JQuery.Duration = "fast",
|
|
41
|
+
): void {
|
|
42
|
+
if (this.node.is_open) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.node.is_open = true;
|
|
47
|
+
|
|
48
|
+
const button = this.getButton();
|
|
49
|
+
button.classList.remove("jqtree-closed");
|
|
50
|
+
button.innerHTML = "";
|
|
51
|
+
|
|
52
|
+
const openedIconElement = this.openedIconElement;
|
|
53
|
+
|
|
54
|
+
if (openedIconElement) {
|
|
55
|
+
const icon = openedIconElement.cloneNode(true);
|
|
56
|
+
button.appendChild(icon);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const doOpen = (): void => {
|
|
60
|
+
this.element.classList.remove("jqtree-closed");
|
|
61
|
+
|
|
62
|
+
const titleSpan = this.getTitleSpan();
|
|
63
|
+
titleSpan.setAttribute("aria-expanded", "true");
|
|
64
|
+
|
|
65
|
+
if (onFinished) {
|
|
66
|
+
onFinished(this.node);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.triggerEvent("tree.open", {
|
|
70
|
+
node: this.node,
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (slide) {
|
|
75
|
+
jQuery(this.getUl()).slideDown(animationSpeed, doOpen);
|
|
76
|
+
} else {
|
|
77
|
+
jQuery(this.getUl()).show();
|
|
78
|
+
doOpen();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public close(
|
|
83
|
+
slide = true,
|
|
84
|
+
animationSpeed: JQuery.Duration | undefined = "fast",
|
|
85
|
+
): void {
|
|
86
|
+
if (!this.node.is_open) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.node.is_open = false;
|
|
91
|
+
|
|
92
|
+
const button = this.getButton();
|
|
93
|
+
button.classList.add("jqtree-closed");
|
|
94
|
+
button.innerHTML = "";
|
|
95
|
+
|
|
96
|
+
const closedIconElement = this.closedIconElement;
|
|
97
|
+
|
|
98
|
+
if (closedIconElement) {
|
|
99
|
+
const icon = closedIconElement.cloneNode(true);
|
|
100
|
+
button.appendChild(icon);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const doClose = (): void => {
|
|
104
|
+
this.element.classList.add("jqtree-closed");
|
|
105
|
+
|
|
106
|
+
const titleSpan = this.getTitleSpan();
|
|
107
|
+
titleSpan.setAttribute("aria-expanded", "false");
|
|
108
|
+
|
|
109
|
+
this.triggerEvent("tree.close", {
|
|
110
|
+
node: this.node,
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (slide) {
|
|
115
|
+
jQuery(this.getUl()).slideUp(animationSpeed, doClose);
|
|
116
|
+
} else {
|
|
117
|
+
jQuery(this.getUl()).hide();
|
|
118
|
+
doClose();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
protected mustShowBorderDropHint(position: Position): boolean {
|
|
123
|
+
return !this.node.is_open && position === Position.Inside;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private getButton(): HTMLLinkElement {
|
|
127
|
+
return this.element.querySelector(
|
|
128
|
+
":scope > .jqtree-element > a.jqtree-toggler",
|
|
129
|
+
) as HTMLLinkElement;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default FolderElement;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Position, Node } from "../node";
|
|
2
|
+
import { DropHint } from "../dragAndDropHandler/types";
|
|
3
|
+
|
|
4
|
+
class GhostDropHint implements DropHint {
|
|
5
|
+
private element: HTMLElement;
|
|
6
|
+
private node: Node;
|
|
7
|
+
private ghost: HTMLElement;
|
|
8
|
+
|
|
9
|
+
constructor(node: Node, element: HTMLElement, position: Position) {
|
|
10
|
+
this.element = element;
|
|
11
|
+
this.node = node;
|
|
12
|
+
this.ghost = this.createGhostElement();
|
|
13
|
+
|
|
14
|
+
if (position === Position.After) {
|
|
15
|
+
this.moveAfter();
|
|
16
|
+
} else if (position === Position.Before) {
|
|
17
|
+
this.moveBefore();
|
|
18
|
+
} else if (position === Position.Inside) {
|
|
19
|
+
if (node.isFolder() && node.is_open) {
|
|
20
|
+
this.moveInsideOpenFolder();
|
|
21
|
+
} else {
|
|
22
|
+
this.moveInside();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public remove(): void {
|
|
28
|
+
this.ghost.remove();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private moveAfter(): void {
|
|
32
|
+
this.element.after(this.ghost);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private moveBefore(): void {
|
|
36
|
+
this.element.before(this.ghost);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private moveInsideOpenFolder(): void {
|
|
40
|
+
const childElement = this.node.children[0]?.element;
|
|
41
|
+
|
|
42
|
+
if (childElement) {
|
|
43
|
+
childElement.before(this.ghost);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private moveInside(): void {
|
|
48
|
+
this.element.after(this.ghost);
|
|
49
|
+
this.ghost.classList.add("jqtree-inside");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private createGhostElement() {
|
|
53
|
+
const ghost = document.createElement("li");
|
|
54
|
+
ghost.className = "jqtree_common jqtree-ghost";
|
|
55
|
+
|
|
56
|
+
const circleSpan = document.createElement("span");
|
|
57
|
+
circleSpan.className = "jqtree_common jqtree-circle";
|
|
58
|
+
ghost.append(circleSpan);
|
|
59
|
+
|
|
60
|
+
const lineSpan = document.createElement("span");
|
|
61
|
+
lineSpan.className = "jqtree_common jqtree-line";
|
|
62
|
+
ghost.append(lineSpan);
|
|
63
|
+
|
|
64
|
+
return ghost;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default GhostDropHint;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Position, Node } from "../node";
|
|
2
|
+
import { DropHint } from "../dragAndDropHandler/types";
|
|
3
|
+
import BorderDropHint from "./borderDropHint";
|
|
4
|
+
import GhostDropHint from "./ghostDropHint";
|
|
5
|
+
import { GetScrollLeft } from "../jqtreeMethodTypes";
|
|
6
|
+
|
|
7
|
+
export interface NodeElementParams {
|
|
8
|
+
getScrollLeft: GetScrollLeft;
|
|
9
|
+
node: Node;
|
|
10
|
+
tabIndex?: number;
|
|
11
|
+
$treeElement: JQuery<HTMLElement>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class NodeElement {
|
|
15
|
+
public node: Node;
|
|
16
|
+
public element: HTMLElement;
|
|
17
|
+
private getScrollLeft: GetScrollLeft;
|
|
18
|
+
private tabIndex?: number;
|
|
19
|
+
private $treeElement: JQuery<HTMLElement>;
|
|
20
|
+
|
|
21
|
+
constructor({
|
|
22
|
+
getScrollLeft,
|
|
23
|
+
node,
|
|
24
|
+
tabIndex,
|
|
25
|
+
$treeElement,
|
|
26
|
+
}: NodeElementParams) {
|
|
27
|
+
this.getScrollLeft = getScrollLeft;
|
|
28
|
+
this.tabIndex = tabIndex;
|
|
29
|
+
this.$treeElement = $treeElement;
|
|
30
|
+
|
|
31
|
+
this.init(node);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public init(node: Node): void {
|
|
35
|
+
this.node = node;
|
|
36
|
+
|
|
37
|
+
if (!node.element) {
|
|
38
|
+
const element = this.$treeElement.get(0);
|
|
39
|
+
|
|
40
|
+
if (element) {
|
|
41
|
+
node.element = element;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (node.element) {
|
|
46
|
+
this.element = node.element;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public addDropHint(position: number): DropHint {
|
|
51
|
+
if (this.mustShowBorderDropHint(position)) {
|
|
52
|
+
return new BorderDropHint(this.element, this.getScrollLeft());
|
|
53
|
+
} else {
|
|
54
|
+
return new GhostDropHint(this.node, this.element, position);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public select(mustSetFocus: boolean): void {
|
|
59
|
+
this.element.classList.add("jqtree-selected");
|
|
60
|
+
|
|
61
|
+
const titleSpan = this.getTitleSpan();
|
|
62
|
+
const tabIndex = this.tabIndex;
|
|
63
|
+
|
|
64
|
+
// Check for null or undefined
|
|
65
|
+
if (tabIndex != null) {
|
|
66
|
+
titleSpan.setAttribute("tabindex", tabIndex.toString());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
titleSpan.setAttribute("aria-selected", "true");
|
|
70
|
+
|
|
71
|
+
if (mustSetFocus) {
|
|
72
|
+
titleSpan.focus();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public deselect(): void {
|
|
77
|
+
this.element.classList.remove("jqtree-selected");
|
|
78
|
+
|
|
79
|
+
const titleSpan = this.getTitleSpan();
|
|
80
|
+
titleSpan.removeAttribute("tabindex");
|
|
81
|
+
titleSpan.setAttribute("aria-selected", "false");
|
|
82
|
+
|
|
83
|
+
titleSpan.blur();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
protected getUl(): HTMLUListElement {
|
|
87
|
+
return this.element.querySelector(":scope > ul") as HTMLUListElement;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
protected getTitleSpan(): HTMLSpanElement {
|
|
91
|
+
return this.element.querySelector(
|
|
92
|
+
":scope > .jqtree-element > span.jqtree-title",
|
|
93
|
+
) as HTMLSpanElement;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected mustShowBorderDropHint(position: Position): boolean {
|
|
97
|
+
return position === Position.Inside;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default NodeElement;
|
package/src/nodeUtils.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface NodeRecordWithChildren extends NodeRecord {
|
|
2
|
+
children: NodeData[];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const isNodeRecordWithChildren = (
|
|
6
|
+
data: NodeData,
|
|
7
|
+
): data is NodeRecordWithChildren =>
|
|
8
|
+
typeof data === "object" &&
|
|
9
|
+
"children" in data &&
|
|
10
|
+
data["children"] instanceof Array;
|
|
@@ -13,14 +13,11 @@ 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
19
|
`playwright_coverage_${generateUUID()}.json`
|
|
22
20
|
);
|
|
23
|
-
console.log(`Writing coverage to ${filename}`);
|
|
24
21
|
fs.writeFileSync(filename, coverageJSON);
|
|
25
22
|
}
|
|
26
23
|
}
|