Skip to content

Commit e6ceb68

Browse files
jolheiserzeripath
authored andcommitted
Prefix all user-generated IDs in markup (#9477)
* Prefix all user-generated IDs in markup * Add user-content- to IDs in unit-tests * fixup markdown_test.go * update the hrefs for the wiki test * Add blackfriday extension regex Signed-off-by: jolheiser <[email protected]>
1 parent 071e7c4 commit e6ceb68

File tree

5 files changed

+24
-24
lines changed

5 files changed

+24
-24
lines changed

modules/markup/html.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ var (
5858
emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|\\.(\\s|$))")
5959

6060
linkRegex, _ = xurls.StrictMatchingScheme("https?://")
61+
62+
// blackfriday extensions create IDs like fn:user-content-footnote
63+
blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`)
6164
)
6265

6366
// CSS class for action keywords (e.g. "closes: #1")
@@ -312,6 +315,12 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
312315
}
313316

314317
func (ctx *postProcessCtx) visitNode(node *html.Node) {
318+
// Add user-content- to IDs if they don't already have them
319+
for idx, attr := range node.Attr {
320+
if attr.Key == "id" && !(strings.HasPrefix(attr.Val, "user-content-") || blackfridayExtRegex.MatchString(attr.Val)) {
321+
node.Attr[idx].Val = "user-content-" + attr.Val
322+
}
323+
}
315324
// We ignore code, pre and already generated links.
316325
switch node.Type {
317326
case html.TextNode:

modules/markup/markdown/markdown.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ const (
146146
func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
147147
renderer := &Renderer{
148148
Renderer: blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
149-
Flags: blackfridayHTMLFlags,
149+
Flags: blackfridayHTMLFlags,
150+
FootnoteAnchorPrefix: "user-content-",
151+
HeadingIDPrefix: "user-content-",
150152
}),
151153
URLPrefix: urlPrefix,
152154
IsWiki: wikiMarkdown,

modules/markup/markdown/markdown_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
116116
<li><a href="` + baseURLContent + `/plot_var_example" rel="nofollow">Plot var helper</a></li>
117117
</ul>
118118
`,
119-
`<h2 id="what-is-wine-staging">What is Wine Staging?</h2>
119+
`<h2 id="user-content-what-is-wine-staging">What is Wine Staging?</h2>
120120
121121
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
122122
123-
<h2 id="quick-links">Quick Links</h2>
123+
<h2 id="user-content-quick-links">Quick Links</h2>
124124
125125
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
126126
@@ -149,11 +149,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
149149
<a href="` + baseURLImages + `/images/2.png" rel="nofollow"><img src="` + baseURLImages + `/images/2.png" title="2.png" alt="images/2.png"/></a></li>
150150
</ol>
151151
152-
<h2 id="custom-id">More tests</h2>
152+
<h2 id="user-content-custom-id">More tests</h2>
153153
154154
<p>(from <a href="https://www.markdownguide.org/extended-syntax/" rel="nofollow">https://www.markdownguide.org/extended-syntax/</a>)</p>
155155
156-
<h3 id="definition-list">Definition list</h3>
156+
<h3 id="user-content-definition-list">Definition list</h3>
157157
158158
<dl>
159159
<dt>First Term</dt>
@@ -163,18 +163,18 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
163163
<dd>This is another definition of the second term.</dd>
164164
</dl>
165165
166-
<h3 id="footnotes">Footnotes</h3>
166+
<h3 id="user-content-footnotes">Footnotes</h3>
167167
168-
<p>Here is a simple footnote,<sup id="fnref:1"><a href="#fn:1" rel="nofollow">1</a></sup> and here is a longer one.<sup id="fnref:bignote"><a href="#fn:bignote" rel="nofollow">2</a></sup></p>
168+
<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>
169169
170170
<div>
171171
172172
<hr/>
173173
174174
<ol>
175-
<li id="fn:1">This is the first footnote.</li>
175+
<li id="fn:user-content-1">This is the first footnote.</li>
176176
177-
<li id="fn:bignote"><p>Here is one with multiple paragraphs and code.</p>
177+
<li id="fn:user-content-bignote"><p>Here is one with multiple paragraphs and code.</p>
178178
179179
<p>Indent paragraphs to include them in the footnote.</p>
180180

routers/api/v1/misc/markdown_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ Here are some links to the most important topics. You can find the full list of
8787
[[images/icon-bug.png]]
8888
`,
8989
// rendered
90-
`<h2 id="what-is-wine-staging">What is Wine Staging?</h2>
90+
`<h2 id="user-content-what-is-wine-staging">What is Wine Staging?</h2>
9191
9292
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
9393
94-
<h2 id="quick-links">Quick Links</h2>
94+
<h2 id="user-content-quick-links">Quick Links</h2>
9595
9696
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
9797

web_src/js/index.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,21 +2472,10 @@ $(document).ready(() => {
24722472

24732473
// Set anchor.
24742474
$('.markdown').each(function () {
2475-
const headers = {};
24762475
$(this).find('h1, h2, h3, h4, h5, h6').each(function () {
24772476
let node = $(this);
2478-
const val = encodeURIComponent(node.text().toLowerCase().replace(/[^\u00C0-\u1FFF\u2C00-\uD7FF\w\- ]/g, '').replace(/[ ]/g, '-'));
2479-
let name = val;
2480-
if (headers[val] > 0) {
2481-
name = `${val}-${headers[val]}`;
2482-
}
2483-
if (headers[val] === undefined) {
2484-
headers[val] = 1;
2485-
} else {
2486-
headers[val] += 1;
2487-
}
2488-
node = node.wrap(`<div id="${name}" class="anchor-wrap" ></div>`);
2489-
node.append(`<a class="anchor" href="#${name}"><span class="octicon octicon-link"></span></a>`);
2477+
node = node.wrap('<div class="anchor-wrap"></div>');
2478+
node.append(`<a class="anchor" href="#${encodeURIComponent(node.attr('id'))}"><span class="octicon octicon-link"></span></a>`);
24902479
});
24912480
});
24922481

0 commit comments

Comments
 (0)