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 20 matching lines...) Expand all Loading... |
45 /** @type {AutomationPredicate.Unary} */ | 48 /** @type {AutomationPredicate.Unary} */ |
46 AutomationPredicate.comboBox = AutomationPredicate.withRole(RoleType.comboBox); | 49 AutomationPredicate.comboBox = AutomationPredicate.withRole(RoleType.comboBox); |
47 /** @type {AutomationPredicate.Unary} */ | 50 /** @type {AutomationPredicate.Unary} */ |
48 AutomationPredicate.heading = AutomationPredicate.withRole(RoleType.heading); | 51 AutomationPredicate.heading = AutomationPredicate.withRole(RoleType.heading); |
49 /** @type {AutomationPredicate.Unary} */ | 52 /** @type {AutomationPredicate.Unary} */ |
50 AutomationPredicate.inlineTextBox = | 53 AutomationPredicate.inlineTextBox = |
51 AutomationPredicate.withRole(RoleType.inlineTextBox); | 54 AutomationPredicate.withRole(RoleType.inlineTextBox); |
52 /** @type {AutomationPredicate.Unary} */ | 55 /** @type {AutomationPredicate.Unary} */ |
53 AutomationPredicate.link = AutomationPredicate.withRole(RoleType.link); | 56 AutomationPredicate.link = AutomationPredicate.withRole(RoleType.link); |
54 /** @type {AutomationPredicate.Unary} */ | 57 /** @type {AutomationPredicate.Unary} */ |
| 58 AutomationPredicate.row = AutomationPredicate.withRole(RoleType.row); |
| 59 /** @type {AutomationPredicate.Unary} */ |
55 AutomationPredicate.table = AutomationPredicate.withRole(RoleType.table); | 60 AutomationPredicate.table = AutomationPredicate.withRole(RoleType.table); |
56 | 61 |
57 /** | 62 /** |
58 * @param {!AutomationNode} node | 63 * @param {!AutomationNode} node |
59 * @return {boolean} | 64 * @return {boolean} |
60 */ | 65 */ |
61 AutomationPredicate.button = function(node) { | 66 AutomationPredicate.button = function(node) { |
62 return /button/i.test(node.role); | 67 return /button/i.test(node.role); |
63 }; | 68 }; |
64 | 69 |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 if (node.role == RoleType.listMarker) | 281 if (node.role == RoleType.listMarker) |
277 return true; | 282 return true; |
278 | 283 |
279 // Don't ignore nodes with names. | 284 // Don't ignore nodes with names. |
280 if (node.name || node.value || node.description) | 285 if (node.name || node.value || node.description) |
281 return false; | 286 return false; |
282 | 287 |
283 // Ignore some roles. | 288 // Ignore some roles. |
284 return AutomationPredicate.leaf(node) && | 289 return AutomationPredicate.leaf(node) && |
285 (node.role == RoleType.client || | 290 (node.role == RoleType.client || |
| 291 node.role == RoleType.column || |
286 node.role == RoleType.div || | 292 node.role == RoleType.div || |
287 node.role == RoleType.group || | 293 node.role == RoleType.group || |
288 node.role == RoleType.image || | 294 node.role == RoleType.image || |
289 node.role == RoleType.staticText); | 295 node.role == RoleType.staticText || |
| 296 node.role == RoleType.tableHeaderContainer); |
290 }; | 297 }; |
291 | 298 |
292 | 299 |
293 /** | 300 /** |
294 * Returns if the node has a meaningful checked state. | 301 * Returns if the node has a meaningful checked state. |
295 * @param {!AutomationNode} node | 302 * @param {!AutomationNode} node |
296 * @return {boolean} | 303 * @return {boolean} |
297 */ | 304 */ |
298 AutomationPredicate.checkable = function(node) { | 305 AutomationPredicate.checkable = function(node) { |
299 return node.role == RoleType.checkBox || | 306 return node.role == RoleType.checkBox || |
300 node.role == RoleType.radioButton || | 307 node.role == RoleType.radioButton || |
301 node.role == RoleType.menuItemCheckBox || | 308 node.role == RoleType.menuItemCheckBox || |
302 node.role == RoleType.menuItemRadio; | 309 node.role == RoleType.menuItemRadio; |
303 }; | 310 }; |
304 | 311 |
| 312 // Table related predicates. |
| 313 /** |
| 314 * Returns if the node has a cell like role. |
| 315 * @param {!AutomationNode} node |
| 316 * @return {boolean} |
| 317 */ |
| 318 AutomationPredicate.cellLike = function(node) { |
| 319 return node.role == RoleType.cell || |
| 320 node.role == RoleType.rowHeader || |
| 321 node.role == RoleType.columnHeader; |
| 322 }; |
| 323 |
| 324 /** |
| 325 * Returns a predicate that will match against the directed next cell taking |
| 326 * into account the current ancestor cell's position in the table. |
| 327 * @param {AutomationNode} start |
| 328 * @param {{dir: (Dir|undefined), |
| 329 * row: (boolean|undefined), |
| 330 * col: (boolean|undefined)}} opts |
| 331 * |dir|, specifies direction for |row or/and |col| movement by one cell. |
| 332 * |dir| defaults to forward. |
| 333 * |row| and |col| are both false by default. |
| 334 * |end| defaults to false. If set to true, |col| must also be set to true. |
| 335 * It will then return the first or last cell in the current column. |
| 336 * @return {?AutomationPredicate.Unary} Returns null if not in a table. |
| 337 */ |
| 338 AutomationPredicate.makeTableCellPredicate = function(start, opts) { |
| 339 if (!opts.row && !opts.col) |
| 340 throw new Error('You must set either row or col to true'); |
| 341 |
| 342 var dir = opts.dir || Dir.FORWARD; |
| 343 |
| 344 // Compute the row/col index defaulting to 0. |
| 345 var rowIndex = 0, colIndex = 0; |
| 346 var tableNode = start; |
| 347 while (tableNode) { |
| 348 if (AutomationPredicate.table(tableNode)) |
| 349 break; |
| 350 |
| 351 if (AutomationPredicate.cellLike(tableNode)) { |
| 352 rowIndex = tableNode.tableCellRowIndex; |
| 353 colIndex = tableNode.tableCellColumnIndex; |
| 354 } |
| 355 |
| 356 tableNode = tableNode.parent; |
| 357 } |
| 358 if (!tableNode) |
| 359 return null; |
| 360 |
| 361 // Only support making a predicate for column ends. |
| 362 if (opts.end) { |
| 363 if (!opts.col) |
| 364 throw 'Unsupported option.'; |
| 365 |
| 366 if (dir == Dir.FORWARD) { |
| 367 return function(node) { |
| 368 return AutomationPredicate.cellLike(node) && |
| 369 node.tableCellColumnIndex == colIndex && |
| 370 node.tableCellRowIndex >= 0; |
| 371 }; |
| 372 } else { |
| 373 return function(node) { |
| 374 return AutomationPredicate.cellLike(node) && |
| 375 node.tableCellColumnIndex == colIndex && |
| 376 node.tableCellRowIndex < tableNode.tableRowCount; |
| 377 }; |
| 378 } |
| 379 } |
| 380 |
| 381 // Adjust for the next/previous row/col. |
| 382 if (opts.row) |
| 383 rowIndex = dir == Dir.FORWARD ? rowIndex + 1 : rowIndex - 1; |
| 384 if (opts.col) |
| 385 colIndex = dir == Dir.FORWARD ? colIndex + 1 : colIndex - 1; |
| 386 |
| 387 return function(node) { |
| 388 return AutomationPredicate.cellLike(node) && |
| 389 node.tableCellColumnIndex == colIndex && |
| 390 node.tableCellRowIndex == rowIndex; |
| 391 }; |
| 392 }; |
| 393 |
305 }); // goog.scope | 394 }); // goog.scope |
OLD | NEW |