mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Remove support for element listener magical closures (#782)
This commit is contained in:
parent
f48bc90edb
commit
0e8ffcc54c
@ -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(
|
||||
|
||||
@ -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<TagAttribute>,
|
||||
pub listeners: Vec<(Ident, TokenStream)>,
|
||||
pub listeners: Vec<TagAttribute>,
|
||||
pub classes: Option<ClassesForm>,
|
||||
pub value: Option<Expr>,
|
||||
pub kind: Option<Expr>,
|
||||
@ -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<TagAttribute>) -> Vec<TagListener> {
|
||||
fn drain_listeners(attrs: &mut Vec<TagAttribute>) -> Vec<TagAttribute> {
|
||||
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
|
||||
|
||||
@ -30,9 +30,7 @@ fn compile_fail() {
|
||||
html! { <a href=() /> };
|
||||
|
||||
html! { <input onclick=1 /> };
|
||||
html! { <input onclick=|| () /> };
|
||||
html! { <input onclick=|a, b| () /> };
|
||||
html! { <input onclick=|a: String| () /> };
|
||||
html! { <input onclick=Callback::from(|a: String| ()) /> };
|
||||
|
||||
html! { <input string=NotToString /> };
|
||||
|
||||
|
||||
@ -102,28 +102,10 @@ error: only one `class` attribute allowed
|
||||
23 | html! { <div class="first" class="second" /> };
|
||||
| ^^^^^
|
||||
|
||||
error: there must be one closure argument
|
||||
--> $DIR/html-tag-fail.rs:33:28
|
||||
|
|
||||
33 | html! { <input onclick=|| () /> };
|
||||
| ^^
|
||||
|
||||
error: there must be one closure argument
|
||||
--> $DIR/html-tag-fail.rs:34:28
|
||||
|
|
||||
34 | html! { <input onclick=|a, b| () /> };
|
||||
| ^^^^^^
|
||||
|
||||
error: invalid closure argument
|
||||
--> $DIR/html-tag-fail.rs:35:28
|
||||
|
|
||||
35 | html! { <input onclick=|a: String| () /> };
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: only one `ref` attribute allowed
|
||||
--> $DIR/html-tag-fail.rs:40:27
|
||||
--> $DIR/html-tag-fail.rs:38:27
|
||||
|
|
||||
40 | html! { <input ref=() ref=() /> };
|
||||
38 | html! { <input ref=() ref=() /> };
|
||||
| ^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
@ -193,13 +175,22 @@ error[E0308]: mismatched types
|
||||
= note: expected type `yew::callback::Callback<stdweb::webapi::events::mouse::ClickEvent>`
|
||||
found type `{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/html-tag-fail.rs:33:20
|
||||
|
|
||||
33 | html! { <input onclick=Callback::from(|a: String| ()) /> };
|
||||
| ^^^^^^^ expected struct `stdweb::webapi::events::mouse::ClickEvent`, found struct `std::string::String`
|
||||
|
|
||||
= note: expected type `yew::callback::Callback<stdweb::webapi::events::mouse::ClickEvent>`
|
||||
found type `yew::callback::Callback<std::string::String>`
|
||||
|
||||
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! { <input string=NotToString /> };
|
||||
35 | html! { <input string=NotToString /> };
|
||||
| ^^^^^^^^^^^ 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! { <input ref=() /> };
|
||||
37 | html! { <input ref=() /> };
|
||||
| ^^ expected struct `yew::html::NodeRef`, found ()
|
||||
|
|
||||
= note: expected type `yew::html::NodeRef`
|
||||
|
||||
@ -37,7 +37,6 @@ pass_helper! {
|
||||
</svg>
|
||||
<img class=("avatar", "hidden") src="http://pic.com" />
|
||||
<img class="avatar hidden", />
|
||||
<button onclick=|e| panic!(e) />
|
||||
<button onclick=&onclick />
|
||||
<button onclick=onclick />
|
||||
<a href="http://google.com" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user