CKEditor在上下文(嵌套)菜单中添加格式组合项

时间:2016-11-25 14:20:44

标签: ckeditor

我在我的一个项目中使用CKEditor 4.5.7。我们已经定制了格式组合,如下面的屏幕截图所示,问题是右键单击此组合中出现的所有项目。

CKEditorFormatCombo

以下是格式组合的代码:

config.format_tags = 'p;h3;h4;pre;ImageInline;ImageCentered;ImageCenteredWithDropShadow;FigureHeading;Equation;EquationDefinition;TableWithoutBorder';
config.format_ImageInline = { name: 'Image inline', element: 'img', attributes: { 'class': 'noborder' } };
config.format_ImageCentered = { name: 'Image centered', element: 'img', attributes: { 'class': 'noborderblock' } };
config.format_ImageCenteredWithDropShadow = { name: 'Image centered drop shadow', element: 'img', attributes: { 'class': 'border' } };
config.format_FigureHeading = { name: 'Figure/Table heading', element: 'p'/*['p', 'td']*/, attributes: { 'class': 'footing' } };
config.format_Equation = { name: 'Equation', element: 'table', attributes: { 'class': 'equation' } };
config.format_EquationDefinition = { name: 'Equation definition', element: 'table', attributes: { 'class': 'where' } };
config.format_TableWithoutBorder = { name: 'Table without border', element: 'table', attributes: { 'class': 'nobordertable' } };

我能够在上下文菜单中显示它们,如下面的屏幕截图所示: CKEditor Context menu

但我不确定每个人的command名称是什么。即。

command: 'format_ImageCentered' /*I need help here*/ command: 'format_ImageCenteredWithDropShadow' /*I need help here*/

我已经下载了CKEditor的完整源代码,然后通过ckeditor \ plugins \ format \ plugin.js,但无法确定指定为command的内容。

以下是我自定义上下文菜单的代码:

var ck_article = CKEDITOR.replace("content", { customConfig: '<config js file path>', bodyClass: '<css class>' });
ck_article.on("instanceReady", function (evt) {
    var editor = evt.editor;        
    /*Code for checking if editor has context menu or not removed for brevity*/
    //... 
    //...
    editor.addMenuGroup('ck_group');

    editor.addMenuItem('bold', {
        label: 'Bold',
        command: 'bold',
        group: 'ck_group'
    });

    editor.addMenuItem('iconselector', {
        label: '...',
        command: 'iconselector',
        group: 'ck_group'
    });

    editor.addMenuItem('numberedlist', {
        label: 'Numbered List',
        command: 'numberedlist',
        group: 'ck_group'
    });

    editor.addMenuItem('bulletedlist', {
        label: 'Bulleted List',
        command: 'bulletedlist',
        group: 'ck_group'
    });

    editor.addMenuItem('link', {
        label: 'Link',
        command: 'link',
        group: 'ck_group'
    });

    editor.addMenuItems({
        formatting: {
            label: 'Formatting',
            group: 'ck_group',
            getItems: function () {
                var selection = editor.getSelection();
                //This is to nest items inside context menu of CKEditor
                return {
                    format_ImageCentered: CKEDITOR.TRISTATE_ON,
                    format_ImageCenteredWithDropShadow: CKEDITOR.TRISTATE_ON
                }
            }
        },

        format_ImageCentered: {
            label: "Image centered",
            group: 'ck_group',
            command: 'format_ImageCentered' /*I need help here*/
        },

        format_ImageCenteredWithDropShadow: {
            label: "Image centered drop shadow",
            group: 'ck_group',
            command: 'format_ImageCenteredWithDropShadow' /*I need help here*/
        }
    });

    editor.contextMenu.addListener(function (element, selection, elementPath) {

        var contentMenuItems = {
            link: CKEDITOR.TRISTATE_ON,
            bold: CKEDITOR.TRISTATE_ON,
            numberedlist: CKEDITOR.TRISTATE_ON,
            bulletedlist: CKEDITOR.TRISTATE_ON,
            iconselector: CKEDITOR.TRISTATE_ON,
            formatting: CKEDITOR.TRISTATE_ON
        };

        if (element.getAscendant('a', true)) {
            //If we are already inside 'a' tag then remove link from Context menu else we will end up with two "Link" menus
            delete contentMenuItems.link
        }

        if ($.trim(selection.getSelectedText()) === '') {
            //If no text is selected then remove bold from context menu
            delete contentMenuItems.bold;
            //contentMenuItems.bold = CKEDITOR.TRISTATE_DISABLED; //This doesn't work as the menu item is disabled but hover effect is still there

            //Similarly remove link if nothing is selected as it will insert hyperlink text as words inside CKEditor
            delete contentMenuItems.link;
            //contentMenuItems.link = CKEDITOR.TRISTATE_DISABLED; //This doesn't work as the menu item is disabled but hover effect is still there
        }

        return contentMenuItems;
    }); 
});

