use crate::{
Computed, DomNode, EmbedDom, Reactive, ToComputed,
computed::{Value, get_dependencies},
dev::command::{LocationSetMode, LocationTarget},
driver_module::api::api_location,
};
#[derive(Clone, PartialEq)]
pub struct Router<T: Clone + ToString + From<String> + PartialEq + 'static> {
location_target: LocationTarget,
pub route: Computed<T>,
}
impl<T: Clone + ToString + From<String> + PartialEq + 'static> Router<T> {
pub fn new_hash_router() -> Router<T> {
Self::new(false)
}
pub fn new_history_router() -> Router<T> {
Self::new(true)
}
fn new(use_history_api: bool) -> Self {
let location_target = match use_history_api {
false => LocationTarget::Hash,
true => LocationTarget::History,
};
let init_value = T::from(api_location().get_location(location_target));
let route = Value::with_connect(init_value, move |value| {
let value = value.clone();
let callback = move |url: String| {
value.set(T::from(url));
};
api_location().on_change(location_target, callback)
});
Self {
location_target,
route,
}
}
pub fn set(&self, route: T) {
api_location().push_location(
self.location_target,
LocationSetMode::Push,
&route.to_string(),
);
}
fn change(&self, change_fn: impl FnOnce(&mut T)) {
get_dependencies().transaction(|ctx| {
let mut value = self.get(ctx);
change_fn(&mut value);
self.set(value);
});
}
}
impl<T: Clone + PartialEq + ToString + From<String>> Reactive<T> for Router<T> {
fn set(&self, value: T) {
Router::set(self, value)
}
fn get(&self, context: &crate::Context) -> T {
self.route.get(context)
}
fn change(&self, change_fn: impl FnOnce(&mut T)) {
Router::change(self, change_fn)
}
}
impl<T: Clone + PartialEq + ToString + From<String>> ToComputed<T> for Router<T> {
fn to_computed(&self) -> Computed<T> {
self.route.to_computed()
}
}
impl<T: Clone + PartialEq + ToString + From<String>> EmbedDom for Router<T> {
fn embed(self) -> DomNode {
self.route.embed()
}
}
impl<T: Clone + PartialEq + ToString + From<String>> Default for Router<T> {
fn default() -> Self {
Router::new(true)
}
}