]> git.parisson.com Git - pdf.js.git/commitdiff
Better way to listen to events and verify them.
authorBrendan Dahl <brendan.dahl@gmail.com>
Fri, 27 Jan 2012 18:53:07 +0000 (10:53 -0800)
committerBrendan Dahl <brendan.dahl@gmail.com>
Fri, 27 Jan 2012 18:53:07 +0000 (10:53 -0800)
extensions/firefox/bootstrap.js
extensions/firefox/components/pdfContentHandler.js

index 06fcf182fc520e193fc46aa02add22cb4aba093f..f1a712c0c268d51d5fd4b2c86d54d3804a2b7b74 100644 (file)
@@ -9,149 +9,14 @@ let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cm = Components.manager;
 let Cu = Components.utils;
-let application = Cc['@mozilla.org/fuel/application;1']
-                    .getService(Ci.fuelIApplication);
-let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
-                        .getService(Ci.nsIPrivateBrowsingService);
 
 Cu.import('resource://gre/modules/Services.jsm');
 
 function log(str) {
   dump(str + '\n');
 }
-// watchWindows() and unload() are from Ed Lee's examples at
-// https://github.com/Mardak/restartless/blob/watchWindows/bootstrap.js
-/**
- * Apply a callback to each open and new browser windows.
- *
- * @param {function} callback 1-parameter function that gets a browser window.
- */
-function watchWindows(callback) {
-  // Wrap the callback in a function that ignores failures
-  function watcher(window) {
-    try {
-      // Now that the window has loaded, only handle browser windows
-      let {documentElement} = window.document;
-      if (documentElement.getAttribute('windowtype') == 'navigator:browser')
-        callback(window);
-    }
-    catch (ex) {}
-  }
-
-  // Wait for the window to finish loading before running the callback
-  function runOnLoad(window) {
-    // Listen for one load event before checking the window type
-    window.addEventListener('load', function runOnce() {
-      window.removeEventListener('load', runOnce, false);
-      watcher(window);
-    }, false);
-  }
 
-  // Add functionality to existing windows
-  let windows = Services.wm.getEnumerator(null);
-  while (windows.hasMoreElements()) {
-    // Only run the watcher immediately if the window is completely loaded
-    let window = windows.getNext();
-    if (window.document.readyState == 'complete')
-      watcher(window);
-    // Wait for the window to load before continuing
-    else
-      runOnLoad(window);
-  }
 
-  // Watch for new browser windows opening then wait for it to load
-  function windowWatcher(subject, topic) {
-    if (topic == 'domwindowopened')
-      runOnLoad(subject);
-  }
-  Services.ww.registerNotification(windowWatcher);
-
-  // Make sure to stop watching for windows if we're unloading
-  unload(function() Services.ww.unregisterNotification(windowWatcher));
-}
-
-/**
- * Save callbacks to run when unloading. Optionally scope the callback to a
- * container, e.g., window. Provide a way to run all the callbacks.
- *
- * @param {function} callback 0-parameter function to call on unload.
- * @param {node} container Remove the callback when this container unloads.
- * @return {function} A 0-parameter function that undoes adding the callback.
- */
-function unload(callback, container) {
-  // Initialize the array of unloaders on the first usage
-  let unloaders = unload.unloaders;
-  if (unloaders == null)
-    unloaders = unload.unloaders = [];
-
-  // Calling with no arguments runs all the unloader callbacks
-  if (callback == null) {
-    unloaders.slice().forEach(function(unloader) unloader());
-    unloaders.length = 0;
-    return;
-  }
-
-  // The callback is bound to the lifetime of the container if we have one
-  if (container != null) {
-    // Remove the unloader when the container unloads
-    container.addEventListener('unload', removeUnloader, false);
-
-    // Wrap the callback to additionally remove the unload listener
-    let origCallback = callback;
-    callback = function() {
-      container.removeEventListener('unload', removeUnloader, false);
-      origCallback();
-    }
-  }
-
-  // Wrap the callback in a function that ignores failures
-  function unloader() {
-    try {
-      callback();
-    }
-    catch (ex) {}
-  }
-  unloaders.push(unloader);
-
-  // Provide a way to remove the unloader
-  function removeUnloader() {
-    let index = unloaders.indexOf(unloader);
-    if (index != -1)
-      unloaders.splice(index, 1);
-  }
-  return removeUnloader;
-}
-
-function messageCallback(event) {
-  log(event.target.ownerDocument.currentScript);
-  var message = event.target, doc = message.ownerDocument;
-  var inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
-  // Verify the message came from a PDF.
-  // TODO
-  var action = message.getUserData('action');
-  var data = message.getUserData('data');
-  switch (action) {
-    case 'download':
-      Services.wm.getMostRecentWindow('navigator:browser').saveURL(data);
-      break;
-    case 'setDatabase':
-      if (inPrivateBrowswing)
-        return;
-      application.prefs.setValue(EXT_PREFIX + '.database', data);
-      break;
-    case 'getDatabase':
-      var response;
-      if (inPrivateBrowswing)
-        response = '{}';
-      else
-        response = application.prefs.getValue(EXT_PREFIX + '.database', '{}');
-      message.setUserData('response', response, null);
-      break;
-  }
-}
-
-
-// All the boostrap functions:
 function startup(aData, aReason) {
   let manifestPath = 'chrome.manifest';
   let manifest = Cc['@mozilla.org/file/local;1']
@@ -164,22 +29,11 @@ function startup(aData, aReason) {
   } catch (e) {
     log(e);
   }
-
-  watchWindows(function(window) {
-    window.addEventListener(PDFJS_EVENT_ID, messageCallback, false, true);
-    unload(function() {
-      window.removeEventListener(PDFJS_EVENT_ID, messageCallback, false, true);
-    });
-  });
 }
 
 function shutdown(aData, aReason) {
-  if (Services.prefs.getBoolPref('extensions.pdf.js.active')) {
+  if (Services.prefs.getBoolPref('extensions.pdf.js.active'))
     Services.prefs.setBoolPref('extensions.pdf.js.active', false);
-    // Clean up with unloaders when we're deactivating
-    if (aReason != APP_SHUTDOWN)
-      unload();
-  }
 }
 
 function install(aData, aReason) {
index edd8ee3e056bb94ec7c17a114885896394481069..1c6c72c81e319ac10c87758fd742fbdd263e00df 100644 (file)
@@ -7,8 +7,10 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
-
+const PDFJS_EVENT_ID = 'pdf.js.message';
 const PDF_CONTENT_TYPE = 'application/pdf';
+const NS_ERROR_NOT_IMPLEMENTED = 0x80004001;
+const EXT_PREFIX = 'extensions.uriloader@pdf.js';
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
@@ -19,8 +21,50 @@ function log(aMsg) {
                                      .logStringMessage(msg);
   dump(msg + '\n');
 }
+let application = Cc['@mozilla.org/fuel/application;1']
+                    .getService(Ci.fuelIApplication);
+let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
+                        .getService(Ci.nsIPrivateBrowsingService);
+let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
+
+// All the priviledged actions.
+function ChromeActions() {
+  this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
+}
+ChromeActions.prototype = {
+  download: function(data) {
+    Services.wm.getMostRecentWindow('navigator:browser').saveURL(data);
+  },
+  setDatabase: function() {
+    if (this.inPrivateBrowswing)
+      return;
+    application.prefs.setValue(EXT_PREFIX + '.database', data);
+  },
+  getDatabase: function() {
+    if (this.inPrivateBrowswing)
+      return '{}';
+    return application.prefs.getValue(EXT_PREFIX + '.database', '{}');
+  }
+};
+
+// Event listener to trigger chrome privedged code.
+function RequestListener(actions) {
+  this.actions = actions;
+}
+// Recieves an event and synchronously responds.
+RequestListener.prototype.recieve = function(event) {
+  var message = event.target;
+  var action = message.getUserData('action');
+  var data = message.getUserData('data');
+  var actions = this.actions;
+  if (!(action in actions)) {
+    log('Unknown action: ' + action);
+    return;
+  }
+  var response = actions[action].call(this.actions, data);
+  message.setUserData('response', response, null);
+};
 
-const NS_ERROR_NOT_IMPLEMENTED = 0x80004001;
 
 function pdfContentHandler() {
 }
@@ -70,6 +114,7 @@ pdfContentHandler.prototype = {
 
   // nsIRequestObserver::onStartRequest
   onStartRequest: function(aRequest, aContext) {
+
     // Setup the request so we can use it below.
     aRequest.QueryInterface(Ci.nsIChannel);
     // Cancel the request so the viewer can handle it.
@@ -80,15 +125,34 @@ pdfContentHandler.prototype = {
                       .getService(Ci.nsIIOService);
     var channel = ioService.newChannel(
                     'resource://pdf.js/web/viewer.html', null, null);
+
     // Keep the URL the same so the browser sees it as the same.
     channel.originalURI = aRequest.originalURI;
     channel.asyncOpen(this.listener, aContext);
+
+    // Setup a global listener waiting for the next DOM to be created and verfiy
+    // that its the one we want by its URL. When the correct DOM is found create
+    // an event listener on that window for the pdf.js events that require
+    // chrome priviledges.
+    var url = aRequest.originalURI.spec;
+    var gb = Services.wm.getMostRecentWindow('navigator:browser');
+    var domListener = function domListener(event) {
+      var doc = event.originalTarget;
+      var win = doc.defaultView;
+      if (doc.location.href === url) {
+        gb.removeEventListener('DOMContentLoaded', domListener);
+        var requestListener = new RequestListener(new ChromeActions());
+        win.addEventListener(PDFJS_EVENT_ID, function(event) {
+          requestListener.recieve(event);
+        }, false, true);
+      }
+    };
+    gb.addEventListener('DOMContentLoaded', domListener, false);
   },
 
   // nsIRequestObserver::onStopRequest
   onStopRequest: function(aRequest, aContext, aStatusCode) {
     // Do nothing.
-    return;
   }
 };