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