premier commit
[bazdig.git] / bazdig / codepress / engines / msie.js
blobfd609b2223da5c061133ddef08eeb22cf572a23f
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
21         \r
22         // set initial vars and start sh\r
23         initialize : function() {\r
24                 if(typeof(editor)=='undefined' && !arguments[0]) return;\r
25                 chars = '|32|46|62|'; // charcodes that trigger syntax highlighting\r
26                 cc = '\u2009'; // carret char\r
27                 editor = document.getElementsByTagName('pre')[0];\r
28                 editor.contentEditable = 'true';\r
29                 document.getElementsByTagName('body')[0].onfocus = function() {editor.focus();}\r
30                 document.attachEvent('onkeydown', this.metaHandler);\r
31                 document.attachEvent('onkeypress', this.keyHandler);\r
32                 window.attachEvent('onscroll', function() { if(!CodePress.scrolling) setTimeout(function(){CodePress.syntaxHighlight('scroll')},1)});\r
33                 completeChars = this.getCompleteChars();\r
34                 completeEndingChars =  this.getCompleteEndingChars();\r
35                 setTimeout(function() { window.scroll(0,0) },50); // scroll IE to top\r
36         },\r
37         \r
38         // treat key bindings\r
39         keyHandler : function(evt) {\r
40                 charCode = evt.keyCode;\r
41                 fromChar = String.fromCharCode(charCode);\r
42                 \r
43                 if( (completeEndingChars.indexOf('|'+fromChar+'|')!= -1 || completeChars.indexOf('|'+fromChar+'|')!=-1  )&& CodePress.autocomplete) { // auto complete\r
44                         if(!CodePress.completeEnding(fromChar))\r
45                              CodePress.complete(fromChar);\r
46                 }\r
47             else if(chars.indexOf('|'+charCode+'|')!=-1||charCode==13) { // syntax highlighting\r
48                         CodePress.syntaxHighlight('generic');\r
49                 }\r
50         },\r
52         metaHandler : function(evt) {\r
53                 keyCode = evt.keyCode;\r
54                 \r
55                 if(keyCode==9 || evt.tabKey) { \r
56                         CodePress.snippets();\r
57                 }\r
58                 else if((keyCode==122||keyCode==121||keyCode==90) && evt.ctrlKey) { // undo and redo\r
59                         (keyCode==121||evt.shiftKey) ? CodePress.actions.redo() :  CodePress.actions.undo(); \r
60                         evt.returnValue = false;\r
61                 }\r
62                 else if(keyCode==34||keyCode==33) { // handle page up/down for IE\r
63                         self.scrollBy(0, (keyCode==34) ? 200 : -200); \r
64                         evt.returnValue = false;\r
65                 }\r
66                 else if(keyCode==46||keyCode==8) { // save to history when delete or backspace pressed\r
67                         CodePress.actions.history[CodePress.actions.next()] = editor.innerHTML;\r
68                 }\r
69                 else if((evt.ctrlKey || evt.metaKey) && evt.shiftKey && keyCode!=90)  { // shortcuts = ctrl||appleKey+shift+key!=z(undo) \r
70                         CodePress.shortcuts(keyCode);\r
71                         evt.returnValue = false;\r
72                 }\r
73                 else if(keyCode==86 && evt.ctrlKey)  { // handle paste\r
74                         window.clipboardData.setData('Text',window.clipboardData.getData('Text').replace(/\t/g,'\u2008'));\r
75                         top.setTimeout(function(){CodePress.syntaxHighlight('paste');},10);\r
76                 }\r
77                 else if(keyCode==67 && evt.ctrlKey)  { // handle cut\r
78                         // window.clipboardData.setData('Text',x[0]);\r
79                         // code = window.clipboardData.getData('Text');\r
80                 }\r
81         },\r
83         // put cursor back to its original position after every parsing\r
84         \r
85         \r
86         findString : function() {\r
87                 range = self.document.body.createTextRange();\r
88                 if(range.findText(cc)){\r
89                         range.select();\r
90                         range.text = '';\r
91                 }\r
92         },\r
93         \r
94         // split big files, highlighting parts of it\r
95         split : function(code,flag) {\r
96                 if(flag=='scroll') {\r
97                         this.scrolling = true;\r
98                         return code;\r
99                 }\r
100                 else {\r
101                         this.scrolling = false;\r
102                         mid = code.indexOf(cc);\r
103                         if(mid-2000<0) {ini=0;end=4000;}\r
104                         else if(mid+2000>code.length) {ini=code.length-4000;end=code.length;}\r
105                         else {ini=mid-2000;end=mid+2000;}\r
106                         code = code.substring(ini,end);\r
107                         return code.substring(code.indexOf('<P>'),code.lastIndexOf('</P>')+4);\r
108                 }\r
109         },\r
110         \r
111         // syntax highlighting parser\r
112         syntaxHighlight : function(flag) {\r
113                 if(flag!='init') document.selection.createRange().text = cc;\r
114                 o = editor.innerHTML;\r
115                 if(flag=='paste') { // fix pasted text\r
116                         o = o.replace(/<BR>/g,'\r\n'); \r
117                         o = o.replace(/\u2008/g,'\t');\r
118                 }\r
119                 o = o.replace(/<P>/g,'\n');\r
120                 o = o.replace(/<\/P>/g,'\r');\r
121                 o = o.replace(/<.*?>/g,'');\r
122                 o = o.replace(/&nbsp;/g,'');                    \r
123                 o = '<PRE><P>'+o+'</P></PRE>';\r
124                 o = o.replace(/\n\r/g,'<P></P>');\r
125                 o = o.replace(/\n/g,'<P>');\r
126                 o = o.replace(/\r/g,'<\/P>');\r
127                 o = o.replace(/<P>(<P>)+/,'<P>');\r
128                 o = o.replace(/<\/P>(<\/P>)+/,'</P>');\r
129                 o = o.replace(/<P><\/P>/g,'<P><BR/></P>');\r
130                 x = z = this.split(o,flag);\r
132                 if(arguments[1]&&arguments[2]) x = x.replace(arguments[1],arguments[2]);\r
133         \r
134                 for(i=0;i<Language.syntax.length;i++) \r
135                         x = x.replace(Language.syntax[i].input,Language.syntax[i].output);\r
136                         \r
137                 editor.innerHTML = this.actions.history[this.actions.next()] = (flag=='scroll') ? x : o.replace(z,x);\r
138                 if(flag!='init') this.findString();\r
139         },\r
141         snippets : function(evt) {\r
142                 var snippets = Language.snippets;\r
143                 var trigger = this.getLastWord();\r
144                 for (var i=0; i<snippets.length; i++) {\r
145                         if(snippets[i].input == trigger) {\r
146                                 var content = snippets[i].output.replace(/</g,'&lt;');\r
147                                 content = content.replace(/>/g,'&gt;');\r
148                                 if(content.indexOf('$0')<0) content += cc;\r
149                                 else content = content.replace(/\$0/,cc);\r
150                                 content = content.replace(/\n/g,'</P><P>');\r
151                                 var pattern = new RegExp(trigger+cc,"gi");\r
152                                 this.syntaxHighlight('snippets',pattern,content);\r
153                         }\r
154                 }\r
155         },\r
156         \r
157         readOnly : function() {\r
158                 editor.contentEditable = (arguments[0]) ? 'false' : 'true';\r
159         },\r
160         \r
161         complete : function(trigger) {\r
162                 var complete = Language.complete;\r
163                 for (var i=0; i<complete.length; i++) {\r
164                         if(complete[i].input == trigger) {\r
165                                 var pattern = new RegExp('\\'+trigger+cc);\r
166                                 var content = complete[i].output.replace(/\$0/g,cc);\r
167                                 setTimeout(function () { CodePress.syntaxHighlight('complete',pattern,content)},0); // wait for char to appear on screen\r
168                         }\r
169                 }\r
170         },\r
171         \r
172         getCompleteChars : function() {\r
173                 var cChars = '';\r
174                 for(var i=0;i<Language.complete.length;i++)\r
175                         cChars += '|'+Language.complete[i].input;\r
176                 return cChars+'|';\r
177         },\r
179         getCompleteEndingChars : function() {\r
180                 var cChars = '';\r
181                 for(var i=0;i<Language.complete.length;i++)\r
182                         cChars += '|'+Language.complete[i].output.charAt(Language.complete[i].output.length-1);\r
183                 return cChars+'|';\r
184         },\r
186         completeEnding : function(trigger) {\r
187                 var range = document.selection.createRange();\r
188                 try {\r
189                         range.moveEnd('character', 1)\r
190                 }\r
191                 catch(e) {\r
192                         return false;\r
193                 }\r
194                 var next_character = range.text\r
195                 range.moveEnd('character', -1)\r
196                 if(next_character != trigger )  return false;\r
197                 else {\r
198                         range.moveEnd('character', 1)\r
199                         range.text=''\r
200                         return true;\r
201                 }\r
202         },      \r
204         shortcuts : function() {\r
205                 var cCode = arguments[0];\r
206                 if(cCode==13) cCode = '[enter]';\r
207                 else if(cCode==32) cCode = '[space]';\r
208                 else cCode = '['+String.fromCharCode(keyCode).toLowerCase()+']';\r
209                 for(var i=0;i<Language.shortcuts.length;i++)\r
210                         if(Language.shortcuts[i].input == cCode)\r
211                                 this.insertCode(Language.shortcuts[i].output,false);\r
212         },\r
213         \r
214         getLastWord : function() {\r
215                 var rangeAndCaret = CodePress.getRangeAndCaret();\r
216                 words = rangeAndCaret[0].substring(rangeAndCaret[1]-40,rangeAndCaret[1]);\r
217                 words = words.replace(/[\s\n\r\);\W]/g,'\n').split('\n');\r
218                 return words[words.length-1].replace(/[\W]/gi,'').toLowerCase();\r
219         }, \r
221         getRangeAndCaret : function() { \r
222                 var range = document.selection.createRange();\r
223                 var caret = Math.abs(range.moveStart('character', -1000000)+1);\r
224                 range = this.getCode();\r
225                 range = range.replace(/\n\r/gi,'  ');\r
226                 range = range.replace(/\n/gi,'');\r
227                 return [range.toString(),caret];\r
228         },\r
229         \r
230         insertCode : function(code,replaceCursorBefore) {\r
231                 var repdeb = '';\r
232                 var repfin = '';\r
233                 \r
234                 if(replaceCursorBefore) { repfin = code; }\r
235                 else { repdeb = code; }\r
236                 \r
237                 if(typeof document.selection != 'undefined') {\r
238                         var range = document.selection.createRange();\r
239                         range.text = repdeb + repfin;\r
240                         range = document.selection.createRange();\r
241                         range.move('character', -repfin.length);\r
242                         range.select(); \r
243                 }       \r
244         },\r
246         // get code from editor \r
247         getCode : function() {\r
248                 var code = editor.innerHTML;\r
249                 code = code.replace(/<br>/g,'\n');\r
250                 code = code.replace(/<\/p>/gi,'\r');\r
251                 code = code.replace(/<p>/i,''); // IE first line fix\r
252                 code = code.replace(/<p>/gi,'\n');\r
253                 code = code.replace(/&nbsp;/gi,'');\r
254                 code = code.replace(/\u2009/g,'');\r
255                 code = code.replace(/<.*?>/g,'');\r
256                 code = code.replace(/&lt;/g,'<');\r
257                 code = code.replace(/&gt;/g,'>');\r
258                 code = code.replace(/&amp;/gi,'&');\r
259                 return code;\r
260         },\r
262         // put code inside editor\r
263         setCode : function() {\r
264                 var code = arguments[0];\r
265                 code = code.replace(/\u2009/gi,'');\r
266                 code = code.replace(/&/gi,'&amp;');             \r
267         code = code.replace(/</g,'&lt;');\r
268         code = code.replace(/>/g,'&gt;');\r
269                 editor.innerHTML = '<pre>'+code+'</pre>';\r
270         },\r
272         \r
273         // undo and redo methods\r
274         actions : {\r
275                 pos : -1, // actual history position\r
276                 history : [], // history vector\r
277                 \r
278                 undo : function() {\r
279                         if(editor.innerHTML.indexOf(cc)==-1){\r
280                                 document.selection.createRange().text = cc;\r
281                                 this.history[this.pos] = editor.innerHTML;\r
282                         }\r
283                         this.pos--;\r
284                         if(typeof(this.history[this.pos])=='undefined') this.pos++;\r
285                         editor.innerHTML = this.history[this.pos];\r
286                         CodePress.findString();\r
287                 },\r
288                 \r
289                 redo : function() {\r
290                         this.pos++;\r
291                         if(typeof(this.history[this.pos])=='undefined') this.pos--;\r
292                         editor.innerHTML = this.history[this.pos];\r
293                         CodePress.findString();\r
294                 },\r
295                 \r
296                 next : function() { // get next vector position and clean old ones\r
297                         if(this.pos>20) this.history[this.pos-21] = undefined;\r
298                         return ++this.pos;\r
299                 }\r
300         }\r
303 Language={};\r
304 window.attachEvent('onload', function() { CodePress.initialize('new');});