Skip to content

Commit

Permalink
Fix to match GH for HTML generated for backreferences
Browse files Browse the repository at this point in the history
*   GH previously generated HTML for backreferences to repeated references
    that was not accessible, as it failed [WCAG 2.1 SC 2.4.4 — Link Purpose
    (In Context)](https://www.w3.org/TR/WCAG21/#link-purpose-in-context)
*   GH changed the text content they use in their backreferences from
    `Back to content` to `Back to reference i`, where `i` is either `x` or
    `x-y`, of which `x` is the reference index, and `y` the reference index

This commit changes all HTML output for users that relied on the defaults, so
that it matches GH again, exactly.
The default handling is exposed as `defaultBackLabel`.

Users who set `backLabel` are not affected.
But these users can now provide a function instead of a `string`, to also solve
the WCAG issue.
The type for this function is exposed as `BackLabelTemplate`.

Related-to: github/cmark-gfm#307.
  • Loading branch information
wooorm committed Apr 4, 2023
1 parent 02a1d9b commit b976b1c
Show file tree
Hide file tree
Showing 26 changed files with 238 additions and 123 deletions.
3 changes: 2 additions & 1 deletion dev/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* @typedef {import('./lib/html.js').BackLabelTemplate} BackLabelTemplate
* @typedef {import('./lib/html.js').Options} HtmlOptions
*/

export {gfmFootnote} from './lib/syntax.js'
export {gfmFootnoteHtml} from './lib/html.js'
export {gfmFootnoteHtml, defaultBackLabel} from './lib/html.js'
78 changes: 71 additions & 7 deletions dev/lib/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,36 @@
* @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension
*/

/**
* @callback BackLabelTemplate
* Generate a back label dynamically.
*
* For the following markdown:
*
* ```markdown
* Alpha[^micromark], bravo[^micromark], and charlie[^remark].
*
* [^remark]: things about remark
* [^micromark]: things about micromark
* ```
*
* This function will be called with:
*
* * `0` and `0` for the backreference from `things about micromark` to
* `alpha`, as it is the first used definition, and the first call to it
* * `0` and `1` for the backreference from `things about micromark` to
* `bravo`, as it is the first used definition, and the second call to it
* * `1` and `0` for the backreference from `things about remark` to
* `charlie`, as it is the second used definition
* @param {number} referenceIndex
* Index of the definition in the order that they are first referenced,
* 0-indexed.
* @param {number} rereferenceIndex
* Index of calls to the same definition, 0-indexed.
* @returns {string}
* Back label to use when linking back from definitions to their reference.
*/

/**
* @typedef Options
* Configuration.
Expand Down Expand Up @@ -59,10 +89,21 @@
* is defined that does that) and so affects screen readers only.
* If you do have such a class, but want to show this section to everyone,
* pass different attributes with the `labelAttributes` option.
* @property {string} [backLabel='Back to content']
* Textual label to describe the backreference back to footnote calls.
* @property {BackLabelTemplate | string} [backLabel]
* Textual label to describe the backreference back to references.
*
* The default value is:
*
* ```js
* function defaultBackLabel(referenceIndex, rereferenceIndex) {
* return (
* 'Back to reference ' +
* (referenceIndex + 1) +
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '')
* )
* }
* ```
*
* The default value is `'Back to content'`.
* Change it when the markdown is not in English.
*
* This label is used in the `aria-label` attribute on each backreference
Expand All @@ -79,6 +120,25 @@ const own = {}.hasOwnProperty
/** @type {Options} */
const emptyOptions = {}

/**
* Generate the default label that GitHub uses on backreferences.
*
* @param {number} referenceIndex
* Index of the definition in the order that they are first referenced,
* 0-indexed.
* @param {number} rereferenceIndex
* Index of calls to the same definition, 0-indexed.
* @returns {string}
* Default label.
*/
export function defaultBackLabel(referenceIndex, rereferenceIndex) {
return (
'Back to reference ' +
(referenceIndex + 1) +
(rereferenceIndex > 1 ? '-' + rereferenceIndex : '')
)
}

/**
* Create an extension for `micromark` to support GFM footnotes when
* serializing to HTML.
Expand All @@ -97,7 +157,7 @@ export function gfmFootnoteHtml(options) {
config.labelAttributes === null || config.labelAttributes === undefined
? 'class="sr-only"'
: config.labelAttributes
const backLabel = config.backLabel || 'Back to content'
const backLabel = config.backLabel || defaultBackLabel
const clobberPrefix =
config.clobberPrefix === null || config.clobberPrefix === undefined
? 'user-content-'
Expand Down Expand Up @@ -243,9 +303,13 @@ export function gfmFootnoteHtml(options) {
'fnref-' +
safeId +
(referenceIndex > 1 ? '-' + referenceIndex : '') +
'" data-footnote-backref="" class="data-footnote-backref" aria-label="' +
this.encode(backLabel) +
'">↩' +
'" data-footnote-backref="" aria-label="' +
this.encode(
typeof backLabel === 'string'
? backLabel
: backLabel(index, referenceIndex)
) +
'" class="data-footnote-backref">↩' +
(referenceIndex > 1
? '<sup>' + referenceIndex + '</sup>'
: '') +
Expand Down
58 changes: 54 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`defaultBackLabel(referenceIndex, rereferenceIndex)`](#defaultbacklabelreferenceindex-rereferenceindex)
* [`gfmFootnote()`](#gfmfootnote)
* [`gfmFootnoteHtml(options?)`](#gfmfootnotehtmloptions)
* [`BackLabelTemplate`](#backlabeltemplate)
* [`HtmlOptions`](#htmloptions)
* [Bugs](#bugs)
* [Authoring](#authoring)
Expand Down Expand Up @@ -147,14 +149,21 @@ console.log(output)

## API

This package exports the identifiers [`gfmFootnote`][api-gfm-footnote] and
This package exports the identifiers
[`defaultBackLabel`][api-default-back-label],
[`gfmFootnote`][api-gfm-footnote], and
[`gfmFootnoteHtml`][api-gfm-footnote-html].
There is no default export.

The export map supports the [`development` condition][development].
Run `node --conditions development module.js` to get instrumented dev code.
Without this condition, production code is loaded.

### `defaultBackLabel(referenceIndex, rereferenceIndex)`

Generate the default label that GitHub uses on backreferences
([`BackLabelTemplate`][api-back-label-template]).

### `gfmFootnote()`

Create an extension for `micromark` to enable GFM footnote syntax.
Expand All @@ -180,6 +189,41 @@ Extension for `micromark` that can be passed in `htmlExtensions` to support GFM
footnotes when serializing to HTML
([`HtmlExtension`][micromark-html-extension]).

### `BackLabelTemplate`

Generate a back label dynamically.

For the following markdown:

```markdown
Alpha[^micromark], bravo[^micromark], and charlie[^remark].

[^remark]: things about remark
[^micromark]: things about micromark
```

This function will be called with:

* `0` and `0` for the backreference from `things about micromark` to
`alpha`, as it is the first used definition, and the first call to it
* `0` and `1` for the backreference from `things about micromark` to
`bravo`, as it is the first used definition, and the second call to it
* `1` and `0` for the backreference from `things about remark` to
`charlie`, as it is the second used definition

###### Parameters

* `referenceIndex` (`number`)
— index of the definition in the order that they are first referenced,
0-indexed
* `rereferenceIndex` (`number`)
— index of calls to the same definition, 0-indexed

###### Returns

Back label to use when linking back from definitions to their reference
(`string`).

### `HtmlOptions`

Configuration (TypeScript type).
Expand Down Expand Up @@ -246,8 +290,9 @@ is defined that does that) and so affects screen readers only.

###### `backLabel`

Textual label to describe the backreference back to footnote calls (`string`,
default: `'Back to content'`).
Textual label to describe the backreference back to footnote calls
([`BackLabelTemplate`][api-back-label-template] or `string`,
default: [`defaultBackLabel`][api-default-back-label]).

Change it when the markdown is not in English.

Expand Down Expand Up @@ -466,7 +511,8 @@ They can even include references to themselves.
## Types

This package is fully typed with [TypeScript][].
It exports the additional type [`HtmlOptions`][api-html-options].
It exports the additional types [`BackLabelTemplate`][api-back-label-template]
and [`HtmlOptions`][api-html-options].

## Compatibility

Expand Down Expand Up @@ -606,3 +652,7 @@ abide by its terms.
[api-gfm-footnote-html]: #gfmfootnotehtmloptions

[api-html-options]: #htmloptions

[api-default-back-label]: #defaultbacklabelreferenceindex-rereferenceindex

[api-back-label-template]: #backlabeltemplate
2 changes: 1 addition & 1 deletion test/fixtures/bang-caret-interplay.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>b <a href="#user-content-fnref-1" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a> <a href="#user-content-fnref-1-2" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"><sup>2</sup></a></p>
<p>b <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a> <a href="#user-content-fnref-1-2" data-footnote-backref="" aria-label="Back to reference 1-2" class="data-footnote-backref"><sup>2</sup></a></p>
</li>
</ol>
</section>
2 changes: 1 addition & 1 deletion test/fixtures/bang-caret.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>b <a href="#user-content-fnref-1" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>b <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
</ol>
</section>
6 changes: 3 additions & 3 deletions test/fixtures/calls.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="user-content-fn-1234567890">
<p>numbers <a href="#user-content-fnref-1234567890" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>numbers <a href="#user-content-fnref-1234567890" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-%5e">
<p>caret <a href="#user-content-fnref-%5E" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<li id="user-content-fn-%5E">
<p>caret <a href="#user-content-fnref-%5E" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"></a></p>
</li>
</ol>
</section>
8 changes: 4 additions & 4 deletions test/fixtures/constructs-in-identifiers.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@
<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="user-content-fn-*emphasis*">
<p>a <a href="#user-content-fnref-*emphasis*" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>a <a href="#user-content-fnref-*emphasis*" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-**strong**">
<p>a <a href="#user-content-fnref-**strong**" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>a <a href="#user-content-fnref-**strong**" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-%60code%60">
<p>a <a href="#user-content-fnref-%60code%60" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>a <a href="#user-content-fnref-%60code%60" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-www.example.com">
<p>a <a href="#user-content-fnref-www.example.com" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>a <a href="#user-content-fnref-www.example.com" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-https://example.com">
<p>a ↩</p>
Expand Down
8 changes: 4 additions & 4 deletions test/fixtures/containers.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>Defined in a block quote. <a href="#user-content-fnref-1" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>Defined in a block quote. <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-2">
<p>Directly after a block quote. <a href="#user-content-fnref-2" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>Directly after a block quote. <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-3">
<p>Defined in a list item. <a href="#user-content-fnref-3" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>Defined in a list item. <a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-4">
<p>Directly after a list item. <a href="#user-content-fnref-4" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>Directly after a list item. <a href="#user-content-fnref-4" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref"></a></p>
</li>
</ol>
</section>
8 changes: 4 additions & 4 deletions test/fixtures/continuation.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ <h1>Heading</h1>
<ol>
<li id="user-content-fn-1">
<p>Paragraph
…continuation <a href="#user-content-fnref-1" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
…continuation <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-2">
<p>Paragraph
…continuation</p>
<p>“code”, which is paragraphs…</p>
<p>…because of the indent! <a href="#user-content-fnref-2" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>…because of the indent! <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-3">
<p>Paragraph
…continuation <a href="#user-content-fnref-3" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
…continuation <a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-4">
<p>Paragraph
…continuation <a href="#user-content-fnref-4" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
…continuation <a href="#user-content-fnref-4" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref"></a></p>
</li>
</ol>
</section>
10 changes: 5 additions & 5 deletions test/fixtures/definitions-initial-blank.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
<ol>
<li id="user-content-fn-1">
<hr />
<a href="#user-content-fnref-1" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a>
<a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a>
</li>
<li id="user-content-fn-2">
<p>Paragraph. <a href="#user-content-fnref-2" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>Paragraph. <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-3">
<a href="#user-content-fnref-3" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a>
<a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref"></a>
</li>
<li id="user-content-fn-4">
<p>Another blank. <a href="#user-content-fnref-4" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a></p>
<p>Another blank. <a href="#user-content-fnref-4" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-5">
<a href="#user-content-fnref-5" data-footnote-backref="" class="data-footnote-backref" aria-label="Back to content"></a>
<a href="#user-content-fnref-5" data-footnote-backref="" aria-label="Back to reference 5" class="data-footnote-backref"></a>
</li>
</ol>
</section>
Loading

0 comments on commit b976b1c

Please sign in to comment.