Web Development Blog

Adding the "rel" and "title" attributes to image links in CKEditor 3

01.08.2010 01:37PM by Evan Johnson

CKEditor is the new and improved successor to the venerable FCKeditor JavaScript WYSIWYG editor. I've used TinyMCE and FCKeditor before, but this was my first time trying out the new CKEditor 3.1. I am using it on a new Drupal website via the Drupal CKEditor module. The problem I ran into, however, is using Lightbox2 on images inserted via CKEditor. CK does not provide a way to add the "rel" attribute to image links (or any links for that matter). CK also doesn't allow adding the "title" attribute to image links. Lightbox uses both of these to determine which images to display, group together in galleries, provide a caption, etc. I found a patch for FCKeditor which allows adding a "rel" attribute to image links, but I couldn't find one for the new CKEditor. So here we are. :)

This is a total hack, since I have not looked in to how to properly make a plugin for the new CKEditor, but it works pretty well. Maybe someone who knows how to make plugins to CKEditor can show me the way.

To start hacking, we need to first copy over the minified ckeditor\plugins\image\dialogs\image.js with the indented ckeditor\_source\plugins\image\dialogs\image.js, since it's really hard to work with the minified image.js.

In image.js all of the tabs and fields in the Image popup dialog are defined in the "contents" array (below the onHide function). We will add our new "rel" and "title" fields to the content array, in the "Link" tab's sub-array. I added the new code at the end of the Link tab's definition array after the txtUrl, browse, and cmbTarget fields (around line 1146). The code I added is:

{
id : 'txtTitle',
type : 'text',
label : editor.lang.link.advisoryTitle,
'default' : '',
setup : function( type, element )
{
	if ( type == LINK )
	{
		this.setValue( element.getAttribute( 'title' ) );
	}
},
commit : function( type, element )
{
	if ( type == LINK )
	{
		if ( this.getValue() || this.isChanged() )
		{
			element.setAttribute( 'title', this.getValue() );
		}
	}
}
},
{
id : 'txtRel',
type : 'text',
label : editor.lang.link.rel,
'default' : '',
setup : function( type, element )
{
	if ( type == LINK )
	{
		this.setValue( element.getAttribute( 'rel' ) );
	}
},
commit : function( type, element )
{
	if ( type == LINK )
	{
		if ( this.getValue() || this.isChanged() )
		{
			element.setAttribute( 'rel', this.getValue() );
		}
	}
}
},

This adds a _txtTitle_ and _txtRel_ field to the Link tab on the Insert Image CKEditor dialog. Look out for commas! The first time I did this I missed a comma between the cmbTarget and txtTitle declarations, which borked everything.

The final thing we need to do is create the "editor.lang.link.rel" English translation definition so the new _txtRel_ field is properly labeled in the dialog (I re-used the existing "editor.lang.link.advisoryTitle" translation for _txtTitle_). To do this, open up _ckeditor\lang\en.js_. I added the following snipped between _styles_ and _selectAnchor_ in the "Link" block, but just make sure it's in the "Link" block of translations.

rel:'Rel',

You could probably hard-code this label, but I kept with the translation system. I didn't do any labels except the English one, but you get the idea. If you are using another language insert the "rel" label into the appropriate file for that language.

You can now set the "rel" and "title" attributes on the image link, and use them with the Lightbox of your choice!

Comment

Gravatar Image
On Jan 11, 07:42 PM, (Link)
Wesley said:

Evan,

How does CKeditor’s markup output look compared to TinyMCE? I’ve used TinyMCE quite a bit but I’ve been disappointed with the quality of markup it produces, even after I customize it. I’ve been using Tidy on the server to clean up what I don’t like about TinyMCE but would rather avoid that process.

cheers,
Wes

Gravatar Image
On Jan 14, 11:25 AM, (Link)
Evan Johnson said:

@Wesley

Well, I mean nothing beats custom markup, but it seems to be okay. There is some extra whitespace in the lists, but everything renders OK. CK uses em instead of i and all that jazz too. Defining custom styles works well too. Good enough for me!

Gravatar Image
On Feb 2, 05:17 AM, (Link)
Dennis said:

