@page-agent/page-controller 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,6 +48,11 @@ declare interface DomConfig {
48
48
  includeAttributes?: string[];
49
49
  highlightOpacity?: number;
50
50
  highlightLabelOpacity?: number;
51
+ /**
52
+ * Preserve semantic landmark tags in dehydrated output even if not interactive
53
+ * @note maybe confusing for LLM combining with page scrolling, use with caution
54
+ **/
55
+ keepSemanticTags?: boolean;
51
56
  }
52
57
 
53
58
  declare type DomNode = TextDomNode | ElementDomNode | InteractiveElementDomNode;
@@ -95,7 +100,7 @@ declare interface FlatDomTree {
95
100
  *
96
101
  * @todo 数据脱敏过滤器
97
102
  */
98
- declare function flatTreeToString(flatTree: FlatDomTree, includeAttributes?: string[]): string;
103
+ declare function flatTreeToString(flatTree: FlatDomTree, includeAttributes?: string[], keepSemanticTags?: boolean): string;
99
104
 
100
105
  declare const getAllTextTillNextClickableElement: (node: TreeNode, maxDepth?: number) => string;
101
106
 
@@ -256,20 +261,14 @@ export declare interface PageControllerConfig extends dom.DomConfig {
256
261
 
257
262
  declare function resolveViewportExpansion(viewportExpansion?: number): number;
258
263
 
259
- /**
260
- * @private Internal method, subject to change at any time.
261
- */
262
- export declare function scrollHorizontally(right: boolean, scroll_amount: number, element?: HTMLElement | null): Promise<string>;
264
+ export declare function scrollHorizontally(scroll_amount: number, element?: HTMLElement | null): Promise<string>;
263
265
 
264
266
  /**
265
267
  * @private Internal method, subject to change at any time.
266
268
  */
267
269
  export declare function scrollIntoViewIfNeeded(element: Element): Promise<void>;
268
270
 
269
- /**
270
- * @private Internal method, subject to change at any time.
271
- */
272
- export declare function scrollVertically(down: boolean, scroll_amount: number, element?: HTMLElement | null): Promise<string>;
271
+ export declare function scrollVertically(scroll_amount: number, element?: HTMLElement | null): Promise<string>;
273
272
 
274
273
  /**
275
274
  * @todo browser-use version is very complex and supports menu tags, need to follow up
@@ -208,7 +208,7 @@ async function scrollIntoViewIfNeeded(element) {
208
208
  }
209
209
  }
210
210
  __name(scrollIntoViewIfNeeded, "scrollIntoViewIfNeeded");
211
- async function scrollVertically(down, scroll_amount, element) {
211
+ async function scrollVertically(scroll_amount, element) {
212
212
  if (element) {
213
213
  const targetElement = element;
214
214
  let currentElement = targetElement;
@@ -219,7 +219,7 @@ async function scrollVertically(down, scroll_amount, element) {
219
219
  const dy2 = scroll_amount;
220
220
  while (currentElement && attempts < 10) {
221
221
  const computedStyle = window.getComputedStyle(currentElement);
222
- const hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY);
222
+ const hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY) || computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== "auto" || computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== "auto";
223
223
  const canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight;
224
224
  if (hasScrollableY && canScrollVertically) {
225
225
  const beforeScroll = currentElement.scrollTop;
@@ -273,6 +273,8 @@ async function scrollVertically(down, scroll_amount, element) {
273
273
  if (reachedTop) return `✅ Scrolled page by ${scrolled}px. Reached the top of the page.`;
274
274
  return `✅ Scrolled page by ${scrolled}px.`;
275
275
  } else {
276
+ const warningMsg = `The document is not scrollable. Falling back to container scroll.`;
277
+ console.log(`[PageController] ${warningMsg}`);
276
278
  const scrollBefore = el.scrollTop;
277
279
  const scrollMax = el.scrollHeight - el.clientHeight;
278
280
  el.scrollBy({ top: dy, behavior: "smooth" });
@@ -280,19 +282,19 @@ async function scrollVertically(down, scroll_amount, element) {
280
282
  const scrollAfter = el.scrollTop;
281
283
  const scrolled = scrollAfter - scrollBefore;
282
284
  if (Math.abs(scrolled) < 1) {
283
- return dy > 0 ? `⚠️ Already at the bottom of container (${el.tagName}), cannot scroll down further.` : `⚠️ Already at the top of container (${el.tagName}), cannot scroll up further.`;
285
+ return dy > 0 ? `⚠️ ${warningMsg} Already at the bottom of container (${el.tagName}), cannot scroll down further.` : `⚠️ ${warningMsg} Already at the top of container (${el.tagName}), cannot scroll up further.`;
284
286
  }
285
287
  const reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1;
286
288
  const reachedTop = dy < 0 && scrollAfter <= 1;
287
289
  if (reachedBottom)
288
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the bottom.`;
290
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the bottom.`;
289
291
  if (reachedTop)
290
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the top.`;
291
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px.`;
292
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the top.`;
293
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px.`;
292
294
  }
293
295
  }
294
296
  __name(scrollVertically, "scrollVertically");
295
- async function scrollHorizontally(right, scroll_amount, element) {
297
+ async function scrollHorizontally(scroll_amount, element) {
296
298
  if (element) {
297
299
  const targetElement = element;
298
300
  let currentElement = targetElement;
@@ -300,10 +302,10 @@ async function scrollHorizontally(right, scroll_amount, element) {
300
302
  let scrolledElement = null;
301
303
  let scrollDelta = 0;
302
304
  let attempts = 0;
303
- const dx2 = right ? scroll_amount : -scroll_amount;
305
+ const dx2 = scroll_amount;
304
306
  while (currentElement && attempts < 10) {
305
307
  const computedStyle = window.getComputedStyle(currentElement);
306
- const hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX);
308
+ const hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX) || computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== "auto" || computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== "auto";
307
309
  const canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth;
308
310
  if (hasScrollableX && canScrollHorizontally) {
309
311
  const beforeScroll = currentElement.scrollLeft;
@@ -336,7 +338,7 @@ async function scrollHorizontally(right, scroll_amount, element) {
336
338
  return `No horizontally scrollable container found for element (${targetElement.tagName})`;
337
339
  }
338
340
  }
339
- const dx = right ? scroll_amount : -scroll_amount;
341
+ const dx = scroll_amount;
340
342
  const bigEnough = /* @__PURE__ */ __name((el2) => el2.clientWidth >= window.innerWidth * 0.5, "bigEnough");
341
343
  const canScroll = /* @__PURE__ */ __name((el2) => el2 && /(auto|scroll|overlay)/.test(getComputedStyle(el2).overflowX) && el2.scrollWidth > el2.clientWidth && bigEnough(el2), "canScroll");
342
344
  let el = document.activeElement;
@@ -358,6 +360,8 @@ async function scrollHorizontally(right, scroll_amount, element) {
358
360
  if (reachedLeft) return `✅ Scrolled page by ${scrolled}px. Reached the left edge of the page.`;
359
361
  return `✅ Scrolled page horizontally by ${scrolled}px.`;
360
362
  } else {
363
+ const warningMsg = `The document is not scrollable. Falling back to container scroll.`;
364
+ console.log(`[PageController] ${warningMsg}`);
361
365
  const scrollBefore = el.scrollLeft;
362
366
  const scrollMax = el.scrollWidth - el.clientWidth;
363
367
  el.scrollBy({ left: dx, behavior: "smooth" });
@@ -365,15 +369,15 @@ async function scrollHorizontally(right, scroll_amount, element) {
365
369
  const scrollAfter = el.scrollLeft;
366
370
  const scrolled = scrollAfter - scrollBefore;
367
371
  if (Math.abs(scrolled) < 1) {
368
- return dx > 0 ? `⚠️ Already at the right edge of container (${el.tagName}), cannot scroll right further.` : `⚠️ Already at the left edge of container (${el.tagName}), cannot scroll left further.`;
372
+ return dx > 0 ? `⚠️ ${warningMsg} Already at the right edge of container (${el.tagName}), cannot scroll right further.` : `⚠️ ${warningMsg} Already at the left edge of container (${el.tagName}), cannot scroll left further.`;
369
373
  }
370
374
  const reachedRight = dx > 0 && scrollAfter >= scrollMax - 1;
371
375
  const reachedLeft = dx < 0 && scrollAfter <= 1;
372
376
  if (reachedRight)
373
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the right edge.`;
377
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the right edge.`;
374
378
  if (reachedLeft)
375
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the left edge.`;
376
- return `✅ Scrolled container (${el.tagName}) horizontally by ${scrolled}px.`;
379
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the left edge.`;
380
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) horizontally by ${scrolled}px.`;
377
381
  }
378
382
  }
379
383
  __name(scrollHorizontally, "scrollHorizontally");
@@ -630,9 +634,10 @@ const domTree = /* @__PURE__ */ __name((args = {
630
634
  }
631
635
  const overflowX = style.overflowX;
632
636
  const overflowY = style.overflowY;
637
+ const hasScrollbarSignal = style.scrollbarWidth && style.scrollbarWidth !== "auto" || style.scrollbarGutter && style.scrollbarGutter !== "auto";
633
638
  const scrollableX = overflowX === "auto" || overflowX === "scroll";
634
639
  const scrollableY = overflowY === "auto" || overflowY === "scroll";
635
- if (!scrollableX && !scrollableY) {
640
+ if (!scrollableX && !scrollableY && !hasScrollbarSignal) {
636
641
  return null;
637
642
  }
638
643
  const scrollWidth = element.scrollWidth - element.clientWidth;
@@ -641,10 +646,10 @@ const domTree = /* @__PURE__ */ __name((args = {
641
646
  if (scrollWidth < threshold && scrollHeight < threshold) {
642
647
  return null;
643
648
  }
644
- if (!scrollableY && scrollWidth < threshold) {
649
+ if (!scrollableY && !hasScrollbarSignal && scrollWidth < threshold) {
645
650
  return null;
646
651
  }
647
- if (!scrollableX && scrollHeight < threshold) {
652
+ if (!scrollableX && !hasScrollbarSignal && scrollHeight < threshold) {
648
653
  return null;
649
654
  }
650
655
  const distanceToTop = element.scrollTop;
@@ -661,6 +666,7 @@ const domTree = /* @__PURE__ */ __name((args = {
661
666
  scrollable: true,
662
667
  scrollData
663
668
  });
669
+ console.log("scrollData!!!", scrollData);
664
670
  return scrollData;
665
671
  }
666
672
  __name(isScrollableElement, "isScrollableElement");
@@ -1095,6 +1101,28 @@ const domTree = /* @__PURE__ */ __name((args = {
1095
1101
  return false;
1096
1102
  }
1097
1103
  __name(isInExpandedViewport, "isInExpandedViewport");
1104
+ const INTERACTIVE_ARIA_ATTRS = [
1105
+ "aria-expanded",
1106
+ "aria-checked",
1107
+ "aria-selected",
1108
+ "aria-pressed",
1109
+ "aria-haspopup",
1110
+ "aria-controls",
1111
+ "aria-owns",
1112
+ "aria-activedescendant",
1113
+ "aria-valuenow",
1114
+ "aria-valuetext",
1115
+ "aria-valuemax",
1116
+ "aria-valuemin",
1117
+ "aria-autocomplete"
1118
+ ];
1119
+ function hasInteractiveAria(el) {
1120
+ for (let i = 0; i < INTERACTIVE_ARIA_ATTRS.length; i++) {
1121
+ if (el.hasAttribute(INTERACTIVE_ARIA_ATTRS[i])) return true;
1122
+ }
1123
+ return false;
1124
+ }
1125
+ __name(hasInteractiveAria, "hasInteractiveAria");
1098
1126
  function isInteractiveCandidate(element) {
1099
1127
  if (!element || element.nodeType !== Node.ELEMENT_NODE) return false;
1100
1128
  const tagName = element.tagName.toLowerCase();
@@ -1109,7 +1137,7 @@ const domTree = /* @__PURE__ */ __name((args = {
1109
1137
  "label"
1110
1138
  ]);
1111
1139
  if (interactiveElements.has(tagName)) return true;
1112
- const hasQuickInteractiveAttr = element.hasAttribute("onclick") || element.hasAttribute("role") || element.hasAttribute("tabindex") || element.hasAttribute("aria-") || element.hasAttribute("data-action") || element.getAttribute("contenteditable") === "true";
1140
+ const hasQuickInteractiveAttr = element.hasAttribute("onclick") || element.hasAttribute("role") || element.hasAttribute("tabindex") || hasInteractiveAria(element) || element.hasAttribute("data-action") || element.getAttribute("contenteditable") === "true";
1113
1141
  return hasQuickInteractiveAttr;
1114
1142
  }
1115
1143
  __name(isInteractiveCandidate, "isInteractiveCandidate");
@@ -1122,9 +1150,10 @@ const domTree = /* @__PURE__ */ __name((args = {
1122
1150
  "summary",
1123
1151
  "details",
1124
1152
  "label",
1125
- "option"
1153
+ "option",
1154
+ "li"
1126
1155
  ]);
1127
- const INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
1156
+ const DISTINCT_INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
1128
1157
  "button",
1129
1158
  "link",
1130
1159
  "menuitem",
@@ -1140,6 +1169,9 @@ const domTree = /* @__PURE__ */ __name((args = {
1140
1169
  "searchbox",
1141
1170
  "textbox",
1142
1171
  "listbox",
1172
+ "listitem",
1173
+ "treeitem",
1174
+ "row",
1143
1175
  "option",
1144
1176
  "scrollbar"
1145
1177
  ]);
@@ -1170,7 +1202,7 @@ const domTree = /* @__PURE__ */ __name((args = {
1170
1202
  if (DISTINCT_INTERACTIVE_TAGS.has(tagName)) {
1171
1203
  return true;
1172
1204
  }
1173
- if (role && INTERACTIVE_ROLES.has(role)) {
1205
+ if (role && DISTINCT_INTERACTIVE_ROLES.has(role)) {
1174
1206
  return true;
1175
1207
  }
1176
1208
  if (element.isContentEditable || element.getAttribute("contenteditable") === "true") {
@@ -1182,6 +1214,9 @@ const domTree = /* @__PURE__ */ __name((args = {
1182
1214
  if (element.hasAttribute("onclick") || typeof element.onclick === "function") {
1183
1215
  return true;
1184
1216
  }
1217
+ if (hasInteractiveAria(element)) {
1218
+ return true;
1219
+ }
1185
1220
  try {
1186
1221
  const getEventListenersForNode = element?.ownerDocument?.defaultView?.getEventListenersForNode || window.getEventListenersForNode;
1187
1222
  if (typeof getEventListenersForNode === "function") {
@@ -1225,6 +1260,9 @@ const domTree = /* @__PURE__ */ __name((args = {
1225
1260
  if (isHeuristicallyInteractive(element)) {
1226
1261
  return true;
1227
1262
  }
1263
+ if (extraData.get(element)?.scrollable) {
1264
+ return true;
1265
+ }
1228
1266
  return false;
1229
1267
  }
1230
1268
  __name(isElementDistinctInteraction, "isElementDistinctInteraction");
@@ -1415,6 +1453,17 @@ function resolveViewportExpansion(viewportExpansion) {
1415
1453
  return viewportExpansion ?? DEFAULT_VIEWPORT_EXPANSION;
1416
1454
  }
1417
1455
  __name(resolveViewportExpansion, "resolveViewportExpansion");
1456
+ const SEMANTIC_TAGS = /* @__PURE__ */ new Set([
1457
+ "nav",
1458
+ "menu",
1459
+ // 'main',
1460
+ "header",
1461
+ "footer",
1462
+ "aside",
1463
+ // 'article',
1464
+ // 'form',
1465
+ "dialog"
1466
+ ]);
1418
1467
  const newElementsCache = /* @__PURE__ */ new WeakMap();
1419
1468
  function getFlatTree(config) {
1420
1469
  const viewportExpansion = resolveViewportExpansion(config.viewportExpansion);
@@ -1489,7 +1538,7 @@ function matchAttributes(attrs, patterns) {
1489
1538
  return result2;
1490
1539
  }
1491
1540
  __name(matchAttributes, "matchAttributes");
1492
- function flatTreeToString(flatTree, includeAttributes) {
1541
+ function flatTreeToString(flatTree, includeAttributes = [], keepSemanticTags = false) {
1493
1542
  const DEFAULT_INCLUDE_ATTRIBUTES = [
1494
1543
  "title",
1495
1544
  "type",
@@ -1516,7 +1565,7 @@ function flatTreeToString(flatTree, includeAttributes) {
1516
1565
  // content editable
1517
1566
  "contenteditable"
1518
1567
  ];
1519
- const includeAttrs = [...includeAttributes || [], ...DEFAULT_INCLUDE_ATTRIBUTES];
1568
+ const includeAttrs = [...includeAttributes, ...DEFAULT_INCLUDE_ATTRIBUTES];
1520
1569
  const capTextLength = /* @__PURE__ */ __name((text, maxLength) => {
1521
1570
  if (text.length > maxLength) {
1522
1571
  return text.substring(0, maxLength) + "...";
@@ -1585,6 +1634,7 @@ function flatTreeToString(flatTree, includeAttributes) {
1585
1634
  let nextDepth = depth;
1586
1635
  const depthStr = " ".repeat(depth);
1587
1636
  if (node.type === "element") {
1637
+ const isSemantic = keepSemanticTags && node.tagName && SEMANTIC_TAGS.has(node.tagName);
1588
1638
  if (node.highlightIndex !== void 0) {
1589
1639
  nextDepth += 1;
1590
1640
  const text = getAllTextTillNextClickableElement(node);
@@ -1652,9 +1702,22 @@ function flatTreeToString(flatTree, includeAttributes) {
1652
1702
  line += " />";
1653
1703
  result22.push(line);
1654
1704
  }
1705
+ const emitSemantic = isSemantic && node.highlightIndex === void 0;
1706
+ const mark = emitSemantic ? result22.length : -1;
1707
+ if (emitSemantic) {
1708
+ result22.push(`${depthStr}<${node.tagName}>`);
1709
+ nextDepth += 1;
1710
+ }
1655
1711
  for (const child of node.children) {
1656
1712
  processNode(child, nextDepth, result22);
1657
1713
  }
1714
+ if (emitSemantic) {
1715
+ if (result22.length === mark + 1) {
1716
+ result22.pop();
1717
+ } else {
1718
+ result22.push(`${depthStr}</${node.tagName}>`);
1719
+ }
1720
+ }
1658
1721
  } else if (node.type === "text") {
1659
1722
  if (hasParentWithHighlightIndex(node)) {
1660
1723
  return;
@@ -1889,7 +1952,11 @@ ${scrollHintAbove}`;
1889
1952
  ...this.config,
1890
1953
  interactiveBlacklist: blacklist
1891
1954
  });
1892
- this.simplifiedHTML = flatTreeToString(this.flatTree, this.config.includeAttributes);
1955
+ this.simplifiedHTML = flatTreeToString(
1956
+ this.flatTree,
1957
+ this.config.includeAttributes,
1958
+ this.config.keepSemanticTags
1959
+ );
1893
1960
  this.selectorMap.clear();
1894
1961
  this.selectorMap = getSelectorMap(this.flatTree);
1895
1962
  this.elementTextMap.clear();
@@ -1991,9 +2058,9 @@ ${scrollHintAbove}`;
1991
2058
  try {
1992
2059
  const { down, numPages, pixels, index } = options;
1993
2060
  this.assertIndexed();
1994
- const scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight;
2061
+ const scrollAmount = (pixels ?? numPages * window.innerHeight) * (down ? 1 : -1);
1995
2062
  const element = index !== void 0 ? getElementByIndex(this.selectorMap, index) : null;
1996
- const message = await scrollVertically(down, scrollAmount, element);
2063
+ const message = await scrollVertically(scrollAmount, element);
1997
2064
  return {
1998
2065
  success: true,
1999
2066
  message
@@ -2014,7 +2081,7 @@ ${scrollHintAbove}`;
2014
2081
  this.assertIndexed();
2015
2082
  const scrollAmount = pixels * (right ? 1 : -1);
2016
2083
  const element = index !== void 0 ? getElementByIndex(this.selectorMap, index) : null;
2017
- const message = await scrollHorizontally(right, scrollAmount, element);
2084
+ const message = await scrollHorizontally(scrollAmount, element);
2018
2085
  return {
2019
2086
  success: true,
2020
2087
  message
@@ -1 +1 @@
1
- {"version":3,"file":"page-controller.js","sources":["../../src/utils/index.ts","../../src/actions.ts","../../src/dom/dom_tree/index.js","../../src/dom/index.ts","../../src/dom/getPageInfo.ts","../../src/patches/react.ts","../../src/PageController.ts"],"sourcesContent":["// ======= type guards =======\n// @note instanceof fails for elements inside iframes\n\nexport function isHTMLElement(el: unknown): el is HTMLElement {\n\t// @todo either specify to HTMLElement or allow Element here.\n\treturn !!el && (el as Node).nodeType === 1\n}\n\nexport function isInputElement(el: Element): el is HTMLInputElement {\n\treturn el?.nodeType === 1 && el.tagName === 'INPUT'\n}\n\nexport function isTextAreaElement(el: Element): el is HTMLTextAreaElement {\n\treturn el?.nodeType === 1 && el.tagName === 'TEXTAREA'\n}\n\nexport function isSelectElement(el: Element): el is HTMLSelectElement {\n\treturn el?.nodeType === 1 && el.tagName === 'SELECT'\n}\n\nexport function isAnchorElement(el: Element): el is HTMLAnchorElement {\n\treturn el?.nodeType === 1 && el.tagName === 'A'\n}\n\n// ======= iframe helpers =======\n\n/** Iframe offset for translating element coordinates to top-frame viewport. */\nexport function getIframeOffset(element: HTMLElement): { x: number; y: number } {\n\tconst frame = element.ownerDocument.defaultView?.frameElement as HTMLElement | null\n\tif (!frame) return { x: 0, y: 0 }\n\tconst rect = frame.getBoundingClientRect()\n\treturn { x: rect.left, y: rect.top }\n}\n\n/**\n * Get native value setter from the element's own prototype (iframe-safe).\n * @note for React\n */\nexport function getNativeValueSetter(element: HTMLInputElement | HTMLTextAreaElement) {\n\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\treturn Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element) as object, 'value')!\n\t\t.set as (v: string) => void\n}\n\n// ======= general utils =======\n\nexport async function waitFor(seconds: number): Promise<void> {\n\tawait new Promise((resolve) => setTimeout(resolve, seconds * 1000))\n}\n\n// ======= mask events =======\n\n/**\n * Move the visual pointer to a position within an element.\n * @param x - x coordinate in the element's document viewport\n * @param y - y coordinate in the element's document viewport\n */\nexport async function movePointerToElement(element: HTMLElement, x: number, y: number) {\n\tconst offset = getIframeOffset(element)\n\n\twindow.dispatchEvent(\n\t\tnew CustomEvent('PageAgent::MovePointerTo', {\n\t\t\tdetail: { x: x + offset.x, y: y + offset.y },\n\t\t})\n\t)\n\n\tawait waitFor(0.3)\n}\n\nexport async function clickPointer() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::ClickPointer'))\n}\n\nexport async function enablePassThrough() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::EnablePassThrough'))\n}\n\nexport async function disablePassThrough() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::DisablePassThrough'))\n}\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n */\nimport type { InteractiveElementDomNode } from './dom/dom_tree/type'\nimport {\n\tclickPointer,\n\tdisablePassThrough,\n\tenablePassThrough,\n\tgetNativeValueSetter,\n\tisHTMLElement,\n\tisInputElement,\n\tisSelectElement,\n\tisTextAreaElement,\n\tmovePointerToElement,\n\twaitFor,\n} from './utils'\n\n/**\n * Get the HTMLElement by index from a selectorMap.\n * @private Internal method, subject to change at any time.\n */\nexport function getElementByIndex(\n\tselectorMap: Map<number, InteractiveElementDomNode>,\n\tindex: number\n): HTMLElement {\n\tconst interactiveNode = selectorMap.get(index)\n\tif (!interactiveNode) {\n\t\tthrow new Error(`No interactive element found at index ${index}`)\n\t}\n\n\tconst element = interactiveNode.ref\n\tif (!element) {\n\t\tthrow new Error(`Element at index ${index} does not have a reference`)\n\t}\n\n\tif (!isHTMLElement(element)) {\n\t\tthrow new Error(`Element at index ${index} is not an HTMLElement`)\n\t}\n\n\treturn element\n}\n\nlet lastClickedElement: HTMLElement | null = null\n\nfunction blurLastClickedElement() {\n\tif (lastClickedElement) {\n\t\tlastClickedElement.dispatchEvent(new PointerEvent('pointerout', { bubbles: true }))\n\t\tlastClickedElement.dispatchEvent(new PointerEvent('pointerleave', { bubbles: false }))\n\t\tlastClickedElement.dispatchEvent(new MouseEvent('mouseout', { bubbles: true }))\n\t\tlastClickedElement.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false }))\n\t\tlastClickedElement.blur()\n\t\tlastClickedElement = null\n\t}\n}\n\n/**\n * Simulate a full click following W3C Pointer Events + UI Events spec order:\n * pointerover/enter → mouseover/enter → pointerdown → mousedown → [focus] →\n * pointerup → mouseup → click\n *\n * @private Internal method, subject to change at any time.\n */\nexport async function clickElement(element: HTMLElement) {\n\tblurLastClickedElement()\n\n\tlastClickedElement = element\n\n\tawait scrollIntoViewIfNeeded(element)\n\tconst frame = element.ownerDocument.defaultView?.frameElement\n\tif (frame) await scrollIntoViewIfNeeded(frame)\n\n\tconst rect = element.getBoundingClientRect()\n\tconst x = rect.left + rect.width / 2\n\tconst y = rect.top + rect.height / 2\n\n\tawait movePointerToElement(element, x, y)\n\tawait clickPointer()\n\n\tawait waitFor(0.1)\n\n\t// Hit-test to find the deepest element at click coordinates, matching\n\t// real browser behavior where events target the innermost element.\n\t// @note This may hit a element in the blacklist\n\t// TODO: This is a temporary workaround. Should have been handled during dom extraction.\n\tconst doc = element.ownerDocument\n\tawait enablePassThrough()\n\tconst hitTarget = doc.elementFromPoint(x, y)\n\tawait disablePassThrough()\n\tconst target =\n\t\thitTarget instanceof HTMLElement && element.contains(hitTarget) ? hitTarget : element\n\n\tconst pointerOpts = {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tclientX: x,\n\t\tclientY: y,\n\t\tpointerType: 'mouse',\n\t}\n\tconst mouseOpts = { bubbles: true, cancelable: true, clientX: x, clientY: y, button: 0 }\n\n\t// Hover — pointer events first, then mouse events (spec order)\n\ttarget.dispatchEvent(new PointerEvent('pointerover', pointerOpts))\n\ttarget.dispatchEvent(new PointerEvent('pointerenter', { ...pointerOpts, bubbles: false }))\n\ttarget.dispatchEvent(new MouseEvent('mouseover', mouseOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseenter', { ...mouseOpts, bubbles: false }))\n\n\t// Press\n\ttarget.dispatchEvent(new PointerEvent('pointerdown', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mousedown', mouseOpts))\n\n\t// Focus is not part of the standard pointer/mouse event sequence\n\t// \"undefined and varies between user agents\".\n\t// We focus the original element (nearest focusable ancestor), not the hit-test target, matching browser behavior.\n\telement.focus({ preventScroll: true })\n\n\t// Release\n\ttarget.dispatchEvent(new PointerEvent('pointerup', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseup', mouseOpts))\n\n\t// Click — activation behavior (navigation, form submit, etc.) triggers\n\t// via bubbling from target up to the interactive ancestor.\n\ttarget.click()\n\n\tawait waitFor(0.2)\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function inputTextElement(element: HTMLElement, text: string) {\n\tconst isContentEditable = element.isContentEditable\n\tif (!isInputElement(element) && !isTextAreaElement(element) && !isContentEditable) {\n\t\tthrow new Error('Element is not an input, textarea, or contenteditable')\n\t}\n\n\tawait clickElement(element)\n\n\tif (isContentEditable) {\n\t\t// Contenteditable support (partial)\n\t\t// Not supported:\n\t\t// - Monaco/CodeMirror: Require direct JS instance access. No universal way to obtain.\n\t\t// - Draft.js: Not responsive to synthetic/execCommand/Range/DataTransfer. Unmaintained.\n\t\t//\n\t\t// Strategy: Try Plan A (synthetic events) first, then verify and fall back\n\t\t// to Plan B (execCommand) if the text wasn't actually inserted.\n\t\t//\n\t\t// Plan A: Dispatch synthetic events\n\t\t// Works: React contenteditable, Quill.\n\t\t// Fails: Slate.js, some contenteditable editors that ignore synthetic events.\n\t\t// Sequence: beforeinput -> mutation -> input -> change -> blur\n\n\t\t// Dispatch beforeinput + mutation + input for clearing\n\t\tif (\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('beforeinput', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tinputType: 'deleteContent',\n\t\t\t\t})\n\t\t\t)\n\t\t) {\n\t\t\telement.innerText = ''\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('input', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tinputType: 'deleteContent',\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// Dispatch beforeinput + mutation + input for insertion (important for React apps)\n\t\tif (\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('beforeinput', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tinputType: 'insertText',\n\t\t\t\t\tdata: text,\n\t\t\t\t})\n\t\t\t)\n\t\t) {\n\t\t\telement.innerText = text\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('input', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tinputType: 'insertText',\n\t\t\t\t\tdata: text,\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// Verify Plan A worked by checking if the text was actually inserted\n\t\tconst planASucceeded = element.innerText.trim() === text.trim()\n\n\t\tif (!planASucceeded) {\n\t\t\t// Plan B: execCommand fallback (deprecated but widely supported)\n\t\t\t// Works: Quill, Slate.js, react contenteditable components.\n\t\t\t// This approach integrates with the browser's undo stack and is handled\n\t\t\t// natively by most rich-text editors.\n\t\t\telement.focus()\n\n\t\t\t// Select all existing content and delete it\n\t\t\tconst doc = element.ownerDocument\n\t\t\tconst selection = (doc.defaultView || window).getSelection()\n\t\t\tconst range = doc.createRange()\n\t\t\trange.selectNodeContents(element)\n\t\t\tselection?.removeAllRanges()\n\t\t\tselection?.addRange(range)\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tdoc.execCommand('delete', false)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tdoc.execCommand('insertText', false, text)\n\t\t}\n\n\t\t// Dispatch change event (for good measure)\n\t\telement.dispatchEvent(new Event('change', { bubbles: true }))\n\n\t\t// Trigger blur for validation\n\t\telement.blur()\n\t} else {\n\t\tgetNativeValueSetter(element as HTMLInputElement | HTMLTextAreaElement).call(element, text)\n\t}\n\n\t// Only dispatch shared input event for non-contenteditable (contenteditable has its own)\n\tif (!isContentEditable) {\n\t\telement.dispatchEvent(new Event('input', { bubbles: true }))\n\t}\n\n\tawait waitFor(0.1)\n\n\tblurLastClickedElement()\n}\n\n/**\n * @todo browser-use version is very complex and supports menu tags, need to follow up\n * @private Internal method, subject to change at any time.\n */\nexport async function selectOptionElement(selectElement: HTMLSelectElement, optionText: string) {\n\tif (!isSelectElement(selectElement)) {\n\t\tthrow new Error('Element is not a select element')\n\t}\n\n\tconst options = Array.from(selectElement.options)\n\tconst option = options.find((opt) => opt.textContent?.trim() === optionText.trim())\n\n\tif (!option) {\n\t\tthrow new Error(`Option with text \"${optionText}\" not found in select element`)\n\t}\n\n\tselectElement.value = option.value\n\tselectElement.dispatchEvent(new Event('change', { bubbles: true }))\n\n\tawait waitFor(0.1) // Wait to ensure change event processing completes\n}\n\ninterface ScrollableElement extends Element {\n\tscrollIntoViewIfNeeded?: (centerIfNeeded?: boolean) => void\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function scrollIntoViewIfNeeded(element: Element) {\n\tconst el = element as ScrollableElement\n\tif (typeof el.scrollIntoViewIfNeeded === 'function') {\n\t\tel.scrollIntoViewIfNeeded()\n\t\t// await waitFor(0.5) // Animation playback\n\t} else {\n\t\t// @todo visibility check\n\t\telement.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' })\n\t\t// await waitFor(0.5) // Animation playback\n\t}\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function scrollVertically(\n\tdown: boolean,\n\tscroll_amount: number,\n\telement?: HTMLElement | null\n) {\n\t// Element-specific scrolling if element is provided\n\tif (element) {\n\t\tconst targetElement = element\n\t\tlet currentElement = targetElement as HTMLElement | null\n\t\tlet scrollSuccess = false\n\t\tlet scrolledElement: HTMLElement | null = null\n\t\tlet scrollDelta = 0\n\t\tlet attempts = 0\n\t\tconst dy = scroll_amount\n\n\t\twhile (currentElement && attempts < 10) {\n\t\t\tconst computedStyle = window.getComputedStyle(currentElement)\n\t\t\tconst hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY)\n\t\t\tconst canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight\n\n\t\t\tif (hasScrollableY && canScrollVertically) {\n\t\t\t\tconst beforeScroll = currentElement.scrollTop\n\t\t\t\tconst maxScroll = currentElement.scrollHeight - currentElement.clientHeight\n\n\t\t\t\tlet scrollAmount = dy / 3\n\n\t\t\t\tif (scrollAmount > 0) {\n\t\t\t\t\tscrollAmount = Math.min(scrollAmount, maxScroll - beforeScroll)\n\t\t\t\t} else {\n\t\t\t\t\tscrollAmount = Math.max(scrollAmount, -beforeScroll)\n\t\t\t\t}\n\n\t\t\t\tcurrentElement.scrollTop = beforeScroll + scrollAmount\n\n\t\t\t\tconst afterScroll = currentElement.scrollTop\n\t\t\t\tconst actualScrollDelta = afterScroll - beforeScroll\n\n\t\t\t\tif (Math.abs(actualScrollDelta) > 0.5) {\n\t\t\t\t\tscrollSuccess = true\n\t\t\t\t\tscrolledElement = currentElement\n\t\t\t\t\tscrollDelta = actualScrollDelta\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentElement === document.body || currentElement === document.documentElement) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentElement = currentElement.parentElement\n\t\t\tattempts++\n\t\t}\n\n\t\tif (scrollSuccess) {\n\t\t\treturn `Scrolled container (${scrolledElement?.tagName}) by ${scrollDelta}px`\n\t\t} else {\n\t\t\treturn `No scrollable container found for element (${targetElement.tagName})`\n\t\t}\n\t}\n\n\t// Page-level scrolling (default or fallback)\n\n\tconst dy = scroll_amount\n\tconst bigEnough = (el: HTMLElement) => el.clientHeight >= window.innerHeight * 0.5\n\tconst canScroll = (el: HTMLElement | null) =>\n\t\tel &&\n\t\t/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowY) &&\n\t\tel.scrollHeight > el.clientHeight &&\n\t\tbigEnough(el)\n\n\tlet el: HTMLElement | null = document.activeElement as HTMLElement | null\n\twhile (el && !canScroll(el) && el !== document.body) el = el.parentElement\n\n\tel = canScroll(el)\n\t\t? el\n\t\t: Array.from(document.querySelectorAll<HTMLElement>('*')).find(canScroll) ||\n\t\t\t(document.scrollingElement as HTMLElement) ||\n\t\t\t(document.documentElement as HTMLElement)\n\n\tif (el === document.scrollingElement || el === document.documentElement || el === document.body) {\n\t\t// Page-level scroll\n\t\tconst scrollBefore = window.scrollY\n\t\tconst scrollMax = document.documentElement.scrollHeight - window.innerHeight\n\n\t\twindow.scrollBy(0, dy)\n\n\t\tconst scrollAfter = window.scrollY\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dy > 0\n\t\t\t\t? `⚠️ Already at the bottom of the page, cannot scroll down further.`\n\t\t\t\t: `⚠️ Already at the top of the page, cannot scroll up further.`\n\t\t}\n\n\t\tconst reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedTop = dy < 0 && scrollAfter <= 1\n\n\t\tif (reachedBottom) return `✅ Scrolled page by ${scrolled}px. Reached the bottom of the page.`\n\t\tif (reachedTop) return `✅ Scrolled page by ${scrolled}px. Reached the top of the page.`\n\t\treturn `✅ Scrolled page by ${scrolled}px.`\n\t} else {\n\t\t// Container scroll\n\t\tconst scrollBefore = el!.scrollTop\n\t\tconst scrollMax = el!.scrollHeight - el!.clientHeight\n\n\t\tel!.scrollBy({ top: dy, behavior: 'smooth' })\n\t\tawait waitFor(0.1)\n\n\t\tconst scrollAfter = el!.scrollTop\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dy > 0\n\t\t\t\t? `⚠️ Already at the bottom of container (${el!.tagName}), cannot scroll down further.`\n\t\t\t\t: `⚠️ Already at the top of container (${el!.tagName}), cannot scroll up further.`\n\t\t}\n\n\t\tconst reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedTop = dy < 0 && scrollAfter <= 1\n\n\t\tif (reachedBottom)\n\t\t\treturn `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the bottom.`\n\t\tif (reachedTop)\n\t\t\treturn `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the top.`\n\t\treturn `✅ Scrolled container (${el!.tagName}) by ${scrolled}px.`\n\t}\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function scrollHorizontally(\n\tright: boolean,\n\tscroll_amount: number,\n\telement?: HTMLElement | null\n) {\n\t// Element-specific scrolling if element is provided\n\tif (element) {\n\t\tconst targetElement = element\n\t\tlet currentElement = targetElement as HTMLElement | null\n\t\tlet scrollSuccess = false\n\t\tlet scrolledElement: HTMLElement | null = null\n\t\tlet scrollDelta = 0\n\t\tlet attempts = 0\n\t\tconst dx = right ? scroll_amount : -scroll_amount\n\n\t\twhile (currentElement && attempts < 10) {\n\t\t\tconst computedStyle = window.getComputedStyle(currentElement)\n\t\t\tconst hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX)\n\t\t\tconst canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth\n\n\t\t\tif (hasScrollableX && canScrollHorizontally) {\n\t\t\t\tconst beforeScroll = currentElement.scrollLeft\n\t\t\t\tconst maxScroll = currentElement.scrollWidth - currentElement.clientWidth\n\n\t\t\t\tlet scrollAmount = dx / 3\n\n\t\t\t\tif (scrollAmount > 0) {\n\t\t\t\t\tscrollAmount = Math.min(scrollAmount, maxScroll - beforeScroll)\n\t\t\t\t} else {\n\t\t\t\t\tscrollAmount = Math.max(scrollAmount, -beforeScroll)\n\t\t\t\t}\n\n\t\t\t\tcurrentElement.scrollLeft = beforeScroll + scrollAmount\n\n\t\t\t\tconst afterScroll = currentElement.scrollLeft\n\t\t\t\tconst actualScrollDelta = afterScroll - beforeScroll\n\n\t\t\t\tif (Math.abs(actualScrollDelta) > 0.5) {\n\t\t\t\t\tscrollSuccess = true\n\t\t\t\t\tscrolledElement = currentElement\n\t\t\t\t\tscrollDelta = actualScrollDelta\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentElement === document.body || currentElement === document.documentElement) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentElement = currentElement.parentElement\n\t\t\tattempts++\n\t\t}\n\n\t\tif (scrollSuccess) {\n\t\t\treturn `Scrolled container (${scrolledElement?.tagName}) horizontally by ${scrollDelta}px`\n\t\t} else {\n\t\t\treturn `No horizontally scrollable container found for element (${targetElement.tagName})`\n\t\t}\n\t}\n\n\t// Page-level scrolling (default or fallback)\n\n\tconst dx = right ? scroll_amount : -scroll_amount\n\tconst bigEnough = (el: HTMLElement) => el.clientWidth >= window.innerWidth * 0.5\n\tconst canScroll = (el: HTMLElement | null) =>\n\t\tel &&\n\t\t/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowX) &&\n\t\tel.scrollWidth > el.clientWidth &&\n\t\tbigEnough(el)\n\n\tlet el: HTMLElement | null = document.activeElement as HTMLElement | null\n\twhile (el && !canScroll(el) && el !== document.body) el = el.parentElement\n\n\tel = canScroll(el)\n\t\t? el\n\t\t: Array.from(document.querySelectorAll<HTMLElement>('*')).find(canScroll) ||\n\t\t\t(document.scrollingElement as HTMLElement) ||\n\t\t\t(document.documentElement as HTMLElement)\n\n\tif (el === document.scrollingElement || el === document.documentElement || el === document.body) {\n\t\t// Page-level scroll\n\t\tconst scrollBefore = window.scrollX\n\t\tconst scrollMax = document.documentElement.scrollWidth - window.innerWidth\n\n\t\twindow.scrollBy(dx, 0)\n\n\t\tconst scrollAfter = window.scrollX\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dx > 0\n\t\t\t\t? `⚠️ Already at the right edge of the page, cannot scroll right further.`\n\t\t\t\t: `⚠️ Already at the left edge of the page, cannot scroll left further.`\n\t\t}\n\n\t\tconst reachedRight = dx > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedLeft = dx < 0 && scrollAfter <= 1\n\n\t\tif (reachedRight)\n\t\t\treturn `✅ Scrolled page by ${scrolled}px. Reached the right edge of the page.`\n\t\tif (reachedLeft) return `✅ Scrolled page by ${scrolled}px. Reached the left edge of the page.`\n\t\treturn `✅ Scrolled page horizontally by ${scrolled}px.`\n\t} else {\n\t\t// Container scroll\n\t\tconst scrollBefore = el!.scrollLeft\n\t\tconst scrollMax = el!.scrollWidth - el!.clientWidth\n\n\t\tel!.scrollBy({ left: dx, behavior: 'smooth' })\n\t\tawait waitFor(0.1)\n\n\t\tconst scrollAfter = el!.scrollLeft\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dx > 0\n\t\t\t\t? `⚠️ Already at the right edge of container (${el!.tagName}), cannot scroll right further.`\n\t\t\t\t: `⚠️ Already at the left edge of container (${el!.tagName}), cannot scroll left further.`\n\t\t}\n\n\t\tconst reachedRight = dx > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedLeft = dx < 0 && scrollAfter <= 1\n\n\t\tif (reachedRight)\n\t\t\treturn `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the right edge.`\n\t\tif (reachedLeft)\n\t\t\treturn `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the left edge.`\n\t\treturn `✅ Scrolled container (${el!.tagName}) horizontally by ${scrolled}px.`\n\t}\n}\n","/**\n * @file port from browser-use\n * @see https://github.com/browser-use/browser-use/commits/main/browser_use/dom/dom_tree/index.js\n * @match 0.5.9 d51b6e73daff7165fdd3e44debd667e7f5f7fdc5\n *\n * search @edit for all the changed lines.\n *\n * @edit export\n * @edit add interactiveBlacklist interactiveWhitelist\n * @edit adjustable opacity\n * @edit direct dom ref\n * @edit @workaround input.checked\n * @edit smaller zIndex for highlight\n * @edit no need for xpath\n * @edit add `extra` field for extra data\n * @edit scrollable element detection\n * @edit add `data-browser-use-ignore` attribute\n * @edit improve `sampleRect`, filter out rects with 0 area\n * @edit exclude aria-hidden elements\n * @edit make sure attributes exist for interactive candidates.\n */\n\nexport default (\n\targs = {\n\t\tdoHighlightElements: true,\n\t\tfocusHighlightIndex: -1,\n\t\tviewportExpansion: 0,\n\t\tdebugMode: false,\n\n\t\t/**\n\t\t * @edit\n\t\t */\n\t\t/** @type {Element[]} */\n\t\tinteractiveBlacklist: [],\n\t\t/** @type {Element[]} */\n\t\tinteractiveWhitelist: [],\n\t\thighlightOpacity: 0.1,\n\t\thighlightLabelOpacity: 0.5,\n\t}\n) => {\n\t/**\n\t * @edit\n\t */\n\tconst { interactiveBlacklist, interactiveWhitelist, highlightOpacity, highlightLabelOpacity } =\n\t\targs\n\n\tconst { doHighlightElements, focusHighlightIndex, viewportExpansion, debugMode } = args\n\tlet highlightIndex = 0 // Reset highlight index\n\n\t/**\n\t * @edit add `extra` field for extra data\n\t */\n\tconst extraData = new WeakMap()\n\tfunction addExtraData(element, data) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return\n\t\textraData.set(element, { ...extraData.get(element), ...data })\n\t}\n\n\t// Add caching mechanisms at the top level\n\tconst DOM_CACHE = {\n\t\tboundingRects: new WeakMap(),\n\t\tclientRects: new WeakMap(),\n\t\tcomputedStyles: new WeakMap(),\n\t\tclearCache: () => {\n\t\t\tDOM_CACHE.boundingRects = new WeakMap()\n\t\t\tDOM_CACHE.clientRects = new WeakMap()\n\t\t\tDOM_CACHE.computedStyles = new WeakMap()\n\t\t},\n\t}\n\n\t/**\n\t * Gets the cached bounding rect for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the bounding rect for.\n\t * @returns {DOMRect | null} The cached bounding rect, or null if the element is not found.\n\t */\n\tfunction getCachedBoundingRect(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.boundingRects.has(element)) {\n\t\t\treturn DOM_CACHE.boundingRects.get(element)\n\t\t}\n\n\t\tconst rect = element.getBoundingClientRect()\n\n\t\tif (rect) {\n\t\t\tDOM_CACHE.boundingRects.set(element, rect)\n\t\t}\n\t\treturn rect\n\t}\n\n\t/**\n\t * Gets the cached computed style for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the computed style for.\n\t * @returns {CSSStyleDeclaration | null} The cached computed style, or null if the element is not found.\n\t */\n\tfunction getCachedComputedStyle(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.computedStyles.has(element)) {\n\t\t\treturn DOM_CACHE.computedStyles.get(element)\n\t\t}\n\n\t\tconst style = window.getComputedStyle(element)\n\n\t\tif (style) {\n\t\t\tDOM_CACHE.computedStyles.set(element, style)\n\t\t}\n\t\treturn style\n\t}\n\n\t/**\n\t * Gets the cached client rects for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the client rects for.\n\t * @returns {DOMRectList | null} The cached client rects, or null if the element is not found.\n\t */\n\tfunction getCachedClientRects(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.clientRects.has(element)) {\n\t\t\treturn DOM_CACHE.clientRects.get(element)\n\t\t}\n\n\t\tconst rects = element.getClientRects()\n\n\t\tif (rects) {\n\t\t\tDOM_CACHE.clientRects.set(element, rects)\n\t\t}\n\t\treturn rects\n\t}\n\n\t/**\n\t * Hash map of DOM nodes indexed by their highlight index.\n\t *\n\t * @type {Object<string, any>}\n\t */\n\tconst DOM_HASH_MAP = {}\n\n\tconst ID = { current: 0 }\n\n\tconst HIGHLIGHT_CONTAINER_ID = 'playwright-highlight-container'\n\n\t// Add a WeakMap cache for XPath strings\n\tconst xpathCache = new WeakMap()\n\n\t// // Initialize once and reuse\n\t// const viewportObserver = new IntersectionObserver(\n\t// (entries) => {\n\t// entries.forEach(entry => {\n\t// elementVisibilityMap.set(entry.target, entry.isIntersecting);\n\t// });\n\t// },\n\t// { rootMargin: `${viewportExpansion}px` }\n\t// );\n\n\t/**\n\t * Highlights an element in the DOM and returns the index of the next element.\n\t *\n\t * @param {HTMLElement} element - The element to highlight.\n\t * @param {number} index - The index of the element.\n\t * @param {HTMLElement | null} parentIframe - The parent iframe node.\n\t * @returns {number} The index of the next element.\n\t */\n\tfunction highlightElement(element, index, parentIframe = null) {\n\t\tif (!element) return index\n\n\t\tconst overlays = []\n\t\t/**\n\t\t * @type {HTMLElement | null}\n\t\t */\n\t\tlet label = null\n\t\tlet labelWidth = 20\n\t\tlet labelHeight = 16\n\t\tlet cleanupFn = null\n\n\t\ttry {\n\t\t\t// Create or get highlight container\n\t\t\tlet container = document.getElementById(HIGHLIGHT_CONTAINER_ID)\n\t\t\tif (!container) {\n\t\t\t\tcontainer = document.createElement('div')\n\t\t\t\tcontainer.id = HIGHLIGHT_CONTAINER_ID\n\t\t\t\tcontainer.style.position = 'fixed'\n\t\t\t\tcontainer.style.pointerEvents = 'none'\n\t\t\t\tcontainer.style.top = '0'\n\t\t\t\tcontainer.style.left = '0'\n\t\t\t\tcontainer.style.width = '100%'\n\t\t\t\tcontainer.style.height = '100%'\n\n\t\t\t\t/**\n\t\t\t\t * @edit smaller zIndex for highlight\n\t\t\t\t */\n\t\t\t\t// Use the maximum valid value in zIndex to ensure the element is not blocked by overlapping elements.\n\t\t\t\t// container.style.zIndex = \"2147483647\";\n\t\t\t\tcontainer.style.zIndex = '2147483640'\n\n\t\t\t\tcontainer.style.backgroundColor = 'transparent'\n\t\t\t\tdocument.body.appendChild(container)\n\t\t\t}\n\n\t\t\t// Get element client rects\n\t\t\tconst rects = element.getClientRects() // Use getClientRects()\n\n\t\t\tif (!rects || rects.length === 0) return index // Exit if no rects\n\n\t\t\t// Generate a color based on the index\n\t\t\tconst colors = [\n\t\t\t\t'#FF0000',\n\t\t\t\t'#00FF00',\n\t\t\t\t'#0000FF',\n\t\t\t\t'#FFA500',\n\t\t\t\t'#800080',\n\t\t\t\t'#008080',\n\t\t\t\t'#FF69B4',\n\t\t\t\t'#4B0082',\n\t\t\t\t'#FF4500',\n\t\t\t\t'#2E8B57',\n\t\t\t\t'#DC143C',\n\t\t\t\t'#4682B4',\n\t\t\t]\n\t\t\tconst colorIndex = index % colors.length\n\t\t\tlet baseColor = colors[colorIndex]\n\n\t\t\t/**\n\t\t\t * @edit adjustable opacity\n\t\t\t */\n\t\t\t// const backgroundColor = baseColor + \"1A\"; // 10% opacity version of the color\n\t\t\tconst backgroundColor =\n\t\t\t\tbaseColor +\n\t\t\t\tMath.floor(highlightOpacity * 255)\n\t\t\t\t\t.toString(16)\n\t\t\t\t\t.padStart(2, '0')\n\t\t\tbaseColor =\n\t\t\t\tbaseColor +\n\t\t\t\tMath.floor(highlightLabelOpacity * 255)\n\t\t\t\t\t.toString(16)\n\t\t\t\t\t.padStart(2, '0')\n\n\t\t\t// Get iframe offset if necessary\n\t\t\tlet iframeOffset = { x: 0, y: 0 }\n\t\t\tif (parentIframe) {\n\t\t\t\tconst iframeRect = parentIframe.getBoundingClientRect() // Keep getBoundingClientRect for iframe offset\n\t\t\t\tiframeOffset.x = iframeRect.left\n\t\t\t\tiframeOffset.y = iframeRect.top\n\t\t\t}\n\n\t\t\t// Create fragment to hold overlay elements\n\t\t\tconst fragment = document.createDocumentFragment()\n\n\t\t\t// Create highlight overlays for each client rect\n\t\t\tfor (const rect of rects) {\n\t\t\t\tif (rect.width === 0 || rect.height === 0) continue // Skip empty rects\n\n\t\t\t\tconst overlay = document.createElement('div')\n\t\t\t\toverlay.style.position = 'fixed'\n\t\t\t\toverlay.style.border = `2px solid ${baseColor}`\n\t\t\t\toverlay.style.backgroundColor = backgroundColor\n\t\t\t\toverlay.style.pointerEvents = 'none'\n\t\t\t\toverlay.style.boxSizing = 'border-box'\n\n\t\t\t\tconst top = rect.top + iframeOffset.y\n\t\t\t\tconst left = rect.left + iframeOffset.x\n\n\t\t\t\toverlay.style.top = `${top}px`\n\t\t\t\toverlay.style.left = `${left}px`\n\t\t\t\toverlay.style.width = `${rect.width}px`\n\t\t\t\toverlay.style.height = `${rect.height}px`\n\n\t\t\t\tfragment.appendChild(overlay)\n\t\t\t\toverlays.push({ element: overlay, initialRect: rect }) // Store overlay and its rect\n\t\t\t}\n\n\t\t\t// Create and position a single label relative to the first rect\n\t\t\tconst firstRect = rects[0]\n\t\t\tlabel = document.createElement('div')\n\t\t\tlabel.className = 'playwright-highlight-label'\n\t\t\tlabel.style.position = 'fixed'\n\t\t\tlabel.style.background = baseColor\n\t\t\tlabel.style.color = 'white'\n\t\t\tlabel.style.padding = '1px 4px'\n\t\t\tlabel.style.borderRadius = '4px'\n\t\t\tlabel.style.fontSize = `${Math.min(12, Math.max(8, firstRect.height / 2))}px`\n\t\t\tlabel.textContent = index.toString()\n\n\t\t\tlabelWidth = label.offsetWidth > 0 ? label.offsetWidth : labelWidth // Update actual width if possible\n\t\t\tlabelHeight = label.offsetHeight > 0 ? label.offsetHeight : labelHeight // Update actual height if possible\n\n\t\t\tconst firstRectTop = firstRect.top + iframeOffset.y\n\t\t\tconst firstRectLeft = firstRect.left + iframeOffset.x\n\n\t\t\tlet labelTop = firstRectTop + 2\n\t\t\tlet labelLeft = firstRectLeft + firstRect.width - labelWidth - 2\n\n\t\t\t// Adjust label position if first rect is too small\n\t\t\tif (firstRect.width < labelWidth + 4 || firstRect.height < labelHeight + 4) {\n\t\t\t\tlabelTop = firstRectTop - labelHeight - 2\n\t\t\t\tlabelLeft = firstRectLeft + firstRect.width - labelWidth // Align with right edge\n\t\t\t\tif (labelLeft < iframeOffset.x) labelLeft = firstRectLeft // Prevent going off-left\n\t\t\t}\n\n\t\t\t// Ensure label stays within viewport bounds slightly better\n\t\t\tlabelTop = Math.max(0, Math.min(labelTop, window.innerHeight - labelHeight))\n\t\t\tlabelLeft = Math.max(0, Math.min(labelLeft, window.innerWidth - labelWidth))\n\n\t\t\tlabel.style.top = `${labelTop}px`\n\t\t\tlabel.style.left = `${labelLeft}px`\n\n\t\t\tfragment.appendChild(label)\n\n\t\t\t// Update positions on scroll/resize\n\t\t\tconst updatePositions = () => {\n\t\t\t\tconst newRects = element.getClientRects() // Get fresh rects\n\t\t\t\tlet newIframeOffset = { x: 0, y: 0 }\n\n\t\t\t\tif (parentIframe) {\n\t\t\t\t\tconst iframeRect = parentIframe.getBoundingClientRect() // Keep getBoundingClientRect for iframe\n\t\t\t\t\tnewIframeOffset.x = iframeRect.left\n\t\t\t\t\tnewIframeOffset.y = iframeRect.top\n\t\t\t\t}\n\n\t\t\t\t// Update each overlay\n\t\t\t\toverlays.forEach((overlayData, i) => {\n\t\t\t\t\tif (i < newRects.length) {\n\t\t\t\t\t\t// Check if rect still exists\n\t\t\t\t\t\tconst newRect = newRects[i]\n\t\t\t\t\t\tconst newTop = newRect.top + newIframeOffset.y\n\t\t\t\t\t\tconst newLeft = newRect.left + newIframeOffset.x\n\n\t\t\t\t\t\toverlayData.element.style.top = `${newTop}px`\n\t\t\t\t\t\toverlayData.element.style.left = `${newLeft}px`\n\t\t\t\t\t\toverlayData.element.style.width = `${newRect.width}px`\n\t\t\t\t\t\toverlayData.element.style.height = `${newRect.height}px`\n\t\t\t\t\t\toverlayData.element.style.display =\n\t\t\t\t\t\t\tnewRect.width === 0 || newRect.height === 0 ? 'none' : 'block'\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If fewer rects now, hide extra overlays\n\t\t\t\t\t\toverlayData.element.style.display = 'none'\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\t// If there are fewer new rects than overlays, hide the extras\n\t\t\t\tif (newRects.length < overlays.length) {\n\t\t\t\t\tfor (let i = newRects.length; i < overlays.length; i++) {\n\t\t\t\t\t\toverlays[i].element.style.display = 'none'\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Update label position based on the first new rect\n\t\t\t\tif (label && newRects.length > 0) {\n\t\t\t\t\tconst firstNewRect = newRects[0]\n\t\t\t\t\tconst firstNewRectTop = firstNewRect.top + newIframeOffset.y\n\t\t\t\t\tconst firstNewRectLeft = firstNewRect.left + newIframeOffset.x\n\n\t\t\t\t\tlet newLabelTop = firstNewRectTop + 2\n\t\t\t\t\tlet newLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth - 2\n\n\t\t\t\t\tif (firstNewRect.width < labelWidth + 4 || firstNewRect.height < labelHeight + 4) {\n\t\t\t\t\t\tnewLabelTop = firstNewRectTop - labelHeight - 2\n\t\t\t\t\t\tnewLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth\n\t\t\t\t\t\tif (newLabelLeft < newIframeOffset.x) newLabelLeft = firstNewRectLeft\n\t\t\t\t\t}\n\n\t\t\t\t\t// Ensure label stays within viewport bounds\n\t\t\t\t\tnewLabelTop = Math.max(0, Math.min(newLabelTop, window.innerHeight - labelHeight))\n\t\t\t\t\tnewLabelLeft = Math.max(0, Math.min(newLabelLeft, window.innerWidth - labelWidth))\n\n\t\t\t\t\tlabel.style.top = `${newLabelTop}px`\n\t\t\t\t\tlabel.style.left = `${newLabelLeft}px`\n\t\t\t\t\tlabel.style.display = 'block'\n\t\t\t\t} else if (label) {\n\t\t\t\t\t// Hide label if element has no rects anymore\n\t\t\t\t\tlabel.style.display = 'none'\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst throttleFunction = (func, delay) => {\n\t\t\t\tlet lastCall = 0\n\t\t\t\treturn (...args) => {\n\t\t\t\t\tconst now = performance.now()\n\t\t\t\t\tif (now - lastCall < delay) return\n\t\t\t\t\tlastCall = now\n\t\t\t\t\treturn func(...args)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst throttledUpdatePositions = throttleFunction(updatePositions, 16) // ~60fps\n\t\t\twindow.addEventListener('scroll', throttledUpdatePositions, true)\n\t\t\twindow.addEventListener('resize', throttledUpdatePositions)\n\n\t\t\t// Add cleanup function\n\t\t\tcleanupFn = () => {\n\t\t\t\twindow.removeEventListener('scroll', throttledUpdatePositions, true)\n\t\t\t\twindow.removeEventListener('resize', throttledUpdatePositions)\n\t\t\t\t// Remove overlay elements if needed\n\t\t\t\toverlays.forEach((overlay) => overlay.element.remove())\n\t\t\t\tif (label) label.remove()\n\t\t\t}\n\n\t\t\t// Then add fragment to container in one operation\n\t\t\tcontainer.appendChild(fragment)\n\n\t\t\treturn index + 1\n\t\t} finally {\n\t\t\t// Store cleanup function for later use\n\t\t\tif (cleanupFn) {\n\t\t\t\t// Keep a reference to cleanup functions in a global array\n\t\t\t\t;(window._highlightCleanupFunctions = window._highlightCleanupFunctions || []).push(\n\t\t\t\t\tcleanupFn\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// // Add this function to perform cleanup when needed\n\t// function cleanupHighlights() {\n\t// if (window._highlightCleanupFunctions && window._highlightCleanupFunctions.length) {\n\t// window._highlightCleanupFunctions.forEach(fn => fn());\n\t// window._highlightCleanupFunctions = [];\n\t// }\n\n\t// // Also remove the container\n\t// const container = document.getElementById(HIGHLIGHT_CONTAINER_ID);\n\t// if (container) container.remove();\n\t// }\n\n\t/**\n\t * Gets the position of an element in its parent.\n\t *\n\t * @param {HTMLElement} currentElement - The element to get the position for.\n\t * @returns {number} The position of the element in its parent.\n\t */\n\tfunction getElementPosition(currentElement) {\n\t\tif (!currentElement.parentElement) {\n\t\t\treturn 0 // No parent means no siblings\n\t\t}\n\n\t\tconst tagName = currentElement.nodeName.toLowerCase()\n\n\t\tconst siblings = Array.from(currentElement.parentElement.children).filter(\n\t\t\t(sib) => sib.nodeName.toLowerCase() === tagName\n\t\t)\n\n\t\tif (siblings.length === 1) {\n\t\t\treturn 0 // Only element of its type\n\t\t}\n\n\t\tconst index = siblings.indexOf(currentElement) + 1 // 1-based index\n\t\treturn index\n\t}\n\n\tfunction getXPathTree(element, stopAtBoundary = true) {\n\t\tif (xpathCache.has(element)) return xpathCache.get(element)\n\n\t\tconst segments = []\n\t\tlet currentElement = element\n\n\t\twhile (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) {\n\t\t\t// Stop if we hit a shadow root or iframe\n\t\t\tif (\n\t\t\t\tstopAtBoundary &&\n\t\t\t\t(currentElement.parentNode instanceof ShadowRoot ||\n\t\t\t\t\tcurrentElement.parentNode instanceof HTMLIFrameElement)\n\t\t\t) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst position = getElementPosition(currentElement)\n\t\t\tconst tagName = currentElement.nodeName.toLowerCase()\n\t\t\tconst xpathIndex = position > 0 ? `[${position}]` : ''\n\t\t\tsegments.unshift(`${tagName}${xpathIndex}`)\n\n\t\t\tcurrentElement = currentElement.parentNode\n\t\t}\n\n\t\tconst result = segments.join('/')\n\t\txpathCache.set(element, result)\n\t\treturn result\n\t}\n\n\t/**\n\t * @edit scrollable element detection\n\t * Checks if an element is scrollable. if so, return the scrollable distance on each direction (left right top bottom). if not return null.\n\t * @note distance smaller than 4 will be considered as not scrollable.\n\t * @note only check block elements, not inline elements.\n\t */\n\tfunction isScrollableElement(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn null // Not a valid element\n\t\t}\n\n\t\tconst style = getCachedComputedStyle(element)\n\t\tif (!style) return null\n\n\t\t// Check if the element is a block-level element\n\t\tconst display = style.display\n\t\tif (display === 'inline' || display === 'inline-block') {\n\t\t\treturn null // Not a block-level element\n\t\t}\n\n\t\t// Check overflow properties\n\t\tconst overflowX = style.overflowX\n\t\tconst overflowY = style.overflowY\n\n\t\t// Check scrollable distances\n\t\tconst scrollableX = overflowX === 'auto' || overflowX === 'scroll'\n\t\tconst scrollableY = overflowY === 'auto' || overflowY === 'scroll'\n\n\t\tif (!scrollableX && !scrollableY) {\n\t\t\treturn null // Not scrollable in any direction\n\t\t}\n\n\t\tconst scrollWidth = element.scrollWidth - element.clientWidth\n\t\tconst scrollHeight = element.scrollHeight - element.clientHeight\n\n\t\t// Consider small distances as not scrollable\n\t\tconst threshold = 4\n\n\t\tif (scrollWidth < threshold && scrollHeight < threshold) {\n\t\t\treturn null // Not scrollable\n\t\t}\n\n\t\tif (!scrollableY && scrollWidth < threshold) {\n\t\t\treturn null // Not scrollable horizontally\n\t\t}\n\n\t\tif (!scrollableX && scrollHeight < threshold) {\n\t\t\treturn null // Not scrollable vertically\n\t\t}\n\n\t\tconst distanceToTop = element.scrollTop\n\t\tconst distanceToLeft = element.scrollLeft\n\t\tconst distanceToRight = element.scrollWidth - element.clientWidth - element.scrollLeft\n\t\tconst distanceToBottom = element.scrollHeight - element.clientHeight - element.scrollTop\n\n\t\tconst scrollData = {\n\t\t\ttop: distanceToTop,\n\t\t\tright: distanceToRight,\n\t\t\tbottom: distanceToBottom,\n\t\t\tleft: distanceToLeft,\n\t\t}\n\n\t\t// Store extra data for the element\n\t\taddExtraData(element, {\n\t\t\tscrollable: true,\n\t\t\tscrollData: scrollData,\n\t\t})\n\n\t\treturn scrollData\n\t}\n\n\t/**\n\t * Checks if a text node is visible.\n\t *\n\t * @param {Text} textNode - The text node to check.\n\t * @returns {boolean} Whether the text node is visible.\n\t */\n\tfunction isTextNodeVisible(textNode) {\n\t\ttry {\n\t\t\t// Special case: when viewportExpansion is -1, consider all text nodes as visible\n\t\t\tif (viewportExpansion === -1) {\n\t\t\t\t// Still check parent visibility for basic filtering\n\t\t\t\tconst parentElement = textNode.parentElement\n\t\t\t\tif (!parentElement) return false\n\n\t\t\t\ttry {\n\t\t\t\t\treturn parentElement.checkVisibility({\n\t\t\t\t\t\tcheckOpacity: true,\n\t\t\t\t\t\tcheckVisibilityCSS: true,\n\t\t\t\t\t})\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Fallback if checkVisibility is not supported\n\t\t\t\t\tconst style = window.getComputedStyle(parentElement)\n\t\t\t\t\treturn style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(textNode)\n\t\t\tconst rects = range.getClientRects() // Use getClientRects for Range\n\n\t\t\tif (!rects || rects.length === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tlet isAnyRectVisible = false\n\t\t\tlet isAnyRectInViewport = false\n\n\t\t\tfor (const rect of rects) {\n\t\t\t\t// Check size\n\t\t\t\tif (rect.width > 0 && rect.height > 0) {\n\t\t\t\t\tisAnyRectVisible = true\n\n\t\t\t\t\t// Viewport check for this rect\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tisAnyRectInViewport = true\n\t\t\t\t\t\tbreak // Found a visible rect in viewport, no need to check others\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!isAnyRectVisible || !isAnyRectInViewport) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check parent visibility\n\t\t\tconst parentElement = textNode.parentElement\n\t\t\tif (!parentElement) return false\n\n\t\t\ttry {\n\t\t\t\treturn parentElement.checkVisibility({\n\t\t\t\t\tcheckOpacity: true,\n\t\t\t\t\tcheckVisibilityCSS: true,\n\t\t\t\t})\n\t\t\t} catch (e) {\n\t\t\t\t// Fallback if checkVisibility is not supported\n\t\t\t\tconst style = window.getComputedStyle(parentElement)\n\t\t\t\treturn style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn('Error checking text node visibility:', e)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Checks if an element is accepted.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is accepted.\n\t */\n\tfunction isElementAccepted(element) {\n\t\tif (!element || !element.tagName) return false\n\n\t\t// Always accept body and common container elements\n\t\tconst alwaysAccept = new Set([\n\t\t\t'body',\n\t\t\t'div',\n\t\t\t'main',\n\t\t\t'article',\n\t\t\t'section',\n\t\t\t'nav',\n\t\t\t'header',\n\t\t\t'footer',\n\t\t])\n\t\tconst tagName = element.tagName.toLowerCase()\n\n\t\tif (alwaysAccept.has(tagName)) return true\n\n\t\tconst leafElementDenyList = new Set([\n\t\t\t'svg',\n\t\t\t'script',\n\t\t\t'style',\n\t\t\t'link',\n\t\t\t'meta',\n\t\t\t'noscript',\n\t\t\t'template',\n\t\t])\n\n\t\treturn !leafElementDenyList.has(tagName)\n\t}\n\n\t/**\n\t * Checks if an element is visible.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is visible.\n\t */\n\tfunction isElementVisible(element) {\n\t\tconst style = getCachedComputedStyle(element)\n\t\treturn (\n\t\t\telement.offsetWidth > 0 &&\n\t\t\telement.offsetHeight > 0 &&\n\t\t\tstyle?.visibility !== 'hidden' &&\n\t\t\tstyle?.display !== 'none'\n\t\t)\n\t}\n\n\t/**\n\t * Checks if an element is interactive.\n\t *\n\t * lots of comments, and uncommented code - to show the logic of what we already tried\n\t *\n\t * One of the things we tried at the beginning was also to use event listeners, and other fancy class, style stuff -> what actually worked best was just combining most things with computed cursor style :)\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t */\n\tfunction isInteractiveElement(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn false\n\t\t}\n\n\t\t/**\n\t\t * @edit add interactiveBlacklist interactiveWhitelist\n\t\t */\n\t\tif (interactiveBlacklist.includes(element)) {\n\t\t\treturn false // Skip blacklisted elements\n\t\t}\n\t\tif (interactiveWhitelist.includes(element)) {\n\t\t\treturn true // Skip whitelisted elements\n\t\t}\n\n\t\t// Cache the tagName and style lookups\n\t\tconst tagName = element.tagName.toLowerCase()\n\t\tconst style = getCachedComputedStyle(element)\n\n\t\t// Define interactive cursors\n\t\tconst interactiveCursors = new Set([\n\t\t\t'pointer', // Link/clickable elements\n\t\t\t'move', // Movable elements\n\t\t\t'text', // Text selection\n\t\t\t'grab', // Grabbable elements\n\t\t\t'grabbing', // Currently grabbing\n\t\t\t'cell', // Table cell selection\n\t\t\t'copy', // Copy operation\n\t\t\t'alias', // Alias creation\n\t\t\t'all-scroll', // Scrollable content\n\t\t\t'col-resize', // Column resize\n\t\t\t'context-menu', // Context menu available\n\t\t\t'crosshair', // Precise selection\n\t\t\t'e-resize', // East resize\n\t\t\t'ew-resize', // East-west resize\n\t\t\t'help', // Help available\n\t\t\t'n-resize', // North resize\n\t\t\t'ne-resize', // Northeast resize\n\t\t\t'nesw-resize', // Northeast-southwest resize\n\t\t\t'ns-resize', // North-south resize\n\t\t\t'nw-resize', // Northwest resize\n\t\t\t'nwse-resize', // Northwest-southeast resize\n\t\t\t'row-resize', // Row resize\n\t\t\t's-resize', // South resize\n\t\t\t'se-resize', // Southeast resize\n\t\t\t'sw-resize', // Southwest resize\n\t\t\t'vertical-text', // Vertical text selection\n\t\t\t'w-resize', // West resize\n\t\t\t'zoom-in', // Zoom in\n\t\t\t'zoom-out', // Zoom out\n\t\t])\n\n\t\t// Define non-interactive cursors\n\t\tconst nonInteractiveCursors = new Set([\n\t\t\t'not-allowed', // Action not allowed\n\t\t\t'no-drop', // Drop not allowed\n\t\t\t'wait', // Processing\n\t\t\t'progress', // In progress\n\t\t\t'initial', // Initial value\n\t\t\t'inherit', // Inherited value\n\t\t\t//? Let's just include all potentially clickable elements that are not specifically blocked\n\t\t\t// 'none', // No cursor\n\t\t\t// 'default', // Default cursor\n\t\t\t// 'auto', // Browser default\n\t\t])\n\n\t\t/**\n\t\t * Checks if an element has an interactive pointer.\n\t\t *\n\t\t * @param {HTMLElement} element - The element to check.\n\t\t * @returns {boolean} Whether the element has an interactive pointer.\n\t\t */\n\t\tfunction doesElementHaveInteractivePointer(element) {\n\t\t\tif (element.tagName.toLowerCase() === 'html') return false\n\n\t\t\tif (style?.cursor && interactiveCursors.has(style.cursor)) return true\n\n\t\t\treturn false\n\t\t}\n\n\t\tlet isInteractiveCursor = doesElementHaveInteractivePointer(element)\n\n\t\t// Genius fix for almost all interactive elements\n\t\tif (isInteractiveCursor) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst interactiveElements = new Set([\n\t\t\t'a', // Links\n\t\t\t'button', // Buttons\n\t\t\t'input', // All input types (text, checkbox, radio, etc.)\n\t\t\t'select', // Dropdown menus\n\t\t\t'textarea', // Text areas\n\t\t\t'details', // Expandable details\n\t\t\t'summary', // Summary element (clickable part of details)\n\t\t\t'label', // Form labels (often clickable)\n\t\t\t'option', // Select options\n\t\t\t'optgroup', // Option groups\n\t\t\t'fieldset', // Form fieldsets (can be interactive with legend)\n\t\t\t'legend', // Fieldset legends\n\t\t])\n\n\t\t// Define explicit disable attributes and properties\n\t\tconst explicitDisableTags = new Set([\n\t\t\t'disabled', // Standard disabled attribute\n\t\t\t// 'aria-disabled', // ARIA disabled state\n\t\t\t'readonly', // Read-only state\n\t\t\t// 'aria-readonly', // ARIA read-only state\n\t\t\t// 'aria-hidden', // Hidden from accessibility\n\t\t\t// 'hidden', // Hidden attribute\n\t\t\t// 'inert', // Inert attribute\n\t\t\t// 'aria-inert', // ARIA inert state\n\t\t\t// 'tabindex=\"-1\"', // Removed from tab order\n\t\t\t// 'aria-hidden=\"true\"' // Hidden from screen readers\n\t\t])\n\n\t\t// handle inputs, select, checkbox, radio, textarea, button and make sure they are not cursor style disabled/not-allowed\n\t\tif (interactiveElements.has(tagName)) {\n\t\t\t// Check for non-interactive cursor\n\t\t\tif (style?.cursor && nonInteractiveCursors.has(style.cursor)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for explicit disable attributes\n\t\t\tfor (const disableTag of explicitDisableTags) {\n\t\t\t\tif (\n\t\t\t\t\telement.hasAttribute(disableTag) ||\n\t\t\t\t\telement.getAttribute(disableTag) === 'true' ||\n\t\t\t\t\telement.getAttribute(disableTag) === ''\n\t\t\t\t) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for disabled property on form elements\n\t\t\tif (element.disabled) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for readonly property on form elements\n\t\t\tif (element.readOnly) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for inert property\n\t\t\tif (element.inert) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tconst role = element.getAttribute('role')\n\t\tconst ariaRole = element.getAttribute('aria-role')\n\n\t\t// Check for contenteditable attribute\n\t\tif (element.getAttribute('contenteditable') === 'true' || element.isContentEditable) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Added enhancement to capture dropdown interactive elements\n\t\tif (\n\t\t\telement.classList &&\n\t\t\t(element.classList.contains('button') ||\n\t\t\t\telement.classList.contains('dropdown-toggle') ||\n\t\t\t\telement.getAttribute('data-index') ||\n\t\t\t\telement.getAttribute('data-toggle') === 'dropdown' ||\n\t\t\t\telement.getAttribute('aria-haspopup') === 'true')\n\t\t) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst interactiveRoles = new Set([\n\t\t\t'button', // Directly clickable element\n\t\t\t// 'link', // Clickable link\n\t\t\t'menu', // Menu container (ARIA menus)\n\t\t\t'menubar', // Menu bar container\n\t\t\t'menuitem', // Clickable menu item\n\t\t\t'menuitemradio', // Radio-style menu item (selectable)\n\t\t\t'menuitemcheckbox', // Checkbox-style menu item (toggleable)\n\t\t\t'radio', // Radio button (selectable)\n\t\t\t'checkbox', // Checkbox (toggleable)\n\t\t\t'tab', // Tab (clickable to switch content)\n\t\t\t'switch', // Toggle switch (clickable to change state)\n\t\t\t'slider', // Slider control (draggable)\n\t\t\t'spinbutton', // Number input with up/down controls\n\t\t\t'combobox', // Dropdown with text input\n\t\t\t'searchbox', // Search input field\n\t\t\t'textbox', // Text input field\n\t\t\t'listbox', // Selectable list\n\t\t\t'option', // Selectable option in a list\n\t\t\t'scrollbar', // Scrollable control\n\t\t])\n\n\t\t// Basic role/attribute checks\n\t\tconst hasInteractiveRole =\n\t\t\tinteractiveElements.has(tagName) ||\n\t\t\t(role && interactiveRoles.has(role)) ||\n\t\t\t(ariaRole && interactiveRoles.has(ariaRole))\n\n\t\tif (hasInteractiveRole) return true\n\n\t\t// check whether element has event listeners by window.getEventListeners\n\t\ttry {\n\t\t\tif (typeof getEventListeners === 'function') {\n\t\t\t\tconst listeners = getEventListeners(element)\n\t\t\t\tconst mouseEvents = ['click', 'mousedown', 'mouseup', 'dblclick']\n\t\t\t\tfor (const eventType of mouseEvents) {\n\t\t\t\t\tif (listeners[eventType] && listeners[eventType].length > 0) {\n\t\t\t\t\t\treturn true // Found a mouse interaction listener\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst getEventListenersForNode =\n\t\t\t\telement?.ownerDocument?.defaultView?.getEventListenersForNode ||\n\t\t\t\twindow.getEventListenersForNode\n\t\t\tif (typeof getEventListenersForNode === 'function') {\n\t\t\t\tconst listeners = getEventListenersForNode(element)\n\t\t\t\tconst interactionEvents = [\n\t\t\t\t\t'click',\n\t\t\t\t\t'mousedown',\n\t\t\t\t\t'mouseup',\n\t\t\t\t\t'keydown',\n\t\t\t\t\t'keyup',\n\t\t\t\t\t'submit',\n\t\t\t\t\t'change',\n\t\t\t\t\t'input',\n\t\t\t\t\t'focus',\n\t\t\t\t\t'blur',\n\t\t\t\t]\n\t\t\t\tfor (const eventType of interactionEvents) {\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\tif (listener.type === eventType) {\n\t\t\t\t\t\t\treturn true // Found a common interaction listener\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: Check common event attributes if getEventListeners is not available (getEventListeners doesn't work in page.evaluate context)\n\t\t\tconst commonMouseAttrs = ['onclick', 'onmousedown', 'onmouseup', 'ondblclick']\n\t\t\tfor (const attr of commonMouseAttrs) {\n\t\t\t\tif (element.hasAttribute(attr) || typeof element[attr] === 'function') {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// console.warn(`Could not check event listeners for ${element.tagName}:`, e);\n\t\t\t// If checking listeners fails, rely on other checks\n\t\t}\n\n\t\t/**\n\t\t * @edit scrollable element detection\n\t\t */\n\t\tif (isScrollableElement(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\t/**\n\t * Checks if an element is the topmost element at its position.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is the topmost element at its position.\n\t */\n\tfunction isTopElement(element) {\n\t\t// Special case: when viewportExpansion is -1, consider all elements as \"top\" elements\n\t\tif (viewportExpansion === -1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst rects = getCachedClientRects(element) // Replace element.getClientRects()\n\n\t\tif (!rects || rects.length === 0) {\n\t\t\treturn false // No geometry, cannot be top\n\t\t}\n\n\t\tlet isAnyRectInViewport = false\n\t\tfor (const rect of rects) {\n\t\t\t// Use the same logic as isInExpandedViewport check\n\t\t\tif (\n\t\t\t\trect.width > 0 &&\n\t\t\t\trect.height > 0 &&\n\t\t\t\t!(\n\t\t\t\t\t// Only check non-empty rects\n\t\t\t\t\t(\n\t\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tisAnyRectInViewport = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (!isAnyRectInViewport) {\n\t\t\treturn false // All rects are outside the viewport area\n\t\t}\n\n\t\t// Find the correct document context and root element\n\t\tlet doc = element.ownerDocument\n\n\t\t// If we're in an iframe, elements are considered top by default\n\t\tif (doc !== window.document) {\n\t\t\treturn true\n\t\t}\n\n\t\t/**\n\t\t * @edit improve `sampleRect`, filter out rects with 0 area\n\t\t */\n\t\t// find a rect that has width and height as sample\n\t\tlet rect = Array.from(rects).find((r) => r.width > 0 && r.height > 0)\n\t\tif (!rect) {\n\t\t\treturn false // No valid rect found\n\t\t}\n\n\t\t// For shadow DOM, we need to check within its own root context\n\t\tconst shadowRoot = element.getRootNode()\n\t\tif (shadowRoot instanceof ShadowRoot) {\n\t\t\tconst centerX = rect.left + rect.width / 2\n\t\t\tconst centerY = rect.top + rect.height / 2\n\n\t\t\ttry {\n\t\t\t\tconst topEl = shadowRoot.elementFromPoint(centerX, centerY)\n\t\t\t\tif (!topEl) return false\n\n\t\t\t\tlet current = topEl\n\t\t\t\twhile (current && current !== shadowRoot) {\n\t\t\t\t\tif (current === element) return true\n\t\t\t\t\tcurrent = current.parentElement\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} catch (e) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tconst margin = 5\n\n\t\t// For elements in viewport, check if they're topmost. Do the check in the\n\t\t// center of the element and at the corners to ensure we catch more cases.\n\t\tconst checkPoints = [\n\t\t\t// Initially only this was used, but it was not enough\n\t\t\t{ x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 },\n\t\t\t{ x: rect.left + margin, y: rect.top + margin }, // top left\n\t\t\t// { x: rect.right - margin, y: rect.top + margin }, // top right\n\t\t\t// { x: rect.left + margin, y: rect.bottom - margin }, // bottom left\n\t\t\t{ x: rect.right - margin, y: rect.bottom - margin }, // bottom right\n\t\t]\n\n\t\treturn checkPoints.some(({ x, y }) => {\n\t\t\ttry {\n\t\t\t\tconst topEl = document.elementFromPoint(x, y)\n\t\t\t\tif (!topEl) return false\n\n\t\t\t\tlet current = topEl\n\t\t\t\twhile (current && current !== document.documentElement) {\n\t\t\t\t\tif (current === element) return true\n\t\t\t\t\tcurrent = current.parentElement\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} catch (e) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Checks if an element is within the expanded viewport.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @param {number} viewportExpansion - The viewport expansion.\n\t * @returns {boolean} Whether the element is within the expanded viewport.\n\t */\n\tfunction isInExpandedViewport(element, viewportExpansion) {\n\t\tif (viewportExpansion === -1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst rects = element.getClientRects() // Use getClientRects\n\n\t\tif (!rects || rects.length === 0) {\n\t\t\t// Fallback to getBoundingClientRect if getClientRects is empty,\n\t\t\t// useful for elements like <svg> that might not have client rects but have a bounding box.\n\t\t\tconst boundingRect = getCachedBoundingRect(element)\n\t\t\tif (!boundingRect || boundingRect.width === 0 || boundingRect.height === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !(\n\t\t\t\tboundingRect.bottom < -viewportExpansion ||\n\t\t\t\tboundingRect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\tboundingRect.right < -viewportExpansion ||\n\t\t\t\tboundingRect.left > window.innerWidth + viewportExpansion\n\t\t\t)\n\t\t}\n\n\t\t// Check if *any* client rect is within the viewport\n\t\tfor (const rect of rects) {\n\t\t\tif (rect.width === 0 || rect.height === 0) continue // Skip empty rects\n\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true // Found at least one rect in the viewport\n\t\t\t}\n\t\t}\n\n\t\treturn false // No rects were found in the viewport\n\t}\n\n\t// /**\n\t// * Gets the effective scroll of an element.\n\t// *\n\t// * @param {HTMLElement} element - The element to get the effective scroll for.\n\t// * @returns {Object} The effective scroll of the element.\n\t// */\n\t// function getEffectiveScroll(element) {\n\t// let currentEl = element;\n\t// let scrollX = 0;\n\t// let scrollY = 0;\n\n\t// while (currentEl && currentEl !== document.documentElement) {\n\t// if (currentEl.scrollLeft || currentEl.scrollTop) {\n\t// scrollX += currentEl.scrollLeft;\n\t// scrollY += currentEl.scrollTop;\n\t// }\n\t// currentEl = currentEl.parentElement;\n\t// }\n\n\t// scrollX += window.scrollX;\n\t// scrollY += window.scrollY;\n\n\t// return { scrollX, scrollY };\n\t// }\n\n\t/**\n\t * Checks if an element is an interactive candidate.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is an interactive candidate.\n\t */\n\tfunction isInteractiveCandidate(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return false\n\n\t\tconst tagName = element.tagName.toLowerCase()\n\n\t\t// Fast-path for common interactive elements\n\t\tconst interactiveElements = new Set([\n\t\t\t'a',\n\t\t\t'button',\n\t\t\t'input',\n\t\t\t'select',\n\t\t\t'textarea',\n\t\t\t'details',\n\t\t\t'summary',\n\t\t\t'label',\n\t\t])\n\n\t\tif (interactiveElements.has(tagName)) return true\n\n\t\t// Quick attribute checks without getting full lists\n\t\tconst hasQuickInteractiveAttr =\n\t\t\telement.hasAttribute('onclick') ||\n\t\t\telement.hasAttribute('role') ||\n\t\t\telement.hasAttribute('tabindex') ||\n\t\t\telement.hasAttribute('aria-') ||\n\t\t\telement.hasAttribute('data-action') ||\n\t\t\telement.getAttribute('contenteditable') === 'true'\n\n\t\treturn hasQuickInteractiveAttr\n\t}\n\n\t// --- Define constants for distinct interaction check ---\n\tconst DISTINCT_INTERACTIVE_TAGS = new Set([\n\t\t'a',\n\t\t'button',\n\t\t'input',\n\t\t'select',\n\t\t'textarea',\n\t\t'summary',\n\t\t'details',\n\t\t'label',\n\t\t'option',\n\t])\n\tconst INTERACTIVE_ROLES = new Set([\n\t\t'button',\n\t\t'link',\n\t\t'menuitem',\n\t\t'menuitemradio',\n\t\t'menuitemcheckbox',\n\t\t'radio',\n\t\t'checkbox',\n\t\t'tab',\n\t\t'switch',\n\t\t'slider',\n\t\t'spinbutton',\n\t\t'combobox',\n\t\t'searchbox',\n\t\t'textbox',\n\t\t'listbox',\n\t\t'option',\n\t\t'scrollbar',\n\t])\n\n\t/**\n\t * Heuristically determines if an element should be considered as independently interactive,\n\t * even if it's nested inside another interactive container.\n\t *\n\t * This function helps detect deeply nested actionable elements (e.g., menu items within a button)\n\t * that may not be picked up by strict interactivity checks.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is heuristically interactive.\n\t */\n\tfunction isHeuristicallyInteractive(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return false\n\n\t\t// Skip non-visible elements early for performance\n\t\tif (!isElementVisible(element)) return false\n\n\t\t// Check for common attributes that often indicate interactivity\n\t\tconst hasInteractiveAttributes =\n\t\t\telement.hasAttribute('role') ||\n\t\t\telement.hasAttribute('tabindex') ||\n\t\t\telement.hasAttribute('onclick') ||\n\t\t\ttypeof element.onclick === 'function'\n\n\t\t// Check for semantic class names suggesting interactivity\n\t\tconst hasInteractiveClass = /\\b(btn|clickable|menu|item|entry|link)\\b/i.test(\n\t\t\telement.className || ''\n\t\t)\n\n\t\t// Determine whether the element is inside a known interactive container\n\t\tconst isInKnownContainer = Boolean(\n\t\t\telement.closest('button,a,[role=\"button\"],.menu,.dropdown,.list,.toolbar')\n\t\t)\n\n\t\t// Ensure the element has at least one visible child (to avoid marking empty wrappers)\n\t\tconst hasVisibleChildren = [...element.children].some(isElementVisible)\n\n\t\t// Avoid highlighting elements whose parent is <body> (top-level wrappers)\n\t\tconst isParentBody = element.parentElement && element.parentElement.isSameNode(document.body)\n\n\t\treturn (\n\t\t\t(isInteractiveElement(element) || hasInteractiveAttributes || hasInteractiveClass) &&\n\t\t\thasVisibleChildren &&\n\t\t\tisInKnownContainer &&\n\t\t\t!isParentBody\n\t\t)\n\t}\n\n\t/**\n\t * Checks if an element likely represents a distinct interaction\n\t * separate from its parent (if the parent is also interactive).\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is a distinct interaction.\n\t */\n\tfunction isElementDistinctInteraction(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst tagName = element.tagName.toLowerCase()\n\t\tconst role = element.getAttribute('role')\n\n\t\t// Check if it's an iframe - always distinct boundary\n\t\tif (tagName === 'iframe') {\n\t\t\treturn true\n\t\t}\n\n\t\t// Check tag name\n\t\tif (DISTINCT_INTERACTIVE_TAGS.has(tagName)) {\n\t\t\treturn true\n\t\t}\n\t\t// Check interactive roles\n\t\tif (role && INTERACTIVE_ROLES.has(role)) {\n\t\t\treturn true\n\t\t}\n\t\t// Check contenteditable\n\t\tif (element.isContentEditable || element.getAttribute('contenteditable') === 'true') {\n\t\t\treturn true\n\t\t}\n\t\t// Check for common testing/automation attributes\n\t\tif (\n\t\t\telement.hasAttribute('data-testid') ||\n\t\t\telement.hasAttribute('data-cy') ||\n\t\t\telement.hasAttribute('data-test')\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t\t// Check for explicit onclick handler (attribute or property)\n\t\tif (element.hasAttribute('onclick') || typeof element.onclick === 'function') {\n\t\t\treturn true\n\t\t}\n\n\t\t// return false\n\n\t\t// Check for other common interaction event listeners\n\t\ttry {\n\t\t\tconst getEventListenersForNode =\n\t\t\t\telement?.ownerDocument?.defaultView?.getEventListenersForNode ||\n\t\t\t\twindow.getEventListenersForNode\n\t\t\tif (typeof getEventListenersForNode === 'function') {\n\t\t\t\tconst listeners = getEventListenersForNode(element)\n\t\t\t\tconst interactionEvents = [\n\t\t\t\t\t'click',\n\t\t\t\t\t'mousedown',\n\t\t\t\t\t'mouseup',\n\t\t\t\t\t'keydown',\n\t\t\t\t\t'keyup',\n\t\t\t\t\t'submit',\n\t\t\t\t\t'change',\n\t\t\t\t\t'input',\n\t\t\t\t\t'focus',\n\t\t\t\t\t'blur',\n\t\t\t\t]\n\t\t\t\tfor (const eventType of interactionEvents) {\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\tif (listener.type === eventType) {\n\t\t\t\t\t\t\treturn true // Found a common interaction listener\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: Check common event attributes if getEventListeners is not available (getEventListenersForNode doesn't work in page.evaluate context)\n\t\t\tconst commonEventAttrs = [\n\t\t\t\t'onmousedown',\n\t\t\t\t'onmouseup',\n\t\t\t\t'onkeydown',\n\t\t\t\t'onkeyup',\n\t\t\t\t'onsubmit',\n\t\t\t\t'onchange',\n\t\t\t\t'oninput',\n\t\t\t\t'onfocus',\n\t\t\t\t'onblur',\n\t\t\t]\n\t\t\tif (commonEventAttrs.some((attr) => element.hasAttribute(attr))) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// console.warn(`Could not check event listeners for ${element.tagName}:`, e);\n\t\t\t// If checking listeners fails, rely on other checks\n\t\t}\n\n\t\t// if the element is not strictly interactive but appears clickable based on heuristic signals\n\t\tif (isHeuristicallyInteractive(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Default to false: if it's interactive but doesn't match above,\n\t\t// assume it triggers the same action as the parent.\n\t\treturn false\n\t}\n\t// --- End distinct interaction check ---\n\n\t/**\n * Handles the logic for deciding whether to highlight an element and performing the highlight.\n * @param {\n {\n tagName: string;\n attributes: Record<string, string>;\n xpath: any;\n children: never[];\n isVisible?: boolean;\n isTopElement?: boolean;\n isInteractive?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n }} nodeData - The node data object.\n * @param {HTMLElement} node - The node to highlight.\n * @param {HTMLElement | null} parentIframe - The parent iframe node.\n * @param {boolean} isParentHighlighted - Whether the parent node is highlighted.\n * @returns {boolean} Whether the element was highlighted.\n */\n\tfunction handleHighlighting(nodeData, node, parentIframe, isParentHighlighted) {\n\t\tif (!nodeData.isInteractive) return false // Not interactive, definitely don't highlight\n\n\t\tlet shouldHighlight = false\n\t\tif (!isParentHighlighted) {\n\t\t\t// Parent wasn't highlighted, this interactive node can be highlighted.\n\t\t\tshouldHighlight = true\n\t\t} else {\n\t\t\t// Parent *was* highlighted. Only highlight this node if it represents a distinct interaction.\n\t\t\tif (isElementDistinctInteraction(node)) {\n\t\t\t\tshouldHighlight = true\n\t\t\t} else {\n\t\t\t\t// console.log(`Skipping highlight for ${nodeData.tagName} (parent highlighted)`);\n\t\t\t\tshouldHighlight = false\n\t\t\t}\n\t\t}\n\n\t\tif (shouldHighlight) {\n\t\t\t// Check viewport status before assigning index and highlighting\n\t\t\tnodeData.isInViewport = isInExpandedViewport(node, viewportExpansion)\n\n\t\t\t// When viewportExpansion is -1, all interactive elements should get a highlight index\n\t\t\t// regardless of viewport status\n\t\t\tif (nodeData.isInViewport || viewportExpansion === -1) {\n\t\t\t\tnodeData.highlightIndex = highlightIndex++\n\n\t\t\t\tif (doHighlightElements) {\n\t\t\t\t\tif (focusHighlightIndex >= 0) {\n\t\t\t\t\t\tif (focusHighlightIndex === nodeData.highlightIndex) {\n\t\t\t\t\t\t\thighlightElement(node, nodeData.highlightIndex, parentIframe)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\thighlightElement(node, nodeData.highlightIndex, parentIframe)\n\t\t\t\t\t}\n\t\t\t\t\treturn true // Successfully highlighted\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// console.log(`Skipping highlight for ${nodeData.tagName} (outside viewport)`);\n\t\t\t}\n\t\t}\n\n\t\treturn false // Did not highlight\n\t}\n\n\t/**\n\t * Creates a node data object for a given node and its descendants.\n\t *\n\t * @param {HTMLElement} node - The node to process.\n\t * @param {HTMLElement | null} parentIframe - The parent iframe node.\n\t * @param {boolean} isParentHighlighted - Whether the parent node is highlighted.\n\t * @returns {string | null} The ID of the node data object, or null if the node is not processed.\n\t */\n\tfunction buildDomTree(node, parentIframe = null, isParentHighlighted = false) {\n\t\t// Fast rejection checks first\n\t\tif (\n\t\t\t!node ||\n\t\t\tnode.id === HIGHLIGHT_CONTAINER_ID ||\n\t\t\t(node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE)\n\t\t) {\n\t\t\treturn null\n\t\t}\n\n\t\tif (!node || node.id === HIGHLIGHT_CONTAINER_ID) {\n\t\t\treturn null\n\t\t}\n\n\t\t/**\n\t\t * @edit add `data-browser-use-ignore` attribute\n\t\t */\n\t\tif (node.dataset?.browserUseIgnore === 'true' || node.dataset?.pageAgentIgnore === 'true') {\n\t\t\treturn null // Skip this node and its children\n\t\t}\n\n\t\t/**\n\t\t * @edit exclude aria-hidden elements\n\t\t */\n\t\tif (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {\n\t\t\treturn null // Skip this node and its children\n\t\t}\n\n\t\t// Special handling for root node (body)\n\t\tif (node === document.body) {\n\t\t\tconst nodeData = {\n\t\t\t\ttagName: 'body',\n\t\t\t\tattributes: {},\n\t\t\t\txpath: '/body',\n\t\t\t\tchildren: [],\n\t\t\t}\n\n\t\t\t// Process children of body\n\t\t\tfor (const child of node.childNodes) {\n\t\t\t\tconst domElement = buildDomTree(child, parentIframe, false) // Body's children have no highlighted parent initially\n\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t}\n\n\t\t\tconst id = `${ID.current++}`\n\t\t\tDOM_HASH_MAP[id] = nodeData\n\t\t\treturn id\n\t\t}\n\n\t\t// Early bailout for non-element nodes except text\n\t\tif (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Process text nodes\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst textContent = node.textContent?.trim()\n\t\t\tif (!textContent) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\t// Only check visibility for text nodes that might be visible\n\t\t\tconst parentElement = node.parentElement\n\t\t\tif (!parentElement || parentElement.tagName.toLowerCase() === 'script') {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst id = `${ID.current++}`\n\t\t\tDOM_HASH_MAP[id] = {\n\t\t\t\ttype: 'TEXT_NODE',\n\t\t\t\ttext: textContent,\n\t\t\t\tisVisible: isTextNodeVisible(node),\n\t\t\t}\n\t\t\treturn id\n\t\t}\n\n\t\t// Quick checks for element nodes\n\t\tif (node.nodeType === Node.ELEMENT_NODE && !isElementAccepted(node)) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Early viewport check - only filter out elements clearly outside viewport\n\t\t// The getBoundingClientRect() of the Shadow DOM host element may return width/height = 0\n\t\tif (viewportExpansion !== -1 && !node.shadowRoot) {\n\t\t\tconst rect = getCachedBoundingRect(node) // Keep for initial quick check\n\t\t\tconst style = getCachedComputedStyle(node)\n\n\t\t\t// Skip viewport check for fixed/sticky elements as they may appear anywhere\n\t\t\tconst isFixedOrSticky = style && (style.position === 'fixed' || style.position === 'sticky')\n\n\t\t\t// Check if element has actual dimensions using offsetWidth/Height (quick check)\n\t\t\tconst hasSize = node.offsetWidth > 0 || node.offsetHeight > 0\n\n\t\t\t// Use getBoundingClientRect for the quick OUTSIDE check.\n\t\t\t// isInExpandedViewport will do the more accurate check later if needed.\n\t\t\tif (\n\t\t\t\t!rect ||\n\t\t\t\t(!isFixedOrSticky &&\n\t\t\t\t\t!hasSize &&\n\t\t\t\t\t(rect.bottom < -viewportExpansion ||\n\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion))\n\t\t\t) {\n\t\t\t\t// console.log(\"Skipping node outside viewport (quick check):\", node.tagName, rect);\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\n\t\t/**\n * @type {\n {\n tagName: string;\n attributes: Record<string, string | null>;\n xpath: any;\n children: never[];\n isVisible?: boolean;\n isTopElement?: boolean;\n isInteractive?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n }\n } nodeData - The node data object.\n */\n\t\tconst nodeData = {\n\t\t\ttagName: node.tagName.toLowerCase(),\n\t\t\tattributes: {},\n\n\t\t\t/**\n\t\t\t * @edit no need for xpath\n\t\t\t */\n\t\t\t// xpath: getXPathTree(node, true),\n\n\t\t\tchildren: [],\n\t\t}\n\n\t\t// Get attributes for interactive elements or potential text containers\n\t\tif (\n\t\t\tisInteractiveCandidate(node) ||\n\t\t\tnode.tagName.toLowerCase() === 'iframe' ||\n\t\t\tnode.tagName.toLowerCase() === 'body'\n\t\t) {\n\t\t\tconst attributeNames = node.getAttributeNames?.() || []\n\t\t\tfor (const name of attributeNames) {\n\t\t\t\tconst value = node.getAttribute(name)\n\t\t\t\tnodeData.attributes[name] = value\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * @edit @workaround input.checked\n\t\t\t */\n\t\t\tif (\n\t\t\t\tnode.tagName.toLowerCase() === 'input' &&\n\t\t\t\t(node.type === 'checkbox' || node.type === 'radio')\n\t\t\t) {\n\t\t\t\tnodeData.attributes.checked = node.checked ? 'true' : 'false' // Store as string for consistency\n\t\t\t}\n\t\t}\n\n\t\tlet nodeWasHighlighted = false\n\t\t// Perform visibility, interactivity, and highlighting checks\n\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\tnodeData.isVisible = isElementVisible(node) // isElementVisible uses offsetWidth/Height, which is fine\n\t\t\tif (nodeData.isVisible) {\n\t\t\t\tnodeData.isTopElement = isTopElement(node)\n\n\t\t\t\t// Special handling for ARIA menu containers - check interactivity even if not top element\n\t\t\t\tconst role = node.getAttribute('role')\n\t\t\t\tconst isMenuContainer = role === 'menu' || role === 'menubar' || role === 'listbox'\n\n\t\t\t\tif (nodeData.isTopElement || isMenuContainer) {\n\t\t\t\t\tnodeData.isInteractive = isInteractiveElement(node)\n\t\t\t\t\t// Call the dedicated highlighting function\n\t\t\t\t\tnodeWasHighlighted = handleHighlighting(nodeData, node, parentIframe, isParentHighlighted)\n\n\t\t\t\t\t/**\n\t\t\t\t\t * @edit direct dom ref\n\t\t\t\t\t */\n\t\t\t\t\tnodeData.ref = node\n\n\t\t\t\t\t/**\n\t\t\t\t\t * @edit make sure attributes exist for interactive candidates.\n\t\t\t\t\t * @note if the element failed the isInteractiveCandidate, attributes would be empty.\n\t\t\t\t\t */\n\t\t\t\t\tif (nodeData.isInteractive && Object.keys(nodeData.attributes).length === 0) {\n\t\t\t\t\t\tconst attributeNames = node.getAttributeNames?.() || []\n\t\t\t\t\t\tfor (const name of attributeNames) {\n\t\t\t\t\t\t\tconst value = node.getAttribute(name)\n\t\t\t\t\t\t\tnodeData.attributes[name] = value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Process children, with special handling for iframes and rich text editors\n\t\tif (node.tagName) {\n\t\t\tconst tagName = node.tagName.toLowerCase()\n\n\t\t\t// Handle iframes\n\t\t\tif (tagName === 'iframe') {\n\t\t\t\ttry {\n\t\t\t\t\tconst iframeDoc = node.contentDocument || node.contentWindow?.document\n\t\t\t\t\tif (iframeDoc) {\n\t\t\t\t\t\tfor (const child of iframeDoc.childNodes) {\n\t\t\t\t\t\t\tconst domElement = buildDomTree(child, node, false)\n\t\t\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.warn('Unable to access iframe:', e)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle rich text editors and contenteditable elements\n\t\t\telse if (\n\t\t\t\tnode.isContentEditable ||\n\t\t\t\tnode.getAttribute('contenteditable') === 'true' ||\n\t\t\t\tnode.id === 'tinymce' ||\n\t\t\t\tnode.classList.contains('mce-content-body') ||\n\t\t\t\t(tagName === 'body' && node.getAttribute('data-id')?.startsWith('mce_'))\n\t\t\t) {\n\t\t\t\t// Process all child nodes to capture formatted text\n\t\t\t\tfor (const child of node.childNodes) {\n\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, nodeWasHighlighted)\n\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Handle shadow DOM\n\t\t\t\tif (node.shadowRoot) {\n\t\t\t\t\tnodeData.shadowRoot = true\n\t\t\t\t\tfor (const child of node.shadowRoot.childNodes) {\n\t\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, nodeWasHighlighted)\n\t\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Handle regular elements\n\t\t\t\tfor (const child of node.childNodes) {\n\t\t\t\t\t// Pass the highlighted status of the *current* node to its children\n\t\t\t\t\tconst passHighlightStatusToChild = nodeWasHighlighted || isParentHighlighted\n\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, passHighlightStatusToChild)\n\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Skip empty anchor tags only if they have no dimensions and no children\n\t\tif (nodeData.tagName === 'a' && nodeData.children.length === 0 && !nodeData.attributes.href) {\n\t\t\t// Check if the anchor has actual dimensions\n\t\t\tconst rect = getCachedBoundingRect(node)\n\t\t\tconst hasSize =\n\t\t\t\t(rect && rect.width > 0 && rect.height > 0) || node.offsetWidth > 0 || node.offsetHeight > 0\n\n\t\t\tif (!hasSize) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @edit add `extra` field for extra data\n\t\t */\n\t\tnodeData.extra = extraData.get(node) || null\n\n\t\tconst id = `${ID.current++}`\n\t\tDOM_HASH_MAP[id] = nodeData\n\t\treturn id\n\t}\n\n\tconst rootId = buildDomTree(document.body)\n\n\t// Clear the cache before starting\n\tDOM_CACHE.clearCache()\n\n\treturn { rootId, map: DOM_HASH_MAP }\n}\n","import domTree from './dom_tree/index.js'\nimport {\n\tElementDomNode,\n\tFlatDomTree,\n\tInteractiveElementDomNode,\n\tTextDomNode,\n} from './dom_tree/type'\n\n/**\n * Viewport expansion for DOM tree extraction.\n * -1 means full page (no viewport restriction)\n * 0 means viewport only\n * positive values expand the viewport by that many pixels\n *\n * @note Since isTopElement depends on elementFromPoint,\n * it returns null when out of viewport, this feature has no practical use, only differ between -1 and 0\n */\nconst DEFAULT_VIEWPORT_EXPANSION = -1\n\nexport function resolveViewportExpansion(viewportExpansion?: number): number {\n\treturn viewportExpansion ?? DEFAULT_VIEWPORT_EXPANSION\n}\n\nexport interface DomConfig {\n\tviewportExpansion?: number\n\tinteractiveBlacklist?: (Element | (() => Element))[]\n\tinteractiveWhitelist?: (Element | (() => Element))[]\n\tincludeAttributes?: string[]\n\thighlightOpacity?: number\n\thighlightLabelOpacity?: number\n}\n\n/**\n * 用于检测可交互元素是否是新出现的。\n */\nconst newElementsCache = new WeakMap<HTMLElement, string>()\n\nexport function getFlatTree(config: DomConfig): FlatDomTree {\n\tconst viewportExpansion = resolveViewportExpansion(config.viewportExpansion)\n\n\tconst interactiveBlacklist = [] as Element[]\n\tfor (const item of config.interactiveBlacklist || []) {\n\t\tif (typeof item === 'function') {\n\t\t\tinteractiveBlacklist.push(item())\n\t\t} else {\n\t\t\tinteractiveBlacklist.push(item)\n\t\t}\n\t}\n\n\tconst interactiveWhitelist = [] as Element[]\n\tfor (const item of config.interactiveWhitelist || []) {\n\t\tif (typeof item === 'function') {\n\t\t\tinteractiveWhitelist.push(item())\n\t\t} else {\n\t\t\tinteractiveWhitelist.push(item)\n\t\t}\n\t}\n\n\tconst elements = domTree({\n\t\tdoHighlightElements: true,\n\t\tdebugMode: true,\n\t\tfocusHighlightIndex: -1,\n\t\tviewportExpansion,\n\t\tinteractiveBlacklist,\n\t\tinteractiveWhitelist,\n\t\thighlightOpacity: config.highlightOpacity ?? 0.0,\n\t\thighlightLabelOpacity: config.highlightLabelOpacity ?? 0.1,\n\t}) as FlatDomTree\n\n\tconst currentUrl = window.location.href\n\n\t/**\n\t * 标记新出现的元素\n\t * @todo browser-use 使用 hash(位置,属性等信息) 来判断是否同一个元素,\n\t * 能够解决 1. 元素被删除后重新添加 2. 页面卸载 等问题。\n\t * 这里先简单做.\n\t */\n\tfor (const nodeId in elements.map) {\n\t\tconst node = elements.map[nodeId]\n\t\tif (node.isInteractive && node.ref) {\n\t\t\tconst ref = node.ref as HTMLElement\n\t\t\t// @note 这样太严格,元素是可以跨页面存在的\n\t\t\t// if (newElementsCache.get(ref) !== currentUrl) {\n\t\t\tif (!newElementsCache.has(ref)) {\n\t\t\t\tnewElementsCache.set(ref, currentUrl)\n\t\t\t\tnode.isNew = true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn elements\n}\n\nconst globRegexCache = new Map<string, RegExp>()\n\nfunction globToRegex(pattern: string): RegExp {\n\tlet regex = globRegexCache.get(pattern)\n\tif (!regex) {\n\t\tconst escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n\t\tregex = new RegExp(`^${escaped.replace(/\\*/g, '.*')}$`)\n\t\tglobRegexCache.set(pattern, regex)\n\t}\n\treturn regex\n}\n\nfunction matchAttributes(\n\tattrs: Record<string, string>,\n\tpatterns: string[]\n): Record<string, string> {\n\tconst result: Record<string, string> = {}\n\n\tfor (const pattern of patterns) {\n\t\tif (pattern.includes('*')) {\n\t\t\tconst regex = globToRegex(pattern)\n\t\t\tfor (const key of Object.keys(attrs)) {\n\t\t\t\tif (regex.test(key) && attrs[key].trim()) {\n\t\t\t\t\tresult[key] = attrs[key].trim()\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst value = attrs[pattern]\n\t\t\tif (value && value.trim()) {\n\t\t\t\tresult[pattern] = value.trim()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * elementsToString 内部使用的类型\n */\ninterface TreeNode {\n\ttype: 'text' | 'element'\n\tparent: TreeNode | null\n\tchildren: TreeNode[]\n\tisVisible: boolean\n\t// Text node properties\n\ttext?: string\n\t// Element node properties\n\ttagName?: string\n\tattributes?: Record<string, string>\n\tisInteractive?: boolean\n\tisTopElement?: boolean\n\tisNew?: boolean\n\thighlightIndex?: number\n\textra?: Record<string, any>\n}\n\n/**\n * 对应 python 中的 views::clickable_elements_to_string,\n * 将 dom 信息处理成适合 llm 阅读的文本格式\n * @形如\n * ``` text\n * [0]<a aria-label=page-agent.js 首页 />\n * [1]<div >P />\n * [2]<div >page-agent.js\n * UI Agent in your webpage />\n * [3]<a >文档 />\n * [4]<a aria-label=查看源码(在新窗口打开)>源码 />\n * UI Agent in your webpage\n * 用户输入需求,AI 理解页面并自动操作。\n * [5]<a role=button>快速开始 />\n * [6]<a role=button>查看文档 />\n * 无需后端\n * ```\n * 其中可交互元素用序号标出,提示llm可以用序号操作。\n * 缩进代表父子关系。\n * 普通文本则直接列出来。\n *\n * @todo 数据脱敏过滤器\n */\nexport function flatTreeToString(flatTree: FlatDomTree, includeAttributes?: string[]): string {\n\tconst DEFAULT_INCLUDE_ATTRIBUTES = [\n\t\t'title',\n\t\t'type',\n\t\t'checked',\n\t\t'name',\n\t\t'role',\n\t\t'value',\n\t\t'placeholder',\n\t\t'data-date-format',\n\t\t'alt',\n\t\t'aria-label',\n\t\t'aria-expanded',\n\t\t'data-state',\n\t\t'aria-checked',\n\n\t\t// @edit added for better form handling\n\t\t'id',\n\t\t'for',\n\n\t\t// for jump check\n\t\t'target',\n\n\t\t// absolute position dropdown menu\n\t\t'aria-haspopup',\n\t\t'aria-controls',\n\t\t'aria-owns',\n\n\t\t// content editable\n\t\t'contenteditable',\n\t]\n\n\tconst includeAttrs = [...(includeAttributes || []), ...DEFAULT_INCLUDE_ATTRIBUTES]\n\n\t// Helper function to cap text length\n\tconst capTextLength = (text: string, maxLength: number): string => {\n\t\tif (text.length > maxLength) {\n\t\t\treturn text.substring(0, maxLength) + '...'\n\t\t}\n\t\treturn text\n\t}\n\n\t// Build tree structure from flat map\n\tconst buildTreeNode = (nodeId: string): TreeNode | null => {\n\t\tconst node = flatTree.map[nodeId]\n\t\tif (!node) return null\n\n\t\tif (node.type === 'TEXT_NODE') {\n\t\t\tconst textNode = node as TextDomNode\n\t\t\treturn {\n\t\t\t\ttype: 'text',\n\t\t\t\ttext: textNode.text,\n\t\t\t\tisVisible: textNode.isVisible,\n\t\t\t\tparent: null,\n\t\t\t\tchildren: [],\n\t\t\t}\n\t\t} else {\n\t\t\tconst elementNode = node as ElementDomNode\n\t\t\tconst children: TreeNode[] = []\n\n\t\t\tif (elementNode.children) {\n\t\t\t\tfor (const childId of elementNode.children) {\n\t\t\t\t\tconst child = buildTreeNode(childId)\n\t\t\t\t\tif (child) {\n\t\t\t\t\t\tchild.parent = null // Will be set later\n\t\t\t\t\t\tchildren.push(child)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttype: 'element',\n\t\t\t\ttagName: elementNode.tagName,\n\t\t\t\tattributes: elementNode.attributes ?? {},\n\t\t\t\tisVisible: elementNode.isVisible ?? false,\n\t\t\t\tisInteractive: elementNode.isInteractive ?? false,\n\t\t\t\tisTopElement: elementNode.isTopElement ?? false,\n\t\t\t\tisNew: elementNode.isNew ?? false,\n\t\t\t\thighlightIndex: elementNode.highlightIndex,\n\t\t\t\tparent: null,\n\t\t\t\tchildren,\n\t\t\t\textra: elementNode.extra ?? {},\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set parent references\n\tconst setParentReferences = (node: TreeNode, parent: TreeNode | null = null) => {\n\t\tnode.parent = parent\n\t\tfor (const child of node.children) {\n\t\t\tsetParentReferences(child, node)\n\t\t}\n\t}\n\n\t// Build root node\n\tconst rootNode = buildTreeNode(flatTree.rootId)\n\tif (!rootNode) return ''\n\n\tsetParentReferences(rootNode)\n\n\t// Helper to check if text node has parent with highlight index\n\tconst hasParentWithHighlightIndex = (node: TreeNode): boolean => {\n\t\tlet current = node.parent\n\t\twhile (current) {\n\t\t\tif (current.type === 'element' && current.highlightIndex !== undefined) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tcurrent = current.parent\n\t\t}\n\t\treturn false\n\t}\n\n\t// Helper to check if parent is top element\n\t// const isParentTopElement = (node: TreeNode): boolean => {\n\t// \treturn node.parent?.type === 'element' && node.parent.isTopElement === true\n\t// }\n\n\t// Main processing function\n\tconst processNode = (node: TreeNode, depth: number, result: string[]): void => {\n\t\tlet nextDepth = depth\n\t\tconst depthStr = '\\t'.repeat(depth)\n\n\t\tif (node.type === 'element') {\n\t\t\t// Add element with highlight_index\n\t\t\tif (node.highlightIndex !== undefined) {\n\t\t\t\tnextDepth += 1\n\n\t\t\t\tconst text = getAllTextTillNextClickableElement(node)\n\t\t\t\tlet attributesHtmlStr = ''\n\n\t\t\t\tif (includeAttrs.length > 0 && node.attributes) {\n\t\t\t\t\tconst attributesToInclude = matchAttributes(node.attributes, includeAttrs)\n\n\t\t\t\t\t// Remove duplicate values (for attributes longer than 5 chars)\n\t\t\t\t\tconst keys = Object.keys(attributesToInclude)\n\t\t\t\t\tif (keys.length > 1) {\n\t\t\t\t\t\tconst keysToRemove = new Set<string>()\n\t\t\t\t\t\tconst seenValues: Record<string, string> = {}\n\n\t\t\t\t\t\tfor (const key of keys) {\n\t\t\t\t\t\t\tconst value = attributesToInclude[key]\n\t\t\t\t\t\t\tif (value.length > 5) {\n\t\t\t\t\t\t\t\tif (value in seenValues) {\n\t\t\t\t\t\t\t\t\tkeysToRemove.add(key)\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tseenValues[value] = key\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const key of keysToRemove) {\n\t\t\t\t\t\t\tdelete attributesToInclude[key]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove role if it matches tagName\n\t\t\t\t\tif (attributesToInclude.role === node.tagName) {\n\t\t\t\t\t\tdelete attributesToInclude.role\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove attributes that duplicate text content\n\t\t\t\t\tconst attrsToRemoveIfTextMatches = ['aria-label', 'placeholder', 'title']\n\t\t\t\t\tfor (const attr of attrsToRemoveIfTextMatches) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tattributesToInclude[attr] &&\n\t\t\t\t\t\t\tattributesToInclude[attr].toLowerCase().trim() === text.toLowerCase().trim()\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tdelete attributesToInclude[attr]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Object.keys(attributesToInclude).length > 0) {\n\t\t\t\t\t\tattributesHtmlStr = Object.entries(attributesToInclude)\n\t\t\t\t\t\t\t.map(([key, value]) => `${key}=${capTextLength(value, 20)}`)\n\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Build the line\n\t\t\t\tconst highlightIndicator = node.isNew\n\t\t\t\t\t? `*[${node.highlightIndex}]`\n\t\t\t\t\t: `[${node.highlightIndex}]`\n\t\t\t\tlet line = `${depthStr}${highlightIndicator}<${node.tagName ?? ''}`\n\n\t\t\t\tif (attributesHtmlStr) {\n\t\t\t\t\tline += ` ${attributesHtmlStr}`\n\t\t\t\t}\n\n\t\t\t\t/**\n\t\t\t\t * @edit scrollable 数据\n\t\t\t\t */\n\t\t\t\tif (node.extra) {\n\t\t\t\t\tif (node.extra.scrollable) {\n\t\t\t\t\t\tlet scrollDataText = ''\n\t\t\t\t\t\tif (node.extra.scrollData?.left)\n\t\t\t\t\t\t\tscrollDataText += `left=${node.extra.scrollData.left}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.top) scrollDataText += `top=${node.extra.scrollData.top}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.right)\n\t\t\t\t\t\t\tscrollDataText += `right=${node.extra.scrollData.right}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.bottom)\n\t\t\t\t\t\t\tscrollDataText += `bottom=${node.extra.scrollData.bottom}`\n\n\t\t\t\t\t\tline += ` data-scrollable=\"${scrollDataText}\"`\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (text) {\n\t\t\t\t\tconst trimmedText = text.trim()\n\t\t\t\t\tif (!attributesHtmlStr) {\n\t\t\t\t\t\tline += ' '\n\t\t\t\t\t}\n\t\t\t\t\tline += `>${trimmedText}`\n\t\t\t\t} else if (!attributesHtmlStr) {\n\t\t\t\t\tline += ' '\n\t\t\t\t}\n\n\t\t\t\tline += ' />'\n\t\t\t\tresult.push(line)\n\t\t\t}\n\n\t\t\t// Process children regardless\n\t\t\tfor (const child of node.children) {\n\t\t\t\tprocessNode(child, nextDepth, result)\n\t\t\t}\n\t\t} else if (node.type === 'text') {\n\t\t\t// Add text only if it doesn't have a highlighted parent\n\t\t\tif (hasParentWithHighlightIndex(node)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tnode.parent &&\n\t\t\t\tnode.parent.type === 'element' &&\n\t\t\t\tnode.parent.isVisible &&\n\t\t\t\tnode.parent.isTopElement\n\t\t\t) {\n\t\t\t\tresult.push(`${depthStr}${node.text ?? ''}`)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result: string[] = []\n\tprocessNode(rootNode, 0, result)\n\treturn result.join('\\n')\n}\n\n// Get all text until next clickable element\nexport const getAllTextTillNextClickableElement = (node: TreeNode, maxDepth = -1): string => {\n\tconst textParts: string[] = []\n\n\tconst collectText = (currentNode: TreeNode, currentDepth: number) => {\n\t\tif (maxDepth !== -1 && currentDepth > maxDepth) {\n\t\t\treturn\n\t\t}\n\n\t\t// Skip this branch if we hit a highlighted element (except for the current node)\n\t\tif (\n\t\t\tcurrentNode.type === 'element' &&\n\t\t\tcurrentNode !== node &&\n\t\t\tcurrentNode.highlightIndex !== undefined\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tif (currentNode.type === 'text' && currentNode.text) {\n\t\t\ttextParts.push(currentNode.text)\n\t\t} else if (currentNode.type === 'element') {\n\t\t\tfor (const child of currentNode.children) {\n\t\t\t\tcollectText(child, currentDepth + 1)\n\t\t\t}\n\t\t}\n\t}\n\n\tcollectText(node, 0)\n\treturn textParts.join('\\n').trim()\n}\n\nexport function getSelectorMap(flatTree: FlatDomTree): Map<number, InteractiveElementDomNode> {\n\tconst selectorMap = new Map<number, InteractiveElementDomNode>()\n\n\tconst keys = Object.keys(flatTree.map)\n\tfor (const key of keys) {\n\t\tconst node = flatTree.map[key]\n\t\tif (node.isInteractive && typeof node.highlightIndex === 'number') {\n\t\t\tselectorMap.set(node.highlightIndex, node as InteractiveElementDomNode)\n\t\t}\n\t}\n\n\treturn selectorMap\n}\n\nexport function getElementTextMap(simplifiedHTML: string) {\n\tconst lines = simplifiedHTML\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => line.length > 0)\n\tconst elementTextMap = new Map<number, string>()\n\tfor (const line of lines) {\n\t\tconst regex = /^\\[(\\d+)\\]<[^>]+>([^<]*)/\n\t\tconst match = regex.exec(line)\n\t\tif (match) {\n\t\t\tconst index = parseInt(match[1], 10)\n\t\t\telementTextMap.set(index, line)\n\t\t}\n\t}\n\n\treturn elementTextMap\n}\n\nexport function cleanUpHighlights() {\n\tconst cleanupFunctions = (window as any)._highlightCleanupFunctions || []\n\tfor (const cleanup of cleanupFunctions) {\n\t\tif (typeof cleanup === 'function') {\n\t\t\tcleanup()\n\t\t}\n\t}\n\n\t;(window as any)._highlightCleanupFunctions = []\n}\n\n// 监听 URL 的任何变化,立刻清空 highLights\nwindow.addEventListener('popstate', () => {\n\t// console.log('URL changed (popstate), highlights cleaned up.')\n\tcleanUpHighlights()\n})\nwindow.addEventListener('hashchange', () => {\n\t// console.log('URL changed (hashchange), highlights cleaned up.')\n\tcleanUpHighlights()\n})\nwindow.addEventListener('beforeunload', () => {\n\t// console.log('Page is unloading, highlights cleaned up.')\n\tcleanUpHighlights()\n})\n\nconst navigation = (window as any).navigation\nif (navigation && typeof navigation.addEventListener === 'function') {\n\tnavigation.addEventListener('navigate', () => {\n\t\t// console.log('Navigation event detected, highlights cleaned up.')\n\t\tcleanUpHighlights()\n\t})\n} else {\n\t// 定时器\n\tlet currentUrl = window.location.href\n\tsetInterval(() => {\n\t\tif (window.location.href !== currentUrl) {\n\t\t\tcurrentUrl = window.location.href\n\t\t\t// console.log('URL changed (interval), highlights cleaned up.')\n\t\t\tcleanUpHighlights()\n\t\t}\n\t}, 500)\n}\n","export function getPageInfo() {\n\tconst viewport_width = window.innerWidth\n\tconst viewport_height = window.innerHeight\n\n\tconst page_width = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth || 0)\n\tconst page_height = Math.max(\n\t\tdocument.documentElement.scrollHeight,\n\t\tdocument.body.scrollHeight || 0\n\t)\n\n\tconst scroll_x = window.scrollX || window.pageXOffset || document.documentElement.scrollLeft || 0\n\tconst scroll_y = window.scrollY || window.pageYOffset || document.documentElement.scrollTop || 0\n\n\tconst pixels_below = Math.max(0, page_height - (window.innerHeight + scroll_y))\n\tconst pixels_right = Math.max(0, page_width - (window.innerWidth + scroll_x))\n\n\treturn {\n\t\t// Current viewport dimensions\n\t\tviewport_width,\n\t\tviewport_height,\n\n\t\t// Total page dimensions\n\t\tpage_width,\n\t\tpage_height,\n\n\t\t// Current scroll position\n\t\tscroll_x,\n\t\tscroll_y,\n\n\t\tpixels_above: scroll_y,\n\t\tpixels_below,\n\n\t\tpages_above: viewport_height > 0 ? scroll_y / viewport_height : 0,\n\t\tpages_below: viewport_height > 0 ? pixels_below / viewport_height : 0,\n\t\ttotal_pages: viewport_height > 0 ? page_height / viewport_height : 0,\n\n\t\tcurrent_page_position: scroll_y / Math.max(1, page_height - viewport_height),\n\n\t\tpixels_left: scroll_x,\n\t\tpixels_right,\n\t}\n}\n","import type { PageController } from '../PageController'\n\n// Find common React root elements and add data-page-agent-not-interactive attribute\nexport function patchReact(pageController: PageController) {\n\tconst reactRootElements = document.querySelectorAll(\n\t\t'[data-reactroot], [data-reactid], [data-react-checksum], #root, #app, [id^=\"root-\"], [id^=\"app-\"], #adex-wrapper, #adex-root'\n\t)\n\n\tfor (const element of reactRootElements) {\n\t\telement.setAttribute('data-page-agent-not-interactive', 'true')\n\t}\n}\n\n/**\n * @todo (Heavy, might have false negatives) Interaction detection, if element width/height equals body offsetWidth/Height, consider it root element and non-interactive (React often attaches many events to root elements, causing false positives)\n */\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n *\n * PageController - Manages DOM operations and element interactions.\n * Designed to be independent of LLM and can be tested in unit tests.\n * All public methods are async for potential remote calling support.\n */\nimport {\n\tclickElement,\n\tgetElementByIndex,\n\tinputTextElement,\n\tscrollHorizontally,\n\tscrollVertically,\n\tselectOptionElement,\n} from './actions'\nimport * as dom from './dom'\nimport type { FlatDomTree, InteractiveElementDomNode } from './dom/dom_tree/type'\nimport { getPageInfo } from './dom/getPageInfo'\nimport { patchReact } from './patches/react'\nimport { isAnchorElement } from './utils'\n\n/**\n * Configuration for PageController\n */\nexport interface PageControllerConfig extends dom.DomConfig {\n\t/** Enable visual mask overlay during operations (default: false) */\n\tenableMask?: boolean\n}\n\n/**\n * Structured browser state for LLM consumption\n */\nexport interface BrowserState {\n\turl: string\n\ttitle: string\n\t/** Page info + scroll position hint (e.g. \"Page info: 1920x1080px...\\n[Start of page]\") */\n\theader: string\n\t/** Simplified HTML of interactive elements */\n\tcontent: string\n\t/** Page footer hint (e.g. \"... 300 pixels below ...\" or \"[End of page]\") */\n\tfooter: string\n}\n\ninterface ActionResult {\n\tsuccess: boolean\n\tmessage: string\n}\n\n/**\n * PageController manages DOM state and element interactions.\n * It provides async methods for all DOM operations, keeping state isolated.\n *\n * @lifecycle\n * - beforeUpdate: Emitted before the DOM tree is updated.\n * - afterUpdate: Emitted after the DOM tree is updated.\n */\nexport class PageController extends EventTarget {\n\tprivate config: PageControllerConfig\n\n\t/** Corresponds to eval_page in browser-use */\n\tprivate flatTree: FlatDomTree | null = null\n\n\t/**\n\t * All highlighted index-mapped interactive elements\n\t * Corresponds to DOMState.selector_map in browser-use\n\t */\n\tprivate selectorMap = new Map<number, InteractiveElementDomNode>()\n\n\t/** Index -> element text description mapping */\n\tprivate elementTextMap = new Map<number, string>()\n\n\t/**\n\t * Simplified HTML for LLM consumption.\n\t * Corresponds to clickable_elements_to_string in browser-use\n\t */\n\tprivate simplifiedHTML = '<EMPTY>'\n\n\t/** last time the tree was updated */\n\tprivate lastTimeUpdate = 0\n\n\t/** Whether the tree has been indexed at least once */\n\tprivate isIndexed = false\n\n\t/** Visual mask overlay for blocking user interaction during automation */\n\tprivate mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null\n\tprivate maskReady: Promise<void> | null = null\n\n\tconstructor(config: PageControllerConfig = {}) {\n\t\tsuper()\n\n\t\tthis.config = config\n\n\t\tpatchReact(this)\n\n\t\tif (config.enableMask) this.initMask()\n\t}\n\n\t/**\n\t * Initialize mask asynchronously (dynamic import to avoid CSS loading in Node)\n\t */\n\tinitMask() {\n\t\tif (this.maskReady !== null) return\n\t\tthis.maskReady = (async () => {\n\t\t\tconst { SimulatorMask } = await import('./mask/SimulatorMask')\n\t\t\tthis.mask = new SimulatorMask()\n\t\t})()\n\t}\n\t// ======= State Queries =======\n\n\t/**\n\t * Get current page URL\n\t */\n\tasync getCurrentUrl(): Promise<string> {\n\t\treturn window.location.href\n\t}\n\n\t/**\n\t * Get last tree update timestamp\n\t */\n\tasync getLastUpdateTime(): Promise<number> {\n\t\treturn this.lastTimeUpdate\n\t}\n\n\t/**\n\t * Get structured browser state for LLM consumption.\n\t * Automatically calls updateTree() to refresh the DOM state.\n\t */\n\tasync getBrowserState(): Promise<BrowserState> {\n\t\tconst url = window.location.href\n\t\tconst title = document.title\n\t\tconst pi = getPageInfo()\n\t\tconst viewportExpansion = dom.resolveViewportExpansion(this.config.viewportExpansion)\n\n\t\tawait this.updateTree()\n\n\t\tconst content = this.simplifiedHTML\n\n\t\t// Build header: page info + scroll position hint\n\t\tconst titleLine = `Current Page: [${title}](${url})`\n\n\t\tconst pageInfoLine = `Page info: ${pi.viewport_width}x${pi.viewport_height}px viewport, ${pi.page_width}x${pi.page_height}px total page size, ${pi.pages_above.toFixed(1)} pages above, ${pi.pages_below.toFixed(1)} pages below, ${pi.total_pages.toFixed(1)} total pages, at ${(pi.current_page_position * 100).toFixed(0)}% of page`\n\n\t\tconst elementsLabel =\n\t\t\tviewportExpansion === -1\n\t\t\t\t? 'Interactive elements from top layer of the current page (full page):'\n\t\t\t\t: 'Interactive elements from top layer of the current page inside the viewport:'\n\n\t\tconst hasContentAbove = pi.pixels_above > 4\n\t\tconst scrollHintAbove =\n\t\t\thasContentAbove && viewportExpansion !== -1\n\t\t\t\t? `... ${pi.pixels_above} pixels above (${pi.pages_above.toFixed(1)} pages) - scroll to see more ...`\n\t\t\t\t: '[Start of page]'\n\n\t\tconst header = `${titleLine}\\n${pageInfoLine}\\n\\n${elementsLabel}\\n\\n${scrollHintAbove}`\n\n\t\t// Build footer: scroll position hint\n\t\tconst hasContentBelow = pi.pixels_below > 4\n\t\tconst footer =\n\t\t\thasContentBelow && viewportExpansion !== -1\n\t\t\t\t? `... ${pi.pixels_below} pixels below (${pi.pages_below.toFixed(1)} pages) - scroll to see more ...`\n\t\t\t\t: '[End of page]'\n\n\t\treturn { url, title, header, content, footer }\n\t}\n\n\t// ======= DOM Tree Operations =======\n\n\t/**\n\t * Update DOM tree, returns simplified HTML for LLM.\n\t * This is the main method to refresh the page state.\n\t * Automatically bypasses mask during DOM extraction if enabled.\n\t */\n\tasync updateTree(): Promise<string> {\n\t\tthis.dispatchEvent(new Event('beforeUpdate'))\n\n\t\tthis.lastTimeUpdate = Date.now()\n\n\t\t// Temporarily bypass mask to allow DOM extraction\n\t\tif (this.mask) {\n\t\t\tthis.mask.wrapper.style.pointerEvents = 'none'\n\t\t}\n\n\t\tdom.cleanUpHighlights()\n\n\t\tconst blacklist = [\n\t\t\t...(this.config.interactiveBlacklist || []),\n\t\t\t...document.querySelectorAll('[data-page-agent-not-interactive]').values(),\n\t\t]\n\n\t\tthis.flatTree = dom.getFlatTree({\n\t\t\t...this.config,\n\t\t\tinteractiveBlacklist: blacklist,\n\t\t})\n\n\t\tthis.simplifiedHTML = dom.flatTreeToString(this.flatTree, this.config.includeAttributes)\n\n\t\tthis.selectorMap.clear()\n\t\tthis.selectorMap = dom.getSelectorMap(this.flatTree)\n\n\t\tthis.elementTextMap.clear()\n\t\tthis.elementTextMap = dom.getElementTextMap(this.simplifiedHTML)\n\n\t\t// Mark as indexed - now element actions are allowed\n\t\tthis.isIndexed = true\n\n\t\t// Restore mask blocking\n\t\tif (this.mask) {\n\t\t\tthis.mask.wrapper.style.pointerEvents = 'auto'\n\t\t}\n\n\t\tthis.dispatchEvent(new Event('afterUpdate'))\n\n\t\treturn this.simplifiedHTML\n\t}\n\n\t/**\n\t * Clean up all element highlights\n\t */\n\tasync cleanUpHighlights(): Promise<void> {\n\t\tconsole.log('[PageController] cleanUpHighlights')\n\t\tdom.cleanUpHighlights()\n\t}\n\n\t// ======= Element Actions =======\n\n\t/**\n\t * Ensure the tree has been indexed before any index-based operation.\n\t * Throws if updateTree() hasn't been called yet.\n\t */\n\tprivate assertIndexed(): void {\n\t\tif (!this.isIndexed) {\n\t\t\tthrow new Error('DOM tree not indexed yet. Can not perform actions on elements.')\n\t\t}\n\t}\n\n\t/**\n\t * Click element by index\n\t */\n\tasync clickElement(index: number): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait clickElement(element)\n\n\t\t\t// Handle links that open in new tabs\n\t\t\tif (isAnchorElement(element) && element.target === '_blank') {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tmessage: `✅ Clicked element (${elemText ?? index}). ⚠️ Link opened in a new tab.`,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Clicked element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to click element: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Input text into element by index\n\t */\n\tasync inputText(index: number, text: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait inputTextElement(element, text)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Input text (${text}) into element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to input text: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Select dropdown option by index and option text\n\t */\n\tasync selectOption(index: number, optionText: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait selectOptionElement(element as HTMLSelectElement, optionText)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Selected option (${optionText}) in element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to select option: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Scroll vertically\n\t */\n\tasync scroll(options: {\n\t\tdown: boolean\n\t\tnumPages: number\n\t\tpixels?: number\n\t\tindex?: number\n\t}): Promise<ActionResult> {\n\t\ttry {\n\t\t\tconst { down, numPages, pixels, index } = options\n\n\t\t\tthis.assertIndexed()\n\n\t\t\tconst scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight\n\n\t\t\tconst element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null\n\n\t\t\tconst message = await scrollVertically(down, scrollAmount, element)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to scroll: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Scroll horizontally\n\t */\n\tasync scrollHorizontally(options: {\n\t\tright: boolean\n\t\tpixels: number\n\t\tindex?: number\n\t}): Promise<ActionResult> {\n\t\ttry {\n\t\t\tconst { right, pixels, index } = options\n\n\t\t\tthis.assertIndexed()\n\n\t\t\tconst scrollAmount = pixels * (right ? 1 : -1)\n\n\t\t\tconst element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null\n\n\t\t\tconst message = await scrollHorizontally(right, scrollAmount, element)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to scroll horizontally: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Execute arbitrary JavaScript on the page\n\t */\n\tasync executeJavascript(script: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\t// Wrap script in async function to support await\n\t\t\tconst asyncFunction = eval(`(async () => { ${script} })`)\n\t\t\tconst result = await asyncFunction()\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Executed JavaScript. Result: ${result}`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Error executing JavaScript: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t// ======= Mask Operations =======\n\n\t/**\n\t * Show the visual mask overlay.\n\t * Only works after mask is setup.\n\t */\n\tasync showMask(): Promise<void> {\n\t\tawait this.maskReady\n\t\tthis.mask?.show()\n\t}\n\n\t/**\n\t * Hide the visual mask overlay.\n\t * Only works after mask is setup.\n\t */\n\tasync hideMask(): Promise<void> {\n\t\tawait this.maskReady\n\t\tthis.mask?.hide()\n\t}\n\n\t/**\n\t * Dispose and clean up resources\n\t */\n\tdispose(): void {\n\t\tdom.cleanUpHighlights()\n\t\tthis.flatTree = null\n\t\tthis.selectorMap.clear()\n\t\tthis.elementTextMap.clear()\n\t\tthis.simplifiedHTML = '<EMPTY>'\n\t\tthis.isIndexed = false\n\t\tthis.mask?.dispose()\n\t\tthis.mask = null\n\t}\n}\n\nexport * from './actions'\n"],"names":["dy","el","dx","args","parentElement","element","rect","viewportExpansion","nodeData","id","result","dom.resolveViewportExpansion","dom.cleanUpHighlights","dom.getFlatTree","dom.flatTreeToString","dom.getSelectorMap","dom.getElementTextMap"],"mappings":"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"}
1
+ {"version":3,"file":"page-controller.js","sources":["../../src/utils/index.ts","../../src/actions.ts","../../src/dom/dom_tree/index.js","../../src/dom/index.ts","../../src/dom/getPageInfo.ts","../../src/patches/react.ts","../../src/PageController.ts"],"sourcesContent":["// ======= type guards =======\n// @note instanceof fails for elements inside iframes\n\nexport function isHTMLElement(el: unknown): el is HTMLElement {\n\t// @todo either specify to HTMLElement or allow Element here.\n\treturn !!el && (el as Node).nodeType === 1\n}\n\nexport function isInputElement(el: Element): el is HTMLInputElement {\n\treturn el?.nodeType === 1 && el.tagName === 'INPUT'\n}\n\nexport function isTextAreaElement(el: Element): el is HTMLTextAreaElement {\n\treturn el?.nodeType === 1 && el.tagName === 'TEXTAREA'\n}\n\nexport function isSelectElement(el: Element): el is HTMLSelectElement {\n\treturn el?.nodeType === 1 && el.tagName === 'SELECT'\n}\n\nexport function isAnchorElement(el: Element): el is HTMLAnchorElement {\n\treturn el?.nodeType === 1 && el.tagName === 'A'\n}\n\n// ======= iframe helpers =======\n\n/** Iframe offset for translating element coordinates to top-frame viewport. */\nexport function getIframeOffset(element: HTMLElement): { x: number; y: number } {\n\tconst frame = element.ownerDocument.defaultView?.frameElement as HTMLElement | null\n\tif (!frame) return { x: 0, y: 0 }\n\tconst rect = frame.getBoundingClientRect()\n\treturn { x: rect.left, y: rect.top }\n}\n\n/**\n * Get native value setter from the element's own prototype (iframe-safe).\n * @note for React\n */\nexport function getNativeValueSetter(element: HTMLInputElement | HTMLTextAreaElement) {\n\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\treturn Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element) as object, 'value')!\n\t\t.set as (v: string) => void\n}\n\n// ======= general utils =======\n\nexport async function waitFor(seconds: number): Promise<void> {\n\tawait new Promise((resolve) => setTimeout(resolve, seconds * 1000))\n}\n\n// ======= mask events =======\n\n/**\n * Move the visual pointer to a position within an element.\n * @param x - x coordinate in the element's document viewport\n * @param y - y coordinate in the element's document viewport\n */\nexport async function movePointerToElement(element: HTMLElement, x: number, y: number) {\n\tconst offset = getIframeOffset(element)\n\n\twindow.dispatchEvent(\n\t\tnew CustomEvent('PageAgent::MovePointerTo', {\n\t\t\tdetail: { x: x + offset.x, y: y + offset.y },\n\t\t})\n\t)\n\n\tawait waitFor(0.3)\n}\n\nexport async function clickPointer() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::ClickPointer'))\n}\n\nexport async function enablePassThrough() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::EnablePassThrough'))\n}\n\nexport async function disablePassThrough() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::DisablePassThrough'))\n}\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n */\nimport type { InteractiveElementDomNode } from './dom/dom_tree/type'\nimport {\n\tclickPointer,\n\tdisablePassThrough,\n\tenablePassThrough,\n\tgetNativeValueSetter,\n\tisHTMLElement,\n\tisInputElement,\n\tisSelectElement,\n\tisTextAreaElement,\n\tmovePointerToElement,\n\twaitFor,\n} from './utils'\n\n/**\n * Get the HTMLElement by index from a selectorMap.\n * @private Internal method, subject to change at any time.\n */\nexport function getElementByIndex(\n\tselectorMap: Map<number, InteractiveElementDomNode>,\n\tindex: number\n): HTMLElement {\n\tconst interactiveNode = selectorMap.get(index)\n\tif (!interactiveNode) {\n\t\tthrow new Error(`No interactive element found at index ${index}`)\n\t}\n\n\tconst element = interactiveNode.ref\n\tif (!element) {\n\t\tthrow new Error(`Element at index ${index} does not have a reference`)\n\t}\n\n\tif (!isHTMLElement(element)) {\n\t\tthrow new Error(`Element at index ${index} is not an HTMLElement`)\n\t}\n\n\treturn element\n}\n\nlet lastClickedElement: HTMLElement | null = null\n\nfunction blurLastClickedElement() {\n\tif (lastClickedElement) {\n\t\tlastClickedElement.dispatchEvent(new PointerEvent('pointerout', { bubbles: true }))\n\t\tlastClickedElement.dispatchEvent(new PointerEvent('pointerleave', { bubbles: false }))\n\t\tlastClickedElement.dispatchEvent(new MouseEvent('mouseout', { bubbles: true }))\n\t\tlastClickedElement.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false }))\n\t\tlastClickedElement.blur()\n\t\tlastClickedElement = null\n\t}\n}\n\n/**\n * Simulate a full click following W3C Pointer Events + UI Events spec order:\n * pointerover/enter → mouseover/enter → pointerdown → mousedown → [focus] →\n * pointerup → mouseup → click\n *\n * @private Internal method, subject to change at any time.\n */\nexport async function clickElement(element: HTMLElement) {\n\tblurLastClickedElement()\n\n\tlastClickedElement = element\n\n\tawait scrollIntoViewIfNeeded(element)\n\tconst frame = element.ownerDocument.defaultView?.frameElement\n\tif (frame) await scrollIntoViewIfNeeded(frame)\n\n\tconst rect = element.getBoundingClientRect()\n\tconst x = rect.left + rect.width / 2\n\tconst y = rect.top + rect.height / 2\n\n\tawait movePointerToElement(element, x, y)\n\tawait clickPointer()\n\n\tawait waitFor(0.1)\n\n\t// Hit-test to find the deepest element at click coordinates, matching\n\t// real browser behavior where events target the innermost element.\n\t// @note This may hit a element in the blacklist\n\t// TODO: This is a temporary workaround. Should have been handled during dom extraction.\n\tconst doc = element.ownerDocument\n\tawait enablePassThrough()\n\tconst hitTarget = doc.elementFromPoint(x, y)\n\tawait disablePassThrough()\n\tconst target =\n\t\thitTarget instanceof HTMLElement && element.contains(hitTarget) ? hitTarget : element\n\n\tconst pointerOpts = {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tclientX: x,\n\t\tclientY: y,\n\t\tpointerType: 'mouse',\n\t}\n\tconst mouseOpts = { bubbles: true, cancelable: true, clientX: x, clientY: y, button: 0 }\n\n\t// Hover — pointer events first, then mouse events (spec order)\n\ttarget.dispatchEvent(new PointerEvent('pointerover', pointerOpts))\n\ttarget.dispatchEvent(new PointerEvent('pointerenter', { ...pointerOpts, bubbles: false }))\n\ttarget.dispatchEvent(new MouseEvent('mouseover', mouseOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseenter', { ...mouseOpts, bubbles: false }))\n\n\t// Press\n\ttarget.dispatchEvent(new PointerEvent('pointerdown', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mousedown', mouseOpts))\n\n\t// Focus is not part of the standard pointer/mouse event sequence\n\t// \"undefined and varies between user agents\".\n\t// We focus the original element (nearest focusable ancestor), not the hit-test target, matching browser behavior.\n\telement.focus({ preventScroll: true })\n\n\t// Release\n\ttarget.dispatchEvent(new PointerEvent('pointerup', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseup', mouseOpts))\n\n\t// Click — activation behavior (navigation, form submit, etc.) triggers\n\t// via bubbling from target up to the interactive ancestor.\n\ttarget.click()\n\n\tawait waitFor(0.2)\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function inputTextElement(element: HTMLElement, text: string) {\n\tconst isContentEditable = element.isContentEditable\n\tif (!isInputElement(element) && !isTextAreaElement(element) && !isContentEditable) {\n\t\tthrow new Error('Element is not an input, textarea, or contenteditable')\n\t}\n\n\tawait clickElement(element)\n\n\tif (isContentEditable) {\n\t\t// Contenteditable support (partial)\n\t\t// Not supported:\n\t\t// - Monaco/CodeMirror: Require direct JS instance access. No universal way to obtain.\n\t\t// - Draft.js: Not responsive to synthetic/execCommand/Range/DataTransfer. Unmaintained.\n\t\t//\n\t\t// Strategy: Try Plan A (synthetic events) first, then verify and fall back\n\t\t// to Plan B (execCommand) if the text wasn't actually inserted.\n\t\t//\n\t\t// Plan A: Dispatch synthetic events\n\t\t// Works: React contenteditable, Quill.\n\t\t// Fails: Slate.js, some contenteditable editors that ignore synthetic events.\n\t\t// Sequence: beforeinput -> mutation -> input -> change -> blur\n\n\t\t// Dispatch beforeinput + mutation + input for clearing\n\t\tif (\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('beforeinput', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tinputType: 'deleteContent',\n\t\t\t\t})\n\t\t\t)\n\t\t) {\n\t\t\telement.innerText = ''\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('input', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tinputType: 'deleteContent',\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// Dispatch beforeinput + mutation + input for insertion (important for React apps)\n\t\tif (\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('beforeinput', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tinputType: 'insertText',\n\t\t\t\t\tdata: text,\n\t\t\t\t})\n\t\t\t)\n\t\t) {\n\t\t\telement.innerText = text\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('input', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tinputType: 'insertText',\n\t\t\t\t\tdata: text,\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// Verify Plan A worked by checking if the text was actually inserted\n\t\tconst planASucceeded = element.innerText.trim() === text.trim()\n\n\t\tif (!planASucceeded) {\n\t\t\t// Plan B: execCommand fallback (deprecated but widely supported)\n\t\t\t// Works: Quill, Slate.js, react contenteditable components.\n\t\t\t// This approach integrates with the browser's undo stack and is handled\n\t\t\t// natively by most rich-text editors.\n\t\t\telement.focus()\n\n\t\t\t// Select all existing content and delete it\n\t\t\tconst doc = element.ownerDocument\n\t\t\tconst selection = (doc.defaultView || window).getSelection()\n\t\t\tconst range = doc.createRange()\n\t\t\trange.selectNodeContents(element)\n\t\t\tselection?.removeAllRanges()\n\t\t\tselection?.addRange(range)\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tdoc.execCommand('delete', false)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tdoc.execCommand('insertText', false, text)\n\t\t}\n\n\t\t// Dispatch change event (for good measure)\n\t\telement.dispatchEvent(new Event('change', { bubbles: true }))\n\n\t\t// Trigger blur for validation\n\t\telement.blur()\n\t} else {\n\t\tgetNativeValueSetter(element as HTMLInputElement | HTMLTextAreaElement).call(element, text)\n\t}\n\n\t// Only dispatch shared input event for non-contenteditable (contenteditable has its own)\n\tif (!isContentEditable) {\n\t\telement.dispatchEvent(new Event('input', { bubbles: true }))\n\t}\n\n\tawait waitFor(0.1)\n\n\tblurLastClickedElement()\n}\n\n/**\n * @todo browser-use version is very complex and supports menu tags, need to follow up\n * @private Internal method, subject to change at any time.\n */\nexport async function selectOptionElement(selectElement: HTMLSelectElement, optionText: string) {\n\tif (!isSelectElement(selectElement)) {\n\t\tthrow new Error('Element is not a select element')\n\t}\n\n\tconst options = Array.from(selectElement.options)\n\tconst option = options.find((opt) => opt.textContent?.trim() === optionText.trim())\n\n\tif (!option) {\n\t\tthrow new Error(`Option with text \"${optionText}\" not found in select element`)\n\t}\n\n\tselectElement.value = option.value\n\tselectElement.dispatchEvent(new Event('change', { bubbles: true }))\n\n\tawait waitFor(0.1) // Wait to ensure change event processing completes\n}\n\ninterface ScrollableElement extends Element {\n\tscrollIntoViewIfNeeded?: (centerIfNeeded?: boolean) => void\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function scrollIntoViewIfNeeded(element: Element) {\n\tconst el = element as ScrollableElement\n\tif (typeof el.scrollIntoViewIfNeeded === 'function') {\n\t\tel.scrollIntoViewIfNeeded()\n\t\t// await waitFor(0.5) // Animation playback\n\t} else {\n\t\t// @todo visibility check\n\t\telement.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' })\n\t\t// await waitFor(0.5) // Animation playback\n\t}\n}\n\nexport async function scrollVertically(scroll_amount: number, element?: HTMLElement | null) {\n\t// Element-specific scrolling if element is provided\n\tif (element) {\n\t\tconst targetElement = element\n\t\tlet currentElement = targetElement as HTMLElement | null\n\t\tlet scrollSuccess = false\n\t\tlet scrolledElement: HTMLElement | null = null\n\t\tlet scrollDelta = 0\n\t\tlet attempts = 0\n\t\tconst dy = scroll_amount\n\n\t\twhile (currentElement && attempts < 10) {\n\t\t\tconst computedStyle = window.getComputedStyle(currentElement)\n\t\t\tconst hasScrollableY =\n\t\t\t\t/(auto|scroll|overlay)/.test(computedStyle.overflowY) ||\n\t\t\t\t(computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== 'auto') ||\n\t\t\t\t(computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== 'auto')\n\t\t\tconst canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight\n\n\t\t\tif (hasScrollableY && canScrollVertically) {\n\t\t\t\tconst beforeScroll = currentElement.scrollTop\n\t\t\t\tconst maxScroll = currentElement.scrollHeight - currentElement.clientHeight\n\n\t\t\t\tlet scrollAmount = dy / 3\n\n\t\t\t\tif (scrollAmount > 0) {\n\t\t\t\t\tscrollAmount = Math.min(scrollAmount, maxScroll - beforeScroll)\n\t\t\t\t} else {\n\t\t\t\t\tscrollAmount = Math.max(scrollAmount, -beforeScroll)\n\t\t\t\t}\n\n\t\t\t\tcurrentElement.scrollTop = beforeScroll + scrollAmount\n\n\t\t\t\tconst afterScroll = currentElement.scrollTop\n\t\t\t\tconst actualScrollDelta = afterScroll - beforeScroll\n\n\t\t\t\tif (Math.abs(actualScrollDelta) > 0.5) {\n\t\t\t\t\tscrollSuccess = true\n\t\t\t\t\tscrolledElement = currentElement\n\t\t\t\t\tscrollDelta = actualScrollDelta\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentElement === document.body || currentElement === document.documentElement) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentElement = currentElement.parentElement\n\t\t\tattempts++\n\t\t}\n\n\t\tif (scrollSuccess) {\n\t\t\treturn `Scrolled container (${scrolledElement?.tagName}) by ${scrollDelta}px`\n\t\t} else {\n\t\t\treturn `No scrollable container found for element (${targetElement.tagName})`\n\t\t}\n\t}\n\n\t// Page-level scrolling (default or fallback)\n\n\tconst dy = scroll_amount\n\tconst bigEnough = (el: HTMLElement) => el.clientHeight >= window.innerHeight * 0.5\n\tconst canScroll = (el: HTMLElement | null) =>\n\t\tel &&\n\t\t/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowY) &&\n\t\tel.scrollHeight > el.clientHeight &&\n\t\tbigEnough(el)\n\n\t// @deprecated Heuristic container search.\n\t// Unreliable in multi-panel layouts. Should guide LLMs to use indexed scroll for consistency.\n\t// TODO: remove this fallback\n\n\t// try to find the nearest scrollable container\n\t// document.activeElement is usually body.\n\t// After a successful element.focus(), activeElement become the nearest focusable parent\n\n\tlet el: HTMLElement | null = document.activeElement as HTMLElement | null\n\twhile (el && !canScroll(el) && el !== document.body) el = el.parentElement\n\n\t// Something is wrong if it falls back to global '*' search\n\t// TODO: Return error message instead of global '*' search\n\n\tel = canScroll(el)\n\t\t? el\n\t\t: Array.from(document.querySelectorAll<HTMLElement>('*')).find(canScroll) ||\n\t\t\t(document.scrollingElement as HTMLElement) ||\n\t\t\t(document.documentElement as HTMLElement)\n\n\tif (el === document.scrollingElement || el === document.documentElement || el === document.body) {\n\t\t// Page-level scroll\n\t\tconst scrollBefore = window.scrollY\n\t\tconst scrollMax = document.documentElement.scrollHeight - window.innerHeight\n\n\t\twindow.scrollBy(0, dy)\n\n\t\tconst scrollAfter = window.scrollY\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dy > 0\n\t\t\t\t? `⚠️ Already at the bottom of the page, cannot scroll down further.`\n\t\t\t\t: `⚠️ Already at the top of the page, cannot scroll up further.`\n\t\t}\n\n\t\tconst reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedTop = dy < 0 && scrollAfter <= 1\n\n\t\tif (reachedBottom) return `✅ Scrolled page by ${scrolled}px. Reached the bottom of the page.`\n\t\tif (reachedTop) return `✅ Scrolled page by ${scrolled}px. Reached the top of the page.`\n\t\treturn `✅ Scrolled page by ${scrolled}px.`\n\t} else {\n\t\t// Container scroll\n\n\t\tconst warningMsg = `The document is not scrollable. Falling back to container scroll.`\n\t\tconsole.log(`[PageController] ${warningMsg}`)\n\n\t\tconst scrollBefore = el!.scrollTop\n\t\tconst scrollMax = el!.scrollHeight - el!.clientHeight\n\n\t\tel!.scrollBy({ top: dy, behavior: 'smooth' })\n\t\tawait waitFor(0.1)\n\n\t\tconst scrollAfter = el!.scrollTop\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dy > 0\n\t\t\t\t? `⚠️ ${warningMsg} Already at the bottom of container (${el!.tagName}), cannot scroll down further.`\n\t\t\t\t: `⚠️ ${warningMsg} Already at the top of container (${el!.tagName}), cannot scroll up further.`\n\t\t}\n\n\t\tconst reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedTop = dy < 0 && scrollAfter <= 1\n\n\t\tif (reachedBottom)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the bottom.`\n\t\tif (reachedTop)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the top.`\n\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px.`\n\t}\n}\n\nexport async function scrollHorizontally(scroll_amount: number, element?: HTMLElement | null) {\n\t// Element-specific scrolling if element is provided\n\tif (element) {\n\t\tconst targetElement = element\n\t\tlet currentElement = targetElement as HTMLElement | null\n\t\tlet scrollSuccess = false\n\t\tlet scrolledElement: HTMLElement | null = null\n\t\tlet scrollDelta = 0\n\t\tlet attempts = 0\n\t\tconst dx = scroll_amount\n\n\t\twhile (currentElement && attempts < 10) {\n\t\t\tconst computedStyle = window.getComputedStyle(currentElement)\n\t\t\tconst hasScrollableX =\n\t\t\t\t/(auto|scroll|overlay)/.test(computedStyle.overflowX) ||\n\t\t\t\t(computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== 'auto') ||\n\t\t\t\t(computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== 'auto')\n\t\t\tconst canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth\n\n\t\t\tif (hasScrollableX && canScrollHorizontally) {\n\t\t\t\tconst beforeScroll = currentElement.scrollLeft\n\t\t\t\tconst maxScroll = currentElement.scrollWidth - currentElement.clientWidth\n\n\t\t\t\tlet scrollAmount = dx / 3\n\n\t\t\t\tif (scrollAmount > 0) {\n\t\t\t\t\tscrollAmount = Math.min(scrollAmount, maxScroll - beforeScroll)\n\t\t\t\t} else {\n\t\t\t\t\tscrollAmount = Math.max(scrollAmount, -beforeScroll)\n\t\t\t\t}\n\n\t\t\t\tcurrentElement.scrollLeft = beforeScroll + scrollAmount\n\n\t\t\t\tconst afterScroll = currentElement.scrollLeft\n\t\t\t\tconst actualScrollDelta = afterScroll - beforeScroll\n\n\t\t\t\tif (Math.abs(actualScrollDelta) > 0.5) {\n\t\t\t\t\tscrollSuccess = true\n\t\t\t\t\tscrolledElement = currentElement\n\t\t\t\t\tscrollDelta = actualScrollDelta\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentElement === document.body || currentElement === document.documentElement) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentElement = currentElement.parentElement\n\t\t\tattempts++\n\t\t}\n\n\t\tif (scrollSuccess) {\n\t\t\treturn `Scrolled container (${scrolledElement?.tagName}) horizontally by ${scrollDelta}px`\n\t\t} else {\n\t\t\treturn `No horizontally scrollable container found for element (${targetElement.tagName})`\n\t\t}\n\t}\n\n\t// Page-level scrolling (default or fallback)\n\n\tconst dx = scroll_amount\n\n\tconst bigEnough = (el: HTMLElement) => el.clientWidth >= window.innerWidth * 0.5\n\tconst canScroll = (el: HTMLElement | null) =>\n\t\tel &&\n\t\t/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowX) &&\n\t\tel.scrollWidth > el.clientWidth &&\n\t\tbigEnough(el)\n\n\t// @deprecated Same heuristic container search as scrollVertically.\n\t// TODO: Remove once LLMs reliably use indexed scrolling via data-scrollable.\n\n\tlet el: HTMLElement | null = document.activeElement as HTMLElement | null\n\twhile (el && !canScroll(el) && el !== document.body) el = el.parentElement\n\n\tel = canScroll(el)\n\t\t? el\n\t\t: Array.from(document.querySelectorAll<HTMLElement>('*')).find(canScroll) ||\n\t\t\t(document.scrollingElement as HTMLElement) ||\n\t\t\t(document.documentElement as HTMLElement)\n\n\tif (el === document.scrollingElement || el === document.documentElement || el === document.body) {\n\t\t// Page-level scroll\n\t\tconst scrollBefore = window.scrollX\n\t\tconst scrollMax = document.documentElement.scrollWidth - window.innerWidth\n\n\t\twindow.scrollBy(dx, 0)\n\n\t\tconst scrollAfter = window.scrollX\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dx > 0\n\t\t\t\t? `⚠️ Already at the right edge of the page, cannot scroll right further.`\n\t\t\t\t: `⚠️ Already at the left edge of the page, cannot scroll left further.`\n\t\t}\n\n\t\tconst reachedRight = dx > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedLeft = dx < 0 && scrollAfter <= 1\n\n\t\tif (reachedRight)\n\t\t\treturn `✅ Scrolled page by ${scrolled}px. Reached the right edge of the page.`\n\t\tif (reachedLeft) return `✅ Scrolled page by ${scrolled}px. Reached the left edge of the page.`\n\t\treturn `✅ Scrolled page horizontally by ${scrolled}px.`\n\t} else {\n\t\t// Container scroll\n\t\tconst warningMsg = `The document is not scrollable. Falling back to container scroll.`\n\t\tconsole.log(`[PageController] ${warningMsg}`)\n\n\t\tconst scrollBefore = el!.scrollLeft\n\t\tconst scrollMax = el!.scrollWidth - el!.clientWidth\n\n\t\tel!.scrollBy({ left: dx, behavior: 'smooth' })\n\t\tawait waitFor(0.1)\n\n\t\tconst scrollAfter = el!.scrollLeft\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dx > 0\n\t\t\t\t? `⚠️ ${warningMsg} Already at the right edge of container (${el!.tagName}), cannot scroll right further.`\n\t\t\t\t: `⚠️ ${warningMsg} Already at the left edge of container (${el!.tagName}), cannot scroll left further.`\n\t\t}\n\n\t\tconst reachedRight = dx > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedLeft = dx < 0 && scrollAfter <= 1\n\n\t\tif (reachedRight)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the right edge.`\n\t\tif (reachedLeft)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the left edge.`\n\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) horizontally by ${scrolled}px.`\n\t}\n}\n","/**\n * @file port from browser-use\n * @see https://github.com/browser-use/browser-use/commits/main/browser_use/dom/dom_tree/index.js\n * @match 0.5.9 d51b6e73daff7165fdd3e44debd667e7f5f7fdc5\n *\n * search @edit for all the changed lines.\n *\n * @edit export\n * @edit add interactiveBlacklist interactiveWhitelist\n * @edit adjustable opacity\n * @edit direct dom ref\n * @edit @workaround input.checked\n * @edit smaller zIndex for highlight\n * @edit no need for xpath\n * @edit add `extra` field for extra data\n * @edit scrollable element detection\n * @edit add `data-browser-use-ignore` attribute\n * @edit improve `sampleRect`, filter out rects with 0 area\n * @edit exclude aria-hidden elements\n * @edit make sure attributes exist for interactive candidates.\n * @edit fix \"aria-*\" attributes check\n */\n\nexport default (\n\targs = {\n\t\tdoHighlightElements: true,\n\t\tfocusHighlightIndex: -1,\n\t\tviewportExpansion: 0,\n\t\tdebugMode: false,\n\n\t\t/**\n\t\t * @edit\n\t\t */\n\t\t/** @type {Element[]} */\n\t\tinteractiveBlacklist: [],\n\t\t/** @type {Element[]} */\n\t\tinteractiveWhitelist: [],\n\t\thighlightOpacity: 0.1,\n\t\thighlightLabelOpacity: 0.5,\n\t}\n) => {\n\t/**\n\t * @edit\n\t */\n\tconst { interactiveBlacklist, interactiveWhitelist, highlightOpacity, highlightLabelOpacity } =\n\t\targs\n\n\tconst { doHighlightElements, focusHighlightIndex, viewportExpansion, debugMode } = args\n\tlet highlightIndex = 0 // Reset highlight index\n\n\t/**\n\t * @edit add `extra` field for extra data\n\t */\n\tconst extraData = new WeakMap()\n\tfunction addExtraData(element, data) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return\n\t\textraData.set(element, { ...extraData.get(element), ...data })\n\t}\n\n\t// Add caching mechanisms at the top level\n\tconst DOM_CACHE = {\n\t\tboundingRects: new WeakMap(),\n\t\tclientRects: new WeakMap(),\n\t\tcomputedStyles: new WeakMap(),\n\t\tclearCache: () => {\n\t\t\tDOM_CACHE.boundingRects = new WeakMap()\n\t\t\tDOM_CACHE.clientRects = new WeakMap()\n\t\t\tDOM_CACHE.computedStyles = new WeakMap()\n\t\t},\n\t}\n\n\t/**\n\t * Gets the cached bounding rect for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the bounding rect for.\n\t * @returns {DOMRect | null} The cached bounding rect, or null if the element is not found.\n\t */\n\tfunction getCachedBoundingRect(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.boundingRects.has(element)) {\n\t\t\treturn DOM_CACHE.boundingRects.get(element)\n\t\t}\n\n\t\tconst rect = element.getBoundingClientRect()\n\n\t\tif (rect) {\n\t\t\tDOM_CACHE.boundingRects.set(element, rect)\n\t\t}\n\t\treturn rect\n\t}\n\n\t/**\n\t * Gets the cached computed style for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the computed style for.\n\t * @returns {CSSStyleDeclaration | null} The cached computed style, or null if the element is not found.\n\t */\n\tfunction getCachedComputedStyle(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.computedStyles.has(element)) {\n\t\t\treturn DOM_CACHE.computedStyles.get(element)\n\t\t}\n\n\t\tconst style = window.getComputedStyle(element)\n\n\t\tif (style) {\n\t\t\tDOM_CACHE.computedStyles.set(element, style)\n\t\t}\n\t\treturn style\n\t}\n\n\t/**\n\t * Gets the cached client rects for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the client rects for.\n\t * @returns {DOMRectList | null} The cached client rects, or null if the element is not found.\n\t */\n\tfunction getCachedClientRects(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.clientRects.has(element)) {\n\t\t\treturn DOM_CACHE.clientRects.get(element)\n\t\t}\n\n\t\tconst rects = element.getClientRects()\n\n\t\tif (rects) {\n\t\t\tDOM_CACHE.clientRects.set(element, rects)\n\t\t}\n\t\treturn rects\n\t}\n\n\t/**\n\t * Hash map of DOM nodes indexed by their highlight index.\n\t *\n\t * @type {Object<string, any>}\n\t */\n\tconst DOM_HASH_MAP = {}\n\n\tconst ID = { current: 0 }\n\n\tconst HIGHLIGHT_CONTAINER_ID = 'playwright-highlight-container'\n\n\t// Add a WeakMap cache for XPath strings\n\tconst xpathCache = new WeakMap()\n\n\t// // Initialize once and reuse\n\t// const viewportObserver = new IntersectionObserver(\n\t// (entries) => {\n\t// entries.forEach(entry => {\n\t// elementVisibilityMap.set(entry.target, entry.isIntersecting);\n\t// });\n\t// },\n\t// { rootMargin: `${viewportExpansion}px` }\n\t// );\n\n\t/**\n\t * Highlights an element in the DOM and returns the index of the next element.\n\t *\n\t * @param {HTMLElement} element - The element to highlight.\n\t * @param {number} index - The index of the element.\n\t * @param {HTMLElement | null} parentIframe - The parent iframe node.\n\t * @returns {number} The index of the next element.\n\t */\n\tfunction highlightElement(element, index, parentIframe = null) {\n\t\tif (!element) return index\n\n\t\tconst overlays = []\n\t\t/**\n\t\t * @type {HTMLElement | null}\n\t\t */\n\t\tlet label = null\n\t\tlet labelWidth = 20\n\t\tlet labelHeight = 16\n\t\tlet cleanupFn = null\n\n\t\ttry {\n\t\t\t// Create or get highlight container\n\t\t\tlet container = document.getElementById(HIGHLIGHT_CONTAINER_ID)\n\t\t\tif (!container) {\n\t\t\t\tcontainer = document.createElement('div')\n\t\t\t\tcontainer.id = HIGHLIGHT_CONTAINER_ID\n\t\t\t\tcontainer.style.position = 'fixed'\n\t\t\t\tcontainer.style.pointerEvents = 'none'\n\t\t\t\tcontainer.style.top = '0'\n\t\t\t\tcontainer.style.left = '0'\n\t\t\t\tcontainer.style.width = '100%'\n\t\t\t\tcontainer.style.height = '100%'\n\n\t\t\t\t/**\n\t\t\t\t * @edit smaller zIndex for highlight\n\t\t\t\t */\n\t\t\t\t// Use the maximum valid value in zIndex to ensure the element is not blocked by overlapping elements.\n\t\t\t\t// container.style.zIndex = \"2147483647\";\n\t\t\t\tcontainer.style.zIndex = '2147483640'\n\n\t\t\t\tcontainer.style.backgroundColor = 'transparent'\n\t\t\t\tdocument.body.appendChild(container)\n\t\t\t}\n\n\t\t\t// Get element client rects\n\t\t\tconst rects = element.getClientRects() // Use getClientRects()\n\n\t\t\tif (!rects || rects.length === 0) return index // Exit if no rects\n\n\t\t\t// Generate a color based on the index\n\t\t\tconst colors = [\n\t\t\t\t'#FF0000',\n\t\t\t\t'#00FF00',\n\t\t\t\t'#0000FF',\n\t\t\t\t'#FFA500',\n\t\t\t\t'#800080',\n\t\t\t\t'#008080',\n\t\t\t\t'#FF69B4',\n\t\t\t\t'#4B0082',\n\t\t\t\t'#FF4500',\n\t\t\t\t'#2E8B57',\n\t\t\t\t'#DC143C',\n\t\t\t\t'#4682B4',\n\t\t\t]\n\t\t\tconst colorIndex = index % colors.length\n\t\t\tlet baseColor = colors[colorIndex]\n\n\t\t\t/**\n\t\t\t * @edit adjustable opacity\n\t\t\t */\n\t\t\t// const backgroundColor = baseColor + \"1A\"; // 10% opacity version of the color\n\t\t\tconst backgroundColor =\n\t\t\t\tbaseColor +\n\t\t\t\tMath.floor(highlightOpacity * 255)\n\t\t\t\t\t.toString(16)\n\t\t\t\t\t.padStart(2, '0')\n\t\t\tbaseColor =\n\t\t\t\tbaseColor +\n\t\t\t\tMath.floor(highlightLabelOpacity * 255)\n\t\t\t\t\t.toString(16)\n\t\t\t\t\t.padStart(2, '0')\n\n\t\t\t// Get iframe offset if necessary\n\t\t\tlet iframeOffset = { x: 0, y: 0 }\n\t\t\tif (parentIframe) {\n\t\t\t\tconst iframeRect = parentIframe.getBoundingClientRect() // Keep getBoundingClientRect for iframe offset\n\t\t\t\tiframeOffset.x = iframeRect.left\n\t\t\t\tiframeOffset.y = iframeRect.top\n\t\t\t}\n\n\t\t\t// Create fragment to hold overlay elements\n\t\t\tconst fragment = document.createDocumentFragment()\n\n\t\t\t// Create highlight overlays for each client rect\n\t\t\tfor (const rect of rects) {\n\t\t\t\tif (rect.width === 0 || rect.height === 0) continue // Skip empty rects\n\n\t\t\t\tconst overlay = document.createElement('div')\n\t\t\t\toverlay.style.position = 'fixed'\n\t\t\t\toverlay.style.border = `2px solid ${baseColor}`\n\t\t\t\toverlay.style.backgroundColor = backgroundColor\n\t\t\t\toverlay.style.pointerEvents = 'none'\n\t\t\t\toverlay.style.boxSizing = 'border-box'\n\n\t\t\t\tconst top = rect.top + iframeOffset.y\n\t\t\t\tconst left = rect.left + iframeOffset.x\n\n\t\t\t\toverlay.style.top = `${top}px`\n\t\t\t\toverlay.style.left = `${left}px`\n\t\t\t\toverlay.style.width = `${rect.width}px`\n\t\t\t\toverlay.style.height = `${rect.height}px`\n\n\t\t\t\tfragment.appendChild(overlay)\n\t\t\t\toverlays.push({ element: overlay, initialRect: rect }) // Store overlay and its rect\n\t\t\t}\n\n\t\t\t// Create and position a single label relative to the first rect\n\t\t\tconst firstRect = rects[0]\n\t\t\tlabel = document.createElement('div')\n\t\t\tlabel.className = 'playwright-highlight-label'\n\t\t\tlabel.style.position = 'fixed'\n\t\t\tlabel.style.background = baseColor\n\t\t\tlabel.style.color = 'white'\n\t\t\tlabel.style.padding = '1px 4px'\n\t\t\tlabel.style.borderRadius = '4px'\n\t\t\tlabel.style.fontSize = `${Math.min(12, Math.max(8, firstRect.height / 2))}px`\n\t\t\tlabel.textContent = index.toString()\n\n\t\t\tlabelWidth = label.offsetWidth > 0 ? label.offsetWidth : labelWidth // Update actual width if possible\n\t\t\tlabelHeight = label.offsetHeight > 0 ? label.offsetHeight : labelHeight // Update actual height if possible\n\n\t\t\tconst firstRectTop = firstRect.top + iframeOffset.y\n\t\t\tconst firstRectLeft = firstRect.left + iframeOffset.x\n\n\t\t\tlet labelTop = firstRectTop + 2\n\t\t\tlet labelLeft = firstRectLeft + firstRect.width - labelWidth - 2\n\n\t\t\t// Adjust label position if first rect is too small\n\t\t\tif (firstRect.width < labelWidth + 4 || firstRect.height < labelHeight + 4) {\n\t\t\t\tlabelTop = firstRectTop - labelHeight - 2\n\t\t\t\tlabelLeft = firstRectLeft + firstRect.width - labelWidth // Align with right edge\n\t\t\t\tif (labelLeft < iframeOffset.x) labelLeft = firstRectLeft // Prevent going off-left\n\t\t\t}\n\n\t\t\t// Ensure label stays within viewport bounds slightly better\n\t\t\tlabelTop = Math.max(0, Math.min(labelTop, window.innerHeight - labelHeight))\n\t\t\tlabelLeft = Math.max(0, Math.min(labelLeft, window.innerWidth - labelWidth))\n\n\t\t\tlabel.style.top = `${labelTop}px`\n\t\t\tlabel.style.left = `${labelLeft}px`\n\n\t\t\tfragment.appendChild(label)\n\n\t\t\t// Update positions on scroll/resize\n\t\t\tconst updatePositions = () => {\n\t\t\t\tconst newRects = element.getClientRects() // Get fresh rects\n\t\t\t\tlet newIframeOffset = { x: 0, y: 0 }\n\n\t\t\t\tif (parentIframe) {\n\t\t\t\t\tconst iframeRect = parentIframe.getBoundingClientRect() // Keep getBoundingClientRect for iframe\n\t\t\t\t\tnewIframeOffset.x = iframeRect.left\n\t\t\t\t\tnewIframeOffset.y = iframeRect.top\n\t\t\t\t}\n\n\t\t\t\t// Update each overlay\n\t\t\t\toverlays.forEach((overlayData, i) => {\n\t\t\t\t\tif (i < newRects.length) {\n\t\t\t\t\t\t// Check if rect still exists\n\t\t\t\t\t\tconst newRect = newRects[i]\n\t\t\t\t\t\tconst newTop = newRect.top + newIframeOffset.y\n\t\t\t\t\t\tconst newLeft = newRect.left + newIframeOffset.x\n\n\t\t\t\t\t\toverlayData.element.style.top = `${newTop}px`\n\t\t\t\t\t\toverlayData.element.style.left = `${newLeft}px`\n\t\t\t\t\t\toverlayData.element.style.width = `${newRect.width}px`\n\t\t\t\t\t\toverlayData.element.style.height = `${newRect.height}px`\n\t\t\t\t\t\toverlayData.element.style.display =\n\t\t\t\t\t\t\tnewRect.width === 0 || newRect.height === 0 ? 'none' : 'block'\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If fewer rects now, hide extra overlays\n\t\t\t\t\t\toverlayData.element.style.display = 'none'\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\t// If there are fewer new rects than overlays, hide the extras\n\t\t\t\tif (newRects.length < overlays.length) {\n\t\t\t\t\tfor (let i = newRects.length; i < overlays.length; i++) {\n\t\t\t\t\t\toverlays[i].element.style.display = 'none'\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Update label position based on the first new rect\n\t\t\t\tif (label && newRects.length > 0) {\n\t\t\t\t\tconst firstNewRect = newRects[0]\n\t\t\t\t\tconst firstNewRectTop = firstNewRect.top + newIframeOffset.y\n\t\t\t\t\tconst firstNewRectLeft = firstNewRect.left + newIframeOffset.x\n\n\t\t\t\t\tlet newLabelTop = firstNewRectTop + 2\n\t\t\t\t\tlet newLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth - 2\n\n\t\t\t\t\tif (firstNewRect.width < labelWidth + 4 || firstNewRect.height < labelHeight + 4) {\n\t\t\t\t\t\tnewLabelTop = firstNewRectTop - labelHeight - 2\n\t\t\t\t\t\tnewLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth\n\t\t\t\t\t\tif (newLabelLeft < newIframeOffset.x) newLabelLeft = firstNewRectLeft\n\t\t\t\t\t}\n\n\t\t\t\t\t// Ensure label stays within viewport bounds\n\t\t\t\t\tnewLabelTop = Math.max(0, Math.min(newLabelTop, window.innerHeight - labelHeight))\n\t\t\t\t\tnewLabelLeft = Math.max(0, Math.min(newLabelLeft, window.innerWidth - labelWidth))\n\n\t\t\t\t\tlabel.style.top = `${newLabelTop}px`\n\t\t\t\t\tlabel.style.left = `${newLabelLeft}px`\n\t\t\t\t\tlabel.style.display = 'block'\n\t\t\t\t} else if (label) {\n\t\t\t\t\t// Hide label if element has no rects anymore\n\t\t\t\t\tlabel.style.display = 'none'\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst throttleFunction = (func, delay) => {\n\t\t\t\tlet lastCall = 0\n\t\t\t\treturn (...args) => {\n\t\t\t\t\tconst now = performance.now()\n\t\t\t\t\tif (now - lastCall < delay) return\n\t\t\t\t\tlastCall = now\n\t\t\t\t\treturn func(...args)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst throttledUpdatePositions = throttleFunction(updatePositions, 16) // ~60fps\n\t\t\twindow.addEventListener('scroll', throttledUpdatePositions, true)\n\t\t\twindow.addEventListener('resize', throttledUpdatePositions)\n\n\t\t\t// Add cleanup function\n\t\t\tcleanupFn = () => {\n\t\t\t\twindow.removeEventListener('scroll', throttledUpdatePositions, true)\n\t\t\t\twindow.removeEventListener('resize', throttledUpdatePositions)\n\t\t\t\t// Remove overlay elements if needed\n\t\t\t\toverlays.forEach((overlay) => overlay.element.remove())\n\t\t\t\tif (label) label.remove()\n\t\t\t}\n\n\t\t\t// Then add fragment to container in one operation\n\t\t\tcontainer.appendChild(fragment)\n\n\t\t\treturn index + 1\n\t\t} finally {\n\t\t\t// Store cleanup function for later use\n\t\t\tif (cleanupFn) {\n\t\t\t\t// Keep a reference to cleanup functions in a global array\n\t\t\t\t;(window._highlightCleanupFunctions = window._highlightCleanupFunctions || []).push(\n\t\t\t\t\tcleanupFn\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// // Add this function to perform cleanup when needed\n\t// function cleanupHighlights() {\n\t// if (window._highlightCleanupFunctions && window._highlightCleanupFunctions.length) {\n\t// window._highlightCleanupFunctions.forEach(fn => fn());\n\t// window._highlightCleanupFunctions = [];\n\t// }\n\n\t// // Also remove the container\n\t// const container = document.getElementById(HIGHLIGHT_CONTAINER_ID);\n\t// if (container) container.remove();\n\t// }\n\n\t/**\n\t * Gets the position of an element in its parent.\n\t *\n\t * @param {HTMLElement} currentElement - The element to get the position for.\n\t * @returns {number} The position of the element in its parent.\n\t */\n\tfunction getElementPosition(currentElement) {\n\t\tif (!currentElement.parentElement) {\n\t\t\treturn 0 // No parent means no siblings\n\t\t}\n\n\t\tconst tagName = currentElement.nodeName.toLowerCase()\n\n\t\tconst siblings = Array.from(currentElement.parentElement.children).filter(\n\t\t\t(sib) => sib.nodeName.toLowerCase() === tagName\n\t\t)\n\n\t\tif (siblings.length === 1) {\n\t\t\treturn 0 // Only element of its type\n\t\t}\n\n\t\tconst index = siblings.indexOf(currentElement) + 1 // 1-based index\n\t\treturn index\n\t}\n\n\tfunction getXPathTree(element, stopAtBoundary = true) {\n\t\tif (xpathCache.has(element)) return xpathCache.get(element)\n\n\t\tconst segments = []\n\t\tlet currentElement = element\n\n\t\twhile (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) {\n\t\t\t// Stop if we hit a shadow root or iframe\n\t\t\tif (\n\t\t\t\tstopAtBoundary &&\n\t\t\t\t(currentElement.parentNode instanceof ShadowRoot ||\n\t\t\t\t\tcurrentElement.parentNode instanceof HTMLIFrameElement)\n\t\t\t) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst position = getElementPosition(currentElement)\n\t\t\tconst tagName = currentElement.nodeName.toLowerCase()\n\t\t\tconst xpathIndex = position > 0 ? `[${position}]` : ''\n\t\t\tsegments.unshift(`${tagName}${xpathIndex}`)\n\n\t\t\tcurrentElement = currentElement.parentNode\n\t\t}\n\n\t\tconst result = segments.join('/')\n\t\txpathCache.set(element, result)\n\t\treturn result\n\t}\n\n\t/**\n\t * @edit scrollable element detection\n\t * Checks if an element is scrollable. if so, return the scrollable distance on each direction (left right top bottom). if not return null.\n\t * @note distance smaller than 4 will be considered as not scrollable.\n\t * @note only check block elements, not inline elements.\n\t */\n\tfunction isScrollableElement(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn null // Not a valid element\n\t\t}\n\n\t\tconst style = getCachedComputedStyle(element)\n\t\tif (!style) return null\n\n\t\t// Check if the element is a block-level element\n\t\tconst display = style.display\n\t\tif (display === 'inline' || display === 'inline-block') {\n\t\t\treturn null // Not a block-level element\n\t\t}\n\n\t\t// Check overflow properties\n\t\tconst overflowX = style.overflowX\n\t\tconst overflowY = style.overflowY\n\n\t\t// scrollbar-width/scrollbar-gutter are only set on elements designed to scroll;\n\t\t// their presence signals scroll intent even when overflow is hidden (e.g. overflow: auto on :hover)\n\t\tconst hasScrollbarSignal =\n\t\t\t(style.scrollbarWidth && style.scrollbarWidth !== 'auto') ||\n\t\t\t(style.scrollbarGutter && style.scrollbarGutter !== 'auto')\n\n\t\tconst scrollableX = overflowX === 'auto' || overflowX === 'scroll'\n\t\tconst scrollableY = overflowY === 'auto' || overflowY === 'scroll'\n\n\t\tif (!scrollableX && !scrollableY && !hasScrollbarSignal) {\n\t\t\treturn null // Not scrollable in any direction\n\t\t}\n\n\t\tconst scrollWidth = element.scrollWidth - element.clientWidth\n\t\tconst scrollHeight = element.scrollHeight - element.clientHeight\n\n\t\t// Consider small distances as not scrollable\n\t\tconst threshold = 4\n\n\t\tif (scrollWidth < threshold && scrollHeight < threshold) {\n\t\t\treturn null // Not scrollable\n\t\t}\n\n\t\tif (!scrollableY && !hasScrollbarSignal && scrollWidth < threshold) {\n\t\t\treturn null // Not scrollable horizontally\n\t\t}\n\n\t\tif (!scrollableX && !hasScrollbarSignal && scrollHeight < threshold) {\n\t\t\treturn null // Not scrollable vertically\n\t\t}\n\n\t\tconst distanceToTop = element.scrollTop\n\t\tconst distanceToLeft = element.scrollLeft\n\t\tconst distanceToRight = element.scrollWidth - element.clientWidth - element.scrollLeft\n\t\tconst distanceToBottom = element.scrollHeight - element.clientHeight - element.scrollTop\n\n\t\tconst scrollData = {\n\t\t\ttop: distanceToTop,\n\t\t\tright: distanceToRight,\n\t\t\tbottom: distanceToBottom,\n\t\t\tleft: distanceToLeft,\n\t\t}\n\n\t\t// Store extra data for the element\n\t\taddExtraData(element, {\n\t\t\tscrollable: true,\n\t\t\tscrollData: scrollData,\n\t\t})\n\n\t\tconsole.log('scrollData!!!', scrollData)\n\n\t\treturn scrollData\n\t}\n\n\t/**\n\t * Checks if a text node is visible.\n\t *\n\t * @param {Text} textNode - The text node to check.\n\t * @returns {boolean} Whether the text node is visible.\n\t */\n\tfunction isTextNodeVisible(textNode) {\n\t\ttry {\n\t\t\t// Special case: when viewportExpansion is -1, consider all text nodes as visible\n\t\t\tif (viewportExpansion === -1) {\n\t\t\t\t// Still check parent visibility for basic filtering\n\t\t\t\tconst parentElement = textNode.parentElement\n\t\t\t\tif (!parentElement) return false\n\n\t\t\t\ttry {\n\t\t\t\t\treturn parentElement.checkVisibility({\n\t\t\t\t\t\tcheckOpacity: true,\n\t\t\t\t\t\tcheckVisibilityCSS: true,\n\t\t\t\t\t})\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Fallback if checkVisibility is not supported\n\t\t\t\t\tconst style = window.getComputedStyle(parentElement)\n\t\t\t\t\treturn style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(textNode)\n\t\t\tconst rects = range.getClientRects() // Use getClientRects for Range\n\n\t\t\tif (!rects || rects.length === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tlet isAnyRectVisible = false\n\t\t\tlet isAnyRectInViewport = false\n\n\t\t\tfor (const rect of rects) {\n\t\t\t\t// Check size\n\t\t\t\tif (rect.width > 0 && rect.height > 0) {\n\t\t\t\t\tisAnyRectVisible = true\n\n\t\t\t\t\t// Viewport check for this rect\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tisAnyRectInViewport = true\n\t\t\t\t\t\tbreak // Found a visible rect in viewport, no need to check others\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!isAnyRectVisible || !isAnyRectInViewport) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check parent visibility\n\t\t\tconst parentElement = textNode.parentElement\n\t\t\tif (!parentElement) return false\n\n\t\t\ttry {\n\t\t\t\treturn parentElement.checkVisibility({\n\t\t\t\t\tcheckOpacity: true,\n\t\t\t\t\tcheckVisibilityCSS: true,\n\t\t\t\t})\n\t\t\t} catch (e) {\n\t\t\t\t// Fallback if checkVisibility is not supported\n\t\t\t\tconst style = window.getComputedStyle(parentElement)\n\t\t\t\treturn style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn('Error checking text node visibility:', e)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Checks if an element is accepted.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is accepted.\n\t */\n\tfunction isElementAccepted(element) {\n\t\tif (!element || !element.tagName) return false\n\n\t\t// Always accept body and common container elements\n\t\tconst alwaysAccept = new Set([\n\t\t\t'body',\n\t\t\t'div',\n\t\t\t'main',\n\t\t\t'article',\n\t\t\t'section',\n\t\t\t'nav',\n\t\t\t'header',\n\t\t\t'footer',\n\t\t])\n\t\tconst tagName = element.tagName.toLowerCase()\n\n\t\tif (alwaysAccept.has(tagName)) return true\n\n\t\tconst leafElementDenyList = new Set([\n\t\t\t'svg',\n\t\t\t'script',\n\t\t\t'style',\n\t\t\t'link',\n\t\t\t'meta',\n\t\t\t'noscript',\n\t\t\t'template',\n\t\t])\n\n\t\treturn !leafElementDenyList.has(tagName)\n\t}\n\n\t/**\n\t * Checks if an element is visible.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is visible.\n\t */\n\tfunction isElementVisible(element) {\n\t\tconst style = getCachedComputedStyle(element)\n\t\treturn (\n\t\t\telement.offsetWidth > 0 &&\n\t\t\telement.offsetHeight > 0 &&\n\t\t\tstyle?.visibility !== 'hidden' &&\n\t\t\tstyle?.display !== 'none'\n\t\t)\n\t}\n\n\t/**\n\t * Checks if an element is interactive.\n\t *\n\t * lots of comments, and uncommented code - to show the logic of what we already tried\n\t *\n\t * One of the things we tried at the beginning was also to use event listeners, and other fancy class, style stuff -> what actually worked best was just combining most things with computed cursor style :)\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t */\n\tfunction isInteractiveElement(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn false\n\t\t}\n\n\t\t/**\n\t\t * @edit add interactiveBlacklist interactiveWhitelist\n\t\t */\n\t\tif (interactiveBlacklist.includes(element)) {\n\t\t\treturn false // Skip blacklisted elements\n\t\t}\n\t\tif (interactiveWhitelist.includes(element)) {\n\t\t\treturn true // Skip whitelisted elements\n\t\t}\n\n\t\t// Cache the tagName and style lookups\n\t\tconst tagName = element.tagName.toLowerCase()\n\t\tconst style = getCachedComputedStyle(element)\n\n\t\t// Define interactive cursors\n\t\tconst interactiveCursors = new Set([\n\t\t\t'pointer', // Link/clickable elements\n\t\t\t'move', // Movable elements\n\t\t\t'text', // Text selection\n\t\t\t'grab', // Grabbable elements\n\t\t\t'grabbing', // Currently grabbing\n\t\t\t'cell', // Table cell selection\n\t\t\t'copy', // Copy operation\n\t\t\t'alias', // Alias creation\n\t\t\t'all-scroll', // Scrollable content\n\t\t\t'col-resize', // Column resize\n\t\t\t'context-menu', // Context menu available\n\t\t\t'crosshair', // Precise selection\n\t\t\t'e-resize', // East resize\n\t\t\t'ew-resize', // East-west resize\n\t\t\t'help', // Help available\n\t\t\t'n-resize', // North resize\n\t\t\t'ne-resize', // Northeast resize\n\t\t\t'nesw-resize', // Northeast-southwest resize\n\t\t\t'ns-resize', // North-south resize\n\t\t\t'nw-resize', // Northwest resize\n\t\t\t'nwse-resize', // Northwest-southeast resize\n\t\t\t'row-resize', // Row resize\n\t\t\t's-resize', // South resize\n\t\t\t'se-resize', // Southeast resize\n\t\t\t'sw-resize', // Southwest resize\n\t\t\t'vertical-text', // Vertical text selection\n\t\t\t'w-resize', // West resize\n\t\t\t'zoom-in', // Zoom in\n\t\t\t'zoom-out', // Zoom out\n\t\t])\n\n\t\t// Define non-interactive cursors\n\t\tconst nonInteractiveCursors = new Set([\n\t\t\t'not-allowed', // Action not allowed\n\t\t\t'no-drop', // Drop not allowed\n\t\t\t'wait', // Processing\n\t\t\t'progress', // In progress\n\t\t\t'initial', // Initial value\n\t\t\t'inherit', // Inherited value\n\t\t\t//? Let's just include all potentially clickable elements that are not specifically blocked\n\t\t\t// 'none', // No cursor\n\t\t\t// 'default', // Default cursor\n\t\t\t// 'auto', // Browser default\n\t\t])\n\n\t\t/**\n\t\t * Checks if an element has an interactive pointer.\n\t\t *\n\t\t * @param {HTMLElement} element - The element to check.\n\t\t * @returns {boolean} Whether the element has an interactive pointer.\n\t\t */\n\t\tfunction doesElementHaveInteractivePointer(element) {\n\t\t\tif (element.tagName.toLowerCase() === 'html') return false\n\n\t\t\tif (style?.cursor && interactiveCursors.has(style.cursor)) return true\n\n\t\t\treturn false\n\t\t}\n\n\t\tlet isInteractiveCursor = doesElementHaveInteractivePointer(element)\n\n\t\t// Genius fix for almost all interactive elements\n\t\tif (isInteractiveCursor) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst interactiveElements = new Set([\n\t\t\t'a', // Links\n\t\t\t'button', // Buttons\n\t\t\t'input', // All input types (text, checkbox, radio, etc.)\n\t\t\t'select', // Dropdown menus\n\t\t\t'textarea', // Text areas\n\t\t\t'details', // Expandable details\n\t\t\t'summary', // Summary element (clickable part of details)\n\t\t\t'label', // Form labels (often clickable)\n\t\t\t'option', // Select options\n\t\t\t'optgroup', // Option groups\n\t\t\t'fieldset', // Form fieldsets (can be interactive with legend)\n\t\t\t'legend', // Fieldset legends\n\t\t])\n\n\t\t// Define explicit disable attributes and properties\n\t\tconst explicitDisableTags = new Set([\n\t\t\t'disabled', // Standard disabled attribute\n\t\t\t// 'aria-disabled', // ARIA disabled state\n\t\t\t'readonly', // Read-only state\n\t\t\t// 'aria-readonly', // ARIA read-only state\n\t\t\t// 'aria-hidden', // Hidden from accessibility\n\t\t\t// 'hidden', // Hidden attribute\n\t\t\t// 'inert', // Inert attribute\n\t\t\t// 'aria-inert', // ARIA inert state\n\t\t\t// 'tabindex=\"-1\"', // Removed from tab order\n\t\t\t// 'aria-hidden=\"true\"' // Hidden from screen readers\n\t\t])\n\n\t\t// handle inputs, select, checkbox, radio, textarea, button and make sure they are not cursor style disabled/not-allowed\n\t\tif (interactiveElements.has(tagName)) {\n\t\t\t// Check for non-interactive cursor\n\t\t\tif (style?.cursor && nonInteractiveCursors.has(style.cursor)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for explicit disable attributes\n\t\t\tfor (const disableTag of explicitDisableTags) {\n\t\t\t\tif (\n\t\t\t\t\telement.hasAttribute(disableTag) ||\n\t\t\t\t\telement.getAttribute(disableTag) === 'true' ||\n\t\t\t\t\telement.getAttribute(disableTag) === ''\n\t\t\t\t) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for disabled property on form elements\n\t\t\tif (element.disabled) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for readonly property on form elements\n\t\t\tif (element.readOnly) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for inert property\n\t\t\tif (element.inert) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tconst role = element.getAttribute('role')\n\t\tconst ariaRole = element.getAttribute('aria-role')\n\n\t\t// Check for contenteditable attribute\n\t\tif (element.getAttribute('contenteditable') === 'true' || element.isContentEditable) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Added enhancement to capture dropdown interactive elements\n\t\tif (\n\t\t\telement.classList &&\n\t\t\t(element.classList.contains('button') ||\n\t\t\t\telement.classList.contains('dropdown-toggle') ||\n\t\t\t\telement.getAttribute('data-index') ||\n\t\t\t\telement.getAttribute('data-toggle') === 'dropdown' ||\n\t\t\t\telement.getAttribute('aria-haspopup') === 'true')\n\t\t) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst interactiveRoles = new Set([\n\t\t\t'button', // Directly clickable element\n\t\t\t// 'link', // Clickable link\n\t\t\t'menu', // Menu container (ARIA menus)\n\t\t\t'menubar', // Menu bar container\n\t\t\t'menuitem', // Clickable menu item\n\t\t\t'menuitemradio', // Radio-style menu item (selectable)\n\t\t\t'menuitemcheckbox', // Checkbox-style menu item (toggleable)\n\t\t\t'radio', // Radio button (selectable)\n\t\t\t'checkbox', // Checkbox (toggleable)\n\t\t\t'tab', // Tab (clickable to switch content)\n\t\t\t'switch', // Toggle switch (clickable to change state)\n\t\t\t'slider', // Slider control (draggable)\n\t\t\t'spinbutton', // Number input with up/down controls\n\t\t\t'combobox', // Dropdown with text input\n\t\t\t'searchbox', // Search input field\n\t\t\t'textbox', // Text input field\n\t\t\t'listbox', // Selectable list\n\t\t\t'option', // Selectable option in a list\n\t\t\t'scrollbar', // Scrollable control\n\t\t])\n\n\t\t// Basic role/attribute checks\n\t\tconst hasInteractiveRole =\n\t\t\tinteractiveElements.has(tagName) ||\n\t\t\t(role && interactiveRoles.has(role)) ||\n\t\t\t(ariaRole && interactiveRoles.has(ariaRole))\n\n\t\tif (hasInteractiveRole) return true\n\n\t\t// check whether element has event listeners by window.getEventListeners\n\t\ttry {\n\t\t\tif (typeof getEventListeners === 'function') {\n\t\t\t\tconst listeners = getEventListeners(element)\n\t\t\t\tconst mouseEvents = ['click', 'mousedown', 'mouseup', 'dblclick']\n\t\t\t\tfor (const eventType of mouseEvents) {\n\t\t\t\t\tif (listeners[eventType] && listeners[eventType].length > 0) {\n\t\t\t\t\t\treturn true // Found a mouse interaction listener\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst getEventListenersForNode =\n\t\t\t\telement?.ownerDocument?.defaultView?.getEventListenersForNode ||\n\t\t\t\twindow.getEventListenersForNode\n\t\t\tif (typeof getEventListenersForNode === 'function') {\n\t\t\t\tconst listeners = getEventListenersForNode(element)\n\t\t\t\tconst interactionEvents = [\n\t\t\t\t\t'click',\n\t\t\t\t\t'mousedown',\n\t\t\t\t\t'mouseup',\n\t\t\t\t\t'keydown',\n\t\t\t\t\t'keyup',\n\t\t\t\t\t'submit',\n\t\t\t\t\t'change',\n\t\t\t\t\t'input',\n\t\t\t\t\t'focus',\n\t\t\t\t\t'blur',\n\t\t\t\t]\n\t\t\t\tfor (const eventType of interactionEvents) {\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\tif (listener.type === eventType) {\n\t\t\t\t\t\t\treturn true // Found a common interaction listener\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: Check common event attributes if getEventListeners is not available (getEventListeners doesn't work in page.evaluate context)\n\t\t\tconst commonMouseAttrs = ['onclick', 'onmousedown', 'onmouseup', 'ondblclick']\n\t\t\tfor (const attr of commonMouseAttrs) {\n\t\t\t\tif (element.hasAttribute(attr) || typeof element[attr] === 'function') {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// console.warn(`Could not check event listeners for ${element.tagName}:`, e);\n\t\t\t// If checking listeners fails, rely on other checks\n\t\t}\n\n\t\t/**\n\t\t * @edit scrollable element detection\n\t\t */\n\t\tif (isScrollableElement(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\t/**\n\t * Checks if an element is the topmost element at its position.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is the topmost element at its position.\n\t */\n\tfunction isTopElement(element) {\n\t\t// Special case: when viewportExpansion is -1, consider all elements as \"top\" elements\n\t\tif (viewportExpansion === -1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst rects = getCachedClientRects(element) // Replace element.getClientRects()\n\n\t\tif (!rects || rects.length === 0) {\n\t\t\treturn false // No geometry, cannot be top\n\t\t}\n\n\t\tlet isAnyRectInViewport = false\n\t\tfor (const rect of rects) {\n\t\t\t// Use the same logic as isInExpandedViewport check\n\t\t\tif (\n\t\t\t\trect.width > 0 &&\n\t\t\t\trect.height > 0 &&\n\t\t\t\t!(\n\t\t\t\t\t// Only check non-empty rects\n\t\t\t\t\t(\n\t\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tisAnyRectInViewport = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (!isAnyRectInViewport) {\n\t\t\treturn false // All rects are outside the viewport area\n\t\t}\n\n\t\t// Find the correct document context and root element\n\t\tlet doc = element.ownerDocument\n\n\t\t// If we're in an iframe, elements are considered top by default\n\t\tif (doc !== window.document) {\n\t\t\treturn true\n\t\t}\n\n\t\t/**\n\t\t * @edit improve `sampleRect`, filter out rects with 0 area\n\t\t */\n\t\t// find a rect that has width and height as sample\n\t\tlet rect = Array.from(rects).find((r) => r.width > 0 && r.height > 0)\n\t\tif (!rect) {\n\t\t\treturn false // No valid rect found\n\t\t}\n\n\t\t// For shadow DOM, we need to check within its own root context\n\t\tconst shadowRoot = element.getRootNode()\n\t\tif (shadowRoot instanceof ShadowRoot) {\n\t\t\tconst centerX = rect.left + rect.width / 2\n\t\t\tconst centerY = rect.top + rect.height / 2\n\n\t\t\ttry {\n\t\t\t\tconst topEl = shadowRoot.elementFromPoint(centerX, centerY)\n\t\t\t\tif (!topEl) return false\n\n\t\t\t\tlet current = topEl\n\t\t\t\twhile (current && current !== shadowRoot) {\n\t\t\t\t\tif (current === element) return true\n\t\t\t\t\tcurrent = current.parentElement\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} catch (e) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tconst margin = 5\n\n\t\t// For elements in viewport, check if they're topmost. Do the check in the\n\t\t// center of the element and at the corners to ensure we catch more cases.\n\t\tconst checkPoints = [\n\t\t\t// Initially only this was used, but it was not enough\n\t\t\t{ x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 },\n\t\t\t{ x: rect.left + margin, y: rect.top + margin }, // top left\n\t\t\t// { x: rect.right - margin, y: rect.top + margin }, // top right\n\t\t\t// { x: rect.left + margin, y: rect.bottom - margin }, // bottom left\n\t\t\t{ x: rect.right - margin, y: rect.bottom - margin }, // bottom right\n\t\t]\n\n\t\treturn checkPoints.some(({ x, y }) => {\n\t\t\ttry {\n\t\t\t\tconst topEl = document.elementFromPoint(x, y)\n\t\t\t\tif (!topEl) return false\n\n\t\t\t\tlet current = topEl\n\t\t\t\twhile (current && current !== document.documentElement) {\n\t\t\t\t\tif (current === element) return true\n\t\t\t\t\tcurrent = current.parentElement\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} catch (e) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Checks if an element is within the expanded viewport.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @param {number} viewportExpansion - The viewport expansion.\n\t * @returns {boolean} Whether the element is within the expanded viewport.\n\t */\n\tfunction isInExpandedViewport(element, viewportExpansion) {\n\t\tif (viewportExpansion === -1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst rects = element.getClientRects() // Use getClientRects\n\n\t\tif (!rects || rects.length === 0) {\n\t\t\t// Fallback to getBoundingClientRect if getClientRects is empty,\n\t\t\t// useful for elements like <svg> that might not have client rects but have a bounding box.\n\t\t\tconst boundingRect = getCachedBoundingRect(element)\n\t\t\tif (!boundingRect || boundingRect.width === 0 || boundingRect.height === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !(\n\t\t\t\tboundingRect.bottom < -viewportExpansion ||\n\t\t\t\tboundingRect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\tboundingRect.right < -viewportExpansion ||\n\t\t\t\tboundingRect.left > window.innerWidth + viewportExpansion\n\t\t\t)\n\t\t}\n\n\t\t// Check if *any* client rect is within the viewport\n\t\tfor (const rect of rects) {\n\t\t\tif (rect.width === 0 || rect.height === 0) continue // Skip empty rects\n\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true // Found at least one rect in the viewport\n\t\t\t}\n\t\t}\n\n\t\treturn false // No rects were found in the viewport\n\t}\n\n\t// /**\n\t// * Gets the effective scroll of an element.\n\t// *\n\t// * @param {HTMLElement} element - The element to get the effective scroll for.\n\t// * @returns {Object} The effective scroll of the element.\n\t// */\n\t// function getEffectiveScroll(element) {\n\t// let currentEl = element;\n\t// let scrollX = 0;\n\t// let scrollY = 0;\n\n\t// while (currentEl && currentEl !== document.documentElement) {\n\t// if (currentEl.scrollLeft || currentEl.scrollTop) {\n\t// scrollX += currentEl.scrollLeft;\n\t// scrollY += currentEl.scrollTop;\n\t// }\n\t// currentEl = currentEl.parentElement;\n\t// }\n\n\t// scrollX += window.scrollX;\n\t// scrollY += window.scrollY;\n\n\t// return { scrollX, scrollY };\n\t// }\n\n\t/**\n\t * Checks if an element is an interactive candidate.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is an interactive candidate.\n\t */\n\n\t// @edit fix \"aria-*\" attributes check\n\tconst INTERACTIVE_ARIA_ATTRS = [\n\t\t'aria-expanded',\n\t\t'aria-checked',\n\t\t'aria-selected',\n\t\t'aria-pressed',\n\t\t'aria-haspopup',\n\t\t'aria-controls',\n\t\t'aria-owns',\n\t\t'aria-activedescendant',\n\t\t'aria-valuenow',\n\t\t'aria-valuetext',\n\t\t'aria-valuemax',\n\t\t'aria-valuemin',\n\t\t'aria-autocomplete',\n\t]\n\n\tfunction hasInteractiveAria(el) {\n\t\tfor (let i = 0; i < INTERACTIVE_ARIA_ATTRS.length; i++) {\n\t\t\tif (el.hasAttribute(INTERACTIVE_ARIA_ATTRS[i])) return true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunction isInteractiveCandidate(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return false\n\n\t\tconst tagName = element.tagName.toLowerCase()\n\n\t\t// Fast-path for common interactive elements\n\t\tconst interactiveElements = new Set([\n\t\t\t'a',\n\t\t\t'button',\n\t\t\t'input',\n\t\t\t'select',\n\t\t\t'textarea',\n\t\t\t'details',\n\t\t\t'summary',\n\t\t\t'label',\n\t\t])\n\n\t\tif (interactiveElements.has(tagName)) return true\n\n\t\t// Quick attribute checks without getting full lists\n\t\tconst hasQuickInteractiveAttr =\n\t\t\telement.hasAttribute('onclick') ||\n\t\t\telement.hasAttribute('role') ||\n\t\t\telement.hasAttribute('tabindex') ||\n\t\t\thasInteractiveAria(element) ||\n\t\t\telement.hasAttribute('data-action') ||\n\t\t\telement.getAttribute('contenteditable') === 'true'\n\n\t\treturn hasQuickInteractiveAttr\n\t}\n\n\t// --- Define constants for distinct interaction check ---\n\tconst DISTINCT_INTERACTIVE_TAGS = new Set([\n\t\t'a',\n\t\t'button',\n\t\t'input',\n\t\t'select',\n\t\t'textarea',\n\t\t'summary',\n\t\t'details',\n\t\t'label',\n\t\t'option',\n\t\t'li',\n\t])\n\tconst DISTINCT_INTERACTIVE_ROLES = new Set([\n\t\t'button',\n\t\t'link',\n\t\t'menuitem',\n\t\t'menuitemradio',\n\t\t'menuitemcheckbox',\n\t\t'radio',\n\t\t'checkbox',\n\t\t'tab',\n\t\t'switch',\n\t\t'slider',\n\t\t'spinbutton',\n\t\t'combobox',\n\t\t'searchbox',\n\t\t'textbox',\n\t\t'listbox',\n\t\t'listitem',\n\t\t'treeitem',\n\t\t'row',\n\t\t'option',\n\t\t'scrollbar',\n\t])\n\n\t/**\n\t * Heuristically determines if an element should be considered as independently interactive,\n\t * even if it's nested inside another interactive container.\n\t *\n\t * This function helps detect deeply nested actionable elements (e.g., menu items within a button)\n\t * that may not be picked up by strict interactivity checks.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is heuristically interactive.\n\t */\n\tfunction isHeuristicallyInteractive(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return false\n\n\t\t// Skip non-visible elements early for performance\n\t\tif (!isElementVisible(element)) return false\n\n\t\t// Check for common attributes that often indicate interactivity\n\t\tconst hasInteractiveAttributes =\n\t\t\telement.hasAttribute('role') ||\n\t\t\telement.hasAttribute('tabindex') ||\n\t\t\telement.hasAttribute('onclick') ||\n\t\t\ttypeof element.onclick === 'function'\n\n\t\t// Check for semantic class names suggesting interactivity\n\t\tconst hasInteractiveClass = /\\b(btn|clickable|menu|item|entry|link)\\b/i.test(\n\t\t\telement.className || ''\n\t\t)\n\n\t\t// Determine whether the element is inside a known interactive container\n\t\tconst isInKnownContainer = Boolean(\n\t\t\telement.closest('button,a,[role=\"button\"],.menu,.dropdown,.list,.toolbar')\n\t\t)\n\n\t\t// Ensure the element has at least one visible child (to avoid marking empty wrappers)\n\t\tconst hasVisibleChildren = [...element.children].some(isElementVisible)\n\n\t\t// Avoid highlighting elements whose parent is <body> (top-level wrappers)\n\t\tconst isParentBody = element.parentElement && element.parentElement.isSameNode(document.body)\n\n\t\treturn (\n\t\t\t(isInteractiveElement(element) || hasInteractiveAttributes || hasInteractiveClass) &&\n\t\t\thasVisibleChildren &&\n\t\t\tisInKnownContainer &&\n\t\t\t!isParentBody\n\t\t)\n\t}\n\n\t/**\n\t * Checks if an element likely represents a distinct interaction\n\t * separate from its parent (if the parent is also interactive).\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is a distinct interaction.\n\t */\n\tfunction isElementDistinctInteraction(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst tagName = element.tagName.toLowerCase()\n\t\tconst role = element.getAttribute('role')\n\n\t\t// Check if it's an iframe - always distinct boundary\n\t\tif (tagName === 'iframe') {\n\t\t\treturn true\n\t\t}\n\n\t\t// Check tag name\n\t\tif (DISTINCT_INTERACTIVE_TAGS.has(tagName)) {\n\t\t\treturn true\n\t\t}\n\t\t// Check interactive roles\n\t\tif (role && DISTINCT_INTERACTIVE_ROLES.has(role)) {\n\t\t\treturn true\n\t\t}\n\t\t// Check contenteditable\n\t\tif (element.isContentEditable || element.getAttribute('contenteditable') === 'true') {\n\t\t\treturn true\n\t\t}\n\t\t// Check for common testing/automation attributes\n\t\tif (\n\t\t\telement.hasAttribute('data-testid') ||\n\t\t\telement.hasAttribute('data-cy') ||\n\t\t\telement.hasAttribute('data-test')\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t\t// Check for explicit onclick handler (attribute or property)\n\t\tif (element.hasAttribute('onclick') || typeof element.onclick === 'function') {\n\t\t\treturn true\n\t\t}\n\t\t// ARIA state attributes imply the element manages its own interaction state\n\t\tif (hasInteractiveAria(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// return false\n\n\t\t// Check for other common interaction event listeners\n\t\ttry {\n\t\t\tconst getEventListenersForNode =\n\t\t\t\telement?.ownerDocument?.defaultView?.getEventListenersForNode ||\n\t\t\t\twindow.getEventListenersForNode\n\t\t\tif (typeof getEventListenersForNode === 'function') {\n\t\t\t\tconst listeners = getEventListenersForNode(element)\n\t\t\t\tconst interactionEvents = [\n\t\t\t\t\t'click',\n\t\t\t\t\t'mousedown',\n\t\t\t\t\t'mouseup',\n\t\t\t\t\t'keydown',\n\t\t\t\t\t'keyup',\n\t\t\t\t\t'submit',\n\t\t\t\t\t'change',\n\t\t\t\t\t'input',\n\t\t\t\t\t'focus',\n\t\t\t\t\t'blur',\n\t\t\t\t]\n\t\t\t\tfor (const eventType of interactionEvents) {\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\tif (listener.type === eventType) {\n\t\t\t\t\t\t\treturn true // Found a common interaction listener\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: Check common event attributes if getEventListeners is not available (getEventListenersForNode doesn't work in page.evaluate context)\n\t\t\tconst commonEventAttrs = [\n\t\t\t\t'onmousedown',\n\t\t\t\t'onmouseup',\n\t\t\t\t'onkeydown',\n\t\t\t\t'onkeyup',\n\t\t\t\t'onsubmit',\n\t\t\t\t'onchange',\n\t\t\t\t'oninput',\n\t\t\t\t'onfocus',\n\t\t\t\t'onblur',\n\t\t\t]\n\t\t\tif (commonEventAttrs.some((attr) => element.hasAttribute(attr))) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// console.warn(`Could not check event listeners for ${element.tagName}:`, e);\n\t\t\t// If checking listeners fails, rely on other checks\n\t\t}\n\n\t\t// if the element is not strictly interactive but appears clickable based on heuristic signals\n\t\tif (isHeuristicallyInteractive(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Scrollable containers are always distinct — the LLM needs their index for targeted scrolling.\n\t\t// Check extraData (already set by isScrollableElement in isInteractiveElement) to avoid redundant layout reads.\n\t\tif (extraData.get(element)?.scrollable) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Default to false: if it's interactive but doesn't match above,\n\t\t// assume it triggers the same action as the parent.\n\t\treturn false\n\t}\n\t// --- End distinct interaction check ---\n\n\t/**\n * Handles the logic for deciding whether to highlight an element and performing the highlight.\n * @param {\n {\n tagName: string;\n attributes: Record<string, string>;\n xpath: any;\n children: never[];\n isVisible?: boolean;\n isTopElement?: boolean;\n isInteractive?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n }} nodeData - The node data object.\n * @param {HTMLElement} node - The node to highlight.\n * @param {HTMLElement | null} parentIframe - The parent iframe node.\n * @param {boolean} isParentHighlighted - Whether the parent node is highlighted.\n * @returns {boolean} Whether the element was highlighted.\n */\n\tfunction handleHighlighting(nodeData, node, parentIframe, isParentHighlighted) {\n\t\tif (!nodeData.isInteractive) return false // Not interactive, definitely don't highlight\n\n\t\tlet shouldHighlight = false\n\t\tif (!isParentHighlighted) {\n\t\t\t// Parent wasn't highlighted, this interactive node can be highlighted.\n\t\t\tshouldHighlight = true\n\t\t} else {\n\t\t\t// Parent *was* highlighted. Only highlight this node if it represents a distinct interaction.\n\t\t\tif (isElementDistinctInteraction(node)) {\n\t\t\t\tshouldHighlight = true\n\t\t\t} else {\n\t\t\t\t// console.log(`Skipping highlight for ${nodeData.tagName} (parent highlighted)`);\n\t\t\t\tshouldHighlight = false\n\t\t\t}\n\t\t}\n\n\t\tif (shouldHighlight) {\n\t\t\t// Check viewport status before assigning index and highlighting\n\t\t\tnodeData.isInViewport = isInExpandedViewport(node, viewportExpansion)\n\n\t\t\t// When viewportExpansion is -1, all interactive elements should get a highlight index\n\t\t\t// regardless of viewport status\n\t\t\tif (nodeData.isInViewport || viewportExpansion === -1) {\n\t\t\t\tnodeData.highlightIndex = highlightIndex++\n\n\t\t\t\tif (doHighlightElements) {\n\t\t\t\t\tif (focusHighlightIndex >= 0) {\n\t\t\t\t\t\tif (focusHighlightIndex === nodeData.highlightIndex) {\n\t\t\t\t\t\t\thighlightElement(node, nodeData.highlightIndex, parentIframe)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\thighlightElement(node, nodeData.highlightIndex, parentIframe)\n\t\t\t\t\t}\n\t\t\t\t\treturn true // Successfully highlighted\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// console.log(`Skipping highlight for ${nodeData.tagName} (outside viewport)`);\n\t\t\t}\n\t\t}\n\n\t\treturn false // Did not highlight\n\t}\n\n\t/**\n\t * Creates a node data object for a given node and its descendants.\n\t *\n\t * @param {HTMLElement} node - The node to process.\n\t * @param {HTMLElement | null} parentIframe - The parent iframe node.\n\t * @param {boolean} isParentHighlighted - Whether the parent node is highlighted.\n\t * @returns {string | null} The ID of the node data object, or null if the node is not processed.\n\t */\n\tfunction buildDomTree(node, parentIframe = null, isParentHighlighted = false) {\n\t\t// Fast rejection checks first\n\t\tif (\n\t\t\t!node ||\n\t\t\tnode.id === HIGHLIGHT_CONTAINER_ID ||\n\t\t\t(node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE)\n\t\t) {\n\t\t\treturn null\n\t\t}\n\n\t\tif (!node || node.id === HIGHLIGHT_CONTAINER_ID) {\n\t\t\treturn null\n\t\t}\n\n\t\t/**\n\t\t * @edit add `data-browser-use-ignore` attribute\n\t\t */\n\t\tif (node.dataset?.browserUseIgnore === 'true' || node.dataset?.pageAgentIgnore === 'true') {\n\t\t\treturn null // Skip this node and its children\n\t\t}\n\n\t\t/**\n\t\t * @edit exclude aria-hidden elements\n\t\t */\n\t\tif (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {\n\t\t\treturn null // Skip this node and its children\n\t\t}\n\n\t\t// Special handling for root node (body)\n\t\tif (node === document.body) {\n\t\t\tconst nodeData = {\n\t\t\t\ttagName: 'body',\n\t\t\t\tattributes: {},\n\t\t\t\txpath: '/body',\n\t\t\t\tchildren: [],\n\t\t\t}\n\n\t\t\t// Process children of body\n\t\t\tfor (const child of node.childNodes) {\n\t\t\t\tconst domElement = buildDomTree(child, parentIframe, false) // Body's children have no highlighted parent initially\n\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t}\n\n\t\t\tconst id = `${ID.current++}`\n\t\t\tDOM_HASH_MAP[id] = nodeData\n\t\t\treturn id\n\t\t}\n\n\t\t// Early bailout for non-element nodes except text\n\t\tif (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Process text nodes\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst textContent = node.textContent?.trim()\n\t\t\tif (!textContent) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\t// Only check visibility for text nodes that might be visible\n\t\t\tconst parentElement = node.parentElement\n\t\t\tif (!parentElement || parentElement.tagName.toLowerCase() === 'script') {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst id = `${ID.current++}`\n\t\t\tDOM_HASH_MAP[id] = {\n\t\t\t\ttype: 'TEXT_NODE',\n\t\t\t\ttext: textContent,\n\t\t\t\tisVisible: isTextNodeVisible(node),\n\t\t\t}\n\t\t\treturn id\n\t\t}\n\n\t\t// Quick checks for element nodes\n\t\tif (node.nodeType === Node.ELEMENT_NODE && !isElementAccepted(node)) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Early viewport check - only filter out elements clearly outside viewport\n\t\t// The getBoundingClientRect() of the Shadow DOM host element may return width/height = 0\n\t\tif (viewportExpansion !== -1 && !node.shadowRoot) {\n\t\t\tconst rect = getCachedBoundingRect(node) // Keep for initial quick check\n\t\t\tconst style = getCachedComputedStyle(node)\n\n\t\t\t// Skip viewport check for fixed/sticky elements as they may appear anywhere\n\t\t\tconst isFixedOrSticky = style && (style.position === 'fixed' || style.position === 'sticky')\n\n\t\t\t// Check if element has actual dimensions using offsetWidth/Height (quick check)\n\t\t\tconst hasSize = node.offsetWidth > 0 || node.offsetHeight > 0\n\n\t\t\t// Use getBoundingClientRect for the quick OUTSIDE check.\n\t\t\t// isInExpandedViewport will do the more accurate check later if needed.\n\t\t\tif (\n\t\t\t\t!rect ||\n\t\t\t\t(!isFixedOrSticky &&\n\t\t\t\t\t!hasSize &&\n\t\t\t\t\t(rect.bottom < -viewportExpansion ||\n\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion))\n\t\t\t) {\n\t\t\t\t// console.log(\"Skipping node outside viewport (quick check):\", node.tagName, rect);\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\n\t\t/**\n * @type {\n {\n tagName: string;\n attributes: Record<string, string | null>;\n xpath: any;\n children: never[];\n isVisible?: boolean;\n isTopElement?: boolean;\n isInteractive?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n }\n } nodeData - The node data object.\n */\n\t\tconst nodeData = {\n\t\t\ttagName: node.tagName.toLowerCase(),\n\t\t\tattributes: {},\n\n\t\t\t/**\n\t\t\t * @edit no need for xpath\n\t\t\t */\n\t\t\t// xpath: getXPathTree(node, true),\n\n\t\t\tchildren: [],\n\t\t}\n\n\t\t// Get attributes for interactive elements or potential text containers\n\t\tif (\n\t\t\tisInteractiveCandidate(node) ||\n\t\t\tnode.tagName.toLowerCase() === 'iframe' ||\n\t\t\tnode.tagName.toLowerCase() === 'body'\n\t\t) {\n\t\t\tconst attributeNames = node.getAttributeNames?.() || []\n\t\t\tfor (const name of attributeNames) {\n\t\t\t\tconst value = node.getAttribute(name)\n\t\t\t\tnodeData.attributes[name] = value\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * @edit @workaround input.checked\n\t\t\t */\n\t\t\tif (\n\t\t\t\tnode.tagName.toLowerCase() === 'input' &&\n\t\t\t\t(node.type === 'checkbox' || node.type === 'radio')\n\t\t\t) {\n\t\t\t\tnodeData.attributes.checked = node.checked ? 'true' : 'false' // Store as string for consistency\n\t\t\t}\n\t\t}\n\n\t\tlet nodeWasHighlighted = false\n\t\t// Perform visibility, interactivity, and highlighting checks\n\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\tnodeData.isVisible = isElementVisible(node) // isElementVisible uses offsetWidth/Height, which is fine\n\t\t\tif (nodeData.isVisible) {\n\t\t\t\tnodeData.isTopElement = isTopElement(node)\n\n\t\t\t\t// Special handling for ARIA menu containers - check interactivity even if not top element\n\t\t\t\tconst role = node.getAttribute('role')\n\t\t\t\tconst isMenuContainer = role === 'menu' || role === 'menubar' || role === 'listbox'\n\n\t\t\t\tif (nodeData.isTopElement || isMenuContainer) {\n\t\t\t\t\tnodeData.isInteractive = isInteractiveElement(node)\n\t\t\t\t\t// Call the dedicated highlighting function\n\t\t\t\t\tnodeWasHighlighted = handleHighlighting(nodeData, node, parentIframe, isParentHighlighted)\n\n\t\t\t\t\t/**\n\t\t\t\t\t * @edit direct dom ref\n\t\t\t\t\t */\n\t\t\t\t\tnodeData.ref = node\n\n\t\t\t\t\t/**\n\t\t\t\t\t * @edit make sure attributes exist for interactive candidates.\n\t\t\t\t\t * @note if the element failed the isInteractiveCandidate, attributes would be empty.\n\t\t\t\t\t */\n\t\t\t\t\tif (nodeData.isInteractive && Object.keys(nodeData.attributes).length === 0) {\n\t\t\t\t\t\tconst attributeNames = node.getAttributeNames?.() || []\n\t\t\t\t\t\tfor (const name of attributeNames) {\n\t\t\t\t\t\t\tconst value = node.getAttribute(name)\n\t\t\t\t\t\t\tnodeData.attributes[name] = value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Process children, with special handling for iframes and rich text editors\n\t\tif (node.tagName) {\n\t\t\tconst tagName = node.tagName.toLowerCase()\n\n\t\t\t// Handle iframes\n\t\t\tif (tagName === 'iframe') {\n\t\t\t\ttry {\n\t\t\t\t\tconst iframeDoc = node.contentDocument || node.contentWindow?.document\n\t\t\t\t\tif (iframeDoc) {\n\t\t\t\t\t\tfor (const child of iframeDoc.childNodes) {\n\t\t\t\t\t\t\tconst domElement = buildDomTree(child, node, false)\n\t\t\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.warn('Unable to access iframe:', e)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle rich text editors and contenteditable elements\n\t\t\telse if (\n\t\t\t\tnode.isContentEditable ||\n\t\t\t\tnode.getAttribute('contenteditable') === 'true' ||\n\t\t\t\tnode.id === 'tinymce' ||\n\t\t\t\tnode.classList.contains('mce-content-body') ||\n\t\t\t\t(tagName === 'body' && node.getAttribute('data-id')?.startsWith('mce_'))\n\t\t\t) {\n\t\t\t\t// Process all child nodes to capture formatted text\n\t\t\t\tfor (const child of node.childNodes) {\n\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, nodeWasHighlighted)\n\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Handle shadow DOM\n\t\t\t\tif (node.shadowRoot) {\n\t\t\t\t\tnodeData.shadowRoot = true\n\t\t\t\t\tfor (const child of node.shadowRoot.childNodes) {\n\t\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, nodeWasHighlighted)\n\t\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Handle regular elements\n\t\t\t\tfor (const child of node.childNodes) {\n\t\t\t\t\t// Pass the highlighted status of the *current* node to its children\n\t\t\t\t\tconst passHighlightStatusToChild = nodeWasHighlighted || isParentHighlighted\n\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, passHighlightStatusToChild)\n\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Skip empty anchor tags only if they have no dimensions and no children\n\t\tif (nodeData.tagName === 'a' && nodeData.children.length === 0 && !nodeData.attributes.href) {\n\t\t\t// Check if the anchor has actual dimensions\n\t\t\tconst rect = getCachedBoundingRect(node)\n\t\t\tconst hasSize =\n\t\t\t\t(rect && rect.width > 0 && rect.height > 0) || node.offsetWidth > 0 || node.offsetHeight > 0\n\n\t\t\tif (!hasSize) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @edit add `extra` field for extra data\n\t\t */\n\t\tnodeData.extra = extraData.get(node) || null\n\n\t\tconst id = `${ID.current++}`\n\t\tDOM_HASH_MAP[id] = nodeData\n\t\treturn id\n\t}\n\n\tconst rootId = buildDomTree(document.body)\n\n\t// Clear the cache before starting\n\tDOM_CACHE.clearCache()\n\n\treturn { rootId, map: DOM_HASH_MAP }\n}\n","import domTree from './dom_tree/index.js'\nimport {\n\tElementDomNode,\n\tFlatDomTree,\n\tInteractiveElementDomNode,\n\tTextDomNode,\n} from './dom_tree/type'\n\n/**\n * Viewport expansion for DOM tree extraction.\n * -1 means full page (no viewport restriction)\n * 0 means viewport only\n * positive values expand the viewport by that many pixels\n *\n * @note Since isTopElement depends on elementFromPoint,\n * it returns null when out of viewport, this feature has no practical use, only differ between -1 and 0\n */\nconst DEFAULT_VIEWPORT_EXPANSION = -1\n\nexport function resolveViewportExpansion(viewportExpansion?: number): number {\n\treturn viewportExpansion ?? DEFAULT_VIEWPORT_EXPANSION\n}\n\nexport interface DomConfig {\n\tviewportExpansion?: number\n\tinteractiveBlacklist?: (Element | (() => Element))[]\n\tinteractiveWhitelist?: (Element | (() => Element))[]\n\tincludeAttributes?: string[]\n\thighlightOpacity?: number\n\thighlightLabelOpacity?: number\n\n\t/**\n\t * Preserve semantic landmark tags in dehydrated output even if not interactive\n\t * @note maybe confusing for LLM combining with page scrolling, use with caution\n\t **/\n\tkeepSemanticTags?: boolean\n}\n\n// TODO: corresponding roles\nconst SEMANTIC_TAGS = new Set([\n\t'nav',\n\t'menu',\n\t// 'main',\n\t'header',\n\t'footer',\n\t'aside',\n\t// 'article',\n\t// 'form',\n\t'dialog',\n])\n\n/**\n * 用于检测可交互元素是否是新出现的。\n */\nconst newElementsCache = new WeakMap<HTMLElement, string>()\n\nexport function getFlatTree(config: DomConfig): FlatDomTree {\n\tconst viewportExpansion = resolveViewportExpansion(config.viewportExpansion)\n\n\tconst interactiveBlacklist = [] as Element[]\n\tfor (const item of config.interactiveBlacklist || []) {\n\t\tif (typeof item === 'function') {\n\t\t\tinteractiveBlacklist.push(item())\n\t\t} else {\n\t\t\tinteractiveBlacklist.push(item)\n\t\t}\n\t}\n\n\tconst interactiveWhitelist = [] as Element[]\n\tfor (const item of config.interactiveWhitelist || []) {\n\t\tif (typeof item === 'function') {\n\t\t\tinteractiveWhitelist.push(item())\n\t\t} else {\n\t\t\tinteractiveWhitelist.push(item)\n\t\t}\n\t}\n\n\tconst elements = domTree({\n\t\tdoHighlightElements: true,\n\t\tdebugMode: true,\n\t\tfocusHighlightIndex: -1,\n\t\tviewportExpansion,\n\t\tinteractiveBlacklist,\n\t\tinteractiveWhitelist,\n\t\thighlightOpacity: config.highlightOpacity ?? 0.0,\n\t\thighlightLabelOpacity: config.highlightLabelOpacity ?? 0.1,\n\t}) as FlatDomTree\n\n\tconst currentUrl = window.location.href\n\n\t/**\n\t * 标记新出现的元素\n\t * @todo browser-use 使用 hash(位置,属性等信息) 来判断是否同一个元素,\n\t * 能够解决 1. 元素被删除后重新添加 2. 页面卸载 等问题。\n\t * 这里先简单做.\n\t */\n\tfor (const nodeId in elements.map) {\n\t\tconst node = elements.map[nodeId]\n\t\tif (node.isInteractive && node.ref) {\n\t\t\tconst ref = node.ref as HTMLElement\n\t\t\t// @note 这样太严格,元素是可以跨页面存在的\n\t\t\t// if (newElementsCache.get(ref) !== currentUrl) {\n\t\t\tif (!newElementsCache.has(ref)) {\n\t\t\t\tnewElementsCache.set(ref, currentUrl)\n\t\t\t\tnode.isNew = true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn elements\n}\n\nconst globRegexCache = new Map<string, RegExp>()\n\nfunction globToRegex(pattern: string): RegExp {\n\tlet regex = globRegexCache.get(pattern)\n\tif (!regex) {\n\t\tconst escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n\t\tregex = new RegExp(`^${escaped.replace(/\\*/g, '.*')}$`)\n\t\tglobRegexCache.set(pattern, regex)\n\t}\n\treturn regex\n}\n\nfunction matchAttributes(\n\tattrs: Record<string, string>,\n\tpatterns: string[]\n): Record<string, string> {\n\tconst result: Record<string, string> = {}\n\n\tfor (const pattern of patterns) {\n\t\tif (pattern.includes('*')) {\n\t\t\tconst regex = globToRegex(pattern)\n\t\t\tfor (const key of Object.keys(attrs)) {\n\t\t\t\tif (regex.test(key) && attrs[key].trim()) {\n\t\t\t\t\tresult[key] = attrs[key].trim()\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst value = attrs[pattern]\n\t\t\tif (value && value.trim()) {\n\t\t\t\tresult[pattern] = value.trim()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * elementsToString 内部使用的类型\n */\ninterface TreeNode {\n\ttype: 'text' | 'element'\n\tparent: TreeNode | null\n\tchildren: TreeNode[]\n\tisVisible: boolean\n\t// Text node properties\n\ttext?: string\n\t// Element node properties\n\ttagName?: string\n\tattributes?: Record<string, string>\n\tisInteractive?: boolean\n\tisTopElement?: boolean\n\tisNew?: boolean\n\thighlightIndex?: number\n\textra?: Record<string, any>\n}\n\n/**\n * 对应 python 中的 views::clickable_elements_to_string,\n * 将 dom 信息处理成适合 llm 阅读的文本格式\n * @形如\n * ``` text\n * [0]<a aria-label=page-agent.js 首页 />\n * [1]<div >P />\n * [2]<div >page-agent.js\n * UI Agent in your webpage />\n * [3]<a >文档 />\n * [4]<a aria-label=查看源码(在新窗口打开)>源码 />\n * UI Agent in your webpage\n * 用户输入需求,AI 理解页面并自动操作。\n * [5]<a role=button>快速开始 />\n * [6]<a role=button>查看文档 />\n * 无需后端\n * ```\n * 其中可交互元素用序号标出,提示llm可以用序号操作。\n * 缩进代表父子关系。\n * 普通文本则直接列出来。\n *\n * @todo 数据脱敏过滤器\n */\nexport function flatTreeToString(\n\tflatTree: FlatDomTree,\n\tincludeAttributes: string[] = [],\n\tkeepSemanticTags = false\n): string {\n\tconst DEFAULT_INCLUDE_ATTRIBUTES = [\n\t\t'title',\n\t\t'type',\n\t\t'checked',\n\t\t'name',\n\t\t'role',\n\t\t'value',\n\t\t'placeholder',\n\t\t'data-date-format',\n\t\t'alt',\n\t\t'aria-label',\n\t\t'aria-expanded',\n\t\t'data-state',\n\t\t'aria-checked',\n\n\t\t// @edit added for better form handling\n\t\t'id',\n\t\t'for',\n\n\t\t// for jump check\n\t\t'target',\n\n\t\t// absolute position dropdown menu\n\t\t'aria-haspopup',\n\t\t'aria-controls',\n\t\t'aria-owns',\n\n\t\t// content editable\n\t\t'contenteditable',\n\t]\n\n\tconst includeAttrs = [...includeAttributes, ...DEFAULT_INCLUDE_ATTRIBUTES]\n\n\t// Helper function to cap text length\n\tconst capTextLength = (text: string, maxLength: number): string => {\n\t\tif (text.length > maxLength) {\n\t\t\treturn text.substring(0, maxLength) + '...'\n\t\t}\n\t\treturn text\n\t}\n\n\t// Build tree structure from flat map\n\tconst buildTreeNode = (nodeId: string): TreeNode | null => {\n\t\tconst node = flatTree.map[nodeId]\n\t\tif (!node) return null\n\n\t\tif (node.type === 'TEXT_NODE') {\n\t\t\tconst textNode = node as TextDomNode\n\t\t\treturn {\n\t\t\t\ttype: 'text',\n\t\t\t\ttext: textNode.text,\n\t\t\t\tisVisible: textNode.isVisible,\n\t\t\t\tparent: null,\n\t\t\t\tchildren: [],\n\t\t\t}\n\t\t} else {\n\t\t\tconst elementNode = node as ElementDomNode\n\t\t\tconst children: TreeNode[] = []\n\n\t\t\tif (elementNode.children) {\n\t\t\t\tfor (const childId of elementNode.children) {\n\t\t\t\t\tconst child = buildTreeNode(childId)\n\t\t\t\t\tif (child) {\n\t\t\t\t\t\tchild.parent = null // Will be set later\n\t\t\t\t\t\tchildren.push(child)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttype: 'element',\n\t\t\t\ttagName: elementNode.tagName,\n\t\t\t\tattributes: elementNode.attributes ?? {},\n\t\t\t\tisVisible: elementNode.isVisible ?? false,\n\t\t\t\tisInteractive: elementNode.isInteractive ?? false,\n\t\t\t\tisTopElement: elementNode.isTopElement ?? false,\n\t\t\t\tisNew: elementNode.isNew ?? false,\n\t\t\t\thighlightIndex: elementNode.highlightIndex,\n\t\t\t\tparent: null,\n\t\t\t\tchildren,\n\t\t\t\textra: elementNode.extra ?? {},\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set parent references\n\tconst setParentReferences = (node: TreeNode, parent: TreeNode | null = null) => {\n\t\tnode.parent = parent\n\t\tfor (const child of node.children) {\n\t\t\tsetParentReferences(child, node)\n\t\t}\n\t}\n\n\t// Build root node\n\tconst rootNode = buildTreeNode(flatTree.rootId)\n\tif (!rootNode) return ''\n\n\tsetParentReferences(rootNode)\n\n\t// Helper to check if text node has parent with highlight index\n\tconst hasParentWithHighlightIndex = (node: TreeNode): boolean => {\n\t\tlet current = node.parent\n\t\twhile (current) {\n\t\t\tif (current.type === 'element' && current.highlightIndex !== undefined) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tcurrent = current.parent\n\t\t}\n\t\treturn false\n\t}\n\n\t// Helper to check if parent is top element\n\t// const isParentTopElement = (node: TreeNode): boolean => {\n\t// \treturn node.parent?.type === 'element' && node.parent.isTopElement === true\n\t// }\n\n\t// Main processing function\n\tconst processNode = (node: TreeNode, depth: number, result: string[]): void => {\n\t\tlet nextDepth = depth\n\t\tconst depthStr = '\\t'.repeat(depth)\n\n\t\tif (node.type === 'element') {\n\t\t\tconst isSemantic = keepSemanticTags && node.tagName && SEMANTIC_TAGS.has(node.tagName)\n\n\t\t\t// Add element with highlight_index\n\t\t\tif (node.highlightIndex !== undefined) {\n\t\t\t\tnextDepth += 1\n\n\t\t\t\tconst text = getAllTextTillNextClickableElement(node)\n\t\t\t\tlet attributesHtmlStr = ''\n\n\t\t\t\tif (includeAttrs.length > 0 && node.attributes) {\n\t\t\t\t\tconst attributesToInclude = matchAttributes(node.attributes, includeAttrs)\n\n\t\t\t\t\t// Remove duplicate values (for attributes longer than 5 chars)\n\t\t\t\t\tconst keys = Object.keys(attributesToInclude)\n\t\t\t\t\tif (keys.length > 1) {\n\t\t\t\t\t\tconst keysToRemove = new Set<string>()\n\t\t\t\t\t\tconst seenValues: Record<string, string> = {}\n\n\t\t\t\t\t\tfor (const key of keys) {\n\t\t\t\t\t\t\tconst value = attributesToInclude[key]\n\t\t\t\t\t\t\tif (value.length > 5) {\n\t\t\t\t\t\t\t\tif (value in seenValues) {\n\t\t\t\t\t\t\t\t\tkeysToRemove.add(key)\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tseenValues[value] = key\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const key of keysToRemove) {\n\t\t\t\t\t\t\tdelete attributesToInclude[key]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove role if it matches tagName\n\t\t\t\t\tif (attributesToInclude.role === node.tagName) {\n\t\t\t\t\t\tdelete attributesToInclude.role\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove attributes that duplicate text content\n\t\t\t\t\tconst attrsToRemoveIfTextMatches = ['aria-label', 'placeholder', 'title']\n\t\t\t\t\tfor (const attr of attrsToRemoveIfTextMatches) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tattributesToInclude[attr] &&\n\t\t\t\t\t\t\tattributesToInclude[attr].toLowerCase().trim() === text.toLowerCase().trim()\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tdelete attributesToInclude[attr]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Object.keys(attributesToInclude).length > 0) {\n\t\t\t\t\t\tattributesHtmlStr = Object.entries(attributesToInclude)\n\t\t\t\t\t\t\t.map(([key, value]) => `${key}=${capTextLength(value, 20)}`)\n\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Build the line\n\t\t\t\tconst highlightIndicator = node.isNew\n\t\t\t\t\t? `*[${node.highlightIndex}]`\n\t\t\t\t\t: `[${node.highlightIndex}]`\n\t\t\t\tlet line = `${depthStr}${highlightIndicator}<${node.tagName ?? ''}`\n\n\t\t\t\tif (attributesHtmlStr) {\n\t\t\t\t\tline += ` ${attributesHtmlStr}`\n\t\t\t\t}\n\n\t\t\t\t/**\n\t\t\t\t * @edit scrollable 数据\n\t\t\t\t */\n\t\t\t\tif (node.extra) {\n\t\t\t\t\tif (node.extra.scrollable) {\n\t\t\t\t\t\tlet scrollDataText = ''\n\t\t\t\t\t\tif (node.extra.scrollData?.left)\n\t\t\t\t\t\t\tscrollDataText += `left=${node.extra.scrollData.left}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.top) scrollDataText += `top=${node.extra.scrollData.top}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.right)\n\t\t\t\t\t\t\tscrollDataText += `right=${node.extra.scrollData.right}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.bottom)\n\t\t\t\t\t\t\tscrollDataText += `bottom=${node.extra.scrollData.bottom}`\n\n\t\t\t\t\t\tline += ` data-scrollable=\"${scrollDataText}\"`\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (text) {\n\t\t\t\t\tconst trimmedText = text.trim()\n\t\t\t\t\tif (!attributesHtmlStr) {\n\t\t\t\t\t\tline += ' '\n\t\t\t\t\t}\n\t\t\t\t\tline += `>${trimmedText}`\n\t\t\t\t} else if (!attributesHtmlStr) {\n\t\t\t\t\tline += ' '\n\t\t\t\t}\n\n\t\t\t\tline += ' />'\n\t\t\t\tresult.push(line)\n\t\t\t}\n\n\t\t\t// special treatment for semantic tags\n\t\t\t// even if they are not interactive, we can keep them for clear context\n\n\t\t\tconst emitSemantic = isSemantic && node.highlightIndex === undefined\n\t\t\t// to check if this tag is empty\n\t\t\tconst mark = emitSemantic ? result.length : -1\n\n\t\t\tif (emitSemantic) {\n\t\t\t\tresult.push(`${depthStr}<${node.tagName}>`)\n\t\t\t\tnextDepth += 1\n\t\t\t}\n\n\t\t\tfor (const child of node.children) {\n\t\t\t\tprocessNode(child, nextDepth, result)\n\t\t\t}\n\n\t\t\tif (emitSemantic) {\n\t\t\t\t// empty tag should be removed\n\t\t\t\tif (result.length === mark + 1) {\n\t\t\t\t\tresult.pop()\n\t\t\t\t} else {\n\t\t\t\t\tresult.push(`${depthStr}</${node.tagName}>`)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (node.type === 'text') {\n\t\t\t// Add text only if it doesn't have a highlighted parent\n\t\t\tif (hasParentWithHighlightIndex(node)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tnode.parent &&\n\t\t\t\tnode.parent.type === 'element' &&\n\t\t\t\tnode.parent.isVisible &&\n\t\t\t\tnode.parent.isTopElement\n\t\t\t) {\n\t\t\t\tresult.push(`${depthStr}${node.text ?? ''}`)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result: string[] = []\n\tprocessNode(rootNode, 0, result)\n\treturn result.join('\\n')\n}\n\n// Get all text until next clickable element\nexport const getAllTextTillNextClickableElement = (node: TreeNode, maxDepth = -1): string => {\n\tconst textParts: string[] = []\n\n\tconst collectText = (currentNode: TreeNode, currentDepth: number) => {\n\t\tif (maxDepth !== -1 && currentDepth > maxDepth) {\n\t\t\treturn\n\t\t}\n\n\t\t// Skip this branch if we hit a highlighted element (except for the current node)\n\t\tif (\n\t\t\tcurrentNode.type === 'element' &&\n\t\t\tcurrentNode !== node &&\n\t\t\tcurrentNode.highlightIndex !== undefined\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tif (currentNode.type === 'text' && currentNode.text) {\n\t\t\ttextParts.push(currentNode.text)\n\t\t} else if (currentNode.type === 'element') {\n\t\t\tfor (const child of currentNode.children) {\n\t\t\t\tcollectText(child, currentDepth + 1)\n\t\t\t}\n\t\t}\n\t}\n\n\tcollectText(node, 0)\n\treturn textParts.join('\\n').trim()\n}\n\nexport function getSelectorMap(flatTree: FlatDomTree): Map<number, InteractiveElementDomNode> {\n\tconst selectorMap = new Map<number, InteractiveElementDomNode>()\n\n\tconst keys = Object.keys(flatTree.map)\n\tfor (const key of keys) {\n\t\tconst node = flatTree.map[key]\n\t\tif (node.isInteractive && typeof node.highlightIndex === 'number') {\n\t\t\tselectorMap.set(node.highlightIndex, node as InteractiveElementDomNode)\n\t\t}\n\t}\n\n\treturn selectorMap\n}\n\nexport function getElementTextMap(simplifiedHTML: string) {\n\tconst lines = simplifiedHTML\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => line.length > 0)\n\tconst elementTextMap = new Map<number, string>()\n\tfor (const line of lines) {\n\t\tconst regex = /^\\[(\\d+)\\]<[^>]+>([^<]*)/\n\t\tconst match = regex.exec(line)\n\t\tif (match) {\n\t\t\tconst index = parseInt(match[1], 10)\n\t\t\telementTextMap.set(index, line)\n\t\t}\n\t}\n\n\treturn elementTextMap\n}\n\nexport function cleanUpHighlights() {\n\tconst cleanupFunctions = (window as any)._highlightCleanupFunctions || []\n\tfor (const cleanup of cleanupFunctions) {\n\t\tif (typeof cleanup === 'function') {\n\t\t\tcleanup()\n\t\t}\n\t}\n\n\t;(window as any)._highlightCleanupFunctions = []\n}\n\n// 监听 URL 的任何变化,立刻清空 highLights\nwindow.addEventListener('popstate', () => {\n\t// console.log('URL changed (popstate), highlights cleaned up.')\n\tcleanUpHighlights()\n})\nwindow.addEventListener('hashchange', () => {\n\t// console.log('URL changed (hashchange), highlights cleaned up.')\n\tcleanUpHighlights()\n})\nwindow.addEventListener('beforeunload', () => {\n\t// console.log('Page is unloading, highlights cleaned up.')\n\tcleanUpHighlights()\n})\n\nconst navigation = (window as any).navigation\nif (navigation && typeof navigation.addEventListener === 'function') {\n\tnavigation.addEventListener('navigate', () => {\n\t\t// console.log('Navigation event detected, highlights cleaned up.')\n\t\tcleanUpHighlights()\n\t})\n} else {\n\t// 定时器\n\tlet currentUrl = window.location.href\n\tsetInterval(() => {\n\t\tif (window.location.href !== currentUrl) {\n\t\t\tcurrentUrl = window.location.href\n\t\t\t// console.log('URL changed (interval), highlights cleaned up.')\n\t\t\tcleanUpHighlights()\n\t\t}\n\t}, 500)\n}\n","export function getPageInfo() {\n\tconst viewport_width = window.innerWidth\n\tconst viewport_height = window.innerHeight\n\n\tconst page_width = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth || 0)\n\tconst page_height = Math.max(\n\t\tdocument.documentElement.scrollHeight,\n\t\tdocument.body.scrollHeight || 0\n\t)\n\n\tconst scroll_x = window.scrollX || window.pageXOffset || document.documentElement.scrollLeft || 0\n\tconst scroll_y = window.scrollY || window.pageYOffset || document.documentElement.scrollTop || 0\n\n\tconst pixels_below = Math.max(0, page_height - (window.innerHeight + scroll_y))\n\tconst pixels_right = Math.max(0, page_width - (window.innerWidth + scroll_x))\n\n\treturn {\n\t\t// Current viewport dimensions\n\t\tviewport_width,\n\t\tviewport_height,\n\n\t\t// Total page dimensions\n\t\tpage_width,\n\t\tpage_height,\n\n\t\t// Current scroll position\n\t\tscroll_x,\n\t\tscroll_y,\n\n\t\tpixels_above: scroll_y,\n\t\tpixels_below,\n\n\t\tpages_above: viewport_height > 0 ? scroll_y / viewport_height : 0,\n\t\tpages_below: viewport_height > 0 ? pixels_below / viewport_height : 0,\n\t\ttotal_pages: viewport_height > 0 ? page_height / viewport_height : 0,\n\n\t\tcurrent_page_position: scroll_y / Math.max(1, page_height - viewport_height),\n\n\t\tpixels_left: scroll_x,\n\t\tpixels_right,\n\t}\n}\n","import type { PageController } from '../PageController'\n\n// Find common React root elements and add data-page-agent-not-interactive attribute\nexport function patchReact(pageController: PageController) {\n\tconst reactRootElements = document.querySelectorAll(\n\t\t'[data-reactroot], [data-reactid], [data-react-checksum], #root, #app, [id^=\"root-\"], [id^=\"app-\"], #adex-wrapper, #adex-root'\n\t)\n\n\tfor (const element of reactRootElements) {\n\t\telement.setAttribute('data-page-agent-not-interactive', 'true')\n\t}\n}\n\n/**\n * @todo (Heavy, might have false negatives) Interaction detection, if element width/height equals body offsetWidth/Height, consider it root element and non-interactive (React often attaches many events to root elements, causing false positives)\n */\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n *\n * PageController - Manages DOM operations and element interactions.\n * Designed to be independent of LLM and can be tested in unit tests.\n * All public methods are async for potential remote calling support.\n */\nimport {\n\tclickElement,\n\tgetElementByIndex,\n\tinputTextElement,\n\tscrollHorizontally,\n\tscrollVertically,\n\tselectOptionElement,\n} from './actions'\nimport * as dom from './dom'\nimport type { FlatDomTree, InteractiveElementDomNode } from './dom/dom_tree/type'\nimport { getPageInfo } from './dom/getPageInfo'\nimport { patchReact } from './patches/react'\nimport { isAnchorElement } from './utils'\n\n/**\n * Configuration for PageController\n */\nexport interface PageControllerConfig extends dom.DomConfig {\n\t/** Enable visual mask overlay during operations (default: false) */\n\tenableMask?: boolean\n}\n\n/**\n * Structured browser state for LLM consumption\n */\nexport interface BrowserState {\n\turl: string\n\ttitle: string\n\t/** Page info + scroll position hint (e.g. \"Page info: 1920x1080px...\\n[Start of page]\") */\n\theader: string\n\t/** Simplified HTML of interactive elements */\n\tcontent: string\n\t/** Page footer hint (e.g. \"... 300 pixels below ...\" or \"[End of page]\") */\n\tfooter: string\n}\n\ninterface ActionResult {\n\tsuccess: boolean\n\tmessage: string\n}\n\n/**\n * PageController manages DOM state and element interactions.\n * It provides async methods for all DOM operations, keeping state isolated.\n *\n * @lifecycle\n * - beforeUpdate: Emitted before the DOM tree is updated.\n * - afterUpdate: Emitted after the DOM tree is updated.\n */\nexport class PageController extends EventTarget {\n\tprivate config: PageControllerConfig\n\n\t/** Corresponds to eval_page in browser-use */\n\tprivate flatTree: FlatDomTree | null = null\n\n\t/**\n\t * All highlighted index-mapped interactive elements\n\t * Corresponds to DOMState.selector_map in browser-use\n\t */\n\tprivate selectorMap = new Map<number, InteractiveElementDomNode>()\n\n\t/** Index -> element text description mapping */\n\tprivate elementTextMap = new Map<number, string>()\n\n\t/**\n\t * Simplified HTML for LLM consumption.\n\t * Corresponds to clickable_elements_to_string in browser-use\n\t */\n\tprivate simplifiedHTML = '<EMPTY>'\n\n\t/** last time the tree was updated */\n\tprivate lastTimeUpdate = 0\n\n\t/** Whether the tree has been indexed at least once */\n\tprivate isIndexed = false\n\n\t/** Visual mask overlay for blocking user interaction during automation */\n\tprivate mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null\n\tprivate maskReady: Promise<void> | null = null\n\n\tconstructor(config: PageControllerConfig = {}) {\n\t\tsuper()\n\n\t\tthis.config = config\n\n\t\tpatchReact(this)\n\n\t\tif (config.enableMask) this.initMask()\n\t}\n\n\t/**\n\t * Initialize mask asynchronously (dynamic import to avoid CSS loading in Node)\n\t */\n\tinitMask() {\n\t\tif (this.maskReady !== null) return\n\t\tthis.maskReady = (async () => {\n\t\t\tconst { SimulatorMask } = await import('./mask/SimulatorMask')\n\t\t\tthis.mask = new SimulatorMask()\n\t\t})()\n\t}\n\t// ======= State Queries =======\n\n\t/**\n\t * Get current page URL\n\t */\n\tasync getCurrentUrl(): Promise<string> {\n\t\treturn window.location.href\n\t}\n\n\t/**\n\t * Get last tree update timestamp\n\t */\n\tasync getLastUpdateTime(): Promise<number> {\n\t\treturn this.lastTimeUpdate\n\t}\n\n\t/**\n\t * Get structured browser state for LLM consumption.\n\t * Automatically calls updateTree() to refresh the DOM state.\n\t */\n\tasync getBrowserState(): Promise<BrowserState> {\n\t\tconst url = window.location.href\n\t\tconst title = document.title\n\t\tconst pi = getPageInfo()\n\t\tconst viewportExpansion = dom.resolveViewportExpansion(this.config.viewportExpansion)\n\n\t\tawait this.updateTree()\n\n\t\tconst content = this.simplifiedHTML\n\n\t\t// Build header: page info + scroll position hint\n\t\tconst titleLine = `Current Page: [${title}](${url})`\n\n\t\tconst pageInfoLine = `Page info: ${pi.viewport_width}x${pi.viewport_height}px viewport, ${pi.page_width}x${pi.page_height}px total page size, ${pi.pages_above.toFixed(1)} pages above, ${pi.pages_below.toFixed(1)} pages below, ${pi.total_pages.toFixed(1)} total pages, at ${(pi.current_page_position * 100).toFixed(0)}% of page`\n\n\t\tconst elementsLabel =\n\t\t\tviewportExpansion === -1\n\t\t\t\t? 'Interactive elements from top layer of the current page (full page):'\n\t\t\t\t: 'Interactive elements from top layer of the current page inside the viewport:'\n\n\t\tconst hasContentAbove = pi.pixels_above > 4\n\t\tconst scrollHintAbove =\n\t\t\thasContentAbove && viewportExpansion !== -1\n\t\t\t\t? `... ${pi.pixels_above} pixels above (${pi.pages_above.toFixed(1)} pages) - scroll to see more ...`\n\t\t\t\t: '[Start of page]'\n\n\t\tconst header = `${titleLine}\\n${pageInfoLine}\\n\\n${elementsLabel}\\n\\n${scrollHintAbove}`\n\n\t\t// Build footer: scroll position hint\n\t\tconst hasContentBelow = pi.pixels_below > 4\n\t\tconst footer =\n\t\t\thasContentBelow && viewportExpansion !== -1\n\t\t\t\t? `... ${pi.pixels_below} pixels below (${pi.pages_below.toFixed(1)} pages) - scroll to see more ...`\n\t\t\t\t: '[End of page]'\n\n\t\treturn { url, title, header, content, footer }\n\t}\n\n\t// ======= DOM Tree Operations =======\n\n\t/**\n\t * Update DOM tree, returns simplified HTML for LLM.\n\t * This is the main method to refresh the page state.\n\t * Automatically bypasses mask during DOM extraction if enabled.\n\t */\n\tasync updateTree(): Promise<string> {\n\t\tthis.dispatchEvent(new Event('beforeUpdate'))\n\n\t\tthis.lastTimeUpdate = Date.now()\n\n\t\t// Temporarily bypass mask to allow DOM extraction\n\t\tif (this.mask) {\n\t\t\tthis.mask.wrapper.style.pointerEvents = 'none'\n\t\t}\n\n\t\tdom.cleanUpHighlights()\n\n\t\tconst blacklist = [\n\t\t\t...(this.config.interactiveBlacklist || []),\n\t\t\t...document.querySelectorAll('[data-page-agent-not-interactive]').values(),\n\t\t]\n\n\t\tthis.flatTree = dom.getFlatTree({\n\t\t\t...this.config,\n\t\t\tinteractiveBlacklist: blacklist,\n\t\t})\n\n\t\tthis.simplifiedHTML = dom.flatTreeToString(\n\t\t\tthis.flatTree,\n\t\t\tthis.config.includeAttributes,\n\t\t\tthis.config.keepSemanticTags\n\t\t)\n\n\t\tthis.selectorMap.clear()\n\t\tthis.selectorMap = dom.getSelectorMap(this.flatTree)\n\n\t\tthis.elementTextMap.clear()\n\t\tthis.elementTextMap = dom.getElementTextMap(this.simplifiedHTML)\n\n\t\t// Mark as indexed - now element actions are allowed\n\t\tthis.isIndexed = true\n\n\t\t// Restore mask blocking\n\t\tif (this.mask) {\n\t\t\tthis.mask.wrapper.style.pointerEvents = 'auto'\n\t\t}\n\n\t\tthis.dispatchEvent(new Event('afterUpdate'))\n\n\t\treturn this.simplifiedHTML\n\t}\n\n\t/**\n\t * Clean up all element highlights\n\t */\n\tasync cleanUpHighlights(): Promise<void> {\n\t\tconsole.log('[PageController] cleanUpHighlights')\n\t\tdom.cleanUpHighlights()\n\t}\n\n\t// ======= Element Actions =======\n\n\t/**\n\t * Ensure the tree has been indexed before any index-based operation.\n\t * Throws if updateTree() hasn't been called yet.\n\t */\n\tprivate assertIndexed(): void {\n\t\tif (!this.isIndexed) {\n\t\t\tthrow new Error('DOM tree not indexed yet. Can not perform actions on elements.')\n\t\t}\n\t}\n\n\t/**\n\t * Click element by index\n\t */\n\tasync clickElement(index: number): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait clickElement(element)\n\n\t\t\t// Handle links that open in new tabs\n\t\t\tif (isAnchorElement(element) && element.target === '_blank') {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tmessage: `✅ Clicked element (${elemText ?? index}). ⚠️ Link opened in a new tab.`,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Clicked element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to click element: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Input text into element by index\n\t */\n\tasync inputText(index: number, text: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait inputTextElement(element, text)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Input text (${text}) into element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to input text: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Select dropdown option by index and option text\n\t */\n\tasync selectOption(index: number, optionText: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait selectOptionElement(element as HTMLSelectElement, optionText)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Selected option (${optionText}) in element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to select option: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Scroll vertically\n\t */\n\tasync scroll(options: {\n\t\tdown: boolean\n\t\tnumPages: number\n\t\tpixels?: number\n\t\tindex?: number\n\t}): Promise<ActionResult> {\n\t\ttry {\n\t\t\tconst { down, numPages, pixels, index } = options\n\n\t\t\tthis.assertIndexed()\n\n\t\t\tconst scrollAmount = (pixels ?? numPages * window.innerHeight) * (down ? 1 : -1)\n\n\t\t\tconst element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null\n\n\t\t\tconst message = await scrollVertically(scrollAmount, element)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to scroll: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Scroll horizontally\n\t */\n\tasync scrollHorizontally(options: {\n\t\tright: boolean\n\t\tpixels: number\n\t\tindex?: number\n\t}): Promise<ActionResult> {\n\t\ttry {\n\t\t\tconst { right, pixels, index } = options\n\n\t\t\tthis.assertIndexed()\n\n\t\t\tconst scrollAmount = pixels * (right ? 1 : -1)\n\n\t\t\tconst element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null\n\n\t\t\tconst message = await scrollHorizontally(scrollAmount, element)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to scroll horizontally: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Execute arbitrary JavaScript on the page\n\t */\n\tasync executeJavascript(script: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\t// Wrap script in async function to support await\n\t\t\tconst asyncFunction = eval(`(async () => { ${script} })`)\n\t\t\tconst result = await asyncFunction()\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Executed JavaScript. Result: ${result}`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Error executing JavaScript: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t// ======= Mask Operations =======\n\n\t/**\n\t * Show the visual mask overlay.\n\t * Only works after mask is setup.\n\t */\n\tasync showMask(): Promise<void> {\n\t\tawait this.maskReady\n\t\tthis.mask?.show()\n\t}\n\n\t/**\n\t * Hide the visual mask overlay.\n\t * Only works after mask is setup.\n\t */\n\tasync hideMask(): Promise<void> {\n\t\tawait this.maskReady\n\t\tthis.mask?.hide()\n\t}\n\n\t/**\n\t * Dispose and clean up resources\n\t */\n\tdispose(): void {\n\t\tdom.cleanUpHighlights()\n\t\tthis.flatTree = null\n\t\tthis.selectorMap.clear()\n\t\tthis.elementTextMap.clear()\n\t\tthis.simplifiedHTML = '<EMPTY>'\n\t\tthis.isIndexed = false\n\t\tthis.mask?.dispose()\n\t\tthis.mask = null\n\t}\n}\n\nexport * from './actions'\n"],"names":["dy","el","dx","args","parentElement","element","rect","viewportExpansion","nodeData","id","result","dom.resolveViewportExpansion","dom.cleanUpHighlights","dom.getFlatTree","dom.flatTreeToString","dom.getSelectorMap","dom.getElementTextMap"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@page-agent/page-controller",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "type": "module",
5
5
  "main": "./dist/lib/page-controller.js",
6
6
  "module": "./dist/lib/page-controller.js",