virtual_node/
event.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fmt;
4use std::fmt::Formatter;
5use std::ops::{Deref, DerefMut};
6use std::rc::Rc;
7
8pub use self::event_handlers::*;
9pub use self::event_name::EventName;
10pub use self::non_delegated_event_wrapper::insert_non_delegated_event;
11pub(crate) use self::virtual_events::set_events_id;
12pub use self::virtual_events::{
13    ElementEventsId, VirtualEventElement, VirtualEventNode, VirtualEvents, ELEMENT_EVENTS_ID_PROP,
14};
15
16mod event_handlers;
17mod event_name;
18mod non_delegated_event_wrapper;
19mod virtual_events;
20
21type EventAttribFnInner = std::rc::Rc<dyn AsRef<wasm_bindgen::JsValue>>;
22
23/// Box<dyn AsRef<JsValue>>> is our js_sys::Closure. Stored this way to allow us to store
24/// any Closure regardless of the types of its arguments.
25#[derive(Clone)]
26pub struct EventAttribFn(pub EventAttribFnInner);
27
28/// We need a custom implementation of fmt::Debug since JsValue doesn't implement debug.
29#[derive(PartialEq)]
30pub struct Events {
31    events: HashMap<EventName, EventHandler>,
32}
33
34impl Events {
35    /// Whether or not there is at least one event.
36    pub fn has_events(&self) -> bool {
37        !self.events.is_empty()
38    }
39
40    /// All of the events.
41    pub fn events(&self) -> &HashMap<EventName, EventHandler> {
42        &self.events
43    }
44
45    /// Insert an event handler that does not have any arguments.
46    pub fn insert_no_args(&mut self, event_name: EventName, event: Rc<RefCell<dyn FnMut()>>) {
47        self.events.insert(event_name, EventHandler::NoArgs(event));
48    }
49
50    // Used by the html! macro
51    #[doc(hidden)]
52    pub fn __insert_unsupported_signature(
53        &mut self,
54        event_name: EventName,
55        event: EventAttribFnInner,
56    ) {
57        self.events
58            .insert(event_name, EventHandler::UnsupportedSignature(event.into()));
59    }
60
61    /// Insert a mouse event handler.
62    pub fn insert_mouse_event(
63        &mut self,
64        event_name: EventName,
65        event: Rc<RefCell<dyn FnMut(MouseEvent)>>,
66    ) {
67        self.events
68            .insert(event_name, EventHandler::MouseEvent(event));
69    }
70}
71
72impl Events {
73    /// Create a new Events.
74    pub fn new() -> Self {
75        Events {
76            events: HashMap::new(),
77        }
78    }
79}
80
81// Allows us to easily derive PartialEq for some of the types that contain events.
82// Those PartialEq implementations are used for testing.
83// Maybe we can put some of the event related PartialEq implementations
84// behind a #[cfg(any(test, feature = "__test-utils"))].
85impl PartialEq for EventAttribFn {
86    fn eq(&self, _other: &Self) -> bool {
87        true
88    }
89}
90
91impl fmt::Debug for Events {
92    // Print out all of the event names for this VirtualNode
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        let events: String = self
95            .events
96            .keys()
97            .map(|key| " ".to_string() + key.with_on_prefix())
98            .collect();
99        write!(f, "{}", events)
100    }
101}
102
103impl fmt::Debug for EventAttribFn {
104    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105        write!(f, "event_handler()")
106    }
107}
108
109impl From<EventAttribFnInner> for EventAttribFn {
110    fn from(inner: EventAttribFnInner) -> Self {
111        EventAttribFn(inner)
112    }
113}
114
115impl Deref for EventAttribFn {
116    type Target = EventAttribFnInner;
117
118    fn deref(&self) -> &Self::Target {
119        &self.0
120    }
121}
122
123impl Deref for Events {
124    type Target = HashMap<EventName, EventHandler>;
125
126    fn deref(&self) -> &Self::Target {
127        &self.events
128    }
129}
130
131impl DerefMut for Events {
132    fn deref_mut(&mut self) -> &mut Self::Target {
133        &mut self.events
134    }
135}