Bug 1431041: Fix placeholder-shown when the value of the input is invalid. r?smaug draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 17 Jan 2018 18:30:59 +0100
changeset 721789 d22e3b436114f2d0c1c7af4b1157881cba6e42c0
parent 721788 8e2fa96de3dd25373c624d26ccf26f8ac084ef7b
child 721790 14c188daf498834f8d25fe27c42f75fec734fa54
push id95947
push userbmo:emilio@crisal.io
push dateWed, 17 Jan 2018 21:20:18 +0000
reviewerssmaug
bugs1431041
milestone59.0a1
Bug 1431041: Fix placeholder-shown when the value of the input is invalid. r?smaug Wow, the setup for <input type="number"> is really weird :(. Looking at the callers, this should be sane. MozReview-Commit-ID: C0ZNNSdg0Hb
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/html/test/forms/mochitest.ini
dom/html/test/forms/test_input_number_placeholder_shown.html
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -6595,27 +6595,45 @@ HTMLInputElement::IntrinsicState() const
                 GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW))
                  ? NS_EVENT_STATE_OUTOFRANGE
                  : NS_EVENT_STATE_INRANGE;
     }
   }
 
   if (PlaceholderApplies() &&
       HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder) &&
-      IsValueEmpty()) {
+      ShouldShowPlaceholder()) {
     state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
   }
 
   if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
     state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
   }
 
   return state;
 }
 
+bool
+HTMLInputElement::ShouldShowPlaceholder() const
+{
+  MOZ_ASSERT(PlaceholderApplies());
+
+  if (IsValueEmpty()) {
+    return true;
+  }
+
+  // For number controls, even though the (sanitized) value is empty, there may
+  // be text in the anon text control.
+  if (nsNumberControlFrame* frame = do_QueryFrame(GetPrimaryFrame())) {
+    return frame->AnonTextControlIsEmpty();
+  }
+
+  return false;
+}
+
 void
 HTMLInputElement::AddStates(EventStates aStates)
 {
   if (mType == NS_FORM_INPUT_TEXT) {
     EventStates focusStates(aStates & (NS_EVENT_STATE_FOCUS |
                                        NS_EVENT_STATE_FOCUSRING));
     if (!focusStates.IsEmpty()) {
       HTMLInputElement* ownerNumberControl = GetOwnerNumberControl();
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1054,16 +1054,21 @@ protected:
   /**
    * Returns whether the current value is the empty string.  This only makes
    * sense for some input types; does NOT make sense for file inputs.
    *
    * @return whether the current value is the empty string.
    */
   bool IsValueEmpty() const;
 
+  /**
+   * Returns whether the current placeholder value should be shown.
+   */
+  bool ShouldShowPlaceholder() const;
+
   void ClearFiles(bool aSetValueChanged);
 
   void SetIndeterminateInternal(bool aValue,
                                 bool aShouldInvalidate);
 
   /**
    * Called when an attribute is about to be changed
    */
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -53,16 +53,17 @@ skip-if = os == "android"
 # Not run on Firefox for Android where the spin buttons are hidden:
 skip-if = os == "android"
 [test_input_number_rounding.html]
 skip-if = os == "android"
 [test_input_number_validation.html]
 # We don't build ICU for Firefox for Android:
 skip-if = os == "android"
 [test_input_number_focus.html]
+[test_input_number_placeholder_shown.html]
 [test_input_range_attr_order.html]
 [test_input_range_key_events.html]
 [test_input_range_mouse_and_touch_events.html]
 [test_input_range_rounding.html]
 [test_input_sanitization.html]
 skip-if = os == 'android' && debug # Extremely slow on debug android
 [test_input_textarea_set_value_no_scroll.html]
 [test_input_time_key_events.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/test_input_number_placeholder_shown.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>Test for :placeholder-shown on input elements and invalid values.</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<style>
+input {
+  border: 1px solid purple;
+}
+input:placeholder-shown {
+  border-color: blue;
+}
+</style>
+<input type="number" placeholder="foo">
+<script>
+  SimpleTest.waitForExplicitFinish();
+  SimpleTest.waitForFocus(function() {
+    test();
+    SimpleTest.finish();
+  });
+
+  function test() {
+    let input = document.querySelector('input');
+    input.focus();
+    is(getComputedStyle(input).borderLeftColor, "rgb(0, 0, 255)",
+       ":placeholder-shown should apply")
+    synthesizeKey('x', {});
+    isnot(getComputedStyle(input).borderLeftColor, "rgb(0, 0, 255)",
+       ":placeholder-shown should not apply, even though the value is invalid")
+  }
+</script>