This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/virtual_dom/
listeners.rs

1use std::rc::Rc;
2
3use crate::html::ImplicitClone;
4
5/// The [Listener] trait is an universal implementation of an event listener
6/// which is used to bind Rust-listener to JS-listener (DOM).
7pub trait Listener {
8    /// Returns the name of the event
9    fn kind(&self) -> ListenerKind;
10
11    /// Handles an event firing
12    fn handle(&self, event: web_sys::Event);
13
14    /// Makes the event listener passive. See
15    /// [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).
16    fn passive(&self) -> bool;
17}
18
19impl std::fmt::Debug for dyn Listener {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        write!(
22            f,
23            "Listener {{ kind: {}, passive: {:?} }}",
24            self.kind().as_ref(),
25            self.passive(),
26        )
27    }
28}
29
30macro_rules! gen_listener_kinds {
31    ($($kind:ident)*) => {
32        /// Supported kinds of DOM event listeners
33        // Using instead of strings to optimise registry collection performance by simplifying
34        // hashmap hash calculation.
35        #[derive(Clone, PartialEq, Eq, Hash, Debug)]
36        #[allow(non_camel_case_types)]
37        #[allow(missing_docs)]
38        pub enum ListenerKind {
39            $( $kind, )*
40            other(std::borrow::Cow<'static, str>),
41        }
42
43        impl ListenerKind {
44            pub fn type_name(&self) -> std::borrow::Cow<'static, str> {
45                match self {
46                    Self::other(type_name) => type_name.clone(),
47                    $( Self::$kind => stringify!($kind)[2..].into(), )*
48                }
49            }
50        }
51
52        impl AsRef<str> for ListenerKind {
53            fn as_ref(&self) -> &str {
54                match self {
55                    $( Self::$kind => stringify!($kind), )*
56                    Self::other(type_name) => type_name.as_ref(),
57                }
58            }
59        }
60    };
61}
62
63gen_listener_kinds! {
64    onabort
65    onauxclick
66    onblur
67    oncancel
68    oncanplay
69    oncanplaythrough
70    onchange
71    onclick
72    onclose
73    oncontextmenu
74    oncuechange
75    ondblclick
76    ondrag
77    ondragend
78    ondragenter
79    ondragexit
80    ondragleave
81    ondragover
82    ondragstart
83    ondrop
84    ondurationchange
85    onemptied
86    onended
87    onerror
88    onfocus
89    onfocusin
90    onfocusout
91    onformdata
92    oninput
93    oninvalid
94    onkeydown
95    onkeypress
96    onkeyup
97    onload
98    onloadeddata
99    onloadedmetadata
100    onloadstart
101    onmousedown
102    onmouseenter
103    onmouseleave
104    onmousemove
105    onmouseout
106    onmouseover
107    onmouseup
108    onpause
109    onplay
110    onplaying
111    onprogress
112    onratechange
113    onreset
114    onresize
115    onscroll
116    onsecuritypolicyviolation
117    onseeked
118    onseeking
119    onselect
120    onslotchange
121    onstalled
122    onsubmit
123    onsuspend
124    ontimeupdate
125    ontoggle
126    onvolumechange
127    onwaiting
128    onwheel
129    oncopy
130    oncut
131    onpaste
132    onanimationcancel
133    onanimationend
134    onanimationiteration
135    onanimationstart
136    ongotpointercapture
137    onloadend
138    onlostpointercapture
139    onpointercancel
140    onpointerdown
141    onpointerenter
142    onpointerleave
143    onpointerlockchange
144    onpointerlockerror
145    onpointermove
146    onpointerout
147    onpointerover
148    onpointerup
149    onselectionchange
150    onselectstart
151    onshow
152    ontouchcancel
153    ontouchend
154    ontouchmove
155    ontouchstart
156    ontransitioncancel
157    ontransitionend
158    ontransitionrun
159    ontransitionstart
160}
161
162/// A list of event listeners
163#[derive(Debug)]
164pub enum Listeners {
165    /// No listeners registered or pending.
166    /// Distinct from `Pending` with an empty slice to avoid an allocation.
167    None,
168
169    /// Not yet added to the element or registry
170    Pending(Box<[Option<Rc<dyn Listener>>]>),
171}
172
173impl ImplicitClone for Listeners {}
174
175impl PartialEq for Listeners {
176    fn eq(&self, rhs: &Self) -> bool {
177        use Listeners::*;
178
179        match (self, rhs) {
180            (None, None) => true,
181            (Pending(lhs), Pending(rhs)) => {
182                if lhs.len() != rhs.len() {
183                    false
184                } else {
185                    use std::option::Option::None;
186
187                    lhs.iter()
188                        .zip(rhs.iter())
189                        .all(|(lhs, rhs)| match (lhs, rhs) {
190                            (Some(lhs), Some(rhs)) => {
191                                // We are okay with comparisons from different compilation units to
192                                // result in false not-equal results. This should only lead in the
193                                // worst-case to some unneeded re-renders.
194                                #[allow(ambiguous_wide_pointer_comparisons)]
195                                Rc::ptr_eq(lhs, rhs)
196                            }
197                            (None, None) => true,
198                            _ => false,
199                        })
200                }
201            }
202            (None, Pending(pending)) | (Pending(pending), None) => pending.is_empty(),
203        }
204    }
205}
206
207impl Clone for Listeners {
208    fn clone(&self) -> Self {
209        match self {
210            Self::None => Self::None,
211            Self::Pending(v) => Self::Pending(v.clone()),
212        }
213    }
214}
215
216impl Default for Listeners {
217    fn default() -> Self {
218        Self::None
219    }
220}