Short version:
I've been tracking a bug where CKEditor would throw an exception with the message
[CKEDITOR.editor] The instance "<some element id>" already exists.

The problem occurs because modal.js fails to notify the code managing the CKEditor instance(es) in the modal window that it should detach as it is about to update the content of the window.

As far as I can tell the way to fix this is to trigger all related detach-behaviours just before the DOM is updated. I've attached a patch that does just that.

Longer version:
Our site users panopoly which amongst other things provides a very convenient preview-button that allows the user to review the effect an update will have to a pane before saving it.

The steps to reproduce where

  1. Activate the in-place editor for a panel page.
  2. Click settings on a pane.
  3. Click the preview button (this triggers an ajax call and a modal_display command is returned which updates the modal window).
  4. Close the pane
  5. Attempt to reopen the same pane (or another instance of the same pane)

So far i've tracked the problem down to the following lines in modal.js

  Drupal.CTools.Modal.modal_display = function(ajax, response, status) {
    if ($('#modalContent').length == 0) {
      Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(ajax.element));
    }
    $('#modal-title').html(response.title);
    // Simulate an actual page load by scrolling to the top after adding the
    // content. This is helpful for allowing users to see error messages at the
    // top of a form, etc.
    $('#modal-content').html(response.output).scrollTop(0);
    Drupal.attachBehaviors();
  }

In particular the lines

    $('#modal-content').html(response.output).scrollTop(0);
    Drupal.attachBehaviors();

Where the content of the modal-window is updated, and the attach-behaviours triggered, but nothing is done to trigger the detach behaviours before the DOM is updated.

This means that the code in the WYSIWYG module that manages the CKEditor instances never gets a chance to destroy the CKEditor instance that where attached to the old textarea, and while it has no effect on the instance that is subsequently created via an attach-behaviour the instance still remains after the modal-window is closed. The CKEditor instance is identified via the ID of the element it is attached to, so when the user tries to reopen the same modal window (without refreshing the page) wysiwyg-module attempts to attach a new editor to the textarea and the above mentioned exception is thrown as the old instance of the editor already exists.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

danquah’s picture

Patch attached.

danquah’s picture

Now with the actual patch attached

danquah’s picture

Updated patch that uses the general detach behaviour trigger instead of the custom CTools version that as far as I can see where introduced to make sure only things inside the window reacted on the trigger (http://drupal.org/node/947676). The standard trigger should work just fine though as long as the proper context is passed in.

Can anyone come up with at good reason not to do it this way?

danquah’s picture

Status: Active » Needs review
tim.plunkett’s picture

I think it should only run if the modal already exists.

danquah’s picture

Agree, seems like a good thing to check.

gmercer’s picture

I've updated #5 with the following new patch file

nedjo’s picture

Previous patch didn't apply. Also, the first argument to Drupal.attachBehaviors, context, requires a jQuery object, not a selector (see #1851108: modal.js -- Drupal.CTools.Modal.modal_display() should pass context into Drupal.attachBehaviors()).

edmargomes’s picture

Status: Needs review » Reviewed & tested by the community

Works for me

joelpittet’s picture

  • joelpittet committed daa06d7 on 7.x-1.x authored by nedjo
    Issue #1907256 by danquah, nedjo, tim.plunkett, gmercer, edmargomes,...
joelpittet’s picture

Status: Reviewed & tested by the community » Fixed

Thanks all I've committed this to the dev branch

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.