mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:42:43 +00:00 
			
		
		
		
	LibWeb: Add input element valueAsDate property
This commit is contained in:
		
							parent
							
								
									be511fdcf7
								
							
						
					
					
						commit
						cf69fd0a09
					
				
					 10 changed files with 314 additions and 9 deletions
				
			
		|  | @ -630,7 +630,13 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | ||||||
|     auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object())); |     auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object())); | ||||||
| )~~~"); | )~~~"); | ||||||
|     } else if (parameter.type->name() == "object") { |     } else if (parameter.type->name() == "object") { | ||||||
|         if (optional) { |         if (parameter.type->is_nullable()) { | ||||||
|  |             scoped_generator.append(R"~~~( | ||||||
|  |     Optional<JS::Handle<JS::Object>> @cpp_name@; | ||||||
|  |     if (!@js_name@@js_suffix@.is_null() && !@js_name@@js_suffix@.is_undefined()) | ||||||
|  |         @cpp_name@ = JS::make_handle(TRY(@js_name@@js_suffix@.to_object(vm))); | ||||||
|  | )~~~"); | ||||||
|  |         } else if (optional) { | ||||||
|             scoped_generator.append(R"~~~( |             scoped_generator.append(R"~~~( | ||||||
|     Optional<JS::Handle<JS::Object>> @cpp_name@; |     Optional<JS::Handle<JS::Object>> @cpp_name@; | ||||||
|     if (!@js_name@@js_suffix@.is_undefined()) |     if (!@js_name@@js_suffix@.is_undefined()) | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								Tests/LibWeb/Text/expected/input-date.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Tests/LibWeb/Text/expected/input-date.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | 1. "2023-12-11T00:00:00.000Z" | ||||||
|  | 2. null | ||||||
|  | 3. "1970-01-01T19:46:00.000Z" | ||||||
|  | 4. "1970-01-01T19:46:19.000Z" | ||||||
|  | 5. null | ||||||
|  | 6. "1970-01-01" | ||||||
|  | 7. "2023-12-11" | ||||||
|  | 8. Exception: TypeError | ||||||
|  | 9. "" | ||||||
|  | 10. "18:47:37" | ||||||
|  | 11. "18:47:37.100" | ||||||
|  | 12. "18:47:37.864" | ||||||
|  | 13. Exception: TypeError | ||||||
|  | 14. "" | ||||||
							
								
								
									
										126
									
								
								Tests/LibWeb/Text/input/input-date.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								Tests/LibWeb/Text/input/input-date.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,126 @@ | ||||||
|  | <script src="./include.js"></script> | ||||||
|  | <script> | ||||||
|  |     test(() => { | ||||||
|  |         let testCounter = 1; | ||||||
|  |         function testPart(part) { | ||||||
|  |             try { | ||||||
|  |                 println(`${testCounter}. ${JSON.stringify(part())}`); | ||||||
|  |             } catch (e) { | ||||||
|  |                 println(`${testCounter}. Exception: ${e.name}`); | ||||||
|  |             } | ||||||
|  |             testCounter++; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 1. Input date get value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'date'; | ||||||
|  |             input.value = '2023-12-11'; | ||||||
|  |             return input.valueAsDate; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 2. Input date invalid get value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'date'; | ||||||
|  |             input.value = 'invalid'; | ||||||
|  |             return input.valueAsDate; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 3. Input time get value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.value = '19:46'; | ||||||
|  |             return input.valueAsDate; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 4. Input time get value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.value = '19:46:19'; | ||||||
|  |             return input.valueAsDate; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 5. Input time invalid get value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.value = 'invalid'; | ||||||
|  |             return input.valueAsDate; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 6. Input date set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'date'; | ||||||
|  |             input.valueAsDate = new Date(0); | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 7. Input date set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'date'; | ||||||
|  |             input.valueAsDate = new Date(1702320457860); | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 8. Input date invalid set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'date'; | ||||||
|  |             input.valueAsDate = {}; | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 9. Input date null set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'date'; | ||||||
|  |             input.valueAsDate = null; | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 10. Input time set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.valueAsDate = new Date(1702320457000); | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 11. Input time set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.valueAsDate = new Date(1702320457100); | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 12. Input time set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.valueAsDate = new Date(1702320457864.5); | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 13. Input time invalid set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.valueAsDate = {}; | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 14. Input time null set value as date | ||||||
|  |         testPart(() => { | ||||||
|  |             const input = document.createElement('input'); | ||||||
|  |             input.type = 'time'; | ||||||
|  |             input.valueAsDate = null; | ||||||
|  |             return input.value; | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | </script> | ||||||
|  | @ -20,7 +20,7 @@ JS::NonnullGCPtr<KeyframeEffect> KeyframeEffect::create(JS::Realm& realm) | ||||||
| WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> KeyframeEffect::construct_impl( | WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> KeyframeEffect::construct_impl( | ||||||
|     JS::Realm& realm, |     JS::Realm& realm, | ||||||
|     JS::Handle<DOM::Element> const& target, |     JS::Handle<DOM::Element> const& target, | ||||||
|     JS::Handle<JS::Object> const& keyframes, |     Optional<JS::Handle<JS::Object>> const& keyframes, | ||||||
|     Variant<double, KeyframeEffectOptions> options) |     Variant<double, KeyframeEffectOptions> options) | ||||||
| { | { | ||||||
|     auto& vm = realm.vm(); |     auto& vm = realm.vm(); | ||||||
|  | @ -163,10 +163,9 @@ WebIDL::ExceptionOr<Vector<JS::Object*>> KeyframeEffect::get_keyframes() const | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-setkeyframes
 | // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-setkeyframes
 | ||||||
| WebIDL::ExceptionOr<void> KeyframeEffect::set_keyframes(JS::Object* keyframe_object) | WebIDL::ExceptionOr<void> KeyframeEffect::set_keyframes(Optional<JS::Handle<JS::Object>> const&) | ||||||
| { | { | ||||||
|     // FIXME: Implement this
 |     // FIXME: Implement this
 | ||||||
|     (void)keyframe_object; |  | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ public: | ||||||
|     static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> construct_impl( |     static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> construct_impl( | ||||||
|         JS::Realm&, |         JS::Realm&, | ||||||
|         JS::Handle<DOM::Element> const& target, |         JS::Handle<DOM::Element> const& target, | ||||||
|         JS::Handle<JS::Object> const& keyframes, |         Optional<JS::Handle<JS::Object>> const& keyframes, | ||||||
|         Variant<double, KeyframeEffectOptions> options = KeyframeEffectOptions {}); |         Variant<double, KeyframeEffectOptions> options = KeyframeEffectOptions {}); | ||||||
| 
 | 
 | ||||||
|     static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> construct_impl(JS::Realm&, JS::NonnullGCPtr<KeyframeEffect> source); |     static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> construct_impl(JS::Realm&, JS::NonnullGCPtr<KeyframeEffect> source); | ||||||
|  | @ -62,7 +62,7 @@ public: | ||||||
|     void set_composite(Bindings::CompositeOperation value) { m_composite = value; } |     void set_composite(Bindings::CompositeOperation value) { m_composite = value; } | ||||||
| 
 | 
 | ||||||
|     WebIDL::ExceptionOr<Vector<JS::Object*>> get_keyframes() const; |     WebIDL::ExceptionOr<Vector<JS::Object*>> get_keyframes() const; | ||||||
|     WebIDL::ExceptionOr<void> set_keyframes(JS::Object*); |     WebIDL::ExceptionOr<void> set_keyframes(Optional<JS::Handle<JS::Object>> const&); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     KeyframeEffect(JS::Realm&); |     KeyframeEffect(JS::Realm&); | ||||||
|  |  | ||||||
|  | @ -128,6 +128,22 @@ bool is_valid_date_string(StringView value) | ||||||
|     return day >= 1 && day <= AK::days_in_month(year, month); |     return day >= 1 && day <= AK::days_in_month(year, month); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-date-string
 | ||||||
|  | WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Date>> parse_date_string(JS::Realm& realm, StringView value) | ||||||
|  | { | ||||||
|  |     // FIXME: Implement spec compliant date string parsing
 | ||||||
|  |     auto parts = value.split_view('-'); | ||||||
|  |     if (parts.size() >= 3) { | ||||||
|  |         if (auto year = parts.at(0).to_uint(); year.has_value()) { | ||||||
|  |             if (auto month = parts.at(1).to_uint(); month.has_value()) { | ||||||
|  |                 if (auto day_of_month = parts.at(2).to_uint(); day_of_month.has_value()) | ||||||
|  |                     return JS::Date::create(realm, JS::make_date(JS::make_day(*year, *month - 1, *day_of_month), 0)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Can't parse date string"sv }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-local-date-and-time-string
 | // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-local-date-and-time-string
 | ||||||
| bool is_valid_local_date_and_time_string(StringView value) | bool is_valid_local_date_and_time_string(StringView value) | ||||||
| { | { | ||||||
|  | @ -197,4 +213,23 @@ bool is_valid_time_string(StringView value) | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-time-string
 | ||||||
|  | WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Date>> parse_time_string(JS::Realm& realm, StringView value) | ||||||
|  | { | ||||||
|  |     // FIXME: Implement spec compliant time string parsing
 | ||||||
|  |     auto parts = value.split_view(':'); | ||||||
|  |     if (parts.size() >= 2) { | ||||||
|  |         if (auto hours = parts.at(0).to_uint(); hours.has_value()) { | ||||||
|  |             if (auto minutes = parts.at(1).to_uint(); minutes.has_value()) { | ||||||
|  |                 if (parts.size() >= 3) { | ||||||
|  |                     if (auto seconds = parts.at(2).to_uint(); seconds.has_value()) | ||||||
|  |                         return JS::Date::create(realm, JS::make_time(*hours, *minutes, *seconds, 0)); | ||||||
|  |                 } | ||||||
|  |                 return JS::Date::create(realm, JS::make_date(0, JS::make_time(*hours, *minutes, 0, 0))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Can't parse time string"sv }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ | ||||||
| 
 | 
 | ||||||
| #include <AK/Forward.h> | #include <AK/Forward.h> | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
|  | #include <LibJS/Runtime/Date.h> | ||||||
|  | #include <LibWeb/WebIDL/ExceptionOr.h> | ||||||
| 
 | 
 | ||||||
| namespace Web::HTML { | namespace Web::HTML { | ||||||
| 
 | 
 | ||||||
|  | @ -15,8 +17,10 @@ u32 week_number_of_the_last_day(u64 year); | ||||||
| bool is_valid_week_string(StringView value); | bool is_valid_week_string(StringView value); | ||||||
| bool is_valid_month_string(StringView value); | bool is_valid_month_string(StringView value); | ||||||
| bool is_valid_date_string(StringView value); | bool is_valid_date_string(StringView value); | ||||||
|  | WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Date>> parse_date_string(JS::Realm& realm, StringView value); | ||||||
| bool is_valid_local_date_and_time_string(StringView value); | bool is_valid_local_date_and_time_string(StringView value); | ||||||
| String normalize_local_date_and_time_string(String const& value); | String normalize_local_date_and_time_string(String const& value); | ||||||
| bool is_valid_time_string(StringView value); | bool is_valid_time_string(StringView value); | ||||||
|  | WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Date>> parse_time_string(JS::Realm& realm, StringView value); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <LibJS/Runtime/Date.h> | ||||||
| #include <LibJS/Runtime/NativeFunction.h> | #include <LibJS/Runtime/NativeFunction.h> | ||||||
| #include <LibWeb/CSS/StyleValues/DisplayStyleValue.h> | #include <LibWeb/CSS/StyleValues/DisplayStyleValue.h> | ||||||
| #include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h> | #include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h> | ||||||
|  | @ -1117,6 +1118,63 @@ String HTMLInputElement::covert_number_to_string(double input) const | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/input.html#concept-input-value-string-date
 | ||||||
|  | WebIDL::ExceptionOr<JS::GCPtr<JS::Date>> HTMLInputElement::convert_string_to_date(StringView input) const | ||||||
|  | { | ||||||
|  |     // https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date):concept-input-value-string-date
 | ||||||
|  |     if (type_state() == TypeAttributeState::Date) { | ||||||
|  |         // If parsing a date from input results in an error, then return an error;
 | ||||||
|  |         auto maybe_date = parse_date_string(realm(), input); | ||||||
|  |         if (maybe_date.is_exception()) | ||||||
|  |             return maybe_date.exception(); | ||||||
|  | 
 | ||||||
|  |         // otherwise, return a new Date object representing midnight UTC on the morning of the parsed date.
 | ||||||
|  |         return maybe_date.value(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):concept-input-value-string-date
 | ||||||
|  |     if (type_state() == TypeAttributeState::Time) { | ||||||
|  |         // If parsing a time from input results in an error, then return an error;
 | ||||||
|  |         auto maybe_time = parse_time_string(realm(), input); | ||||||
|  |         if (maybe_time.is_exception()) | ||||||
|  |             return maybe_time.exception(); | ||||||
|  | 
 | ||||||
|  |         // otherwise, return a new Date object representing the parsed time in UTC on 1970-01-01.
 | ||||||
|  |         return maybe_time.value(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dbgln("HTMLInputElement::convert_string_to_date() not implemented for input type {}", type()); | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/input.html#concept-input-value-date-string
 | ||||||
|  | String HTMLInputElement::covert_date_to_string(JS::NonnullGCPtr<JS::Date> input) const | ||||||
|  | { | ||||||
|  |     // https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date):concept-input-value-date-string
 | ||||||
|  |     if (type_state() == TypeAttributeState::Date) { | ||||||
|  |         // Return a valid date string that represents the date current at the time represented by input in the UTC time zone.
 | ||||||
|  |         // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
 | ||||||
|  |         return MUST(String::formatted("{:04d}-{:02d}-{:02d}", JS::year_from_time(input->date_value()), JS::month_from_time(input->date_value()) + 1, JS::date_from_time(input->date_value()))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):concept-input-value-string-date
 | ||||||
|  |     if (type_state() == TypeAttributeState::Time) { | ||||||
|  |         // Return a valid time string that represents the UTC time component that is represented by input.
 | ||||||
|  |         // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-time-string
 | ||||||
|  |         auto seconds = JS::sec_from_time(input->date_value()); | ||||||
|  |         auto milliseconds = JS::ms_from_time(input->date_value()); | ||||||
|  |         if (seconds > 0) { | ||||||
|  |             if (milliseconds > 0) | ||||||
|  |                 return MUST(String::formatted("{:02d}:{:02d}:{:02d}.{:3d}", JS::hour_from_time(input->date_value()), JS::min_from_time(input->date_value()), seconds, milliseconds)); | ||||||
|  |             return MUST(String::formatted("{:02d}:{:02d}:{:02d}", JS::hour_from_time(input->date_value()), JS::min_from_time(input->date_value()), seconds)); | ||||||
|  |         } | ||||||
|  |         return MUST(String::formatted("{:02d}:{:02d}", JS::hour_from_time(input->date_value()), JS::min_from_time(input->date_value()))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dbgln("HTMLInputElement::covert_date_to_string() not implemented for input type {}", type()); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // https://html.spec.whatwg.org/multipage/input.html#attr-input-min
 | // https://html.spec.whatwg.org/multipage/input.html#attr-input-min
 | ||||||
| Optional<double> HTMLInputElement::min() const | Optional<double> HTMLInputElement::min() const | ||||||
| { | { | ||||||
|  | @ -1234,8 +1292,50 @@ double HTMLInputElement::step_base() const | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasdate
 | ||||||
|  | JS::Object* HTMLInputElement::value_as_date() const | ||||||
|  | { | ||||||
|  |     // On getting, if the valueAsDate attribute does not apply, as defined for the input element's type attribute's current state, then return null.
 | ||||||
|  |     if (!value_as_date_applies()) | ||||||
|  |         return nullptr; | ||||||
|  | 
 | ||||||
|  |     // Otherwise, run the algorithm to convert a string to a Date object defined for that state to the element's value;
 | ||||||
|  |     // if the algorithm returned a Date object, then return it, otherwise, return null.
 | ||||||
|  |     auto maybe_date = convert_string_to_date(value()); | ||||||
|  |     if (!maybe_date.is_exception()) | ||||||
|  |         return maybe_date.value().ptr(); | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasdate
 | ||||||
|  | WebIDL::ExceptionOr<void> HTMLInputElement::set_value_as_date(Optional<JS::Handle<JS::Object>> const& value) | ||||||
|  | { | ||||||
|  |     // On setting, if the valueAsDate attribute does not apply, as defined for the input element's type attribute's current state, then throw an "InvalidStateError" DOMException;
 | ||||||
|  |     if (!value_as_date_applies()) | ||||||
|  |         return WebIDL::InvalidStateError::create(realm(), "valueAsDate: Invalid input type used"_fly_string); | ||||||
|  | 
 | ||||||
|  |     // otherwise, if the new value is not null and not a Date object throw a TypeError exception;
 | ||||||
|  |     if (value.has_value() && !is<JS::Date>(**value)) | ||||||
|  |         return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "valueAsDate: input is not a Date"sv }; | ||||||
|  | 
 | ||||||
|  |     // otherwise if the new value is null or a Date object representing the NaN time value, then set the value of the element to the empty string;
 | ||||||
|  |     if (!value.has_value()) { | ||||||
|  |         TRY(set_value(String {})); | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  |     auto& date = static_cast<JS::Date&>(**value); | ||||||
|  |     if (!isfinite(date.date_value())) { | ||||||
|  |         TRY(set_value(String {})); | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // otherwise, run the algorithm to convert a Date object to a string, as defined for that state, on the new value, and set the value of the element to the resulting string.
 | ||||||
|  |     TRY(set_value(covert_date_to_string(date))); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasnumber
 | // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasnumber
 | ||||||
| WebIDL::ExceptionOr<double> HTMLInputElement::value_as_number() const | double HTMLInputElement::value_as_number() const | ||||||
| { | { | ||||||
|     // On getting, if the valueAsNumber attribute does not apply, as defined for the input element's type attribute's current state, then return a Not-a-Number (NaN) value.
 |     // On getting, if the valueAsNumber attribute does not apply, as defined for the input element's type attribute's current state, then return a Not-a-Number (NaN) value.
 | ||||||
|     if (!value_as_number_applies()) |     if (!value_as_number_applies()) | ||||||
|  | @ -1537,6 +1637,20 @@ bool HTMLInputElement::change_event_applies() const | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/input.html#the-input-element:dom-input-valueasdate-3
 | ||||||
|  | bool HTMLInputElement::value_as_date_applies() const | ||||||
|  | { | ||||||
|  |     switch (type_state()) { | ||||||
|  |     case TypeAttributeState::Date: | ||||||
|  |     case TypeAttributeState::Month: | ||||||
|  |     case TypeAttributeState::Week: | ||||||
|  |     case TypeAttributeState::Time: | ||||||
|  |         return true; | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // https://html.spec.whatwg.org/multipage/input.html#the-input-element:dom-input-valueasnumber-3
 | // https://html.spec.whatwg.org/multipage/input.html#the-input-element:dom-input-valueasnumber-3
 | ||||||
| bool HTMLInputElement::value_as_number_applies() const | bool HTMLInputElement::value_as_number_applies() const | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -102,7 +102,10 @@ public: | ||||||
|     unsigned size() const; |     unsigned size() const; | ||||||
|     WebIDL::ExceptionOr<void> set_size(unsigned value); |     WebIDL::ExceptionOr<void> set_size(unsigned value); | ||||||
| 
 | 
 | ||||||
|     WebIDL::ExceptionOr<double> value_as_number() const; |     JS::Object* value_as_date() const; | ||||||
|  |     WebIDL::ExceptionOr<void> set_value_as_date(Optional<JS::Handle<JS::Object>> const&); | ||||||
|  | 
 | ||||||
|  |     double value_as_number() const; | ||||||
|     WebIDL::ExceptionOr<void> set_value_as_number(double value); |     WebIDL::ExceptionOr<void> set_value_as_number(double value); | ||||||
| 
 | 
 | ||||||
|     WebIDL::ExceptionOr<void> step_up(long n = 1); |     WebIDL::ExceptionOr<void> step_up(long n = 1); | ||||||
|  | @ -165,6 +168,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     bool has_input_activation_behavior() const; |     bool has_input_activation_behavior() const; | ||||||
|     bool change_event_applies() const; |     bool change_event_applies() const; | ||||||
|  |     bool value_as_date_applies() const; | ||||||
|     bool value_as_number_applies() const; |     bool value_as_number_applies() const; | ||||||
|     bool step_applies() const; |     bool step_applies() const; | ||||||
|     bool step_up_or_down_applies() const; |     bool step_up_or_down_applies() const; | ||||||
|  | @ -191,6 +195,9 @@ private: | ||||||
|     Optional<double> convert_string_to_number(StringView input) const; |     Optional<double> convert_string_to_number(StringView input) const; | ||||||
|     String covert_number_to_string(double input) const; |     String covert_number_to_string(double input) const; | ||||||
| 
 | 
 | ||||||
|  |     WebIDL::ExceptionOr<JS::GCPtr<JS::Date>> convert_string_to_date(StringView input) const; | ||||||
|  |     String covert_date_to_string(JS::NonnullGCPtr<JS::Date> input) const; | ||||||
|  | 
 | ||||||
|     Optional<double> min() const; |     Optional<double> min() const; | ||||||
|     Optional<double> max() const; |     Optional<double> max() const; | ||||||
|     double default_step() const; |     double default_step() const; | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ interface HTMLInputElement : HTMLElement { | ||||||
|     [CEReactions] attribute DOMString type; |     [CEReactions] attribute DOMString type; | ||||||
|     [CEReactions, Reflect=value] attribute DOMString defaultValue; |     [CEReactions, Reflect=value] attribute DOMString defaultValue; | ||||||
|     [CEReactions, LegacyNullToEmptyString] attribute DOMString value; |     [CEReactions, LegacyNullToEmptyString] attribute DOMString value; | ||||||
|     // FIXME: attribute object? valueAsDate; |     attribute object? valueAsDate; | ||||||
|     attribute unrestricted double valueAsNumber; |     attribute unrestricted double valueAsNumber; | ||||||
|     // FIXME: [CEReactions] attribute unsigned long width; |     // FIXME: [CEReactions] attribute unsigned long width; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Bastiaan van der Plaat
						Bastiaan van der Plaat