Newer
Older
use super::css::StyleSheet;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Item {
pub contents: Vec<HtmlElement>,
pub layout: StyleSheet,
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
self.contents
.iter()
.map(|item_content| item_content.to_string())
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlAttributes(pub HashMap<String, String>);
impl HtmlAttributes {
pub fn new() -> Self {
HtmlAttributes(HashMap::new())
}
pub fn get<S: Into<String>>(&self, key: S) -> Option<&String> {
self.0.get(&key.into())
}
impl std::fmt::Display for HtmlAttributes {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
self.0
.iter()
.map(|(key, value)| format!(" {}=\"{}\"", key, value))
.collect::<Vec<String>>()
.join("")
)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlElement {
pub tag: String,
pub text: Option<String>,
pub contents: Option<Vec<HtmlElement>>,
#[serde(default = "HtmlAttributes::new")]
pub attrs: HtmlAttributes,
}
impl std::fmt::Display for HtmlElement {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let body = match &self.contents {
Some(contents) => contents
.iter()
.map(|item| item.to_string())
.collect::<Vec<String>>()
.join(""),
None => match &self.text {
Some(text) => text.to_owned(),
None => String::new(),
},
write!(f, "<{}{}>{}</{}>", self.tag, self.attrs, body, self.tag)
}
}
#[cfg(test)]
mod test_items {
use super::*;
use std::collections::HashMap;
#[test]
fn text_item_content_to_string() {
tag: String::from("p"),
text: Some(String::from("Hello")),
contents: None,
};
assert_eq!(item_content.to_string(), "<p>Hello</p>")
}
#[test]
fn item_content_with_attrs_to_string() {
let mut attrs = HtmlAttributes::new();
attrs.0.insert(String::from("id"), String::from("some-id"));
let mut item_content = HtmlElement {
tag: String::from("p"),
text: Some(String::from("Hello")),
contents: None,
attrs: attrs.clone(),
};
assert_eq!(item_content.to_string(), "<p id=\"some-id\">Hello</p>");
item_content
.attrs
.0
.insert(String::from("class"), String::from("some-class"));
assert_eq!(
item_content.to_string(),
"<p id=\"some-id\" class=\"some-class\">Hello</p>"
);
}
#[test]
fn complex_item_content_to_string() {
tag: String::from("span"),
text: Some(String::from("Hello ")),
contents: None,
tag: String::from("b"),
text: Some(String::from("World")),
contents: None,
},
]),
};
assert_eq!(
item_content.to_string(),
"<p><span>Hello </span><b>World</b></p>"
)
}
#[test]
fn item_to_string() {
let item = Item {
layout: StyleSheet(HashMap::new()),
contents: vec![
tag: String::from("span"),
text: Some(String::from("Hello ")),
contents: None,
tag: String::from("b"),
text: Some(String::from("World")),
contents: None,
},
],
};
assert_eq!(item.to_string(), "<span>Hello </span><b>World</b>")
}
}