use crate::*;
fn dispatch_delegated_event(event: &Event, event_name: &'static str) {
let target: EventTarget = match event.target() {
Some(event_target) => event_target,
None => return,
};
let mut current: Option<Element> = target.dyn_ref::<Element>().cloned().or_else(|| {
target
.dyn_ref::<Node>()
.and_then(|node: &Node| node.parent_node())
.and_then(|parent: Node| parent.dyn_ref::<Element>().cloned())
});
while let Some(element) = current {
if let Some(euv_id_str) = element.get_attribute(DATA_EUV_ID)
&& let Ok(euv_id) = euv_id_str.parse::<usize>()
&& let Some(active_handler) = ensure_handler_registry()
.get(&(euv_id, event_name))
.and_then(|entry: &HandlerEntry| {
entry
.try_borrow()
.ok()
.and_then(|slot: Ref<HandlerSlot>| slot.try_get_handler().as_ref().cloned())
})
{
active_handler.handle(event.clone());
return;
}
current = element.parent_element();
}
}
pub(crate) fn ensure_delegated_listener(event_name: &'static str) {
if is_delegated_event(event_name) {
return;
}
let closure: Closure<dyn FnMut(Event)> = Closure::wrap(Box::new(move |event: Event| {
dispatch_delegated_event(&event, event_name);
}));
let window: Window = match window() {
Some(window_instance) => window_instance,
None => return,
};
let _ = window.add_event_listener_with_callback_and_bool(
event_name,
closure.as_ref().unchecked_ref(),
true,
);
closure.forget();
insert_delegated_event(event_name);
}
pub(crate) fn dispatch_signal_update_callbacks() {
if SIGNAL_UPDATE_DISPATCHING.load(Ordering::Relaxed) {
return;
}
SIGNAL_UPDATE_DISPATCHING.store(true, Ordering::Relaxed);
let mut iterations: usize = 0;
const MAX_ITERATIONS: usize = 3;
loop {
let registry: &mut HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry_mut();
let dirty_keys: Vec<usize> = registry
.iter()
.filter_map(|(key, entry): (&usize, &SignalUpdateEntry)| {
let Ok(slot) = entry.try_borrow() else {
return None;
};
if slot.get_dirty() && !slot.get_removed() {
Some(*key)
} else {
None
}
})
.collect();
if dirty_keys.is_empty() {
break;
}
for key in dirty_keys {
let entry: SignalUpdateEntry = match ensure_signal_update_registry_mut().remove(&key) {
Some(removed_entry) => removed_entry,
None => continue,
};
let callback: Option<Box<dyn FnMut()>> = {
let Ok(mut slot) = entry.try_borrow_mut() else {
continue;
};
if slot.get_removed() {
continue;
}
slot.set_dirty(false);
slot.get_mut_callback().take()
};
if let Some(mut callback) = callback {
callback();
if let Ok(mut slot) = entry.try_borrow_mut()
&& !slot.get_removed()
{
slot.set_callback(Some(callback));
}
}
if entry
.try_borrow()
.map(|slot: Ref<SignalUpdateSlot>| slot.get_removed())
.unwrap_or(true)
{
continue;
}
ensure_signal_update_registry_mut().insert(key, entry);
}
iterations += 1;
if iterations >= MAX_ITERATIONS {
break;
}
}
SIGNAL_UPDATE_DISPATCHING.store(false, Ordering::Relaxed);
}
pub(crate) fn mark_all_slots_dirty() {
let registry: &mut HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry_mut();
for entry in registry.values() {
let Ok(mut slot) = entry.try_borrow_mut() else {
continue;
};
if !slot.get_removed() {
slot.set_dirty(true);
}
}
}
pub(crate) fn register_dynamic_listener(dynamic_id: usize, callback: Box<dyn FnMut()>) {
let entry: SignalUpdateEntry = Rc::new(RefCell::new(SignalUpdateSlot::new(
Some(callback),
false,
true,
)));
ensure_signal_update_registry_mut().insert(dynamic_id, entry);
}
pub(crate) fn register_attr_signal_listener(signal_key: usize, callback: Box<dyn FnMut()>) {
let entry: SignalUpdateEntry = Rc::new(RefCell::new(SignalUpdateSlot::new(
Some(callback),
false,
true,
)));
ensure_signal_update_registry_mut().insert(signal_key, entry);
}
pub(crate) fn cleanup_element_handlers(euv_id: usize) {
let registry_ref: &mut HandlerRegistryMap = ensure_handler_registry_mut();
let keys_to_remove: Vec<(usize, &'static str)> = registry_ref
.keys()
.filter(|(id, _): &&(usize, &'static str)| *id == euv_id)
.copied()
.collect();
for key in keys_to_remove {
registry_ref.remove(&key);
}
}
pub(crate) fn cleanup_dynamic_node(dynamic_id: usize) {
if let Some(entry) = ensure_signal_update_registry().get(&dynamic_id)
&& let Ok(mut slot) = entry.try_borrow_mut()
{
slot.set_removed(true);
slot.set_callback(None);
}
}
#[allow(static_mut_refs)]
fn ensure_handler_registry() -> &'static HandlerRegistryMap {
unsafe {
if (*HANDLER_REGISTRY.get_0().get()).is_none() {
(*HANDLER_REGISTRY.get_0().get()) = Some(HashMap::new());
}
(*HANDLER_REGISTRY.get_0().get())
.as_ref()
.unwrap_unchecked()
}
}
#[allow(static_mut_refs)]
pub(crate) fn ensure_handler_registry_mut() -> &'static mut HandlerRegistryMap {
unsafe {
if (*HANDLER_REGISTRY.get_0().get()).is_none() {
(*HANDLER_REGISTRY.get_0().get()) = Some(HashMap::new());
}
(*HANDLER_REGISTRY.get_0().get())
.as_mut()
.unwrap_unchecked()
}
}
#[allow(static_mut_refs)]
pub(crate) fn is_delegated_event(event_name: &str) -> bool {
unsafe {
if (*DELEGATED_EVENTS.get_0().get()).is_none() {
return false;
}
(*DELEGATED_EVENTS.get_0().get())
.as_ref()
.unwrap_unchecked()
.contains(event_name)
}
}
#[allow(static_mut_refs)]
pub(crate) fn insert_delegated_event(event_name: &'static str) {
unsafe {
if (*DELEGATED_EVENTS.get_0().get()).is_none() {
(*DELEGATED_EVENTS.get_0().get()) = Some(HashSet::new());
}
(*DELEGATED_EVENTS.get_0().get())
.as_mut()
.unwrap_unchecked()
.insert(event_name);
}
}
#[allow(static_mut_refs)]
fn ensure_signal_update_registry() -> &'static HashMap<usize, SignalUpdateEntry> {
unsafe {
if (*SIGNAL_UPDATE_REGISTRY.get_0().get()).is_none() {
(*SIGNAL_UPDATE_REGISTRY.get_0().get()) = Some(HashMap::new());
}
(*SIGNAL_UPDATE_REGISTRY.get_0().get())
.as_ref()
.unwrap_unchecked()
}
}
#[allow(static_mut_refs)]
fn ensure_signal_update_registry_mut() -> &'static mut HashMap<usize, SignalUpdateEntry> {
unsafe {
if (*SIGNAL_UPDATE_REGISTRY.get_0().get()).is_none() {
(*SIGNAL_UPDATE_REGISTRY.get_0().get()) = Some(HashMap::new());
}
(*SIGNAL_UPDATE_REGISTRY.get_0().get())
.as_mut()
.unwrap_unchecked()
}
}
#[allow(static_mut_refs)]
pub(crate) fn ensure_window_event_registry_mut() -> &'static mut WindowEventRegistryMap {
unsafe {
if (*WINDOW_EVENT_REGISTRY.get_0().get()).is_none() {
(*WINDOW_EVENT_REGISTRY.get_0().get()) = Some(HashMap::new());
}
(*WINDOW_EVENT_REGISTRY.get_0().get())
.as_mut()
.unwrap_unchecked()
}
}
pub(crate) fn register_window_event_handler<F>(event_name: &str, callback: F) -> usize
where
F: FnMut() + 'static,
{
let handler_id: usize = NEXT_WINDOW_HANDLER_ID.fetch_add(1, Ordering::Relaxed);
let entry: WindowEventHandlerEntry = (
handler_id,
Rc::new(RefCell::new(Box::new(callback) as Box<dyn FnMut()>)),
);
let registry: &mut WindowEventRegistryMap = ensure_window_event_registry_mut();
let is_new_event: bool = !registry.contains_key(event_name);
registry
.entry(event_name.to_string())
.or_default()
.push(entry);
if is_new_event {
ensure_window_event_listener(event_name);
}
handler_id
}
pub(crate) fn unregister_window_event_handler(event_name: &str, handler_id: usize) {
let registry: &mut WindowEventRegistryMap = ensure_window_event_registry_mut();
if let Some(handlers) = registry.get_mut(event_name) {
handlers.retain(|(id, _): &WindowEventHandlerEntry| *id != handler_id);
}
}
fn ensure_window_event_listener(event_name: &str) {
let event_name_owned: String = event_name.to_string();
let closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
let registry: &WindowEventRegistryMap = ensure_window_event_registry_mut();
if let Some(handlers) = registry.get(&event_name_owned) {
for (_handler_id, callback_rc) in handlers {
if let Ok(mut callback_ref) = callback_rc.try_borrow_mut() {
callback_ref();
}
}
}
}));
let window: Window = match window() {
Some(window_instance) => window_instance,
None => return,
};
let _ = window.add_event_listener_with_callback(event_name, closure.as_ref().unchecked_ref());
closure.forget();
}