mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb/HTML: Implement <input> element valueAsNumber for 'month'
This commit is contained in:
parent
ea880ec8b5
commit
6c2ad49ed2
Notes:
github-actions[bot]
2025-02-22 19:11:04 +00:00
Author: https://github.com/shannonbooth
Commit: 6c2ad49ed2
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3485
Reviewed-by: https://github.com/AtkinsSJ ✅
Reviewed-by: https://github.com/gmta
Reviewed-by: https://github.com/trflynn89
5 changed files with 109 additions and 8 deletions
|
@ -2,12 +2,13 @@
|
|||
* Copyright (c) 2018-2023, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2022, Adam Hodgen <ant1441@gmail.com>
|
||||
* Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
|
||||
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
|
||||
* Copyright (c) 2023-2025, Shannon Booth <shannon@serenityos.org>
|
||||
* Copyright (c) 2023, stelar7 <dudedbz@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/GenericLexer.h>
|
||||
#include <AK/Time.h>
|
||||
#include <LibWeb/HTML/Dates.h>
|
||||
|
||||
|
@ -243,4 +244,68 @@ WebIDL::ExceptionOr<GC::Ref<JS::Date>> parse_time_string(JS::Realm& realm, Strin
|
|||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Can't parse time string"sv };
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-month-component
|
||||
static Optional<YearAndMonth> parse_a_month_component(GenericLexer& input)
|
||||
{
|
||||
// 1. Collect a sequence of code points that are ASCII digits from input given position. If the collected sequence is
|
||||
// not at least four characters long, then fail. Otherwise, interpret the resulting sequence as a base-ten integer.
|
||||
// Let that number be the year.
|
||||
auto year_string = input.consume_while(is_ascii_digit);
|
||||
if (year_string.length() < 4)
|
||||
return {};
|
||||
auto maybe_year = year_string.to_number<u32>();
|
||||
if (!maybe_year.has_value())
|
||||
return {};
|
||||
auto year = maybe_year.value();
|
||||
|
||||
// 2. If year is not a number greater than zero, then fail.
|
||||
if (year < 1)
|
||||
return {};
|
||||
|
||||
// 3. If position is beyond the end of input or if the character at position is not a U+002D HYPHEN-MINUS character, then
|
||||
// fail. Otherwise, move position forwards one character.
|
||||
if (!input.consume_specific('-'))
|
||||
return {};
|
||||
|
||||
// 4. Collect a sequence of code points that are ASCII digits from input given position. If the collected sequence is not
|
||||
// exactly two characters long, then fail. Otherwise, interpret the resulting sequence as a base-ten integer. Let that
|
||||
// number be the month.
|
||||
auto month_string = input.consume_while(is_ascii_digit);
|
||||
if (month_string.length() != 2)
|
||||
return {};
|
||||
auto month = month_string.to_number<u32>().value();
|
||||
|
||||
// 5. If month is not a number in the range 1 ≤ month ≤ 12, then fail.
|
||||
if (month < 1 || month > 12)
|
||||
return {};
|
||||
|
||||
// 6. Return year and month.
|
||||
return YearAndMonth { year, month };
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-month-string
|
||||
Optional<YearAndMonth> parse_a_month_string(StringView input_view)
|
||||
{
|
||||
// 1. Let input be the string being parsed.
|
||||
// 2. Let position be a pointer into input, initially pointing at the start of the string.
|
||||
GenericLexer input { input_view };
|
||||
|
||||
// 3. Parse a month component to obtain year and month. If this returns nothing, then fail.
|
||||
auto year_and_month = parse_a_month_component(input);
|
||||
if (!year_and_month.has_value())
|
||||
return {};
|
||||
|
||||
// 4. If position is not beyond the end of input, then fail.
|
||||
if (!input.is_eof())
|
||||
return {};
|
||||
|
||||
// 5. Return year and month.
|
||||
return year_and_month;
|
||||
}
|
||||
|
||||
i32 number_of_months_since_unix_epoch(YearAndMonth year_and_month)
|
||||
{
|
||||
return (year_and_month.year - 1970) * 12 + year_and_month.month - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,4 +23,11 @@ String normalize_local_date_and_time_string(String const& value);
|
|||
bool is_valid_time_string(StringView value);
|
||||
WebIDL::ExceptionOr<GC::Ref<JS::Date>> parse_time_string(JS::Realm& realm, StringView value);
|
||||
|
||||
struct YearAndMonth {
|
||||
u32 year;
|
||||
u32 month;
|
||||
};
|
||||
Optional<YearAndMonth> parse_a_month_string(StringView);
|
||||
i32 number_of_months_since_unix_epoch(YearAndMonth);
|
||||
|
||||
}
|
||||
|
|
|
@ -2067,6 +2067,18 @@ WebIDL::ExceptionOr<void> HTMLInputElement::set_width(WebIDL::UnsignedLong value
|
|||
return set_attribute(HTML::AttributeNames::width, String::number(value));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):concept-input-value-string-number
|
||||
static Optional<double> convert_month_string_to_number(StringView input)
|
||||
{
|
||||
// The algorithm to convert a string to a number, given a string input, is as follows: If parsing a month from input
|
||||
// results in an error, then return an error; otherwise, return the number of months between January 1970 and the
|
||||
// parsed month.
|
||||
auto maybe_year_and_month = parse_a_month_string(input);
|
||||
if (!maybe_year_and_month.has_value())
|
||||
return {};
|
||||
return number_of_months_since_unix_epoch(maybe_year_and_month.value());
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#concept-input-value-string-number
|
||||
Optional<double> HTMLInputElement::convert_string_to_number(StringView input) const
|
||||
{
|
||||
|
@ -2078,10 +2090,24 @@ Optional<double> HTMLInputElement::convert_string_to_number(StringView input) co
|
|||
if (type_state() == TypeAttributeState::Range)
|
||||
return parse_floating_point_number(input);
|
||||
|
||||
if (type_state() == TypeAttributeState::Month)
|
||||
return convert_month_string_to_number(input);
|
||||
|
||||
dbgln("HTMLInputElement::convert_string_to_number() not implemented for input type {}", type());
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):concept-input-value-number-string
|
||||
static String convert_number_to_month_string(double input)
|
||||
{
|
||||
// The algorithm to convert a number to a string, given a number input, is as follows: Return a valid month
|
||||
// string that represents the month that has input months between it and January 1970.
|
||||
auto months = JS::modulo(input, 12);
|
||||
auto year = 1970 + (input - months) / 12;
|
||||
|
||||
return MUST(String::formatted("{:04d}-{:02d}", static_cast<int>(year), static_cast<int>(months) + 1));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#concept-input-value-string-number
|
||||
String HTMLInputElement::convert_number_to_string(double input) const
|
||||
{
|
||||
|
@ -2093,6 +2119,9 @@ String HTMLInputElement::convert_number_to_string(double input) const
|
|||
if (type_state() == TypeAttributeState::Range)
|
||||
return String::number(input);
|
||||
|
||||
if (type_state() == TypeAttributeState::Month)
|
||||
return convert_number_to_month_string(input);
|
||||
|
||||
dbgln("HTMLInputElement::convert_number_to_string() not implemented for input type {}", type());
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ url threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
|||
email threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
||||
password threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
||||
date did not throw: NaN
|
||||
month did not throw: NaN
|
||||
month did not throw: 100
|
||||
week did not throw: NaN
|
||||
time did not throw: NaN
|
||||
datetime-local did not throw: NaN
|
||||
|
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 60 tests
|
||||
|
||||
34 Pass
|
||||
26 Fail
|
||||
38 Pass
|
||||
22 Fail
|
||||
Pass valueAsNumber getter on type date (actual value: , expected valueAsNumber: NaN)
|
||||
Pass valueAsNumber getter on type date (actual value: 0000-12-10, expected valueAsNumber: NaN)
|
||||
Pass valueAsNumber getter on type date (actual value: 2019-00-12, expected valueAsNumber: NaN)
|
||||
|
@ -18,10 +18,10 @@ Fail valueAsNumber setter on type date (actual valueAsNumber: 1456704000000, exp
|
|||
Pass valueAsNumber getter on type month (actual value: , expected valueAsNumber: NaN)
|
||||
Pass valueAsNumber getter on type month (actual value: 0000-12, expected valueAsNumber: NaN)
|
||||
Pass valueAsNumber getter on type month (actual value: 2019-00, expected valueAsNumber: NaN)
|
||||
Fail valueAsNumber getter on type month (actual value: 2019-12, expected valueAsNumber: 599)
|
||||
Fail valueAsNumber getter on type month (actual value: 1969-12, expected valueAsNumber: -1)
|
||||
Fail valueAsNumber setter on type month (actual valueAsNumber: 599, expected value: 2019-12)
|
||||
Fail valueAsNumber setter on type month (actual valueAsNumber: -1, expected value: 1969-12)
|
||||
Pass valueAsNumber getter on type month (actual value: 2019-12, expected valueAsNumber: 599)
|
||||
Pass valueAsNumber getter on type month (actual value: 1969-12, expected valueAsNumber: -1)
|
||||
Pass valueAsNumber setter on type month (actual valueAsNumber: 599, expected value: 2019-12)
|
||||
Pass valueAsNumber setter on type month (actual valueAsNumber: -1, expected value: 1969-12)
|
||||
Pass valueAsNumber getter on type week (actual value: , expected valueAsNumber: NaN)
|
||||
Pass valueAsNumber getter on type week (actual value: 0000-W50, expected valueAsNumber: NaN)
|
||||
Pass valueAsNumber getter on type week (actual value: 2019-W00, expected valueAsNumber: NaN)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue