Problem/Motivation
In the docs for drupal_attach_tabledrag() it mentions
In a more complex case where there are several groups in one column (such as the block regions on the admin/structure/block page), a separate subgroup class must also be added to differentiate the groups.
I've been trying to get that working with minimal additional JS and I think I might've uncovered some bugs in tabledrag. When trying to use subgroups I was finding that dragging a row from one group into the other didn't seem to copy the subgroup class across correctly.
In #2489826: tabledrag is broken (dcf9ab4) some changes were made to some tabledrag jQuery selectors. I think the changes were meant to be functionally equivelent, just a little more efficient, eg:
- var $indentationLast = $item.find('td').eq(0).find('.js-indentation').eq(-1);
+ var $indentationLast = $item.find('td:first-of-type').find('.js-indentation').eq(-1);
IIUC the starts of both of those lines basically do the same thing - grab the first td. But there are some other situations where I think the behaviour changed, and I wonder if that was unintentional.
-
--- a/core/misc/tabledrag.js +++ b/core/misc/tabledrag.js @@ -718,7 +718,7 @@ // take into account hidden rows. Skip backwards until we find a draggable // row. while ($row.is(':hidden') && $row.prev('tr').is(':hidden')) { - $row = $row.prev('tr').eq(0); + $row = $row.prev('tr:first-of-type'); row = $row.get(0); } return row;In this case
$row.prev('tr:first-of-type')will only return a value if the previous row is also the first row in the table, rather than iterating each previous row. I've reverted that in the patch, but I wonder if the whole while block is redundant:$rowis set from$(this.table.tBodies[0].rows).not(':hidden')at the start offindDropTargetRow().@@ -766,9 +766,9 @@ } // Siblings are easy, check previous and next rows. else if (rowSettings.relationship === 'sibling') { - $previousRow = $changedRow.prev('tr').eq(0); + $previousRow = $changedRow.prev('tr:first-of-type'); previousRow = $previousRow.get(0); - var $nextRow = $changedRow.next('tr').eq(0); + var $nextRow = $changedRow.next('tr:first-of-type'); var nextRow = $nextRow.get(0); sourceRow = changedRow; if ($previousRow.is('.draggable') && $previousRow.find('.' + group).length) {This is what caused the original problem and prevented the weight subgroup class being copied over when moving a row into a different group. As before it's looking for the previous row using
first-of-typeand in this case it means the source row for sibling relationships isn't correctly set. The patch should fix and test this.@@ -811,7 +811,7 @@ // Use the first row in the table as source, because it's guaranteed to // be at the root level. Find the first item, then compare this row // against it as a sibling. - sourceRow = $(this.table).find('tr.draggable').eq(0).get(0); + sourceRow = $(this.table).find('tr.draggable:first-of-type').get(0); if (sourceRow === this.rowObject.element) { sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1]).next('tr.draggable').get(0); }The original line found the first row with the
draggableclass but the modified version looks for a row which is both the first and has thedraggbleclass. This causes an issue with field_group on a table with a non-draggable first row: #3085858: Drag and drop acts weird, sometimes not resetting the parent, or even clearing the region value. The patch should fix and test this.

