BBCode in Text

Adds BBCode support to an antique forum.

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name           BBCode in Text
// @namespace      http://mailerdaemon.home.comcast.net/
// @include        http://forums.secondlife.com/*
// @version        0.2
// @description    Adds BBCode support to an antique forum.
// ==/UserScript==

//configures how urls are displayed.
const ERRORS = false;
const url_start = 40;
const url_end = 25;
const url_len = url_start + url_end;

GM_addStyle = function(css){
    style = document.createElement("style");
    style.type = "text/css";
    style.innerHTML = css;
	document.getElementsByTagName('head')[0].appendChild(style);
};
//GM_log = function(text){};

GM_addStyle(".GMCode {border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: auto; text-align: left; font-family:monospace; } .GMCode br {display:none;}")

const chars = String.fromCharCode(38, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222, 8364, 34, 223, 60, 62, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 8364, 8226, 160, 161);
const entities = new Array ('amp','agrave','aacute','acirc','atilde','auml','aring',
						'aelig','ccedil','egrave','eacute','ecirc','euml','igrave',
						'iacute','icirc','iuml','eth','ntilde','ograve','oacute',
						'ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc',
						'uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc',
						'Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute',
						'Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde',
						'Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave',
						'Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig',
						'lt','gt','cent','pound','curren','yen','brvbar','sect','uml',
						'copy','ordf','laquo','not','shy','reg','macr','deg','plusmn',
						'sup2','sup3','acute','micro','para','middot','cedil','sup1',
						'ordm','raquo','frac14','frac12','frac34',
						'euro','bull','nbsp','iexcl');