It doens’t work for me :(… I do excactly what is said in the tutorial but my image popup dialog doesnt open. Does someone has a complete image.js where the rel code is added already?

thanks,

Dennis

Gravatar Image
On Feb 17, 03:41 PM, (Link)
Martin said:

Hey Evan, thank you very much for your hack!
BUT!!!! This is NOT correct if ( type LINK )

right way is… if ( type == LINK )

Thanks, bye.
m

Gravatar Image
On Feb 17, 04:44 PM, (Link)
Evan Johnson said:

@Martin – Right you are! The stupid Textile markup converter processes the "==" and removes it. I fixed the code in article above.

@Dennis – perhaps this fixed your problem as well?

Sorry folks, it should work now!

Gravatar Image
On Feb 26, 12:36 PM, (Link)
Jeff said:

How about create a diff patch for this? It’s hard to tell where to start the paste of your code, since there is no context.

Gravatar Image
On Feb 26, 01:19 PM, (Link)
Jeff said:

Also, just as a note: something similar can be achieved without hacking for Drupal users, using the Lightbox2 module. One can configure a class of image to have the lightbox rel link automatically included, so it’s as simple as adding a link and a class when inserting an image from CKEditor. The Lightbox2 module does the rest.

Gravatar Image
On Mar 3, 01:41 PM, (Link)
Mark Peters said:

FYI:

I was able to get this working on the recently updated v3.2 of CKeditor.

I had problems with getting the entry field label to appear using the the en.js language file until I copied over a the not minified js version from the source.

Gravatar Image
On Mar 3, 09:34 PM, (Link)
Evan Johnson said:

@Jeff – I have not had the time to roll a proper Diff, sorry it’s confusing about where to insert the code. I will try to get around to this eventually. Also, you make a good point about the Drupal Lightbox2 module. Thanks!

Gravatar Image
On Mar 9, 08:36 AM, (Link)
Joshua Lowery said:

Okay everyone…this frustrated the heck out of me but I finally got it to work. I figured I’d share it with you all and make your life’s a lot easier.

I’m using: – Drupal 6.16 – CKEditor 3.1 – My Brain

Replace ckeditor\plugins\image\dialogs\image.js with this file.

http://docs.google.com/leaf?id=0B-AxBjS8xkHmZDNiN2IwMTItMDkzMS00NzZmLTkxYjAtNzc1ZjBjODA5ZTEz&hl=en

Replace ckeditor\lang\en.js with this file.

http://docs.google.com/leaf?id=0B-AxBjS8xkHmNTFlZjNkMmYtNGQ1NS00Mzg0LThjNGYtZjMyYmVjMTI3OTQ3&hl=en

Here is a screenshot of what it looks like before:

http://docs.google.com/leaf?id=0B-AxBjS8xkHmMDJkOGNlMWEtN2QwMS00NTY2LWE0MmMtMjY0N2RhYjU1NTI5&hl=en

Here is a screenshot of what it looks like after:

http://docs.google.com/leaf?id=0B-AxBjS8xkHmNjNiN2IwYzctMDA4ZC00Yjg2LTgyZjUtNjQxMTQwYWU2Y2Y0&hl=en

Gravatar Image
On Jun 4, 07:26 AM, (Link)
Laurent said:

Whahh !! Enfin un tutoriel intéressant sur CKditor .. et qui fonctionne !! MERCI BEAUCOUP !! Depuis le temps que je cherchais pour faire cette fonction !
/
Whahh !! Finally a tutoriel interesting on CKditor and which works!! THANK YOU VERY MUCH !! Since the time I was looking to make this function !

Gravatar Image
On Jun 4, 01:32 PM, (Link)
Laurent said:

For the ones, like me, who want to do the same for the "Link" button. That’s the same process :

- Copy the plugin.js file from ckeditor\_source\plugins\link\dialogs\link.js to ckeditor\plugins\link\dialogs\link.js

- After the "editor.lang.link.styles" part (line 1129), paste :
{ type : 'hbox', children : [ { type : 'text', label : editor.lang.link.rel, 'default' : '', id : 'advRel', setup : setupAdvParams, commit : commitAdvParams

} ]
}

- Add "advAttr( 'advRel', 'rel' );" after the line "advAttr( 'advStyles', 'style' );" (line 233)

- Add "advAttr( 'advRel', 'rel' );" after the line "advAttr( 'advStyles', 'style' );" (line 1307)

- If you don’t have added the "rel:'Rel'," before in the ckeditor\lang\en.js file, you have to do it, else that’s finished.

- Have Fun !!

Gravatar Image
On Jun 9, 09:17 AM, (Link)
Evan Johnson said:

thanks @Joshua and @Laurent!

Gravatar Image
On Jul 25, 01:53 PM, (Link)
Wais said:

I want to know if this also works with the 3.3 version of ckeditor ?

Gravatar Image
On Aug 9, 04:33 AM, (Link)
ismael said:

Hello,

that´s great!

If you want a drop-down menue for the rel-attribut with the options "none", "lightbox[]" and "lightbox[group]", you can use following code (based on Evans code :-) ):

