From 6b6b5d2e35ff182a0732da245f4eb37c8afa0564 Mon Sep 17 00:00:00 2001 From: grm Date: Wed, 16 Sep 2026 18:37:20 +0300 Subject: Add an HTML mode to posts, page intros and announcements Markdown is the default and unchanged; the editor's new Format switch stores the text as raw HTML instead, put on the blog exactly as written. Like the custom HTML module it is unsanitised on purpose: the escape hatch for embeds, scripts and inline styles that Markdown cannot express. The source column keeps holding the text in both modes and a `format` column says how to read it, so the public templates and the feed still print the stored `*_html`. The dashboard preview of HTML goes into a sandboxed iframe rather than the page, because a superadmin edits other people's blogs and their markup must never run on the dashboard origin. Search snippets of HTML posts are cut from a tag-stripped copy. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A --- internal/web/web_test.go | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'internal/web/web_test.go') diff --git a/internal/web/web_test.go b/internal/web/web_test.go index b803003..48f380e 100644 --- a/internal/web/web_test.go +++ b/internal/web/web_test.go @@ -491,15 +491,41 @@ func TestFileMarkdown(t *testing.T) { if got := fileMarkdown(doc); got != "[notes v2.pdf](/media/6ba7b810-9dad-11d1-80b4-00c04fd430c8)" { t.Errorf("document should be a link: %q", got) } - if got := appendFileMD("", img); got != line+"\n" { + if got := appendFile("", img, store.FormatMarkdown); got != line+"\n" { t.Errorf("empty body: %q", got) } - if got := appendFileMD("hello\n", img); got != "hello\n\n"+line+"\n" { + if got := appendFile("hello\n", img, store.FormatMarkdown); got != "hello\n\n"+line+"\n" { t.Errorf("appended: %q", got) } - if got := appendFileMD("hello", nil); got != "hello" { + if got := appendFile("hello", nil, store.FormatMarkdown); got != "hello" { t.Errorf("nil file should not change the body: %q", got) } + // HTML mode: tags, with the name escaped + img.Filename = `a "cat" <3.png` + tag := `a "cat" <3.png` + if got := fileHTML(img); got != tag { + t.Errorf("image tag: %q", got) + } + if got := fileHTML(doc); got != `notes +v2.pdf` { + t.Errorf("document link: %q", got) + } + if got := appendFile("

hi

", img, store.FormatHTML); got != "

hi

\n\n"+tag+"\n" { + t.Errorf("html appended: %q", got) + } +} + +func TestRenderBody(t *testing.T) { + raw := "**x**\n\n" + if got := renderBody(store.FormatHTML, raw); got != raw { + t.Errorf("html must pass through untouched: %q", got) + } + if got := renderBody(store.FormatMarkdown, raw); !strings.Contains(got, "x") || strings.Contains(got, "