Newer
Older
pub const CSS_LINK_FRAGMENT: &'static str = "<link rel='stylesheet' href='{url}'>";
pub const SCRIPT_FRAGMENT: &'static str = "<script src='{url}'></script>";
pub const FAVICON_LINK_FRAGMENT: &'static str = "<link rel='icon' type='image/*' href='{url}'/>";
pub const IMAGE_LINKS_FRAGMENT: &'static str = "<meta name='image' content='{url}'/>
<meta property='og:image' content='{url}'/>
<meta property='twitter:image' content='{url}'/>";
<html lang='{lang}' prefix='og: https://ogp.me/ns#'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta name='description' content='{description}'>
<meta name='author' content='{author}'>
<meta property='og:title' content='{title}'/>
<meta property='og:description' content='{description}'/>
{image}
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<title>{title}</title>
{css}
</head>
<body>
{body}
</body>
{js}
</html>
";
pub fn replace_placeholders(template: &str, map: HashMap<String, String>) -> String {
let re = Regex::new(r#"\{[a-z]+\}"#).unwrap();
let def = String::new();
re.replace_all(template, |captures: &Captures| {
let placeholder = captures.iter().next().unwrap().unwrap().as_str();
let placeholder = placeholder[1..placeholder.len() - 1].to_owned(); // strip the brackets
match map.get(&placeholder) {
Some(s) => s,
None => &def,
}
})
.to_string()
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlDoc(String);
impl HtmlDoc {
pub fn from_page(page: &Page) -> Self {
HtmlDoc(replace_placeholders(HTML_DOC_TEMPLATE, page.to_map()))
}
pub fn new() -> Self {
HtmlDoc(String::new())
}
}
impl std::fmt::Display for HtmlDoc {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
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 HtmlElement {
pub fn set_contents(&mut self, contents: Vec<HtmlElement>) {
self.contents = Some(contents);
}
}
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()
None => match &self.text {
Some(text) => text.to_owned(),
None => String::new(),
},
write!(f, "<{}{}>{}</{}>", self.tag, self.attrs, body, self.tag)
fn text_html_element_to_string() {
let html_el = HtmlElement {
tag: String::from("p"),
text: Some(String::from("Hello")),
contents: None,
let mut attrs = HtmlAttributes::new();
attrs.0.insert(String::from("id"), String::from("some-id"));
tag: String::from("p"),
text: Some(String::from("Hello")),
contents: None,
attrs: attrs.clone(),
};
assert_eq!(html_el.to_string(), "<p id=\"some-id\">Hello</p>");
fn complex_html_el_to_string() {
let html_el = HtmlElement {
tag: String::from("span"),
text: Some(String::from("Hello ")),
contents: None,
tag: String::from("b"),
text: Some(String::from("World")),
contents: None,
"<p><span>Hello </span><b>World</b></p>"
)
}
}