From bd52e011975cac687d1ddf0511abe04057037164 Mon Sep 17 00:00:00 2001 From: Shunguo Date: Tue, 24 Oct 2023 21:38:35 -0500 Subject: [PATCH] rule update #1674 --- .../v2/checker/accessibility/util/legacy.ts | 65 +++++----- .../src/v4/rules/target_spacing_sufficient.ts | 111 +++++++++++++----- .../link_inline_with_block.html | 11 +- 3 files changed, 118 insertions(+), 69 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 29484c5e1..88a8607b2 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/util/legacy.ts @@ -465,61 +465,52 @@ export class RPTUtil { public static isInline(element) { if (!element) return false; - var uStyle = getComputedStyle(element); - if (!uStyle) return false; - const udisplay = cStyle.getPropertyValue("display"); - // focus on inline element only + const style = getComputedStyle(element); + if (!style) return false; + const udisplay = style.getPropertyValue("display"); + // inline element only if (udisplay !== 'inline') return false; const parent = element.parentElement; if (parent) { - var cStyle = getComputedStyle(parent); - var display = cStyle.getPropertyValue("display"); + const style = getComputedStyle(parent); + const display = style.getPropertyValue("display"); + // an inline element is inside a block. note is a block element too if (display === 'block' || display === 'inline-block') { - let multipleInline = false; let containText = false; - // more than one inline elements with text in the same line: text, text, text + // one or more inline elements with text in the same line: text, text, +text, +text, text+ let walkNode = element.nextSibling; - while (walkNode) { + while (!containText && walkNode) { + // note browsers insert Text nodes to represent whitespaces. if (walkNode.nodeType === Node.TEXT_NODE && walkNode.nodeValue && walkNode.nodeValue.trim().length > 0) { containText = true; } else if (walkNode.nodeType === Node.ELEMENT_NODE) { - cStyle = getComputedStyle(walkNode); - display = cStyle.getPropertyValue("display"); - if (display !== 'inline') { - multipleInline = false; - break; - } - multipleInline = true; + const cStyle = getComputedStyle(walkNode); + const cDisplay = cStyle.getPropertyValue("display"); + if (cDisplay !== 'inline') break; } walkNode = walkNode.nextSibling; } - - walkNode = element.previousSibling; - while (walkNode) { - if (walkNode.nodeType === Node.TEXT_NODE && walkNode.nodeValue && walkNode.nodeValue.trim().length > 0) { - containText = true; - } else if (walkNode.nodeType === Node.ELEMENT_NODE) { - cStyle = getComputedStyle(walkNode); - display = cStyle.getPropertyValue("display"); - if (display !== 'inline') { - multipleInline = false; - break; + if (!containText) { + walkNode = element.previousSibling; + while (!containText && walkNode) { + // note browsers insert Text nodes to represent whitespaces. + if (walkNode.nodeType === Node.TEXT_NODE && walkNode.nodeValue && walkNode.nodeValue.trim().length > 0) { + containText = true; + } else if (walkNode.nodeType === Node.ELEMENT_NODE) { + const cStyle = getComputedStyle(walkNode); + const cDisplay = cStyle.getPropertyValue("display"); + if (cDisplay !== 'inline') break; } - multipleInline = true; + walkNode = walkNode.previousSibling; } - walkNode = walkNode.previousSibling; } - // an inline element is the only element in the line inside a block - // note browsers insert Text nodes to represent whitespaces. - if (parent.childNodes.length === 1) - return false; - - // multiple inline elements are in the same line with text - - + // one or more inline elements are in the same line with text + if (containText) return true; + // one or more inline elements are in the same inline without text + return false; } } // all other cases 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 8fb1a3aa6..ba1d521b9 100644 --- a/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts +++ b/accessibility-checker-engine/src/v4/rules/target_spacing_sufficient.ts @@ -12,11 +12,11 @@ *****************************************************************************/ import { RPTUtil } from "../../v2/checker/accessibility/util/legacy"; - import { Rule, RuleResult, RuleContext, RulePass, RuleContextHierarchy, RulePotential } from "../api/IRule"; + import { Rule, RuleResult, RuleContext, RulePass, RuleContextHierarchy, RuleFail, RulePotential } from "../api/IRule"; import { eRulePolicy, eToolkitLevel } from "../api/IRule"; import { VisUtil } from "../../v2/dom/VisUtil"; import { DOMMapper } from "../../v2/dom/DOMMapper"; - import { getDefinedStyles, getComputedStyle } from "../util/CSSUtil"; + import { getComputedStyle } from "../util/CSSUtil"; export let target_spacing_sufficient: Rule = { id: "target_spacing_sufficient", @@ -25,8 +25,12 @@ help: { "en-US": { "group": "target_spacing_sufficient.html", - "pass": "target_spacing_sufficient.html", - "potential_obscured": "target_spacing_sufficient.html" + "pass_spacing": "target_spacing_sufficient.html", + "pass_sized": "target_spacing_sufficient.html", + "pass_inline": "target_spacing_sufficient.html", + "pass_default": "target_spacing_sufficient.html", + "violation": "target_spacing_sufficient.html", + "potential_overlap": "target_spacing_sufficient.html" } }, messages: { @@ -36,7 +40,6 @@ "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" } @@ -55,23 +58,17 @@ if (RPTUtil.getAncestor(ruleContext, ["pre", "code", "script", "meta", 'head']) !== null || nodeName === "body" || nodeName === "html" ) return null; - console.log("node=" + nodeName +", inline=" +RPTUtil.isInline(ruleContext)); - if (RPTUtil.isInline(ruleContext)) - return null; - + + // ignore hidden, non-target, or inline element without text in the same line if (!VisUtil.isNodeVisible(ruleContext) || !RPTUtil.isTarget(ruleContext)) return null; - - - + + console.log("node=" + nodeName +", id=" + ruleContext.getAttribute('id') +", inline=" +RPTUtil.isInline(ruleContext)); + if (RPTUtil.isInline(ruleContext)) + return RulePass("pass_inline"); const bounds = context["dom"].bounds; - - //in case the bounds not available - if (!bounds) return null; - - //ignore - if (bounds['height'] === 0 || bounds['width'] === 0 ) + if (!bounds || bounds['height'] === 0 || bounds['width'] === 0 ) return null; var doc = ruleContext.ownerDocument; @@ -92,20 +89,24 @@ return; const mapper : DOMMapper = new DOMMapper(); - let violations = []; let before = true; + let minX = 24; + let minY = 24; + let adjacentX = null; + let adjacentY = null; for (let i=0; i < elems.length; i++) { const elem = elems[i] as HTMLElement; /** * 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 + * filter out the elements that’re descendant or ancestors of the target element */ if (ruleContext.contains(elem)) { //the next node in elems will be after the target node (ruleContext). before = false; continue; } - if (!VisUtil.isNodeVisible(elem) || elem.contains(ruleContext)) continue; + if (!VisUtil.isNodeVisible(elem) || !RPTUtil.isTarget(elem) || elem.contains(ruleContext)) continue; const bnds = mapper.getBounds(elem); if (bnds.height === 0 || bnds.width === 0) continue; @@ -117,23 +118,75 @@ if (!z_index || isNaN(Number(z_index))) z_index = "0"; } + + // ignore if the target is entirely covered: tabbable target handled by element_tabbable_unobscured and tabindex=-1 ignored 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: tabbable target handled by element_tabbable_unobscured and tabindex=-1 ignored - continue; + && bnds.left + bnds.height >= bounds.left + bounds.width) + if (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index)) + return null; + else { + if (bnds.height >= 24 && bnds.width >= 24) + return RulePass("pass_sized"); + return RuleFail("violation", [nodeName, elem.nodeName.toLowerCase()]); + } + + // the element overlaps with target + if (((bounds.top >= bnds.top && bounds.top <= bnds.top + bnds.height) || (bounds.top <= bnds.top && bounds.top + bounds.height > bnds.top)) + && ((bounds.left >= bnds.left && bounds.left <= bnds.left + bnds.width) || (bounds.left <= bnds.left && bounds.left + bounds.width > bnds.left))) + return null; + + else { // no overlap + if (bnds.height >= 24 && bnds.width >= 24) + return RulePass("pass_sized"); + // the element is in the horizontally same row + let disX = 24; + let disY = 24; + if ((bounds.top >= bnds.top && bounds.top <= bnds.top + bnds.height) || (bounds.top <= bnds.top && bounds.top + bounds.height > bnds.top)) + disX = Math.min( Math.abs(bounds.left - bnds.left), Math.abs(bounds.left - (bnds.left + bnds.width)), Math.abs(bounds.left + bounds.width - (bnds.left + bnds.width)), Math.abs(bounds.left + bounds.width - bnds.left)); + + // the element is in the horizontally same column + if ((bounds.left >= bnds.left && bounds.left <= bnds.left + bnds.width) || (bounds.left <= bnds.left && bounds.left + bounds.width > bnds.left)) + disY = Math.min(Math.abs(bounds.top - bnds.top), Math.abs(bounds.top - (bnds.top + bnds.height)), Math.abs(bounds.top + bounds.height - (bnds.top + bnds.height)), Math.abs(bounds.top + bounds.height - bnds.top)); + + if (disX < minX) { + minX = disX; + adjacentX = elem; + } + if (disY < minY) { + minY = disY; + adjacentY = elem; + } + + } + } + + if (Math.round(bounds.width/2) + minX < 12 || Math.round(bounds.height/2) + minY < 12) { + if (Math.round(bounds.width/2) + minX < Math.round(bounds.height/2) + minY) + return RuleFail("violation", [nodeName, adjacentX.nodeName.toLowerCase()]); + return RuleFail("violation", [nodeName, adjacentY.nodeName.toLowerCase()]); + } + //if (bounds.top <= bnds.top && bounds.top + bounds.height >= bnds.top || bounds.top <= bnds.top+ bounds.height && bounds.top + bounds.height >= bnds.top + bnds.height) + + + //minX = min(minX, min( abs(bounds.left - bnds.left), abs(bounds.left - bnds.right), abs(bounds.right - bnds.right), abs(bounds.right - bnds.left)) + + //if (bounds.left <= bnds.left && bounds.left+bounds.width >= bnds.left+bnds.width || bounds.left <= bnds.left + bnds.width && bounds.left + bounds.width >= bnds.right) + + //minY = min(minY, min(abs(bounds.top - bnds.top), abs(bounds.top - bnds.bottom), abs(bounds.bottom - bnds.bottom), abs(bounds.bottom - bnds.top))) + + + + // if the target is on top of an overlapping elements + /** 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"); + return RulePass("pass_spacing"); } } \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/link_inline_with_block.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/link_inline_with_block.html index 08ace8e72..76cacff59 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/link_inline_with_block.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/target_spacing_sufficient_ruleunit/link_inline_with_block.html @@ -6,10 +6,15 @@
-
This is X l in text. This is Y l in text.
-
- +
This is link x in text.
This is link y
in text.
+

+

+
 a 
+
 z v
+
  z  v.
+
 z . v
+
  .  z  v