diff options
author | Einar Egilsson <einar@einaregilsson.com> | 2015-09-18 15:42:21 +0000 |
---|---|---|
committer | Einar Egilsson <einar@einaregilsson.com> | 2015-09-18 15:42:21 +0000 |
commit | b2ba3216ea5dbe6a74fdfa75611fce95c1481316 (patch) | |
tree | 0ed80d05edc5497d64455197a04fabec7aa8d69d /js | |
parent | 862d738c79dc6f8188d3f9fefd46c01179041710 (diff) |
Halfway to making Firefox compatible
Diffstat (limited to 'js')
-rw-r--r-- | js/background.js | 18 | ||||
-rw-r--r-- | js/firefox/background-shim.js | 108 | ||||
-rw-r--r-- | js/firefox/content-script-proxy.js | 16 | ||||
-rw-r--r-- | js/firefox/extension-storage.jsm | 152 | ||||
-rw-r--r-- | js/firefox/page-shim.js | 62 | ||||
-rw-r--r-- | js/popup.js | 2 | ||||
-rw-r--r-- | js/redirect.js | 5 |
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'; |