@ubio/webvision 2.6.5 → 3.0.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/global.js CHANGED
@@ -21,7 +21,6 @@ var WebVision = (() => {
21
21
  // src/page/index.ts
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
- Counter: () => Counter,
25
24
  INTERACTIVE_ROLES: () => INTERACTIVE_ROLES,
26
25
  INTERACTIVE_TAGS: () => INTERACTIVE_TAGS,
27
26
  PointSet: () => PointSet,
@@ -44,6 +43,7 @@ var WebVision = (() => {
44
43
  containsSelector: () => containsSelector,
45
44
  escapeAttribute: () => escapeAttribute,
46
45
  fixZIndex: () => fixZIndex,
46
+ getElementDepth: () => getElementDepth,
47
47
  getNormalizedText: () => getNormalizedText,
48
48
  getOffsetTop: () => getOffsetTop,
49
49
  getOverlayContainer: () => getOverlayContainer,
@@ -63,26 +63,13 @@ var WebVision = (() => {
63
63
  probeViewport: () => probeViewport,
64
64
  renderVxNode: () => renderVxNode,
65
65
  resolveDomNode: () => resolveDomNode,
66
+ serializeElement: () => serializeElement,
66
67
  showPoint: () => showPoint,
67
68
  traverseElements: () => traverseElements,
68
69
  traverseVxNode: () => traverseVxNode,
69
70
  truncateAttrValue: () => truncateAttrValue
70
71
  });
71
72
 
72
- // src/page/counter.ts
73
- var Counter = class {
74
- constructor(value = 0) {
75
- this.value = value;
76
- }
77
- next() {
78
- this.value += 1;
79
- return this.value;
80
- }
81
- current() {
82
- return this.value;
83
- }
84
- };
85
-
86
73
  // src/page/dom.ts
87
74
  var ORIGINAL_STYLE_SYMBOL = Symbol("vx:originalStyle");
88
75
  var INTERACTIVE_TAGS = ["a", "button", "input", "textarea", "select", "label", "option", "optgroup"];
@@ -269,6 +256,24 @@ var WebVision = (() => {
269
256
  }
270
257
  }
271
258
  }
259
+ function getElementDepth(el) {
260
+ let depth = 0;
261
+ while (el.parentElement) {
262
+ el = el.parentElement;
263
+ depth += 1;
264
+ }
265
+ return depth;
266
+ }
267
+ function serializeElement(el) {
268
+ const sig = [];
269
+ const depth = getElementDepth(el);
270
+ sig.push(String(depth));
271
+ sig.push(el.tagName);
272
+ for (const attr of el.attributes) {
273
+ sig.push(`${attr.name}=${attr.value}`);
274
+ }
275
+ return sig.join("|");
276
+ }
272
277
 
273
278
  // src/page/traverse.ts
274
279
  function* traverseVxNode(vxNode, depth = 0) {
@@ -351,6 +356,186 @@ var WebVision = (() => {
351
356
  return !Object.values(obj).some((value) => !!value);
352
357
  }
353
358
 
359
+ // src/page/render.ts
360
+ function renderVxNode(scope, options = {}) {
361
+ const buffer = [];
362
+ for (const { vxNode, depth } of traverseVxNode(scope)) {
363
+ if (options.skipNonInteractive && !vxNode.isInteractive) {
364
+ continue;
365
+ }
366
+ const indent = options.skipNonInteractive ? "" : " ".repeat(depth);
367
+ buffer.push(renderIndentedLine(indent, vxNode, options));
368
+ }
369
+ return buffer.join("\n");
370
+ }
371
+ function renderIndentedLine(indent, vxNode, options = {}) {
372
+ const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
373
+ if (!vxNode.tagName) {
374
+ return [diffPrefix, indent, vxNode.textContent].filter(Boolean).join("");
375
+ }
376
+ const tagLine = renderTagLine(vxNode, options);
377
+ const htmlStyle = options.renderStyle === "html";
378
+ return [
379
+ diffPrefix,
380
+ indent,
381
+ tagLine,
382
+ htmlStyle ? "" : " ",
383
+ vxNode.textContent ?? ""
384
+ ].join("");
385
+ }
386
+ function renderTagLine(vxNode, options) {
387
+ const htmlStyle = options.renderStyle === "html";
388
+ const components = [];
389
+ if (options.renderTagNames && vxNode.tagName) {
390
+ components.push(vxNode.tagName);
391
+ }
392
+ if (options.renderIds && vxNode.id) {
393
+ if (htmlStyle) {
394
+ components.push(`id="${vxNode.id}"`);
395
+ } else {
396
+ components.push(`#${vxNode.id}`);
397
+ }
398
+ }
399
+ if (options.renderClassNames && vxNode.classList?.length) {
400
+ if (htmlStyle) {
401
+ components.push(`class="${vxNode.classList.join(" ")}"`);
402
+ } else {
403
+ components.push("." + vxNode.classList.join("."));
404
+ }
405
+ }
406
+ if (options.renderRefs) {
407
+ const isRenderRef = [
408
+ options.renderRefs === "all",
409
+ options.renderRefs === true && !isContainerNode(vxNode)
410
+ ].some(Boolean);
411
+ if (isRenderRef) {
412
+ components.push(`[@${vxNode.ref}]`);
413
+ }
414
+ }
415
+ const attrs = [];
416
+ if (options.renderLabelAttrs) {
417
+ for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
418
+ attrs.push(`${attr}="${truncateAttrValue(value)}"`);
419
+ }
420
+ }
421
+ if (options.renderValueAttrs) {
422
+ for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
423
+ attrs.push(`${attr}="${truncateAttrValue(value)}"`);
424
+ }
425
+ }
426
+ if (options.renderSrcAttrs) {
427
+ for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
428
+ attrs.push(`${attr}="${truncateAttrValue(value)}"`);
429
+ }
430
+ }
431
+ if (htmlStyle) {
432
+ components.push(...attrs);
433
+ } else {
434
+ components.push(...attrs.map((attr) => `[${attr}]`));
435
+ }
436
+ return htmlStyle ? `<${components.join(" ")}>` : components.join("");
437
+ }
438
+
439
+ // src/page/snapshot.ts
440
+ var VX_DOM_SYMBOL = Symbol("vx:dom");
441
+ var VX_TREE_SYMBOL = Symbol("vx:tree");
442
+ var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
443
+ async function captureSnapshot(options = {}) {
444
+ const parser = new VxTreeParser(options);
445
+ const domMap = parser.getDomMap();
446
+ const vxTree = parser.getTree(options.frameId ?? "0", options.iframeRef);
447
+ globalThis[VX_DOM_SYMBOL] = domMap;
448
+ globalThis[VX_TREE_SYMBOL] = vxTree;
449
+ return vxTree;
450
+ }
451
+ function getSnapshot() {
452
+ const vxTree = globalThis[VX_TREE_SYMBOL];
453
+ if (!vxTree) {
454
+ throw new Error("[VX] Snapshot not found");
455
+ }
456
+ return vxTree;
457
+ }
458
+ function resolveDomNode(ref) {
459
+ const domMap = globalThis[VX_DOM_SYMBOL];
460
+ if (!domMap) {
461
+ return null;
462
+ }
463
+ return domMap.get(ref) ?? null;
464
+ }
465
+
466
+ // src/page/tree.ts
467
+ var VxTreeView = class {
468
+ constructor(nodes, frameId, iframeRef) {
469
+ this.nodes = nodes;
470
+ this.frameId = frameId;
471
+ this.iframeRef = iframeRef;
472
+ this.refMap = /* @__PURE__ */ new Map();
473
+ this.buildRefMap(nodes);
474
+ }
475
+ get nodeCount() {
476
+ return this.refMap.size;
477
+ }
478
+ *traverse() {
479
+ for (const vxNode of this.nodes) {
480
+ yield* traverseVxNode(vxNode, 0);
481
+ }
482
+ }
483
+ buildRefMap(nodes) {
484
+ for (const node of nodes) {
485
+ if (node.ref) {
486
+ this.refMap.set(node.ref, node);
487
+ }
488
+ this.buildRefMap(node.children ?? []);
489
+ }
490
+ }
491
+ hasRef(ref) {
492
+ return this.refMap.has(ref);
493
+ }
494
+ findNode(ref) {
495
+ return this.refMap.get(ref) ?? null;
496
+ }
497
+ render(options = {}) {
498
+ return this.nodes.map((node) => {
499
+ return renderVxNode(node, options);
500
+ }).join("\n");
501
+ }
502
+ highlight(options = {}) {
503
+ if (options.clearOverlay) {
504
+ clearOverlay();
505
+ }
506
+ const leafOnly = !options.includeAll;
507
+ const refs = this.collectRefs(leafOnly, options.filterRefs);
508
+ this.highlightRefs(refs, options);
509
+ }
510
+ highlightRefs(refs, options = {}) {
511
+ for (const ref of refs) {
512
+ const el = resolveDomNode(ref);
513
+ if (el instanceof Element) {
514
+ const vxNode = this.findNode(ref);
515
+ const isNew = vxNode?.isNew ?? false;
516
+ const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
517
+ highlightEl(el, ref, color);
518
+ }
519
+ }
520
+ }
521
+ collectRefs(leafOnly = true, filterRefs) {
522
+ const refs = [];
523
+ for (const { vxNode } of this.traverse()) {
524
+ if (!vxNode.ref) {
525
+ continue;
526
+ }
527
+ if (leafOnly && isContainerNode(vxNode)) {
528
+ continue;
529
+ }
530
+ if (filterRefs && !filterRefs.includes(vxNode.ref)) {
531
+ continue;
532
+ }
533
+ refs.push(vxNode.ref);
534
+ }
535
+ return refs;
536
+ }
537
+ };
538
+
354
539
  // src/page/parser.ts
355
540
  var VX_NODE_SYMBOL = Symbol("vx:node");
356
541
  var VX_IGNORE_SYMBOL = Symbol("vx:ignore");
@@ -422,41 +607,36 @@ var WebVision = (() => {
422
607
  var VxTreeParser = class {
423
608
  constructor(options = {}) {
424
609
  this.options = options;
610
+ this.viewport = { width: 0, height: 0 };
611
+ this.vxNodes = [];
425
612
  this.probeElements = [];
426
613
  this.domRefMap = /* @__PURE__ */ new Map();
427
- const { startRef = 0 } = options;
614
+ }
615
+ async parse() {
428
616
  this.viewport = getViewportSize();
429
- this.counter = new Counter(startRef);
430
- if (options.probeViewport) {
617
+ if (this.options.probeViewport) {
431
618
  this.probeElements = probeViewport();
432
619
  }
433
- const vxRoot = this.parseDocument();
434
- this.refRange = [startRef, this.counter.current()];
620
+ const vxRoot = await this.parseNode(document.documentElement, null);
435
621
  this.vxNodes = this.pruneRecursive(vxRoot);
436
622
  }
437
- parseDocument() {
438
- return this.parseNode(document.documentElement, null);
439
- }
440
- getTree() {
441
- return new VxTreeView(this.vxNodes, this.refRange);
623
+ getTree(frameId, iframeRef) {
624
+ return new VxTreeView(this.vxNodes, frameId, iframeRef);
442
625
  }
443
626
  getNodes() {
444
627
  return this.vxNodes;
445
628
  }
446
- getRefRange() {
447
- return this.refRange;
448
- }
449
629
  getDomMap() {
450
630
  return this.domRefMap;
451
631
  }
452
- parseNode(node, parent) {
632
+ async parseNode(node, parent) {
453
633
  if (!node || node[VX_IGNORE_SYMBOL]) {
454
634
  return null;
455
635
  }
456
636
  if (node instanceof Text) {
457
637
  const textContent = normalizeText(node.textContent ?? "");
458
638
  if (textContent) {
459
- return this.makeNode(node, {
639
+ return await this.makeNode(node, {
460
640
  textContent,
461
641
  hasVisibleArea: parent?.hasVisibleArea,
462
642
  isOutsideViewport: parent?.isOutsideViewport,
@@ -469,11 +649,11 @@ var WebVision = (() => {
469
649
  if (this.options.opaqueOverlays) {
470
650
  makeOverlaysOpaque(node);
471
651
  }
472
- return this.parseElement(node);
652
+ return await this.parseElement(node);
473
653
  }
474
654
  return null;
475
655
  }
476
- parseElement(el) {
656
+ async parseElement(el) {
477
657
  const skip = VX_IGNORE_TAGS.includes(el.tagName.toLowerCase()) || isHidden(el);
478
658
  if (skip) {
479
659
  this.clearRecursive(el);
@@ -482,7 +662,7 @@ var WebVision = (() => {
482
662
  const parentEl = el.matches("option, optgroup") ? el.closest("select") ?? el : el;
483
663
  const rect = parentEl.getBoundingClientRect();
484
664
  const id = el.getAttribute("id") ?? "";
485
- const vxNode = this.makeNode(el, {
665
+ const vxNode = await this.makeNode(el, {
486
666
  tagName: el.tagName.toLowerCase(),
487
667
  id: isRandomIdentifier(id) ? void 0 : id,
488
668
  classList: Array.from(el.classList).filter((cls) => !isRandomIdentifier(cls)).slice(0, 4),
@@ -495,7 +675,13 @@ var WebVision = (() => {
495
675
  isProbeHit: this.isProbeHit(parentEl),
496
676
  isKept: el.matches(VX_KEEP_SELECTOR)
497
677
  });
498
- const children = [...el.childNodes].map((child) => this.parseNode(child, vxNode)).filter((_) => _ != null);
678
+ const children = [];
679
+ for (const child of el.childNodes) {
680
+ const childNode = await this.parseNode(child, vxNode);
681
+ if (childNode != null) {
682
+ children.push(childNode);
683
+ }
684
+ }
499
685
  if (children.length === 1 && !children[0]?.tagName) {
500
686
  vxNode.textContent = normalizeText(children[0].textContent ?? "");
501
687
  } else {
@@ -503,15 +689,17 @@ var WebVision = (() => {
503
689
  }
504
690
  return vxNode;
505
691
  }
506
- makeNode(node, spec) {
507
- const ref = this.counter.next();
692
+ async makeNode(node, spec) {
508
693
  const isNew = !node[VX_NODE_SYMBOL];
694
+ const ref = await this.createRef(node);
509
695
  const vxNode = {
510
696
  ...spec,
511
697
  ref,
512
698
  isNew
513
699
  };
514
- this.domRefMap.set(ref, node);
700
+ if (ref) {
701
+ this.domRefMap.set(ref, node);
702
+ }
515
703
  node[VX_NODE_SYMBOL] = vxNode;
516
704
  return vxNode;
517
705
  }
@@ -649,6 +837,13 @@ var WebVision = (() => {
649
837
  }
650
838
  }
651
839
  }
840
+ async createRef(node) {
841
+ if (node instanceof Element) {
842
+ const sig = serializeElement(node);
843
+ const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(sig).buffer);
844
+ return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("").substring(0, 8);
845
+ }
846
+ }
652
847
  };
653
848
 
654
849
  // src/page/overlay.ts
@@ -692,7 +887,7 @@ var WebVision = (() => {
692
887
  }
693
888
 
694
889
  // src/page/highlight.ts
695
- function highlightEl(el, ref = 0, color) {
890
+ function highlightEl(el, ref, color) {
696
891
  if (!(el instanceof Element)) {
697
892
  return;
698
893
  }
@@ -728,197 +923,18 @@ var WebVision = (() => {
728
923
  label.style.transform = "translateY(50%)";
729
924
  label.textContent = String(ref);
730
925
  }
731
- function getRandomColor(index) {
926
+ function getRandomColor(ref) {
927
+ const index = ref.charCodeAt(0);
732
928
  const hue = index * 120 * 0.382 % 360;
733
929
  return `hsl(${hue}, 85%, 50%)`;
734
930
  }
735
931
 
736
- // src/page/render.ts
737
- function renderVxNode(scope, options = {}) {
738
- const buffer = [];
739
- const whitelistRefs = options.whitelistRefs ?? [];
740
- for (const { vxNode, depth } of traverseVxNode(scope)) {
741
- if (whitelistRefs.length > 0) {
742
- if (!whitelistRefs.includes(vxNode.ref)) {
743
- continue;
744
- }
745
- }
746
- if (options.skipNonInteractive && !vxNode.isInteractive) {
747
- continue;
748
- }
749
- const indent = options.skipNonInteractive ? "" : " ".repeat(depth);
750
- buffer.push(renderIndentedLine(indent, vxNode, options));
751
- }
752
- return buffer.join("\n");
753
- }
754
- function renderIndentedLine(indent, vxNode, options = {}) {
755
- const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
756
- if (!vxNode.tagName) {
757
- return [diffPrefix, indent, vxNode.textContent].filter(Boolean).join("");
758
- }
759
- const tagLine = renderTagLine(vxNode, options);
760
- const htmlStyle = options.renderStyle === "html";
761
- return [
762
- diffPrefix,
763
- indent,
764
- tagLine,
765
- htmlStyle ? "" : " ",
766
- vxNode.textContent ?? ""
767
- ].join("");
768
- }
769
- function renderTagLine(vxNode, options) {
770
- const htmlStyle = options.renderStyle === "html";
771
- const components = [];
772
- if (options.renderTagNames && vxNode.tagName) {
773
- components.push(vxNode.tagName);
774
- }
775
- if (options.renderIds && vxNode.id) {
776
- if (htmlStyle) {
777
- components.push(`id="${vxNode.id}"`);
778
- } else {
779
- components.push(`#${vxNode.id}`);
780
- }
781
- }
782
- if (options.renderClassNames && vxNode.classList?.length) {
783
- if (htmlStyle) {
784
- components.push(`class="${vxNode.classList.join(" ")}"`);
785
- } else {
786
- components.push("." + vxNode.classList.join("."));
787
- }
788
- }
789
- if (options.renderRefs) {
790
- const isRenderRef = [
791
- options.renderRefs === "all",
792
- options.renderRefs === true && !isContainerNode(vxNode)
793
- ].some(Boolean);
794
- if (isRenderRef) {
795
- components.push(`[@${vxNode.ref}]`);
796
- }
797
- }
798
- const attrs = [];
799
- if (options.renderLabelAttrs) {
800
- for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
801
- attrs.push(`${attr}="${truncateAttrValue(value)}"`);
802
- }
803
- }
804
- if (options.renderValueAttrs) {
805
- for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
806
- attrs.push(`${attr}="${truncateAttrValue(value)}"`);
807
- }
808
- }
809
- if (options.renderSrcAttrs) {
810
- for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
811
- attrs.push(`${attr}="${truncateAttrValue(value)}"`);
812
- }
813
- }
814
- if (htmlStyle) {
815
- components.push(...attrs);
816
- } else {
817
- components.push(...attrs.map((attr) => `[${attr}]`));
818
- }
819
- return htmlStyle ? `<${components.join(" ")}>` : components.join("");
820
- }
821
-
822
- // src/page/snapshot.ts
823
- var VX_DOM_SYMBOL = Symbol("vx:dom");
824
- var VX_TREE_SYMBOL = Symbol("vx:tree");
825
- var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
826
- function captureSnapshot(options = {}) {
827
- const parser = new VxTreeParser(options);
828
- const domMap = parser.getDomMap();
829
- const vxTree = parser.getTree();
830
- globalThis[VX_DOM_SYMBOL] = domMap;
831
- globalThis[VX_TREE_SYMBOL] = vxTree;
832
- return vxTree;
833
- }
834
- function getSnapshot() {
835
- const vxTree = globalThis[VX_TREE_SYMBOL];
836
- if (!vxTree) {
837
- throw new Error("[VX] Snapshot not found");
838
- }
839
- return vxTree;
840
- }
841
- function resolveDomNode(ref) {
842
- const domMap = globalThis[VX_DOM_SYMBOL];
843
- if (!domMap) {
844
- return null;
845
- }
846
- return domMap.get(ref) ?? null;
847
- }
848
-
849
- // src/page/tree.ts
850
- var VxTreeView = class {
851
- constructor(nodes, refRange) {
852
- this.nodes = nodes;
853
- this.refRange = refRange;
854
- this.refMap = /* @__PURE__ */ new Map();
855
- this.buildRefMap(nodes);
856
- }
857
- get nodeCount() {
858
- return this.refMap.size;
859
- }
860
- *traverse() {
861
- for (const vxNode of this.nodes) {
862
- yield* traverseVxNode(vxNode, 0);
863
- }
864
- }
865
- buildRefMap(nodes) {
866
- for (const node of nodes) {
867
- this.refMap.set(node.ref, node);
868
- this.buildRefMap(node.children ?? []);
869
- }
870
- }
871
- findNode(ref) {
872
- return this.refMap.get(ref) ?? null;
873
- }
874
- render(options = {}) {
875
- return this.nodes.map((node) => {
876
- return renderVxNode(node, options);
877
- }).join("\n");
878
- }
879
- highlight(options = {}) {
880
- if (options.clearOverlay) {
881
- clearOverlay();
882
- }
883
- const leafOnly = !options.includeAll;
884
- const refs = this.collectRefs(leafOnly, options.filterRefs);
885
- this.highlightRefs(refs, options);
886
- }
887
- highlightRefs(refs, options = {}) {
888
- for (const ref of refs) {
889
- const el = resolveDomNode(ref);
890
- if (el instanceof Element) {
891
- const vxNode = this.findNode(ref);
892
- const isNew = vxNode?.isNew ?? false;
893
- const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
894
- highlightEl(el, ref, color);
895
- }
896
- }
897
- }
898
- collectRefs(leafOnly = true, filterRefs) {
899
- const refs = [];
900
- for (const { vxNode } of this.traverse()) {
901
- if (leafOnly && isContainerNode(vxNode)) {
902
- continue;
903
- }
904
- if (filterRefs && !filterRefs.includes(vxNode.ref)) {
905
- continue;
906
- }
907
- refs.push(vxNode.ref);
908
- }
909
- return refs;
910
- }
911
- };
912
-
913
- // src/page/frame.ts
932
+ // src/page/page.ts
914
933
  var VxPageView = class {
915
- constructor(vxFrames) {
916
- this.vxFrames = vxFrames;
917
- this.vxFrameMap = /* @__PURE__ */ new Map();
934
+ constructor(vxTrees) {
918
935
  this.vxTreeMap = /* @__PURE__ */ new Map();
919
- for (const frame of vxFrames) {
920
- this.vxFrameMap.set(frame.frameId, frame);
921
- this.vxTreeMap.set(frame.frameId, new VxTreeView(frame.nodes, frame.refRange));
936
+ for (const vxTree of vxTrees) {
937
+ this.vxTreeMap.set(vxTree.frameId, vxTree);
922
938
  }
923
939
  }
924
940
  get vxTrees() {
@@ -928,43 +944,28 @@ var WebVision = (() => {
928
944
  return this.vxTrees.reduce((acc, vxTree) => acc + vxTree.nodeCount, 0);
929
945
  }
930
946
  findNodeByRef(ref) {
931
- const vxTree = this.findTreeByRef(ref);
932
- if (vxTree == null) {
947
+ const frame = this.findFrameByRef(ref);
948
+ if (frame == null) {
933
949
  return null;
934
950
  }
935
- return vxTree.findNode(ref);
951
+ return frame.findNode(ref);
936
952
  }
937
- findTreeByFrameId(frameId) {
953
+ findFrameById(frameId) {
938
954
  return this.vxTreeMap.get(frameId) ?? null;
939
955
  }
940
- findTreeByRef(ref) {
941
- const vxFrame = this.findFrameByRef(ref);
942
- if (vxFrame == null) {
943
- return null;
944
- }
945
- return this.vxTreeMap.get(vxFrame.frameId) ?? null;
946
- }
947
- findFrameByFrameId(frameId) {
948
- return this.vxFrameMap.get(frameId) ?? null;
949
- }
950
956
  findFrameByRef(ref) {
951
- const vxFrame = this.vxFrames.find(
952
- (frame) => ref >= frame.refRange[0] && ref <= frame.refRange[1]
953
- );
954
- if (!vxFrame) {
955
- return null;
956
- }
957
- return this.vxFrameMap.get(vxFrame.frameId) ?? null;
957
+ const frame = this.vxTrees.find((f) => f.hasRef(ref));
958
+ return frame ?? null;
958
959
  }
959
960
  getFrameByRef(ref) {
960
- const vxFrame = this.findFrameByRef(ref);
961
- if (vxFrame == null) {
961
+ const frame = this.findFrameByRef(ref);
962
+ if (frame == null) {
962
963
  throw new Error(`[VX] Frame not found for [ref=${ref}]`);
963
964
  }
964
- return vxFrame;
965
+ return frame;
965
966
  }
966
967
  findParentFrame(frameId) {
967
- const frame = this.findFrameByFrameId(frameId);
968
+ const frame = this.findFrameById(frameId);
968
969
  const iframeRef = frame?.iframeRef;
969
970
  if (iframeRef == null) {
970
971
  return null;
@@ -972,7 +973,7 @@ var WebVision = (() => {
972
973
  return this.findFrameByRef(iframeRef);
973
974
  }
974
975
  isFrameShown(frameId) {
975
- const frame = this.findFrameByFrameId(frameId);
976
+ const frame = this.findFrameById(frameId);
976
977
  if (!frame) {
977
978
  return false;
978
979
  }
@@ -981,14 +982,12 @@ var WebVision = (() => {
981
982
  if (parentFrame == null || iframeRef == null) {
982
983
  return true;
983
984
  }
984
- const vxTree = this.vxTreeMap.get(frameId);
985
- const existsInParent = !!vxTree?.findNode(iframeRef);
985
+ const existsInParent = !!parentFrame.findNode(iframeRef);
986
986
  return existsInParent ? this.isFrameShown(parentFrame.frameId) : false;
987
987
  }
988
988
  renderAll(options) {
989
- return this.vxFrames.map((frame) => {
990
- const vxTree = this.vxTreeMap.get(frame.frameId);
991
- const rendered = vxTree?.render(options);
989
+ return this.vxTrees.map((frame) => {
990
+ const rendered = frame?.render(options);
992
991
  return [
993
992
  `FRAME ${frame.frameId}${frame.iframeRef ? ` [@${frame.iframeRef}]` : ""}`,
994
993
  rendered