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