vapour's blog

2Mar/11Off

ckeditor添加自定义语法高亮按钮

首先下载并安装ckeditor,我们可以自定义ckeditor工具栏要显示的按钮,工具栏按钮定义可以参考这里

现在我们需要向工具栏添加一个自定义功能的按钮。ckeditor工具栏中的每个按钮都是作为插件定义在ckeditor\plugins\ 目录中。我们在ckeditor\plugins\中创建一个新文件夹highLight。在highLight内包含以下文件:

  • high-light.png 编辑器工具栏显示图标
  • plugin.js 给自定义按钮绑定事件
  • my_dialog.js 单击自定义按钮后,弹出的自定义窗口
  • highLight.js 语法高亮,只实现HTML/CSS/JavaScript

plugin.js代码:

(function(){
    CKEDITOR.plugins.add('highLight', {
        init:function(editor){
            var path = this.path;
            editor.ui.addButton('highLight', {
                label: 'highLight code',
                icon: path + 'high-light.png',
                command: 'highLightCmd'
            });
            editor.on( 'pluginsLoaded', function( ev ){
                if ( !CKEDITOR.dialog.exists( 'highLightDialog' ) ){
                    var href = path + 'my_dialog.js';

                    // Finally, register the dialog.
                    CKEDITOR.dialog.add( 'highLightDialog', href );
                    
                    //load highLight.js
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.src = path + 'highLight.js';
                    document.getElementsByTagName('head')[0].appendChild(s);
                }
                // Register the command used to open the dialog.
                editor.addCommand( 'highLightCmd', new CKEDITOR.dialogCommand( 'highLightDialog' ) );
            });
        }
    });
})();

 

my_dialog.js代码

CKEDITOR.dialog.add( 'highLightDialog', function( editor )
{
    return {
        title : 'highLight code',
        minWidth : 400,
        minHeight : 200,
        onOk : function(){
            var lang = this.getValueOf('tab1', 'hl-lang'),
                code = this.getValueOf('tab1', 'hl-cotent');
            
            switch(lang){
                case 'JavaScript':
                    code = highLightJS.format(code);
                    break;
                case 'HTML':
                    code = highLightHTML.format(code);
                    break;
                case 'CSS':
                    code = highLightCSS.format(code);
                    break;
                default:
                    break;
            }
            
            editor.insertHtml('<div class="code">' + code + '</div>');
        },
        contents : [
            {
                id : 'tab1',
                label : 'First Tab',
                title : 'First Tab',
                elements :
                [
                    {
                        id : 'hl-lang',
                        label : '',
                        type : 'select',
                        items : [['JavaScript'], ['HTML'], ['CSS']],
                        'default' : 'JavaScript'
                    },
                    {
                        id : 'hl-cotent',
                        type : 'textarea',
                        label : '',
                        rows : 12
                    }
                ]
            }
        ]
    };
} );

 

highLight.js代码

if(typeof Object.create !== 'function'){
   Object.create = function(o){
      function F(){}
      F.prototype = o;
      return new F();
   }
}
var highLight = {
    //value: '<span>vapour</span>',
    i: 0,//计数器
    buff: [],//缓存
    encode: function(){//对<、>和&进行编码
        this.replace(/&(\S+?;)/g, '&amp;$1').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        return this;
    },
    replace: function(reg, fn){
        this.value = this.value.replace(reg, fn);
        return this;
    },
    whiteSpace: function(){
        this.replace(/^\t+/gm, function(val){
            return (new Array(val.length + 1)).join('&nbsp;&nbsp;&nbsp;&nbsp;');
        }).replace(/^ +/gm, function(val){
            return (new Array(val.length + 1)).join('&nbsp;');
        }).replace(/\r?\n/g, function(val){
            return '<br />';
        });
        return this;
    },
    get: function(){
        return this.value;
    },
    set: function(v){
        this.value = v;
        return this;
    },
    format: function(v){
        return this.set(v).encode().process().whiteSpace().get();
    }
};

var highLightCSS = Object.create(highLight);
highLightCSS.process = function(){
    var that = this;
    this.replace(/\/\*(?:.|\n)+?\*\//g, function(val){//注释
        that.buff.push({
            cls: 'css-comment',
            value: val
        });
        return '_buff_' + that.i++ + '_buff_';
    }).replace(/(\"|\').*?\1/g, function(val){//字符串
        return '<span class="css-string">' + val + '</span>';
    }).replace(/:(.+?)(;|\})/g, function(val, a, b){//value
        return ':<span class="css-value">' + a + '</span>' + b;
    }).replace(/\{([^\}]*)\}/g, function(val, a){//name
        return '{<span class="css-name">' + a + '</span>}';
    }).replace(/(\}|^)([^|{]*)\{/g, function(val, a){//selector
        return '<span class="css-selector">' + val + '</span>';
    }).replace(/_buff_(\d+)_buff_/g, function(val, index){
        return '<span class="' + that.buff[index].cls + '">' + that.buff[index].value + '</span>';
    });
    return this;
}

