User:Gerbrant/edit/regexReplace.js

From OpenWetWare
Revision as of 14:33, 26 July 2009 by Bill Flanagan (talk | contribs) (1 revision)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
document.write("<style>span.GerbrantEditRegexReplaceHit{font-weight:bold;background:lightsteelblue}span.GerbrantEditRegexReplaceHitOff{font-weight:bold;background:mistyrose}span.GerbrantEditRegexReplaceMaskFailed{font-weight:normal;color:red}</style>");

hookEvent("load", function()
{
	var lang, textBox = document.getElementById("wpTextbox1");
	if(!textBox) return;
	try{  lang = Gerbrant.edit.regexReplace.lang;  }catch(nopresets){}
	if(!lang) lang = wgUserLanguage;
	switch(lang)
	{

// Localized strings:

case "nl": str =
{
	finished: "Voltooid; $1 items werden vervangen.",
	finished2: "Voltooid; $1 van $2 items werden vervangen.",
	notFound: "De gevraagde tekst is niet gevonden.",
	replace: "Vervangen...",
	replaceSel: "Vervang selectie",
	errorNoCheckBox: "Kan het corresponderende keuzevakje niet vinden.",
	textHasChanged: "Waarschuwing! De tekst is gewijzigd nadat op 'Vervangen...' werd geklikt. Deze wijzigingen zullen verloren gaan bij het vervangen. Wilt u doorgaan?",
	looksLikeFunction: "Waarschuwing! De tekst die u wilt gebruiken om de gevonden tekst mee te vervangen ziet eruit als een JavaScript functie. Weet u zeker dat u deze als tekst wilt gebruiken, en dus niet als vervangingsfunctie?",
	maskFailed: "Masker faalde: $1",
	useRepFun: "< functie >"
};
break;

default: str =
{
	finished: "Finished; $1 items were replaced.",
	finished2: "Finished; $1 out of $2 items were replaced.",
	notFound: "Requested text was not found.",
	replace: "Replace...",
	replaceSel: "Replace selection",
	errorNoCheckBox: "Cannot find the corresponding checkbox.",
	textHasChanged: "Warning! The text has changed after 'Replace...' was clicked. These changes will be lost during replacement. Do you want to continue?",
	looksLikeFunction: "Warning! The text you intend to use to replace the matched text looks like a JavaScript function. Are you really sure you want to use this as replacement text, and not as a replacement function?",
	maskFailed: "Mask failed: $1",
	useRepFun: "< function >"
};

// Don't localize anything beyond this point.

	}

	var mask, regex, text, minFrag = 30, minDel = 10, repFun;

	var results = document.createElement("DIV");
	var tbRegex = document.createElement("INPUT");
	//tbRegex.value = "[A-Z]{2,}";

	var hl = document.createElement("INPUT");
	hl.type = "checkbox";

	var rep = document.createElement("DIV");
	rep.style.display = "none";
	rep.style.whiteSpace = "nowrap";

	function returnTrue(){ return true; }

	function evalError(e){ alert(e.message); }

	function getMaskAndRegex(t)
	{
		var p = t.indexOf("**"), r;
		if(p < 0) return [returnTrue, t];
		else
		{
			try{ eval("r=" + t.slice(0, p)) }
			catch(x){ evalError(x); r = returnTrue; }
			return [r, t.slice(p + 2)];
		}
	}

	function findMatches()
	{
		var m = [], r = [], i = 0;
		text = textBox.value;

		var t = text.replace(regex, function(a)
		{
			try
			{
				if(!mask.apply(null, arguments)) return a;
			}
			catch(e)
			{
				m.push(a + ' \u0001span class="GerbrantEditRegexReplaceMaskFailed">(' + str.maskFailed.replace("$1", e.message) + ')\u0001/span>');
				return "\u0001";
			}
			m.push(a);
			return "\u0001";
		}).split("\u0001");

		if(m.length == 0)
		{
			results.innerHTML = str.notFound;
			return;
		}

		if(t[0].length > minFrag + minDel)
		{
			r.push(" \u2026 ");
			r.push(t[0].slice(-minFrag));
		}
		else
			r.push(t[0]);
		while(true)
		{
			r.push('\u0001span class="GerbrantEditRegexReplaceHit">\u0001input type="checkbox" checked id="Gerbrant-errCB');
			r.push(i);
			r.push('" onclick="Gerbrant.edit.regexReplace.toggleCB(this)">');
			r.push(m[i]);
			r.push('\u0001/span>');
			if(++i >= m.length) break;
			if(t[i].length > 2 * minFrag + minDel)
			{
				r.push(t[i].slice(0, minFrag));
				r.push(" \u2026 ");
				r.push(t[i].slice(-minFrag));
			}
			else
				r.push(t[i]);
		}
		if(t[i].length > minFrag + minDel)
		{
			r.push(t[i].slice(0, minFrag));
			r.push(" \u2026 ");
		}
		else
			r.push(t[i]);

		rep.style.display = "";
		onResize();
		results.innerHTML = r.join("").replace(
			/&/g, "&amp;").replace(
			/</g, "&lt;").replace(
			/\u0001/g, "<").replace(
			/\n[ \t]/g, "\n&nbsp;").replace(
			/[ \t](?=[ \t])/g, "&nbsp;").replace(
			/\n/g, "<br>");
	}

	function getRegexAndFind()
	{
		mask = getMaskAndRegex(tbRegex.value);
		regex = new RegExp(mask[1], hl.checked ? "g" : "ig");
		mask = mask[0];
		findMatches();
	}

	var ok = document.createElement("INPUT");
	ok.type = "button";
	ok.value = str.replace;
	ok.onclick = getRegexAndFind;

	var div = document.createElement("DIV");
	div.style.whiteSpace = "nowrap";
	div.appendChild(tbRegex);
	div.appendChild(hl);
	div.appendChild(ok);

	var tbReplace = document.createElement("INPUT");
	
	var chkJS = document.createElement("INPUT");
	chkJS.type = "checkbox";

	function doReplace()
	{
		var rjs = chkJS.checked, i = 0, j = 0, r, nt, ohno = false;
		if(text != textBox.value) if(!confirm(str.textHasChanged)) return;
		r = tbReplace.value;
		if(rjs)
			if(r == str.useRepFun) r = repFun;
			else try{ eval("r=" + r); }
			catch(x){ evalError(x); return; }
		else if(r == str.useRepFun || /^\s*function\s*\([0-9A-Za-z$_, ]*\)\s*\{/.test(r)) if(!confirm(str.looksLikeFunction)) return;
		try
		{
			nt = text.replace(regex, function(a)
			{
				try{ if(!mask.apply(null, arguments)) return a; }catch(e){/* mask failed; assume true */}
				var c = document.getElementById("Gerbrant-errCB" + i++);
				if(c)
					if(c.checked)
					{
						j++;
						if(rjs)
							return r.apply(null, arguments);
						else return r;
					}
					else return a;
				else ohno = true;
			});
		}
		catch(e)
		{
			alert(e.message);
			return;
		}
		if(ohno)
		{
			alert(str.errorNoCheckBox);
			return;
		}
		if(j < i) results.innerHTML = str.finished2.replace("$1", j).replace("$2", i);
		else results.innerHTML = str.finished.replace("$1", j);
		rep.style.display = "none";
		textBox.value = nt;
	}

	var finish = document.createElement("INPUT");
	finish.type = "button";
	finish.value = str.replaceSel;
	finish.onclick = doReplace;

	rep.appendChild(tbReplace);
	rep.appendChild(chkJS);
	rep.appendChild(finish);

	textBox.parentNode.insertBefore(div, textBox);
	textBox.parentNode.insertBefore(results, textBox);
	textBox.parentNode.insertBefore(rep, textBox);

	function onResize()
	{
		finish.style.height = ok.style.height = tbRegex.offsetHeight + "px";
		tbRegex.style.width = textBox.offsetWidth - ok.offsetWidth - hl.offsetWidth - 14 + "px";
		tbReplace.style.width = textBox.offsetWidth - finish.offsetWidth - chkJS.offsetWidth - 14 + "px";
	}
	onResize();
	hookEvent("resize", onResize);

	if(typeof module == "function")
		module("Gerbrant.edit.regexReplace", {replace: function(what, ulcase, repl, isjs)
		{
			if(isjs == undefined && typeof repl == "function")
			{
				repFun = repl;
				tbReplace.value = str.useRepFun;
				chkJS.checked = true;
			}
			else
			{
				tbReplace.value = repl;
				chkJS.checked = isjs;
			}
			if(what instanceof RegExp)
			{
				regex = what;
				mask = ulcase ? ulcase : returnTrue;
				findMatches();
			}
			else
			{
				tbRegex.value = what;
				hl.checked = ulcase;
				getRegexAndFind();
			}
		},
		toggleCB: function(cb)
		{
			var p = cb.parentNode;
			if(cb.checked)
			{
				if(p.className.slice(-3) == "Off")
					p.className = p.className.slice(0, -3);
			}
			else if(p.className.slice(-3) != "Off")
				p.className += "Off";
		}});
});

if(typeof loadModule == "function")
{
	new function()
	{
		var presets;
		try{  presets = Gerbrant.edit.regexReplace.presets;  }catch(nopresets){}
		if(presets)
			loadModule("Gerbrant.gui.lilink", function(l)
			{
				hookEvent("load", function()
				{
					var i, p, e = function(s)
					{
						return s.toString().replace(/["\\]/g, function(a)
						{
							return "\\" + a;
						});
					};
					if(!document.getElementById("wpTextbox1")) return;
					for(i in presets)
					{
						p = presets[i];
						l.addToolboxLink('javascript:Gerbrant.edit.regexReplace.replace(' +
							(p.regex instanceof RegExp
							? p.regex + ',' + p.mask
							: '"' + (p.mask ? e(p.mask) + '**' : '') + e(p.regex) + '",' + !!p.caseSens) +
							',"' + e(p.replace) + '",' + (typeof p.replace == "function") + ');', i);
					}
				});
			});
	};
}