Bug 1582323: When a file input has DOM focus, focus the browse button inside it for a11y. r=MarcoZ a=lizzard
authorJames Teh <jteh@mozilla.com>
Thu, 19 Sep 2019 04:34:29 +0000
changeset 555299 3ca86ab994bff98de8a5cc93c8d75b48ce7bcb03
parent 555298 a552d3955e14a2e2c98f9c56aed0d0a1438e5bf3
child 555300 69a1bd55264869c5a53100ee20020fb727bc722b
push id2165
push userffxbld-merge
push dateMon, 14 Oct 2019 16:30:58 +0000
treeherdermozilla-release@0eae18af659f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMarcoZ, lizzard
bugs1582323
milestone70.0
Bug 1582323: When a file input has DOM focus, focus the browse button inside it for a11y. r=MarcoZ a=lizzard Differential Revision: https://phabricator.services.mozilla.com/D46386
accessible/html/HTMLFormControlAccessible.cpp
accessible/html/HTMLFormControlAccessible.h
accessible/tests/mochitest/events/test_focus_controls.html
--- a/accessible/html/HTMLFormControlAccessible.cpp
+++ b/accessible/html/HTMLFormControlAccessible.cpp
@@ -434,16 +434,33 @@ nsresult HTMLFileInputAccessible::Handle
           event->FromUserInput());
       nsEventShell::FireEvent(childEvent);
     }
   }
 
   return NS_OK;
 }
 
+Accessible* HTMLFileInputAccessible::CurrentItem() const {
+  // Allow aria-activedescendant to override.
+  if (Accessible* item = HyperTextAccessibleWrap::CurrentItem()) {
+    return item;
+  }
+
+  // The HTML file input itself gets DOM focus, not the button inside it.
+  // For a11y, we want the button to get focus.
+  Accessible* button = FirstChild();
+  if (!button) {
+    MOZ_ASSERT_UNREACHABLE("File input doesn't contain a button");
+    return nullptr;
+  }
+  MOZ_ASSERT(button->IsButton());
+  return button;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLSpinnerAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 role HTMLSpinnerAccessible::NativeRole() const { return roles::SPINBUTTON; }
 
 void HTMLSpinnerAccessible::Value(nsString& aValue) const {
   AccessibleWrap::Value(aValue);
--- a/accessible/html/HTMLFormControlAccessible.h
+++ b/accessible/html/HTMLFormControlAccessible.h
@@ -117,16 +117,17 @@ class HTMLTextFieldAccessible final : pu
  */
 class HTMLFileInputAccessible : public HyperTextAccessibleWrap {
  public:
   HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual mozilla::a11y::role NativeRole() const override;
   virtual nsresult HandleAccEvent(AccEvent* aAccEvent) override;
+  virtual Accessible* CurrentItem() const override;
 };
 
 /**
  * Used for HTML input@type="number".
  */
 class HTMLSpinnerAccessible : public AccessibleWrap {
  public:
   HTMLSpinnerAccessible(nsIContent* aContent, DocAccessible* aDoc)
--- a/accessible/tests/mochitest/events/test_focus_controls.html
+++ b/accessible/tests/mochitest/events/test_focus_controls.html
@@ -33,16 +33,19 @@
       gQueue.push(new synthFocus("radio1"));
       gQueue.push(new synthDownKey("radio1", new focusChecker("radio2")));
 
       // no focus events for checkbox or radio inputs when they are checked
       // programmatically
       gQueue.push(new changeCurrentItem("checkbox"));
       gQueue.push(new changeCurrentItem("radio1"));
 
+      let fileBrowseButton = getAccessible("file").firstChild;
+      gQueue.push(new synthFocus("file", new focusChecker(fileBrowseButton)));
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 
@@ -61,12 +64,13 @@
   <input id="textbox">
   <textarea id="textarea"></textarea>
 
   <input id="button1" type="button" value="button">
   <button id="button2">button</button>
   <input id="checkbox" type="checkbox">
   <input id="radio1" type="radio" name="radiogroup">
   <input id="radio2" type="radio" name="radiogroup">
+  <input id="file" type="file">
 
   <div id="eventdump"></div>
 </body>
 </html>