Skip to content

Commit

Permalink
Merge pull request #1917 from IBMa/dev-1622
Browse files Browse the repository at this point in the history
fixrule(`input_haspopup_conflict`): Add additional checks and update the messages
  • Loading branch information
ErickRenteria authored Jun 27, 2024
2 parents 7a88182 + 1353a53 commit ee397d5
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,42 @@ <h3 id="ruleMessage"></h3>

### Why is this important?

* Input types of
[text](https://html.spec.whatwg.org/multipage/input.html#text-%28type=text%29-state-and-search-state-%28type=search%29), [search](https://html.spec.whatwg.org/multipage/input.html#text-%28type=text%29-state-and-search-state-%28type=search%29), [tel](https://html.spec.whatwg.org/multipage/input.html#telephone-state-%28type=tel%29), [url](https://html.spec.whatwg.org/multipage/input.html#url-state-%28type=url%29), and [email](https://html.spec.whatwg.org/multipage/input.html#e-mail-state-%28type=email%29)
(or inputs with a missing or invalid type) that also have a [list](https://html.spec.whatwg.org/multipage/input.html#attr-input-list) attribute have an implicit role of combobox, which in turn has an implicit `aria-haspopup="listbox"`;
therefore, developers should not explicitly assign the `aria-haspopup` attribute, which will be either redundant or possibly conflicting.
When HTML elements use both `aria-*` attributes and their HTML implied equivalents, browsers **_must_** ignore the explicit (redundant or conflicting) ARIA attribute the native HTML attribute with their [implied ARIA semantics](https://www.w3.org/TR/wai-aria-1.2/#implicit_semantics) take precedence.

* To ensure that Assistive Technologies (AT) can gather information, proper coding is required so that the end users can understand and interact with the content.
If standard HTML controls are created according to specification, the conditions of this provision will be met.
For this reason, to avoid unintended consequences, developers **_should not_** specify both the native HTML attribute and an equivalent (redundant or conflicting) `aria-haspopup` attribute on the indicated inputs with a `list` attribute.
Otherwise, any global `aria-*` attributes and any other `aria-*` attributes applicable to the combobox role **_may_** be used.
To ensure that end users can understand and interact with certain types of input,
proper coding is required so that their Assistive Technologies (AT) can gather the information and avoid unintended consequences:
* Input elements that have a `list` attribute with a certain input type,
also have an implicit role of **combobox**,
which in turn has an implicit `aria-haspopup="listbox"` property;
therefore, developers should not explicitly assign the `aria-haspopup` property because it will be either redundant or possibly conflict.
* When HTML elements use both `aria-*` attributes and their HTML implied equivalents,
browsers must ignore the explicit (redundant or conflicting) ARIA attribute the native HTML attribute with their [implied ARIA semantics](https://www.w3.org/TR/wai-aria-1.2/#implicit_semantics) take precedence.
* When standard HTML controls are created according to specification without either redundant or possibly conflicting ARIA attributes,
the conditions of this rule will be met.

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

### What to do

* Remove the `aria-haspopup` attribute from the `<input>` element that has a `list` attribute with input `type=`
[text](https://html.spec.whatwg.org/multipage/input.html#text-%28type=text%29-state-and-search-state-%28type=search%29), [search](https://html.spec.whatwg.org/multipage/input.html#text-%28type=text%29-state-and-search-state-%28type=search%29), [tel](https://html.spec.whatwg.org/multipage/input.html#telephone-state-%28type=tel%29), [url](https://html.spec.whatwg.org/multipage/input.html#url-state-%28type=url%29), or [email](https://html.spec.whatwg.org/multipage/input.html#e-mail-state-%28type=email%29).
* **And/Or**, add an input type if missing or correct the invalid input type.
Developers should not use both the (redundant or conflicting) [`aria-haspopup`](https://www.w3.org/TR/wai-aria-1.2/#aria-haspopup) attribute
and their native HTML implied equivalents on certain inputs types with a [`list`](https://html.spec.whatwg.org/multipage/input.html#attr-input-list) attribute.
Affected input types include
[`text`](https://html.spec.whatwg.org/multipage/input.html#text-%28type=text%29-state-and-search-state-%28type=search%29),
[`search`](https://html.spec.whatwg.org/multipage/input.html#text-%28type=text%29-state-and-search-state-%28type=search%29),
[`tel`](https://html.spec.whatwg.org/multipage/input.html#telephone-state-%28type=tel%29),
[`url`](https://html.spec.whatwg.org/multipage/input.html#url-state-%28type=url%29),
[`email`](https://html.spec.whatwg.org/multipage/input.html#e-mail-state-%28type=email%29),
[`date`](https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date),
[`month`](https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month),
[`week`](https://html.spec.whatwg.org/multipage/input.html#week-state-(type=week),
[`time`](https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time),
[`datetime-local`](https://html.spec.whatwg.org/multipage/input.html#local-date-and-time-state-(type=datetime-local),
[`number`](https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number),
[`range`](https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range),
and [`color`](https://html.spec.whatwg.org/multipage/input.html#color-state-(type=color):
* **Remove** the `aria-haspopup` attribute from the `<input>` element that has a `list` attribute
* **And/Or**, add a valid input type if missing
* **And/Or**, correct the invalid input type
* Otherwise, any [global `aria-*` states and properties](https://www.w3.org/TR/wai-aria-1.2/#global_states) not deprecated and any other `aria-*` attributes applicable to the [`combobox`](https://www.w3.org/TR/wai-aria-1.2/#combobox) role are allowed

</script></mark-down>
<!-- End main panel -->
Expand All @@ -87,7 +104,7 @@ <h3 id="ruleMessage"></h3>
* People with low vision using screen magnification
* People with dexterity impairments using voice control
* People who physically cannot use a pointing device
 

</script></mark-down>
<!-- End side panel -->
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,40 @@
limitations under the License.
*****************************************************************************/

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

export let input_haspopup_conflict: Rule = {
id: "input_haspopup_conflict",
context: "dom:input[list][aria-haspopup]",
refactor: {
"input_haspopup_invalid": {
"Pass": "Pass",
"Potential_1": "Potential_1",
"Potential_2": "Potential_2"}
"Pass": "pass",
"Potential_1": "potential_type_misuse",
"Potential_2": "potential_misuse"}
},
help: {
"en-US": {
"Pass": "input_haspopup_conflict.html",
"Potential_1": "input_haspopup_conflict.html",
"Potential_2": "input_haspopup_conflict.html",
"group": "input_haspopup_conflict.html"
"group": "input_haspopup_conflict.html",
"pass": "input_haspopup_conflict.html",
"potential_type_misuse": "input_haspopup_conflict.html",
"potential_misuse": "input_haspopup_conflict.html",
"potential_list_notexist": "input_haspopup_conflict.html",
"fail_invalid_list_type": "input_haspopup_conflict.html",
"fail_invalid_list_elem": "input_haspopup_conflict.html"
}
},
messages: {
"en-US": {
"Pass_0": "<input> element with 'list' attribute does not use 'aria-haspopup' attribute",
"Potential_1": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with type=\"{0}\"",
"Potential_2": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with missing or invalid input type",
"group": "<input> element with 'list' attribute should not also use 'aria-haspopup' attribute"
"group": "<input> element with a 'list' attribute should not use an explicit 'aria-haspopup' attribute",
"pass": "The <input> element with a 'list' attribute does not use an explicit 'aria-haspopup' attribute",
"potential_type_misuse": "The <input> element with type \"{0}\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"potential_misuse": "The <input> element with a missing or invalid type and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"potential_list_notexist": "The list attribute for the <input> element is invalid",
"fail_invalid_list_type": "The list attribute for the <input> element with the type \"{0}\" is invalid",
"fail_invalid_list_elem": "The list attribute for the <input> element does not reference a datalist element"
}
},
rulesets: [{
Expand All @@ -49,29 +57,52 @@ export let input_haspopup_conflict: Rule = {
run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => {
const ruleContext = context["dom"].node as Element;

//skip if the fieldset is hidden or disabled
if (VisUtil.isNodeHiddenFromAT(ruleContext) || RPTUtil.isNodeDisabled(ruleContext))
return null;

let roles = RPTUtil.getUserDefinedRoles(ruleContext);
// let "aria_role_valid" to handle invalid role. Only allowed role is combobox which is implicit.
if (roles && roles.length > 0 && !roles.includes('combobox'))
return null;

//triggering input types: text, search, tel, url, email, or missing or invalid
let yesTypes = ["text", "search", "tel", "url", "email"];
let noTypes = ["file", "password", "checkbox", "radio", "submit", "reset",
"date", "number", "range", "time", "color", "image",
"month", "week", "datetime-local", "hidden", "button"
];
let yesTypes = ["text", "search", "tel", "url", "email", "date", "month", "week", "time", "datetime-local", "number", "range", "color"];
let noTypes = ["file", "password", "checkbox", "radio", "submit", "reset", "image", "hidden", "button"];

let attrValue = ruleContext.getAttribute("type");
//missing input type
if (!attrValue)
return RulePotential("Potential_2");
//missing input type for list but with aria_has_popup
if (!attrValue || attrValue.trim().length === 0)
return RulePotential("potential_misuse");

attrValue = attrValue.toLowerCase();
// ignore for no triggering input types
if (noTypes.includes(attrValue))
return;
attrValue = attrValue.trim().toLowerCase();
//invalid input types for list but with aria_has_popup
if (!yesTypes.includes(attrValue) && !noTypes.includes(attrValue))
return RulePotential("potential_misuse");

// failure_1 if any triggering input types
if (yesTypes.includes(attrValue))
return RulePotential("Potential_1", [attrValue]);
// the list attribute is used for wrong input type
if (attrValue && noTypes.includes(attrValue))
return RuleFail("fail_invalid_list_type");

//invalid input type
return RulePotential("Potential_2");
let list = ruleContext.getAttribute("list");
// the list attribute is blank
if (!list || list.trim().length === 0)
return RulePotential("potential_list_notexist");

let listElem = ruleContext.ownerDocument.getElementById(list);
// the list element doesn't exist
if (!listElem)
return RuleFail("potential_list_notexist");

// the list element is not a datalist element
if (listElem.nodeName.toLowerCase() !== 'datalist')
return RuleFail("fail_invalid_list_elem");

// valid input types for list but with aria_has_popup
if (yesTypes.includes(attrValue))
return RulePotential("potential_type_misuse", [attrValue]);

// shouldn't get here
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
<input list="function-types" type='text' role='combobox' id="browser3" />


<!-- not triggerred, no failure/pass case, added no triggering explicit role -->
<input list="function-types" type='number' role='combobox' id="browser4" aria-haspopup="listbox">
<datalist id="function-types">
<option value="function">function</option>
Expand All @@ -60,7 +59,7 @@
UnitTest = {
ruleIds: ["input_haspopup_conflict"],
results: [
{
{
"ruleId": "input_haspopup_conflict",
"value": [
"INFORMATION",
Expand All @@ -70,8 +69,8 @@
"dom": "/html[1]/body[1]/main[1]/input[1]",
"aria": "/document[1]/main[1]/combobox[1]"
},
"reasonId": "Potential_2",
"message": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with missing or invalid input type",
"reasonId": "potential_misuse",
"message": "The <input> element with a missing or invalid type and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [],
"apiArgs": [],
"category": "Accessibility"
Expand All @@ -86,13 +85,31 @@
"dom": "/html[1]/body[1]/main[1]/input[2]",
"aria": "/document[1]/main[1]/combobox[2]"
},
"reasonId": "Potential_1",
"message": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with type=\"text\"",
"reasonId": "potential_type_misuse",
"message": "The <input> element with type \"text\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [
"text"
],
"apiArgs": [],
"category": "Accessibility"
},
{
"ruleId": "input_haspopup_conflict",
"value": [
"INFORMATION",
"POTENTIAL"
],
"path": {
"dom": "/html[1]/body[1]/main[1]/input[4]",
"aria": "/document[1]/main[1]/combobox[4]"
},
"reasonId": "potential_type_misuse",
"message": "The <input> element with type \"number\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [
"number"
],
"apiArgs": [],
"category": "Accessibility"
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@

<input list="listbox2" type='mytel' id="browser2" aria-haspopup="listbox">

<!-- not triggerred, no failure/pass case -->
<input list="function-types" type='date' id="browser4" aria-haspopup="listbox">
<datalist id="function-types">
<option value="function">function</option>
Expand All @@ -71,8 +70,8 @@
"dom": "/html[1]/body[1]/main[1]/input[1]",
"aria": "/document[1]/main[1]/combobox[1]"
},
"reasonId": "Potential_1",
"message": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with type=\"search\"",
"reasonId": "potential_type_misuse",
"message": "The <input> element with type \"search\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [
"search"
],
Expand All @@ -89,8 +88,8 @@
"dom": "/html[1]/body[1]/main[1]/input[2]",
"aria": "/document[1]/main[1]/combobox[2]"
},
"reasonId": "Potential_1",
"message": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with type=\"email\"",
"reasonId": "potential_type_misuse",
"message": "The <input> element with type \"email\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [
"email"
],
Expand All @@ -107,8 +106,8 @@
"dom": "/html[1]/body[1]/main[1]/input[3]",
"aria": "/document[1]/main[1]/combobox[3]"
},
"reasonId": "Potential_1",
"message": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with type=\"tel\"",
"reasonId": "potential_type_misuse",
"message": "The <input> element with type \"tel\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [
"tel"
],
Expand All @@ -125,11 +124,29 @@
"dom": "/html[1]/body[1]/main[1]/input[4]",
"aria": "/document[1]/main[1]/combobox[4]"
},
"reasonId": "Potential_2",
"message": "<input> element with 'list' attribute also uses 'aria-haspopup' attribute with missing or invalid input type",
"reasonId": "potential_misuse",
"message": "The <input> element with a missing or invalid type and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [],
"apiArgs": [],
"category": "Accessibility"
},
{
"ruleId": "input_haspopup_conflict",
"value": [
"INFORMATION",
"POTENTIAL"
],
"path": {
"dom": "/html[1]/body[1]/main[1]/input[5]",
"aria": "/document[1]/main[1]"
},
"reasonId": "potential_type_misuse",
"message": "The <input> element with type \"date\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"messageArgs": [
"date"
],
"apiArgs": [],
"category": "Accessibility"
}
]
}
Expand Down
Loading

0 comments on commit ee397d5

Please sign in to comment.