-
Couldn't load subscription status.
- Fork 842
feat(td-headers-attr): report headers attribute referencing other <td> elements as unsupported #4589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(td-headers-attr): report headers attribute referencing other <td> elements as unsupported #4589
Changes from all commits
6942d2a
10e5844
b2dd10e
7942fde
23fdbce
1a1dc0e
de1c148
566c45b
ffb2c4d
57bd7c4
4044fd9
39546fd
cacbb30
effb955
39fb1b1
9cac9ee
1722053
5d1440e
e467de5
4897ecc
379edb8
04ff14d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,63 +1,79 @@ | ||
| import { tokenList } from '../../core/utils'; | ||
| import { isVisibleToScreenReaders } from '../../commons/dom'; | ||
| import { getRole } from '../../commons/aria'; | ||
|
|
||
| // Order determines the priority of reporting | ||
| // Only if 0 of higher issues exists will the next be reported | ||
| const messageKeys = [ | ||
| 'cell-header-not-in-table', | ||
| 'cell-header-not-th', | ||
| 'header-refs-self', | ||
| 'empty-hdrs' // incomplete | ||
| ]; | ||
| const [notInTable, notTh, selfRef, emptyHdrs] = messageKeys; | ||
|
|
||
| export default function tdHeadersAttrEvaluate(node) { | ||
| const cells = []; | ||
| const reviewCells = []; | ||
| const badCells = []; | ||
|
|
||
| const cellRoleById = {}; | ||
| 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]); | ||
| const cell = row.cells[cellIndex]; | ||
| cells.push(cell); | ||
|
|
||
| // Save header id to set if it's th or td with roles columnheader/rowheader | ||
| const cellId = cell.getAttribute('id'); | ||
| if (cellId) { | ||
| cellRoleById[cellId] = getRole(cell); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const ids = cells | ||
| .filter(cell => cell.getAttribute('id')) | ||
| .map(cell => cell.getAttribute('id')); | ||
|
|
||
| const badCells = { | ||
| [selfRef]: new Set(), | ||
| [notInTable]: new Set(), | ||
| [notTh]: new Set(), | ||
| [emptyHdrs]: new Set() | ||
| }; | ||
| cells.forEach(cell => { | ||
| let isSelf = false; | ||
| let notOfTable = false; | ||
|
|
||
| if (!cell.hasAttribute('headers') || !isVisibleToScreenReaders(cell)) { | ||
| return; | ||
| } | ||
|
|
||
| const headersAttr = cell.getAttribute('headers').trim(); | ||
| if (!headersAttr) { | ||
| return reviewCells.push(cell); | ||
| badCells[emptyHdrs].add(cell); | ||
| return; | ||
| } | ||
|
|
||
| const cellId = cell.getAttribute('id'); | ||
| // Get a list all the values of the headers attribute | ||
| const headers = tokenList(headersAttr); | ||
|
|
||
| if (headers.length !== 0) { | ||
| // Check if the cell's id is in this list | ||
| if (cell.getAttribute('id')) { | ||
| isSelf = headers.indexOf(cell.getAttribute('id').trim()) !== -1; | ||
| headers.forEach(headerId => { | ||
engineerklimov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (cellId && headerId === cellId) { | ||
| // Header references its own cell | ||
| badCells[selfRef].add(cell); | ||
| } else if (!cellRoleById[headerId]) { | ||
| // Header references a cell that is not in the table | ||
| badCells[notInTable].add(cell); | ||
| } else if ( | ||
| !['columnheader', 'rowheader'].includes(cellRoleById[headerId]) | ||
| ) { | ||
| // Header references a cell that is not a row or column header | ||
| badCells[notTh].add(cell); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| // Check if the headers are of cells inside the table | ||
| notOfTable = headers.some(header => !ids.includes(header)); | ||
|
|
||
| if (isSelf || notOfTable) { | ||
| badCells.push(cell); | ||
| for (const messageKey of messageKeys) { | ||
| if (badCells[messageKey].size > 0) { | ||
| this.relatedNodes([...badCells[messageKey]]); | ||
| if (messageKey === emptyHdrs) { | ||
| return undefined; | ||
| } | ||
| this.data({ messageKey }); | ||
| return false; | ||
| } | ||
| }); | ||
|
|
||
| if (badCells.length > 0) { | ||
| this.relatedNodes(badCells); | ||
| return false; | ||
| } | ||
|
|
||
| if (reviewCells.length) { | ||
| this.relatedNodes(reviewCells); | ||
| return undefined; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
engineerklimov marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -402,8 +402,8 @@ | |
| "help": "Непустые элементы <td> в больших таблицах должны иметь связанные заголовки таблицы" | ||
| }, | ||
| "td-headers-attr": { | ||
| "description": "Убедитесь, что каждая ячейка в таблице, использующая атрибут headers, ссылается только на другие ячейки в этой таблице", | ||
| "help": "Ячейки таблицы, использующие атрибут headers, должны ссылаться только на ячейки в той же таблице" | ||
| "description": "Убедитесь, что каждая ячейка в таблице, использующая атрибут headers, ссылается только на другие элементы <th> в этой таблице", | ||
| "help": "Атрибуты headers ячеек таблицы должны ссылаться на другие элементы <th> в той же таблице" | ||
| }, | ||
| "th-has-data-cells": { | ||
| "description": "Убедитесь, что элементы <th> и элементы с ролью columnheader/rowheader имеют ячейки данных, которые они описывают", | ||
|
|
@@ -1098,7 +1098,11 @@ | |
| "td-headers-attr": { | ||
| "pass": "Атрибут headers используется исключительно для ссылки на другие ячейки таблицы", | ||
| "incomplete": "Атрибут headers пуст", | ||
| "fail": "Атрибут headers не используется исключительно для ссылки на другие ячейки таблицы" | ||
| "fail": { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to update locales. I found that all locales are quite outdated. Not sure that this change is good place to bring all locales up to date. So i updated only "ru" which i contributed recently. Not sure what is contribution policy here. |
||
| "cell-header-not-in-table": "Атрибут headers не используется исключительно для ссылки на другие заголовочные ячейки в таблице", | ||
| "cell-header-not-th": "Атрибут headers должен ссылаться на заголовочные ячейки, а не на ячейки с данными", | ||
| "header-refs-self": "Элемент с атрибутом headers ссылается на самого себя" | ||
| } | ||
| }, | ||
| "th-has-data-cells": { | ||
| "pass": "Все ячейки заголовков таблицы ссылаются на ячейки данных", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,13 @@ | ||
| { | ||
| "description": "td-headers-attr test", | ||
| "rule": "td-headers-attr", | ||
| "violations": [["#fail1"], ["#fail2"], ["#fail3"]], | ||
| "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]] | ||
| "violations": [ | ||
| ["#fail1"], | ||
| ["#fail2"], | ||
| ["#fail3"], | ||
| ["#fail4"], | ||
| ["#fail5"], | ||
| ["#fail6"] | ||
| ], | ||
| "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"]] | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.