Bug 945784, part 2 - Fire 'change' events for <input type=number> more frequently, per the new HTML5 rules. r=smaug
authorJonathan Watt <jwatt@jwatt.org>
Thu, 05 Dec 2013 16:20:33 +0000
changeset 174619 29db440280c8db85eb32931cc69ab5202900735e
parent 174618 64f359e4e054e9c8f8d61e7f08e5310f9264c894
child 174620 b68f5c69dce226474dcb7603fb933f0a77160337
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs945784
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 945784, part 2 - Fire 'change' events for <input type=number> more frequently, per the new HTML5 rules. r=smaug
content/html/content/src/HTMLInputElement.cpp
content/html/content/test/forms/test_change_event.html
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -3342,16 +3342,28 @@ HTMLInputElement::PreHandleEvent(nsEvent
           // is moved to our anonymous text control.
           nsNumberControlFrame* numberControlFrame =
             do_QueryFrame(GetPrimaryFrame());
           if (numberControlFrame) {
             numberControlFrame->HandleFocusEvent(aVisitor.mEvent);
           }
         }
       }
+    } else if (aVisitor.mEvent->message == NS_KEY_UP) {
+      WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
+      if ((keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
+          !(keyEvent->IsShift() || keyEvent->IsControl() ||
+            keyEvent->IsAlt() || keyEvent->IsMeta() ||
+            keyEvent->IsAltGraph() || keyEvent->IsFn() ||
+            keyEvent->IsOS())) {
+        // The up/down arrow key events fire 'change' events when released
+        // so that at the end of a series of up/down arrow key repeat events
+        // the value is considered to be "commited" by the user.
+        FireChangeEventIfNeeded();
+      }
     }
   }
 
   nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
 
   // We do this after calling the base class' PreHandleEvent so that
   // nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
   if (mType == NS_FORM_INPUT_NUMBER &&
@@ -3501,17 +3513,35 @@ HTMLInputElement::StopNumberControlSpinn
 
     FireChangeEventIfNeeded();
   }
 }
 
 void
 HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
 {
-  ApplyStep(aDirection);
+  // We cannot call ApplyStep here because that eventually calls SetValue, and
+  // that sets mFocusedValue. We are handling a user action here, not a script
+  // action, so we do not want to reset mFocusedValue or else we will fail to
+  // dispatch 'change' events correctly.
+  Decimal value = GetValueAsDecimal();
+  if (value.isNaN()) {
+    value = 0;
+  }
+  Decimal step = GetStep();
+  if (step == kStepAny) {
+    step = GetDefaultStep();
+  }
+  MOZ_ASSERT(value.isFinite() && step.isFinite());
+  Decimal newValue = value + step * aDirection;
+
+  nsAutoString newVal;
+  ConvertNumberToString(newValue, newVal);
+  SetValueInternal(newVal, true, true);
+
   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
                                        static_cast<nsIDOMHTMLInputElement*>(this),
                                        NS_LITERAL_STRING("input"), true,
                                        false);
 }
 
 static bool
 SelectTextFieldOnFocus()
--- a/content/html/content/test/forms/test_change_event.html
+++ b/content/html/content/test/forms/test_change_event.html
@@ -170,19 +170,28 @@ https://bugzilla.mozilla.org/show_bug.cg
     var number = document.getElementById("input_number");
     number.focus();
     synthesizeKey("a", {});
     number.blur();
     is(numberChange, 0, "Change event shouldn't be dispatched on number input element for key changes that don't change its value");
     number.value = "";
     number.focus();
     synthesizeKey("1", {});
+    synthesizeKey("2", {});
     is(numberChange, 0, "Change event shouldn't be dispatched on number input element for keyboard input until it loses focus");
     number.blur();
     is(numberChange, 1, "Change event should be dispatched on number input element on blur");
+    is(number.value, 12, "Sanity check that number keys were actually handled");
+    number.value = "";
+    number.focus();
+    synthesizeKey("VK_UP", {});
+    synthesizeKey("VK_UP", {});
+    synthesizeKey("VK_DOWN", {});
+    is(numberChange, 4, "Change event should be dispatched on number input element for up/down arrow keys (a special case)");
+    is(number.value, 1, "Sanity check that number and arrow keys were actually handled");
 
     // Special case type=range
     var range = document.getElementById("input_range");
     range.focus();
     synthesizeKey("a", {});
     range.blur();
     is(rangeChange, 0, "Change event shouldn't be dispatched on range input element for key changes that don't change its value");
     range.focus();