bloom_html/
element.rs

1use std::{collections::HashMap, fmt::Debug, sync::Arc};
2
3use crate::{DomRef, EventHandler};
4
5/// Represents an html tag such as `<div>`, `<span>`, etc.
6pub struct HtmlElement {
7    pub(crate) tag_name: &'static str,
8    pub(crate) attributes: HashMap<String, String>,
9    pub(crate) callbacks: HashMap<String, EventHandler>,
10    pub(crate) dom_ref: Option<Arc<DomRef>>,
11}
12
13impl Debug for HtmlElement {
14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15        f.debug_struct("HtmlElement")
16            .field("tag_name", &self.tag_name)
17            .field("attributes", &self.attributes)
18            .field("callbacks", &"Callbacks")
19            .field("dom_ref", &self.dom_ref)
20            .finish()
21    }
22}
23
24impl HtmlElement {
25    /// Build a new HtmlElement
26    /// ```
27    /// HtmlElement::new().tag_name("div").build();
28    /// ```
29    pub fn new() -> HtmlElementBuilder<()> {
30        HtmlElementBuilder {
31            tag_name: (),
32            attributes: HashMap::new(),
33            callbacks: HashMap::new(),
34            dom_ref: None,
35        }
36    }
37
38    pub fn tag_name(&self) -> &str {
39        &self.tag_name
40    }
41
42    /// get a map of all the attributes:
43    /// For a `<div id="foo" class="bar">` this would return
44    /// `{"id": "foo", "class": "bar"}`
45    pub fn attributes(&self) -> &HashMap<String, String> {
46        &self.attributes
47    }
48
49    /// get a map of all the callbacks / event handlers:
50    /// For a `<div on_click=|_| { alert!("clicked")}>` this would return
51    /// `{ "click": |event| { alert!("clicked") } }`
52    pub fn callbacks(&self) -> &HashMap<String, EventHandler> {
53        &self.callbacks
54    }
55
56    /// get the dom reference of the element
57    pub fn dom_ref(&self) -> &Option<Arc<DomRef>> {
58        &self.dom_ref
59    }
60}
61
62pub struct HtmlElementBuilder<T> {
63    pub(crate) tag_name: T,
64    pub(crate) attributes: HashMap<String, String>,
65    pub(crate) callbacks: HashMap<String, EventHandler>,
66    pub(crate) dom_ref: Option<Arc<DomRef>>,
67}
68
69impl HtmlElementBuilder<()> {
70    pub fn tag_name(self, tag_name: &'static str) -> HtmlElementBuilder<&'static str> {
71        HtmlElementBuilder {
72            tag_name,
73            attributes: self.attributes,
74            callbacks: self.callbacks,
75            dom_ref: self.dom_ref,
76        }
77    }
78}
79
80impl<T> HtmlElementBuilder<T> {
81    /// set one specific attribute of the element:
82    /// ```
83    /// HtmlElement::new().tag_name("div").attr("id", "foo").build();
84    /// ```
85    /// builds a `<div id="foo">`
86    pub fn attr<K, V>(mut self, key: K, value: V) -> Self
87    where
88        K: Into<String>,
89        V: Into<String>,
90        V: Into<String>,
91    {
92        self.attributes.insert(key.into(), value.into());
93        self
94    }
95
96    /// Set one specific callback / event handler:
97    /// ```
98    /// HtmlElement::new().tag_name("div").on("click", |event| { alert!("clicked") }).build();
99    /// ```
100    /// builds a div that will send an alert on the "click"-event
101    pub fn on<K, C>(mut self, key: K, handler: C) -> Self
102    where
103        K: Into<String>,
104        C: Fn(web_sys::Event) + Send + Sync + 'static,
105    {
106        self.callbacks.insert(key.into(), Box::new(handler));
107        self
108    }
109
110    /// Get a dom reference to the element:
111    /// Use `use_ref::<DomRef>()` to obtain the `Arc<DomRef>` to pass to this method.
112    pub fn dom_ref(mut self, dom_ref: Arc<DomRef>) -> Self {
113        self.dom_ref = Some(dom_ref);
114        self
115    }
116}
117
118impl HtmlElementBuilder<&'static str> {
119    pub fn build(self) -> HtmlElement {
120        HtmlElement {
121            tag_name: self.tag_name,
122            attributes: self.attributes,
123            callbacks: self.callbacks,
124            dom_ref: self.dom_ref,
125        }
126    }
127}
128
129impl PartialEq for HtmlElement {
130    fn eq(&self, other: &Self) -> bool {
131        self.tag_name == other.tag_name
132            && self.attributes == other.attributes
133            && self.callbacks.is_empty()
134            && other.callbacks.is_empty()
135            && self.dom_ref == other.dom_ref
136    }
137}