1use crate::{Html, HtmlContainer, HtmlElement, HtmlTag};
4use std::fmt::{self, Display};
5
6#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
8#[non_exhaustive]
9pub enum ContainerType {
10 Address,
12 Article,
14 #[default]
18 Div,
19 Footer,
21 Header,
23 Main,
25 OrderedList,
27 UnorderedList,
29 Nav,
31 Section,
33}
34
35impl From<ContainerType> for HtmlTag {
36 fn from(value: ContainerType) -> Self {
37 match value {
38 ContainerType::Address => HtmlTag::Address,
39 ContainerType::Article => HtmlTag::Article,
40 ContainerType::Div => HtmlTag::Div,
41 ContainerType::Footer => HtmlTag::Footer,
42 ContainerType::Header => HtmlTag::Header,
43 ContainerType::Main => HtmlTag::Main,
44 ContainerType::OrderedList => HtmlTag::OrderedList,
45 ContainerType::UnorderedList => HtmlTag::UnorderedList,
46 ContainerType::Nav => HtmlTag::Navigation,
47 ContainerType::Section => HtmlTag::Section,
48 }
49 }
50}
51
52impl Display for ContainerType {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 HtmlTag::from(*self).fmt(f)
55 }
56}
57
58#[derive(Debug)]
86pub struct Container(HtmlElement);
87
88impl Default for Container {
89 fn default() -> Self {
90 Self::new(Default::default())
91 }
92}
93
94impl Html for Container {
95 fn to_html_string(&self) -> String {
96 self.0.to_html_string()
97 }
98}
99
100impl HtmlContainer for Container {
101 fn add_html<H: Html>(&mut self, content: H) {
102 match self.0.tag {
103 HtmlTag::OrderedList | HtmlTag::UnorderedList => self.0.add_child(
104 HtmlElement::new(HtmlTag::ListElement)
105 .with_html(content)
106 .into(),
107 ),
108 _ => self.0.add_html(content),
109 };
110 }
111}
112
113impl Container {
114 pub fn new(tag: ContainerType) -> Self {
116 Self(HtmlElement::new(tag.into()))
117 }
118
119 pub fn with_attributes<A, S>(mut self, attributes: A) -> Self
135 where
136 A: IntoIterator<Item = (S, S)>,
137 S: ToString,
138 {
139 for (k, v) in attributes {
140 self.0.add_attribute(k, v);
141 }
142 self
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_content() {
152 let content = concat!(
154 r#"<h1 id="main-header">header</h1>"#,
155 r#"<img src="myimage.png" alt="test image"/>"#,
156 r#"<a href="rust-lang.org">Rust Home</a>"#,
157 r#"<p class="red-text">Sample Text</p>"#,
158 r#"<pre class="code">Text</pre>"#
159 );
160
161 let sut = Container::new(ContainerType::Article)
163 .with_header_attr(1, "header", [("id", "main-header")])
164 .with_image("myimage.png", "test image")
165 .with_link("rust-lang.org", "Rust Home")
166 .with_paragraph_attr("Sample Text", [("class", "red-text")])
167 .with_preformatted_attr("Text", [("class", "code")]);
168
169 assert_eq!(
171 sut.to_html_string(),
172 format!(
173 "<{tag}>{content}</{tag}>",
174 tag = ContainerType::Article,
175 content = content
176 )
177 )
178 }
179
180 #[test]
181 fn test_list() {
182 let content = concat!(
184 r#"<li><h1 id="main-header">header</h1></li>"#,
185 r#"<li><img src="myimage.png" alt="test image"/></li>"#,
186 r#"<li><a href="rust-lang.org">Rust Home</a></li>"#,
187 r#"<li><p class="red-text">Sample Text</p></li>"#,
188 r#"<li><pre class="code">Text</pre></li>"#
189 );
190
191 let sut = Container::new(ContainerType::OrderedList)
193 .with_header_attr(1, "header", [("id", "main-header")])
194 .with_image("myimage.png", "test image")
195 .with_link("rust-lang.org", "Rust Home")
196 .with_paragraph_attr("Sample Text", [("class", "red-text")])
197 .with_preformatted_attr("Text", [("class", "code")]);
198
199 assert_eq!(
201 sut.to_html_string(),
202 format!(
203 "<{tag}>{content}</{tag}>",
204 tag = ContainerType::OrderedList,
205 content = content
206 )
207 )
208 }
209
210 #[test]
211 fn test_nesting() {
212 let container = Container::new(ContainerType::Main)
214 .with_paragraph("paragraph")
215 .with_container(
216 Container::new(ContainerType::OrderedList)
217 .with_container(Container::default().with_paragraph(1))
218 .with_container(Container::default().with_paragraph('2'))
219 .with_container(Container::default().with_paragraph("3")),
220 )
221 .with_paragraph("done");
222
223 assert_eq!(
225 container.to_html_string(),
226 concat!(
227 "<main><p>paragraph</p><ol>",
228 "<li><div><p>1</p></div></li>",
229 "<li><div><p>2</p></div></li>",
230 "<li><div><p>3</p></div></li>",
231 "</ol><p>done</p></main>"
232 )
233 )
234 }
235}