feat(ui): add more emoji and code block rendering in issues
This commit is contained in:
parent
60bcdc8bc3
commit
4a74113dee
14 changed files with 322 additions and 34 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 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))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue