CKeditor插件开发流程(二)SyntaxHighlighter

时间:2023-03-09 02:21:58
CKeditor插件开发流程(二)SyntaxHighlighter

CKEditor整合SyntaxHighlighter实现代码高亮显示

1,版本说明

CKEditor:ckeditor_4.0.1_standard.zip
SyntaxHighlighter:syntaxhighlighter_3.0.83.zip

2,解压syntaxhighlighter_3.0.83.zip,将得到的目录syntaxhighlighter_3.0.83复制到站点目录下,我的是放在/plugins目录下(可以是其它目录,或者根目录),结果得到目录结构/plugins/syntaxhighlighter_3.0.83。

3,在CKEditor中配置插件(安装方法在《CKEditor安装》有介绍,这里就不介绍了)。在ckeditor/plugins目录下创建一个目录syntaxhighlighter,此目录名即为插件名,这点要注意。在syntaxhighlighter目录下创建icons、dialogs两个目录和plugin.js一个文件。icons目录用于存放插件在编辑器工具栏上相应按钮的图标,dialogs用于存放该插件对话框相关类,plugin.js是严格要求这样命名的。因此在CKEditor中新增的目录结构如下:

  • ckeditor/
    • plugins/
      • syntaxhighlighter/
        • icons/
          • syntaxhighlighter.png
        • dialogs/
          • syntaxhighlighter.js
        • plugin.js

4,编辑plugin.js文件,内容如下:

// mo_yq5 在编辑器中定义一个插件,注意,插件名称与插件目录名要保持一致
CKEDITOR.plugins.add( 'syntaxhighlighter', {
// mo_yq5 初始化插件
init: function( editor ) {
//mo_yq5 引入对话框的定义,所引入的文件的内容是对话框的具体逻辑定义
CKEDITOR.dialog.add( 'shDialog', this.path + 'dialogs/syntaxhighlighter.js' );
//mo_yq5 在编辑器中追加一条指令
editor.addCommand( 'shDialog', new CKEDITOR.dialogCommand( 'shDialog' ) );
//mo_yq5 在编辑器中追加一个工具栏按钮
editor.ui.addButton( 'shButton', {
//mo_yq5 鼠标移到按钮上时的提示文本
label: '插入代码',
//mo_yq5 点击按钮时要执行的指令,即上面添加的指令
command: 'shDialog',
//mo_yq5 在编辑器工具栏中嵌入按钮的方式
toolbar: 'insert',
//mo_yq5 工具栏上按钮的图标
icon: this.path + 'icons/syntaxhighlighter.png'
}); }
});

5,编辑syntaxhighlighter.js文件,定义对话框的实现逻辑,代码如下:

//mo_yq5 定义一个对话框。
CKEDITOR.dialog.add( 'shDialog', function ( editor ) {
return {
//mo_yq5 对话框标题。
title: '插入代码',
//mo_yq5 对话框最小宽度。
minWidth: 400,
//mo_yq5 对话框最小高度。
minHeight: 200,
//mo_yq5 对话框内容,一个元素对应一个选项卡。
contents: [
{
//mo_yq5 选项卡标识id。
id: 'tab_hightlighterCode',
//mo_yq5 选项卡标题。
label: '代码内容',
//mo_yq5 选项卡内容,一个元素对应一个表单项。
elements: [
{
//mo_yq5 表单类型。
type: 'select',
//mo_yq5 表单名。
label: '语言:',
//mo_yq5 表单标识id。
id: 'lang',
//mo_yq5 是否为必填项。
required: true,
//mo_yq5 表单默认值。
'default': 'java',
items: [['ActionScript3', 'as3'], ['Bash/shell', 'bash'], ['ColdFusion', 'cf'], ['C#', 'csharp'], ['C++', 'cpp'], ['CSS', 'css'], ['Delphi', 'delphi'], ['Diff', 'diff'], ['Groovy', 'groovy'], ['JavaScript', 'js'], ['Java', 'java'], ['JavaFX', 'jfx'], ['Perl', 'perl'], ['PHP', 'php'], ['Plain Text', 'plain'], ['PowerShell', 'ps'], ['Python', 'py'], ['Ruby', 'rails'], ['Scala', 'scala'], ['SQL', 'sql'], ['Visual Basic', 'vb'], ['XML', 'xml']]
},
{
type: 'textarea',
style: 'width:418px;height:250px',
label: '代码:',
required: true,
id: 'code',
rows: 13,
'default': ''
}
]
}
],
//mo_yq5 定义提交事件。
onOk: function(){
//mo_yq5 从下拉列表获取到的语言类型。
var lang = this.getValueOf('tab_hightlighterCode', 'lang');
//mo_yq5 将要被渲染成高亮显示的内容(代码)。
var code = this.getValueOf('tab_hightlighterCode', 'code');
//mo_yq5 在当前页面上创建的一个用于存放代码的容器,因为渲染器SyntaxHighlighter是取页面内容来渲染的。该容器不显示。
if($("#brushContainer").length==0){
$("body").append('<div id="brushContainer" style="display:none;"></div>');
}
//mo_yq5 主要目的是将‘<’这样的标签转换成实体。
code = CKEDITOR.tools.htmlEncode(code);
//mo_yq5 将要渲染的代码放入容器。
$("#brushContainer").html('<pre class="brush:'+ lang +';">'+code+'</pre>');
//mo_yq5 将渲染各种语言的类准备好 。
SyntaxHighlighter.autoloader.apply(null,shBrushArray);
//mo_yq5 开始渲染。
SyntaxHighlighter.all();
//mo_yqr@163.com 等待2秒(因为渲染是异步的,可能需要点时间),将渲染后的内容插入编辑器。
setTimeout(function(){
//mo_yq5 将类似‘<’等的实体标识为文本内容,不然下次用编辑器打开时会被认为是html标签,造成编辑器上看不到该字符。
code = $("#brushContainer").html().replace(/(&){1}(lt;){1}/g,"<code>&"+"lt;</code>");
code = code.replace(/(&){1}(amp;){1}/g,"<code>&"+"amp;</code>");
//mo_yq5 将渲染后的内容插入编辑器,加‘<p/>’是为了让光标移出被渲染后的代码块。
editor.insertHtml(code+"<p/>");
},2000);
}
};
});

