From fac220fd64274a6cda4e5b34fefeab7a5b936b82 Mon Sep 17 00:00:00 2001 From: Alexander Mescheryakov Date: Thu, 20 Jan 2022 22:30:36 +0300 Subject: [PATCH] Fix add a listener to VTag when the listeners is None (#2375) * Fix add listener and remove unused listener code * Format code --- packages/yew/src/html/listener/macros.rs | 64 ----------------------- packages/yew/src/virtual_dom/listeners.rs | 32 ------------ packages/yew/src/virtual_dom/vtag.rs | 19 ++++--- 3 files changed, 12 insertions(+), 103 deletions(-) delete mode 100644 packages/yew/src/html/listener/macros.rs diff --git a/packages/yew/src/html/listener/macros.rs b/packages/yew/src/html/listener/macros.rs deleted file mode 100644 index 32eee2cfc..000000000 --- a/packages/yew/src/html/listener/macros.rs +++ /dev/null @@ -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, - } - - impl Wrapper { - /// Create a wrapper for an event-typed callback - pub fn new(callback: Callback) -> Self { - Wrapper { callback } - } - - #[doc(hidden)] - #[inline] - pub fn __macro_new(callback: impl IntoEventCallback) -> Option> { - 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) - } - } - } - } - )*}; -} diff --git a/packages/yew/src/virtual_dom/listeners.rs b/packages/yew/src/virtual_dom/listeners.rs index 7a9c0c0f5..0506ec680 100644 --- a/packages/yew/src/virtual_dom/listeners.rs +++ b/packages/yew/src/virtual_dom/listeners.rs @@ -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() { - let (link, el) = init::("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; diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 01d425ca5..e524e43c3 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -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) -> 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, } }