Undocumented CKEditor hack to do your own image uploads.

CKEditor - when insert_image button has been clicked

 

OVERVIEW

CKeditor is notorious for its bad documentation and often people have to run around in circles when they have to write plugins or finding ways of customizing its behavior. One of the most common problems faced is generally to do with image insertions in the text or uploading images.

The official way to customize your own image uploads is to write your own plugin. But a ckeditor plugin has its limitations so there are limits to how much you can customize.

We recently implemented our own image uploading method for a project which uses ckeditor. Part of it uses an unofficial hack , but it turned out to be the simplest and most direct way of getting the custom uploader to work.

 

STEPS TO FOLLOW

1.    Creating the custom upload form
2.    Adding a custom icon in the ckeditor toolbar to invoke the form
3.    Making a ckeditor plugin to open the custom upload form in ckeditor
4.    Integrating the custom upload form with the custom toolbar icon
5.    Inserting the uploaded image into the ckeditor text
6.    Invoking the standard Image attributes dialog form

 

SIMPLE  EXPLANATION

We will first go through the visual steps of how the above steps work

STEP 1 – Creating the custom upload form

This step is completely independent of ckeditor. We can set up our own way of uploading images, in whatever way we want and store it whereever we want to. The form we have used is shown below:

Custom Image upload form

This form uploads an image on the server side, updates the database if required and does other housekeeping functions.

 

STEP 2  – Adding a custom icon in the ckeditor toolbar to invoke the form

This step is taken care of in Step 3 below . The icon needs to be a 16×16 png image as shown below:

STEP 3 – Making a ckeditor plugin to open the custom upload form in ckeditor

Since we want to invoke our own custom image uploader form from ckeditor , we need to write a ckeditor plugin. This plugin will
•    Add a custom icon to the ckeditor toolbar
•    Call the custom image upload form when this icon is clicked

Once the plugin is in place, the custom icon appears as shown in the screenshot below:

toolbar icon

 

STEP 4 – Integrating the custom upload form with the custom toolbar icon

Once the plugin is hooked to the custom icon, we use the plugin to call our custom uploader form in an iframe. This makes it look like the custom upload form is a native ckeditor dialog, because the plugin frame automatically takes on the appearance of a ckeditor dialog.

See the screenshot below:

custom dialog

 

STEP 5 – Inserting the uploaded image into the ckeditor text

Once the image is uploaded, then it calls a javascript function in the plugin.js javascript to insert a new image tag into the current cursor location in ckeditor.

STEP 6 – Invoking the standard Image attributes dialog form

Once the image has been inserted into ckeditor, we hook the click event of the standard image attributes icon in the ckeditor toolbar to open up with the inserted image selected.

See screenshot below:

Image Attributes Dialog

 

TECHNICAL EXPLANATION

FILES/FOLDERS

 

All the actual files will be in our custom plugin folder which itself goes into the ckeditor/plugins folder.  Our plugin is called testimage so all our files go into the folder ckeditor/plugins/testimage

These files are:

  • Expanding-image-mouse-out.png – the image for the toolbar icon
  • form.php – our custom uploader form which will be called within the plugin
  • loading.gif – image used in the custom uploader form
  • plugin.js – the definition file for our plugin
  • uploadimage.php  – this file is called from form.php to handle the actual upload and server-side processing

Apart from this, we need to change ckeditor/config.js to specify our plugin. This involves two steps:

  • Specifying the location of our plugin icon in the toolbar configuration array.
  • Adding our plugin name to the extraPlugins property of ckeditor.

Since our plugin folder is called testimage (case sensitive), the icon specified in the toolbar configuration array has to be exactly the same name. This is shown below:

 

PROCESS SEQUENCE

The sequence diagram given below shows the how the process flow works:

See Sequence Diagram

 

INSERTING THE UPLOADED IMAGE INTO THE CKEDITOR TEXTAREA

Once we have uploaded the image to the server and we have the full path available to us, we use the function CKEDITOR.instances.(our instance name).insertHTML() function to insert an IMG tag with the full image path.

We assign our own id atribute to the image tag. Note that if multiple images will be inserted then the id has to be unique across all images. Our approach is to generate a unique id from the server-side code which uploads the image and then pass this id to the client-side script.

 

SELECTING THE INSERTED IMAGE

Once the image is inserted, we create a javascript variable to the image element by the following code:

var element  = CKEDITOR.instances.(our instance name).document.getById(whatever id attrib the image tag has been given)

Once the element is obtained, we select it in Ckeditor by:

CKEDITOR.instances.(our instance name).getSelection().selectElement(element);

 

CALLING THE IMAGE ATTRIBUTES DIALOG IN CKEDITOR

When the previous step is executed, the image is selected in ckeditor. Now we need to popup the image attributes dialog. To do this we use an undocumented method of hooking the onclick function of the image icon in the ckeditor toolbar.

