Created
February 22, 2024 10:37
-
-
Save aminomancer/ba34e666ecb6242f1612b86bf1909a8a to your computer and use it in GitHub Desktop.
radioGroupTabFocus
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/accessible/tests/mochitest/events/test_focus_controls.html b/accessible/tests/mochitest/events/test_focus_controls.html | |
index 268ec5d0e46b7..0760082ad94b3 100644 | |
--- a/accessible/tests/mochitest/events/test_focus_controls.html | |
+++ b/accessible/tests/mochitest/events/test_focus_controls.html | |
@@ -31,7 +31,17 @@ | |
gQueue.push(new synthFocus("button2")); | |
gQueue.push(new synthFocus("checkbox")); | |
gQueue.push(new synthFocus("radio1")); | |
+ // Only the checked radio button is tabbable. If there's no checked radio | |
+ // button (as in this case), only the first radio button is tabbable. | |
+ gQueue.push(new synthTab("radio1", new nofocusChecker("radio2"))); | |
+ // Shift+Tabbing from after a radiogroup should lead to the first radio | |
+ // button in the group if none is checked. | |
+ gQueue.push(new synthShiftTab("file", new focusChecker("radio1"))); | |
gQueue.push(new synthDownKey("radio1", new focusChecker("radio2"))); | |
+ // Now the second radio button is checked, so it should be tabbable | |
+ // instead of the first. | |
+ gQueue.push(new synthFocus("checkbox")); | |
+ gQueue.push(new synthTab("checkbox", new focusChecker("radio2"))); | |
// no focus events for checkbox or radio inputs when they are checked | |
// programmatically | |
diff --git a/dom/base/RadioGroupContainer.cpp b/dom/base/RadioGroupContainer.cpp | |
index 1d5abb78c6bc0..8217f110b03f4 100644 | |
--- a/dom/base/RadioGroupContainer.cpp | |
+++ b/dom/base/RadioGroupContainer.cpp | |
@@ -131,6 +131,19 @@ nsresult RadioGroupContainer::GetNextRadioButton( | |
return NS_OK; | |
} | |
+nsresult RadioGroupContainer::GetFirstSelectableRadioButton( | |
+ const nsAString& aName, HTMLInputElement** aRadioOut) { | |
+ *aRadioOut = nullptr; | |
+ nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); | |
+ for (RefPtr<HTMLInputElement> radio : radioGroup->mRadioButtons.AsList()) { | |
+ if (!radio->Disabled()) { | |
+ radio.forget(aRadioOut); | |
+ break; | |
+ } | |
+ } | |
+ return NS_OK; | |
+} | |
+ | |
void RadioGroupContainer::AddToRadioGroup(const nsAString& aName, | |
HTMLInputElement* aRadio, | |
nsIContent* aAncestor) { | |
diff --git a/dom/base/RadioGroupContainer.h b/dom/base/RadioGroupContainer.h | |
index 0c920c1c09b7d..2e0649a6ce46e 100644 | |
--- a/dom/base/RadioGroupContainer.h | |
+++ b/dom/base/RadioGroupContainer.h | |
@@ -32,6 +32,8 @@ class RadioGroupContainer final { | |
nsresult GetNextRadioButton(const nsAString& aName, const bool aPrevious, | |
HTMLInputElement* aFocusedRadio, | |
HTMLInputElement** aRadioOut); | |
+ nsresult GetFirstSelectableRadioButton(const nsAString& aName, | |
+ HTMLInputElement** aRadioOut); | |
void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio, | |
nsIContent* aAncestor); | |
void RemoveFromRadioGroup(const nsAString& aName, HTMLInputElement* aRadio); | |
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp | |
index e52ceec22475e..a8cfc48e290ff 100644 | |
--- a/dom/html/HTMLInputElement.cpp | |
+++ b/dom/html/HTMLInputElement.cpp | |
@@ -6482,8 +6482,6 @@ bool HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, | |
return false; | |
} | |
- // Current radio button is not selected. | |
- // But make it tabbable if nothing in group is selected. | |
auto* container = GetCurrentRadioGroupContainer(); | |
if (!container) { | |
*aIsFocusable = defaultFocusable; | |
@@ -6493,8 +6491,17 @@ bool HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, | |
nsAutoString name; | |
GetAttr(nsGkAtoms::name, name); | |
+ // Only the checked radio button (or the 1st, if none is checked) is tabbable. | |
if (container->GetCurrentRadioButton(name)) { | |
*aTabIndex = -1; | |
+ *aIsFocusable = defaultFocusable; | |
+ return false; | |
+ } | |
+ | |
+ RefPtr<HTMLInputElement> firstRadio; | |
+ container->GetFirstSelectableRadioButton(name, getter_AddRefs(firstRadio)); | |
+ if (this != firstRadio) { | |
+ *aTabIndex = -1; | |
} | |
*aIsFocusable = defaultFocusable; | |
return false; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment