@ubio/webvision 1.2.6 → 2.1.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/build/page.mjs +760 -355
- package/out/page/counter.d.ts +6 -0
- package/out/page/counter.js +13 -0
- package/out/page/counter.js.map +1 -0
- package/out/page/dom.d.ts +21 -0
- package/out/page/dom.js +172 -0
- package/out/page/dom.js.map +1 -0
- package/out/page/frame.d.ts +22 -0
- package/out/page/frame.js +69 -0
- package/out/page/frame.js.map +1 -0
- package/out/page/index.d.ts +9 -3
- package/out/page/index.js +9 -3
- package/out/page/index.js.map +1 -1
- package/out/page/overlay.d.ts +3 -0
- package/out/page/overlay.js +75 -0
- package/out/page/overlay.js.map +1 -0
- package/out/page/parser.d.ts +59 -0
- package/out/page/parser.js +249 -0
- package/out/page/parser.js.map +1 -0
- package/out/page/probe.d.ts +5 -0
- package/out/page/probe.js +36 -0
- package/out/page/probe.js.map +1 -0
- package/out/page/render.d.ts +12 -8
- package/out/page/render.js +73 -38
- package/out/page/render.js.map +1 -1
- package/out/page/snapshot.d.ts +9 -68
- package/out/page/snapshot.js +23 -183
- package/out/page/snapshot.js.map +1 -1
- package/out/page/traverse.d.ts +5 -0
- package/out/page/traverse.js +7 -0
- package/out/page/traverse.js.map +1 -0
- package/out/page/tree.d.ts +22 -0
- package/out/page/tree.js +59 -0
- package/out/page/tree.js.map +1 -0
- package/out/page/util.d.ts +3 -0
- package/out/page/util.js +9 -0
- package/out/page/util.js.map +1 -0
- package/package.json +6 -3
- package/out/page/highlight.d.ts +0 -5
- package/out/page/highlight.js +0 -72
- package/out/page/highlight.js.map +0 -1
- package/out/page/html.d.ts +0 -4
- package/out/page/html.js +0 -42
- package/out/page/html.js.map +0 -1
- package/out/page/utils.d.ts +0 -19
- package/out/page/utils.js +0 -68
- package/out/page/utils.js.map +0 -1
package/build/page.mjs
CHANGED
@@ -1,243 +1,254 @@
|
|
1
|
-
// src/page/
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
container.innerHTML = "";
|
6
|
-
highlightRecursive(snapshot, refMap, container);
|
7
|
-
}
|
8
|
-
function highlightRecursive(snapshot, refMap, container) {
|
9
|
-
highlightEl(snapshot, refMap, container);
|
10
|
-
for (const child of snapshot.children ?? []) {
|
11
|
-
highlightRecursive(child, refMap, container);
|
12
|
-
}
|
13
|
-
}
|
14
|
-
function highlightEl(snapshot, refMap, container) {
|
15
|
-
const isContainerEl = !snapshot.leaf && snapshot.children?.every((child) => child.nodeType === "element");
|
16
|
-
if (isContainerEl) {
|
17
|
-
return;
|
1
|
+
// src/page/counter.ts
|
2
|
+
var Counter = class {
|
3
|
+
constructor(value = 0) {
|
4
|
+
this.value = value;
|
18
5
|
}
|
19
|
-
|
20
|
-
|
21
|
-
return;
|
6
|
+
next() {
|
7
|
+
this.value += 1;
|
8
|
+
return this.value;
|
22
9
|
}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
10
|
+
current() {
|
11
|
+
return this.value;
|
12
|
+
}
|
13
|
+
};
|
14
|
+
|
15
|
+
// src/page/dom.ts
|
16
|
+
var ORIGINAL_STYLE_SYMBOL = Symbol("vx:originalStyle");
|
17
|
+
var INTERACTIVE_TAGS = ["a", "button", "input", "textarea", "select", "label"];
|
18
|
+
var INTERACTIVE_ROLES = [
|
19
|
+
"button",
|
20
|
+
"link",
|
21
|
+
"checkbox",
|
22
|
+
"radio",
|
23
|
+
"textbox",
|
24
|
+
"combobox",
|
25
|
+
"listbox",
|
26
|
+
"menu",
|
27
|
+
"menuitem",
|
28
|
+
"menuitemcheckbox",
|
29
|
+
"menuitemradio",
|
30
|
+
"option",
|
31
|
+
"optgroup",
|
32
|
+
"progressbar",
|
33
|
+
"scrollbar",
|
34
|
+
"slider",
|
35
|
+
"spinbutton",
|
36
|
+
"switch",
|
37
|
+
"tab",
|
38
|
+
"tablist",
|
39
|
+
"timer",
|
40
|
+
"toolbar"
|
41
|
+
];
|
42
|
+
function isHidden(el) {
|
43
|
+
const style = getComputedStyle(el);
|
44
|
+
if (style.display === "none") {
|
45
|
+
return true;
|
46
|
+
}
|
47
|
+
if (style.visibility === "hidden") {
|
48
|
+
return true;
|
49
|
+
}
|
50
|
+
if (style.opacity === "0") {
|
51
|
+
return true;
|
52
|
+
}
|
53
|
+
return false;
|
48
54
|
}
|
49
|
-
function
|
50
|
-
|
51
|
-
document.documentElement.removeChild(container);
|
55
|
+
function getNormalizedText(el) {
|
56
|
+
return normalizeText(el.textContent ?? "");
|
52
57
|
}
|
53
|
-
function
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
container.style.pointerEvents = "none";
|
60
|
-
container.style.top = "0";
|
61
|
-
container.style.left = "0";
|
62
|
-
container.style.width = "100%";
|
63
|
-
container.style.height = "100%";
|
64
|
-
container.style.zIndex = "2147483646";
|
65
|
-
document.documentElement.appendChild(container);
|
58
|
+
function normalizeText(str) {
|
59
|
+
return str.replace(/\p{Cf}/gu, " ").replace(/\s+/g, " ").trim();
|
60
|
+
}
|
61
|
+
function truncateAttrValue(value, limit = 100) {
|
62
|
+
if (value.match(/^(javascript:)?void/)) {
|
63
|
+
return "";
|
66
64
|
}
|
67
|
-
|
65
|
+
if (value.startsWith("data:")) {
|
66
|
+
return "";
|
67
|
+
}
|
68
|
+
if (value.length > limit) {
|
69
|
+
return value.slice(0, limit) + "\u2026";
|
70
|
+
}
|
71
|
+
return value;
|
68
72
|
}
|
69
|
-
function
|
70
|
-
|
71
|
-
return `hsl(${hue}, 85%, 50%)`;
|
73
|
+
function escapeAttribute(value) {
|
74
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/\r?\n/g, " ");
|
72
75
|
}
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
let
|
76
|
+
function containsSelector(el, selector) {
|
77
|
+
return el.matches(selector) || !!el.querySelector(selector);
|
78
|
+
}
|
79
|
+
function getOffsetTop(node) {
|
80
|
+
let y = 0;
|
81
|
+
let current = node;
|
78
82
|
while (current) {
|
79
|
-
|
80
|
-
current = current.
|
81
|
-
}
|
82
|
-
if (includeText) {
|
83
|
-
const anyEl = el;
|
84
|
-
path.unshift(anyEl.value || anyEl.innerText || anyEl.textContent || "");
|
83
|
+
y += current.offsetTop ?? 0;
|
84
|
+
current = current.offsetParent;
|
85
85
|
}
|
86
|
-
return
|
86
|
+
return y;
|
87
87
|
}
|
88
|
-
function
|
89
|
-
const
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
return
|
88
|
+
function hasVisibleArea(element) {
|
89
|
+
const rect = element.getBoundingClientRect();
|
90
|
+
const area = rect.width * rect.height;
|
91
|
+
return area > 64;
|
92
|
+
}
|
93
|
+
function isDeepHidden(element) {
|
94
|
+
if (isHidden(element)) {
|
95
|
+
return true;
|
96
96
|
}
|
97
|
-
if (
|
98
|
-
return el
|
97
|
+
if (!hasVisibleArea(element)) {
|
98
|
+
return [...element.children].every((el) => isDeepHidden(el));
|
99
99
|
}
|
100
|
-
return
|
100
|
+
return false;
|
101
101
|
}
|
102
|
-
function
|
103
|
-
|
104
|
-
|
105
|
-
return
|
106
|
-
captureHtmlLine(el),
|
107
|
-
anyEl.value || anyEl.innerText || anyEl.textContent || "",
|
108
|
-
`</${el.tagName.toLowerCase()}>`
|
109
|
-
].filter(Boolean).join("");
|
102
|
+
function isInteractive(el) {
|
103
|
+
const htmlEl = el;
|
104
|
+
if (INTERACTIVE_TAGS.includes(el.tagName.toLowerCase())) {
|
105
|
+
return true;
|
110
106
|
}
|
111
|
-
|
112
|
-
|
107
|
+
const tabindex = htmlEl.getAttribute("tabindex");
|
108
|
+
if (tabindex && parseInt(tabindex) >= 0) {
|
109
|
+
return true;
|
110
|
+
}
|
111
|
+
const role = htmlEl.getAttribute("role") ?? htmlEl.getAttribute("aria-role") ?? "";
|
112
|
+
if (INTERACTIVE_ROLES.includes(role)) {
|
113
|
+
return true;
|
114
|
+
}
|
115
|
+
if (htmlEl.onclick != null) {
|
116
|
+
return true;
|
113
117
|
}
|
114
|
-
return
|
118
|
+
return false;
|
115
119
|
}
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
depth: 0,
|
121
|
-
includeRef: false,
|
122
|
-
includeClassList: false,
|
123
|
-
...options
|
120
|
+
function getViewportSize() {
|
121
|
+
return {
|
122
|
+
width: window.innerWidth,
|
123
|
+
height: window.innerHeight
|
124
124
|
};
|
125
|
-
|
126
|
-
|
125
|
+
}
|
126
|
+
function isRectInViewport(rect, viewport) {
|
127
|
+
return rect.left < viewport.width && rect.right > 0 && rect.top < viewport.height && rect.bottom > 0;
|
128
|
+
}
|
129
|
+
function makeOverlaysOpaque(el) {
|
130
|
+
if (!el[ORIGINAL_STYLE_SYMBOL]) {
|
131
|
+
el[ORIGINAL_STYLE_SYMBOL] = el.getAttribute("style");
|
127
132
|
}
|
128
|
-
const
|
129
|
-
|
130
|
-
|
131
|
-
for (const child of snapshot.children ?? []) {
|
132
|
-
const childSnapshot = renderSnapshot(child, {
|
133
|
-
...opts,
|
134
|
-
depth: opts.depth + 1
|
135
|
-
});
|
136
|
-
if (childSnapshot) {
|
137
|
-
buffer.push(childSnapshot);
|
138
|
-
}
|
133
|
+
const rect = el.getBoundingClientRect();
|
134
|
+
if (rect.width < 500 || rect.height < 500) {
|
135
|
+
return;
|
139
136
|
}
|
140
|
-
|
137
|
+
const style = getComputedStyle(el);
|
138
|
+
if (style.pointerEvents === "none") {
|
139
|
+
return;
|
140
|
+
}
|
141
|
+
el.style.setProperty("animation", "none", "important");
|
142
|
+
el.style.setProperty("transition", "none", "important");
|
143
|
+
el.style.setProperty("backdrop-filter", "none", "important");
|
144
|
+
el.style.setProperty("mix-blend-mode", "normal", "important");
|
145
|
+
el.style.setProperty("opacity", "1", "important");
|
146
|
+
el.style.setProperty("filter", "none", "important");
|
147
|
+
const bg = style.backgroundColor;
|
148
|
+
el.style.setProperty("background-color", removeAlpha(bg));
|
141
149
|
}
|
142
|
-
function
|
143
|
-
const
|
144
|
-
|
145
|
-
|
146
|
-
return [indent, snapshot.textContent].filter(Boolean).join(" ");
|
150
|
+
function removeAlpha(color) {
|
151
|
+
const rgba = color.match(/^rgba\((.*)\)$/);
|
152
|
+
if (!rgba) {
|
153
|
+
return color;
|
147
154
|
}
|
148
|
-
|
149
|
-
if (
|
150
|
-
|
155
|
+
const [r, g, b, a] = rgba[1].split(",").map(parseFloat);
|
156
|
+
if (a > 0 && a < 1) {
|
157
|
+
return `rgba(${r},${g},${b},1)`;
|
151
158
|
}
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
+
return color;
|
160
|
+
}
|
161
|
+
function isRandomIdentifier(str) {
|
162
|
+
const words = str.split(/[_-]/g);
|
163
|
+
return !words.some((w) => isWordLike(w)) || words.some((w) => isRandomString(w));
|
164
|
+
}
|
165
|
+
function isWordLike(str) {
|
166
|
+
if (str.length <= 2) {
|
167
|
+
return false;
|
159
168
|
}
|
160
|
-
if (
|
161
|
-
|
169
|
+
if (/[^eyuioa]{4,}/.test(str)) {
|
170
|
+
return false;
|
162
171
|
}
|
163
|
-
if (
|
164
|
-
|
172
|
+
if (/[eyuioa]{4,}/.test(str)) {
|
173
|
+
return false;
|
165
174
|
}
|
166
|
-
return
|
175
|
+
return true;
|
167
176
|
}
|
168
|
-
|
169
|
-
|
170
|
-
function isHidden(element, options = {}) {
|
171
|
-
const {
|
172
|
-
checkOpacity = true,
|
173
|
-
checkVisibility = true,
|
174
|
-
checkTransform = true
|
175
|
-
} = options;
|
176
|
-
const style = getComputedStyle(element);
|
177
|
-
const opacity = Number(style.opacity);
|
178
|
-
const display = style.display;
|
179
|
-
const visibility = style.visibility;
|
180
|
-
const transform = style.transform;
|
181
|
-
if (display === "none" || checkOpacity && opacity === 0 || checkVisibility && visibility === "hidden" || checkTransform && transform.includes("scale(0)")) {
|
177
|
+
function isRandomString(str) {
|
178
|
+
if (/^[0-9a-f]+$/i.test(str) && /[0-9]/.test(str)) {
|
182
179
|
return true;
|
183
180
|
}
|
184
|
-
if (
|
181
|
+
if (/[0-9][^0-9]+[0-9]/.test(str)) {
|
185
182
|
return true;
|
186
183
|
}
|
187
184
|
return false;
|
188
185
|
}
|
189
|
-
function
|
190
|
-
const
|
191
|
-
|
192
|
-
|
193
|
-
}
|
194
|
-
function deepIsHidden(element, options = {}) {
|
195
|
-
if (isHidden(element, options)) {
|
196
|
-
return true;
|
197
|
-
}
|
198
|
-
if (!hasVisibleArea(element)) {
|
199
|
-
return [...element.children].every((el) => deepIsHidden(el, options));
|
186
|
+
function fixZIndex(el) {
|
187
|
+
const style = getComputedStyle(el);
|
188
|
+
if (Number(style.zIndex) > 2147483600) {
|
189
|
+
el.style.setProperty("z-index", "2147483600", "important");
|
200
190
|
}
|
201
|
-
return false;
|
202
|
-
}
|
203
|
-
function normalizeText(str) {
|
204
|
-
return str.replace(/\p{Cf}/gu, " ").replace(/\s+/g, " ").trim();
|
205
|
-
}
|
206
|
-
function containsSelector(el, selector) {
|
207
|
-
return el.matches(selector) || !!el.querySelector(selector);
|
208
191
|
}
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
192
|
+
|
193
|
+
// src/page/probe.ts
|
194
|
+
function probeViewport(gridSize = 32) {
|
195
|
+
const { width, height } = getViewportSize();
|
196
|
+
const elements = [];
|
197
|
+
for (let y = gridSize / 2; y < height; y += gridSize) {
|
198
|
+
for (let x = gridSize / 2; x < width; x += gridSize) {
|
199
|
+
const element = document.elementFromPoint(x, y);
|
200
|
+
if (element && !elements.includes(element)) {
|
201
|
+
elements.push(element);
|
214
202
|
}
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
203
|
+
}
|
204
|
+
}
|
205
|
+
return elements;
|
206
|
+
}
|
207
|
+
function checkOccluded(element, gridSize = 8) {
|
208
|
+
let total = 0;
|
209
|
+
let hits = 0;
|
210
|
+
const { top, left, width, height } = element.getBoundingClientRect();
|
211
|
+
for (let x = left + gridSize / 2; x < left + width; x += gridSize) {
|
212
|
+
for (let y = top + gridSize / 2; y < top + height; y += gridSize) {
|
213
|
+
total++;
|
214
|
+
const el = document.elementFromPoint(x, y);
|
215
|
+
if (!el) {
|
216
|
+
continue;
|
219
217
|
}
|
220
|
-
if (
|
221
|
-
|
218
|
+
if (element.contains(el) || el.contains(element)) {
|
219
|
+
hits++;
|
222
220
|
}
|
223
221
|
}
|
224
222
|
}
|
225
|
-
return
|
223
|
+
return hits / total < 0.5;
|
226
224
|
}
|
227
225
|
|
228
|
-
// src/page/
|
229
|
-
|
230
|
-
|
226
|
+
// src/page/util.ts
|
227
|
+
function isContainerNode(vxNode) {
|
228
|
+
const children = vxNode.children ?? [];
|
229
|
+
const hasTextChildren = children.some((child) => !child.tagName);
|
230
|
+
return children.length > 0 && !hasTextChildren;
|
231
|
+
}
|
232
|
+
function isObjectEmpty(obj) {
|
233
|
+
return !Object.values(obj).some((value) => !!value);
|
234
|
+
}
|
235
|
+
|
236
|
+
// src/page/parser.ts
|
237
|
+
var VX_NODE_SYMBOL = Symbol("vx:node");
|
238
|
+
var VX_IGNORE_SYMBOL = Symbol("vx:ignore");
|
239
|
+
var VX_IGNORE_TAGS = ["svg", "script", "noscript", "style", "link", "meta"];
|
240
|
+
var VX_LABEL_ATTRS = ["title", "alt", "placeholder", "aria-label"];
|
241
|
+
var VX_VALUE_ATTRS = ["value", "checked", "selected", "disabled", "readonly"];
|
242
|
+
var VX_SRC_ATTRS = ["src", "href"];
|
243
|
+
var VX_TAG_PREFERENCE = [
|
231
244
|
"a",
|
245
|
+
"iframe",
|
246
|
+
"input",
|
232
247
|
"button",
|
248
|
+
"select",
|
249
|
+
"textarea",
|
250
|
+
"img",
|
233
251
|
"label",
|
234
|
-
"section",
|
235
|
-
"article",
|
236
|
-
"main",
|
237
|
-
"header",
|
238
|
-
"footer",
|
239
|
-
"nav",
|
240
|
-
"aside",
|
241
252
|
"h1",
|
242
253
|
"h2",
|
243
254
|
"h3",
|
@@ -250,6 +261,20 @@ var DEFAULT_SEMANTIC_TAGS = [
|
|
250
261
|
"dl",
|
251
262
|
"dt",
|
252
263
|
"dd",
|
264
|
+
"section",
|
265
|
+
"article",
|
266
|
+
"main",
|
267
|
+
"header",
|
268
|
+
"footer",
|
269
|
+
"nav",
|
270
|
+
"aside",
|
271
|
+
"form",
|
272
|
+
"input",
|
273
|
+
"textarea",
|
274
|
+
"select",
|
275
|
+
"option",
|
276
|
+
"fieldset",
|
277
|
+
"legend",
|
253
278
|
"p",
|
254
279
|
"pre",
|
255
280
|
"code",
|
@@ -262,204 +287,584 @@ var DEFAULT_SEMANTIC_TAGS = [
|
|
262
287
|
"tr",
|
263
288
|
"td",
|
264
289
|
"th",
|
265
|
-
"form",
|
266
|
-
"input",
|
267
|
-
"textarea",
|
268
|
-
"select",
|
269
|
-
"option",
|
270
|
-
"fieldset",
|
271
|
-
"legend",
|
272
290
|
"strong",
|
273
291
|
"em",
|
274
292
|
"sub",
|
275
293
|
"sup"
|
276
294
|
];
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
});
|
281
|
-
const opts = {
|
282
|
-
startId: 0,
|
283
|
-
skipHidden: true,
|
284
|
-
skipEmptyText: true,
|
285
|
-
skipImages: false,
|
286
|
-
skipIframes: false,
|
287
|
-
skipTags: DEFAULT_SKIP_TAGS,
|
288
|
-
tagPreference: DEFAULT_SEMANTIC_TAGS,
|
289
|
-
collapseInline: true,
|
290
|
-
...options
|
291
|
-
};
|
292
|
-
const counter = new Counter(opts.startId);
|
293
|
-
const refMap = /* @__PURE__ */ new Map();
|
294
|
-
const tree = new SnapshotTree(root, null, counter, opts);
|
295
|
-
tree.fillMap(refMap);
|
296
|
-
return {
|
297
|
-
refMap,
|
298
|
-
snapshot: tree.toJson(),
|
299
|
-
maxId: counter.value
|
300
|
-
};
|
301
|
-
}
|
302
|
-
var SnapshotTree = class _SnapshotTree {
|
303
|
-
constructor(node, parent, counter, options) {
|
304
|
-
this.node = node;
|
305
|
-
this.parent = parent;
|
306
|
-
this.counter = counter;
|
295
|
+
var VX_KEEP_SELECTOR = "a, button, input, textarea, select, label, iframe";
|
296
|
+
var VxTreeParser = class {
|
297
|
+
constructor(options = {}) {
|
307
298
|
this.options = options;
|
308
|
-
this.
|
309
|
-
this.
|
310
|
-
|
311
|
-
|
312
|
-
|
299
|
+
this.probeElements = [];
|
300
|
+
this.domRefMap = /* @__PURE__ */ new Map();
|
301
|
+
const { startRef = 0 } = options;
|
302
|
+
this.viewport = getViewportSize();
|
303
|
+
this.counter = new Counter(startRef);
|
304
|
+
if (options.probeViewport) {
|
305
|
+
this.probeElements = probeViewport(8);
|
313
306
|
}
|
307
|
+
const vxRoot = this.parseDocument();
|
308
|
+
this.refRange = [startRef, this.counter.current()];
|
309
|
+
this.vxNodes = this.pruneRecursive(vxRoot);
|
314
310
|
}
|
315
|
-
|
316
|
-
return this.
|
311
|
+
parseDocument() {
|
312
|
+
return this.parseNode(document.documentElement, null);
|
317
313
|
}
|
318
|
-
|
319
|
-
return this.
|
314
|
+
getNodes() {
|
315
|
+
return this.vxNodes;
|
320
316
|
}
|
321
|
-
|
322
|
-
return this.
|
317
|
+
getRefRange() {
|
318
|
+
return this.refRange;
|
323
319
|
}
|
324
|
-
|
325
|
-
return this.
|
320
|
+
getDomMap() {
|
321
|
+
return this.domRefMap;
|
326
322
|
}
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
323
|
+
parseNode(node, parent) {
|
324
|
+
if (node[VX_IGNORE_SYMBOL]) {
|
325
|
+
return null;
|
326
|
+
}
|
327
|
+
if (node instanceof Text) {
|
328
|
+
const textContent = normalizeText(node.textContent ?? "");
|
329
|
+
if (textContent) {
|
330
|
+
return this.makeNode(node, {
|
331
|
+
textContent,
|
332
|
+
hasVisibleArea: parent?.hasVisibleArea,
|
333
|
+
isOutsideViewport: parent?.isOutsideViewport,
|
334
|
+
isProbeHit: parent?.isProbeHit
|
335
|
+
});
|
336
|
+
}
|
337
|
+
return null;
|
338
|
+
}
|
339
|
+
if (node instanceof Element) {
|
340
|
+
if (this.options.opaqueOverlays) {
|
341
|
+
makeOverlaysOpaque(node);
|
342
|
+
}
|
343
|
+
fixZIndex(node);
|
344
|
+
return this.parseElement(node);
|
345
|
+
}
|
346
|
+
return null;
|
332
347
|
}
|
333
|
-
|
334
|
-
if (
|
335
|
-
return
|
348
|
+
parseElement(el) {
|
349
|
+
if (VX_IGNORE_TAGS.includes(el.tagName.toLowerCase())) {
|
350
|
+
return null;
|
351
|
+
}
|
352
|
+
if (isHidden(el)) {
|
353
|
+
return null;
|
336
354
|
}
|
337
|
-
const
|
338
|
-
|
339
|
-
|
355
|
+
const rect = el.getBoundingClientRect();
|
356
|
+
const id = el.getAttribute("id") ?? "";
|
357
|
+
const vxNode = this.makeNode(el, {
|
358
|
+
tagName: el.tagName.toLowerCase(),
|
359
|
+
id: isRandomIdentifier(id) ? void 0 : id,
|
360
|
+
classList: Array.from(el.classList).filter((cls) => !isRandomIdentifier(cls)).slice(0, 4),
|
361
|
+
labelAttrs: this.collectLabelAttrs(el),
|
362
|
+
valueAttrs: this.collectValueAttrs(el),
|
363
|
+
srcAttrs: this.collectSrcAttrs(el),
|
364
|
+
hasVisibleArea: hasVisibleArea(el),
|
365
|
+
isInteractive: isInteractive(el),
|
366
|
+
isOutsideViewport: !isRectInViewport(rect, this.viewport),
|
367
|
+
isProbeHit: this.isProbeHit(el),
|
368
|
+
isKept: el.matches(VX_KEEP_SELECTOR)
|
369
|
+
});
|
370
|
+
const children = [...el.childNodes].map((child) => this.parseNode(child, vxNode)).filter((_) => _ != null);
|
371
|
+
if (children.length === 1 && !children[0]?.tagName) {
|
372
|
+
vxNode.textContent = normalizeText(children[0].textContent ?? "");
|
373
|
+
} else {
|
374
|
+
vxNode.children = children;
|
375
|
+
}
|
376
|
+
return vxNode;
|
377
|
+
}
|
378
|
+
makeNode(node, spec) {
|
379
|
+
const ref = this.counter.next();
|
380
|
+
const vxNode = {
|
381
|
+
...spec,
|
382
|
+
ref
|
383
|
+
};
|
384
|
+
this.domRefMap.set(ref, node);
|
385
|
+
node[VX_NODE_SYMBOL] = vxNode;
|
386
|
+
return vxNode;
|
340
387
|
}
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
return this.collapseWrapper(el, childNodes[0]);
|
388
|
+
pruneRecursive(vxNode) {
|
389
|
+
if (!vxNode) {
|
390
|
+
return [];
|
345
391
|
}
|
346
|
-
|
347
|
-
|
392
|
+
const children = vxNode.children ?? [];
|
393
|
+
const newChildren = children.flatMap((child) => this.pruneRecursive(child));
|
394
|
+
if (this.shouldOmit(vxNode)) {
|
395
|
+
return newChildren;
|
348
396
|
}
|
349
|
-
|
350
|
-
|
351
|
-
|
397
|
+
vxNode.children = newChildren;
|
398
|
+
if (newChildren.length === 1) {
|
399
|
+
const child = newChildren[0];
|
400
|
+
return this.collapseSingleChild(vxNode, child);
|
352
401
|
}
|
402
|
+
return [vxNode];
|
403
|
+
}
|
404
|
+
collapseSingleChild(parent, child) {
|
405
|
+
const preferParent = this.collapsePreferParent(parent, child);
|
406
|
+
const merged = preferParent ? this.collapseMerge(parent, child) : this.collapseMerge(child, parent);
|
407
|
+
return this.pruneRecursive({
|
408
|
+
...merged,
|
409
|
+
children: child.children,
|
410
|
+
textContent: child.textContent
|
411
|
+
});
|
412
|
+
}
|
413
|
+
collapsePreferParent(parent, child) {
|
414
|
+
const parentRank = VX_TAG_PREFERENCE.indexOf(parent.tagName ?? "");
|
415
|
+
const childRank = VX_TAG_PREFERENCE.indexOf(child.tagName ?? "");
|
416
|
+
if (parentRank === -1 && childRank === -1) {
|
417
|
+
const parentAttrCount = Object.keys({
|
418
|
+
...parent.labelAttrs,
|
419
|
+
...parent.valueAttrs,
|
420
|
+
...parent.srcAttrs
|
421
|
+
}).length;
|
422
|
+
const childAttrCount = Object.keys({
|
423
|
+
...child.labelAttrs,
|
424
|
+
...child.valueAttrs,
|
425
|
+
...child.srcAttrs
|
426
|
+
}).length;
|
427
|
+
return parentAttrCount > childAttrCount;
|
428
|
+
}
|
429
|
+
return parentRank !== -1 && (childRank === -1 || parentRank < childRank);
|
353
430
|
}
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
431
|
+
collapseMerge(a, b) {
|
432
|
+
return {
|
433
|
+
...b,
|
434
|
+
...a,
|
435
|
+
labelAttrs: { ...b.labelAttrs, ...a.labelAttrs },
|
436
|
+
valueAttrs: { ...b.valueAttrs, ...a.valueAttrs },
|
437
|
+
srcAttrs: { ...b.srcAttrs, ...a.srcAttrs }
|
438
|
+
};
|
439
|
+
}
|
440
|
+
shouldOmit(vxNode) {
|
441
|
+
const tagName = vxNode.tagName ?? "";
|
442
|
+
if (!vxNode.hasVisibleArea) {
|
443
|
+
return true;
|
444
|
+
}
|
445
|
+
if (this.options.viewportOnly && vxNode.isOutsideViewport) {
|
446
|
+
return true;
|
364
447
|
}
|
365
|
-
this.
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
448
|
+
if (this.options.probeViewport && !vxNode.isProbeHit) {
|
449
|
+
return true;
|
450
|
+
}
|
451
|
+
if (this.options.skipImages && vxNode.tagName === "img") {
|
452
|
+
return true;
|
453
|
+
}
|
454
|
+
const hasText = !!vxNode.textContent;
|
455
|
+
const hasChildren = (vxNode.children ?? []).length > 0;
|
456
|
+
const hasAttrs = [vxNode.labelAttrs, vxNode.valueAttrs, vxNode.srcAttrs].some((attrs) => !isObjectEmpty(attrs ?? {}));
|
457
|
+
if (this.options.unnestDivs) {
|
458
|
+
const isDivOrSpan = ["div", "span"].includes(tagName);
|
459
|
+
if (isDivOrSpan && hasChildren && !hasAttrs) {
|
460
|
+
return true;
|
461
|
+
}
|
371
462
|
}
|
372
|
-
if (
|
373
|
-
|
463
|
+
if (vxNode.isKept) {
|
464
|
+
return false;
|
374
465
|
}
|
466
|
+
return !hasText && !hasAttrs && !hasChildren;
|
375
467
|
}
|
376
|
-
|
377
|
-
const
|
378
|
-
|
379
|
-
|
380
|
-
return false;
|
468
|
+
isProbeHit(el) {
|
469
|
+
for (const probeEl of this.probeElements) {
|
470
|
+
if (el.contains(probeEl) || probeEl.contains(el)) {
|
471
|
+
return true;
|
381
472
|
}
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
}
|
392
|
-
if (!this.options.skipImages && containsSelector(node, "img")) {
|
393
|
-
return true;
|
394
|
-
}
|
395
|
-
if (this.options.skipTags.includes(node.tagName.toLowerCase())) {
|
396
|
-
return false;
|
397
|
-
}
|
473
|
+
}
|
474
|
+
return false;
|
475
|
+
}
|
476
|
+
collectLabelAttrs(el) {
|
477
|
+
const attrs = {};
|
478
|
+
for (const attr of VX_LABEL_ATTRS) {
|
479
|
+
const value = truncateAttrValue(el.getAttribute(attr) ?? "");
|
480
|
+
if (value) {
|
481
|
+
attrs[attr] = value;
|
398
482
|
}
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
483
|
+
}
|
484
|
+
return attrs;
|
485
|
+
}
|
486
|
+
collectValueAttrs(el) {
|
487
|
+
const attrs = {};
|
488
|
+
for (const attr of VX_VALUE_ATTRS) {
|
489
|
+
const value = el[attr] ?? "";
|
490
|
+
if (value) {
|
491
|
+
attrs[attr] = String(value);
|
404
492
|
}
|
405
|
-
|
406
|
-
|
493
|
+
}
|
494
|
+
return attrs;
|
495
|
+
}
|
496
|
+
collectSrcAttrs(el) {
|
497
|
+
const attrs = {};
|
498
|
+
for (const attr of VX_SRC_ATTRS) {
|
499
|
+
const value = truncateAttrValue(el[attr] ?? "");
|
500
|
+
if (value) {
|
501
|
+
attrs[attr] = value;
|
502
|
+
}
|
503
|
+
}
|
504
|
+
return attrs;
|
505
|
+
}
|
506
|
+
};
|
507
|
+
|
508
|
+
// src/page/overlay.ts
|
509
|
+
function showPoint(x, y, clear = true) {
|
510
|
+
if (clear) {
|
511
|
+
clearOverlay();
|
512
|
+
}
|
513
|
+
const point = document.createElement("div");
|
514
|
+
point.style.position = "absolute";
|
515
|
+
point.style.left = `${x}px`;
|
516
|
+
point.style.top = `${y}px`;
|
517
|
+
point.style.width = "32px";
|
518
|
+
point.style.height = "32px";
|
519
|
+
point.style.transform = "translate(-50%, -50%)";
|
520
|
+
point.style.backgroundColor = "red";
|
521
|
+
point.style.borderRadius = "100%";
|
522
|
+
point.style.opacity = "0.5";
|
523
|
+
const container = getOverlayContainer();
|
524
|
+
container.appendChild(point);
|
525
|
+
}
|
526
|
+
function clearOverlay() {
|
527
|
+
const container = getOverlayContainer();
|
528
|
+
container.remove();
|
529
|
+
}
|
530
|
+
function highlightEl(el, ref = 0) {
|
531
|
+
if (!(el instanceof Element)) {
|
532
|
+
return;
|
533
|
+
}
|
534
|
+
const container = getOverlayContainer();
|
535
|
+
const color = getColor(ref);
|
536
|
+
const rect = el.getBoundingClientRect();
|
537
|
+
const overlay = document.createElement("div");
|
538
|
+
container.appendChild(overlay);
|
539
|
+
overlay.style.position = "absolute";
|
540
|
+
overlay.style.top = `${rect.top}px`;
|
541
|
+
overlay.style.left = `${rect.left}px`;
|
542
|
+
overlay.style.width = `${rect.width}px`;
|
543
|
+
overlay.style.height = `${rect.height}px`;
|
544
|
+
overlay.style.border = `2px solid ${color}`;
|
545
|
+
const label = document.createElement("div");
|
546
|
+
overlay.appendChild(label);
|
547
|
+
label.style.position = "absolute";
|
548
|
+
label.style.bottom = `100%`;
|
549
|
+
label.style.left = `0`;
|
550
|
+
label.style.backgroundColor = color;
|
551
|
+
label.style.color = "white";
|
552
|
+
label.style.fontSize = "10px";
|
553
|
+
label.style.fontFamily = "monospace";
|
554
|
+
label.style.fontWeight = "normal";
|
555
|
+
label.style.fontStyle = "normal";
|
556
|
+
label.style.opacity = "0.8";
|
557
|
+
label.style.padding = "0 2px";
|
558
|
+
label.style.transform = "translateY(50%)";
|
559
|
+
label.textContent = String(ref);
|
560
|
+
}
|
561
|
+
function getOverlayContainer() {
|
562
|
+
let container = document.querySelector("#webvision-overlay");
|
563
|
+
if (!container) {
|
564
|
+
container = document.createElement("div");
|
565
|
+
container[VX_IGNORE_SYMBOL] = true;
|
566
|
+
container.id = "webvision-overlay";
|
567
|
+
container.style.position = "fixed";
|
568
|
+
container.style.top = "0";
|
569
|
+
container.style.left = "0";
|
570
|
+
container.style.bottom = "0";
|
571
|
+
container.style.right = "0";
|
572
|
+
container.style.zIndex = "2147483647";
|
573
|
+
container.style.pointerEvents = "none";
|
574
|
+
document.body.appendChild(container);
|
575
|
+
}
|
576
|
+
return container;
|
577
|
+
}
|
578
|
+
function getColor(index) {
|
579
|
+
const hue = index * 120 * 0.382 % 360;
|
580
|
+
return `hsl(${hue}, 85%, 50%)`;
|
581
|
+
}
|
582
|
+
|
583
|
+
// src/page/traverse.ts
|
584
|
+
function* traverseVxNode(vxNode, depth = 0) {
|
585
|
+
yield { vxNode, depth };
|
586
|
+
for (const child of vxNode.children ?? []) {
|
587
|
+
yield* traverseVxNode(child, depth + 1);
|
407
588
|
}
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
589
|
+
}
|
590
|
+
|
591
|
+
// src/page/render.ts
|
592
|
+
function renderVxNode(scope, options = {}) {
|
593
|
+
const buffer = [];
|
594
|
+
const whitelistRefs = options.whitelistRefs ?? [];
|
595
|
+
for (const { vxNode, depth } of traverseVxNode(scope)) {
|
596
|
+
if (whitelistRefs.length > 0) {
|
597
|
+
if (!whitelistRefs.includes(vxNode.ref)) {
|
598
|
+
continue;
|
599
|
+
}
|
412
600
|
}
|
601
|
+
const indent = " ".repeat(depth);
|
602
|
+
buffer.push(renderIndentedLine(indent, vxNode, options));
|
413
603
|
}
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
604
|
+
return buffer.join("\n");
|
605
|
+
}
|
606
|
+
function renderIndentedLine(indent, vxNode, options = {}) {
|
607
|
+
if (!vxNode.tagName) {
|
608
|
+
return [indent, vxNode.textContent].filter(Boolean).join("");
|
609
|
+
}
|
610
|
+
const tagLine = renderTagLine(vxNode, options);
|
611
|
+
const htmlStyle = options.renderStyle === "html";
|
612
|
+
return [
|
613
|
+
indent,
|
614
|
+
tagLine,
|
615
|
+
htmlStyle ? "" : " ",
|
616
|
+
vxNode.textContent ?? ""
|
617
|
+
].join("");
|
618
|
+
}
|
619
|
+
function renderTagLine(vxNode, options) {
|
620
|
+
const htmlStyle = options.renderStyle === "html";
|
621
|
+
const components = [];
|
622
|
+
if (options.renderTagNames && vxNode.tagName) {
|
623
|
+
components.push(vxNode.tagName);
|
624
|
+
}
|
625
|
+
if (options.renderIds && vxNode.id) {
|
626
|
+
if (htmlStyle) {
|
627
|
+
components.push(`id="${vxNode.id}"`);
|
628
|
+
} else {
|
629
|
+
components.push(`#${vxNode.id}`);
|
630
|
+
}
|
631
|
+
}
|
632
|
+
if (options.renderClassNames && vxNode.classList?.length) {
|
633
|
+
if (htmlStyle) {
|
634
|
+
components.push(`class="${vxNode.classList.join(" ")}"`);
|
635
|
+
} else {
|
636
|
+
components.push("." + vxNode.classList.join("."));
|
637
|
+
}
|
638
|
+
}
|
639
|
+
if (options.renderRefs) {
|
640
|
+
const isRenderRef = [
|
641
|
+
options.renderRefs === "all",
|
642
|
+
options.renderRefs === true && !isContainerNode(vxNode)
|
643
|
+
].some(Boolean);
|
644
|
+
if (isRenderRef) {
|
645
|
+
components.push(`[@${vxNode.ref}]`);
|
646
|
+
}
|
647
|
+
}
|
648
|
+
const attrs = [];
|
649
|
+
if (options.renderLabelAttrs) {
|
650
|
+
for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
|
651
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
652
|
+
}
|
653
|
+
}
|
654
|
+
if (options.renderValueAttrs) {
|
655
|
+
for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
|
656
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
657
|
+
}
|
658
|
+
}
|
659
|
+
if (options.renderSrcAttrs) {
|
660
|
+
for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
|
661
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
662
|
+
}
|
663
|
+
}
|
664
|
+
if (htmlStyle) {
|
665
|
+
components.push(...attrs);
|
666
|
+
} else {
|
667
|
+
components.push(...attrs.map((attr) => `[${attr}]`));
|
668
|
+
}
|
669
|
+
return htmlStyle ? `<${components.join(" ")}>` : components.join("");
|
670
|
+
}
|
671
|
+
|
672
|
+
// src/page/snapshot.ts
|
673
|
+
var VX_DOM_SYMBOL = Symbol("vx:dom");
|
674
|
+
var VX_TREE_SYMBOL = Symbol("vx:tree");
|
675
|
+
function captureSnapshot(options = {}) {
|
676
|
+
const parser = new VxTreeParser(options);
|
677
|
+
const vxNodes = parser.getNodes();
|
678
|
+
const domMap = parser.getDomMap();
|
679
|
+
const vxTree = new VxTreeView(vxNodes);
|
680
|
+
globalThis[VX_DOM_SYMBOL] = domMap;
|
681
|
+
globalThis[VX_TREE_SYMBOL] = vxTree;
|
682
|
+
return {
|
683
|
+
nodes: vxNodes,
|
684
|
+
refRange: parser.getRefRange()
|
685
|
+
};
|
686
|
+
}
|
687
|
+
function getSnapshot() {
|
688
|
+
const vxTree = globalThis[VX_TREE_SYMBOL];
|
689
|
+
if (!vxTree) {
|
690
|
+
throw new Error("[VX] Snapshot not found");
|
691
|
+
}
|
692
|
+
return vxTree;
|
693
|
+
}
|
694
|
+
function resolveDomNode(ref) {
|
695
|
+
const domMap = globalThis[VX_DOM_SYMBOL];
|
696
|
+
if (!domMap) {
|
697
|
+
return null;
|
698
|
+
}
|
699
|
+
return domMap.get(ref) ?? null;
|
700
|
+
}
|
701
|
+
|
702
|
+
// src/page/tree.ts
|
703
|
+
var VxTreeView = class {
|
704
|
+
constructor(nodes) {
|
705
|
+
this.nodes = nodes;
|
706
|
+
this.refMap = /* @__PURE__ */ new Map();
|
707
|
+
this.buildRefMap(nodes);
|
708
|
+
}
|
709
|
+
*traverse() {
|
710
|
+
for (const vxNode of this.nodes) {
|
711
|
+
yield* traverseVxNode(vxNode, 0);
|
712
|
+
}
|
713
|
+
}
|
714
|
+
buildRefMap(nodes) {
|
715
|
+
for (const node of nodes) {
|
716
|
+
this.refMap.set(node.ref, node);
|
717
|
+
this.buildRefMap(node.children ?? []);
|
718
|
+
}
|
719
|
+
}
|
720
|
+
findNode(ref) {
|
721
|
+
return this.refMap.get(ref) ?? null;
|
722
|
+
}
|
723
|
+
render(options = {}) {
|
724
|
+
return this.nodes.map((node) => {
|
725
|
+
return renderVxNode(node, options);
|
726
|
+
}).join("\n");
|
727
|
+
}
|
728
|
+
highlight(options = {}) {
|
729
|
+
if (options.clearOverlay) {
|
730
|
+
clearOverlay();
|
731
|
+
}
|
732
|
+
const leafOnly = !options.includeAll;
|
733
|
+
const refs = this.collectRefs(leafOnly, options.filterRefs);
|
734
|
+
for (const ref of refs) {
|
735
|
+
const el = resolveDomNode(ref);
|
736
|
+
if (el instanceof Element) {
|
737
|
+
highlightEl(el);
|
738
|
+
}
|
739
|
+
}
|
740
|
+
return refs;
|
741
|
+
}
|
742
|
+
collectRefs(leafOnly = true, filterRefs) {
|
743
|
+
const refs = [];
|
744
|
+
for (const { vxNode } of this.traverse()) {
|
745
|
+
if (leafOnly && isContainerNode(vxNode)) {
|
746
|
+
continue;
|
747
|
+
}
|
748
|
+
if (filterRefs && !filterRefs.includes(vxNode.ref)) {
|
749
|
+
continue;
|
750
|
+
}
|
751
|
+
refs.push(vxNode.ref);
|
752
|
+
}
|
753
|
+
return refs;
|
433
754
|
}
|
434
755
|
};
|
435
|
-
|
436
|
-
|
437
|
-
|
756
|
+
|
757
|
+
// src/page/frame.ts
|
758
|
+
var VxPageView = class {
|
759
|
+
constructor(vxFrames) {
|
760
|
+
this.vxFrames = vxFrames;
|
761
|
+
this.vxFrameMap = /* @__PURE__ */ new Map();
|
762
|
+
this.vxTreeMap = /* @__PURE__ */ new Map();
|
763
|
+
for (const frame of vxFrames) {
|
764
|
+
this.vxFrameMap.set(frame.frameId, frame);
|
765
|
+
this.vxTreeMap.set(frame.frameId, new VxTreeView(frame.nodes));
|
766
|
+
}
|
438
767
|
}
|
439
|
-
|
440
|
-
this.
|
441
|
-
|
768
|
+
findFrameByFrameId(frameId) {
|
769
|
+
return this.vxFrameMap.get(frameId) ?? null;
|
770
|
+
}
|
771
|
+
getFrameByFrameId(frameId) {
|
772
|
+
const vxFrame = this.vxFrameMap.get(frameId);
|
773
|
+
if (vxFrame == null) {
|
774
|
+
throw new Error(`[VX] Frame not found for [frameId=${frameId}]`);
|
775
|
+
}
|
776
|
+
return vxFrame;
|
777
|
+
}
|
778
|
+
findFrameByRef(ref) {
|
779
|
+
const vxFrame = this.vxFrames.find(
|
780
|
+
(frame) => ref >= frame.refRange[0] && ref <= frame.refRange[1]
|
781
|
+
);
|
782
|
+
if (!vxFrame) {
|
783
|
+
return null;
|
784
|
+
}
|
785
|
+
return this.vxFrameMap.get(vxFrame.frameId) ?? null;
|
786
|
+
}
|
787
|
+
getFrameByRef(ref) {
|
788
|
+
const vxFrame = this.findFrameByRef(ref);
|
789
|
+
if (vxFrame == null) {
|
790
|
+
throw new Error(`[VX] Frame not found for [ref=${ref}]`);
|
791
|
+
}
|
792
|
+
return vxFrame;
|
793
|
+
}
|
794
|
+
findParentFrame(frameId) {
|
795
|
+
const frame = this.getFrameByFrameId(frameId);
|
796
|
+
const iframeRef = frame?.iframeRef;
|
797
|
+
if (iframeRef == null) {
|
798
|
+
return null;
|
799
|
+
}
|
800
|
+
return this.findFrameByRef(iframeRef);
|
801
|
+
}
|
802
|
+
isFrameShown(frameId) {
|
803
|
+
const frame = this.getFrameByFrameId(frameId);
|
804
|
+
if (!frame) {
|
805
|
+
return false;
|
806
|
+
}
|
807
|
+
const parentFrame = this.findParentFrame(frameId);
|
808
|
+
const { iframeRef } = frame;
|
809
|
+
if (parentFrame == null || iframeRef == null) {
|
810
|
+
return true;
|
811
|
+
}
|
812
|
+
const vxTree = this.vxTreeMap.get(frameId);
|
813
|
+
const existsInParent = !!vxTree?.findNode(iframeRef);
|
814
|
+
return existsInParent ? this.isFrameShown(parentFrame.frameId) : false;
|
815
|
+
}
|
816
|
+
renderAll(options) {
|
817
|
+
return this.vxFrames.map((frame) => {
|
818
|
+
const vxTree = this.vxTreeMap.get(frame.frameId);
|
819
|
+
const rendered = vxTree?.render(options);
|
820
|
+
return [
|
821
|
+
`FRAME ${frame.frameId}`,
|
822
|
+
rendered
|
823
|
+
].join("\n\n");
|
824
|
+
}).join("\n\n");
|
442
825
|
}
|
443
826
|
};
|
444
827
|
export {
|
445
828
|
Counter,
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
829
|
+
INTERACTIVE_ROLES,
|
830
|
+
INTERACTIVE_TAGS,
|
831
|
+
VX_DOM_SYMBOL,
|
832
|
+
VX_IGNORE_SYMBOL,
|
833
|
+
VX_IGNORE_TAGS,
|
834
|
+
VX_LABEL_ATTRS,
|
835
|
+
VX_NODE_SYMBOL,
|
836
|
+
VX_SRC_ATTRS,
|
837
|
+
VX_TAG_PREFERENCE,
|
838
|
+
VX_TREE_SYMBOL,
|
839
|
+
VX_VALUE_ATTRS,
|
840
|
+
VxPageView,
|
841
|
+
VxTreeParser,
|
842
|
+
VxTreeView,
|
843
|
+
captureSnapshot,
|
844
|
+
checkOccluded,
|
845
|
+
clearOverlay,
|
452
846
|
containsSelector,
|
453
|
-
|
454
|
-
|
455
|
-
|
847
|
+
escapeAttribute,
|
848
|
+
fixZIndex,
|
849
|
+
getNormalizedText,
|
850
|
+
getOffsetTop,
|
851
|
+
getSnapshot,
|
852
|
+
getViewportSize,
|
456
853
|
hasVisibleArea,
|
457
854
|
highlightEl,
|
458
|
-
|
855
|
+
isContainerNode,
|
856
|
+
isDeepHidden,
|
459
857
|
isHidden,
|
460
|
-
|
858
|
+
isInteractive,
|
859
|
+
isObjectEmpty,
|
860
|
+
isRandomIdentifier,
|
861
|
+
isRectInViewport,
|
862
|
+
makeOverlaysOpaque,
|
461
863
|
normalizeText,
|
462
|
-
|
463
|
-
|
464
|
-
|
864
|
+
probeViewport,
|
865
|
+
renderVxNode,
|
866
|
+
resolveDomNode,
|
867
|
+
showPoint,
|
868
|
+
traverseVxNode,
|
869
|
+
truncateAttrValue
|
465
870
|
};
|