2009/09/08

CKEditor events

The new articles will be focused on documenting the events fired by CKEditor as currently there's no documentation besides the source code.

Events are the way to hook different pieces, the glue for the plugin architecture of CKEditor that allows to replace / add several parts without going nuts. In this regard, this doc page is a must read for anyone that really wants to understand the basics about how it works. If you don't read it then you'll be lost and you'll ask questions that have already been answered there.

Yes, that page is quite generic, so we have to looks at the API docs for the CKEDITOR.event information, here we can find out exactly the details about how those ideas have been implemented.

As a summary: an object might implement this Api, so you can listen to their events adding your listener. The syntax is similar to the standard DOM events, but it has some slight improvements like the ability to specify an object upon which the listener must be called without resorting to extra code and specify a priority for the listener (you might need this very few times, but it's nice that it's there).

As any other event system you can remove your listener, and if you need to, you can fire an event whenever you like, on an standard object, your own object, some standard event or your own event.

Something important must be remarked at this point: If you try to register a listener to a non-existing event you won't get any error, but of course it will never be executed. So don't try to put ckeditor.on('imageDeleted') ckeditor.on('fileAdded') or whatever. Unless you write the code to fire those events you are wasting your time. Why does the event system allows to do that: because you can create any event that you want, so the system just register your listeners, expecting that you know what you are doing and the event will be fired later by any other code.

So now we now the basic, let's look at the events of one object

CKEDITOR events

CKEDITOR is the main object of the whole API, and it can fire several events that are useful to do some basic and generic tasks

"loaded"
The first event is fired only if you have used the basic integration, obviously if you use the full code from the start as soon as your code is executed the core is ready (or you wouldn't be able to call CKEDITOR.on() ). Also, there's no editor sent in the eventInfo object.

"instanceCreated"
Each time an instance is created this event is fired, before it's configuration is initialized.

"instanceReady"
It signals that the initialization of an instance has finished.

"currentInstance"
Fired when an editor gets or loses focus. (After CKEDITOR.currentInstance has been updated. This is currently an undocumented property used only for the focus management ). No editor is sent in the eventInfo object. This is fired quite a lot, for example opening a dialog means that the editor loses focus, so the event is fired, and also when it's closed.

"dialogDefinition"
Fired upon creating the definition for a dialog. The event data are the dialog name and its definition. (this is the only event in CKEDITOR that sends some data in the eventInfo.data field). This event is fired when a dialog is launched for the first time in each CKEditor instance.

So that's all for the main CKEDITOR object. It's a short list, but enough to show a bug in my previous code to provide the seamless integration of textareas in CKEDITOR: Yes the CKEDITOR object doesn't fire any event when an instance is destroyed so that part of the code must be written like this:

// Hook each textarea with its editor
CKEDITOR.on('instanceCreated', function(e) {
 if (e.editor.element.getName()=="textarea")
 {
  var node = e.editor.element.$ ;

  // If the .nativeValue hasn't been set for the textarea try to do it now
  if (typeof(node.nativeValue) == "undefined")
  {
   // IE
   if (!document.__defineGetter__) return;
   // for Opera. Safari will fail
   if (!DefineNativeValue(node)) return;
  }

  node.editor = e.editor;

  // House keeping.
  e.editor.on('destroy', function(e) {
   if (node.editor)
    delete node.editor;
  });
 }
});

This just shows again that you must not trust anyone, test whatever you find and use it as a guideline, but always be ready to think that the person that wrote some example might not have tested under your same conditions, that some code has been changed meanwhile (for example I guess that the list of events of CKEDITOR might have increased in v3.2 for example, so if you read this article 2 years from now just think that I'm talking about the 3.0 version), or the code might be wrong because whoever wrote it was too drunk that day :-)

 

4 comments:

Anonymous said...

Hi Alfonso! Thank you for your articles about CKEditor.

I'm using CKEditor 3.0.1 and I have some problems with events system. I've got page based on the ajax.html example (with buttons "Create Editor" and "Remove Editor"). I want to fire some event every time I replace <div id="editor"><div> element pressing "Create Editor" button:

  editor = CKEDITOR.appendTo('editor');
  editor.on('pluginsLoaded', function(ev) {
    …
  });


Everything is OK on first replacement of div. But when I destroy editor with "Remove Editor" button:

  editor.destroy();

and create it once again, event function is not executed.

If You know what I’m doing wrong please help.

Thanks, Karol.

Alfonso said...

Hi Karol.

Replying as a comment for this question looked too "restricted", so I have explained the problem and two solutions in the latest post:
http://alfonsoml.blogspot.com/2009/11/ckeditor-is-fast.html

Federico González said...

Hi, I want to capture "click" event, but not working.

editor.on( 'click', function( evt ) {
console.log("click");
});

"doubleclick" event works fine :S

Ideas?

Thank you, Federico

Alfonso said...

There's no click event for the editor instances. The double click on the document is captured and fired on the editor element to customize opening dialogs that way.

You must set your own listener on the editor document.