In this post I will show you how to build plugins for CKEditor. I will focus on how can take your exisiting functionality and integrate into the editor without rewriting everything.
Background
I have been using CKEditor for my later projects and and before that I used FCKEditor which was the ancestor. Untill lately I have not really touched at building plugins, partially because I found it a bit intimidating.
When I did create this blog I needed the functionality to insert links to my images and files without having to manually copy & paste any links. Luckily there is an very very easy way to insert html into the CKEditor.
editor.insertHtml(html);
That simple line of code will insert the html where the carret is. So for this blog I simply created an image browser and a file browser and when you click on the file or image you want to insert some javascript triggers and insert the proper html into the editor. And the browsers where triggered by clicking an link which I placed in a flyout at the side of the page.
If I click the link I get the dialog
End of story... well not quite!
When I build this blog for me things like usability and great UI didn't have much priority. I mean if the customer(which is only me) wants to whine I'll just tell him get of his lazy ass and fix it himself. In the real world though there is not always(probably never) that luxory.
In another project I needed about the same functionality but here normal people, you know those who calls or emails you as soon as something is right under their nose, will use the editor so I decided that the links must be integrated into the toolbar with all the other commands. I had no issues with allowing custom modal windows instead of the default one from CKEditor but the links to start the browsers should be on the toolbar.
Getting started with building the plugin
In constrast to FCKEditor there actually s some documentation about CKEditor. You can find it here but it's not an easy thing to understand so It is probably better to look at the source code of some of the other plugins which can be found in the _source->plugins folder if you have downloaded the editor.
Each plugin has it's own directory with a file named plugin.js inside. And then there is often a folder named dialogs with a javascriptfile that creates the dialog. In my case I did not need a dialog because I would use my custom ones so my folder structure is slightly different.
Above is my structure and below is the normal structure with the dialogs folder.
Here is the code in plugin.js
/**
* @file Gmok Documents plugin
*/
CKEDITOR.plugins.add('gmokimages',
{
init: function (editor) {
var pluginName = 'gmokimages';
editor.addCommand(pluginName,
{
exec: function (editor) {
showImageDialog(editor);
},
canUndo: false // No support for undo/redo
});
// Register the toolbar button.
editor.ui.addButton('GmokImages',
{
label: editor.lang.gmokImages.toolbar,
command: pluginName,
icon: this.path + "images/images.png"
});
}
});
If you have ever looked at the source of a normal CKEditor plugin you will recognize the pattern. You register the plugin and in the init function you first register the command you need to open your dialog and then you add a button bound to that command.
The only thing that is different is the command I register and that I don't register any dialog. Here is how the normal commands look.
var findCommand = editor.addCommand( 'find', new CKEDITOR.dialogCommand( 'find' ) );
And in a normal plugin I would register the dialog
CKEDITOR.dialog.add( 'find', this.path + 'dialogs/find.js' );
So instead of adding a command to open the dialog defined in find.js as above add a totally custom function and I decide to use the convention that everywhere I use the the editor there should be a js function showImageDialog.
Now you might wonder how the editor knows that you plugin should be used? Well, right now it does not. You need to open the file config.js in the root of the editor folder and add a few lines. Here is how my configuration looks like(Code removed for clarity):
CKEDITOR.editorConfig = function( config )
{
// Define changes to default configuration here. For example:
config.extraPlugins = 'gmokdocuments,gmokimages';
config.toolbar = 'GmokFull';
config.toolbar_GmokFull =
[
['Image', 'Table', 'SpecialChar'],
['Link', 'Unlink', 'Anchor'],
['GmokDocuments','GmokImages']];
};
There is two things that you must do. First you must register the plugin by setting config.extraPlugins and then you must define you own toolbar configuration which includes you plugin.
With this done you will see a button in the toolbar if you run a page with the editor inside.
But if you would click the button you would get an exception at this point because the function showImageDialog is not defined yet.
Inserting the html
I use jQuery UI in this project so I have access to the dialog widget which is great for showing modal dialogs. So what I do is that I make an ajax request to load the data and then I place the response in a elemet on the page which is placed inside the dialog. And then I bring up the dialog.
function showImageDialog(editor) {
activeEditor = editor;
if (!loaded) {
$.get($("#navButtons").children(".fg-button.ui-state-active").attr("href"), function (data) {
$('#imageBrowser').html(data);
$("#imageBrowserWrapper").dialog('open');
loaded = true;
});
}
};
I also save the editor reference for later use. We will need this when we are going to insert the html.
Basically the code above combined with some html creates the following dialog
And when an image is clicked we can simply build whatever html we want from that and insert into the editor by the the handy insertHtml function.
activeEditor.insertHtml('<img src="' + src + '" alt="" />');
The drawbacks
It is a bit awkward to have the plugin calling a method which I define in my normal pages. It is certainly a decision that will not fit everyone but for me it was better because now I coud use my existing image browser without making a special implementation for CKEditor. There is also another drawback in that you can't edit an image as you can if you use the normal image tool. But the purpose here was rather to provide a solution that would allow linking a thumbnail to it's fullsize image and create slideshows(using fancybox) by providing the image grouping.
Conclusion
To register plugins into CKEditor is really simple and even though the documentation is at best scarce you will most likely be able to figure it out by looking at the source of the included plugins. In fact it might benefit you as a developer to spend some time at figuring out how things work from the source rather then getting ready samples served. Reading code is a great way to learn more about programming if you give it some time.