aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEinar Egilsson2007-05-21 22:03:05 +0000
committerEinar Egilsson2007-05-21 22:03:05 +0000
commit502c24f18cdfa0f808d9383313bb4f965c7fb11f (patch)
treec9f2523995b6fc59e3bf6cc3bcc9200bbedd5e95
Redirector
git-svn-id: http://einaregilsson.googlecode.com/svn/mozilla/redirector/trunk@53 119bf307-c92d-0410-89bd-8f53e6181181
-rw-r--r--chrome.manifest5
-rw-r--r--chrome/content/common.js37
-rw-r--r--chrome/content/overlay.xul27
-rw-r--r--chrome/content/redirect.js30
-rw-r--r--chrome/content/redirect.xul39
-rw-r--r--chrome/content/redirectList.js30
-rw-r--r--chrome/content/redirectList.xul37
-rw-r--r--chrome/content/redirector.js97
-rw-r--r--chrome/content/redirector.pngbin0 -> 1462 bytes
-rw-r--r--chrome/content/redirlib.js217
-rw-r--r--chrome/locale/en-US/redirect.dtd8
-rw-r--r--chrome/locale/en-US/redirectList.dtd9
-rw-r--r--chrome/locale/en-US/redirector.dtd5
-rw-r--r--chrome/locale/en-US/redirector.properties4
-rw-r--r--chrome/skin/overlay.css1
-rw-r--r--defaults/preferences/redirector.js6
-rw-r--r--install.rdf23
-rw-r--r--make.bat11
18 files changed, 586 insertions, 0 deletions
diff --git a/chrome.manifest b/chrome.manifest
new file mode 100644
index 0000000..a64fc76
--- /dev/null
+++ b/chrome.manifest
@@ -0,0 +1,5 @@
+# $Id$
+content redirector file:chrome/content/
+locale redirector en-US file:chrome/locale/en-US/
+skin redirector classic/1.0 file:chrome/skin/
+overlay chrome://browser/content/browser.xul chrome://redirector/content/overlay.xul \ No newline at end of file
diff --git a/chrome/content/common.js b/chrome/content/common.js
new file mode 100644
index 0000000..7d13e4b
--- /dev/null
+++ b/chrome/content/common.js
@@ -0,0 +1,37 @@
+
+
+var RedirectorCommon = {
+
+ wildcardMatch : function(pattern, text) {
+ var parts
+ , part
+ , i
+ , pos;
+
+ parts = pattern.split('*');
+
+ for (i in parts) {
+
+ part = parts[i];
+
+ pos = text.indexOf(part);
+
+ if (pos == -1) {
+ return false;
+ }
+
+ if (i == 0 && pos != 0) {
+ return false;
+ }
+
+ if (i == parts.length -1 && i != "" && text.substr(text.length - part.length) != part) {
+ return false;
+
+ }
+
+ text = text.substr(pos + part.length);
+ }
+
+ return true;
+ }
+}; \ No newline at end of file
diff --git a/chrome/content/overlay.xul b/chrome/content/overlay.xul
new file mode 100644
index 0000000..7951516
--- /dev/null
+++ b/chrome/content/overlay.xul
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id$ -->
+<?xml-stylesheet href="chrome://redirector/skin/overlay.css" type="text/css"?>
+<!DOCTYPE overlay SYSTEM "chrome://redirector/locale/redirector.dtd">
+<overlay id="redirector-overlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="redirlib.js"/>
+ <script src="common.js"/>
+ <script src="redirector.js"/>
+
+ <stringbundleset id="stringbundleset">
+ <stringbundle id="redirector-strings" src="chrome://redirector/locale/redirector.properties"/>
+ </stringbundleset>
+
+ <menupopup id="menu_ToolsPopup">
+ <menuitem id="redirector-menuitem" label="&RedirectorMenuItem.label;"
+ accesskey="&RedirectorMenuItem.accesskey;"
+ oncommand="Redirector.onMenuItemCommand(event);"/>
+ </menupopup>
+ <popup id="contentAreaContextMenu">
+ <menuitem id="redirector-context" label="&RedirectorContext.label;"
+ accesskey="&RedirectorContext.accesskey;"
+ insertafter="context-stop"
+ oncommand="Redirector.onContextMenuCommand(event)"/>
+ </popup>
+</overlay> \ No newline at end of file
diff --git a/chrome/content/redirect.js b/chrome/content/redirect.js
new file mode 100644
index 0000000..bd1a686
--- /dev/null
+++ b/chrome/content/redirect.js
@@ -0,0 +1,30 @@
+//// $Id$
+
+var Redirect = {
+
+ onLoad : function() {
+ var params = window.arguments[0];
+ $('txtExampleUrl').value = params.inn.url;
+ $('txtPattern').value = params.inn.url;
+ $('txtRedirectUrl').value = params.inn.redirect || '';
+
+ },
+
+ onAccept : function() {
+ var params = window.arguments[0];
+
+ params.out.pattern = $('txtPattern').value;
+ params.out.patternType = 'Wildcard';
+ params.out.redirectUrl = $('txtRedirectUrl').value;
+ params.out.onlyIfLinkExists = $('chkOnlyIfLinkExists').checked;
+
+ return true;
+ },
+
+ testPattern : function() {
+ try {
+ alert(RedirectorCommon.wildcardMatch($('txtPattern').value, $('txtExampleUrl').value));
+ } catch(e) {alert(e);}
+ }
+
+}; \ No newline at end of file
diff --git a/chrome/content/redirect.xul b/chrome/content/redirect.xul
new file mode 100644
index 0000000..ea8ac02
--- /dev/null
+++ b/chrome/content/redirect.xul
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://redirector/locale/redirect.dtd">
+<dialog title="&redirectWindow.title;"
+ orient="vertical"
+ autostretch="always"
+ onload="Redirect.onLoad();"
+ buttons="accept,cancel"
+ ondialogaccept="return Redirect.onAccept();"
+ 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="common.js"/>
+ <script type="application/x-javascript" src="redirlib.js"/>
+ <script type="application/x-javascript" src="redirect.js"/>
+ <style type="text/css">
+ textbox { width:500px; }
+ </style>
+
+ <grid>
+ <rows>
+ <row>
+ <text value="&txtExampleUrl.label;"/>
+ <textbox id="txtExampleUrl" disabled="true" />
+ </row>
+ <row>
+ <text value="&txtPattern.label;"/>
+ <textbox id="txtPattern"/>
+ <button id="btnTestPattern" label="&btnTestPattern.label;" onclick="Redirect.testPattern();" />
+ </row>
+ <row>
+ <text value="&txtRedirectUrl.label;"/>
+ <textbox id="txtRedirectUrl"/>
+ </row>
+ </rows>
+ </grid>
+ <checkbox id="chkOnlyIfLinkExists" label="&chkOnlyIfLinkExists.label;"/>
+
+</dialog>
diff --git a/chrome/content/redirectList.js b/chrome/content/redirectList.js
new file mode 100644
index 0000000..522fa20
--- /dev/null
+++ b/chrome/content/redirectList.js
@@ -0,0 +1,30 @@
+var RedirectList = {
+
+
+ addItemsToListBox : function(items) {
+
+ var list = document.getElementById('foo');
+ var item, row, value;
+
+ for each (item in items) {
+
+ row = document.createElement('listitem');
+
+ for each (value in item) {
+ cell = document.createElement('listcell');
+ cell.setAttribute('label',value);
+ cell.setAttribute('value',value);
+ row.appendChild(cell);
+ }
+
+ list.appendChild(row);
+ }
+ },
+
+
+
+ onLoad : function() {
+ addItemsToList(items);
+ }
+
+};
diff --git a/chrome/content/redirectList.xul b/chrome/content/redirectList.xul
new file mode 100644
index 0000000..163703e
--- /dev/null
+++ b/chrome/content/redirectList.xul
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://redirector/locale/redirectList.dtd">
+<dialog title="&window.title;"
+ orient="vertical"
+ autostretch="always"
+ onload="RedirectList.onLoad();"
+ buttons="accept"
+ ondialogaccept="return RedirectList.onAccept();"
+ 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="common.js"/>
+ <script type="application/x-javascript" src="redirlib.js"/>
+ <script type="application/x-javascript" src="redirectList.js"/>
+
+ <dialogheader title="&header;" description="&header.description;"/>
+
+ <listbox id="foo">
+
+ <listhead>
+ <listheader label="&colPattern.label;"/>
+ <listheader label="&colRedirectTo.label;"/>
+ <listheader label="&colOnlyIfLinkExits.label;"/>
+ <listheader label="&colPatternType.label;"/>
+ </listhead>
+
+ <listcols>
+ <listcol flex="1"/>
+ <listcol flex="1"/>
+ <listcol flex="1"/>
+ <listcol flex="1"/>
+
+ </listcols>
+
+ </listbox>
+</dialog>
diff --git a/chrome/content/redirector.js b/chrome/content/redirector.js
new file mode 100644
index 0000000..6767840
--- /dev/null
+++ b/chrome/content/redirector.js
@@ -0,0 +1,97 @@
+//// $Id$
+
+var Redirector = {
+
+ id : "redirector@einaregilsson.com",
+ name : "Redirector",
+ initialized : false,
+ strings : null,
+ redirects : [],
+
+ onLoad : function(event) {
+ try {
+
+ // initialization code
+ RedirLib.initialize(this);
+ RedirLib.debug("Initializing...");
+
+ $('contentAreaContextMenu')
+ .addEventListener("popupshowing", function(e) { Redirector.showContextMenu(e); }, false);
+ var appcontent = window.document.getElementById('appcontent');
+
+ if (appcontent && !appcontent.processed) {
+ appcontent.processed = true;
+
+ appcontent.addEventListener('DOMContentLoaded', function(event) {
+
+ Redirector.onDOMContentLoaded(event);
+
+ }, false);
+ }
+ this.strings = document.getElementById("redirector-strings");
+
+ RedirLib.debug("Finished initialization");
+ this.initialized = true;
+
+ } catch(e) {
+ //Don't use RedirLib because it's initialization might have failed.
+ if (this.strings) {
+ alert(this.strings.getString("initError")._(this.name) + "\n\n" + e);
+ } else {
+ alert(e);
+ }
+ }
+ },
+
+ onDOMContentLoaded : function(event) {
+ var redirect;
+ try {
+ for each (redirect in this.redirects) {
+ if (RedirectorCommon.wildcardMatch(redirect.pattern, window.content.location.href)) {
+ window.content.location.href = redirect.redirectUrl;
+ }
+ }
+ } catch(e) {alert(e);}
+
+ },
+
+ onUnload : function(event) {
+ //Clean up here
+ RedirLib.debug("Finished cleanup");
+ },
+
+ showContextMenu : function(event) {
+ if (gContextMenu.onLink) {
+ $("redirector-context").label = this.strings.getString('addLinkUrl');
+ } else {
+ $("redirector-context").label = this.strings.getString('addCurrentUrl');
+ }
+ },
+
+ onContextMenuCommand: function(event) {
+
+ params = { inn : { url : window.content.location.href}, out : {} };
+ if (gContextMenu.onLink) {
+ params.inn.redirect = gContextMenu.link.toString();
+ }
+
+ window.openDialog("chrome://redirector/content/redirect.xul",
+ "redirect",
+ "chrome,dialog,modal,centerscreen", params);
+
+ if (params.out.pattern) {
+ this.redirects.push(params.out);
+ }
+ },
+
+ onMenuItemCommand: function(event) {
+ window.openDialog("chrome://redirector/content/redirectList.xul",
+ "redirectList",
+ "chrome,dialog,modal,centerscreen", this);
+
+ },
+
+};
+
+window.addEventListener("load", function(event) { Redirector.onLoad(event); }, false);
+window.addEventListener("unload", function(event) { Redirector.onUnload(event); }, false); \ No newline at end of file
diff --git a/chrome/content/redirector.png b/chrome/content/redirector.png
new file mode 100644
index 0000000..f8de12c
--- /dev/null
+++ b/chrome/content/redirector.png
Binary files differ
diff --git a/chrome/content/redirlib.js b/chrome/content/redirlib.js
new file mode 100644
index 0000000..493c583
--- /dev/null
+++ b/chrome/content/redirlib.js
@@ -0,0 +1,217 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * RedirLib - Utility functions for Firefox extensions
+ *
+ * Einar Egilsson
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+var RedirLib = {
+
+ _debug : false,
+ _ext : null,
+ _cout : null,
+ _prefBranch : null,
+ version : 0.2,
+
+ initialize : function(extension) {
+ this._ext = extension;
+ this._cout = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+ this._debug = true;
+ this._initPrefs();
+ },
+
+ debug : function(str) {
+ if (this._ext.prefs.debug) {
+ this._cout.logStringMessage("%1: %2"._(this._ext.name, str));
+ }
+ },
+
+
+ debugObject : function(name, obj) {
+ s = name + ': ';
+ for (x in obj)
+ s += "\n\t%1 : %2"._(x, obj[x]);
+ this.debug(s);
+ },
+
+ //Adds all prefs to a prefs object on the extension object, and registers a pref observer
+ //for the branch.
+ _initPrefs : function() {
+
+ this._prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService)
+ .getBranch("extensions.%1."._(this._ext.id.split("@")[0]));
+ this._ext.prefs = {};
+
+ var list = this._prefBranch.getChildList("", {}).toString().split(",");
+
+ for (i in list) {
+
+ var name = list[i];
+
+ var type = this._prefBranch.getPrefType(name);
+
+ if (type == this._prefBranch.PREF_STRING) {
+ this._ext.prefs[name] = this._prefBranch.getCharPref(name);
+ } else if (type == this._prefBranch.PREF_INT) {
+ this._ext.prefs[name] = this._prefBranch.getIntPref(name);
+ } else if (type == this._prefBranch.PREF_BOOL) {
+ this._ext.prefs[name] = this._prefBranch.getBoolPref(name);
+ }
+ }
+ },
+
+
+ getCharPref : function(branch) {
+ return this._prefBranch.getCharPref(branch);
+ },
+
+ getBoolPref : function(branch) {
+ return this._prefBranch.getBoolPref(branch);
+ },
+
+ getIntPref : function(branch) {
+ return this._prefBranch.getIntPref(branch);
+ },
+
+ getExtensionFolder : function() {
+ return Cc["@mozilla.org/extensions/manager;1"]
+ .getService(Ci.nsIExtensionManager)
+ .getInstallLocation(this._ext.id)
+ .getItemLocation(this._ext.id);
+
+ },
+
+ getEnvVar : function(name) {
+ return Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment)
+ .get(name);
+
+ },
+
+ setEnvVar : function(name, value) {
+ return Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment)
+ .set(name, value);
+
+ },
+
+ msgBox : function(title, text) {
+ Cc["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Ci.nsIPromptService)
+ .alert(window, title, text);
+ },
+
+ //Converts a chrome path to a local file path. Note that the
+ //file specified at the end of the chrome path does not have
+ //to exist.
+ chromeToPath : function(path) {
+ var rv;
+ var ios = Cc["@mozilla.org/network/io-service;1"].createInstance(Ci.nsIIOService);
+ var uri = ios.newURI(path, 'UTF-8', null);
+ var cr = Cc["@mozilla.org/chrome/chrome-registry;1"].createInstance(Ci.nsIChromeRegistry);
+ return cr.convertChromeURL(uri);
+ return decodeURI(rv.spec.substr("file:///".length).replace(/\//g, "\\"));
+ },
+
+ //Saves 'content' to file 'filepath'. Note that filepath needs to
+ //be a real file path, not a chrome path.
+ saveToFile : function(filepath, content) {
+ var file = this.getFile(filepath);
+
+ if (!file.exists()) {
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 420);
+ }
+ var outputStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+
+ outputStream.init( file, 0x04 | 0x08 | 0x20, 420, 0 );
+ var result = outputStream.write( content, content.length );
+ outputStream.close();
+ },
+
+ startProcess: function(filename, args) {
+
+ var file = this.getFile(filename);
+
+ args = args ? args : [];
+
+ if (file.exists()) {
+ var nsIProcess = Cc["@mozilla.org/process/util;1"].getService(Ci.nsIProcess);
+ nsIProcess.init(file);
+ nsIProcess.run(false, args, args.length);
+ } else {
+ throw Error("File '%1' does not exist!"._(filename));
+ }
+
+ },
+
+ //Simulates a double click on the file in question
+ launchFile : function(filepath) {
+ var f = this.getFile(filepath);
+ f.launch();
+ },
+
+
+ //Gets a local file reference, return the interface nsILocalFile.
+ getFile : function(filepath) {
+ var f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+ f.initWithPath(filepath);
+ return f;
+ },
+
+ //Returns all elements that match the query sent in. The root used
+ //in the query is the window.content.document, so this will only
+ //work for html content.
+ xpath : function(doc, query) {
+ return doc.evaluate(query, doc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+ }
+
+
+
+};
+
+//************** Some prototype enhancements ************** //
+
+if (!window.Cc) window.Cc = Components.classes;
+if (!window.Ci) window.Ci = Components.interfaces;
+
+//Returns true if the string contains the substring str.
+String.prototype.contains = function (str) {
+ return this.indexOf(str) != -1;
+};
+
+String.prototype.trim = function() {
+ return this.replace(/^\s*|\s*$/gi, '');
+};
+
+String.prototype.startsWith = function(s) {
+ return (this.length >= s.length && this.substr(0, s.length) == s);
+};
+
+String.prototype.endsWith = function(s) {
+ return (this.length >= s.length && this.substr(this.length - s.length) == s);
+};
+
+//Inserts the arguments into the string. E.g. if
+//the string is "Hello %1" then "Hello %1"._('johnny')
+//would return "Hello johnny"
+String.prototype._ = function() {
+ s = this;
+ for (var i = 0; i < arguments.length; i++) {
+ var nr = "%" + (i+1);
+ var repl;
+ if (arguments[i] == null) {
+ repl = "null";
+ } else if (arguments[i] == undefined) {
+ repl = "undefined";
+ } else {
+ repl = arguments[i];
+ }
+ s = s.replace(new RegExp(nr, "g"), repl);
+ }
+ return s;
+};
+
+function $(id) {
+ return document.getElementById(id);
+} \ No newline at end of file
diff --git a/chrome/locale/en-US/redirect.dtd b/chrome/locale/en-US/redirect.dtd
new file mode 100644
index 0000000..3014c52
--- /dev/null
+++ b/chrome/locale/en-US/redirect.dtd
@@ -0,0 +1,8 @@
+<!-- $Id$ -->
+<!ENTITY redirectWindow.title "Redirect">
+<!ENTITY txtExampleUrl.label "Example url">
+<!ENTITY txtPattern.label "Pattern">
+<!ENTITY txtRedirectUrl.label "Redirect to">
+<!ENTITY chkOnlyIfLinkExists.label "Only if link exists">
+<!ENTITY btnTestPattern.label "Test pattern">
+
diff --git a/chrome/locale/en-US/redirectList.dtd b/chrome/locale/en-US/redirectList.dtd
new file mode 100644
index 0000000..7436cb7
--- /dev/null
+++ b/chrome/locale/en-US/redirectList.dtd
@@ -0,0 +1,9 @@
+<!-- $Id$ -->
+<!ENTITY window.title "Redirects">
+<!ENTITY header "Pattern">
+<!ENTITY colPattern.label "Pattern">
+<!ENTITY colRedirectTo.label "Redirect to">
+<!ENTITY colOnlyIfLinkExits.label "Only if link exists">
+<!ENTITY colPatternType.label "Pattern type">
+<!ENTITY header "Redirects">
+<!ENTITY header.description "All active redirects">
diff --git a/chrome/locale/en-US/redirector.dtd b/chrome/locale/en-US/redirector.dtd
new file mode 100644
index 0000000..3755f33
--- /dev/null
+++ b/chrome/locale/en-US/redirector.dtd
@@ -0,0 +1,5 @@
+<!-- $Id$ -->
+<!ENTITY RedirectorMenuItem.label "Redirector">
+<!ENTITY RedirectorMenuItem.accesskey "R">
+<!ENTITY RedirectorContext.label "Add url to Redirector...">
+<!ENTITY RedirectorContext.accesskey "A"> \ No newline at end of file
diff --git a/chrome/locale/en-US/redirector.properties b/chrome/locale/en-US/redirector.properties
new file mode 100644
index 0000000..110f82c
--- /dev/null
+++ b/chrome/locale/en-US/redirector.properties
@@ -0,0 +1,4 @@
+initError=Failed to initialize %1.
+extensions.redirector@einaregilsson.com.description=Automatically redirects to user-defined urls on certain pages
+addCurrentUrl=Add current url to Redirector
+addLinkUrl=Add link url to Redirector \ No newline at end of file
diff --git a/chrome/skin/overlay.css b/chrome/skin/overlay.css
new file mode 100644
index 0000000..b670fa5
--- /dev/null
+++ b/chrome/skin/overlay.css
@@ -0,0 +1 @@
+/* Include your overlay stylings here */ \ No newline at end of file
diff --git a/defaults/preferences/redirector.js b/defaults/preferences/redirector.js
new file mode 100644
index 0000000..d7985a9
--- /dev/null
+++ b/defaults/preferences/redirector.js
@@ -0,0 +1,6 @@
+//// $Id$
+
+pref("extensions.redirector.debug", false);
+
+// See http://kb.mozillazine.org/Localize_extension_descriptions
+pref("extensions.redirector@einaregilsson.com.description", "chrome://redirector/locale/redirector.properties"); \ No newline at end of file
diff --git a/install.rdf b/install.rdf
new file mode 100644
index 0000000..7dabe48
--- /dev/null
+++ b/install.rdf
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id$ -->
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>redirector@einaregilsson.com</em:id>
+ <em:name>Redirector</em:name>
+ <em:version>0.1</em:version>
+ <em:creator>Einar Egilsson</em:creator>
+ <em:description>Automatically redirects to user-defined urls on certain pages</em:description>
+ <!-- <em:homepageURL>http://addons.mozilla.org/{app}/xxx/</em:homepageURL> --> <!-- Add after upload to addons.mozilla.org -->
+ <em:aboutURL>chrome://redirector/content/about.xul</em:aboutURL>
+ <em:optionsURL>chrome://redirector/content/options.xul</em:optionsURL>
+ <em:iconURL>chrome://redirector/content/redirector.png</em:iconURL>
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->
+ <em:minVersion>2.0</em:minVersion>
+ <em:maxVersion>2.0.0.*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+</RDF> \ No newline at end of file
diff --git a/make.bat b/make.bat
new file mode 100644
index 0000000..e4868af
--- /dev/null
+++ b/make.bat
@@ -0,0 +1,11 @@
+::
+:: Build script for extension
+::
+:: Einar Þór Egilsson - 26.10.2006
+::
+
+SET EXT=Redirector.xpi
+
+IF NOT EXIST build md build
+IF EXIST build\%EXT% del build\%EXT%
+zip -r build\%EXT% *.* -x build* *.py *.bat \ No newline at end of file