PDA

View Full Version : Ext.ux.form.CodeMirror



mschwartz
23 Dec 2009, 6:45 AM
http://marijn.haverbeke.nl/codemirror/

CodeMirror is a pretty awesome programmer's source code editor written in Javascript. Until someone writes emacs in Javascript for web browsers, that is.

Anyhow, here's source code to an extension I wrote for it. Feel free to use it, hack it, whatever you like. You owe me nothing.

The following CSS is required:


.codemirror-iframe {
background: white;
color: black;
}

.CodeMirror-line-numbers {
font-size: 10pt;
margin: 0.4em;
font-family: monospace;
text-align: right;
}




Ext.namespace('Ext.ux.form');

Ext.ux.form.CodeMirror = Ext.extend(Ext.form.TextArea, {
language: 'txt',
codeMirrorPath: null, // should be path to code mirror on your server!
initComponent: function() {
if (this.codeMirrorPath === null) {
throw 'Ext.ux.form.CodeMirror: codeMirrorPath required';
}
this.initialized = false;
Ext.ux.form.CodeMirror.superclass.initComponent.apply(this, arguments);
this.addEvents('initialize');
this.on({
resize: function(ta, width, height) {
var el = Ext.select('.'+this.id, true);
if (el) {
width -= 35;
el.elements.forEach(function(e) {
e.setSize(width, height);
});
}
},
afterrender: function() {
var parser, stylesheet;
switch (this.language.toLowerCase()) {
case 'css':
parser = 'parsecss.js';
stylesheet = this.codeMirrorPath+'/css/csscolors.css';
break;
case 'js':
parser = ['tokenizejavascript.js', 'parsejavascript.js'];
stylesheet = this.codeMirrorPath+'/css/jscolors.css';
break;
case 'php':
parser = [
"parsexml.js",
"parsecss.js",
"tokenizejavascript.js",
"parsejavascript.js",
"../contrib/php/js/tokenizephp.js",
"../contrib/php/js/parsephp.js",
"../contrib/php/js/parsephphtmlmixed.js"
];
stylesheet = [
this.codeMirrorPath+'/css/xmlcolors.css',
this.codeMirrorPath+'/css/jscolors.css',
this.codeMirrorPath+'/css/csscolors.css',
this.codeMirrorPath+'/contrib/php/css/phpcolors.css'
];
break;
case 'htm':
case 'html':
case 'xml':
parser = 'parsexml.js';
stylesheet = 'xmlcolors.css';
break;
default:
parser = 'parsedummy.js';
stylesheet = '';
break;

}
var me = this;
me.codeEditor = new CodeMirror.fromTextArea(me.id, {
parserfile: parser,
stylesheet: stylesheet,
path: me.codeMirrorPath+'/js/',
textWrapping: false,
lineNumbers: true,
iframeClass: 'codemirror-iframe '+me.id,
content: me.initialConfig.value,
initCallback: function() {
me.initialized = true;
me.fireEvent('initialize', true);
}
});
}
});
},
getValue: function() {
if (this.initialized) {
return this.codeEditor.getCode();
}
return this.initialConfig.value;
},
setValue: function(v) {
if (this.initialized) {
this.codeEditor.setCode(v);
}
},
validate: function() {
this.getValue();
Ext.ux.form.CodeMirror.superclass.validate.apply(this, arguments);
}
});
Ext.reg('ux-codemirror', Ext.ux.form.CodeMirror);


It's really simple to use:



{
xtype: 'ux-codemirror',
codeMirrorPath: 'path_to_codemirror_on_server',
language: 'js', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
listeners: { // optional
init: function() {
}
}
}


NOTE: You need to include codemirror.js in the head of your HTML:



<head>
...
<script type="text/javascript" src="path/to/CodeMirror-0.63/js/codemirror.js"></script>
...
</head>


Tested with 3.0. I suspect it works with 3.1, haven't tested it. Might work with 2.x, too.

grigory666
24 Dec 2009, 6:16 AM
Thank you, mschwartz!
It is cool extension.
I have one question about strings numbers. I get only 6 rows. Why?
http://www.extjs.com/forum/attachment.php?attachmentid=17979&stc=1&d=1261666468
I use it so:

var CMpanel = new Ext.Panel({
layout : 'fit',
frame : true,
items : [{
xtype : 'ux-codemirror',
codeMirrorPath : 'js/codemirror',
language : 'html'
}]
});

new Ext.Window({
layout : 'fit',
width : 500,
height : 300,
items : [CMpanel]
}).show(); Maybe, do I something wrong?

Could you show an example?

cq.yangyu@gmail.com
24 Dec 2009, 4:09 PM
Is there any version or sample for java programer ?

linux_china
24 Dec 2009, 10:36 PM
Can you upload the example code?

wemerson.januario
25 Dec 2009, 6:24 AM
Thanks for sharing your work!

mschwartz
28 Dec 2009, 9:45 AM
codemirror 0.65 has that error with the line numbers.

If you can download 0.63, use that.

pedroteixeira
6 Jan 2010, 3:50 PM
Do you have any idea what might be causing CTRL+V to duplicate text in this componente?

thanks!
Pedro

coolstar
6 Jan 2010, 6:47 PM
Hi all. This extension looks neat, but I am having trouble in firefox. The window opens, but codemirror doesn't show in firefox. It works fine in chrome.

