1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-19 16:58:37 +00:00

Fix footnote jump behavior on the issue page. (#34621)

Close #34511 
Close #34590 

Add comment ID to the footnote item's id attribute to ensure uniqueness.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
charles
2025-06-10 01:18:11 +08:00
committed by GitHub
parent 9165ea8713
commit c6b2cbd75d
13 changed files with 92 additions and 24 deletions

View File

@@ -409,9 +409,9 @@ func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byt
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`"><a href="#fn:`)
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`" class="footnote-ref" role="doc-noteref">`)
_, _ = w.WriteString(`" class="footnote-ref" role="doc-noteref">`) // FIXME: here and below, need to keep the classes
_, _ = w.WriteString(is)
_, _ = w.WriteString(`</a></sup>`)
_, _ = w.WriteString(` </a></sup>`) // the style doesn't work at the moment, so add a space to separate the names
}
return ast.WalkContinue, nil
}

View File

@@ -320,6 +320,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Nod
}
processNodeAttrID(node)
processFootnoteNode(ctx, node) // FIXME: the footnote processing should be done in the "footnote.go" renderer directly
if isEmojiNode(node) {
// TextNode emoji will be converted to `<span class="emoji">`, then the next iteration will visit the "span"

View File

@@ -30,6 +30,7 @@ func TestRender_IssueList(t *testing.T) {
rctx := markup.NewTestRenderContext(markup.TestAppURL, map[string]string{
"user": "test-user", "repo": "test-repo",
"markupAllowShortIssuePattern": "true",
"footnoteContextId": "12345",
})
out, err := markdown.RenderString(rctx, input)
require.NoError(t, err)
@@ -69,4 +70,22 @@ func TestRender_IssueList(t *testing.T) {
</ul>`,
)
})
t.Run("IssueFootnote", func(t *testing.T) {
test(
"foo[^1][^2]\n\n[^1]: bar\n[^2]: baz",
`<p>foo<sup id="fnref:user-content-1-12345"><a href="#fn:user-content-1-12345" rel="nofollow">1 </a></sup><sup id="fnref:user-content-2-12345"><a href="#fn:user-content-2-12345" rel="nofollow">2 </a></sup></p>
<div>
<hr/>
<ol>
<li id="fn:user-content-1-12345">
<p>bar <a href="#fnref:user-content-1-12345" rel="nofollow">↩︎</a></p>
</li>
<li id="fn:user-content-2-12345">
<p>baz <a href="#fnref:user-content-2-12345" rel="nofollow">↩︎</a></p>
</li>
</ol>
</div>`,
)
})
}

View File

@@ -15,6 +15,14 @@ func isAnchorIDUserContent(s string) bool {
return strings.HasPrefix(s, "user-content-") || strings.Contains(s, ":user-content-")
}
func isAnchorIDFootnote(s string) bool {
return strings.HasPrefix(s, "fnref:user-content-") || strings.HasPrefix(s, "fn:user-content-")
}
func isAnchorHrefFootnote(s string) bool {
return strings.HasPrefix(s, "#fnref:user-content-") || strings.HasPrefix(s, "#fn:user-content-")
}
func processNodeAttrID(node *html.Node) {
// Add user-content- to IDs and "#" links if they don't already have them,
// and convert the link href to a relative link to the host root
@@ -27,6 +35,18 @@ func processNodeAttrID(node *html.Node) {
}
}
func processFootnoteNode(ctx *RenderContext, node *html.Node) {
for idx, attr := range node.Attr {
if (attr.Key == "id" && isAnchorIDFootnote(attr.Val)) ||
(attr.Key == "href" && isAnchorHrefFootnote(attr.Val)) {
if footnoteContextID := ctx.RenderOptions.Metas["footnoteContextId"]; footnoteContextID != "" {
node.Attr[idx].Val = attr.Val + "-" + footnoteContextID
}
continue
}
}
}
func processNodeA(ctx *RenderContext, node *html.Node) {
for idx, attr := range node.Attr {
if attr.Key == "href" {

View File

@@ -223,7 +223,7 @@ This PR has been generated by [Renovate Bot](https://github.com/renovatebot/reno
<dd>This is another definition of the second term.</dd>
</dl>
<h3 id="user-content-footnotes">Footnotes</h3>
<p>Here is a simple footnote,<sup id="fnref:user-content-1"><a href="#fn:user-content-1" rel="nofollow">1</a></sup> and here is a longer one.<sup id="fnref:user-content-bignote"><a href="#fn:user-content-bignote" rel="nofollow">2</a></sup></p>
<p>Here is a simple footnote,<sup id="fnref:user-content-1"><a href="#fn:user-content-1" rel="nofollow">1 </a></sup> and here is a longer one.<sup id="fnref:user-content-bignote"><a href="#fn:user-content-bignote" rel="nofollow">2 </a></sup></p>
<div>
<hr/>
<ol>