2

So I'm trying to develop a chrome extension that will export a list of xpaths of selected elements from a page. However, I'm not being able to compute the xpath of the current selected element in the devtools panel.

I tried using the getPathTo from this answer, but the function can't access the reference to element $0.

With this code I can print the tag of the new selected element:

chrome.devtools.panels.elements.onSelectionChanged.addListener(function () {
    var expression = "(function(){console.log($0);})()"
    chrome.devtools.inspectedWindow.eval(expression)
});

But if I try:

chrome.devtools.panels.elements.onSelectionChanged.addListener(function () {
    var expression = "(function(){console.log(getPathTo($0));})()"
    chrome.devtools.inspectedWindow.eval(expression)
});

It complains of undefined reference to $0.

The code also have this function to set the sidebar HTML:

chrome.devtools.panels.elements.createSidebarPane(
    "Chrome Extension",
    function (sidebar) {
        sidebar.setPage("sidebar/sidebar.html");
    }
);

And sidebar/sidebar.html is a simple HTML page with an item list inside it, where I want to add the path of all selected elements, and a button to copy the list to the clipboard. How can I use the reference to the selected element inside the function? Also, how could I pass the results to the HTML page?

  • Conceptually both expressions are the same so the observed behavior definitely looks like a bug, which I can't reproduce though (the code works for me) so I guess you didn't define `getPathTo` in the page context as eval runs in page context unless you indicate otherwise, see the documentation. – wOxxOm Apr 08 '20 at 19:56
  • @wOxxOm I'm really having a hard time with the documentation and lack of examples... How to define getPathTo in the page context? Also, if I pass { useContentScriptContext: true } as a parameter to eval, I see no error message and no log message... Seems like nothing is happening. – Gabriel Cardoso Apr 10 '20 at 13:47
  • I mean the lack of examples using inspectedWindow. I know there is a samples page, but there is not a single example there using this functionality, and the code snippets in the documentation are not being of much help. – Gabriel Cardoso Apr 10 '20 at 14:12
  • The documentation says you need to have a content script running in the page so I guess you didn't have it. – wOxxOm Apr 10 '20 at 14:13
  • The second part, the message between the scripts, I found [here](https://stackoverflow.com/questions/25128330/how-to-i-send-selected-element-from-devtools-page-to-chrome-sidebar-page/36841655) – Gabriel Cardoso Apr 14 '20 at 13:34

1 Answers1

0

chrome.devtools.inspectedWindow.eval runs in the tab page environment, not in the extension's environment. The web page is a totally different context with its own document, DOM, window, global variables, and so on. To be able to call getPathTo there you need to put it there.

chrome.devtools.inspectedWindow.eval(`(${() => {
  console.log(getPathTo($0));
  function getPathTo(element) {
    // ...................
    // ..... code
    // ...................
  }
}})()`);

Safer approach

By default eval() runs in page context so on some pages your code may fail if they override or mangle standard objects and prototypes. You can run the code in the isolated world of content scripts instead:

chrome.devtools.panels.elements.onSelectionChanged.addListener(() => {
  chrome.tabs.executeScript({
    code: `function getPathTo(element) {
      // ...................
      // ..... code
      // ...................
    }`,
    runAt: 'document_start',
  }, () => {
    chrome.devtools.inspectedWindow.eval(`(${() => {
      console.log(getPathTo($0));
    }})()`, {
      useContentScriptContext: true,
    });
  });
});
wOxxOm
  • 65,848
  • 11
  • 132
  • 136