2

I'm looking for a bit of help here as the examples I've seen have only been from the tab to the extension and not the other way around.

I'm looking to grab the source code of a page/tab that I am debugging with a custom Chrome Extension. I want the extension to call a message and the response to be sent back to the extension panel javascript making the call.

Manifest

"permissions": [
  "tabs",
  "<all_urls>",
  "debugger"
],
"background": {
  "scripts": ["background.js"],
  "persistent": false
},
"content_scripts": [
  {
  "matches": ["<all_urls>"],
  "js": ["content.js"]
  }
],

background.js

chrome.browserAction.onClicked.addListener(function() {
  chrome.tabs.query({active:true, windowId:chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
    debuggee = {tabId:tabs[0].id};
chrome.debugger.attach(debuggee, version, onAttach.bind(null, tabs[0].id));
  });
});

function onAttach(tabId) {
  chrome.windows.create({url: "spy.html?" + tabId, type: "panel", width: 900, height: 700}, function(window) {
    winId = window.id;
});

content.js

chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.data == "getHTML") {
      sendResponse({data: document.getElementById('header').innerHTML});
  }
});

spy.html

<script src="spy.js" type="text/javascript"></script>

spy.js

window.addEventListener("load", function() {
  chrome.debugger.sendCommand({tabId:tabId}, "DOM.getDocument");
  chrome.debugger.onEvent.addListener(onEvent);
});

function onEvent(debuggeeId, message, params) {    
  if (message=="DOM.documentUpdated") {
    chrome.tabs.sendMessage(tabId, {data: "getHTML"}, function(response) {console.log(response.data);});
  }

Result

Port error: Could not establish connection. Receiving end does not exist. miscellaneous_bindings:235 chromeHidden.Port.dispatchOnDisconnect miscellaneous_bindings:235

Error in event handler for 'undefined': Cannot read property 'data' of undefined TypeError: Cannot read property 'data' of undefined
at chrome-extension://fpdkndicjblnkakkiiapbbdflkehjmgm/headers.js:132:91
at miscellaneous_bindings:279:11
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at Object.chromeHidden.Port.dispatchOnDisconnect (miscellaneous_bindings:238:27)

I get this error when I try to run it. What am I missing?

12
  • Where's the background.js? Commented Jan 7, 2013 at 22:27
  • I've updated the initial post. Thanks for looking. Commented Jan 8, 2013 at 15:09
  • @ilya: windows.getCurrent and tabs.getSelected are deprecated and chrome.debugger.attach has only two arguments Commented Jan 8, 2013 at 15:28
  • @Sudarshan so should I just rework the flow to match your answer. i.e remove the "background" in the manifest and add the popup.html to the browser action? I have other code in the background.js, mostly listeners. 1) chrome.windows.onRemoved -> Detach debugger 2) chrome.debugger.onDetach -> Remove popup window Commented Jan 8, 2013 at 15:32
  • @Sudarshan BTW you can specify a callback for the attach - developer.chrome.com/extensions/debugger.html#method-attach Commented Jan 8, 2013 at 15:35

2 Answers 2

1

