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') {