use crate::types::{Attributes, Elements, Token};
pub trait Renderable {
fn html(&self) -> String;
fn text(&self) -> String;
}
impl Renderable for Token {
fn html(&self) -> String {
let borrowed = &self;
borrowed.html()
}
fn text(&self) -> String {
let borrowed = &self;
borrowed.text()
}
}
impl Renderable for &Token {
fn html(&self) -> String {
let mut result = String::new();
match self {
Token::Fragment { children } => {
result.push_str(&children.html());
}
Token::Element {
name,
attributes,
children,
..
} => {
result.push_str(&html_element(name, attributes, children));
}
Token::Span {
attributes,
children,
..
} => {
result.push_str(&html_element("span", attributes, children));
}
Token::Html { html } => {
result.push_str(&html);
}
Token::Text { text } => {
result.push_str(
&text
.replace('&', "&")
.replace('"', """)
.replace('<', "<")
.replace('>', ">"),
);
}
Token::Whitespace => {
result.push_str(" ");
}
Token::Placeholder { .. } | Token::Removed => {}
}
result
}
fn text(&self) -> String {
let mut result = String::new();
match self {
Token::Fragment { children }
| Token::Element { children, .. }
| Token::Span { children, .. } => {
result.push_str(&children.text());
}
Token::Html { html } => {
result.push_str(html);
}
Token::Text { text } => {
result.push_str(text);
}
Token::Whitespace => {
result.push_str(" ");
}
Token::Placeholder { .. } | Token::Removed => {}
};
result
}
}
impl Renderable for &Attributes {
fn html(&self) -> String {
let mut result = String::new();
if let Some(attributes) = &self {
for (key, value) in attributes {
result.push_str(&format!(
r#" {}="{}""#,
key,
value
.replace('&', "&")
.replace('"', """)
.replace('<', "<")
.replace('>', ">")
));
}
}
result
}
fn text(&self) -> String {
String::new()
}
}
impl Renderable for &Elements {
fn html(&self) -> String {
let mut result = String::new();
if let Some(elements) = &self {
for element in elements {
result.push_str(&element.html());
}
}
result
}
fn text(&self) -> String {
let mut result = String::new();
if let Some(elements) = &self {
for element in elements {
result.push_str(&element.text());
}
}
result
}
}
enum ElementType {
Text,
LinkedText,
Image,
LinkedImage,
}
fn html_element(name: &str, attributes: &Attributes, elements: &Elements) -> String {
let mut result = String::new();
match if let Some(attributes) = attributes {
if attributes.contains_key("href") && attributes.contains_key("src") {
ElementType::LinkedImage
} else if attributes.contains_key("src") {
ElementType::Image
} else if attributes.contains_key("href") {
ElementType::LinkedText
} else {
ElementType::Text
}
} else {
ElementType::Text
} {
ElementType::LinkedImage => {
let mut attributes = attributes.clone().unwrap();
let href = attributes.remove("href").unwrap();
result.push_str(&format!(
r#"<a href="{href}"><img{attributes} alt="{alt}"></a>"#,
alt = &Token::Element {
name: "none".into(),
tags: None,
attributes: None,
children: elements.clone(),
}
.text(),
attributes = (&Some(attributes)).html(),
href = href,
));
}
ElementType::Image => result.push_str(&format!(
r#"<img{attributes} alt="{alt}">"#,
alt = &Token::Element {
name: "none".into(),
tags: None,
attributes: None,
children: elements.clone(),
}
.text(),
attributes = attributes.html(),
)),
ElementType::LinkedText => result.push_str(&format!(
"<{name}><a{attributes}>{children}</a></{name}>",
name = name,
attributes = attributes.html(),
children = elements.html(),
)),
_ => result.push_str(&format!(
"<{name}{attributes}>{children}</{name}>",
name = name,
attributes = attributes.html(),
children = elements.html(),
)),
};
result
}