Here is the code:


MyDesktop.CompilerModule = Ext.extend(Ext.app.Module, {
id:'compiler-win',
appType : 'compiler',
init : function(){
this.launcher = {
text: 'Program Coder',
iconCls:'browser',
handler : this.createWindow,
scope: this
}
},

createWindow : function(){
var codertabindex = 1;
var desktop = this.app.getDesktop();
var win = desktop.getWindow('compiler-win');
if(!win){
win = desktop.createWindow({
id: 'compiler-win',
title:'Program Coder',
width:740,
height:480,
iconCls: 'bogus',
shim:false,
animCollapse:false,
constrainHeader:true,
layout: 'fit',
items: new Ext.TabPanel({
enableTabScroll: true,
id:'tabbedcompiler',
activeTab: 0,
plugins: [ 'tabtitleedit',Ext.ux.AddTabButton ],
createTab: function() {
codertabindex = codertabindex + 1;
return {
title: 'Editor ' + codertabindex,
xtype: 'ux-codemirror',
codeMirrorPath: '../codemirror/',
language: 'js', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
closable:true,
};
},
items: [{
title: 'Editor 1',
xtype: 'ux-codemirror',
codeMirrorPath: '../codemirror/',
language: 'js', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
closable: false,
}],
listeners: {
remove: function(){
codertabindex = codertabindex - 1 ;
}

}
})
});

}
win.show();
}
});

Using:
Extjs 3.1 (Desktop)
Firefox 3.5/Chrome 4.0

mschwartz
7 Jan 2010, 6:21 AM
What does the net tab in firebug tell you? Is it fetching the codemirror files?

I would set a breakpoint in the render function of the extension and step through and see what it is doing.

coolstar
8 Jan 2010, 7:45 PM
I checked the net tab in firebug, and it is fetching the codemirror files, but it doesn't show. I noticed that it uses an iframe. When I reloaded the iframe using firefox's context menu, codemirror shows, but I can't have the user reload the iframe themselves. :-?

mschwartz
12 Jan 2010, 6:34 AM
codemirror 0.65 has that error with the line numbers.

If you can download 0.63, use that.


I checked the net tab in firebug, and it is fetching the codemirror files, but it doesn't show. I noticed that it uses an iframe. When I reloaded the iframe using firefox's context menu, codemirror shows, but I can't have the user reload the iframe themselves. :-?

What version of code mirror are you using? It's not even a 1.x release, so I expect there are likely issues from release to release. This extension definitely works with 0.63

coolstar
12 Jan 2010, 7:14 AM
version 0.63

mschwartz
12 Jan 2010, 8:00 AM
See the bottom of the 1st post in the thread.

I forgot to mention that you need to add the codemirror.js in the <head> of your HTML page.

coolstar
12 Jan 2010, 7:50 PM
I already had codemirror.js in he head tag, but it still doesn't show in firefox. Here's a demo:
http://csos.zxq.net/

Username: demo
Password: demo

Extjs 3.1
Codemirror 0.63

mschwartz
13 Jan 2010, 6:36 AM
Try changing from this.on({ render... }) to this.on({ afterrender: ...})

It'd help if you didn't try to disable firebug during development ;-) It doesn't disable it, but generates errors while using it.

coolstar
13 Jan 2010, 6:37 AM
Let me check. Can you stay on so we can see about it?

mschwartz
13 Jan 2010, 6:39 AM
Sure

When I stepped through it, it did come up the first time. I assume it is because the browser had time to init the iframe before getting into the codemirror code.

The afterrender should assure the iframe is at least present in the DOM.

coolstar
13 Jan 2010, 6:39 AM
I just checked my code, but there isn't any of that code.

coolstar
13 Jan 2010, 6:41 AM
It happens to be in the ux. Let me try it out.

coolstar
13 Jan 2010, 6:44 AM
I changed the code to afterrender, but there still is no codemirror displaying in firefox. It displays in chrome, however.

mschwartz
13 Jan 2010, 6:45 AM
I changed the code in the first post to use afterrender.

I never tested this under 3.1, there must be some subtle difference in how the events are done.

mschwartz
13 Jan 2010, 6:46 AM
I changed the code to afterrender, but there still is no codemirror displaying in firefox. It displays in chrome, however.

It displayed in Chrome for me before you changed the code...

Let me look at something...

coolstar
13 Jan 2010, 6:48 AM
The code change probably didn't do anything much.

mschwartz
13 Jan 2010, 6:48 AM
Try the new code in the 1st post.

Replace the whole ux.

coolstar
13 Jan 2010, 6:49 AM
Let me check for a second.

mschwartz
13 Jan 2010, 6:50 AM
I deferred the instantiation of the codemirror editor by a tad.

coolstar
13 Jan 2010, 6:51 AM
This is the error when I replace the ux:

this.initialConfig is undefined

mschwartz
13 Jan 2010, 6:55 AM
me.initialConfig

I'm seeing some weirdness in firebug though.

I set a breakpoint in render: function() ...

As I step into, it suddenly jumps to codemirror insert() function and the stack is messed up. It has something to do with ExtJS swfobject.

Maybe there's something about the order you're doing things...

