65 lines
1.7 KiB
Rust
65 lines
1.7 KiB
Rust
use futures::channel::mpsc;
|
|
use futures::stream::Stream;
|
|
use gloo::events::EventListener;
|
|
use std::{
|
|
future::Future,
|
|
pin::Pin,
|
|
task::{Context, Poll},
|
|
};
|
|
use wasm_bindgen::prelude::*;
|
|
use web_sys::{EventTarget, Node};
|
|
|
|
// From: https://docs.rs/gloo-events/latest/gloo_events/struct.EventListener.html
|
|
|
|
pub struct OnClick {
|
|
receiver: mpsc::UnboundedReceiver<()>,
|
|
// Automatically removed from the DOM on drop.
|
|
listener: EventListener,
|
|
}
|
|
|
|
impl OnClick {
|
|
pub fn new(target: &EventTarget) -> Self {
|
|
Self::new_with_filter(target, |_| true)
|
|
}
|
|
|
|
pub fn new_with_filter<F>(target: &EventTarget, filter: F) -> Self
|
|
where
|
|
F: Fn(&Node) -> bool + 'static,
|
|
{
|
|
let (sender, receiver) = mpsc::unbounded();
|
|
|
|
let listener = EventListener::new(target, "click", move |event| {
|
|
let mut send = true;
|
|
if let Some(event_target) = event.target() {
|
|
if let Some(node) = event_target.dyn_ref::<Node>() {
|
|
send = filter(node);
|
|
}
|
|
}
|
|
if send {
|
|
sender.unbounded_send(()).unwrap_throw();
|
|
}
|
|
});
|
|
|
|
Self { receiver, listener }
|
|
}
|
|
}
|
|
|
|
// Multiple clicks.
|
|
impl Stream for OnClick {
|
|
type Item = ();
|
|
|
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
|
Pin::new(&mut self.receiver).poll_next(cx)
|
|
}
|
|
}
|
|
|
|
// Just one click.
|
|
impl Future for OnClick {
|
|
type Output = ();
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
Pin::new(&mut self.receiver)
|
|
.poll_next(cx)
|
|
.map(Option::unwrap)
|
|
}
|
|
}
|