Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add back a global instance to listen to events
- Loading branch information
Showing
3 changed files
with
83 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use std::cell::RefCell; | ||
use std::rc::{Rc, Weak}; | ||
use wasm_bindgen::JsValue; | ||
|
||
thread_local! { | ||
static INSTANCE: RefCell<InnerHistory> = RefCell::new(InnerHistory { | ||
listeners: vec![], | ||
}); | ||
} | ||
|
||
/// Handle to a history listener. | ||
/// | ||
/// Disposes the listener when dropped. | ||
pub struct HistoryListener(Rc<CallbackFn>); | ||
|
||
pub struct History; | ||
|
||
impl History { | ||
/// Subscribe to events of the browser history. | ||
/// | ||
/// This will receive events when popping items from the stack, as well as changes triggered by calling | ||
/// [`History::push_state`]. | ||
#[must_use = "The listener will only be active for as long as the returned instance exists."] | ||
pub fn listener<F: Fn() + 'static>(f: F) -> HistoryListener { | ||
INSTANCE.with(|instance| instance.borrow_mut().listener(f)) | ||
} | ||
|
||
/// Push a new state to the history stack. | ||
/// | ||
/// This will send out events and update the browser's history. Ultimately calling | ||
/// [`web_sys::History::push_state_with_url`]. | ||
pub fn push_state(state: JsValue, url: &str) -> Result<(), JsValue> { | ||
INSTANCE.with(|instance| instance.borrow_mut().push_state(state, url)) | ||
} | ||
} | ||
|
||
type CallbackFn = dyn Fn() + 'static; | ||
|
||
struct InnerHistory { | ||
listeners: Vec<Weak<CallbackFn>>, | ||
} | ||
|
||
impl InnerHistory { | ||
fn push_state(&mut self, state: JsValue, url: &str) -> Result<(), JsValue> { | ||
let result = gloo_utils::history().push_state_with_url(&state, "", Some(url)); | ||
self.notify(); | ||
result | ||
} | ||
|
||
fn listener<F: Fn() + 'static>(&mut self, f: F) -> HistoryListener { | ||
let callback = Rc::new(f) as Rc<CallbackFn>; | ||
self.listeners.push(Rc::downgrade(&callback)); | ||
HistoryListener(callback) | ||
} | ||
|
||
fn notify(&mut self) { | ||
let mut new = vec![]; | ||
|
||
for listener in &mut self.listeners { | ||
if let Some(cb) = listener.upgrade() { | ||
(*cb)(); | ||
new.push(listener.clone()); | ||
} | ||
} | ||
|
||
self.listeners = new; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters