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.
6 * @fileoverview A bunch of predicates that take as input an array of
7 * nodes with the unique ancestors of a node. They output true if a
8 * certain category of node has been found.
12 goog.provide('cvox.DomPredicates');
17 * @param {Array<Node>} nodes An array of nodes to check.
18 * @return {?Node} Node in the array that is a checkbox.
20 cvox.DomPredicates.checkboxPredicate = function(nodes) {
21 for (var i = 0; i < nodes.length; i++) {
22 if ((nodes[i].getAttribute &&
23 nodes[i].getAttribute('role') == 'checkbox') ||
24 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'checkbox')) {
34 * @param {Array<Node>} nodes An array of nodes to check.
35 * @return {?Node} Node in the array that is a radio button.
37 cvox.DomPredicates.radioPredicate = function(nodes) {
38 for (var i = 0; i < nodes.length; i++) {
39 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'radio') ||
40 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'radio')) {
50 * @param {Array<Node>} nodes An array of nodes to check.
51 * @return {?Node} Node in the array that is a slider.
53 cvox.DomPredicates.sliderPredicate = function(nodes) {
54 for (var i = 0; i < nodes.length; i++) {
55 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'slider') ||
56 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'range')) {
66 * @param {Array<Node>} nodes An array of nodes to check.
67 * @return {?Node} Node in the array that is a graphic.
69 cvox.DomPredicates.graphicPredicate = function(nodes) {
70 for (var i = 0; i < nodes.length; i++) {
71 if (nodes[i].tagName == 'IMG' ||
72 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'img')) {
82 * @param {Array<Node>} nodes An array of nodes to check.
83 * @return {?Node} Node in the array that is a button.
85 cvox.DomPredicates.buttonPredicate = function(nodes) {
86 for (var i = 0; i < nodes.length; i++) {
87 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'button') ||
88 nodes[i].tagName == 'BUTTON' ||
89 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'submit') ||
90 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'button') ||
91 (nodes[i].tagName == 'INPUT' && nodes[i].type == 'reset')) {
101 * @param {Array<Node>} nodes An array of nodes to check.
102 * @return {?Node} Node in the array that is a combo box.
104 cvox.DomPredicates.comboBoxPredicate = function(nodes) {
105 for (var i = 0; i < nodes.length; i++) {
106 if ((nodes[i].getAttribute &&
107 nodes[i].getAttribute('role') == 'combobox') ||
108 nodes[i].tagName == 'SELECT') {
117 * Editable text field.
118 * @param {Array<Node>} nodes An array of nodes to check.
119 * @return {?Node} Node in the array that is an editable text field.
121 cvox.DomPredicates.editTextPredicate = function(nodes) {
122 for (var i = 0; i < nodes.length; i++) {
123 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'textbox') ||
124 nodes[i].tagName == 'TEXTAREA' ||
125 nodes[i].isContentEditable ||
126 (nodes[i].tagName == 'INPUT' &&
127 cvox.DomUtil.isInputTypeText(nodes[i]))) {
137 * @param {Array<Node>} nodes An array of nodes to check.
138 * @return {?Node} Node in the array that is a heading.
140 cvox.DomPredicates.headingPredicate = function(nodes) {
141 for (var i = 0; i < nodes.length; i++) {
142 if (nodes[i].getAttribute &&
143 nodes[i].getAttribute('role') == 'heading') {
146 switch (nodes[i].tagName) {
162 * @param {Array<Node>} nodes An array of nodes to check.
163 * @return {?Node} Node in the array that is a heading level 1.
164 * TODO: handle ARIA headings with ARIA heading levels?
166 cvox.DomPredicates.heading1Predicate = function(nodes) {
167 return cvox.DomPredicates.containsTagName_(nodes, 'H1');
173 * @param {Array<Node>} nodes An array of nodes to check.
174 * @return {?Node} Node in the array that is a heading level 2.
176 cvox.DomPredicates.heading2Predicate = function(nodes) {
177 return cvox.DomPredicates.containsTagName_(nodes, 'H2');
183 * @param {Array<Node>} nodes An array of nodes to check.
184 * @return {?Node} Node in the array that is a heading level 3.
186 cvox.DomPredicates.heading3Predicate = function(nodes) {
187 return cvox.DomPredicates.containsTagName_(nodes, 'H3');
193 * @param {Array<Node>} nodes An array of nodes to check.
194 * @return {?Node} Node in the array that is a heading level 4.
196 cvox.DomPredicates.heading4Predicate = function(nodes) {
197 return cvox.DomPredicates.containsTagName_(nodes, 'H4');
203 * @param {Array<Node>} nodes An array of nodes to check.
204 * @return {?Node} Node in the array that is a heading level 5.
206 cvox.DomPredicates.heading5Predicate = function(nodes) {
207 return cvox.DomPredicates.containsTagName_(nodes, 'H5');
213 * @param {Array<Node>} nodes An array of nodes to check.
214 * @return {?Node} Node in the array that is a heading level 6.
216 cvox.DomPredicates.heading6Predicate = function(nodes) {
217 return cvox.DomPredicates.containsTagName_(nodes, 'H6');
223 * @param {Array<Node>} nodes An array of nodes to check.
224 * @return {?Node} Node in the array that is a link.
226 cvox.DomPredicates.linkPredicate = function(nodes) {
227 for (var i = 0; i < nodes.length; i++) {
228 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'link') ||
229 (nodes[i].tagName == 'A' && nodes[i].href)) {
239 * @param {Array<Node>} nodes An array of nodes to check.
240 * @return {?Node} Node in the array that is a data table.
242 cvox.DomPredicates.tablePredicate = function(nodes) {
243 // TODO(stoarca): Captions should always be allowed!!
244 var node = cvox.DomUtil.findTableNodeInList(nodes, {allowCaptions: true});
245 if (node && !cvox.DomUtil.isLayoutTable(node)) {
254 * @param {Array<Node>} nodes An array of nodes to check.
255 * @return {?Node} Node in the array that is a table cell.
257 cvox.DomPredicates.cellPredicate = function(nodes) {
258 for (var i = nodes.length - 1; i >= 0; --i) {
260 if (node.tagName == 'TD' ||
261 node.tagName == 'TH' ||
262 (node.getAttribute && node.getAttribute('role') == 'gridcell')) {
272 * @param {Array<Node>} nodes An array of nodes to check.
273 * @return {?Node} Node in the array that is a visited link.
275 cvox.DomPredicates.visitedLinkPredicate = function(nodes) {
276 for (var i = nodes.length - 1; i >= 0; --i) {
277 if (cvox.DomPredicates.linkPredicate([nodes[i]]) &&
278 cvox.ChromeVox.visitedUrls[nodes[i].href]) {
287 * @param {Array<Node>} nodes An array of nodes to check.
288 * @return {?Node} Node in the array that is a list.
290 cvox.DomPredicates.listPredicate = function(nodes) {
291 for (var i = 0; i < nodes.length; i++) {
292 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'list') ||
293 nodes[i].tagName == 'UL' ||
294 nodes[i].tagName == 'OL') {
304 * @param {Array<Node>} nodes An array of nodes to check.
305 * @return {?Node} Node in the array that is a list item.
307 cvox.DomPredicates.listItemPredicate = function(nodes) {
308 for (var i = 0; i < nodes.length; i++) {
309 if ((nodes[i].getAttribute &&
310 nodes[i].getAttribute('role') == 'listitem') ||
311 nodes[i].tagName == 'LI') {
321 * @param {Array<Node>} nodes An array of nodes to check.
322 * @return {?Node} Node in the array that is a blockquote.
324 cvox.DomPredicates.blockquotePredicate = function(nodes) {
325 return cvox.DomPredicates.containsTagName_(nodes, 'BLOCKQUOTE');
331 * @param {Array<Node>} nodes An array of nodes to check.
332 * @return {?Node} Node in the array that is any type of form field.
334 cvox.DomPredicates.formFieldPredicate = function(nodes) {
335 for (var i = 0; i < nodes.length; i++) {
336 if (cvox.DomUtil.isControl(nodes[i])) {
346 * @param {Array<Node>} nodes An array of nodes to check.
347 * @return {?Node} Node in the array that is an ARIA landmark.
349 cvox.DomPredicates.landmarkPredicate = function(nodes) {
350 for (var i = 0; i < nodes.length; i++) {
351 if (cvox.AriaUtil.isLandmark(nodes[i])) {
360 * @param {Array} arr Array of nodes.
361 * @param {string} tagName The name of the tag.
362 * @return {?Node} Node if obj is in the array.
365 cvox.DomPredicates.containsTagName_ = function(arr, tagName) {
368 if (arr[i].tagName == tagName) {
378 * @param {Array<Node>} nodes An array of nodes to check.
379 * @return {?Node} Node in the array that is a math expression.
381 cvox.DomPredicates.mathPredicate = function(nodes) {
382 return cvox.DomUtil.findMathNodeInList(nodes);
386 * SECTION: A section is anything that indicates a new section. This includes
387 * headings and landmarks.
388 * @param {Array<Node>} nodes An array of nodes to check.
389 * @return {?Node} Node in the array that is considered a section marker.
391 cvox.DomPredicates.sectionPredicate = function(nodes) {
392 for (var i = 0; i < nodes.length; i++) {
393 if (cvox.DomUtil.isSemanticElt(nodes[i])) {
396 if (cvox.AriaUtil.isLandmark(nodes[i])) {
399 if (nodes[i].getAttribute &&
400 nodes[i].getAttribute('role') == 'heading') {
403 switch (nodes[i].tagName) {
417 * CONTROL: A control is anything that the user can interact with. This includes
418 * form fields and links.
419 * @param {Array<Node>} nodes An array of nodes to check.
420 * @return {?Node} Node in the array that is considered a control.
422 cvox.DomPredicates.controlPredicate = function(nodes) {
423 for (var i = 0; i < nodes.length; i++) {
424 if (cvox.DomUtil.isControl(nodes[i])) {
427 if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'link') ||
428 (nodes[i].tagName == 'A' && nodes[i].href)) {
437 * @param {Array<Node>} nodes An array of nodes to check.
438 * @return {?Node} Node in the array that is a caption.
440 cvox.DomPredicates.captionPredicate = function(nodes) {
441 for (var i = 0; i < nodes.length; i++) {
442 if (nodes[i].tagName == 'CAPTION') {
451 * @param {Array<Node>} nodes An array of nodes to check.
452 * @return {?Node} Node in the array that is a article.
454 cvox.DomPredicates.articlePredicate = function(nodes) {
455 for (var i = 0; i < nodes.length; i++) {
456 if ((nodes[i].getAttribute &&
457 nodes[i].getAttribute('role') == 'article') ||
458 nodes[i].tagName == 'ARTICLE') {
467 * @param {Array<Node>} nodes An array of nodes to check.
468 * @return {?Node} Node in the array that is a media widget (video or audio).
470 cvox.DomPredicates.mediaPredicate = function(nodes) {
471 for (var i = 0; i < nodes.length; i++) {
472 if (nodes[i].tagName == 'AUDIO' ||
473 nodes[i].tagName == 'VIDEO') {
483 * @param {Array<Node>} nodes An array of nodes to check.
484 * @return {?Node} Node in the array that is a ordered list.
486 cvox.DomPredicates.orderedListPredicate = function(nodes) {
487 for (var i = 0; i < nodes.length; i++) {
488 if (nodes[i].tagName == 'OL') {