From 1e1cdee06a3bd5aaa0f97ad3c0d25aa505e723ef Mon Sep 17 00:00:00 2001 From: Blackle Morisanchetto Date: Fri, 2 Sep 2022 05:54:32 -0400 Subject: [PATCH] [feature] Emojify spoiler and content in web templates (#785) * Emojify spoiler and content in web templates * Use more performance emojify code (thanks NyaaaWhatsUpDoc!) --- internal/router/template.go | 52 +++++++++++++++++++++++++++++++++++++ web/source/css/base.css | 8 ++++++ web/template/status.tmpl | 4 +-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/internal/router/template.go b/internal/router/template.go index ebd8629e8..a9d5726ea 100644 --- a/internal/router/template.go +++ b/internal/router/template.go @@ -19,7 +19,9 @@ package router import ( + "bytes" "fmt" + "html" "html/template" "os" "path/filepath" @@ -28,6 +30,7 @@ import ( "github.com/gin-gonic/gin" "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/regexes" ) // LoadTemplates loads html templates for use by the given engine @@ -57,6 +60,11 @@ func oddOrEven(n int) string { return "odd" } +func escape(str string) template.HTML { + /* #nosec G203 */ + return template.HTML(template.HTMLEscapeString(str)) +} + func noescape(str string) template.HTML { /* #nosec G203 */ return template.HTML(str) @@ -97,12 +105,56 @@ func visibilityIcon(visibility model.Visibility) template.HTML { return template.HTML(fmt.Sprintf(``, icon.label, icon.faIcon)) } +// replaces shortcodes in `text` with the emoji in `emojis` +// text is a template.HTML to affirm that the input of this function is already escaped +func emojify(emojis []model.Emoji, text template.HTML) template.HTML { + emojisMap := make(map[string]model.Emoji, len(emojis)) + + for _, emoji := range emojis { + shortcode := ":" + emoji.Shortcode + ":" + emojisMap[shortcode] = emoji + } + + out := regexes.ReplaceAllStringFunc( + regexes.EmojiFinder, + string(text), + func(shortcode string, buf *bytes.Buffer) string { + // Look for emoji according to this shortcode + emoji, ok := emojisMap[shortcode] + if !ok { + return shortcode + } + + // Escape raw emoji content + safeURL := html.EscapeString(emoji.URL) + safeCode := html.EscapeString(emoji.Shortcode) + + // Write HTML emoji repr to buffer + buf.WriteString(`:`)
+			buf.WriteString(safeCode)
+			buf.WriteString(`:`) + + return buf.String() + }, + ) + + /* #nosec G203 */ + // (this is escaped above) + return template.HTML(out) +} + func LoadTemplateFunctions(engine *gin.Engine) { engine.SetFuncMap(template.FuncMap{ + "escape": escape, "noescape": noescape, "oddOrEven": oddOrEven, "visibilityIcon": visibilityIcon, "timestamp": timestamp, "timestampShort": timestampShort, + "emojify": emojify, }) } diff --git a/web/source/css/base.css b/web/source/css/base.css index ba9fef606..3cdf19fe8 100644 --- a/web/source/css/base.css +++ b/web/source/css/base.css @@ -323,3 +323,11 @@ footer { grid-template-columns: 1fr; } } + +.emoji { + width: 2.5ex; + height: 2.5ex; + margin: -0.5ex 0 0; + object-fit: contain; + vertical-align: middle; +} \ No newline at end of file diff --git a/web/template/status.tmpl b/web/template/status.tmpl index decad4764..56d98d89b 100644 --- a/web/template/status.tmpl +++ b/web/template/status.tmpl @@ -6,12 +6,12 @@ {{if .SpoilerText}}
- {{.SpoilerText}} + {{emojify .Emojis (escape .SpoilerText)}}
{{end}}
- {{.Content |noescape}} + {{emojify .Emojis (noescape .Content)}}
{{with .MediaAttachments}}