Each icon in the toolbar is assigned an onclick function which is a number eg.1,2,4,25 ,36 etc.  A particular icon’s onclick function can be found out by using Firebug or a similar tool.

So if we find that the image icon has a function called 49, then we call it by:

CKEDITOR.tools.callFunction(49, this);

IMPORTANT TO NOTE: The function numbers will change as per the current toolbar configuration. In other words, depending on the placement of the icons on the toolbar, the function numbers are assigned by ckeditor. So if you switch toolbar configurations then the function number will change. If you are using different toolbars in various pages, then its best to create a generic javascript function where the function number is passed as an argument and then then the call can be made as :
function clickfunction(num){
CKEDITOR.tools.callFunction(num, this);
}

 

FILE LISTINGS

The toolbar configuration in config.js with the custom icon is shown below. Note the extraPlugins attribute being set at the bottom.:

 config.toolbar = 'Full';
 
config.toolbar_Full =
[
    ['Source','-','Save','NewPage','Preview','-','Templates'],
    ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
    ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
    ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
    '/',
    ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
    ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
    ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
    ['BidiLtr', 'BidiRtl'],
    ['Link','Unlink','Anchor'],
    ['Image','testimage','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak','Iframe'],
    '/',
    ['Styles','Format','Font','FontSize'],
    ['TextColor','BGColor'],
    ['Maximize', 'ShowBlocks','-','About'],
];
 config.extraPlugins = "testimage";

The plugin.js listing is given below. The addIFrame() method is used to link the external upload form to the plugin:

CKEDITOR.plugins.add('testimage',
{
    requires: ['iframedialog'],
	init:function(editor){
		editor.addCommand('testimage', new CKEDITOR.dialogCommand('testimage' )); // associating the executable code with the button
		editor.ui.addButton('testimage',
		{
			 label:'Expanding Image',
			  command : 'testimage',
			 icon: this.path + 'Expanding-image-mouse-out.png',
							  
		 });
		 CKEDITOR.dialog.addIframe( 'testimage', 'upload image', 'ckeditor/plugins/testimage/form.php', 500, 400); 
   },
  
});
function closedialog(url)
{
	
	CKEDITOR.dialog.getCurrent().hide();
	
}
function setText(image_path,id,toolNum) {
	CKEDITOR.instances.FCKeditor1.insertHtml('<img src=\x22' + image_path + '\x22 border=0 id=image'+id+'>'); 
	var element = CKEDITOR.instances.FCKeditor1.document.getById( 'image'+id );
	CKEDITOR.instances.FCKeditor1.getSelection().selectElement( element );
	getToolbar(toolNum);

}
function getToolbar(num) {
	
	CKEDITOR.tools.callFunction(num, this); return false;
			
}	

The critical functions which make it all come together are setText() and getToolbar()

 

In setText() the image path is passed from the server-side code to the ckeditor. Then this path is inserted into ckeditor. Since we cannot directly insert quotes into ckeditor we escape it by x22 within the img tag.

The toolNum argument contains the function number which has to be called within ckeditor to popup the image attributes dialog after the image is inserted and selected in ckeditor.

 

CALLING THE PLUGIN.JS JAVASCRIPT FUNCTIONS FROM SERVER-SIDE CODE

We have used PHP here for server-side but the logic is applicable to any language.

Once the image has been uploaded and processed, the server-side script should have the image file path, the image tag id to be used and optionally the ckeditor function number to be called in plugin.js .  The code below uses JQuery to call the javascript functions in plugin.js

We have used a php variable called $uploaded to check for a successful upload and $url to store the full image path. $new_id stores the img tag id to be used. $toolbarNum is the function number to be called in ckeditor.

<script language="Javascript" src="../../../includes/jquery-1.5.1.min.js"></script>

<script language="Javascript">
	$(document).ready(function() {		
	
		<?php if ($uploaded) { ?>
			  window.parent.closedialog();
				window.parent.setText('<?php echo($url);?>', '<?php echo($new_id);?>', '<?php echo($toolbarNum)?>');
		<?php } ?>
	});
	
</script>

HOOKING THE CLICK FUNCTION FOR A TOOLBAR ICON

Check the image below on what to look for, if you are using FireBug

Firebug Hooking onclick function

9 Comments

  1. Hi, your plugin is exactly what I’ve been looking for. I ported it to my asp.net project and it worked as expected, with just one little thing. The last comma of line 10 and 14 in your plugin.js break IE6 compatibility. I know I know, but just in case anyone has stupid users who still use that stupid browser, this may help.

    • Yong, glad it was of help. Thanks for pointing out the IE6 incompatibility. I cant think of anyone using IE6 in 2012, but thanks for your comment.

Leave a Reply to Yong Cancel reply

Your email address will not be published.


*