fix scroll history
This commit is contained in:
1 parent
dd48c5a163
commit
f94dc85491
1 file changed
+41
-18
@@ -1,7 +1,6 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use gloo::{events::EventListener, render::AnimationFrame};
|
use gloo::{console::error, events::EventListener, render::AnimationFrame};
|
||||||
use log::error;
|
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use web_sys::{window, History, ScrollRestoration, Window};
|
use web_sys::{window, History, ScrollRestoration, Window};
|
||||||
|
|
||||||
@@ -13,6 +12,16 @@ use super::{
|
|||||||
HistoryProvider,
|
HistoryProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn update_scroll<R: Serialize + DeserializeOwned>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct WebHistoryState<R> {
|
struct WebHistoryState<R> {
|
||||||
state: R,
|
state: R,
|
||||||
@@ -45,18 +54,24 @@ pub struct WebHistory<R: Serialize + DeserializeOwned> {
|
|||||||
phantom: std::marker::PhantomData<R>,
|
phantom: std::marker::PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Serialize + DeserializeOwned> Default for WebHistory<R> {
|
impl<R: Serialize + DeserializeOwned + Routable> Default for WebHistory<R>
|
||||||
|
where
|
||||||
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||||
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(None, true)
|
Self::new(None, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Serialize + DeserializeOwned> WebHistory<R> {
|
impl<R: Serialize + DeserializeOwned + Routable> WebHistory<R> {
|
||||||
/// 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
|
||||||
/// state. It'll also set the browsers scroll restoration to `manual`.
|
/// state. It'll also set the browsers scroll restoration to `manual`.
|
||||||
pub fn new(prefix: Option<String>, do_scroll_restoration: bool) -> Self {
|
pub fn new(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
||||||
|
where
|
||||||
|
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||||
|
{
|
||||||
let window = window().expect("access to `window`");
|
let window = window().expect("access to `window`");
|
||||||
let history = window.history().expect("`window` has access to `history`");
|
let history = window.history().expect("`window` has access to `history`");
|
||||||
|
|
||||||
@@ -69,15 +84,14 @@ impl<R: Serialize + DeserializeOwned> WebHistory<R> {
|
|||||||
let h = history.clone();
|
let h = history.clone();
|
||||||
let document = w.document().expect("`window` has access to `document`");
|
let document = w.document().expect("`window` has access to `document`");
|
||||||
|
|
||||||
// Some(EventListener::new(&document, "scroll", move |_| {
|
Some(EventListener::new(&document, "scroll", move |_| {
|
||||||
// set_state(&w, &h);
|
update_scroll::<R>(&w, &h);
|
||||||
// }))
|
}))
|
||||||
None
|
|
||||||
}
|
}
|
||||||
false => None,
|
false => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
let myself = Self {
|
||||||
do_scroll_restoration,
|
do_scroll_restoration,
|
||||||
history,
|
history,
|
||||||
listener_navigation: None,
|
listener_navigation: None,
|
||||||
@@ -86,7 +100,14 @@ impl<R: Serialize + DeserializeOwned> WebHistory<R> {
|
|||||||
prefix,
|
prefix,
|
||||||
window,
|
window,
|
||||||
phantom: Default::default(),
|
phantom: Default::default(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let state = myself.current_route();
|
||||||
|
|
||||||
|
let state = myself.create_state(state);
|
||||||
|
let _ = replace_state_with_url(&myself.history, &state, None);
|
||||||
|
|
||||||
|
myself
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_state(&self, state: R) -> WebHistoryState<R> {
|
fn create_state(&self, state: R) -> WebHistoryState<R> {
|
||||||
@@ -124,13 +145,13 @@ where
|
|||||||
|
|
||||||
fn go_back(&mut self) {
|
fn go_back(&mut self) {
|
||||||
if let Err(e) = self.history.back() {
|
if let Err(e) = self.history.back() {
|
||||||
error!("failed to go back: {e:?}")
|
error!("failed to go back: ", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn go_forward(&mut self) {
|
fn go_forward(&mut self) {
|
||||||
if let Err(e) = self.history.forward() {
|
if let Err(e) = self.history.forward() {
|
||||||
error!("failed to go forward: {e:?}")
|
error!("failed to go forward: ", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +171,7 @@ where
|
|||||||
self.window.scroll_to_with_x_and_y(0.0, 0.0)
|
self.window.scroll_to_with_x_and_y(0.0, 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("failed to push state: {e:?}"),
|
Err(e) => error!("failed to push state: ", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +191,7 @@ where
|
|||||||
self.window.scroll_to_with_x_and_y(0.0, 0.0)
|
self.window.scroll_to_with_x_and_y(0.0, 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("failed to replace state: {e:?}"),
|
Err(e) => error!("failed to replace state:", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +199,7 @@ where
|
|||||||
match self.window.location().set_href(&url) {
|
match self.window.location().set_href(&url) {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("failed to navigate to external url (`{url}): {e:?}");
|
error!("failed to navigate to external url (", url, "): ", e);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,8 +214,10 @@ where
|
|||||||
self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
|
self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
|
||||||
(*callback)();
|
(*callback)();
|
||||||
if d {
|
if d {
|
||||||
// let mut s = s.lock().expect("unpoisoned scroll mutex");
|
let mut s = s.lock().expect("unpoisoned scroll mutex");
|
||||||
// *s = Some(update_scroll(&w, &h));
|
if let Some(current_state) = get_current::<WebHistoryState<R>>(&h) {
|
||||||
|
*s = Some(current_state.scroll.scroll_to(w.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user