use std::borrow::Cow;
use web_sys::{EventTarget, HtmlElement};
use futures_signals::signal::{Mutable, ReadOnlyMutable};
use crate::bindings;
use crate::bindings::WINDOW;
use crate::dom::{Dom, DomBuilder, EventOptions};
use crate::utils::{EventListener, RefCounter, MutableListener};
use crate::events;
fn change_url(mutable: &Mutable<String>) {
let mut lock = mutable.lock_mut();
let new_url = String::from(bindings::current_url());
if *lock != new_url {
*lock = new_url;
}
}
thread_local! {
static CURRENT_URL: RefCounter<MutableListener<String>> = RefCounter::new();
}
fn try_url<F>(f: F) where F: FnOnce(&Mutable<String>) {
CURRENT_URL.with(|url| {
if let Some(url) = &*url.try_borrow() {
f(url.as_mutable());
}
})
}
pub fn url() -> ReadOnlyMutable<String> {
CURRENT_URL.with(|url| {
let url = url.increment(|| {
let url = Mutable::new(String::from(bindings::current_url()));
let listener = {
let url = url.clone();
WINDOW.with(move |window| {
EventListener::new(window, "popstate", &EventOptions::default(), move |_| {
change_url(&url);
})
})
};
MutableListener::new(url, listener)
});
url.as_mutable().read_only()
})
}
#[inline]
#[track_caller]
pub fn go_to_url(new_url: &str) {
bindings::go_to_url(new_url);
try_url(change_url);
}
#[inline]
#[track_caller]
pub fn replace_url(new_url: &str) {
bindings::replace_url(new_url);
try_url(change_url);
}
#[deprecated(since = "0.5.1", note = "Use the on_click_go_to_url macro instead")]
#[inline]
pub fn on_click_go_to_url<A, B>(new_url: A) -> impl FnOnce(DomBuilder<B>) -> DomBuilder<B>
where A: Into<Cow<'static, str>>,
B: AsRef<EventTarget> {
let new_url = new_url.into();
#[inline]
move |dom| {
dom.event_with_options(&EventOptions::preventable(), move |e: events::Click| {
e.prevent_default();
go_to_url(&new_url);
})
}
}
#[deprecated(since = "0.5.1", note = "Use the link macro instead")]
#[allow(deprecated)]
#[inline]
pub fn link<A, F>(url: A, f: F) -> Dom
where A: Into<Cow<'static, str>>,
F: FnOnce(DomBuilder<HtmlElement>) -> DomBuilder<HtmlElement> {
let url = url.into();
html!("a", {
.attr("href", &url)
.apply(on_click_go_to_url(url))
.apply(f)
})
}
#[macro_export]
macro_rules! on_click_go_to_url {
($this:ident, $url:expr) => {{
let url = $url;
$this.event_with_options(&$crate::EventOptions::preventable(), move |e: $crate::events::Click| {
e.prevent_default();
$crate::routing::go_to_url(&url);
})
}};
}
#[macro_export]
macro_rules! link {
($url:expr, { $($methods:tt)* }) => {{
let url = $url;
$crate::html!("a", {
.attr("href", &url)
.apply(move |dom| $crate::on_click_go_to_url!(dom, url))
$($methods)*
})
}};
}