Skip to content

Commit

Permalink
update aria definition #1974
Browse files Browse the repository at this point in the history
  • Loading branch information
shunguoy committed Sep 12, 2024
1 parent 8c513c7 commit a74a077
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 269 deletions.
13 changes: 13 additions & 0 deletions accessibility-checker-engine/src/v2/aria/ARIADefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,19 @@ export class ARIADefinitions {
deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid']
},

"image": {
container: null,
props: null,
reqProps: null,
reqChildren: null,
htmlEquiv: "img",
roleType: "structure",
nameRequired: true,
nameFrom: ["author"],
presentationalChildren: true,
deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid']
},

"insertion": {
container: null,
props: null,
Expand Down
271 changes: 4 additions & 267 deletions accessibility-checker-engine/src/v2/aria/ARIAMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ export class ARIAMapper extends CommonMapper {
if (!elem || elem.nodeType !== 1 /* Node.ELEMENT_NODE */) {
return null;
}

if (elem.hasAttribute("role") && elem.getAttribute("role").trim().length > 0) {
let roleStr = elem.getAttribute("role").trim();
let roles = roleStr.split(" ");
Expand All @@ -666,273 +667,9 @@ export class ARIAMapper extends CommonMapper {
}
//return this.elemToImplicitRole(elem);
const roles = AriaUtil.getImplicitRole(elem);

return !roles || roles.length ===0 ? null : roles[0];

//return AriaUtil.getResolvedRole(elem);
}
/**
public static elemToImplicitRole(elem : Element) {
let nodeName = elem.nodeName.toLowerCase();
if (!(nodeName in ARIAMapper.elemToRoleMap)) {
return null;
}
let role = ARIAMapper.elemToRoleMap[nodeName];
if (typeof role === "string") {
return role;
} else if (typeof role === "function") {
return role(elem);
} else {
return null;
}
}
public static hasParentRole(element, role) : boolean {
let parent = DOMWalker.parentNode(element);
// If link is in a menu, it's a menuitem
while (parent) {
if (ARIAMapper.nodeToRole(parent) === role)
return true;
parent = DOMWalker.parentNode(parent);
}
return false;
}
private static inputToRoleMap = (function() {
let hasList = function(element) {
if (element.hasAttribute("list")) {
let id = element.getAttribute("list");
let idRef = FragmentUtil.getById(element, id);
if (idRef && idRef.nodeName.toLowerCase() === "datalist") {
return true;
}
}
return false;
};
let textSuggestions = function(element) {
return hasList(element) ? "combobox" : "textbox";
}
return {
"button": "button",
"image": "button",
"checkbox": "checkbox",
"radio": "radio",
"email": textSuggestions,
"search": function(element) {
return hasList(element) ? "combobox" : "searchbox";
},
"tel": textSuggestions,
"text": textSuggestions,
"url": textSuggestions,
"number": "spinbutton",
"range": "slider",
"reset": "button",
"submit": "button"
}
})();
private static inputToRole(element) {
if (!element) {
return null;
}
let eType = "text";
if (element.hasAttribute("type") && element.getAttribute("type").toLowerCase().trim().length > 0) {
eType = element.getAttribute("type").toLowerCase().trim();
}
if (!(eType in ARIAMapper.inputToRoleMap)) {
return null;
}
let role = ARIAMapper.inputToRoleMap[eType];
if (typeof role === "string") {
return role;
} else if (typeof role === "function") {
return role(element);
} else {
return null;
}
}
private static elemToRoleMap = (function() {
let sectioningRoots = {
"blockquote": true,
"body": true,
"details": true,
"dialog": true,
"fieldset": true,
"figure": true,
"td": true
};
let sectioningContent = {
"article": true,
"aside": true,
"nav": true,
"section": true,
"main": true
};
let sectioningRole = {
"article": true,
"complementary": true,
"navigation": true,
"region": true,
"main": true
};
let inputToRole = function(element) {
return ARIAMapper.inputToRole(element);
}
return {
"a": function(element) {
// If it doesn't represent a hyperlink, 'generic' role
if (!element.hasAttribute("href")) return null;
return "link";
},
"area": function(element) {
// If it doesn't represent a hyperlink, no corresponding role
if (!element.hasAttribute("href")) return null;
return "link";
},
"article": "article",
"aside": "complementary",
"button": "button",
"datalist": "listbox",
"dd": "definition",
"details": "group",
"dfn": "term",
"dialog": "dialog",
"dt": "term",
"fieldset": "group",
"figure": "figure",
"footer": function(element) {
let parent = DOMWalker.parentNode(element);
// If nearest sectioningRoot or sectioningContent is body
while (parent && parent.nodeType === 1) {
let role = (parent.nodeType === 1 && (parent as HTMLElement).getAttribute("role")) || ""
let nodeName = parent.nodeName.toLowerCase();
if (sectioningRoots[nodeName] || sectioningContent[nodeName] || sectioningRole[role]) {
return (nodeName === "body") ? "contentinfo" : null;
}
parent = DOMWalker.parentNode(parent);
}
return null;
},
"form": function(element) {
let name = ARIAMapper.computeName(element);
return (name && name.trim().length > 0) ? "form" : null;
},
// TODO "form-associated custom element"
"h1": "heading",
"h2": "heading",
"h3": "heading",
"h4": "heading",
"h5": "heading",
"h6": "heading",
"header": function(element) {
let parent = DOMWalker.parentNode(element);
// If nearest sectioningRoot or sectioningContent is body
while (parent && parent.nodeType === 1) {
let nodeName = parent.nodeName.toLowerCase();
let role = (parent.nodeType === 1 && (parent as HTMLElement).getAttribute("role")) || ""
if (sectioningRoots[nodeName] || sectioningContent[nodeName] || sectioningRole[role]) {
return (nodeName === "body") ? "banner" : null;
}
parent = DOMWalker.parentNode(parent);
}
return null;
},
"hr": "separator",
"html": "document",
"img": function(element) {
if (element.hasAttribute("alt") && element.getAttribute("alt").length === 0) {
return "presentation";
} else {
return "img";
}
},
"input": inputToRole,
"keygen": "listbox", // deprecated, but keep for backward compat
"li": "listitem",
"main": "main",
"math": "math",
"menu": "list",
"nav": "navigation",
"ol": "list",
"optgroup": "group",
"option": "option",
"output": "status",
"progress": "progressbar",
"section": function(element) {
let name = ARIAMapper.computeName(element);
return (name && name.trim().length > 0) ? "region" : null;
},
"select": function(element) {
if (element.hasAttribute("multiple") || (RPTUtil.attributeNonEmpty(element, "size") && parseInt(element.getAttribute("size")) > 1)) {
return "listbox";
} else {
return "combobox";
}
},
"summary": "button",
"svg": "graphics-document",
"table": "table",
"tbody": function(element) {
let parent = DOMWalker.parentNode(element);
while (parent) {
let role = ARIAMapper.nodeToRole(parent);
if (role === "table" || role === "grid" || role === "treegrid") return "rowgroup";
parent = DOMWalker.parentNode(parent);
}
return null;
},
"textarea": "textbox",
"td": function(element) {
let parent = DOMWalker.parentNode(element);
while (parent) {
let role = ARIAMapper.nodeToRole(parent);
if (role === "table") return "cell";
if (role === "grid" || role === "treegrid") return "gridcell";
parent = DOMWalker.parentNode(parent);
}
return null;
},
"th": function(element) {
let parent = DOMWalker.parentNode(element);
while (parent) {
let role = ARIAMapper.nodeToRole(parent);
if (role !== "table" && role !== "grid" && role !== "treegrid") {
parent = DOMWalker.parentNode(parent);
continue;
}
// Easiest answer is if scope is specified
if (element.hasAttribute("scope")) {
let scope = element.getAttribute("scope").toLowerCase();
if (scope === "row" || scope === 'rowgroup') return "rowheader";
if (scope === "col" || scope === 'colgroup') return "columnheader";
}
// scope is auto, default (without a scope) or invalid value.
// if all the sibling elements are th, then return "columnheader"
var siblings = element => [...element.parentElement.children].filter(node=>node.nodeType === 1 && node.tagName != "TH");
if (siblings === null || siblings.length === 0)
return "columnheader";
else return "rowheader";
}
return null;
},
"tfoot": "rowgroup",
"thead": "rowgroup",
"tr": function(element) {
let parent = DOMWalker.parentNode(element);
while (parent) {
let role = ARIAMapper.nodeToRole(parent);
if (role === "table" || role === "grid" || role === "treegrid") return "row";
parent = DOMWalker.parentNode(parent);
}
return null;
},
"ul": "list"
}
})()
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ARIADefinitions } from "../../v2/aria/ARIADefinitions";

export const aria_accessiblename_exists: Rule = {
id: "aria_accessiblename_exists",
context: "aria:columnheader, aria:form, aria:heading, aria:rowheader, aria:table, aria:graphics-document,aria:graphics-symbol, aria:img, doc-backlink, doc-biblioentry, doc-biblioref, doc-glossref, doc-noteref, doc-pagebreak",
context: "aria:columnheader, aria:form, aria:heading, aria:rowheader, aria:table, aria:graphics-document,aria:graphics-symbol, aria:img,aria:image, doc-backlink, doc-biblioentry, doc-biblioref, doc-glossref, doc-noteref, doc-pagebreak",
help: {
"en-US": {
"pass": "aria_accessiblename_exists.html",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { VisUtil } from "../util/VisUtil";

export const aria_img_labelled: Rule = {
id: "aria_img_labelled",
context: "aria:img",
context: "aria:img, aria:image",
refactor: {
"HAAC_Aria_ImgAlt": {
"Pass_0": "Pass_0",
Expand Down

0 comments on commit a74a077

Please sign in to comment.