{
id : 'cmbLightbox',
type : 'select',
label : editor.lang.link.advisoryTitle,
'default' : '',
items :
[
[ editor.lang.common.notSet , ''],
[ 'Lightbox for one Picture' , 'lightbox[]'],
[ 'Lightbox for Picture-Group' , 'lightbox[group]'],
],
setup : function( type, element )
{
if ( type == LINK )
this.setValue( element.getAttribute( 'title' ) );
},
commit : function( type, element )
{
if ( type == LINK )
{
if ( this.getValue() || this.isChanged() )
element.setAttribute( 'title', this.getValue() );
}
}
},
{
id : 'txtRel',
type : 'text',
label : editor.lang.link.rel,
'default' : '',
setup : function( type, element )
{
if ( type == LINK )
{
this.setValue( element.getAttribute( 'rel' ) );
}
},
commit : function( type, element )
{
if ( type == LINK )
{
if ( this.getValue() || this.isChanged() )
{
element.setAttribute( 'rel', this.getValue() );
}
}
}
},

Maybe that will be helpfully.

best regards, ismael

Gravatar Image
On Aug 17, 09:54 AM, (Link)
Reijo Nyberg said:

Or you can just do this:

<script type="text/javascript"> $("div.your_content_container").find("img").each(function (i) { $("div.your_content_container") .find("img") .eq(i) .wrap("<a rel=\"lightbox\" href=\"" + $("div.your_content_container") .find("img") .eq(i) .attr("src") + "\"/>"); });
</script>

- Place this after the $content variable in your page.tpl.php

- Do NOT use $(document).ready();

- Configure Lightbox2 (advanced tab) to load on footer so the HTML has been altered before LB2 runs.

Code seems awful here so you may want to grab it from: http://pastie.org/1097940

Gravatar Image
On Aug 18, 04:20 AM, (Link)
Reijo Nyberg said:

This is an updated and optimized version of the above. In addition of adding the <a> tags, it will also check wether the image element already is wrapped inside an <a> tag and will skip those images.

<script type="text/javascript">

var yourdiv = $("div.yourdiv");
var images = yourdiv .find("img:not(a > img)");

images.each(function i() {
var $this = $(this);
$this.wrap('<a rel="lightbox" href="' + $this.attr("src") + '"/>');
});

</script>

Gravatar Image
On Feb 5, 09:59 PM, (Link)
Dan said:

Hey thanks for this, I’ve been digging around for a way to set a default class on images for the last day or so.

Gravatar Image
On Apr 18, 06:58 PM, (Link)
David Lawrence said:

Hi Evan,

This hack is exactly what I’ve been looking for but it’s not working for me with the latest version of CKEditor 3.5.3.

Any advice on how to get this working again?

Thanks!

Gravatar Image
On Apr 18, 08:02 PM, (Link)
Evan Johnson said:

@David – I have not messed with this is a looong time; sorry, but I have no tips for you. :( I invite anyone who comes by the blog to post a fix if they find out why it doesn’t work with 3.5.3 though!

Gravatar Image
On Apr 19, 04:20 PM, (Link)
David Lawrence said:

@Evan,

Did a little poking around and got it working! I realized I’m actually using 3.5.2, not 3.5.3 so I went back and got the correct source and that made all the difference.

Woot! I’m a happy camper! Thanks for this mod! :)

Gravatar Image
On May 9, 06:25 AM, (Link)
Dave said:

Evan – just a quick post to say thanks! I’ve just implemented your hack on a site I’m building and it works a treat.

In case anyone else comes across the same issues as me, ith regards to how to upload images with CKEditor in the first place, you can use a free plugin for CKEditor called KCFinder. I’ve just implemented that and it works a treat!

KCFinder, combined with Evan’s hack here, is a pretty complete way of using CKEditor with Ligthbox.

Gravatar Image
On Sep 18, 04:52 AM, (Link)
Philipp said:

You can do all of this without changeing anything in the core sources.

This is accomplished by hooking into the "dialogDefinition" event of CKEditor and changing the original definition of the screen on the fly instead of changing the real code.

I pasted the required lines of code for all of this here:
http://pastebin.com/gjZxwyfC

Have fun with it :)

  Subscribe to article comments