add web history integration
This commit is contained in:
6 files changed
+144
-4
No files matched your search
@@ -10,12 +10,16 @@ async-rwlock = "1.3.0"
|
|||||||
either = "1.8.0"
|
either = "1.8.0"
|
||||||
futures-channel = "0.3.25"
|
futures-channel = "0.3.25"
|
||||||
futures-util = "0.3.25"
|
futures-util = "0.3.25"
|
||||||
|
gloo = { version = "0.8.0", optional = true }
|
||||||
|
log = "0.4.17"
|
||||||
regex = { version = "1.6.0", optional = true }
|
regex = { version = "1.6.0", optional = true }
|
||||||
serde = { version = "1.0.147", optional = true }
|
serde = { version = "1.0.147", optional = true }
|
||||||
serde_urlencoded = { version = "0.7.1", optional = true }
|
serde_urlencoded = { version = "0.7.1", optional = true }
|
||||||
url = "2.3.1"
|
url = "2.3.1"
|
||||||
urlencoding = "2.1.2"
|
urlencoding = "2.1.2"
|
||||||
|
web-sys = { version = "0.3.60", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
regex = ["dep:regex"]
|
regex = ["dep:regex"]
|
||||||
serde = ["dep:serde", "serde_urlencoded"]
|
serde = ["dep:serde", "serde_urlencoded"]
|
||||||
|
web = ["gloo", "web-sys"]
|
||||||
@@ -11,6 +11,11 @@ use std::sync::Arc;
|
|||||||
mod memory;
|
mod memory;
|
||||||
pub use memory::*;
|
pub use memory::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
mod web;
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
pub use web::*;
|
||||||
|
|
||||||
/// An integration with some kind of navigation history.
|
/// An integration with some kind of navigation history.
|
||||||
///
|
///
|
||||||
/// Depending on your use case, your implementation may deviate from the described procedure. This
|
/// Depending on your use case, your implementation may deviate from the described procedure. This
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
use gloo::{
|
||||||
|
history::{BrowserHistory, History, HistoryListener},
|
||||||
|
utils::window,
|
||||||
|
};
|
||||||
|
use log::error;
|
||||||
|
use web_sys::Window;
|
||||||
|
|
||||||
|
use super::HistoryProvider;
|
||||||
|
|
||||||
|
/// A [`HistoryProvider`] that integrates with a browser via the [History API].
|
||||||
|
///
|
||||||
|
/// # Prefix
|
||||||
|
/// This [`HistoryProvider`] supports a prefix, which can be used for web apps that aren't located
|
||||||
|
/// at the root of their domain.
|
||||||
|
///
|
||||||
|
/// Application developers are responsible for ensuring that right after the prefix comes a `/`. If
|
||||||
|
/// that is not the case, this [`HistoryProvider`] will replace the first character after the prefix
|
||||||
|
/// with one.
|
||||||
|
///
|
||||||
|
/// Application developers are responsible for not rendering the router if the prefix is not present
|
||||||
|
/// in the URL. Otherwise, if a router navigation is triggered, the prefix will be added.
|
||||||
|
///
|
||||||
|
/// [History API]: https://developer.mozilla.org/en-US/docs/Web/API/History_API
|
||||||
|
pub struct WebHistory {
|
||||||
|
history: BrowserHistory,
|
||||||
|
listener_navigation: Option<HistoryListener>,
|
||||||
|
prefix: Option<String>,
|
||||||
|
window: Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebHistory {
|
||||||
|
/// Create a new [`WebHistory`] with a prefix.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_prefix(prefix: String) -> Self {
|
||||||
|
Self {
|
||||||
|
prefix: Some(prefix),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WebHistory {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
history: BrowserHistory::new(),
|
||||||
|
listener_navigation: None,
|
||||||
|
prefix: None,
|
||||||
|
window: window(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HistoryProvider for WebHistory {
|
||||||
|
fn current_path(&self) -> String {
|
||||||
|
let location = self.history.location();
|
||||||
|
let path = location.path();
|
||||||
|
|
||||||
|
match &self.prefix {
|
||||||
|
None => path.to_string(),
|
||||||
|
Some(prefix) => path
|
||||||
|
.starts_with(prefix)
|
||||||
|
.then(|| path.split_at(prefix.len()).1)
|
||||||
|
.unwrap_or("/")
|
||||||
|
.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_query(&self) -> Option<String> {
|
||||||
|
let location = self.history.location();
|
||||||
|
let query = location.query_str();
|
||||||
|
|
||||||
|
if query.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(query.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_prefix(&self) -> Option<String> {
|
||||||
|
self.prefix.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_back(&mut self) {
|
||||||
|
self.history.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_forward(&mut self) {
|
||||||
|
self.history.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, path: String) {
|
||||||
|
self.history.push(match &self.prefix {
|
||||||
|
None => path,
|
||||||
|
Some(prefix) => format!("{prefix}{path}"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace(&mut self, path: String) {
|
||||||
|
self.history.replace(match &self.prefix {
|
||||||
|
None => path,
|
||||||
|
Some(prefix) => format!("{prefix}{path}"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn external(&mut self, url: String) -> bool {
|
||||||
|
match self.window.location().set_href(&url) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(_) => {
|
||||||
|
error!("`WebHistory` failed to navigate to external target: {url}");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updater(&mut self, callback: std::sync::Arc<dyn Fn() + Send + Sync>) {
|
||||||
|
self.listener_navigation = Some(self.history.listen(move || (*callback)()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,13 +20,18 @@ futures-util = "0.3.25"
|
|||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
|
|
||||||
# for wasm
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
regex = ["dioxus-router-core/regex"]
|
regex = ["dioxus-router-core/regex"]
|
||||||
serde = ["dioxus-router-core/serde"]
|
serde = ["dioxus-router-core/serde"]
|
||||||
|
web = ["dioxus-router-core/web"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dioxus = { path = "../dioxus" }
|
dioxus = { path = "../dioxus" }
|
||||||
dioxus-desktop = { path = "../desktop" }
|
|
||||||
dioxus-ssr = { path = "../ssr" }
|
dioxus-ssr = { path = "../ssr" }
|
||||||
|
|
||||||
|
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
|
||||||
|
dioxus-desktop = { path = "../desktop" }
|
||||||
|
|
||||||
|
[target.'cfg(target_family = "wasm")'.dev-dependencies]
|
||||||
|
dioxus-router = { path = ".", features = ["web"] }
|
||||||
|
dioxus-web = { path= "../web" }
|
||||||
@@ -4,7 +4,10 @@ use dioxus::prelude::*;
|
|||||||
use dioxus_router::prelude::*;
|
use dioxus_router::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
#[cfg(not(feature = "web"))]
|
||||||
dioxus_desktop::launch(App);
|
dioxus_desktop::launch(App);
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
dioxus_web::launch(App);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn App(cx: Scope) -> Element {
|
fn App(cx: Scope) -> Element {
|
||||||
|
|||||||
@@ -188,11 +188,16 @@ pub struct RouterConfiguration {
|
|||||||
|
|
||||||
impl Default for RouterConfiguration {
|
impl Default for RouterConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
#[cfg(not(feature = "web"))]
|
||||||
|
let history = Box::<MemoryHistory>::default();
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
let history = Box::<crate::history::WebHistory>::default();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
failure_external_navigation: comp(FailureExternalNavigation),
|
failure_external_navigation: comp(FailureExternalNavigation),
|
||||||
failure_named_navigation: comp(FailureNamedNavigation),
|
failure_named_navigation: comp(FailureNamedNavigation),
|
||||||
failure_redirection_limit: comp(FailureRedirectionLimit),
|
failure_redirection_limit: comp(FailureRedirectionLimit),
|
||||||
history: Box::<MemoryHistory>::default(),
|
history: history,
|
||||||
on_update: None,
|
on_update: None,
|
||||||
synchronous: false,
|
synchronous: false,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user