@ubio/webvision 3.1.8 → 3.2.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/README.md +173 -0
- package/build/global.js +79 -42
- package/build/global.js.map +3 -3
- package/build/page.mjs +79 -42
- package/build/webvision.user.js +1 -1
- package/out/page/dom.d.ts +1 -0
- package/out/page/dom.js +27 -1
- package/out/page/dom.js.map +1 -1
- package/out/page/parser.d.ts +1 -1
- package/out/page/parser.js +19 -15
- package/out/page/parser.js.map +1 -1
- package/out/page/probe.js +1 -1
- package/out/page/probe.js.map +1 -1
- package/out/page/render.d.ts +0 -1
- package/out/page/render.js +4 -3
- package/out/page/render.js.map +1 -1
- package/out/page/snapshot.js +1 -1
- package/out/page/snapshot.js.map +1 -1
- package/out/page/traverse.js +3 -2
- package/out/page/traverse.js.map +1 -1
- package/out/page/tree.js +1 -3
- package/out/page/tree.js.map +1 -1
- package/out/page/util.d.ts +1 -0
- package/out/page/util.js +10 -0
- package/out/page/util.js.map +1 -1
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# WebVision
|
|
2
|
+
|
|
3
|
+
**Structured, ref-addressable views of the live DOM** for automation, debugging, and tooling.
|
|
4
|
+
|
|
5
|
+
WebVision walks the browser document, builds a compact **VX tree** (semantic nodes with stable refs), and can **render** it as text, **highlight** regions on the page, and **resolve** refs back to real DOM nodes. It is designed for scenarios where you need a consistent, inspectable snapshot of “what’s on screen” without shipping a full browser automation stack.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why use it?
|
|
10
|
+
|
|
11
|
+
- **Stable refs** — Each meaningful node gets a ref you can use to talk about “that button” or “that heading” across snapshots and tools.
|
|
12
|
+
- **Readable dumps** — Turn the tree into a line-oriented string (tags, ids, classes, key attrs, text) for LLMs, logs, or diffing.
|
|
13
|
+
- **Visual debugging** — Draw overlays on elements that correspond to VX nodes.
|
|
14
|
+
- **Shadow DOM** — Open shadow roots are flattened into the tree by default (see [Shadow DOM](#shadow-dom)).
|
|
15
|
+
- **Ships for browser and Node-oriented bundles** — ESM page bundle, IIFE global, optional Tampermonkey userscript for the **page** console.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @ubio/webvision
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Build artifacts (`out/page`, `build/*`) are included in the published package. Run `npm run compile` after cloning the repo if you develop from source.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick start (ESM)
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import { captureSnapshot } from '@ubio/webvision';
|
|
33
|
+
|
|
34
|
+
const tree = await captureSnapshot();
|
|
35
|
+
console.log(tree.render({ renderRefs: true, renderTagNames: true }));
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`captureSnapshot()` parses `document`, stores the latest tree and ref→DOM map on `globalThis`, and returns a **`VxTreeView`**.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Core API
|
|
43
|
+
|
|
44
|
+
| Export | Role |
|
|
45
|
+
|--------|------|
|
|
46
|
+
| `captureSnapshot(options?)` | Parse the page; returns `VxTreeView`; updates last snapshot. |
|
|
47
|
+
| `getSnapshot()` | Return the last `VxTreeView` (throws if none). |
|
|
48
|
+
| `resolveDomNode(ref)` | Map a ref string to a DOM `Node` or `null`. |
|
|
49
|
+
| `renderVxNode(node, options?)` | Render a single `VxNode` subtree as text. |
|
|
50
|
+
|
|
51
|
+
### `VxTreeView`
|
|
52
|
+
|
|
53
|
+
| Method / property | Description |
|
|
54
|
+
|-------------------|-------------|
|
|
55
|
+
| `render(options?)` | String dump of the frame’s tree (see `VxRenderOptions` in source). |
|
|
56
|
+
| `nodeCount` | Number of ref’d nodes in the map. |
|
|
57
|
+
| `highlight(options?)` | Overlay borders for refs (needs snapshot first). |
|
|
58
|
+
| `findNode(ref)` | Get the `VxNode` for a ref. |
|
|
59
|
+
|
|
60
|
+
### Example: snapshot, render, highlight
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
import { captureSnapshot, resolveDomNode } from '@ubio/webvision';
|
|
64
|
+
|
|
65
|
+
const tree = await captureSnapshot();
|
|
66
|
+
|
|
67
|
+
console.log(tree.render({
|
|
68
|
+
renderRefs: true,
|
|
69
|
+
renderTagNames: true,
|
|
70
|
+
renderIds: true,
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
tree.highlight({ clearOverlay: true });
|
|
74
|
+
|
|
75
|
+
const el = resolveDomNode('0abc'); // example ref from render output
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Parser options (`VxTreeOptions`)
|
|
79
|
+
|
|
80
|
+
Passed to `captureSnapshot({ ... })`:
|
|
81
|
+
|
|
82
|
+
| Option | Default | Meaning |
|
|
83
|
+
|--------|---------|---------|
|
|
84
|
+
| `flattenShadowDom` | `true` | Include **open** shadow roots after light-DOM children; set `false` for light DOM only. |
|
|
85
|
+
| `viewportOnly` | `false` | Drop nodes outside the viewport. |
|
|
86
|
+
| `probeViewport` | `false` | Extra viewport probing (see `probe.ts`). |
|
|
87
|
+
| `skipImages` | `false` | Omit `img` nodes when omitting. |
|
|
88
|
+
| `opaqueOverlays` | `false` | Try to flatten opaque overlays for parsing. |
|
|
89
|
+
| `unnestDivs` | `false` | Aggressive pruning of bare div/spans. |
|
|
90
|
+
| `frameId` / `iframeRef` | — | Multi-frame scenarios. |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Shadow DOM
|
|
95
|
+
|
|
96
|
+
Open shadow trees are walked **after** each host’s light DOM children so the rendered tree matches a **flattened** structural view. **Closed** shadow roots cannot be accessed from script.
|
|
97
|
+
|
|
98
|
+
To restore the previous behavior (ignore shadow trees):
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
await captureSnapshot({ flattenShadowDom: false });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Package exports
|
|
107
|
+
|
|
108
|
+
| Import path | Output | Use case |
|
|
109
|
+
|-------------|--------|----------|
|
|
110
|
+
| `@ubio/webvision` | `out/page` (TypeScript build) | Types + ESM in TS projects. |
|
|
111
|
+
| `@ubio/webvision/page` | `build/page.mjs` | Single ESM bundle of the page module. |
|
|
112
|
+
| `@ubio/webvision/global` | `build/global.js` | IIFE; exposes `globalThis.WebVision` in the browser. |
|
|
113
|
+
|
|
114
|
+
Generate bundles from source:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npm run compile:page # build/page.mjs
|
|
118
|
+
npm run compile:global # build/global.js + source map
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Browser console: Tampermonkey
|
|
124
|
+
|
|
125
|
+
For **`window.WebVision`** in the **page** DevTools console (not the extension isolated world), use the generated userscript.
|
|
126
|
+
|
|
127
|
+
1. **Build** (from repo root):
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npm run compile:userscript
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Produces `build/global.js` and `build/webvision.user.js`.
|
|
134
|
+
|
|
135
|
+
2. **Default workflow (hot reload)**
|
|
136
|
+
- Terminal A: `npm run serve:build` — serves `build/` at `http://127.0.0.1:3847`.
|
|
137
|
+
- Terminal B: `npm run dev:global` — rebuilds `global.js` on TS changes.
|
|
138
|
+
- Install **`build/webvision.user.js`** in Tampermonkey (Dashboard → install).
|
|
139
|
+
- Reload the tab; the script fetches `global.js` with a cache-busting query and injects it into the page.
|
|
140
|
+
|
|
141
|
+
3. **Offline / no server** — embed the bundle when generating:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
WEBVISION_INLINE=1 npm run compile:userscript
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Reinstall the userscript after each rebuild (large file).
|
|
148
|
+
|
|
149
|
+
4. **Custom URL** when building:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
WEBVISION_INJECT_URL=https://your.cdn/webvision/global.js npm run compile:userscript
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Requires `@grant GM.xmlHttpRequest` and matching `// @connect` for the host (generated for you for `http`/`https` URLs).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
| Script | Purpose |
|
|
162
|
+
|--------|---------|
|
|
163
|
+
| `npm run compile` | Clean, `tsc`, bundle `page.mjs` + `global.js` + `webvision.user.js`. |
|
|
164
|
+
| `npm run dev` | Parallel `tsc -w` and esbuild watch for `page.mjs`. |
|
|
165
|
+
| `npm run dev:global` | Watch rebuild `build/global.js`. |
|
|
166
|
+
| `npm run dev:userscript` | One-shot userscript build, then `dev:global` watch. |
|
|
167
|
+
| `npm run lint` | ESLint. |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
ISC
|
package/build/global.js
CHANGED
|
@@ -57,8 +57,10 @@ var WebVision = (() => {
|
|
|
57
57
|
isHidden: () => isHidden,
|
|
58
58
|
isInteractive: () => isInteractive,
|
|
59
59
|
isObjectEmpty: () => isObjectEmpty,
|
|
60
|
+
isPopup: () => isPopup,
|
|
60
61
|
isRandomIdentifier: () => isRandomIdentifier,
|
|
61
62
|
isRectInViewport: () => isRectInViewport,
|
|
63
|
+
iterate: () => iterate,
|
|
62
64
|
makeOverlaysOpaque: () => makeOverlaysOpaque,
|
|
63
65
|
normalizeRef: () => normalizeRef,
|
|
64
66
|
normalizeText: () => normalizeText,
|
|
@@ -71,6 +73,31 @@ var WebVision = (() => {
|
|
|
71
73
|
truncateAttrValue: () => truncateAttrValue
|
|
72
74
|
});
|
|
73
75
|
|
|
76
|
+
// src/page/util.ts
|
|
77
|
+
function isContainerNode(vxNode) {
|
|
78
|
+
if (vxNode.tagName === "select") {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const children = vxNode.children ?? [];
|
|
82
|
+
const hasTextChildren = children.some((child) => !child.tagName);
|
|
83
|
+
return children.length > 0 && !hasTextChildren;
|
|
84
|
+
}
|
|
85
|
+
function isObjectEmpty(obj) {
|
|
86
|
+
return !Object.values(obj).some((value) => !!value);
|
|
87
|
+
}
|
|
88
|
+
function normalizeRef(ref) {
|
|
89
|
+
return String(ref).toLowerCase().trim().replace(/[^a-z0-9]/gi, "");
|
|
90
|
+
}
|
|
91
|
+
function* iterate(items) {
|
|
92
|
+
if (!items) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
96
|
+
const item = items[i];
|
|
97
|
+
yield item;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
74
101
|
// src/page/dom.ts
|
|
75
102
|
var ORIGINAL_STYLE_SYMBOL = Symbol("vx:originalStyle");
|
|
76
103
|
var INTERACTIVE_TAGS = ["a", "button", "input", "textarea", "select", "label", "option", "optgroup"];
|
|
@@ -155,7 +182,15 @@ var WebVision = (() => {
|
|
|
155
182
|
return true;
|
|
156
183
|
}
|
|
157
184
|
if (!hasVisibleArea(element)) {
|
|
158
|
-
|
|
185
|
+
if (element.children.length === 0) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
for (const child of iterate(element.children)) {
|
|
189
|
+
if (!isDeepHidden(child)) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
159
194
|
}
|
|
160
195
|
return false;
|
|
161
196
|
}
|
|
@@ -181,6 +216,21 @@ var WebVision = (() => {
|
|
|
181
216
|
}
|
|
182
217
|
return false;
|
|
183
218
|
}
|
|
219
|
+
function isPopup(el) {
|
|
220
|
+
const style = getComputedStyle(el);
|
|
221
|
+
const zIndex = parseInt(style.zIndex, 10);
|
|
222
|
+
const hasPopupPosition = style.position === "fixed" || style.position === "sticky" || style.position === "absolute" && zIndex >= 1e3;
|
|
223
|
+
if (!hasPopupPosition) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
const rect = el.getBoundingClientRect();
|
|
227
|
+
const area = rect.width * rect.height;
|
|
228
|
+
const viewportArea = window.innerWidth * window.innerHeight;
|
|
229
|
+
if (area <= viewportArea * 0.2) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
184
234
|
function getViewportSize() {
|
|
185
235
|
return {
|
|
186
236
|
width: window.innerWidth,
|
|
@@ -291,11 +341,11 @@ var WebVision = (() => {
|
|
|
291
341
|
return;
|
|
292
342
|
}
|
|
293
343
|
yield element;
|
|
294
|
-
for (const child of element.children) {
|
|
344
|
+
for (const child of iterate(element.children)) {
|
|
295
345
|
yield* traverseElements(child);
|
|
296
346
|
}
|
|
297
347
|
if (element.shadowRoot) {
|
|
298
|
-
for (const child of element.shadowRoot.children) {
|
|
348
|
+
for (const child of iterate(element.shadowRoot.children)) {
|
|
299
349
|
yield* traverseElements(child);
|
|
300
350
|
}
|
|
301
351
|
}
|
|
@@ -316,7 +366,7 @@ var WebVision = (() => {
|
|
|
316
366
|
}
|
|
317
367
|
for (const { x, y } of points.getAll()) {
|
|
318
368
|
const element = document.elementFromPoint(x, y);
|
|
319
|
-
if (element
|
|
369
|
+
if (element) {
|
|
320
370
|
result.add(element);
|
|
321
371
|
}
|
|
322
372
|
}
|
|
@@ -355,22 +405,6 @@ var WebVision = (() => {
|
|
|
355
405
|
}
|
|
356
406
|
};
|
|
357
407
|
|
|
358
|
-
// src/page/util.ts
|
|
359
|
-
function isContainerNode(vxNode) {
|
|
360
|
-
if (vxNode.tagName === "select") {
|
|
361
|
-
return false;
|
|
362
|
-
}
|
|
363
|
-
const children = vxNode.children ?? [];
|
|
364
|
-
const hasTextChildren = children.some((child) => !child.tagName);
|
|
365
|
-
return children.length > 0 && !hasTextChildren;
|
|
366
|
-
}
|
|
367
|
-
function isObjectEmpty(obj) {
|
|
368
|
-
return !Object.values(obj).some((value) => !!value);
|
|
369
|
-
}
|
|
370
|
-
function normalizeRef(ref) {
|
|
371
|
-
return String(ref).toLowerCase().trim().replace(/[^a-z0-9]/gi, "");
|
|
372
|
-
}
|
|
373
|
-
|
|
374
408
|
// src/page/render.ts
|
|
375
409
|
function renderVxNode(scope, options = {}) {
|
|
376
410
|
const buffer = [];
|
|
@@ -388,14 +422,12 @@ var WebVision = (() => {
|
|
|
388
422
|
return buffer.join("\n");
|
|
389
423
|
}
|
|
390
424
|
function renderIndentedLine(indent, vxNode, options = {}) {
|
|
391
|
-
const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
|
|
392
425
|
if (!vxNode.tagName) {
|
|
393
|
-
return [
|
|
426
|
+
return [indent, vxNode.textContent].filter(Boolean).join("");
|
|
394
427
|
}
|
|
395
428
|
const tagLine = renderTagLine(vxNode, options);
|
|
396
429
|
const htmlStyle = options.renderStyle === "html";
|
|
397
430
|
return [
|
|
398
|
-
diffPrefix,
|
|
399
431
|
indent,
|
|
400
432
|
tagLine,
|
|
401
433
|
htmlStyle ? "" : " ",
|
|
@@ -431,6 +463,9 @@ var WebVision = (() => {
|
|
|
431
463
|
components.push(`[@${vxNode.ref}]`);
|
|
432
464
|
}
|
|
433
465
|
}
|
|
466
|
+
for (const meta of vxNode.meta ?? []) {
|
|
467
|
+
components.push(`[${meta}]`);
|
|
468
|
+
}
|
|
434
469
|
const attrs = [];
|
|
435
470
|
if (options.renderLabelAttrs) {
|
|
436
471
|
for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
|
|
@@ -482,7 +517,7 @@ var WebVision = (() => {
|
|
|
482
517
|
var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
|
|
483
518
|
async function captureSnapshot(options = {}) {
|
|
484
519
|
const parser = new VxTreeParser(options);
|
|
485
|
-
|
|
520
|
+
parser.parse();
|
|
486
521
|
const domMap = parser.getDomMap();
|
|
487
522
|
const vxTree = parser.getTree();
|
|
488
523
|
globalThis[VX_DOM_SYMBOL] = domMap;
|
|
@@ -555,9 +590,7 @@ var WebVision = (() => {
|
|
|
555
590
|
for (const ref of refs) {
|
|
556
591
|
const el = resolveDomNode(ref);
|
|
557
592
|
if (el instanceof Element) {
|
|
558
|
-
const
|
|
559
|
-
const isNew = vxNode?.isNew ?? false;
|
|
560
|
-
const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
|
|
593
|
+
const color = options.useColors ? void 0 : "#060";
|
|
561
594
|
highlightEl(el, ref, color);
|
|
562
595
|
}
|
|
563
596
|
}
|
|
@@ -602,7 +635,7 @@ var WebVision = (() => {
|
|
|
602
635
|
/title-/i
|
|
603
636
|
// title-* attributes
|
|
604
637
|
];
|
|
605
|
-
var VX_VALUE_ATTRS = ["value", "checked", "selected", "disabled", "readonly"];
|
|
638
|
+
var VX_VALUE_ATTRS = ["role", "value", "checked", "selected", "disabled", "readonly"];
|
|
606
639
|
var VX_SRC_ATTRS = ["src", "href"];
|
|
607
640
|
var VX_TAG_PREFERENCE = [
|
|
608
641
|
"a",
|
|
@@ -721,6 +754,8 @@ var WebVision = (() => {
|
|
|
721
754
|
const parentEl = el.matches("option, optgroup") ? el.closest("select") ?? el : el;
|
|
722
755
|
const rect = parentEl.getBoundingClientRect();
|
|
723
756
|
const id = el.getAttribute("id") ?? "";
|
|
757
|
+
const isProbeHit = this.isProbeHit(parentEl);
|
|
758
|
+
const isInViewport = isRectInViewport(rect, this.viewport);
|
|
724
759
|
const vxNode = this.makeElementNode(el, {
|
|
725
760
|
tagName: el.tagName.toLowerCase(),
|
|
726
761
|
id: isRandomIdentifier(id) ? void 0 : id,
|
|
@@ -730,19 +765,23 @@ var WebVision = (() => {
|
|
|
730
765
|
srcAttrs: this.collectSrcAttrs(el),
|
|
731
766
|
hasVisibleArea: hasVisibleArea(parentEl),
|
|
732
767
|
isInteractive: isInteractive(parentEl),
|
|
733
|
-
isOutsideViewport: !
|
|
734
|
-
isProbeHit
|
|
735
|
-
isKept: el.matches(VX_KEEP_SELECTOR)
|
|
768
|
+
isOutsideViewport: !isInViewport,
|
|
769
|
+
isProbeHit,
|
|
770
|
+
isKept: el.matches(VX_KEEP_SELECTOR),
|
|
771
|
+
meta: [
|
|
772
|
+
isPopup(parentEl) ? "popup" : null,
|
|
773
|
+
isInViewport && !isProbeHit ? "occluded" : null
|
|
774
|
+
].filter((_) => _ != null)
|
|
736
775
|
});
|
|
737
776
|
const children = [];
|
|
738
|
-
for (const child of el.childNodes) {
|
|
777
|
+
for (const child of iterate(el.childNodes)) {
|
|
739
778
|
const childNode = this.parseNode(child, vxNode);
|
|
740
779
|
if (childNode != null) {
|
|
741
780
|
children.push(childNode);
|
|
742
781
|
}
|
|
743
782
|
}
|
|
744
783
|
if (this.options.flattenShadowDom !== false && el.shadowRoot) {
|
|
745
|
-
for (const child of el.shadowRoot.childNodes) {
|
|
784
|
+
for (const child of iterate(el.shadowRoot.childNodes)) {
|
|
746
785
|
const childNode = this.parseNode(child, vxNode);
|
|
747
786
|
if (childNode != null) {
|
|
748
787
|
children.push(childNode);
|
|
@@ -758,9 +797,8 @@ var WebVision = (() => {
|
|
|
758
797
|
}
|
|
759
798
|
makeElementNode(el, spec) {
|
|
760
799
|
const existingRef = el[VX_NODE_REF_SYMBOL];
|
|
761
|
-
const isNew = existingRef === void 0;
|
|
762
800
|
let ref;
|
|
763
|
-
if (
|
|
801
|
+
if (existingRef === void 0) {
|
|
764
802
|
const counter = this.nextCounterValue();
|
|
765
803
|
ref = `${this.frameId}${counter}`;
|
|
766
804
|
this.usedCounters.add(counter);
|
|
@@ -771,8 +809,7 @@ var WebVision = (() => {
|
|
|
771
809
|
}
|
|
772
810
|
const vxNode = {
|
|
773
811
|
...spec,
|
|
774
|
-
ref
|
|
775
|
-
isNew
|
|
812
|
+
ref
|
|
776
813
|
};
|
|
777
814
|
this.domRefMap.set(ref, el);
|
|
778
815
|
return vxNode;
|
|
@@ -867,7 +904,7 @@ var WebVision = (() => {
|
|
|
867
904
|
}
|
|
868
905
|
collectLabelAttrs(el) {
|
|
869
906
|
const attrs = {};
|
|
870
|
-
for (const attr of el.attributes) {
|
|
907
|
+
for (const attr of iterate(el.attributes)) {
|
|
871
908
|
const attrName = attr.name;
|
|
872
909
|
const value = truncateAttrValue(attr.value);
|
|
873
910
|
if (!value) {
|
|
@@ -907,11 +944,11 @@ var WebVision = (() => {
|
|
|
907
944
|
delete node[VX_NODE_REF_SYMBOL];
|
|
908
945
|
delete node[VX_NODE_COUNTER_SYMBOL];
|
|
909
946
|
if (node instanceof Element) {
|
|
910
|
-
for (const child of node.children) {
|
|
947
|
+
for (const child of iterate(node.children)) {
|
|
911
948
|
this.clearRecursive(child);
|
|
912
949
|
}
|
|
913
950
|
if (node.shadowRoot) {
|
|
914
|
-
for (const child of node.shadowRoot.children) {
|
|
951
|
+
for (const child of iterate(node.shadowRoot.children)) {
|
|
915
952
|
this.clearRecursive(child);
|
|
916
953
|
}
|
|
917
954
|
}
|
|
@@ -931,11 +968,11 @@ var WebVision = (() => {
|
|
|
931
968
|
if (cnt !== void 0) {
|
|
932
969
|
this.usedCounters.add(cnt);
|
|
933
970
|
}
|
|
934
|
-
for (const child of el.children
|
|
971
|
+
for (const child of iterate(el.children)) {
|
|
935
972
|
this.collectDomCounters(child);
|
|
936
973
|
}
|
|
937
974
|
if (el.shadowRoot) {
|
|
938
|
-
for (const child of el.shadowRoot.children) {
|
|
975
|
+
for (const child of iterate(el.shadowRoot.children)) {
|
|
939
976
|
this.collectDomCounters(child);
|
|
940
977
|
}
|
|
941
978
|
}
|