Redirector is an extension for Firefox that allows you to automatically redirect from
+ one webpage to another. For example, every time you visit http://abc.com you will automatically
+ load http://def.com instead. This can be useful for instance to always redirect articles to printer friendly
+ versions, redirect http:// to https:// for sites that support both, bypass advertising pages that appear before
+ being able to view certain pages and more.
+
+
+
Basic usage
+
To add a new redirect you can go to the Tools menuitem and select Redirector. That will
+ open the Redirector settings window which shows all your redirects. The window can also be opened
+ by right clicking on the R icon in your statusbar and selecting Manage redirects.
+ There you can press the Add... button and then you can enter the details for the new redirect. A redirect
+ consists of a few things:
+
+
Example url: This is an example of an url you want to redirect. It is not really used for anything,
+ it's just there to show what types of urls you're targetting. You can leave this out, but then you can't use the Test pattern button.
+
+
Include pattern: This is pattern for the urls you want to redirect. In the simplest case, where you just want
+ to redirect one specific url to another then this will just be the exact url you want to redirect. For instance, if you just want http://aaa.com to
+ redirect to http://bbb.com then Include pattern will just be http://aaa.com. For more complex patterns that match many
+ urls you can use either wildcards or regular expressions.
+
+
Exclude pattern: Urls that match this pattern will never be redirected. This is not necessary to
+ fill out, but can be useful when you want to redirect all urls that contain some text except if they contain some other text.
+ Redirects like that can often be done with a complex regular expression, but using an exclude pattern makes it much simpler. The exclude
+ patterns can use wildcard characters or regular expressions like the include patterns.
+
+
Redirect to: This is the url that you will be redirected to when you open any page where the url matches the
+ include pattern. You can use the special signs $1, $2, $3 etc. in the url, they will be replaced by the results of captures with regular
+ expressions or stars with wildcards. For instance, if you have the include pattern http://google.com/*, redirect to http://froogle.com/$1
+ and you open the page http://google.com/foobar, then you will be redireced to http://froogle.com/foobar, since 'foobar' was what the star replaced. $1 is for the
+ first star in the pattern, $2 for the second and so on. For regular expression $1 is for the first parantheses, $2 for the second etc. The redirect url
+ can also be specified as a XPath expression.
+
+
Pattern type: This specifies how Redirector should interpret the patterns, either as
+ wildcards or regular expressions.
+
+
Only if link exists: If this is checked then the redirect will only happen if there is a link
+ to the target page on the page that matches the include pattern. For instance, if you have a redirect from http://foo.com to
+ http://bar.com and check Only if link exists then http://foo.com has to have a hyperlink to http://bar.com, otherwise
+ nothing will happen.
+
+
+
+
+
+
Wildcards
+
+
Wildcards are the simplest way to specify include and exclude patterns. When you create a wildcard pattern there
+ is just one special character, the asterisk *. An asterisk in your pattern will match zero or more characters and you can
+ have more than one star in your pattern. Some examples:
+
+
http://example.com/* matches http://example.com/, http://example.com/foo, http://example.com/bar and all other urls that start with http://example.com/.
+
http://*.example.com matches all subdomains of example.com, like http://www.example.com, http://mail.example.com.
+
http*://example.com matches both http://example.com and https://example.com.
+ $1, $2, $3 in the redirect urls will match the text that the stars matched. Examples:
+
+
http://example.com/* matches http://example.com/foobar, $1 is foobar.
+
http://*.example.com/* matches http://www.example.com/foobar, $1 is www, $2 is foobar.
+
+
+
+
+
Regular expressions
+
+
Regular expressions allow for more complicated patterns but they are a lot harder to learn than wildcards. I'm not gonna
+ create a regex tutorial here but normal javascript regex syntax works, look at http://regular-expressions.info for
+ an introduction to regular expressions. $1,$2 etc. can be used in the redirect url and will be replaced with contents of captures in
+ the regular expressions. Captures are specified with parantheses. Example: http://example.com/index.asp\?id=(\d+) will match the url
+ http://example.com/index.asp?id=12345 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 \?).
+
+
+
XPath redirects
+
The redirect url can be specified as an xpath expression by starting it with xpath: and then you will be redirected to the url
+ that the xpath expression matches. Example: Redirect url is xpath:/div/span/a/@href, then you will be redirected to the href value
+ of the first link that's inside a div in the original page.
+
+
+
Examples
+
+
To be continued in next version...
+
+
\ No newline at end of file
diff --git a/chrome/content/overlay.js b/chrome/content/overlay.js
index b7bd560..dd6f527 100644
--- a/chrome/content/overlay.js
+++ b/chrome/content/overlay.js
@@ -1,5 +1,6 @@
//// $Id$
+
var RedirectorOverlay = {
id : "redirector@einaregilsson.com",
@@ -13,24 +14,19 @@ var RedirectorOverlay = {
// initialization code
RedirLib.initialize(this);
RedirLib.debug("Initializing...");
-
$('contentAreaContextMenu')
.addEventListener("popupshowing", function(e) { RedirectorOverlay.showContextMenu(e); }, false);
+ if (!RedirLib.getBoolPref('showContextMenu')) {
+ $('redirector-context').hidden = true;
+ }
+ if (!RedirLib.getBoolPref('showStatusBarIcon')) {
+ $('redirector-status').hidden = true;
+ }
Redirector.init();
-
- var appcontent = window.document.getElementById('appcontent');
this.overrideOnStateChange();
-
- if (appcontent && !appcontent.processed) {
- appcontent.processed = true;
-
- appcontent.addEventListener('DOMContentLoaded', function(event) {
-
- RedirectorOverlay.onDOMContentLoaded(event);
-
- }, false);
- }
+ this.overrideOpenNewWindowWith();
+ this.overrideOpenNewTabWith();
this.strings = document.getElementById("redirector-strings");
Redirector.strings = this.strings;
this.prefObserver.register();
@@ -53,11 +49,11 @@ var RedirectorOverlay = {
var origOnStateChange = nsBrowserStatusHandler.prototype.onStateChange;
nsBrowserStatusHandler.prototype.onStateChange = function(aWebProgress, aRequest, aStateFlags, aStatus) {
-
+
if(aStateFlags & Ci.nsIWebProgressListener.STATE_START
&& aStateFlags| Ci.nsIWebProgressListener.STATE_IS_NETWORK
&& aStateFlags| Ci.nsIWebProgressListener.STATE_IS_REQUEST
- && aRequest && aWebProgress.DOMWindow == content) {
+ && aRequest && aWebProgress.DOMWindow) {
//If it's not a GET request we'll always do a slow redirect so the web will continue
//to work in the way you'd expect
@@ -99,17 +95,47 @@ var RedirectorOverlay = {
};
},
+ overrideOpenNewWindowWith: function() {
+
+ window.__openNewWindowWith = window.openNewWindowWith;
+ window.openNewWindowWith = function (href, sourceURL, postData, allowThirdPartyFixup) {
+ var redirectUrl = Redirector.getRedirectUrlForInstantRedirect(href);
+ if (redirectUrl.url) {
+ __openNewWindowWith(redirectUrl.url, href, postData, allowThirdPartyFixup);
+ } else {
+ __openNewWindowWith(href, sourceURL, postData, allowThirdPartyFixup);
+ }
+
+ };
+ },
+
+
+ overrideOpenNewTabWith: function() {
+
+ window.__openNewTabWith = window.openNewTabWith;
+ window.openNewTabWith = function (href, sourceURL, postData, event, allowThirdPartyFixup) {
+ var redirectUrl = Redirector.getRedirectUrlForInstantRedirect(href);
+ if (redirectUrl.url) {
+ __openNewTabWith(redirectUrl.url, href, postData, event, allowThirdPartyFixup);
+ } else {
+ __openNewTabWith(href, sourceURL, postData, event, allowThirdPartyFixup);
+ }
+
+ };
+ },
+
+
onDOMContentLoaded : function(event) {
var redirect, link, links, url;
-
- if (event.target != window.content.document) {
+
+ if (event.target.toString().indexOf('HTMLDocument') == -1) {
return;
}
- url = window.content.location.href;
+ url = event.target.location.href;
RedirLib.debug('Processing url %1'._(url));
- Redirector.processUrl(url, window.content);
+ Redirector.processUrl(url, event.target);
},
@@ -146,16 +172,25 @@ var RedirectorOverlay = {
},
onMenuItemCommand: function(event) {
- window.openDialog("chrome://redirector/content/redirectList.xul",
- "redirectList",
- "chrome,dialog,modal,centerscreen", this);
-
+ Redirector.openSettings();
},
toggleEnabled : function(event) {
RedirLib.setBoolPref('enabled', !RedirLib.getBoolPref('enabled'));
},
+ statusBarClick : function(event) {
+ var LEFT = 0, RIGHT = 2;
+
+ alert($('redirector-status-popup').style.right);
+ if (event.button == LEFT) {
+ RedirectorOverlay.toggleEnabled();
+ } else if (event.button == RIGHT) {
+ $('redirector-status-popup').left = $('redirector-status').left;
+ $('redirector-status-popup').showPopup();
+ }
+ },
+
setStatusBarImg : function() {
var statusImg = $('redirector-statusbar-img');
@@ -195,4 +230,5 @@ var RedirectorOverlay = {
};
window.addEventListener("load", function(event) { RedirectorOverlay.onLoad(event); }, false);
+window.addEventListener("DOMContentLoaded", function(event) { RedirectorOverlay.onDOMContentLoaded(event); }, true);
window.addEventListener("unload", function(event) { RedirectorOverlay.onUnload(event); }, false);
\ No newline at end of file
diff --git a/chrome/content/overlay.xul b/chrome/content/overlay.xul
index e229530..3333be1 100644
--- a/chrome/content/overlay.xul
+++ b/chrome/content/overlay.xul
@@ -26,10 +26,14 @@
+
+
+
+
+ onclick="RedirectorOverlay.statusBarClick(event);" />
diff --git a/chrome/content/redirect.js b/chrome/content/redirect.js
index 08af778..be6cb96 100644
--- a/chrome/content/redirect.js
+++ b/chrome/content/redirect.js
@@ -8,9 +8,10 @@ var Redirect = {
$('txtExampleUrl').value = item.exampleUrl;
$('txtPattern').value = item.pattern;
$('txtRedirectUrl').value = item.redirectUrl || '';
+ $('txtExcludePattern').value = item.excludePattern || '';
$('chkOnlyIfLinkExists').checked = item.onlyIfLinkExists || false;
- $('txtPattern').focus();
+ $('txtPattern').focus();
this.strings = document.getElementById("redirector-strings");
if (item.patternType == kRedirectorRegex) {
@@ -30,6 +31,7 @@ var Redirect = {
}
item.exampleUrl =$('txtExampleUrl').value;
item.redirectUrl = $('txtRedirectUrl').value;
+ item.excludePattern = $('txtExcludePattern').value;
item.onlyIfLinkExists = $('chkOnlyIfLinkExists').checked;
item.saved = true;
@@ -37,22 +39,32 @@ var Redirect = {
},
testPattern : function() {
- var redirectUrl, pattern, example, extName;
+ var redirectUrl, pattern, excludePattern, example, extName, isExcluded;
redirectUrl = $('txtRedirectUrl').value;
pattern = $('txtPattern').value;
+ excludePattern = $('txtExcludePattern').value;
example = $('txtExampleUrl').value;
extName = this.strings.getString('extensionName');
if ($('rdoRegex').selected) {
redirectUrl = Redirector.regexMatch(pattern, example, redirectUrl);
+ if (excludePattern) {
+ isExcluded = Redirector.regexMatch(excludePattern, example, 'exclude');
+ }
} else {
redirectUrl = Redirector.wildcardMatch(pattern, example, redirectUrl);
+ if (excludePattern) {
+ isExcluded = Redirector.wildcardMatch(excludePattern, example, 'exclude');
+ }
}
- if (redirectUrl || (redirectUrl === '' && $('txtRedirectUrl').value === '')) {
+ var isRedirectMatch = redirectUrl || (redirectUrl === '' && $('txtRedirectUrl').value === '');
+ if (isRedirectMatch && !isExcluded) {
RedirLib.msgBox(extName, this.strings.getFormattedString('testPatternSuccess', [pattern, example, redirectUrl]));
+ } else if (isExcluded) {
+ RedirLib.msgBox(extName, this.strings.getFormattedString('testPatternExclude', [example, excludePattern]));
} else {
RedirLib.msgBox(extName, this.strings.getFormattedString('testPatternFailure', [pattern, example]));
}
diff --git a/chrome/content/redirect.xul b/chrome/content/redirect.xul
index 68d23c4..83ed8df 100644
--- a/chrome/content/redirect.xul
+++ b/chrome/content/redirect.xul
@@ -28,20 +28,24 @@
+
+
+
+
-
+
-
-
+
+
-
+
diff --git a/chrome/content/redirectList.js b/chrome/content/redirectList.js
index 4680075..30bb64e 100644
--- a/chrome/content/redirectList.js
+++ b/chrome/content/redirectList.js
@@ -9,42 +9,35 @@ var RedirectList = {
addItemsToListBox : function(items) {
var list = $('lstRedirects');
- var item, row, value;
-
+ var item, row, value, newItem;
+
for each (item in items) {
- row = this.createRow(item);
- list.appendChild(row);
- }
- },
-
- createCell : function(row, value) {
- var cell = document.createElement('listcell');
- cell.setAttribute('label', value);
- cell.setAttribute('value', value);
- row.appendChild(cell);
- },
-
- createRow : function(item) {
- var row = document.createElement('listitem');
-
- this.createCell(row, item.pattern);
- this.createCell(row, item.exampleUrl);
- this.createCell(row, item.redirectUrl);
- this.createCell(row, item.onlyIfLinkExists);
- this.createCell(row, item.patternType);
+ newItem = this.template.cloneNode(true);
- row.item = item;
- return row;
+ newItem.getElementsByAttribute('name', 'dscrIncludePattern')[0].setAttribute('value', item.pattern);
+ newItem.getElementsByAttribute('name', 'dscrExcludePattern')[0].setAttribute('value', item.excludePattern);
+ newItem.getElementsByAttribute('name', 'dscrRedirectTo')[0].setAttribute('value', item.redirectUrl);
+ newItem.item = item;
+ list.appendChild(newItem);
+ }
+ if (list.children.length > 0) {
+ list.selectedIndex = 0;
+ }
+ list.clearSelection();
},
onLoad : function() {
try {
RedirLib.initialize(this);
Redirector.init();
+
this.lstRedirects = $('lstRedirects');
+ this.template = document.getElementsByTagName('richlistitem')[0];
+ this.lstRedirects.removeChild(this.template);
this.btnDelete = $('btnDelete');
this.btnEdit = $('btnEdit');
this.addItemsToListBox(Redirector.list);
+ this.lstRedirects.selectedIndex = -1;
} catch(e) {
alert(e);
}
@@ -63,8 +56,7 @@ var RedirectList = {
"chrome,dialog,modal,centerscreen", item);
if (item.saved) {
- var row = this.createRow(item);
- $('lstRedirects').appendChild(row);
+ this.addItemsToListBox([item]);
Redirector.addRedirect(item);
}
@@ -85,13 +77,9 @@ var RedirectList = {
"chrome,dialog,modal,centerscreen", item);
if (item.saved) {
- var map = [item.pattern, item.exampleUrl, item.redirectUrl, item.onlyIfLinkExists, item.patternType];
-
- for (var i in map) {
- listItem.childNodes[i].setAttribute('value', map[i]);
- listItem.childNodes[i].setAttribute('label', map[i]);
- }
-
+ listItem.getElementsByAttribute('name', 'dscrIncludePattern')[0].setAttribute('value', item.pattern);
+ listItem.getElementsByAttribute('name', 'dscrExcludePattern')[0].setAttribute('value', item.excludePattern);
+ listItem.getElementsByAttribute('name', 'dscrRedirectTo')[0].setAttribute('value', item.redirectUrl);
Redirector.save();
}
@@ -105,9 +93,11 @@ var RedirectList = {
}
try {
- this.lstRedirects.removeItemAt(index);
- Redirector.deleteAt(index);
- } catch(e) {alert(e);}
+ this.lstRedirects.removeChild(this.lstRedirects.children[index]);
+ Redirector.deleteAt(index);
+ } catch(e) {
+ alert(e);
+ }
},
selectionChange : function() {
diff --git a/chrome/content/redirectList.xul b/chrome/content/redirectList.xul
index 975497b..ed0a130 100644
--- a/chrome/content/redirectList.xul
+++ b/chrome/content/redirectList.xul
@@ -3,12 +3,12 @@
@@ -16,31 +16,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chrome/content/redirector.js b/chrome/content/redirector.js
index cc09300..622f170 100644
--- a/chrome/content/redirector.js
+++ b/chrome/content/redirector.js
@@ -21,7 +21,7 @@ var Redirector = {
, tempList = [];
for each (r in this.list) {
- tempList.push([r.exampleUrl, r.pattern, r.redirectUrl, r.onlyIfLinkExists, r.patternType]);
+ tempList.push([r.exampleUrl, r.pattern, r.redirectUrl, r.onlyIfLinkExists, r.patternType, r.excludePattern]);
}
RedirLib.setCharPref('redirects', tempList.toSource());
},
@@ -38,7 +38,8 @@ var Redirector = {
pattern : arr[1],
redirectUrl : arr[2],
onlyIfLinkExists : arr[3],
- patternType : arr[4]
+ patternType : arr[4],
+ excludePattern : arr[5] || ''
});
}
@@ -81,15 +82,24 @@ var Redirector = {
},
getRedirectUrl: function(url, redirect) {
+
if (redirect.patternType == kRedirectorWildcard) {
+ if (this.wildcardMatch(redirect.excludePattern, url, 'whatever')) {
+ RedirLib.debug('%1 matches exclude pattern %2'._(url, redirect.excludePattern));
+ return null;
+ }
return this.wildcardMatch(redirect.pattern, url, redirect.redirectUrl);
} else if (redirect.patternType == kRedirectorRegex) {
+ if (this.regexMatch(redirect.excludePattern, url, 'whatever')) {
+ RedirLib.debug('%1 matches exclude pattern %2'._(url, redirect.excludePattern));
+ return null;
+ }
return this.regexMatch(redirect.pattern, url, redirect.redirectUrl);
}
return null;
},
- processUrl : function(url) {
+ processUrl : function(url, doc) {
var redirect, link, links, redirectUrl;
if (!this.enabled) {
@@ -109,7 +119,7 @@ var Redirector = {
if (link.href && link.href.toString() == redirectUrl) {
RedirLib.debug('Found a link for %1'._(redirectUrl));
- this.goto(redirectUrl, redirect.pattern, url, window.content.document);
+ this.goto(redirectUrl, redirect.pattern, url, doc);
return;
}
}
@@ -117,7 +127,7 @@ var Redirector = {
RedirLib.debug('Did not find a link for %1'._(redirectUrl));
} else {
- this.goto(redirectUrl, redirect.pattern, url, window.content.document);
+ this.goto(redirectUrl, redirect.pattern, url, doc);
}
}
}
@@ -169,6 +179,9 @@ var Redirector = {
regexMatch : function(pattern, text, redirectUrl) {
+ if (!pattern) {
+ return null;
+ }
var strings, rx, match;
try {
rx = new RegExp(pattern, 'gi');
@@ -202,10 +215,19 @@ var Redirector = {
var parts
, part
, i
- , pos;
+ , pos
+ , originalText
+ , stars;
+ if (!pattern) {
+ return null;
+ }
parts = pattern.split('*');
+ stars = [];
+ originalText = text;
+ var starStart = -1;
+
for (i in parts) {
part = parts[i];
@@ -224,13 +246,51 @@ var Redirector = {
return null;
}
-
+
+ if (i == 0) {
+ //Do nothing, part will be added on next run
+ } else if (i == parts.length-1 && parts[i] == '') {
+ stars.push(text);
+ } else {
+ stars.push(text.substr(0, pos));
+ }
+
text = text.substr(pos + part.length);
}
+
+ for (var i = 1; i <= stars.length; i++) {
+ redirectUrl = redirectUrl.replace(new RegExp('\\$' + i, 'gi'), stars[i-1]);
+ }
return redirectUrl;
},
+ openHelp : function() {
+ var windowsMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ var win;
+ var iter = windowsMediator.getEnumerator(null);
+ while (iter.hasMoreElements()) {
+ win = iter.getNext();
+ alert(win.name);
+ }
+ //window.openDialog("chrome://redirector/content/help.html", windowName, "chrome,dialog,resizable=yes,location=0,toolbar=0,status=0,width=800px,height=600px,centerscreen", this);
+ },
+
+
+ openSettings : function() {
+ var windowName = "redirectorSettings";
+ var windowsMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ var win = windowsMediator.getMostRecentWindow(windowName);
+ if (win) {
+ win.focus();
+ } else {
+ window.openDialog("chrome://redirector/content/redirectList.xul",
+ windowName,
+ "chrome,dialog,resizable=no,centerscreen", this);
+ }
+
+ },
+
prefObserver : {
getService : function() {
@@ -263,3 +323,4 @@ var Redirector = {
}
};
+
diff --git a/chrome/content/redirlib.js b/chrome/content/redirlib.js
index 894c088..c25f0fb 100644
--- a/chrome/content/redirlib.js
+++ b/chrome/content/redirlib.js
@@ -22,9 +22,13 @@ var RedirLib = {
},
debug : function(str) {
+ if (!this._ext) {
+ return; //not initalized yet, _ext will be null
+ }
+
if (this._ext.prefs.debug) {
this._cout.logStringMessage("%1: %2"._(this._ext.name, str));
- }
+ }
},
diff --git a/chrome/locale/en-US/redirect.dtd b/chrome/locale/en-US/redirect.dtd
index 45a1d30..ecf1d76 100644
--- a/chrome/locale/en-US/redirect.dtd
+++ b/chrome/locale/en-US/redirect.dtd
@@ -1,7 +1,8 @@
-
+
+
diff --git a/chrome/locale/en-US/redirectList.dtd b/chrome/locale/en-US/redirectList.dtd
index 21434c5..a4475a6 100644
--- a/chrome/locale/en-US/redirectList.dtd
+++ b/chrome/locale/en-US/redirectList.dtd
@@ -1,11 +1,10 @@
-
-
+
+
-
-
+
diff --git a/chrome/locale/en-US/redirector.dtd b/chrome/locale/en-US/redirector.dtd
index daec007..3aaa0fc 100644
--- a/chrome/locale/en-US/redirector.dtd
+++ b/chrome/locale/en-US/redirector.dtd
@@ -3,3 +3,7 @@
+
+
+
+
diff --git a/chrome/locale/en-US/redirector.properties b/chrome/locale/en-US/redirector.properties
index 66a0287..f32005d 100644
--- a/chrome/locale/en-US/redirector.properties
+++ b/chrome/locale/en-US/redirector.properties
@@ -8,4 +8,5 @@ enabledTooltip=Redirector is enabled
disabledTooltip=Redirector is disabled
testPatternSuccess=The pattern %S matches example URL %S, and would redirect you to url: %S
testPatternFailure=The pattern %S does not match example URL %S
+testPatternExclude=Example URL %S matches the exclude pattern %S and so would not be redirected
regexPatternError=The pattern '%S' is not a legal regular expression pattern. Details: %S
\ No newline at end of file
diff --git a/defaults/preferences/redirector.js b/defaults/preferences/redirector.js
index 693c099..6fb628b 100644
--- a/defaults/preferences/redirector.js
+++ b/defaults/preferences/redirector.js
@@ -2,6 +2,8 @@
pref("extensions.redirector.debug", false);
pref("extensions.redirector.enabled", true);
+pref("extensions.redirector.showContextMenu", true);
+pref("extensions.redirector.showStatusBarIcon", true);
pref("extensions.redirector.redirects", '[]');
// See http://kb.mozillazine.org/Localize_extension_descriptions
--
cgit v1.2.3-70-g09d2