From 8272bec038753f81644fd9b5eb817fcbb6eecf09 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Thu, 12 Oct 2023 09:35:11 -0500 Subject: [PATCH 01/48] create initial rule #1674 --- .../src/v4/rules/target_spacing_sufficient.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts diff --git a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts new file mode 100644 index 000000000..5663f6ca2 --- /dev/null +++ b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts @@ -0,0 +1,61 @@ +/****************************************************************************** + Copyright:: 2022- IBM, Inc + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +import { RPTUtil } from "../../v2/checker/accessibility/util/legacy"; +import { VisUtil } from "../../v2/dom/VisUtil"; +import { Rule, RuleResult, RuleFail, RuleContext, RulePotential, RuleManual, RulePass, RuleContextHierarchy } from "../api/IRule"; +import { eRulePolicy, eToolkitLevel } from "../api/IRule"; + +export let area_alt_exists: Rule = { + id: "area_alt_exists", + context: "dom:area", + refactor: { + "WCAG20_Area_HasAlt": { + "Pass_0": "Pass_0", + "Fail_1": "Fail_1" + } + }, + help: { + "en-US": { + "group": `area_alt_exists.html`, + "Pass_0": `area_alt_exists.html`, + "Fail_1": `area_alt_exists.html` + } + }, + messages: { + "en-US": { + "group": " elements in an image map must have a text alternative", + "Pass_0": "Rule Passed", + "Fail_1": " element in an image map has no text alternative" + } + }, + rulesets: [{ + id: [ "IBM_Accessibility", "WCAG_2_0", "WCAG_2_1"], + num: "1.1.1", // num: [ "2.4.4", "x.y.z" ] also allowed + level: eRulePolicy.VIOLATION, + toolkitLevel: eToolkitLevel.LEVEL_ONE +}], + act: [], + run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => { + const ruleContext = context["dom"].node as Element; + //skip the rule + if (VisUtil.isNodeHiddenFromAT(ruleContext)) return null; + // JCH - NO OUT OF SCOPE hidden in context + if (RPTUtil.attributeNonEmpty(ruleContext, "alt")) { + return RulePass("Pass_0"); + } else { + return RuleFail("Fail_1"); + } + } +} + \ No newline at end of file From 6fd5aa6040cf3d7e108adef9aceff0ef63bbff44 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Fri, 13 Oct 2023 08:58:24 -0500 Subject: [PATCH 02/48] initial rule #1674 --- .../en-US/target_spacing_sufficient.html | 96 +++++++++++ .../src/v4/rules/target_spacing_sufficient.ts | 156 +++++++++++++----- .../element_overlaid_hidden_default.html | 99 +++++++++++ .../element_overlaid_hidden_zindex.html | 101 ++++++++++++ .../element_overlaid_visible_default.html | 99 +++++++++++ .../element_overlaid_visible_zindex.html | 101 ++++++++++++ 6 files changed, 608 insertions(+), 44 deletions(-) create mode 100644 accessibility-checker-engine/help-v4/en-US/target_spacing_sufficient.html create mode 100755 accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_default.html create mode 100755 accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_zindex.html create mode 100755 accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_default.html create mode 100755 accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_zindex.html diff --git a/accessibility-checker-engine/help-v4/en-US/target_spacing_sufficient.html b/accessibility-checker-engine/help-v4/en-US/target_spacing_sufficient.html new file mode 100644 index 000000000..870cd8dd7 --- /dev/null +++ b/accessibility-checker-engine/help-v4/en-US/target_spacing_sufficient.html @@ -0,0 +1,96 @@ + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts index 5663f6ca2..94c670643 100644 --- a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts +++ b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts @@ -11,51 +11,119 @@ limitations under the License. *****************************************************************************/ -import { RPTUtil } from "../../v2/checker/accessibility/util/legacy"; -import { VisUtil } from "../../v2/dom/VisUtil"; -import { Rule, RuleResult, RuleFail, RuleContext, RulePotential, RuleManual, RulePass, RuleContextHierarchy } from "../api/IRule"; -import { eRulePolicy, eToolkitLevel } from "../api/IRule"; - -export let area_alt_exists: Rule = { - id: "area_alt_exists", - context: "dom:area", - refactor: { - "WCAG20_Area_HasAlt": { - "Pass_0": "Pass_0", - "Fail_1": "Fail_1" - } - }, - help: { - "en-US": { - "group": `area_alt_exists.html`, - "Pass_0": `area_alt_exists.html`, - "Fail_1": `area_alt_exists.html` - } - }, - messages: { - "en-US": { - "group": " elements in an image map must have a text alternative", - "Pass_0": "Rule Passed", - "Fail_1": " element in an image map has no text alternative" + import { RPTUtil } from "../../v2/checker/accessibility/util/legacy"; + import { Rule, RuleResult, RuleContext, RulePass, RuleContextHierarchy, RulePotential } from "../api/IRule"; + import { eRulePolicy, eToolkitLevel } from "../api/IRule"; + import { VisUtil } from "../../v2/dom/VisUtil"; + import { DOMMapper } from "../../v2/dom/DOMMapper"; + import { DOMUtil } from "../../v2/dom/DOMUtil"; + + export let target_spacing_sufficient: Rule = { + id: "target_spacing_sufficient", + context: "dom:*", + dependencies: [], + help: { + "en-US": { + "group": "target_spacing_sufficient.html", + "pass": "target_spacing_sufficient.html", + "potential_obscured": "target_spacing_sufficient.html" + } + }, + messages: { + "en-US": { + "group": "The target is sufficiently spaced from other targets", + "pass_spacing": "The target's spacing from other targets is more than minimum", + "pass_sized": "The target’s size is more than 24 CSS pixels", + "pass_inline": "The target is in a sentence or its size is otherwise constrained by the line-height of non-target text", + "pass_default": "The size of the target is determined by the user agent and is not modified by the author", + "pass": "The element is not entirely covered by other content", + "violation": "The center of the <0> target is less than 12 CSS pixels from the bounding box (edge) of an adjacent target <1>", + "potential_overlap": "Ensure the overlapped <0> element meets a minimum target size or has sufficient spacing from the overlapping element" + } + }, + rulesets: [{ + id: ["WCAG_2_2"], + num: ["2.5.8"], + level: eRulePolicy.VIOLATION, + toolkitLevel: eToolkitLevel.LEVEL_THREE + }], + act: [], + run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => { + const ruleContext = context["dom"].node as HTMLElement; + if (!VisUtil.isNodeVisible(ruleContext) || (!RPTUtil.isTabbable(ruleContext) && (!ruleContext .hasAttribute("tabindex")))) + return null; + + const nodeName = ruleContext.nodeName.toLocaleLowerCase(); + + //ignore certain elements + if (RPTUtil.getAncestor(ruleContext, ["pre", "code", "script", "meta"]) !== null + || nodeName === "body" || nodeName === "html" ) + return null; + + const bounds = context["dom"].bounds; + + //in case the bounds not available + if (!bounds) return null; + + //ignore + if (bounds['height'] === 0 || bounds['width'] === 0 ) + return null; + + var doc = ruleContext.ownerDocument; + if (!doc) { + return null; + } + var win = doc.defaultView; + if (!win) { + return null; } - }, - rulesets: [{ - id: [ "IBM_Accessibility", "WCAG_2_0", "WCAG_2_1"], - num: "1.1.1", // num: [ "2.4.4", "x.y.z" ] also allowed - level: eRulePolicy.VIOLATION, - toolkitLevel: eToolkitLevel.LEVEL_ONE -}], - act: [], - run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => { - const ruleContext = context["dom"].node as Element; - //skip the rule - if (VisUtil.isNodeHiddenFromAT(ruleContext)) return null; - // JCH - NO OUT OF SCOPE hidden in context - if (RPTUtil.attributeNonEmpty(ruleContext, "alt")) { - return RulePass("Pass_0"); - } else { - return RuleFail("Fail_1"); + + var cStyle = win.getComputedStyle(ruleContext); + if (cStyle === null) + return null; + + let zindex = cStyle.zIndex; + if (!zindex || isNaN(Number(zindex))) + zindex = "0"; + + var elems = doc.querySelectorAll('body *:not(script)'); + if (!elems || elems.length == 0) + return; + + const mapper : DOMMapper = new DOMMapper(); + let violations = []; + let before = true; + elems.forEach(elem => { + /** + * the nodes returned from querySelectorAll is in document order + * if two elements overlap and z-index are not defined, then the node rendered earlier will be overlaid by the node rendered later + */ + if (ruleContext.contains(elem)) { + //the next node in elems will be after the target node (ruleContext). + before = false; + } else { + if (VisUtil.isNodeVisible(elem) && !elem.contains(ruleContext)) { + const bnds = mapper.getBounds(elem); + var zStyle = win.getComputedStyle(elem); + let z_index = '0'; + if (zStyle) { + z_index = zStyle.zIndex; + if (!z_index || isNaN(Number(z_index))) + z_index = "0"; + } + if (bnds.height !== 0 && bnds.width !== 0 + && bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height + && bnds.left + bnds.height >= bounds.left + bounds.width + && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) + violations.push(elem); + } + } + }); + + if (violations.length > 0) + return RulePotential("potential_obscured", []); + + return RulePass("pass"); } } -} \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_default.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_default.html new file mode 100755 index 000000000..02268eb3d --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_default.html @@ -0,0 +1,99 @@ + + + + + + + + RPT Test Suite + + + + + +
1
+
2
+ + + + + diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_zindex.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_zindex.html new file mode 100755 index 000000000..ac5812e05 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_hidden_zindex.html @@ -0,0 +1,101 @@ + + + + + + + + RPT Test Suite + + + + + +
1
+
2
+ + + + + diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_default.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_default.html new file mode 100755 index 000000000..4bec86731 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_default.html @@ -0,0 +1,99 @@ + + + + + + + + RPT Test Suite + + + + + +
1
+
2
+ + + + + diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_zindex.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_zindex.html new file mode 100755 index 000000000..f8dce5098 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_overlaid_visible_zindex.html @@ -0,0 +1,101 @@ + + + + + + + + RPT Test Suite + + + + + +
1
+
2
+ + + + + From 0e811d3411fcd46e942daece16d61f147c352785 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Fri, 13 Oct 2023 16:17:22 -0500 Subject: [PATCH 03/48] initial rule #1674 --- .../src/v4/rules/target_spacing_sufficient.ts | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts index 94c670643..3b94a250b 100644 --- a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts +++ b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts @@ -50,7 +50,7 @@ act: [], run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as HTMLElement; - if (!VisUtil.isNodeVisible(ruleContext) || (!RPTUtil.isTabbable(ruleContext) && (!ruleContext .hasAttribute("tabindex")))) + if (!VisUtil.isNodeVisible(ruleContext) || (!RPTUtil.isTabbable(ruleContext) && !ruleContext .hasAttribute("tabindex"))) return null; const nodeName = ruleContext.nodeName.toLocaleLowerCase(); @@ -93,7 +93,8 @@ const mapper : DOMMapper = new DOMMapper(); let violations = []; let before = true; - elems.forEach(elem => { + for (let i=0; i < elems.length; i++) { + const elem = elems[i]; /** * the nodes returned from querySelectorAll is in document order * if two elements overlap and z-index are not defined, then the node rendered earlier will be overlaid by the node rendered later @@ -101,24 +102,32 @@ if (ruleContext.contains(elem)) { //the next node in elems will be after the target node (ruleContext). before = false; - } else { - if (VisUtil.isNodeVisible(elem) && !elem.contains(ruleContext)) { - const bnds = mapper.getBounds(elem); - var zStyle = win.getComputedStyle(elem); - let z_index = '0'; - if (zStyle) { - z_index = zStyle.zIndex; - if (!z_index || isNaN(Number(z_index))) - z_index = "0"; - } - if (bnds.height !== 0 && bnds.width !== 0 - && bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height - && bnds.left + bnds.height >= bounds.left + bounds.width - && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) - violations.push(elem); - } - } - }); + continue; + } + if (!VisUtil.isNodeVisible(elem) || elem.contains(ruleContext)) continue; + + const bnds = mapper.getBounds(elem); + if (bnds.height === 0 || bnds.width === 0) continue; + + var zStyle = win.getComputedStyle(elem); + let z_index = '0'; + if (zStyle) { + z_index = zStyle.zIndex; + if (!z_index || isNaN(Number(z_index))) + z_index = "0"; + } + if (bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height + && bnds.left + bnds.height >= bounds.left + bounds.width + && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) + // if the target is entirely covered: handled by element_tabbable_unobscured + continue; + + if (bnds.height !== 0 && bnds.width !== 0 + && bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height + && bnds.left + bnds.height >= bounds.left + bounds.width + && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) + violations.push(elem); + } if (violations.length > 0) return RulePotential("potential_obscured", []); From 41d127dd55f2e0134aa1b341ec80e3d67ec812b5 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Fri, 13 Oct 2023 18:45:48 -0500 Subject: [PATCH 04/48] initial rule #1674 --- .../v2/checker/accessibility/util/legacy.ts | 26 +++++++++++++++++++ .../src/v4/rules/target_spacing_sufficient.ts | 2 +- .../src/v4/util/CommonUtil.ts | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts index 9523e5bc8..9b78b05c0 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts @@ -419,6 +419,32 @@ export class RPTUtil { } } + /** + * a target is en element that accept a pointer action (click or touch) + */ + public static isTarget(element) { + if (!element) return false; + + if (element.hasAttribute("tabindex") || RPTUtil.isTabbable(element)) return true; + + const roles = RPTUtil.getRoles(element, true); + if (!roles && roles.length === 0) + return false; + + let tagProperty = RPTUtil.getElementAriaProperty(element); + let allowedRoles = RPTUtil.getAllowedAriaRoles(element, tagProperty); + if (!allowedRoles && allowedRoles.length === 0) + return false; + + const parent = element.parentElement; + if (parent && (parent.hasAttribute("tabindex") || RPTUtil.isTabbable(parent))) { + const target_roles =["listitem", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "treeitem"]; + if (allowedRoles.includes('any') || roles.some(role => target_roles.includes(role))) + return true; + } + return false; + } + public static tabIndexLEZero(elem) { if (RPTUtil.hasAttribute(elem, "tabindex")) { if (elem.getAttribute("tabindex").match(/^-?\d+$/)) { diff --git a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts index 3b94a250b..4c8311f7f 100644 --- a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts +++ b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts @@ -119,7 +119,7 @@ if (bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height && bnds.left + bnds.height >= bounds.left + bounds.width && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) - // if the target is entirely covered: handled by element_tabbable_unobscured + // if the target is entirely covered: tabbable target handled by element_tabbable_unobscured and tabindex=-1 ignored continue; if (bnds.height !== 0 && bnds.width !== 0 diff --git a/accessibility-checker-engine/src/v4/util/CommonUtil.ts b/accessibility-checker-engine/src/v4/util/CommonUtil.ts index c6b0e9ab5..7632f91bf 100644 --- a/accessibility-checker-engine/src/v4/util/CommonUtil.ts +++ b/accessibility-checker-engine/src/v4/util/CommonUtil.ts @@ -60,7 +60,7 @@ export function getInvalidRoles(ruleContext: Element) { let invalidRoles = []; - if (allowedRoles && allowedRoles.includes('any')) + if (allowedRoles.includes('any')) return []; for (let i = 0; i < domRoles.length; i++) From ee16f586d326f0165cb54e6c4d5b833563ff6378 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Mon, 16 Oct 2023 18:22:39 -0500 Subject: [PATCH 05/48] add utilities for target #1674 --- .../v2/checker/accessibility/util/legacy.ts | 40 +++++- .../src/v4/rules/index.ts | 1 + .../src/v4/rules/target_spacing_sufficient.ts | 2 +- .../block_element_inline.html | 116 +++++++++++++++++ .../element_inline.html | 121 ++++++++++++++++++ 5 files changed, 278 insertions(+), 2 deletions(-) create mode 100755 accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/block_element_inline.html create mode 100755 accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_inline.html diff --git a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts index 9b78b05c0..8e396b82c 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts @@ -436,7 +436,45 @@ export class RPTUtil { if (!allowedRoles && allowedRoles.length === 0) return false; - const parent = element.parentElement; + let parent = element.parentElement; + // datalist, fieldset, optgroup, etc. may be just used for grouping purpose, so go up to the parent + while (parent && roles.some(role => role === 'group')) + parent = parent.parentElement; + + if (parent && (parent.hasAttribute("tabindex") || RPTUtil.isTabbable(parent))) { + const target_roles =["listitem", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "treeitem"]; + if (allowedRoles.includes('any') || roles.some(role => target_roles.includes(role))) + return true; + } + return false; + } + + /** + * an "inline" CSS display property tells the element to fit itself on the same line. An 'inline' element's width and height are ignored. + * some element has default inline property, such as , , + * most formatting elements inherent inline property, such as , , , + * an "inline-block" element still place element in the same line without breaking the line, but the element's width and height are applied. + */ + public static isInline(element) { + if (!element) return false; + + const inline_elements = ["listitem", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "treeitem"]; + if (element.hasAttribute("tabindex") || RPTUtil.isTabbable(element)) return true; + + const roles = RPTUtil.getRoles(element, true); + if (!roles && roles.length === 0) + return false; + + let tagProperty = RPTUtil.getElementAriaProperty(element); + let allowedRoles = RPTUtil.getAllowedAriaRoles(element, tagProperty); + if (!allowedRoles && allowedRoles.length === 0) + return false; + + let parent = element.parentElement; + // datalist, fieldset, optgroup, etc. may be just used for grouping purpose, so go up to the parent + while (parent && roles.some(role => role === 'group')) + parent = parent.parentElement; + if (parent && (parent.hasAttribute("tabindex") || RPTUtil.isTabbable(parent))) { const target_roles =["listitem", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "treeitem"]; if (allowedRoles.includes('any') || roles.some(role => target_roles.includes(role))) diff --git a/accessibility-checker-engine/src/v4/rules/index.ts b/accessibility-checker-engine/src/v4/rules/index.ts index f9430b5e7..d3988e786 100644 --- a/accessibility-checker-engine/src/v4/rules/index.ts +++ b/accessibility-checker-engine/src/v4/rules/index.ts @@ -175,6 +175,7 @@ export * from "./table_layout_linearized" export * from "./table_scope_valid" export * from "./table_structure_misuse" export * from "./table_summary_redundant" +export * from "./target_spacing_sufficient" export * from "./text_block_heading" export * from "./text_contrast_sufficient" export * from "./text_quoted_correctly" diff --git a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts index 4c8311f7f..7993bc346 100644 --- a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts +++ b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts @@ -50,7 +50,7 @@ act: [], run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as HTMLElement; - if (!VisUtil.isNodeVisible(ruleContext) || (!RPTUtil.isTabbable(ruleContext) && !ruleContext .hasAttribute("tabindex"))) + if (!VisUtil.isNodeVisible(ruleContext) || (!RPTUtil.isTarget(ruleContext))) return null; const nodeName = ruleContext.nodeName.toLocaleLowerCase(); diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/block_element_inline.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/block_element_inline.html new file mode 100755 index 000000000..204c8c8dc --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/block_element_inline.html @@ -0,0 +1,116 @@ + + + + + + + + RPT Test Suite + + + + + +

