diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 34674e8119e..25370c2965e 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -408,22 +408,11 @@ void HTMLInputElement::did_edit_text_node(Badge) update_placeholder_visibility(); - // NOTE: This is a bit ad-hoc, but basically implements part of "4.10.5.5 Common event behaviors" - // https://html.spec.whatwg.org/multipage/input.html#common-input-element-events - queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { - auto input_event = DOM::Event::create(realm(), HTML::EventNames::input); - input_event->set_bubbles(true); - input_event->set_composed(true); - dispatch_event(*input_event); - }); + user_interaction_did_change_input_value(); } void HTMLInputElement::did_pick_color(Optional picked_color, ColorPickerUpdateState state) { - // https://html.spec.whatwg.org/multipage/input.html#common-input-element-events - // For input elements without a defined input activation behavior, but to which these events apply - // and for which the user interface involves both interactive manipulation and an explicit commit action - if (type_state() == TypeAttributeState::Color && picked_color.has_value()) { // then when the user changes the element's value m_value = value_sanitization_algorithm(picked_color.value().to_string_without_alpha()); @@ -432,15 +421,10 @@ void HTMLInputElement::did_pick_color(Optional picked_color, ColorPickerU update_color_well_element(); // the user agent must queue an element task on the user interaction task source - queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { - // given the input element to fire an event named input at the input element, with the bubbles and composed attributes initialized to true - auto input_event = DOM::Event::create(realm(), HTML::EventNames::input); - input_event->set_bubbles(true); - input_event->set_composed(true); - dispatch_event(*input_event); - }); + user_interaction_did_change_input_value(); - // and any time the user commits the change, the user agent must queue an element task on the user interaction task source + // https://html.spec.whatwg.org/multipage/input.html#common-input-element-events + // [...] any time the user commits the change, the user agent must queue an element task on the user interaction task source if (state == ColorPickerUpdateState::Closed) { queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { // given the input element @@ -980,18 +964,8 @@ void HTMLInputElement::create_range_input_shadow_tree() MUST(slider_runnable_track->append_child(*m_slider_thumb)); update_slider_thumb_element(); - //  User event listeners - auto dispatch_input_event = [this]() { - queue_an_element_task(HTML::Task::Source::UserInteraction, [&] { - auto input_event = DOM::Event::create(realm(), HTML::EventNames::input); - input_event->set_bubbles(true); - input_event->set_composed(true); - dispatch_event(*input_event); - }); - }; - auto keydown_callback_function = JS::NativeFunction::create( - realm(), [this, dispatch_input_event](JS::VM& vm) { + realm(), [this](JS::VM& vm) { auto key = MUST(vm.argument(0).get(vm, "key")).as_string().utf8_string(); if (key == "ArrowLeft" || key == "ArrowDown") @@ -1004,7 +978,7 @@ void HTMLInputElement::create_range_input_shadow_tree() if (key == "PageUp") MUST(step_up(10)); - dispatch_input_event(); + user_interaction_did_change_input_value(); return JS::js_undefined(); }, 0, "", &realm()); @@ -1012,28 +986,28 @@ void HTMLInputElement::create_range_input_shadow_tree() add_event_listener_without_options(UIEvents::EventNames::keydown, DOM::IDLEventListener::create(realm(), keydown_callback)); auto wheel_callback_function = JS::NativeFunction::create( - realm(), [this, dispatch_input_event](JS::VM& vm) { + realm(), [this](JS::VM& vm) { auto deltaY = MUST(vm.argument(0).get(vm, "deltaY")).as_i32(); if (deltaY > 0) { MUST(step_down()); } else { MUST(step_up()); } - dispatch_input_event(); + user_interaction_did_change_input_value(); return JS::js_undefined(); }, 0, "", &realm()); auto wheel_callback = realm().heap().allocate_without_realm(*wheel_callback_function, Bindings::host_defined_environment_settings_object(realm())); add_event_listener_without_options(UIEvents::EventNames::wheel, DOM::IDLEventListener::create(realm(), wheel_callback)); - auto update_slider_by_mouse = [this, dispatch_input_event](JS::VM& vm) { + auto update_slider_by_mouse = [this](JS::VM& vm) { auto client_x = MUST(vm.argument(0).get(vm, "clientX")).as_double(); auto rect = get_bounding_client_rect(); double minimum = *min(); double maximum = *max(); // FIXME: Snap new value to input steps MUST(set_value_as_number(clamp(round(((client_x - rect->left()) / rect->width()) * (maximum - minimum) + minimum), minimum, maximum))); - dispatch_input_event(); + user_interaction_did_change_input_value(); }; auto mousedown_callback_function = JS::NativeFunction::create( @@ -1070,6 +1044,23 @@ void HTMLInputElement::create_range_input_shadow_tree() add_event_listener_without_options(UIEvents::EventNames::mousedown, DOM::IDLEventListener::create(realm(), mousedown_callback)); } +void HTMLInputElement::user_interaction_did_change_input_value() +{ + // https://html.spec.whatwg.org/multipage/input.html#common-input-element-events + // For input elements without a defined input activation behavior, but to which these events apply, + // and for which the user interface involves both interactive manipulation and an explicit commit action, + // then when the user changes the element's value, the user agent must queue an element task on the user interaction task source + // given the input element to fire an event named input at the input element, with the bubbles and composed attributes initialized to true, + // and any time the user commits the change, the user agent must queue an element task on the user interaction task source given the input + // element to set its user validity to true and fire an event named change at the input element, with the bubbles attribute initialized to true. + queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { + auto input_event = DOM::Event::create(realm(), HTML::EventNames::input); + input_event->set_bubbles(true); + input_event->set_composed(true); + dispatch_event(*input_event); + }); +} + void HTMLInputElement::update_slider_thumb_element() { if (!m_slider_thumb) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index 9ae84128f7d..5039bd91535 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -255,6 +255,8 @@ private: void handle_readonly_attribute(Optional const& value); WebIDL::ExceptionOr handle_src_attribute(String const& value); + void user_interaction_did_change_input_value(); + // https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm String value_sanitization_algorithm(String const&) const;