mirror of
https://github.com/RGBCube/serenity
synced 2025-07-10 10:17:35 +00:00

We currently fire the change event on <input> elements when they lose focus. The spec allows for us to also fire the event when changes are "committed", so long as such an action makes sense for the input type. This patch detects when the return key is entered in an <input> element and uses that as the commit action for text-related types. If no change has occurred since the last commit, no change event is fired.
93 lines
2.8 KiB
C++
93 lines
2.8 KiB
C++
/*
|
||
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include <LibJS/Runtime/VM.h>
|
||
#include <LibWeb/Bindings/InternalsPrototype.h>
|
||
#include <LibWeb/Bindings/Intrinsics.h>
|
||
#include <LibWeb/DOM/Document.h>
|
||
#include <LibWeb/DOM/Event.h>
|
||
#include <LibWeb/DOM/EventTarget.h>
|
||
#include <LibWeb/HTML/BrowsingContext.h>
|
||
#include <LibWeb/HTML/HTMLElement.h>
|
||
#include <LibWeb/HTML/Window.h>
|
||
#include <LibWeb/Internals/Internals.h>
|
||
#include <LibWeb/Page/Page.h>
|
||
#include <LibWeb/Painting/PaintableBox.h>
|
||
|
||
namespace Web::Internals {
|
||
|
||
JS_DEFINE_ALLOCATOR(Internals);
|
||
|
||
Internals::Internals(JS::Realm& realm)
|
||
: Bindings::PlatformObject(realm)
|
||
{
|
||
}
|
||
|
||
Internals::~Internals() = default;
|
||
|
||
void Internals::initialize(JS::Realm& realm)
|
||
{
|
||
Base::initialize(realm);
|
||
Object::set_prototype(&Bindings::ensure_web_prototype<Bindings::InternalsPrototype>(realm, "Internals"_fly_string));
|
||
}
|
||
|
||
void Internals::signal_text_test_is_done()
|
||
{
|
||
if (auto* page = global_object().browsing_context()->page()) {
|
||
page->client().page_did_finish_text_test();
|
||
}
|
||
}
|
||
|
||
void Internals::gc()
|
||
{
|
||
vm().heap().collect_garbage();
|
||
}
|
||
|
||
JS::Object* Internals::hit_test(double x, double y)
|
||
{
|
||
auto* active_document = global_object().browsing_context()->top_level_browsing_context()->active_document();
|
||
// NOTE: Force a layout update just before hit testing. This is because the current layout tree, which is required
|
||
// for stacking context traversal, might not exist if this call occurs between the tear_down_layout_tree()
|
||
// and update_layout() calls
|
||
active_document->update_layout();
|
||
auto result = active_document->paintable_box()->hit_test({ x, y }, Painting::HitTestType::Exact);
|
||
if (result.has_value()) {
|
||
auto hit_tеsting_result = JS::Object::create(realm(), nullptr);
|
||
hit_tеsting_result->define_direct_property("node", result->dom_node(), JS::default_attributes);
|
||
hit_tеsting_result->define_direct_property("indexInNode", JS::Value(result->index_in_node), JS::default_attributes);
|
||
return hit_tеsting_result;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
void Internals::send_text(HTML::HTMLElement& target, String const& text)
|
||
{
|
||
auto* page = global_object().browsing_context()->page();
|
||
if (!page)
|
||
return;
|
||
|
||
target.focus();
|
||
|
||
for (auto code_point : text.code_points())
|
||
page->handle_keydown(code_point_to_key_code(code_point), 0, code_point);
|
||
}
|
||
|
||
void Internals::commit_text()
|
||
{
|
||
auto* page = global_object().browsing_context()->page();
|
||
if (!page)
|
||
return;
|
||
|
||
page->handle_keydown(Key_Return, 0, 0);
|
||
}
|
||
|
||
WebIDL::ExceptionOr<bool> Internals::dispatch_user_activated_event(DOM::EventTarget& target, DOM::Event& event)
|
||
{
|
||
event.set_is_trusted(true);
|
||
return target.dispatch_event(event);
|
||
}
|
||
|
||
}
|