This is my first time touching tabledrag so careful review welcome :p
Also it's quite an old commit that introduced this, I know tabledrag is used in lots of places, so I'm not sure if I'm just missing something obvious... (:
Proposed resolution
Replace occurrences of
('tr:first-of-type')with('tr')in tabledrag.js, for example in this block of code:--- a/core/misc/tabledrag.js +++ b/core/misc/tabledrag.js @@ -718,7 +718,7 @@ // take into account hidden rows. Skip backwards until we find a draggable // row. while ($row.is(':hidden') && $row.prev('tr').is(':hidden')) { - $row = $row.prev('tr').eq(0); + $row = $row.prev('tr:first-of-type'); row = $row.get(0); } return row;Remaining tasks
- Manual testing
- Code review
User interface changes
N/A
Introduced terminology
N/A
API changes
N/A
Data model changes
N/A
Release notes snippet
N/A
| Comment | File | Size | Author |
|---|
Issue fork drupal-3089151
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
andyf commentedHere's a simple change of the JS based on searching for
:first-of-typeand making sure it wasn't being used with.prev()or.next(). There's more that could be tested but I just wanted to get something replicable first and make sure I'm not imagining things (:Comment #4
andyf commentedSo I was hunting around for any other issues that might be explained/fixed by this. I came across #3085858: Drag and drop acts weird, sometimes not resetting the parent, or even clearing the region value which wasn't fixed by the previous patch, but I poked around a little and it looks like it's caused by another
:first-of-typeissue I missed the first time around (it's really easy to misread that selector...).I've managed to recreate the issue by expanding the subgroup test to include parenting, but annoyingly I can't seem to drag the row up and to the left in the test. I've attached two screenshots that show the initial and final state of
testParent(). However trying it out manually the new patch seems to fix the issue.Thanks!
Comment #5
andyf commentedPossibly related to the test failure? #2769825: Cannot swap tabledrag rows by dragging the lower over the upper row in tests
Comment #8
andyf commentedThe patch from #2769825: Cannot swap tabledrag rows by dragging the lower over the upper row in tests does seem to fix dragging upwards. I've added a hidden group field and expanded the subgroup tests slightly. I wasn't sure what the best way to drag a row as a child of another might be. They need to use different targets depending on whether they're being dragged up or down. In the end I've settled for adding a prefix to the first TD element of each row that adds two stylable spans. One is for dragging a row from below and the other for dragging a row from above. I wonder if there's a neater way?
I've also added a version of the patch which has the fix from #2769825: Cannot swap tabledrag rows by dragging the lower over the upper row in tests folded in, just to confirm the tests pass.
Comment #11
andyf commentedOops, need to set a default theme when using the testing profile since The 'testing' install profile's setting of a default theme (Classy) is now deprecated.
Comment #13
andyf commentedComment #14
andyf commentedComment #15
andyf commentedUpdate summary: Add task to fix Claro tabledrag
Comment #16
andyf commented#2769825: Cannot swap tabledrag rows by dragging the lower over the upper row in tests has landed so remove task to wait for it from IS. Also trigger a retest of #11 to check the bare patch now passes.
Comment #17
andyf commentedFix and test Claro tabledrag as well.
Comment #19
electrokate commentedThis issue may be related.
Comment #21
scotwith1tCame here from #3085858: Drag and drop acts weird, sometimes not resetting the parent, or even clearing the region value and the patch solved this issue for us. Thanks!
Comment #22
andyf commented👍 Thanks @scotwith1t for the feeback!
Also tagging with javascript, not sure if that's appropriate given it's already the component... ¯\_(ツ)_/¯
Comment #23
andyf commentedOops, retagging (:
Comment #24
bnjmnmIf this issue: #3083051: Refactor tabledrag when core issues are resolved lands, all the Claro changes here can probably be removed. This would make the patch for this issue smaller, and thus easier to review/commit.
Comment #26
gaëlgHere's a try to reroll #17 against 9.2.x (claro tests removed, as advised in #24.
Comment #27
gaëlgWhoops
Comment #28
andyf commentedClean up cspell fails.
Comment #30
init90Thanks for the great work! The patch has tests and fixes the related problems with the Field Group module #3085858: Drag and drop acts weird, sometimes not resetting the parent, or even clearing the region value
Comment #31
bnjmnmThis can't be set to RTBC because the most recent patch (#28) is not passing code standard/formatting tests (hence the "custom commands failed" status of the patch). Looks like it is just this
Comment #32
andyf commentedThanks both!
Also I don't think it's had a hint of a review, so I think it's a ways away yet anyway.
Here's an updated patch with the missing comment, fingers crossed.
Comment #33
init90Comment #34
bnjmnmThis isn't a deep review, but in a quick readthrough I spotted a few things that need attention before this is RTBC worthy, but I think this should probably get a deeper review overall:
This seems like quite a bit of documentation for an unlikely + unadvisiable scenario. I think this probably adds more noise than it helps. (though I typically prefer erring in the direction of more docs)
Needs a period at the end.
Nit: explicitly specifying (optional) here while next to several other variables that are also optional but not labeled the same way. The (optional) shouldn't be needed since there's a default value in the function signature.
I like that there is added test coverage for the edge cases reported in this issue. It would be good if the review confirmed the tests are fully covering the scenarios impacted by these scenarios, and are doing so in the most efficient possible manner.
Comment #36
wellsReroll of #32 against 9.4.x-dev. No other changes.
Comment #37
wellsOops. Forgot to build JS in #36... updated patch attached.
Still just a reroll of #32 with no other changes.
Comment #39
liquidcms commentedI was using the patch from #37 to seemingly fix my issue with not being able to place field groups on entity manage display form. This was with core 9.2.16.
I just upgraded core to 9.3.16 and this is now broken again.
and the patch from #31/32 that is listed for 9.3.x does not apply to 9.3.16.. :(
going back to latest patch and i have been able to get my new field group placed correctly by moving it in small steps at a time between saves. certainly still issues with this.
Comment #40
sandeepsingh199 commentedre-rolling the #32 patch for 9.3.x,9.4.x & 9.5.x
Comment #42
milos.kroulik commentedThe patches from #37 and #40 are the same.
Comment #43
wellsHere is another re-roll of #32 for 9.5.x.
Comment #44
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #45
ayush.khare commentedReroll of #43 for 10.1.x
Comment #46
nikhil_110 commentedComment #47
smustgrave commentedThis seems like a difficult one to test but from what I can tell it has something to do with parent value.
Tried using the test module provided by the patch. Can it be updated to include parent value as well.
Comment #48
andyf commentedThanks for your time @smustgrave! I'm not really sure what you're asking for here?
Does it really need work rather than review? I tried my best in the IS, there's a test that fails without the patch, it seems to me like NR is appropriate?
Thanks again!
Comment #50
heikkiy commentedThe patch does not seem to apply anymore against core 10.2.
Comment #51
wellsRe-roll of #45 attached for Drupal 10.2.x.
Comment #52
smustgrave commentedRecommend turning to an MR for quicker reviews.
#51 seems to have failures.
Comment #55
gauravvvv commentedComment #56
smustgrave commentedNew functions should use type hints and returns.
Also learned we can use constructor promotion.
Comment #57
heikkiy commentedI can also confirm that the latest merge request applies against 10.2.
Are there any clear instructions how to repeat the issue without the patch? Would make it easier to test that it works.
I originally applied this patch in our project because we had trouble reordering the fields in the node edit form layout but I also had other related patches applied so I would like to confirm I am testing the right thing.
Comment #58
jsimonis commentedheikkiy:
For me, it happens when I am trying to create a set of vertical tabs. So, I create the "tabs" and then the "tab". I drag the tab up under the tabs, then add the content to the tab. Save. The content stays under the tabs item, but the tab has moved down to disabled.
I've tried using the latest patch, but I get:
a "b" folder created in my /web folder
failures in the patch
Comment #59
malcomio commentedSee #3333953: Nested field groups improperly display as "Disable" in the admin UI for details of an issue affecting the field_group module - the core patch seems to fix that for me.
@jsimonis - how are you applying the patch, and what are the failures that you see when trying to apply the patch?
https://vazcell.com/blog/how-apply-patch-drupal-9-and-drupal-10-composer is a good explanation of how to do this.
Comment #60
loze commentedI am seeing the same as @malcomio this patch applies but unfortunately does not fix the issue for me.
I am unable to disable fields using the drag and drop. I need to turn that feature off and select disabled in the dropdown
Drupal 10.4.2
Gin 4.0.2
field_group 3.x-dev
Comment #61
anybodySetting the priority to major, as this seems to cause a lot of trouble downstream for people using Field Groups heavily: #3085858: Drag and drop acts weird, sometimes not resetting the parent, or even clearing the region value
Comment #63
sleitner commentedRerolled and addressed these:
Comment #64
smustgrave commentedSomething noticed is this could use a summary update. With a clear proposed solution. Changing these selectors think will need manual testing as well.
Comment #65
ironnuts commented2x broken functional tests in pipeline.
Test-only test appears good:
https://git.drupalcode.org/issue/drupal-3089151/-/jobs/7086430
Comment #66
ironnuts commentedComment #67
ironnuts commentedRe: #64, applied IS template and re-structured IS, some re-writing for clarity. I updated the 'Remaining tasks' according to #64.
Comment #68
ironnuts commentedComment #69
sleitner commentedRerolled. The broken funtional tests were random temporary problems.
Comment #70
sleitner commentedRerolled
Comment #72
smustgrave commentedSorry tried using the summary to figure out the problem but not super clear and want to make sure I'm testing the right scenario. Can the steps to reproduce section be added back to the summary please.