1

I have a method in the Javascript runtime for a tab that I want to fire from my extension's content script. At face value, this calls for message passing between contexts, but I cannot find any documentation of CS-to-tab messages, only tab-to-CS or CS-to-background. Essentially I want to flip the Communication with the embedding page section of the content scripts reference.

So far, I am attaching an event listener to the tab's window by injecting a small Javascript payload (this will trigger the tab method on the correct type of message):

listenerScript = document.createElement('script');
listenerScript.textContent = "window.addEventListener('message',function(ev){console.log('New event: ' + ev);},false);console.log('installed');";
(document.head||document.documentElement).appendChild(listenerScript);
listenerScript.remove();

This listener is registered, however I can't figure out how to trigger it from my content script. window.postMessage() in the content script doesn't seem to do anything, and the documentation only talks about using chrome.runtime to create a port, which is for background scripts.

How do I pass messages, in the simplest way possible, from content script to tab?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
RedBassett
  • 3,469
  • 3
  • 32
  • 56
  • The documentation you've linked shows `window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");` and it works for me. Just don't forget the `"*"`. – wOxxOm Sep 19 '16 at 21:12
  • From a content script? I tried that exact code you quoted with the snippet above injected into the page, and it is not logging anything. Remember that I am trying to go `CS->page`, not `page->CS`. – RedBassett Sep 19 '16 at 21:15
  • Here is my test extension: https://github.com/redbassett/extension-message-test I see the log messages for the injected script being installed and the message being sent, but the event listener never triggers. – RedBassett Sep 19 '16 at 21:32

1 Answers1

5

The code is correct, so, considering you see installed in the console, the only explanations are:

  1. the page was redirected and the entire DOM and its listeners were destroyed.
  2. the page has spoofed window.addEventListener or attached its own 'message' listener and cancels the event before your listener sees it (e.g. by using event.stopPropagation() etc.)

    In this case you need to declare your content script to run before the page starts loading and use a listener that captures the event before it bubbles down the DOM chain (useCapture, the 3rd parameter of addEventListener, should be true).

    manifest.json:

    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["content.js"],
        "run_at": "document_start"
    }],
    

    content.js:

    // this code runs before page starts loading
    var injected = document.documentElement.appendChild(document.createElement('script'));
    injected.text = '(' + function() {
        window.addEventListener('message', function(ev) {
            console.log('New event:', ev);
        }, true); // useCapture: true
        console.log('installed');
    } + ')()';
    injected.remove();
    
    document.addEventListener('DOMContentLoaded', function() {
        // this code will run when the DOM is ready
        window.postMessage({ foo: 'bar', text: "Hello from content script!" }, "*");
    });
    

    Note we add the script to documentElement because at document_start there's often no head. See also: other methods of injecting a DOM script.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • That was an artifact of copying the code from another test. Good catch, but it still doesn't fix the issue. Pushed the correct version with `message` to the repo, still doesn't log anything in response to the message. – RedBassett Sep 19 '16 at 21:40
  • 1
    Using `'message'` the code works. As it should. Make sure the page isn't redirected to a new URL. – wOxxOm Sep 19 '16 at 21:43
  • The redirect may be the issue! I tested this on a different host domain and the message shows. It would seem that the injected script is in fact being disconnected. Post as a new answer so I can accept it? – RedBassett Sep 19 '16 at 21:46