参考文献:

我使用以下网址作为参考:

1 个答案:

答案 0 :(得分:0)

我最终为Format组合中列出的每个选项创建了插件。如果还有其他更好的方式,请告诉我。我正在传递代码以防其他人遇到类似问题。

屏幕截图显示了插件文件夹在CKEditor文件夹中的显示方式: Plugin Folder

我只粘贴一个插件代码,因为所有插件都具有完全相同的代码,唯一的区别是pluginName的值,这与文件夹名称完全相同:

//All the files inside folder stating with context_<name> have exact same code except pluginName variable.
//I need to this to support format inside right click
(function () {
    "use strict";
    var pluginName = 'contextmenu_tablewithoutborder'; //This name will be used to add to 'config.extraPlugins' string
    var commandName = pluginName;
    // Register the plugin within the editor.
    CKEDITOR.plugins.add(pluginName, {
        // Register the icons. They must match command names.
        icons: pluginName,
        // The plugin initialization logic goes inside this method.
        init: function (editor) {
            // Define an editor command.
            editor.addCommand(commandName, { //Command name must match with name provided in editor.ui.addButton
                // Define the function that will be fired when the command is executed.
                exec: function (editor) {
                    if (typeof editor.applyFormatStyles === 'function')
                        editor.applyFormatStyles(pluginName.split('_')[1]);
                    else
                        throw new Error('applyFormatStyles is not defined as function (' + pluginName + ')');
                }
            });
        }
    });
})();

然后我扩展了CKEditor并添加了以下方法:

CKEDITOR.editor.prototype.getFormatStyles = function () {
    var styles = {}
    var editor = this;
    var config = editor.config,
        lang = editor.lang.format;

    // Gets the list of tags from the settings.
    var tags = config.format_tags.split(';');

    for (var i = 0; i < tags.length; i++) {
        var tag = tags[i];
        var style = new CKEDITOR.style(config['format_' + tag]);
        if (!editor.filter.customConfig || editor.filter.check(style)) {
            styles[tag] = style;
            styles[tag]._.enterMode = editor.config.enterMode;            
        }
    }

    return styles;
}

CKEDITOR.editor.prototype.applyFormatStyles = function (styleName) {
    var editor = this;
    var styles = editor.getFormatStyles();
    editor.focus();
    editor.fire('saveSnapshot');

    var style = styles[styleName],
        elementPath = editor.elementPath();

    editor[style.checkActive(elementPath, editor) ? 'removeStyle' : 'applyStyle'](style);

    // Save the undo snapshot after all changes are affected. (#4899)
    setTimeout(function () {
        editor.fire('saveSnapshot');
    }, 0);
}

然后我修改了我的配置文件,并将所有这些插件添加为额外的插件:

CKEDITOR.editorConfig = function (config) {
    var extraPlugins = [];
    //Remove other code for brevity
    //...
    //... 
    config.format_tags = 'p;h3;h4;pre;imageinline;imagecentered;imagecenteredwithdropshadow;figureheading;equation;equationdefinition;tablewithoutborder';
    config.format_imageinline = { name: 'Image inline', element: 'img', attributes: { 'class': 'noborder' } };
    config.format_imagecentered = { name: 'Image centered', element: 'img', attributes: { 'class': 'noborderblock' } };
    config.format_imagecenteredwithdropshadow = { name: 'Image centered drop shadow', element: 'img', attributes: { 'class': 'border' } };
    config.format_figureheading = { name: 'Figure/Table heading', element: 'p'/*['p', 'td']*/, attributes: { 'class': 'footing' } };
    config.format_equation = { name: 'Equation', element: 'table', attributes: { 'class': 'equation' } };
    config.format_equationdefinition = { name: 'Equation definition', element: 'table', attributes: { 'class': 'where' } };
    config.format_tablewithoutborder = { name: 'Table without border', element: 'table', attributes: { 'class': 'nobordertable' } };

    var contextmenu_plugins = config.format_tags.split(";");
    for (var i = 0; i < contextmenu_plugins.length; i++) {
        var pluginName = contextmenu_plugins[i];
        extraPlugins.push("contextmenu_{0}".format(pluginName))
    }

    config.extraPlugins = extraPlugins.join(',');
}

