Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,34 @@ package system, module will add itself globally as `window.markdownitFootnote`.

### Customize

#### Custom href prefix

You can customize the `href` attribute in footnote links by providing a `footnoteHrefPrefix` in the `env` parameter when calling `render()`. This is useful when you want footnotes to link to a different page or use a custom URL structure:

```js
const md = require('markdown-it')().use(require('markdown-it-footnote'));

// Custom href prefix for footnote links
md.render('Here is a footnote[^1]\n\n[^1]: Footnote text', {
footnoteHrefPrefix: '/docs/page#'
});

// Output includes: <a href="/docs/page#fn1" ...>
```

You can also combine this with `docId` to customize both the IDs and href prefix:

```js
md.render('Here is a footnote[^1]\n\n[^1]: Footnote text', {
docId: 'my-doc',
footnoteHrefPrefix: '/docs/page#'
});

// Output includes: <a href="/docs/page#fn-my-doc-1" id="fnref-my-doc-1">
```

#### Renderer customization

If you want to customize the output, you'll need to replace the template
functions. To see which templates exist and their default implementations,
look in [`index.js`](index.js). The API of these template functions is out of
Expand Down
15 changes: 13 additions & 2 deletions index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ function render_footnote_anchor_name (tokens, idx, options, env/*, slf */) {
return prefix + n
}

function render_footnote_href_prefix (tokens, idx, options, env/*, slf */) {
let prefix = '#'

if (typeof env.footnoteHrefPrefix === 'string') prefix = env.footnoteHrefPrefix

return prefix
}

function render_footnote_caption (tokens, idx/*, options, env, slf */) {
let n = Number(tokens[idx].meta.id + 1).toString()

Expand All @@ -25,11 +33,12 @@ function render_footnote_caption (tokens, idx/*, options, env, slf */) {
function render_footnote_ref (tokens, idx, options, env, slf) {
const id = slf.rules.footnote_anchor_name(tokens, idx, options, env, slf)
const caption = slf.rules.footnote_caption(tokens, idx, options, env, slf)
const hrefPrefix = slf.rules.footnote_href_prefix(tokens, idx, options, env, slf)
let refid = id

if (tokens[idx].meta.subId > 0) refid += `:${tokens[idx].meta.subId}`

return `<sup class="footnote-ref"><a href="#fn${id}" id="fnref${refid}">${caption}</a></sup>`
return `<sup class="footnote-ref"><a href="${hrefPrefix}fn${id}" id="fnref${refid}">${caption}</a></sup>`
}

function render_footnote_block_open (tokens, idx, options) {
Expand All @@ -56,11 +65,12 @@ function render_footnote_close () {

function render_footnote_anchor (tokens, idx, options, env, slf) {
let id = slf.rules.footnote_anchor_name(tokens, idx, options, env, slf)
const hrefPrefix = slf.rules.footnote_href_prefix(tokens, idx, options, env, slf)

if (tokens[idx].meta.subId > 0) id += `:${tokens[idx].meta.subId}`

/* ↩ with escape code to prevent display as Apple Emoji on iOS */
return ` <a href="#fnref${id}" class="footnote-backref">\u21a9\uFE0E</a>`
return ` <a href="${hrefPrefix}fnref${id}" class="footnote-backref">\u21a9\uFE0E</a>`
}

export default function footnote_plugin (md) {
Expand All @@ -77,6 +87,7 @@ export default function footnote_plugin (md) {
// helpers (only used in other rules, no tokens are attached to those)
md.renderer.rules.footnote_caption = render_footnote_caption
md.renderer.rules.footnote_anchor_name = render_footnote_anchor_name
md.renderer.rules.footnote_href_prefix = render_footnote_href_prefix

// Process footnote block definition
function footnote_def (state, startLine, endLine, silent) {
Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/footnote-combined.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Both docId and custom href prefix:
.
Here is a footnote reference,[^1] and another.[^longnote]

[^1]: Here is the footnote.

[^longnote]: Here's one with multiple blocks.
.
<p>Here is a footnote reference,<sup class="footnote-ref"><a href="/docs#fn-my-doc-1" id="fnref-my-doc-1">[1]</a></sup> and another.<sup class="footnote-ref"><a href="/docs#fn-my-doc-2" id="fnref-my-doc-2">[2]</a></sup></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn-my-doc-1" class="footnote-item"><p>Here is the footnote. <a href="/docs#fnref-my-doc-1" class="footnote-backref">↩</a></p>
</li>
<li id="fn-my-doc-2" class="footnote-item"><p>Here's one with multiple blocks. <a href="/docs#fnref-my-doc-2" class="footnote-backref">↩</a></p>
</li>
</ol>
</section>
.
57 changes: 57 additions & 0 deletions test/fixtures/footnote-custom-href.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Custom href prefix:
.
Here is a footnote reference,[^1] and another.[^longnote]

[^1]: Here is the footnote.

[^longnote]: Here's one with multiple blocks.
.
<p>Here is a footnote reference,<sup class="footnote-ref"><a href="/custom/path#fn1" id="fnref1">[1]</a></sup> and another.<sup class="footnote-ref"><a href="/custom/path#fn2" id="fnref2">[2]</a></sup></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Here is the footnote. <a href="/custom/path#fnref1" class="footnote-backref">↩</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Here's one with multiple blocks. <a href="/custom/path#fnref2" class="footnote-backref">↩</a></p>
</li>
</ol>
</section>
.


Inline footnote with custom href:
.
Here is an inline note.^[Inlines notes are easier to write.]
.
<p>Here is an inline note.<sup class="footnote-ref"><a href="/custom/path#fn1" id="fnref1">[1]</a></sup></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Inlines notes are easier to write. <a href="/custom/path#fnref1" class="footnote-backref">↩</a></p>
</li>
</ol>
</section>
.


Multiple references with custom href:
.
[^1][^2][^3]

[^1]: foo
[^2]: bar
[^3]: baz
.
<p><sup class="footnote-ref"><a href="/custom/path#fn1" id="fnref1">[1]</a></sup><sup class="footnote-ref"><a href="/custom/path#fn2" id="fnref2">[2]</a></sup><sup class="footnote-ref"><a href="/custom/path#fn3" id="fnref3">[3]</a></sup></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>foo <a href="/custom/path#fnref1" class="footnote-backref">↩</a></p>
</li>
<li id="fn2" class="footnote-item"><p>bar <a href="/custom/path#fnref2" class="footnote-backref">↩</a></p>
</li>
<li id="fn3" class="footnote-item"><p>baz <a href="/custom/path#fnref3" class="footnote-backref">↩</a></p>
</li>
</ol>
</section>
.
14 changes: 14 additions & 0 deletions test/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,17 @@ describe('custom docId in env', function () {
// Now check that using `env.documentId` works to prefix IDs
generate(fileURLToPath(new URL('fixtures/footnote-prefixed.txt', import.meta.url)), md, { docId: 'test-doc-id' })
})

describe('custom href prefix in env', function () {
const md = markdownit().use(footnote)

// Check that using `env.footnoteHrefPrefix` works to customize href
generate(fileURLToPath(new URL('fixtures/footnote-custom-href.txt', import.meta.url)), md, { footnoteHrefPrefix: '/custom/path#' })
})

describe('combined docId and custom href prefix in env', function () {
const md = markdownit().use(footnote)

// Check that both env.docId and env.footnoteHrefPrefix work together
generate(fileURLToPath(new URL('fixtures/footnote-combined.txt', import.meta.url)), md, { docId: 'my-doc', footnoteHrefPrefix: '/docs#' })
})