make RemoveEventHandler a concrete type

This commit is contained in:
Greg Johnston 2024-06-25 20:42:20 -04:00
parent 9de6c5bb4a
commit 598c59b9c2
4 changed files with 31 additions and 15 deletions

View file

@ -93,13 +93,13 @@ impl<E, T, R> From<E> for Targeted<E, T, R> {
}
}
pub fn on<E, R, F>(event: E, cb: F) -> On<E, F, R>
pub fn on<E, F, R>(event: E, cb: F) -> On<E, F, R>
where
F: FnMut(E::EventType) + 'static,
E: EventDescriptor + Send + 'static,
E::EventType: 'static,
R: DomRenderer,
E::EventType: From<R::Event>,
R: DomRenderer,
{
On {
event,
@ -212,7 +212,7 @@ where
{
const MIN_LENGTH: usize = 0;
// a function that can be called once to remove the event listener
type State = (R::Element, Option<Box<dyn FnOnce(&R::Element)>>);
type State = (R::Element, Option<RemoveEventHandler<R::Element>>);
type Cloneable = On<E, SharedEventCallback<E::EventType>, R>;
type CloneableOwned = On<E, SharedEventCallback<E::EventType>, R>;
@ -247,7 +247,7 @@ where
fn rebuild(self, state: &mut Self::State) {
let (el, prev_cleanup) = state;
if let Some(prev) = prev_cleanup.take() {
prev(el);
(prev.into_inner())(el);
}
*prev_cleanup = Some(self.attach(el));
}

View file

@ -1,4 +1,4 @@
use super::{CastFrom, DomRenderer, Renderer};
use super::{CastFrom, DomRenderer, RemoveEventHandler, Renderer};
use crate::{
dom::{document, window},
ok_or_debug, or_debug,
@ -125,7 +125,7 @@ impl DomRenderer for Dom {
el: &Self::Element,
name: &str,
cb: Box<dyn FnMut(Self::Event)>,
) -> Box<dyn FnOnce(&Self::Element) + Send> {
) -> RemoveEventHandler<Self::Element> {
let cb = wasm_bindgen::closure::Closure::wrap(cb);
let name = intern(name);
or_debug!(
@ -138,10 +138,10 @@ impl DomRenderer for Dom {
);
// return the remover
Box::new({
RemoveEventHandler::new({
let name = name.to_owned();
let cb = send_wrapper::SendWrapper::new(cb);
move |el| {
move |el: &Self::Element| {
or_debug!(
el.remove_event_listener_with_callback(
intern(&name),
@ -171,7 +171,7 @@ impl DomRenderer for Dom {
name: Cow<'static, str>,
delegation_key: Cow<'static, str>,
cb: Box<dyn FnMut(Self::Event)>,
) -> Box<dyn FnOnce(&Self::Element) + Send> {
) -> RemoveEventHandler<Self::Element> {
let cb = Closure::wrap(cb);
let key = intern(&delegation_key);
or_debug!(
@ -249,10 +249,10 @@ impl DomRenderer for Dom {
});
// return the remover
Box::new({
RemoveEventHandler::new({
let key = key.to_owned();
let cb = send_wrapper::SendWrapper::new(cb);
move |el| {
move |el: &Self::Element| {
drop(cb.take());
or_debug!(
js_sys::Reflect::delete_property(

View file

@ -4,7 +4,7 @@
//!
//! Do not use this for anything real.
use super::{CastFrom, DomRenderer, Renderer};
use super::{CastFrom, DomRenderer, RemoveEventHandler, Renderer};
use crate::{
html::element::{CreateElement, ElementType},
view::Mountable,
@ -225,7 +225,7 @@ impl DomRenderer for MockDom {
el: &Self::Element,
name: &str,
cb: Box<dyn FnMut(Self::Event)>,
) -> Box<dyn FnOnce(&Self::Element) + Send> {
) -> RemoveEventHandler<Self::Element> {
todo!()
}
@ -234,7 +234,7 @@ impl DomRenderer for MockDom {
name: Cow<'static, str>,
delegation_key: Cow<'static, str>,
cb: Box<dyn FnMut(Self::Event)>,
) -> Box<dyn FnOnce(&Self::Element) + Send> {
) -> RemoveEventHandler<Self::Element> {
todo!()
}

View file

@ -127,7 +127,23 @@ pub trait Renderer: Send + Sized + Debug + 'static {
}
/// A function that can be called to remove an event handler from an element after it has been added.
pub type RemoveEventHandler<T> = Box<dyn FnOnce(&T) + Send>;
#[must_use = "This will invalidate the event handler when it is dropped. You \
should store it in some other data structure to clean it up \
later to avoid dropping it immediately, or leak it with \
std::mem::forget() to never drop it."]
pub struct RemoveEventHandler<T>(Box<dyn FnOnce(&T) + Send + Sync>);
impl<T> RemoveEventHandler<T> {
/// Creates a new container with a function that will be called when it is dropped.
pub(crate) fn new(remove: impl FnOnce(&T) + Send + Sync + 'static) -> Self {
Self(Box::new(remove))
}
pub(crate) fn into_inner(self) -> Box<dyn FnOnce(&T) + Send + Sync> {
self.0
}
}
/// Additional rendering behavior that applies only to DOM nodes.
pub trait DomRenderer: Renderer {
/// Generic event type, from which any specific event can be converted.