From 0ee5f981f3e708246674d26f8a26fc9b6d8f5fc9 Mon Sep 17 00:00:00 2001
From: Einar Egilsson
Date: Tue, 1 Jan 2008 21:40:32 +0000
Subject: git-svn-id:
 http://einaregilsson.googlecode.com/svn/mozilla/redirector/trunk@101
 119bf307-c92d-0410-89bd-8f53e6181181

---
 chrome/content/help.html        | 120 ++++++++++++++++++++++++++++++++++++++++
 chrome/content/overlay.js       |  82 +++++++++++++++++++--------
 chrome/content/overlay.xul      |   6 +-
 chrome/content/redirect.js      |  18 +++++-
 chrome/content/redirect.xul     |  12 ++--
 chrome/content/redirectList.js  |  62 +++++++++------------
 chrome/content/redirectList.xul |  51 +++++++++--------
 chrome/content/redirector.js    |  75 ++++++++++++++++++++++---
 chrome/content/redirlib.js      |   6 +-
 9 files changed, 333 insertions(+), 99 deletions(-)
 create mode 100644 chrome/content/help.html

(limited to 'chrome/content')

diff --git a/chrome/content/help.html b/chrome/content/help.html
new file mode 100644
index 0000000..a9f5245
--- /dev/null
+++ b/chrome/content/help.html
@@ -0,0 +1,120 @@
+<html>
+	<head>
+		<title>Redirector Help</title>
+		<style type="text/css">
+			body { font-family: Verdana, Arial; color:black; background-color:white; font-size:0.9em;}
+			a { color:blue; }
+		</style>
+	</head>
+	<body>
+		<h1>Redirector Help</h1>
+		<h3>Table of contents</h3>
+		<ol>
+			<li><a href="#whatisredirector">What is Redirector?</a></li>
+			<li><a href="#basicusage">Basic usage</a>
+				<ul>
+					<li><a href="#exampleurl">Example url</a></li>
+					<li><a href="#includepattern">Include pattern</a></li>
+					<li><a href="#excludepattern">Exclude pattern</a></li>
+					<li><a href="#redirectto">Redirect to</a></li>
+					<li><a href="#patterntype">Pattern type</a></li>
+					<li><a href="#onlyiflinkexists">Only if link exists</a></li>
+				</ul>
+			</li>
+			<li><a href="#wildcards">Wildcards</a></li>
+			<li><a href="#regularexpressions">Regular expressions</a></li>
+			<li><a href="#xpathredirects">XPath redirects</a></li>
+			<li><a href="#examples">Examples</a></li>
+		</ol>
+		
+		
+		<a name="whatisredirector"></a>
+		<h4>What is Redirector?</h4>
+		
+		<p>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.</p>
+		
+		<a name="basicusage"></a>
+		<h4>Basic usage</h4>
+		<p>To add a new redirect you can go to the <em>Tools</em> menuitem and select <em>Redirector</em>. That will
+		open the <em>Redirector settings</em> window which shows all your redirects. The window can also be opened
+		by right clicking on the <strong>R</strong> icon in your statusbar and selecting <em>Manage redirects</em>. 
+		There you can press the <em>Add...</em> button and then you can enter the details for the new redirect. A redirect
+		consists of a few things:
+		<ul>
+			<li><a name="exampleurl"></a><strong>Example url:</strong> 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 <em>Test pattern</em> button.</li>
+			
+			<li><a name="includepattern"></a><strong>Include pattern:</strong> 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 <em>Include pattern</em> will just be http://aaa.com. For more complex patterns that match many
+			urls you can use either <a href="#wildcards">wildcards</a> or <a href="#regularexpressions">regular expressions</a>.</li>
+			
+            <li><a name="excludepattern"></a><strong>Exclude pattern:</strong> 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.</li>
+
+            <li><a name="redirectto"></a><strong>Redirect to:</strong> 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 <em>http://google.com/*</em>, redirect to <em>http://froogle.com/$1</em>
+            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 <a href="#xpathredirects">XPath expression</a>.</li>
+		
+            <li><a name="patterntype"></a><strong>Pattern type:</strong> This specifies how Redirector should interpret the patterns, either as
+            <a href="#wildcards">wildcards</a> or <a href="#regularexpressions#">regular expressions</a>.</li>
+            
+            <li><a name="onlyiflinkexists"></a><strong>Only if link exists:</strong> 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 <em>Only if link exists</em> then http://foo.com has to have a hyperlink to http://bar.com, otherwise
+            nothing will happen.
+			</li>
+		</ul>
+		</p>
+
+		<a name="wildcards"></a>
+		<h4>Wildcards</h4>
+		
+		<p>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:
+			<ul>
+				<li><em>http://example.com/*</em> matches http://example.com/, http://example.com/foo, http://example.com/bar and all other urls that start with http://example.com/.</li>
+				<li><em>http://*.example.com</em> matches all subdomains of example.com, like http://www.example.com, http://mail.example.com.</li>
+				<li><em>http*://example.com</em> matches both http://example.com and https://example.com.</li>
+				<li><em>http://example.com/index.asp*</em> matches http://example.com/index.asp, http://example.com/index.asp?a=b&c=d.</li>
+			</ul>
+		$1, $2, $3 in the redirect urls will match the text that the stars matched. Examples:
+			<ul>
+				<li><em>http://example.com/*</em> matches http://example.com/foobar, $1 is foobar.</li>
+				<li><em>http://*.example.com/*</em> matches http://www.example.com/foobar, $1 is www, $2 is foobar.</li>
+			</ul>
+		</p>
+		
+		<a name="regularexpressions"></a>
+		<h4>Regular expressions</h4>
+		
+		<p>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 <a href="http://regular-expressions.info" target="_blank">http://regular-expressions.info</a> 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 \?).</p>
+
+		<a name="xpathredirects"></a>
+		<h4>XPath redirects</h4>
+		<p>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.</p>
+		
+		<a name="examples"></a>
+		<h4>Examples</h4>
+			
+		<p>To be continued in next version...</p>
+	</body>
+</html>
\ 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 @@
   </popup>
   <statusbar id="status-bar">
   <statusbarpanel id="redirector-status">
