Skip to content

Commit

Permalink
Use dfn elements for defining terms (#1744)
Browse files Browse the repository at this point in the history
* Use <dfn> elements for defining terms
* Add internal link
* Namespace dfn in rule
* Accept internal links to HTML elements with id
* Accept internal links to id of HTML elements
* Accept links to IDs in glossary files
* Accept links to IDs from one def to another
  • Loading branch information
Jym77 committed Feb 14, 2022
1 parent a6984e1 commit 245eb40
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 30 deletions.
14 changes: 12 additions & 2 deletions __tests__/link-to-glossary-term-valid.js
Expand Up @@ -6,6 +6,7 @@ const describePage = require('../test-utils/describe-page')
const isUrl = require('is-url')
const getMarkdownAstNodesOfType = require('../utils/get-markdown-ast-nodes-of-type')
const uniqueArray = require('../utils/unique-array')
const getIds = require('../utils/get-ids')

const whitelist = [
/^description$/,
Expand Down Expand Up @@ -45,7 +46,10 @@ describe(`Validate glossary references`, () => {
})
})

function validateGlossaryReferences({ markdownAST }, { glossaryKeys = [] }) {
function validateGlossaryReferences({ markdownAST }, { glossaryKeys = [], glossaryIds = [] }) {
// Get the value of all HTML `id` attributes in the file and in glossary
const htmlIds = getIds(markdownAST).concat(...glossaryIds)

/**
* get all links
* -> eg: [Alpha](https://....) or [Beta](#semantic-role)
Expand Down Expand Up @@ -75,9 +79,15 @@ function validateGlossaryReferences({ markdownAST }, { glossaryKeys = [] }) {
return
}

/**
* Check that each link (in page or in definitions list) is either a known glossary key
* or an internal link to an HTML element in the page (including glossary) with an id.
*/
test.each(links)('%s', link => {
// Remove leading '#'
const key = link.substr(1)
const actual = glossaryKeys.includes(key)
// Is it a known key, or an HTML `id`?
const actual = glossaryKeys.includes(key) || htmlIds.includes(key)
const msg = `Glossary term - [#${key}] does not exist`
expect(actual, msg).toBe(true)
})
Expand Down
1 change: 0 additions & 1 deletion _rules/aria-required-owned-element-bc4a75.md
Expand Up @@ -140,7 +140,6 @@ This element with the `list` role only owns elements with the `listitem` role, o
</div>
```


#### Passed Example 7

This element with the `menu` role only owns an element with a `group` role. The `group` in turn owns an element with the `menuitem` role, and an element with the `group` role, in which each element has the `menuitem` role. ARIA `group` roles are allowed to own other elements with a `group` role.
Expand Down
21 changes: 11 additions & 10 deletions _rules/element-lang-matches-default-language-off6ek.md 100755 → 100644
Expand Up @@ -35,10 +35,10 @@ htmlHintIgnore:

This rule applies to any [HTML element][] with a `lang` attribute for which all the following are true:

- the element is an [inclusive descendant][] in the [flat tree][] of a `body` element; and
- the element is in a [document][] with a [content type][] of `text/html`; and
- the element's `lang` [attribute value][] has a [known primary language tag][]; and
- there is some non-empty [text inheriting its programmatic language][] from the element.
- <dfn id="off6ek:in-body">in body</dfn>: the element is an [inclusive descendant][] in the [flat tree][] of a `body` element; and
- <dfn id="off6ek:html">HTML</dfn>: the element is in a [document][] with a [content type][] of `text/html`; and
- <dfn id="off6ek:valid-lang">Valid language</dfn>: the element's `lang` [attribute value][] has a [known primary language tag][]; and
- <dfn id="off6ek:not-empty">Not empty</dfn>: there is some non-empty [text inheriting its programmatic language][] from the element.

## Expectation

Expand Down Expand Up @@ -247,7 +247,7 @@ This `div` element has a `lang` attribute value of `fr` (French), which does not

#### Inapplicable Example 1

There are no HTML elements in this document.
This document is not [HTML](#off6ek:html).

```svg
<svg xmlns="http://www.w3.org/2000/svg" lang="en">
Expand All @@ -257,7 +257,7 @@ There are no HTML elements in this document.

#### Inapplicable Example 2

There is no descendant of a `body` element with a `lang` attribute.
There is no [descendant of a `body`](#off6ek:in-body) element with a `lang` attribute.

```html
<html lang="en">
Expand All @@ -269,7 +269,7 @@ There is no descendant of a `body` element with a `lang` attribute.

#### Inapplicable Example 3

This `p` element has an invalid language tag.
This `p` element does not have a [valid language tag](#off6ek:valid-lang).

```html
<html lang="en">
Expand All @@ -283,7 +283,7 @@ This `p` element has an invalid language tag.

#### Inapplicable Example 4

There is no [text inheriting its programmatic language][] from the first `p` element because it has no content.
The first `p` element is [empty](#off6ek:not-empty) because the only [element inheriting its programmatic language][] is itself, and it has no text node child.

```html
<html lang="en">
Expand All @@ -296,7 +296,7 @@ There is no [text inheriting its programmatic language][] from the first `p` ele

#### Inapplicable Example 5

There is no [text inheriting its programmatic language][] from this `p` element because it has no content that is either [visible][] or [included in the accessibility tree][].
This `p` element is [empty](#off6ek:not-empty) because it has no content that is either [visible][] or [included in the accessibility tree][].

```html
<html lang="en">
Expand Down Expand Up @@ -333,6 +333,7 @@ The `lang` [attribute value][] of this `p` element has no [known primary languag
[attribute value]: #attribute-value 'Definition of Attribute Value'
[content type]: https://dom.spec.whatwg.org/#concept-document-content-type 'DOM definition of Content Type'
[document]: https://dom.spec.whatwg.org/#document-element 'DOM definition of Document Element'
[element inheriting its programmatic language]: #text-inheriting-language:element 'Definition of Element Inheriting its Programmatic Language from an Element'
[flat tree]: https://drafts.csswg.org/css-scoping/#flat-tree 'CSS Scoping definition of Flat tree, working draft'
[grandfathered tags]: https://www.rfc-editor.org/rfc/rfc5646.html#section-2.2.8
[included in the accessibility tree]: #included-in-the-accessibility-tree 'Definition of Included in the Accessibility Tree'
Expand All @@ -341,7 +342,7 @@ The `lang` [attribute value][] of this `p` element has no [known primary languag
[most common language]: #most-common-element-language 'Definition of Common Language of an Element'
[primary language]: https://www.rfc-editor.org/rfc/rfc5646.html#section-2.2.1 'Definition of primary language subtag'
[rfc 5646]: https://www.rfc-editor.org/rfc/rfc5646.html#section-2.1
[text inheriting its programmatic language]: #text-inheriting-language 'Definition of Text Inheriting its Programmatic Language from an Element'
[text inheriting its programmatic language]: #text-inheriting-language:text 'Definition of Text Inheriting its Programmatic Language from an Element'
[sc312]: https://www.w3.org/TR/WCAG21/#language-of-parts 'Success Criterion 3.1.2 Language of Parts'
[usc312]: https://www.w3.org/WAI/WCAG21/Understanding/language-of-parts.html 'Understanding Success Criterion 3.1.2: Language of Parts'
[known primary language tag]: #known-primary-language-tag 'Definition of Known Primary Language Tag'
Expand Down
2 changes: 1 addition & 1 deletion _rules/image-button-non-empty-accessible-name-59796f.md
Expand Up @@ -177,6 +177,6 @@ The image button is ignored by assistive technologies because it is not [include
```

[accessible name]: #accessible-name 'Definition of Accessible Name'
[attribute value]: #attribute-value 'Definition of Attribute Value'
[attribute value]: #attribute-value:enumerated 'Definition of Attribute Value'
[html aam image button]: https://www.w3.org/TR/html-aam-1.0/#input-type-image 'HTML Accessibility API Mapping, image button'
[included in the accessibility tree]: #included-in-the-accessibility-tree 'Definition of Included in the Accessibility Tree'
16 changes: 8 additions & 8 deletions pages/glossary/attribute-value.md
Expand Up @@ -7,20 +7,20 @@ input_aspects:
- DOM tree
---

The _attribute value_ of a content attribute set on an HTML element is the value that the attribute gets after being parsed and computed according to specifications. It may differ from the value that is actually written in the HTML code due to trimming whitespace or non-digits characters, default values, or case-insensitivity.
The <dfn id="attribute-value:attribute">attribute value</dfn> of a content attribute set on an HTML element is the value that the attribute gets after being parsed and computed according to specifications. It may differ from the value that is actually written in the HTML code due to trimming whitespace or non-digits characters, default values, or case-insensitivity.

Some notable case of attribute value, among others:

- For [enumerated attributes][], the _attribute value_ is either the state of the attribute, or the keyword that maps to it; even for the default states. Thus `<input type="image" />` has an attribute value of either `Image Button` (the state) or `image` (the keyword mapping to it), both formulations having the same meaning; similarly, "an input element with a `type` _attribute value_ of `Text`" can be either `<input type="text" />`, `<input />` (missing value default), or `<input type="invalid" />` (invalid value default).
- For [boolean attributes][], the _attribute value_ is `true` when the attribute is present and `false` otherwise. Thus `<button disabled>`, `<button disabled="disabled">` and `<button disabled="">` all have a `disabled` _attribute value_ of `true`.
- For attributes whose value is used in a case-insensitive context, the _attribute value_ is the lowercase version of the value written in the HTML code.
- For attributes that accept [numbers][], the _attribute value_ is the result of parsing the value written in the HTML code according to the rules for parsing this kind of number.
- For attributes that accept sets of tokens, whether [space separated][] or [comma separated][], the _attribute value_ is the set of tokens obtained after parsing the set and, depending on the case, converting its items to lowercase (if the set is used in a case-insensitive context).
- For `aria-*` attributes, the _attribute value_ is computed as indicated in the [WAI-ARIA specification][] and the [HTML Accessibility API Mappings][html aam].
- For [enumerated attributes][], the <dfn id="attribute-value:enumerated">attribute value</dfn> is either the state of the attribute, or the keyword that maps to it; even for the default states. Thus `<input type="image" />` has an attribute value of either `Image Button` (the state) or `image` (the keyword mapping to it), both formulations having the same meaning; similarly, "an input element with a `type` _attribute value_ of `Text`" can be either `<input type="text" />`, `<input />` (missing value default), or `<input type="invalid" />` (invalid value default).
- For [boolean attributes][], the <dfn id="attribute-value:boolean">attribute value</dfn> is `true` when the attribute is present and `false` otherwise. Thus `<button disabled>`, `<button disabled="disabled">` and `<button disabled="">` all have a `disabled` _attribute value_ of `true`.
- For attributes whose value is used in a case-insensitive context, the <dfn id="attribute-value:case-insensitive">attribute value</dfn> is the lowercase version of the value written in the HTML code.
- For attributes that accept [numbers][], the <dfn id="attribute-value:number">attribute value</dfn> is the result of parsing the value written in the HTML code according to the rules for parsing this kind of number.
- For attributes that accept sets of tokens, whether [space separated][] or [comma separated][], the <dfn id="attribute-value:tokens-list">attribute value</dfn> is the set of tokens obtained after parsing the set and, depending on the case, converting its items to lowercase (if the set is used in a case-insensitive context).
- For `aria-*` attributes, the <dfn id="attribute-value:aria">attribute value</dfn> is computed as indicated in the [WAI-ARIA specification][] and the [HTML Accessibility API Mappings][html aam].

This list is not exhaustive, and only serves as an illustration for some of the most common cases.

The _attribute value_ of an [IDL attribute][] is the value returned on getting it. Note that when an [IDL attribute][] [reflects][reflect] a content attribute, they have the same attribute value.
The <dfn id="attribute-value:idl">attribute value</dfn> of an [IDL attribute][] is the value returned on getting it. Note that when an [IDL attribute][] [reflects][reflect] a content attribute, they have the same attribute value.

[boolean attributes]: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes 'HTML Specification of Boolean Attribute'
[comma separated]: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#comma-separated-tokens 'HTML Specification of Comma Separated Tokens'
Expand Down
6 changes: 3 additions & 3 deletions pages/glossary/text-inheriting-language.md
Expand Up @@ -9,13 +9,13 @@ input_aspects:
- CSS Styling
---

The _text inheriting its programmatic language_ from an element E is composed of all the following texts:
The <dfn id="text-inheriting-language:text">text inheriting its programmatic language</dfn> from an element E is composed of all the following texts:

- **text nodes**: the value of any [text nodes][] that are [visible][] or [included in the accessibility tree][] and children of an element inheriting its programmatic language from E;
- **accessible text**: the [accessible name][] and [accessible description][] of any element inheriting its programmatic language from E, and [included in the accessibility tree][];
- **accessible text**: the [accessible name][] and [accessible description][] of any [element inheriting its programmatic language](#text-inheriting-language:element) from E, and [included in the accessibility tree][];
- **page title**: the value of the [document title][], only if E is a [document][] in a [top-level browsing context][].

An element F is an _element inheriting its programmatic language_ from an element E if at least one of the following conditions is true (recursively):
An element F is an <dfn id="text-inheriting-language:element">element inheriting its programmatic language</dfn> from an element E if at least one of the following conditions is true (recursively):

- F is E itself (an element always inherits its programmatic language from itself); or
- F does not have a non-empty `lang` attribute, and is the child in the [flat tree][] of an element inheriting its programmatic language from E; or
Expand Down
14 changes: 11 additions & 3 deletions test-utils/describe-page.js
@@ -1,4 +1,5 @@
const getMarkdownData = require('../utils/get-markdown-data')
const getIds = require('../utils/get-ids')
const pagesData = getMarkdownData(`./pages`, [
`!**/**/license.md`, // Note: there is a lot of markdown(esque) verbiage in W3C license
])
Expand All @@ -9,12 +10,19 @@ const pagesData = getMarkdownData(`./pages`, [
* @param {Function} runTests function callback of `describle` block, which executes per page
*/
const describePage = (groupName, runTests) => {
const glossaryData = getMarkdownData(`./pages/glossary`)
// The keys of all glossary items
const glossaryKeys = glossaryData.map(({ frontmatter }) => frontmatter.key)
// The `id` of all elements used in glossary items
const glossaryIds = glossaryData
.map(({ markdownAST }) => getIds(markdownAST))
.reduce((flattened, element) => flattened.concat(element), [])

/**
* Create arbitrary meta data that can be used in various tests
*/
const metaData = {
glossaryKeys: getMarkdownData(`./pages/glossary`).map(({ frontmatter }) => frontmatter.key),
}
const metaData = { glossaryIds, glossaryKeys }

pagesData.forEach(pageData => {
const { filename } = pageData
describe(filename, () => {
Expand Down
14 changes: 12 additions & 2 deletions test-utils/describe-rule.js
@@ -1,5 +1,6 @@
const { contributors } = require('../package.json')
const getMarkdownData = require('../utils/get-markdown-data')
const getIds = require('../utils/get-ids')
const rulesData = getMarkdownData(`./_rules`)

/**
Expand All @@ -8,13 +9,22 @@ const rulesData = getMarkdownData(`./_rules`)
* @param {Function} runTests function callback of `describe` block, which executes per rule
*/
const describeRule = (groupName, runTests) => {
const glossaryData = getMarkdownData(`./pages/glossary`)
// The keys of all glossary items
const glossaryKeys = glossaryData.map(({ frontmatter }) => frontmatter.key)
// The `id` of all elements used in glossary items
const glossaryIds = glossaryData
.map(({ markdownAST }) => getIds(markdownAST))
.reduce((flattened, element) => flattened.concat(element), [])

/**
* Create arbitrary meta data that can be used in various tests
*/
const metaData = {
contributors: contributors.map(contributor => contributor.name.toLowerCase()),
atomicRuleIds: getRuleIdsOfRuleType(rulesData, 'atomic'),
glossaryKeys: getMarkdownData(`./pages/glossary`).map(({ frontmatter }) => frontmatter.key),
contributors: contributors.map(contributor => contributor.name.toLowerCase()),
glossaryIds,
glossaryKeys,
}

rulesData.forEach(ruleData => {
Expand Down
19 changes: 19 additions & 0 deletions utils/get-ids.js
@@ -0,0 +1,19 @@
const getMarkdownAstNodesOfType = require('../utils/get-markdown-ast-nodes-of-type')

/**
* get the `id` of all html elements in the AST (notably the dfn elements)
* -> eg: <dfn id="123456:anchor-name">
*/
function getIds(markdownAST) {
return (
// Find all HTML elements in the markdown
getMarkdownAstNodesOfType(markdownAST, 'html')
// Keep the ones with an `id` attribute
.map(({ value }) => value.match(/id="([^"]*)"/))
.filter(value => value !== null)
// Only keep the matched group, aka the value of the `id` attribute
.map(matches => matches[1])
)
}

module.exports = getIds

0 comments on commit 245eb40

Please sign in to comment.