|
@@ -23,7 +23,6 @@ fn base_path() -> Option<&'static str> {
|
|
base_path
|
|
base_path
|
|
}
|
|
}
|
|
|
|
|
|
-#[cfg(not(feature = "serde"))]
|
|
|
|
#[allow(clippy::extra_unused_type_parameters)]
|
|
#[allow(clippy::extra_unused_type_parameters)]
|
|
fn update_scroll<R>(window: &Window, history: &History) {
|
|
fn update_scroll<R>(window: &Window, history: &History) {
|
|
let scroll = ScrollPosition::of_window(window);
|
|
let scroll = ScrollPosition::of_window(window);
|
|
@@ -32,27 +31,6 @@ fn update_scroll<R>(window: &Window, history: &History) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#[cfg(feature = "serde")]
|
|
|
|
-fn update_scroll<R: serde::Serialize + serde::de::DeserializeOwned + Routable>(
|
|
|
|
- window: &Window,
|
|
|
|
- history: &History,
|
|
|
|
-) {
|
|
|
|
- if let Some(WebHistoryState { state, .. }) = get_current::<WebHistoryState<R>>(history) {
|
|
|
|
- let scroll = ScrollPosition::of_window(window);
|
|
|
|
- let state = WebHistoryState { state, scroll };
|
|
|
|
- if let Err(err) = replace_state_with_url(history, &state, None) {
|
|
|
|
- error!(err);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(feature = "serde")]
|
|
|
|
-#[derive(serde::Deserialize, serde::Serialize)]
|
|
|
|
-struct WebHistoryState<R> {
|
|
|
|
- state: R,
|
|
|
|
- scroll: ScrollPosition,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/// A [`HistoryProvider`] that integrates with a browser via the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API).
|
|
/// A [`HistoryProvider`] that integrates with a browser via the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API).
|
|
///
|
|
///
|
|
/// # Prefix
|
|
/// # Prefix
|
|
@@ -75,21 +53,9 @@ pub struct WebHistory<R: Routable> {
|
|
phantom: std::marker::PhantomData<R>,
|
|
phantom: std::marker::PhantomData<R>,
|
|
}
|
|
}
|
|
|
|
|
|
-#[cfg(not(feature = "serde"))]
|
|
|
|
-impl<R: Routable> Default for WebHistory<R>
|
|
|
|
-where
|
|
|
|
- <R as std::str::FromStr>::Err: std::fmt::Display,
|
|
|
|
-{
|
|
|
|
- fn default() -> Self {
|
|
|
|
- Self::new(None, true)
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(feature = "serde")]
|
|
|
|
impl<R: Routable> Default for WebHistory<R>
|
|
impl<R: Routable> Default for WebHistory<R>
|
|
where
|
|
where
|
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
|
- R: serde::Serialize + serde::de::DeserializeOwned,
|
|
|
|
{
|
|
{
|
|
fn default() -> Self {
|
|
fn default() -> Self {
|
|
Self::new(None, true)
|
|
Self::new(None, true)
|
|
@@ -97,7 +63,6 @@ where
|
|
}
|
|
}
|
|
|
|
|
|
impl<R: Routable> WebHistory<R> {
|
|
impl<R: Routable> WebHistory<R> {
|
|
- #[cfg(not(feature = "serde"))]
|
|
|
|
/// Create a new [`WebHistory`].
|
|
/// Create a new [`WebHistory`].
|
|
///
|
|
///
|
|
/// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
|
/// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
|
@@ -116,47 +81,6 @@ impl<R: Routable> WebHistory<R> {
|
|
myself
|
|
myself
|
|
}
|
|
}
|
|
|
|
|
|
- #[cfg(feature = "serde")]
|
|
|
|
- /// Create a new [`WebHistory`].
|
|
|
|
- ///
|
|
|
|
- /// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
|
|
|
- /// state. It'll also set the browsers scroll restoration to `manual`.
|
|
|
|
- pub fn new(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
|
|
|
- where
|
|
|
|
- <R as std::str::FromStr>::Err: std::fmt::Display,
|
|
|
|
- R: serde::Serialize + serde::de::DeserializeOwned,
|
|
|
|
- {
|
|
|
|
- let w = window().expect("access to `window`");
|
|
|
|
- let h = w.history().expect("`window` has access to `history`");
|
|
|
|
- let document = w.document().expect("`window` has access to `document`");
|
|
|
|
-
|
|
|
|
- let myself = Self::new_inner(
|
|
|
|
- prefix,
|
|
|
|
- do_scroll_restoration,
|
|
|
|
- EventListener::new(&document, "scroll", {
|
|
|
|
- let mut last_updated = 0.0;
|
|
|
|
- move |evt| {
|
|
|
|
- // the time stamp in milliseconds
|
|
|
|
- let time_stamp = evt.time_stamp();
|
|
|
|
- // throttle the scroll event to 100ms
|
|
|
|
- if (time_stamp - last_updated) < 100.0 {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- update_scroll::<R>(&w, &h);
|
|
|
|
- last_updated = time_stamp;
|
|
|
|
- }
|
|
|
|
- }),
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- let current_route = myself.current_route();
|
|
|
|
- tracing::trace!("initial route: {:?}", current_route);
|
|
|
|
- let current_url = current_route.to_string();
|
|
|
|
- let state = myself.create_state(current_route);
|
|
|
|
- let _ = replace_state_with_url(&myself.history, &state, Some(¤t_url));
|
|
|
|
-
|
|
|
|
- myself
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
fn new_inner(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
|
fn new_inner(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
|
where
|
|
where
|
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
|
@@ -191,17 +115,10 @@ impl<R: Routable> WebHistory<R> {
|
|
.unwrap_or_default()
|
|
.unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
|
|
- #[cfg(not(feature = "serde"))]
|
|
|
|
fn create_state(&self, _state: R) -> [f64; 2] {
|
|
fn create_state(&self, _state: R) -> [f64; 2] {
|
|
let scroll = self.scroll_pos();
|
|
let scroll = self.scroll_pos();
|
|
[scroll.x, scroll.y]
|
|
[scroll.x, scroll.y]
|
|
}
|
|
}
|
|
-
|
|
|
|
- #[cfg(feature = "serde")]
|
|
|
|
- fn create_state(&self, state: R) -> WebHistoryState<R> {
|
|
|
|
- let scroll = self.scroll_pos();
|
|
|
|
- WebHistoryState { state, scroll }
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
impl<R: Routable> WebHistory<R>
|
|
impl<R: Routable> WebHistory<R>
|
|
@@ -254,91 +171,6 @@ where
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#[cfg(feature = "serde")]
|
|
|
|
-impl<R: serde::Serialize + serde::de::DeserializeOwned + Routable> HistoryProvider<R>
|
|
|
|
- for WebHistory<R>
|
|
|
|
-where
|
|
|
|
- <R as std::str::FromStr>::Err: std::fmt::Display,
|
|
|
|
-{
|
|
|
|
- fn current_route(&self) -> R {
|
|
|
|
- match get_current::<WebHistoryState<_>>(&self.history) {
|
|
|
|
- // Try to get the route from the history state
|
|
|
|
- Some(route) => route.state,
|
|
|
|
- // If that fails, get the route from the current URL
|
|
|
|
- None => self.route_from_location(),
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn current_prefix(&self) -> Option<String> {
|
|
|
|
- self.prefix.clone()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn go_back(&mut self) {
|
|
|
|
- if let Err(e) = self.history.back() {
|
|
|
|
- error!("failed to go back: ", e)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn go_forward(&mut self) {
|
|
|
|
- if let Err(e) = self.history.forward() {
|
|
|
|
- error!("failed to go forward: ", e)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn push(&mut self, state: R) {
|
|
|
|
- use gloo_utils::format::JsValueSerdeExt;
|
|
|
|
- if JsValue::from_serde(&state) != JsValue::from_serde(&self.current_route()) {
|
|
|
|
- // don't push the same state twice
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let w = window().expect("access to `window`");
|
|
|
|
- let h = w.history().expect("`window` has access to `history`");
|
|
|
|
-
|
|
|
|
- // update the scroll position before pushing the new state
|
|
|
|
- update_scroll::<R>(&w, &h);
|
|
|
|
-
|
|
|
|
- let path = self.full_path(&state);
|
|
|
|
-
|
|
|
|
- let state = self.create_state(state);
|
|
|
|
-
|
|
|
|
- self.handle_nav(push_state_and_url(&self.history, &state, path));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn replace(&mut self, state: R) {
|
|
|
|
- let path = match &self.prefix {
|
|
|
|
- None => format!("{state}"),
|
|
|
|
- Some(prefix) => format!("{prefix}{state}"),
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- let state = self.create_state(state);
|
|
|
|
-
|
|
|
|
- self.handle_nav(replace_state_with_url(&self.history, &state, Some(&path)));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn external(&mut self, url: String) -> bool {
|
|
|
|
- self.navigate_external(url)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn updater(&mut self, callback: std::sync::Arc<dyn Fn() + Send + Sync>) {
|
|
|
|
- let w = self.window.clone();
|
|
|
|
- let h = self.history.clone();
|
|
|
|
- let s = self.listener_animation_frame.clone();
|
|
|
|
- let d = self.do_scroll_restoration;
|
|
|
|
-
|
|
|
|
- self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
|
|
|
|
- (*callback)();
|
|
|
|
- if d {
|
|
|
|
- let mut s = s.lock().expect("unpoisoned scroll mutex");
|
|
|
|
- if let Some(current_state) = get_current::<WebHistoryState<R>>(&h) {
|
|
|
|
- *s = Some(current_state.scroll.scroll_to(w.clone()));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }));
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(feature = "serde"))]
|
|
|
|
impl<R: Routable> HistoryProvider<R> for WebHistory<R>
|
|
impl<R: Routable> HistoryProvider<R> for WebHistory<R>
|
|
where
|
|
where
|
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|