代码说明:此代码虽然是在CKEditor插件syntaxhighlighter中定义,但使用到了一些全局对象,比如59行的SyntaxHighlighterSyntaxHighlighter组件中定义的对象,‘shBrushArray’是我在页面上定义的全局数组对象,以及代码中使用了JQuery类库,这些对象的引入将在后面进行说明。重点说明65、66行之目的所在:1,将内容的标签实体用code标签包装(ckeditor内部机制决定),是为了防止编辑器显示内容时,将内容中的标签实体转换为html标签,造成内容在编辑器显示结果与保存结果跟预想的不一致;2,将标签实体(如“&”与“lt;”的连接串)拆分成如代码所示的形式,是为了保证即使在编辑器中编辑上面的代码时显示结果也是正确的;这两点也是我纠结了两三天才写出来,其它问题有待发现。

6,至此,syntaxhighlighter插件在CKEditor上的配置已经完成,效果如下图:

CKeditor插件开发流程(二)SyntaxHighlighter

7,完成以上步骤,已经可以将代码插入到编辑器中,但代码还不能在编辑器上高亮显示。要达到这个目的,我们需要考虑被渲染后的代码引用的样式起效情况。被渲染后,代码内容已经定义上SyntaxHighlighter组件中定义的样式,因此我们需要将SyntaxHighlighter组件定义的样式文件引入到编辑器所在页面中来。经过深入,我们了解到,编辑器的编辑框是定义在编辑器所在页面的一个iframe标签下的(即在不同的document对象中),所以直接在编辑器所在页面引入SyntaxHighlighter组件定义的样式文件,是不起作用,因为样式影响不到iframe下的内容。我们需要想法办能够在编辑框所在iframe(即document对象)中引入SyntaxHighlighter组件定义的样式文件。通过用火狐浏览器访问编辑器所在的页面,鼠标右键查看页面元素可以发现,编辑框所在iframe中引入了ckeditor/contents.css这个样式文件。经过测试,引入SyntaxHighlighter组件定义的样式比较简便的方法就是在ckeditor/contents.css中追加SyntaxHighlighter组件定义的样式。具体方法就是加入以下两行(根据自己SyntaxHighlighter的实际路径进行变动):

@IMPORT url("../plugin/syntaxhighlighter_3.0.83/styles/shCoreEclipse.css");
@IMPORT url("../plugin/syntaxhighlighter_3.0.83/styles/shThemeEclipse.css");

