yew_nested_router/
history.rs1use gloo_events::EventListener;
2use std::cell::RefCell;
3use std::rc::{Rc, Weak};
4use wasm_bindgen::JsValue;
5
6thread_local! {
7 static INSTANCE: RefCell<InnerHistory> = RefCell::new(InnerHistory::new());
8}
9
10pub struct HistoryListener {
14 _callback: Rc<CallbackFn>,
15}
16
17pub struct History;
18
19impl History {
20 #[must_use = "The listener will only be active for as long as the returned instance exists."]
25 pub fn listener<F: Fn() + 'static>(f: F) -> HistoryListener {
26 INSTANCE.with(|instance| instance.borrow_mut().listener(f))
27 }
28
29 pub fn push_state(state: JsValue, url: &str) -> Result<(), JsValue> {
34 INSTANCE.with(|instance| instance.borrow_mut().push_state(state, url))
35 }
36 pub fn replace_state(state: JsValue, url: &str) -> Result<(), JsValue> {
41 INSTANCE.with(|instance| instance.borrow_mut().replace_state(state, url))
42 }
43}
44
45type CallbackFn = dyn Fn() + 'static;
46
47#[derive(Default)]
48struct Listeners {
49 listeners: Vec<Weak<CallbackFn>>,
50}
51
52impl Listeners {
53 fn add(&mut self, listener: Weak<CallbackFn>) {
54 self.listeners.push(listener);
55 }
56
57 fn notify(&mut self) {
58 log::info!("Notify listeners");
59
60 let mut new = vec![];
61
62 for listener in &mut self.listeners {
63 if let Some(cb) = listener.upgrade() {
64 (*cb)();
65 new.push(listener.clone());
66 }
67 }
68
69 self.listeners = new;
70 }
71}
72
73struct InnerHistory {
74 _event: EventListener,
75 listeners: Rc<RefCell<Listeners>>,
76}
77
78impl InnerHistory {
79 fn new() -> Self {
80 let listeners = Rc::new(RefCell::new(Listeners::default()));
81 let _event = {
82 let listeners = listeners.clone();
83 EventListener::new(&gloo_utils::window(), "popstate", move |_| {
84 listeners.borrow_mut().notify();
85 })
86 };
87
88 Self { listeners, _event }
89 }
90
91 fn push_state(&mut self, state: JsValue, url: &str) -> Result<(), JsValue> {
92 let result = gloo_utils::history().push_state_with_url(&state, "", Some(url));
93 self.listeners.borrow_mut().notify();
94 result
95 }
96
97 fn replace_state(&mut self, state: JsValue, url: &str) -> Result<(), JsValue> {
98 let result = gloo_utils::history().replace_state_with_url(&state, "", Some(url));
99 self.listeners.borrow_mut().notify();
100 result
101 }
102
103 fn listener<F: Fn() + 'static>(&mut self, f: F) -> HistoryListener {
104 let callback = Rc::new(f) as Rc<CallbackFn>;
105 self.listeners.borrow_mut().add(Rc::downgrade(&callback));
106 HistoryListener {
107 _callback: callback,
108 }
109 }
110}