yew/virtual_dom/
listeners.rs1use std::rc::Rc;
2
3use crate::html::ImplicitClone;
4
5pub trait Listener {
8    fn kind(&self) -> ListenerKind;
10
11    fn handle(&self, event: web_sys::Event);
13
14    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        #[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#[derive(Debug, Clone, ImplicitClone, Default)]
164pub enum Listeners {
165    #[default]
168    None,
169
170    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                                #[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}