1pub fn esc(s: &str) -> String {
6 let mut out = String::with_capacity(s.len());
7 for c in s.chars() {
8 match c {
9 '&' => out.push_str("&"),
10 '<' => out.push_str("<"),
11 '>' => out.push_str(">"),
12 '"' => out.push_str("""),
13 '\'' => out.push_str("'"),
14 _ => out.push(c),
15 }
16 }
17 out
18}
19
20pub fn options(values: &[String], selected: Option<&str>) -> String {
22 values
23 .iter()
24 .map(|v| {
25 let sel = if Some(v.as_str()) == selected {
26 " selected"
27 } else {
28 ""
29 };
30 format!("<option value=\"{0}\"{sel}>{0}</option>", esc(v))
31 })
32 .collect()
33}
34
35pub fn labelled_options(pairs: &[(String, String)], selected: Option<&str>) -> String {
37 pairs
38 .iter()
39 .map(|(label, value)| {
40 let sel = if Some(value.as_str()) == selected {
41 " selected"
42 } else {
43 ""
44 };
45 format!(
46 "<option value=\"{}\"{sel}>{}</option>",
47 esc(value),
48 esc(label)
49 )
50 })
51 .collect()
52}
53
54pub fn checkbox(name: &str, label: &str, checked: bool) -> String {
56 format!(
57 "<label class=\"check\"><input type=\"checkbox\" name=\"{name}\"{}> {}</label>",
58 if checked { " checked" } else { "" },
59 esc(label)
60 )
61}
62
63pub fn text_input(name: &str, label: &str, placeholder: &str) -> String {
65 format!(
66 "<label class=\"field\"><span>{}</span><input name=\"{name}\" placeholder=\"{}\"></label>",
67 esc(label),
68 esc(placeholder)
69 )
70}
71
72pub fn number_input(name: &str, label: &str, value: i64) -> String {
74 format!(
75 "<label class=\"field\"><span>{}</span><input type=\"number\" min=\"0\" step=\"1\" name=\"{name}\" value=\"{value}\"></label>",
76 esc(label)
77 )
78}
79
80pub fn status(text: &str) -> String {
82 format!("<div class=\"status\">{}</div>", esc(text))
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn escapes_markup_and_quotes() {
91 assert_eq!(
92 esc("<a href=\"x\">'&'</a>"),
93 "<a href="x">'&'</a>"
94 );
95 assert_eq!(
96 options(&["a<b".into(), "c".into()], Some("c")),
97 "<option value=\"a<b\">a<b</option><option value=\"c\" selected>c</option>"
98 );
99 }
100}