Opened 10 years ago

Closed 10 years ago

Last modified 10 years ago

#12061 closed Bug (wontfix)

CKEditor loses event handlers attached to DOM nodes when performing an Undo/Redo operation

Reported by: Christophe Guillou Owned by:
Priority: Normal Milestone:
Component: General Version:
Keywords: IBM Cc: Irina, Satya Minnekanti, Piotrek Koszuliński


Steps to reproduce

  1. Open a CKEditor with HTML Source plugin
  2. Switch to HTML Source view
  3. Paste this snippet:

<a id="link1" href="javascript:;">Hover me!</a>

  1. Switch to Rich Text view
  2. Observe the hyperlink is created and has no action on hover
  3. From the console, type:

window.frames[0].document.getElementById('link1').addEventListener('mouseover', function(){alert('Hello!');});

This will add an onmouseover event listener to the hyperlink;

  1. Hover the hyperlink
  2. Observe an alert dialog pops up with the message Hello!
  3. Type some text after the hyperlink, e.g. aaa
  4. Hit Undo or type Ctrl+Z
  5. Hover the hyperlink again

Expected result The alert dialog pops up with the message Hello! again

Actual result Nothing happens

This defect can be reproduced on the CKEditor 4.4.2 nightly

Looks related to :

Change History (2)

comment:1 Changed 10 years ago by Piotrek Koszuliński

Resolution: wontfix
Status: newclosed

Unfortunately, this is won't fix, because this cannot be fixed. Undoing, redoing and many other actions mean taking a previously created snapshot of a content and loading it to the editable element. Unfortunately, listeners added by addEventListener cannot be cloned together with content - neither if cloning happens by serialising to HTML string and creating new document fragment from it, nor when using native cloneNode method. In both cases all listeners except inline ones (on* attributes) are forgotten.

However, the workaround (or rather the correct way to listen to events in editable element or generally - dynamically changing DOM tree) is to use events delegation.

Here's a nice article about this technique:

The idea bases on "events bubbling" which means that event is not only fired on its target but on the entire DOM tree down to the root.

A simplified event delegation could look like this:

editor.on( 'contentDom', function() {
	editor.editable().attachListener( editor.editable(), 'mouseover', function( evt ) {
		// Check where the event started. This needs to be improved
		// because <a> may have children and then target will be set to them.
		if ( 'a' ) )
			console.log( 'mouseover' );
	} );
} );

See that mouseover is logged on the console after redoing, copy&paste, switching between modes, etc.

An alternative solution could be to use widgets because they make it possibile to perform custom actions when specific widget is initialised (what happens after undo, redo, pasting, switching between modes, etc). However, widget system has some limitations, so analysis is required to make a decision if they are the right choice.

PS. Events delegation is heavily used in widget system :).

comment:2 Changed 10 years ago by Christophe Guillou

Thanks very much, it has been very helpful to us. We will relay the information to our customer. Thanks again for your very prompt response, really appreciate this.

Note: See TracTickets for help on using tickets.
© 2003 – 2022, CKSource sp. z o.o. sp.k. All rights reserved. | Terms of use | Privacy policy