diff extension/modules/content-injector.js @ 4:1c02976d8809

Changed to Firebug's progress listener, which allows us to inject our code before any scripts are executed on target pages.
author Atul Varma <varmaa@toolness.com>
date Thu, 06 Aug 2009 17:18:45 -0700
parents 413435fc6202
children c01a64fefbf5
line wrap: on
line diff
--- a/extension/modules/content-injector.js	Thu Aug 06 15:50:24 2009 -0700
+++ b/extension/modules/content-injector.js	Thu Aug 06 17:18:45 2009 -0700
@@ -60,50 +60,74 @@
   };
 }
 
+// Taken from Firebug's content/firebug/tabWatcher.js.
+function safeGetName(request) {
+    try {
+      return request.name;
+    } catch (exc) {
+      return null;
+    }
+}
+
 var listener = {
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
                                           Ci.nsISupportsWeakReference]),
 
+  // Much of this is taken from Firebug's content/firebug/tabWatcher.js,
+  // specifically the FrameProgressListener object.
   onStateChange : function (aWebProgress, aRequest,
                             aStateFlags,  aStatus) {
-    // STATE_START is too early, doc is still the old page.
-    // STATE_STOP is inconviently late (it's onload)
-    if (!(aStateFlags & Ci.nsIWebProgressListener.STATE_TRANSFERRING))
-      return;
-
-    var window = aWebProgress.DOMWindow;
+    if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_REQUEST &&
+        aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
+      // We need to get the hook in as soon as the new DOMWindow is
+      // created, but before it starts executing any scripts in the
+      // page.  After lengthy analysis, it seems that the start of
+      // these "dummy" requests is the only state that works.
 
-    if (window.wrappedJSObject) {
-      var sandbox = Cu.Sandbox(window);
-      sandbox.importFunction(buildRequestor(window));
-      sandbox.window = window.wrappedJSObject;
+      // TODO: Firebug's code mentions that XHTML doesn't dispatch
+      // any of these dummy requests, so we should probably use the
+      // Firebug's XHTML workaround here.
+      var safeName = safeGetName(aRequest);
+      var window = aWebProgress.DOMWindow;
+      if (window && window.wrappedJSObject &&
+          (safeName == "about:layout-dummy-request" ||
+           safeName == "about:document-onload-blocker")) {
+        // TODO: Firebug's code mentions that about:blank causes strange
+        // behavior here; I don't think it should apply to our use case,
+        // though.
+        var sandbox = Cu.Sandbox(window);
+        sandbox.importFunction(buildRequestor(window));
+        sandbox.window = window.wrappedJSObject;
 
-      function setupPowerbox() {
-        window.powerbox = {request: request};
+        function setupPowerbox() {
+          window.powerbox = {request: request};
+        }
+
+        Cu.evalInSandbox("(" + setupPowerbox.toString() + ")();", sandbox);
       }
-
-      Cu.evalInSandbox("(" + setupPowerbox.toString() + ")();", sandbox);
     }
   },
 
-  // stubs for the nsIWebProgressListener interfaces which we don't use.
+  // Stubs for the nsIWebProgressListener interfaces which we don't use.
   onProgressChange : function() { },
   onLocationChange : function() { },
   onStatusChange   : function() { },
   onSecurityChange : function() { }
 };
 
-function init() {
-  // WebProgressListener for getting notification of new doc loads.
-  // XXX Ugh. Since we're a chrome overlay, it would be nice to just
-  // use gBrowser.addProgressListener(). But that isn't sending
-  // STATE_TRANSFERRING, and the earliest we can get at the page is
-  // STATE_STOP (which is onload, and is inconviently late).
-  // We'll use the docloader service instead, but that means we need to
-  // filter out loads for other windows.
-  var docsvc = Cc["@mozilla.org/docloaderservice;1"].
-               getService(Ci.nsIWebProgress);
+function init(window) {
+  var tabbrowser = window.getBrowser();
+
+  function addListener(browser) {
+    browser.addProgressListener(listener,
+                                Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
+  }
 
-  docsvc.addProgressListener(listener,
-                             Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
+  tabbrowser.tabContainer.addEventListener(
+    "TabOpen",
+    function onTabOpen(event) { addListener(event.target.linkedBrowser); },
+    false
+  );
+
+  tabbrowser.browsers.forEach(function(browser) { addListener(browser); });
 }