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/handlers_blog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'internal/web/handlers_blog.go') diff --git a/internal/web/handlers_blog.go b/internal/web/handlers_blog.go index e842e84..6538c34 100644 --- a/internal/web/handlers_blog.go +++ b/internal/web/handlers_blog.go @@ -171,7 +171,7 @@ func (s *Server) handleBlogSearch(w http.ResponseWriter, r *http.Request) { re := regexp.MustCompile("(?is)" + pattern) // (?s): "." crosses lines as it does in Postgres; QuoteMeta output always compiles hits := make([]searchHit, 0, len(posts)) for _, p := range posts { - hits = append(hits, searchHit{Post: p, Snippet: searchSnippet(p.BodyMD, re)}) + hits = append(hits, searchHit{Post: p, Snippet: searchSnippet(snippetSource(&p), re)}) } v["hits"], v["total"], v["pageNum"], v["lastPage"] = hits, total, n, (total+searchPerPage-1)/searchPerPage } -- cgit v1.2.3