Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / chromevox / common / dom_predicates.js
blob685a8ecf8f43f41f411c24ec1bbd44c0162c7bac
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.
5 /**
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.
9  *
10  */
12 goog.provide('cvox.DomPredicates');
15 /**
16  * Checkbox.
17  * @param {Array<Node>} nodes An array of nodes to check.
18  * @return {?Node} Node in the array that is a checkbox.
19  */
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')) {
25       return nodes[i];
26     }
27   }
28   return null;
32 /**
33  * Radio button.
34  * @param {Array<Node>} nodes An array of nodes to check.
35  * @return {?Node} Node in the array that is a radio button.
36  */
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')) {
41       return nodes[i];
42     }
43   }
44   return null;
48 /**
49  * Slider.
50  * @param {Array<Node>} nodes An array of nodes to check.
51  * @return {?Node} Node in the array that is a slider.
52  */
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')) {
57       return nodes[i];
58     }
59   }
60   return null;
64 /**
65  * Graphic.
66  * @param {Array<Node>} nodes An array of nodes to check.
67  * @return {?Node} Node in the array that is a graphic.
68  */
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')) {
73       return nodes[i];
74     }
75   }
76   return null;
80 /**
81  * Button.
82  * @param {Array<Node>} nodes An array of nodes to check.
83  * @return {?Node} Node in the array that is a button.
84  */
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')) {
92       return nodes[i];
93     }
94   }
95   return null;
99 /**
100  * Combo box.
101  * @param {Array<Node>} nodes An array of nodes to check.
102  * @return {?Node} Node in the array that is a combo box.
103  */
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') {
109       return nodes[i];
110     }
111   }
112   return null;
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.
120  */
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]))) {
128       return nodes[i];
129     }
130   }
131   return null;
136  * Heading.
137  * @param {Array<Node>} nodes An array of nodes to check.
138  * @return {?Node} Node in the array that is a heading.
139  */
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') {
144       return nodes[i];
145     }
146     switch (nodes[i].tagName) {
147       case 'H1':
148       case 'H2':
149       case 'H3':
150       case 'H4':
151       case 'H5':
152       case 'H6':
153         return nodes[i];
154     }
155   }
156   return null;
161  * Heading level 1.
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?
165  */
166 cvox.DomPredicates.heading1Predicate = function(nodes) {
167   return cvox.DomPredicates.containsTagName_(nodes, 'H1');
172  * Heading level 2.
173  * @param {Array<Node>} nodes An array of nodes to check.
174  * @return {?Node} Node in the array that is a heading level 2.
175  */
176 cvox.DomPredicates.heading2Predicate = function(nodes) {
177   return cvox.DomPredicates.containsTagName_(nodes, 'H2');
182  * Heading level 3.
183  * @param {Array<Node>} nodes An array of nodes to check.
184  * @return {?Node} Node in the array that is a heading level 3.
185  */
186 cvox.DomPredicates.heading3Predicate = function(nodes) {
187   return cvox.DomPredicates.containsTagName_(nodes, 'H3');
192  * Heading level 4.
193  * @param {Array<Node>} nodes An array of nodes to check.
194  * @return {?Node} Node in the array that is a heading level 4.
195  */
196 cvox.DomPredicates.heading4Predicate = function(nodes) {
197   return cvox.DomPredicates.containsTagName_(nodes, 'H4');
202  * Heading level 5.
203  * @param {Array<Node>} nodes An array of nodes to check.
204  * @return {?Node} Node in the array that is a heading level 5.
205  */
206 cvox.DomPredicates.heading5Predicate = function(nodes) {
207   return cvox.DomPredicates.containsTagName_(nodes, 'H5');
212  * Heading level 6.
213  * @param {Array<Node>} nodes An array of nodes to check.
214  * @return {?Node} Node in the array that is a heading level 6.
215  */
216 cvox.DomPredicates.heading6Predicate = function(nodes) {
217   return cvox.DomPredicates.containsTagName_(nodes, 'H6');
222  * Link.
223  * @param {Array<Node>} nodes An array of nodes to check.
224  * @return {?Node} Node in the array that is a link.
225  */
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)) {
230       return nodes[i];
231     }
232   }
233   return null;
238  * Table.
239  * @param {Array<Node>} nodes An array of nodes to check.
240  * @return {?Node} Node in the array that is a data table.
241  */
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)) {
246     return node;
247   } else {
248     return null;
249   }
253  * Table Cell.
254  * @param {Array<Node>} nodes An array of nodes to check.
255  * @return {?Node} Node in the array that is a table cell.
256  */
257 cvox.DomPredicates.cellPredicate = function(nodes) {
258   for (var i = nodes.length - 1; i >= 0; --i) {
259     var node = nodes[i];
260     if (node.tagName == 'TD' ||
261         node.tagName == 'TH' ||
262         (node.getAttribute && node.getAttribute('role') == 'gridcell')) {
263       return node;
264     }
265   }
266   return null;
271  * Visited link.
272  * @param {Array<Node>} nodes An array of nodes to check.
273  * @return {?Node} Node in the array that is a visited link.
274  */
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]) {
279       return nodes[i];
280     }
281   }
286  * List.
287  * @param {Array<Node>} nodes An array of nodes to check.
288  * @return {?Node} Node in the array that is a list.
289  */
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') {
295       return nodes[i];
296     }
297   }
298   return null;
303  * List item.
304  * @param {Array<Node>} nodes An array of nodes to check.
305  * @return {?Node} Node in the array that is a list item.
306  */
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') {
312       return nodes[i];
313     }
314   }
315   return null;
320  * Blockquote.
321  * @param {Array<Node>} nodes An array of nodes to check.
322  * @return {?Node} Node in the array that is a blockquote.
323  */
324 cvox.DomPredicates.blockquotePredicate = function(nodes) {
325   return cvox.DomPredicates.containsTagName_(nodes, 'BLOCKQUOTE');
330  * Form field.
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.
333  */
334 cvox.DomPredicates.formFieldPredicate = function(nodes) {
335   for (var i = 0; i < nodes.length; i++) {
336     if (cvox.DomUtil.isControl(nodes[i])) {
337       return nodes[i];
338     }
339   }
340   return null;
345  * ARIA landmark.
346  * @param {Array<Node>} nodes An array of nodes to check.
347  * @return {?Node} Node in the array that is an ARIA landmark.
348  */
349 cvox.DomPredicates.landmarkPredicate = function(nodes) {
350   for (var i = 0; i < nodes.length; i++) {
351     if (cvox.AriaUtil.isLandmark(nodes[i])) {
352       return nodes[i];
353     }
354   }
355   return null;
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.
363  * @private
364  */
365 cvox.DomPredicates.containsTagName_ = function(arr, tagName) {
366   var i = arr.length;
367   while (i--) {
368     if (arr[i].tagName == tagName) {
369       return arr[i];
370     }
371   }
372   return null;
377  * MathML expression
378  * @param {Array<Node>} nodes An array of nodes to check.
379  * @return {?Node} Node in the array that is a math expression.
380  */
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.
390  */
391 cvox.DomPredicates.sectionPredicate = function(nodes) {
392   for (var i = 0; i < nodes.length; i++) {
393     if (cvox.DomUtil.isSemanticElt(nodes[i])) {
394       return nodes[i];
395     }
396     if (cvox.AriaUtil.isLandmark(nodes[i])) {
397       return nodes[i];
398     }
399     if (nodes[i].getAttribute &&
400         nodes[i].getAttribute('role') == 'heading') {
401       return nodes[i];
402     }
403     switch (nodes[i].tagName) {
404       case 'H1':
405       case 'H2':
406       case 'H3':
407       case 'H4':
408       case 'H5':
409       case 'H6':
410         return nodes[i];
411     }
412   }
413   return null;
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.
421  */
422 cvox.DomPredicates.controlPredicate = function(nodes) {
423   for (var i = 0; i < nodes.length; i++) {
424     if (cvox.DomUtil.isControl(nodes[i])) {
425       return nodes[i];
426     }
427     if ((nodes[i].getAttribute && nodes[i].getAttribute('role') == 'link') ||
428         (nodes[i].tagName == 'A' && nodes[i].href)) {
429       return nodes[i];
430     }
431   }
432   return null;
436  * Caption.
437  * @param {Array<Node>} nodes An array of nodes to check.
438  * @return {?Node} Node in the array that is a caption.
439  */
440 cvox.DomPredicates.captionPredicate = function(nodes) {
441   for (var i = 0; i < nodes.length; i++) {
442     if (nodes[i].tagName == 'CAPTION') {
443       return nodes[i];
444     }
445   }
446   return null;
450  * Article.
451  * @param {Array<Node>} nodes An array of nodes to check.
452  * @return {?Node} Node in the array that is a article.
453  */
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') {
459       return nodes[i];
460     }
461   }
462   return null;
466  * Media.
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).
469  */
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') {
474       return nodes[i];
475     }
476   }
477   return null;
482  * Ordered List.
483  * @param {Array<Node>} nodes An array of nodes to check.
484  * @return {?Node} Node in the array that is a ordered list.
485  */
486 cvox.DomPredicates.orderedListPredicate = function(nodes) {
487   for (var i = 0; i < nodes.length; i++) {
488     if (nodes[i].tagName == 'OL') {
489       return nodes[i];
490     }
491   }
492   return null;