mod escape;
mod layout;
mod noscript;
mod outline;
mod style;
mod svg;
use std::io::Write;
use crate::localization::{self, keys};
use super::GraphView;
use super::render::{GraphRenderError, GraphRenderer};
use escape::{escape_attr, escape_text};
use layout::layout_positions;
use noscript::write_noscript;
use outline::write_outline;
use style::write_inline_style;
use svg::{SvgHeader, write_svg};
#[derive(Debug, Clone)]
pub struct HtmlRenderer {
locale: String,
}
impl Default for HtmlRenderer {
fn default() -> Self {
Self::new(None)
}
}
impl HtmlRenderer {
#[must_use]
pub fn new(locale: Option<&str>) -> Self {
Self {
locale: locale.unwrap_or("en").to_owned(),
}
}
}
impl GraphRenderer for HtmlRenderer {
fn render(&self, view: &GraphView, sink: &mut dyn Write) -> Result<(), GraphRenderError> {
let positions = layout_positions(view);
let title = localized(keys::GRAPH_HTML_TITLE);
let heading = localized(keys::GRAPH_HTML_HEADING);
let description = format!(
"{} ({}, {})",
localized(keys::GRAPH_HTML_DESCRIPTION),
view.nodes.len(),
view.edges.len()
);
let outline_summary = localized(keys::GRAPH_HTML_OUTLINE_SUMMARY);
let noscript_notice = localized(keys::GRAPH_HTML_NOSCRIPT_NOTICE);
writeln!(sink, "<!doctype html>")?;
writeln!(sink, "<html lang=\"{}\">", escape_attr(&self.locale))?;
writeln!(sink, "<head>")?;
writeln!(sink, " <meta charset=\"utf-8\">")?;
writeln!(
sink,
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
)?;
writeln!(sink, " <title>{}</title>", escape_text(&title))?;
write_inline_style(sink)?;
writeln!(sink, "</head>")?;
writeln!(sink, "<body>")?;
writeln!(sink, " <h1>{}</h1>", escape_text(&heading))?;
write_svg(
sink,
view,
&positions,
SvgHeader {
title: &title,
description: &description,
},
)?;
write_outline(sink, view, &outline_summary)?;
write_noscript(sink, view, &noscript_notice)?;
writeln!(sink, "</body>")?;
writeln!(sink, "</html>")?;
Ok(())
}
}
pub(super) fn localized(key: &'static str) -> String {
localization::message(key).to_string()
}
#[cfg(test)]
mod tests;