use std::pin::Pin;
use std::task::{Context, Poll};
use crate::prelude::*;
use futures_core::Stream;
use pin_project::pin_project;
use wasm_bindgen::JsValue;
#[pin_project]
#[derive(Debug)]
pub struct History {
inner: web_sys::History,
#[pin]
listener: Option<crate::events::EventStream>,
}
impl History {
pub fn new() -> Self {
Self {
inner: crate::utils::window().history().unwrap_throw(),
listener: None,
}
}
pub fn len(&self) -> usize {
self.inner.length().unwrap_throw() as usize
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn current(&self) -> String {
crate::utils::document()
.location()
.unwrap_throw()
.href()
.unwrap_throw()
}
pub fn push(&self, url: &str) {
let null = JsValue::null();
self.inner
.push_state_with_url(&null, "", Some(url))
.unwrap_throw();
}
pub fn pop(&self) {
self.inner.back().unwrap_throw();
}
pub fn replace(&self, url: &str) {
let null = JsValue::null();
self.inner
.replace_state_with_url(&null, "", Some(url))
.unwrap_throw();
}
pub async fn move_by(&self, delta: i32) {
let fut = crate::utils::window().once("popstate");
self.inner.go_with_delta(delta).unwrap_throw();
fut.await;
}
pub async fn move_next(&self) {
let fut = crate::utils::window().once("popstate");
self.inner.forward().unwrap_throw();
fut.await;
}
pub async fn move_prev(&self) {
let fut = crate::utils::window().once("popstate");
self.inner.back().unwrap_throw();
fut.await;
}
pub async fn reload(&self) {
let fut = crate::utils::window().once("popstate");
self.inner.go().unwrap_throw();
fut.await;
}
}
impl Stream for History {
type Item = String;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
if self.listener.is_none() {
self.listener = Some(crate::utils::window().on("popstate"));
}
let listener = self.project().listener.get_mut().as_mut().unwrap_throw();
match Pin::new(listener).poll_next(cx) {
Poll::Ready(_) => Poll::Ready(Some(
crate::utils::document()
.location()
.unwrap_throw()
.href()
.unwrap_throw(),
)),
Poll::Pending => Poll::Pending,
}
}
}
impl Default for History {
fn default() -> Self {
Self::new()
}
}