use std::mem::ManuallyDrop;
use discard::Discard;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::{intern, JsCast, UnwrapThrowExt};
use web_sys::{Event, EventTarget};
use crate::bindings;
use crate::dom::EventOptions;
use crate::traits::StaticEvent;
pub(crate) struct EventListener {
elem: EventTarget,
name: &'static str,
capture: bool,
closure: Option<Closure<dyn FnMut(&Event)>>,
}
impl EventListener {
#[inline]
pub(crate) fn new<F>(
elem: EventTarget,
name: &'static str,
options: &EventOptions,
callback: F,
) -> Self
where
F: FnMut(&Event) + 'static,
{
let closure = Closure::wrap(Box::new(callback) as Box<dyn FnMut(&Event)>);
let name: &'static str = intern(name);
let capture = !options.bubbles;
bindings::add_event(
&elem,
name,
capture,
!options.preventable,
closure.as_ref().unchecked_ref(),
);
Self {
elem,
name,
capture,
closure: Some(closure),
}
}
#[inline]
pub(crate) fn once<F>(elem: EventTarget, name: &'static str, callback: F) -> Self
where
F: FnOnce(&Event) + 'static,
{
let closure = Closure::once(callback);
let name: &'static str = intern(name);
bindings::add_event_once(&elem, name, closure.as_ref().unchecked_ref());
Self {
elem,
name,
capture: true,
closure: Some(closure),
}
}
}
impl Drop for EventListener {
#[inline]
fn drop(&mut self) {
if let Some(closure) = self.closure.take() {
closure.forget();
}
}
}
impl Discard for EventListener {
#[inline]
fn discard(mut self) {
let closure = self.closure.take().unwrap_throw();
bindings::remove_event(
&self.elem,
&self.name,
self.capture,
closure.as_ref().unchecked_ref(),
);
}
}
#[inline]
pub(crate) fn on<E, F>(
element: EventTarget,
options: &EventOptions,
mut callback: F,
) -> EventListener
where
E: StaticEvent,
F: FnMut(E) + 'static,
{
EventListener::new(element, E::EVENT_TYPE, options, move |e| {
callback(E::unchecked_from_event(e.clone()));
})
}
pub(crate) struct ValueDiscard<A>(ManuallyDrop<A>);
impl<A> ValueDiscard<A> {
#[inline]
pub(crate) fn new(value: A) -> Self {
ValueDiscard(ManuallyDrop::new(value))
}
}
impl<A> Discard for ValueDiscard<A> {
#[inline]
fn discard(self) {
ManuallyDrop::into_inner(self.0);
}
}
pub(crate) struct FnDiscard<A>(A);
impl<A> FnDiscard<A>
where
A: FnOnce(),
{
#[inline]
pub(crate) fn new(f: A) -> Self {
FnDiscard(f)
}
}
impl<A> Discard for FnDiscard<A>
where
A: FnOnce(),
{
#[inline]
fn discard(self) {
self.0();
}
}