enhance(markup): improve issue title rendering (#37908)

This commit is contained in:
silverwind
2026-05-30 18:55:26 +02:00
committed by GitHub
parent 0359746abe
commit 82cf75b68a
5 changed files with 53 additions and 5 deletions
+5
View File
@@ -69,6 +69,11 @@ func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) {
m[1] += start
start = m[1]
// don't render a shortcode whose ":" directly follows a backtick (an unclosed code span)
if m[0] > 0 && node.Data[m[0]-1] == '`' {
continue
}
alias := node.Data[m[0]:m[1]]
var nextChar byte
+3
View File
@@ -377,6 +377,9 @@ func TestRender_emoji(t *testing.T) {
test(":100:200", `<p>:100:200</p>`)
test("std::thread::something", `<p>std::thread::something</p>`)
test(":not exist:", `<p>:not exist:</p>`)
test("foo `:smile:", "<p>foo `:smile:</p>")
test("foo `:smile:`", `<p>foo <code>:smile:</code></p>`)
test("foo ` :smile:", "<p>foo ` <span class=\"emoji\" aria-label=\"grinning face with smiling eyes\">😄</span></p>")
}
func TestRender_ShortLinks(t *testing.T) {
+12 -5
View File
@@ -107,19 +107,26 @@ func renderCodeBlock(htmlEscapedTextToRender template.HTML) template.HTML {
// RenderIssueTitle renders issue/pull title with defined post processors
func (ut *RenderUtils) RenderIssueTitle(text string, repo *repo.Repository) template.HTML {
renderedText, err := markup.PostProcessIssueTitle(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), template.HTMLEscapeString(text))
// wrap "`…`" in <code> before post-processing so code-span content stays literal, like comment bodies
htmlWithCode := renderCodeBlock(template.HTML(template.HTMLEscapeString(text)))
renderedText, err := markup.PostProcessIssueTitle(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), string(htmlWithCode))
if err != nil {
log.Error("PostProcessIssueTitle: %v", err)
return ""
}
return renderCodeBlock(template.HTML(renderedText))
return template.HTML(renderedText)
}
// RenderIssueSimpleTitle only renders with emoji and inline code block
func (ut *RenderUtils) RenderIssueSimpleTitle(text string) template.HTML {
ret := ut.RenderEmoji(text)
ret = renderCodeBlock(ret)
return ret
// see RenderIssueTitle: wrap code spans before processing emoji
htmlWithCode := renderCodeBlock(template.HTML(template.HTMLEscapeString(text)))
renderedText, err := markup.PostProcessEmoji(markup.NewRenderContext(ut.ctx), string(htmlWithCode))
if err != nil {
log.Error("RenderIssueSimpleTitle: %v", err)
return ""
}
return template.HTML(renderedText)
}
func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
+32
View File
@@ -180,6 +180,38 @@ mail@domain.com
})
}
func TestRenderIssueTitleCodeSpan(t *testing.T) {
defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
mockRepo := &repo.Repository{
ID: 1, OwnerName: "user13", Name: "repo11",
Owner: &user_model.User{ID: 13, Name: "user13"},
Units: []*repo.RepoUnit{},
}
ut := newTestRenderUtils(t)
cases := []struct {
input string
expected string
emojiSafe bool
}{
{"foo `:100:`", `foo <code class="inline-code-block">:100:</code>`, true},
{"`#123`", `<code class="inline-code-block">#123</code>`, false},
{"`88fc37a3c0a4dda553bdcfc80c178a58247f42fb`", `<code class="inline-code-block">88fc37a3c0a4dda553bdcfc80c178a58247f42fb</code>`, false},
{"foo `:100:", "foo `:100:", true},
{"foo ` :100:", `foo ` + "`" + ` <span class="emoji" aria-label="hundred points">💯</span>`, true},
{":100:", `<span class="emoji" aria-label="hundred points">💯</span>`, true},
{"#123", `<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>`, false},
{"`x`:100:", `<code class="inline-code-block">x</code><span class="emoji" aria-label="hundred points">💯</span>`, true},
{"a `:100:` b `:+1:` c", `a <code class="inline-code-block">:100:</code> b <code class="inline-code-block">:+1:</code> c`, true},
}
for _, c := range cases {
assert.Equal(t, c.expected, string(ut.RenderIssueTitle(c.input, mockRepo)), "input=%q", c.input)
if c.emojiSafe {
assert.Equal(t, c.expected, string(ut.RenderIssueSimpleTitle(c.input)), "simple input=%q", c.input)
}
}
}
func TestRenderMarkdownToHtml(t *testing.T) {
defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
expected := `<p>space <a href="/mention-user" rel="nofollow">@mention-user</a><br/>
+1
View File
@@ -39,6 +39,7 @@
font-weight: var(--font-weight-semibold);
color: var(--color-text);
text-decoration: none;
overflow-wrap: anywhere;
}
#issue-list .branches {