Put xpath to selected element in sidebar extension html

Viewed 139

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?

1 Answers

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,
    });
  });
});
Related