aboutsummaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/background.js18
-rw-r--r--js/firefox/background-shim.js108
-rw-r--r--js/firefox/content-script-proxy.js16
-rw-r--r--js/firefox/extension-storage.jsm152
-rw-r--r--js/firefox/page-shim.js62
-rw-r--r--js/popup.js2
-rw-r--r--js/redirect.js5
7 files changed, 356 insertions, 7 deletions
diff --git a/js/background.js b/js/background.js
index c86a4e2..4b2d1cf 100644
--- a/js/background.js
+++ b/js/background.js
@@ -3,9 +3,15 @@
//as well as monitoring changes in the redirects and the disabled status and reacting to them.
//TODO: Better browser detection...
-var isFirefox = !!navigator.userAgent.match(/Firefox\//);
-var storage = chrome.storage.local; //TODO: Change to sync when Firefox supports it...
-
+var isFirefox = false;
+
+if (!this.chrome) {
+ isFirefox = true;
+ var firefoxShim = require('./firefox/background-shim');
+ chrome = firefoxShim.chrome;
+ Redirect = firefoxShim.Redirect;
+ console.log(this.Redirect)
+}
//Hopefully Firefox will fix this at some point and we can just use onBeforeRequest everywhere...
var redirectEvent = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.webRequest.onBeforeRequest;
@@ -173,7 +179,7 @@ function setUpRedirectListener() {
redirectEvent.removeListener(checkRedirects); //Unsubscribe first, in case there are changes...
- storage.get({redirects:'firstrun'}, function(obj) {
+ chrome.storage.local.get({redirects:'firstrun'}, function(obj) {
var redirects = obj.redirects;
if (redirects === 'firstrun') {
@@ -195,7 +201,7 @@ function setUpRedirectListener() {
}
function updateIcon() {
- storage.get({disabled:false}, function(obj) {
+ chrome.storage.local.get({disabled:false}, function(obj) {
if (obj.disabled) {
setIcon("images/icon19disabled.png", "images/icon38disabled.png");
} else {
@@ -206,7 +212,7 @@ function updateIcon() {
//First time setup
updateIcon();
-storage.get({disabled:false}, function(obj) {
+chrome.storage.local.get({disabled:false}, function(obj) {
if (!obj.disabled) {
setUpRedirectListener();
} else {
diff --git a/js/firefox/background-shim.js b/js/firefox/background-shim.js
new file mode 100644
index 0000000..fb08039
--- /dev/null
+++ b/js/firefox/background-shim.js
@@ -0,0 +1,108 @@
+var self = require("sdk/self");
+
+const {Cu} = require('chrome');
+
+function makeUrl(relativeUrl) {
+ return self.data.url(relativeUrl).replace('/data/', '/');
+}
+//Get the extension storage from Nightly.
+Cu.import(makeUrl('js/firefox/extension-storage.jsm'));
+
+//Create the browser action:
+var { ToggleButton } = require("sdk/ui/button/toggle");
+var panels = require("sdk/panel");
+
+var button = ToggleButton({
+ id: "redirector",
+ label: "Redirector",
+ icon: {
+ "16": makeUrl("images/icon16active.png"),
+ "32": makeUrl("images/icon32active.png")
+ },
+ onChange: function(state) {
+ if (state.checked) {
+ panel.show({position: button});
+ }
+ }
+});
+
+var panel = panels.Panel({
+ width: 200,
+ height: 130,
+ contentURL: makeUrl('popup.html'),
+ contentScriptFile : makeUrl('js/firefox/content-script-proxy.js'),
+ onHide: function() {
+ button.state('window', {checked: false});
+ }
+});
+
+var extensionId = require('../../package.json').id;
+
+var chrome = {
+ webRequest : Cu.import('resource://gre/modules/WebRequest.jsm', {}),
+
+ storage : {
+ local : {
+ get : function(query, callback) {
+ ExtensionStorage.get(extensionId, query).then(callback);
+ },
+ set : function(data, callback) {
+ ExtensionStorage.set(extensionId, data).then(callback);
+ }
+ },
+
+ onChanged : {
+ addListener : function(listener) {
+ ExtensionStorage.addOnChangedListener(extensionId, listener);
+ },
+ removeListener : function(listener) {
+ ExtensionStorage.removeOnChangedListener(extensionId, listener);
+ }
+ }
+ },
+
+ runtime : {
+ },
+
+ browserAction : {
+ setIcon : function(data, callback) {
+
+ }
+ }
+};
+
+var pageMod = require("sdk/page-mod");
+
+function attachedPage(worker) {
+ worker.port.on('message', function(message) {
+ console.info('background got message: ' + JSON.stringify(message));
+
+ if (message.messageType == 'storage.get') {
+ console.info('Getting from storage');
+ chrome.storage.local.get(message.payload, function(data) {
+ var resultMsg = { messageId: message.messageId, payload: data };
+ console.info('background sending message: ' + JSON.stringify(resultMsg));
+ worker.port.emit('message', resultMsg);
+ });
+ } else if (message.messageType == 'storage.set') {
+ chrome.storage.local.set(message.payload, function(data) {
+ var resultMsg = { messageId: message.messageId, payload: data };
+ console.info('background sending message: ' + JSON.stringify(resultMsg));
+ worker.port.emit('message', resultMsg);
+ });
+ }
+ });
+}
+
+pageMod.PageMod({
+ include: makeUrl('redirector.html'),
+ contentScriptFile: makeUrl('js/firefox/content-script-proxy.js'),
+ onAttach : attachedPage
+});
+
+
+exports.chrome = chrome;
+
+//Get redirect.js, which is included in the background page in webextensions.
+exports.Redirect = require('../redirect').Redirect;
+
diff --git a/js/firefox/content-script-proxy.js b/js/firefox/content-script-proxy.js
new file mode 100644
index 0000000..58a6bc0
--- /dev/null
+++ b/js/firefox/content-script-proxy.js
@@ -0,0 +1,16 @@
+// This file listens to messages
+
+window.addEventListener('message', function(message) {
+ if (message.data.sender !== 'page') {
+ return;
+ }
+ console.info('proxy got page message: ' + JSON.stringify(message.data));
+
+ //Forward the message to the background script
+ self.port.emit('message', message.data);
+})
+
+self.port.on('message', function(message) {
+ console.info('proxy got chrome message: ' + JSON.stringify(message));
+ window.postMessage(message, '*');
+}); \ No newline at end of file
diff --git a/js/firefox/extension-storage.jsm b/js/firefox/extension-storage.jsm
new file mode 100644
index 0000000..02c59a3
--- /dev/null
+++ b/js/firefox/extension-storage.jsm
@@ -0,0 +1,152 @@
+//Copied from resource://gre/modules/ExtensionStorage.jsm in Nightly.
+//Will be removed when this addon moves to the WebExtensions API.
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ExtensionStorage"];
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/osfile.jsm")
+Cu.import("resource://gre/modules/AsyncShutdown.jsm");
+
+let Path = OS.Path;
+let profileDir = OS.Constants.Path.profileDir;
+
+this.ExtensionStorage = {
+ cache: new Map(),
+ listeners: new Map(),
+
+ extensionDir: Path.join(profileDir, "browser-extension-data"),
+
+ getExtensionDir(extensionId) {
+ return Path.join(this.extensionDir, extensionId);
+ },
+
+ getStorageFile(extensionId) {
+ return Path.join(this.extensionDir, extensionId, "storage.js");
+ },
+
+ read(extensionId) {
+ if (this.cache.has(extensionId)) {
+ return this.cache.get(extensionId);
+ }
+
+ let path = this.getStorageFile(extensionId);
+ let decoder = new TextDecoder();
+ let promise = OS.File.read(path);
+ promise = promise.then(array => {
+ return JSON.parse(decoder.decode(array));
+ }).catch(() => {
+ Cu.reportError("Unable to parse JSON data for extension storage.");
+ return {};
+ });
+ this.cache.set(extensionId, promise);
+ return promise;
+ },
+
+ write(extensionId) {
+ let promise = this.read(extensionId).then(extData => {
+ let encoder = new TextEncoder();
+ let array = encoder.encode(JSON.stringify(extData));
+ let path = this.getStorageFile(extensionId);
+ OS.File.makeDir(this.getExtensionDir(extensionId), {ignoreExisting: true, from: profileDir});
+ let promise = OS.File.writeAtomic(path, array);
+ return promise;
+ }).catch(() => {
+ // Make sure this promise is never rejected.
+ Cu.reportError("Unable to write JSON data for extension storage.");
+ });
+
+ AsyncShutdown.profileBeforeChange.addBlocker(
+ "ExtensionStorage: Finish writing extension data",
+ promise);
+
+ return promise.then(() => {
+ AsyncShutdown.profileBeforeChange.removeBlocker(promise);
+ });
+ },
+
+ set(extensionId, items) {
+ return this.read(extensionId).then(extData => {
+ let changes = {};
+ for (let prop in items) {
+ changes[prop] = {oldValue: extData[prop], newValue: items[prop]};
+ extData[prop] = items[prop];
+ }
+
+ let listeners = this.listeners.get(extensionId);
+ if (listeners) {
+ for (let listener of listeners) {
+ listener(changes);
+ }
+ }
+
+ return this.write(extensionId);
+ });
+ },
+
+ remove(extensionId, items) {
+ return this.read(extensionId).then(extData => {
+ let changes = {};
+ for (let prop in items) {
+ changes[prop] = {oldValue: extData[prop]};
+ delete extData[prop];
+ }
+
+ let listeners = this.listeners.get(extensionId);
+ if (listeners) {
+ for (let listener of listeners) {
+ listener(changes);
+ }
+ }
+
+ return this.write(extensionId);
+ });
+ },
+
+ get(extensionId, keys) {
+ return this.read(extensionId).then(extData => {
+ let result = {};
+ if (keys === null) {
+ Object.assign(result, extData);
+ } else if (typeof(keys) == "object") {
+ for (let prop in keys) {
+ if (prop in extData) {
+ result[prop] = extData[prop];
+ } else {
+ result[prop] = keys[prop];
+ }
+ }
+ } else if (typeof(keys) == "string") {
+ result[prop] = extData[prop] || undefined;
+ } else {
+ for (let prop of keys) {
+ result[prop] = extData[prop] || undefined;
+ }
+ }
+
+ return result;
+ });
+ },
+
+ addOnChangedListener(extensionId, listener) {
+ let listeners = this.listeners.get(extensionId) || new Set();
+ listeners.add(listener);
+ this.listeners.set(extensionId, listeners);
+ },
+
+ removeOnChangedListener(extensionId, listener) {
+ let listeners = this.listeners.get(extensionId);
+ listeners.delete(listener);
+ },
+};
diff --git a/js/firefox/page-shim.js b/js/firefox/page-shim.js
new file mode 100644
index 0000000..fc63f89
--- /dev/null
+++ b/js/firefox/page-shim.js
@@ -0,0 +1,62 @@
+(function() {
+ //Communication functions for
+
+ var messageId = 1;
+ var callbacks = {};
+ function send(type, message, callback) {
+ var id = messageId++;
+ window.postMessage({sender:'page', messageId:id, messageType:type, payload:message}, '*');
+ callbacks[id] = callback;
+ }
+
+ window.addEventListener('message', function(message) {
+ if (message.data.sender == 'page') {
+ return; //Ignore messages we sent ourselves
+ }
+
+ console.info('page got message: ' + JSON.stringify(message.data));
+
+ var callback = callbacks[message.data.messageId];
+ if (callback) {
+ callback(message.data.payload);
+ delete callbacks[message.data.messageId];
+ }
+ });
+
+ window.chrome = {
+ storage : {
+ local : {
+ get : function(query, callback) {
+ send('storage.get', query, callback);
+ },
+ set : function(data, callback) {
+ send('storage.set', data, callback);
+ }
+ }
+ },
+
+ extension : {
+ getURL : function(file) {
+ return document.location.protocol + '//' + document.location.host + '/' + file;
+ }
+ },
+
+ tabs : {
+ query : function(data, callback) {
+
+ },
+
+ update : function(tabId, options, callback) {
+
+ }
+ },
+
+ runtime : {
+ getManifest : function() {
+ return { version : '3.0' };
+ }
+ }
+ };
+
+})();
+
diff --git a/js/popup.js b/js/popup.js
index 9aa13cf..1e9d353 100644
--- a/js/popup.js
+++ b/js/popup.js
@@ -20,7 +20,7 @@ angular.module('popupApp', []).controller('PopupCtrl', ['$scope', function($s) {
//switch to open one if we have it to minimize conflicts
var url = chrome.extension.getURL('redirector.html');
-
+
chrome.tabs.query({currentWindow:true, url:url}, function(tabs) {
if (tabs.length > 0) {
chrome.tabs.update(tabs[0].id, {active:true}, function(tab) {
diff --git a/js/redirect.js b/js/redirect.js
index f0b429d..c9036e1 100644
--- a/js/redirect.js
+++ b/js/redirect.js
@@ -3,6 +3,11 @@ function Redirect(o) {
this._init(o);
}
+//temp, allow addon sdk to require this.
+if (typeof exports !== 'undefined') {
+ exports.Redirect = Redirect;
+}
+
//Static
Redirect.WILDCARD = 'W';
Redirect.REGEX = 'R';