mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:38:12 +00:00
LibWeb: Fire a change event on input elements in the focus update steps
This ensures the change event is received before the blur event.
This commit is contained in:
parent
301d58e2d9
commit
08ee48606d
5 changed files with 82 additions and 7 deletions
2
Tests/LibWeb/Text/expected/input-commit-on-unfocus.txt
Normal file
2
Tests/LibWeb/Text/expected/input-commit-on-unfocus.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
wfh :^) wfh :^)
|
||||||
|
blur
|
18
Tests/LibWeb/Text/input/input-commit-on-unfocus.html
Normal file
18
Tests/LibWeb/Text/input/input-commit-on-unfocus.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<input id=input type=text>
|
||||||
|
<script src="include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let input = document.getElementById("input");
|
||||||
|
|
||||||
|
input.addEventListener("change", () => {
|
||||||
|
println(input.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
input.addEventListener("blur", () => {
|
||||||
|
println("blur");
|
||||||
|
});
|
||||||
|
|
||||||
|
internals.sendText(input, "wfh :^)");
|
||||||
|
input.blur();
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -13,6 +13,7 @@
|
||||||
#include <LibWeb/DOM/Element.h>
|
#include <LibWeb/DOM/Element.h>
|
||||||
#include <LibWeb/DOM/ShadowRoot.h>
|
#include <LibWeb/DOM/ShadowRoot.h>
|
||||||
#include <LibWeb/HTML/Focus.h>
|
#include <LibWeb/HTML/Focus.h>
|
||||||
|
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||||
#include <LibWeb/UIEvents/FocusEvent.h>
|
#include <LibWeb/UIEvents/FocusEvent.h>
|
||||||
|
|
||||||
|
@ -32,13 +33,21 @@ static void run_focus_update_steps(Vector<JS::Handle<DOM::Node>> old_chain, Vect
|
||||||
|
|
||||||
// 2. For each entry entry in old chain, in order, run these substeps:
|
// 2. For each entry entry in old chain, in order, run these substeps:
|
||||||
for (auto& entry : old_chain) {
|
for (auto& entry : old_chain) {
|
||||||
// FIXME: 1. If entry is an input element, and the change event applies to the element,
|
// 1. If entry is an input element, and the change event applies to the element, and the element does not have
|
||||||
// and the element does not have a defined activation behavior,
|
// a defined activation behavior, and the user has changed the element's value or its list of selected files
|
||||||
// and the user has changed the element's value or its list of selected files
|
// while the control was focused without committing that change (such that it is different to what it was
|
||||||
// while the control was focused without committing that change
|
// when the control was first focused), then fire an event named change at the element, with the bubbles
|
||||||
// (such that it is different to what it was when the control was first focused),
|
// attribute initialized to true.
|
||||||
// then fire an event named change at the element,
|
if (is<HTMLInputElement>(*entry)) {
|
||||||
// with the bubbles attribute initialized to true.
|
auto& input_element = static_cast<HTMLInputElement&>(*entry);
|
||||||
|
|
||||||
|
// FIXME: Spec issue: It doesn't make sense to check if the element has a defined activation behavior, as
|
||||||
|
// that is always true. Instead, we check if it has an *input* activation behavior.
|
||||||
|
// https://github.com/whatwg/html/issues/9973
|
||||||
|
if (input_element.change_event_applies() && !input_element.has_input_activation_behavior()) {
|
||||||
|
input_element.commit_pending_changes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JS::GCPtr<DOM::EventTarget> blur_event_target;
|
JS::GCPtr<DOM::EventTarget> blur_event_target;
|
||||||
if (is<DOM::Element>(*entry)) {
|
if (is<DOM::Element>(*entry)) {
|
||||||
|
|
|
@ -1340,4 +1340,47 @@ void HTMLInputElement::activation_behavior(DOM::Event const&)
|
||||||
run_input_activation_behavior().release_value_but_fixme_should_propagate_errors();
|
run_input_activation_behavior().release_value_but_fixme_should_propagate_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HTMLInputElement::has_input_activation_behavior() const
|
||||||
|
{
|
||||||
|
switch (type_state()) {
|
||||||
|
case TypeAttributeState::Checkbox:
|
||||||
|
case TypeAttributeState::Color:
|
||||||
|
case TypeAttributeState::FileUpload:
|
||||||
|
case TypeAttributeState::ImageButton:
|
||||||
|
case TypeAttributeState::RadioButton:
|
||||||
|
case TypeAttributeState::ResetButton:
|
||||||
|
case TypeAttributeState::SubmitButton:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:event-change-2
|
||||||
|
bool HTMLInputElement::change_event_applies() const
|
||||||
|
{
|
||||||
|
switch (type_state()) {
|
||||||
|
case TypeAttributeState::Checkbox:
|
||||||
|
case TypeAttributeState::Color:
|
||||||
|
case TypeAttributeState::Date:
|
||||||
|
case TypeAttributeState::Email:
|
||||||
|
case TypeAttributeState::FileUpload:
|
||||||
|
case TypeAttributeState::LocalDateAndTime:
|
||||||
|
case TypeAttributeState::Month:
|
||||||
|
case TypeAttributeState::Number:
|
||||||
|
case TypeAttributeState::Password:
|
||||||
|
case TypeAttributeState::RadioButton:
|
||||||
|
case TypeAttributeState::Range:
|
||||||
|
case TypeAttributeState::Search:
|
||||||
|
case TypeAttributeState::Telephone:
|
||||||
|
case TypeAttributeState::Text:
|
||||||
|
case TypeAttributeState::Time:
|
||||||
|
case TypeAttributeState::URL:
|
||||||
|
case TypeAttributeState::Week:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,9 @@ public:
|
||||||
virtual bool has_activation_behavior() const override;
|
virtual bool has_activation_behavior() const override;
|
||||||
virtual void activation_behavior(DOM::Event const&) override;
|
virtual void activation_behavior(DOM::Event const&) override;
|
||||||
|
|
||||||
|
bool has_input_activation_behavior() const;
|
||||||
|
bool change_event_applies() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HTMLInputElement(DOM::Document&, DOM::QualifiedName);
|
HTMLInputElement(DOM::Document&, DOM::QualifiedName);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue