use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
pub struct EventRegistry {
handlers: Rc<RefCell<HashMap<String, Vec<Closure<dyn FnMut(web_sys::Event)>>>>>,
}
impl EventRegistry {
pub fn new() -> Self {
Self {
handlers: Rc::new(RefCell::new(HashMap::new())),
}
}
pub fn register<F>(&self, element_id: &str, event_type: &str, handler: F) -> Result<(), JsValue>
where
F: FnMut(web_sys::Event) + 'static,
{
let closure = Closure::wrap(Box::new(handler) as Box<dyn FnMut(_)>);
let window = web_sys::window().ok_or("No window")?;
let document = window.document().ok_or("No document")?;
let element = document
.get_element_by_id(element_id)
.ok_or_else(|| JsValue::from_str(&format!("Element not found: {}", element_id)))?;
element.add_event_listener_with_callback(event_type, closure.as_ref().unchecked_ref())?;
let key = format!("{}:{}", element_id, event_type);
self.handlers
.borrow_mut()
.entry(key)
.or_insert_with(Vec::new)
.push(closure);
Ok(())
}
pub fn clear(&self, element_id: &str) {
let mut handlers = self.handlers.borrow_mut();
handlers.retain(|key, _| !key.starts_with(&format!("{}:", element_id)));
}
pub fn clear_all(&self) {
self.handlers.borrow_mut().clear();
}
}
impl Default for EventRegistry {
fn default() -> Self {
Self::new()
}
}
use std::cell::OnceCell;
thread_local! {
static GLOBAL_REGISTRY: OnceCell<EventRegistry> = OnceCell::new();
}
pub fn with_global_registry<F, R>(f: F) -> R
where
F: FnOnce(&EventRegistry) -> R,
{
GLOBAL_REGISTRY.with(|registry| f(registry.get_or_init(EventRegistry::new)))
}
pub fn attach_handler<F>(element_id: &str, event_type: &str, handler: F) -> Result<(), JsValue>
where
F: FnMut(web_sys::Event) + 'static,
{
with_global_registry(|registry| registry.register(element_id, event_type, handler))
}
pub fn on_click<F>(element_id: &str, handler: F) -> Result<(), JsValue>
where
F: FnMut(web_sys::Event) + 'static,
{
attach_handler(element_id, "click", handler)
}
pub fn on_input<F>(element_id: &str, handler: F) -> Result<(), JsValue>
where
F: FnMut(web_sys::Event) + 'static,
{
attach_handler(element_id, "input", handler)
}
pub fn on_submit<F>(element_id: &str, handler: F) -> Result<(), JsValue>
where
F: FnMut(web_sys::Event) + 'static,
{
attach_handler(element_id, "submit", handler)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_registry_creation() {
let registry = EventRegistry::new();
assert_eq!(registry.handlers.borrow().len(), 0);
}
#[test]
fn test_event_registry_clear() {
let registry = EventRegistry::new();
registry.clear_all();
assert_eq!(registry.handlers.borrow().len(), 0);
}
}