1 use std::fmt;
2 
3 use webcore::value::Reference;
4 use webcore::try_from::TryInto;
5 use webapi::event::{ConcreteEvent, IEvent};
6 
7 pub struct EventListenerHandle {
8     event_type: &'static str,
9     reference: Reference,
10     listener_reference: Reference
11 }
12 
13 impl fmt::Debug for EventListenerHandle {
fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result14     fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
15         write!( formatter, "EventListenerHandle {{ event_type: {}, reference: {:?} }}", self.event_type, self.reference )
16     }
17 }
18 
19 impl EventListenerHandle {
20     /// Removes the handler from the [IEventTarget](trait.IEventTarget.html) on
21     /// which it was previously registered.
22     ///
23     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener)
remove( self )24     pub fn remove( self ) {
25         js! { @(no_return)
26             var self = @{self.reference};
27             var event_type = @{self.event_type};
28             var listener = @{self.listener_reference};
29             listener.drop();
30             self.removeEventListener( event_type, listener );
31         }
32     }
33 }
34 
35 /// `IEventTarget` is an interface implemented by objects that
36 /// can receive events and may have listeners for them.
37 ///
38 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
39 pub trait IEventTarget: AsRef< Reference > {
40     /// Adds given event handler to the list the list of event listeners for
41     /// the specified `EventTarget` on which it's called.
42     ///
43     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
add_event_listener< T, F >( &self, listener: F ) -> EventListenerHandle where T: ConcreteEvent, F: FnMut( T ) + 'static44     fn add_event_listener< T, F >( &self, listener: F ) -> EventListenerHandle
45         where T: ConcreteEvent, F: FnMut( T ) + 'static
46     {
47         let reference = self.as_ref();
48         let listener_reference = js! {
49             var listener = @{listener};
50             @{reference}.addEventListener( @{T::EVENT_TYPE}, listener );
51             return listener;
52         }.try_into().unwrap();
53 
54         EventListenerHandle {
55             event_type: T::EVENT_TYPE,
56             reference: reference.clone(),
57             listener_reference: listener_reference
58         }
59     }
60 
61     /// Dispatches an `Event` at this `EventTarget`, invoking the affected event listeners in the
62     /// appropriate order.
63     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)
dispatch_event< T: IEvent >( &self, event: &T ) -> bool64     fn dispatch_event< T: IEvent >( &self, event: &T ) -> bool {
65         js! (
66             return @{self.as_ref()}.dispatchEvent( @{event.as_ref()} );
67         ).try_into().unwrap()
68     }
69 }
70 
71 /// A reference to a JavaScript object which implements the [IEventTarget](trait.IEventTarget.html)
72 /// interface.
73 ///
74 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
75 pub struct EventTarget( Reference );
76 
77 impl IEventTarget for EventTarget {}
78 
79 reference_boilerplate! {
80     EventTarget,
81     instanceof EventTarget
82 }
83