Skip to content

Commit fd25ae9

Browse files
author
Pooja0504
committed
AXE-1598 : no-visible-label rule
1 parent 1a504b3 commit fd25ae9

File tree

2 files changed

+178
-41
lines changed

2 files changed

+178
-41
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { getNodeFromTree, memoize } from '../../core/utils';
2+
import { sanitize } from '../text';
3+
import { getIntersectionRect, getRectCenter, isPointInRect } from '../math';
4+
import getOverflowHiddenAncestors from './get-overflow-hidden-ancestors';
5+
import cache from '../../core/base/cache';
6+
7+
/**
8+
* Get the visible text client rects of a node.
9+
* @method getVisibleChildTextRect
10+
* @memberof axe.commons.dom
11+
* @instance
12+
* @param {Element} node
13+
*/
14+
const getVisibleChildTextRect = memoize(
15+
function getVisibleChildTextRectMemoized(node) {
16+
const vNode = getNodeFromTree(node);
17+
const nodeRect = vNode.boundingClientRect;
18+
const clientRects = [];
19+
const overflowHiddenNodes = getOverflowHiddenAncestors(vNode);
20+
21+
node.childNodes.forEach(textNode => {
22+
if (textNode.nodeType !== 3 || sanitize(textNode.nodeValue) === '') {
23+
return;
24+
}
25+
26+
const contentRects = getContentRects(textNode);
27+
if (isOutsideNodeBounds(contentRects, nodeRect) && !cache.get('ruleId')) {
28+
return;
29+
}
30+
31+
clientRects.push(...filterHiddenRects(contentRects, overflowHiddenNodes));
32+
});
33+
34+
// a11y-engine-domforge change
35+
if (clientRects.length <= 0) {
36+
return [];
37+
}
38+
/**
39+
* if all text rects are larger than the bounds of the node,
40+
* or goes outside of the bounds of the node, we need to use
41+
* the nodes bounding rect so we stay within the bounds of the
42+
* element.
43+
*
44+
* @see https://github.com/dequelabs/axe-core/issues/2178
45+
* @see https://github.com/dequelabs/axe-core/issues/2483
46+
* @see https://github.com/dequelabs/axe-core/issues/2681
47+
*
48+
* also need to resize the nodeRect to fit within the bounds of any overflow: hidden ancestors.
49+
*
50+
* @see https://github.com/dequelabs/axe-core/issues/4253
51+
*/
52+
return clientRects.length
53+
? clientRects
54+
: filterHiddenRects([nodeRect], overflowHiddenNodes);
55+
}
56+
);
57+
export default getVisibleChildTextRect;
58+
59+
function getContentRects(node) {
60+
const range = document.createRange();
61+
range.selectNodeContents(node);
62+
return Array.from(range.getClientRects());
63+
}
64+
65+
/**
66+
* Check to see if the text rect size is outside the of the
67+
* nodes bounding rect. Since we use the midpoint of the element
68+
* when determining the rect stack we will also use the midpoint
69+
* of the text rect to determine out of bounds
70+
*/
71+
function isOutsideNodeBounds(rects, nodeRect) {
72+
return rects.some(rect => {
73+
const centerPoint = getRectCenter(rect);
74+
return !isPointInRect(centerPoint, nodeRect);
75+
});
76+
}
77+
78+
/**
79+
* Filter out 0 width and height rects (newline characters) and
80+
* any rects that are outside the bounds of overflow hidden
81+
* ancestors
82+
*/
83+
function filterHiddenRects(contentRects, overflowHiddenNodes) {
84+
const visibleRects = [];
85+
contentRects.forEach(contentRect => {
86+
// ie11 has newline characters return 0.00998, so we'll say if the
87+
// line is < 1 it shouldn't be counted
88+
if (contentRect.width < 1 || contentRect.height < 1) {
89+
return;
90+
}
91+
92+
// update the rect size to fit inside the bounds of all overflow
93+
// hidden ancestors
94+
const visibleRect = overflowHiddenNodes.reduce((rect, overflowNode) => {
95+
return rect && getIntersectionRect(rect, overflowNode.boundingClientRect);
96+
}, contentRect);
97+
98+
if (visibleRect) {
99+
visibleRects.push(visibleRect);
100+
}
101+
});
102+
103+
return visibleRects;
104+
}

