Added dynatos-title to manage the document title.

This commit is contained in:
Filipe Rodrigues 2024-02-16 16:44:48 +00:00
parent ede516500a
commit eab0e669c3
Signed by: zenithsiz
SSH Key Fingerprint: SHA256:Mb5ppb3Sh7IarBO/sBTXLHbYEOz37hJAlslLQPPAPaU
5 changed files with 158 additions and 0 deletions

15
Cargo.lock generated
View File

@ -108,6 +108,21 @@ dependencies = [
"web-sys",
]
[[package]]
name = "dynatos-title"
version = "0.1.0"
dependencies = [
"anyhow",
"duplicate",
"dynatos-reactive",
"dynatos-util",
"extend",
"js-sys",
"tracing",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "dynatos-util"
version = "0.1.0"

View File

@ -7,6 +7,7 @@ members = [
"dynatos-logger",
"dynatos-reactive",
"dynatos-router",
"dynatos-title",
"dynatos-util",
]
resolver = "2"
@ -20,6 +21,7 @@ dynatos-html = { path = "dynatos-html" }
dynatos-logger = { path = "dynatos-logger" }
dynatos-reactive = { path = "dynatos-reactive" }
dynatos-router = { path = "dynatos-router" }
dynatos-title = { path = "dynatos-title" }
dynatos-util = { path = "dynatos-util" }
anyhow = "1.0.79"

17
dynatos-title/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "dynatos-title"
version = "0.1.0"
edition = "2021"
[dependencies]
dynatos-reactive = { workspace = true }
dynatos-util = { workspace = true }
anyhow = { workspace = true }
duplicate = { workspace = true }
extend = { workspace = true }
js-sys = { workspace = true }
tracing = { workspace = true }
wasm-bindgen = { workspace = true }
web-sys = { workspace = true }

123
dynatos-title/src/lib.rs Normal file
View File

@ -0,0 +1,123 @@
//! Title management for [`dynatos`]
// TODO: It seems that titles aren't getting dropped for some reason.
// Features
#![feature(lint_reasons)]
// Imports
use {dynatos_util::ObjectSetProp, std::cell::RefCell, wasm_bindgen::prelude::wasm_bindgen};
thread_local! {
/// Title stack.
static TITLE_STACK: RefCell<Vec<Option<String>>> = RefCell::new(vec![]);
}
/// Title.
///
/// Sets the title for as long as this lives.
#[derive(Debug)]
pub struct Title {
/// Title index
title_idx: usize,
}
impl Title {
/// Creates a title.
pub fn new<S>(title: S) -> Self
where
S: Into<String>,
{
let title = title.into();
// Set and add the title to the stack
self::set_title(&title);
let title_idx = TITLE_STACK.with_borrow_mut(|stack| {
// If no title exists, add the current one
if stack.is_empty() {
stack.push(Some(self::cur_title()));
}
// Then add ours
let title_idx = stack.len();
stack.push(Some(title));
title_idx
});
Self { title_idx }
}
}
impl Drop for Title {
fn drop(&mut self) {
// Get the value
TITLE_STACK.with_borrow_mut(|stack| {
// Remove our title
let _prev_title = stack
.get_mut(self.title_idx)
.and_then(Option::take)
.expect("Title was already taken");
// Then find the next title to set back to.
let next_title = loop {
let last = stack.last().expect("Should contain at least 1 title");
match last {
Some(title) => break title,
None => {
stack.pop().expect("Just checked the value existed");
},
}
};
self::set_title(next_title);
});
}
}
/// Extension trait to attach a title to an object.
#[extend::ext(name = ObjectAttachTitle)]
pub impl js_sys::Object {
/// Attaches a title to this object
fn attach_title(&self, title: &str) {
let prop_name: &str = "__dynatos_title";
let title = Title::new(title);
self.set_prop(prop_name, WasmTitle(title));
}
}
/// Extension trait to attach a title to an object.
#[extend::ext(name = ObjectWithTitle)]
pub impl<T> T
where
T: AsRef<js_sys::Object>,
{
/// Attaches a title to this object.
///
/// Returns the object, for chaining
fn with_title(self, title: &str) -> Self {
self.as_ref().attach_title(title);
self
}
}
/// Returns the current title
fn cur_title() -> String {
web_sys::window()
.expect("Unable to get window")
.document()
.expect("Unable to get document")
.title()
}
/// Sets the title
fn set_title(title: &str) {
web_sys::window()
.expect("Unable to get window")
.document()
.expect("Unable to get document")
.set_title(title);
}
/// A wasm `Title` type.
#[wasm_bindgen]
struct WasmTitle(Title);

View File

@ -12,6 +12,7 @@ dynatos-html = { path = "../dynatos-html" }
dynatos-logger = { path = "../dynatos-logger" }
dynatos-reactive = { path = "../dynatos-reactive" }
dynatos-router = { path = "../dynatos-router" }
dynatos-title = { path = "../dynatos-title" }
dynatos-util = { path = "../dynatos-util" }
anyhow = "1.0.79"