shele/element/
mod.rs

1pub(crate) mod template;
2
3use std::collections::HashMap;
4use std::{fmt, hash};
5
6use template::Template;
7
8/// Represents a children in a HTML Element.
9///
10/// Used as a Box for usage of any type that implements the `Template` trait.
11pub type Children<'a> = Vec<Box<dyn Template + 'a>>;
12
13/// Represents the attributes in a HTML Element.
14///
15/// Attributes are all the parameters that are not tags.
16/// For example, using the `styles` attribute could be used to change the css in a given Element.
17pub type Attributes<'a> = HashMap<&'a str, &'a str>;
18
19/// Struct representing a HTML Element.
20/// Any content that would be inside a tag, is considered a Child.
21/// Any parameter or prop to the element, is considered an Attribute.
22///
23/// ```
24/// use shele::element::Element;
25///
26/// // Creating a div with a red text
27/// let el = Element::new("div")
28///    .add_child("Hello, world")
29///    .add_attr("styles", "color: red;");
30///
31/// assert_eq!(el.to_string(), "<div styles=\"color: red;\">Hello, world</div>");
32/// ```
33#[derive(Debug)]
34pub struct Element<'a> {
35    tagname: String,
36    children: Children<'a>,
37    attrs: Attributes<'a>,
38}
39
40impl<'a> Element<'a> {
41    /// Creates a new HTML Element
42    pub fn new(tagname: impl ToString) -> Self {
43        Self {
44            tagname: tagname.to_string(),
45            children: Vec::new(),
46            attrs: HashMap::new(),
47        }
48    }
49
50    /// Creates a new HTML Element with prepopulated children
51    ///
52    /// Same as calling `Element::new`, followed by a `Element::children`
53    pub fn with<T: Template + 'a, const N: usize>(tagname: impl ToString, content: [T; N]) -> Self {
54        Self::new(tagname).children(content)
55    }
56
57    /// Getter for the tag of the HTML Element.
58    pub fn get_tag_name(&self) -> &str {
59        self.tagname.as_str()
60    }
61
62    /// Getter for the internal representation of children for an HTML Element.
63    /// The returning type is the internal representation of the children.
64    /// Since the type is boxed, there will be no difference in the API.
65    pub fn get_children(&self) -> &Children {
66        &self.children
67    }
68
69    /// Getter for the attributes of an HTML Element.
70    pub fn get_attrs(&self) -> &Attributes {
71        &self.attrs
72    }
73
74    /// Adds one child to the end of the children.
75    pub fn add_child<T: Template + 'a>(mut self, template: T) -> Self {
76        self.children.push(Box::new(template));
77
78        self
79    }
80
81    /// Adds one attribute to Element.
82    /// If an attribute with the same key already exists, it will be replaced by the new value.
83    pub fn add_attr(mut self, key: &'a str, value: &'a str) -> Self {
84        self.attrs.insert(key, value);
85
86        self
87    }
88
89    /// Replaces all the content(children) inside this Element.
90    /// Unlike the `Element::children` function, this function uses the internal representation of a children, without doing any checks.
91    pub fn children_boxed(mut self, ch: Children<'a>) -> Self {
92        self.children = ch;
93
94        self
95    }
96
97    /// Replaces all the content(children) inside this Element.
98    pub fn children<T: Template + 'a, const N: usize>(mut self, ch: [T; N]) -> Self {
99        self.children = ch
100            .into_iter()
101            .map(|c| -> Box<dyn Template> { Box::new(c) })
102            .collect::<Children<'a>>();
103
104        self
105    }
106
107    /// Replaces all the attributes inside this Element.
108    pub fn attributes(mut self, attrs: Attributes<'a>) -> Self {
109        self.attrs = attrs;
110
111        self
112    }
113}
114
115impl<'a> fmt::Display for Element<'a> {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        let children = self
118            .get_children()
119            .iter()
120            .map(|templ| templ.to_string())
121            .collect::<String>();
122
123        let attrs = self
124            .get_attrs()
125            .iter()
126            .map(|(k, v)| format!("{k}=\"{v}\""))
127            .collect::<Vec<_>>()
128            .join(" ");
129
130        let tag = format!(
131            "<{tag} {attrs}>{child}</{tag}>",
132            tag = self.get_tag_name(),
133            child = children,
134            attrs = attrs,
135        )
136        .replace(" >", ">");
137
138        write!(f, "{}", tag)
139    }
140}
141
142impl<'a> Eq for Element<'a> {}
143impl<'a> PartialEq for Element<'a> {
144    fn eq(&self, other: &Self) -> bool {
145        self.tagname == other.get_tag_name() && self.attrs == *other.get_attrs()
146    }
147}
148
149impl<'a> Ord for Element<'a> {
150    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
151        self.to_string().cmp(&other.to_string())
152    }
153}
154
155impl<'a> PartialOrd for Element<'a> {
156    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
157        self.to_string().partial_cmp(&other.to_string())
158    }
159}
160
161impl<'a> Default for Element<'a> {
162    fn default() -> Self {
163        Self::new("")
164    }
165}
166
167impl<'a> hash::Hash for Element<'a> {
168    fn hash<H: hash::Hasher>(&self, state: &mut H) {
169        let stringified = self.to_string();
170        let bytes = stringified.as_bytes();
171
172        state.write(bytes);
173        state.finish();
174    }
175}