Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js

Issue 1866043004: Add a nameFromNode attrib to link output rule (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix tests. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 Provides output services for ChromeVox. 6 * @fileoverview Provides output services for ChromeVox.
7 */ 7 */
8 8
9 goog.provide('Output'); 9 goog.provide('Output');
10 goog.provide('Output.EventType'); 10 goog.provide('Output.EventType');
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 navigation: { 250 navigation: {
251 msgId: 'role_navigation', 251 msgId: 'role_navigation',
252 inherits: 'abstractContainer' 252 inherits: 'abstractContainer'
253 }, 253 },
254 note: { 254 note: {
255 msgId: 'role_note', 255 msgId: 'role_note',
256 inherits: 'abstractContainer' 256 inherits: 'abstractContainer'
257 }, 257 },
258 popUpButton: { 258 popUpButton: {
259 msgId: 'role_button', 259 msgId: 'role_button',
260 earconId: 'POP_UP_BUTTON'
260 }, 261 },
261 radioButton: { 262 radioButton: {
262 msgId: 'role_radio' 263 msgId: 'role_radio'
263 }, 264 },
264 radioGroup: { 265 radioGroup: {
265 msgId: 'role_radiogroup', 266 msgId: 'role_radiogroup',
266 }, 267 },
267 rowHeader: { 268 rowHeader: {
268 msgId: 'role_rowheader', 269 msgId: 'role_rowheader',
269 inherits: 'abstractContainer' 270 inherits: 'abstractContainer'
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 * Rules specifying format of AutomationNodes for output. 390 * Rules specifying format of AutomationNodes for output.
390 * @type {!Object<Object<Object<string>>>} 391 * @type {!Object<Object<Object<string>>>}
391 */ 392 */
392 Output.RULES = { 393 Output.RULES = {
393 navigate: { 394 navigate: {
394 'default': { 395 'default': {
395 speak: '$name $value $role $description', 396 speak: '$name $value $role $description',
396 braille: '' 397 braille: ''
397 }, 398 },
398 abstractContainer: { 399 abstractContainer: {
399 enter: '$name $role $description', 400 enter: '$nameFromNode $role $description',
400 leave: '@exited_container($role)' 401 leave: '@exited_container($role)'
401 }, 402 },
402 alert: { 403 alert: {
403 speak: '!doNotInterrupt $role $descendants' 404 speak: '!doNotInterrupt $role $descendants'
404 }, 405 },
405 alertDialog: { 406 alertDialog: {
406 enter: '$name $role $description $descendants' 407 enter: '$nameFromNode $role $description $descendants'
407 }, 408 },
408 cell: { 409 cell: {
409 enter: '@column_granularity $tableCellColumnIndex' 410 enter: '@column_granularity $tableCellColumnIndex'
410 }, 411 },
411 checkBox: { 412 checkBox: {
412 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + 413 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' +
413 '$name $role $checked $description' 414 '$name $role $checked $description'
414 }, 415 },
415 dialog: { 416 dialog: {
416 enter: '$name $role $description' 417 enter: '$nameFromNode $role $description'
417 }, 418 },
418 div: { 419 div: {
419 enter: '$name', 420 enter: '$nameFromNode',
420 speak: '$name $description' 421 speak: '$name $description'
421 }, 422 },
422 grid: { 423 grid: {
423 enter: '$name $role $description' 424 enter: '$nameFromNode $role $description'
424 }, 425 },
425 heading: { 426 heading: {
426 enter: '@tag_h+$hierarchicalLevel', 427 enter: '@tag_h+$hierarchicalLevel',
427 speak: '!relativePitch(hierarchicalLevel)' + 428 speak: '!relativePitch(hierarchicalLevel)' +
428 ' $nameOrDescendants= @tag_h+$hierarchicalLevel' 429 ' $nameOrDescendants= @tag_h+$hierarchicalLevel'
429 }, 430 },
430 inlineTextBox: { 431 inlineTextBox: {
431 speak: '$name=' 432 speak: '$name='
432 }, 433 },
433 link: { 434 link: {
434 enter: '$name= $if($visited, @visited_link, $role)', 435 enter: '$nameFromNode $if($visited, @visited_link, $role)',
435 speak: '$name= $if($visited, @visited_link, $role) $description' 436 speak: '$name= $if($visited, @visited_link, $role) $description'
436 }, 437 },
437 list: { 438 list: {
438 enter: '$role @@list_with_items($countChildren(listItem))' 439 enter: '$role @@list_with_items($countChildren(listItem))'
439 }, 440 },
440 listBox: { 441 listBox: {
441 enter: '$name $role @@list_with_items($countChildren(listBoxOption)) ' + 442 enter: '$nameFromNode ' +
443 '$role @@list_with_items($countChildren(listBoxOption)) ' +
442 '$description' 444 '$description'
443 }, 445 },
444 listBoxOption: { 446 listBoxOption: {
445 speak: '$name $role @describe_index($indexInParent, $parentChildCount) ' + 447 speak: '$name $role @describe_index($indexInParent, $parentChildCount) ' +
446 '$description' 448 '$description'
447 }, 449 },
448 listItem: { 450 listItem: {
449 enter: '$role' 451 enter: '$role'
450 }, 452 },
451 menu: { 453 menu: {
452 enter: '$name $role', 454 enter: '$name $role',
453 speak: '$name $role @@list_with_items($countChildren(menuItem))' 455 speak: '$name $role @@list_with_items($countChildren(menuItem))'
454 }, 456 },
455 menuItem: { 457 menuItem: {
456 speak: '$name $role $if($haspopup, @has_submenu) ' + 458 speak: '$name $role $if($haspopup, @has_submenu) ' +
457 '@describe_index($indexInParent, $parentChildCount) ' + 459 '@describe_index($indexInParent, $parentChildCount) ' +
458 '$description' 460 '$description'
459 }, 461 },
460 menuListOption: { 462 menuListOption: {
461 speak: '$name @role_menuitem ' + 463 speak: '$name @role_menuitem ' +
462 '@describe_index($indexInParent, $parentChildCount) $description' 464 '@describe_index($indexInParent, $parentChildCount) $description'
463 }, 465 },
464 paragraph: { 466 paragraph: {
465 speak: '$descendants' 467 speak: '$descendants'
466 }, 468 },
467 popUpButton: { 469 popUpButton: {
468 speak: '$earcon(POP_UP_BUTTON) $value $name $role @aria_has_popup ' + 470 speak: '$value $name $role @aria_has_popup ' +
469 '$if($collapsed, @aria_expanded_false, @aria_expanded_true) ' + 471 '$if($collapsed, @aria_expanded_false, @aria_expanded_true) ' +
470 '$description' 472 '$description'
471 }, 473 },
472 radioButton: { 474 radioButton: {
473 speak: '$if($checked, @describe_radio_selected($name), ' + 475 speak: '$if($checked, @describe_radio_selected($name), ' +
474 '@describe_radio_unselected($name)) $description' 476 '@describe_radio_unselected($name)) $description'
475 }, 477 },
476 radioGroup: { 478 radioGroup: {
477 enter: '$name $role $description' 479 enter: '$name $role $description'
478 }, 480 },
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
916 else 918 else
917 this.range_(range, prevRange, type, buff); 919 this.range_(range, prevRange, type, buff);
918 }, 920 },
919 921
920 /** 922 /**
921 * Format the node given the format specifier. 923 * Format the node given the format specifier.
922 * @param {AutomationNode} node 924 * @param {AutomationNode} node
923 * @param {string|!Object} format The output format either specified as an 925 * @param {string|!Object} format The output format either specified as an
924 * output template string or a parsed output format tree. 926 * output template string or a parsed output format tree.
925 * @param {!Array<Spannable>} buff Buffer to receive rendered output. 927 * @param {!Array<Spannable>} buff Buffer to receive rendered output.
928 * @param {!AutomationNode=} opt_prevNode
926 * @private 929 * @private
927 */ 930 */
928 format_: function(node, format, buff) { 931 format_: function(node, format, buff, opt_prevNode) {
929 var tokens = []; 932 var tokens = [];
930 var args = null; 933 var args = null;
931 934
932 // Hacky way to support args. 935 // Hacky way to support args.
933 if (typeof(format) == 'string') { 936 if (typeof(format) == 'string') {
934 format = format.replace(/([,:])\W/g, '$1'); 937 format = format.replace(/([,:])\W/g, '$1');
935 tokens = format.split(' '); 938 tokens = format.split(' ');
936 } else { 939 } else {
937 tokens = [format]; 940 tokens = [format];
938 } 941 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
977 if (node.textSelStart !== undefined) { 980 if (node.textSelStart !== undefined) {
978 options.annotation.push(new Output.SelectionSpan( 981 options.annotation.push(new Output.SelectionSpan(
979 node.textSelStart, 982 node.textSelStart,
980 node.textSelEnd)); 983 node.textSelEnd));
981 } 984 }
982 } 985 }
983 options.annotation.push(token); 986 options.annotation.push(token);
984 this.append_(buff, text, options); 987 this.append_(buff, text, options);
985 } else if (token == 'name') { 988 } else if (token == 'name') {
986 options.annotation.push(token); 989 options.annotation.push(token);
987 var earcon = node ? this.findEarcon_(node) : null; 990 var earcon = node ? this.findEarcon_(node, opt_prevNode) : null;
988 if (earcon) 991 if (earcon)
989 options.annotation.push(earcon); 992 options.annotation.push(earcon);
990 this.append_(buff, node.name, options); 993 this.append_(buff, node.name, options);
994 } else if (token == 'nameFromNode') {
995 if (chrome.automation.NameFromType[node.nameFrom] ==
996 'nameFromContents')
997 return;
998
999 options.annotation.push(token);
1000 this.append_(buff, node.name, options);
991 } else if (token == 'nameOrDescendants') { 1001 } else if (token == 'nameOrDescendants') {
992 options.annotation.push(token); 1002 options.annotation.push(token);
993 if (node.name) 1003 if (node.name)
994 this.append_(buff, node.name, options); 1004 this.append_(buff, node.name, options);
995 else 1005 else
996 this.format_(node, '$descendants', buff); 1006 this.format_(node, '$descendants', buff);
997 } else if (token == 'indexInParent') { 1007 } else if (token == 'indexInParent') {
998 options.annotation.push(token); 1008 options.annotation.push(token);
999 this.append_(buff, String(node.indexInParent + 1)); 1009 this.append_(buff, String(node.indexInParent + 1));
1000 } else if (token == 'parentChildCount') { 1010 } else if (token == 'parentChildCount') {
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
1297 for (var i = 0, formatPrevNode; 1307 for (var i = 0, formatPrevNode;
1298 (formatPrevNode = prevUniqueAncestors[i]); 1308 (formatPrevNode = prevUniqueAncestors[i]);
1299 i++) { 1309 i++) {
1300 // This prevents very repetitive announcements. 1310 // This prevents very repetitive announcements.
1301 if (enteredRoleSet[formatPrevNode.role] || 1311 if (enteredRoleSet[formatPrevNode.role] ||
1302 localStorage['useVerboseMode'] == 'false') 1312 localStorage['useVerboseMode'] == 'false')
1303 continue; 1313 continue;
1304 1314
1305 var roleBlock = getMergedRoleBlock(formatPrevNode.role); 1315 var roleBlock = getMergedRoleBlock(formatPrevNode.role);
1306 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') 1316 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true')
1307 this.format_(formatPrevNode, roleBlock.leave, buff); 1317 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode);
1308 } 1318 }
1309 1319
1310 var enterOutputs = []; 1320 var enterOutputs = [];
1311 var enterRole = {}; 1321 var enterRole = {};
1312 for (var j = uniqueAncestors.length - 2, formatNode; 1322 for (var j = uniqueAncestors.length - 2, formatNode;
1313 (formatNode = uniqueAncestors[j]); 1323 (formatNode = uniqueAncestors[j]);
1314 j--) { 1324 j--) {
1315 var roleBlock = getMergedRoleBlock(formatNode.role); 1325 var roleBlock = getMergedRoleBlock(formatNode.role);
1316 if (roleBlock.enter) { 1326 if (roleBlock.enter) {
1317 if (enterRole[formatNode.role]) 1327 if (enterRole[formatNode.role])
1318 continue; 1328 continue;
1319 enterRole[formatNode.role] = true; 1329 enterRole[formatNode.role] = true;
1320 this.format_(formatNode, roleBlock.enter, buff); 1330 this.format_(formatNode, roleBlock.enter, buff, prevNode);
1321 } 1331 }
1322 if (formatNode.role == 'window') 1332 if (formatNode.role == 'window')
1323 break; 1333 break;
1324 } 1334 }
1325 }, 1335 },
1326 1336
1327 /** 1337 /**
1328 * @param {!AutomationNode} node 1338 * @param {!AutomationNode} node
1329 * @param {!AutomationNode} prevNode 1339 * @param {!AutomationNode} prevNode
1330 * @param {EventType|Output.EventType} type 1340 * @param {EventType|Output.EventType} type
1331 * @param {!Array<Spannable>} buff 1341 * @param {!Array<Spannable>} buff
1332 * @private 1342 * @private
1333 */ 1343 */
1334 node_: function(node, prevNode, type, buff) { 1344 node_: function(node, prevNode, type, buff) {
1335 // Navigate is the default event. 1345 // Navigate is the default event.
1336 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; 1346 var eventBlock = Output.RULES[type] || Output.RULES['navigate'];
1337 var roleBlock = eventBlock[node.role] || {}; 1347 var roleBlock = eventBlock[node.role] || {};
1338 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; 1348 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits;
1339 var parentRoleBlock = eventBlock[parentRole || ''] || {}; 1349 var parentRoleBlock = eventBlock[parentRole || ''] || {};
1340 var speakFormat = roleBlock.speak || 1350 var speakFormat = roleBlock.speak ||
1341 parentRoleBlock.speak || 1351 parentRoleBlock.speak ||
1342 eventBlock['default'].speak; 1352 eventBlock['default'].speak;
1343 1353
1344 this.format_(node, speakFormat, buff); 1354 this.format_(node, speakFormat, buff, prevNode);
1345 }, 1355 },
1346 1356
1347 /** 1357 /**
1348 * @param {!cursors.Range} range 1358 * @param {!cursors.Range} range
1349 * @param {cursors.Range} prevRange 1359 * @param {cursors.Range} prevRange
1350 * @param {EventType|Output.EventType} type 1360 * @param {EventType|Output.EventType} type
1351 * @param {!Array<Spannable>} buff 1361 * @param {!Array<Spannable>} buff
1352 * @private 1362 * @private
1353 */ 1363 */
1354 subNode_: function(range, prevRange, type, buff) { 1364 subNode_: function(range, prevRange, type, buff) {
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
1537 return result; 1547 return result;
1538 }, 1548 },
1539 1549
1540 /** 1550 /**
1541 * Find the earcon for a given node (including ancestry). 1551 * Find the earcon for a given node (including ancestry).
1542 * @param {!AutomationNode} node 1552 * @param {!AutomationNode} node
1543 * @param {!AutomationNode=} opt_prevNode 1553 * @param {!AutomationNode=} opt_prevNode
1544 * @return {Output.Action} 1554 * @return {Output.Action}
1545 */ 1555 */
1546 findEarcon_: function(node, opt_prevNode) { 1556 findEarcon_: function(node, opt_prevNode) {
1557 if (node === opt_prevNode)
1558 return null;
1559
1547 if (this.formatOptions_.speech) { 1560 if (this.formatOptions_.speech) {
1548 var earconFinder = node; 1561 var earconFinder = node;
1549 var ancestors; 1562 var ancestors;
1550 if (opt_prevNode) { 1563 if (opt_prevNode)
1551 // Don't include the node itself.
1552 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); 1564 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node);
1553 ancestors.pop(); 1565 else
1554 } else {
1555 ancestors = AutomationUtil.getAncestors(node); 1566 ancestors = AutomationUtil.getAncestors(node);
1556 }
1557 1567
1558 while (earconFinder = ancestors.pop()) { 1568 while (earconFinder = ancestors.pop()) {
1559 var info = Output.ROLE_INFO_[earconFinder.role]; 1569 var info = Output.ROLE_INFO_[earconFinder.role];
1560 if (info && info.earconId) { 1570 if (info && info.earconId) {
1561 return new Output.EarconAction(info.earconId); 1571 return new Output.EarconAction(info.earconId);
1562 break; 1572 break;
1563 } 1573 }
1564 earconFinder = earconFinder.parent; 1574 earconFinder = earconFinder.parent;
1565 } 1575 }
1566 } 1576 }
1567 return null; 1577 return null;
1568 } 1578 }
1569 }; 1579 };
1570 1580
1571 }); // goog.scope 1581 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698