Feđa Feđa - 2 months ago 16
HTML Question

Add class to selected image in ckeditor

I'm having trouble adding classes to selected image in ckeditor. What I came up with is this http://pokit.org/get/img/8d89802e1d6f6371f5bc326898d8b414.jpg.

I added 2 buttons for selecting whether whether a picture is in portrait or landscape mode. You can select either of them or none, and add costum height/width.

Here is my code:

CKEDITOR.replace('maindesc', {
"extraPlugins": "imgbrowse",
"filebrowserImageBrowseUrl": "/ckeditor/plugins/imgbrowse",
on: {
instanceReady: function() {
this.dataProcessor.htmlFilter.addRules( {
elements: {
img: function( el ) {
// Add an attribute.
if ( !el.attributes.alt ) {
el.attributes.alt = 'Img';
el.addClass('ckeditorImg');
if (Landscape == 1) {
el.addClass('ckLandscape');
el.attributes['style'] = '';
}
else if (Portrait == 1) {
el.addClass('ckPortrait');
el.attributes['style'] = '';
}

}

}
}
} );
}
}
});


So as far as I understand this goes through all, so I wrote that if the image has no alt attribute to add one and add the classes I want. Unfortunately this approach doesn't allow me to change the class on selected image when a user wants to change it, but instead he has to delete the image, select it again and then choose class.

My question is whether there is a way to get to currently selected image instead of going through all
<img>
tags in ckeditor and change its class.

Answer

Here is an example for how to add a new button to ckeditor that is enabled/disables based on the element that you currently select and add a class to that specific element (in this example it's for images, however you can use it in any way you want).

// Set the callback function 
var setLandscapeClass = {
    exec: function(editor) {
        editor.getSelection().getStartElement().addClass('ckLandscape')
    }
}

//Create the plugin
CKEDITOR.plugins.add('setLandscapeClass', {
    init: function(editor) {
        editor.addCommand('setLandscapeClass', setLandscapeClass);
        editor.ui.addButton("setLandscapeClass", {
            label: 'Set Landscape Class', 
            icon: '',
            command: 'setLandscapeClass'
        });
    }
}); 

// Create the instance and add the plugin
CKEDITOR.replace( 'editor1', {
    extraPlugins: 'setLandscapeClass',
    allowedContent: true
});

// enable/disable the button based on the selection of the text in the editor
CKEDITOR.instances.editor1.on( 'selectionChange', function( evt ) {
    var landscapeButton = this.getCommand( 'setLandscapeClass' );
    if ( evt.data.path.lastElement.is( 'img' ) ) { 
        landscapeButton.enable();
    } else {
        landscapeButton.disable();
    }
});

You can see a working demo here:
https://jsfiddle.net/7nm9q1qv/

I only created 1 button, and there is no icon there. I think you can use that code to create also the second button (for portrait class).

Update - add item to the context menu

In order to add a new item to the context-menu you should add this code:

// Add the context-menu
if (editor.addMenuItem) {
      editor.addMenuGroup('testgroup');
      editor.addMenuItem('setLandscapeItem', {
            label: 'Set landscape class',
            command: 'setLandscapeClass',
            group: 'testgroup'
      });
}

// On contextmenu - set the item as "visible" by the menu
if (editor.contextMenu) {
    editor.contextMenu.addListener(function(element, selection) {
        if (element.hasClass('ckLandscape') === false) {
            return { setLandscapeItem: CKEDITOR.TRISTATE_ON };
        }
    });
}

Inside the init function of the plugin you add.

You can see that I added this line:

if (element.hasClass('ckLandscape') === false) {

(Which you can remove) only to give you an example of how to show the item in the menu only if the ckLandscape class doesn't exists for this image.

The updated version of the jsfiddle is here:
https://jsfiddle.net/7nm9q1qv/1/