2012/09/09

Adjusting a CKEditor plugin to be compatible with v3 and v4

Recently CKSource announced the first beta of the new CKEditor 4, and along the improvements, it also brings some changes of the API. You can read about those changes in the included API-CHANGES.md file (open it with any text editor, I don't know if there's an easier way to read it correctly)

I'm gonna record here the changes that I have to go through to update my plugins when I touch them (although I'm not gonna try to do full testing until it goes out of beta).

Translations

The first breaking change is that CKEDITOR.plugins.setLang has changed, so now when you pass the object with the translations it must not include the "parent" object, as the doc says:

So, in v3 we had:

    CKEDITOR.plugins.setLang( 'myplugin', 'en',
    {
        myplugin :
        {
            title : 'My Plugin'
        }
    });
In v4 it should be changed to:
    CKEDITOR.plugins.setLang( 'myplugin', 'en',
    {
        title : 'My Plugin'
    });

That's good if you want to release a plugin only for v4 or you plan to ignore it, but if you want to be ready to upgrade and try to make your code compatible with both v3 and v4 you now have a problem because the name of the function hasn't changed but the expected parameters have done so.

So my solution is to create a new helper function and call this one instead of CKEDITOR.plugins.setLang:

CKEDITOR.addPluginLang = function( plugin, lang, obj )
{
    // v3 using feature detection
    if (CKEDITOR.skins)
    {
        var newObj = {};
        newObj[ plugin ] = obj;
        obj = newObj;
    }
    CKEDITOR.plugins.setLang( plugin, lang, obj );
}

This way, we use the new format for the obj parameter, but if the function detects that it's running in v3 it adds the plugin name as the root of all the strings

CKEDITOR.addPluginLang( 'myplugin', 'en',
{
        title : 'My Plugin'
});

Spacer image

Another change is that they decided that leaving the images/spacer.gif file there was polluting the global scope, so now you just have to copy that image in every plugin to be sure that it's included in the install and then adjust the paths in your code to use this copy of the image. It's not a big deal, but certainly to me it doesn't seem a big problem to leave that simple image in a common place so it can be easily reused.

Adding CSS

The doc explain this about this change:

The "additional CSS" feature provided by `CKEDITOR.editor::addCss` is now moved
to a global `CKEDITOR.addCss`, with specified style rules applies **document wide**.

Thus the proper way for a plugin to style it's editable content is to call `CKEDITOR.addCss`
inside of the plugin's `onLoad` function, rather than it's `init` function in v3.

So in order to make your code work in both versions you have to use something like this:

...
    getPlaceholderCss : function()
    {
        return 'img.cke_video' +
                '{' +
                    'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/placeholder.png' ) + ');' +
                    'background-position: center center;' +
                    'background-repeat: no-repeat;' +
                    'background-color:gray;'+
                    'border: 1px solid #a9a9a9;' +
                    'width: 80px;' +
                    'height: 80px;' +
                '}';
    },

    onLoad : function()
    {
        // v4
        if (CKEDITOR.addCss)
            CKEDITOR.addCss( this.getPlaceholderCss() );
    },

    init : function( editor )
    {
....
        // v3
        if (editor.addCss)
            editor.addCss( this.getPlaceholderCss() );
...

 

 

So this is all for the moment. I'll keep editing this post in the future as I upgrade more code.