feat: Markdown 工具栏编辑器与服务端预览

共用 md_editor 于发帖/改帖/评论,扩展 ComposeBodyToHTML,并提供 /compose/preview。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 04:50:07 +08:00
parent 7f048bd9b5
commit 1f777eebb1
17 changed files with 1056 additions and 232 deletions

View File

@@ -2,7 +2,6 @@ package web
import (
"fmt"
"html"
"net/http"
"net/url"
"strconv"
@@ -510,7 +509,7 @@ func (d Deps) PostComment(c *gin.Context) {
ctx.Redirect(fmt.Sprintf("/post/%d#comments", id))
return
}
safe := "<p>" + html.EscapeString(content) + "</p>"
safe := services.ComposeBodyToHTML(content)
cm, err := d.Comment.Create(services.CommentCreateInput{
PostID: id, UserID: ctx.UserID(), Content: safe,
ReplyTo: replyTo, IsPrivate: isPrivate,
@@ -815,7 +814,7 @@ func (d Deps) CommentEditGet(c *gin.Context) {
PostID: postID,
CommentID: cm.ID,
Floor: cm.Floor,
Content: commentHTMLToPlain(cm.Content),
Content: services.HTMLToComposePlain(cm.Content),
})
}
@@ -841,7 +840,7 @@ func (d Deps) CommentEditPost(c *gin.Context) {
d.renderCommentEdit(ctx, "评论不能为空", postID, cm, plain)
return
}
safe := "<p>" + html.EscapeString(plain) + "</p>"
safe := services.ComposeBodyToHTML(plain)
_, enteredPending, err := d.Comment.Update(ctx.UserID(), cm.ID, ctx.IsAdmin(), ctx.SkipsModeration(), safe)
if err != nil {
d.renderCommentEdit(ctx, err.Error(), postID, cm, plain)
@@ -923,14 +922,6 @@ func (d Deps) renderCommentEdit(ctx *webctx.Context, errMsg string, postID uint,
})
}
// commentHTMLToPlain 发评存的是转义后的 <p>…</p>,编辑时还原为纯文本
func commentHTMLToPlain(s string) string {
s = strings.TrimSpace(s)
s = strings.TrimPrefix(s, "<p>")
s = strings.TrimSuffix(s, "</p>")
return html.UnescapeString(s)
}
type postRevisionRow struct {
ID uint
EditorName string