Currently, when using the tinymce editor on a multi-valued CCK text field, when you begin dragging the CCK item row to re-position it, if the editor is enabled, you lose the contents in some browsers. This is because the tabledrag.js code uses DOM manipulation, and an IFRAME within the DOM responds to that manipulation by reloading its src. The fckeditor also has its iframe reload its src, but that doesn't result in breakage the way it does for tinymce.

A user can circumvent the problem by disabling the editor before dragging the row.

I created a module that fixes this: Wysiwyg API CCK Integration.

Ideally, this fix should become part of the Wysiwyg API module, but probably not in its current form, because it involves using the jquery AOP plugin to modify the behavior of Drupal.tableDrag.prototype.row.prototype.swap, and that's too much of a hack. Better would be to patch tabledrag.js to allow for this to be done cleanly. I'll work on that patch, especially for D7, but I'm not confident about it being accepted for D6.

Comments

sun’s picture

Status: Active » Closed (duplicate)

Marking as duplicate of #350035: Implement Drupal.detachBehaviors(). Please search for existing issues before creating a new one. You can follow up on that issue instead to track its status. If any information from this issue is missing in the other issue, please make sure you provide it over there.

However, thanks for taking the time to report this issue.

jedihe’s picture

Title: Data loss when using tabledrag to re-order items for a CCK text field using tinymce » Data loss when using tabledrag to re-order items for a CCK text field using tinymce/CKEditor
Issue summary: View changes

Just posting a couple snippets that can be of help for anybody wanting to have a quick fix.

Starting with the code shown in #1296804: Tabledrag compatibility, I adjusted it to work for Wysiwyg (6.x-2.4) + CKEditor (3.6). New code is:

if (Drupal.tableDrag) {
  Drupal.tableDrag.prototype.onDrag = function() {
    // I happened to have an easy selector to use as "context" ('.widget-edit'), you may need to do some juggling here to reach to the right one for your use-case
    $(this.rowObject.element).find('.widget-edit').each(
      function() {
        // "this" refers to .widget-edit, above
        var paramsSrc = $('.wysiwyg[checked]', this)[0];
        if (paramsSrc) {
          var params = Drupal.wysiwyg.getParams(paramsSrc);
          Drupal.wysiwygDetach(this, params);
        }
      }
    );
  };

  Drupal.tableDrag.prototype.onDrop = function() {
    // See comment above, about picking the right selector
    $(this.rowObject.element).find('.widget-edit').each(
      function() {
        var paramsSrc = $('.wysiwyg[checked]', this)[0];
        if (paramsSrc) {
          var params = Drupal.wysiwyg.getParams(paramsSrc);
          Drupal.wysiwygAttach(this, params);
        }
      }
    );
  };
} 

The whole idea is: register onDrag and onDrop handlers for tabledrag, on each handler find a good "context" to use to target inner textareas having a WYSIWYG editor enabled and, finally, get the needed params to call either Drupal.wysiwygAttach() or Drupal.wysiwygDetach().

Another issue related to this is the removal of CKEditor when adding a new item to a multi-valued field. For that, this snippet is working for me (adapted from https://www.drupal.org/node/712846):

function destroyWYSIWYG(fieldContext){                                                                                                                                                                   
  for (var instanceName in CKEDITOR.instances) {
    if ($('#' + instanceName, fieldContext).length > 0 ) {
      // @TODO: refactor to use Drupal.wysiwygDetach(), as snippet above.
      CKEDITOR.instances[instanceName].destroy();
    }
  }
  return false;
}

Drupal.behaviors.destroyWYSIWYG_FIX = function(context) {
  // @TODO: change selector to target the right field for your use-case
  var fieldContext = $('#field-somefield-items');
  var addMoreButton = $('.content-add-more .form-submit:not(.destroyWYSIWYGFix)', context);
  if (addMoreButton.length > 0) {
    addMoreButton.addClass('destroyWYSIWYGFix')
    addMoreButton
      .click(function(){
        destroyWYSIWYG(fieldContext);
      })
      .mousedown(function(){
        destroyWYSIWYG(fieldContext);
      })
      .keypress(function(){
        destroyWYSIWYG(fieldContext);                                                                                                                                                                    
      });
  }
  // @TODO: you must tweak your selector to fit your use-case; also, look for a way to not target value="Remove", since that'll break very easily (I provide it here only to make sure this snippet works).
  var removeButton = $('.filefield-element .widget-edit .form-submit[value="Remove"]:not(.destroyWYSIWYGFix)', context);
  if (removeButton.length > 0) {
    removeButton.each(function() {
      $(this).addClass('destroyWYSIWYGFix');
      // @TODO: tweak parent selector to fit your use-case
      var curParent = $(this).parents('.filefield-element');
      $(this)
        .click(function() {
          destroyWYSIWYG(curParent);
        })
        .mousedown(function() {
          destroyWYSIWYG(curParent);
        })
        .keypress(function() {
          destroyWYSIWYG(curParent);
        });
    });
  }
};

Though not the nicest solution, it's working correctly according to the relatively extensive testing I did. Only browser used for testing was Chromium 41.