Skip to content

Commit

Permalink
Merge branch 'master' into dev-1735
Browse files Browse the repository at this point in the history
  • Loading branch information
shunguoy authored Apr 11, 2024
2 parents 4bd6c30 + c19b837 commit bfe4908
Show file tree
Hide file tree
Showing 70 changed files with 1,470 additions and 584 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ <h2 id="topic1">Breaking News</h2>
### About this requirement

* [IBM 2.4.4 Link Purpose (in Context)](https://www.ibm.com/able/requirements/requirements/#2_4_4)
* [IBM 4.1.2 Name, Role, Value](https://www.ibm.com/able/requirements/requirements/#4_1_2)
* [H30: Link text that describes the purpose of a link](https://www.w3.org/WAI/WCAG22/Techniques/html/H30)
* [ARIA7: aria-labelledby for link purpose](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA7)

Expand Down
17 changes: 11 additions & 6 deletions accessibility-checker-engine/help-v4/en-US/img_alt_valid.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,20 @@ <h3 id="ruleMessage"></h3>

### Why is this important?

When an image contains important information, providing a text alternative makes the same information accessible through audio or other channels, such as a Braille display.
When an image contains important information, providing a text alternative makes the same information accessible through assistive technologies, such as a Braille display.
When an image is decorative or redundant, providing correct markup allows assistive technologies to ignore or not repeat the information.


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

### What to do

* If the image conveys meaning, use the `alt` attribute on the `<img>` element to provide a short description that serves the same purpose as the image
If the image conveys meaning, provide an `non-empty accessible name`:
* Use the `alt` attribute on the `<img>` element to provide a short description that serves the same purpose as the image
* **Or**, use an `aria-label` or `aria-labelledby` to provide a short description that correctly follows the [accessible name calculation](https://www.w3.org/TR/wai-aria-1.2/#namecalculation)
* **And**, if the image contains important words, include them in the short description (e.g., `alt="submit"`)
* **Or**, if the image is decorative or redundant, use the attribute with an empty string as its value (e.g., `<img alt="">`)
* **And**, if the image contains important words, include them in the short description (e.g., `alt="Submit"`) so they match
* **Or**, if the image is decorative or redundant, use an empty string as the attribute's value (e.g., `<img alt="">`) or set the `role="presentation"`

</script></mark-down>
<!-- End main panel -->
Expand All @@ -70,14 +73,16 @@ <h3 id="ruleMessage"></h3>

* [IBM 1.1.1 Non-text content](https://www.ibm.com/able/requirements/requirements/#1_1_1)
* [H37: Using alt attributes on img elements](https://www.w3.org/WAI/WCAG22/Techniques/html/H37)
* [G94: Providing short text alternatives that serve the same purpose as the non-text content](https://www.w3.org/WAI/WCAG22/Techniques/general/G94)
* [F38: Not marking up decorative images in a way that allows assistive technology to ignore them](https://www.w3.org/WAI/WCAG22/Techniques/failures/F38)
* [ARIA specification - accessible name calculation](https://www.w3.org/TR/wai-aria-1.2/#namecalculation)

### Who does this affect?

* People using a screen reader, including blind, low vision, and neurodivergent people
* People who turn off image-loading on their web browsers
* People using text only, monochrome, or Braille displays
* People using text-based browsers (e.g., Lynx) or audio interfaces
* People using Braille displays
* People using text-only browsers (e.g., Lynx) or audio interfaces

</script></mark-down>
<!-- End side panel -->
Expand Down
4 changes: 3 additions & 1 deletion accessibility-checker-engine/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
],
exclude: [
//Disable - due to a defect that needs to be addressed regarding visibility.
'test/v2/checker/accessibility/rules/a_text_purpose_ruleunit/A-hasTextEmbedded.html'
'test/v2/checker/accessibility/rules/a_text_purpose_ruleunit/A-hasTextEmbedded.html',
// disable because the rule is turned off
'test/v2/checker/accessibility/rules/style_before_after_review_ruleunit/*'
],

frameworks: ['jasmine'],
Expand Down
4 changes: 3 additions & 1 deletion accessibility-checker-engine/karmaaction.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ module.exports = (config) => {
],
exclude: [
//Disable - due to a defect that needs to be addressed regarding visibility.
'test/v2/checker/accessibility/rules/a_text_purpose_ruleunit/A-hasTextEmbedded.html'
'test/v2/checker/accessibility/rules/a_text_purpose_ruleunit/A-hasTextEmbedded.html',
// disable because the rule is turned off
'test/v2/checker/accessibility/rules/style_before_after_review_ruleunit/*'
],

frameworks: ['jasmine'],
Expand Down
18 changes: 9 additions & 9 deletions accessibility-checker-engine/src/v2/aria/ARIADefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2355,23 +2355,23 @@ export class ARIADefinitions {

},
"img": {
"img-with-alt-text": {
"img-with-accname": {
implicitRole: ["img"],
//roleCondition: " when alt attribute has text (is not empty)",
validRoles: ["button", "checkbox", "doc-cover", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "progressbar", "radio", "scrollbar", "separator", "slider", "switch", "tab", "treeitem"],
//roleCondition: "when accessible name presents",
validRoles: ["button", "checkbox", "doc-cover", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "meter", "option", "progressbar", "radio", "scrollbar", "separator", "slider", "switch", "tab", "treeitem"],
globalAriaAttributesValid: true
},
"img-with-empty-alt": {
implicitRole: ["presentation"],
//roleCondition: " when alt attribute is empty",
"img-without-accname-empty-alt": {
implicitRole: ["presentation", "none"],
//roleCondition: "when no accessible name presents and alt=''",
validRoles: null,
globalAriaAttributesValid: false,
otherAllowedAriaAttributes: ["aria-hidden=true"]
},
"img-without-alt": {
"img-without-accname-no-alt": {
implicitRole: ["img"],
//roleCondition: " when alt attribute, aria-label, or aria-labelledby are not present",
validRoles: null,
//roleCondition: "when neither accessible name no alt presents",
validRoles: ["presentation", "none"],
globalAriaAttributesValid: false,
otherAllowedAriaAttributes: ["aria-hidden=true"]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ export class RPTUtil {
*
* @memberOf RPTUtil
*/
public static getResolvedRole(elem: Element) : string {
public static getResolvedRole(elem: Element, considerImplicitRoles: boolean = true) : string {
if (!elem) return null;
let role = getCache(elem, "RPTUTIL_ELEMENT_RESOLVED_ROLE", null);
if (role === null) {
Expand All @@ -936,7 +936,7 @@ export class RPTUtil {
}
}

if (role === null) {
if (role === null && considerImplicitRoles) {
const implicitRole = RPTUtil.getImplicitRole(elem);
role = implicitRole && implicitRole.length > 0 ? implicitRole[0] : undefined;
}
Expand Down Expand Up @@ -2868,11 +2868,20 @@ export class RPTUtil {
tagProperty = specialTagProperties["other"];
break;
case "img":
if (ruleContext.hasAttribute("alt")) {
ruleContext.getAttribute("alt").trim() === "" ? tagProperty = specialTagProperties["img-with-empty-alt"] : tagProperty = specialTagProperties["img-with-alt-text"];
let alt = ruleContext.hasAttribute("alt") ? ruleContext.getAttribute("alt") : null;
let title = ruleContext.hasAttribute("title") ? ruleContext.getAttribute("title") : null;
if ( RPTUtil.getAriaLabel(ruleContext).trim().length !== 0 || (alt !== null && alt.length > 0) || (title !== null && title.length > 0)) {
// If the img has non-empty alt (alt="some text" or alt=" ") or an accessible name is provided
tagProperty = specialTagProperties["img-with-accname"];
} else {
RPTUtil.hasAriaLabel(ruleContext) ? tagProperty = specialTagProperties["img-with-alt-text"] : tagProperty = specialTagProperties["img-without-alt"];
}
if (alt !== null) {
// If the img has an empty alt (alt="")
tagProperty = specialTagProperties["img-without-accname-empty-alt"];
} else {
// If the img lacks an alt attribute
tagProperty = specialTagProperties["img-without-accname-no-alt"];
}
}
break;
case "input":
if (RPTUtil.attributeNonEmpty(ruleContext, "type")) {
Expand Down
4 changes: 2 additions & 2 deletions accessibility-checker-engine/src/v4/rules/a_text_purpose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ export let a_text_purpose: Rule = {
},
messages: {
"en-US": {
"group": "Hyperlinks must have a text description of their purpose",
"group": "Hyperlinks must have an accessible name for their purpose",
"Pass_0": "Hyperlink has a description of its purpose",
"Fail_1": "Hyperlink has no link text, label or image with a text alternative"
}
},
rulesets: [{
id: [ "IBM_Accessibility", "WCAG_2_0", "WCAG_2_1", "WCAG_2_2"],
num: "2.4.4", // num: [ "2.4.4", "x.y.z" ] also allowed
num: ["2.4.4", "4.1.2"], // num: [ "2.4.4", "x.y.z" ] also allowed
level: eRulePolicy.VIOLATION,
toolkitLevel: eToolkitLevel.LEVEL_TWO
}],
Expand Down
4 changes: 2 additions & 2 deletions accessibility-checker-engine/src/v4/rules/aria_semantics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ export let aria_attribute_valid: Rule = {
},
messages: {
"en-US": {
"group": "ARIA attributes must be valid for the element and ARIA role to which they are assigned",
"group": "ARIA attributes should be valid for the element and ARIA role to which they are assigned",
"Pass": "ARIA attributes are valid for the element and ARIA role",
"Fail_invalid_role_attr": "The ARIA attributes \"{0}\" are not valid for the element <{1}> with ARIA role \"{2}\"",
"Fail_invalid_implicit_role_attr": "The ARIA attributes \"{0}\" are not valid for the element <{1}> with implicit ARIA role \"{2}\""
}
},
rulesets: [{
"id": ["IBM_Accessibility", "WCAG_2_1", "WCAG_2_0", "WCAG_2_2"],
"num": ["4.1.2"],
"num": ["ARIA"],
"level": eRulePolicy.VIOLATION,
"toolkitLevel": eToolkitLevel.LEVEL_ONE
}],
Expand Down
77 changes: 39 additions & 38 deletions accessibility-checker-engine/src/v4/rules/img_alt_valid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ export let img_alt_valid: Rule = {
},
messages: {
"en-US": {
"pass": "Image has required 'alt' attribute, ARIA label, or title if it conveys meaning, or 'alt=\"\" if decorative",
"pass": "The image has an accessible name or is correctly marked as decorative or redundant",
"fail_blank_alt": "Image 'alt' attribute value consists only of blank space(s)",
"fail_no_alt": "The image has neither an 'alt' attribute, an ARIA label, nor a title",
"fail_no_alt": "The image has neither an accessible name nor is marked as decorative or redundant",
"fail_blank_title": "The image does not have an 'alt' attribute or ARIA label, and the 'title' attribute value consists only of blank space(s)",
"group": "Images require an 'alt' attribute with a short text alternative if they convey meaning, or 'alt=\"\" if decorative"
"group": "Images must have accessible names unless they are decorative or redundant"
}
},
rulesets: [{
Expand All @@ -57,43 +57,44 @@ export let img_alt_valid: Rule = {
if (VisUtil.isNodeHiddenFromAT(ruleContext))
return null;

//pass if images with a valid 'alt'
let alt = ruleContext.getAttribute("alt");
if (alt !== null) {
if (alt.trim().length > 0)
return RulePass("pass");
else {
// alt.trim().length === 0
if (alt.length > 0) {
// alt contains blank space only (alt=" ")
return RuleFail("fail_blank_alt");
} else {
// alt.length === 0, presentational image, title is optional, handled by other rule(s)
return RulePass("pass");
if (RPTUtil.getAriaLabel(ruleContext).trim().length !== 0) {
// the img has non-empty aria label
return RulePass("pass");
}

let alt = ruleContext.hasAttribute("alt") ? ruleContext.getAttribute("alt") : null;

// check title attribute
if (alt === null) {
// the img has no alt or attribute, examine the title attribute
let title = ruleContext.hasAttribute("title") ? ruleContext.getAttribute("title") : null;
if (title === null || title.length === 0) {
// no title or title is empty, examine alt further
if (alt === null) {
let role = RPTUtil.getResolvedRole(ruleContext, false);
if (role === 'presentation' || role === 'none')
return RulePass("pass");

return RuleFail("fail_no_alt");
}
if (alt.length === 0)
return RulePass("pass");
} else {
if (title.trim().length === 0) {
// title contains blank space only (title=" ")
return RuleFail("fail_blank_title");
}
// title contains some text (title="some text")
return RulePass("pass");
}
} else {
// no alt
let label = RPTUtil.getAriaLabel(ruleContext);
if (label && label.trim().length > 0)
return RulePass("pass");
else {
let title = ruleContext.getAttribute("title");
if (title) {
if (title.trim().length > 0)
return RulePass("pass");
else {
// title.trim().length === 0
if (title.length > 0) {
// title contains blank space only (title=" ")
return RuleFail("fail_blank_title");
}
}
} else {
// neither alt nor aria label or title
return RuleFail("fail_no_alt");
}
}
}
if (alt.length === 0 || alt.trim().length > 0) {
// the img has empty alt (alt="") or non-empty alt (alt="some text")
return RulePass("pass");
} else {
// alt contains blank space only (alt=" ")
return RuleFail("fail_blank_alt");
}
}
}
}
Loading

0 comments on commit bfe4908

Please sign in to comment.