How are you capturing tabId of chrome.tabs.sendMessage(tabId,, can you post your full script to debug problem,if you are looking for a sample code for passing message from Chrome Extension to Debugging Tab check this.

References

manifest.json

Registered popup page and content scripts.

{
 "name": "Pass message from Chrome Extension to Debugging Tab",
 "version": "1",
 "description": "http://stackoverflow.com/questions/14205155/how-can-i-pass-a-message-from-my-chrome-extension-to-debugging-tab",
 "browser_action": {
   "default_title": "Selected Text",
   "default_popup": "popup.html" 
 },
 "permissions": [
   "tabs",
   "<all_urls>"
 ],
 "content_scripts": [
  {
    "matches": ["<all_urls>"],
    "js": ["selection.js"]
  }
 ],
 "manifest_version": 2
}

popup.html

Ensured HTML Adheres to CSP

<!DOCTYPE html>
<html>

    <head>
        <style>
            body {
                width: 300px;
            }
            textarea {
                width: 250px;
                height: 100px;
            }
        </style>
        <script src="popup.js"></script>
    </head>

    <body>
          <button id="submit">Pass Message</button>
    </body>

</html>

popup.js

Pass Message to Content Scripts.

function passMessage() {
    //Select current tab to send message
  chrome.tabs.query({"active":true,"currentWindow":true,"status":"complete","windowType":"normal"}, function(tabs) {
  //It returns array so looping over tabs result
    for(tab in tabs){

    //Send Message to a tab
    chrome.tabs.sendMessage(tabs[tab].id, {method: "Hi Content Script"});
    }   
});
}


// Bind On click event to passMessage() function
document.addEventListener("DOMContentLoaded",function (){

    document.getElementById("submit").onclick = passMessage;
});

selection.js

Added a handler to catch messages sent from popup page

 //Add a handler to handle message sent from popup.html
 chrome.extension.onMessage.addListener(function(request, sender) {
    console.log("Message "+request+" is recieved");

});

EDIT:

I got your code working after eliminates some deprecated API() like sendResponse

background.js

chrome.browserAction.onClicked.addListener(function () {
    version = "1.0";
    chrome.tabs.query({
        active: true,
        windowId: chrome.windows.WINDOW_ID_CURRENT
    }, function (tabs) {
        debuggee = {
            tabId: tabs[0].id
        };
        chrome.debugger.attach(debuggee, version, onAttach.bind(null, tabs[0].id));
    });
});

function onAttach(tabId) {
    chrome.windows.create({
        url: "spy.html?" + tabId,
        type: "panel",
        width: 900,
        height: 700
    }, function (window) {
        winId = window.id;
    });
}

content.js

chrome.extension.onMessage.addListener(function (request, sender) {
    console.log("Message recieved");
    if (request.data == "getHTML") {
        chrome.extension.sendMessage({
            "data": "Some Stuff"
        });
    }
});

spy.js

tabId = parseInt(window.location.search.substring(1));
window.addEventListener("load", function () {

    chrome.debugger.sendCommand({
        tabId: tabId
    }, "DOM.getDocument");
    chrome.debugger.onEvent.addListener(onEvent);
});

function onEvent(debuggeeId, message, params) {
    if (message == "DOM.documentUpdated") {
        chrome.tabs.sendMessage(tabId, {
            "data": "getHTML"
        });
    }
}
chrome.extension.onMessage.addListener(function (response, sender) {
    console.log(response);
});

How ever ensure you do not trigger developer tools manually during testing.

Sign up to request clarification or add additional context in comments.

6 Comments

TabId is set by the background.js file that is attaching the debugger and opening the popup. I'll add the code to the original post. I tried just changing the manifest to include the "<all_urls>", but the rest seems to fit the same. The only other difference is that you are loading the popup as a browser action, while I'm using the background.js to load the popup.
@ilya: You are not loading popup you are creating a new window of type panel, how ever you can bind your debugger session after creating a new panel
That is correct. I have changed the terminology since I tried your method and i DON'T want a default popup for the extension, but rather a new frame to display the results.
I was able to implement what you corrected, but this doesn't work as expected. The chrome.tabs.sendMessage(tabId, {"data": "getHTML"}); does not get called within the function... or if it does there is nothing listening. When the page is finally done loading, i can manually send the message via console and only then do I get something back. Any ideas why this isn't happening? Is there a different tOt value to find out when the DOM has been fully loaded than Dom.documentUpdated?
@ilya: Can you explain what is not working as per expectations?, i tested this and i was able to trace debugger events; What is you want to track?
|
1

OK I've figured it out. Since I need the DOM of the loaded page, I'm going to use the chrome.tabs.onUpdated.addListener in my background page to send the code when the page is loaded. This way I don't have to depend on the 2 way communication between the tab and extension.

Manifest

Removed content.js

background.js

Added the following

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  if (tabId != _tabId) {return;}
  if (changeInfo.status == "complete") {
    chrome.tabs.executeScript(tabId, {code:"var x = document.documentElement.innerHTML;x"}, function (r) {
      chrome.extension.sendMessage(null, {"data": r[0]});       
    });
  }
});

content.js

REMOVED

spy.js

Added the following

chrome.extension.onMessage.addListener(function(request, sender) {
  console.log("Request.data: " + request.data);
});

1 Comment

Changing the title to help others

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.