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| {
let slot: &HandlerSlot = unsafe { &**entry };
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 slot: &SignalUpdateSlot = unsafe { &**entry };
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 slot: &mut SignalUpdateSlot = unsafe { &mut *entry };
if slot.get_removed() {
unsafe {
let _ = Box::from_raw(entry);
}
continue;
}
slot.set_dirty(false);
let callback: Option<Box<dyn FnMut()>> = slot.get_mut_callback().take();
if let Some(mut callback) = callback {
callback();
let slot: &mut SignalUpdateSlot = unsafe { &mut *entry };
if !slot.get_removed() {
slot.set_callback(Some(callback));
}
}
let slot: &SignalUpdateSlot = unsafe { &*entry };
if slot.get_removed() {
unsafe {
let _ = Box::from_raw(entry);
}
continue;
}
let registry: &mut HashMap<usize, SignalUpdateEntry> =
ensure_signal_update_registry_mut();
if registry.contains_key(&key) {
unsafe {
let _ = Box::from_raw(entry);
}
continue;
}
registry.insert(key, entry);
}
iterations += 1;
if iterations >= MAX_ITERATIONS {
break;
}
}
sweep_removed_signal_update_entries();
SIGNAL_UPDATE_DISPATCHING.store(false, Ordering::Relaxed);
}
fn sweep_removed_signal_update_entries() {
ensure_signal_update_registry_mut().retain(|_key, entry| {
let slot: &SignalUpdateSlot = unsafe { &**entry };
if slot.get_removed() {
unsafe {
let _ = Box::from_raw(*entry);
}
false
} else {
true
}
});
}
pub(crate) fn mark_all_slots_dirty() {
let registry: &mut HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry_mut();
for entry in registry.values() {
let slot: &mut SignalUpdateSlot = unsafe { &mut **entry };
if !slot.get_removed() {
slot.set_dirty(true);
}
}
}
pub(crate) fn mark_slots_dirty_targeted(dynamic_ids: &[usize]) {
let registry: &mut HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry_mut();
for dynamic_id in dynamic_ids {
if let Some(entry) = registry.get(dynamic_id) {
let slot: &mut SignalUpdateSlot = unsafe { &mut **entry };
if !slot.get_removed() {
slot.set_dirty(true);
}
}
}
}
pub(crate) fn register_dynamic_listener(dynamic_id: usize, callback: Box<dyn FnMut()>) {
let slot: Box<SignalUpdateSlot> = Box::new(SignalUpdateSlot::new(Some(callback), false, true));
let entry: SignalUpdateEntry = Box::into_raw(slot);
if let Some(old_entry) = ensure_signal_update_registry_mut().insert(dynamic_id, entry) {
unsafe {
let _ = Box::from_raw(old_entry);
}
}
}
pub(crate) fn register_attr_signal_listener(signal_key: usize, callback: Box<dyn FnMut()>) {
let slot: Box<SignalUpdateSlot> = Box::new(SignalUpdateSlot::new(Some(callback), false, true));
let entry: SignalUpdateEntry = Box::into_raw(slot);
if let Some(old_entry) = ensure_signal_update_registry_mut().insert(signal_key, entry) {
unsafe {
let _ = Box::from_raw(old_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 {
if let Some(entry) = registry_ref.remove(&key) {
unsafe {
let _ = Box::from_raw(entry);
}
}
}
}
pub(crate) fn cleanup_dynamic_node(dynamic_id: usize) {
if let Some(entry) = ensure_signal_update_registry().get(&dynamic_id) {
let slot: &mut SignalUpdateSlot = unsafe { &mut **entry };
slot.set_removed(true);
slot.set_callback(None);
}
}
pub(crate) fn cleanup_attr_signal_update_slot(addr: usize) {
if let Some(entry) = ensure_signal_update_registry().get(&addr) {
let slot: &mut SignalUpdateSlot = unsafe { &mut **entry };
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 boxed: Box<Box<dyn FnMut()>> = Box::new(Box::new(callback) as Box<dyn FnMut()>);
let entry: WindowEventHandlerEntry = (handler_id, Box::into_raw(boxed));
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, ptr): &WindowEventHandlerEntry| {
if *id == handler_id {
unsafe {
let _ = Box::from_raw(*ptr);
}
false
} else {
true
}
});
}
}
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 handler_ids: Vec<usize> =
match ensure_window_event_registry_mut().get(&event_name_owned) {
Some(handlers) => handlers.iter().map(|(id, _ptr)| *id).collect(),
None => return,
};
for handler_id in handler_ids {
let callback_ptr: *mut Box<dyn FnMut()> =
match ensure_window_event_registry_mut().get(&event_name_owned) {
Some(handlers) => match handlers.iter().find(|(id, _ptr)| *id == handler_id) {
Some((_id, ptr)) => *ptr,
None => continue,
},
None => return,
};
let callback: &mut Box<dyn FnMut()> = unsafe { &mut *callback_ptr };
callback();
}
}));
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();
}