8,要体验最终效果,需要在编辑器所在页面引入一些必要的类库,如下(包括之前CKEditor安装所引入的):

  • 在需要显示编辑器的位置贴入
  • <textarea name="article.body">${article.body }</textarea>
  • 在页面底部引入类库
  • <script src="${pageContext.request.contextPath}/include/js/jquery-1.4.1.min.js"></script>
    <script src="${pageContext.request.contextPath}/plugin/syntaxhighlighter_3.0.83/scripts/shCore.js"></script>
    <script src="${pageContext.request.contextPath}/plugin/syntaxhighlighter_3.0.83/scripts/shAutoloader.js"></script>
    <script src="${pageContext.request.contextPath}/ckeditor/ckeditor.js"></script>
    <script>
    var g_contextPath="${pageContext.request.contextPath}";
    //mo_yq5 syntaxhighlighter插件的定义中需要到此对象,具体请看dialogs/syntaxhighlighter.js。
    var shBrushArray = (function(){
    var args = arguments,result = [];
    for(var i = 0; i < args.length; i++)
    result.push(args[i].replace('@', g_contextPath+'/plugin/syntaxhighlighter_3.0.83/scripts/'));
    return result;
    })(
    'applescript @shBrushAppleScript.js',
    'actionscript3 as3 @shBrushAS3.js',
    'bash shell @shBrushBash.js',
    'coldfusion cf @shBrushColdFusion.js',
    'cpp c @shBrushCpp.js',
    'c# c-sharp csharp @shBrushCSharp.js',
    'css @shBrushCss.js',
    'delphi pascal @shBrushDelphi.js',
    'diff patch pas @shBrushDiff.js',
    'erl erlang @shBrushErlang.js',
    'groovy @shBrushGroovy.js',
    'java @shBrushJava.js',
    'jfx javafx @shBrushJavaFX.js',
    'js jscript javascript @shBrushJScript.js',
    'perl pl @shBrushPerl.js',
    'php @shBrushPhp.js',
    'text plain @shBrushPlain.js',
    'py python @shBrushPython.js',
    'ruby rails ror rb @shBrushRuby.js',
    'sass scss @shBrushSass.js',
    'scala @shBrushScala.js',
    'sql @shBrushSql.js',
    'vb vbnet @shBrushVb.js',
    'xml xhtml xslt html @shBrushXml.js');
    //mo_yq5 指定编辑的显示高度
    CKEDITOR.config.height=450;
    //mo_yq5 启用代码高亮显示插件
    CKEDITOR.config.extraPlugins="syntaxhighlighter";
    //mo_yq5 初始化页面上的编辑器
    var editor = CKEDITOR.replace( 'article.body'); </script>

    代码说明:“article.body”是表单名。第4到27行是针对各种语言渲染类;按照官方文档上意思,定义第30到61行即可(syntaxhighlighter.js文件中有调用)。但实际测试结果是,如果只定义30到61行的代码,在编辑器中插入代码时只是第一次插入有效,第二次插入时如果选择的语言类型与上次插入的不同,将会报“Can't find brush for XXX”的错误,所以在我看来4到27行也是需要的(至少目前当作是SyntaxHighlighter的bug来处理),根据需要提供的语言类型进行增减即可。

    9,编辑器配置完成,代码在编辑器中高亮显示的效果,如图:

  • CKeditor插件开发流程(二)SyntaxHighlighter

10,以上是针对编辑器的配置,当编辑后的文章需要在页面中显示时,我们需要在显示文章的页面引入样式文件即可(不需要SyntaxHighlighter的类库),如(也可点击鼠标右键来查看本页面的源代码):

<link rel=stylesheet type=text/css href="${pageContext.request.contextPath}/plugin/syntaxhighlighter_3.0.83/styles/shCoreEclipse.css" />
<link rel=stylesheet type=text/css href="${pageContext.request.contextPath}/plugin/syntaxhighlighter_3.0.83/styles/shThemeEclipse.css" />

以上内容来自:http://www.moyq5.me/article/1/detail/32

补充:

1、在"ckeditor\"目录下找到“config.js”文件,这是CKEditor的配置文件,添加如下代码

config.extraPlugins = 'syntaxhighlighter';//这里只能出现一次,如果之前有加过,用,隔开

2.如果出现中文乱码问题,是页面编码不对,我是ASP.NET,折腾了一番,最终解决,修改Web.config文件

-----旧的
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
<customErrors mode="Off" />
<globalization fileEncoding="GB2312" requestEncoding="GB2312" responseEncoding="GB2312"/>
</system.web>
</configuration>
--乱码问题新的解决办法,,原来是新增的那两个JS文件编码不对,重新打开编码另存为UTF-8格式即可

3.如果CkEditor 添加源码后没有 高亮颜色等,需要 添加配置

config.allowedContent = true;