Better way to listen to events and verify them.
This commit is contained in:
parent
0d839c1c59
commit
e7a0a2e129
148
extensions/firefox/bootstrap.js
vendored
148
extensions/firefox/bootstrap.js
vendored
@ -9,149 +9,14 @@ let Cc = Components.classes;
|
|||||||
let Ci = Components.interfaces;
|
let Ci = Components.interfaces;
|
||||||
let Cm = Components.manager;
|
let Cm = Components.manager;
|
||||||
let Cu = Components.utils;
|
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');
|
Cu.import('resource://gre/modules/Services.jsm');
|
||||||
|
|
||||||
function log(str) {
|
function log(str) {
|
||||||
dump(str + '\n');
|
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) {
|
function startup(aData, aReason) {
|
||||||
let manifestPath = 'chrome.manifest';
|
let manifestPath = 'chrome.manifest';
|
||||||
let manifest = Cc['@mozilla.org/file/local;1']
|
let manifest = Cc['@mozilla.org/file/local;1']
|
||||||
@ -164,22 +29,11 @@ function startup(aData, aReason) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(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) {
|
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);
|
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) {
|
function install(aData, aReason) {
|
||||||
|
@ -7,8 +7,10 @@ const Cc = Components.classes;
|
|||||||
const Ci = Components.interfaces;
|
const Ci = Components.interfaces;
|
||||||
const Cr = Components.results;
|
const Cr = Components.results;
|
||||||
const Cu = Components.utils;
|
const Cu = Components.utils;
|
||||||
|
const PDFJS_EVENT_ID = 'pdf.js.message';
|
||||||
const PDF_CONTENT_TYPE = 'application/pdf';
|
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/XPCOMUtils.jsm');
|
||||||
Cu.import('resource://gre/modules/Services.jsm');
|
Cu.import('resource://gre/modules/Services.jsm');
|
||||||
@ -19,8 +21,50 @@ function log(aMsg) {
|
|||||||
.logStringMessage(msg);
|
.logStringMessage(msg);
|
||||||
dump(msg + '\n');
|
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() {
|
function pdfContentHandler() {
|
||||||
}
|
}
|
||||||
@ -70,6 +114,7 @@ pdfContentHandler.prototype = {
|
|||||||
|
|
||||||
// nsIRequestObserver::onStartRequest
|
// nsIRequestObserver::onStartRequest
|
||||||
onStartRequest: function(aRequest, aContext) {
|
onStartRequest: function(aRequest, aContext) {
|
||||||
|
|
||||||
// Setup the request so we can use it below.
|
// Setup the request so we can use it below.
|
||||||
aRequest.QueryInterface(Ci.nsIChannel);
|
aRequest.QueryInterface(Ci.nsIChannel);
|
||||||
// Cancel the request so the viewer can handle it.
|
// Cancel the request so the viewer can handle it.
|
||||||
@ -80,15 +125,34 @@ pdfContentHandler.prototype = {
|
|||||||
.getService(Ci.nsIIOService);
|
.getService(Ci.nsIIOService);
|
||||||
var channel = ioService.newChannel(
|
var channel = ioService.newChannel(
|
||||||
'resource://pdf.js/web/viewer.html', null, null);
|
'resource://pdf.js/web/viewer.html', null, null);
|
||||||
|
|
||||||
// Keep the URL the same so the browser sees it as the same.
|
// Keep the URL the same so the browser sees it as the same.
|
||||||
channel.originalURI = aRequest.originalURI;
|
channel.originalURI = aRequest.originalURI;
|
||||||
channel.asyncOpen(this.listener, aContext);
|
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
|
// nsIRequestObserver::onStopRequest
|
||||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user