html_site_generator/html/
hyperlink.rs1use std::io::Write;
2
3use anyhow::Result;
4use derive_builder::Builder;
5use html_site_generator_macro::DeriveSetHtmlAttributes;
6
7use crate::attributes::HtmlAttributes;
8use crate::html::{IntoHtmlNode, IsParagraph};
9
10#[derive(Debug, Clone)]
12pub enum ReferrerPolicy {
13 NoReferrer,
14 NoReferrerWhenDowngrade,
15 Origin,
16 OriginWhenCrossOrigin,
17 SameOrigin,
18 StrictOriginWhenCrossOrigin,
19 UnsafeUrl,
20}
21
22impl ReferrerPolicy {
23 pub(crate) fn to_html_string(&self) -> &'static str {
24 match self {
25 ReferrerPolicy::NoReferrer => "no-referrer",
26 ReferrerPolicy::NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
27 ReferrerPolicy::Origin => "origin",
28 ReferrerPolicy::OriginWhenCrossOrigin => "origin-when-cross-origin",
29 ReferrerPolicy::SameOrigin => "same-origin",
30 ReferrerPolicy::StrictOriginWhenCrossOrigin => "strict-origin-when-cross-origin",
31 ReferrerPolicy::UnsafeUrl => "unsafe-url",
32 }
33 }
34}
35
36#[derive(Debug, Clone)]
38pub enum Relationship {
39 Alternate,
40 Author,
41 Bookmark,
42 External,
43 Help,
44 License,
45 Next,
46 NoFollow,
47 NoReferrer,
48 NoOpener,
49 Prev,
50 Search,
51 Tag,
52}
53
54impl Relationship {
55 fn to_html_string(&self) -> &'static str {
56 match self {
57 Relationship::Alternate => "alternate",
58 Relationship::Author => "author",
59 Relationship::Bookmark => "bookmark",
60 Relationship::External => "external",
61 Relationship::Help => "help",
62 Relationship::License => "license",
63 Relationship::Next => "next",
64 Relationship::NoFollow => "nofollow",
65 Relationship::NoReferrer => "noreferrer",
66 Relationship::NoOpener => "noopener",
67 Relationship::Prev => "prev",
68 Relationship::Search => "search",
69 Relationship::Tag => "tag",
70 }
71 }
72}
73
74#[derive(Debug, Clone)]
76pub enum Target {
77 Blank,
78 Parent,
79 SSelf,
81 Top,
82}
83
84impl Target {
85 fn to_html_string(&self) -> &'static str {
86 match self {
87 Target::Blank => "_blank",
88 Target::Parent => "_parent",
89 Target::SSelf => "_self",
90 Target::Top => "_top",
91 }
92 }
93}
94
95#[derive(Debug, Builder, DeriveSetHtmlAttributes)]
97pub struct Hyperlink {
98 #[builder(setter(strip_option, into), default)]
100 download: Option<String>,
101
102 #[builder(setter(strip_option, into), default)]
104 href: Option<String>,
105
106 #[builder(setter(strip_option, into), default)]
108 href_lang: Option<String>,
109
110 #[builder(setter(strip_option, into), default)]
112 media: Option<String>,
113
114 #[builder(setter(strip_option, into), default)]
118 ping: Option<String>,
119
120 #[builder(setter(strip_option, into), default)]
122 referrer_policy: Option<ReferrerPolicy>,
123
124 #[builder(default = "Some(vec![Relationship::NoOpener, Relationship::NoReferrer])")]
126 rel: Option<Vec<Relationship>>,
127
128 #[builder(default = "Some(Target::Blank)")]
130 target: Option<Target>,
131
132 #[builder(setter(strip_option, into), default)]
135 mime_type: Option<String>,
136
137 #[builder(setter(skip))]
138 children: Vec<Box<dyn IntoHtmlNode>>,
139
140 #[builder(setter(skip))]
141 _attributes: HtmlAttributes,
142}
143
144impl Hyperlink {
145 pub fn add_element(&mut self, item: impl IntoHtmlNode + 'static) {
146 self.children.push(Box::new(item))
147 }
148}
149
150impl IntoHtmlNode for Hyperlink {
151 fn transform_into_html_node(&self, buffer: &mut dyn Write) -> Result<()> {
152 write!(buffer, "<a")?;
153 self._attributes.transform_into_html_node(buffer)?;
154
155 if let Some(value) = &self.download {
156 write!(buffer, " download=\"{}\"", value)?;
157 }
158 if let Some(value) = &self.href {
159 write!(buffer, " href=\"{}\"", value)?;
160 }
161 if let Some(value) = &self.href_lang {
162 write!(buffer, " hreflang=\"{}\"", value)?;
163 }
164 if let Some(value) = &self.media {
165 write!(buffer, " media=\"{}\"", value)?;
166 }
167 if let Some(value) = &self.ping {
168 write!(buffer, " ping=\"{}\"", value)?;
169 }
170 if let Some(value) = &self.referrer_policy {
171 write!(buffer, " referrerpolicy=\"{}\"", value.to_html_string())?;
172 }
173 if let Some(value) = &self.rel {
174 let raw = value
175 .iter()
176 .map(|item| item.to_html_string())
177 .enumerate()
178 .fold("".to_string(), |acc, (i, item)| {
179 acc + if i == 0 { "" } else { " " } + item
180 });
181
182 write!(buffer, " rel=\"{}\"", raw)?;
183 }
184 if let Some(value) = &self.target {
185 write!(buffer, " target=\"{}\"", value.to_html_string())?;
186 }
187 if let Some(value) = &self.mime_type {
188 write!(buffer, " type=\"{}\"", value)?;
189 }
190
191 write!(buffer, ">")?;
192
193 for child in &self.children {
194 child.transform_into_html_node(buffer)?;
195 }
196
197 writeln!(buffer, "</a>")?;
198
199 Ok(())
200 }
201}
202
203impl IsParagraph for Hyperlink {
208 fn to_raw(&self) -> String {
209 let mut vec = Vec::new();
210
211 self.transform_into_html_node(&mut vec).unwrap();
212
213 String::from_utf8(vec).unwrap()
214 }
215}