web/wp-includes/js/codepress/engines/gecko.js
changeset 136 bde1974c263b
equal deleted inserted replaced
135:53cff4b4a802 136:bde1974c263b
       
     1 /*
       
     2  * CodePress - Real Time Syntax Highlighting Editor written in JavaScript - http://codepress.org/
       
     3  * 
       
     4  * Copyright (C) 2007 Fernando M.A.d.S. <fermads@gmail.com>
       
     5  *
       
     6  * Developers:
       
     7  *		Fernando M.A.d.S. <fermads@gmail.com>
       
     8  *		Michael Hurni <michael.hurni@gmail.com>
       
     9  * Contributors: 	
       
    10  *		Martin D. Kirk
       
    11  *
       
    12  * This program is free software; you can redistribute it and/or modify it under the terms of the 
       
    13  * GNU Lesser General Public License as published by the Free Software Foundation.
       
    14  * 
       
    15  * Read the full licence: http://www.opensource.org/licenses/lgpl-license.php
       
    16  */
       
    17 
       
    18 CodePress = {
       
    19 	scrolling : false,
       
    20 	autocomplete : true,
       
    21 
       
    22 	// set initial vars and start sh
       
    23 	initialize : function() {
       
    24 		if(typeof(editor)=='undefined' && !arguments[0]) return;
       
    25 		body = document.getElementsByTagName('body')[0];
       
    26 		body.innerHTML = body.innerHTML.replace(/\n/g,"");
       
    27 		chars = '|32|46|62|8|'; // charcodes that trigger syntax highlighting
       
    28 		cc = '\u2009'; // carret char
       
    29 		editor = document.getElementsByTagName('pre')[0];
       
    30 		document.designMode = 'on';
       
    31 		document.addEventListener('keypress', this.keyHandler, true);
       
    32 		window.addEventListener('scroll', function() { if(!CodePress.scrolling) CodePress.syntaxHighlight('scroll') }, false);
       
    33 		completeChars = this.getCompleteChars();
       
    34 		completeEndingChars =  this.getCompleteEndingChars();
       
    35 	},
       
    36 
       
    37 	// treat key bindings
       
    38 	keyHandler : function(evt) {
       
    39     	keyCode = evt.keyCode;	
       
    40 		charCode = evt.charCode;
       
    41 		fromChar = String.fromCharCode(charCode);
       
    42 
       
    43 		if((evt.ctrlKey || evt.metaKey) && evt.shiftKey && charCode!=90)  { // shortcuts = ctrl||appleKey+shift+key!=z(undo) 
       
    44 			CodePress.shortcuts(charCode?charCode:keyCode);
       
    45 		}
       
    46 		else if( (completeEndingChars.indexOf('|'+fromChar+'|')!= -1 || completeChars.indexOf('|'+fromChar+'|')!=-1) && CodePress.autocomplete) { // auto complete
       
    47 			if(!CodePress.completeEnding(fromChar))
       
    48 			     CodePress.complete(fromChar);
       
    49 		}
       
    50 	    else if(chars.indexOf('|'+charCode+'|')!=-1||keyCode==13) { // syntax highlighting
       
    51 			top.setTimeout(function(){CodePress.syntaxHighlight('generic');},100);
       
    52 		}
       
    53 		else if(keyCode==9 || evt.tabKey) {  // snippets activation (tab)
       
    54 			CodePress.snippets(evt);
       
    55 		}
       
    56 		else if(keyCode==46||keyCode==8) { // save to history when delete or backspace pressed
       
    57 		 	CodePress.actions.history[CodePress.actions.next()] = editor.innerHTML;
       
    58 		}
       
    59 		else if((charCode==122||charCode==121||charCode==90) && evt.ctrlKey) { // undo and redo
       
    60 			(charCode==121||evt.shiftKey) ? CodePress.actions.redo() :  CodePress.actions.undo(); 
       
    61 			evt.preventDefault();
       
    62 		}
       
    63 		else if(charCode==118 && evt.ctrlKey)  { // handle paste
       
    64 		 	top.setTimeout(function(){CodePress.syntaxHighlight('generic');},100);
       
    65 		}
       
    66 		else if(charCode==99 && evt.ctrlKey)  { // handle cut
       
    67 		 	//alert(window.getSelection().getRangeAt(0).toString().replace(/\t/g,'FFF'));
       
    68 		}
       
    69 
       
    70 	},
       
    71 
       
    72 	// put cursor back to its original position after every parsing
       
    73 	findString : function() {
       
    74 		if(self.find(cc))
       
    75 			window.getSelection().getRangeAt(0).deleteContents();
       
    76 	},
       
    77 	
       
    78 	// split big files, highlighting parts of it
       
    79 	split : function(code,flag) {
       
    80 		if(flag=='scroll') {
       
    81 			this.scrolling = true;
       
    82 			return code;
       
    83 		}
       
    84 		else {
       
    85 			this.scrolling = false;
       
    86 			mid = code.indexOf(cc);
       
    87 			if(mid-2000<0) {ini=0;end=4000;}
       
    88 			else if(mid+2000>code.length) {ini=code.length-4000;end=code.length;}
       
    89 			else {ini=mid-2000;end=mid+2000;}
       
    90 			code = code.substring(ini,end);
       
    91 			return code;
       
    92 		}
       
    93 	},
       
    94 	
       
    95 	getEditor : function() {
       
    96 		if(!document.getElementsByTagName('pre')[0]) {
       
    97 			body = document.getElementsByTagName('body')[0];
       
    98 			if(!body.innerHTML) return body;
       
    99 			if(body.innerHTML=="<br>") body.innerHTML = "<pre> </pre>";
       
   100 			else body.innerHTML = "<pre>"+body.innerHTML+"</pre>";
       
   101 		}
       
   102 		return document.getElementsByTagName('pre')[0];
       
   103 	},
       
   104 	
       
   105 	// syntax highlighting parser
       
   106 	syntaxHighlight : function(flag) {
       
   107 		//if(document.designMode=='off') document.designMode='on'
       
   108 		if(flag != 'init') { window.getSelection().getRangeAt(0).insertNode(document.createTextNode(cc));}
       
   109 		editor = CodePress.getEditor();
       
   110 		o = editor.innerHTML;
       
   111 		o = o.replace(/<br>/g,'\n');
       
   112 		o = o.replace(/<.*?>/g,'');
       
   113 		x = z = this.split(o,flag);
       
   114 		x = x.replace(/\n/g,'<br>');
       
   115 
       
   116 		if(arguments[1]&&arguments[2]) x = x.replace(arguments[1],arguments[2]);
       
   117 	
       
   118 		for(i=0;i<Language.syntax.length;i++) 
       
   119 			x = x.replace(Language.syntax[i].input,Language.syntax[i].output);
       
   120 
       
   121 		editor.innerHTML = this.actions.history[this.actions.next()] = (flag=='scroll') ? x : o.split(z).join(x);
       
   122 		if(flag!='init') this.findString();
       
   123 	},
       
   124 	
       
   125 	getLastWord : function() {
       
   126 		var rangeAndCaret = CodePress.getRangeAndCaret();
       
   127 		words = rangeAndCaret[0].substring(rangeAndCaret[1]-40,rangeAndCaret[1]);
       
   128 		words = words.replace(/[\s\n\r\);\W]/g,'\n').split('\n');
       
   129 		return words[words.length-1].replace(/[\W]/gi,'').toLowerCase();
       
   130 	},
       
   131 	
       
   132 	snippets : function(evt) {
       
   133 		var snippets = Language.snippets;	
       
   134 		var trigger = this.getLastWord();
       
   135 		for (var i=0; i<snippets.length; i++) {
       
   136 			if(snippets[i].input == trigger) {
       
   137 				var content = snippets[i].output.replace(/</g,'&lt;');
       
   138 				content = content.replace(/>/g,'&gt;');
       
   139 				if(content.indexOf('$0')<0) content += cc;
       
   140 				else content = content.replace(/\$0/,cc);
       
   141 				content = content.replace(/\n/g,'<br>');
       
   142 				var pattern = new RegExp(trigger+cc,'gi');
       
   143 				evt.preventDefault(); // prevent the tab key from being added
       
   144 				this.syntaxHighlight('snippets',pattern,content);
       
   145 			}
       
   146 		}
       
   147 	},
       
   148 	
       
   149 	readOnly : function() {
       
   150 		document.designMode = (arguments[0]) ? 'off' : 'on';
       
   151 	},
       
   152 
       
   153 	complete : function(trigger) {
       
   154 		window.getSelection().getRangeAt(0).deleteContents();
       
   155 		var complete = Language.complete;
       
   156 		for (var i=0; i<complete.length; i++) {
       
   157 			if(complete[i].input == trigger) {
       
   158 				var pattern = new RegExp('\\'+trigger+cc);
       
   159 				var content = complete[i].output.replace(/\$0/g,cc);
       
   160 				parent.setTimeout(function () { CodePress.syntaxHighlight('complete',pattern,content)},0); // wait for char to appear on screen
       
   161 			}
       
   162 		}
       
   163 	},
       
   164 
       
   165 	getCompleteChars : function() {
       
   166 		var cChars = '';
       
   167 		for(var i=0;i<Language.complete.length;i++)
       
   168 			cChars += '|'+Language.complete[i].input;
       
   169 		return cChars+'|';
       
   170 	},
       
   171 	
       
   172 	getCompleteEndingChars : function() {
       
   173 		var cChars = '';
       
   174 		for(var i=0;i<Language.complete.length;i++)
       
   175 			cChars += '|'+Language.complete[i].output.charAt(Language.complete[i].output.length-1);
       
   176 		return cChars+'|';
       
   177 	},
       
   178 	
       
   179 	completeEnding : function(trigger) {
       
   180 		var range = window.getSelection().getRangeAt(0);
       
   181 		try {
       
   182 			range.setEnd(range.endContainer, range.endOffset+1)
       
   183 		}
       
   184 		catch(e) {
       
   185 			return false;
       
   186 		}
       
   187 		var next_character = range.toString()
       
   188 		range.setEnd(range.endContainer, range.endOffset-1)
       
   189 		if(next_character != trigger) return false;
       
   190 		else {
       
   191 			range.setEnd(range.endContainer, range.endOffset+1)
       
   192 			range.deleteContents();
       
   193 			return true;
       
   194 		}
       
   195 	},
       
   196 	
       
   197 	shortcuts : function() {
       
   198 		var cCode = arguments[0];
       
   199 		if(cCode==13) cCode = '[enter]';
       
   200 		else if(cCode==32) cCode = '[space]';
       
   201 		else cCode = '['+String.fromCharCode(charCode).toLowerCase()+']';
       
   202 		for(var i=0;i<Language.shortcuts.length;i++)
       
   203 			if(Language.shortcuts[i].input == cCode)
       
   204 				this.insertCode(Language.shortcuts[i].output,false);
       
   205 	},
       
   206 	
       
   207 	getRangeAndCaret : function() {	
       
   208 		var range = window.getSelection().getRangeAt(0);
       
   209 		var range2 = range.cloneRange();
       
   210 		var node = range.endContainer;			
       
   211 		var caret = range.endOffset;
       
   212 		range2.selectNode(node);	
       
   213 		return [range2.toString(),caret];
       
   214 	},
       
   215 	
       
   216 	insertCode : function(code,replaceCursorBefore) {
       
   217 		var range = window.getSelection().getRangeAt(0);
       
   218 		var node = window.document.createTextNode(code);
       
   219 		var selct = window.getSelection();
       
   220 		var range2 = range.cloneRange();
       
   221 		// Insert text at cursor position
       
   222 		selct.removeAllRanges();
       
   223 		range.deleteContents();
       
   224 		range.insertNode(node);
       
   225 		// Move the cursor to the end of text
       
   226 		range2.selectNode(node);		
       
   227 		range2.collapse(replaceCursorBefore);
       
   228 		selct.removeAllRanges();
       
   229 		selct.addRange(range2);
       
   230 	},
       
   231 	
       
   232 	// get code from editor
       
   233 	getCode : function() {
       
   234 		if(!document.getElementsByTagName('pre')[0] || editor.innerHTML == '')
       
   235 			editor = CodePress.getEditor();
       
   236 		var code = editor.innerHTML;
       
   237 		code = code.replace(/<br>/g,'\n');
       
   238 		code = code.replace(/\u2009/g,'');
       
   239 		code = code.replace(/<.*?>/g,'');
       
   240 		code = code.replace(/&lt;/g,'<');
       
   241 		code = code.replace(/&gt;/g,'>');
       
   242 		code = code.replace(/&amp;/gi,'&');
       
   243 		return code;
       
   244 	},
       
   245 
       
   246 	// put code inside editor
       
   247 	setCode : function() {
       
   248 		var code = arguments[0];
       
   249 		code = code.replace(/\u2009/gi,'');
       
   250 		code = code.replace(/&/gi,'&amp;');
       
   251 		code = code.replace(/</g,'&lt;');
       
   252 		code = code.replace(/>/g,'&gt;');
       
   253 		editor.innerHTML = code;
       
   254 		if (code == '')
       
   255 			document.getElementsByTagName('body')[0].innerHTML = '';
       
   256 	},
       
   257 
       
   258 	// undo and redo methods
       
   259 	actions : {
       
   260 		pos : -1, // actual history position
       
   261 		history : [], // history vector
       
   262 		
       
   263 		undo : function() {
       
   264 			editor = CodePress.getEditor();
       
   265 			if(editor.innerHTML.indexOf(cc)==-1){
       
   266 				if(editor.innerHTML != " ")
       
   267 					window.getSelection().getRangeAt(0).insertNode(document.createTextNode(cc));
       
   268 				this.history[this.pos] = editor.innerHTML;
       
   269 			}
       
   270 			this.pos --;
       
   271 			if(typeof(this.history[this.pos])=='undefined') this.pos ++;
       
   272 			editor.innerHTML = this.history[this.pos];
       
   273 			if(editor.innerHTML.indexOf(cc)>-1) editor.innerHTML+=cc;
       
   274 			CodePress.findString();
       
   275 		},
       
   276 		
       
   277 		redo : function() {
       
   278 			// editor = CodePress.getEditor();
       
   279 			this.pos++;
       
   280 			if(typeof(this.history[this.pos])=='undefined') this.pos--;
       
   281 			editor.innerHTML = this.history[this.pos];
       
   282 			CodePress.findString();
       
   283 		},
       
   284 		
       
   285 		next : function() { // get next vector position and clean old ones
       
   286 			if(this.pos>20) this.history[this.pos-21] = undefined;
       
   287 			return ++this.pos;
       
   288 		}
       
   289 	}
       
   290 }
       
   291 
       
   292 Language={};
       
   293 window.addEventListener('load', function() { CodePress.initialize('new'); }, true);