coolstar
13 Jan 2010, 6:58 AM
I just updated the demo, so you can see some of the changes we made.

AndreaCammarata
13 Jan 2010, 7:03 AM
This is a very usefull component congratulation :)
However i found a bug if I try to write this XML document.


<?xml version="1.0" ?>
<test>
<element>
<child>
<![CDATA[
Hello
]]>
</child>
</element>
</test>


As you see the CDATA content is not weel formatted and the tab key is locked.
Did you already notice it?
Thanks</SPAN>

mschwartz
13 Jan 2010, 7:06 AM
I'm not seeing the code changes, even after clearing my browser cache.

On line 24 of CodeMirror.js, in render: function() {...

I set a breakpoint

I open the code editor

It hits the breakpoint

I click on "run" button

And it renders every time.

However, I'm seeing all kinds of errors. Many PHP errors, it's fetching your 404 page, a few javascript errors too.

Here's one:

Syntax error
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML ...> 404 (line 1)

mschwartz
13 Jan 2010, 7:08 AM
It works perfect in FF 3.0 under windows XP...

wow

coolstar
13 Jan 2010, 7:14 AM
When I run the thing locally, I don't get any php errors.

mschwartz
13 Jan 2010, 7:15 AM
Is it possible to temporarily strip out most of the code in your demo to just have the desktop and the code mirror app?

I mean, don't even load any .js files for other 3rd party extensions...

coolstar
13 Jan 2010, 7:16 AM
I can do that. Hold on for a few minutes.

coolstar
13 Jan 2010, 7:20 AM
I stripped out most of the code except the desktop, and Program Coder window.

mschwartz
13 Jan 2010, 7:29 AM
When I run the thing locally, I don't get any php errors.

I see about 5 of them.

Can you use ext-all-debug.js and ext-core-debug.js so I can see the stack proper?

Alan Heywood
14 Jan 2010, 11:44 PM
Thanks for this great plugin. There is one section that is causing an error in IE8, since forEach is not supported. Once I made the change below it started working fine in Internet Explorer.


this.on({
resize: function(ta, width, height) {
var el = Ext.select('.' + this.id, true);
if (el) {
//width -= 35;

for (var i=0; i< el.elements.length; i++)
{
el.elements[i].setSize(width, height);
}

/* Doesn't work in ie8.
el.elements.forEach(function(e) {
e.setSize(width, height);
});*/
}

mschwartz
15 Jan 2010, 6:07 AM
Thanks for this great plugin. There is one section that is causing an error in IE8, since forEach is not supported. Once I made the change below it started working fine in Internet Explorer.


this.on({
resize: function(ta, width, height) {
var el = Ext.select('.' + this.id, true);
if (el) {
//width -= 35;

for (var i=0; i< el.elements.length; i++)
{
el.elements[i].setSize(width, height);
}

/* Doesn't work in ie8.
el.elements.forEach(function(e) {
e.setSize(width, height);
});*/
}


LOL @ IE

It's better form to do something like this:


for (var i=0,len=el.elements.length; i<len; i++) {
...


So it doesn't have to evaluate the length each time through the loop.

coolstar
20 Jan 2010, 8:26 PM
I finally got codemirror to work cross-browser.

Here is the code:
CodeMirror.js:


Ext.namespace('Ext.ux.form');

Ext.ux.form.CodeMirror = Ext.extend(Ext.form.TextArea, {
language: 'txt',
codeMirrorPath: null, // should be path to code mirror on your server!
initComponent: function() {
if (this.codeMirrorPath === null) {
throw 'Ext.ux.form.CodeMirror: codeMirrorPath required';
}
this.initialized = false;
Ext.ux.form.CodeMirror.superclass.initComponent.apply(this, arguments);
this.addEvents('initialize');
this.on({
resize: function(ta, width, height) {
var el = Ext.select('.'+this.id, true);
if (el){
//width -= 35;

for (var i=0; i< el.elements.length; i++)
{
el.elements[i].setSize(width, height);
}
}
if (el) {
width -= 35;
/* Doesn't work in ie.
el.elements.forEach(function(e) {
e.setSize(width, height);
});*/
}
},
afterrender: function() {
var parser, stylesheet;
switch (this.language.toLowerCase()) {
case 'css':
parser = 'parsecss.js';
stylesheet = this.codeMirrorPath+'/css/csscolors.css';
break;
case 'js':
parser = ['tokenizejavascript.js', 'parsejavascript.js'];
stylesheet = this.codeMirrorPath+'/css/jscolors.css';
break;
case 'php':
parser = [
"parsexml.js",
"parsecss.js",
"tokenizejavascript.js",
"parsejavascript.js",
"../contrib/php/js/tokenizephp.js",
"../contrib/php/js/parsephp.js",
"../contrib/php/js/parsephphtmlmixed.js"
];
stylesheet = [
this.codeMirrorPath+'/css/xmlcolors.css',
this.codeMirrorPath+'/css/jscolors.css',
this.codeMirrorPath+'/css/csscolors.css',
this.codeMirrorPath+'/contrib/php/css/phpcolors.css'
];
break;
case 'htm':
case 'html':
case 'xml':
parser = 'parsexml.js';
stylesheet = 'xmlcolors.css';
break;
default:
parser = 'parsedummy.js';
stylesheet = '';
break;

}
var me = this;
(function() {
me.codeEditor = new CodeMirror.fromTextArea(me.id, {
parserfile: parser,
stylesheet: stylesheet,
path: me.codeMirrorPath+'/js/',
textWrapping: false,
lineNumbers: true,
iframeClass: 'codemirror-iframe '+me.id,
content: this.value,
initCallback: function() {
me.initialized = true;
me.fireEvent('initialize', true);
}
});
}).defer(100);
}
});
},
getValue: function() {
if (this.initialized) {
return this.codeEditor.getCode();
}
return this.value;
},
setValue: function(v) {
if (this.initialized) {
this.codeEditor.setCode(v);
}
},
validate: function() {
this.getValue();
Ext.ux.form.CodeMirror.superclass.validate.apply(this, arguments);
}
});
Ext.reg('ux-codemirror', Ext.ux.form.CodeMirror);

imnederland
27 Jan 2010, 4:21 AM
Thanks for the great extension. I did a minor update. In order to edit html/xml, I had to change the lines:


case 'xml':
parser = 'parsexml.js';
stylesheet = 'xmlcolors.css';

to:


case 'xml':
parser = 'parsexml.js';
stylesheet = this.codeMirrorPath + '/css/xmlcolors.css';

moegal
6 Feb 2010, 5:06 AM
Hi, I am using it with 2.3 and it works fine except for 1 problem in IE7(I have not tried IE8 yet).

I am opening a new tab and adding the form there, when I close the tab I get the following error.

"Object required"

Any suggestions?

Thanks, Marty

PS: I did not use afterrender, render works.

coolstar
6 Feb 2010, 4:11 PM
Notice that this is a 3.* forum, so we might not be able to help you much. Besides, the component is for 3.*

meisong
7 Feb 2010, 10:08 PM
very nice!

peterrr73
17 Feb 2010, 12:19 AM
Folks
Like many, I am immensely impressed with CodeMirror.
But, one thing I would like to do and can't figure how: I want to change the font for the display in the editor window (Ie: the font which appears in the <textarea> element in the html). I have tried changing in various places in the css files addressed by code mirror: no dice. Help please!
Peter

knowledgeVirtue
19 Apr 2010, 6:25 AM
Hi,

I need to add keypress listener to the codemirror. I've done like this but nothing happens:


xtype: 'ux-codemirror',
codeMirrorPath: 'path_to_codemirror_on_server',
language: 'js', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
enableKeyEvents: true,
listeners: { // optional
init: function() {
},
'keypress': {
fn: function(t){
alert("hello");
}
}
}

mschwartz
19 Apr 2010, 7:32 AM
Folks
Like many, I am immensely impressed with CodeMirror.
But, one thing I would like to do and can't figure how: I want to change the font for the display in the editor window (Ie: the font which appears in the <textarea> element in the html). I have tried changing in various places in the css files addressed by code mirror: no dice. Help please!
Peter

You specify the font in the CSS file loaded by code mirror in its IFRAME.

mschwartz
19 Apr 2010, 7:33 AM
Hi,

I need to add keypress listener to the codemirror. I've done like this but nothing happens:


xtype: 'ux-codemirror',
codeMirrorPath: 'path_to_codemirror_on_server',
language: 'js', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
enableKeyEvents: true,
listeners: { // optional
init: function() {
},
'keypress': {
fn: function(t){
alert("hello");
}
}
}



Code Mirror is replacing the textarea with its own HTML stuff in the DOM, including an IFRAME. Your listener would apply to the textarea, not Code Mirror's iframe!

knowledgeVirtue
19 Apr 2010, 8:14 AM
Oh ok....so is there a way to add keypress to codemirror?

mschwartz
19 Apr 2010, 8:52 AM
Oh ok....so is there a way to add keypress to codemirror?

Look at the code mirror sources and documentation. I know they handle ^S to save files...

Alan Heywood
19 Apr 2010, 3:20 PM
You can specify saveFunction in the codemirror config to capture Ctrl-S. I've added



,saveFunction: function() {
me.fireEvent('save', true);
}


to the plugin after initCallback, you can then hook into the save event of the plugin.

Zerogiven
14 May 2010, 12:49 AM
i changed a few stuff to get it working in air :)
(for those who's interested about):

I also implemented four methods: showCodeMirror, hideCodeMirror, setTextareaValue, getTextareaValue
and three new propertys: codeMirrorHidden, initCallBackFn, onResize

show/hideCodeMirror:
Two methods for viewing the textarea or the codemirror iframe. Note: Data inside codemirror will be shown inside the text area as raw data.

set/getTextareaValue:
You don't need this two functions cause set/getValue looks if codemirror is hidden and which function is needed to set the value.

codeMirrorHidden: Property to get the hidden state from a field
initCallBackFn: a function which will be called right after this.initialized will be set to true
onResizeCallBackFn: you may not need that but if you want you can have your own resize callback function



Ext.namespace('Ext.ux.form');

Ext.ux.form.CodeMirror = Ext.extend(Ext.form.TextArea, {
language: 'txt',
codeMirrorHidden: false,
codeMirrorPath: null, // should be path to code mirror on your server!

initCallBackFn: null, // Executes right after the init from codemirror
onResizeCallBackFn: null, // If we need our own resize function

initComponent: function() {
if (this.codeMirrorPath === null) {
throw 'Ext.ux.form.CodeMirror: codeMirrorPath required';
}
this.initialized = false;
Ext.ux.form.CodeMirror.superclass.initComponent.apply(this, arguments);
this.addEvents('initialize');
this.on({
resize: function(ta, width, height) {
if (this.onResizeCallBackFn)
this.onResizeCallBackFn(this);
else {
var el = Ext.select('.'+this.id, true);
var lineNumbersEl = Ext.select("."+this.id+" ~ div", true); // the lineNumbersEl is always the next div from the iframe

// Sometimes it happens in air that width or height from the resize event is undefined...
if (!width)
width = ta.getWidth();
if (!height)
height = ta.getHeight();
//...but we got it back from the container

if (el){
// If we find the lineNumbersEl we subtract the width
if ( this.initialized && !this.codeMirrorHidden && count(lineNumbersEl.elements) > 0 && width )
width = width - lineNumbersEl.elements[0].getWidth();

for (var i=0; i< el.elements.length; i++)
{
// It should not but it could be that the width or height is undefined.. i realy have no plan why this
// happens in Air. However we set what isn't undefined
if (width)
el.elements[i].setWidth(width);
if (height)
el.elements[i].setHeight(height);

// On resize we set the height for the line numbers element too
lineNumbersEl.elements[i].setHeight(height);
}
}
}
},
afterrender: function() {
var parser, stylesheet;
switch (this.language.toLowerCase()) {
case 'json':
parser = ['tokenizejson.js', 'parsejson.js'];
stylesheet = this.codeMirrorPath+'/css/jsoncolors.css';
break;
case 'css':
parser = 'parsecss.js';
stylesheet = this.codeMirrorPath+'/css/csscolors.css';
break;
case 'js':
parser = ['tokenizejavascript.js', 'parsejavascript.js'];
stylesheet = this.codeMirrorPath+'/css/jscolors.css';
break;
case 'php':
parser = [
"parsexml.js",
"parsecss.js",
"tokenizejavascript.js",
"parsejavascript.js",
"../contrib/php/js/tokenizephp.js",
"../contrib/php/js/parsephp.js",
"../contrib/php/js/parsephphtmlmixed.js"
];
stylesheet = [
this.codeMirrorPath+'/css/xmlcolors.css',
this.codeMirrorPath+'/css/jscolors.css',
this.codeMirrorPath+'/css/csscolors.css',
this.codeMirrorPath+'/contrib/php/css/phpcolors.css'
];
break;
case 'htm':
case 'html':
case 'xml':
parser = 'parsexml.js';
stylesheet = this.codeMirrorPath + '/css/xmlcolors.css';
break;
default:
parser = 'parsedummy.js';
stylesheet = '';
break;

}
var me = this;
(function() {
me.codeEditor = new CodeMirror.fromTextArea(me.id, {
parserfile: parser,
stylesheet: stylesheet,
path: me.codeMirrorPath+'/js/',
/*textWrapping: true,
autoMatchParens: true,
lineNumbers: true,*/
//continuousScanning: true,
/*passDelay: 100,
passTime: 50,
lineNumberDelay: 1000,
lineNumberTime: 50,*/
iframeClass: 'codemirror-iframe '+me.id,
content: this.value,
/*parserConfig: {
json: true
},
lang: me.language.toLowerCase(),*/
initCallback: function() {
me.initialized = true;
me.fireEvent('initialize', true);

if (me.initCallBackFn != null)
me.initCallBackFn(me);

if (me.codeMirrorHidden)
me.hideCodeMirror();
}
});
}).defer(100);
}
});
},
getValue: function() {
if (this.initialized) {
if ( this.codeMirrorHidden )
return this.getTextareaValue();
else
return this.codeEditor.getCode();
}
return this.value;
},
setValue: function(v) {
if (this.initialized) {

if (this.codeMirrorHidden)
this.setTextareaValue(v)
else
this.codeEditor.setCode(v);
}
},
getTextareaValue : function(){
if(!this.rendered) {
return this.value;
}
var v = this.el.getValue();
if(v === this.emptyText || v === undefined){
v = '';
}
return v;
},
setTextareaValue : function(v){
if(this.emptyText && this.el && !Ext.isEmpty(v)){
this.el.removeClass(this.emptyClass);
}
Ext.form.TextField.superclass.setValue.apply(this, arguments);
this.applyEmptyText();
this.autoSize();
return this;
},
hideCodeMirror: function () {
var me = this;
var iframeEl = Ext.select('.'+this.id, true);
var textareaEl = Ext.select("textarea#" + me.id, true);

textareaEl.setVisibilityMode(Ext.Element.DISPLAY);
iframeEl.setVisibilityMode(Ext.Element.DISPLAY);

me.setTextareaValue( me.getValue() );

iframeEl.setVisible(false);
textareaEl.setVisible(true);

me.codeMirrorHidden = true;
},
showCodeMirror: function () {
var me = this;
var iframeEl = Ext.select('.'+this.id, true);
var textareaEl = Ext.select("textarea#" + me.id, true);

textareaEl.setVisibilityMode(Ext.Element.DISPLAY);
iframeEl.setVisibilityMode(Ext.Element.DISPLAY);

textareaEl.setVisible(false);
iframeEl.setVisible(true);

me.codeMirrorHidden = false;

me.setValue( this.getTextareaValue() );
me.setTextareaValue( '' );
},
validate: function() {
this.getValue();
Ext.ux.form.CodeMirror.superclass.validate.apply(this, arguments);
}
});
Ext.reg('ux-codemirror', Ext.ux.form.CodeMirror);

N1 work @mschwartz!

cheers
Chris

Stju
12 Jul 2010, 8:41 AM
Excellent and handy component!
Any way to paste some code dynamically at cursor position in already rendered CodeMirror panel?

Ronaldo
29 Jul 2010, 11:28 AM
Hi all,

Like many, I *love* this thingy.
Unfortunately, I'm using codemirror 0.8 now (Ext 3.2.1), and I still have a limited set of line numbers...
I noticed in firebug that every height is changed when I drag firebug up and down to resize the viewport but the height of the div with class="CodeMirror-wrapping" remains the same height... Changing that height manually in firebug fixes the line height issue for me.
In code, it means:


Ext.ux.form.CodeMirror = Ext.extend(Ext.form.TextArea, {
...
this.on({
resize: function(ta, width, height) {
var el = Ext.select('.'+this.id, true);
if (el) {
Ext.select(".CodeMirror-wrapping").setSize(width,height);
width -= 35;
el.elements.forEach(function(e) {
e.setSize(width, height);
});
}
},
afterrender: function() {
....

I'll have to check if this works if you have multiple codemirror editors in different tabs for example (Not sure if the selector gets them all as I haven't used the selector before.


Ronaldo

Stju
29 Jul 2010, 11:43 AM
Check this thread: http://www.sencha.com/forum/showthread.php?89795-Ext.ux.panel.CodeMirror
I am using that extension version. Can confirm, that it works with latest CodeMirror revision, line numbers are correct, and it correctly behaves in multiple instances , even in multiple tabs!

21728

GeorgeGG
27 Aug 2010, 2:32 AM
Hello,

I made a form with a textfield and 3 codemirror fields. I want to be able to submit that form with the code in every codemirror field,
but I was unable to do so.

Here is my code...



Ext.ns('Code')

Code.Window = function(){
var form = new Ext.form.FormPanel({
id: 'CodeForm',
frame: true,
plugins: [new Escape.plugin.Negotiable()],
items: [
{
border:false,
layout: 'form',
labelWidth:60,
items:[
new Ext.form.TextField({
name: 'name',
fieldLabel: Escape.util.Dictionary.Translate('Name'),
allowBlank: true,
msgTarget: 'side',
anchor: '-20'
})
]
},
{
xtype: 'tabpanel',
border: false,
id: 'MalfunctionCreateFormTabpanel',
anchor: '100% -30',
deferredRender: false,
plain: true,
activeTab: 0,
defaults: {
border: false,
layout: 'form'
},
items: [{
title: Escape.util.Dictionary.Translate('Html'),
iconCls: 'html-icon',
layout: 'fit',
frame: true,
hideMode: 'offsets',
bodyStyle: 'background-color: #cedef0;',
items:{
xtype: 'ux-codemirror',
name: 'html',
codeMirrorPath: 'js/ext/ux/codemirror/CodeMirror-0.8',
language: 'html', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
listeners: { // optional
init: function() {
}
}
}
},
{
title: Escape.util.Dictionary.Translate('Javascript'),
iconCls: 'js-icon',
layout: 'fit',
frame: true,
hideMode: 'offsets',
bodyStyle: 'background-color: #cedef0;',
items:{
xtype: 'ux-codemirror',
name: 'js',
codeMirrorPath: 'js/ext/ux/codemirror/CodeMirror-0.8',
language: 'js', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
listeners: { // optional
init: function() {
}
}
}
},
{
title: Escape.util.Dictionary.Translate('PHP'),
iconCls: 'php-icon',
layout: 'fit',
frame: true,
hideMode: 'offsets',
bodyStyle: 'background-color: #cedef0;',
items:{
xtype: 'ux-codemirror',
name: 'php',
codeMirrorPath: 'js/ext/ux/codemirror/CodeMirror-0.8',
language: 'php', // possibilities: 'js', 'css', 'php', 'htm', 'html', 'xml', anything else is plain text
listeners: { // optional
init: function() {
}
}
}
}
]
}],
monitorValid: true,
buttons: [{
text: Escape.util.Dictionary.Translate('Save'),
iconCls: 'save-icon',
formBind: true,
handler: function(){
form.getForm().submit({
url: 'test_json.php',
params:{
cmd: 'save'
},
waitMsg: Escape.util.Dictionary.Translate('Please wait'),
success: function(f, action){
Ext.WindowMgr.getActive().destroy();
Ext.myMsg.msg(Escape.util.Dictionary.Translate('Success'), action.result.message, 'success');
},
failure: function(f, action){
Ext.Msg.show({
title: Escape.util.Dictionary.Translate('Error'),
msg: 'Error',
modal: true,
icon: Ext.Msg.ERROR,
buttons: Ext.Msg.OK
});
}
});
}
}, {
text: Escape.util.Dictionary.Translate('Cancel'),
iconCls: 'cancel-icon',
handler: function(){
Ext.WindowMgr.getActive().destroy();
}
}]
});
form.on({
afterlayout:{
single: true,
fn: function(){
this.getForm().load({
url: 'test_json.php',
waitTitle:Escape.util.Dictionary.Translate('Loading'),
waitMsg: Escape.util.Dictionary.Translate('Please wait'),
params: {
cmd: 'load'
}
});
}
},
actioncomplete:{
fn: function(f, a){
if(a.type == 'load'){

}
}
}
});

var win = new Ext.Window({
title: String.format('{0} - {1}', Escape.util.Dictionary.Translate('Code'), Escape.util.Dictionary.Translate('Edit')),
iconCls: 'code-icon',
width: 700,
height: 480,
layout: 'fit',
closable: true,
resizable: true,
modal: true,
shadow: false,
border: false,
bodyStyle: 'background-color: #cedef0;',
items: form,
listeners: {
'beforedestroy': function(){
}
},
tools: [
{
id:'maximize',
handler: function(e, target, window){
window.toggleMaximize();
}
},
{
id:'close',
handler: function(e, target, window){
window.destroy();
}
}
]
});
return win;
}



I use extjs 3.2.1 on mac os x and codemirror 0.8
I don't get any errors but I don't see any post in firebug at all.

Any ideas???
Please help

mschwartz
27 Aug 2010, 5:34 AM
Here is the latest code I've been using. No problems with line numbers, pasting into the editor, etc.




Ext.namespace('Ext.ux.form');

Ext.ux.form.CodeMirror = Ext.extend(Ext.form.TextArea, {
language: 'txt',
hideLabel: true,
codeMirrorPath: 'path/to/CodeMirror-0.8', // <---- change this!
initComponent: function() {
if ( this.codeMirrorPath === null ) {
throw 'Ext.ux.form.CodeMirror: codeMirrorPath required';
}
this.codeEditor = null;
this.initialized = false;
this.initialWidth = 0;
this.initialHeight = 0;
if ( this.hideLabel ) {
this.separator = '';
}
Ext.ux.form.CodeMirror.superclass.initComponent.apply(this, arguments);
this.addEvents('initialize');
this.on({
resize: function(ta, width, height) {
if ( Ext.isNumber(width) ) {
width -= 50;
}
if ( !this.initialized ) {
this.initialWidth = width;
this.initialHeight = height;
}
else if ( this.codeEditor ) {
width = width || this.initialWidth;
height = height || this.initialHeight;
var el = Ext.get(this.codeEditor.wrapping);
el.setSize(width, height);
// Ext.get(this.id).setSize(width, height);
}
return true;
},
render: function() {
var parser, stylesheet;
switch (this.language.toLowerCase()) {
case 'css':
parser = 'parsecss.js';
stylesheet = this.codeMirrorPath + '/css/csscolors.css';
break;
case 'js':
parser = [
'tokenizejavascript.js',
'parsejavascript.js'
];
stylesheet = this.codeMirrorPath + '/css/jscolors.css';
break;
case 'php':
parser = [
"parsexml.js",
"parsecss.js",
"tokenizejavascript.js",
"parsejavascript.js",
"../contrib/php/js/tokenizephp.js",
"../contrib/php/js/parsephp.js",
"../contrib/php/js/parsephphtmlmixed.js"
];
stylesheet = [
this.codeMirrorPath + '/css/xmlcolors.css',
this.codeMirrorPath + '/css/jscolors.css',
this.codeMirrorPath + '/css/csscolors.css',
this.codeMirrorPath + '/contrib/php/css/phpcolors.css'
];
break;
case 'htm':
case 'html':
case 'xml':
parser = 'parsexml.js';
stylesheet = this.codeMirrorPath + '/css/xmlcolors.css';
break;
default:
parser = 'parsedummy.js';
stylesheet = 'path/to/codemirror-text.css'; // <-- change this
break;

}
var me = this;
this.codeEditor = new CodeMirror.fromTextArea(this.id, {
saveFunction: this.initialConfig.saveFn || undefined,
parserfile: parser,
stylesheet: stylesheet,
path: this.codeMirrorPath + '/js/',
textWrapping: false,
lineNumbers: true,
iframeClass: 'codemirror-iframe ' + this.id,
content: this.initialConfig.value,
initCallback: function() {
me.initialized = true;
(function() {
if ( me.codeEditor ) {
var el = Ext.get(me.codeEditor.wrapping);
el.setSize(me.initialwidth, me.initialHeight);
Ext.get(me.id).setSize(me.initialWidth, me.initialHeight);
}
}).defer(10);
me.fireEvent('initialize', true);
}
});

}
});
},
getValue: function() {
if ( this.initialized ) {
return this.codeEditor.getCode();
}
return this.initialConfig.value;
},
setValue: function(v) {
if ( this.initialized ) {
this.codeEditor.setCode(v);
}
},
validate: function() {
this.getValue();
Ext.ux.form.CodeMirror.superclass.validate.apply(this, arguments);
}
});
Ext.reg('ux-codemirror', Ext.ux.form.CodeMirror);

GeorgeGG
30 Aug 2010, 5:47 AM
Thanks for your quick reply but even with your code the form doesn't submit anything.

Thanks in advance.
Georgegg

mschwartz
30 Aug 2010, 7:26 AM
it needs to call the parent's getValue and setValue methods in those functions. Something like the line in validate:



Ext.ux.form.CodeMirror.superclass.validate.apply(this, arguments);


e.g. put this line before the "if" in getValue():



Ext.ux.form.CodeMirror.superclass.getValue.apply(this, arguments);


and similarly for setValue.

Let me know if that fixes it for you.

I've never had a need to submit the contents as part of a form.

GeorgeGG
30 Aug 2010, 8:27 AM
Thought so myself and tried that before, but no luck!!!
I want to use codemirror to edit some files in my project file system,
so I was thinking to get/send the data via Ajax. If you can suggest a petter way I would appreciate that.

Thanks again for your -yet again- super-fast response.. :-)

Georgegg

mschwartz
30 Aug 2010, 9:04 AM
Unless I'm doing a file upload, I never submit forms. I serialize them myself and use Ext.Ajax.request(). In the process of serializing them, I also do validation and other error checking.

I think what I posted is wrong, about the super class stuff.

You have to get the value from codemirror, then call the superclass method with that value.

Something like this, completely untested:



var value = this.codeEditor.getCode(); // Change this.name to this.id
Ext.ux.form.CodeMirror.superclass.setValue.apply(this, [value]);
return Ext.ux.form.CodeMirror.superclass.getValue.call(this); // Change getValue(this) to

GeorgeGG
30 Aug 2010, 11:35 PM
Thanks a lot!!!
I' ll try that later this day and I'll let you know if it works.

Georgegg

GeorgeGG
31 Aug 2010, 2:17 AM
After I played around with your code with no success, I think I ll try to find an other way to pass my data (Like manual serialization of the form).

Thanks a lot anyway.
Georgegg

mschwartz
31 Aug 2010, 5:03 AM
Did you try stepping into the superclass' setValue() method? I'm pretty sure it's putting the contents of the code editor into the text area so it should submit fine.

You also need to do something similar in the setValue() method.

GeorgeGG
31 Aug 2010, 6:24 AM
Did you try stepping into the superclass' setValue() method? I'm pretty sure it's putting the contents of the code editor into the text area so it should submit fine.

You also need to do something similar in the setValue() method.

Since I want this to act as a normal form field, I think I need to step into a lot of thing.
I am trying to rewrite a bit of your code so that the editor is just the medium for the textarea's content.
I think (regardless my not-to-much-ext-experience) I think with the onChange method of the editor I ll be able to do so.
Thus I think the submission and validation of the form (which are most of my problems) will be working just fine.


I ll do my best and I ll let you know if I did this.
Thanks a lot
Georgegg

mschwartz
31 Aug 2010, 6:50 AM
This code extends Ext.form.TextArea, so for all intents and purposes it is a textarea and should submit like one. What ExtJS is doing is creating an actual textarea element, and codemirror is hiding that element. When you submit your form, the ExtJS textarea's content needs to have the content of the codemirror editor.

If you're going to update the textarea content in the onChange method of the editor, I think it may be a really slow operation. The strings involved could be rather long...

Perhaps a better approach is to implement a syncValue() method that copies the text from the editor into the textarea and call it before you submit, call it from the validate() function, etc.

GeorgeGG
31 Aug 2010, 7:56 AM
This code extends Ext.form.TextArea, so for all intents and purposes it is a textarea and should submit like one. What ExtJS is doing is creating an actual textarea element, and codemirror is hiding that element. When you submit your form, the ExtJS textarea's content needs to have the content of the codemirror editor.

If you're going to update the textarea content in the onChange method of the editor, I think it may be a really slow operation. The strings involved could be rather long...

Perhaps a better approach is to implement a syncValue() method that copies the text from the editor into the textarea and call it before you submit, call it from the validate() function, etc.

Yes I totally agree with you but the bind button in the validation process won't work (correct me if I'm wrong..).

Ian Young
11 Oct 2010, 9:50 PM
I added this to the validate function, and it seems to work.


validate: function() {
this.getValue();
Ext.ux.form.CodeMirror.superclass.validate.apply(this, arguments);
var value = this.codeEditor.getCode();
var area = Ext.get(this.id);
area.dom.value = value;
return true; //just going to assume this is valid.
}

tot2ivn
18 Oct 2010, 9:53 PM
Nice ux man. I've implemented something like this before. Wrapping CodeMirror around by an Ext field.
However, CodeMirror (0.8 I tried) is still buggy in showing pointer cursor cross-browser.. so I dropped CodeMirror.

Will try your ext and let you know. :D

dorramide7
19 Oct 2010, 3:19 PM
codemirror 0.65 has that error with the line numbers.

If you can download 0.63, use that.
Do you have any idea what might be causing CTRL+V to duplicate text in this componente?

thanks!

mschwartz
20 Oct 2010, 6:22 AM
Do you have any idea what might be causing CTRL+V to duplicate text in this componente?

thanks!

One of my coworkers found a bug in the codemirror code and posted the fix on their google group. You can find it there. I don't know exactly what the fix was off the top of my head ;)

uwolfer
8 May 2014, 10:22 PM
You can find an updated and extended version of this extension which works fine with CodeMirror 4.1.0 here:

https://github.com/tocco/extjs3-codemirror-extension