Eduardo Almeida
Eduardo Almeida

Reputation: 171

Cannot call iframe function from parent (firefox addon)

I´m developing a firefox addon and one of the features I need is inject a pop-up element inside the page the user is navigating.

I tried injecting a DIV in the body but I had problems with my DIV inhering the page CSS and the pop-up show different in every page, so I decied to add it inside an iframe.

Here is the addon code: main.js

    exports.main = function() {};

var page_mod            = require("page-mod");  
var data                = require("self").data;
var self                = require("self"); 

function initPageMod()
{
      myPageMod = page_mod.PageMod({
          include: ['*'],
          contentScriptWhen: "start",
          contentScriptFile: [data.url("jquery.js"), data.url("modPage.js")],
           onAttach: function(worker) {
            worker.port.emit("inject", data.load("iframecontent.html"));
           }
        });
}

initPageMod();

What I do here is install a page-mod on every page, inject jquery and my modPage.js and call the "inject" port when attached. iframecontent.html:

<html>
    <head>
    <title>title</title>
    <script type="text/javascript">
        window.showPopup = function() {
        }
    </script>
    </head>
    <body>
        body
    </body>
</html>

This is a very simple HTML file with a script tag that defines the showPopup function that I want to call from the parent document.

modPage.js:

self.port.on("inject", function(iframeContent) {
    $(function(){
        if(window.frameElement == null) {
            $('body').append(
                '<div id="myExternalDiv" style="position:fixed;width:2560;height:auto;float:left;left:0px;top:0px;z-index:2147483647;overflow-x:hidden;overflow-y:hidden;background: transparent;margin: 0px;padding: 0px;">' +
                '<iframe id="myMagicIframe" width="100%" height="100%" frameborder="0" style="width:100%; overflow-y: hidden;background-color:transparent;" scrolling="no" marginheight="0" frameborder="0" allowtransparency="true" onload="alert(1)"></iframe>' +
                '</div>'
            );

            try {
                var oIframe = document.getElementById("myMagicIframe");
                var iframeDoc = (oIframe.contentWindow.document || oIframe.contentDocument);

                iframeDoc.open();
                iframeDoc.write(iframeContent);
                iframeDoc.close();
            } catch (err) {
                alert(err);
            }

            setTimeout(function(){func()}, 5000);          
        }
    });
});

function func() {
    if (document.getElementById("myMagicIframe") != null) {
        try {
            document.getElementById("myMagicIframe").contentWindow.showPopup();
        }catch(err) {
            alert(err);
            setTimeout(function(){func()}, 1000);
        }
    }
}

The "inject" creates an iframe inside a div, writes the iframecontent inside it and calls the func function after 5 seconds. What is happening is that I´m receiving the following exception: "showPopup is not a function". the document.getElementById("myMagicIframe").contentWindow.showPopup is undefined.

If I add the above code in a HTML and run it in firefox it works and calls the showPopup function but inside the addon it is not working.

I´m using addon builder: https://builder.addons.mozilla.org/package/159673/latest/

Thank you

Upvotes: 2

Views: 1775

Answers (2)

Eduardo Almeida
Eduardo Almeida

Reputation: 171

First thank you to canuckistani for letting me know of the proxy concept. When you add a page-mod you script will run on a sandbox and the variables you use are proxies.

Changing the following file:

document.getElementById("myMagicIframe").contentWindow.showPopup();

to

document.getElementById("myMagicIframe").contentWindow.wrappedJSObject.showPopup();

solved the problem.

My iframe was being added in the page so the showPopup function was being added in the real window object. The currentWindow object was a proxy and did not have the added function. Using the wrappedJSObject object I was able to get the real window object and call the function.

Upvotes: 2

therealjeffg
therealjeffg

Reputation: 5830

This is happening because, as with any page where iframes are loaded from different servers ( or in this case, via a resource uri ) you cannot get access across the frame boundary to the other document.

My best suggestion would be to have a content script attached to the iframe send a message back into main.js, which can then route the message to a content script attached to the parent document. It's indirect, but it will work.

For more info:

An example of something similar, but using a panel:

https://builder.addons.mozilla.org/package/159682/latest/

Docs on using content scripts:

https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/guides/content-scripts/index.html

Upvotes: 1

Related Questions