diff --git a/crates/macro/src/html_tree/html_tag/mod.rs b/crates/macro/src/html_tree/html_tag/mod.rs index 98a9aa053f4..6db099320ac 100644 --- a/crates/macro/src/html_tree/html_tag/mod.rs +++ b/crates/macro/src/html_tree/html_tag/mod.rs @@ -149,7 +149,10 @@ impl ToTokens for HtmlTag { #vtag.node_ref = #node_ref; } }); - let listeners = listeners.iter().map(|(name, callback)| { + let listeners = listeners.iter().map(|listener| { + let name = &listener.label.name; + let callback = &listener.value; + quote_spanned! {name.span()=> { ::yew::html::#name::Wrapper::new( <::yew::virtual_dom::vtag::VTag<_> as ::yew::virtual_dom::Transformer<_, _, _>>::transform( diff --git a/crates/macro/src/html_tree/html_tag/tag_attributes.rs b/crates/macro/src/html_tree/html_tag/tag_attributes.rs index 5a6dbb3e933..543b29c693b 100644 --- a/crates/macro/src/html_tree/html_tag/tag_attributes.rs +++ b/crates/macro/src/html_tree/html_tag/tag_attributes.rs @@ -1,15 +1,14 @@ use crate::html_tree::HtmlProp as TagAttribute; use crate::PeekValue; use lazy_static::lazy_static; -use proc_macro2::TokenStream; -use quote::{quote, quote_spanned, ToTokens}; -use std::collections::HashMap; +use std::collections::HashSet; +use std::iter::FromIterator; use syn::parse::{Parse, ParseStream, Result as ParseResult}; -use syn::{Expr, ExprClosure, ExprTuple, Ident, Pat}; +use syn::{Expr, ExprTuple}; pub struct TagAttributes { pub attributes: Vec, - pub listeners: Vec<(Ident, TokenStream)>, + pub listeners: Vec, pub classes: Option, pub value: Option, pub kind: Option, @@ -25,75 +24,67 @@ pub enum ClassesForm { Single(Expr), } -pub struct TagListener { - name: Ident, - handler: Expr, - event_name: String, -} - lazy_static! { - static ref LISTENER_MAP: HashMap<&'static str, &'static str> = { - let mut m = HashMap::new(); - m.insert("onclick", "ClickEvent"); - m.insert("ondoubleclick", "DoubleClickEvent"); - m.insert("onkeypress", "KeyPressEvent"); - m.insert("onkeydown", "KeyDownEvent"); - m.insert("onkeyup", "KeyUpEvent"); - m.insert("onmousedown", "MouseDownEvent"); - m.insert("onmousemove", "MouseMoveEvent"); - m.insert("onmouseout", "MouseOutEvent"); - m.insert("onmouseenter", "MouseEnterEvent"); - m.insert("onmouseleave", "MouseLeaveEvent"); - m.insert("onmousewheel", "MouseWheelEvent"); - m.insert("onmouseover", "MouseOverEvent"); - m.insert("onmouseup", "MouseUpEvent"); - m.insert("ontouchcancel", "TouchCancel"); - m.insert("ontouchend", "TouchEnd"); - m.insert("ontouchenter", "TouchEnter"); - m.insert("ontouchmove", "TouchMove"); - m.insert("ontouchstart", "TouchStart"); - m.insert("ongotpointercapture", "GotPointerCaptureEvent"); - m.insert("onlostpointercapture", "LostPointerCaptureEvent"); - m.insert("onpointercancel", "PointerCancelEvent"); - m.insert("onpointerdown", "PointerDownEvent"); - m.insert("onpointerenter", "PointerEnterEvent"); - m.insert("onpointerleave", "PointerLeaveEvent"); - m.insert("onpointermove", "PointerMoveEvent"); - m.insert("onpointerout", "PointerOutEvent"); - m.insert("onpointerover", "PointerOverEvent"); - m.insert("onpointerup", "PointerUpEvent"); - m.insert("onscroll", "ScrollEvent"); - m.insert("onblur", "BlurEvent"); - m.insert("onfocus", "FocusEvent"); - m.insert("onsubmit", "SubmitEvent"); - m.insert("oninput", "InputData"); - m.insert("onchange", "ChangeData"); - m.insert("ondrag", "DragEvent"); - m.insert("ondragstart", "DragStartEvent"); - m.insert("ondragend", "DragEndEvent"); - m.insert("ondragenter", "DragEnterEvent"); - m.insert("ondragleave", "DragLeaveEvent"); - m.insert("ondragover", "DragOverEvent"); - m.insert("ondragexit", "DragExitEvent"); - m.insert("ondrop", "DragDropEvent"); - m.insert("oncontextmenu", "ContextMenuEvent"); - m + static ref LISTENER_SET: HashSet<&'static str> = { + HashSet::from_iter( + vec![ + "onclick", + "ondoubleclick", + "onkeypress", + "onkeydown", + "onkeyup", + "onmousedown", + "onmousemove", + "onmouseout", + "onmouseenter", + "onmouseleave", + "onmousewheel", + "onmouseover", + "onmouseup", + "ontouchcancel", + "ontouchend", + "ontouchenter", + "ontouchmove", + "ontouchstart", + "ongotpointercapture", + "onlostpointercapture", + "onpointercancel", + "onpointerdown", + "onpointerenter", + "onpointerleave", + "onpointermove", + "onpointerout", + "onpointerover", + "onpointerup", + "onscroll", + "onblur", + "onfocus", + "onsubmit", + "oninput", + "onchange", + "ondrag", + "ondragstart", + "ondragend", + "ondragenter", + "ondragleave", + "ondragover", + "ondragexit", + "ondrop", + "oncontextmenu", + ] + .into_iter(), + ) }; } impl TagAttributes { - fn drain_listeners(attrs: &mut Vec) -> Vec { + fn drain_listeners(attrs: &mut Vec) -> Vec { let mut i = 0; let mut drained = Vec::new(); while i < attrs.len() { let name_str = attrs[i].label.to_string(); - if let Some(event_type) = LISTENER_MAP.get(&name_str.as_str()) { - let TagAttribute { label, value } = attrs.remove(i); - drained.push(TagListener { - name: label.name, - handler: value, - event_name: event_type.to_owned().to_string(), - }); + if LISTENER_SET.contains(&name_str.as_str()) { + drained.push(attrs.remove(i)); } else { i += 1; } @@ -119,54 +110,6 @@ impl TagAttributes { expr => ClassesForm::Single(expr), } } - - fn map_listener(listener: TagListener) -> ParseResult<(Ident, TokenStream)> { - let TagListener { - name, - event_name, - handler, - } = listener; - - let callback: TokenStream = match handler { - Expr::Closure(closure) => { - let ExprClosure { - inputs, - body, - or1_token, - or2_token, - .. - } = closure; - - let or_span = quote! {#or1_token#or2_token}; - if inputs.len() != 1 { - return Err(syn::Error::new_spanned( - or_span, - "there must be one closure argument", - )); - } - - let var = match inputs.first().unwrap() { - Pat::Ident(pat) => Ok(pat.into_token_stream()), - Pat::Wild(pat) => Ok(pat.into_token_stream()), - _ => Err(syn::Error::new_spanned(or_span, "invalid closure argument")), - }?; - let callback = - Ident::new(&format!("__yew_{}_callback", name.to_string()), name.span()); - let segment = syn::PathSegment { - ident: Ident::new(&event_name, name.span()), - arguments: syn::PathArguments::None, - }; - - quote_spanned! {name.span()=> { - let #callback = move | #var: ::yew::events::#segment | #body; - #callback - }} - } - callback => callback.into_token_stream(), - }; - - Ok((name, callback)) - } } impl Parse for TagAttributes { @@ -178,7 +121,7 @@ impl Parse for TagAttributes { let mut listeners = Vec::new(); for listener in TagAttributes::drain_listeners(&mut attributes) { - listeners.push(TagAttributes::map_listener(listener)?); + listeners.push(listener); } // Multiple listener attributes are allowed, but no others diff --git a/tests/macro/html-tag-fail.rs b/tests/macro/html-tag-fail.rs index 2a8bda43215..8a8ebd1d6d1 100644 --- a/tests/macro/html-tag-fail.rs +++ b/tests/macro/html-tag-fail.rs @@ -30,9 +30,7 @@ fn compile_fail() { html! { }; html! { }; - html! { }; - html! { }; - html! { }; + html! { }; html! { }; diff --git a/tests/macro/html-tag-fail.stderr b/tests/macro/html-tag-fail.stderr index 147ec3cb66d..969579cd8bd 100644 --- a/tests/macro/html-tag-fail.stderr +++ b/tests/macro/html-tag-fail.stderr @@ -102,28 +102,10 @@ error: only one `class` attribute allowed 23 | html! {
}; | ^^^^^ -error: there must be one closure argument - --> $DIR/html-tag-fail.rs:33:28 - | -33 | html! { }; - | ^^ - -error: there must be one closure argument - --> $DIR/html-tag-fail.rs:34:28 - | -34 | html! { }; - | ^^^^^^ - -error: invalid closure argument - --> $DIR/html-tag-fail.rs:35:28 - | -35 | html! { }; - | ^^^^^^^^^^^ - error: only one `ref` attribute allowed - --> $DIR/html-tag-fail.rs:40:27 + --> $DIR/html-tag-fail.rs:38:27 | -40 | html! { }; +38 | html! { }; | ^^^ error[E0308]: mismatched types @@ -193,13 +175,22 @@ error[E0308]: mismatched types = note: expected type `yew::callback::Callback` found type `{integer}` +error[E0308]: mismatched types + --> $DIR/html-tag-fail.rs:33:20 + | +33 | html! { }; + | ^^^^^^^ expected struct `stdweb::webapi::events::mouse::ClickEvent`, found struct `std::string::String` + | + = note: expected type `yew::callback::Callback` + found type `yew::callback::Callback` + error[E0599]: no method named `to_string` found for type `NotToString` in the current scope - --> $DIR/html-tag-fail.rs:37:27 + --> $DIR/html-tag-fail.rs:35:27 | 3 | struct NotToString; | ------------------- method `to_string` not found for this ... -37 | html! { }; +35 | html! { }; | ^^^^^^^^^^^ method not found in `NotToString` | = note: the method `to_string` exists but the following trait bounds were not satisfied: @@ -209,9 +200,9 @@ error[E0599]: no method named `to_string` found for type `NotToString` in the cu candidate #1: `std::string::ToString` error[E0308]: mismatched types - --> $DIR/html-tag-fail.rs:39:24 + --> $DIR/html-tag-fail.rs:37:24 | -39 | html! { }; +37 | html! { }; | ^^ expected struct `yew::html::NodeRef`, found () | = note: expected type `yew::html::NodeRef` diff --git a/tests/macro/html-tag-pass.rs b/tests/macro/html-tag-pass.rs index f660b5f96f9..76ccdd3cf05 100644 --- a/tests/macro/html-tag-pass.rs +++ b/tests/macro/html-tag-pass.rs @@ -37,7 +37,6 @@ pass_helper! { -