LibWeb: Fire "input" and "change" events when editing a text <input>

This isn't entirely on-spec, but will hopefully allow us to make
progress in other areas.
This commit is contained in:
Andreas Kling 2022-02-17 12:59:32 +01:00
parent 4cbce0e34c
commit 5f54b8dd6c
Notes: sideshowbarker 2024-07-17 18:38:04 +09:00
5 changed files with 39 additions and 1 deletions

View File

@ -1,11 +1,12 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibWeb/DOM/Text.h> #include <LibWeb/DOM/Text.h>
#include <LibWeb/DOM/Window.h> #include <LibWeb/DOM/Window.h>
#include <LibWeb/HTML/HTMLInputElement.h>
#include <LibWeb/Layout/TextNode.h> #include <LibWeb/Layout/TextNode.h>
namespace Web::DOM { namespace Web::DOM {
@ -25,4 +26,9 @@ NonnullRefPtr<Text> Text::create_with_global_object(Bindings::WindowObject& wind
return make_ref_counted<Text>(window.impl().associated_document(), data); return make_ref_counted<Text>(window.impl().associated_document(), data);
} }
void Text::set_owner_input_element(Badge<HTML::HTMLInputElement>, HTML::HTMLInputElement& input_element)
{
m_owner_input_element = input_element;
}
} }

View File

@ -27,7 +27,12 @@ public:
void set_always_editable(bool b) { m_always_editable = b; } void set_always_editable(bool b) { m_always_editable = b; }
void set_owner_input_element(Badge<HTML::HTMLInputElement>, HTML::HTMLInputElement&);
HTML::HTMLInputElement* owner_input_element() { return m_owner_input_element; }
private: private:
WeakPtr<HTML::HTMLInputElement> m_owner_input_element;
bool m_always_editable { false }; bool m_always_editable { false };
}; };

View File

@ -11,6 +11,7 @@
#include <LibWeb/HTML/BrowsingContextContainer.h> #include <LibWeb/HTML/BrowsingContextContainer.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h> #include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/HTML/HTMLAnchorElement.h> #include <LibWeb/HTML/HTMLAnchorElement.h>
#include <LibWeb/HTML/HTMLInputElement.h>
#include <LibWeb/Layout/BreakNode.h> #include <LibWeb/Layout/BreakNode.h>
#include <LibWeb/Layout/InitialContainingBlock.h> #include <LibWeb/Layout/InitialContainingBlock.h>
#include <LibWeb/Layout/TextNode.h> #include <LibWeb/Layout/TextNode.h>
@ -41,6 +42,12 @@ BrowsingContext::~BrowsingContext()
void BrowsingContext::did_edit(Badge<EditEventHandler>) void BrowsingContext::did_edit(Badge<EditEventHandler>)
{ {
reset_cursor_blink_cycle(); reset_cursor_blink_cycle();
if (m_cursor_position.node() && is<DOM::Text>(*m_cursor_position.node())) {
auto& text_node = static_cast<DOM::Text&>(*m_cursor_position.node());
if (auto* input_element = text_node.owner_input_element())
input_element->did_edit_text_node({});
}
} }
void BrowsingContext::reset_cursor_blink_cycle() void BrowsingContext::reset_cursor_blink_cycle()

View File

@ -112,6 +112,23 @@ void HTMLInputElement::run_input_activation_behavior()
} }
} }
void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
{
// 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(HTML::EventNames::input);
input_event->set_bubbles(true);
input_event->set_composed(true);
dispatch_event(move(input_event));
// FIXME: This should only fire when the input is "committed", whatever that means.
auto change_event = DOM::Event::create(HTML::EventNames::change);
change_event->set_bubbles(true);
dispatch_event(move(change_event));
});
}
bool HTMLInputElement::enabled() const bool HTMLInputElement::enabled() const
{ {
return !has_attribute(HTML::AttributeNames::disabled); return !has_attribute(HTML::AttributeNames::disabled);
@ -147,6 +164,7 @@ void HTMLInputElement::create_shadow_tree_if_needed()
element->set_attribute(HTML::AttributeNames::style, "white-space: pre"); element->set_attribute(HTML::AttributeNames::style, "white-space: pre");
m_text_node = adopt_ref(*new DOM::Text(document(), initial_value)); m_text_node = adopt_ref(*new DOM::Text(document(), initial_value));
m_text_node->set_always_editable(true); m_text_node->set_always_editable(true);
m_text_node->set_owner_input_element({}, *this);
element->append_child(*m_text_node); element->append_child(*m_text_node);
shadow_root->append_child(move(element)); shadow_root->append_child(move(element));
set_shadow_root(move(shadow_root)); set_shadow_root(move(shadow_root));

View File

@ -42,6 +42,8 @@ public:
void did_click_button(Badge<Layout::ButtonBox>); void did_click_button(Badge<Layout::ButtonBox>);
void did_edit_text_node(Badge<BrowsingContext>);
virtual bool is_focusable() const override; virtual bool is_focusable() const override;
virtual void parse_attribute(FlyString const&, String const&) override; virtual void parse_attribute(FlyString const&, String const&) override;