if(!String.prototype.trim) String.prototype.trim = function() { return this.replace(/^\s*/,'').replace(/\s*$/, ''); }
if(!String.prototype.htmlUnescape) String.prototype.htmlUnescape = function(){
	var r = /&(#[0-9]*|[A-Za-z0-9]*);/;
	var i = this;
	var o = ""
	var p;
	do
	{
		if(!(p = r.exec(i)))
			return o + i;
		if(p.index > 0)
			o += i.slice(0, p.index);
		i = i.slice(p.index + p[0].length);
		if(p[1].charAt(0) == '#')
			o += String.fromCharCode(p[1].slice(1))
		else
		{
			var w = entities.indexOf(p[1]);
			o += (w != -1)?chars[w]:("&"+p[1]+";");
		}
	}while(1);
}
if(!String.prototype.htmlEscape) String.prototype.htmlEscape = function(){
	var i = this;
	for(var k = 0;k < chars.length; k++)
		i = i.replace(new RegExp(chars[k], "g"), "&"+entities[k]+";");
	return i;
}
if(!Array.prototype.insert) Array.prototype.insert = function( i, v ) {
	var b = this.splice( i );
	this.push(v);
	return this.concat( b );
};

var count = 0;
var base = document.URL;
count = base.indexOf("?");
if(count >= 0) base = base.substring(0, count);
base = base.substring(0, base.lastIndexOf("/")+1);
var pattern = /(?:\[(?:[\/\\]?)(url|email|thread|post|indent|code|php|font|size|color|b|u|i|right|left|center|highlight|list|img|[*])(?:|=[^\]]*)\]|((?:https?|mms|rstp|secondlife|ftp|mailto):[^\s\[]*)|((?:[a-z0-9.\-]{3,}\.(?:com|net|org|co\.uk)|(?:(?:0x[0-9a-f]{1,8}|[0-9]{1,3})\.){3}(?:0x[0-9a-f]{1,8}|[0-9]{1,3}))(?:(?:\:[0-9]+|)\/[^\s\[]*|(?=[^0-9a-z\-.]|$))))/im;
var split_pattern = /\[([\/\\]?)([^=\]]*?)(?:\s*=\s*"?([^\]"]*)"?\s*|)\]/im;
count = 0;
var calls = 100000;//stops a race condition that doesn't happen anymore.

start();

function start()
{
	var i, j, divs;
	var xpath = "//td[@class='thead']/../../tr[2]/td[position()=2 and @class='alt1']"+"|"+//thread
						"//tr[contains(td, 'Preview')]/td[@class='tcat']/../../tr[2]"+"|"+//edit - preview
						"//td[@class='thead']/../../tr/td[position()=2 and @class='alt2']/..";//topic review
	var res = document.evaluate(xpath, document, null,	XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); 
	for (i = 0; divs = res.snapshotItem(i); ++i) {
		var t = divs.childNodes.length;
//		GM_log(divs.nodeName + "\nChild Count = " + t+ "\n"+divs.innerHTML);
		for (t=0; t<divs.childNodes.length; t++){
			parse(divs.childNodes[t]);
		}
	}
	if(i > 0 || count > 0)
	{
//		GM_log(document.URL.concat("\nHad "+count+" broken tag"+((count != 1)?"s":"") + " in "+i +" messages. (debug = " + calls + " )"));
//		GM_log(calls);
	}
}

function parse(element, only, nourl)
{
	var table = new Array(0);
	var urls = new Array(0);
	var badurls = new Array(0);
	var t = element.firstChild;
	for (;t != null; t = t.nextSibling){
		if(--calls < 0)
			return;
//		GM_log("nodeName = "+t.nodeName+"\nnodeType = "+t.nodeType );
		if(t.nodeType == 3)
		{
			var nodes = pattern;
			var p = pattern.exec(t.nodeValue);
			if(p != null)
			{
//				GM_log(p.length+"\n"+p[0]+"\n"+p[1]+"\n"+p[2]+"\n"+p[3]);
//				if(p[1] != null || p[2] != null || p[3] != null)
				{
					var m=document.createTextNode(p[0]);
					var n=document.createTextNode(t.nodeValue.substring(p.index + p[0].length));
					t.nodeValue = t.nodeValue.substring(0,p.index);
					insertAfter(m, t);
					insertAfter(n, m);
					++count;
				}
				if(p[1] != null)
					table.push(m);
				else if(p[2] != null && !nourl)
					urls.push(m);
				else if(p[3] != null && !nourl)
					badurls.push(m);
				t = t.nextSibling;
			}
		}
		else if(t.nodeType == 1)
		{
			if(t.nodeName != "TEXTAREA" && t.nodeName != "INPUT" && t.nodeName != "PRE")
				parse(t, only, nourl);
		}
//		else
//			GM_log("nodeName = "+t.nodeName+"\nnodeType = "+t.nodeType );
	}
//	if(element.innerHTML)
//		GM_log("Count = "+table.length+"\n"+table+"\n" + element.innerHTML);
	if(table.length > 0)
		tag(table, only);
	var i;
	for(i = 0; i < urls.length; i++)
	{
		var t = urls[i];
		var v = t;
		while(v = v.parentNode)
		{
			if(v.nodeName == "A" || v.nodeName == "PRE")//keep it honest
				break;
		}
		if(v == null && t.parentNode)
		{
//			GM_log(t.nodeValue);
			var m=document.createElement("A");
			m.href = (m.innerHTML = t.nodeValue).htmlUnescape();
			if(m.innerHTML.length > url_len)
				m.innerHTML = m.innerHTML.slice(0,url_start)+"..."+m.innerHTML.slice(m.innerHTML.length-url_end);
			t.parentNode.replaceChild(m, t);
		}
	}
	for(i = 0; i < badurls.length; i++)
	{
		var t = badurls[i];
		var v = t;
		while(v = v.parentNode)
		{
			if(v.nodeName == "A" || v.nodeName == "PRE")//keep it honest
				break;
		}
		if(v == null && t.parentNode)
		{
//			GM_log(t.nodeValue);
			var m=document.createElement("A");
			m.href = "http://"+(m.innerHTML = t.nodeValue).htmlUnescape();
			if(m.innerHTML.length > url_len)
				m.innerHTML = m.innerHTML.slice(0,url_start)+"..."+m.innerHTML.slice(m.innerHTML.length-url_end);
			t.parentNode.replaceChild(m, t);
		}
	}
	badurls = urls = table = null;
}

/*
function juggle(table)
{
	var t;
	var map = new Object();
	for (t=0; t<table.length; t++){
		var type = split_pattern.exec(table[t].nodeValue);
		if(type[1] == "")
		{
			if(map[type[2].toLowerCase()])
				++map[type[2].toLowerCase()];
			else
				map[type[2].toLowerCase()] = 1;
		}
		else
		{
			if(map[type[2].toLowerCase()])
				--map[type[2].toLowerCase()];
			else
				map[type[2].toLowerCase()] = -1;
		}
	}
	map = null;
	return table;
}
*/
function log(table, sep, msg_a, msg_b)
{
	var kw = "";
	Array.forEach(table, function(item) {if(kw !="") kw +=sep;kw += item.nodeValue;});
//	GM_log(msg_a+kw+msg_b);
}

function oc(a)
{
	if(a && a.length)
	{
		var o = {};
		for(var i=0;i<a.length;i++)
		{
			o[a[i]]='';
		}
		return o;
	}
	return null;
}

function tag(table, only)
{
//	log(table, "\n", "tags = [\n","\n]");
	var t;
	var z = oc(only);
	for (t=0; t<table.length; t++){
		if(--calls < 0)
			return;
		var type = split_pattern.exec(table[t].nodeValue);
		if(type)//make sure it is infact a valid tag.
		{
			if(type[1] == "")
			{
				var c = 1;
				var m = t;
				var r = type[2].toLowerCase();
				var dtype;
				var k = table.length - 1;
				if(z && !(r in z));//silently ignore missing tags
				else if(r == "*")
				{
					while(t < k && c != 0)
					{
						if(--calls < 0)
							return;
						dtype = split_pattern.exec(table[++t].nodeValue);
						if(dtype)
						{
							var dt = dtype[2].toLowerCase();
							if(dt == "list")
							{
								if(dtype[1] == "")
									c++;
								else
									c--;
							}
							else if(dt == "*" && c == 1)
								c = 0;
						}
					}
					if(c > 0)
						t++;
				}
				else
				{
					while(t < k && c != 0)
					{
						if(--calls < 0)
							return;
						dtype = split_pattern.exec(table[++t].nodeValue);
						if(dtype)
						{
							if(dtype[2].toLowerCase() == r)
							{
								if(dtype[1] == "")
									c++;
								else
									c--;
							}
						}
					}
					if(c > 0 && (r == "url" || r =="img") && type[3] && type[3] != "")
					{//some idiot didn't close thier URL/IMG tag, *rolls eyes*
//						log(table, ", ", "before: " + table.length+"\n")
						table.splice(t = m+1, 0, insertAfter(document.createTextNode("[/"+r+"]"), table[m]));
//						log(table, ", ", "after: " + table.length+"\n")
						insertAfter(document.createTextNode(type[3]), table[m]);
						k+=1;//adjust the end...
						type[3]="";//makes it work harder
						c = 0;
					}
				}
				
	//			if(table.length > t)
	//				GM_log("( "+(t - m)+", " + c + " ) = " + type[0] +" && " + split_pattern.exec(table[t].nodeValue)[0]);
	//			else
	//				GM_log("( "+(t - m)+", " + c + " ) = " + type[0] +" && last");
				if(c == 0 || r == "*")
				{
					var nodes = new Array(0);
					var p = null;
					var q = null;
					if(r == "url" || r == "thread" || r == "post" || r =="email")
					{
						p = document.createElement("a");
						var d = "";
						if(type[3] != null)
							d = type[3].replace(/  /g,"").htmlUnescape();
						if(r == "thread")
							p.href = (base + "showthread.php?t=" + d);
						else if(r == "post")
							p.href = (base + "showthread.php?p=" + d);
						else if(d != "")
						{
							if(r == "email")
								p.href = (d.trim().toLowerCase().indexOf("mailto:") != 0)?"mailto:"+d:d;
							else if(r == "url")
							{
								var d1 = d.trim();
								var d3 = d1.indexOf("/");
								var d4 = d1.indexOf(":");
								var d5 = d1.indexOf("?");
								if(d4 == -1 || (d4 > d3 && d3 != -1))
								{
									if(d5 == -1 || d3 != -1)
										p.href = "http://"+d;
									else
										p.href = base + d;
								}
								else
									p.href = d;
							}
						}
					}
					else if(r == "color" ||  r == "size" || r == "font")
					{
						p = document.createElement("font");
						if(r == "color")
							p.color = type[3];
						else if(r == "size")
							p.size = type[3];
						else if(r == "font")
							p.face = type[3];
					}
					else if(r == "right" || r == "left" || r == "center")
					{
						p = document.createElement("div");
						if(r == "right")
							p.align = "right";
						else if(r == "left")
							p.align = "left";
						else if(r == "center")
							p.align = "center";
					}
					else if(r == "u" || r == "b" ||  r == "i")
					{
						p = document.createElement(r);
					}
					else if(r == "highlight")
					{
						p = document.createElement("span");
						p.className = "highlight";
					}
					else if(r == "indent")
					{
						p = document.createElement("blockquote");
						q = document.createElement("div");
						p.appendChild(q);
					}
					else if(r == "code" || r == "php")
					{
						p = document.createElement("div");
						p.style.margin="5px 20px 20px";
						q = document.createElement("div");
						q.className = "smallfont";
						q.style.marginBottom="2px";
						q.appendChild(document.createTextNode("Code:"));
						p.appendChild(q);
						q = document.createElement("pre");
						q.className = "alt2 GMCode";
						q.dir = "ltr";
						p.appendChild(q);
					}
					else if(r == "list")
					{//<ol type="1"><li>list item 1</li><li>list item 2</li></ol>
						if(type[3] != "" && type[3] != null)
						{
							p = document.createElement("ol");
							p.type=type[3];
						}
						else
						{
							p = document.createElement("ul");
						}
					}
					else if(r == "img")
					{
						p = document.createElement("img");
						q = document.createElement("span");
					}
					else if(r == "*")
					{
						p = document.createElement("li");
					}
					if(q == null)
						q = p;
					if(p != null)
					{
						var h = table[m];
						var w = h.parentNode;
						var n = h.nextSibling;
						var s = null;
						if(table.length > t)
							s = table[t];
						while(n != s && n != null)
						{
							y = n.nextSibling;
							child = w.removeChild(n);
							if(child.nodeName != "BR" || (r != "code" && r != "php"))
								q.appendChild(child);
							if(child.nodeName == "#text")
								child.nodeValue = child.nodeValue.replace(/([\S]{50,52})  /gm,"$1");
							n = y;
							if(--calls < 0)
								return;
						}
						if(s != null)
						{
							var rtype = split_pattern.exec(s.nodeValue);
							if(rtype[1] != "" && rtype[2].toLowerCase() == r /*/&& w/**/)//catch for lists ~_~
								w.removeChild(s);
						}
						if(r == "code" || r == "php")//keeps it from trying to parse code and php stuff.
						{
						//FIXME: make the replacement smarter, i'm too lazy.
							q.innerHTML = q.innerHTML.replace(/\t/g,"    ");
							//if(r != "code")//oddly enabling this test borks things, not exactly sure what causesit.
								m = t;//no internal parsing
							if(r == "code")//this is the wrong solutions but it works
								parse(q, ["i", "b", "u", "color", "highlight", "url", "thread", "post", "email"], true);
						}
						else if(r == "img")
						{
							if("" == (p.src = q.textContent.trim().htmlUnescape()))
								p = q;
							m = t;//no internal parsing
						}
						else if((r == "url" || r == "email" || r == "post" || r == "thread") && (type[3]=="" || type[3] == null))
						{
							s = q.textContent.trim().replace(/  /g,"").htmlUnescape();
							if(r == "email")
								q.href = (s.toLowerCase().indexOf("mailto:") != 0)?"mailto:"+s:s;
							else if(r == "url")
								q.href = ((s+"/:").indexOf(":") > s.indexOf("/"))?"http://"+s:s;
							else
								p.href += s;
							if(s.length > url_len)
								q.innerHTML = (s.slice(0,url_start)+"..."+s.slice(s.length-url_end)).htmlEscape();
							else
								q.innerHTML = q.textContent;//strip the html from it, it should be unformated.
							m = t;//no internal parsing
						}
						/*/if(w)/**/
							w.replaceChild(p,h);
					}
				}
				else //if(c > 0 && r != "*")
				{
					++t;
					if(ERRORS)
					{
//						GM_log("tag error = " + type[0]);
//						log(table, "\n", "tags = [\n","\n]");
					}
				}
				if(m+1 < t)
					tag(table.slice(m+1, t));
				if((r == "*" && c == 0))// || (c == 1 && r != "*"))
					--t;
			}
			else if(ERRORS)
			{
//				GM_log("tag error = " + type[0]);
//				log(table, "\n", "tags = [\n","\n]");
			}
		}
	}
}

function insertAfter(insert, after)
{
	return after.parentNode.insertBefore(insert, after.nextSibling);
}