Bug 638293 - When the value of <input type=number> changes, keep its anonymous text input field child in sync as appropriate. r=smaug
authorJonathan Watt <jwatt@jwatt.org>
Tue, 21 Jun 2011 16:17:10 +0200
changeset 157385 582687f6eaba5aeb4ab5df370f7447130658444b
parent 157384 4c2b12f35738354caa3df66f8e8f4962a7a46dd4
child 157386 764f96661644ef67e85950101c27d6194a50127e
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssmaug
bugs638293
milestone28.0a1
Bug 638293 - When the value of <input type=number> changes, keep its anonymous text input field child in sync as appropriate. r=smaug
content/html/content/src/HTMLInputElement.cpp
layout/forms/nsNumberControlFrame.cpp
layout/forms/nsNumberControlFrame.h
layout/reftests/forms/input/number/reftest.list
layout/reftests/forms/input/number/show-value-ref.html
layout/reftests/forms/input/number/show-value.html
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -2691,16 +2691,24 @@ HTMLInputElement::SetValueInternal(const
       if (IsSingleLineTextControl(false)) {
         mInputData.mState->SetValue(value, aUserInput, aSetValueChanged);
       } else {
         mInputData.mValue = ToNewUnicode(value);
         if (aSetValueChanged) {
           SetValueChanged(true);
         }
         OnValueChanged(!mParserCreating);
+
+        if (mType == NS_FORM_INPUT_NUMBER) {
+          nsNumberControlFrame* numberControlFrame =
+            do_QueryFrame(GetPrimaryFrame());
+          if (numberControlFrame) {
+            numberControlFrame->UpdateForValueChange(value);
+          }
+        }
       }
 
       // Call parent's SetAttr for color input so its control frame is notified
       // and updated
       if (mType == NS_FORM_INPUT_COLOR) {
         return nsGenericHTMLFormElement::SetAttr(kNameSpaceID_None,
                                                  nsGkAtoms::value, aValue,
                                                  true);
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -218,16 +218,21 @@ nsNumberControlFrame::CreateAnonymousCon
                             nsGkAtoms::input,
                             nsCSSPseudoElements::ePseudo_mozNumberText,
                             outerWrapperCI.mStyleContext);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mTextField->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
                       NS_LITERAL_STRING("text"), PR_FALSE);
 
+  // Initialize the text field value:
+  nsAutoString value;
+  HTMLInputElement::FromContent(mContent)->GetValue(value);
+  mTextField->SetAttr(kNameSpaceID_None, nsGkAtoms::value, value, false);
+
   if (mContent->AsElement()->State().HasState(NS_EVENT_STATE_FOCUS)) {
     // We don't want to focus the frame but the text field.
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mTextField);
     NS_ASSERTION(element, "Really, this should be a nsIDOMElement!");
     fm->SetFocus(element, 0);
   }
 
@@ -272,8 +277,18 @@ nsNumberControlFrame::GetAnonTextControl
 
 void
 nsNumberControlFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
                                                uint32_t aFilter)
 {
   // Only one direct anonymous child:
   aElements.MaybeAppendElement(mOuterWrapper);
 }
+
+void
+nsNumberControlFrame::UpdateForValueChange(const nsAString& aValue)
+{
+  // We need to update the value of our anonymous text control here. Note that
+  // this must be its value, and not its 'value' attribute (the default value),
+  // since the default value is ignored once a user types into the text
+  // control.
+  HTMLInputElement::FromContent(mTextField)->SetValue(aValue);
+}
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -60,16 +60,22 @@ public:
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
+  /**
+   * When our HTMLInputElement's value changes, it calls this method to tell
+   * us to sync up our anonymous text input field child.
+   */
+  void UpdateForValueChange(const nsAString& aValue);
+
   HTMLInputElement* GetAnonTextControl();
 
 private:
 
   nsresult MakeAnonymousElement(nsIContent** aResult,
                                 nsTArray<ContentInfo>& aElements,
                                 nsIAtom* aTagName,
                                 nsCSSPseudoElements::Type aPseudoType,
--- a/layout/reftests/forms/input/number/reftest.list
+++ b/layout/reftests/forms/input/number/reftest.list
@@ -9,11 +9,14 @@ skip-if(!Android&&!B2G) == number-same-a
 
 # should look the same as type=text, except for the spin box
 == number-similar-to-text-unthemed.html number-similar-to-text-unthemed-ref.html
 
 # dynamic type changes:
 fuzzy-if(/^Windows\x20NT\x205\.1/.test(http.oscpu),64,4) fuzzy-if(cocoaWidget,63,4) == to-number-from-other-type-unthemed-1.html to-number-from-other-type-unthemed-1-ref.html
 == from-number-to-other-type-unthemed-1.html from-number-to-other-type-unthemed-1-ref.html
 
+# dynamic value changes:
+== show-value.html show-value-ref.html
+
 # focus
 fails-if(B2G) needs-focus == focus-handling.html focus-handling-ref.html # bug 940760
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/number/show-value-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">                                                         
+    <style>                                                                        
+                                                                                   
+input {                                                                            
+  -moz-appearance: none;                                                           
+}                                                                                  
+                                                                                   
+    </style>                                                                       
+  </head>
+  <body>
+    <input value='42'><br>
+    <input value='42'><br>
+    <input value='42'><br>
+    <input value='42'><br>
+    <input value='42'><br>
+    <form>
+      <input value='42'>
+    </form>
+    <!-- div to cover spin box area for type=number to type=text comparison -->
+    <div style="display:block; position:absolute; background-color:black; width:200px; height:400px; top:0px; left:100px;">
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/number/show-value.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <head>
+    <meta charset="utf-8">
+    <style>
+
+input {
+  -moz-appearance: none;
+}
+
+    </style>
+    <script>
+
+function run() {
+  var numbers = document.getElementsByTagName('input');
+  numbers[2].style.display = 'inline-block'; // none -> inline-block
+  numbers[3].setAttribute('value', '42');
+  numbers[4].value = '42';
+  numbers[5].varue = '1337'; // deliberately misspelt - should not set value
+  document.forms[0].reset(); // numbers[5] value should be 42 again.
+  document.documentElement.className = '';
+}
+
+document.addEventListener("MozReftestInvalidate", run);
+
+    </script>
+  </head>
+  <body onload="run();">
+    <input type='number' value='42'><br>
+    <input value='42' type='number'><br>
+    <input type='number' value='42' style="display: none;"><br>
+    <input type='number' value='1337'><br>
+    <input type='number' value='1337'><br>
+    <form>
+      <input type='number' value='42'>
+    </form>
+    <!-- div to cover spin box area for type=number to type=text comparison -->
+    <div style="display:block; position:absolute; background-color:black; width:200px; height:400px; top:0px; left:100px;">
+  </body>
+</html>