1 /* 2 * CodePress - Real Time Syntax Highlighting Editor written in JavaScript - http://codepress.org/ 3 * 4 * Copyright (C) 2006 Fernando M.A.d.S. <fermads@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it under the terms of the 7 * GNU Lesser General Public License as published by the Free Software Foundation. 8 * 9 * Read the full licence: http://www.opensource.org/licenses/lgpl-license.php 10 * 11 * This file is not the original but has been modified to be more compliant with 12 * ExtJs. Changes are made by S.J.Hoeksma 13 */ 14 Ext.namespace('Ext.ux'); 15 16 /** 17 * Component which wraps the <a href="http://codepress.org">CodePress</a> library to make 18 * it available for ExtJs. CodePress gives syntax highlighting for different programming 19 * languages. 20 * @type component 21 */ 22 Ext.ux.CodePress = Ext.extend(Ext.form.Field, { 23 24 /** 25 * The id of the element to pull code from 26 * @type {String} 27 @cfg */ 28 sourceEl : false, 29 30 /** 31 * The code to use in the editor 32 * @type {String} 33 @cfg */ 34 code : false, 35 36 /** 37 * The language to render the code with (defaults none) 38 * @type {String} 39 @cfg */ 40 language : false, 41 42 /** 43 * The url used to read code which is display in editor 44 * @type {String} 45 @cfg */ 46 url : false, 47 48 /** 49 * Height of the editor (defaults false) 50 * @type {Int} 51 @cfg */ 52 height : false, 53 54 /** 55 * Width of the editor (defaults false) 56 * @type {Int} 57 @cfg */ 58 width : false, 59 60 /** 61 * AutoResize window on change container (defaults false) 62 * @type {Boolean} 63 @cfg */ 64 autoResize : false, 65 66 /** 67 * Trim the code of trailing spaces and empty lines (defaults true) 68 * @type {Boolean} 69 @cfg */ 70 trim : true, 71 72 /** 73 * Is autoComplete for keywords turned on or off (defaults true) 74 * @type {Boolean} 75 @cfg */ 76 autoComplete : true, 77 78 /** 79 * Is the editor readonly (defaults false) 80 * @type {Boolean} 81 @cfg */ 82 readOnly : false, 83 84 /** 85 * Are lineNumbers visible (defaults true) 86 * @type {Boolean} 87 @cfg */ 88 lineNumbers : true, 89 90 //@private Has the editor been initialized 91 initialized : false, 92 93 /** 94 * @private Init the codepress component for ExtJs 95 */ 96 initComponent : function(){ 97 if (!Ext.ux.CodePress.path) { 98 s = document.getElementsByTagName('script'); 99 for(var i=0,n=s.length;i<n;i++) { 100 var name = s[i].src ? s[i].src : s[i].id; 101 if(name.match('Ext\.ux\.CodePress\.js')) { 102 Ext.ux.CodePress.path = name.replace("Ext.ux.CodePress.js",''); 103 break; 104 } 105 } 106 } 107 Ext.ux.CodePress.superclass.initComponent.call(this); 108 109 // Hide the sourceEl if provided 110 if(this.sourceEl) Ext.get(this.sourceEl).hide(); 111 112 this.addEvents({ 113 /** 114 * Fires when the editor is fully initialized (including the iframe) 115 * @event initialize 116 * @param {Object} editor The editor 117 */ 118 initialize: true, 119 120 /** 121 * Fires when the editor is first receives the focus. Any insertion must wait 122 * until after this event. 123 * @event activate 124 * @param {Object} editor The editor when activated 125 */ 126 activate: true 127 128 }); 129 }, 130 131 /** 132 * @private (for BoxComponent) 133 */ 134 adjustSize : Ext.BoxComponent.prototype.adjustSize, 135 136 /** 137 * Resize the the editor depending, behavior depends on height,width and autoResize 138 */ 139 resize : function(){ 140 if (!this.editor) return; 141 var h,w; 142 if (this.autoResize) { 143 h = this.ownerCt.body.dom.clientHeight +'px'; 144 w = this.ownerCt.body.dom.clientWidth +'px'; 145 } else { 146 h = (this.height || this.ownerCt.body.dom.clientHeight) +'px'; 147 w = (this.width || this.ownerCt.body.dom.clientWidth) +'px'; 148 } 149 this.editor.body.style.width = w; 150 this.iframe.setStyle('height', h); 151 this.iframe.setStyle('width', w); 152 }, 153 154 /** 155 * @private During render we create textarea of code press 156 * @param {Component} ct The component to render 157 * @param {Object} position A object containing the position of the component 158 */ 159 onRender : function(ct, position){ 160 Ext.ux.CodePress.superclass.onRender.call(this, ct, position); 161 162 //Taken from Ext.form.HtmlEditor 163 this.el.dom.style.border = '0 none'; 164 this.el.dom.setAttribute('tabIndex', -1); 165 this.el.addClass('x-hidden'); 166 167 168 if(Ext.isIE){ // fix IE 1px bogus margin 169 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;') 170 } 171 this.wrap = this.el.wrap({}); 172 173 // Create the iframe 174 this.iframe = Ext.get(document.createElement('iframe')); 175 this.iframe.src = (Ext.SSL_SECURE_URL || 'javascript:false'); 176 177 // Create the textarea element if not created 178 if(!this.sourceEl){ 179 this.textarea = Ext.get(document.createElement('textarea')); 180 }else{ 181 this.textarea = Ext.get(this.sourceEl); 182 } 183 this.textarea.dom.disabled = true; 184 this.textarea.dom.style.overflow = 'hidden'; 185 this.textarea.dom.style.overflow = 'auto'; 186 this.iframe.dom.frameBorder = 0; // remove IE internal iframe border 187 this.iframe.setStyle('visibility', 'hidden'); 188 this.iframe.setStyle('position', 'absolute'); 189 this.options = this.textarea.dom.className; 190 this.wrap.dom.appendChild(this.textarea.dom); 191 this.textarea.dom.parentNode.insertBefore(this.iframe.dom, this.textarea.dom); 192 this.edit(); 193 this.height = (this.height || this.ownerCt.body.dom.clientHeight); 194 this.width= (this.width || this.ownerCt.body.dom.clientWidth); 195 }, 196 197 /** 198 * @private We don't support focus of editor 199 */ 200 focus : function(){}, 201 202 /** 203 * @private Initialize the editor 204 */ 205 initialize : function() { 206 if(Ext.isIE){ 207 this.doc = this.iframe.dom.contentWindow.document; 208 this.win = this.iframe.dom.contentWindow; 209 } else { 210 this.doc = this.iframe.dom.contentDocument; 211 this.win = this.iframe.dom.contentWindow; 212 } 213 this.editor = this.win.CodePress; 214 this.editor.body = this.doc.getElementsByTagName('body')[0]; 215 if(this.url){ 216 Ext.Ajax.request({ 217 url: this.url 218 , method:'get' 219 , success:function(response, options){ 220 var code = response.responseText; 221 this.code = code; 222 this.editor.setCode(this.code); 223 }.createDelegate(this) 224 }); 225 }else{ 226 this.editor.setCode(this.code || this.textarea.dom.value); 227 } 228 this.resize(); 229 this.setOptions(); 230 this.editor.syntaxHighlight('init'); 231 this.textarea.dom.style.display = 'none'; 232 this.iframe.dom.style.position = 'static'; 233 this.iframe.dom.style.visibility = 'visible'; 234 this.iframe.dom.style.display = 'inline'; 235 236 this.initialized = true; 237 this.fireEvent('initialize', this); 238 }, 239 240 /** 241 * Initailize the editor with a element and set the langauge 242 * @param {Object} obj Can by a textarea id or a string 243 * @param {String} language The langauge to use 244 */ 245 edit : function(obj,language) { 246 if(obj) this.textarea.dom.value = document.getElementById(obj) ? document.getElementById(obj).value : obj; 247 if(!this.textarea.dom.disabled) return; 248 this.language = language ? language : this.getLanguage(); 249 this.iframe.dom.src = Ext.ux.CodePress.path+'codepress.html?language='+this.language+'&ts='+(new Date).getTime(); 250 this.iframe.removeListener('load', this.initialize); 251 this.iframe.on('load', this.initialize, this); 252 }, 253 254 /** 255 * Get the current langauge used by the editor 256 * @return {String} The language used by editor 257 */ 258 getLanguage : function() { 259 if(this.language) return this.language; 260 for (language in Ext.ux.CodePress.languages) 261 if(this.options.match('\\b'+language+'\\b')) 262 return Ext.ux.CodePress.languages[language] ? language : 'generic'; 263 }, 264 265 /** 266 * Set the options of editor 267 * See config items autoComplete, readOnly, lineNumbers 268 */ 269 setOptions : function() { 270 if(this.autoComplete===false || this.options.match('autocomplete-off')) this.toggleAutoComplete(); 271 if(this.readOnly===true || this.options.match('readonly-on')) this.toggleReadOnly(); 272 if(this.lineNumbers===false || this.options.match('linenumbers-off')) this.toggleLineNumbers(); 273 }, 274 275 /** 276 * Original CodePress function to get the code from the editor. For compatibility reasons 277 * with ExtJs TextArea whe implemented getValue 278 * @return {String} The code from editor 279 */ 280 getCode : function() { 281 var code; 282 if (this.textarea && this.editor) 283 code = this.textarea.dom.disabled ? this.editor.getCode() : this.textarea.dom.value; 284 else 285 code = this.code || ""; 286 code = this.trim ? code.replace(/^\s+|(\s+$|\n$|\r$)/g,"") : code; 287 return code; 288 }, 289 290 /** 291 * Original CodePress function to set the code of the editor.For compatibility reasons 292 * with ExtJs TextArea whe implemented setValue 293 * @param {String} code The code to be display in editor 294 */ 295 setCode : function(code) { 296 if (this.textarea && this.editor) { 297 this.textarea.dom.disabled ? this.editor.setCode(code) : this.textarea.dom.value = code; 298 this.editor.syntaxHighlight('init'); 299 } else { 300 this.code = code; 301 } 302 }, 303 304 /** 305 * Set the value to be used by the editor 306 * @param {String} text The code to be display in editor 307 */ 308 setValue : function(text) { 309 this.setCode(text); 310 }, 311 312 /** 313 * Get the value of the code within the editor 314 * @return {String} The code within the editor 315 */ 316 getValue : function() { 317 return this.getCode(); 318 }, 319 320 /** 321 * Toggle autocomplreate on or off 322 */ 323 toggleAutoComplete : function() { 324 if (this.editor) 325 this.editor.autocomplete = (this.editor.autocomplete) ? false : true; 326 }, 327 328 /** 329 * Toggle readonly on or off 330 */ 331 toggleReadOnly : function() { 332 this.textarea.dom.readOnly = (this.textarea.dom.readOnly) ? false : true; 333 if(this.iframe.dom.style.display != 'none' && this.editor) // prevent exception on FF + iframe with display:none 334 this.editor.readOnly(this.textarea.dom.readOnly ? true : false); 335 }, 336 337 /** 338 * Toggle line numbers on or off 339 */ 340 toggleLineNumbers : function() { 341 if (!this.editor) return; 342 var cn = this.editor.body.className; 343 this.editor.body.className = (cn==''||cn=='show-line-numbers') ? 'hide-line-numbers' : 'show-line-numbers'; 344 }, 345 346 /** 347 * Toggle between codepress and textarea 348 */ 349 toggleEditor : function() { 350 if(this.textarea.dom.disabled) { 351 this.textarea.dom.value = this.getCode(); 352 this.textarea.dom.disabled = false; 353 this.iframe.dom.style.display = 'none'; 354 this.textarea.dom.style.display = 'inline'; 355 } 356 else { 357 this.textarea.dom.disabled = true; 358 this.setCode(this.textarea.dom.value); 359 if (this.editor) this.editor.syntaxHighlight('init'); 360 this.iframe.domstyle.display = 'inline'; 361 this.textarea.dom.style.display = 'none'; 362 } 363 } 364 }); 365 366 Ext.reg('codepress', Ext.ux.CodePress); 367 368 Ext.ux.CodePress.languages = { 369 csharp : 'C#', 370 css : 'CSS', 371 generic : 'Generic', 372 html : 'HTML', 373 java : 'Java', 374 javascript : 'JavaScript', 375 perl : 'Perl', 376 ruby : 'Ruby', 377 php : 'PHP', 378 text : 'Text', 379 sql : 'SQL', 380 vbscript : 'VBScript' 381 } 382 383