UNPKG

axe-core

Version:

Accessibility engine for automated Web UI testing

153 lines (129 loc) 4.5 kB
/* global table, dom */ /* eslint max-statements: ["error",70], complexity: ["error",47] */ /** * Determines whether a table is a data table * @method isDataTable * @memberof axe.commons.table * @instance * @param {HTMLTableElement} node The table to test * @return {Boolean} * @see http://asurkov.blogspot.co.uk/2011/10/data-vs-layout-table.html */ table.isDataTable = function (node) { var role = (node.getAttribute('role') || '').toLowerCase(); // The element is not focusable and has role=presentation if ((role === 'presentation' || role === 'none') && !dom.isFocusable(node)) { return false; } // Table inside editable area is data table always since the table structure is crucial for table editing if (node.getAttribute('contenteditable') === 'true' || dom.findUp(node, '[contenteditable="true"]')) { return true; } // Table having ARIA table related role is data table if (role === 'grid' || role === 'treegrid' || role === 'table') { return true; } // Table having ARIA landmark role is data table if (commons.aria.getRoleType(role) === 'landmark') { return true; } // Table having datatable="0" attribute is layout table if (node.getAttribute('datatable') === '0') { return false; } // Table having summary attribute is data table if (node.getAttribute('summary')) { return true; } // Table having legitimate data table structures is data table if (node.tHead || node.tFoot || node.caption) { return true; } // colgroup / col - colgroup is magically generated for (var childIndex = 0, childLength = node.children.length; childIndex < childLength; childIndex++) { if (node.children[childIndex].nodeName.toUpperCase() === 'COLGROUP') { return true; } } var cells = 0; var rowLength = node.rows.length; var row, cell; var hasBorder = false; for (var rowIndex = 0; rowIndex < rowLength; rowIndex++) { row = node.rows[rowIndex]; for (var cellIndex = 0, cellLength = row.cells.length; cellIndex < cellLength; cellIndex++) { cell = row.cells[cellIndex]; if (cell.nodeName.toUpperCase() === 'TH') { return true; } if (!hasBorder && (cell.offsetWidth !== cell.clientWidth || cell.offsetHeight !== cell.clientHeight)) { hasBorder = true; } if (cell.getAttribute('scope') || cell.getAttribute('headers') || cell.getAttribute('abbr')) { return true; } if (['columnheader', 'rowheader'].includes((cell.getAttribute('role') || '').toLowerCase())) { return true; } // abbr element as a single child element of table cell if (cell.children.length === 1 && cell.children[0].nodeName.toUpperCase() === 'ABBR') { return true; } cells++; } } // Table having nested table is layout table if (node.getElementsByTagName('table').length) { return false; } // Table having only one row or column is layout table (row) if (rowLength < 2) { return false; } // Table having only one row or column is layout table (column) var sampleRow = node.rows[Math.ceil(rowLength / 2)]; if (sampleRow.cells.length === 1 && sampleRow.cells[0].colSpan === 1) { return false; } // Table having many columns (>= 5) is data table if (sampleRow.cells.length >= 5) { return true; } // Table having borders around cells is data table if (hasBorder) { return true; } // Table having differently colored rows is data table var bgColor, bgImage; for (rowIndex = 0; rowIndex < rowLength; rowIndex++) { row = node.rows[rowIndex]; if (bgColor && bgColor !== window.getComputedStyle(row).getPropertyValue('background-color')) { return true; } else { bgColor = window.getComputedStyle(row).getPropertyValue('background-color'); } if (bgImage && bgImage !== window.getComputedStyle(row).getPropertyValue('background-image')) { return true; } else { bgImage = window.getComputedStyle(row).getPropertyValue('background-image'); } } // Table having many rows (>= 20) is data table if (rowLength >= 20) { return true; } // Wide table (more than 95% of the document width) is layout table if (dom.getElementCoordinates(node).width > dom.getViewportSize(window).width * 0.95) { return false; } // Table having small amount of cells (<= 10) is layout table if (cells < 10) { return false; } // Table containing embed, object, applet of iframe elements (typical advertisements elements) is layout table if (node.querySelector('object, embed, iframe, applet')) { return false; } // Otherwise it's data table return true; };