accessibility-developer-tools
Version:
This is a library of accessibility-related testing and utility code.
70 lines (67 loc) • 3.04 kB
JavaScript
// Copyright 2014 Google 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.
goog.require('axs.AuditRules');
goog.require('axs.browserUtils');
goog.require('axs.constants');
goog.require('axs.dom');
goog.require('axs.utils');
/**
* This test checks ARIA roles which must be owned by another role.
* For example a role of `tab` can only exist within a `tablist`.
* This ownership can be represented implicitly by DOM hierarchy or explictly through the `aria-owns` attribute.
*/
axs.AuditRules.addRule({
name: 'ariaRoleNotScoped',
heading: 'Elements with ARIA roles must be in the correct scope',
url: 'https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_09',
severity: axs.constants.Severity.SEVERE,
relevantElementMatcher: function(element) {
return axs.browserUtils.matchSelector(element, '[role]');
},
test: function(element) {
/*
* Checks that this element is in the required scope for its role.
*/
var elementRole = axs.utils.getRoles(element);
if (!elementRole || !elementRole.applied)
return false;
var appliedRole = elementRole.applied;
var ariaRole = appliedRole.details;
var requiredScope = ariaRole['scope'];
if (!requiredScope || requiredScope.length === 0) {
return false;
}
var parent = element;
while (parent = axs.dom.parentElement(parent)) {
var parentRole = axs.utils.getRoles(parent, true);
if (parentRole && parentRole.applied) {
var appliedParentRole = parentRole.applied;
if (requiredScope.indexOf(appliedParentRole.name) >= 0) // if this ancestor role is one of the required roles
return false;
}
}
// If we made it this far then no DOM ancestor has a required scope role.
// Now we need to check if anything aria-owns this element.
var owners = axs.utils.getAriaIdReferrers(element, 'aria-owns'); // there can only be ONE explicit owner but that's a different test
if (owners) {
for (var i = 0; i < owners.length; i++) {
var ownerRole = axs.utils.getRoles(owners[i], true);
if (ownerRole && ownerRole.applied && requiredScope.indexOf(ownerRole.applied.name) >= 0)
return false; // the owner role is one of the required roles
}
}
return true;
},
code: 'AX_ARIA_09'
});