use super::Node;
#[derive(Debug, Clone, PartialEq)]
pub struct HtmlAttribute {
pub name: String,
pub value: String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct HtmlElement {
pub tag: String,
pub attributes: Vec<HtmlAttribute>,
pub children: Vec<Node>,
pub self_closing: bool,
}
impl HtmlElement {
pub fn new(tag: &str) -> Self {
Self {
tag: tag.to_string(),
attributes: Vec::new(),
children: Vec::new(),
self_closing: false,
}
}
pub fn with_attribute(mut self, name: &str, value: &str) -> Self {
self.attributes.push(HtmlAttribute {
name: name.to_string(),
value: value.to_string(),
});
self
}
pub fn with_attributes(mut self, attrs: Vec<(&str, &str)>) -> Self {
for (name, value) in attrs {
self.attributes.push(HtmlAttribute {
name: name.to_string(),
value: value.to_string(),
});
}
self
}
pub fn with_children(mut self, children: Vec<Node>) -> Self {
self.children = children;
self
}
pub fn self_closing(mut self, is_self_closing: bool) -> Self {
self.self_closing = is_self_closing;
self
}
pub fn tag_matches_any(&self, tags: &[String]) -> bool {
tags.iter().any(|tag| tag.eq_ignore_ascii_case(&self.tag))
}
}
pub fn escape_html(content: &str) -> String {
content
.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
.replace('\'', "'")
}
pub fn safe_html(element: HtmlElement, disallowed_tags: &[String]) -> Node {
if element.tag_matches_any(disallowed_tags) {
let mut html_text = String::new();
html_text.push_str(&format!("<{}", element.tag));
for attr in &element.attributes {
html_text.push_str(&format!(" {}=\"{}\"", attr.name, attr.value));
}
if element.self_closing {
html_text.push_str(" />");
} else {
html_text.push_str(">");
for child in &element.children {
html_text.push_str(&format!("{}", child));
}
html_text.push_str(&format!("</{}>", element.tag));
}
Node::Text(html_text)
} else {
Node::HtmlElement(element)
}
}