OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview ChromeVox predicates for the automation extension API. | 6 * @fileoverview ChromeVox predicates for the automation extension API. |
7 */ | 7 */ |
8 | 8 |
9 goog.provide('AutomationPredicate'); | 9 goog.provide('AutomationPredicate'); |
10 goog.provide('AutomationPredicate.Binary'); | 10 goog.provide('AutomationPredicate.Binary'); |
11 goog.provide('AutomationPredicate.Unary'); | 11 goog.provide('AutomationPredicate.Unary'); |
12 | 12 |
13 goog.require('constants'); | |
14 | |
13 goog.scope(function() { | 15 goog.scope(function() { |
14 var AutomationNode = chrome.automation.AutomationNode; | 16 var AutomationNode = chrome.automation.AutomationNode; |
17 var Dir = constants.Dir; | |
15 var RoleType = chrome.automation.RoleType; | 18 var RoleType = chrome.automation.RoleType; |
16 | 19 |
17 /** | 20 /** |
18 * @constructor | 21 * @constructor |
19 */ | 22 */ |
20 AutomationPredicate = function() {}; | 23 AutomationPredicate = function() {}; |
21 | 24 |
22 /** | 25 /** |
23 * @typedef {function(!AutomationNode) : boolean} | 26 * @typedef {function(!AutomationNode) : boolean} |
24 */ | 27 */ |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 if (node.role == RoleType.listMarker) | 279 if (node.role == RoleType.listMarker) |
277 return true; | 280 return true; |
278 | 281 |
279 // Don't ignore nodes with names. | 282 // Don't ignore nodes with names. |
280 if (node.name || node.value || node.description) | 283 if (node.name || node.value || node.description) |
281 return false; | 284 return false; |
282 | 285 |
283 // Ignore some roles. | 286 // Ignore some roles. |
284 return AutomationPredicate.leaf(node) && | 287 return AutomationPredicate.leaf(node) && |
285 (node.role == RoleType.client || | 288 (node.role == RoleType.client || |
289 node.role == RoleType.column || | |
286 node.role == RoleType.div || | 290 node.role == RoleType.div || |
287 node.role == RoleType.group || | 291 node.role == RoleType.group || |
288 node.role == RoleType.image || | 292 node.role == RoleType.image || |
289 node.role == RoleType.staticText); | 293 node.role == RoleType.staticText || |
294 node.role == RoleType.tableHeaderContainer); | |
290 }; | 295 }; |
291 | 296 |
292 | 297 |
293 /** | 298 /** |
294 * Returns if the node has a meaningful checked state. | 299 * Returns if the node has a meaningful checked state. |
295 * @param {!AutomationNode} node | 300 * @param {!AutomationNode} node |
296 * @return {boolean} | 301 * @return {boolean} |
297 */ | 302 */ |
298 AutomationPredicate.checkable = function(node) { | 303 AutomationPredicate.checkable = function(node) { |
299 return node.role == RoleType.checkBox || | 304 return node.role == RoleType.checkBox || |
300 node.role == RoleType.radioButton || | 305 node.role == RoleType.radioButton || |
301 node.role == RoleType.menuItemCheckBox || | 306 node.role == RoleType.menuItemCheckBox || |
302 node.role == RoleType.menuItemRadio; | 307 node.role == RoleType.menuItemRadio; |
303 }; | 308 }; |
304 | 309 |
310 // Table related predicates. | |
311 /** | |
312 * Returns if the node has a cell like role. | |
313 * @param {!AutomationNode} node | |
314 * @return {boolean} | |
315 */ | |
316 AutomationPredicate.cellLike = function(node) { | |
317 return node.role == RoleType.cell || | |
318 node.role == RoleType.rowHeader || | |
319 node.role == RoleType.columnHeader; | |
320 }; | |
321 | |
322 /** | |
323 * Returns a predicate that will match against the directed next vertical cell | |
324 * taking into account the current ancestor cell's position in the table. | |
325 * @param {AutomationNode} start | |
326 * @param {{dir: (Dir|undefined), | |
327 * end: (boolean|undefined), | |
328 * row: (boolean|undefined), | |
329 * col: (boolean|undefined)}} opts | |
330 * |dir|, specifies direction for |row or/and |col| movement by one cell. | |
331 * |dir| defaults to forward. | |
332 * |row| and |col| are both false by default. | |
333 * |end| defaults to false. If set to true, the first row or co will be | |
334 * returned. | |
335 * @return {?AutomationPredicate.Unary} Returns null if not in a table. | |
336 */ | |
337 AutomationPredicate.rowCol = function(start, opts) { | |
dmazzoni
2016/07/13 23:38:28
I'd maybe call the predicate tableNavigation or mo
David Tseng
2016/07/14 20:24:41
Probably part of the confusion...it makes a predic
| |
338 if (!opts.row && !opts.col) | |
339 throw new Error('You must set either row or col to true'); | |
dmazzoni
2016/07/13 23:38:28
indent
David Tseng
2016/07/14 20:24:41
Done.
| |
340 | |
341 var dir = opts.dir || Dir.FORWARD; | |
342 | |
343 // Compute the row/col index defaulting to 0. | |
344 var rowIndex = 0, colIndex = 0; | |
345 var tableNode = start; | |
346 while (tableNode) { | |
347 if (AutomationPredicate.table(tableNode)) | |
348 break; | |
349 | |
350 if (AutomationPredicate.cellLike(tableNode)) { | |
351 rowIndex = tableNode.tableCellRowIndex; | |
352 colIndex = tableNode.tableCellColumnIndex; | |
353 } | |
354 | |
355 tableNode = tableNode.parent; | |
356 } | |
357 if (!tableNode) | |
358 return null; | |
359 | |
360 if (!opts.end) { | |
361 // Adjust for the next/previous row/col. | |
362 if (opts.row) | |
363 rowIndex = dir == Dir.FORWARD ? rowIndex + 1 : rowIndex - 1; | |
364 if (opts.col) | |
365 colIndex = dir == Dir.FORWARD ? colIndex + 1 : colIndex - 1; | |
366 } else { | |
367 var rowEnd = dir == Dir.FORWARD ? (tableNode.tableRowCount - 1) : 0; | |
368 var colEnd = dir == Dir.FORWARD ? (tableNode.tableColumnCount - 1) : 0; | |
369 | |
370 if (opts.row && opts.col) { | |
371 // Do nothing if we're already there. | |
372 if (rowEnd === rowIndex && colEnd === colIndex) | |
373 return null; | |
374 | |
375 rowIndex = rowEnd; | |
376 colIndex = colEnd; | |
377 } else if (opts.row) { | |
378 // This looks counter-intuitive, but moving to the end of a row, means | |
379 // moving horizontally (by col). | |
380 | |
381 // Do nothing if we're already there. | |
382 if (colEnd == colIndex) | |
383 return null; | |
384 | |
385 colIndex = colEnd; | |
386 } else if (opts.col) { | |
387 // Do nothing if we're already there. | |
388 if (rowEnd == rowIndex) | |
389 return null; | |
390 | |
391 rowIndex = rowEnd; | |
392 } | |
393 } | |
394 | |
395 return function(node) { | |
dmazzoni
2016/07/13 23:38:28
Why is this a predicate that returns a function ra
David Tseng
2016/07/14 20:24:41
How did you conclude that? This method makes a pre
| |
396 return AutomationPredicate.cellLike(node) && | |
397 node.tableCellColumnIndex == colIndex && | |
398 node.tableCellRowIndex == rowIndex; | |
399 }; | |
400 }; | |
401 | |
305 }); // goog.scope | 402 }); // goog.scope |
OLD | NEW |