User:Zocky/wysawyg.js
From Wikipedia
Note: After saving, you may have to bypass your browser's cache to see the changes. Mozilla / Firefox / Safari: hold down Shift while clicking Reload, or press Ctrl-Shift-R (Cmd-Shift-R on Apple Mac); IE: hold Ctrl while clicking Refresh, or press Ctrl-F5; Konqueror:: simply click the Reload button, or press F5; Opera users may need to completely clear their cache in Tools→Preferences.
//<pre><nowiki>
/*
CodePress - A Real Time Syntax Highlighting JS Engine - v0.85
You can use and modify this code as you want.
Just keep my credits somewhere around. Thanks.
Fernando M.A.d.S. - fermads@gmail.com
http://codepress.fermads.net/
*/
CodePress = {
range : null,
language : 'wiki',
doc: null,
// set initial vars and start sh
initialize : function(editdocument) {
this.detect();
chars = top.codePressTriggerChars || '[{|}]\n'; // charcodes that trigger syntax highlighting
this.doc=editdocument;
this.language=this.doc.body.getAttribute('codePressLanguage');
highlightTrigger=false;
cc = '­'; // control char
if(browser.ff) {
editor = this.doc.getElementById('ffedt');
this.doc.designMode = 'on';
this.doc.addEventListener('keydown', this.keyDownHandler, true);
this.doc.addEventListener('keypress', this.keyPressHandler, true);
this.doc.addEventListener('keyup', this.keyUpHandler, true);
this.doc.addEventListener('blur', this.blurHandler,true);
this.doc.body.focus();
}
else if(browser.ie) {
editor = this.doc.getElementById('ieedt');
editor.contentEditable = 'true';
this.doc.onkeypress = this.keyPressHandler;
this.doc.onkeydown = this.keyDownHandler;
this.doc.onkeyup = this.keyUpHandler;
this.doc.onblur = this.blurHandler;
}
else {
// TODO: textarea without syntax highlighting for non supported browsers
alert('your browser is not supported at the moment');
return;
}
this.syntaxHighlight(1);
window.scroll(0,0);
},
// detect browser, for now IE and FF
detect : function() {
browser = { ie:false, ff:false };
if(navigator.appName.indexOf("Microsoft") != -1) browser.ie = true;
else if (navigator.appName == "Netscape") browser.ff = true;
},
// transform syntax highlighted code to original code
plainText : function() {
code = editor.innerHTML;
code = code.replace(/<br\/?>/gi,'\n');
code = code.replace(/<\/p>/gi,'\r');
code = code.replace(/<p>/gi,'\n');
code = code.replace(/ /gi,' ');
code = code.replace(/­/gi,'');
code = code.replace(/<.*?>/g,'');
code = code.replace(/</g,'<');
code = code.replace(/>/g,'>');
code= code.replace(/&#(\d+);/g, function(p,p1)
{
return String.fromCharCode(p1);
});
code = code.replace(/&/g,'&');
return code;
},
blurHandler : function(evt) {
if (top.codePressBlurHook)
{
top.codePressBlurHook(CodePress.plainText());
}
},
// treat key bindings
keyPressHandler : function(evt) {
evt = (evt) ? evt : (window.event) ? event : null;
if(evt) {
charCode = (evt.charCode);
if(charCode && chars.indexOf(String.fromCharCode(charCode))>=0) { // syntax highlighting
highlightTrigger=true;
}
}
},
keyUpHandler : function(evt) {
if (highlightTrigger) {
CodePress.syntaxHighlight();
CodePress.findString();
highlightTrigger=false;
}
},
keyDownHandler : function(evt) {
evt = (evt) ? evt : (window.event) ? event : null;
if(evt) {
charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode : ((evt.which) ? evt.which : 0));
if(charCode==13) highlightTrigger=true; //dirty hack
else if(charCode==46||charCode==8) { // save to history when delete or backspace pressed
CodePress.actions.history[CodePress.actions.next()] = editor.innerHTML;
highlightTrigger=true; //dirty hack
}
else if((charCode==90||charCode==89) && evt.ctrlKey) { // undo and redo
(charCode==89||evt.shiftKey) ? CodePress.actions.redo() : CodePress.actions.undo() ;
evt.returnValue = false;
if(browser.ff)evt.preventDefault();
}
else if(charCode==86 && evt.ctrlKey) { // paste
// TODO: pasted text should be parsed and highlighted
highlightTrigger=true;
}
}
},
// put cursor back to its original position after every parsing
findString : function() {
if(browser.ff) {
if(self.find(cc))
window.getSelection().getRangeAt(0).deleteContents();
}
else if(browser.ie) {
range = this.doc.body.createTextRange();
if(range.findText(cc)){
range.select();
range.text = '';
}
}
},
insertSpace : function() {
if(browser.ff) {
if(!arguments[0]) window.getSelection().getRangeAt(0).insertNode(this.doc.createTextNode(" "));
}
else if(browser.ie) {
if(!arguments[0]) this.doc.selection.createRange().text = " ";
}
},
// syntax highlighting parser
syntaxHighlight : function() {
if(browser.ff) {
//document.execCommand("inserthtml", false, cc); // crash firefox+linux?
if(!arguments[0]) window.getSelection().getRangeAt(0).insertNode(this.doc.createTextNode(cc));
x = editor.innerHTML;
x = x.replace(/<br\/?>/g,'\n');
x = x.replace(/<.*?>|<\/.*?>/g,'');
}
else if(browser.ie) {
if(!arguments[0]) this.doc.selection.createRange().text = cc;
x = editor.innerHTML;
x = x.replace(/<P>/g,'\n');
x = x.replace(/<\/P>/g,'\r');
x = x.replace(/<\/?.*?>/g,'');
}
if (this.language=='hook' && top.codePressHighlightHook)
{
x=top.codePressHighlightHook(x);
}
else if (languages[this.language])
{
for(i=0;i<languages[this.language].length;i++)
x = x.replace(languages[this.language][i],languages[this.language][i+1]);
}
if(browser.ff) {
x = x.replace(/\n/g,'<br/>');
}
else if(browser.ie) {
x = '<P>'+x;
x = x.replace(/\n/g,'<P>');
x = x.replace(/\r/g,'<\/P>');
x = x.replace(/(<P>)+/,'<P>');
x = x.replace(/<P><\/P>/g,'<P> <\/P>');
}
editor.innerHTML = this.actions.history[this.actions.next()] = (browser.ff) ? x : '<pre>'+x+'</pre>' ;
},
// undo and redo methods
actions : {
pos : -1, // actual history position
history : [], // history vector
undo : function() {
if(editor.innerHTML.indexOf(cc)==-1){
if(browser.ff) window.getSelection().getRangeAt(0).insertNode(this.doc.createTextNode(cc));
else this.doc.selection.createRange().text = cc;
this.history[this.pos] = editor.innerHTML;
}
this.pos--;
if(typeof(this.history[this.pos])=='undefined') this.pos++;
editor.innerHTML = this.history[this.pos];
CodePress.findString();
},
redo : function() {
this.pos++;
if(typeof(this.history[this.pos])=='undefined') this.pos--;
editor.innerHTML = this.history[this.pos];
CodePress.findString();
},
next : function() { // get next vector position and clean old ones
if(this.pos>20) this.history[this.pos-21] = undefined;
return ++this.pos;
}
}
}
// language specific regular expressions
// TODO: distribute languages into specific [language].js files
languages = {
java : [
/([\"\'].*?[\"\'])/g,'<s>$1</s>', // strings
/(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)([ \.\"\'\{\(;&<])/g,'<b>$1</b>$2', // reserved words
/([^:])\/\/(.*?)(<br>|<\/P>)/g,'$1<i>//$2</i>$3', // comments
/\/\*(.*?)\*\//g,'<i>/*$1*/</i>' // comments
],
javascript : [
/([\"\'].*?[\"\'])/g,'<s>$1</s>', // strings
/(break|continue|do|for|new|this|void|case|default|else|function|return|typeof|while|if|label|switch|var|with|catch|boolean|int|try|false|throws|null|true|goto)([ \.\"\'\{\(\);,&<])/g,'<b>$1</b>$2', // reserved words
/(alert|isNaN|parent|Array|parseFloat|parseInt|blur|clearTimeout|prompt|prototype|close|confirm|length|Date|location|scroll|Math|document|element|name|self|elements|setTimeout|navigator|status| String|escape|Number|submit|eval|Object|event|onblur|focus|onerror|onfocus|top|onload|toString|onunload|unescape|open|opener|valueOf|window)([ \.\"\'\{\(\);,&<])/g,'<u>$1</u>$2', // special words
// /([&\|\\\/=!\[\]\(\)])([ \.\"\'\{\(;\xad&<])/g,'<em>$1</em>$2', // special chars;
/([\(\){}\?\[\]])/g,'<em>$1</em>', // special chars;
/([^:])\/\/(.*?)(<br>|<\/P>)/g,'$1<i>//$2</i>$3', // comments
/\/\*(.*?)\*\//g,'<i>/*$1*/</i>' // comments
],
php : [
/(<[^!\?]*?>)/g,'<b>$1</b>', // all tags
/(<style.*?>)(.*?)(<\/style>)/g,'<em>$1</em><em>$2</em><em>$3</em>', // style tags
/(<script.*?>)(.*?)(<\/script>)/g,'<u>$1</u><u>$2</u><u>$3</u>', // script tags
/([\"\'].*?[\"\'])/g,'<s>$1</s>', // strings
/(<\?.*?\?>)/g,'<strong>$1</strong>', // bgcolor inside php tags
/(<\?php|\?>)/g,'<cite>$1</cite>', // php tags
/(\$.*?)([ \)\(\[\{\+\-\*\/&!\|%=;])/g,'<var>$1</var>$2',
/(and|or|xor|__FILE__|exception|__LINE__|array|as|break|case|class|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|for|foreach|function|global|if|include|include_once|isset|list|new|print|require|require_once|return|static|switch|unset|use|var|while|__FUNCTION__|__CLASS__|__METHOD__|final|php_user_filter|interface|implements|extends|public|private|protected|abstract|clone|try|catch|throw|this)([ \.\"\'\{\(;&<])/g,'<ins>$1</ins>$2', // reserved words
/([^:])\/\/(.*?)(<br>|<\/P>)/g,'$1<i>//$2</i>$3', // php comments
/\/\*(.*?)\*\//g,'<i>/*$1*/</i>', // php comments
/(<!--.*?-->.)/g,'<big>$1</big>' // html comments
],
html : [
/(<[^!]*?>)/g,'<b>$1</b>', // all tags
/(<style.*?>)(.*?)(<\/style>)/g,'<em>$1</em><em>$2</em><em>$3</em>', // style tags
/(<script.*?>)(.*?)(<\/script>)/g,'<u>$1</u><u>$2</u><u>$3</u>', // script tags
/=(["'].*?["'])/g,'=<s>$1</s>', // atributes
/(<!--.*?-->.)/g,'<i>$1</i>' // comments
],
css : [
/(\}|^)(.*?)(\{)/g,'$1<b>$2</b>$3', // tags, ids, classes, etc
/([\{;])(.*?):/g,'$1<em>$2</em>:', // keys
// /([\{\}:;])/g,'<u>$1</u>', // dividers // SHY BUG HERE !!!!!!!!!
/([\"\'].*?[\"\'])/g,'<s>$1</s>', // strings
/\/\*(.*?)\*\//g,'<i>/*$1*/</i>', // comments
],
text : [
// do nothing, as expected
] };
//</nowiki></pre>
// <pre><nowiki>
// hook
String.prototype.tidy= function()
{
var c=document.createElement('div');
c.innerHTML=this;
return c.innerHTML;
}
addEventListener("load",wysawygInit,true);
//init
function wysawygInit()
{
if ($('wpTextbox1'))
{
var d=document.createElement('div');
var width=$('wpTextbox1').style.width || $('wpTextbox1').cols+"em";;
var height=$('wpTextbox1').style.height || $('wpTextbox1').rows+"em";
d.innerHTML='<d'+'iv id="wysawygButtons"><a href="javascript:wysawygToggle()">hide</a></div>'
+'<i'+'frame style="width:'+width+';height:'+height+';border:silver solid 1px!important" id="rtshed" name="rtshed"></i'+'frame>';
var loc=$('editpage-copywarn3') || $('wpTextbox1');
loc.parentNode.insertBefore(d,loc);
wysawygShow();
};
}
function wysawygToggle()
{
if ($('wpTextbox1').style.display=='none')
{
wysawygHide();
}
}
function wysawygShow()
{
if (wgTitle.match(/\.js$/))
{
lang="javascript";
style="http://codepress.fermads.net/codepress/languages/codepress-javascript.css";
}
else if (wgTitle.match(/\.css$/))
{
lang="css";
style="http://codepress.fermads.net/codepress/languages/codepress-css.css";
}
else
{
lang="hook";
style="http://test.wikipedia.org/w/index.php?title=User:Zocky/wysawyg.css&action=raw&type=text/css";
}
rtshed.document.open();
rtshed.document.write(' <html><head>'
+ '<l'+'ink type="text/css" rel="stylesheet" href="'+style+'"/>'//+'<s'+'cript>const CodePress=0</s'+'cript>'
+ '</head><body id="ffedt" codePressLanguage="' + lang + '"><pre id="ieedt">'
+ $('wpTextbox1').value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
+ '</pre></body></html>');
rtshed.onload=function(){CodePress.initialize(rtshed.document);}
rtshed.document.close();
$('rtshed').style.display='block';
$('wpTextbox1').style.display='none';
}
function wysawygHide()
{
$('rtshed').blur();
$('rtshed').style.display='none';
$('wpTextbox1').style.display='block';
}
codePressTriggerChars="[{|}]='*#:<>\"";
function codePressBlurHook(x)
{
$('wpTextbox1').value=x;
}
function codePressHighlightHook(x)
{
x=x.replace( /<nowiki( .*?)?>([\s\S]*?)<\/nowiki( .*?)?>/gi, function (p,p1,p2,p3)
{
r2=p2.replace (/([\]*#|:\[\{\}'"=])/g, function (q, q1) {return '&#' + q1.charCodeAt(0) + ';'}).replace (/\n/g,'<br/>');
r2=r2.replace(/</,'<').replace(/>/,'>');
return '<ww><</ww><wh>nowiki' + p1 + '</wh><ww>></ww><wnw>' + r2 + '</wnw><ww></</ww><wh>nowiki' + p3 + '</wh><ww>></ww>';
});
x=x.replace( /<!--(.*?)-->/gi, function (p,p1)
{
r1=p1.replace (/([\]*#|:\[\{\}'"<=>])/g, function (q, q1) {return '&#' + q1.charCodeAt(0) + ';'}).replace (/\n/g,'<br/>');
return '<ww><!--</ww><wc>' + p1 + '</wc><ww>--></ww>';
});
x=x.replace( /<(\/?)([-a-zA-Z0-9]+)(\s.*?)?(\/?)>/g, function (p,p1,p2,p3,p4)
{
r3=p3.replace (/([\]#|:\[])/g, function (q, q1) {return '&#' + q1.charCodeAt(0) + ';'});
r3=r3.replace (/"(.*?)"/g,'<ww>"</ww><whs>$1</whs><ww>"</ww>');
r3=r3.replace (/"(.*?)$/g,'<ww>"</ww><whs>$1</whs>');
switch (p2.toLowerCase())
{
case 'b':
case 'i':
case 's':
case 'sub':
case 'sup':
case 'span':
case 'font':
case 'big':
case 'small':
case 'tt':
case 'code':
case 'em':
case 'strong':
if (p1)
return ('<'+p1+p2+'><ww><'+ p1 + '</ww><wh>'+ p2 + r3 + '</wh><ww>'+ p4 +'></ww>');
else
return ('<ww><'+p1+'</ww><wh>'+ p2 + r3 + '</wh><ww>' + p4 + '></ww><'+p1+p2+p3+p4+'>');
break;
case 'br':
return ('<ww><'+p1+'</ww><wh>'+ p2 + r3 + '</wh><ww c="b">' + p4 + '></ww>');
break;
default:
return ('<ww><'+p1+'</ww><wh>'+ p2 + r3 + '</wh><ww>'+ p4 + '></ww>');
}
});
//{{{ }}} -> wp
for (var i=0; i<4; i++) // too stupid for words
{
x=x.replace( /\{\{\{(.*?)\}\}\}/g,
'<ww>{{{</ww><wp><wa>$1</wa></wp><ww>}}}</ww>' );
}
//{{ }} -> wt wa
x=x.replace( /()\}\}/g, '$1</wa></wt><ww>}}</ww>' );
x=x.replace( /\{\{()/g, '<ww>{{</ww><wt><wa>$1' );
x=x.replace( /()\}\}/g, '$1</wa></wt><ww>}}</ww>' );
//[[ ]] -> wl wa
x=x.replace( /\[\[([Ii]mage:)/g, '<ww>[[</ww><wl c="img"><wa>$1' );
x=x.replace( /\[\[()/g, '<ww>[[</ww><wl c="int"><wa>$1' );
x=x.replace( /()\]\]/g, '$1</wa></wl><ww>]]</ww>' );
//[http ] -> wx wxx
x=x.replace( /\[http:\/\/([^\]\s]+)\]/g, '<ww>[</ww><wx><wxx>http://$1</wxx></wx><ww>]</ww>');
x=x.replace( /\[http:\/\/([^\]\s]+) (.*?)\]/g,
'<ww>[</ww><wx><wxx>http://$1</wxx> <wxx>$2</wxx></wx><ww>]</ww>' );
x=x.replace( /http:\/\/([^\]\s]+)/g, '<wx><wxx>http://$1</wxx></wx>' );
//'' ''' -> i b *** BADLY BROKEN FOR UNCLEAR CASES ***
x=x.replace( /'''(.*?)'''/g, '<ww>'''</ww><b>$1</b><ww>'''</ww>' );
x=x.replace( /''(.*?)''/g, '<ww>''</ww><i>$1</i><ww>''</ww>' );
// | -> wa
x=x.replace( /\|([^<|]*?)=/g, '</wa><wa><ww>|</ww><waa>$1=</waa>' );
x=x.replace( /\|()/g, '</wa><wa><ww>|</ww>$1' );
x=x.tidy();
// == == -> ww
x=x.replace( /(^|\n)()====(.*)====( *)(\n|$)/g,
'$1$2<ww>====</ww><wh4>$3</wh4><ww>====</ww>$4$5' );
x=x.replace( /(^|\n)()===(.*)===( *)(\n|$)/g,
'$1$2<ww>===</ww><wh3>$3</wh3><ww>===</ww>$4$5');
x=x.replace( /(^|\n)()==(.*)==( *)(\n|$)/g,
'$1$2<ww>==</ww><wh2>$3</wh2><ww>==</ww>$4$5');
x=x.replace( /(^|\n)()=(.*)=( *)(\n|$)/g,
'$1$2<ww>=</ww><wh1>$3</wh1><ww>=</ww>$4$5');
// ---- -> whr
x=x.replace( /(^|\n)---(-+ *)/g, '$1<whr>---$2</whr>');
// pre -> wpr
x=x.replace( /(^|\n)( +[^\n]*?)(?=\n|$)/g, '$1<wpr>$2</wpr>');
// *#: -> wr
x=x.replace( /(^|\n)([*#:]+)(;?)([^\n]*?)(?=\n|$)/g, function (p,p1,p2,p3,p4)
{
return p1+'<wr><ww>' + p2 + p3 + '</ww><wrr c="'+p3+'">' + p4 +'</wrr></wr>';
});
// $('debug').innerHTML=x.replace(/\n/g,'<br/>').replace(/&/g,'&').replace(/</g,'<');
return x;
}
// cross-browser event functions
function eventAddListener (element,event,handler)
{
if (element.addEventListener)
element.addEventListener(event,handler,false)
else
element.attachEvent('on'+event,handler);
}
function eventRemoveListener (element, event, handler)
{
if (element.removeEventListener)
element.removeEventListener(event,handler,false)
else
element.detachEvent('on'+event,handler);
}
function eventStop(event)
{
if (event.preventDefault)
{
event.preventDefault();
event.stopPropagation();
}
else
{
event.returnValue = false;
event.cancelBubble = true;
}
}
function eventTarget(event)
{
return event.target || event.srcElement;
}
function eventKeyCode(event)
{
return event.preventDefault ? event.which : event.keyCode ;
}
function $(id)
{
return document.getElementById(id);
}
//</nowiki></pre>

