script: Focus on mousedown instead of mouse click according to spec (#38589)

- Focus on mousedown instead of mouse click according to
[spec](https://w3c.github.io/uievents/#handle-native-mouse-down)
- Refactor to follow spec closer and make things more clear.
- Add some spec link.
- Remove some dead spec link.

Still some preparation before implementing #38435.
Testing: No regression in WebDriver & WPT. But update some outdated
test.
Fixes: #38588

---------

Signed-off-by: Euclid Ye <euclid.ye@huawei.com>
This commit is contained in:
Euclid Ye 2025-08-12 10:40:21 +08:00 committed by GitHub
parent d2122c8bd8
commit 5d21234872
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 69 additions and 31 deletions

View file

@ -1546,6 +1546,7 @@ impl Document {
}
}
/// <https://w3c.github.io/uievents/#mouseevent-algorithms>
pub(crate) fn handle_mouse_button_event(
&self,
event: MouseButtonEvent,
@ -1579,15 +1580,6 @@ impl Document {
if el.is_actually_disabled() {
return;
}
// For a node within a text input UA shadow DOM, delegate the focus target into its shadow host.
// TODO: This focus delegation should be done with shadow DOM delegateFocus attribute.
let target_el = el.find_focusable_shadow_host_if_necessary();
self.begin_focus_transaction();
// Try to focus `el`. If it's not focusable, focus the document instead.
self.request_focus(None, FocusInitiator::Local, can_gc);
self.request_focus(target_el.as_deref(), FocusInitiator::Local, can_gc);
}
let dom_event = DomRoot::upcast::<Event>(MouseEvent::for_platform_mouse_event(
@ -1599,44 +1591,65 @@ impl Document {
can_gc,
));
// https://html.spec.whatwg.org/multipage/#run-authentic-click-activation-steps
let activatable = el.as_maybe_activatable();
match event.action {
// https://w3c.github.io/uievents/#handle-native-mouse-click
MouseButtonAction::Click => {
el.set_click_in_progress(true);
dom_event.fire(node.upcast(), can_gc);
dom_event.dispatch(node.upcast(), false, can_gc);
el.set_click_in_progress(false);
self.maybe_fire_dblclick(node, &hit_test_result, input_event, can_gc);
},
// https://w3c.github.io/uievents/#handle-native-mouse-down
MouseButtonAction::Down => {
// (TODO) Step 6. Maybe send pointerdown event with `dom_event`.
if let Some(a) = activatable {
a.enter_formal_activation_state();
}
let target = node.upcast();
dom_event.fire(target, can_gc);
// For a node within a text input UA shadow DOM,
// delegate the focus target into its shadow host.
// TODO: This focus delegation should be done
// with shadow DOM delegateFocus attribute.
let target_el = el.find_focusable_shadow_host_if_necessary();
self.begin_focus_transaction();
// Try to focus `el`. If it's not focusable, focus the document instead.
self.request_focus(None, FocusInitiator::Local, can_gc);
self.request_focus(target_el.as_deref(), FocusInitiator::Local, can_gc);
// Step 7. Let result = dispatch event at target
let result = dom_event.dispatch(node.upcast(), false, can_gc);
// Step 8. If result is true and target is a focusable area
// that is click focusable, then Run the focusing steps at target.
if result && self.focus_transaction.borrow().is_some() {
self.commit_focus_transaction(FocusInitiator::Local, can_gc);
}
// Step 9. If mbutton is the secondary mouse button, then
// Maybe show context menu with native, target.
if let (MouseButtonAction::Down, MouseButton::Right) = (event.action, event.button)
{
self.maybe_show_context_menu(
node.upcast(),
&hit_test_result,
input_event,
can_gc,
);
}
},
// https://w3c.github.io/uievents/#handle-native-mouse-up
MouseButtonAction::Up => {
if let Some(a) = activatable {
a.exit_formal_activation_state();
}
// (TODO) Step 6. Maybe send pointerup event with `dom_event``.
let target = node.upcast();
dom_event.fire(target, can_gc);
// Step 7. dispatch event at target.
dom_event.dispatch(node.upcast(), false, can_gc);
},
}
if let MouseButtonAction::Click = event.action {
if self.focus_transaction.borrow().is_some() {
self.commit_focus_transaction(FocusInitiator::Local, can_gc);
}
self.maybe_fire_dblclick(node, &hit_test_result, input_event, can_gc);
}
// When the contextmenu event is triggered by right mouse button
// the contextmenu event MUST be dispatched after the mousedown event.
if let (MouseButtonAction::Down, MouseButton::Right) = (event.action, event.button) {
self.maybe_show_context_menu(node.upcast(), &hit_test_result, input_event, can_gc);
}
}
/// <https://www.w3.org/TR/uievents/#maybe-show-context-menu>

View file

@ -222,6 +222,7 @@ impl MouseEvent {
}
/// Create a [MouseEvent] triggered by the embedder
/// <https://w3c.github.io/uievents/#create-a-cancelable-mouseevent-id>
pub(crate) fn for_platform_mouse_event(
event: embedder_traits::MouseButtonEvent,
pressed_mouse_buttons: u16,