最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Chrome DevTools extension: how to get selected element from elements panel in content script? - Stack Overflow

programmeradmin5浏览0评论

I've done my research and struggled with this for a while, but I need your help.

I'm building a Chrome DevTools extension. It should should pass the currently selected element from the 'Elements' panel as a reference to a JS object defined in a content script.

It is important that I pass the reference to the selected element, or some other way of identifying the element from the content script.

I understand the workflow with 'isolated worlds' in Chrome DevTools. I also understand messaging between extension pages, background page and content scripts. This only happens with JSON primitives, hence no JS scope passing.

How can I pass the element selected in devtools Elements panel to the content script that lives in the inspected page?

Edit

Here's what I know so far:

Getting a reference to the selected element:

chrome.devtools.inspectedWindow.eval("(" + function(){ console.log($0) }.toString() + ")()")
  • That function expression will run in the context of the inspected page, not in the context of the devtools extension and not in the context of the 'isolated world' of the content script. I don't believe it is possible to pass in a reference to a different context using closures.

  • The reference to the selected DOM element $0 can't be returned because it can't be serialized to JSON due to circular references.

  • The chrome.devtools namespace isn't available outside the devtools extension page. The $0 reference can't be used outside the evaluated expression in chrome.devtools.inspectedWindow

Workaround

As a workaround, I chose to use the shared DOM to mark the selected element with a data attribute and use that to re-select it in the context of the content script. Messaging is used to pass the data attribute marker around.

Here's a simplified version of the code:

In the devtools extension page:

// setup a munication port
port = chrome.runtime.connect({name: "devtools"});

chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){

  // expression to run in the context of the inspected page
  var expression = "(" + mark.toString() + ")()"

  // evaluate the expression and handle the result
  chrome.devtools.inspectedWindow.eval(expression, dispatchToContentScript)
});


function mark(){

  // mark the currently selected element
  $0.setAttribute('data-selected')

  // send the marker to the callback
  return { marker: 'data-selected' }
}

function dispatchToContentScript(data){

  // dispatch data to the content script which is listening to the same port.
  port.postMessage(data)
}

In the content script:

var port = chrome.runtime.connect({name: "devtools"});

port.onMessage.addListener(function(data) {

  // re-select the element in the context of the content script
  var el = document.querySelector('['+ data.marker +']')
})

It's not a clean solution but I can use it for my needs.

Is there a simpler way to achieve the same result - identify from a content script the element selected in the devtools 'Elements' panel?

I've done my research and struggled with this for a while, but I need your help.

I'm building a Chrome DevTools extension. It should should pass the currently selected element from the 'Elements' panel as a reference to a JS object defined in a content script.

It is important that I pass the reference to the selected element, or some other way of identifying the element from the content script.

I understand the workflow with 'isolated worlds' in Chrome DevTools. I also understand messaging between extension pages, background page and content scripts. This only happens with JSON primitives, hence no JS scope passing.

How can I pass the element selected in devtools Elements panel to the content script that lives in the inspected page?

Edit

Here's what I know so far:

Getting a reference to the selected element:

chrome.devtools.inspectedWindow.eval("(" + function(){ console.log($0) }.toString() + ")()")
  • That function expression will run in the context of the inspected page, not in the context of the devtools extension and not in the context of the 'isolated world' of the content script. I don't believe it is possible to pass in a reference to a different context using closures.

  • The reference to the selected DOM element $0 can't be returned because it can't be serialized to JSON due to circular references.

  • The chrome.devtools namespace isn't available outside the devtools extension page. The $0 reference can't be used outside the evaluated expression in chrome.devtools.inspectedWindow

Workaround

As a workaround, I chose to use the shared DOM to mark the selected element with a data attribute and use that to re-select it in the context of the content script. Messaging is used to pass the data attribute marker around.

Here's a simplified version of the code:

In the devtools extension page:

// setup a munication port
port = chrome.runtime.connect({name: "devtools"});

chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){

  // expression to run in the context of the inspected page
  var expression = "(" + mark.toString() + ")()"

  // evaluate the expression and handle the result
  chrome.devtools.inspectedWindow.eval(expression, dispatchToContentScript)
});


function mark(){

  // mark the currently selected element
  $0.setAttribute('data-selected')

  // send the marker to the callback
  return { marker: 'data-selected' }
}

function dispatchToContentScript(data){

  // dispatch data to the content script which is listening to the same port.
  port.postMessage(data)
}

In the content script:

var port = chrome.runtime.connect({name: "devtools"});

port.onMessage.addListener(function(data) {

  // re-select the element in the context of the content script
  var el = document.querySelector('['+ data.marker +']')
})

It's not a clean solution but I can use it for my needs.

Is there a simpler way to achieve the same result - identify from a content script the element selected in the devtools 'Elements' panel?

Share Improve this question edited Jul 25, 2016 at 14:09 Xan 77.5k18 gold badges197 silver badges217 bronze badges asked Jun 20, 2013 at 12:54 Razvan CalimanRazvan Caliman 4,6236 gold badges22 silver badges25 bronze badges 6
  • Could you edit your question to include the code used to get a reference to the currently selected element and/or the code which should get the reference? That would make it easier to prehend what you want to achieve. – Rob W Commented Jun 20, 2013 at 13:49
  • I have edited my question to answer your question and to share a workaround. – Razvan Caliman Commented Jun 24, 2013 at 19:39
  • I suggest to post the work-around as an answer. I can think of another solution, but that's a too big hammer, especially since you've got a reasonable work-around. – Rob W Commented Jun 24, 2013 at 21:08
  • Do give me a hint about your solution, please. I've tried in many other ways and failed. – Razvan Caliman Commented Jun 24, 2013 at 21:27
  • stackoverflow./a/17044405/938089 – Rob W Commented Jun 24, 2013 at 21:28
 |  Show 1 more ment

2 Answers 2

Reset to default 10

The API for chrome.devtools.inspectedWindow has been updated to support executing scripts in the context of the content script.

This update in the official Chrome API obsoletes our hacks described above. We can now achieve the expected result with:

chrome.devtools.inspectedWindow.eval("aContentScriptFunction($0)", 
    { useContentScriptContext: true });

The $0 parameter will reference the element selected in the Elements panel.

my way of doing it is sort of a hack too.. instead of injecting a content script defined in your extention you can inject a script tag pointing to your files online (or locally, relative to inspected html ):

//devtools.js
var str = "var s = document.createElement('script');" +
      "s.src = 'http://extentionDomain/extentionFile.js';" +
      "document.body.appendChild(s);";
chrome.devtools.inspectedWindow.eval(str);

online file defines a global:

var myExtention = { doStuff: function(selectedElement){ ..}}

and devtools can call it and pass it the selected element:

chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){
    chrome.devtools.inspectedWindow.eval('myExtention.doStuff($0)');});

however i have not found a way to send a reference back from the inspected window to the devtools extention with this setup.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论