NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Caravel On the fly Preview
// @namespace Mauft.com
// @include *forum.caravelgames.com/message.php*
// @include *forum.caravelgames.com/pm.php*
// @description Displays the preview of your post on the fly, as you are typing
// @version 1.0.0
// @copyright 2011, Maurycy Zarzycki
// ==/UserScript==
var PREVIEW_UPDATE_DELAY = 500;
var EMOTICONS = [
[":\\)","emoticons/smile1.gif"],
[";\\)","emoticons/wink.gif"],
[":D","emoticons/grin.gif"],
[":P","emoticons/tongue.gif"],
[":\\(","emoticons/sad.gif"],
[":~\\(","emoticons/cry.gif"],
[":\\|","emoticons/noexpression.gif"],
[":\\?","emoticons/confused.gif"],
[":\\-O","emoticons/ohmy.gif"],
[":glasses","emoticons/cool1.gif"],
["O:\\-","emoticons/angel.gif"],
["\\-\\_-","emoticons/sleep.gif"],
[":angry","emoticons/angry.gif"],
[":smile","emoticons/smile2.gif"],
[":lol","emoticons/laugh.gif"],
[":cool","emoticons/cool2.gif"],
[":fun","emoticons/fun.gif"],
[":thumbsup","emoticons/thumbsup.gif"],
[":thumbsdown","emoticons/thumbsdown.gif"],
[":blush","emoticons/blush.gif"],
[":weep","emoticons/weep.gif"],
[":unsure","emoticons/unsure.gif"],
[":closedeyes","emoticons/closedeyes.gif"],
[":yes","emoticons/yes.gif"],
[":no","emoticons/no.gif"],
[":huh","emoticons/huh.gif"],
[":w00t","emoticons/w00t.gif"],
[":look","emoticons/look.gif"],
[":rolleyes","emoticons/rolleyes.gif"],
[":kiss","emoticons/kiss.gif"],
[":shifty","emoticons/shifty.gif"],
[":blink","emoticons/blink.gif"],
[":smartass:","emoticons/smartass.gif"],
[":sick","emoticons/sick.gif"],
[":crazy","emoticons/crazy.gif"],
[":wacko","emoticons/wacko.gif"],
[":alien","emoticons/alien.gif"],
[":wizard","emoticons/wizard.gif"],
[":wavecry:","emoticons/wavecry.gif"],
[":wave:","emoticons/wave.gif"],
[":baby","emoticons/baby.gif"],
[":ras","emoticons/ras.gif"],
[":sly","emoticons/sly.gif"],
[":devil","emoticons/devil.gif"],
[":evilmad:","emoticons/evilmad.gif"],
[":evil:","emoticons/evil.gif"],
[":yucky","emoticons/yucky.gif"],
[":nugget","emoticons/nugget.gif"],
[":sneaky","emoticons/sneaky.gif"],
[":smart:","emoticons/smart.gif"],
[":shutup","emoticons/shutup.gif"],
[":yikes","emoticons/yikes.gif"],
[":flowers","emoticons/flowers.gif"],
[":wub","emoticons/wub.gif"],
[":santa","emoticons/santa.gif"],
[":indian","emoticons/indian.gif"],
[":guns","emoticons/guns.gif"],
[":crockett","emoticons/crockett.gif"],
[":zorro","emoticons/zorro.gif"],
[":snap","emoticons/snap.gif"],
[":beer","emoticons/beer.gif"],
[":drunk","emoticons/drunk.gif"],
[":sleeping","emoticons/sleeping.gif"],
[":mama","emoticons/mama.gif"],
[":pepsi","emoticons/pepsi.gif"],
[":medieval","emoticons/medieval.gif"],
[":rambo","emoticons/rambo.gif"],
[":ninja","emoticons/ninja.gif"],
[":hannibal","emoticons/hannibal.gif"],
[":party","emoticons/party.gif"],
[":snorkle","emoticons/snorkle.gif"],
[":evo","emoticons/evo.gif"],
[":king","emoticons/king.gif"],
[":mario","emoticons/mario.gif"],
[":pope","emoticons/pope.gif"],
[":fez","emoticons/fez.gif"],
[":cap","emoticons/cap.gif"],
[":cowboy","emoticons/cowboy.gif"],
[":pirate","emoticons/pirate.gif"],
[":rock","emoticons/rock.gif"],
[":cigar","emoticons/cigar.gif"],
[":icecream","emoticons/icecream.gif"],
[":oldtimer","emoticons/oldtimer.gif"],
[":wolverine","emoticons/wolverine.gif"],
[":strongbench","emoticons/strongbench.gif"],
[":weakbench","emoticons/weakbench.gif"],
[":bike","emoticons/bike.gif"],
[":music","emoticons/music.gif"],
[":book","emoticons/book.gif"],
[":fish","emoticons/fish.gif"],
[":whistle","emoticons/whistling.gif"],
[":hooray","emoticons/hooray.gif"],
[":yay","emoticons/yay.gif"],
[":cake","emoticons/cake.gif"],
[":hbd","emoticons/hbd.gif"],
[":hi","emoticons/hi.gif"],
[":offtopic","emoticons/offtopic.gif"],
[":punk","emoticons/punk.gif"],
[":bounce","emoticons/bounce.gif"],
[":group","emoticons/group.gif"],
[":console","emoticons/console.gif"],
[":eyes","emoticons/eyes.gif"],
[":twak","emoticons/twak.gif"],
[":onei","emoticons/onei.gif"],
[":afro","emoticons/afro.gif"],
[":2alien","emoticons/alien2.gif"],
[":1eye","emoticons/1eye.gif"],
[":band","emoticons/band.gif"],
[":bangin","emoticons/bangin.gif"],
[":banned","emoticons/banned.gif"],
[":batman","emoticons/batman.gif"],
[":blowup","emoticons/blowup.gif"],
[":1alien","emoticons/alien1.gif"],
[":tcaptain","emoticons/captain.gif"],
[":borg","emoticons/borg.gif"],
[":1disguise","emoticons/disguise.gif"],
[":2disguise","emoticons/disguise2.gif"],
[":eek","emoticons/eek.gif"],
[":excl","emoticons/excl.gif"],
[":drool","emoticons/drool.gif"],
[":fear","emoticons/fear.gif"],
[":donatello","emoticons/donatello.gif"],
[":dontgetit","emoticons/dontgetit.gif"],
[":fullmop","emoticons/fullmop.gif"],
[":gathering","emoticons/gathering.gif"],
[":geek","emoticons/geek.gif"],
[":frusty","emoticons/frusty.gif"],
[":glare","emoticons/glare.gif"],
[":gossip","emoticons/gossip.gif"],
[":holiday","emoticons/holiday.gif"],
[":jumpy","emoticons/jumpy.gif"],
[":lamo","emoticons/lamo.gif"],
[":moptop","emoticons/moptop.gif"],
[":nerd","emoticons/nerd.gif"],
[":Notworthy","emoticons/notworthy.gif"],
[":nuke","emoticons/nuke.gif"],
[":paperbag","emoticons/paperbag3.gif"],
[":pimp","emoticons/pimp.gif"],
[":robot","emoticons/robot.gif"],
[":ranting","emoticons/ranting.gif"],
[":scared","emoticons/scared.gif"],
[":2pirate","emoticons/pirate2.gif"],
[":pizza","emoticons/pizza.gif"],
[":shock","emoticons/shock.gif"],
[":pokey","emoticons/pokey.gif"],
[":shhocking","emoticons/shocking.gif"],
[":spamlaser","emoticons/spam_laser.gif"],
[":stretcher","emoticons/stretcher.gif"],
[":surprise","emoticons/surprise.gif"],
[":sweat","emoticons/sweat.gif"],
[":starwars","emoticons/starwars.gif"],
[":tabletalk","emoticons/tabletalk.gif"],
[":tomato","emoticons/tomato.gif"],
[":tongue","emoticons/tongue_ss.gif"],
[":trumpet","emoticons/trumpet.gif"],
[":tvhorror","emoticons/tv_horror.gif"],
[":tvhappy","emoticons/tv_happy.gif"],
[":sombrero","emoticons/sombrero2.gif"],
[":vampire","emoticons/vampire.gif"],
[":whip","emoticons/whip.gif"],
[":yawn","emoticons/yawn.gif"],
[":yinyang","emoticons/yinyang.gif"],
[":bomb","emoticons/bomb.gif"],
[":bond","emoticons/bond.gif"],
[":8bounce","emoticons/bounce8.gif"],
[":cold","emoticons/cold.gif"],
[":disgust","emoticons/disgust1.gif"],
[":2evil","emoticons/evil1.gif"],
[":frankie","emoticons/frankie.gif"],
[":greedy","emoticons/greedy.gif"],
[":ill","emoticons/ill.gif"],
[":lmao","emoticons/lmao.gif"],
[":matrix2","emoticons/matrix_2.gif"],
[":protest","emoticons/protest.gif"],
[":rain","emoticons/rain.gif"],
[":slap","emoticons/slap.gif"],
[":smurf","emoticons/smurf.gif"],
[":throw","emoticons/throw.gif"],
[":brklnk","emoticons/x.gif"],
[":doh","emoticons/doh.gif"],
[":toohard","emoticons/toohard.gif"],
[":selftwak","emoticons/selftwak.gif"],
[":teamtwak","emoticons/teamtwak.gif"],
[":tease","emoticons/tease8le.gif"],
[":stud","emoticons/stud.gif"],
[":yahoo:","emoticons/yahoo.gif"],
[":cheers:","emoticons/cheers.gif"],
[":hmmm:","emoticons/hmmm.gif"],
[":swordfight:","emoticons/swordfight.gif"],
[":tumbleweed:","emoticons/tumbleweed.gif"],
[":facepalm:","emoticons/facepalm.gif"]];
// -----------------------------------------------------------------------
// Copyright (c) 2008, Stone Steps Inc.
// All rights reserved
// http://www.stonesteps.ca/legal/bsd-license/
//
// This is a BBCode parser written in JavaScript. The parser is intended
// to demonstrate how to parse text containing BBCode tags in one pass
// using regular expressions.
//
// The parser may be used as a backend component in ASP or in the browser,
// after the text containing BBCode tags has been served to the client.
//
// Following BBCode expressions are recognized:
//
// [b]bold[/b]
// [i]italic[/i]
// [u]underlined[/u]
// [s]strike-through[/s]
// [samp]sample[/samp]
//
// [color=red]red[/color]
// [color=#FF0000]red[/color]
// [size=1.2]1.2em[/size]
//
// [url]http://blogs.stonesteps.ca/showpost.asp?pid=33[/url]
// [url=http://blogs.stonesteps.ca/showpost.asp?pid=33][b]BBCode[/b] Parser[/url]
//
// [q=http://blogs.stonesteps.ca/showpost.asp?pid=33]inline quote[/q]
// [q]inline quote[/q]
// [blockquote=http://blogs.stonesteps.ca/showpost.asp?pid=33]block quote[/blockquote]
// [blockquote]block quote[/blockquote]
//
// [pre]formatted
// text[/pre]
// [code]if(a == b)
// print("done");[/code]
//
// text containing [noparse] [brackets][/noparse]
//
// -----------------------------------------------------------------------
var opentags; // open tag stack
var crlf2br = true; // convert CRLF to <br>?
var noparse = false; // ignore BBCode tags?
var urlstart = -1; // beginning of the URL if zero or greater (ignored if -1)
// aceptable BBcode tags, optionally prefixed with a slash
var tagname_re = /^\/?(?:b|i|u|code|color|secret|SECRET|size|url|s|img|quote|lb|rb)$/;
// color names or hex color
var color_re = /^(red|green|blue|yellow|orange)$/i;
// numbers
var number_re = /^(\-2|\-1|\+1|\+2)/i;
// reserved, unreserved, escaped and alpha-numeric [RFC2396]
var uri_re = /^[-;\/\?:@&=\+\$,_\.!~\*'\(\)%0-9a-z]{1,512}$/i;
// main regular expression: CRLF, [tag=option], [tag] or [/tag]
var postfmt_re = /([\r\n])|(?:\[([a-z]{1,16})(?:=([^\x00-\x1F"'\(\)<>\[\]]{1,256}))?\])|(?:\[\/([a-z]{1,16})\])/ig;
var secret_count = 100;
// stack frame object
function taginfo_t(bbtag, etag)
{
this.bbtag = bbtag;
this.etag = etag;
}
// check if it's a valid BBCode tag
function isValidTag(str)
{
if(!str || !str.length)
return false;
return tagname_re.test(str);
}
function getSecretContentOpen(){
}
//
// m1 - CR or LF
// m2 - the tag of the [tag=option] expression
// m3 - the option of the [tag=option] expression
// m4 - the end tag of the [/tag] expression
//
function textToHtmlCB(mstr, m1, m2, m3, m4, offset, string)
{
var i;
//
// CR LF sequences
//
if(m1 && m1.length) {
if(!crlf2br)
return mstr;
switch (m1) {
case '\r':
return "";
case '\n':
return "<br>";
}
}
//
// handle start tags
//
if(isValidTag(m2)) {
// if in the noparse state, just echo the tag
if(noparse)
return "[" + m2 + "]";
// ignore any tags if there's an open option-less [url] tag
if(opentags.length && opentags[opentags.length-1].bbtag == "url" && urlstart >= 0)
return "[" + m2 + "]";
switch (m2) {
case "code":
opentags.push(new taginfo_t(m2, "</pre>"));
crlf2br = false;
return "<pre>";
case "color":
if(!m3)
return "[" + m2 + "]";
else if (!color_re.test(m3))
return "[" + m2 + "=" + m3 + "]";
opentags.push(new taginfo_t(m2, "</span>"));
return "<span style=\"color: " + m3 + "\">";
case "secret":
opentags.push(new taginfo_t(m2, "</div><br>"));
i = secret_count;
secret_count += 1;
return ("<div onclick=\"document.getElementById('secret"+i+"').style.display='block';"+
"document.getElementById('secretclick"+i+"').style.display='none';\""+
"id='secretclick"+i+"' class='secretclick1'>"+
"Click here to view the secret text</div>"+
"<div class='secret1' style='display: none;' id='secret"+i+"'>"+
"<span onclick=\"document.getElementById('secretclick"+i+"').style.display='block';"+
"document.getElementById('secret"+i+"').style.display='none';\" style='border: none; padding-right: 4px' class='secretclick'>×"+
"</span>");
case "SECRET":
opentags.push(new taginfo_t(m2, '</font></td></tr><tr><td><font size="2">(Highlight the secret text above.)</font></td></tr></tbody></table>'));
return '<table><tbody><tr><td bgcolor="white"><font color="white">';
case "size":
if(!m3)
return "[" + m2 + "]";
else if (!number_re.test(m3))
return "[" + m2 + "=" + m3 + "]";
switch(m3){
case("-2"): m3 = "60%"; break;
case("-1"): m3 = "80%"; break;
case("+1"): m3 = "120%"; break;
case("+2"): m3 = "135%"; break;
}
opentags.push(new taginfo_t(m2, "</span>"));
return "<span style=\"font-size: " + m3 + "\">";
case "s":
opentags.push(new taginfo_t(m2, "</span>"));
return "<span style=\"text-decoration: line-through\">";
case "noparse":
noparse = true;
return "";
case "url":
opentags.push(new taginfo_t(m2, "</a>"));
// check if there's a valid option
if(m3 && uri_re.test(m3)) {
// if there is, output a complete start anchor tag
urlstart = -1;
return "<a href=\"" + m3 + "\">";
}
// otherwise, remember the URL offset
urlstart = mstr.length + offset;
// and treat the text following [url] as a URL
return "<a href=\"";
case "quote":
opentags.push(new taginfo_t(m2, "<hr></blockquote>"));
if (!m3){
return '<blockquote><font size="1">quote:</font><hr>';
} else {
return '<blockquote><font size="1">quote:</font><hr><b>'+m3+' wrote:</b>';
}
case "img":
opentags.push(new taginfo_t(m2, '">'));
return '<img border="0" src="';
case "lb":
return "[";
case "rb":
return "]";
default:
// [samp], [b], [i] and [u] don't need special processing
opentags.push(new taginfo_t(m2, "</" + m2 + ">"));
return "<" + m2 + ">";
}
}
//
// process end tags
//
if(isValidTag(m4)) {
if(noparse) {
// if it's the closing noparse tag, flip the noparse state
if(m4 == "noparse") {
noparse = false;
return "";
}
// otherwise just output the original text
return "[/" + m4 + "]";
}
// highlight mismatched end tags
if(!opentags.length || opentags[opentags.length-1].bbtag != m4)
return "[/" + m4 + "]";
if(m4 == "url") {
// if there was no option, use the content of the [url] tag
if(urlstart > 0)
return "\">" + string.substr(urlstart, offset-urlstart) + opentags.pop().etag;
// otherwise just close the tag
return opentags.pop().etag;
}
else if(m4 == "code" || m4 == "pre")
crlf2br = true;
// other tags require no special processing, just output the end tag
return opentags.pop().etag;
}
return mstr;
}
//
// post must be HTML-encoded
//
function parseBBCode(post)
{
var result, endtags, tag, i, l;
secret_count = 100;
// convert CRLF to <br> by default
crlf2br = true;
// create a new array for open tags
if(opentags == null || opentags.length)
opentags = new Array(0);
// run the text through main regular expression matcher
result = post.replace(postfmt_re, textToHtmlCB);
// reset noparse, if it was unbalanced
if(noparse)
noparse = false;
// if there are any unbalanced tags, make sure to close them
if(opentags.length) {
endtags = new String();
// if there's an open [url] at the top, close it
if(opentags[opentags.length-1].bbtag == "url") {
opentags.pop();
endtags += "\">" + post.substr(urlstart, post.length-urlstart) + "</a>";
}
// close remaining open tags
while(opentags.length)
endtags += opentags.pop().etag;
}
i = 0;
l = EMOTICONS.length;
for(i; i < l; i++){
result = result.replace(new RegExp(EMOTICONS[i][0], 'g'),
"<img align='absmiddle' src='"+EMOTICONS[i][1]+"' border='0' title='"+EMOTICONS[i][0]+"' alt='"+EMOTICONS[i][0]+"'>");
}
return endtags ? result + endtags : result;
}
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
initParser();
};
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
init(); // call the onload handler
}
};
/*@end @*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = init;
// :::::::::::::::::::::::::::::::
// :: ACTUAL CODE
// :::::::::::::::::::::::::::::::
var box, container;
function initParser(){
box = getBox();//document.getElementById("message");
if (!box)
return;
container = getBoxContainer(box);
if (!container)
return;
var throttleFunction = throttle(doParse, PREVIEW_UPDATE_DELAY);
if(typeof box.addEventListener == 'function') {
box.addEventListener("keyup", throttleFunction);
box.addEventListener("focus", throttleFunction);
box.addEventListener("blur", throttleFunction);
box.addEventListener("change", throttleFunction);
} else {
box.attachEvent("keyup", throttleFunction);
box.attachEvent("focus", throttleFunction);
box.attachEvent("blur", throttleFunction);
}
doParse();
}
function doParse(){
container.innerHTML = parseBBCode(box.value);
}
function getBox(){
var box = document.getElementById("message");
if (box)
return box;
box = document.getElementsByTagName("textarea");
var i = 0;
var l = box.length;
for(;i < l; i++){
if (box[i].getAttribute('name') == 'message')
return box[i];
}
}
function getBoxContainer(item){
var bigTr;
var msgTd;
var msgTable;
var itemName;
var newTable;
var html = document.createElement('table');
html.innerHTML = getNewTableHTML();
html = html.firstChild.firstChild;
while (item.parentNode){
item = item.parentNode;
itemName = item.nodeName.toLowerCase();
if (itemName == "table" && !msgTable){
msgTable = item;
}else if (itemName == "td" && msgTable){
msgTd = item;
} else if (itemName == "tr" && msgTable){
bigTr = item;
break;
}
}
if (!bigTr)
return null;
bigTr.parentNode.insertBefore(html, bigTr.nextSibling);
return document.getElementById('previewMagic');
}
function getNewTableHTML(){
return ('<tbody><tr valign="top" class="message1">' +
'<td width="130" valign="top" align="left"><b>Preview:</b></td>' +
'<td id="previewMagic"valign="top">' +
'</td>' +
'</tr></tbody>');
}
function getNewTableHTML_(){
return ('<tbody><tr valign="top" class="message1">' +
'<td width="130" valign="top" align="left"><b>Preview:</b></td>' +
'<td width="100%" valign="top" nowrap="">' +
'<table width="100%"><tbody><tr>' +
'<td id="previewMagic" align="left" rowspan="2"></td>' +
'</tr>' +
'</tbody></table>' +
'</td>' +
'</tr></tbody>');
}
function throttle(f, delay){
var timer = null;
return function(){
var context = this, args = arguments;
clearTimeout(timer);
timer = window.setTimeout(function(){
f.apply(context, args);
},
delay || 500);
};
}