Search code examples
javascriptfirefox-addon-sdkmessage-passing

How to communicate with a webpage via browser plugin


How can I communicate from a JavaScript code of a webpage to the main code of the add-on?

For example, something like this: If some element is clicked, in the corresponding event handler of the page script, which is the syntax that can be used to send some message to the main code?

Specifically, something like this, where the frame now must be replaced by a generic webpage. Is it possible?

Edit: I have tried the suggested code, but how I had said, the application returns this error:

console.error: sherlock: Message: ReferenceError: document is not defined Stack: A coding exception was thrown in a Promise resolution callback. See https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise
Full message: ReferenceError: document is not defined

Previously my question, I had infact tried something similar without any effect.


Solution

  • The answer to the question is not as trivial as it may seem at first sight. I had also thought of a logic of the type described in the Pogrindis' response.

    But here, in the case of interaction between the main script (i.e. that of the add-on) and generic script of arbitrary documents, the pattern is different.

    In summary, the interaction takes place in this way:

    • It is required the API page-mod.
    • Through the property includes of the object PageMod you create a reference to the document, specifying the URI (wildcards are allowed).
    • Via the contentScriptFile property it is set the URL of the .js file that will act as a vehicle between the main code and that of the document.

    Here's an example that refers to the specific needs of the context in which I am. We have:

    • an add-on code (the main code);
    • a Sidebar type html document (gui1.html) loaded in the file that I use as a simple UI (I advise against the use of Frames, since it does not support many typical HTML features - eg the click on a link, etc.) containing a link to a second document (gui2.html) which will then be loaded into the browser tab (I needed this trick because the Sidebar does not support localStorage, while it is necessary for me);
    • a script in the document.

    We must create an exchange of information between the two elements. In my case the exchange is unidirectional, from the page script to the main one.

    Here's the code (main.js):

    var pageMod = require("sdk/page-mod");
    pageMod.PageMod({
        include: "resource://path/to/document/gui2.html",
        contentScriptFile: data.url("listen.js"),
        onAttach: function(worker) {
            worker.port.on("gotElement", function(elementContent) {
                console.log(elementContent);
            });
        }
    });
    

    and in the html page script:

    <script type="text/javascript">
    
    [...]
    
    SOWIN = (navigator.userAgent.toLowerCase().indexOf("win") > -1) ? "win" : "nix";
                if (SOWIN == "win") {
                window.postMessage("win","*");
                } else {
                window.postMessage("Linux","*");
                }
    [...]
    
    </script>
    

    Finally in the JS file (listen.js) to be attached to the page script:

    window.addEventListener('message', function(event) {
       self.port.emit("gotElement", event.data);
    }, false);
    

    This is just a small example, but logic I would say that it is clear. The uploaded content scripts are not accessible directly from main.js (i.e. the add-on), but you can create a bidirectional communication through the exchange of messages. To achieve this we have to put ourselves in listening the event Attach of the page-mod. Then, it is passed a worker object to the listener; that worker may be used by the add-on for the exchange of messages.

    Here are the references to have an exhaustive picture:

    Interacting with page scripts

    Communicating with other scripts

    page-mod

    port

    Communicating using "port"

    postMessage

    Communicating using postMessage