[Pkg-mozext-commits] [greasemonkey] 23/43: Move all the observer / runner logic back into the frame script.
David Prévot
taffit at moszumanska.debian.org
Sun Feb 22 21:56:11 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 6298013ea7f16c940d4613b45d4528bd5e69bc34
Author: Anthony Lieuallen <arantius at gmail.com>
Date: Wed Nov 19 16:44:42 2014 -0500
Move all the observer / runner logic back into the frame script.
Based on: http://bugzil.la/1048164#c32
Because the logic before this only worked with E10S on, failed with it off.
Refs #2004
---
content/framescript.js | 264 +++++++++++++++++++++++++++++++++--
modules/contentObserver.js | 259 ----------------------------------
modules/util/messageManagerForWin.js | 27 ----
3 files changed, 252 insertions(+), 298 deletions(-)
diff --git a/content/framescript.js b/content/framescript.js
index 059ed0a..d35d133 100644
--- a/content/framescript.js
+++ b/content/framescript.js
@@ -5,16 +5,256 @@ var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
-// For every *content* frame/process, make sure the content observer is running.
-var rti = docShell.QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem;
-if (rti.itemType == Ci.nsIDocShellTreeItem.typeContent) {
- Cu.import('resource://greasemonkey/contentObserver.js');
-
- addEventListener("pagehide", contentObserver.pagehide.bind(contentObserver));
- addEventListener("pageshow", contentObserver.pageshow.bind(contentObserver));
-
- addMessageListener("greasemonkey:inject-script",
- contentObserver.runDelayedScript.bind(contentObserver));
- addMessageListener("greasemonkey:menu-command-clicked",
- contentObserver.runMenuCommand.bind(contentObserver));
+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 gScope = this;
+var gScriptRunners = {};
+var gStripUserPassRegexp = new RegExp('(://)([^:/]+)(:[^@/]+)?@');
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+function ScriptRunner(aWindow, aUrl) {
+ this.menuCommands = [];
+ this.window = aWindow;
+ this.windowId = GM_util.windowId(this.window);
+ 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 = this.windowIsTop(this.window);
+
+ for (var i = 0, script = null; script = aScripts[i]; i++) {
+ if (script.noframes && !winIsTop) continue;
+ var sandbox = createSandbox(script, this, gScope);
+ runScriptInSandbox(script, sandbox);
+ }
+};
+
+ScriptRunner.prototype.openInTab = function(aUrl, aInBackground) {
+ var response = sendSyncMessage('greasemonkey:open-in-tab', {
+ inBackground: aInBackground,
+ url: aUrl
+ });
+ return response ? response[0] : null;
+};
+
+
+ScriptRunner.prototype.registeredMenuCommand = function(aCommand) {
+ var length = this.menuCommands.push(aCommand);
+
+ sendAsyncMessage('greasemonkey:menu-command-registered', {
+ accessKey: aCommand.accessKey,
+ frozen: aCommand.frozen,
+ index: length - 1,
+ name: aCommand.name,
+ windowId: aCommand.contentWindowId
+ });
+};
+
+ScriptRunner.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;
+};
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+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) {
+ var contentWin = aEvent.target.defaultView;
+
+ // Now that we've seen any first load event, stop listening for any more.
+ contentWin.removeEventListener('DOMContentLoaded', gContentLoad, true);
+ contentWin.removeEventListener('load', gContentLoad, true);
+
+ 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 win = doc && doc.defaultView;
+ if (!doc || !win) return;
+ if (win.top !== content) return;
+
+ var url = doc.documentURI;
+ if (!GM_util.isGreasemonkeyable(url)) return;
+
+ // Listen for whichever kind of load event arrives first.
+ win.addEventListener('DOMContentLoaded', gContentLoad, true);
+ win.addEventListener('load', gContentLoad, true);
+
+ this.runScripts('document-start', win);
+ break;
+ default:
+ dump('Content frame observed unknown topic: ' + aTopic + '\n');
+ }
+};
+
+
+ContentObserver.prototype.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
+ });
+ }
+};
+
+
+ContentObserver.prototype.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
+ });
+};
+
+
+ContentObserver.prototype.runDelayedScript = function(aMessage) {
+ var windowId = aMessage.data.windowId;
+ var scriptRunner = gScriptRunners[windowId];
+ if (!scriptRunner) return;
+
+ var script = this.createScriptFromObject(aMessage.data.script);
+ scriptRunner.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) {
+ // 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 scriptRunner = gScriptRunners[windowId];
+ var windowId = GM_util.windowId(aContentWin);
+ if (!scriptRunner) {
+ scriptRunner = new ScriptRunner(aContentWin, url);
+ gScriptRunners[windowId] = scriptRunner;
+ } else if (scriptRunner.window !== aContentWin) {
+ // Sanity check, shouldn't be necessary.
+ // TODO: remove
+ dump('Script runner window changed for ' + url + ' at ' + aRunWhen + '\n');
+ scriptRunner.window = aContentWin;
+ }
+
+ 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);
+ scriptRunner.injectScripts(scripts);
+};
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+// Create a singleton object within this frame, attach observer/listeners to it.
+var contentObserver = new ContentObserver();
+
+// This global function reference can easily be both attached as an event
+// listener, and then removed again.
+var gContentLoad = contentObserver.contentLoad.bind(contentObserver);
+
+addEventListener('pagehide', contentObserver.pagehide.bind(contentObserver));
+addEventListener('pageshow', contentObserver.pageshow.bind(contentObserver));
+addMessageListener('greasemonkey:inject-script',
+ contentObserver.runDelayedScript.bind(contentObserver));
+addMessageListener('greasemonkey:menu-command-clicked',
+ contentObserver.runMenuCommand.bind(contentObserver));
+Services.obs.addObserver(contentObserver, 'document-element-inserted', false);
+addEventListener('unload', function() {
+ Services.obs.removeObserver(contentObserver, 'document-element-inserted');
+}, false);
diff --git a/modules/contentObserver.js b/modules/contentObserver.js
deleted file mode 100644
index ab32e88..0000000
--- a/modules/contentObserver.js
+++ /dev/null
@@ -1,259 +0,0 @@
-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 gScriptRunners = {};
-var gStripUserPassRegexp = new RegExp('(://)([^:/]+)(:[^@/]+)?@');
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-function ScriptRunner(aWindow, aUrl) {
- this.menuCommands = [];
- this.window = aWindow;
- this.windowId = GM_util.windowId(this.window);
- this.url = aUrl;
-}
-
-ScriptRunner.prototype.injectScripts = function(aScripts, aMessageManager) {
- 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 = this.windowIsTop(this.window);
-
- for (var i = 0, script = null; script = aScripts[i]; i++) {
- if (script.noframes && !winIsTop) continue;
- var sandbox = createSandbox(script, this, aMessageManager);
- runScriptInSandbox(script, sandbox);
- }
-};
-
-ScriptRunner.prototype.openInTab = function(aUrl, aInBackground) {
- var mm = GM_util.messageManagerForWin(this.window);
- var response = mm.sendSyncMessage('greasemonkey:open-in-tab', {
- inBackground: aInBackground,
- url: aUrl
- });
-
- return response ? response[0] : null;
-};
-
-
-ScriptRunner.prototype.registeredMenuCommand = function(aCommand) {
- var length = this.menuCommands.push(aCommand);
-
- var mm = GM_util.messageManagerForWin(this.window);
- mm.sendAsyncMessage("greasemonkey:menu-command-registered", {
- accessKey: aCommand.accessKey,
- frozen: aCommand.frozen,
- index: length - 1,
- name: aCommand.name,
- windowId: aCommand.contentWindowId
- });
-};
-
-ScriptRunner.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;
-};
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-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) {
- var contentWin = aEvent.target.defaultView;
-
- // Now that we've seen any first load event, stop listening for any more.
- contentWin.removeEventListener("DOMContentLoaded", gContentLoad, true);
- contentWin.removeEventListener("load", gContentLoad, true);
-
- 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);
-
- 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);
-
- 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;
-
- var mm = GM_util.messageManagerForWin(contentWin);
- if (aEvent.persisted) {
- mm.sendAsyncMessage("greasemonkey:toggle-menu-commands", {
- frozen: true,
- windowId: windowId
- });
- } else {
- mm.sendAsyncMessage("greasemonkey:clear-menu-commands", {
- windowId: windowId
- });
- }
-};
-
-
-ContentObserver.prototype.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;
-
- var mm = GM_util.messageManagerForWin(contentWin);
- mm.sendAsyncMessage("greasemonkey:toggle-menu-commands", {
- frozen: false,
- windowId: windowId
- });
-};
-
-
-ContentObserver.prototype.runDelayedScript = function(aMessage) {
- var windowId = aMessage.data.windowId;
- var scriptRunner = gScriptRunners[windowId];
- if (!scriptRunner) return;
-
- var script = this.createScriptFromObject(aMessage.data.script);
- scriptRunner.injectScripts(
- [script],
- GM_util.messageManagerForWin(scriptRunner.window));
-};
-
-
-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) {
- // 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 scriptRunner = gScriptRunners[windowId];
- var windowId = GM_util.windowId(aContentWin);
- if (!scriptRunner) {
- scriptRunner = new ScriptRunner(aContentWin, url);
- gScriptRunners[windowId] = scriptRunner;
- } else if (scriptRunner.window !== aContentWin) {
- // Sanity check, shouldn't be necessary.
- // TODO: remove
- dump("Script runner window changed for " + url + " at " + aRunWhen + "\n");
- scriptRunner.window = aContentWin;
- }
-
- var mm = GM_util.messageManagerForWin(aContentWin);
- var response = mm.sendSyncMessage(
- 'greasemonkey:scripts-for-url', {
- 'url': url,
- 'when': aRunWhen,
- 'windowId': windowId
- });
- if (!response || !response[0]) return;
-
- var scripts = response[0].map(this.createScriptFromObject);
- scriptRunner.injectScripts(
- scripts, GM_util.messageManagerForWin(aContentWin));
-};
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-// 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/util/messageManagerForWin.js b/modules/util/messageManagerForWin.js
deleted file mode 100644
index 7d2f523..0000000
--- a/modules/util/messageManagerForWin.js
+++ /dev/null
@@ -1,27 +0,0 @@
-var EXPORTED_SYMBOLS = ['messageManagerForWin'];
-
-var Ci = Components.interfaces;
-
-function messageManagerForWin(aContentWin) {
- try {
- // This crazy incantation works only when E10S is ENabled.
- return aContentWin.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIContentFrameMessageManager);
- } catch (e) {
- // While this one works when E10S is DISabled.
- try {
- return aContentWin.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell)
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIContentFrameMessageManager);
- } catch (e) {
- dump('Could not get message manager round 2:\n'+e+'\n\n');
- return null;
- }
- }
-};
--
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