Skip to content

Commit

Permalink
Merge pull request #1124 from dequelabs/release/3.1.2
Browse files Browse the repository at this point in the history
Release v3.1.2
  • Loading branch information
WilcoFiers authored Sep 13, 2018
2 parents 6fc5c8e + c802a84 commit 0026154
Show file tree
Hide file tree
Showing 21 changed files with 291 additions and 97 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

<a name="3.1.2"></a>
## [3.1.2](https://github.com/dequelabs/axe-core/compare/v3.0.3...v3.1.2) (2018-09-07)


### Bug Fixes

* **i18n:** Update Japanese locale ([#1107](https://github.com/dequelabs/axe-core/issues/1107)) ([8138e55](https://github.com/dequelabs/axe-core/commit/8138e55))
* autocomplete appropriate to handle state terms ([#1121](https://github.com/dequelabs/axe-core/issues/1121)) ([35a4d11](https://github.com/dequelabs/axe-core/commit/35a4d11))
* banner comment in generated axe files ([#1112](https://github.com/dequelabs/axe-core/issues/1112)) ([e4788bf](https://github.com/dequelabs/axe-core/commit/e4788bf))
* ignore invalid and allow redundant role in aria-allowed-role ([#1118](https://github.com/dequelabs/axe-core/issues/1118)) ([a0f9b31](https://github.com/dequelabs/axe-core/commit/a0f9b31))



<a name="3.1.1"></a>
## [3.1.1](https://github.com/dequelabs/axe-core/compare/v3.0.3...v3.1.1) (2018-08-28)

Expand Down
7 changes: 3 additions & 4 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ module.exports = function(grunt) {
quote_style: 1
},
output: {
comments: /^!/
comments: /^\/*! aXe/
}
}
},
Expand All @@ -243,9 +243,8 @@ module.exports = function(grunt) {
};
}),
options: {
preserveComments: function(node, comment) {
// preserve comments that start with a bang
return /^!/.test(comment.value);
output: {
comments: /^\/*! aXe/
},
mangle: {
reserved: ['commons', 'utils', 'axe', 'window', 'document']
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "axe-core",
"version": "3.1.1",
"version": "3.1.2",
"contributors": [
{
"name": "David Sturley",
Expand Down
4 changes: 2 additions & 2 deletions doc/examples/jest_react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"babel-jest": "^23.0.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"enzyme": "^3.4.4",
"enzyme-adapter-react-16": "^1.2.0",
"enzyme": "^3.5.0",
"enzyme-adapter-react-16": "^1.3.0",
"jest": "^22.4.0",
"jest-cli": "^23.0.1",
"react": "^16.4.0",
Expand Down
6 changes: 5 additions & 1 deletion lib/checks/forms/autocomplete-appropriate.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ const autocomplete = node.getAttribute('autocomplete');
const autocompleteTerms = autocomplete
.split(/\s+/g)
.map(term => term.toLowerCase());

const purposeTerm = autocompleteTerms[autocompleteTerms.length - 1];
const allowedTypes = allowedTypesMap[purposeTerm];
if (axe.commons.text.autocomplete.stateTerms.includes(purposeTerm)) {
return true;
}

const allowedTypes = allowedTypesMap[purposeTerm];
if (typeof allowedTypes === 'undefined') {
return node.type === 'text';
}
Expand Down
104 changes: 59 additions & 45 deletions lib/commons/aria/get-element-unallowed-roles.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
/* global aria */

/**
* Returns all roles applicable to element in a list
*
* @method getRoleSegments
* @private
* @param {Element} node
* @returns {Array} Roles list or empty list
*/

function getRoleSegments(node) {
let roles = [];

if (!node) {
return roles;
}

if (node.hasAttribute('role')) {
const nodeRoles = axe.utils.tokenList(
node.getAttribute('role').toLowerCase()
);
roles = roles.concat(nodeRoles);
}

if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) {
const epubRoles = axe.utils
.tokenList(
node
.getAttributeNS('http://www.idpf.org/2007/ops', 'type')
.toLowerCase()
)
.map(role => `doc-${role}`);

roles = roles.concat(epubRoles);
}

// filter invalid roles
roles = roles.filter(role => axe.commons.aria.isValidRole(role));

return roles;
}

/**
* gets all unallowed roles for a given node
* @method getElementUnallowedRoles
Expand All @@ -9,38 +51,8 @@
*/
aria.getElementUnallowedRoles = function getElementUnallowedRoles(
node,
allowImplicit
allowImplicit = true
) {
/**
* Get roles applied to a given node
* @param {HTMLElement} node HTMLElement
* @return {Array<String>} return an array of roles applied to the node, if no roles, return an empty array.
*/
// TODO: not moving this to outer namespace yet, work with wilco to see overlap with his PR(WIP) - aria.getRole
function getRoleSegments(node) {
let roles = [];
if (!node) {
return roles;
}
if (node.hasAttribute('role')) {
const nodeRoles = axe.utils.tokenList(
node.getAttribute('role').toLowerCase()
);
roles = roles.concat(nodeRoles);
}
if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) {
const epubRoles = axe.utils
.tokenList(
node
.getAttributeNS('http://www.idpf.org/2007/ops', 'type')
.toLowerCase()
)
.map(role => `doc-${role}`);
roles = roles.concat(epubRoles);
}
return roles;
}

const tagName = node.nodeName.toUpperCase();

// by pass custom elements
Expand All @@ -53,24 +65,26 @@ aria.getElementUnallowedRoles = function getElementUnallowedRoles(

// stores all roles that are not allowed for a specific element most often an element only has one explicit role
const unallowedRoles = roleSegments.filter(role => {
if (!axe.commons.aria.isValidRole(role)) {
// do not check made-up/ fake roles
// if role and implicit role are same, when allowImplicit: true
// ignore as it is a redundant role
if (allowImplicit && role === implicitRole) {
return false;
}

// check if an implicit role may be set explicit following a setting
if (!allowImplicit && role === implicitRole) {
// edge case: setting implicit role row on tr element is allowed when child of table[role='grid']
if (
!(
role === 'row' &&
tagName === 'TR' &&
axe.utils.matchesSelector(node, 'table[role="grid"] > tr')
)
) {
return true;
}
// Edge case:
// setting implicit role row on tr element is allowed when child of table[role='grid']
if (
!allowImplicit &&
!(
role === 'row' &&
tagName === 'TR' &&
axe.utils.matchesSelector(node, 'table[role="grid"] > tr')
)
) {
return true;
}

// check if role is allowed on element
if (!aria.isAriaRoleAllowedOnElement(node, role)) {
return true;
}
Expand Down
1 change: 1 addition & 0 deletions lib/commons/aria/get-role.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ aria.getRole = function getRole(
}
return aria.isValidRole(role, { allowAbstract: abstracts });
});

const explicitRole = validRoles[0];

// Get the implicit role, if permitted
Expand Down
41 changes: 31 additions & 10 deletions lib/commons/aria/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,15 @@ lookupTable.role = {
},
nameFrom: ['author'],
context: null,
unsupported: false
unsupported: false,
allowedElements: [
{
tagName: 'INPUT',
attributes: {
TYPE: 'TEXT'
}
}
]
},
command: {
nameFrom: ['author'],
Expand Down Expand Up @@ -1687,7 +1695,15 @@ lookupTable.role = {
nameFrom: ['author'],
context: null,
implicit: ['input[type="search"]'],
unsupported: false
unsupported: false,
allowedElements: [
{
tagName: 'INPUT',
attributes: {
TYPE: 'TEXT'
}
}
]
},
section: {
nameFrom: ['author', 'contents'],
Expand Down Expand Up @@ -1756,7 +1772,15 @@ lookupTable.role = {
nameFrom: ['author'],
context: null,
implicit: ['input[type="number"]'],
unsupported: false
unsupported: false,
allowedElements: [
{
tagName: 'INPUT',
attributes: {
TYPE: 'TEXT'
}
}
]
},
status: {
type: 'widget',
Expand Down Expand Up @@ -2148,13 +2172,6 @@ lookupTable.elementsAllowedNoRole = [
TYPE: 'TEL'
}
},
{
tagName: 'INPUT',
condition: elementConditions.CANNOT_HAVE_LIST_ATTRIBUTE,
attributes: {
TYPE: 'TEXT'
}
},
{
tagName: 'INPUT',
attributes: {
Expand Down Expand Up @@ -2368,6 +2385,10 @@ lookupTable.evaluateRoleForElement = {
return out;
case 'radio':
return role === 'menuitemradio';
case 'text':
return (
role === 'combobox' || role === 'searchbox' || role === 'spinbutton'
);
default:
return false;
}
Expand Down
7 changes: 7 additions & 0 deletions lib/rules/aria-allowed-role-matches.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
return (
axe.commons.aria.getRole(node, {
noImplicit: true,
dpub: true,
fallback: true
}) !== null
);
1 change: 1 addition & 0 deletions lib/rules/aria-allowed-role.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "aria-allowed-role",
"excludeHidden": false,
"selector": "[role]",
"matches": "aria-allowed-role-matches.js",
"tags": [
"cat.aria",
"best-practice"
Expand Down
33 changes: 24 additions & 9 deletions locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@
"description": "各HTMLドキュメントに空でない<title>要素が含まれていることを確認してください",
"help": "ドキュメントにはナビゲーションを補助するために<title>要素がなければなりません"
},
"duplicate-id-active": {
"description": "有効な要素のid属性値が一意であることを確認してください",
"help": "有効な要素のIDは一意でなければなりません"
},
"duplicate-id-aria": {
"description": "ARIAおよびラベルに使用されているid属性値が一意であることを確認してください",
"help": "ARIAおよびラベルに使用されているIDは一意でなければなりません"
},
"duplicate-id": {
"description": "全てのid属性値が一意であることを確認してください",
"help": "id属性値は一意でなければなりません"
Expand Down Expand Up @@ -326,7 +334,7 @@
"aria-required-children": {
"pass": "必須のARIA子ロールが存在しています",
"fail": "必須のARIAロールが提供されていません:{{~it.data:value}} {{=value}}{{~}}",
"incomplete": "Expecting ARIA {{=it.data && it.data.length > 1 ? 'children' : 'child'}} role to be added:{{~it.data:value}} {{=value}}{{~}}"
"incomplete": "ARIAの子ロールが追加されることが求められます:{{~it.data:value}} {{=value}}{{~}}"
},
"aria-required-parent": {
"pass": "必須のARIA親ロールが存在しています",
Expand Down Expand Up @@ -361,6 +369,7 @@
"elmPartiallyObscuring": "他の要素と部分的に重なっているため、要素の背景色を判定できません",
"outsideViewport": "ビューポートの外にあるため、要素の背景色を判定できません",
"equalRatio": "要素のコントラスト比が背景と1:1です",
"shortTextContent": "実際のテキストコンテンツであるかを判断するには要素のコンテンツが短すぎます",
"default": "コントラスト比を判定できません"
}
},
Expand Down Expand Up @@ -441,8 +450,8 @@
"fail": "ヘルプテキスト(titleまたはaria-describedby)がラベルテキストと同じです"
},
"hidden-explicit-label": {
"pass": "Form element has a visible explicit <label>",
"fail": "Form element has explicit <label> that is hidden"
"pass": "フォーム要素に視認可能で明確な<label>があります",
"fail": "フォーム要素に非表示の明確な<label>があります"
},
"implicit-label": {
"pass": "フォーム要素に暗黙の(包含された)<label>が存在しています",
Expand Down Expand Up @@ -494,12 +503,10 @@
},
"caption": {
"pass": "マルチメディア要素にキャプショントラックが存在しています",
"fail": "マルチメディア要素にキャプショントラックが存在していません",
"incomplete": "この要素のキャプショントラックが見つかりません"
},
"description": {
"pass": "マルチメディア要素に音声解説トラックが存在しています",
"fail": "マルチメディア要素に音声解説トラックが存在していません",
"incomplete": "この要素の音声解説トラックが見つかりません"
},
"frame-tested": {
Expand Down Expand Up @@ -556,6 +563,18 @@
"pass": "要素のtitle属性が一意です",
"fail": "要素のtitle属性が一意ではありません"
},
"duplicate-id-active": {
"pass": "ドキュメントに同じid属性を持つ有効な要素はありません",
"fail": "ドキュメントに同じid属性を持つ有効な要素があります: {{=it.data}}"
},
"duplicate-id-aria": {
"pass": "ドキュメントに同じid属性を持つARIAまたはラベルに参照された要素はありません",
"fail": "ドキュメントに同じid属性を持つARIAに参照された複数の要素があります: {{=it.data}}"
},
"duplicate-id": {
"pass": "ドキュメントに同じid属性を持つ要素は存在していません",
"fail": "ドキュメントに同じid属性を持つ要素が複数存在しています: {{=it.data}}"
},
"aria-label": {
"pass": "aria-label属性が存在し、空ではありません",
"fail": "aria-label属性が存在しない、または空です"
Expand All @@ -572,10 +591,6 @@
"pass": "ドキュメントに空ではない<title>要素が存在しています",
"fail": "ドキュメントに空ではない<title>要素が存在していません"
},
"duplicate-id": {
"pass": "ドキュメントに同じid属性を持つ要素は存在していません",
"fail": "ドキュメントに同じid属性を持つ要素が複数存在しています: {{=it.data}}"
},
"exists": {
"pass": "要素は存在していません",
"fail": "要素が存在しています"
Expand Down
Loading

0 comments on commit 0026154

Please sign in to comment.