This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew_router/
navigator.rs

1use std::borrow::Cow;
2
3use crate::history::{AnyHistory, History, HistoryError, HistoryResult};
4use crate::query::ToQuery;
5use crate::routable::Routable;
6
7pub type NavigationError = HistoryError;
8pub type NavigationResult<T> = HistoryResult<T>;
9
10/// The kind of Navigator Provider.
11#[derive(Debug, PartialEq, Eq, Clone, Copy)]
12pub enum NavigatorKind {
13    /// Browser History.
14    Browser,
15    /// Hash History.
16    Hash,
17    /// Memory History.
18    Memory,
19}
20
21/// A struct to navigate between locations.
22#[derive(Debug, PartialEq, Clone)]
23pub struct Navigator {
24    inner: AnyHistory,
25    basename: Option<String>,
26}
27
28impl Navigator {
29    pub(crate) fn new(history: AnyHistory, basename: Option<String>) -> Self {
30        Self {
31            inner: history,
32            basename,
33        }
34    }
35
36    /// Returns basename of current navigator.
37    pub fn basename(&self) -> Option<&str> {
38        self.basename.as_deref()
39    }
40
41    /// Navigate back 1 page.
42    pub fn back(&self) {
43        self.go(-1);
44    }
45
46    /// Navigate forward 1 page.
47    pub fn forward(&self) {
48        self.go(1);
49    }
50
51    /// Navigate to a specific page with a `delta` relative to current page.
52    ///
53    /// See: <https://developer.mozilla.org/en-US/docs/Web/API/History/go>
54    pub fn go(&self, delta: isize) {
55        self.inner.go(delta);
56    }
57
58    /// Pushes a [`Routable`] entry.
59    pub fn push<R>(&self, route: &R)
60    where
61        R: Routable,
62    {
63        self.inner.push(self.prefix_basename(&route.to_path()));
64    }
65
66    /// Replaces the current history entry with provided [`Routable`] and [`None`] state.
67    pub fn replace<R>(&self, route: &R)
68    where
69        R: Routable,
70    {
71        self.inner.replace(self.prefix_basename(&route.to_path()));
72    }
73
74    /// Pushes a [`Routable`] entry with state.
75    pub fn push_with_state<R, T>(&self, route: &R, state: T)
76    where
77        R: Routable,
78        T: 'static,
79    {
80        self.inner
81            .push_with_state(self.prefix_basename(&route.to_path()), state);
82    }
83
84    /// Replaces the current history entry with provided [`Routable`] and state.
85    pub fn replace_with_state<R, T>(&self, route: &R, state: T)
86    where
87        R: Routable,
88        T: 'static,
89    {
90        self.inner
91            .replace_with_state(self.prefix_basename(&route.to_path()), state);
92    }
93
94    /// Same as `.push()` but affix the queries to the end of the route.
95    pub fn push_with_query<R, Q>(&self, route: &R, query: Q) -> Result<(), Q::Error>
96    where
97        R: Routable,
98        Q: ToQuery,
99    {
100        self.inner
101            .push_with_query(self.prefix_basename(&route.to_path()), query)
102    }
103
104    /// Same as `.replace()` but affix the queries to the end of the route.
105    pub fn replace_with_query<R, Q>(&self, route: &R, query: Q) -> Result<(), Q::Error>
106    where
107        R: Routable,
108        Q: ToQuery,
109    {
110        self.inner
111            .replace_with_query(self.prefix_basename(&route.to_path()), query)
112    }
113
114    /// Same as `.push_with_state()` but affix the queries to the end of the route.
115    pub fn push_with_query_and_state<R, Q, T>(
116        &self,
117        route: &R,
118        query: Q,
119        state: T,
120    ) -> Result<(), Q::Error>
121    where
122        R: Routable,
123        Q: ToQuery,
124        T: 'static,
125    {
126        self.inner
127            .push_with_query_and_state(self.prefix_basename(&route.to_path()), query, state)
128    }
129
130    /// Same as `.replace_with_state()` but affix the queries to the end of the route.
131    pub fn replace_with_query_and_state<R, Q, T>(
132        &self,
133        route: &R,
134        query: Q,
135        state: T,
136    ) -> Result<(), Q::Error>
137    where
138        R: Routable,
139        Q: ToQuery,
140        T: 'static,
141    {
142        self.inner.replace_with_query_and_state(
143            self.prefix_basename(&route.to_path()),
144            query,
145            state,
146        )
147    }
148
149    /// Returns the Navigator kind.
150    pub fn kind(&self) -> NavigatorKind {
151        match &self.inner {
152            AnyHistory::Browser(_) => NavigatorKind::Browser,
153            AnyHistory::Hash(_) => NavigatorKind::Hash,
154            AnyHistory::Memory(_) => NavigatorKind::Memory,
155        }
156    }
157
158    pub(crate) fn prefix_basename<'a>(&self, route_s: &'a str) -> Cow<'a, str> {
159        match self.basename() {
160            Some(base) => {
161                if base.is_empty() && route_s.is_empty() {
162                    Cow::from("/")
163                } else {
164                    Cow::from(format!("{base}{route_s}"))
165                }
166            }
167            None => route_s.into(),
168        }
169    }
170
171    pub(crate) fn strip_basename<'a>(&self, path: Cow<'a, str>) -> Cow<'a, str> {
172        match self.basename() {
173            Some(m) => {
174                let mut path = path
175                    .strip_prefix(m)
176                    .map(|m| Cow::from(m.to_owned()))
177                    .unwrap_or(path);
178
179                if !path.starts_with('/') {
180                    path = format!("/{m}").into();
181                }
182
183                path
184            }
185            None => path,
186        }
187    }
188}