use crate::config::{Config, DisplayMode};
use crate::glossary::Term;
pub(super) fn render_term_html(
term: &Term,
matched_text: &str,
glossary_path: &str,
config: &Config,
) -> String {
let title_attr = term
.definition()
.map(|d| format!(r#" title="{}""#, html_escape(d)))
.unwrap_or_default();
let css_class = config.css_class();
let escaped = html_escape(matched_text);
let anchor = term.anchor();
match config.display_mode() {
DisplayMode::Link => format!(
r#"<a href="{glossary_path}#{anchor}"{title_attr} class="{css_class}">{escaped}</a>"#,
),
DisplayMode::Tooltip => {
format!(r#"<abbr{title_attr} tabindex="0" class="{css_class}">{escaped}</abbr>"#)
}
DisplayMode::Both => format!(
r#"<a href="{glossary_path}#{anchor}" class="{css_class}"><abbr{title_attr} tabindex="0">{escaped}</abbr></a>"#,
),
}
}
fn html_escape(text: &str) -> String {
text.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::config_with_display_mode;
fn term_with_definition() -> Term {
Term::with_definition("API", Some("Application Programming Interface".to_string()))
}
#[test]
fn html_escape_escapes_metacharacters() {
assert_eq!(html_escape("a < b"), "a < b");
assert_eq!(html_escape("a & b"), "a & b");
assert_eq!(html_escape("<script>"), "<script>");
assert_eq!(html_escape(r#"say "hello""#), "say "hello"");
}
#[test]
fn snapshot_link_mode() {
let html = render_term_html(
&term_with_definition(),
"API",
"glossary.html",
&config_with_display_mode(DisplayMode::Link),
);
insta::assert_snapshot!(html);
}
#[test]
fn snapshot_tooltip_mode() {
let html = render_term_html(
&term_with_definition(),
"API",
"glossary.html",
&config_with_display_mode(DisplayMode::Tooltip),
);
insta::assert_snapshot!(html);
}
#[test]
fn snapshot_both_mode() {
let html = render_term_html(
&term_with_definition(),
"API",
"glossary.html",
&config_with_display_mode(DisplayMode::Both),
);
insta::assert_snapshot!(html);
}
#[test]
fn snapshot_link_mode_without_definition() {
let html = render_term_html(
&Term::new("API"),
"API",
"glossary.html",
&config_with_display_mode(DisplayMode::Link),
);
insta::assert_snapshot!(html);
}
}