From 96966ca83f96ed1babcd2bd23aa68feb63fbb7a7 Mon Sep 17 00:00:00 2001 From: Einar Egilsson Date: Tue, 15 Sep 2009 21:41:06 +0000 Subject: Total restructuring of files. Unescape matches fully working Export of redirects working. git-svn-id: http://einaregilsson.googlecode.com/svn/mozilla/redirector/trunk@249 119bf307-c92d-0410-89bd-8f53e6181181 --- chrome/content/code/browserOverlay.xul.js | 137 ++++++++++++ chrome/content/code/editRedirect.xul.js | 86 +++++++ chrome/content/code/redirectList.xul.js | 193 ++++++++++++++++ chrome/content/code/redirector.prototype.js | 333 ++++++++++++++++++++++++++++ 4 files changed, 749 insertions(+) create mode 100644 chrome/content/code/browserOverlay.xul.js create mode 100644 chrome/content/code/editRedirect.xul.js create mode 100644 chrome/content/code/redirectList.xul.js create mode 100644 chrome/content/code/redirector.prototype.js (limited to 'chrome/content/code') diff --git a/chrome/content/code/browserOverlay.xul.js b/chrome/content/code/browserOverlay.xul.js new file mode 100644 index 0000000..636c02b --- /dev/null +++ b/chrome/content/code/browserOverlay.xul.js @@ -0,0 +1,137 @@ +//// $Id$ + +var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject; + +var RedirectorOverlay = { + + id : "redirector@einaregilsson.com", + name : "Redirector", + initialized : false, + strings : null, + + onLoad : function(event) { + try { + + // initialization code + Redirector.debug("Initializing..."); + document.getElementById('contentAreaContextMenu') + .addEventListener("popupshowing", function(e) { RedirectorOverlay.showContextMenu(e); }, false); + + if (!Redirector.getBoolPref('showContextMenu')) { + document.getElementById('redirector-context').hidden = true; + } + if (!Redirector.getBoolPref('showStatusBarIcon')) { + document.getElementById('redirector-status').hidden = true; + } + this.strings = document.getElementById("redirector-strings"); + this.prefObserver.register(); + this.setStatusBarImg(); + + Redirector.debug("Finished initialization"); + this.initialized = true; + + } catch(e) { + if (this.strings) { + alert(this.strings.getFormattedString("initError", [this.name]) + "\n\n" + e); + } else { + alert(e); + } + } + }, + + onUnload : function(event) { + RedirectorOverlay.prefObserver.unregister(); + Redirector.debug("Finished cleanup"); + }, + + showContextMenu : function(event) { + if (gContextMenu.onLink) { + document.getElementById("redirector-context").label = this.strings.getString('addLinkUrl'); + } else { + document.getElementById("redirector-context").label = this.strings.getString('addCurrentUrl'); + } + }, + + onContextMenuCommand: function(event) { + + var item = { exampleUrl : window.content.location.href, pattern: window.content.location.href}; + if (gContextMenu.onLink) { + item.redirectUrl = gContextMenu.link.toString(); + } + + window.openDialog("chrome://redirector/content/ui/editRedirect.xul", + "redirect", + "chrome,dialog,modal,centerscreen", item); + + if (item.saved) { + Redirector.addRedirect(item); + } + }, + + onMenuItemCommand: function(event) { + this.openSettings(); + }, + + toggleEnabled : function(event) { + Redirector.setEnabled(!Redirector.enabled); + }, + + openSettings : function() { + var windowName = "redirectorSettings"; + var windowsMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator); + var win = windowsMediator.getMostRecentWindow(windowName); + if (win) { + win.focus(); + } else { + window.openDialog("chrome://redirector/content/ui/redirectList.xul", + windowName, + "chrome,dialog,resizable=no,centerscreen", this); + } + + }, + + statusBarClick : function(event) { + var LEFT = 0, RIGHT = 2; + + if (event.button == LEFT) { + RedirectorOverlay.toggleEnabled(); + } else if (event.button == RIGHT) { + this.openSettings(); + } + }, + + setStatusBarImg : function() { + var statusImg = document.getElementById('redirector-statusbar-img'); + + if (Redirector.enabled) { + statusImg.src = 'chrome://redirector/content/images/statusactive.PNG' + statusImg.setAttribute('tooltiptext', this.strings.getString('enabledTooltip')); + } else { + statusImg.src = 'chrome://redirector/content/images/statusinactive.PNG' + statusImg.setAttribute('tooltiptext', this.strings.getString('disabledTooltip')); + } + }, + + prefObserver : { + + getService : function() { + return Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranchInternal); + }, + + register: function() { + this.getService().addObserver('extensions.redirector', this, false); + }, + + unregister: function() { + this.getService().removeObserver('extensions.redirector', this); + }, + + observe : function(subject, topic, data) { + if (topic == 'nsPref:changed' && data == 'extensions.redirector.enabled') { + RedirectorOverlay.setStatusBarImg(); + } + } + } +}; +window.addEventListener("load", function(event) { RedirectorOverlay.onLoad(event); }, false); +window.addEventListener("unload", function(event) { RedirectorOverlay.onUnload(event); }, false); diff --git a/chrome/content/code/editRedirect.xul.js b/chrome/content/code/editRedirect.xul.js new file mode 100644 index 0000000..6e981d2 --- /dev/null +++ b/chrome/content/code/editRedirect.xul.js @@ -0,0 +1,86 @@ +//// $Id$ + +const kRedirectorWildcard = 'W'; +const kRedirectorRegex= 'R'; +var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject; + +function $(id) { + return document.getElementById(id); +} + +var EditRedirect = { + + onLoad : function() { + var item = window.arguments[0]; + item.saved = false; + $('txtExampleUrl').value = item.exampleUrl; + $('txtPattern').value = item.pattern; + $('txtRedirectUrl').value = item.redirectUrl || ''; + $('txtExcludePattern').value = item.excludePattern || ''; + $('chkUnescapeMatches').setAttribute('checked', !!item.unescapeMatches); + + $('txtPattern').focus(); + this.strings = document.getElementById("redirector-strings"); + + if (item.patternType == kRedirectorRegex) { + $('rdoRegex').setAttribute('selected', true); + $('rdoWildcard').setAttribute('selected', false); + } + }, + + onAccept : function() { + var item = window.arguments[0]; + + item.pattern = $('txtPattern').value; + if ($('rdoRegex').selected) { + item.patternType = kRedirectorRegex; + } else { + item.patternType = kRedirectorWildcard; + } + item.exampleUrl = $('txtExampleUrl').value; + item.redirectUrl = $('txtRedirectUrl').value; + item.excludePattern = $('txtExcludePattern').value; + item.unescapeMatches = $('chkUnescapeMatches').hasAttribute('checked') && $('chkUnescapeMatches').getAttribute('checked'); + item.saved = true; + + return true; + }, + + msgBox : function(title, text) { + Components.classes["@mozilla.org/embedcomp/prompt-service;1"] + .getService(Components.interfaces.nsIPromptService) + .alert(window, title, text); + }, + + testPattern : function() { + var redirectUrl, pattern, excludePattern, example, extName, isExcluded, unescapeMatches; + redirectUrl = $('txtRedirectUrl').value; + pattern = $('txtPattern').value; + excludePattern = $('txtExcludePattern').value; + example = $('txtExampleUrl').value; + unescapeMatches = $('chkUnescapeMatches').checked; + + extName = this.strings.getString('extensionName'); + + if ($('rdoRegex').selected) { + redirectUrl = Redirector.regexMatch(pattern, example, redirectUrl, unescapeMatches); + if (excludePattern) { + isExcluded = Redirector.regexMatch(excludePattern, example, 'exclude'); + } + } else { + redirectUrl = Redirector.wildcardMatch(pattern, example, redirectUrl, unescapeMatches); + if (excludePattern) { + isExcluded = Redirector.wildcardMatch(excludePattern, example, 'exclude'); + } + } + + var isRedirectMatch = redirectUrl || (redirectUrl === '' && $('txtRedirectUrl').value === ''); + if (isRedirectMatch && !isExcluded) { + this.msgBox(extName, this.strings.getFormattedString('testPatternSuccess', [pattern, example, redirectUrl])); + } else if (isExcluded) { + this.msgBox(extName, this.strings.getFormattedString('testPatternExclude', [example, excludePattern])); + } else { + this.msgBox(extName, this.strings.getFormattedString('testPatternFailure', [pattern, example])); + } + } +}; \ No newline at end of file diff --git a/chrome/content/code/redirectList.xul.js b/chrome/content/code/redirectList.xul.js new file mode 100644 index 0000000..65957b4 --- /dev/null +++ b/chrome/content/code/redirectList.xul.js @@ -0,0 +1,193 @@ +//// $Id$ + +var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject; +const Cc = Components.classes; +const Ci = Components.interfaces; + +function $(id) { + return document.getElementById(id); +} + +var RedirectList = { + + id : "redirector@einaregilsson.com", + name : "Redirector", + lstRedirects: null, + btnDelete : null, + btnEdit : null, + + addItemsToListBox : function(items) { + + var list = $('lstRedirects'); + var item, row, value, newItem; + + for each (item in items) { + newItem = this.template.cloneNode(true); + + 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); + newItem.setAttribute("selected", false); + } + + }, + + onLoad : function() { + try { + this.lstRedirects = $('lstRedirects'); + this.lstRedirects.selType = 'single'; + this.template = document.getElementsByTagName('richlistitem')[0]; + this.lstRedirects.removeChild(this.template); + this.btnDelete = $('btnDelete'); + this.btnEdit = $('btnEdit'); + this.addItemsToListBox(Redirector.list); + } catch(e) { + alert(e); + } + }, + + openHelp : function() { + var windowName = "redirectorHelp"; + 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(); + if (win.name == windowName) { + win.focus(); + return; + } + } + window.openDialog("chrome://redirector/content/ui/help.html", windowName, "chrome,dialog,resizable=yes,location=0,toolbar=0,status=0,width=800px,height=600px,centerscreen", this); + }, + + close : function() { + window.close(); + }, + + moveUp : function(){ + if (this.lstRedirects.selectedIndex <= 0) { + return; + } + this.switchItems(this.lstRedirects.selectedIndex-1); + }, + + moveDown : function() { + if (this.lstRedirects.selectedIndex == Redirector.list.length-1) { + return; + } + this.switchItems(this.lstRedirects.selectedIndex); + }, + + switchItems : function(firstIndex) { + var first = Redirector.list[firstIndex]; + var second = Redirector.list[firstIndex+1]; + Redirector.list[firstIndex] = second; + Redirector.list[firstIndex+1] = first; + this.setListItemValues(this.lstRedirects.children[firstIndex+1], first); + this.setListItemValues(this.lstRedirects.children[firstIndex], second); + this.lstRedirects.selectedIndex -= 1; + Redirector.save(); + }, + + setListItemValues : function(listItem, item){ + 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); + }, + + addRedirect : function() { + + var item = { pattern : '', exampleUrl : '', redirectUrl : '', patternType : 'W', unescapeMatches : false}; + + window.openDialog("chrome://redirector/content/ui/editRedirect.xul", + "redirect", + "chrome,dialog,modal,centerscreen", item); + + if (item.saved) { + this.addItemsToListBox([item]); + Redirector.addRedirect(item); + } + + }, + + editRedirect : function() { + + var listItem = this.lstRedirects.selectedItem; + + if (!listItem) { + return; + } + + var item = listItem.item; + + window.openDialog("chrome://redirector/content/ui/editRedirect.xul", + "redirect", + "chrome,dialog,modal,centerscreen", item); + + if (item.saved) { + this.setListItemValues(listItem, item); + Redirector.save(); + } + }, + + deleteRedirect : function() { + var index = this.lstRedirects.selectedIndex; + + if (index == -1) { + return; + } + + try { + this.lstRedirects.removeChild(this.lstRedirects.children[index]); + Redirector.deleteAt(index); + } catch(e) { + alert(e); + } + }, + + selectionChange : function() { + var index = $('lstRedirects').selectedIndex; + + $('btnEdit').disabled = (index == -1); + $('btnDelete').disabled = (index == -1); + }, + + importExport : function(mode, captionKey, func) { + //Mostly borrowed from Adblock Plus + var picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); + picker.init(window, Redirector.getString(captionKey), mode); + picker.defaultExtension = ".rdx"; + var dir = Redirector.getDefaultDir(); + if (dir) { + picker.displayDirectory = dir; + } + picker.appendFilter(Redirector.getString('redirectorFiles'), '*.rdx'); + + if (picker.show() != picker.returnCancel) + { + try + { + func(picker.file); + } + catch (e) + { + alert(e); + } + } + }, + + export : function() { + this.importExport(Ci.nsIFilePicker.modeSave, 'exportCaption', function(file) { + Redirector.exportRedirects(file); + }); + }, + + import : function() { + this.importExport(Ci.nsIFilePicker.modeOpen, 'importCaption', function(file) { + Redirector.importRedirects(file); + }); + } +}; diff --git a/chrome/content/code/redirector.prototype.js b/chrome/content/code/redirector.prototype.js new file mode 100644 index 0000000..24a41ba --- /dev/null +++ b/chrome/content/code/redirector.prototype.js @@ -0,0 +1,333 @@ +//// $Id$ + +Cc = Components.classes; +Ci = Components.interfaces; +Cr = Components.results; +kRedirectorWildcard = 'W'; +kRedirectorRegex= 'R'; +nsIContentPolicy = Ci.nsIContentPolicy; + + +Redirector.prototype = { + prefBranch : null, + list : null, + strings : null, + cout : Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService), + + init : function() { + this.prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("extensions.redirector."); + + //Check if we need to update existing redirects + + var data = this.prefBranch.getCharPref('redirects'); + var version = this.prefBranch.getCharPref('version'); + this.debugEnabled = this.prefBranch.getBoolPref('debug'); + this.enabled = this.prefBranch.getBoolPref('enabled'); + this.loadStrings(); + //Here update checks are handled + if (version == 'undefined') { //Either a fresh install of Redirector, or first time install of v2.0 + if (data) { //There is some data in redirects, we are upgrading from a previous version, need to upgrade data + var tempList = eval(data); + var arr; + var newArr = [] + for each (arr in tempList) { + if (arr.length == 5) { + arr.push(''); //For those that don't have an exclude pattern. Backwards compatibility is a bitch! + } + arr.splice(3,1); //Remove the "only if link exists" data + newArr.push(arr.join(',,,')); + } + this.prefBranch.setCharPref('redirects', newArr.join(':::')); + } + this.prefBranch.setCharPref('version', '2.0'); + } + //Update finished + + //Now get from the new format + data = this.prefBranch.getCharPref('redirects'); + var arr; + this.list = []; + if (data != '') { + for each (redirectString in data.split(':::')) { + arr = redirectString.split(',,,'); + this.list.push({ + exampleUrl : arr[0], + pattern : arr[1], + redirectUrl : arr[2], + patternType : arr[3], + excludePattern : arr[4], + unescapeMatches : arr[5] == 'true' //This might be undefined for those upgrading from 1.7.1 but that's ok + }); + } + } + + }, + + getDefaultDir : function() { + return this.prefBranch.getCharPref('defaultDir'); + }, + + setDefaultDir : function(dir) { + this.prefBranch.setCharPref('defaultDir', dir.spec); + }, + + loadStrings : function() { + var src = 'chrome://redirector/locale/redirector.properties'; + var localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService); + var appLocale = localeService.getApplicationLocale(); + var stringBundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService); + this.strings = stringBundleService.createBundle(src, appLocale); + }, + + debug : function(msg) { + if (this.debugEnabled) { + this.cout.logStringMessage('REDIRECTOR: ' + msg); + } + }, + + // nsIContentPolicy interface implementation + shouldLoad: function(contentType, contentLocation, requestOrigin, aContext, mimeTypeGuess, extra) { + if (!this.enabled) { + return nsIContentPolicy.ACCEPT; + } + if (contentLocation.scheme != "http" && contentLocation.scheme != "https") { + return nsIContentPolicy.ACCEPT; + } + + if (contentType != nsIContentPolicy.TYPE_DOCUMENT) { + return nsIContentPolicy.ACCEPT; + } + + if (!aContext || !aContext.loadURI) { + return nsIContentPolicy.ACCEPT; + } + this.debug("CHECK: " + contentLocation.spec); + + var url = contentLocation.spec; + + for each (var redirect in this.list) { + var redirectUrl = this.getRedirectUrl(url, redirect); + if (redirectUrl) { + redirectUrl = this.makeAbsoluteUrl(url, redirectUrl); + this.debug('Redirecting ' + url + ' to ' + redirectUrl); + aContext.loadURI(redirectUrl, requestOrigin, null); + return nsIContentPolicy.REJECT_REQUEST; + } + } + return nsIContentPolicy.ACCEPT; + }, + + // nsIContentPolicy interface implementation + shouldProcess: function(contentType, contentLocation, requestOrigin, insecNode, mimeType, extra) { + return nsIContentPolicy.ACCEPT; + }, + + setEnabled : function(val) { + this.enabled = val; + this.prefBranch.setBoolPref('enabled', val); + }, + + reload : function() { + Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript('chrome://redirector/content/code/redirector.prototype.js'); + + for (var key in Redirector.prototype) { + this[key] = Redirector.prototype[key]; + } + this.init(); + }, + + addRedirect : function(redirect) { + this.list.push(redirect); + this.save(); + }, + + deleteAt : function(index) { + this.list.splice(index, 1); + this.save(); + }, + + save : function() { + this.prefBranch.setCharPref('redirects', this.redirectsAsStrings().join(':::')); + }, + + redirectsAsStrings : function() { + var r + , tempList = []; + + for each (r in this.list) { + this.debug(r.unescapeMatches); + tempList.push([r.exampleUrl, r.pattern, r.redirectUrl, r.patternType, r.excludePattern, r.unescapeMatches].join(',,,')); + } + return tempList; + }, + + getBoolPref : function(name) { + return this.prefBranch.getBoolPref(name); + }, + + regexMatch : function(pattern, text, redirectUrl, unescapeMatches) { + + if (!pattern) { + return null; + } + var strings, rx, match; + try { + rx = new RegExp(pattern, 'gi'); + match = rx.exec(text); + } catch(e) { + this.msgBox(this.strings.GetStringFromName('extensionName'), this.strings.formatStringFromName('regexPatternError', [pattern, e.toString()],2)); + return null; + } + + var rxrepl; + + if (match) { + for (var i = 1; i < match.length; i++) { + rxrepl = new RegExp('\\$' + i, 'gi'); + redirectUrl = redirectUrl.replace(rxrepl, unescapeMatches ? unescape(match[i]) : match[i]); + } + return redirectUrl; + } + + return null; + + }, + + exportRedirects : function(file) { + var fileStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + const PR_WRONLY = 0x02; + const PR_CREATE_FILE = 0x08; + const PR_TRUNCATE = 0x20; + + fileStream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644, 0); + //file.parent.QueryInterface(Ci.nsILocalFile) + var stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream); + stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + stream.writeString(this.redirectsAsStrings().join('\n')); + stream.close(); + }, + + importRedirects : function(file) { + var fileStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); + fileStream.init(file, 0x01, 0444, 0); //TODO: Find the actual constants for these magic numbers + + var stream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream); + stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + stream = stream.QueryInterface(Ci.nsIUnicharLineInputStream); + + var importCount = 0, existsCount = 0; + var lines = []; + var line = {value: null}; + while (stream.readLine(line)) { + var parts = line.replace('\n', '').split(',,,'); + if (parts.length < 6) { + var redirect = { + exampleUrl : parts[0], + pattern : parts[1], + redirectUrl : parts[2], + patternType : parts[3], + excludePattern : parts[4], + unescapeMatches : parts[5] == 'true' ? true : false + }; + + + } + } + stream.close(); + this.save(); + }, + + getString : function(name) { + return this.strings.GetStringFromName(name); + }, + + msgBox : function(title, text) { + Cc["@mozilla.org/embedcomp/prompt-service;1"] + .getService(Ci.nsIPromptService) + .alert(null, title, text); + }, + + getRedirectUrl: function(url, redirect) { + + if (redirect.patternType == kRedirectorWildcard) { + if (this.wildcardMatch(redirect.excludePattern, url, 'whatever')) { + this.debug(url + ' matches exclude pattern ' + redirect.excludePattern); + return null; + } + return this.wildcardMatch(redirect.pattern, url, redirect.redirectUrl, redirect.unescapeMatches); + } else if (redirect.patternType == kRedirectorRegex) { + if (this.regexMatch(redirect.excludePattern, url, 'whatever')) { + this.debug(url + ' matches exclude pattern ' + redirect.excludePattern); + return null; + } + return this.regexMatch(redirect.pattern, url, redirect.redirectUrl, redirect.unescapeMatches); + } + return null; + }, + + makeAbsoluteUrl : function(currentUrl, relativeUrl) { + + if (relativeUrl.match(/https?:/)) { + return relativeUrl; + } + + var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + //this.debug(currentUrl); + var uri = ioService.newURI(currentUrl, null, null); + + return uri.resolve(relativeUrl); + }, + + wildcardMatch : function(pattern, text, redirectUrl, unescapeMatches) { + + if (!pattern || !text) { + return null; + } + if (pattern.indexOf('*') == -1) { + return (pattern == text) ? redirectUrl : null; + } + + var parts = pattern.split('*'); + var first = parts[0], + last = parts[parts.length-1]; + + if (first) { + if (text.substr(0, first.length) != first) { + return null; + } + text = text.substr(first.length); + } + + if (last) { + if (text.substr(text.length-last.length) != last) { + return null; + } + text = text.substr(0, text.length-last.length); + } + + if ((first || last) && parts.length == 2) { + return redirectUrl.replace('$1', text); + } + parts.splice(0,1); + parts.splice(parts.length-1,1); + var pos = 0, lastPos = 0; + var matches = []; + for each(part in parts) { + pos = text.indexOf(part, lastPos); + if (pos == -1) { + return null; + } + var match = text.substr(lastPos, pos-lastPos); + matches.push(match); + lastPos = pos + part.length; + } + matches.push(text.substr(lastPos)); + for (var i = 1; i <= matches.length; i++) { + redirectUrl = redirectUrl.replace(new RegExp('\\$' + i, 'gi'), unescapeMatches ? unescape(matches[i-1]) : matches[i-1]); + } + + return redirectUrl; + } +}; -- cgit v1.2.3-70-g09d2