rndm
rndm

Reputation: 379

How to run script with custom global context in Firefox chrome?

I am trying to create extension which work with DOM of some web pages.

I have a code:

document.getElementById("appcontent").addEventListener("DOMContentLoaded", function(e) {
    _this._onPageLoad(e);
}, true);

But in _onPageLoad function my global context is global window (ChromeWindow), not a window with my webpage. How do I can run _onPageLoad with global context of window where event was fired (webpage) and pass arguments here?

Thank you.

Upvotes: 1

Views: 343

Answers (2)

rndm
rndm

Reputation: 379

My solution:

Lpr2.prototype._evalInSandbox = function(script, doc, data) {
    var sandbox = new Components.utils.Sandbox(doc.defaultView);
    sandbox.unsafeWindow = doc.defaultView.window.wrappedJSObject;
    sandbox.window = doc.defaultView.window;
    sandbox.document = sandbox.window.document;
    sandbox.__proto__ = sandbox.window;
    var functionName = 'execute_' + script.name;
    var functionText = 'function ' + functionName + script.run.toString().substring(8);
    functionText += '; window.lpr2data = ' + JSON.stringify(data) + '; ' + functionName + '(window, document, Zepto);';
    Services.scriptloader.loadSubScript('chrome://*/content/lib/zepto.min.js', sandbox, 'UTF–8');
    Components.utils.evalInSandbox(functionText, sandbox);
}

Bad, but this is only one working solutuion for me.

Upvotes: 0

nmaier
nmaier

Reputation: 33162

Well, overlay scripts run in the context of the top-level window, i.e. the ChromeWindow.

However, you somewhat simulate another context.

_this._onPageLoad = function(window, document, e) {
  // Called as .call(window, window, window.document, e);
  // this === window === <content window>
  // document === <content document>
}; 

document.getElementById("appcontent").addEventListener("DOMContentLoaded", function(e) {
    let win = e.originalTarget;
    if (win.ownerDocument) {
      win = win.ownerDocument;
    }
    if (win.defaultView) {
      win = win.defaultView;
    }
    _this._onPageLoad.call(win, win, win.document, e);
}, true);

This would call your _onPageLoad with a proper this, window and document belonging to the document that the event indicates the load of. This scheme will not really reset the global, however, so addEventListener would still refer to the top-level window. Also, the script would not run in a sandbox, and would still have full privileges. So in the end, this just adds a bit more convenience.

It would also be possible to set up and use a real Sandbox, however that is kind of complicated. The basic idea would be to choose the appropriate principal (fully privileged, or content-privilged), constructing a sandbox and supplying the content window as the sandboxPrototype and the calling .evalInSandbox(...). This is more or less what the SDK does internally for content scripts... However, this is usually overkill unless you need a real and proper security boundary (e.g. need to execute user-provided or remote scripts).

Upvotes: 1

Related Questions