var highLightJS = Object.create(highLight);
highLightJS.process = function(){
    var that = this,
        reg,
        keyword = {
            reserved: "break|case|catch|continue|default|delete|do|else|export|function|false|finally|for|if|import|in|item|new|null|return|switch|this|throw|true|try|var|void|while|with",
            native: "abs|acos|Array|asin|atan|atan2|Boolean|ceil|charAt|charCodeAt|concat|cos|Date|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|exp|floor|fromCharCode|Function|getDate|getDay|getFullYear|getHours|getMilliseconds|getMinutes|getMonth|getSeconds|getSelection|getTime|getTimezoneOffset|getUTCDate|getUTCDay|getUTCFullYear|getUTCHours|getUTCMilliseconds|getUTCMinutes|getUTCMonth|getUTCSeconds|getYear|Image|indexOf|isNaN|join|lastIndexOf|log|match|Math|max|min|Number|Object|parse|parseFloat|parseInt|pop|pow|preference|print|push|random|RegExp|replace|reset|resizeBy|resizeTo|reverse|round|search|select|setDate|setFullYear|setHours|setMilliseconds|setInterval|setMinutes|setMonth|setSeconds|setTime|setTimeout|setUTCDate|setUTCFullYear|setUTCHours|setUTCMilliseconds|setUTCMinutes|setUTCMonth|setUTCSeconds|setYear|shift|sin|slice|sort|splice|split|sqrt|String|substr|substring|tan|toGMTString|toLocaleString|toLowerCase|toSource|toString|toUpperCase|toUTCString|typeof|unescape|unshift|unwatch|UTC|valueOf|watch|write|writeln",
            client: "alert|all|anchor|back|big|blink|blur|body|bold|byteToString|captureEvents|clearInterval|clearTimeout|click|close|confirm|disableExternalCapture|document|enableExternalCapture|event|find|fixed|focus|fontcolor|fontsize|forward|getOptionValueCount|getOptionValue|go|handleEvent|home|italics|javaEnabled|link|load|log|mimeTypes|moveAbove|moveBelow|moveBy|moveTo|moveToAbsolute|navigator|open|options|plugins|prompt|refresh|releaseEvents|reload|routeEvent|screen|scroll|scrollBy|scrollTo|small|stop|strike|sub|submit|sup|taintEnabled|unit|window",
            other: "\\(|\\)|\\[|\\]|\\{|\\}"
        };
    this.replace(/(.)?(\/\*(?:.|\n)*?\*\/)/gm, function(val, a, b){//多行注释
        if(a == '/') return val;
        that.buff.push({
            cls: 'js-comment',
            value: b
        });
        return a + '_buff_' + that.i++ + '_buff_';
    }).replace(/(.)?(\/\/.*)$/gm, function(val, a, b){//单行注释
        if(a == '\\') return val;
        that.buff.push({
            cls: 'js-comment',
            value: b
        });
        return a + '_buff_' + that.i++ + '_buff_';
    }).replace(/\/.+?[^\\]\/g?m?i?/g, function(val){//正则表达式
        that.buff.push({
            cls: 'js-regular',
            value: val
        });
        return '_buff_' + that.i++ + '_buff_';
    }).replace(/([^\\])?((\"|\').*?([^\\])\3)/g, function(val, a, b){//字符串
        that.buff.push({
            cls: 'js-string',
            value: b
        });
        return a + '_buff_' + that.i++ + '_buff_';
    }).replace(/\b([+-]?(?:\d+(?:\.\d*)?(?:e[+-]?\d+)?|0x[\dA-F]+))\b/gi, function(val){//数字
        return '<span class="js-number">' + val + '</span>';
    });
    
    //关键字
    reg = new RegExp('\\b(' + keyword.client + ')\\b', 'g');
    this.replace(reg, '<span class="js-client">$1</span>');
    reg = new RegExp('\\b(' + keyword.native + ')\\b', 'g');
    this.replace(reg, '<span class="js-native">$1</span>');
    reg = new RegExp('\\b(' + keyword.reserved + ')\\b', 'g');
    this.replace(reg, '<span class="js-reserved">$1</span>');
    
    //运算符
    reg = new RegExp('(' + keyword.other + ')', 'g');
    this.replace(reg, '<span class="js-reserved">$1</span>');
    
    this.replace(/_buff_(\d+)_buff_/g, function(val, index){
        return '<span class="' + that.buff[index].cls + '">' + that.buff[index].value + '</span>';
    });
    return this;
}

highLightHTML = Object.create(highLight);
highLightHTML.process = function(){
    var that = this,
        reg,
        scripts = [],
        styles = [],
        i = 0,
        j = 0,
        tableList = "table|thead|tbody|tfoot|td|th|tr",
        formList = "form|input|select|option|textarea";
    
    this.replace(/(&lt;script[^&]*>)([\s\S]*?)(&lt;\/script[^&]*>)/g, function(all, start, middle, end){//缓存内联JS
        scripts[i] = {
            start: '<span class="xml-script">' + start.replace(/(['"]).*?\1/g, function(m){ return '<span class="xml-script-quote">' + m + '<_buff_81_buff_span>',
            middle: middle,
            end: '<span class="xml-script">' + end + '</span>'
        };
        return "_js_" + i++ + "_js_";
    }).replace(/(&lt;style[^&]*>)([\s\S]*?)(&lt;\/style[^&]*>)/g, function(all, start, middle, end){//缓存内联CSS
        styles[j]={
            start: '<span class="xml-style">' + start.replace(/(['"]).*?\1/g, function(m){ return '<span class="xml-style-quote">' + m + '<_buff_84_buff_span>',
            middle: middle,
            end: '<span class="xml-style">' + end + '</span>'
        };
        return "_css_" + j++ + "_css_";
    }).replace(/&lt;!--(?:.|\n)+?--&gt;/g, function(val){//缓存html注释
        that.buff.push({
            cls: 'xml-comment',
            value: val
        });
        return '_buff_' + that.i++ + '_buff_';
    }).replace(/([^\\])?((\"|\').*?([^\\])\3)/g, function(val){
        return '<span class="xml-string">' + val + '</span>';
    }).replace(/&lt;\/?([a-z]+)(?:.|\n)*?&gt;/g, function(m, n){
        reg = new RegExp('^' + tableList + '$', 'gi');
        if(reg.test(n)){
            return '<span class="xml-table">' + m + '</span>';
        }
        reg = new RegExp('^' + formList + '$', 'gi');
        if(reg.test(n)){
            return '<span class="xml-form">' + m + '</span>';
        }
        switch(n){
            case 'img':
                return '<span class="xml-img">' + m + '</span>';
            case 'a':
                return '<span class="xml-link">' + m + '</span>';
            default:
                return '<span class="xml-tag">' + m + '</span>';
        }
    }).replace(/_buff_(\d+)_buff_/g, function(val, index){
        return '<span class="' + that.buff[index].cls + '">' + that.buff[index].value + '</span>';
    }).replace(/_css_(\d+)_css_/g, function(all, num){//高亮内联CSS
        return styles[num].start + highLightCSS.format(styles[num].middle) + styles[num].end;
    }).replace(/_js_(\d+)_js_/g, function(all,num){//高亮内联JS
        return scripts[num].start + highLightJS.format(scripts[num].middle) + scripts[num].end;
    });
    
    return this;
}

 

接下来我们需要在config.js中注册我们自定义的插件highLight,并显示在编辑器工具栏中,config.js代码

CKEDITOR.editorConfig = function( config )
{
    config.height = '360px';
    config.extraPlugins = 'highLight';
    config.toolbar = 'Full';
 
    config.toolbar_Full =
    [
        ['Source','-','Save','NewPage','Preview','-','Templates'],
        ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
        ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
        ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
        '/',
        ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
        ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
        ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
        ['BidiLtr', 'BidiRtl'],
        ['Link','Unlink','Anchor'],
        ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak','Iframe'],
        '/',
        ['Styles','Format','Font','FontSize'],
        ['TextColor','BGColor'],
        ['Maximize', 'ShowBlocks','-','About','-','highLight']
    ];
};

注意:自定义插件的名称必须在任何地方都要保持一致。这个例子中highLight显示为红色的地方。

参考:Customizing Ckeditor and adding a new toolbar button

Comments (2) Trackbacks (0)
  1. 类似:items : [['JavaScript'], ['HTML'], ['CSS']],
    这样的值我想用.aspx页面从数据库读取的值来绑定,有没有办法??

  2. .net中服务器控件都可以绑定数据源的


Trackbacks are disabled.