use crate::*;
fn dispatch_delegated_event(event: &Event, event_name: &str) {
let target: EventTarget = match event.target() {
Some(t) => t,
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 key: (usize, Cow<'static, str>) = (euv_id, Cow::Owned(event_name.to_string()));
let found: Option<NativeEventHandler> = {
let registry: &HashMap<(usize, Cow<'static, str>), HandlerEntry> =
ensure_handler_registry();
registry.get(&key).and_then(|entry| {
let slot: std::cell::Ref<HandlerSlot> = entry.borrow();
slot.try_get_handler().as_ref().cloned()
})
};
if let Some(active_handler) = found {
active_handler.handle(event.clone());
return;
}
}
current = element.parent_element();
}
}
pub(crate) fn ensure_delegated_listener(event_name: Cow<'static, str>) {
let already_delegated: bool = is_delegated_event(&event_name);
if already_delegated {
return;
}
let event_name_clone: Cow<'static, str> = event_name.clone();
let closure: Closure<dyn FnMut(Event)> = Closure::wrap(Box::new(move |event: Event| {
dispatch_delegated_event(&event, &event_name_clone);
}));
let window: Window = window().unwrap();
window
.add_event_listener_with_callback_and_bool(
&event_name,
closure.as_ref().unchecked_ref(),
true,
)
.unwrap();
closure.forget();
insert_delegated_event(event_name);
}
pub(crate) fn init_event_delegation() {
for event_name_str in NativeEventName::DELEGATABLE_EVENT_NAMES {
let event_name: Cow<'static, str> = Cow::Borrowed(event_name_str);
ensure_delegated_listener(event_name);
}
}
pub(crate) fn ensure_signal_update_listener() {
let already_registered: bool = is_signal_update_listener_registered();
if already_registered {
return;
}
let closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(|| {
dispatch_signal_update_callbacks();
}));
let event_name: Cow<'static, str> = NativeEventName::EuvSignalUpdate.as_str();
let window: Window = window().unwrap();
window
.add_event_listener_with_callback(&event_name, closure.as_ref().unchecked_ref())
.unwrap();
closure.forget();
set_signal_update_listener_registered(true);
}
fn dispatch_signal_update_callbacks() {
if SIGNAL_UPDATE_DISPATCHING.load(Ordering::Relaxed) {
return;
}
SIGNAL_UPDATE_DISPATCHING.store(true, Ordering::Relaxed);
let keys: Vec<usize> = ensure_signal_update_registry().keys().cloned().collect();
let mut keys_to_cleanup: Vec<usize> = Vec::new();
for key in keys {
let callback: Option<Box<dyn FnMut()>> = {
let registry_ref: &HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry();
let Some(entry) = registry_ref.get(&key) else {
continue;
};
let mut slot: RefMut<SignalUpdateSlot> = entry.borrow_mut();
if slot.get_removed() {
keys_to_cleanup.push(key);
continue;
}
slot.get_mut_callback().take()
};
if let Some(mut callback) = callback {
callback();
let registry_ref: &mut HashMap<usize, SignalUpdateEntry> =
ensure_signal_update_registry_mut();
if let Some(entry) = registry_ref.get(&key) {
let mut slot: RefMut<SignalUpdateSlot> = entry.borrow_mut();
if !slot.get_removed() {
slot.set_callback(Some(callback));
}
}
}
}
if !keys_to_cleanup.is_empty() {
let registry_ref: &mut HashMap<usize, SignalUpdateEntry> =
ensure_signal_update_registry_mut();
for key in keys_to_cleanup {
registry_ref.remove(&key);
}
}
SIGNAL_UPDATE_DISPATCHING.store(false, Ordering::Relaxed);
}
pub(crate) fn register_dynamic_listener(dynamic_id: usize, callback: Box<dyn FnMut()>) {
ensure_signal_update_listener();
let registry_ref: &mut HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry_mut();
let entry: SignalUpdateEntry =
Rc::new(RefCell::new(SignalUpdateSlot::new(Some(callback), false)));
registry_ref.insert(dynamic_id, entry);
}
pub(crate) fn register_attr_signal_listener(signal_key: usize, callback: Box<dyn FnMut()>) {
let registry_ref: &mut HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry_mut();
let entry: SignalUpdateEntry =
Rc::new(RefCell::new(SignalUpdateSlot::new(Some(callback), false)));
registry_ref.insert(signal_key, entry);
}
pub(crate) fn cleanup_event_handler(_euv_id: usize, event_name: &str) {
let registry_ref: &mut HashMap<(usize, Cow<'static, str>), HandlerEntry> =
ensure_handler_registry_mut();
let key: (usize, Cow<'static, str>) = (_euv_id, Cow::Owned(event_name.to_string()));
registry_ref.remove(&key);
}
pub(crate) fn cleanup_element_handlers(euv_id: usize) {
let registry_ref: &mut HashMap<(usize, Cow<'static, str>), HandlerEntry> =
ensure_handler_registry_mut();
let keys_to_remove: Vec<(usize, Cow<'static, str>)> = registry_ref
.keys()
.filter(|(id, _)| *id == euv_id)
.cloned()
.collect();
for key in keys_to_remove {
registry_ref.remove(&key);
}
}
pub(crate) fn cleanup_dynamic_node(dynamic_id: usize) {
let registry_ref: &HashMap<usize, SignalUpdateEntry> = ensure_signal_update_registry();
if let Some(entry) = registry_ref.get(&dynamic_id) {
let mut slot: RefMut<SignalUpdateSlot> = entry.borrow_mut();
slot.set_removed(true);
slot.set_callback(None);
}
}
pub fn cleanup_all() {
ensure_handler_registry_mut().clear();
ensure_signal_update_registry_mut().clear();
clear_delegated_events();
set_signal_update_listener_registered(false);
NEXT_EUV_ID.store(0, Ordering::Relaxed);
NEXT_EUV_DYNAMIC_ID.store(0, Ordering::Relaxed);
}
#[allow(unused_variables)]
pub(crate) fn cleanup_text_signal_listeners(text: &Text) {}
#[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: Cow<'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)]
pub(crate) fn clear_delegated_events() {
unsafe {
if let Some(set) = (*DELEGATED_EVENTS.get_0().get()).as_mut() {
set.clear();
}
}
}
#[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 is_signal_update_listener_registered() -> bool {
unsafe { *SIGNAL_UPDATE_LISTENER_REGISTERED.get_0().get() }
}
#[allow(static_mut_refs)]
pub(crate) fn set_signal_update_listener_registered(value: bool) {
unsafe {
*SIGNAL_UPDATE_LISTENER_REGISTERED.get_0().get() = value;
}
}