diff options
author | Einar Egilsson <einar@einaregilsson.com> | 2016-05-31 14:53:32 +0200 |
---|---|---|
committer | Einar Egilsson <einar@einaregilsson.com> | 2016-05-31 14:53:32 +0200 |
commit | 44dfb4ec3c4585454ebfbb7b30fe7774c5c6a877 (patch) | |
tree | f37394844b1b1960d77e6dd1ac6275d23415cc6e | |
parent | 77f60e0af6c36009a9bb6edbea04aeace9478637 (diff) |
Mostly Firefox compatible
-rw-r--r-- | .jpmignore | 18 | ||||
-rwxr-xr-x | build.py | 37 | ||||
-rw-r--r-- | js/background.js | 64 | ||||
-rw-r--r-- | js/controllers/redirectorpage.js | 17 | ||||
-rw-r--r-- | js/firefox/background-shim.js | 243 | ||||
-rw-r--r-- | js/firefox/page-shim.js | 80 | ||||
-rw-r--r-- | js/popup-scriptload.js | 13 | ||||
-rw-r--r-- | js/popup.js | 13 | ||||
-rw-r--r-- | js/redirector-scriptload.js | 19 | ||||
-rw-r--r-- | package.json | 18 | ||||
-rw-r--r-- | popup.html | 3 | ||||
-rw-r--r-- | redirector.html | 11 |
12 files changed, 88 insertions, 448 deletions
diff --git a/.jpmignore b/.jpmignore deleted file mode 100644 index 8208b36..0000000 --- a/.jpmignore +++ /dev/null @@ -1,18 +0,0 @@ -.DS_Store -*.zip -*.xpi -manifest.json -.git/* -*.pem -.gitignore -.jpmignore -*.py -icon.html -devprofile/* -unittest/* -build/* -*.nex -debug.sh -*.sh -promo/* - @@ -20,36 +20,18 @@ def get_files_to_zip(): zippable_files.append(file) return zippable_files -def create_firefox_addon(): - print '' - print '**** Creating addon for Firefox ****' - os.system('jpm xpi') - import glob, shutil - name = glob.glob('*.xpi')[0] - new_name = os.path.join('build', 'redirector-firefox.xpi') - #Manually update the install.rdf to get the preferences button working... - - #jpm created the install.rdf during build, but doesn't allow adding a options url - #so we patch it here - with zipfile.ZipFile(name, 'r') as zin: - with zipfile.ZipFile(new_name, 'w') as zout: - zout.comment = zin.comment - for item in zin.infolist(): - bytes = zin.read(item.filename) - if item.filename == 'install.rdf': - bytes = bytes.replace('</em:creator>', '</em:creator>\n <em:optionsURL>resource://redirector-at-einaregilsson-dot-com/redirector.html</em:optionsURL>\n <em:optionsType>3</em:optionsType>\n') - - zout.writestr(item, bytes) - - os.remove(name) - def create_addon(files, browser): output_folder = 'build' if not os.path.isdir(output_folder): os.mkdir(output_folder) - output_file = os.path.join(output_folder, 'redirector-%s.zip' % browser) + if browser == 'firefox': + ext = 'xpi' + else: + ext = 'zip' + + output_file = os.path.join(output_folder, 'redirector-%s.%s' % (browser,ext)) zf = zipfile.ZipFile(output_file, 'w', zipfile.ZIP_STORED) cert = 'extension-certificate.pem' @@ -67,6 +49,10 @@ def create_addon(files, browser): if browser != 'firefox': del manifest['applications'] #Firefox specific, and causes warnings in other browsers... + + if browser == 'firefox': + del manifest['background']['persistent'] #Firefox chokes on this, is always persistent anyway + if browser == 'opera': manifest['options_ui']['page'] = 'redirector.html' #Opera opens options in new tab, where the popup would look really ugly manifest['options_ui']['chrome_style'] = False @@ -93,8 +79,7 @@ if __name__ == '__main__': print '******* REDIRECTOR BUILD SCRIPT *******' print '' - browsers = ['chrome', 'firefox', 'opera'] create_addon(files, 'chrome') create_addon(files, 'opera') - create_firefox_addon() + create_addon(files, 'firefox') diff --git a/js/background.js b/js/background.js index e66be8f..5b393db 100644 --- a/js/background.js +++ b/js/background.js @@ -6,25 +6,13 @@ function log(msg) { console.log('REDIRECTOR: ' + msg); } } -log.enabled = false; - - -var isFirefox = false; - -if (typeof chrome == 'undefined') { - console.log('Creating fake chrome...'); - isFirefox = true; - var firefoxShim = require('./firefox/background-shim'); - chrome = firefoxShim.chrome; - Redirect = firefoxShim.Redirect; - log = firefoxShim.log; - exports.onUnload = function (reason) { - log('Unloading (' + reason + '), removing listeners'); - redirectEvent.removeListener(checkRedirects); - chrome.storage.onChanged.removeListener(monitorChanges); - chrome.storage.clearCache(); //<-Firefox specific - }; -} +log.enabled = true; + + +var isFirefox = !!navigator.userAgent.match(/Firefox/i); + +log('Is Firefox: ' + isFirefox); + //Hopefully Firefox will fix this at some point and we can just use onBeforeRequest everywhere... var redirectEvent = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.webRequest.onBeforeRequest; @@ -121,6 +109,8 @@ function checkRedirects(details) { ignoreNextRequest[result.redirectTo] = new Date().getTime(); return { redirectUrl: result.redirectTo }; + } else { + log(details.url + ' is not a match for ' + r.includePattern + ', type ' + r.patternType); } } @@ -163,10 +153,8 @@ function createFilter(redirects) { } types.sort(); - //FIXME: The Firefox implementation of the url matching is seriously broken still, - //so we can't filter by url on Firefox for now, have to cut non http urls out in checkRedirects. return { - urls: isFirefox ? null : ["https://*/*", "http://*/*"], + urls: ["https://*/*", "http://*/*"], types : types }; } @@ -215,6 +203,38 @@ function updateIcon() { }); } + +//Firefox doesn't allow the "content script" which is actually privileged +//to access the objects it gets from chrome.storage directly, so we +//proxy it through here. +chrome.runtime.onMessage.addListener( + function(request, sender, sendResponse) { + log('Received background message: ' + JSON.stringify(request)); + if (request.type == 'getredirects') { + log('Getting redirects from storage'); + chrome.storage.local.get({redirects:[]}, function(obj) { + log('Got redirects from storage: ' + JSON.stringify(obj)); + sendResponse(obj); + log('Sent redirects to content page'); + }); + } else if (request.type == 'saveredirects') { + console.log('Saving redirects, count=' + request.redirects.length); + delete request.type; + chrome.storage.local.set(request, function(a) { + log('Finished saving redirects to storage'); + sendResponse({message:"Redirects saved"}); + }); + } else { + log('Unexpected message: ' + JSON.stringify(request)); + return false; + } + + return true; //This tells the browser to keep sendResponse alive because + //we're sending the response asynchronously. + } +); + + //First time setup updateIcon(); diff --git a/js/controllers/redirectorpage.js b/js/controllers/redirectorpage.js index 9f0fba6..d18883c 100644 --- a/js/controllers/redirectorpage.js +++ b/js/controllers/redirectorpage.js @@ -18,19 +18,22 @@ redirectorApp.controller('RedirectorPageCtrl', ['$scope', '$timeout', function($ // Clean them up so angular $$hash things and stuff don't get serialized. var arr = $s.redirects.map(normalize); - storage.set({redirects:arr}, function() { - console.log('Saved ' + arr.length + ' redirects at ' + new Date()); + chrome.runtime.sendMessage({type:"saveredirects", redirects:arr}, function(response) { + console.log('Saved ' + arr.length + ' redirects at ' + new Date() + '. Message from background page:' + response.message); }); } $s.redirects = []; - storage.get({redirects:[]}, function(results) { - - for (var i=0; i < results.redirects.length; i++) { - $s.redirects.push(normalize(results.redirects[i])); + + //Need to proxy this through the background page, because Firefox gives us dead objects + //nonsense when accessing chrome.storage directly. + chrome.runtime.sendMessage({type: "getredirects"}, function(response) { + console.log('Received redirects message, count=' + response.redirects.length); + for (var i=0; i < response.redirects.length; i++) { + $s.redirects.push(normalize(response.redirects[i])); } $s.$apply(); - }); + }); // Shows a message bar above the list of redirects. $s.showMessage = function(message, success) { diff --git a/js/firefox/background-shim.js b/js/firefox/background-shim.js deleted file mode 100644 index d937104..0000000 --- a/js/firefox/background-shim.js +++ /dev/null @@ -1,243 +0,0 @@ -var self = require('sdk/self'); -var tabs = require('sdk/tabs'); - -const {Cu} = require('chrome'); - -function log(msg) { - console.log(msg); -} - -function migrateFromOlderVersion() { - const { pathFor } = require('sdk/system'); - const path = require('sdk/fs/path'); - const file = require('sdk/io/file'); - - var oldRedirectsFile = path.join(pathFor('ProfD'), 'Redirector.rjson'); - if (!file.exists(oldRedirectsFile)) { - return; - } - - var extensionId = require('sdk/self').id; - var newFolder = path.join(pathFor('ProfD'), 'browser-extension-data', extensionId); - file.mkpath(newFolder); - var newFile = path.join(newFolder, 'storage.js'); - - if (file.exists(newFile)) { - return; - } - - - var textReader = file.open(oldRedirectsFile, 'r'); - var jsonData = JSON.parse(textReader.read()); - textReader.close(); - var Redirect = require('../redirect').Redirect; - var newData = {redirects:[]}; - for (var r of jsonData.redirects) { - var redirect = new Redirect(r); - redirect.updateExampleResult(); - newData.redirects.push(redirect.toObject()); - } - - Cu.import("resource://gre/modules/Services.jsm"); - - var enabled = true; - try { - enabled = Services.prefs.getBoolPref('extensions.redirector.enabled'); - } catch(e) {} - newData.disabled = !enabled; - - //Kill old prefs: - var oldPrefs = ['enabled', 'debugEnabled', 'enableShortcutKey', 'version', 'defaultDir']; - for (var p of oldPrefs) { - try { - Services.prefs.deleteBranch('extensions.redirector.' + p); - } catch(e) { - } - } - - - var textWriter = file.open(newFile, 'w'); - textWriter.write(JSON.stringify(newData)); - textWriter.close(); - - file.remove(oldRedirectsFile); -} - -migrateFromOlderVersion(); - -function makeUrl(relativeUrl) { - return self.data.url(relativeUrl).replace('/data/', '/'); -} - -Cu.import('resource://gre/modules/ExtensionStorage.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/icon-active-16.png"), - "32": makeUrl("images/icon-active-32.png"), - "48": makeUrl("images/icon-active-48.png"), - "64": makeUrl("images/icon-active-64.png") - }, - onChange: function(state) { - if (state.checked) { - panel.show({position: button}); - } - } -}); - -var extensionId = require('sdk/self').id; - -var chrome = { - webRequest : Cu.import('resource://gre/modules/WebRequest.jsm', {}), - - storage : { - local : { - get : function(query, callback) { - ExtensionStorage.get(extensionId, query).then(callback || function(){}); - }, - set : function(data, callback) { - ExtensionStorage.set(extensionId, data).then(callback || function(){}); - } - }, - - clearCache : function() { - ExtensionStorage.cache.clear(); - }, - - onChanged : { - addListener : function(listener) { - ExtensionStorage.addOnChangedListener(extensionId, listener); - }, - removeListener : function(listener) { - ExtensionStorage.removeOnChangedListener(extensionId, listener); - } - } - }, - - runtime : { - }, - - browserAction : { - setIcon : function(data, callback) { - var icon = {}; - for (var s of ['16','32','48', '64']) { - icon[s] = makeUrl(data.path['19'].replace('19', s)); - } - button.icon = icon; - } - } -}; - -var pageMod = require("sdk/page-mod"); - -var panel = panels.Panel({ - width: 200, - height: 110, - contentURL: makeUrl('popup.html'), - contentScriptFile : [ - makeUrl('js/firefox/page-shim.js'), - makeUrl('js/angular.min.js'), - makeUrl('js/popup.js') - ], - onHide: function() { - button.state('window', {checked: false}); - } -}); - -function attachedPage(worker) { - function sendReply(originalMessage, reply) { - var msg = {messageId:originalMessage.messageId, payload:reply}; - log('background sending message: ' + JSON.stringify(msg)); - worker.port.emit('message', msg); - } - - //We proxy all logging over here so we can control it with one switch - worker.port.on('log', log); - - function receive(message) { - log('background got message: ' + JSON.stringify(message)); - - if (message.messageType == 'storage.get') { - chrome.storage.local.get(message.payload, function(data) { - sendReply(message, data); - }); - } else if (message.messageType == 'storage.set') { - chrome.storage.local.set(message.payload, function(data) { - sendReply(message, data); - }); - } else if (message.messageType == 'manifest.get') { - var p = require('package.json'); - sendReply(message, p); - } else if (message.messageType == 'log.enabled') { - if (!message.payload.enabled) { - log('Logging has been disabled for Redirector'); - } - log.enabled = message.payload.enabled; - if (log.enabled) { - log('Logging has been enabled for Redirector'); - } - } else if (message.messageType == 'tabs.query') { - var result = []; - var windows = require("sdk/windows").browserWindows; - - for (let tab of windows.activeWindow.tabs) { - if (tab.url == message.payload.url) { - result.push({id:tab.id, url:tab.url}); - } - } - sendReply(message, result); - } else if (message.messageType == 'tabs.update') { - for (let tab of tabs) { - if (tab.id == message.payload.tabId) { - tab.activate(); - panel.hide(); - sendReply(message, tab); - } - } - sendReply(message, null); - } else if (message.messageType == 'tabs.create') { - tabs.open(message.payload.url); - panel.hide(); - sendReply(message, null); - } - } - worker.port.on('message', receive); - - worker.on('detach', function() { - worker.port.removeListener('message', receive); - worker.port.removeListener('log', log); - }); -} - -attachedPage(panel); - -pageMod.PageMod({ - include: makeUrl('redirector.html'), - contentScriptFile: [ - makeUrl("js/firefox/page-shim.js"), - makeUrl("js/angular.min.js"), - makeUrl("js/redirect.js"), - makeUrl("js/app.js"), - makeUrl("js/controllers/redirectorpage.js"), - makeUrl("js/controllers/editredirect.js"), - makeUrl("js/controllers/deleteredirect.js"), - makeUrl("js/controllers/importexport.js"), - makeUrl("js/controllers/listredirects.js") - ], - contentScriptWhen: 'start', - onAttach : attachedPage -}); - - -exports.chrome = chrome; - -//Get redirect.js, which is included in the background page in webextensions. -exports.Redirect = require('../redirect').Redirect; - -exports.log = log; diff --git a/js/firefox/page-shim.js b/js/firefox/page-shim.js deleted file mode 100644 index 4607d7c..0000000 --- a/js/firefox/page-shim.js +++ /dev/null @@ -1,80 +0,0 @@ -(function() { - - function log(msg) { - self.port.emit('log', msg); - } - var parts = location.pathname.split('/'); - var urlName = parts[parts.length-1]; - - var messageId = 1; - var callbacks = {}; - function send(type, message, callback) { - var id = messageId++; - self.port.emit('message', {url:urlName, messageId:id, messageType:type, payload:message}); - callbacks[id] = callback || function(){}; - } - - - self.port.on('message', function(message) { - log('page got message: ' + JSON.stringify(message)); - - var callback = callbacks[message.messageId]; - if (callback) { - callback(message.payload); - delete callbacks[message.messageId]; - } - }); - - var manifest = { version:'unknown' }; - send('manifest.get', {}, function(data) { - manifest = data; - }) - - 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) { - send('tabs.query', data, callback); - }, - - create : function(data, callback) { - send('tabs.create', data, callback); - }, - - update : function(tabId, options, callback) { - if (!options.active) { - throw 'Unexpected update call'; - } - - options.tabId = tabId; - - send('tabs.update', options, callback); - } - }, - - runtime : { - getManifest : function() { - return manifest; - } - } - }; - -})(); - - diff --git a/js/popup-scriptload.js b/js/popup-scriptload.js deleted file mode 100644 index bcb5370..0000000 --- a/js/popup-scriptload.js +++ /dev/null @@ -1,13 +0,0 @@ - -//Do it this way to make the Firefox version work with content -//scripts and all that crap. Will be removed when everything -//can use the WebExtensions API. - -function loadScript(path) { - document.write('<script src="' + path + '"></script>'); -} - -if (typeof chrome !== 'undefined') { - loadScript("js/angular.min.js"); - loadScript("js/popup.js"); -} diff --git a/js/popup.js b/js/popup.js index 5305f13..1241d20 100644 --- a/js/popup.js +++ b/js/popup.js @@ -21,6 +21,19 @@ 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}, function(tabs)) { + for (var i=0; i < tabs.length; i++) { + if (tabs[i].url == url) { + chrome.tabs.update(tabs[i].id, {active:true}, function(tab) { + close(); + }); + return; + } + } + + chrome.tabs.create({url:url, active:true}); + }); + return; 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/redirector-scriptload.js b/js/redirector-scriptload.js deleted file mode 100644 index 844576d..0000000 --- a/js/redirector-scriptload.js +++ /dev/null @@ -1,19 +0,0 @@ - -//Do it this way to make the Firefox version work with content -//scripts and all that crap. Will be removed when everything -//can use the WebExtensions API. - -function loadScript(path) { - document.write('<script src="' + path + '"></script>'); -} - -if (typeof chrome !== 'undefined') { - loadScript("js/angular.min.js"); - loadScript("js/redirect.js"); - loadScript("js/app.js"); - loadScript("js/controllers/redirectorpage.js"); - loadScript("js/controllers/editredirect.js"); - loadScript("js/controllers/deleteredirect.js"); - loadScript("js/controllers/importexport.js"); - loadScript("js/controllers/listredirects.js"); -} diff --git a/package.json b/package.json deleted file mode 100644 index 955112b..0000000 --- a/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "title": "Redirector", - "name": "redirector", - "id" : "redirector@einaregilsson.com", - "version": "3.0.6", - "homepage" : "http://einaregilsson.com/redirector", - "icon" : "resource://redirector-at-einaregilsson-dot-com/images/icon-active-48.png", - "icon64" : "resource://redirector-at-einaregilsson-dot-com/images/icon-active-64.png", - "description": "Automatically redirect pages based on user-defined rules. E.g. always redirect an article url to its printer-friendly version.", - "main": "js/background.js", - "author": "Einar Egilsson", - "permissions" : { "multiprocess" : true }, - "engines": { - "firefox": ">=41.0", - "fennec": ">=41.0" - }, - "license": "MIT" -} @@ -4,7 +4,8 @@ <title>REDIRECTOR</title> <link rel="stylesheet" href="css/popup.css" /> <meta charset="UTF-8"> - <script src="js/popup-scriptload.js"></script> + <script src="js/angular.min.js"></script> + <script src="js/popup.js"></script> </head> <body ng-app="popupApp" ng-controller="PopupCtrl"> <h1>REDIRECTOR</h1> diff --git a/redirector.html b/redirector.html index 8717c1b..0285e00 100644 --- a/redirector.html +++ b/redirector.html @@ -6,7 +6,16 @@ <link rel="stylesheet" href="css/redirector.css" /> <!-- ☈ --> <link rel="shortcut icon" href="images/icon-active-32.png"> - <script src="js/redirector-scriptload.js"></script> + + + <script src="js/angular.min.js"></script> + <script src="js/redirect.js"></script> + <script src="js/app.js"></script> + <script src="js/controllers/redirectorpage.js"></script> + <script src="js/controllers/editredirect.js"></script> + <script src="js/controllers/deleteredirect.js"></script> + <script src="js/controllers/importexport.js"></script> + <script src="js/controllers/listredirects.js"></script> </head> <body ng-app="redirectorApp" ng-controller="RedirectorPageCtrl" class="private"> <div id="cover" ng-show="showEditForm || showDeleteForm"> |