Bug 1319078 - Form validation should account for the visibility of the input element. r=gijs
authorJohn Dai <jdai@mozilla.com>
Thu, 12 Jan 2017 18:54:00 -0500
changeset 357575 c36d3ce91e1685724114ad330651edf21980bb57
parent 357574 d700dc85c04c1db2cf2a3ddc77398d371ae45e28
child 357576 da4c295b7d1474d7c49409d271dd6c27008752d7
push id10621
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 16:02:43 +0000
treeherdermozilla-aurora@dca7b42e6c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs1319078
milestone53.0a1
Bug 1319078 - Form validation should account for the visibility of the input element. r=gijs
browser/modules/FormSubmitObserver.jsm
browser/modules/test/browser.ini
browser/modules/test/browser_bug1319078.js
--- a/browser/modules/FormSubmitObserver.jsm
+++ b/browser/modules/FormSubmitObserver.jsm
@@ -96,50 +96,58 @@ FormSubmitObserver.prototype =
   notifyInvalidSubmit(aFormElement, aInvalidElements) {
     // We are going to handle invalid form submission attempt by focusing the
     // first invalid element and show the corresponding validation message in a
     // panel attached to the element.
     if (!aInvalidElements.length) {
       return;
     }
 
-    // Insure that this is the FormSubmitObserver associated with the
-    // element / window this notification is about.
-    let element = aInvalidElements.queryElementAt(0, Ci.nsISupports);
-    if (this._content != element.ownerGlobal.top.document.defaultView) {
-      return;
-    }
+    // Show a validation message on the first focusable element.
+    for (let i = 0; i < aInvalidElements.length; i++) {
+      // Insure that this is the FormSubmitObserver associated with the
+      // element / window this notification is about.
+      let element = aInvalidElements.queryElementAt(i, Ci.nsISupports);
+      if (this._content != element.ownerGlobal.top.document.defaultView) {
+        return;
+      }
 
-    if (!(element instanceof HTMLInputElement ||
-          element instanceof HTMLTextAreaElement ||
-          element instanceof HTMLSelectElement ||
-          element instanceof HTMLButtonElement)) {
-      return;
-    }
+      if (!(element instanceof HTMLInputElement ||
+            element instanceof HTMLTextAreaElement ||
+            element instanceof HTMLSelectElement ||
+            element instanceof HTMLButtonElement)) {
+        continue;
+      }
 
-    // Update validation message before showing notification
-    this._validationMessage = element.validationMessage;
+      if (!Services.focus.elementIsFocusable(element, 0)) {
+        continue;
+      }
 
-    // Don't connect up to the same element more than once.
-    if (this._element == element) {
-      this._showPopup(element);
-      return;
-    }
-    this._element = element;
+      // Update validation message before showing notification
+      this._validationMessage = element.validationMessage;
 
-    element.focus();
+      // Don't connect up to the same element more than once.
+      if (this._element == element) {
+        this._showPopup(element);
+        break;
+      }
+      this._element = element;
 
-    // Watch for input changes which may change the validation message.
-    element.addEventListener("input", this, false);
+      element.focus();
+
+      // Watch for input changes which may change the validation message.
+      element.addEventListener("input", this, false);
 
-    // Watch for focus changes so we can disconnect our listeners and
-    // hide the popup.
-    element.addEventListener("blur", this, false);
+      // Watch for focus changes so we can disconnect our listeners and
+      // hide the popup.
+      element.addEventListener("blur", this, false);
 
-    this._showPopup(element);
+      this._showPopup(element);
+      break;
+    }
   },
 
   /*
    * Internal
    */
 
   /*
    * Handles input changes on the form element we've associated a popup
--- a/browser/modules/test/browser.ini
+++ b/browser/modules/test/browser.ini
@@ -36,8 +36,9 @@ support-files =
   usageTelemetrySearchSuggestions.xml
 [browser_UsageTelemetry_searchbar.js]
 support-files =
   usageTelemetrySearchSuggestions.sjs
   usageTelemetrySearchSuggestions.xml
 [browser_UsageTelemetry_content.js]
 [browser_UsageTelemetry_content_aboutHome.js]
 [browser_urlBar_zoom.js]
+[browser_bug1319078.js]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/browser_bug1319078.js
@@ -0,0 +1,49 @@
+"use strict";
+
+var gInvalidFormPopup = document.getElementById('invalid-form-popup');
+
+function checkPopupHide() {
+  ok(gInvalidFormPopup.state != 'showing' && gInvalidFormPopup.state != 'open',
+     "[Test " + testId + "] The invalid form popup should not be shown");
+}
+
+var testId = 0;
+
+function incrementTest() {
+  testId++;
+  info("Starting next part of test");
+}
+
+/**
+ * In this test, we check that no popup appears if the element display is none.
+ */
+add_task(function* () {
+  ok(gInvalidFormPopup,
+     "The browser should have a popup to show when a form is invalid");
+
+  incrementTest();
+  let testPage =
+    'data:text/html,' +
+    '<form target="t"><input type="url"  placeholder="url" value="http://" style="display: none;"><input id="s" type="button" value="check"></form>';
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, testPage);
+  yield BrowserTestUtils.synthesizeMouse("#s", 0, 0, {}, gBrowser.selectedBrowser);
+
+  checkPopupHide();
+  yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * In this test, we check that no popup appears if the element visibility is hidden.
+ */
+add_task(function* () {
+  incrementTest();
+  let testPage =
+    'data:text/html,' +
+    '<form target="t"><input type="url"  placeholder="url" value="http://" style="visibility: hidden;"><input id="s" type="button" value="check"></form>';
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, testPage);
+  yield BrowserTestUtils.synthesizeMouse("#s", 0, 0, {}, gBrowser.selectedBrowser);
+
+  checkPopupHide();
+  yield BrowserTestUtils.removeTab(tab);
+});
+