+      <menupopup id="redirector-status-popup">
+        <menuitem label="&RedirectorManageRedirects.label;" accesskey="&RedirectorManageRedirects.accesskey;" oncommand="Redirector.openSettings();" />
+        <menuitem label="&RedirectorHelp.label;" accesskey="&RedirectorHelp.accesskey;" oncommand="Redirector.openHelp();" />
+      </menupopup>
       <image id="redirector-statusbar-img" src="chrome://redirector/content/statusactive.PNG"
              tooltiptext="Redirector is enabled;"
              style="width:16px; height:16px;"
-             onclick="RedirectorOverlay.toggleEnabled();" />
+             onclick="RedirectorOverlay.statusBarClick(event);" />
   </statusbarpanel>
   </statusbar>
 
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 @@
         <textbox id="txtPattern" taborder="1"/>
         <button id="btnTestPattern" label="&btnTestPattern.label;" onclick="Redirect.testPattern();" taborder="2"/>
       </row>
+      <row>
+        <text value="&txtExcludePattern.label;" style="margin-top:6px;"/>
+        <textbox id="txtExcludePattern" taborder="3"/>
+      </row>
       <row>
         <text value="&txtRedirectUrl.label;" style="margin-top:6px;"/>
-        <textbox id="txtRedirectUrl" taborder="3"/>
+        <textbox id="txtRedirectUrl" taborder="4"/>
       </row>
       <row>
         <text value="&rdoPatternTypes.label;"/>
         <radiogroup>
