1use std::sync::Arc;
17
18#[derive(Debug, Clone)]
20pub struct BubbaEvent {
21 pub kind: &'static str,
23 pub value: Option<String>,
25 pub key: Option<String>,
27}
28
29pub type Callback = Arc<dyn Fn(BubbaEvent) + Send + Sync + 'static>;
31
32#[derive(Clone)]
34pub struct EventHandler {
35 pub event: &'static str,
37 pub callback: Callback,
39}
40
41impl std::fmt::Debug for EventHandler {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("EventHandler")
44 .field("event", &self.event)
45 .field("callback", &"<fn>")
46 .finish()
47 }
48}
49
50impl EventHandler {
51 pub fn new<F>(event: &'static str, f: F) -> Self
53 where
54 F: Fn(BubbaEvent) + Send + Sync + 'static,
55 {
56 Self {
57 event,
58 callback: Arc::new(f),
59 }
60 }
61
62 pub fn onclick<F: Fn(BubbaEvent) + Send + Sync + 'static>(f: F) -> Self {
64 Self::new("click", f)
65 }
66
67 pub fn oninput<F: Fn(BubbaEvent) + Send + Sync + 'static>(f: F) -> Self {
69 Self::new("input", f)
70 }
71
72 pub fn onkeypress<F: Fn(BubbaEvent) + Send + Sync + 'static>(f: F) -> Self {
74 Self::new("keypress", f)
75 }
76
77 pub fn onfocus<F: Fn(BubbaEvent) + Send + Sync + 'static>(f: F) -> Self {
79 Self::new("focus", f)
80 }
81
82 pub fn onblur<F: Fn(BubbaEvent) + Send + Sync + 'static>(f: F) -> Self {
84 Self::new("blur", f)
85 }
86
87 pub fn dispatch(&self, event: BubbaEvent) {
89 (self.callback)(event);
90 }
91}
92
93pub struct EventDispatcher {
95 queue: std::sync::Mutex<Vec<(String, BubbaEvent)>>,
97}
98
99impl EventDispatcher {
100 pub fn new() -> Self {
102 Self {
103 queue: std::sync::Mutex::new(Vec::new()),
104 }
105 }
106
107 pub fn push(&self, element_id: impl Into<String>, event: BubbaEvent) {
109 let mut q = self.queue.lock().unwrap();
110 q.push((element_id.into(), event));
111 }
112
113 pub fn flush(&self, handlers: &[(String, EventHandler)]) {
115 let events: Vec<(String, BubbaEvent)> = {
116 let mut q = self.queue.lock().unwrap();
117 std::mem::take(&mut *q)
118 };
119
120 for (element_id, event) in events {
121 for (handler_id, handler) in handlers {
122 if *handler_id == element_id && handler.event == event.kind {
123 handler.dispatch(event.clone());
124 }
125 }
126 }
127 }
128}
129
130impl Default for EventDispatcher {
131 fn default() -> Self {
132 Self::new()
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use std::sync::atomic::{AtomicBool, Ordering};
140
141 #[test]
142 fn handler_fires() {
143 let fired = Arc::new(AtomicBool::new(false));
144 let fired_clone = Arc::clone(&fired);
145
146 let h = EventHandler::onclick(move |_e| {
147 fired_clone.store(true, Ordering::SeqCst);
148 });
149
150 h.dispatch(BubbaEvent {
151 kind: "click",
152 value: None,
153 key: None,
154 });
155
156 assert!(fired.load(Ordering::SeqCst));
157 }
158}