зеркало из https://github.com/mozilla/gecko-dev.git
Bug 976739 - Allow user initiated stepping of <input type=number> when its value is the empty string (even if it is invalid due to the 'required' attribute being present) and step correctly if the value 0 (the default for the empty string) is not on a step. r=smaug
This commit is contained in:
Родитель
807ab2beae
Коммит
64f3cbe833
|
@ -2140,7 +2140,15 @@ HTMLInputElement::GetValueIfStepped(int32_t aStep,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (GetValidityState(VALIDITY_STATE_STEP_MISMATCH) &&
|
||||
// If the current value isn't aligned on a step, then shift the value to the
|
||||
// nearest step that will cause the addition of aStep steps (further below)
|
||||
// to |value| to hit the required value.
|
||||
// (Instead of using GetValidityState(VALIDITY_STATE_STEP_MISMATCH) we have
|
||||
// to check HasStepMismatch and pass true as its aUseZeroIfValueNaN argument
|
||||
// since we need to treat the value "" as zero for stepping purposes even
|
||||
// though we don't suffer from a step mismatch when our value is the empty
|
||||
// string.)
|
||||
if (HasStepMismatch(true) &&
|
||||
value != minimum && value != maximum) {
|
||||
if (aStep > 0) {
|
||||
value -= NS_floorModulo(value - GetStepBase(), step);
|
||||
|
@ -3641,13 +3649,21 @@ HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
|
|||
// want to wipe out what they typed if they try to increment/decrement the
|
||||
// value. Better is to highlight the value as being invalid so that they
|
||||
// can correct what they typed.
|
||||
// We pass 'true' for UpdateValidityUIBits' aIsFocused argument regardless
|
||||
// because we need the UI to update _now_ or the user will wonder why the
|
||||
// step behavior isn't functioning.
|
||||
// We only do this if there actually is a value typed in by/displayed to
|
||||
// the user. (IsValid() can return false if the 'required' attribute is
|
||||
// set and the value is the empty string.)
|
||||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(GetPrimaryFrame());
|
||||
if (numberControlFrame &&
|
||||
!numberControlFrame->AnonTextControlIsEmpty()) {
|
||||
// We pass 'true' for UpdateValidityUIBits' aIsFocused argument
|
||||
// regardless because we need the UI to update _now_ or the user will
|
||||
// wonder why the step behavior isn't functioning.
|
||||
UpdateValidityUIBits(true);
|
||||
UpdateState(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Decimal newValue = Decimal::nan(); // unchanged if value will not change
|
||||
|
||||
|
@ -6433,7 +6449,7 @@ HTMLInputElement::IsRangeUnderflow() const
|
|||
}
|
||||
|
||||
bool
|
||||
HTMLInputElement::HasStepMismatch() const
|
||||
HTMLInputElement::HasStepMismatch(bool aUseZeroIfValueNaN) const
|
||||
{
|
||||
if (!DoesStepApply()) {
|
||||
return false;
|
||||
|
@ -6441,9 +6457,13 @@ HTMLInputElement::HasStepMismatch() const
|
|||
|
||||
Decimal value = GetValueAsDecimal();
|
||||
if (value.isNaN()) {
|
||||
if (aUseZeroIfValueNaN) {
|
||||
value = 0;
|
||||
} else {
|
||||
// The element can't suffer from step mismatch if it's value isn't a number.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Decimal step = GetStep();
|
||||
if (step == kStepAny) {
|
||||
|
|
|
@ -256,7 +256,7 @@ public:
|
|||
bool HasPatternMismatch() const;
|
||||
bool IsRangeOverflow() const;
|
||||
bool IsRangeUnderflow() const;
|
||||
bool HasStepMismatch() const;
|
||||
bool HasStepMismatch(bool aUseZeroIfValueNaN = false) const;
|
||||
bool HasBadInput() const;
|
||||
void UpdateTooLongValidityState();
|
||||
void UpdateValueMissingValidityState();
|
||||
|
|
|
@ -71,6 +71,18 @@ function getStepBase(element) {
|
|||
Number(element.getAttribute("value") || "NaN") || 0;
|
||||
}
|
||||
|
||||
function hasStepMismatch(element) {
|
||||
var value = element.value;
|
||||
if (value == "") {
|
||||
value = 0;
|
||||
}
|
||||
var step = getStep(element);
|
||||
if (step == "any") {
|
||||
return false;
|
||||
}
|
||||
return ((value - getStepBase(element)) % step) != 0;
|
||||
}
|
||||
|
||||
function floorModulo(x, y) {
|
||||
return (x - y * Math.floor(x / y));
|
||||
}
|
||||
|
@ -101,7 +113,7 @@ function expectedValueAfterStepUpOrDown(stepFactor, element) {
|
|||
return value;
|
||||
}
|
||||
|
||||
if (element.validity.stepMismatch &&
|
||||
if (hasStepMismatch(element) &&
|
||||
value != minimum && value != maximum) {
|
||||
if (stepFactor > 0) {
|
||||
value -= floorModulo(value - getStepBase(element), step);
|
||||
|
@ -138,8 +150,8 @@ function test() {
|
|||
var elem = document.getElementById("input");
|
||||
elem.focus();
|
||||
|
||||
elem.min = -3;
|
||||
elem.max = 3;
|
||||
elem.min = -5;
|
||||
elem.max = 5;
|
||||
elem.step = 2;
|
||||
var defaultValue = 0;
|
||||
var oldVal, expectedVal;
|
||||
|
@ -203,6 +215,22 @@ function test() {
|
|||
sendString("abc");
|
||||
synthesizeKey(key, {});
|
||||
is(elem.value, "", "Test " + key + " does nothing when the input is invalid");
|
||||
|
||||
// Test that no value does not block UI initiated stepping:
|
||||
oldVal = elem.value = "";
|
||||
elem.setAttribute("required", "required");
|
||||
elem.select();
|
||||
expectedVal = expectedValAfterKeyEvent(key, elem);
|
||||
synthesizeKey(key, {});
|
||||
is(elem.value, expectedVal, "Test " + key + " for number control with value set to the empty string and with the 'required' attribute set");
|
||||
|
||||
// Same again:
|
||||
expectedVal = expectedValAfterKeyEvent(key, elem);
|
||||
synthesizeKey(key, {});
|
||||
is(elem.value, expectedVal, "Test repeat of " + key + " for number control");
|
||||
|
||||
// Reset 'required' attribute:
|
||||
elem.removeAttribute("required");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче