Commit fe83def1 authored by Jonathan Watt's avatar Jonathan Watt
Browse files

Bug 927435 - When a user types into <input type=number>'s anonymous text...

Bug 927435 - When a user types into <input type=number>'s anonymous text control, update the value of the <input type=number> as appropriate. r=smaug
parent 9f8bfb29
Loading
Loading
Loading
Loading
+39 −1
Original line number Diff line number Diff line
@@ -3274,7 +3274,45 @@ HTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
    }
  }

  return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
  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 &&
      aVisitor.mEvent->mFlags.mIsTrusted  &&
      aVisitor.mEvent->originalTarget != this) {
    // <input type=number> has an anonymous <input type=text> descendant. If
    // 'input' or 'change' events are fired at that text control then we need
    // to do some special handling here.
    HTMLInputElement* textControl = nullptr;
    nsNumberControlFrame* numberControlFrame =
      do_QueryFrame(GetPrimaryFrame());
    if (numberControlFrame) {
      textControl = numberControlFrame->GetAnonTextControl();
    }
    if (textControl && aVisitor.mEvent->originalTarget == textControl) {
      if (aVisitor.mEvent->message == NS_FORM_INPUT) {
        // Propogate the anon text control's new value to our HTMLInputElement:
        numberControlFrame->HandlingInputEvent(true);
        nsAutoString value;
        textControl->GetValue(value);
        SetValueInternal(value, false, true);
        numberControlFrame->HandlingInputEvent(false);
      }
      else if (aVisitor.mEvent->message == NS_FORM_CHANGE) {
        // We cancel the DOM 'change' event that is fired for any change to our
        // anonymous text control since we fire our own 'change' events and
        // content shouldn't be seeing two 'change' events. Besides that we
        // (as a number) control have tighter restrictions on when our internal
        // value changes than our anon text control does, so in some cases
        // (if our text control's value doesn't parse as a number) we don't
        // want to fire a 'change' event at all.
        aVisitor.mCanHandle = false;
      }
    }
  }

  return rv;
}

void
+15 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
<input type="reset" id="input_reset" onchange="++NonTextInputChange[3];"></input>
<input type="radio" id="input_radio" onchange="++NonTextInputChange[4];"></input>
<input type="checkbox" id="input_checkbox" onchange="++NonTextInputChange[5];"></input>
<input type="number" id="input_number" onchange="++numberChange;"></input>
<input type="range" id="input_range" onchange="++rangeChange;"></input>
 
</div>
@@ -45,6 +46,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
  var NonTextInputTypes = ["button", "submit", "image", "reset", "radio", "checkbox"];
  var NonTextInputChange = [0, 0, 0, 0, 0, 0];

  var numberChange = 0;
  var rangeChange = 0;

  var blurTestCalled = false; //Sentinel to prevent infinite loop.
@@ -164,6 +166,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
      }
    }

    // Special case type=number
    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", {});
    is(numberChange, 0, "Change event shouldn't be dispatched on number input element for keyboard input until it is looses focus");
    number.blur();
    is(numberChange, 1, "Change event should be dispatched on number input element on blur");

    // Special case type=range
    var range = document.getElementById("input_range");
    range.focus();
+13 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)

nsNumberControlFrame::nsNumberControlFrame(nsStyleContext* aContext)
  : nsContainerFrame(aContext)
  , mHandlingInputEvent(false)
{
}

@@ -286,6 +287,18 @@ nsNumberControlFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
void
nsNumberControlFrame::UpdateForValueChange(const nsAString& aValue)
{
  if (mHandlingInputEvent) {
    // We have been called while our HTMLInputElement is processing a DOM
    // 'input' event targeted at our anonymous text control. Our
    // HTMLInputElement has taken the value of our anon text control and
    // called SetValueInternal on itself to keep its own value in sync. As a
    // result SetValueInternal has called us. In this one case we do not want
    // to update our anon text control, especially since aValue will be the
    // sanitized value, and only the internal value should be sanitized (not
    // the value shown to the user, and certainly we shouldn't change it as
    // they type).
    return;
  }
  // 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
+10 −0
Original line number Diff line number Diff line
@@ -71,6 +71,15 @@ public:
   */
  void UpdateForValueChange(const nsAString& aValue);

  /**
   * Called to notify this frame that its HTMLInputElement is currently
   * processing a DOM 'input' event.
   */
  void HandlingInputEvent(bool aHandlingEvent)
  {
    mHandlingInputEvent = aHandlingEvent;
  }

  HTMLInputElement* GetAnonTextControl();

private:
@@ -95,6 +104,7 @@ private:
  nsCOMPtr<nsIContent> mSpinBox;
  nsCOMPtr<nsIContent> mSpinUp;
  nsCOMPtr<nsIContent> mSpinDown;
  bool mHandlingInputEvent;
};

#endif // nsNumberControlFrame_h__