lib/commons/dom/get-visible-child-text-rects.js

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getNodeFromTree, memoize } from '../../core/utils';
1+
import { getNodeFromTree } from '../../core/utils';
22
import { sanitize } from '../text';
33
import { getIntersectionRect, getRectCenter, isPointInRect } from '../math';
44
import getOverflowHiddenAncestors from './get-overflow-hidden-ancestors';
@@ -11,49 +11,72 @@ import cache from '../../core/base/cache';
1111
* @instance
1212
* @param {Element} node
1313
*/
14-
const getVisibleChildTextRects = memoize(
15-
function getVisibleChildTextRectsMemoized(node) {
16-
const vNode = getNodeFromTree(node);
17-
const nodeRect = vNode.boundingClientRect;
18-
const clientRects = [];
19-
const overflowHiddenNodes = getOverflowHiddenAncestors(vNode);
14+
const getVisibleChildTextRects = (node, options = {}) => {
15+
const {
16+
checkTextRectOutsideNodeBoundingRect = false,
17+
includeOutsideBounds = true,
18+
includeOverflowHidden = false,
19+
checkNoVisibleRectsIdentified = false
20+
} = options;
21+
const vNode = getNodeFromTree(node);
22+
const nodeRect = vNode.boundingClientRect;
23+
const clientRects = [];
24+
const overflowHiddenNodes = getOverflowHiddenAncestors(vNode);
2025

21-
node.childNodes.forEach(textNode => {
22-
if (textNode.nodeType !== 3 || sanitize(textNode.nodeValue) === '') {
23-
return;
24-
}
26+
node.childNodes.forEach(textNode => {
27+
if (textNode.nodeType !== 3 || sanitize(textNode.nodeValue) === '') {
28+
return;
29+
}
2530

26-
const contentRects = getContentRects(textNode);
27-
if (isOutsideNodeBounds(contentRects, nodeRect) && !cache.get('ruleId')) {
28-
return;
29-
}
31+
const contentRects = getContentRects(textNode);
32+
if (
33+
includeOutsideBounds &&
34+
isOutsideNodeBounds(
35+
contentRects,
36+
nodeRect,
37+
checkTextRectOutsideNodeBoundingRect
38+
) &&
39+
(!cache.get('ruleId') ||
40+
cache.get('ruleId') === 'reflow-4x-zoom-scroll' ||
41+
cache.get('ruleId') === 'color-contrast')
42+
) {
43+
return;
44+
}
3045

31-
clientRects.push(...filterHiddenRects(contentRects, overflowHiddenNodes));
32-
});
46+
clientRects.push(
47+
...filterHiddenRects(
48+
contentRects,
49+
includeOverflowHidden ? [] : overflowHiddenNodes
50+
)
51+
);
52+
});
3353

34-
// a11y-engine-domforge change
35-
if (clientRects.length <= 0) {
36-
return [];
37-
}
38-
/**
39-
* if all text rects are larger than the bounds of the node,
40-
* or goes outside of the bounds of the node, we need to use
41-
* the nodes bounding rect so we stay within the bounds of the
42-
* element.
43-
*
44-
* @see https://github.com/dequelabs/axe-core/issues/2178
45-
* @see https://github.com/dequelabs/axe-core/issues/2483
46-
* @see https://github.com/dequelabs/axe-core/issues/2681
47-
*
48-
* also need to resize the nodeRect to fit within the bounds of any overflow: hidden ancestors.
49-
*
50-
* @see https://github.com/dequelabs/axe-core/issues/4253
51-
*/
52-
return clientRects.length
53-
? clientRects
54-
: filterHiddenRects([nodeRect], overflowHiddenNodes);
54+
// a11y-engine-domforge change
55+
if (
56+
clientRects.length <= 0 &&
57+
((cache.get('ruleId') && cache.get('ruleId') === 'resize-2x-zoom') ||
58+
checkNoVisibleRectsIdentified)
59+
) {
60+
return [];
5561
}
56-
);
62+
/**
63+
* if all text rects are larger than the bounds of the node,
64+
* or goes outside of the bounds of the node, we need to use
65+
* the nodes bounding rect so we stay within the bounds of the
66+
* element.
67+
*
68+
* @see https://github.com/dequelabs/axe-core/issues/2178
69+
* @see https://github.com/dequelabs/axe-core/issues/2483
70+
* @see https://github.com/dequelabs/axe-core/issues/2681
71+
*
72+
* also need to resize the nodeRect to fit within the bounds of any overflow: hidden ancestors.
73+
*
74+
* @see https://github.com/dequelabs/axe-core/issues/4253
75+
*/
76+
return clientRects.length
77+
? clientRects
78+
: filterHiddenRects([nodeRect], overflowHiddenNodes);
79+
};
5780
export default getVisibleChildTextRects;
5881

5982
function getContentRects(node) {
@@ -68,10 +91,20 @@ function getContentRects(node) {
6891
* when determining the rect stack we will also use the midpoint
6992
* of the text rect to determine out of bounds
7093
*/
71-
function isOutsideNodeBounds(rects, nodeRect) {
94+
function isOutsideNodeBounds(
95+
rects,
96+
nodeRect,
97+
checkTextRectOutsideNodeBoundingRect = false
98+
) {
7299
return rects.some(rect => {
73100
const centerPoint = getRectCenter(rect);
74-
return !isPointInRect(centerPoint, nodeRect);
101+
if (checkTextRectOutsideNodeBoundingRect) {
102+
return (
103+
!isPointInRect(centerPoint, nodeRect) || rect.right > nodeRect.right
104+
);
105+
} else {
106+
return !isPointInRect(centerPoint, nodeRect);
107+
}
75108
});
76109
}
77110

0 commit comments

Comments
 (0)