This a following issue to a problem introduced by the patch commited in #2489826 : tabledrag is broken
$form['table_a'] = ['#type' => 'table'];
$form['table_a']['row1'] = ...;
$form['table_a']['row1']['column_1'] = .....;
$form['table_a']['row1']['column_1']['table_b'] = ['#type' => 'table'];
Now all the rows of table_b will get a double tabledrag-handle, when makeDraggable is running.
First from the run for table_a and then from the run for table_b!
Until the patch was commited everything was functioning properpy for this kind of nested tables....
And at least this problem appears to be caused by changes in core/misc/tabledrag.js because of exchanging the row
$item.find('td').eq(0).prepend(handle);
with
$item.find('td:first-of-type').prepend(handle);
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | tabledrag-tabledrag-hierarchical-draggable-2499605-3.patch | 419 bytes | davidum |
| #2 | hierarchical_draggable_false.png | 13.03 KB | davidum |
| #2 | hierarchical_draggable.png | 13.52 KB | davidum |
| #2 | taxonomy.png | 15.75 KB | davidum |
Comments
Comment #1
davidum commentedComment #2
davidum commentedThe line

$item.find('td:first-of-type').prepend(handle);in tabledrag.js is used to add the handle element to the first td of each as draggable marked tr in a table.This makes sense in drupal components like Taxonomy or Menu, since all draggable Rows are at the same level within the table, so there is no hierarchical ordering, and the indentation of child elements is just resolved with javascript creating a space for each underlying level. So this is a kind of visual hierarchy, but not real if you look at the code of the table.
For example, Taxonomy is looking like this:
and the HTML structure of Table body is like this:
Beecause of the line
$item.find('td:first-of-type').prepend(handle);each td within an tr.draggable ($item) being the first td of its parent will get a handle added. This is okay in this case, cause within a tr.draggable there is always just one element matching td:first-of-type.
But sometimes a module would implement a real hierarchical table structure, whith draggable rows containing other draggable rows, like this:
Which should look like this:

Butin this case the line
$item.find('td:first-of-type').prepend(handle);leads to the situation, that for a top level tr.draggable not only it self but also every child will match the td:first-of-type selector and get a handle element added. Now for the next tr.draggable ($item) found, which will be a child element, there will be a new addition of a handle element, so the child elements will have more than one handle, and ends looking like this:
Solution:
Changing the line
$item.find('td:first-of-type').prepend(handle);back to
$item.find('td).eq(0).prepend(handle);resolves the problem without affecting the Drupal core implementations. In this case, for each tr.draggable just the first td of all matched ones will get a handle element, preserving child elements to also get a handle when the tr.draggable is a parent element.
For Drupal core implementations like Taxonomy every draggable row will also get a handle element.
Comment #3
davidum commentedComment #4
nod_That does fix the issue. Thanks for the extensive explanation too!
Tabledrag is my new overlay…
Comment #5
alexpottThis issue is a normal bug fix, and doesn't include any disruptive changes, so it is allowed per https://www.drupal.org/core/beta-changes. Committed 962d0c3 and pushed to 8.0.x. Thanks!