Chromium Code Reviews| 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 |