【ExtJs】Ext.form.CKEditor:整合CKEditor的组件
CKEditor是一个出色的所见即所得的富文本编辑器,相比ExtJs原生的htmleditor要强大很多,于是把CKEditor集成到ExtJs中便是一个很好的选择。
从ExtJs官方论坛找到了整合的实例,不过其中的问题不少,比如组件setValue、isDiry等方法无法得到正确的结果。经过改造,修正了以上问题,并将CKFinder做了整合,同时增加了对CKEditor工具栏选择配置的支持。
修改后的Ext.form.CKEditor组件源码如下:
/****************************************************
* CKEditor Extension
* by Maple Nan 2010.7.21
* http://witmax.cn/extjs-ckeditor.html
*****************************************************/
Ext.form.CKEditor = function(config){
this.config = config;
Ext.form.CKEditor.superclass.constructor.call(this, config);
};
Ext.form.CKEditor.CKEDITOR_CONFIG = "/ckeditor/config.js";
Ext.form.CKEditor.CKEDITOR_TOOLBAR = "Default";
Ext.extend(Ext.form.CKEditor, Ext.form.TextArea, {
onRender : function(ct, position){
if(!this.el){
this.defaultAutoCreate = {
tag: "textarea",
autocomplete: "off"
};
}
Ext.form.TextArea.superclass.onRender.call(this, ct, position);
var config = {
customConfig: Ext.form.CKEditor.CKEDITOR_CONFIG
//,toolbar: Ext.form.CKEditor.CKEDITOR_TOOLBAR // 如需要默认工具条设置,请去掉行前注释
};
Ext.apply(config, this.config.CKConfig);
var editor = CKEDITOR.replace(this.id, config);
CKFinder.setupCKEditor( editor, './ckfinder/' ) ;
},
onDestroy: function(){
if (CKEDITOR.instances[this.id]) {
delete CKEDITOR.instances[this.id];
}
},
setValue : function(value){
Ext.form.TextArea.superclass.setValue.apply(this,[value]);
CKEDITOR.instances[this.id].setData( value );
},
getValue : function(){
CKEDITOR.instances[this.id].updateElement();
var value=CKEDITOR.instances[this.id].getData();
Ext.form.TextArea.superclass.setValue.apply(this,[value]);
return Ext.form.TextArea.superclass.getValue.apply(this);
},
getRawValue : function(){
CKEDITOR.instances[this.id].updateElement();
return Ext.form.TextArea.superclass.getRawValue(this);
},
isDirty : function() {
if(this.disabled) {
return false;
}
var value = String(this.getValue()).replace(/\s/g,'');
value = (value == "<br />" || value == "<br/>" ? "" : value);
this.originalValue = this.originalValue || "";
this.originalValue = this.originalValue.replace(/\s/g,'');
return String(value) !== String(this.originalValue) ? String(value) !== "<p>"+String(this.originalValue)+"</p>" : false;
}
});
Ext.reg('ckeditor', Ext.form.CKEditor);
由于Ext.form.CKEditor组件的特殊性,需要重写Ext.form.BasicForm组件的一些方法,对Ext.form.CKEditor组件提供特殊的支持,Ext.form.BasicForm组件重写部分源码如下:
// Add methods to the BasicForm that clears the isDirty flag to return "false" again.
Ext.override(Ext.form.BasicForm,{
/**
* clear the value of all items in BasicForm and set originalValue to ''
* @param {Object} o
*/
clearValues: function(o){
o = o || this;
o.items.each(function(f){
if(f.items){
this.clearValues(f);
} else if(f.setValue){
f.setValue('');
// ckeditor needs being treated specially, or an error will appear in IE
if (f.getXType() == "ckeditor"){
f.originalValue = '';
}
else if (f.getValue){
f.originalValue = f.getValue();
}
}
}, this);
this.clearInvalid();
}
/**
* clear isDirty flag of all items of BasicForm
* @param {Object} o
*
* reference: http://www.extjs.com/forum/showthread.php?t=40568
*/
,clearDirty : function(o){
o = o || this;
o.items.each(function(f){
if(f.items){
this.clearDirty(f);
} else if(typeof(f.originalValue) != "undefined" && f.getValue){ // Ext.isEmpty(f.originalValue) &&
f.originalValue = f.getValue();
}
}, this);
}
,setValues : function(values){
if(Ext.isArray(values)){ // array of objects
for(var i = 0, len = values.length; i < len; i++){
var v = values[i];
var f = this.findField(v.id);
if(f){
f.setValue(v.value);
// ckeditor is special
if (f.getXType() == "ckeditor"){
f.originalValue = v.value;
}
// checkboxgroup.originalValue won't be set, or it may cause a bug when reset
else if(this.trackResetOnLoad && typeof(f.originalValue) != "undefined" && f.getValue){
f.originalValue = f.getValue();
}
}
}
}else{ // object hash
var field, id;
for(id in values){
if(typeof values[id] != 'function' && (field = this.findField(id))){
field.setValue(values[id]);
if (this.trackResetOnLoad){
if (field.getXType() == "ckeditor"){
field.originalValue = values[id];
}
else if(typeof(field.originalValue) != "undefined" && field.getValue){
field.originalValue = field.getValue();
}
}
}
}
}
return this;
}
,findField : function(id){
var field = this.items.get(id);
if(!field){
this.items.each(function(f){
if(f.isXType('radiogroup')||f.isXType('checkboxgroup')){
if (f.isXType('radiogroup'))
f.unitedValue = true;
f.items.each(function(c){
if(c.isFormField && (c.dataIndex == id || c.id == id || c.getName() == id)){
field = f.unitedValue ? f : c;
if (typeof(f.trackResetOnLoad) == "undefined")
f.trackResetOnLoad = this.trackResetOnLoad;
return false;
}
}, this);
}
if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
field = f;
return false;
}
}, this);
}
return field || null;
}
});
组件使用方法:
{
xtype: 'ckeditor',
fieldLabel: 'Editor',
name: 'htmlcode',
CKConfig: {
/* Enter your CKEditor config paramaters here or define a custom CKEditor config file. */
customConfig : '/ckeditor/config.js',
toolbar: 'Other',
height : 200,
width: 250
}
}
说明:以上customConfig为CKEditor组件配置文件的绝对路径(使用相对路径好像有问题,会无效,暂不清楚原因),不设定时默认为/ckeditor/config.js,默认值设定可以通过对Ext.form.CKEditor.CKEDITOR_CONFIG重新赋值来完成,也可修改Ext.form.CKEditor组件源码的对应部分;toolbar为采用的CKEditor配置文件中工具栏配置的名词,对于CKEditor工具栏如何配置可参考FckEditor(CKEditor)配置,不设定时默认为Default,此项默认值可以通过重新赋值Ext.form.CKEditor.CKEDITOR_TOOLBAR来设定或修改Ext.form.CKEditor组件源码的对应部分;width、height对应为组件显示的宽和高。
完整实例源码下载ExtJs CKEditor插件,其中ckeditor、ckfinder及extjs都需位于站点根目录下,具体路径也可自行修改实例源码。
没用过~~一直用notepad++来着
[回复]
晴枫 2010年8月23日 20:29 回复:
@老饕, notepad++是桌面应用程序 CKEditor是网页版的的富文本编辑器,不一样
[回复]
大侠我好,你好大害,我好崇拜你。
另外问下怎么配置工具条。。
我弄了好久没弄明白。可以给点配置工具栏上按钮的代码吗
我的email :23444440@qq.com
谢谢了啊。。
[回复]
晴枫 2010年9月24日 17:17 回复:
@你好, 末尾增加一段说明,看是否对你有帮助
[回复]
很奇怪,关闭窗口时会出现container.getChild(…)的错误,
把onDestroy改成
var o = CKEDITOR.instances[this.id];
if (o) o.destroy();
就好了
[回复]
谢谢大侠的贡献!
问个问题:
在这个ckeditor中编辑文本之后,如何取得其文本呢?
对应的,怎么让它初始时显示特定的文本呢?
期待大侠的解答
[回复]
晴枫 2011年8月3日 19:35 回复:
@赵伟雄, 用法和其他的控件一样,比如textfield
[回复]
这个组件有个问题就是如果把这个组件放在window窗体中,第一次打开window窗体可以展示,如果关闭掉window窗口,然后重新打开,此时就无法打开window窗口了
[回复]
晴枫 2011年8月3日 19:37 回复:
@rar, 你需要设置window的closeAction为hide,使得窗口关闭后控件不被销毁
[回复]
我想问下 ,我用你说的把CKEditor集成到ExtJs中,但是我要给CKeditor添加附加组件的时候,(比如说行距),怎么样都没有反应,自定义插件也不行,是不是什么地方没有配置
[回复]
晴枫 2011年8月14日 23:40 回复:
@IT信任, 有可能插件引入没有生效,看看插件引入的配置代码是不是被执行到了
[回复]
如果加载数据,比如 myform.getForm().load({ ….
会提示错误
ckeditor.js ….. 16行
‘this.$.innerHTML’ 为空或不是对象
[回复]
晴枫 2011年8月14日 23:41 回复:
@测试我的, 应该是这时候组件还没有被渲染导致的,建议在load数据前让组件渲染好
[回复]
这个问题解决了,居然ID不能有下划线命名
[回复]
晴枫 2011年8月14日 23:41 回复:
@测试我的, 还有这样的问题 没碰到过
[回复]
新问题:在TABLPANEL的FROM中的编辑器,好像初始化有问题,也是加载数据的时候:
ext.form.CKEDITOR.JS 行 38
‘CKEDITOR.instances[...]‘ 为空或不是对象
在代码: setValue : function(value){
Ext.form.TextArea.superclass.setValue.apply(this,[value]);
CKEDITOR.instances[this.id].setData( value );
},
就是这行CKEDITOR.instances[this.id].setData( value );
出现问题
[回复]
晴枫 2011年8月14日 23:45 回复:
@测试我的, 应该是这时候组件还没有被渲染导致的,建议在load数据前让组件渲染好
[回复]
我也考虑过这个问题,通过按钮手工加载也不行,我在试试
[回复]
在TABPANEL 中的CKEDITOR 要激活选项才会被渲染的,郁闷,设置看deferredRender: false, 也没有用
[回复]
同过WINDOW加载的TABPANEL 中的CKEDITOR 居然没有问题,其他方式的不行
[回复]
终于解决了,要在代码里,把每个TAB激活后,在赋值
核心代码:
Ext.getCmp(“EditBaseinfotab”).setActiveTab(‘EditBaseinfotab4′);
Ext.getCmp(“wincomment”).setValue(fdata["wincomment"]);
‘EditBaseinfotab4′ 就是包含有ckeditor的TAB的 id, 希望对各位有帮助,在非window里加载TABPANEL 中的CKEDITOR 要激活选项才会被渲染的,设置deferredRender: false, 也没有用的,默认只会激活第一个TAB, 但是在window的TABPANEL 只要加了设置deferredRender: false, 所有的TAB项都被激活渲染的,到目前我也不明白原因。可能是Ext.form.CKEditor组件的问题,在渲染的时候要处理一下。
[回复]
还有忘记提醒了:不能用FORM.LOAD这种方式加载赋值,因为它是自动赋值的,只能通过侦听事件的方式,用Ext.Ajax.request来加载服务器数据,然后逐一赋值.
[回复]