feat(ui): add more emoji and code block rendering in issues

This commit is contained in:
Bram Hagens 2024-07-17 01:37:20 +02:00
parent 60bcdc8bc3
commit 4a74113dee
No known key found for this signature in database
GPG key ID: CEF9728B2127ECDC
14 changed files with 322 additions and 34 deletions

View file

@ -73,6 +73,8 @@ var (
// EmojiShortCodeRegex find emoji by alias like :smile:
EmojiShortCodeRegex = regexp.MustCompile(`:[-+\w]+:`)
InlineCodeBlockRegex = regexp.MustCompile("`[^`]+`")
)
// CSS class for action keywords (e.g. "closes: #1")
@ -243,6 +245,7 @@ func RenderIssueTitle(
title string,
) (string, error) {
return renderProcessString(ctx, []processor{
inlineCodeBlockProcessor,
issueIndexPatternProcessor,
commitCrossReferencePatternProcessor,
hashCurrentPatternProcessor,
@ -251,6 +254,19 @@ func RenderIssueTitle(
}, title)
}
// RenderRefIssueTitle to process title on places where an issue is referenced
func RenderRefIssueTitle(
ctx *RenderContext,
title string,
) (string, error) {
return renderProcessString(ctx, []processor{
inlineCodeBlockProcessor,
issueIndexPatternProcessor,
emojiShortCodeProcessor,
emojiProcessor,
}, title)
}
func renderProcessString(ctx *RenderContext, procs []processor, content string) (string, error) {
var buf strings.Builder
if err := postProcess(ctx, procs, strings.NewReader(content), &buf); err != nil {
@ -438,6 +454,24 @@ func createKeyword(content string) *html.Node {
return span
}
func createInlineCode(content string) *html.Node {
code := &html.Node{
Type: html.ElementNode,
Data: atom.Code.String(),
Attr: []html.Attribute{},
}
code.Attr = append(code.Attr, html.Attribute{Key: "class", Val: "inline-code-block"})
text := &html.Node{
Type: html.TextNode,
Data: content,
}
code.AppendChild(text)
return code
}
func createEmoji(content, class, name string) *html.Node {
span := &html.Node{
Type: html.ElementNode,
@ -1070,6 +1104,21 @@ func filePreviewPatternProcessor(ctx *RenderContext, node *html.Node) {
}
}
func inlineCodeBlockProcessor(ctx *RenderContext, node *html.Node) {
start := 0
next := node.NextSibling
for node != nil && node != next && start < len(node.Data) {
m := InlineCodeBlockRegex.FindStringSubmatchIndex(node.Data[start:])
if m == nil {
return
}
code := node.Data[m[0]+1 : m[1]-1]
replaceContent(node, m[0], m[1], createInlineCode(code))
node = node.NextSibling.NextSibling
}
}
// emojiShortCodeProcessor for rendering text like :smile: into emoji
func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) {
start := 0

View file

@ -172,11 +172,12 @@ func NewFuncMap() template.FuncMap {
"RenderCommitMessage": RenderCommitMessage,
"RenderCommitMessageLinkSubject": RenderCommitMessageLinkSubject,
"RenderCommitBody": RenderCommitBody,
"RenderCodeBlock": RenderCodeBlock,
"RenderIssueTitle": RenderIssueTitle,
"RenderEmoji": RenderEmoji,
"ReactionToEmoji": ReactionToEmoji,
"RenderCommitBody": RenderCommitBody,
"RenderCodeBlock": RenderCodeBlock,
"RenderIssueTitle": RenderIssueTitle,
"RenderRefIssueTitle": RenderRefIssueTitle,
"RenderEmoji": RenderEmoji,
"ReactionToEmoji": ReactionToEmoji,
"RenderMarkdownToHtml": RenderMarkdownToHtml,
"RenderLabel": RenderLabel,

View file

@ -130,6 +130,17 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string)
return template.HTML(renderedText)
}
// RenderRefIssueTitle renders referenced issue/pull title with defined post processors
func RenderRefIssueTitle(ctx context.Context, text string) template.HTML {
renderedText, err := markup.RenderRefIssueTitle(&markup.RenderContext{Ctx: ctx}, template.HTMLEscapeString(text))
if err != nil {
log.Error("RenderRefIssueTitle: %v", err)
return ""
}
return template.HTML(renderedText)
}
// RenderLabel renders a label
// locale is needed due to an import cycle with our context providing the `Tr` function
func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML {

View file

@ -35,8 +35,8 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
mail@domain.com
@mention-user test
#123
space
`
space
` + "`code :+1: #123 code`\n"
var testMetas = map[string]string{
"user": "user13",
@ -115,8 +115,8 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<a href="mailto:mail@domain.com" class="mailto">mail@domain.com</a>
<a href="/mention-user" class="mention">@mention-user</a> test
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
space`
space
` + "`code <span class=\"emoji\" aria-label=\"thumbs up\">👍</span> <a href=\"/user13/repo11/issues/123\" class=\"ref-issue\">#123</a> code`"
assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas))
}
@ -152,11 +152,38 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
mail@domain.com
@mention-user test
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
space
space
<code class="inline-code-block">code :+1: #123 code</code>
`
assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
}
func TestRenderRefIssueTitle(t *testing.T) {
expected := ` space @mention-user
/just/a/path.bin
https://example.com/file.bin
[local link](file.bin)
[remote link](https://example.com)
[[local link|file.bin]]
[[remote link|https://example.com]]
![local image](image.jpg)
![remote image](https://example.com/image.jpg)
[[local image|image.jpg]]
[[remote link|https://example.com/image.jpg]]
https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<span class="emoji" aria-label="thumbs up">👍</span>
mail@domain.com
@mention-user test
#123
space
<code class="inline-code-block">code :+1: #123 code</code>
`
assert.EqualValues(t, expected, RenderRefIssueTitle(context.Background(), testInput))
}
func TestRenderMarkdownToHtml(t *testing.T) {
expected := `<p>space <a href="/mention-user" rel="nofollow">@mention-user</a><br/>
/just/a/path.bin
@ -177,7 +204,8 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<a href="mailto:mail@domain.com" rel="nofollow">mail@domain.com</a>
<a href="/mention-user" rel="nofollow">@mention-user</a> test
#123
space</p>
space
<code>code :+1: #123 code</code></p>
`
assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput))
}