Fix add a listener to VTag when the listeners is None (#2375)

* Fix add listener and remove unused listener code

* Format code
This commit is contained in:
Alexander Mescheryakov 2022-01-20 22:30:36 +03:00 committed by GitHub
parent a8f7113d4a
commit fac220fd64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 12 additions and 103 deletions

View File

@ -1,64 +0,0 @@
macro_rules! impl_action {
($($action:ident(name: $name:literal, event: $type:ident) -> $ret:ty => $convert:expr)*) => {$(
/// An abstract implementation of a listener.
#[doc(hidden)]
pub mod $action {
use crate::callback::Callback;
#[allow(unused_imports)]
use crate::html::{listener::*, IntoPropValue};
use crate::virtual_dom::Listener;
use gloo::events::{EventListener, EventListenerOptions};
use wasm_bindgen::JsValue;
use web_sys::{$type as WebSysType, Element, EventTarget};
use std::rc::Rc;
/// A wrapper for a callback which attaches event listeners to elements.
#[derive(Clone, Debug)]
pub struct Wrapper {
callback: Callback<Event>,
}
impl Wrapper {
/// Create a wrapper for an event-typed callback
pub fn new(callback: Callback<Event>) -> Self {
Wrapper { callback }
}
#[doc(hidden)]
#[inline]
pub fn __macro_new(callback: impl IntoEventCallback<Event>) -> Option<Rc<dyn Listener>> {
let callback = callback.into_event_callback()?;
Some(Rc::new(Self::new(callback)))
}
}
/// And event type which keeps the returned type.
pub type Event = $ret;
impl Listener for Wrapper {
fn kind(&self) -> &'static str {
stringify!($action)
}
fn attach(&self, element: &Element) -> EventListener {
let this = element.clone();
let callback = self.callback.clone();
let listener = move |
event: &web_sys::Event
| {
let event: WebSysType = JsValue::from(event).into();
callback.emit($convert(&this, event));
};
// We should only set passive event listeners for `touchstart` and `touchmove`.
// See here: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners
if $name == "touchstart" || $name == "touchmove" {
EventListener::new(&EventTarget::from(element.clone()), $name, listener)
} else {
let options = EventListenerOptions::enable_prevent_default();
EventListener::new_with_options(&EventTarget::from(element.clone()), $name, options, listener)
}
}
}
}
)*};
}

View File

@ -525,7 +525,6 @@ mod tests {
use crate::{html, html::TargetCast, AppHandle, Component, Context, Html};
use gloo_utils::document;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
#[derive(Clone)]
enum Message {
@ -655,37 +654,6 @@ mod tests {
assert_count(&el, 2);
}
async fn await_animation_frame() {
JsFuture::from(js_sys::Promise::new(&mut |resolve, _| {
gloo_utils::window()
.request_animation_frame(&resolve)
.unwrap();
}))
.await
.unwrap();
}
async fn assert_async<M: Mixin + 'static>() {
let (link, el) = init::<M>("a");
macro_rules! assert_after_click {
($c:expr) => {
el.click();
await_animation_frame().await;
assert_count(&el, $c);
};
}
assert_count(&el, 0);
assert_after_click!(1);
assert_after_click!(2);
link.send_message(Message::StopListening);
assert_after_click!(2);
}
#[test]
async fn non_bubbling_event() {
struct NonBubbling;

View File

@ -434,14 +434,19 @@ impl VTag {
/// Add event listener on the [VTag]'s [Element].
/// Returns `true` if the listener has been added, `false` otherwise.
pub fn add_listener(&mut self, listener: Rc<dyn Listener>) -> bool {
if let Listeners::Pending(listeners) = &mut self.listeners {
let mut listeners = mem::take(listeners).into_vec();
listeners.push(Some(listener));
match &mut self.listeners {
Listeners::None => {
self.set_listeners([Some(listener)].into());
true
}
Listeners::Pending(listeners) => {
let mut listeners = mem::take(listeners).into_vec();
listeners.push(Some(listener));
self.set_listeners(listeners.into_boxed_slice());
true
} else {
false
self.set_listeners(listeners.into());
true
}
Listeners::Registered(_) => false,
}
}