The display Property

+ +

display: inline

+
+ +

display: inline-block

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat scelerisque elit sit amet consequat. Aliquam erat volutpat. Aliquam venenatis gravida nisl sit amet facilisis. Nullam cursus fermentum velit sed laoreet.
+ +

display: block

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat scelerisque elit sit amet consequat. Aliquam erat volutpat. Aliquam venenatis gravida nisl sit amet facilisis. Nullam cursus fermentum velit sed laoreet.
+ + + + + + + diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_inline.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_inline.html new file mode 100755 index 000000000..013531b8e --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/element_inline.html @@ -0,0 +1,121 @@ + + + + + + + + RPT Test Suite + + + + + +

The display Property

+ +

display: inline

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat scelerisque elit sit amet consequat. Aliquam erat volutpat. + Aliquam + + gravida nisl sit amet facilisis. Nullam cursus fermentum velit sed laoreet. +
+ +

display: inline-block

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat scelerisque elit sit amet consequat. Aliquam erat volutpat. Aliquam venenatis gravida nisl sit amet facilisis. Nullam cursus fermentum velit sed laoreet.
+ +

display: block

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat scelerisque elit sit amet consequat. Aliquam erat volutpat. Aliquam venenatis gravida nisl sit amet facilisis. Nullam cursus fermentum velit sed laoreet.
+ + + + + + + From dcb35ab3598afbb3eedaa778fb433b18c848fb72 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Tue, 17 Oct 2023 15:08:26 -0500 Subject: [PATCH 06/48] add more test cases #1674 --- .../v2/checker/accessibility/util/legacy.ts | 11 ++- ...tml => block_overlaid_hidden_default.html} | 0 ...html => block_overlaid_hidden_zindex.html} | 0 ...tml => block_overlaid_visible_zindex.html} | 0 .../element_inline.html | 64 +++++++++++--- ...sible_default.html => element_target.html} | 83 +++++++++++++++++-- 6 files changed, 135 insertions(+), 23 deletions(-) rename accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/{element_overlaid_hidden_default.html => block_overlaid_hidden_default.html} (100%) rename accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/{element_overlaid_hidden_zindex.html => block_overlaid_hidden_zindex.html} (100%) rename accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/{element_overlaid_visible_zindex.html => block_overlaid_visible_zindex.html} (100%) rename accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/{element_overlaid_visible_default.html => element_target.html} (56%) diff --git a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts index 8e396b82c..7fe26ae23 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts @@ -451,9 +451,16 @@ export class RPTUtil { /** * an "inline" CSS display property tells the element to fit itself on the same line. An 'inline' element's width and height are ignored. - * some element has default inline property, such as , , + * some element has default inline property, such as , * most formatting elements inherent inline property, such as , , , - * an "inline-block" element still place element in the same line without breaking the line, but the element's width and height are applied. + * other inline elements: