domus/
lib.rs

1
2use {
3    wasm_bindgen::{
4        prelude::*,
5        JsCast,
6    },
7    web_sys::{
8        Element,
9        Document,
10        HtmlElement,
11        console,
12    },
13};
14
15pub trait DomusElement {
16    fn empty(&self);
17}
18
19impl DomusElement for HtmlElement {
20    /// only remove child elements, not text nodes
21    fn empty(&self) {
22        while let Some(child) = self.first_element_child() {
23            child.remove();
24        }
25    }
26}
27
28pub fn doc() -> Document {
29    let window = web_sys::window().expect("no global `window` exists");
30    let document = window.document().expect("should have a document on window");
31    document
32}
33
34// will crash your app when there's no body in the current document.
35// This is usually fine.
36pub fn body() -> HtmlElement {
37    doc().body().unwrap()
38}
39
40pub fn js_err<T>(message: &str) -> Result<T, JsValue> {
41    Err(JsValue::from_str(message))
42}
43
44pub fn by_id(id: &str) -> Option<HtmlElement> {
45    doc()
46        .get_element_by_id(id)
47        .and_then(|element|
48             element
49            .dyn_into::<HtmlElement>()
50            .ok()
51        )
52}
53
54// TODO in order to eliminate dynamic errors we should use
55// an enum of tags instead of taking a str
56pub fn tag(tag_name: &str) -> Result<HtmlElement, JsValue> {
57    let e: Element = doc().create_element(tag_name)?;
58    match e.dyn_into::<HtmlElement>() {
59        Ok(e) => Ok(e),
60        Err(_) => js_err(&format!("{:?} tag not making a HtmlElement", tag_name)),
61    }
62}
63
64pub fn tag_class(tag_name: &str, class: &str) -> Result<HtmlElement, JsValue> {
65    let e = tag(tag_name)?;
66    e.class_list().add_1(class)?;
67    Ok(e)
68}
69
70pub fn remove_by_selector(selector: &str) {
71    let node_list = doc().query_selector_all(selector).unwrap();
72    for i in 0..node_list.length() {
73        let node = node_list.item(i);
74        if let Some(node) = node {
75            if let Ok(e) = node.dyn_into::<HtmlElement>() {
76                e.remove();
77            }
78        }
79    }
80}
81
82pub fn log_str(s: &str) {
83    console::log_1(&JsValue::from_str(s));
84}
85
86/// log anything. Uses format!
87#[macro_export]
88macro_rules! log {
89    ($($arg:tt)*) => (crate::domus::log_str(&format!($($arg)*)));
90}
91