1 use webcore::value::Reference;
2 use webcore::try_from::TryInto;
3 use webcore::reference_type::ReferenceType;
4 use webapi::event_target::EventTarget;
5 use webapi::window::Window;
6 
7 /// The `IEvent` interface represents any event which takes place in the DOM; some
8 /// are user-generated (such as mouse or keyboard events), while others are
9 /// generated by APIs (such as events that indicate an animation has finished
10 /// running, a video has been paused, and so forth). There are many types of event,
11 /// some of which use other interfaces based on the main `IEvent` interface. `IEvent`
12 /// itself contains the properties and methods which are common to all events.
13 ///
14 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
15 // https://dom.spec.whatwg.org/#event
16 pub trait IEvent: ReferenceType {
17     /// Indicates whether this event bubbles upward through the DOM.
18     ///
19     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
20     // https://dom.spec.whatwg.org/#ref-for-dom-event-bubbles%E2%91%A0
21     #[inline]
bubbles( &self ) -> bool22     fn bubbles( &self ) -> bool {
23         js!(
24             return @{self.as_ref()}.bubbles;
25         ).try_into().unwrap()
26     }
27 
28     /// A historical alias to `Event.stopPropagation()`.
29     ///
30     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)
31     // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelbubble
32     #[inline]
cancel_bubble( &self ) -> bool33     fn cancel_bubble( &self ) -> bool {
34         js!(
35             return @{self.as_ref()}.cancelBubble;
36         ).try_into().unwrap()
37     }
38 
39     /// A historical alias to `Event.stopPropagation()`.
40     /// Setting this to `true` before returning from an event handler will stop propagation
41     /// of the event.
42     ///
43     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)
44     // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelbubble
45     #[inline]
set_cancel_bubble( &self, value: bool )46     fn set_cancel_bubble( &self, value: bool ) {
47         js! { @(no_return)
48             @{self.as_ref()}.cancelBubble = @{value};
49         }
50     }
51 
52     /// Indicates whether the event is cancelable.
53     ///
54     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelable)
55     // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelable
56     #[inline]
cancelable( &self ) -> bool57     fn cancelable( &self ) -> bool {
58         js!(
59             return @{self.as_ref()}.cancelable;
60         ).try_into().unwrap()
61     }
62 
63     /// A reference to the currently registered target of this event.
64     ///
65     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget)
66     // https://dom.spec.whatwg.org/#ref-for-dom-event-currenttarget%E2%91%A0
67     #[inline]
current_target( &self ) -> Option< EventTarget >68     fn current_target( &self ) -> Option< EventTarget > {
69         js!(
70             return @{self.as_ref()}.currentTarget;
71         ).try_into().ok()
72     }
73 
74     /// Indicates whether `preventDefault` has been called on this event.
75     ///
76     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/defaultPrevented)
77     // https://dom.spec.whatwg.org/#ref-for-dom-event-defaultprevented
78     #[inline]
default_prevented( &self ) -> bool79     fn default_prevented( &self ) -> bool {
80         js!(
81             return @{self.as_ref()}.defaultPrevented;
82         ).try_into().unwrap()
83     }
84 
85     /// Indicates which phase of event flow is currently being evaluated.
86     ///
87     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase)
88     // https://dom.spec.whatwg.org/#ref-for-dom-event-eventphase%E2%91%A1
event_phase( &self ) -> EventPhase89     fn event_phase( &self ) -> EventPhase {
90         match js!(
91             return @{self.as_ref()}.eventPhase;
92         ).try_into().unwrap() {
93             0 => EventPhase::None,
94             1 => EventPhase::Capturing,
95             2 => EventPhase::AtTarget,
96             3 => EventPhase::Bubbling,
97             _ => unreachable!("Unexpected EventPhase type"),
98         }
99     }
100 
101     /// Prevents any further listeners from being called for this event.
102     ///
103     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation)
104     #[inline]
stop_immediate_propagation( &self )105     fn stop_immediate_propagation( &self ) {
106         js! { @(no_return)
107             @{self.as_ref()}.stopImmediatePropagation();
108         }
109     }
110 
111     /// Stops the propagation of this event to descendants in the DOM.
112     ///
113     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation)
114     // https://dom.spec.whatwg.org/#ref-for-dom-event-stopimmediatepropagation
115     #[inline]
stop_propagation( &self )116     fn stop_propagation( &self ) {
117         js! { @(no_return)
118             @{self.as_ref()}.stopPropagation();
119         }
120     }
121 
122 
123     /// Returns a reference to the target to which this event was originally registered.
124     ///
125     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/target)
126     // https://dom.spec.whatwg.org/#ref-for-dom-event-target%E2%91%A1
127     #[inline]
target( &self ) -> Option< EventTarget >128     fn target( &self ) -> Option< EventTarget > {
129         js!(
130             return @{self.as_ref()}.target;
131         ).try_into().ok()
132     }
133 
134     /// Returns the time in milliseconds at which this event was created.
135     ///
136     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/timeStamp)
137     // https://dom.spec.whatwg.org/#ref-for-dom-event-timestamp
138     #[inline]
time_stamp( &self ) -> Option< f64 >139     fn time_stamp( &self ) -> Option< f64 > {
140         js!(
141             return @{self.as_ref()}.timeStamp;
142         ).try_into().ok()
143     }
144 
145     /// Indicates whether the event was generated by a user action.
146     // https://dom.spec.whatwg.org/#ref-for-dom-event-istrusted
147     #[inline]
is_trusted( &self ) -> bool148     fn is_trusted( &self ) -> bool {
149         js!(
150             return @{self.as_ref()}.isTrusted;
151         ).try_into().unwrap()
152     }
153 
154     /// Returns a string containing the type of event. It is set when
155     /// the event is constructed and is the name commonly used to refer
156     /// to the specific event.
157     ///
158     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/type)
159     // https://dom.spec.whatwg.org/#ref-for-dom-event-type%E2%91%A1
160     #[inline]
event_type( &self ) -> String161     fn event_type( &self ) -> String {
162         js!(
163             return @{self.as_ref()}.type;
164         ).try_into().unwrap()
165     }
166 
167     /// Cancels the event if it is cancelable, without
168     /// stopping further propagation of the event.
169     ///
170     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
171     // https://dom.spec.whatwg.org/#ref-for-dom-event-preventdefault%E2%91%A0
172     #[inline]
prevent_default( &self )173     fn prevent_default( &self ) {
174         js! { @(no_return)
175             @{self.as_ref()}.preventDefault();
176         }
177     }
178 }
179 
180 /// Indicates the phase of event flow during event proessing.
181 // https://dom.spec.whatwg.org/#dom-event-eventphase
182 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
183 pub enum EventPhase {
184     /// No event is currently being processed.
185     None,
186     /// The event is being propagated down through the target's ancestors.
187     Capturing,
188     /// The target is currently processing the event.
189     AtTarget,
190     /// The event is propagating back up through the target's ancestors.
191     Bubbling,
192 }
193 
194 /// A trait representing a concrete event type.
195 pub trait ConcreteEvent: IEvent {
196     /// A string representing the event type.
197     ///
198     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/type)
199     const EVENT_TYPE: &'static str;
200 }
201 
202 /// A reference to a JavaScript object which implements the [IEvent](trait.IEvent.html)
203 /// interface.
204 ///
205 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
206 // https://dom.spec.whatwg.org/#event
207 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
208 #[reference(instance_of = "Event")]
209 pub struct Event( Reference );
210 
211 impl IEvent for Event {}
212 
213 /// The `BeforeUnload` event fires when the window is about to be unloaded (to close the page or
214 /// follow a link). If the event propagation is cancelled, the browser will present the user with
215 /// a confirmation dialog allowing them to stay on the page or continue.
216 ///
217 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event)
218 // https://html.spec.whatwg.org/multipage/indices.html#event-beforeunload
219 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
220 #[reference(instance_of = "BeforeUnloadEvent")]
221 #[reference(event = "beforeunload")]
222 pub struct BeforeUnloadEvent( Reference );
223 
224 impl IEvent for BeforeUnloadEvent {}
225 
226 
227 /// The `Unload` event fires when the window has been unloaded and is no longer visible. This event
228 /// can't be cancelled.
229 ///
230 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event)
231 // https://html.spec.whatwg.org/multipage/indices.html#event-unload
232 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
233 #[reference(instance_of = "UnloadEvent")]
234 #[reference(event = "unload")]
235 pub struct UnloadEvent( Reference );
236 
237 impl IEvent for UnloadEvent {}
238 
239 /// The 'FullscreenChange' event fires when an element enters or exits fullscreen
240 ///
241 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event)
242 // https://fullscreen.spec.whatwg.org/#handler-document-onfullscreenchange
243 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
244 #[reference(instance_of = "Event")]
245 #[reference(event = "fullscreenchange")]
246 pub struct FullscreenChangeEvent( Reference );
247 
248 impl IEvent for FullscreenChangeEvent {}
249 
250 /// The `IUiEvent` interface represents simple user interface events.
251 ///
252 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent)
253 // https://w3c.github.io/uievents/#uievent
254 pub trait IUiEvent: IEvent {
255     /// Provides the current click count for this event, if applicable.
256     ///
257     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail)
258     // https://w3c.github.io/uievents/#dom-uievent-detail
259     #[inline]
detail( &self ) -> i32260     fn detail( &self ) -> i32 {
261         js!(
262             return @{self.as_ref()}.detail;
263         ).try_into().unwrap()
264     }
265 
266     /// Returns the `WindowProxy` that generated the event.
267     ///
268     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/view)
269     // https://w3c.github.io/uievents/#dom-uievent-view
270     #[inline]
view( &self ) -> Option< Window >271     fn view( &self ) -> Option< Window > {
272         js!(
273             return @{self.as_ref()}.view;
274         ).try_into().ok()
275     }
276 }
277 
278 /// A reference to a JavaScript object which implements the [IUiEvent](trait.IUiEvent.html)
279 /// interface.
280 ///
281 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent)
282 // https://w3c.github.io/uievents/#uievent
283 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
284 #[reference(instance_of = "UIEvent")]
285 #[reference(subclass_of(Event))]
286 pub struct UiEvent( Reference );
287 
288 impl IEvent for UiEvent {}
289 impl IUiEvent for UiEvent {}
290 
291 #[cfg(all(test, feature = "web_test"))]
292 mod tests {
293     use super::*;
294 
295     #[test]
test_event()296     fn test_event() {
297         let event: Event = js!(
298             return new Event("dummy")
299         ).try_into().unwrap();
300 
301         assert_eq!( event.event_type(), "dummy" );
302         assert_eq!( event.bubbles(), false );
303         assert!( !event.cancel_bubble() );
304         assert!( !event.cancelable(), false );
305         assert!( event.current_target().is_none() );
306         assert!( !event.default_prevented() );
307         assert_eq!( event.event_phase(), EventPhase::None );
308         assert!( event.target().is_none() );
309         assert!( event.time_stamp().is_some() );
310         assert!( !event.is_trusted() );
311 
312         event.stop_immediate_propagation();
313         event.stop_propagation();
314     }
315 
316     #[test]
test_ui_event()317     fn test_ui_event() {
318         use webapi::events::mouse::ClickEvent;
319 
320         let event: UiEvent = js!(
321             return new UIEvent(
322                 @{ClickEvent::EVENT_TYPE},
323                 {
324                     detail: 1,
325                 }
326             )
327         ).try_into().unwrap();
328         assert_eq!( event.event_type(), ClickEvent::EVENT_TYPE );
329         assert_eq!( event.detail(), 1 );
330         assert!( event.view().is_none() );
331     }
332 }
333