how to append iframe to hosted page using Firefox

2020-04-08 03:42发布

问题:

Assume frame.html inside data folder in Firefox SDK addon, how to append an iframe and define frame.html as its source?

Additional info: Because of CPS, its not possible to use inline source, so I can't use data.load('frame.html'), I need to use URL of the file:

lib/main.js

tabs.activeTab.attach({
  contentScriptFile: [self.data.url("js/appender.js") ],
  attachTo: 'top',
  contentScriptOptions: {
    scriptUrl: self.data.url("js/sandbox.js"),
    imageUrl: self.data.url("image.jpg")
    frameUrl: self.data.url("sandbox.html")
  }
});

data/appender.js

  var scriptTag = document.createElement("script");
  scriptTag.src = self.options.scriptUrl;
  document.body.appendChild(scriptTag); // worked fine

  var imageTag = document.createElement("image");
  imageTag.src = self.options.imageUrl;
  document.body.appendChild(imageTag); // worked fine

  var iframeTag = document.createElement("iframe");
  iframeTag.src = self.options.frameUrl;
  document.body.appendChild(iframeTag); // the html tag of iframe is empty

回答1:

It's blank because of the firefox security policy which doens't allow content scripts to load resources URLs as iframes. The solution could be to set it directly from the background script, for this you'll need to use low level sdk.

var { viewFor } = require("sdk/view/core");
var tab_utils = require("sdk/tabs/utils");

var iframe = viewFor(tab).linkedBrowser._contentWindow.document.querySelector('iframe[src="' + self.data.url("sandbox.html") + '"]')
iframe.contentWindow.location.href = iframe.getAttribute("src")

so the completely working code would look like:

data/appender.js

var iframeTag = document.createElement("iframe");
iframeTag.src = self.options.frameUrl;
document.body.appendChild(iframeTag); // the html tag of iframe is empty

// note that the iframe is attached after the content ready event, so you have to inform the background when it can start working with the iframe
self.port.emit("attached", true);

main.js

tabs = require("sdk/tabs")
self = require("sdk/self")

var { viewFor } = require("sdk/view/core");
tab_utils = require("sdk/tabs/utils");

tabs.on("ready", function(tab) {
  var worker = tab.attach({
    contentScriptFile: [self.data.url("js/appender.js") ],
    attachTo: 'top',
    contentScriptOptions: {
      frameUrl: self.data.url("sandbox.html")
    }
  });

  worker.port.on('attached', function() {
    reinitIframe(tab)
  });

  function reinitIframe(tab) {
    var iframe = viewFor(tab).linkedBrowser._contentWindow.document.querySelector('iframe[src="' + self.data.url("sandbox.html") + '"]')
    iframe.contentWindow.location.href = iframe.getAttribute("src")
  }
})

You'll probably need a cross-process wrapper in order to make it work in future version of Firefox with electrolysis



回答2:

Found a better way. You add a blank <iframe> and attach an event listener for the load event. Then you can easily append whatever elements you want to the iframe as usual.

Include this in your content-script:

var iframe = document.createElement('iframe'),
  div = document.createElement('div');
div.textContent('Hello World');
document.body.appendChild(iframe);
iframe.addEventListener('load', function(){
  this.contentWindow.document.body.appendChild(div)
})