mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Encode Path Parameters in yew-router (#3187)
* Escape for URL in `routable_derive` * Fixed generic datatypes bug * FQN * FQN Again * remove encode_for_url from public API * fmt --------- Co-authored-by: Muhammad Hamza <muhammadhamza1311@gmail.com>
This commit is contained in:
parent
0cd979c956
commit
27f537a288
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2875,6 +2875,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
@ -3388,6 +3394,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_urlencoded",
|
||||
"tracing",
|
||||
"urlencoding",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
"web-sys",
|
||||
|
||||
@ -129,10 +129,15 @@ impl Routable {
|
||||
Fields::Unit => quote! { Self::#ident },
|
||||
Fields::Named(field) => {
|
||||
let fields = field.named.iter().map(|it| {
|
||||
//named fields have idents
|
||||
// named fields have idents
|
||||
it.ident.as_ref().unwrap()
|
||||
});
|
||||
quote! { Self::#ident { #(#fields: params.get(stringify!(#fields))?.parse().ok()?,)* } }
|
||||
quote! { Self::#ident { #(#fields: {
|
||||
let param = params.get(stringify!(#fields))?;
|
||||
let param = &*::yew_router::__macro::decode_for_url(param).ok()?;
|
||||
let param = param.parse().ok()?;
|
||||
param
|
||||
},)* } }
|
||||
}
|
||||
Fields::Unnamed(_) => unreachable!(), // already checked
|
||||
};
|
||||
@ -176,7 +181,7 @@ impl Routable {
|
||||
}
|
||||
|
||||
quote! {
|
||||
Self::#ident { #(#fields),* } => ::std::format!(#right, #(#fields = #fields),*)
|
||||
Self::#ident { #(#fields),* } => ::std::format!(#right, #(#fields = ::yew_router::__macro::encode_for_url(&::std::format!("{}", #fields))),*)
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(_) => unreachable!(), // already checked
|
||||
|
||||
@ -22,6 +22,7 @@ route-recognizer = "0.3"
|
||||
serde = "1"
|
||||
serde_urlencoded = "0.7.1"
|
||||
tracing = "0.1.37"
|
||||
urlencoding = "2.1.2"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
pub use urlencoding::{decode as decode_for_url, encode as encode_for_url};
|
||||
|
||||
use crate::utils::strip_slash_suffix;
|
||||
use crate::Routable;
|
||||
|
||||
|
||||
@ -48,3 +48,26 @@ fn router_trailing_slash() {
|
||||
AppRoute::recognize("/category/cooking-recipes/")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn router_url_encoding() {
|
||||
#[derive(Routable, Debug, Clone, PartialEq)]
|
||||
enum AppRoute {
|
||||
#[at("/")]
|
||||
Root,
|
||||
#[at("/search/:query")]
|
||||
Search { query: String },
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
yew_router::__macro::decode_for_url("/search/a%2Fb/").unwrap(),
|
||||
"/search/a/b/"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Some(AppRoute::Search {
|
||||
query: "a/b".to_string()
|
||||
}),
|
||||
AppRoute::recognize("/search/a%2Fb/")
|
||||
);
|
||||
}
|
||||
|
||||
63
packages/yew-router/tests/url_encoded_routes.rs
Normal file
63
packages/yew-router/tests/url_encoded_routes.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use yew::platform::time::sleep;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
|
||||
mod utils;
|
||||
use utils::*;
|
||||
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
#[derive(Routable, Debug, Clone, PartialEq)]
|
||||
enum AppRoute {
|
||||
#[at("/")]
|
||||
Root,
|
||||
#[at("/search/:query")]
|
||||
Search { query: String },
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn Comp() -> Html {
|
||||
let switch = move |routes: AppRoute| match routes {
|
||||
AppRoute::Root => html! {
|
||||
<>
|
||||
<h1>{ "Root" }</h1>
|
||||
<Link<AppRoute> to={AppRoute::Search { query: "a/b".to_string() }}>
|
||||
{"Click me"}
|
||||
</Link<AppRoute>>
|
||||
</>
|
||||
},
|
||||
AppRoute::Search { query } => html! {
|
||||
<p id="q">{ query }</p>
|
||||
},
|
||||
};
|
||||
html! {
|
||||
<Switch<AppRoute> render={switch} />
|
||||
}
|
||||
}
|
||||
|
||||
#[function_component(Root)]
|
||||
fn root() -> Html {
|
||||
html! {
|
||||
<BrowserRouter>
|
||||
<Comp />
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
async fn url_encoded_roundtrip() {
|
||||
yew::Renderer::<Root>::with_root(gloo::utils::document().get_element_by_id("output").unwrap())
|
||||
.render();
|
||||
sleep(Duration::ZERO).await;
|
||||
click("a");
|
||||
sleep(Duration::ZERO).await;
|
||||
let res = obtain_result_by_id("q");
|
||||
assert_eq!(res, "a/b");
|
||||
|
||||
assert_eq!(
|
||||
gloo::utils::window().location().pathname().unwrap(),
|
||||
"/search/a%2Fb"
|
||||
)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user