@eko-ai/eko 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/web.esm.js CHANGED
@@ -6,15 +6,16 @@
6
6
  * @returns { element_str, selector_map }
7
7
  */
8
8
  function get_clickable_elements(doHighlightElements = true, includeAttributes) {
9
+ window.clickable_elements = {};
9
10
  let page_tree = build_dom_tree(doHighlightElements);
10
11
  let element_tree = parse_node(page_tree);
11
12
  let selector_map = create_selector_map(element_tree);
12
13
  let element_str = clickable_elements_to_string(element_tree, includeAttributes);
13
14
  return { element_str, selector_map };
14
15
  }
15
- /**
16
- * Remove highlight
17
- */
16
+ function get_highlight_element(highlightIndex) {
17
+ return window.clickable_elements[highlightIndex];
18
+ }
18
19
  function remove_highlight() {
19
20
  let highlight = document.getElementById('playwright-highlight-container');
20
21
  if (highlight) {
@@ -537,6 +538,7 @@ function build_dom_tree(doHighlightElements) {
537
538
  // Highlight if element meets all criteria and highlighting is enabled
538
539
  if (isInteractive && isVisible && isTop) {
539
540
  nodeData.highlightIndex = highlightIndex++;
541
+ window.clickable_elements[nodeData.highlightIndex] = node;
540
542
  if (doHighlightElements) {
541
543
  highlightElement(node, nodeData.highlightIndex, parentIframe);
542
544
  }
@@ -577,198 +579,9 @@ function build_dom_tree(doHighlightElements) {
577
579
  return buildDomTree(document.body);
578
580
  }
579
581
  window.get_clickable_elements = get_clickable_elements;
582
+ window.get_highlight_element = get_highlight_element;
580
583
  window.remove_highlight = remove_highlight;
581
584
 
582
- function exportFile(filename, type, content) {
583
- const blob = new Blob([content], { type: type });
584
- const link = document.createElement('a');
585
- link.href = URL.createObjectURL(blob);
586
- link.download = filename;
587
- document.body.appendChild(link);
588
- link.click();
589
- document.body.removeChild(link);
590
- URL.revokeObjectURL(link.href);
591
- }
592
- function xpath(element) {
593
- if (element.id !== '') {
594
- return '//*[@id=\"' + element.id + '\"]';
595
- }
596
- if (element == document.body) {
597
- return '/html/' + element.tagName.toLowerCase();
598
- }
599
- var ix = 1, siblings = element.parentNode.childNodes;
600
- for (var i = 0, l = siblings.length; i < l; i++) {
601
- var sibling = siblings[i];
602
- if (sibling == element) {
603
- return xpath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + ix + ']';
604
- }
605
- else if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
606
- ix++;
607
- }
608
- }
609
- return '';
610
- }
611
- function getDropdownOptions(xpath) {
612
- const select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
613
- .singleNodeValue;
614
- if (!select) {
615
- return null;
616
- }
617
- return {
618
- options: Array.from(select.options).map((opt) => ({
619
- index: opt.index,
620
- text: opt.text.trim(),
621
- value: opt.value,
622
- })),
623
- id: select.id,
624
- name: select.name,
625
- };
626
- }
627
- function selectDropdownOption(xpath, text) {
628
- const select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
629
- .singleNodeValue;
630
- if (!select || select.tagName.toUpperCase() !== 'SELECT') {
631
- return { success: false, error: 'Select not found or invalid element type' };
632
- }
633
- const option = Array.from(select.options).find((opt) => opt.text.trim() === text);
634
- if (!option) {
635
- return {
636
- success: false,
637
- error: 'Option not found',
638
- availableOptions: Array.from(select.options).map((o) => o.text.trim()),
639
- };
640
- }
641
- select.value = option.value;
642
- select.dispatchEvent(new Event('change'));
643
- return {
644
- success: true,
645
- selectedValue: option.value,
646
- selectedText: option.text.trim(),
647
- };
648
- }
649
- /**
650
- * Extract the elements related to html operability and wrap them into pseudo-html code.
651
- */
652
- function extractOperableElements() {
653
- // visible
654
- const isElementVisible = (element) => {
655
- const style = window.getComputedStyle(element);
656
- return (style.display !== 'none' &&
657
- style.visibility !== 'hidden' &&
658
- style.opacity !== '0' &&
659
- element.offsetWidth > 0 &&
660
- element.offsetHeight > 0);
661
- };
662
- // element original index
663
- const getElementIndex = (element) => {
664
- const xpath = document.evaluate('preceding::*', element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
665
- return xpath.snapshotLength;
666
- };
667
- // exclude
668
- const addExclude = (excludes, children) => {
669
- for (let i = 0; i < children.length; i++) {
670
- excludes.push(children[i]);
671
- if (children[i].children) {
672
- addExclude(excludes, children[i].children);
673
- }
674
- }
675
- };
676
- // { pseudoId: element }
677
- let elementMap = {};
678
- let nextId = 1;
679
- let elements = [];
680
- let excludes = [];
681
- // operable element
682
- const operableSelectors = 'a, button, input, textarea, select';
683
- document.querySelectorAll(operableSelectors).forEach((element) => {
684
- if (isElementVisible(element) && excludes.indexOf(element) == -1) {
685
- const id = nextId++;
686
- elementMap[id.toString()] = element;
687
- const tagName = element.tagName.toLowerCase();
688
- const attributes = Array.from(element.attributes)
689
- .filter((attr) => ['id', 'name', 'type', 'value', 'href', 'title', 'placeholder'].includes(attr.name))
690
- .map((attr) => `${attr.name == 'id' ? 'target' : attr.name}="${attr.value}"`)
691
- .join(' ');
692
- elements.push({
693
- originalIndex: getElementIndex(element),
694
- id: id,
695
- html: `<${tagName} id="${id}" ${attributes}>${tagName == 'select' ? element.innerHTML : element.innerText || ''}</${tagName}>`,
696
- });
697
- addExclude(excludes, element.children);
698
- }
699
- });
700
- // short text element
701
- const textWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
702
- acceptNode: function (node) {
703
- var _a;
704
- if (node.matches(operableSelectors) || excludes.indexOf(node) != -1) {
705
- // skip
706
- return NodeFilter.FILTER_SKIP;
707
- }
708
- // text <= 100
709
- const text = (_a = node.innerText) === null || _a === void 0 ? void 0 : _a.trim();
710
- if (isElementVisible(node) &&
711
- text &&
712
- text.length <= 100 &&
713
- text.length > 0 &&
714
- node.children.length === 0) {
715
- return NodeFilter.FILTER_ACCEPT;
716
- }
717
- // skip
718
- return NodeFilter.FILTER_SKIP;
719
- },
720
- });
721
- let currentNode;
722
- while ((currentNode = textWalker.nextNode())) {
723
- const id = nextId++;
724
- elementMap[id.toString()] = currentNode;
725
- const tagName = currentNode.tagName.toLowerCase();
726
- elements.push({
727
- originalIndex: getElementIndex(currentNode),
728
- id: id,
729
- html: `<${tagName} id="${id}">${currentNode.innerText.trim()}</${tagName}>`,
730
- });
731
- }
732
- // element sort
733
- elements.sort((a, b) => a.originalIndex - b.originalIndex);
734
- // cache
735
- window.operableElementMap = elementMap;
736
- // pseudo html
737
- return elements.map((e) => e.html).join('\n');
738
- }
739
- function clickOperableElement(id) {
740
- let element = window.operableElementMap[id];
741
- if (!element) {
742
- return false;
743
- }
744
- if (element.click) {
745
- element.click();
746
- }
747
- else {
748
- element.dispatchEvent(new MouseEvent('click', {
749
- view: window,
750
- bubbles: true,
751
- cancelable: true,
752
- }));
753
- }
754
- return true;
755
- }
756
- function getOperableElementRect(id) {
757
- let element = window.operableElementMap[id];
758
- if (!element) {
759
- return null;
760
- }
761
- const rect = element.getBoundingClientRect();
762
- return {
763
- left: rect.left + window.scrollX,
764
- top: rect.top + window.scrollY,
765
- right: rect.right + window.scrollX,
766
- bottom: rect.bottom + window.scrollY,
767
- width: rect.right - rect.left,
768
- height: rect.bottom - rect.top,
769
- };
770
- }
771
-
772
585
  /*!
773
586
  * html2canvas 1.4.1 <https://html2canvas.hertzen.com>
774
587
  * Copyright (c) 2022 Niklas von Hertzen <https://hertzen.com>
@@ -8589,20 +8402,20 @@ var parseBackgroundColor = function (context, element, backgroundColorOverride)
8589
8402
  : defaultBackgroundColor;
8590
8403
  };
8591
8404
 
8592
- function type(xpath, text) {
8593
- return do_input(xpath, text);
8405
+ function type(text, xpath, highlightIndex) {
8406
+ return do_input(text, xpath, highlightIndex);
8594
8407
  }
8595
- function clear_input(xpath) {
8596
- return do_input(xpath, '');
8408
+ function clear_input(xpath, highlightIndex) {
8409
+ return do_input('', xpath, highlightIndex);
8597
8410
  }
8598
- function left_click(xpath) {
8599
- return simulateMouseEvent(xpath, ['mousedown', 'mouseup', 'click'], 0);
8411
+ function left_click(xpath, highlightIndex) {
8412
+ return simulateMouseEvent(['mousedown', 'mouseup', 'click'], 0, xpath, highlightIndex);
8600
8413
  }
8601
- function right_click(xpath) {
8602
- return simulateMouseEvent(xpath, ['mousedown', 'mouseup', 'contextmenu'], 2);
8414
+ function right_click(xpath, highlightIndex) {
8415
+ return simulateMouseEvent(['mousedown', 'mouseup', 'contextmenu'], 2, xpath, highlightIndex);
8603
8416
  }
8604
- function double_click(xpath) {
8605
- return simulateMouseEvent(xpath, ['mousedown', 'mouseup', 'click', 'mousedown', 'mouseup', 'click', 'dblclick'], 0);
8417
+ function double_click(xpath, highlightIndex) {
8418
+ return simulateMouseEvent(['mousedown', 'mouseup', 'click', 'mousedown', 'mouseup', 'click', 'dblclick'], 0, xpath, highlightIndex);
8606
8419
  }
8607
8420
  async function screenshot() {
8608
8421
  const [width, height] = size();
@@ -8632,12 +8445,72 @@ async function screenshot() {
8632
8445
  },
8633
8446
  };
8634
8447
  }
8635
- function scroll_to(xpath) {
8636
- let result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
8637
- let element = result.singleNodeValue;
8638
- return element.scrollIntoView({
8448
+ function scroll_to(xpath, highlightIndex) {
8449
+ let element = null;
8450
+ if (highlightIndex != null) {
8451
+ element = window.get_highlight_element(highlightIndex);
8452
+ }
8453
+ else if (xpath) {
8454
+ element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
8455
+ .singleNodeValue;
8456
+ }
8457
+ if (!element) {
8458
+ return false;
8459
+ }
8460
+ element.scrollIntoView({
8639
8461
  behavior: 'smooth',
8640
8462
  });
8463
+ return true;
8464
+ }
8465
+ function get_dropdown_options(xpath, highlightIndex) {
8466
+ let select = null;
8467
+ if (highlightIndex != null) {
8468
+ select = window.get_highlight_element(highlightIndex);
8469
+ }
8470
+ else if (xpath) {
8471
+ select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
8472
+ .singleNodeValue;
8473
+ }
8474
+ if (!select) {
8475
+ return null;
8476
+ }
8477
+ return {
8478
+ options: Array.from(select.options).map((opt) => ({
8479
+ index: opt.index,
8480
+ text: opt.text.trim(),
8481
+ value: opt.value,
8482
+ })),
8483
+ id: select.id,
8484
+ name: select.name,
8485
+ };
8486
+ }
8487
+ function select_dropdown_option(text, xpath, highlightIndex) {
8488
+ let select = null;
8489
+ if (highlightIndex != null) {
8490
+ select = window.get_highlight_element(highlightIndex);
8491
+ }
8492
+ else if (xpath) {
8493
+ select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
8494
+ .singleNodeValue;
8495
+ }
8496
+ if (!select || select.tagName.toUpperCase() !== 'SELECT') {
8497
+ return { success: false, error: 'Select not found or invalid element type' };
8498
+ }
8499
+ const option = Array.from(select.options).find((opt) => opt.text.trim() === text);
8500
+ if (!option) {
8501
+ return {
8502
+ success: false,
8503
+ error: 'Option not found',
8504
+ availableOptions: Array.from(select.options).map((o) => o.text.trim()),
8505
+ };
8506
+ }
8507
+ select.value = option.value;
8508
+ select.dispatchEvent(new Event('change'));
8509
+ return {
8510
+ success: true,
8511
+ selectedValue: option.value,
8512
+ selectedText: option.text.trim(),
8513
+ };
8641
8514
  }
8642
8515
  function extractHtmlContent() {
8643
8516
  let element = document.body;
@@ -8674,11 +8547,26 @@ function size() {
8674
8547
  window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
8675
8548
  ];
8676
8549
  }
8677
- function do_input(xpath, text) {
8678
- let query_result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
8679
- let element = query_result.singleNodeValue;
8550
+ function do_input(text, xpath, highlightIndex) {
8551
+ let element = null;
8552
+ if (highlightIndex != null) {
8553
+ element = window.get_highlight_element(highlightIndex);
8554
+ }
8555
+ else if (xpath) {
8556
+ element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
8557
+ .singleNodeValue;
8558
+ }
8680
8559
  if (!element) {
8681
- return;
8560
+ return false;
8561
+ }
8562
+ let enter = false;
8563
+ if (text.endsWith('\\n')) {
8564
+ enter = true;
8565
+ text = text.substring(0, text.length - 2);
8566
+ }
8567
+ else if (text.endsWith('\n')) {
8568
+ enter = true;
8569
+ text = text.substring(0, text.length - 1);
8682
8570
  }
8683
8571
  let input;
8684
8572
  if (element.tagName == 'INPUT' ||
@@ -8697,13 +8585,33 @@ function do_input(xpath, text) {
8697
8585
  input.value += text;
8698
8586
  }
8699
8587
  let result = input.dispatchEvent(new Event('input', { bubbles: true }));
8588
+ if (enter) {
8589
+ ['keydown', 'keypress', 'keyup'].forEach((eventType) => {
8590
+ const event = new KeyboardEvent(eventType, {
8591
+ key: 'Enter',
8592
+ code: 'Enter',
8593
+ keyCode: 13,
8594
+ bubbles: true,
8595
+ cancelable: true,
8596
+ });
8597
+ input.dispatchEvent(event);
8598
+ });
8599
+ }
8700
8600
  console.log('type', input, result);
8701
- return result;
8601
+ return true;
8702
8602
  }
8703
- function simulateMouseEvent(xpath, eventTypes, button) {
8704
- let query_result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
8705
- let element = query_result.singleNodeValue;
8706
- let result = false;
8603
+ function simulateMouseEvent(eventTypes, button, xpath, highlightIndex) {
8604
+ let element = null;
8605
+ if (highlightIndex != null) {
8606
+ element = window.get_highlight_element(highlightIndex);
8607
+ }
8608
+ else if (xpath) {
8609
+ element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
8610
+ .singleNodeValue;
8611
+ }
8612
+ if (!element) {
8613
+ return false;
8614
+ }
8707
8615
  for (let i = 0; i < eventTypes.length; i++) {
8708
8616
  const event = new MouseEvent(eventTypes[i], {
8709
8617
  view: window,
@@ -8711,25 +8619,12 @@ function simulateMouseEvent(xpath, eventTypes, button) {
8711
8619
  cancelable: true,
8712
8620
  button, // 0 left; 2 right
8713
8621
  });
8714
- result = element.dispatchEvent(event);
8622
+ let result = element.dispatchEvent(event);
8715
8623
  console.log('simulateMouse', element, { xpath, eventTypes, button }, result);
8716
8624
  }
8717
- return result;
8625
+ return true;
8718
8626
  }
8719
8627
 
8720
- var browser = /*#__PURE__*/Object.freeze({
8721
- __proto__: null,
8722
- clear_input: clear_input,
8723
- double_click: double_click,
8724
- extractHtmlContent: extractHtmlContent,
8725
- left_click: left_click,
8726
- right_click: right_click,
8727
- screenshot: screenshot,
8728
- scroll_to: scroll_to,
8729
- size: size,
8730
- type: type
8731
- });
8732
-
8733
8628
  /**
8734
8629
  * Browser Use for general
8735
8630
  */
@@ -8815,7 +8710,7 @@ class BrowserUse {
8815
8710
  if (params === null || !params.action) {
8816
8711
  throw new Error('Invalid parameters. Expected an object with a "action" property.');
8817
8712
  }
8818
- let selector_map = context.variables.get('selector_map');
8713
+ let selector_map = context.selector_map;
8819
8714
  let selector_xpath;
8820
8715
  if (params.index != null && selector_map) {
8821
8716
  selector_xpath = (_a = selector_map[params.index]) === null || _a === void 0 ? void 0 : _a.xpath;
@@ -8832,42 +8727,42 @@ class BrowserUse {
8832
8727
  if (params.text == null) {
8833
8728
  throw new Error('text parameter is required');
8834
8729
  }
8835
- result = await type(selector_xpath, params.text);
8730
+ result = await type(params.text, selector_xpath, params.index);
8836
8731
  await sleep(200);
8837
8732
  break;
8838
8733
  case 'clear_text':
8839
8734
  if (params.index == null) {
8840
8735
  throw new Error('index parameter is required');
8841
8736
  }
8842
- result = await clear_input(selector_xpath);
8737
+ result = await clear_input(selector_xpath, params.index);
8843
8738
  await sleep(100);
8844
8739
  break;
8845
8740
  case 'click':
8846
8741
  if (params.index == null) {
8847
8742
  throw new Error('index parameter is required');
8848
8743
  }
8849
- result = await left_click(selector_xpath);
8744
+ result = await left_click(selector_xpath, params.index);
8850
8745
  await sleep(100);
8851
8746
  break;
8852
8747
  case 'right_click':
8853
8748
  if (params.index == null) {
8854
8749
  throw new Error('index parameter is required');
8855
8750
  }
8856
- result = await right_click(selector_xpath);
8751
+ result = await right_click(selector_xpath, params.index);
8857
8752
  await sleep(100);
8858
8753
  break;
8859
8754
  case 'double_click':
8860
8755
  if (params.index == null) {
8861
8756
  throw new Error('index parameter is required');
8862
8757
  }
8863
- result = await double_click(selector_xpath);
8758
+ result = await double_click(selector_xpath, params.index);
8864
8759
  await sleep(100);
8865
8760
  break;
8866
8761
  case 'scroll_to':
8867
8762
  if (params.index == null) {
8868
8763
  throw new Error('index parameter is required');
8869
8764
  }
8870
- result = await scroll_to(selector_xpath);
8765
+ result = await scroll_to(selector_xpath, params.index);
8871
8766
  await sleep(500);
8872
8767
  break;
8873
8768
  case 'extract_content':
@@ -8882,7 +8777,7 @@ class BrowserUse {
8882
8777
  if (params.index == null) {
8883
8778
  throw new Error('index parameter is required');
8884
8779
  }
8885
- result = getDropdownOptions(selector_xpath);
8780
+ result = get_dropdown_options(selector_xpath, params.index);
8886
8781
  break;
8887
8782
  case 'select_dropdown_option':
8888
8783
  if (params.index == null) {
@@ -8891,12 +8786,12 @@ class BrowserUse {
8891
8786
  if (params.text == null) {
8892
8787
  throw new Error('text parameter is required');
8893
8788
  }
8894
- result = selectDropdownOption(selector_xpath, params.text);
8789
+ result = select_dropdown_option(params.text, selector_xpath, params.index);
8895
8790
  break;
8896
8791
  case 'screenshot_extract_element':
8897
8792
  await sleep(100);
8898
8793
  let element_result = get_clickable_elements(true, null);
8899
- context.variables.set('selector_map', element_result.selector_map);
8794
+ context.selector_map = element_result.selector_map;
8900
8795
  let screenshot$1 = await screenshot();
8901
8796
  remove_highlight();
8902
8797
  result = { image: screenshot$1.image, text: element_result.element_str };
@@ -8915,11 +8810,187 @@ class BrowserUse {
8915
8810
  return { success: false, error: e === null || e === void 0 ? void 0 : e.message };
8916
8811
  }
8917
8812
  }
8813
+ destroy(context) {
8814
+ delete context.selector_map;
8815
+ }
8918
8816
  }
8919
8817
  function sleep(time) {
8920
8818
  return new Promise((resolve) => setTimeout(() => resolve(), time));
8921
8819
  }
8922
8820
 
8821
+ function exportFile(filename, type, content) {
8822
+ const blob = new Blob([content], { type: type });
8823
+ const link = document.createElement('a');
8824
+ link.href = URL.createObjectURL(blob);
8825
+ link.download = filename;
8826
+ document.body.appendChild(link);
8827
+ link.click();
8828
+ document.body.removeChild(link);
8829
+ URL.revokeObjectURL(link.href);
8830
+ }
8831
+ function xpath(element) {
8832
+ if (element == document.body) {
8833
+ return '/html/' + element.tagName.toLowerCase();
8834
+ }
8835
+ if (element.parentNode instanceof ShadowRoot) {
8836
+ let shadowRoot = element.parentNode;
8837
+ let parent = shadowRoot.getRootNode().host;
8838
+ return xpath(parent) + '//' + element.tagName.toLowerCase();
8839
+ }
8840
+ else {
8841
+ let sp;
8842
+ let parent;
8843
+ if (element.parentNode instanceof ShadowRoot) {
8844
+ sp = '//';
8845
+ let shadowRoot = element.parentNode;
8846
+ parent = shadowRoot.getRootNode().host;
8847
+ }
8848
+ else {
8849
+ sp = '/';
8850
+ parent = element.parentNode;
8851
+ }
8852
+ let siblings = parent.childNodes;
8853
+ if (siblings.length == 1) {
8854
+ return xpath(parent) + sp + element.tagName.toLowerCase();
8855
+ }
8856
+ else {
8857
+ let ix = 1;
8858
+ for (let i = 0, l = siblings.length; i < l; i++) {
8859
+ let sibling = siblings[i];
8860
+ if (sibling == element) {
8861
+ return xpath(parent) + sp + element.tagName.toLowerCase() + '[' + ix + ']';
8862
+ }
8863
+ else if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
8864
+ ix++;
8865
+ }
8866
+ }
8867
+ return '';
8868
+ }
8869
+ }
8870
+ }
8871
+ /**
8872
+ * Extract the elements related to html operability and wrap them into pseudo-html code.
8873
+ */
8874
+ function extractOperableElements() {
8875
+ // visible
8876
+ const isElementVisible = (element) => {
8877
+ const style = window.getComputedStyle(element);
8878
+ return (style.display !== 'none' &&
8879
+ style.visibility !== 'hidden' &&
8880
+ style.opacity !== '0' &&
8881
+ element.offsetWidth > 0 &&
8882
+ element.offsetHeight > 0);
8883
+ };
8884
+ // element original index
8885
+ const getElementIndex = (element) => {
8886
+ const xpath = document.evaluate('preceding::*', element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
8887
+ return xpath.snapshotLength;
8888
+ };
8889
+ // exclude
8890
+ const addExclude = (excludes, children) => {
8891
+ for (let i = 0; i < children.length; i++) {
8892
+ excludes.push(children[i]);
8893
+ if (children[i].children) {
8894
+ addExclude(excludes, children[i].children);
8895
+ }
8896
+ }
8897
+ };
8898
+ // { pseudoId: element }
8899
+ let elementMap = {};
8900
+ let nextId = 1;
8901
+ let elements = [];
8902
+ let excludes = [];
8903
+ // operable element
8904
+ const operableSelectors = 'a, button, input, textarea, select';
8905
+ document.querySelectorAll(operableSelectors).forEach((element) => {
8906
+ if (isElementVisible(element) && excludes.indexOf(element) == -1) {
8907
+ const id = nextId++;
8908
+ elementMap[id.toString()] = element;
8909
+ const tagName = element.tagName.toLowerCase();
8910
+ const attributes = Array.from(element.attributes)
8911
+ .filter((attr) => ['id', 'name', 'type', 'value', 'href', 'title', 'placeholder'].includes(attr.name))
8912
+ .map((attr) => `${attr.name == 'id' ? 'target' : attr.name}="${attr.value}"`)
8913
+ .join(' ');
8914
+ elements.push({
8915
+ originalIndex: getElementIndex(element),
8916
+ id: id,
8917
+ html: `<${tagName} id="${id}" ${attributes}>${tagName == 'select' ? element.innerHTML : element.innerText || ''}</${tagName}>`,
8918
+ });
8919
+ addExclude(excludes, element.children);
8920
+ }
8921
+ });
8922
+ // short text element
8923
+ const textWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
8924
+ acceptNode: function (node) {
8925
+ var _a;
8926
+ if (node.matches(operableSelectors) || excludes.indexOf(node) != -1) {
8927
+ // skip
8928
+ return NodeFilter.FILTER_SKIP;
8929
+ }
8930
+ // text <= 100
8931
+ const text = (_a = node.innerText) === null || _a === void 0 ? void 0 : _a.trim();
8932
+ if (isElementVisible(node) &&
8933
+ text &&
8934
+ text.length <= 100 &&
8935
+ text.length > 0 &&
8936
+ node.children.length === 0) {
8937
+ return NodeFilter.FILTER_ACCEPT;
8938
+ }
8939
+ // skip
8940
+ return NodeFilter.FILTER_SKIP;
8941
+ },
8942
+ });
8943
+ let currentNode;
8944
+ while ((currentNode = textWalker.nextNode())) {
8945
+ const id = nextId++;
8946
+ elementMap[id.toString()] = currentNode;
8947
+ const tagName = currentNode.tagName.toLowerCase();
8948
+ elements.push({
8949
+ originalIndex: getElementIndex(currentNode),
8950
+ id: id,
8951
+ html: `<${tagName} id="${id}">${currentNode.innerText.trim()}</${tagName}>`,
8952
+ });
8953
+ }
8954
+ // element sort
8955
+ elements.sort((a, b) => a.originalIndex - b.originalIndex);
8956
+ // cache
8957
+ window.operableElementMap = elementMap;
8958
+ // pseudo html
8959
+ return elements.map((e) => e.html).join('\n');
8960
+ }
8961
+ function clickOperableElement(id) {
8962
+ let element = window.operableElementMap[id];
8963
+ if (!element) {
8964
+ return false;
8965
+ }
8966
+ if (element.click) {
8967
+ element.click();
8968
+ }
8969
+ else {
8970
+ element.dispatchEvent(new MouseEvent('click', {
8971
+ view: window,
8972
+ bubbles: true,
8973
+ cancelable: true,
8974
+ }));
8975
+ }
8976
+ return true;
8977
+ }
8978
+ function getOperableElementRect(id) {
8979
+ let element = window.operableElementMap[id];
8980
+ if (!element) {
8981
+ return null;
8982
+ }
8983
+ const rect = element.getBoundingClientRect();
8984
+ return {
8985
+ left: rect.left + window.scrollX,
8986
+ top: rect.top + window.scrollY,
8987
+ right: rect.right + window.scrollX,
8988
+ bottom: rect.bottom + window.scrollY,
8989
+ width: rect.right - rect.left,
8990
+ height: rect.bottom - rect.top,
8991
+ };
8992
+ }
8993
+
8923
8994
  /**
8924
8995
  * Element click
8925
8996
  */
@@ -9304,4 +9375,4 @@ function getAllTools() {
9304
9375
  return toolsMap;
9305
9376
  }
9306
9377
 
9307
- export { browser, getAllTools, tools };
9378
+ export { getAllTools, tools };