enabled the liveview history by default if the liveview feature is enabled in the router

This commit is contained in:
Evan Almloff committed 2023-12-20 09:53:41 -06:00
1 parent cd019db9ef
commit 3feee729bc
3 files changed
+65 -38

No files matched your search

+24 -17
View File
@@ -54,10 +54,7 @@ fn main() {
#[cfg(feature = "liveview")] #[cfg(feature = "liveview")]
#[component] #[component]
fn Root(cx: Scope) -> Element { fn Root(cx: Scope) -> Element {
let history = LiveviewHistory::new(cx); render! { Router::<Route> {} }
render! { Router::<Route> {
config: || RouterConfig::default().history(history),
} }
} }
#[cfg(not(feature = "liveview"))] #[cfg(not(feature = "liveview"))]
@@ -84,12 +81,19 @@ fn Route1(cx: Scope, user_id: usize, dynamic: usize, query: String, extra: Strin
"Route1{{\n\tuser_id:{user_id},\n\tdynamic:{dynamic},\n\tquery:{query},\n\textra:{extra}\n}}" "Route1{{\n\tuser_id:{user_id},\n\tdynamic:{dynamic},\n\tquery:{query},\n\textra:{extra}\n}}"
} }
Link { Link {
to: Route::Route1 { user_id: *user_id, dynamic: *dynamic, query: String::new(), extra: extra.clone() + "." }, to: Route::Route1 {
user_id: *user_id,
dynamic: *dynamic,
query: String::new(),
extra: extra.clone() + ".",
},
"Route1 with extra+\".\"" "Route1 with extra+\".\""
} }
p { "Footer" } p { "Footer" }
Link { Link {
to: Route::Route3 { dynamic: String::new() }, to: Route::Route3 {
dynamic: String::new(),
},
"Home" "Home"
} }
} }
@@ -98,13 +102,13 @@ fn Route1(cx: Scope, user_id: usize, dynamic: usize, query: String, extra: Strin
#[component] #[component]
fn Route2(cx: Scope, user_id: usize) -> Element { fn Route2(cx: Scope, user_id: usize) -> Element {
render! { render! {
pre { pre { "Route2{{\n\tuser_id:{user_id}\n}}" }
"Route2{{\n\tuser_id:{user_id}\n}}"
}
(0..*user_id).map(|i| rsx!{ p { "{i}" } }), (0..*user_id).map(|i| rsx!{ p { "{i}" } }),
p { "Footer" } p { "Footer" }
Link { Link {
to: Route::Route3 { dynamic: String::new() }, to: Route::Route3 {
dynamic: String::new(),
},
"Home" "Home"
} }
} }
@@ -130,22 +134,25 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
value: "{current_route_str.read()}" value: "{current_route_str.read()}"
} }
"dynamic: {dynamic}" "dynamic: {dynamic}"
Link { Link { to: Route::Route2 { user_id: 8888 }, "hello world link" }
to: Route::Route2 { user_id: 8888 },
"hello world link"
}
button { button {
disabled: !navigator.can_go_back(), disabled: !navigator.can_go_back(),
onclick: move |_| { navigator.go_back(); }, onclick: move |_| {
navigator.go_back();
},
"go back" "go back"
} }
button { button {
disabled: !navigator.can_go_forward(), disabled: !navigator.can_go_forward(),
onclick: move |_| { navigator.go_forward(); }, onclick: move |_| {
navigator.go_forward();
},
"go forward" "go forward"
} }
button { button {
onclick: move |_| { navigator.push("https://www.google.com"); }, onclick: move |_| {
navigator.push("https://www.google.com");
},
"google link" "google link"
} }
p { "Site Map" } p { "Site Map" }
+27 -17
View File
@@ -132,6 +132,15 @@ where
} }
} }
impl<R: Routable> Default for LiveviewHistory<R>
where
<R as FromStr>::Err: std::fmt::Display,
{
fn default() -> Self {
Self::new()
}
}
impl<R: Routable> LiveviewHistory<R> impl<R: Routable> LiveviewHistory<R>
where where
<R as FromStr>::Err: std::fmt::Display, <R as FromStr>::Err: std::fmt::Display,
@@ -141,10 +150,9 @@ where
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if not in a Liveview context. /// Panics if the function is not called in a dioxus runtime with a Liveview context.
pub fn new(cx: &ScopeState) -> Self { pub fn new() -> Self {
Self::new_with_initial_path( Self::new_with_initial_path(
cx,
"/".parse().unwrap_or_else(|err| { "/".parse().unwrap_or_else(|err| {
panic!("index route does not exist:\n{}\n use LiveviewHistory::new_with_initial_path to set a custom path", err) panic!("index route does not exist:\n{}\n use LiveviewHistory::new_with_initial_path to set a custom path", err)
}), }),
@@ -156,17 +164,16 @@ where
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if not in a Liveview context. /// Panics if the function is not called in a dioxus runtime with a Liveview context.
pub fn new_with_initial_path(cx: &ScopeState, initial_path: R) -> Self { pub fn new_with_initial_path(initial_path: R) -> Self {
let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel::<Action<R>>(); let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel::<Action<R>>();
let action_rx = Arc::new(Mutex::new(action_rx)); let action_rx = Arc::new(Mutex::new(action_rx));
let timeline = Arc::new(Mutex::new(Timeline::new(initial_path))); let timeline = Arc::new(Mutex::new(Timeline::new(initial_path)));
let updater_callback: Arc<RwLock<Arc<dyn Fn() + Send + Sync>>> = let updater_callback: Arc<RwLock<Arc<dyn Fn() + Send + Sync>>> =
Arc::new(RwLock::new(Arc::new(|| {}))); Arc::new(RwLock::new(Arc::new(|| {})));
let eval_provider = cx let eval_provider =
.consume_context::<Rc<dyn EvalProvider>>() consume_context::<Rc<dyn EvalProvider>>().expect("evaluator not provided");
.expect("evaluator not provided");
let create_eval = Rc::new(move |script: &str| { let create_eval = Rc::new(move |script: &str| {
eval_provider eval_provider
@@ -175,7 +182,7 @@ where
}) as Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>; }) as Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
// Listen to server actions // Listen to server actions
cx.push_future({ push_future({
let timeline = timeline.clone(); let timeline = timeline.clone();
let action_rx = action_rx.clone(); let action_rx = action_rx.clone();
let create_eval = create_eval.clone(); let create_eval = create_eval.clone();
@@ -235,7 +242,7 @@ where
}); });
// Listen to browser actions // Listen to browser actions
cx.push_future({ push_future({
let updater = updater_callback.clone(); let updater = updater_callback.clone();
let timeline = timeline.clone(); let timeline = timeline.clone();
let create_eval = create_eval.clone(); let create_eval = create_eval.clone();
@@ -256,15 +263,16 @@ where
Option<State>, Option<State>,
Option<Session<R>>, Option<Session<R>>,
usize, usize,
)>(init_eval).expect("serializable state"); )>(init_eval)
.expect("serializable state");
let Ok(route) = R::from_str(&route.to_string()) else { let Ok(route) = R::from_str(&route.to_string()) else {
return; return;
}; };
let mut timeline = timeline.lock().expect("unpoisoned mutex"); let mut timeline = timeline.lock().expect("unpoisoned mutex");
let state = timeline.init(route.clone(), state, session, depth); let state = timeline.init(route.clone(), state, session, depth);
let state = serde_json::to_string(&state).expect("serializable state"); let state = serde_json::to_string(&state).expect("serializable state");
let session = serde_json::to_string(&timeline.session()) let session =
.expect("serializable session"); serde_json::to_string(&timeline.session()).expect("serializable session");
// Call the updater callback // Call the updater callback
(updater.read().unwrap())(); (updater.read().unwrap())();
@@ -288,22 +296,24 @@ where
Ok(event) => event, Ok(event) => event,
Err(_) => continue, Err(_) => continue,
}; };
let (route, state) = serde_json::from_value::<(String, Option<State>)>(event).expect("serializable state"); let (route, state) = serde_json::from_value::<(String, Option<State>)>(event)
.expect("serializable state");
let Ok(route) = R::from_str(&route.to_string()) else { let Ok(route) = R::from_str(&route.to_string()) else {
return; return;
}; };
let mut timeline = timeline.lock().expect("unpoisoned mutex"); let mut timeline = timeline.lock().expect("unpoisoned mutex");
let state = timeline.update(route.clone(), state); let state = timeline.update(route.clone(), state);
let state = serde_json::to_string(&state).expect("serializable state"); let state = serde_json::to_string(&state).expect("serializable state");
let session = serde_json::to_string(&timeline.session()) let session =
.expect("serializable session"); serde_json::to_string(&timeline.session()).expect("serializable session");
let _ = create_eval(&format!( let _ = create_eval(&format!(
r#" r#"
// this does not trigger a PopState event // this does not trigger a PopState event
history.replaceState({state}, "", "{route}"); history.replaceState({state}, "", "{route}");
sessionStorage.setItem("liveview", '{session}'); sessionStorage.setItem("liveview", '{session}');
"#)); "#
));
// Call the updater callback // Call the updater callback
(updater.read().unwrap())(); (updater.read().unwrap())();
+14 -4
View File
@@ -53,10 +53,15 @@ where
{ {
pub(crate) fn get_history(self) -> Box<dyn HistoryProvider<R>> { pub(crate) fn get_history(self) -> Box<dyn HistoryProvider<R>> {
self.history.unwrap_or_else(|| { self.history.unwrap_or_else(|| {
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(not(feature = "liveview"), target_arch = "wasm32", feature = "web"))]
let history = Box::<WebHistory<R>>::default(); let history = Box::<WebHistory<R>>::default();
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(all(
not(feature = "liveview"),
any(not(target_arch = "wasm32"), not(feature = "web"))
))]
let history = Box::<MemoryHistory<R>>::default(); let history = Box::<MemoryHistory<R>>::default();
#[cfg(feature = "liveview")]
let history = Box::<LiveviewHistory<R>>::default();
history history
}) })
} }
@@ -83,10 +88,15 @@ where
{ {
pub(crate) fn take_history(&mut self) -> Box<dyn AnyHistoryProvider> { pub(crate) fn take_history(&mut self) -> Box<dyn AnyHistoryProvider> {
self.history.take().unwrap_or_else(|| { self.history.take().unwrap_or_else(|| {
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(not(feature = "liveview"), target_arch = "wasm32", feature = "web"))]
let history = Box::<AnyHistoryProviderImplWrapper<R, WebHistory<R>>>::default(); let history = Box::<AnyHistoryProviderImplWrapper<R, WebHistory<R>>>::default();
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(all(
not(feature = "liveview"),
any(not(target_arch = "wasm32"), not(feature = "web"))
))]
let history = Box::<AnyHistoryProviderImplWrapper<R, MemoryHistory<R>>>::default(); let history = Box::<AnyHistoryProviderImplWrapper<R, MemoryHistory<R>>>::default();
#[cfg(feature = "liveview")]
let history = Box::<AnyHistoryProviderImplWrapper<R, LiveviewHistory<R>>>::default();
history history
}) })
} }