I'm currently working on adding drag-n-drop reordering of CCK field values for multiple fields on the node edit form.
When a node has several multiple fields, this of course leads to several separate dnd-enabled tables (a value from one field cannot be dropped into another field - thus differing from the blocks admin page).

It seems the drag-n-drop feature only works on the last table where the tabledrag behavior has been attached, be it when 1st building the page, or when reattaching to an ahah-updated subpart of the form.

No easy way to test right now, I'm posting this here as a placeholder until I can publish my code either in CCK HEAD or as a patch in the CCK queue - it still needs a little polishing.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

A 1st pass of firebugging through dragtable.js showed this :
the function dragRow() (the mousemove event handler) starts by checking the existence of self.dragObject, wich seems to only exist when trying to drag from the last attached table.

Time to go to bed, I'll try dig more tomorrow.

yched’s picture

Status: Active » Needs review
FileSize
9.38 KB

The bug lies in these lines in tabledrag.js :

$(document).bind('mousemove', { tableDrag: self }, self.dragRow);
$(document).bind('mouseup', { tableDrag: self }, self.dropRow);

When executed with different values of self (different table), jquery considers that you're re-binding the same handler (dragRow) to the same object (document), and thus overrides the previous binding instead of adding a new one (dragRow function already has a guid - uncompressed jquery.js, line 1582)

Attached patch fixes this by having dragRow / dropRow take self as a param, and return a new handler function for every value of self :

$(document).bind('mousemove', self.dragRow(self));
(...)
Drupal.tableDrag.prototype.dropRow = function(self) {
  return function(event) {
    if (self.dragObject) { 
      (...)
    }
  }
}

It does work, but I'm absolutely not sure it's the cleanest/proper way to fix this. Reviews welcome (... Nate ? :-)

PS : I published the 'drag-n-drop field values' patch for CCK HEAD in http://drupal.org/node/195268 - I'm not committing it until we have a fix for this.
In order to test : grab CCK HEAD, apply the patch, add 2 or 3 multiple fields to a content type, and play with the node edit form.
Without the tabledrag fix, only the last table (or the last on which you hit the AHAH-'add new values' button) gets correct d-n-d.

As a side note, I guess fixing this might not only benefit CCK, but also maybe Views UI (seperately reorder filters, fields, sorts, etc) ? Not sure what is in the works about that...

quicksketch’s picture

Eaton pointed this patch out to me. I'm having a look at it, though right off it seems a bit unconventional. A function that does nothing but return an anonymous function... seems like there must be a clearer solution, but I've seen this sort of weirdness before when working with multiple object instances.

quicksketch’s picture

Title: drag-drop only works on the last attached table » Multiple drag and drop tables do not work
Priority: Normal » Critical
FileSize
1.5 KB

This patch should fix the problem.

jQuery has a (very neat) ability to not only attach functions to events, but also to remove them also. However, setting two functions with the same name (such as "dragRow") will over-write the previous function stored in that binding. I was not aware that this would occur even if it was separate instances of an object like ours.

So, rather than attaching a named "dragRow" function to the document, this creates an anonymous function with no name to bind to the document, so we won't run into these conflicts. It's actually less code, so cheers to that.

I'm bumping up to critical, because tabledrag.js was always intended to be used on multiple tables on a single page. This flaw is a critical bug that needs to get fixed ASAP.

yched’s picture

FileSize
1.73 KB

Of course, much cleaner than my original patch. And works perfectly.

Attached patch updates the signature of the call to dropRow in the blur handler (was missing in my patch too)
Aside from that, I think this is ready, but I cannot RTBC this new patch.

Gábor Hojtsy’s picture

Status: Needs review » Fixed

Looks good, thanks, committed.

yched’s picture

Cool :-) Thanks Nate !

yched’s picture

multiple values reordering is committed to CCK HEAD :-)

quicksketch’s picture

Status: Fixed » Needs review
FileSize
533 bytes

Nice catch yched on the other call to dropRow. We can remove one more line that is no longer needed. Previously we were setting the 'self' variable to 'event.data.tableDrag'. But now we're passing it in directly so we don't need to be making this assignment.

yched’s picture

Status: Needs review » Reviewed & tested by the community

Ah, true. It was a nice catch, but an incomplete one...
This is straightforward. RTBC.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Committed, thanks.

Anonymous’s picture

Status: Fixed » Closed (fixed)

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

yched’s picture

Status: Closed (fixed) » Active

Actually this seems to have broken tabledrag in IE7.
When you click a dnd handler, the moment your pointer leaves the handler area, dragRow() (mousemove handler) is not called anymore, until you unclick, which does not trigger dropRow() (mouseup handler) but lets dragRow() be called again

Reopening, and leaving the 'critical' priority on.

Gábor Hojtsy’s picture

Title: Multiple drag and drop tables do not work » Drag and drop broken in IE7
yched’s picture

Right, sorry about the title.

So. This doesn't make any sense.

If I simply comment out these lines from current HEAD tabledrag.js :

Drupal.tableDrag.prototype.row = function(tableRow, method, indentEnabled, maxDepth, addClasses) {
  this.element = tableRow;
  this.method = method;
//  this.group = new Array(tableRow);
  this.groupDepth = $('.indentation', tableRow).size();
  this.changed = false;
//  this.table = $(tableRow).parents('table:first').get(0);
  this.indentEnabled = indentEnabled;
  this.maxDepth = maxDepth;
  this.direction = ''; // Direction the row is being moved.
  (..)

this of course breaks the functionality *but* the event handlers are called the way they're supposed to.
Uncommenting either one of these lines makes event handlers break again.
Appending an _ after the variable names (this.group_, this.table_), makes the thing work again...

Beats me for now...

yched’s picture

Side note : everything works fine in IE6.

yched’s picture

Status: Active » Needs review
FileSize
881 bytes

OK, I'm not sure exactly what is happening, but after a couple hours trying to follow the evenements flow, I tried preventing the mousedown event from bubbling up, and this fixed it.

Of course it's only afterwards that I that I noticed the 'return false' at the end of dragRow() which was there precisely to this intent, but wasn't effective anymore after the patch in #5 above got committed...

Tested to work in FF2, IE7, IE6, Opera...

starbow’s picture

I just tested this patch. Before, I experienced the problem with IE7, after the patch it seemed to work fine. I also tested on FF2 after the patch, and it still works fine.

quicksketch’s picture

FileSize
726 bytes

Wow, I'm glad we've got you checking on this yched. If this would've gone unnoticed it would've taken a hella lot more work to get this fixed looking for the problem.

So here's the deal, previously dragRow() was returning FALSE, which prevented the mousemove event from exiting out. I don't quite understand why IE7 requires this, but it makes sense for things like .click(), where if you return FALSE the normal click operation by the browser doesn't execute. When we made anonymous functions wrapped around dragRow(), I forgot to return the value from dragRow(). Adding a return seems to correct the problem.

dropRow() doesn't need the return because it doesn't return anything anyway.

quicksketch’s picture

Ha, looks like we cross-posted. Either solution works fine. I like yched's patch in #17 more because it's more clear and affects the mousedown event directly.

quicksketch’s picture

Status: Needs review » Reviewed & tested by the community

Tested Safari, IE6, Firefox, Opera with no negative side-effects. IE7 works properly. #17 is good to go.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

I've committed this patch to CVS HEAD. Thanks again folks.

quicksketch’s picture

Title: Drag and drop broken in IE7 » Multiple drag and drop tables do not work

Thanks Dries :)

Putting title back to original for posterity.

Anonymous’s picture

Status: Fixed » Closed (fixed)

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