CKEditor:多个小部件模板

CKEditor: multiple widget templates

我目前正在创建一个 'smartobject' 小部件。在小部件对话框中,用户可以选择 'smartobject',简单地说,生成一些 html,应该将其添加到编辑器中。棘手的部分来了:html 有时是 div 元素,有时只是跨越元素。在 div 变体的情况下,小部件应包装在 div 'template' 中。在 span 变体的情况下,小部件应包含在 span 中,并且应添加 html 'inline'。

在小部件中 API 我看到了以下定义模板的方法:

editor.widgets.add('smartobject', {
                dialog: 'smartobject',
                pathName: lang.pathName,
                template: '<div class="cke_smartobject"></div>', // <------

                upcast: function(element) {
                    return element.hasClass('smartObject');
                },

                init: function() {
                    this.setData('editorHtml', this.element.getOuterHtml());
                },

                data: function() {
                    var editorHtml = this.data.editorHtml;

                    var newElement = new CKEDITOR.dom.element.createFromHtml(editorHtml);

                    newElement.copyAttributes(this.element);

                    this.element.setText(newElement.getText());
                }
            });

但在我的例子中,模板更加动态:有时 div 有时 span 会做正确的事情..

如何解决这个问题而不需要创建两个完全相同的小部件,只是包装元素有所不同?

我已经尝试在 'data' 方法中替换整个元素,例如:

newElement.replace(this.element);
this.element = newElement;

但这似乎不受支持:调用 editor.getData() 后导致未定义的错误。

我正在使用 ckeditor v4.5.9

感谢您的帮助!

正如 this ckeditor 论坛帖子中所建议的那样,最好的方法是将模板设置为包含所有可能的内容元素。然后,在data函数中,根据你的具体逻辑去掉不需要的部分。

看来我成功了(有解决方法)。 代码:

CKEDITOR.dialog.add('smartobject', this.path + 'dialogs/smartobject.js');

        editor.widgets.add('smartobject', {
            pathName: lang.pathName,

            // This template is needed, to activate the widget logic, but does nothing.
            // The entire widgets html is defined and created in the dialog.
            template: '<div class="cke_smartobject"></div>',

            init: function() {
                var widget = this;
                widget.on('doubleclick', function(evt) {
                    editor.execCommand('smartobject');
                }, null, null, 5);
            },

            upcast: function(element) {
                return element.hasClass('smartObject');
            }
        });

        // Add a custom command, instead of using the default widget command,
        // otherwise multiple smartobject variants (div / span / img) are not supported. 
        editor.addCommand('smartobject', new CKEDITOR.dialogCommand('smartobject'));

        editor.ui.addButton && editor.ui.addButton('CreateSmartobject', {
            label: lang.toolbar,
            command: 'smartobject',
            toolbar: 'insert,5',
            icon: 'smartobject'
        });

在对话框中,插入代码如下所示:

return {
    title: lang.title,
    minWidth: 300,
    minHeight: 80,

    onOk: function() {
        var element = CKEDITOR.dom.element.createFromHtml(smartobjectEditorHtml);

        editor.insertElement(element);

        // Trigge the setData method, so the widget html is transformed,
        // to an actual widget!
        editor.setData(editor.getData());
    },
...etc.

更新 我改进了 'onOk' 方法:插入后现在选择了 smartobject 元素。

onOk: function() {
        var element = CKEDITOR.dom.element.createFromHtml(smartobjectEditorHtml);
        var elementId = "ckeditor-element-" + element.getUniqueId();

        element.setAttribute("id", elementId);

        editor.insertElement(element);

        // Trigger the setData method, so the widget html is transformed,
        // to an actual widget!
        editor.setData(editor.getData());

        // Get the element 'fresh' by it's ID, because the setData method,
        // makes the element change into a widget, and thats the element which should be selected,
        // after adding.
        var refreshedElement = CKEDITOR.document.getById(elementId);
        var widgetWrapperElement = CKEDITOR.document.getById(elementId).getParent();

        // Better safe then sorry: if the fresh element doesn't have a parent, simply select the element itself.
        var elementToSelect = widgetWrapperElement != null ? widgetWrapperElement : refreshedElement;

        // Normally the 'insertElement' makes sure the inserted element is selected,
        // but because we call the setData method (to ensure the element is transformed to a widget)
        // the selection is cleared and the cursor points to the start of the editor.
        editor.getSelection().selectElement(elementToSelect);
    },

所以简而言之,我部分地使用了小部件 API 作为我想要的部分: - 使小部件的 html 不可编辑 - 使其可移动

但我创建了一个自定义对话框命令,它简单地绕过了默认的小部件插入,因此我可以完全决定我自己的 html 小部件结构。

一切似乎都是这样。

如有任何改进建议,我们将不胜感激:)!