Bug 1622221 - Rework number input localization. r=jwatt

This restores our previous behavior with the new <input type=number>
implementation (see the changes in test_input_number_l10n.html, which undoes the
changes of the regressing bug), and adds a test that shows that we display the
localized value properly.

Differential Revision: https://phabricator.services.mozilla.com/D66822

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2020-03-23 09:36:52 +00:00
Родитель ae23069b7b
Коммит 0c9bcce517
9 изменённых файлов: 63 добавлений и 12 удалений

Просмотреть файл

@ -1441,7 +1441,7 @@ void HTMLInputElement::GetValue(nsAString& aValue, CallerType aCallerType) {
GetValueInternal(aValue, aCallerType);
if (SanitizesOnValueGetter()) {
SanitizeValue(aValue);
SanitizeValue(aValue, ForValueGetter::Yes);
}
}
@ -4495,7 +4495,8 @@ void HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify) {
}
}
void HTMLInputElement::SanitizeValue(nsAString& aValue) {
void HTMLInputElement::SanitizeValue(nsAString& aValue,
ForValueGetter aForGetter) {
NS_ASSERTION(mDoneCreating, "The element creation should be finished!");
switch (mType) {
@ -4517,7 +4518,40 @@ void HTMLInputElement::SanitizeValue(nsAString& aValue) {
bool ok = mInputType->ConvertStringToNumber(aValue, value);
if (!ok) {
aValue.Truncate();
return;
}
nsAutoString sanitizedValue;
if (aForGetter == ForValueGetter::Yes) {
// If the default non-localized algorithm parses the value, then we're
// done, don't un-localize it, to avoid precision loss, and to preserve
// scientific notation as well for example.
//
// FIXME(emilio, bug 1622808): Localization should ideally be more
// input-preserving.
if (StringToDecimal(aValue).isFinite()) {
return;
}
// For the <input type=number> value getter, we return the unlocalized
// value if it doesn't parse as StringToDecimal, for compat with other
// browsers.
char buf[32];
DebugOnly<bool> ok = value.toString(buf, ArrayLength(buf));
sanitizedValue.AssignASCII(buf);
MOZ_ASSERT(ok, "buf not big enough");
} else {
mInputType->ConvertNumberToString(value, sanitizedValue);
// Otherwise we localize as needed, but if both the localized and
// unlocalized version parse, we just use the unlocalized one, to
// preserve the input as much as possible.
//
// FIXME(emilio, bug 1622808): Localization should ideally be more
// input-preserving.
if (StringToDecimal(sanitizedValue).isFinite()) {
return;
}
}
aValue.Assign(sanitizedValue);
} break;
case NS_FORM_INPUT_RANGE: {
Decimal minimum = GetMinimum();

Просмотреть файл

@ -1085,12 +1085,14 @@ class HTMLInputElement final : public TextControlElement,
MOZ_CAN_RUN_SCRIPT
void HandleTypeChange(uint8_t aNewType, bool aNotify);
enum class ForValueGetter { No, Yes };
/**
* Sanitize the value of the element depending of its current type.
* See:
* http://www.whatwg.org/specs/web-apps/current-work/#value-sanitization-algorithm
*/
void SanitizeValue(nsAString& aValue);
void SanitizeValue(nsAString& aValue, ForValueGetter = ForValueGetter::No);
/**
* Returns whether the placeholder attribute applies for the current type.

Просмотреть файл

@ -95,8 +95,6 @@ nsresult NumericInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage) {
bool NumericInputTypeBase::ConvertStringToNumber(nsAString& aValue,
Decimal& aResultValue) const {
// FIXME(emilio, bug 1605158): This should really just be
// StringToDecimal(aValue).
ICUUtils::LanguageTagIterForContent langTagIter(mInputElement);
aResultValue =
Decimal::fromDouble(ICUUtils::ParseNumber(aValue, langTagIter));
@ -120,7 +118,7 @@ bool NumericInputTypeBase::ConvertNumberToString(
return ok;
}
/* input type=numer */
/* input type=number */
bool NumberInputType::IsValueMissing() const {
if (!mInputElement->IsRequired()) {
@ -140,6 +138,16 @@ bool NumberInputType::HasBadInput() const {
return !value.IsEmpty() && mInputElement->GetValueAsDecimal().isNaN();
}
bool NumberInputType::ConvertNumberToString(
Decimal aValue, nsAString& aResultString) const {
MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
aResultString.Truncate();
ICUUtils::LanguageTagIterForContent langTagIter(mInputElement);
ICUUtils::LocalizeNumber(aValue.toDouble(), langTagIter, aResultString);
return true;
}
nsresult NumberInputType::GetValueMissingMessage(nsAString& aMessage) {
return nsContentUtils::GetMaybeLocalizedString(
nsContentUtils::eDOM_PROPERTIES, "FormValidationBadInputNumber",

Просмотреть файл

@ -34,7 +34,7 @@ class NumericInputTypeBase : public InputType {
};
// input type=number
class NumberInputType : public NumericInputTypeBase {
class NumberInputType final : public NumericInputTypeBase {
public:
static InputType* Create(HTMLInputElement* aInputElement, void* aMemory) {
return new (aMemory) NumberInputType(aInputElement);
@ -46,6 +46,9 @@ class NumberInputType : public NumericInputTypeBase {
nsresult GetValueMissingMessage(nsAString& aMessage) override;
nsresult GetBadInputMessage(nsAString& aMessage) override;
bool ConvertNumberToString(Decimal aValue,
nsAString& aResultString) const override;
protected:
bool IsMutable() const override;

Просмотреть файл

@ -47,8 +47,8 @@ function runTest(test) {
sendString(test.inputWithoutGrouping);
is(elem.valueAsNumber, test.value, "Test " + test.desc + " ('" + test.langTag +
"') localization without grouping separator");
is(elem.value, test.inputWithoutGrouping,
"Test " + test.desc + " ('" + test.langTag + "') localization without grouping separator as string");
is(elem.value, String(test.value), "Test " + test.desc + " ('" + test.langTag +
"') localization without grouping separator as string");
}
function runInvalidInputTest(test) {

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type=number value=1.25 step=0.01>

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type=number value=1.25 step=0.01 lang=de>

Просмотреть файл

@ -55,5 +55,8 @@ fuzzy(0-128,0-4) == number-reframe-anon-text-field.html number-reframe-anon-text
# Style inheritance:
== number-style-inheritance.html number-style-inheritance-ref.html
# l10n
!= number-localized.html number-localized-notref.html
== overflow-clip-box.html overflow-clip-box-ref.html
!= overflow-clip-box.html overflow-clip-box-notref.html

Просмотреть файл

@ -1,8 +1,5 @@
[number.html]
max-asserts: 2
[value >= Number.MAX_VALUE]
expected: FAIL
[value = +1]
expected: FAIL