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