// Package html renders an internal.AggregatorWriter as a complete, // standalone HTML document built around the same table fragment produced by // pretty.PrettyPrinter.RenderHTML. The document includes the Bootstrap 5.3 // stylesheet via CDN and embeds the raw table fragment without HTML-escaping // it so the result opens directly in a browser. package html import ( "fmt" "html/template" "io" "time" "github.com/nmoniz/any2anexoj/internal" "github.com/nmoniz/any2anexoj/internal/writing/pretty" ) // bootstrapCSSURL is the jsDelivr CDN URL for Bootstrap 5.3.3. const bootstrapCSSURL = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" // bootstrapIntegrity is the official SRI hash for Bootstrap 5.3.3 css. const bootstrapIntegrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" // HTMLWriter writes a complete HTML document for an AggregatorWriter. type HTMLWriter struct { output io.Writer printer *pretty.PrettyPrinter title string lang string } // NewHTMLWriter builds an HTMLWriter that writes a complete HTML document to // w. The printer is used purely as a source for the raw fragment via // RenderHTML; this writer never invokes Render or any method that writes to // printer's own io.Writer. func NewHTMLWriter(w io.Writer, printer *pretty.PrettyPrinter, title, lang string) *HTMLWriter { return &HTMLWriter{ output: w, printer: printer, title: title, lang: lang, } } // documentTemplate renders the full HTML page. The table fragment is typed as // template.HTML so the template engine emits it verbatim without escaping // the angle brackets in the
markup. var documentTemplate = template.Must(template.New("html").Parse(`{{.Title}}

{{.Title}}

{{.TableFragment}}

Generated at {{.GeneratedAt}}

`)) // Render writes a complete standalone HTML document for aw to the configured // output. The same HTMLWriter may be reused; each call rebuilds the table // fragment from aw so the rendered count reflects aw's current items and // no rows are duplicated across invocations. func (hw *HTMLWriter) Render(aw *internal.AggregatorWriter) error { if hw.printer == nil { return fmt.Errorf("html: nil printer") } fragment := hw.printer.RenderHTML(aw) data := struct { Lang string Title string CSSURL string Integrity string TableFragment template.HTML GeneratedAt string }{ Lang: hw.lang, Title: hw.title, CSSURL: bootstrapCSSURL, Integrity: bootstrapIntegrity, TableFragment: template.HTML(fragment), GeneratedAt: time.Now().UTC().Format(time.RFC3339), } if err := documentTemplate.Execute(hw.output, data); err != nil { return fmt.Errorf("render html document: %w", err) } return nil }