Reputation: 379
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
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
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