1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 /** 6 * @fileoverview DOM utility functions to aid in table navigation. 7 */ 8 9 goog.provide('cvox.TableUtil'); 10 11 goog.require('cvox.XpathUtil'); 12 13 14 /** 15 * Utility function to check if a particular table cell is a candidate 16 * header cell. 17 * @param {Node} cell The table cell. 18 * @return {boolean} Whether or not the table cell is acting as a header cell. 19 */ 20 cvox.TableUtil.checkIfHeader = function(cell) { 21 /* 22 * Headers are defined here as <TH> or <TD> elements. <TD> elements when 23 * serving as header cells must have either: 24 * - The scope attribute defined 25 * - Their IDs referenced in the header content attribute of another <TD> or 26 * <TH> element. 27 * This function does not check whether this cell is referenced by another 28 * <TD>. So this function by itself will not be able to gather all possible 29 * header cells when applied across all table cells. 30 * 31 * Please Note: 32 * The HTML5 spec specifies that only header <TH> elements can be headers 33 * ( http://dev.w3.org/html5/spec/tabular-data.html#row-header ) but the 34 * HTML4 spec says that <TD> elements can act as headers if they have a 35 * scope attribute defined 36 * ( http://www.w3.org/TR/html401/struct/tables.html#h-11.2.6 ). In the 37 * interest of providing meaningful header information for all tables, here 38 * we take the position that <TD> elements can act as headers. 39 */ 40 return ((cell.tagName == 'TH') || 41 cell.hasAttribute('scope') || (cell.hasAttribute('role') && 42 ((cell.getAttribute('role') == 'rowheader') || 43 (cell.getAttribute('role') == 'columnheader')))); 44 }; 45 46 47 /** 48 * Utility function to determine colgroup structure. Builds an array that 49 * associates a column number to a particular col group. 50 * @param {Array} colGroups An array of all the colgroup elements in a 51 * particular table. 52 * @return {Array} An array that maps indexes representing table columns 53 * to indexes into the colGroups array. 54 */ 55 cvox.TableUtil.determineColGroups = function(colGroups) { 56 var colToColGroup = []; 57 58 if (colGroups.length == 0) { 59 return colToColGroup; 60 } 61 // A colgroup has either a series of col element children or a span 62 // attribute. If it has col children, ignore the span attribute 63 for (var colGroupCtr = 0; colGroupCtr < colGroups.length; 64 colGroupCtr++) { 65 66 var currentColGroup = colGroups[colGroupCtr]; 67 68 var childCols = cvox.TableUtil.getColNodes(currentColGroup); 69 if (childCols.length > 0) { 70 for (var colNodeCtr = 0; colNodeCtr < childCols.length; 71 colNodeCtr++) { 72 var colElement = childCols[colNodeCtr]; 73 74 if (colElement.hasAttribute('span')) { 75 var span = parseInt(colElement.getAttribute('span'), 10); 76 77 for (var s = 0; s < span; s++) { 78 colToColGroup.push(colGroupCtr); 79 } 80 } else { 81 colToColGroup.push(colGroupCtr); 82 } 83 } 84 } else { 85 // No children of the current colgroup. Does it have a span attribute? 86 if (currentColGroup.hasAttribute('span')) { 87 var span = parseInt(currentColGroup.getAttribute('span'), 10); 88 89 for (var s = 0; s < span; s++) { 90 colToColGroup.push(colGroupCtr); 91 } 92 } else { 93 // Default span value is 1 94 colToColGroup.push(colGroupCtr); 95 } 96 } 97 } 98 return colToColGroup; 99 100 }; 101 102 103 /** 104 * Utility function to push an element into a given array only if that element 105 * is not already contained in the array. 106 * @param {Array} givenArray The given array. 107 * @param {Node} givenElement The given element. 108 */ 109 cvox.TableUtil.pushIfNotContained = function(givenArray, givenElement) { 110 if (givenArray.indexOf(givenElement) == -1) { 111 givenArray.push(givenElement); 112 } 113 }; 114 115 116 /** 117 * Returns a JavaScript array of all the non-nested rows in the given table. 118 * 119 * @param {Node} table A table node. 120 * @return {Array} An array of all the child rows of the active table. 121 */ 122 cvox.TableUtil.getChildRows = function(table) { 123 return cvox.XpathUtil.evalXPath('child::tbody/tr | child::thead/tr | ' + 124 'child::*[attribute::role="row"]', table); 125 }; 126 127 128 /** 129 * Returns a JavaScript array of all the child cell <TD> or <TH> or 130 * role='gridcell' nodes of the given row. 131 * 132 * @param {Node} rowNode The specified row node. 133 * @return {Array} An array of all the child cells of the given row node. 134 */ 135 cvox.TableUtil.getChildCells = function(rowNode) { 136 return cvox.XpathUtil.evalXPath('child::td | child::th | ' + 137 'child::*[attribute::role="gridcell"] |' + 138 'child::*[attribute::role="rowheader"] |' + 139 'child::*[attribute::role="columnheader"]', rowNode); 140 }; 141 142 143 /** 144 * Returns a JavaScript array containing the cell in the active table 145 * with the given ID. 146 * 147 * @param {Node} table A table node. 148 * @param {string} cellID The specified ID. 149 * @return {Array} An array containing the cell with the specified ID. 150 */ 151 cvox.TableUtil.getCellWithID = function(table, cellID) { 152 return cvox.XpathUtil.evalXPath('id(\'' + cellID + '\')', table); 153 }; 154 155 156 /** 157 * Returns a Javascript array containing the colgroup elements in the 158 * active table. 159 * 160 * @param {Node} table A table node. 161 * @return {Array} An array of all the colgroup elements in the active table. 162 */ 163 cvox.TableUtil.getColGroups = function(table) { 164 return cvox.XpathUtil.evalXPath('child::colgroup', table); 165 }; 166 167 168 /** 169 * Returns a Javascript array containing the child col elements of the given 170 * colgroup element. 171 * 172 * @param {Node} colGroupNode The specified <COLGROUP> element. 173 * @return {Array} An array of all of the child col elements of the given 174 * colgroup element. 175 */ 176 cvox.TableUtil.getColNodes = function(colGroupNode) { 177 return cvox.XpathUtil.evalXPath('child::col', colGroupNode); 178 }; 179 180