然后最后当我创建编辑器时,我会扩展上下文菜单。我可以在plugin.js文件中添加这个逻辑,但是因为我希望plugin.js代码完全相同,除了一行或两行之外我没有在那里添加它。

var ck_article = CKEDITOR.replace("content", { customConfig: '<config js file path>', bodyClass: '<css class>' });

ck_article.on("instanceReady", function (evt) { 
    var editor = evt.editor;
    editor.addMenuGroup('ck_group');

    editor.addMenuItem('bold', {
        label: 'Bold',
        command: 'bold',
        group: 'ck_group'
    });

    editor.addMenuItem('iconselector', {
        label: '...',
        command: 'iconselector',
        group: 'ck_group'
    });

    editor.addMenuItem('numberedlist', {
        label: 'Numbered List',
        command: 'numberedlist',
        group: 'ck_group'
    });

    editor.addMenuItem('bulletedlist', {
        label: 'Bulleted List',
        command: 'bulletedlist',
        group: 'ck_group'
    });

    editor.addMenuItem('link', {
        label: 'Link',
        command: 'link',
        group: 'ck_group'
    });

    editor.addMenuItems({
        formatting: {
            label: 'Formatting',
            group: 'ck_group',
            getItems: function () {
                var selection = editor.getSelection();
                //This is to nest items inside context menu of CKEditor
                var tags = editor.config.format_tags.split(";");
                var menu_items = {
                };
                for (var i = 0; i < tags.length; i++) {
                    menu_items[tags[i]] = CKEDITOR.TRISTATE_ON;
                }
                //menu_items - will have object something like below 
                //{p: 1, h3: 1, h4: 1......}
                return menu_items;
            }
        },

        p: {
            label: "Normal",
            group: 'ck_group',
            command: 'contextmenu_p'
        },

        h3: {
            label: "Heading",
            group: 'ck_group',
            command: 'contextmenu_h3'
        },

        h4: {
            label: "Sub Heading",
            group: 'ck_group',
            command: 'contextmenu_h4'
        },

        pre: {
            label: "Formatted",
            group: 'ck_group',
            command: 'contextmenu_pre'
        },

        imageinline: {
            label: "Image inline",
            group: 'ck_group',
            command: 'contextmenu_imageinline'
        },

        imagecentered: {
            label: "Image centered",
            group: 'ck_group',
            command: 'contextmenu_imagecentered'
        },

        imagecenteredwithdropshadow: {
            label: "Image centered drop shadow",
            group: 'ck_group',
            command: 'contextmenu_imagecenteredwithdropshadow'
        },

        figureheading: {
            label: "Figure/Table heading",
            group: 'ck_group',
            command: 'contextmenu_figureheading'
        },

        equation: {
            label: "Equation",
            group: 'ck_group',
            command: 'contextmenu_equation'
        },

        equationdefinition: {
            label: "Equation definition",
            group: 'ck_group',
            command: 'contextmenu_equationdefinition'
        },

        tablewithoutborder: {
            label: "Table without border",
            group: 'ck_group',
            command: 'contextmenu_tablewithoutborder'
        }
    });

    editor.contextMenu.addListener(function (element, selection, elementPath) {

        var contentMenuItems = {
            link: CKEDITOR.TRISTATE_ON,
            bold: CKEDITOR.TRISTATE_ON,
            numberedlist: CKEDITOR.TRISTATE_ON,
            bulletedlist: CKEDITOR.TRISTATE_ON,
            iconselector: CKEDITOR.TRISTATE_ON,
            formatting: CKEDITOR.TRISTATE_ON
        };

        if (element.getAscendant('a', true)) {
            //If we are already inside 'a' tag then remove link from Context menu else we will end up with two "Link" menus
            delete contentMenuItems.link
        }

        if ($.trim(selection.getSelectedText()) === '') {
            //If no text is selected then remove bold from context menu
            delete contentMenuItems.bold;

            //Similarly remove link if nothing is selected as it will insert hyperlink text as words inside CKEditor
            delete contentMenuItems.link;
        }

        return contentMenuItems;
    });
});

我知道代码太多但我找不到其他任何简单的方法。

当完成所有这些是它的样子: CKEditor Nested Context Menu

快速回顾:

  • 为“格式化组合”中显示的每个项目创建插件
  • 只更改所有plugin.js文件pluginName(它是文件夹的名称)
  • 扩展CKEditor并添加将由plugin.js文件调用的applyFormatStyles方法
  • 在您的配置文件中添加所有这些作为额外的插件
  • 创建CKEditor实例扩展上下文菜单