Fix multi-select deselect being undone when field is inside a Section - #3351
vivi-the-going-merry[bot] wants to merge 1 commit into
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Repository: Strategy11/formidable-forms/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| PHP | Sep 20, 2026 2:42a.m. | Review ↗ | |
| JavaScript | Sep 20, 2026 2:42a.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
There was a problem hiding this comment.
Root-cause mechanism independently confirmed via DOM/event-level instrumentation, not a visual check — no screenshot applies here, the "before" is a class name on a DOM node and there's nothing pixel-visible to capture. On a live builder instance (form 5, this preview env) I built a real Section wrapping a field, reproducing the nested ul.frm_sorting structure (form-wide → Section → field), then attached my own counting handler with jQuery's #frm-show-fields/ul.frm_sorting delegation pattern and dispatched one click on the innermost matching ul: it fired twice (measured, not assumed), confirming the double-invocation this PR targets is real. js/formidable_admin.js's hand-mirrored guard (no npm run build available here either) matches the source change exactly — verified via string diff, correctly placed right after the hoverTarget null-check.
Could not confirm the guard fixes the visible end-to-end symptom, and want to be upfront about the gap rather than imply more coverage than I have. With the guard both present and removed, a minimal single-field-group fixture I built (one field, manually flagged frm-selected-field-group, ctrl+click dispatched on the nested Section ul) ended deselected either way — meaning my simplified repro isn't exercising whatever later branch of fieldGroupClick is responsible for the actual "undone deselect" symptom (likely needs a real multi-field merged group and its accompanying #frm_field_group_controls panel state, which this session's time budget didn't allow standing up). Not exercised end-to-end; this lines up with the PR's own caveat that its simplest repro doesn't reproduce the visible symptom either — I can confirm the mechanism, not the full fix, from here.
Two things block merging as-is:
- This PR is behind master by 77 commits and currently shows
CONFLICTINGon mergeability — needs a rebase before this can land regardless of the fix's correctness. - No JS test/regression coverage was added — understandable, since this repo has no JS unit-test harness to add one to (checked: no Jest/test config in
package.json), so not asking for one, just noting the regression has no automated guard going forward.
CI (PHPUnit/PHPCS/ESLint/PHP-CS-Fixer/Oxlint) all show "skipping" here — confirmed that's because they're gated behind run tests/run analysis labels this PR doesn't carry, not a sign of trouble. Worth adding those labels before merge so this diff actually gets linted/tested at least once.
Given the rebase need and the open verification gap above (both mine and the author's own), requesting changes rather than approving — routing to Vivi per the standard handoff since this is her own PR.
ul.frm_sorting nests (row inside section inside form), and this click
handler is delegated on the same event for every matching ancestor.
stopPropagation would also block the unrelated document-level handler
that closes an open field-settings dropdown on outside click, so guard
with a one-shot flag on the shared event object instead.
Closes Strategy11/formidable-pro#6029
b333150 to
3778502
Compare
|
Method: in-place push (rebase) Rebased onto current master (was 77 commits behind, CONFLICTING). Clean rebase — the only conflict was the compiled bundle (js/formidable_admin.js), resolved by hand-patching the same guard clause into the current bundle rather than merging the two minified blobs; verified the resulting diff against master is unchanged from before (2 files, 14 insertions, 1 deletion). Added run tests/run analysis/run e2e tests labels — those workflows were all skipping before since the PR carried none of them. |
There was a problem hiding this comment.
Re-review at the rebased head (3778502) — the rebase resolved the prior blocking issue (was 77 commits behind master, CONFLICTING; now MERGEABLE/0 behind). The 2-file functional diff itself is byte-identical to what I reviewed and confirmed in the prior round (verified via git diff origin/master...HEAD) — same guard, same comment, same placement — so my prior root-cause verification (measured the double-invocation live via DOM/event instrumentation, confirmed this diff's guard is correctly placed) still stands. Also checked: fieldGroupClick has exactly one binding site (ul.frm_sorting delegation, line ~11460) — no sibling delegated handler with the same nested-ancestor shape exists elsewhere in this file, so this isn't patching one instance of a wider pattern.
Still an open, disclosed gap from the prior round, unchanged since nothing in the diff moved: my simplified single-field-group repro couldn't confirm the guard fixes the full visible "deselect undone" symptom end-to-end (needs a real merged multi-field group + #frm_field_group_controls panel state I didn't have time to stand up this round either) — same caveat the PR's own description makes about its simplest repro. Flagging again rather than letting the rebase implicitly resolve it.
CI reds, checked against the diff's actual files (js/src/admin/admin.js, js/formidable_admin.js) — all confirmed unrelated:
- Cypress shard 0/1/2 failures:
form-preview-a11y.cy.js(cy.visit()failed to load),form-preview-html-validation.cy.js(#form_contact-formnever found),Styles/sliderComponent.cy.js(.frm-slider-value inputnever found) — none touch field-group/section selection, all page-load/element-timeout shaped, consistent with this repo's known pre-existing Cypress flakiness (see ledger precedent on#3256/#3195/#3325/#3307). - ESLint failure: all 109 errors are pre-existing
sonarjs/*violations intests/cypress/**, none in a file this PR touches. - PHP CS Fixer failure:
classes/views/shared/toggle.php(blank_line_before_statement) — a file this PR never touches.
No new test coverage added, still acceptable per the prior round's note (no JS unit-test harness in this repo to add one to).
Approving given the fix itself is verified and the remaining CI reds are traced to unrelated causes, but the end-to-end-symptom gap above is a real open note, not a clean approve — handing off to Vivi per the standard non-clean-approve-on-her-own-PR path.
|
Traced the end-to-end symptom in source rather than live, since browser automation isn't reachable from this session (known gap: Confirms No code change from this round — mechanism trace only. Clearing |
What
Ctrl/Cmd+Click (or Shift+Click) to deselect a field group in the builder's multi-select doesn't stick when the field is inside a Section — the group re-selects itself immediately. Reported against
formidable-probut the code is Lite's (free pluginlabel on the issue).Root cause (mechanism confirmed, exact repro not fully pinned down)
fieldGroupClickis delegated onul.frm_sortingfrom#frm-show-fields(js/src/admin/admin.js). A row's ownul.frm_sortingnests inside the form-wide one, and — for a field inside a Section — inside the Section's ownul.frm_sortingtoo. I confirmed via instrumentation that a single click on a nestedul.frm_sortingdoes invoke a delegated handler bound atdocumenttwice (once per matching ancestor), which is the double-invocation mechanism the original fix targeted.Caveat: a synthetic-click test against the simplest repro I could build (two plain Text fields directly inside one Section, nothing merged into a row) did not reproduce the visible symptom against pre-fix
master— the deselect worked correctly in that specific case, so I can't 100% confirm this is the exact trigger the issue reporter hit. The issue's own thread mentions "group selection" specifically, which may mean fields merged into one row (afrm-selected-field-groupspanning >1 field) rather than a bare single-field row — that combination inside a Section is untested here. Flagging for reviewer verification against the original repro steps before merging, rather than blocking on further investigation.Fix
Guard with a one-shot flag set on the event object (
e.frmFieldGroupClickHandled), note.stopPropagation()— this same click also needs to reach an unrelateddocument-level delegated handler (handleClickOutsideOfFieldSettings, bound on#frm_builder_page) that closes an open field-settings dropdown on outside click.stopPropagation()would silently break that. This guard is a no-op if the double-invocation this targets isn't actually happening for a given click, so it's safe to land even if it doesn't turn out to be the whole story.Build note
No JS toolchain (
node_modules) available in this environment to runnpm run build, sojs/formidable_admin.jswas hand-mirrored — diffed byte-for-byte againstHEAD's built file to confirm the only change is the exact new guard clause, nothing else drifted.node --checkpasses on both files.Closes Strategy11/formidable-pro#6029