Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems with a custom self-closing tag in CKEditor

I have a plugin for inserting tag <cut /> in text. It works fine, result is expectable, but in editor window <cut /> transforms into <cut></cut>, wraps the paragraphs below and hampers further edits.

GIF - http://gyazo.com/dd7c36ba7cb7bc7cb00186cfb83e5fbc

Any ideas how to fix it?

CKEDITOR.plugins.add('pagecut', {
lang: 'de,en,ru',
onLoad: function(){
    var css = ('display:block;clear:both;width:100%;border-top:#999 1px dotted;padding:0;height:1px;cursor:default;');
    var cssBefore = (
            'content:"";' +
            'background: url(' + CKEDITOR.getUrl( this.path + 'images/image.png' ) + ') no-repeat right center;' +
            'height:14px;width:25px;position:relative;display:block;top:-8px;float:right;'
        );
    CKEDITOR.addCss( 'cut{' + css + '} cut:before{' + cssBefore + '}' );
},
init: function(editor) {
    CKEDITOR.dtd['cut'] = {};
    CKEDITOR.dtd.$empty['cut'] = 1;
    CKEDITOR.dtd.$nonEditable['cut'] = 1;
    CKEDITOR.dtd.$object['cut'] = 1;
    editor.addCommand('insertPagecut', {
        exec: function(editor) {
            var element = CKEDITOR.dom.element.createFromHtml('<cut />');
            editor.insertElement(element);
        }
    });

    editor.ui.addButton('Pagecut', {
        label: editor.lang.pagecut.toolbar,
        command: 'insertPagecut',
        icon: this.path + 'images/icon.png',
        toolbar: 'links'
    });
}
});
like image 748
ArtyGrand Avatar asked Apr 11 '15 17:04

ArtyGrand


1 Answers

Uh, I'm sure that I explained this thoroughly in some question, but I can't find it, so here goes another explanation :D.

There are two important facts that one must understand before trying to edit non-HTML tags in CKEditor:

  1. CKEditor is an HTML editor.

    Of course custom tags start to be more and more popular in HTML. You can also say that XML is some kind of generalisation of HTML (although not precisely, because it has other rules), so if CKEditor handles HTML why doesn't it handle other tags equally well. Well - the answer is simple - because HTML tags have a meaning and CKEditor knows it. But it does not know meaning of your custom tags. And the meaning of tags (what a list is, that it has items, that they are block elements, etc.) is crucial to implement editing algorithms.

    Fair enough, you could say. But why wasn't CKEditor's configuration (e.g. the CKEDITOR.dtd object) generalised so meaning of every possible tag can be configured? Because every generalisation increases complexity and HTML editing is already complex enough.

    So why does the CKEDITOR.dtd object exist at all? Because some components of CKEditor are configurable to some extent. The DTD has the biggest impact on CKEditor's HTML parser (which is used mostly during data processing) so this is the most configurable component. Other algorithms, like the enter key handling, backspace/delete, lists editing (which is a very complex task) are only slightly configurable and there is no guarantee given that they will work with your custom tags.

  2. The editing happens in the browsers and is partially handled by the browsers.

    This fact is important because it means that browsers' capabilities are affecting CKEditor's limits too. Browser must be able to parse and render your tags (fortunately, this part works rather well in modern browsers - IE8 is the last one with a huge problems) and must be able to edit it. This means - render caret, handle selection, handle backspace, enter, etc. Since browsers are not easily extensible and their implementations of contentEditable are highly inconsistent, incompatible and buggy, from release to release CKEditor overrides more and more of their native behaviours. Not all yet (actually - it will never override all, because that could be disastrous for certain reasons), but a significant amount. For instance, all the enter key behaviour is custom, on Webkit and Blink CKEditor handles backspace and delete in many scenarios due to still unresolved bugs (1 and 2), it implements its own undo system, intercepts pasted and dropped content and perform custom HTML insertion (I remember that when we implemented it this closed a huge number of tickets), etc., etc.

    One of the greatest efforts to ensure consistent, configurable and powerful editing experience is the widgets system. It is full of hacks inside, but it exposes a clean and pretty powerful API to the developer and a very consistent behaviour to the end user. It allows to implement a "special rich content units that are groups of elements which are treated as a single entity inside the editor". So the widgets system has the power to encapsulate part of your content and isolate it from the browsers.

After this short introduction I can finally answer your question. You need to implement your <cut> tag as a widget. You already configured your DTD pretty well (you only forgot to set in what elements the <cut> element can exist and whether it is more like a block or inline element), so the parser will accept it and handle as an empty tag. Now you need to wrap it with a widget in order to isolate it so it does not break the editing experience. That should do the trick.

like image 141
Reinmar Avatar answered Oct 16 '22 02:10

Reinmar