mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
dom: Firing "click" event as synthetic pointer event (#36274)
According to specification https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-click-event "Firing a click event at target means firing a synthetic pointer event named click at target" So need to replace synthetic mouse event with "click" type to pointer event. https://w3c.github.io/pointerevents/#the-click-auxclick-and-contextmenu-events https://www.w3.org/TR/uievents/#event-type-click Firing "click" event could be triggered from script or by UA: - element.click() (https://html.spec.whatwg.org/multipage/interaction.html#dom-click) - form implicit submission (https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission) - keyboard activation (space) --- - [x] ./mach build -d does not report any errors - [x] ./mach test-tidy does not report any errors - [x] There are tests for these changes tests/wpt/tests/shadow-dom/event-composed.html tests/wpt/tests/uievents/interface/click-event.htm Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
b925c31424
commit
3bc0eeab8f
7 changed files with 73 additions and 60 deletions
|
@ -171,7 +171,7 @@ use crate::dom::nodeiterator::NodeIterator;
|
||||||
use crate::dom::nodelist::NodeList;
|
use crate::dom::nodelist::NodeList;
|
||||||
use crate::dom::pagetransitionevent::PageTransitionEvent;
|
use crate::dom::pagetransitionevent::PageTransitionEvent;
|
||||||
use crate::dom::performanceentry::PerformanceEntry;
|
use crate::dom::performanceentry::PerformanceEntry;
|
||||||
use crate::dom::pointerevent::PointerEvent;
|
use crate::dom::pointerevent::{PointerEvent, PointerId};
|
||||||
use crate::dom::processinginstruction::ProcessingInstruction;
|
use crate::dom::processinginstruction::ProcessingInstruction;
|
||||||
use crate::dom::promise::Promise;
|
use crate::dom::promise::Promise;
|
||||||
use crate::dom::range::Range;
|
use crate::dom::range::Range;
|
||||||
|
@ -1402,7 +1402,6 @@ impl Document {
|
||||||
// <https://w3c.github.io/uievents/#contextmenu>
|
// <https://w3c.github.io/uievents/#contextmenu>
|
||||||
let menu_event = PointerEvent::new(
|
let menu_event = PointerEvent::new(
|
||||||
&self.window, // window
|
&self.window, // window
|
||||||
None, // proto
|
|
||||||
DOMString::from("contextmenu"), // type
|
DOMString::from("contextmenu"), // type
|
||||||
EventBubbles::Bubbles, // can_bubble
|
EventBubbles::Bubbles, // can_bubble
|
||||||
EventCancelable::Cancelable, // cancelable
|
EventCancelable::Cancelable, // cancelable
|
||||||
|
@ -1420,22 +1419,20 @@ impl Document {
|
||||||
pressed_mouse_buttons, // buttons
|
pressed_mouse_buttons, // buttons
|
||||||
None, // related_target
|
None, // related_target
|
||||||
None, // point_in_target
|
None, // point_in_target
|
||||||
// TODO: decide generic pointer id
|
PointerId::Mouse as i32, // pointer_id
|
||||||
// <https://www.w3.org/TR/pointerevents3/#dom-pointerevent-pointerid>
|
1, // width
|
||||||
0, // pointer_id
|
1, // height
|
||||||
1, // width
|
0.5, // pressure
|
||||||
1, // height
|
0.0, // tangential_pressure
|
||||||
0.5, // pressure
|
0, // tilt_x
|
||||||
0.0, // tangential_pressure
|
0, // tilt_y
|
||||||
0, // tilt_x
|
0, // twist
|
||||||
0, // tilt_y
|
PI / 2.0, // altitude_angle
|
||||||
0, // twist
|
0.0, // azimuth_angle
|
||||||
PI / 2.0, // altitude_angle
|
DOMString::from("mouse"), // pointer_type
|
||||||
0.0, // azimuth_angle
|
true, // is_primary
|
||||||
DOMString::from("mouse"), // pointer_type
|
vec![], // coalesced_events
|
||||||
true, // is_primary
|
vec![], // predicted_events
|
||||||
vec![], // coalesced_events
|
|
||||||
vec![], // predicted_events
|
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
let event = menu_event.upcast::<Event>();
|
let event = menu_event.upcast::<Event>();
|
||||||
|
@ -2186,7 +2183,7 @@ impl Document {
|
||||||
{
|
{
|
||||||
if let Some(elem) = target.downcast::<Element>() {
|
if let Some(elem) = target.downcast::<Element>() {
|
||||||
elem.upcast::<Node>()
|
elem.upcast::<Node>()
|
||||||
.fire_synthetic_mouse_event_not_trusted(DOMString::from("click"), can_gc);
|
.fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,7 +395,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
|
||||||
Some(item_attr_values.into_iter().collect())
|
Some(item_attr_values.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-click
|
/// <https://html.spec.whatwg.org/multipage/#dom-click>
|
||||||
fn Click(&self, can_gc: CanGc) {
|
fn Click(&self, can_gc: CanGc) {
|
||||||
let element = self.as_element();
|
let element = self.as_element();
|
||||||
if element.disabled_state() {
|
if element.disabled_state() {
|
||||||
|
@ -407,7 +407,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
|
||||||
element.set_click_in_progress(true);
|
element.set_click_in_progress(true);
|
||||||
|
|
||||||
self.upcast::<Node>()
|
self.upcast::<Node>()
|
||||||
.fire_synthetic_mouse_event_not_trusted(DOMString::from("click"), can_gc);
|
.fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc);
|
||||||
element.set_click_in_progress(false);
|
element.set_click_in_progress(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2149,7 +2149,7 @@ impl HTMLInputElement {
|
||||||
// but we can get here from synthetic keydown events
|
// but we can get here from synthetic keydown events
|
||||||
button
|
button
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
.fire_synthetic_mouse_event_not_trusted(DOMString::from("click"), can_gc);
|
.fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::{Cell, LazyCell, UnsafeCell};
|
use std::cell::{Cell, LazyCell, UnsafeCell};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
use std::f64::consts::PI;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::slice::from_ref;
|
use std::slice::from_ref;
|
||||||
use std::sync::Arc as StdArc;
|
use std::sync::Arc as StdArc;
|
||||||
|
@ -105,9 +106,9 @@ use crate::dom::htmlslotelement::{HTMLSlotElement, Slottable};
|
||||||
use crate::dom::htmlstyleelement::HTMLStyleElement;
|
use crate::dom::htmlstyleelement::HTMLStyleElement;
|
||||||
use crate::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
use crate::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||||
use crate::dom::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers};
|
use crate::dom::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers};
|
||||||
use crate::dom::mouseevent::MouseEvent;
|
|
||||||
use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
|
use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
|
||||||
use crate::dom::nodelist::NodeList;
|
use crate::dom::nodelist::NodeList;
|
||||||
|
use crate::dom::pointerevent::{PointerEvent, PointerId};
|
||||||
use crate::dom::processinginstruction::ProcessingInstruction;
|
use crate::dom::processinginstruction::ProcessingInstruction;
|
||||||
use crate::dom::range::WeakRangeVec;
|
use crate::dom::range::WeakRangeVec;
|
||||||
use crate::dom::raredata::NodeRareData;
|
use crate::dom::raredata::NodeRareData;
|
||||||
|
@ -438,43 +439,59 @@ impl Node {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatg.org/#fire_a_synthetic_mouse_event>
|
/// <https://html.spec.whatwg.org/multipage/#fire-a-synthetic-pointer-event>
|
||||||
pub(crate) fn fire_synthetic_mouse_event_not_trusted(&self, name: DOMString, can_gc: CanGc) {
|
pub(crate) fn fire_synthetic_pointer_event_not_trusted(&self, name: DOMString, can_gc: CanGc) {
|
||||||
// Spec says the choice of which global to create
|
// Spec says the choice of which global to create the pointer event
|
||||||
// the mouse event on is not well-defined,
|
// on is not well-defined,
|
||||||
// and refers to heycam/webidl#135
|
// and refers to heycam/webidl#135
|
||||||
let win = self.owner_window();
|
let window = self.owner_window();
|
||||||
|
|
||||||
let mouse_event = MouseEvent::new(
|
// <https://w3c.github.io/pointerevents/#the-click-auxclick-and-contextmenu-events>
|
||||||
&win, // ambiguous in spec
|
let pointer_event = PointerEvent::new(
|
||||||
|
&window, // ambiguous in spec
|
||||||
name,
|
name,
|
||||||
EventBubbles::Bubbles, // Step 3: bubbles
|
EventBubbles::Bubbles, // Step 3: bubbles
|
||||||
EventCancelable::Cancelable, // Step 3: cancelable,
|
EventCancelable::Cancelable, // Step 3: cancelable
|
||||||
Some(&win), // Step 7: view (this is unambiguous in spec)
|
Some(&window), // Step 7: view
|
||||||
0, // detail uninitialized
|
0, // detail uninitialized
|
||||||
0, // coordinates uninitialized
|
0, // coordinates uninitialized
|
||||||
0, // coordinates uninitialized
|
0, // coordinates uninitialized
|
||||||
0, // coordinates uninitialized
|
0, // coordinates uninitialized
|
||||||
0, // coordinates uninitialized
|
0, // coordinates uninitialized
|
||||||
false,
|
false, // ctrl_key
|
||||||
false,
|
false, // alt_key
|
||||||
false,
|
false, // shift_key
|
||||||
false, // Step 6 modifier keys TODO compositor hook needed
|
false, // meta_key
|
||||||
0, // button uninitialized (and therefore left)
|
0, // button, left mouse button
|
||||||
0, // buttons uninitialized (and therefore none)
|
0, // buttons
|
||||||
None, // related_target uninitialized,
|
None, // related_target
|
||||||
None, // point_in_target uninitialized,
|
None, // point_in_target
|
||||||
|
PointerId::NonPointerDevice as i32, // pointer_id
|
||||||
|
1, // width
|
||||||
|
1, // height
|
||||||
|
0.5, // pressure
|
||||||
|
0.0, // tangential_pressure
|
||||||
|
0, // tilt_x
|
||||||
|
0, // tilt_y
|
||||||
|
0, // twist
|
||||||
|
PI / 2.0, // altitude_angle
|
||||||
|
0.0, // azimuth_angle
|
||||||
|
DOMString::from(""), // pointer_type
|
||||||
|
false, // is_primary
|
||||||
|
vec![], // coalesced_events
|
||||||
|
vec![], // predicted_events
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Step 4: TODO composed flag for shadow root
|
// Step 4. Set event's composed flag.
|
||||||
|
pointer_event.upcast::<Event>().set_composed(true);
|
||||||
|
|
||||||
// Step 5
|
// Step 5. If the not trusted flag is set, initialize event's isTrusted attribute to false.
|
||||||
mouse_event.upcast::<Event>().set_trusted(false);
|
pointer_event.upcast::<Event>().set_trusted(false);
|
||||||
|
|
||||||
// Step 8: TODO keyboard modifiers
|
// Step 6,8. TODO keyboard modifiers
|
||||||
|
|
||||||
mouse_event
|
pointer_event
|
||||||
.upcast::<Event>()
|
.upcast::<Event>()
|
||||||
.dispatch(self.upcast::<EventTarget>(), false, can_gc);
|
.dispatch(self.upcast::<EventTarget>(), false, can_gc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,13 @@ use crate::dom::mouseevent::MouseEvent;
|
||||||
use crate::dom::window::Window;
|
use crate::dom::window::Window;
|
||||||
use crate::script_runtime::CanGc;
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/pointerevents/#dom-pointerevent-pointerid>
|
||||||
|
#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
|
||||||
|
pub(crate) enum PointerId {
|
||||||
|
NonPointerDevice = -1,
|
||||||
|
Mouse,
|
||||||
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub(crate) struct PointerEvent {
|
pub(crate) struct PointerEvent {
|
||||||
mouseevent: MouseEvent,
|
mouseevent: MouseEvent,
|
||||||
|
@ -83,7 +90,6 @@ impl PointerEvent {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
window: &Window,
|
window: &Window,
|
||||||
proto: Option<HandleObject>,
|
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
can_bubble: EventBubbles,
|
can_bubble: EventBubbles,
|
||||||
cancelable: EventCancelable,
|
cancelable: EventCancelable,
|
||||||
|
@ -119,7 +125,7 @@ impl PointerEvent {
|
||||||
) -> DomRoot<PointerEvent> {
|
) -> DomRoot<PointerEvent> {
|
||||||
Self::new_with_proto(
|
Self::new_with_proto(
|
||||||
window,
|
window,
|
||||||
proto,
|
None,
|
||||||
type_,
|
type_,
|
||||||
can_bubble,
|
can_bubble,
|
||||||
cancelable,
|
cancelable,
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[event-composed.html]
|
|
||||||
[A UA click event should not be scoped]
|
|
||||||
expected: FAIL
|
|
|
@ -1,4 +0,0 @@
|
||||||
[click-event.htm]
|
|
||||||
[synthetic click event is a PointerEvent]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue