diff options
-rw-r--r-- | css/redirector.css | 2 | ||||
-rw-r--r-- | help.html | 24 | ||||
-rw-r--r-- | js/background.js | 192 | ||||
-rw-r--r-- | js/controllers/editredirect.js | 2 | ||||
-rw-r--r-- | js/controllers/importexport.js | 4 | ||||
-rw-r--r-- | js/controllers/redirectorpage.js | 52 | ||||
-rw-r--r-- | js/popup.js | 17 | ||||
-rw-r--r-- | js/redirect.js | 7 | ||||
-rw-r--r-- | manifest.json | 2 | ||||
-rw-r--r-- | popup.html | 4 | ||||
-rw-r--r-- | redirector.html | 14 |
11 files changed, 294 insertions, 26 deletions
diff --git a/css/redirector.css b/css/redirector.css index 26f9c1a..e2df85f 100644 --- a/css/redirector.css +++ b/css/redirector.css @@ -269,7 +269,7 @@ a.disabled:hover { margin-left:-260px; top:50%; margin-top:-220px; - height:220px; + height:255px; } #delete-redirect-form div{ @@ -33,6 +33,7 @@ </li> <li><a href="#wildcards">Wildcards</a></li> <li><a href="#regularexpressions">Regular expressions</a></li> + <li><a href="#storageArea">Storage Area (Sync vs Local)</a></li> <li><a href="#examples">Examples</a> <ol> <li><a href="#ex1">Static redirect</a></li> @@ -149,7 +150,28 @@ the regular expressions. Captures are specified with parentheses. Example: <span class="pattern">http://example.com/index.asp\?id=(\d+)</span> will match the url <span class="url">http://example.com/index.asp?id=12345</span> and $1 will be replaced by 12345. (A common mistake in regex patterns is to forget to escape the ? sign in the querystring of the url. ? is a special character in regular expressions so if you want to match an url with a querystring - you should escape it as \?).</p> + you should escape it as \?). To test your regular expressions, you may use any website or service. For example, <a href="https://regexr.com" target="_blank">regexr.com</a> </p> + + <a name="storageArea"></a> + <h4>Storage Area (Sync vs Local)</h4> + + <p>Storage Area, by default, is set to Local. If you wish to sync your redirector rules across devices, you may choose to enable Sync from Settings page. + When you toggle to Sync, data will be copied over to Sync storage and local storage will be deleted. + Similary, sync storage will be deleted if you disable sync and data will be moved to Local storage. + <div> + <em>Note:</em><ol> <li>Google Chrome Sync and Mozilla Firefox Sync limits the storage size as per below. + This limit is decided by browser vendors and Redirector addon cannot do anything about changing the below.</li> + <li>You need to use chrome/firefox settings to setup a sync account for syncing to work. + If that is not completed, Sync will just act like local storage - take note of the storage sizes below. + If sync account is not setup in chrome/firefox browser settings, leave the storage area to LOCAL as it has much larger size than Sync storage size. + </li> </ol> + + <ul> + <li>Local Storage: 5 MB - Redirector uses this as Default upon its installation</li> + <li>Sync Storage : 0.008192 MB to store "Redirects" (8192 bytes) </li> + </ul> +</div> + </p> <a name="examples"></a> <h4>Examples</h4> diff --git a/js/background.js b/js/background.js index d1a939e..e087c22 100644 --- a/js/background.js +++ b/js/background.js @@ -7,7 +7,9 @@ function log(msg) { } } log.enabled = false; +var enableNotifications=false; +var storageArea = chrome.storage.local; //Redirects partitioned by request type, so we have to run through //the minimum number of redirects for each request. var partitionedRedirects = {}; @@ -66,7 +68,7 @@ function checkRedirects(details) { return {}; } - + for (var i = 0; i < list.length; i++) { var r = list[i]; var result = r.getMatch(details.url); @@ -90,8 +92,10 @@ function checkRedirects(details) { } - log('Redirecting ' + details.url + ' ===> ' + result.redirectTo + ', type: ' + details.type + ', pattern: ' + r.includePattern); - + log('Redirecting ' + details.url + ' ===> ' + result.redirectTo + ', type: ' + details.type + ', pattern: ' + r.includePattern + ' which is in Rule : ' + r.description); + if(enableNotifications){ + sendNotifications(r, details.url, result.redirectTo); + } ignoreNextRequest[result.redirectTo] = new Date().getTime(); return { redirectUrl: result.redirectTo }; @@ -125,7 +129,11 @@ function monitorChanges(changes, namespace) { if (changes.logging) { log('Logging settings have changed, updating...'); updateLogging(); - } + } + if (changes.enableNotifications){ + log('notifications setting changed'); + enableNotifications=changes.enableNotifications.newValue; + } } chrome.storage.onChanged.addListener(monitorChanges); @@ -135,9 +143,14 @@ function createFilter(redirects) { var types = []; for (var i = 0; i < redirects.length; i++) { redirects[i].appliesTo.forEach(function(type) { + // Added this condition below as part of fix for issue 115 https://github.com/einaregilsson/Redirector/issues/115 + // Firefox considers responsive web images request as imageset. Chrome doesn't. + // Chrome throws an error for imageset type, so let's add to 'types' only for the values that chrome or firefox supports + if(chrome.webRequest.ResourceType[type.toUpperCase()]!== undefined){ if (types.indexOf(type) == -1) { types.push(type); } + } }); } types.sort(); @@ -171,7 +184,7 @@ function setUpRedirectListener() { chrome.webRequest.onBeforeRequest.removeListener(checkRedirects); //Unsubscribe first, in case there are changes... - chrome.storage.local.get({redirects:[]}, function(obj) { + storageArea.get({redirects:[]}, function(obj) { var redirects = obj.redirects; if (redirects.length == 0) { log('No redirects defined, not setting up listener'); @@ -201,7 +214,9 @@ chrome.runtime.onMessage.addListener( log('Received background message: ' + JSON.stringify(request)); if (request.type == 'getredirects') { log('Getting redirects from storage'); - chrome.storage.local.get({redirects:[]}, function(obj) { + storageArea.get({ + redirects: [] + }, function (obj) { log('Got redirects from storage: ' + JSON.stringify(obj)); sendResponse(obj); log('Sent redirects to content page'); @@ -209,10 +224,95 @@ chrome.runtime.onMessage.addListener( } else if (request.type == 'saveredirects') { console.log('Saving redirects, count=' + request.redirects.length); delete request.type; - chrome.storage.local.set(request, function(a) { + storageArea.set(request, function (a) { + if(chrome.runtime.lastError) { + if(chrome.runtime.lastError.message.indexOf("QUOTA_BYTES_PER_ITEM quota exceeded")>-1){ + log("Redirects failed to save as size of redirects larger than allowed limit per item by Sync"); + sendResponse({ + message: "Redirects failed to save as size of redirects larger than what's allowed by Sync. Refer Help Page" + }); + } + } else { log('Finished saving redirects to storage'); - sendResponse({message:"Redirects saved"}); + sendResponse({ + message: "Redirects saved" + }); + } }); + } else if (request.type == 'ToggleSync') { + // Notes on Toggle Sync feature here https://github.com/einaregilsson/Redirector/issues/86#issuecomment-389943854 + // This provides for feature request - issue 86 + delete request.type; + log('toggling sync to ' + request.isSyncEnabled); + // Setting for Sync enabled or not, resides in Local. + chrome.storage.local.set({ + isSyncEnabled: request.isSyncEnabled + }, + function () { + if (request.isSyncEnabled) { + storageArea = chrome.storage.sync; + log('storageArea size for sync is 5 MB but one object (redirects) is allowed to hold only ' + storageArea.QUOTA_BYTES_PER_ITEM / 1000000 + ' MB, that is .. ' + storageArea.QUOTA_BYTES_PER_ITEM + " bytes"); + chrome.storage.local.getBytesInUse("redirects", + function (size) { + log("size of redirects is " + size + " bytes"); + if (size > storageArea.QUOTA_BYTES_PER_ITEM) { + log("size of redirects " + size + " is greater than allowed for Sync which is " + storageArea.QUOTA_BYTES_PER_ITEM); + // Setting storageArea back to Local. + storageArea = chrome.storage.local; + sendResponse({ + message: "Sync Not Possible - size of Redirects larger than what's allowed by Sync. Refer Help page" + }); + } else { + chrome.storage.local.get({ + redirects: [] + }, function (obj) { + //check if at least one rule is there. + if (obj.redirects.length>0) { + chrome.storage.sync.set(obj, function (a) { + log('redirects moved from Local to Sync Storage Area'); + //Remove Redirects from Local storage + chrome.storage.local.remove("redirects"); + // Call setupRedirectListener to setup the redirects + setUpRedirectListener(); + sendResponse({ + message: "syncEnabled" + }); + }); + } else { + log('No redirects are setup currently in Local, just enabling Sync'); + sendResponse({ + message: "syncEnabled" + }); + } + }); + } + }); + } else { + storageArea = chrome.storage.local; + log('storageArea size for local is ' + storageArea.QUOTA_BYTES / 1000000 + ' MB, that is .. ' + storageArea.QUOTA_BYTES + " bytes"); + chrome.storage.sync.get({ + redirects: [] + }, function (obj) { + if (obj.redirects.length>0) { + chrome.storage.local.set(obj, function (a) { + log('redirects moved from Sync to Local Storage Area'); + //Remove Redirects from sync storage + chrome.storage.sync.remove("redirects"); + // Call setupRedirectListener to setup the redirects + setUpRedirectListener(); + sendResponse({ + message: "syncDisabled" + }); + }); + } else { + sendResponse({ + message: "syncDisabled" + }); + } + }); + } + }); + } else { log('Unexpected message: ' + JSON.stringify(request)); return false; @@ -234,12 +334,78 @@ function updateLogging() { } updateLogging(); -chrome.storage.local.get({disabled:false}, function(obj) { - if (!obj.disabled) { - setUpRedirectListener(); +chrome.storage.local.get({ + isSyncEnabled: false +}, function (obj) { + if (obj.isSyncEnabled) { + storageArea = chrome.storage.sync; } else { - log('Redirector is disabled'); + storageArea = chrome.storage.local; } + // Now we know which storageArea to use, call setupInitial function + setupInitial(); }); + +//wrapped the below inside a function so that we can call this once we know the value of storageArea from above. + +function setupInitial() { + chrome.storage.local.get({enableNotifications:false},function(obj){ + enableNotifications = obj.enableNotifications; + }); + + chrome.storage.local.get({ + disabled: false + }, function (obj) { + if (!obj.disabled) { + setUpRedirectListener(); + } else { + log('Redirector is disabled'); + } + }); +} log('Redirector starting up...'); -
\ No newline at end of file + +// Below is a feature request by an user who wished to see visual indication for an Redirect rule being applied on URL +// https://github.com/einaregilsson/Redirector/issues/72 +// By default, we will have it as false. If user wishes to enable it from settings page, we can make it true until user disables it (or browser is restarted) + +// Upon browser startup, just set enableNotifications to false. +// Listen to a message from Settings page to change this to true. +function sendNotifications(redirect, originalUrl, redirectedUrl ){ + //var message = "Applied rule : " + redirect.description + " and redirected original page " + originalUrl + " to " + redirectedUrl; + log("Showing redirect success notification"); + //Firefox and other browsers does not yet support "list" type notification like in Chrome. + // Console.log(JSON.stringify(chrome.notifications)); -- This will still show "list" as one option but it just won't work as it's not implemented by Firefox yet + // Can't check if "chrome" typeof either, as Firefox supports both chrome and browser namespace. + // So let's use useragent. + // Opera UA has both chrome and OPR. So check against that ( Only chrome which supports list) - other browsers to get BASIC type notifications. + + if(navigator.userAgent.toLowerCase().indexOf("chrome") > -1 && navigator.userAgent.toLowerCase().indexOf("OPR")<0){ + var items = [{title:"Original page: ", message: originalUrl},{title:"Redirected to: ",message:redirectedUrl}]; + var head = "Redirector - Applied rule : " + redirect.description; + chrome.notifications.create({ + "type": "list", + "items": items, + "title": head, + "message": head, + "iconUrl": "images/icon-active-38.png" + }); } + else{ + var message = "Applied rule : " + redirect.description + " and redirected original page " + originalUrl + " to " + redirectedUrl; + + chrome.notifications.create({ + "type": "basic", + "title": "Redirector", + "message": message, + "iconUrl": "images/icon-active-38.png" + }); + } +} + +chrome.runtime.onStartup.addListener(handleStartup); +function handleStartup(){ + enableNotifications=false; + chrome.storage.local.set({ + enableNotifications: false + }); +}
\ No newline at end of file diff --git a/js/controllers/editredirect.js b/js/controllers/editredirect.js index 3d63340..81a4ee9 100644 --- a/js/controllers/editredirect.js +++ b/js/controllers/editredirect.js @@ -79,7 +79,7 @@ redirectorApp.controller('EditRedirectCtrl', ['$scope', function($s) { arr.splice(index, 1); } - var order = 'main_frame,sub_frame,stylesheet,script,image,object,xmlhttprequest,other'; + var order = 'main_frame,sub_frame,stylesheet,script,image,imageset,object,xmlhttprequest,other'; arr.sort(function(a,b) { return order.indexOf(a) - order.indexOf(b); diff --git a/js/controllers/importexport.js b/js/controllers/importexport.js index b9a90c7..5ea9756 100644 --- a/js/controllers/importexport.js +++ b/js/controllers/importexport.js @@ -51,7 +51,7 @@ redirectorApp.config([ reader.onload = function(e) { var data; try { - var data = JSON.parse(reader.result); + data = JSON.parse(reader.result); } catch(e) { $s.showMessage('Failed to parse JSON data, invalid JSON: ' + (e.message||'').substr(0,100)); return $s.$parent.$apply(); @@ -107,4 +107,4 @@ redirectorApp.config([ } $s.updateExportLink(); //Run once so the a will have a href to begin with -}]);
\ No newline at end of file +}]); diff --git a/js/controllers/redirectorpage.js b/js/controllers/redirectorpage.js index d18883c..e9ed30c 100644 --- a/js/controllers/redirectorpage.js +++ b/js/controllers/redirectorpage.js @@ -19,10 +19,45 @@ redirectorApp.controller('RedirectorPageCtrl', ['$scope', '$timeout', function($ var arr = $s.redirects.map(normalize); chrome.runtime.sendMessage({type:"saveredirects", redirects:arr}, function(response) { - console.log('Saved ' + arr.length + ' redirects at ' + new Date() + '. Message from background page:' + response.message); + console.log(response.message); + if(response.message.indexOf("Redirects failed to save") > -1){ + $s.showMessage(response.message, false); + }else{ + console.log('Saved ' + arr.length + ' redirects at ' + new Date() + '. Message from background page:' + response.message); + } }); } - + + // Default is LOCAL storage, allow user to select toggle to Sync if they wish + $s.isSyncEnabled = false; + + chrome.storage.local.get({isSyncEnabled:false},function(obj){ + $s.isSyncEnabled = obj.isSyncEnabled; + $s.$apply(); + }); + + $s.toggleSyncSetting = function(){ + chrome.runtime.sendMessage({type:"ToggleSync", isSyncEnabled: !$s.isSyncEnabled}, function(response) { + if(response.message === "syncEnabled"){ + $s.isSyncEnabled = true; + $s.showMessage('Sync is enabled!',true); + } else if(response.message === "syncDisabled"){ + $s.isSyncEnabled = false; + $s.showMessage('Sync is disabled - local storage will be used!',true); + } else if(response.message.indexOf("Sync Not Possible")>-1){ + $s.isSyncEnabled = false; + chrome.storage.local.set({isSyncEnabled: $s.isSyncEnabled}, function(){ + // console.log("set back to false"); + }); + $s.showMessage(response.message, false); + } + else { + $s.showMessage('Error occured when trying to change Sync settings. Refer logging and raise an issue',false); + } + $s.$apply(); + }); + } + $s.redirects = []; //Need to proxy this through the background page, because Firefox gives us dead objects @@ -39,12 +74,21 @@ redirectorApp.controller('RedirectorPageCtrl', ['$scope', '$timeout', function($ $s.showMessage = function(message, success) { $s.message = message; $s.messageType = success ? 'success' : 'error'; + var timer = 20; + /*if($s.message.indexOf("Error occured")>-1 || $s.message.indexOf("Sync Not Possible")>-1 || $s.message.indexOf("Redirects failed to save")>-1 ){ + timer = 10; + // just to reload the page - when I tested, $s.$apply() didn't refresh as I expected for "Sync Not Possible". + // Reloading the page is going to getRedirects and show actual values to user after showing 10 seconds error message + } */ //Remove the message in 20 seconds if it hasn't been changed... $timeout(function() { if ($s.message == message) { $s.message = null; - } - }, 20 * 1000); + } + /* if(timer == 10){ + chrome.tabs.reload(); + } */ + }, timer * 1000); } }]); diff --git a/js/popup.js b/js/popup.js index 6658fc0..c27a29f 100644 --- a/js/popup.js +++ b/js/popup.js @@ -30,6 +30,23 @@ angular.module('popupApp', []).controller('PopupCtrl', ['$scope', function($s) { }); }; + + //Toggle Notifications by sending a notifications + $s.enableNotifications = false; + + storage.get({enableNotifications:false},function(obj){ + $s.enableNotifications = obj.enableNotifications; + $s.$apply(); + }); + + $s.toggleNotifications=function(){ + storage.get({enableNotifications:false},function(obj){ + storage.set({enableNotifications:!obj.enableNotifications}); + $s.enableNotifications = !obj.enableNotifications; + $s.$apply(); + }); + } + $s.openRedirectorSettings = function() { //switch to open one if we have it to minimize conflicts diff --git a/js/redirect.js b/js/redirect.js index 83681fc..ac06ff7 100644 --- a/js/redirect.js +++ b/js/redirect.js @@ -18,6 +18,7 @@ Redirect.requestTypes = { stylesheet : "Stylesheets", script : "Scripts", image : "Images", + imageset: "Responsive Images in Firefox", object : "Objects (e.g. Flash videos, Java applets)", xmlhttprequest : "XMLHttpRequests (Ajax)", other : "Other" @@ -33,6 +34,7 @@ Redirect.prototype = { error : null, includePattern : '', excludePattern : '', + patternDesc:'', redirectUrl : '', patternType : '', processMatches : 'noProcessing', @@ -56,6 +58,7 @@ Redirect.prototype = { && this.exampleUrl == redirect.exampleUrl && this.includePattern == redirect.includePattern && this.excludePattern == redirect.excludePattern + && this.patternDesc == redirect.patternDesc && this.redirectUrl == redirect.redirectUrl && this.patternType == redirect.patternType && this.processMatches == redirect.processMatches @@ -70,6 +73,7 @@ Redirect.prototype = { error : this.error, includePattern : this.includePattern, excludePattern : this.excludePattern, + patternDesc : this.patternDesc, redirectUrl : this.redirectUrl, patternType : this.patternType, processMatches : this.processMatches, @@ -208,6 +212,7 @@ Redirect.prototype = { this.excludePattern = o.excludePattern || ''; this.redirectUrl = o.redirectUrl || ''; this.patternType = o.patternType || Redirect.WILDCARD; + this.patternDesc = o.patternDesc || ''; this.processMatches = o.processMatches || 'noProcessing'; if (!o.processMatches && o.unescapeMatches) { this.processMatches = 'urlDecode'; @@ -261,7 +266,7 @@ Redirect.prototype = { if (!this._rxExclude) { return false; } - var shouldExclude = !!this._rxExclude.exec(url); + var shouldExclude = this._rxExclude.test(url); this._rxExclude.lastIndex = 0; return shouldExclude; } diff --git a/manifest.json b/manifest.json index e3128f1..1325ba9 100644 --- a/manifest.json +++ b/manifest.json @@ -11,7 +11,7 @@ "64": "images/icon-active-64.png", "128": "images/icon-active-128.png" }, - "permissions" : ["webRequest", "webRequestBlocking", "storage", "tabs", "http://*/*", "https://*/*"], + "permissions" : ["webRequest", "webRequestBlocking", "storage", "tabs", "http://*/*", "https://*/*", "notifications"], "applications": { "gecko": { @@ -12,6 +12,8 @@ <div class="disabled"><span ng-show="disabled">Disabled</span></div> <button ng-click="toggleDisabled()">{{disabled ? 'Enable Redirector' : 'Disable Redirector'}}</button> <button ng-click="openRedirectorSettings()">Edit Redirects</button> - <label><input type="checkbox" ng-model="logging" ng-click="toggleLogging()" /> Logging enabled</label> + <label><input type="checkbox" ng-model="logging" ng-click="toggleLogging()" /> Logging enabled</label> + <br/> + <label><input type="checkbox" ng-model="enableNotifications" ng-click="toggleNotifications()" /> Enable Notifications</label> </body> </html> diff --git a/redirector.html b/redirector.html index 1785f0e..eb27611 100644 --- a/redirector.html +++ b/redirector.html @@ -46,7 +46,11 @@ <div> <label>Pattern type:</label> <span>{{redirect.patternType == 'W' ? 'Wildcard' : 'Regular Expression'}}</span> - </div> + </div> + <div> + <label>Pattern Description:</label> + <span>{{redirect.patternDesc}}</span> + </div> <div class="button-container"> <a class="btn red large" ng-click="deleteRedirect()">Yes, delete it</a> <a class="btn grey large" ng-click="cancelDelete()">No, don't delete it</a> @@ -84,6 +88,10 @@ </div> </div> <div> + <label>Pattern Description:</label> + <div class="input-cell"><input type="text" ng-model="redirect.patternDesc" placeholder="Describe your pattern" /></div> + </div> + <div> <label>Example result:</label> <div class="input-cell"><span class="error example-result-error" ng-show="redirect.error">{{redirect.error}}</span><span class="example-result" ng-show="redirect.exampleResult">{{redirect.exampleResult}}</span></div> </div> @@ -166,6 +174,9 @@ <div ng-show="r.excludePattern"> <label>excluding:</label><p>{{r.excludePattern}}</p> </div> + <div ng-if="r.patternDesc"> + <label>Hint:</label><p>{{r.patternDesc}}</p> + </div> <div> <label>Example:</label> <p><span class="error" ng-show="r.error">{{r.error}}</span><span ng-show="r.exampleResult">{{r.exampleUrl}} <span class="arrow">→</span> {{r.exampleResult}}</span></p> </div> @@ -182,6 +193,7 @@ <a class="btn medium grey padded" ng-click="duplicateRedirect($index)">Duplicate</a> </div> </div> + <label><input type="checkbox" ng-model="isSyncEnabled" ng-click="toggleSyncSetting()" /> Enable Storage Sync</label> </div> <footer> |