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, Clone, ImplicitClone, Default)]
164pub enum Listeners {
165    /// No listeners registered or pending.
166    /// Distinct from `Pending` with an empty slice to avoid an allocation.
167    #[default]
168    None,
169
170    /// Not yet added to the element or registry
171    Pending(Box<[Option<Rc<dyn Listener>>]>),
172}
173
174impl PartialEq for Listeners {
175    fn eq(&self, rhs: &Self) -> bool {
176        use Listeners::*;
177
178        match (self, rhs) {
179            (None, None) => true,
180            (Pending(lhs), Pending(rhs)) => {
181                if lhs.len() != rhs.len() {
182                    false
183                } else {
184                    use std::option::Option::None;
185
186                    lhs.iter()
187                        .zip(rhs.iter())
188                        .all(|(lhs, rhs)| match (lhs, rhs) {
189                            (Some(lhs), Some(rhs)) => {
190                                // We are okay with comparisons from different compilation units to
191                                // result in false not-equal results. This should only lead in the
192                                // worst-case to some unneeded re-renders.
193                                #[allow(ambiguous_wide_pointer_comparisons)]
194                                Rc::ptr_eq(lhs, rhs)
195                            }
196                            (None, None) => true,
197                            _ => false,
198                        })
199                }
200            }
201            (None, Pending(pending)) | (Pending(pending), None) => pending.is_empty(),
202        }
203    }
204}