html_site_generator/html/
link.rs

1use std::io::Write;
2
3use anyhow::Result;
4use derive_builder::Builder;
5
6use crate::html::hyperlink::ReferrerPolicy;
7use crate::html::IntoHtmlNode;
8
9/// Specifies how the element handles cross-origin requests
10#[derive(Debug, Clone)]
11pub enum CrossOrigin {
12    Anonymous,
13    UseCredentials,
14}
15
16impl CrossOrigin {
17    pub(crate) fn to_html_string(&self) -> &'static str {
18        match self {
19            CrossOrigin::Anonymous => "anonymous",
20            CrossOrigin::UseCredentials => "use-credentials",
21        }
22    }
23}
24
25/// Specifies the relationship between the current document and the linked document
26#[derive(Debug, Clone, Default)]
27pub enum Relationship {
28    Alternate,
29    Author,
30    DnsPrefetch,
31    Help,
32    Icon,
33    License,
34    Next,
35    Pingback,
36    Preconnect,
37    Prefetch,
38    Preload,
39    Prerender,
40    Prev,
41    Search,
42    #[default]
43    Stylesheet,
44}
45
46impl Relationship {
47    fn to_html_string(&self) -> &'static str {
48        match self {
49            Relationship::Alternate => "alternate",
50            Relationship::Author => "author",
51            Relationship::DnsPrefetch => "dns-prefetch",
52            Relationship::Help => "help",
53            Relationship::Icon => "icon",
54            Relationship::License => "license",
55            Relationship::Next => "next",
56            Relationship::Pingback => "pingback",
57            Relationship::Preconnect => "preconnect",
58            Relationship::Prefetch => "prefetch",
59            Relationship::Preload => "preload",
60            Relationship::Prerender => "prerender",
61            Relationship::Prev => "prev",
62            Relationship::Search => "search",
63            Relationship::Stylesheet => "stylesheet",
64        }
65    }
66}
67
68/// HTML Attribute: [`<link>`](https://www.w3schools.com/tags/tag_link.asp)
69#[derive(Debug, Default, Builder)]
70pub struct Link {
71    /// Specifies how the element handles cross-origin requests
72    #[builder(setter(strip_option), default)]
73    crossorigin: Option<CrossOrigin>,
74
75    /// Specifies the location of the linked document
76    #[builder(setter(strip_option, into), default)]
77    href: Option<String>,
78
79    /// Specifies the language of the text in the linked document
80    #[builder(setter(strip_option, into), default)]
81    href_lang: Option<String>,
82
83    /// Specifies on what device the linked document will be displayed
84    #[builder(setter(strip_option, into), default)]
85    media: Option<String>,
86
87    /// Specifies which referrer to use when fetching the resource
88    #[builder(setter(strip_option), default)]
89    referrer_policy: Option<ReferrerPolicy>,
90
91    /// Specifies the relationship between the current document and the linked document
92    rel: Relationship,
93
94    /// Specifies the size of the linked resource. Only for rel="icon"
95    #[builder(setter(strip_option, into), default)]
96    sizes: Option<String>,
97
98    /// Defines a preferred or an alternate stylesheet
99    #[builder(setter(strip_option, into), default)]
100    title: Option<String>,
101
102    // TODO maybe use a crate with mime types
103    /// Specifies the media type of the linked document
104    #[builder(setter(strip_option, into), default)]
105    media_type: Option<String>,
106}
107
108impl IntoHtmlNode for Link {
109    fn transform_into_html_node(&self, buffer: &mut dyn Write) -> Result<()> {
110        write!(buffer, "<link")?;
111
112        if let Some(value) = &self.crossorigin {
113            write!(buffer, " crossorigin=\"{}\"", value.to_html_string())?;
114        }
115        if let Some(value) = &self.href {
116            write!(buffer, " href=\"{}\"", value)?;
117        }
118        if let Some(value) = &self.href_lang {
119            write!(buffer, " hreflang=\"{}\"", value)?;
120        }
121        if let Some(value) = &self.media {
122            write!(buffer, " media=\"{}\"", value)?;
123        }
124        if let Some(value) = &self.referrer_policy {
125            write!(buffer, " referrerpolicy=\"{}\"", value.to_html_string())?;
126        }
127        write!(buffer, " rel=\"{}\"", self.rel.to_html_string())?;
128        if let Some(value) = &self.sizes {
129            write!(buffer, " sizes=\"{}\"", value)?;
130        }
131        if let Some(value) = &self.title {
132            write!(buffer, " title=\"{}\"", value)?;
133        }
134        if let Some(value) = &self.title {
135            write!(buffer, " title=\"{}\"", value)?;
136        }
137        if let Some(value) = &self.media_type {
138            write!(buffer, " type=\"{}\"", value)?;
139        }
140
141        writeln!(buffer, ">")?;
142
143        Ok(())
144    }
145}