Lingua Franca

By Mike Sugarbaker Last update Jul 19, 2005 — Installed 1,085 times. Daily Installs: 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
/*
    (c) Mike Sugarbaker, misuba@gmail.com
    Based on Instant Textile,
    (c) Phil Wilson, greasemonkey@philwilson.org
    in turn based on Textileable by Roberto De Almeida  
   (http://dealmeida.net/en/Projects/PyTextile/greasemonkey_and_textile.html)
    and the JS Textile function by Jeff Minard (http://www.creatimation.net/textile.js)   

    GPL.
	This (Mike's) version is the epitome of an ugly hack. Please forgive me.
	This is version 0.1 of Lingua Franca.
*/

// ==UserScript==
// @name            Lingua Franca
// @namespace       http://www.gibberish.com/hacks/gm/
// @description     Translate a textarea from Textile to HTML, BBCode, or MediaWiki markup
// @include         http://*
// @include         https://*
// ==/UserScript==

(function() {

    function init() 
	{
        var textareas = window._content.document.getElementsByTagName("textarea");

        var i;
        var id;
        var button;
        for (i = 0; i < textareas.length; i++) 
		{
            // Get id.
            id = textareas[i].getAttribute("id");
            if (!id) 
			{
                id = "__textarea_" + i;
                textareas[i].setAttribute("id", id);
            }
			
			themenu = document.createElementNS("http://www.w3.org/1999/xhtml", "select");
			
			defaulty = document.createElementNS("http://www.w3.org/1999/xhtml", "option");
            defaulty.setAttribute("value", "");
			defaulty.appendChild(document.createTextNode('Textile to:'));
			themenu.appendChild(defaulty);
			
			htmlguy = document.createElementNS("http://www.w3.org/1999/xhtml", "option");
            htmlguy.setAttribute("value", "H");
			htmlguy.appendChild(document.createTextNode('HTML'));
			themenu.appendChild(htmlguy);
			
			bbguy = document.createElementNS("http://www.w3.org/1999/xhtml", "option");
            bbguy.setAttribute("value", "B");
			bbguy.appendChild(document.createTextNode('BBCode'));
			themenu.appendChild(bbguy);
			
			mediaguy = document.createElementNS("http://www.w3.org/1999/xhtml", "option");
            mediaguy.setAttribute("value", "W");
			mediaguy.appendChild(document.createTextNode('MediaWiki'));
			themenu.appendChild(mediaguy);
			
            themenu.setAttribute("id", '__linguaf_' + id);
            themenu.onchange = doTextile;

            textareas[i].parentNode.insertBefore(themenu, textareas[i].nextSibling);
        }
    }

    function doTextile() 
	{
        var head = window._content.document.getElementsByTagName("head");
        var id = this.id.substring(10, this.id.length);
		var dest = this.options[this.selectedIndex].value;
        var textarea = window._content.document.getElementById(id);
		//alert("dest = " + dest);
        textarea.value = textile(textarea.value,dest);
		this.selectedIndex = 0;
    }

function textile(s,dest) 
{
	var r = s;
	// quick tags first
    qtags = [['\\*', 'strong', 'b', '\'\'\''],
             ['\\?\\?', 'cite', 'quote', ':'],
             ['\\+', 'ins', '', ''],  //fixed
             ['~', 'sub', '', 'sub'],   
             ['\\^', 'sup', '', 'sup'], // me
             ['@', 'code', 'code', 'code']];
    for (var i=0;i<qtags.length;i++) {
        ttag = qtags[i][0]; 
		htag = qtags[i][1];
		btag = qtags[i][2];
		wtag = qtags[i][3];
        re = new RegExp(ttag+'\\b(.+?)\\b'+ttag,'g');
		if (dest == "H")
		{
	        r = r.replace(re,'<'+htag+'>'+'$1'+'</'+htag+'>');
		}
		else if (dest == "B")
		{
			if (btag != '')
			{
				r = r.replace(re,'['+btag+']'+'$1'+'[/'+btag+']');
			}
			else
			{
				r = r.replace(re,'$1');
			}
		}
		else if (dest == "W")
		{
			if (wtag == ":")
			{
				// just needs not to go on the end
				r = r.replace(re,wtag+'$1');
			}
			else if (wtag == "sub" || wtag == "sup" || wtag == "code")
			{
				// use HTML for these
				r = r.replace(re,'<'+wtag+'>'+'$1'+'</'+wtag+'>');
			}
			else if (wtag != "")
			{
				// uh, i guess we're down to bold
				r = r.replace(re,wtag+'$1'+wtag);
			}
		}
    }
    // underscores count as part of a word, so do them separately
    re = new RegExp('\\b_(.+?)_\\b','g');
    if (dest == "H")
	{
		r = r.replace(re,'<em>$1</em>');
	}
	else if (dest == "B")
	{
		r = r.replace(re,'[i]$1[/i]');
	}
	else if (dest == "W")
	{
		r = r.replace(re,'\'\'$1\'\'');
	}
	
	//jeff: so do dashes
    re = new RegExp('[\s\n]-(.+?)-[\s\n]','g');
    if (dest == "H")
	{
		r = r.replace(re,'<del>$1</del>');
	}
	else
	{
		r = r.replace(re,'-$1-');
	}

    // links
    re = new RegExp('"\\b(.+?)\\(\\b(.+?)\\b\\)":([^\\s]+)','g');
    if (dest == "H")
	{
		r = r.replace(re,'<a href="$3" title="$2">$1</a>');
	}
	else if (dest == "B")
	{
		r = r.replace(re,'$1: [url]$3[/url]');
	}
	else if (dest == "W")
	{
		r = r.replace(re,'[$3 $1]');
	}
	
    re = new RegExp('"\\b(.+?)\\b":([^\\s]+)','g');
	if (dest == "H")
	{
		r = r.replace(re,'<a href="$2">$1</a>');
	}
	else if (dest == "B")
	{
		r = r.replace(re,'$1: [url]$2[/url]');
	}
	else if (dest == "W")
	{
		r = r.replace(re,'[$2 $1]');
	}
	
    // images
    re = new RegExp('!\\b(.+?)\\(\\b(.+?)\\b\\)!','g');
	if (dest == "H")
	{
		r = r.replace(re,'<img src="$1" alt="$2" />');
	}
	else if (dest == "B")
	{
		r = r.replace(re,'[img]$1[/img]');
	}
	else if (dest == "W")
	{
		r = r.replace(re,'[[Image:$1|$2]]');
	}
    re = new RegExp('!\\b(.+?)\\b!','g');
    if (dest == "H")
	{
		r = r.replace(re,'<img src="$1" />');
	}
	else if (dest == "B")
	{
		r = r.replace(re,'[img]$1[/img]');
	}
	else if (dest == "W")
	{
		r = r.replace(re,'[[Image:$1]]');
	}
    
    // block level formatting
	
	// Jeff's hack to show single line breaks as they should.
	// insert breaks - but you get some....stupid ones
    re = new RegExp('(.*)\n([^#\*\n].*)','g');
    if (dest != "B") r = r.replace(re,'$1<br />$2');
	// remove the stupid breaks.
    re = new RegExp('\n<br />','g');
    if (dest != "B") r = r.replace(re,'\n');
	
    lines = r.split('\n');
    nr = '';
    for (var i=0;i<lines.length;i++) 
	{
        line = lines[i].replace(/\s*$/,'');
        changed = 0;
        if (line.search(/^\s*bq\.\s+/) != -1) 
		{
			if (dest == "H")
			{
				line = line.replace(/^\s*bq\.\s+/,'\t<blockquote>')+'</blockquote>'; 
			}
			else if (dest == "B")
			{
				line = line.replace(/^\s*bq\.\s+/,'\t[quote]')+'[/quote]'; 
			}
			else if (dest == "W")
			{
				line = line.replace(/^\s*bq\.\s+/,'\:'); 
			}
			changed = 1; 
		}
		
		// jeff adds h#.
        if (line.search(/^\s*h[1-6]\.\s+/) != -1) 
		{ 
	    	re = new RegExp('h([1-6])\.(.+)','g');
			if (dest == "H")
			{
				line = line.replace(re,'<h$1>$2</h$1>');
			}
			else if (dest == "B")
			{
				line = line.replace(re,'$2');
			}
			else
			{
				thematch = line.match(re);
				whatlevel = parseInt(thematch[1]);
				if (whatlevel > 3) whatlevel = 3;
				theguys = "";
				while (whatlevel)
				{
					theguys += "="; whatlevel--;
				} // must be a better way to do all this...
				line = line.replace(re,'='+theguys+' $2 ='+theguys);
			}
			changed = 1; 
		}
		
		if (dest != "W")
		{
			if (line.search(/^\s*\*\s+/) != -1) 
			{ 
				line = line.replace(/^\s*\*\s+/,'\t<liu>') + '</liu>';
				changed = 1;
			} // * for bullet list; make up an liu tag to be fixed later
	        if (line.search(/^\s*#\s+/) != -1) 
			{ 
				line = line.replace(/^\s*#\s+/,'\t<lio>') + '</lio>';
				changed = 1;
			} // # for numeric list; make up an lio tag to be fixed later
			
	        if (!changed && (line.replace(/\s/g,'').length > 0))
			{
				if (dest == "H") line = '<p>'+line+'</p>';
			}
	        lines[i] = line + '\n';
		}
    }
	
    // Second pass to do lists
	if (dest != "W")
	{
	    inlist = 0; 
		listtype = '';
	    for (var i = 0; i < lines.length; i++) 
		{
	        line = lines[i];
	        if (inlist && listtype == 'ul' && !line.match(/^\t<liu/)) 
			{
				line = (dest == "B" ? '[/list]\n' : '</ul>\n') + line; 
				inlist = 0; 
			}
	        if (inlist && listtype == 'ol' && !line.match(/^\t<lio/)) 
			{ 
				line = (dest == "B" ? '[/list]\n' : '</ol>\n') + line; 
				inlist = 0;
			}
	        if (!inlist && line.match(/^\t<liu/)) 
			{ 
				line = (dest == "B" ? '[list]' : '<ul>') + line; 
				inlist = 1; 
				listtype = 'ul'; 
			}
	        if (!inlist && line.match(/^\t<lio/)) 
			{ 
				line = (dest == "B" ? '[list]' : '<ol>') + line; 
				inlist = 1; 
				listtype = 'ol'; 
			}
	        lines[i] = line;
	    }
		if (inlist) // hey, we shouldn't still be in it, we're done!!
		{
			if (listtype == 'ol')
			{
				lines[lines.length] = (dest == "B" ? '[/list]\n' : '</ol>\n'); 
			}
			else
			{
				lines[lines.length] = (dest == "B" ? '[/list]\n' : '</ul>\n'); 
			}
		}
	}

    r = lines.join('\n');
	
	// jeff added : will correctly replace <li(o|u)> AND </li(o|u)>
	if (dest == "H")
	{
	    r = r.replace(/<(\/?)li[o|u]>/g,'<'+'$1'+'li>');
	}
	else if (dest == "B")
	{
		r = r.replace(/<li[o|u]>/g,'[*]');
		r = r.replace(/<\/li[o|u]>/g,'');
	}

    return r;
}

    init();

})();