use serde::Serialize;
use wasm_bindgen::JsValue;
use web_sys::{CustomEvent, CustomEventInit, Element};
use crate::refs;
use crate::scope::{current_el, current_scope_id};
use crate::tick;
pub trait Emit {
fn event_name(&self) -> &'static str;
fn to_detail(&self) -> Result<JsValue, serde_wasm_bindgen::Error>;
fn event_names() -> &'static [&'static str]
where
Self: Sized;
fn from_event(name: &str, detail: JsValue) -> Option<Self>
where
Self: Sized;
}
pub fn emit<T: Serialize>(name: &str, detail: T) {
let Some(el) = current_el() else { return };
emit_from(&el, name, detail);
}
pub fn emit_from_host<T: Serialize>(name: &str, detail: T) {
let Some(el) = current_el() else { return };
let Some(host) = crate::directives::teleport::host_of(&el) else {
return;
};
emit_from(&host, name, detail);
}
pub fn emit_model<T: Serialize>(value: T) {
let Some(scope) = current_scope_id() else {
return;
};
let root_el = crate::model_runtime::emit_target(scope).or_else(|| refs::get_on(scope, "root"));
let Some(root_el) = root_el else { return };
emit_from(&root_el, "pp:update:model", value);
}
pub fn emit_model_field<T: Serialize>(field: &str, value: T) {
let Some(scope) = current_scope_id() else {
return;
};
let root_el = crate::model_runtime::emit_target(scope).or_else(|| refs::get_on(scope, "root"));
let Some(root_el) = root_el else { return };
emit_from(&root_el, &format!("pp:update:{field}"), value);
}
pub fn emit_event<E: Emit>(event: E) {
let Some(el) = current_el() else { return };
emit_event_from(&el, event);
}
pub fn emit_event_from<E: Emit>(el: &Element, event: E) {
let name = event.event_name();
let detail_js = match event.to_detail() {
Ok(v) => v,
Err(_) => return,
};
let el = el.clone();
let name = name.to_string();
tick::next(move || {
let init = CustomEventInit::new();
init.set_bubbles(true);
init.set_detail(&detail_js);
if let Ok(ev) = CustomEvent::new_with_event_init_dict(&name, &init) {
let _ = el.dispatch_event(&ev);
}
});
}
pub fn emit_raw<T: Serialize>(name: &str, detail: T) {
emit(name, detail);
}
pub fn emit_raw_from<T: Serialize>(el: &Element, name: &str, detail: T) {
emit_from(el, name, detail);
}
pub fn emit_from<T: Serialize>(el: &Element, name: &str, detail: T) {
let detail_js: JsValue = match serde_wasm_bindgen::to_value(&detail) {
Ok(v) => v,
Err(_) => return,
};
let el = el.clone();
let name = name.to_string();
tick::next(move || {
let init = CustomEventInit::new();
init.set_bubbles(true);
init.set_detail(&detail_js);
if let Ok(ev) = CustomEvent::new_with_event_init_dict(&name, &init) {
let _ = el.dispatch_event(&ev);
}
});
}
pub fn emit_cancelable<T: Serialize>(name: &str, detail: T) -> bool {
let Some(el) = current_el() else { return false };
emit_cancelable_from(&el, name, detail)
}
pub fn emit_cancelable_from<T: Serialize>(el: &Element, name: &str, detail: T) -> bool {
let Ok(detail_js) = serde_wasm_bindgen::to_value(&detail) else {
return false;
};
let init = CustomEventInit::new();
init.set_bubbles(true);
init.set_cancelable(true);
init.set_detail(&detail_js);
let Ok(ev) = CustomEvent::new_with_event_init_dict(name, &init) else {
return false;
};
let _ = el.dispatch_event(&ev);
ev.default_prevented()
}