现在来完成文章管理的编辑窗口。在开始之前,先去官方论坛一个名称为Ext.ux.form.TinyMCETextArea的扩展,地址是http://www.sencha.com/forum/showthread.php?198699。该扩展的作用是将TinyMCE封装为一个表单字段。TinyMCE则是一个所见即所得的HTML编辑器,相当好用的一个东西。
下载解压缩后,把TinyMCETextArea.js放到解决方案Scripts/ExtJS/ux/Form目录下,记得要创建Form目录,别直接放在ux目录下,因为类名中有一个form,根据类名规则,会在Form目录下找TinyMCETextArea.js文件,这个必须牢记。
在包目录里还有一个tinymce目录,里面包含了所有tinymce的脚本,把整个目录直接复制到scripts目录下。
现在切换到解决方案的首页文件,也就是index.cshtml文件,在添加swfupload引用的下面添加对tinymce的引用,代码如下:
<script type="text/javascript"src="@Url.Content("Scripts/tinymce/tiny_mce.js")"></script>
还要在postParams下添加一个全局的对象来对tinymce进行配置,这样可避免每次创建TinyMCETextArea都要写一次配置,代码如下:
SimpleCMS.tinyCfg = {
// 基本选项
theme:"advanced", //使用高级选项
language:"zh", //使用中文
skin:"extjs", //使用extjs的样式
inlinepopups_skin: "extjs",
inline_styles: true,
theme_advanced_row_height: 27,
delta_height: 0,
convert_urls : false,
relative_urls :true,
media_use_script:true,
//要添加那些插件
plugins:"autolink,lists,pagebreak,style,layer,table,advhr,advimage,advlink,inlinepopups,media,searchreplace,contextmenu,paste,directionality,noneditable,visualchars,nonbreaking,advlist",
// 样式选项,用来设置显示那些操作按钮
theme_advanced_buttons1: "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2:"cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,code,|,forecolor,backcolor",
theme_advanced_buttons3:"tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,media,advhr,|,ltr,rtl",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align:"left",
theme_advanced_statusbar_location: "bottom",
// 设置前台站点使用到的样式,这样样式会显示在样式列表中,这里没有,就没设置
//content_css: "Scripts/Extjs/ux/Form/site.css"
};
这里还有点小问题,现在下载的tinymce是不带语言包的,因而还要去http://www.tinymce.com/i18n/index.php?ctrl=lang&act=download&pr_id=1下载语言包,在页面中选择chinese,2012年10月16日更新的那个就好。下载后,把里面的langs、plugins和themes目录直接复制到解决方案中scripts/tinymce目录中就行了。
好了,准备工作做好了,现在开始编写编辑窗口,在scripts/app/view/Content目录下创建一个名称为ContentEdit.js的文件,文件内容与文章类别的其实差不多,可以复制过来做修改。
现在先看看表单上有那些字段。首先是ContentId,这个要用隐藏字段。接着是CategroyId,这个将使用与文章类别编辑窗口中的类别选择一样的下拉列表框。Title、Image和SrotOrder与文章类别中的状况一样。Summay和Content则需要使用TinyMCETextArea字段,而且为了便于编辑,分别用一个标签页来放置它。还要添加和Tags。
因为要用到标签页,因而要先在表单内添加一个标签控件。
和文章类别的编辑窗口区别不大,复制过来,修改一下就可以了,修改后的代码如下:
Ext.define("SimpleCMS.view.Content.ContentEdit",{
extend:"Ext.window.Window",
requires:["Ext.ux.Dialog.PicSelected","SimpleCMS.store.CategoriesCombo","Ext.ux.form.TinyMCETextArea"],
hideMode:'offsets',
closeAction: 'hide',
closable:true,
resizable: true,
layout: "fit",
title: '文章',
width:800,
height:600,
modal:true,
singleton: true,
bodyPadding: "0 0 10 0",
initComponent: function () {
varme = this;
me.form = Ext.create(Ext.form.Panel, {
border: false, bodyPadding: 5,layout:"fit",
bodyStyle: "background:#DFE9F6",
trackResetOnLoad: true,
fieldDefaults: {
labelWidth: 80, labelSeparator: ":", anchor: "0"
},
items: [
{ xtype: "tabpanel", activeTab: 0,
defaults: { xtype: "panel", border: false,
bodyPadding: 5,bodyStyle: "background:#DFE9F6"
},
items: [
{ title: "基本信息",layout: "anchor",
defaultType: "textfield",
items: [
{ xtype:"hidden", name: "ContentId" },
{ xtype: "textfield",fieldLabel: "标题",name: "Title", allowBlank: false },
{
xtype:"fieldcontainer", layout: "hbox", fieldLabel: "题图", defaults: { hideLabel: true },
items: [
{ xtype: 'textfield', flex: 1,name: "Image",
listeners: {
scope: me,
change: function(filed, newValue, oldValue) {
Ext.getCmp("ContentPreviewImage").setSrc(newValue);
}
}
},
{ xtype: "button",width: 80, text: "选择",
handler: function () {
var img =this.up("form").getForm().findField("Image");
Ext.ux.Dialog.PicSelected.imagePath = "upload";
Ext.ux.Dialog.PicSelected.ed = img;
Ext.ux.Dialog.PicSelected.show();
}
}
]
},
{
xtype: 'fieldset', title:"题图预览",height: 280, items: [
{ xtype: "image", id:"ContentPreviewImage" }
]
},
{
xtype: "combobox",fieldLabel: "文章类别",name: "CategroyId", allowBlank: false,
editable: true, shadow:false, mode: 'local', triggerAction: 'all', store: "categoriesCombo",
displayField:"text", valueField: "id", flex: 1, queryMode:"local",
listConfig: {
displayField:"listText"
}
},
{
xtype: 'numberfield',fieldLabel: "排序序数",name: "SortOrder", allowBlank: false
},
{
fieldLabel: "标签", name: "Tags",allowBlank: false
},
{
xtype: 'container', html:"**请使用英文逗号分隔标签",anchor: "0", padding: "0 0 0 80px"
}
]
},
{ title: "摘要",layout: "fit",
items: [
{ xtype: 'tinymce_textarea',
fieldStyle: 'font-family: Courier New;font-size: 12px;',
noWysiwyg: false,
tinyMCEConfig: SimpleCMS.tinyCfg,
name: 'Summary',
allowBlank: false
}
]
},
{ title: "内容",layout: "fit",
items: [
{ xtype: 'tinymce_textarea',
fieldStyle: 'font-family: Courier New;font-size: 12px;',
noWysiwyg: false,
tinyMCEConfig: SimpleCMS.tinyCfg,
name: 'Content',
allowBlank: false
}
]
}
]
}
],
dockedItems: [{
xtype: 'toolbar', dock: 'bottom', ui: 'footer', layout: { pack:"center" },
items: [
{ text: "保存", width: 80, disabled: true,formBind: true, handler: me.onSave, scope: me },
{ text: "重置", width: 80, handler:me.onReset, scope: me }
]
}]
});
me.items = [me.form];
me.callParent(arguments);
},
onReset:function () {
varme = this;
me.form.getForm().reset();
},
onSave:function () {
varme = this,
f= me.form.getForm();
if(f.isValid()) {
f.submit({
//waitMsg: "正在保存,请等待……",
//waitTitle: "正在保存",
success: function (form, action) {
var me = this;
},
failure: SimpleCMS.FormSubmitFailure,
scope: me
});
}
}
})
代码中,修改了类名,这是必须的。然后requires内添加了对Ext.ux.form.TinyMCETextArea的请求,不然不会自动下载扩展。如果想编辑区域更大点,可修改宽度和高度,在这里没有修改。
接着是在表单内添加了一个标签页,这里很关键一点,就是修改表单面板的布局,一定要改为Fit布局,不然标签页就不能完全填满表单面板的内容区域,会出现问题。
要保留字段的锚固布局,在基本信息标签页内的布局修改回anchor布局就行了,这样就让表单字段的表现与在表单面板内的表现没什么区别了。而对于摘要和内容两个标签页,则使用Fit布局,让TinyMCETextArea扩展自动填满标签页内容区域就行了。
在基本信息页中,记得修改预览图片的id,不然就和文章类别编辑的id冲突了。最后还要在下面添加一个标签的编辑字段,并在下面显示一行说明。
TinyMCETextArea扩展的使用与普通字段区别不大,主要是多了几个配置项。譬如fieldStyle是用来设置字段内编辑区域的字体的;noWysiwyg是用来是否使用所见即所得效果的,这里当然是使用,tinyMCEConfig则是用来设置TinyMCE,这个直接调用在首页预算好的设置就行了。
完成后,就可以测试了,切换到文章管理的控制器,完成onContentAdd方法,代码如下:
onContentAdd: function () {
var me =this,
win =SimpleCMS.view.Content.ContentEdit,
model= me.getContentModel();
win.form.getForm().url = "/Content/Add";
win.setTitle("新增文章");
win.form.loadRecord(new model);
win.show();
},
代码和文章类别的新增操作区别不大。主要变化是模型、url和标题的改变。
现在刷新一下页面,单击新增文章按钮,将看到如图58的效果。
图58 文章编辑窗口基本信息页
切换到摘要,将看到如图59的效果。
图59 文章编辑窗口摘要信息页
到这里,还有一个问题没有解决,就是如何在摘要和内容的编辑器中插入由图片管理扩展提供的图片。解决的思路就是在TinyMCE中添加插件,添加一个按钮弹出图片管理窗口,然后使用TinyMCE提供的命令将图片插入到编辑器中,下面来完成这个插件。
在Scripts/tinymce/plugins目录下,有example和example_dependenc这2个插件示例目录,第一个是没有依赖的示例。第二就是有依赖的。在这里,用那个都没关系,第一个文件多点,其实很多不需要,因而复制一份example_dependenc目录,然后复制后的目录修改为imagemanager。
在目录里会有editor_plugin.js和editor_plugin_scr.js两个文件,第一个文件一般是压缩后的文件,第二个文件是源文件,一般使用的是压缩后的文件,因而修改源代码文件后,还要将代码复制到压缩后的文件。现在打开editor_plugin_scr.js文件,会看到以下代码:
(function() {
tinymce.create('tinymce.plugins.ExampleDependencyPlugin',{
init: function(ed, url) {
},
getInfo: function() {
return{
longname: 'Example Dependency plugin',
author: 'Some author',
authorurl: 'http://tinymce.moxiecode.com',
infourl: 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example_dependency',
version: "1.0"
};
}
});
tinymce.PluginManager.add('example_dependency',tinymce.plugins.ExampleDependencyPlugin, ['example']);
})();
代码中的注释我已经去掉了,有兴趣可以自己看一下。在代码中,首先要修改的是类名,就是tinymce.create方法第一个参数。这里要注意,“tinymce.plugins.”最好别改,不然麻烦事很多,就修改最后那个类名好了,在这里修改为“ImageManagerPlugin”。
接着就要在init方法内注册一个命令并定义该命令要执行代码,还要注册一个按钮,让它可以显示在工具栏中。添加的代码如下:
init : function(ed, url) {
ed.addCommand('mceImageManager', function () {
Ext.ux.Dialog.PicSelected.ed = ed;
Ext.ux.Dialog.PicSelected.show();
});
ed.addButton('imagemanager', {
title: '从图库中插入图片',
cmd:'mceImageManager',
image: url + '/img/images.png'
});
},
代码中,参数ed返回的就是编辑器自身,通过它的addCommand方法就可添加一个命令,方法的第一个参数就是命令的名称,第二参数就是命令执行的代码。在执行代码中,设置了对话框的编辑控件为编辑器,这个很重要图片选择对话框的插入按钮就是根据编辑器进入插入操作的。接着就是显示对话框了。
方法addButton的作用是添加按钮,方法的第一参数是按钮的名称,这个在定义tinymce配置的时候要用到,按钮通过cmd配置项关联到刚才定义的命令mceImageManager,这样,单击该按钮,就可显示图片选择对话框了。配置项image的作用是为按钮定义一个图片。目前还没做这个,现在来完成这个,很简单,在imagemanger目录下创建一个img目录,把自己喜欢的图标文件复制到该目录就行了。
在插件代码中的getInfo方法是用来返回插件的一些信息的,如作者是谁,插件的名称是什么等等,这里就不改了。
最后要修改的地方就是将插件注册到tinymce的插件管理器中,首先将add放的第一个参数修改为“imagemanager”,也就是在plugins中定义的名称,后面的类名就是定义的插件的名称了。第三个参数不需要,删除就行了。
修改完成后把全部内容复制到editor_plugin.js中,替换掉原来的代码。
现在切换到首页,在tinyCfg内的plugins内,在最后添加插件的引用,在最后加入imagemanager就行。接着就是在编辑器的三个工具栏中选择一个放置按钮了,我一般习惯放在第三行按钮的最后位置,也就是在theme_advanced_buttons3的最后,加入“,|,imagemanager”。
现在可以调试一下了,不过,在这里给Firefox气死了,在IE和Chorme中都能正常显示按钮,Firefox就是不显示,原来是缓存的editor_plugin.js文件一直没更新。刷新后,将看到如图60所示的效果,在工具栏第三行最后加了一个按钮,单击它就能显示出图片选择对话框了。
图60 添加了插入图片编辑对话框按钮的编辑器
现在单击插入是插入不了图片的,还要加入代码来实现插入功能。
切换到PicSelected.js文件,在插入按钮的单击方法中,当ed指向的预览图片这样的FormField的时候,直接插入字符就行了。而tinymce并不是FormField,不能使用这种方式插入,要使用Tinymce的mceInsertContent命令来插入一段HTML代码到编辑器中,代码如下:
var html = "";
me.imagePath = "upload";
for (var i = 0; ln = rs.length, i < ln; i++) {
html +=Ext.String.format("<img src='{0}{1}{2}' >", me.imagePath,rs[i].data.path, rs[i].data.filename);
}
me.ed.execCommand('mceInsertContent', false, html);
代码先从Store中找出选择的图片,将图片信息组合成HTML代码,然后调用execCommand方法执行mceInsertContent命令,将HTML代码作为内容插入到编辑器中。
在代码中,要注意的还是图片路径,这里还是使用了一个预设的路径。
现在测试一下插入图片,将看到如图61所示的效果。
图61 在编辑器中插入图片
好了,编辑对话框就完成了。可以完成服务端代码了,基本过程和类别一样,先建立模型,然后添加,这个就当成作业,留给读者自己来完成了。还有编辑、删除和查看功能也是。
如果有任何疑问或者问题,可在这里留言、发评论或发邮件等方式联系我,共同解决,也可以加我微博,发私信给我。
我的微博是:http://weibo.com/gerneal
源代码:http://vdisk.weibo.com/s/jNryi