This commit is contained in:
Alexander Kalenik 2024-11-21 13:12:15 +00:00 committed by GitHub
commit aee2a230b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 105 additions and 15 deletions

View file

@ -17,6 +17,7 @@
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLMediaElement.h>
#include <LibWeb/HTML/HTMLVideoElement.h>
#include <LibWeb/Layout/Label.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Page/DragAndDropEventHandler.h>
#include <LibWeb/Page/EventHandler.h>
@ -40,8 +41,6 @@ namespace Web {
static GC::Ptr<DOM::Node> dom_node_for_event_dispatch(Painting::Paintable& paintable)
{
if (auto node = paintable.mouse_event_target())
return node;
if (auto node = paintable.dom_node())
return node;
auto* layout_parent = paintable.layout_node().parent();
@ -53,6 +52,17 @@ static GC::Ptr<DOM::Node> dom_node_for_event_dispatch(Painting::Paintable& paint
return nullptr;
}
static DOM::Node* input_control_associated_with_ancestor_label_element(Painting::Paintable& paintable)
{
if (is<Layout::Label>(paintable.layout_node())) {
auto const& label = verify_cast<Layout::Label>(paintable.layout_node());
return label.dom_node().control().ptr();
}
if (auto const* label = paintable.layout_node().first_ancestor_of_type<Layout::Label>())
return label->dom_node().control().ptr();
return nullptr;
}
static bool parent_element_for_event_dispatch(Painting::Paintable& paintable, GC::Ptr<DOM::Node>& node, Layout::Node*& layout_node)
{
auto* current_ancestor_node = node.ptr();
@ -351,6 +361,12 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
}
}
}
if (auto* input_control = input_control_associated_with_ancestor_label_element(*paintable)) {
if (button == UIEvents::MouseButton::Primary) {
input_control->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
}
}
}
}
@ -434,10 +450,14 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (dom_node) {
// See if we want to focus something.
GC::Ptr<DOM::Node> focus_candidate;
for (auto candidate = node; candidate; candidate = candidate->parent_or_shadow_host()) {
if (candidate->is_focusable()) {
focus_candidate = candidate;
break;
if (auto* input_control = input_control_associated_with_ancestor_label_element(*paintable)) {
focus_candidate = input_control;
} else {
for (auto candidate = node; candidate; candidate = candidate->parent_or_shadow_host()) {
if (candidate->is_focusable()) {
focus_candidate = candidate;
break;
}
}
}

View file

@ -179,7 +179,6 @@ public:
virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers);
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers);
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers);
virtual DOM::Node* mouse_event_target() const { return nullptr; }
virtual bool handle_mousewheel(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y);

View file

@ -30,13 +30,6 @@ bool TextPaintable::wants_mouse_events() const
return layout_node().first_ancestor_of_type<Layout::Label>();
}
DOM::Node* TextPaintable::mouse_event_target() const
{
if (auto const* label = layout_node().first_ancestor_of_type<Layout::Label>())
return label->dom_node().control().ptr();
return nullptr;
}
TextPaintable::DispatchEventOfSameName TextPaintable::handle_mousedown(Badge<EventHandler>, CSSPixelPoint position, unsigned button, unsigned)
{
auto* label = layout_node().first_ancestor_of_type<Layout::Label>();

View file

@ -21,7 +21,6 @@ public:
Layout::TextNode const& layout_node() const { return static_cast<Layout::TextNode const&>(Paintable::layout_node()); }
virtual bool wants_mouse_events() const override;
virtual DOM::Node* mouse_event_target() const override;
virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers) override;
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers) override;
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers) override;

View file

@ -0,0 +1,4 @@
mouseup event on box
click event on box
click event on input#radio1
click event on input#radio2

View file

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<style>
* {
margin: 0;
}
.box {
display: inline-block;
width: 100px;
height: 100px;
background-color: purple;
}
input {
display: none;
}
label {
display: block;
width: 200px;
height: 200px;
border: 1px solid black;
}
</style>
<script src="../include.js"></script>
<body>
<form>
<label>
<input type="radio" name="fruit" value="apple" id="radio1">
<span class="box"></span>
</label>
<label>
<input type="radio" name="fruit" value="banana" id="radio2">
hey
</label>
</form>
</body>
<script>
asyncTest(done => {
let eventCount = 0;
function endTestIfGotAllEvents() {
eventCount++;
if (eventCount == 4) {
done();
}
}
document.querySelectorAll('input').forEach(function (element) {
element.addEventListener('click', function (event) {
println(`click event on input#${event.target.id}`);
endTestIfGotAllEvents();
});
element.addEventListener('mouseup', function (event) {
println(`mouseup event on input#${event.target.id}`);
endTestIfGotAllEvents();
});
});
document.querySelectorAll('.box').forEach(function (element) {
element.addEventListener('click', function (event) {
println('click event on box');
endTestIfGotAllEvents();
});
element.addEventListener('mouseup', function (event) {
println('mouseup event on box');
endTestIfGotAllEvents();
});
});
internals.click(50, 50);
internals.click(50, 250);
});
</script>
</html>