Skip to content
This repository has been archived by the owner on Dec 7, 2022. It is now read-only.

Commit

Permalink
Short-circuit collectMatchingElements if a non-visible subtree is found.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alice Boxhall committed Dec 3, 2015
1 parent 34c11c2 commit 36c574c
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 21 deletions.
46 changes: 32 additions & 14 deletions src/js/AccessibilityUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,6 @@ axs.utils.getContrastRatioForElement = function(element) {
* @return {?number}
*/
axs.utils.getContrastRatioForElementWithComputedStyle = function(style, element) {
if (axs.utils.isElementHidden(element))
return null;

var bgColor = axs.utils.getBgColor(style, element);
if (!bgColor)
return null;
Expand Down Expand Up @@ -569,22 +566,41 @@ axs.utils.isElementDisabled = function(element) {

/**
* @param {Element} element An element to check.
* @return {boolean} True if the element is hidden from accessibility.
* @return {boolean} True if an element itself has a style attribute which causes it
* not to be visible.
*/
axs.utils.isElementHidden = function(element) {
if (!(element instanceof element.ownerDocument.defaultView.HTMLElement))
return false;

if (element.hasAttribute('chromevoxignoreariahidden'))
var chromevoxignoreariahidden = true;

axs.utils.elementHasNonVisibleStyle = function(element) {
var style = window.getComputedStyle(element, null);
if (style.display == 'none' || style.visibility == 'hidden')
return true;
return false;
}

/**
* @param {Element} element An element to check.
* @return {boolean} True if the element is not visible to any user.
*/
axs.utils.elementIsNotVisible = function(element) {
if (axs.utils.elementHasNonVisibleStyle(element))
return true;
var boundingClientRect = element.getBoundingClientRect();
if (boundingClientRect.width === 0 && boundingClientRect.height === 0 &&
boundingClientRect.top === 0 && boundingClientRect.bottom === 0 &&
boundingClientRect.left === 0 && boundingClientRect.right === 0) {
return true;
}
return false;
}

/**
* @param {Element} element An element to check.
* @return {boolean} True if the element is hidden from accessibility.
*/
axs.utils.elementIsAriaHidden = function(element) {
if (element.hasAttribute('aria-hidden') &&
element.getAttribute('aria-hidden').toLowerCase() == 'true') {
return !chromevoxignoreariahidden;
element.getAttribute('aria-hidden').toLowerCase() == 'true' &&
!document.documentElement.hasAttribute('chromevoxignoreariahidden')) {
return true;
}

return false;
Expand All @@ -596,7 +612,9 @@ axs.utils.isElementHidden = function(element) {
* hidden from accessibility.
*/
axs.utils.isElementOrAncestorHidden = function(element) {
if (axs.utils.isElementHidden(element))
if (axs.utils.elementIsNotVisible(element))
return true;
if (axs.utils.elementIsAriaHidden(element))
return true;

if (axs.dom.parentElement(element))
Expand Down
2 changes: 2 additions & 0 deletions src/js/AuditRule.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ axs.AuditRule.collectMatchingElements = function(scope, matcher, collection, opt
* @return boolean
*/
function relevantElementCollector(element) {
if (axs.utils.elementHasNonVisibleStyle(element))
return false;
if (opt_ignoreSelectors) {
for (var i = 0; i < opt_ignoreSelectors.length; i++) {
if (axs.browserUtils.matchSelector(element, opt_ignoreSelectors[i]))
Expand Down
10 changes: 5 additions & 5 deletions test/audits/aria-on-reserved-element-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

test('Reserved element with role and aria- attributes', function() {
var fixture = document.getElementById('qunit-fixture');
var widget = fixture.appendChild(document.createElement('meta'));
var widget = fixture.appendChild(document.createElement('map'));
widget.setAttribute('role', 'spinbutton');
widget.setAttribute('aria-hidden', 'false'); // global
widget.setAttribute('aria-required', 'true'); // supported
Expand All @@ -59,23 +59,23 @@

test('Reserved element with role only', function() {
var fixture = document.getElementById('qunit-fixture');
var widget = fixture.appendChild(document.createElement('meta'));
var widget = fixture.appendChild(document.createElement('map'));
widget.setAttribute('role', 'spinbutton');
var expected = { elements: [widget], result: axs.constants.AuditResult.FAIL };
deepEqual(rule.run({ scope: fixture }), expected, 'Reserved elements can\'t take any ARIA attributes.');
});

test('Reserved element with aria-attributes only', function() {
var fixture = document.getElementById('qunit-fixture');
var widget = fixture.appendChild(document.createElement('meta'));
var widget = fixture.appendChild(document.createElement('map'));
widget.setAttribute('aria-hidden', 'false'); // global
var expected = { elements: [widget], result: axs.constants.AuditResult.FAIL };
deepEqual(rule.run({ scope: fixture }), expected, 'Reserved elements can\'t take any ARIA attributes.');
});

test('Using ignoreSelectors, reserved element with aria-attributes only', function() {
var fixture = document.getElementById('qunit-fixture');
var widget = fixture.appendChild(document.createElement('meta'));
var widget = fixture.appendChild(document.createElement('map'));
var ignoreSelectors = ['#' + (widget.id = 'ignoreMe')];
widget.setAttribute('aria-hidden', 'false'); // global
var expected = { result: axs.constants.AuditResult.NA };
Expand All @@ -84,7 +84,7 @@

test('Reserved element with no ARIA attributes', function() {
var fixture = document.getElementById('qunit-fixture');
fixture.appendChild(document.createElement('meta'));
fixture.appendChild(document.createElement('map'));
var expected = { elements: [], result: axs.constants.AuditResult.PASS };
deepEqual(rule.run({ scope: fixture }), expected, 'A reserved element with no ARIA attributes should pass');
});
Expand Down
2 changes: 1 addition & 1 deletion test/audits/bad-aria-attribute-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
*/
test('Element with role and global but missing supported and required attributes', function() {
var fixture = document.getElementById('qunit-fixture');
var widget = fixture.appendChild(document.createElement('meta')); // note, a reserved HTML element
var widget = fixture.appendChild(document.createElement('map')); // note, a reserved HTML element
widget.setAttribute('role', 'spinbutton');
widget.setAttribute('aria-hidden', 'false'); // global (so the audit will encounter this element)
var expected = { elements: [], result: axs.constants.AuditResult.PASS };
Expand Down
2 changes: 1 addition & 1 deletion test/audits/unsupported-aria-attribute-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
*/
test('Element with role and global but missing supported and required attributes', function() {
var fixture = document.getElementById('qunit-fixture');
var widget = fixture.appendChild(document.createElement('meta')); // note, a reserved HTML element
var widget = fixture.appendChild(document.createElement('map')); // note, a reserved HTML element
var expected = { elements: [], result: axs.constants.AuditResult.PASS };
widget.setAttribute('role', 'spinbutton');
widget.setAttribute('aria-hidden', 'false'); // global (so the audit will encounter this element)
Expand Down

0 comments on commit 36c574c

Please sign in to comment.