[Pkg-mozext-commits] [greasemonkey] 11/43: Sloppily migrate document-element-inserted observer into a JSM.
David Prévot
taffit at moszumanska.debian.org
Sun Feb 22 21:56:10 UTC 2015
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository greasemonkey.
commit f82a7e813a3280f89cba16c60ccb340b688b468a
Author: Anthony Lieuallen <arantius at gmail.com>
Date: Fri Oct 31 15:29:34 2014 -0400
Sloppily migrate document-element-inserted observer into a JSM.
As suggested: http://bugzil.la/1048164#c27
---
content/framescript.js | 196 ++++----------------------------------
modules/contentObserver.js | 230 +++++++++++++++++++++++++++++++++++++++++++++
modules/sandbox.js | 35 ++++---
3 files changed, 263 insertions(+), 198 deletions(-)
diff --git a/content/framescript.js b/content/framescript.js
index a1c0678..fa9ada0 100644
--- a/content/framescript.js
+++ b/content/framescript.js
@@ -5,17 +5,16 @@ var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import('resource://greasemonkey/GM_setClipboard.js');
-Cu.import("resource://greasemonkey/ipcscript.js");
-Cu.import("resource://greasemonkey/miscapis.js");
-Cu.import("resource://greasemonkey/sandbox.js");
-Cu.import('resource://greasemonkey/util.js');
+//var gScriptRunners = {};
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-var gStripUserPassRegexp = new RegExp('(://)([^:/]+)(:[^@/]+)?@');
-var gScriptRunners = {};
+// For every frame/process, make sure the content observer is running.
+
+Cu.import('resource://greasemonkey/contentObserver.js');
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
function ScriptRunner(aWindow, aUrl) {
this.menuCommands = [];
@@ -24,31 +23,6 @@ function ScriptRunner(aWindow, aUrl) {
this.url = aUrl;
}
-ScriptRunner.prototype.injectScripts = function(aScripts) {
- try {
- this.window.QueryInterface(Ci.nsIDOMChromeWindow);
- // Never ever inject scripts into a chrome context window.
- return;
- } catch(e) {
- // Ignore, it's good if we can't QI to a chrome window.
- }
-
- var winIsTop = true;
- try {
- this.window.QueryInterface(Ci.nsIDOMWindow);
- if (this.window.frameElement) winIsTop = false;
- } catch (e) {
- // Ignore non-DOM-windows.
- dump('Could not QI this.window to nsIDOMWindow at\n'
- + this.url + ' ?!\n');
- }
-
- for (var i = 0, script = null; script = aScripts[i]; i++) {
- if (script.noframes && !winIsTop) continue;
- var sandbox = createSandbox(script, this);
- runScriptInSandbox(script, sandbox);
- }
-}
ScriptRunner.prototype.openInTab = function(aUrl, aInBackground) {
var response = sendSyncMessage('greasemonkey:open-in-tab', {
@@ -57,7 +31,8 @@ ScriptRunner.prototype.openInTab = function(aUrl, aInBackground) {
});
return response ? response[0] : null;
-}
+};
+
ScriptRunner.prototype.registeredMenuCommand = function(aCommand) {
var length = this.menuCommands.push(aCommand);
@@ -69,158 +44,19 @@ ScriptRunner.prototype.registeredMenuCommand = function(aCommand) {
name: aCommand.name,
windowId: aCommand.contentWindowId
});
-}
-
-var observer = {
- observe: function(aSubject, aTopic, aData) {
- if (!GM_util.getEnabled()) return;
-
- switch (aTopic) {
- case 'document-element-inserted':
- var doc = aSubject;
- var win = doc && doc.defaultView;
-
- if (!doc || !win) break;
-
- // Listen for load event (which unlike DOMContentLoaded can't be done
- // globally), as some documents (e.g. images) don't fire DCL.
- win.addEventListener("load", contentLoad, true);
-
- // TODO:
- // Sometimes we get this notification twice with different windows but
- // identical documentURI/location.href. In one of those cases, the call
- // to sendSyncMessage will throw, and I can't find a way to detect which
- // notification is the correct one. if (win !== content) would also
- // exclude iframes.
- this.runScripts('document-start', win);
- break;
- case 'inner-window-destroyed':
- // Make sure we don't keep any window references around
- var windowId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
- delete gScriptRunners[windowId];
- break;
- default:
- dump("received unknown topic: " + aTopic + "\n");
- }
- },
-
- contentLoad: function(aEvent) {
- var contentWin = aEvent.target.defaultView;
- contentWin.removeEventListener("load", contentLoad, true);
-
- if (!GM_util.getEnabled()) return;
- this.runScripts('document-end', contentWin);
- },
-
- pagehide: function(aEvent) {
- var contentWin = aEvent.target.defaultView;
- var windowId = GM_util.windowId(contentWin);
- if (!windowId || !gScriptRunners[windowId]) return;
-
- // Small optimization: only send a notification if there's a menu command
- // for this window.
- if (!gScriptRunners[windowId].menuCommands.length) return;
-
- if (aEvent.persisted) {
- sendAsyncMessage("greasemonkey:toggle-menu-commands", {
- frozen: true,
- windowId: windowId
- });
- } else {
- sendAsyncMessage("greasemonkey:clear-menu-commands", {
- windowId: windowId
- });
- }
- },
-
- pageshow: function(aEvent) {
- var contentWin = aEvent.target.defaultView;
- var windowId = GM_util.windowId(contentWin);
- if (!windowId || !gScriptRunners[windowId]) return;
-
- if (!gScriptRunners[windowId].menuCommands.length) return;
-
- sendAsyncMessage("greasemonkey:toggle-menu-commands", {
- frozen: false,
- windowId: windowId
- });
- },
-
- runScripts: function(aRunWhen, aWrappedContentWin) {
- // See #1970
- // When content does (e.g.) history.replacestate() in an inline script,
- // the location.href changes between document-start and document-end time.
- // But the content can call replacestate() much later, too. The only way to
- // be consistent is to ignore it. Luckily, the document.documentURI does
- // _not_ change, so always use it when deciding whether to run scripts.
- var url = aWrappedContentWin.document.documentURI;
- // But ( #1631 ) ignore user/pass in the URL.
- url = url.replace(gStripUserPassRegexp, '$1');
-
- if (!GM_util.isGreasemonkeyable(url)) return;
-
- var windowId = GM_util.windowId(aWrappedContentWin);
- if (gScriptRunners[windowId]) {
- // Update the window in case it changed, see the comment in observe().
- gScriptRunners[windowId].window = aWrappedContentWin;
- } else {
- gScriptRunners[windowId] = new ScriptRunner(aWrappedContentWin, url);
- }
-
- var response = sendSyncMessage('greasemonkey:scripts-for-url', {
- 'url': url,
- 'when': aRunWhen,
- 'windowId': windowId
- });
-
- if (!response || !response[0]) return;
- var scripts = response[0].map(this.createScriptFromObject);
- gScriptRunners[windowId].injectScripts(scripts);
- },
-
- runDelayedScript: function(aMessage) {
- var windowId = aMessage.data.windowId;
- if (!gScriptRunners[windowId]) return;
-
- var script = this.createScriptFromObject(aMessage.data.script);
- gScriptRunners[windowId].injectScripts([script]);
- },
-
- runMenuCommand: function(aMessage) {
- var windowId = aMessage.data.windowId;
- if (!gScriptRunners[windowId]) return;
-
- var index = aMessage.data.index;
- var command = gScriptRunners[windowId].menuCommands[index];
- if (!command || !command.commandFunc) return;
-
- // Ensure |this| is set to the sandbox object inside the command function.
- command.commandFunc.call(null);
- },
-
- createScriptFromObject: function(aObject) {
- var script = Object.create(IPCScript.prototype);
- // TODO: better way for this? Object.create needs property descriptors.
- for (var key in aObject)
- script[key] = aObject[key];
-
- return script;
- }
-}
+};
-var observerService = Cc['@mozilla.org/observer-service;1']
- .getService(Ci.nsIObserverService);
-observerService.addObserver(observer, 'document-element-inserted', false);
-observerService.addObserver(observer, 'inner-window-destroyed', false);
-
-// Used for DOMContentLoaded here and load in observer.observe.
-var contentLoad = observer.contentLoad.bind(observer);
-addEventListener("DOMContentLoaded", contentLoad, true);
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+/*
addEventListener("pagehide", observer.pagehide.bind(observer));
addEventListener("pageshow", observer.pageshow.bind(observer));
+*/
+
+/*
addMessageListener("greasemonkey:inject-script",
observer.runDelayedScript.bind(observer));
addMessageListener("greasemonkey:menu-command-clicked",
observer.runMenuCommand.bind(observer));
+*/
diff --git a/modules/contentObserver.js b/modules/contentObserver.js
new file mode 100644
index 0000000..848b3f4
--- /dev/null
+++ b/modules/contentObserver.js
@@ -0,0 +1,230 @@
+var EXPORTED_SYMBOLS = ['contentObserver'];
+
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+Cu.import('resource://greasemonkey/GM_setClipboard.js');
+Cu.import("resource://greasemonkey/ipcscript.js");
+Cu.import("resource://greasemonkey/miscapis.js");
+Cu.import("resource://greasemonkey/sandbox.js");
+Cu.import('resource://greasemonkey/util.js');
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+var gStripUserPassRegexp = new RegExp('(://)([^:/]+)(:[^@/]+)?@');
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+function ContentObserver() {
+}
+
+
+ContentObserver.prototype.QueryInterface = XPCOMUtils.generateQI([
+ Ci.nsIObserver]);
+
+
+ContentObserver.prototype.createScriptFromObject = function(aObject) {
+ var script = Object.create(IPCScript.prototype);
+ // TODO: better way for this? Object.create needs property descriptors.
+ for (var key in aObject) {
+ script[key] = aObject[key];
+ }
+ return script;
+};
+
+
+ContentObserver.prototype.contentLoad = function(aEvent) {
+ // Now that we've seen any first load event, stop listening for any more.
+ aEvent.target.removeEventListener("DOMContentLoaded", gContentLoad, true);
+ aEvent.target.removeEventListener("load", gContentLoad, true);
+
+ var contentWin = aEvent.target.defaultView;
+ this.runScripts('document-end', contentWin);
+};
+
+
+ContentObserver.prototype.observe = function(aSubject, aTopic, aData) {
+ if (!GM_util.getEnabled()) return;
+
+ switch (aTopic) {
+ case 'document-element-inserted':
+ if (!GM_util.getEnabled()) return;
+
+ var doc = aSubject;
+ var url = doc.documentURI;
+ if (!GM_util.isGreasemonkeyable(url)) return;
+
+ var win = doc && doc.defaultView;
+ if (!doc || !win) break;
+
+ // Listen for whichever kind of load event arrives first.
+ win.addEventListener("DOMContentLoaded", gContentLoad, true);
+ win.addEventListener("load", gContentLoad, true);
+
+ // TODO:
+ // Sometimes we get this notification twice with different windows but
+ // identical documentURI/location.href. In one of those cases, the call
+ // to sendSyncMessage will throw, and I can't find a way to detect which
+ // notification is the correct one. if (win !== content) would also
+ // exclude iframes.
+ this.runScripts('document-start', win);
+ break;
+ default:
+ dump("received unknown topic: " + aTopic + "\n");
+ }
+};
+
+
+ContentObserver.prototype.pagehide = function(aEvent) {
+ var contentWin = aEvent.target.defaultView;
+ var windowId = GM_util.windowId(contentWin);
+ // TODO: Fix.
+ /*
+ if (!windowId || !gScriptRunners[windowId]) return;
+
+ // Small optimization: only send a notification if there's a menu command
+ // for this window.
+ if (!gScriptRunners[windowId].menuCommands.length) return;
+
+ if (aEvent.persisted) {
+ sendAsyncMessage("greasemonkey:toggle-menu-commands", {
+ frozen: true,
+ windowId: windowId
+ });
+ } else {
+ sendAsyncMessage("greasemonkey:clear-menu-commands", {
+ windowId: windowId
+ });
+ }
+ */
+};
+
+
+ContentObserver.prototype.pageshow = function(aEvent) {
+ var contentWin = aEvent.target.defaultView;
+ var windowId = GM_util.windowId(contentWin);
+ // TODO: Fix.
+ /*
+ if (!windowId || !gScriptRunners[windowId]) return;
+
+ if (!gScriptRunners[windowId].menuCommands.length) return;
+
+ sendAsyncMessage("greasemonkey:toggle-menu-commands", {
+ frozen: false,
+ windowId: windowId
+ });
+ */
+};
+
+
+ContentObserver.prototype.runDelayedScript = function(aMessage) {
+ var windowId = aMessage.data.windowId;
+ if (!gScriptRunners[windowId]) return;
+
+ var script = this.createScriptFromObject(aMessage.data.script);
+ gScriptRunners[windowId].injectScripts([script]);
+};
+
+
+ContentObserver.prototype.runMenuCommand = function(aMessage) {
+ var windowId = aMessage.data.windowId;
+ if (!gScriptRunners[windowId]) return;
+
+ var index = aMessage.data.index;
+ var command = gScriptRunners[windowId].menuCommands[index];
+ if (!command || !command.commandFunc) return;
+
+ // Ensure |this| is set to the sandbox object inside the command function.
+ command.commandFunc.call(null);
+};
+
+
+ContentObserver.prototype.runScripts = function(aRunWhen, aContentWin) {
+ try {
+ this.window.QueryInterface(Ci.nsIDOMChromeWindow);
+ // Never ever inject scripts into a chrome context window.
+ return;
+ } catch(e) {
+ // Ignore, it's good if we can't QI to a chrome window.
+ }
+
+ // See #1970
+ // When content does (e.g.) history.replacestate() in an inline script,
+ // the location.href changes between document-start and document-end time.
+ // But the content can call replacestate() much later, too. The only way to
+ // be consistent is to ignore it. Luckily, the document.documentURI does
+ // _not_ change, so always use it when deciding whether to run scripts.
+ var url = aContentWin.document.documentURI;
+ // But ( #1631 ) ignore user/pass in the URL.
+ url = url.replace(gStripUserPassRegexp, '$1');
+
+ if (!GM_util.isGreasemonkeyable(url)) return;
+
+ var windowId = GM_util.windowId(aContentWin);
+ // TODO: Fix.
+ /*
+ if (gScriptRunners[windowId]) {
+ // Update the window in case it changed, see the comment in observe().
+ gScriptRunners[windowId].window = aContentWin;
+ } else {
+ gScriptRunners[windowId] = new ScriptRunner(aContentWin, url);
+ }
+ */
+
+ var response = this.windowMessageManager(aContentWin).sendSyncMessage(
+ 'greasemonkey:scripts-for-url', {
+ 'url': url,
+ 'when': aRunWhen,
+ 'windowId': windowId
+ });
+ if (!response || !response[0]) return;
+
+ var scripts = response[0].map(this.createScriptFromObject);
+ var winIsTop = this.windowIsTop(aContentWin);
+ for (var i = 0, script = null; script = scripts[i]; i++) {
+ if (script.noframes && !winIsTop) continue;
+ var sandbox = createSandbox(script, url, aContentWin);
+ runScriptInSandbox(script, sandbox);
+ }
+};
+
+
+ContentObserver.prototype.windowIsTop = function(aContentWin) {
+ try {
+ aContentWin.QueryInterface(Ci.nsIDOMWindow);
+ if (aContentWin.frameElement) return false;
+ } catch (e) {
+ var url = 'unknown';
+ try {
+ url = aContentWin.location.href;
+ } catch (e) { }
+ // Ignore non-DOM-windows.
+ dump('Could not QI this.window to nsIDOMWindow at\n' + url + ' ?!\n');
+ }
+ return true;
+};
+
+ContentObserver.prototype.windowMessageManager = function(aContentWin) {
+ return aContentWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell)
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIContentFrameMessageManager);
+};
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+// Since observers are process-global, create this observer singleton in the
+// process-global JSM scope.
+var contentObserver = new ContentObserver();
+Services.obs.addObserver(contentObserver, 'document-element-inserted', false);
+
+// This single global function reference can easily be both attached as
+// an event listener, and then removed again.
+var gContentLoad = contentObserver.contentLoad.bind(contentObserver);
diff --git a/modules/sandbox.js b/modules/sandbox.js
index 56e1548..f36dea9 100644
--- a/modules/sandbox.js
+++ b/modules/sandbox.js
@@ -24,18 +24,15 @@ function alert(msg) {
.alert(null, "Greasemonkey alert", msg);
}
-function createSandbox(aScript, aScriptRunner) {
- var contentWin = aScriptRunner.window;
- var url = aScriptRunner.url;
-
+function createSandbox(aScript, aUrl, aWindow) {
if (GM_util.inArray(aScript.grants, 'none')) {
// If there is an explicit none grant, use a plain unwrapped sandbox
// with no other content.
var contentSandbox = new Components.utils.Sandbox(
- contentWin,
+ aWindow,
{
'sandboxName': aScript.id,
- 'sandboxPrototype': contentWin,
+ 'sandboxPrototype': aWindow,
'wantXrays': false,
});
// GM_info is always provided.
@@ -56,10 +53,10 @@ function createSandbox(aScript, aScriptRunner) {
}
var sandbox = new Components.utils.Sandbox(
- [contentWin],
+ [aWindow],
{
'sandboxName': aScript.id,
- 'sandboxPrototype': contentWin,
+ 'sandboxPrototype': aWindow,
'wantXrays': true,
});
@@ -75,15 +72,16 @@ function createSandbox(aScript, aScriptRunner) {
sandbox.exportFunction = Cu.exportFunction;
if (GM_util.inArray(aScript.grants, 'GM_addStyle')) {
- sandbox.GM_addStyle = GM_util.hitch(null, GM_addStyle, contentWin.document);
+ sandbox.GM_addStyle = GM_util.hitch(null, GM_addStyle, aWindow.document);
}
if (GM_util.inArray(aScript.grants, 'GM_log')) {
sandbox.GM_log = GM_util.hitch(new GM_ScriptLogger(aScript), 'log');
}
- if (GM_util.inArray(aScript.grants, 'GM_registerMenuCommand')) {
- var gmrmc = GM_util.hitch(null, registerMenuCommand, aScriptRunner);
- sandbox.GM_registerMenuCommand = gmrmc;
- }
+ // TODO: Fix.
+// if (GM_util.inArray(aScript.grants, 'GM_registerMenuCommand')) {
+// var gmrmc = GM_util.hitch(null, registerMenuCommand, aScriptRunner);
+// sandbox.GM_registerMenuCommand = gmrmc;
+// }
var scriptStorage = new GM_ScriptStorage(aScript);
if (GM_util.inArray(aScript.grants, 'GM_deleteValue')) {
@@ -111,13 +109,14 @@ function createSandbox(aScript, aScriptRunner) {
if (GM_util.inArray(aScript.grants, 'GM_listValues')) {
sandbox.GM_listValues = GM_util.hitch(scriptStorage, 'listValues');
}
- if (GM_util.inArray(aScript.grants, 'GM_openInTab')) {
- sandbox.GM_openInTab = GM_util.hitch(
- null, GM_openInTab, aScriptRunner);
- }
+ // TODO: Fix.
+// if (GM_util.inArray(aScript.grants, 'GM_openInTab')) {
+// sandbox.GM_openInTab = GM_util.hitch(
+// null, GM_openInTab, aScriptRunner);
+// }
if (GM_util.inArray(aScript.grants, 'GM_xmlhttpRequest')) {
sandbox.GM_xmlhttpRequest = GM_util.hitch(
- new GM_xmlhttpRequester(contentWin, aScriptRunner.url, sandbox),
+ new GM_xmlhttpRequester(aWindow, aUrl, sandbox),
'contentStartRequest');
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/greasemonkey.git
More information about the Pkg-mozext-commits
mailing list