Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixrule(element_accesskey_labelled) fix the label requirement for the elements with accesskey attribute #1773

Merged
merged 7 commits into from
Dec 14, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ <h3 id="ruleMessage"></h3>

### Why is this important?

The label of an HTML element with an `accesskey` attribute allows the user agent to display a list of access keys with a name describing each access key’s function. It also allows voice control users to speak the label to activate its function.
The label of an element with an `accesskey` attribute allows the user agent to display a list of access keys with a name describing each access key’s function.
The label also allows voice control users to speak the label to activate its function.

<!-- This is where the code snippet is injected -->
<div id="locSnippet"></div>

### What to do

* Provide a label using a `title` attribute (e.g. `<a title="Activities" accesskey="A" href="/Consortium/activities">Activities</a>`);
* **Or**, use `<label for="">` or `aria-labelledby` to designate visible text as the label;
* **Or**, use an input embedded in a `<label>` (e.g. `<label><input type="checkbox" accesskey="A"/>foo</label>`);
* **Or**, if the element does not have a visible label, provide a label using the `aria-label` attribute (e.g. `aria-label="Activities"`).
Provide an accessible name for the element with the `accesskey` attribute using one of the following examples:
* `title` attribute (e.g., `<p title="Activity" accesskey="A" href="/Consortium/activity">Activity: This is a paragraph that users need to jump to.</a>`)
* `<label for="an id">` or `aria-labelledby` to designate visible text as the label
* `<input>` embedded in a `<label>` (e.g., `<label><input type="checkbox" accesskey="A"/>Activity</label>`)
* `aria-label` attribute if the element does not have a visible label (e.g., `aria-label="Activity"`)

</script></mark-down>
<!-- End main panel -->
Expand All @@ -69,12 +71,14 @@ <h3 id="ruleMessage"></h3>
### About this requirement

* [IBM 3.3.2 Labels and Instructions](https://www.ibm.com/able/requirements/requirements/#3_3_2)
* [WebAIM - The accesskey attribute](https://webaim.org/techniques/keyboard/accesskey#spec)
* [ARIA practices - Developing a Keyboard Interface](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/)
* [WebAIM - The accesskey attribute](https://webaim.org/techniques/keyboard/accesskey/#spec)
* [ARIA practices - Developing a Keyboard Interface](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/)
* [ARIA practices - Providing Accessible Names and Descriptions](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/)


### Who does this affect?

* People using a screen reader, including blind, low vision and neurodivergent people
* People using a screen reader, including blind, low vision, and neurodivergent people
* People who physically cannot use a pointing device
* People with dexterity impairment using voice control

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
limitations under the License.
*****************************************************************************/

import { Rule, RuleResult, RuleFail, RuleContext, RulePotential, RuleManual, RulePass, RuleContextHierarchy } from "../api/IRule";
import { Rule, RuleResult, RuleContext, RulePotential, RulePass, RuleContextHierarchy } from "../api/IRule";
import { eRulePolicy, eToolkitLevel } from "../api/IRule";
import { RPTUtil } from "../../v2/checker/accessibility/util/legacy";
import { DOMWalker } from "../../v2/dom/DOMWalker";
import { VisUtil } from "../../v2/dom/VisUtil";
import { ARIADefinitions } from "../../v2/aria/ARIADefinitions";
import { ARIAMapper } from "../../v2/aria/ARIAMapper";

export let element_accesskey_labelled: Rule = {
id: "element_accesskey_labelled",
Expand All @@ -34,8 +36,8 @@ export let element_accesskey_labelled: Rule = {
messages: {
"en-US": {
"Pass_0": "Rule Passed",
"Potential_1": "The HTML element with an assigned 'accesskey' attribute does not have an associated label",
"group": "An HTML element with an assigned 'accesskey' attribute must have an associated label"
"Potential_1": "The element with an assigned 'accesskey' attribute does not have an associated label",
"group": "An element with an assigned 'accesskey' attribute must have an associated label"
}
},
rulesets: [{
Expand All @@ -46,25 +48,36 @@ export let element_accesskey_labelled: Rule = {
}],
act: [],
run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => {
const ruleContext = context["dom"].node as Element;
let passed = false;
if (RPTUtil.attributeNonEmpty(ruleContext, "title")) {
passed = true;
} else if (RPTUtil.attributeNonEmpty(ruleContext, "aria-label")) {
passed = true;
} else if (RPTUtil.getLabelForElementHidden(ruleContext, true)) { // ignore hidden
passed = true;
} else if (RPTUtil.attributeNonEmpty(ruleContext, "aria-labelledby")) {
// assume the validity of the id (of aria-labelledby) is checked by a different rule
passed = true;
} else if (ruleContext.nodeName.toLowerCase() === "input"
&& DOMWalker.parentNode(ruleContext).nodeName.toLowerCase() === "label") {
// assume the validity of the label, e.g. empty label, is checked by a different rule
passed = true;
}
const ruleContext = context["dom"].node as HTMLElement;
//skip the check if the element is hidden or disabled
if (!VisUtil.isNodeVisible(ruleContext) || RPTUtil.isNodeDisabled(ruleContext))
return;

//skip if the element is tabbable, it's covered by other rules
if (RPTUtil.isTabbable(ruleContext))
return;

let roles = RPTUtil.getRoles(ruleContext, true);
//skip the native element, mostly text elements
if (!roles || roles.length === 0) return;

let patterns = ARIADefinitions.designPatterns[roles[0]]
if (!patterns.nameFrom)
return;

// ignore if accessble name is required (checked in other rules) or prohibited (text element)
if (patterns.nameRequired || !patterns.nameFrom || patterns.nameFrom.includes("prohibited"))
return;

//special case: legend, as a child of a fieldset, delegate the accesskey command to the field of the fieldset which is covered by other rules
if (ruleContext.parentElement && ruleContext.parentElement.nodeName.toLowerCase() === 'fieldset')
return;

// check if accessible name exists
if (ARIAMapper.computeName(ruleContext).trim().length > 0)
return RulePass("Pass_0");

if (passed) return RulePass("Pass_0");
if (!passed) return RulePotential("Potential_1");
return RulePotential("Potential_1");

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
passedXpaths: [
],
failedXpaths: [
"/html/body/p"

]
}
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us" xml:lang="en-us">
<head>
<title>accessble key</title>
</head>
<body role="main">

<button accesskey="s">Stress reliever</button>

<a href="https://www.w3schools.com/html/" accesskey="h">HTML</a><br>
<a href="https://www.w3schools.com/css/" accesskey="c">CSS</a>


<script type="text/javascript">
UnitTest = {
ruleIds: ["element_accesskey_labelled"],
results: [

]
}
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us" xml:lang="en-us">
<head>
<title>word spacing</title>
</head>
<body role="main" id="ko2ru00253">
<fieldset>
<legend accesskey=p>
<label>I want <input name=pizza type=number step=1 value=1 min=0>
pizza(s) with these toppings</label>
</legend>
<label><input name=pizza-cheese type=checkbox checked> Cheese</label>
<label><input name=pizza-ham type=checkbox checked> Ham</label>
<label><input name=pizza-pineapple type=checkbox> Pineapple</label>
</fieldset>

<script type="text/javascript">
UnitTest = {
ruleIds: ["element_accesskey_labelled"],
results: [

]
}
</script>
</body>
</html>