-          <radio id="rdoWildcard" label="&rdoWildcard.label;" accesskey="&rdoWildcard.accessKey;" selected="true" taborder="4"/>
-          <radio id="rdoRegex" label="&rdoRegex.label;"  accesskey="&rdoRegex.accessKey;" taborder="5"/>
+          <radio id="rdoWildcard" label="&rdoWildcard.label;" accesskey="&rdoWildcard.accessKey;" selected="true" taborder="5"/>
+          <radio id="rdoRegex" label="&rdoRegex.label;"  accesskey="&rdoRegex.accessKey;" taborder="6"/>
         </radiogroup>
       </row>
       <row>
         <text value="&chkOnlyIfLinkExists.label;" />
-        <checkbox id="chkOnlyIfLinkExists" label="" taborder="6"/>
+        <checkbox id="chkOnlyIfLinkExists" label="" taborder="7"/>
       </row>
     </rows>
 
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 @@
 <!DOCTYPE dialog SYSTEM "chrome://redirector/locale/redirectList.dtd">
 <window title="&window.title;"
         orient="vertical"
-        autostretch="always"
         onload="RedirectList.onLoad();"
         buttons="accept"
-        width="600px;"
-        height="400px;"
-        xmlns:nc="http://home.netscape.com/NC-rdf#"
+        width="600px"
+        height="400px"
+        windowtype="redirectorSettings"
+		xmlns:nc="http://home.netscape.com/NC-rdf#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/x-javascript" src="redirlib.js"/>
@@ -16,31 +16,34 @@
   <script type="application/x-javascript" src="redirectList.js"/>
 
   <vbox>
-  <listbox id="lstRedirects" style="margin-bottom:5px;" height="330px" ondblclick="RedirectList.editRedirect();" onselect="RedirectList.selectionChange();">
-
-    <listhead>
-      <listheader label="&colPattern.label;"/>
-      <listheader label="&colExample.label;"/>
-      <listheader label="&colRedirectTo.label;"/>
-      <listheader label="&colOnlyIfLinkExits.label;"/>
-      <listheader label="&colPatternType.label;"/>
-    </listhead>
-
-    <listcols>
-      <listcol/>
-      <listcol/>
-      <listcol/>
-      <listcol/>
-      <listcol/>
-
-    </listcols>
-
-  </listbox>
+  <richlistbox id="lstRedirects" style="margin-bottom:5px; border:solid 1px grey;" height="330px" ondblclick="RedirectList.editRedirect();" onselect="RedirectList.selectionChange();">
+    <richlistitem style="border-bottom:dotted 1px grey;">
+        <grid>
+			<cols>
+			</cols>
+			<rows>
+				<row>
+		          <label style="font-weight:bold;" value="&colIncludePattern.label;:" />
+		          <description name="dscrIncludePattern" />
+				</row>
+				<row>
+		          <label style="font-weight:bold;" value="&colExcludePattern.label;:" />
+		          <description name="dscrExcludePattern" />
+				</row>
+				<row>
+		          <label style="font-weight:bold;" value="&colRedirectTo.label;:" />
+		          <description name="dscrRedirectTo" />
+				</row>
+			</rows>
+        </grid>
+    </richlistitem>
+  </richlistbox>
   <hbox style="align:right;">
     <button id="btnAdd" onclick="RedirectList.addRedirect();" label="&btnAdd.label;" disabled="false" />
     <button id="btnEdit" onclick="RedirectList.editRedirect();" label="&btnEdit.label;" disabled="true" />
     <button id="btnDelete" onclick="RedirectList.deleteRedirect();" label="&btnDelete.label;" disabled="true" />
     <button id="btnClose" onclick="RedirectList.close();" label="&btnClose.label;"/>
+    <button id="btnHelp" onclick="Redirector.openHelp();" label="&btnHelp.label;"/>
   </hbox>
   </vbox>
 </window>
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));
-        }
+        }    
     },
 
 
-- 
cgit v1.2.3-70-g09d2