Adding in event_with_options and global_event_with_options
This commit is contained in:
parent
6d43c4baa1
commit
ca54166f10
|
@ -7,32 +7,24 @@ use web_sys::{HtmlElement, Element, Node, Window, History, Document, Text, Comme
|
|||
#[wasm_bindgen(inline_js = "
|
||||
export function set_property(obj, name, value) { obj[name] = value; }
|
||||
|
||||
export function add_event(elem, name, f) {
|
||||
export function add_event(elem, name, capture, passive, f) {
|
||||
elem.addEventListener(name, f, {
|
||||
capture: true,
|
||||
capture,
|
||||
passive,
|
||||
once: false,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
export function add_event_once(elem, name, f) {
|
||||
elem.addEventListener(name, f, {
|
||||
capture: true,
|
||||
once: true,
|
||||
passive: true,
|
||||
once: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function add_event_preventable(elem, name, f) {
|
||||
elem.addEventListener(name, f, {
|
||||
capture: true,
|
||||
once: false,
|
||||
passive: false
|
||||
});
|
||||
}
|
||||
|
||||
export function remove_event(elem, name, f) {
|
||||
elem.removeEventListener(name, f, true);
|
||||
export function remove_event(elem, name, capture, f) {
|
||||
elem.removeEventListener(name, f, capture);
|
||||
}
|
||||
")]
|
||||
extern "C" {
|
||||
|
@ -41,10 +33,9 @@ extern "C" {
|
|||
pub(crate) fn set_property(obj: &JsValue, name: &str, value: &JsValue);
|
||||
|
||||
// TODO replace with gloo-events
|
||||
pub(crate) fn add_event(elem: &EventTarget, name: &str, f: &Function);
|
||||
pub(crate) fn add_event(elem: &EventTarget, name: &str, capture: bool, passive: bool, f: &Function);
|
||||
pub(crate) fn add_event_once(elem: &EventTarget, name: &str, f: &Function);
|
||||
pub(crate) fn add_event_preventable(elem: &EventTarget, name: &str, f: &Function);
|
||||
pub(crate) fn remove_event(elem: &EventTarget, name: &str, f: &Function);
|
||||
pub(crate) fn remove_event(elem: &EventTarget, name: &str, capture: bool, f: &Function);
|
||||
}
|
||||
|
||||
|
||||
|
|
69
src/dom.rs
69
src/dom.rs
|
@ -18,7 +18,7 @@ use crate::callbacks::Callbacks;
|
|||
use crate::traits::*;
|
||||
use crate::operations;
|
||||
use crate::operations::{for_each, spawn_future};
|
||||
use crate::utils::{EventListener, on, on_preventable, ValueDiscard, FnDiscard};
|
||||
use crate::utils::{EventListener, on, ValueDiscard, FnDiscard};
|
||||
|
||||
|
||||
pub struct RefFn<A, B, C> where B: ?Sized, C: Fn(&A) -> &B {
|
||||
|
@ -408,6 +408,38 @@ fn set_property<A, B, C>(element: &A, name: &B, value: C) where A: AsRef<JsValue
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct EventOptions {
|
||||
pub bubbles: bool,
|
||||
pub preventable: bool,
|
||||
}
|
||||
|
||||
impl EventOptions {
|
||||
pub fn bubbles() -> Self {
|
||||
Self {
|
||||
bubbles: true,
|
||||
preventable: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preventable() -> Self {
|
||||
Self {
|
||||
bubbles: false,
|
||||
preventable: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EventOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bubbles: false,
|
||||
preventable: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO better warning message for must_use
|
||||
#[must_use]
|
||||
pub struct DomBuilder<A> {
|
||||
|
@ -445,17 +477,19 @@ impl<A> DomBuilder<A> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn _event<T, F>(&mut self, element: EventTarget, listener: F)
|
||||
fn _event<T, F>(&mut self, element: EventTarget, options: &EventOptions, listener: F)
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
self.callbacks.after_remove(on(element, listener));
|
||||
self.callbacks.after_remove(on(element, options, listener));
|
||||
}
|
||||
|
||||
// TODO add this to the StylesheetBuilder and ClassBuilder too
|
||||
#[inline]
|
||||
fn _event_preventable<T, F>(&mut self, element: EventTarget, listener: F)
|
||||
pub fn global_event_with_options<T, F>(mut self, options: &EventOptions, listener: F) -> Self
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
self.callbacks.after_remove(on_preventable(element, listener));
|
||||
self._event(bindings::window_event_target(), options, listener);
|
||||
self
|
||||
}
|
||||
|
||||
// TODO add this to the StylesheetBuilder and ClassBuilder too
|
||||
|
@ -463,17 +497,16 @@ impl<A> DomBuilder<A> {
|
|||
pub fn global_event<T, F>(mut self, listener: F) -> Self
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
self._event(bindings::window_event_target(), listener);
|
||||
self
|
||||
self.global_event_with_options(&EventOptions::default(), listener)
|
||||
}
|
||||
|
||||
// TODO add this to the StylesheetBuilder and ClassBuilder too
|
||||
#[deprecated(since = "0.5.21", note = "Use global_event_with_options instead")]
|
||||
#[inline]
|
||||
pub fn global_event_preventable<T, F>(mut self, listener: F) -> Self
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
self._event_preventable(bindings::window_event_target(), listener);
|
||||
self
|
||||
self.global_event_with_options(&EventOptions::preventable(), listener)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -598,21 +631,27 @@ impl<A> DomBuilder<A> where A: AsRef<JsValue> {
|
|||
|
||||
impl<A> DomBuilder<A> where A: AsRef<EventTarget> {
|
||||
#[inline]
|
||||
pub fn event<T, F>(mut self, listener: F) -> Self
|
||||
pub fn event_with_options<T, F>(mut self, options: &EventOptions, listener: F) -> Self
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
// TODO can this clone be avoided ?
|
||||
self._event(self.element.as_ref().clone(), listener);
|
||||
self._event(self.element.as_ref().clone(), options, listener);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn event_preventable<T, F>(mut self, listener: F) -> Self
|
||||
pub fn event<T, F>(self, listener: F) -> Self
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
// TODO can this clone be avoided ?
|
||||
self._event_preventable(self.element.as_ref().clone(), listener);
|
||||
self
|
||||
self.event_with_options(&EventOptions::default(), listener)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.5.21", note = "Use event_with_options instead")]
|
||||
#[inline]
|
||||
pub fn event_preventable<T, F>(self, listener: F) -> Self
|
||||
where T: StaticEvent,
|
||||
F: FnMut(T) + 'static {
|
||||
self.event_with_options(&EventOptions::preventable(), listener)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use once_cell::sync::Lazy;
|
|||
use futures_signals::signal::{Mutable, ReadOnlyMutable};
|
||||
|
||||
use crate::bindings;
|
||||
use crate::dom::{Dom, DomBuilder};
|
||||
use crate::dom::{Dom, DomBuilder, EventOptions};
|
||||
use crate::utils::EventListener;
|
||||
use crate::events;
|
||||
|
||||
|
@ -34,7 +34,7 @@ impl CurrentUrl {
|
|||
let value = Mutable::new(String::from(bindings::current_url()));
|
||||
|
||||
// TODO clean this up somehow ?
|
||||
let _ = EventListener::new(bindings::window_event_target(), "popstate", {
|
||||
let _ = EventListener::new(bindings::window_event_target(), "popstate", &EventOptions::default(), {
|
||||
let value = value.clone();
|
||||
move |_| {
|
||||
change_url(&value);
|
||||
|
|
35
src/utils.rs
35
src/utils.rs
|
@ -6,6 +6,7 @@ use discard::Discard;
|
|||
use web_sys::{EventTarget, Event};
|
||||
|
||||
use crate::bindings;
|
||||
use crate::dom::EventOptions;
|
||||
use crate::traits::StaticEvent;
|
||||
|
||||
|
||||
|
@ -13,29 +14,22 @@ use crate::traits::StaticEvent;
|
|||
pub(crate) struct EventListener {
|
||||
elem: EventTarget,
|
||||
name: &'static str,
|
||||
capture: bool,
|
||||
closure: Option<Closure<dyn FnMut(&Event)>>,
|
||||
}
|
||||
|
||||
// TODO should these inline ?
|
||||
impl EventListener {
|
||||
#[inline]
|
||||
pub(crate) fn new<F>(elem: EventTarget, name: &'static str, callback: F) -> Self where F: FnMut(&Event) + 'static {
|
||||
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);
|
||||
|
||||
bindings::add_event(&elem, name, closure.as_ref().unchecked_ref());
|
||||
let capture = !options.bubbles;
|
||||
|
||||
Self { elem, name, closure: Some(closure) }
|
||||
}
|
||||
bindings::add_event(&elem, name, capture, !options.preventable, closure.as_ref().unchecked_ref());
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new_preventable<F>(elem: EventTarget, name: &'static str, 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);
|
||||
|
||||
bindings::add_event_preventable(&elem, name, closure.as_ref().unchecked_ref());
|
||||
|
||||
Self { elem, name, closure: Some(closure) }
|
||||
Self { elem, name, capture, closure: Some(closure) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -45,7 +39,7 @@ impl EventListener {
|
|||
|
||||
bindings::add_event_once(&elem, name, closure.as_ref().unchecked_ref());
|
||||
|
||||
Self { elem, name, closure: Some(closure) }
|
||||
Self { elem, name, capture: true, closure: Some(closure) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,25 +57,16 @@ impl Discard for EventListener {
|
|||
#[inline]
|
||||
fn discard(mut self) {
|
||||
let closure = self.closure.take().unwrap_throw();
|
||||
bindings::remove_event(&self.elem, &self.name, closure.as_ref().unchecked_ref());
|
||||
bindings::remove_event(&self.elem, &self.name, self.capture, closure.as_ref().unchecked_ref());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn on<E, F>(element: EventTarget, mut callback: F) -> EventListener
|
||||
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, move |e| {
|
||||
callback(E::unchecked_from_event(e.clone()));
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn on_preventable<E, F>(element: EventTarget, mut callback: F) -> EventListener
|
||||
where E: StaticEvent,
|
||||
F: FnMut(E) + 'static {
|
||||
EventListener::new_preventable(element, E::EVENT_TYPE, move |e| {
|
||||
EventListener::new(element, E::EVENT_TYPE, options, move |e| {
|
||||
callback(E::unchecked_from_event(e.clone()));
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue