Skip to content

Commit

Permalink
Merge pull request #2096 from dequelabs/tdHeadersAttr
Browse files Browse the repository at this point in the history
fix(td-headers-attr): mark as needs review if headers attr is empty
  • Loading branch information
straker authored Mar 13, 2020
2 parents eca7e05 + 4e248cf commit 699b566
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 36 deletions.
2 changes: 1 addition & 1 deletion doc/rule-descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/3.5/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | wcag2a, wcag211 | failure |
| [server-side-image-map](https://dequeuniversity.com/rules/axe/3.5/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review |
| [svg-img-alt](https://dequeuniversity.com/rules/axe/3.5/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure |
| [td-headers-attr](https://dequeuniversity.com/rules/axe/3.5/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure |
| [td-headers-attr](https://dequeuniversity.com/rules/axe/3.5/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review |
| [th-has-data-cells](https://dequeuniversity.com/rules/axe/3.5/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review |
| [valid-lang](https://dequeuniversity.com/rules/axe/3.5/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure |
| [video-caption](https://dequeuniversity.com/rules/axe/3.5/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review |
Expand Down
63 changes: 31 additions & 32 deletions lib/checks/tables/td-headers-attr.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,37 @@
var cells = [];

for (
var rowIndex = 0, rowLength = node.rows.length;
rowIndex < rowLength;
rowIndex++
) {
var row = node.rows[rowIndex];
for (
var cellIndex = 0, cellLength = row.cells.length;
cellIndex < cellLength;
cellIndex++
) {
const cells = [];
const reviewCells = [];
const badCells = [];

for (let rowIndex = 0; rowIndex < node.rows.length; rowIndex++) {
const row = node.rows[rowIndex];

for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {
cells.push(row.cells[cellIndex]);
}
}

var ids = cells.reduce(function(ids, cell) {
const ids = cells.reduce((ids, cell) => {
if (cell.getAttribute('id')) {
ids.push(cell.getAttribute('id'));
}
return ids;
}, []);

var badCells = cells.reduce(function(badCells, cell) {
var isSelf, notOfTable;
cells.forEach(cell => {
let isSelf = false;
let notOfTable = false;

if (!cell.hasAttribute('headers')) {
return;
}

const headersAttr = cell.getAttribute('headers').trim();
if (!headersAttr) {
return reviewCells.push(cell);
}

// Get a list all the values of the headers attribute
var headers = (cell.getAttribute('headers') || '')
.split(/\s/)
.reduce(function(headers, header) {
header = header.trim();
if (header) {
headers.push(header);
}
return headers;
}, []);
const headers = axe.utils.tokenList(headersAttr);

if (headers.length !== 0) {
// Check if the cell's id is in this list
Expand All @@ -43,20 +40,22 @@ var badCells = cells.reduce(function(badCells, cell) {
}

// Check if the headers are of cells inside the table
notOfTable = headers.reduce(function(fail, header) {
return fail || ids.indexOf(header) === -1;
}, false);
notOfTable = headers.some(header => !ids.includes(header));

if (isSelf || notOfTable) {
badCells.push(cell);
}
}
return badCells;
}, []);
});

if (badCells.length > 0) {
this.relatedNodes(badCells);
return false;
} else {
return true;
}

if (reviewCells.length) {
this.relatedNodes(reviewCells);
return undefined;
}

return true;
1 change: 1 addition & 0 deletions lib/checks/tables/td-headers-attr.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"impact": "serious",
"messages": {
"pass": "The headers attribute is exclusively used to refer to other cells in the table",
"incomplete": "The headers attribute is empty",
"fail": "The headers attribute is not exclusively used to refer to other cells in the table"
}
}
Expand Down
7 changes: 4 additions & 3 deletions test/checks/tables/td-headers-attr.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,17 @@ describe('td-headers-attr', function() {
assert.isTrue(checks['td-headers-attr'].evaluate.call(checkContext, node));
});

it('returns true if no headers are present', function() {
// this is a failure for td-has-header
it('returns undefined if headers is empty', function() {
fixture.innerHTML =
'<table>' +
' <tr> <th id="hi"> </th> </tr>' +
' <tr> <td headers="">goodbye</td> </tr>' +
'</table>';

var node = fixture.querySelector('table');
assert.isTrue(checks['td-headers-attr'].evaluate.call(checkContext, node));
assert.isUndefined(
checks['td-headers-attr'].evaluate.call(checkContext, node)
);
});

it('returns false if the header is a table cell', function() {
Expand Down

0 comments on commit 699b566

Please sign in to comment.