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 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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 * @private | 80 * @private |
| 81 */ | 81 */ |
| 82 this.speechCategory_ = cvox.TtsCategory.NAV; | 82 this.speechCategory_ = cvox.TtsCategory.NAV; |
| 83 | 83 |
| 84 /** | 84 /** |
| 85 * The speech queue mode for the generated speech utterance. | 85 * The speech queue mode for the generated speech utterance. |
| 86 * @type {cvox.QueueMode} | 86 * @type {cvox.QueueMode} |
| 87 * @private | 87 * @private |
| 88 */ | 88 */ |
| 89 this.queueMode_ = cvox.QueueMode.QUEUE; | 89 this.queueMode_ = cvox.QueueMode.QUEUE; |
| 90 | |
| 91 /** | |
| 92 * @type {boolean} | |
| 93 * @private | |
| 94 */ | |
| 95 this.outputContextFirst_ = localStorage['outputContextFirst'] == 'true'; | |
| 90 }; | 96 }; |
| 91 | 97 |
| 92 /** | 98 /** |
| 93 * Delimiter to use between output values. | 99 * Delimiter to use between output values. |
| 94 * @type {string} | 100 * @type {string} |
| 95 */ | 101 */ |
| 96 Output.SPACE = ' '; | 102 Output.SPACE = ' '; |
| 97 | 103 |
| 98 /** | 104 /** |
| 99 * Metadata about supported automation roles. | 105 * Metadata about supported automation roles. |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 129 }, | 135 }, |
| 130 button: { | 136 button: { |
| 131 msgId: 'role_button', | 137 msgId: 'role_button', |
| 132 earconId: 'BUTTON' | 138 earconId: 'BUTTON' |
| 133 }, | 139 }, |
| 134 buttonDropDown: { | 140 buttonDropDown: { |
| 135 msgId: 'role_button', | 141 msgId: 'role_button', |
| 136 earconId: 'BUTTON' | 142 earconId: 'BUTTON' |
| 137 }, | 143 }, |
| 138 cell: { | 144 cell: { |
| 139 msgId: 'role_gridcell' | 145 msgId: 'role_column' |
|
dmazzoni
2016/07/13 23:38:28
Why is "cell" speaking the "column" message?
David Tseng
2016/07/14 20:24:41
This is unused by the cell speech rule...removed.
| |
| 140 }, | 146 }, |
| 141 checkBox: { | 147 checkBox: { |
| 142 msgId: 'role_checkbox' | 148 msgId: 'role_checkbox' |
| 143 }, | 149 }, |
| 144 columnHeader: { | 150 columnHeader: { |
| 145 msgId: 'role_columnheader', | 151 msgId: 'role_columnheader', |
| 146 inherits: 'abstractContainer' | 152 inherits: 'cell' |
| 147 }, | 153 }, |
| 148 comboBox: { | 154 comboBox: { |
| 149 msgId: 'role_combobox' | 155 msgId: 'role_combobox' |
| 150 }, | 156 }, |
| 151 complementary: { | 157 complementary: { |
| 152 msgId: 'role_complementary', | 158 msgId: 'role_complementary', |
| 153 inherits: 'abstractContainer' | 159 inherits: 'abstractContainer' |
| 154 }, | 160 }, |
| 155 contentInfo: { | 161 contentInfo: { |
| 156 msgId: 'role_contentinfo', | 162 msgId: 'role_contentinfo', |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 popUpButton: { | 267 popUpButton: { |
| 262 msgId: 'role_button', | 268 msgId: 'role_button', |
| 263 earconId: 'POP_UP_BUTTON' | 269 earconId: 'POP_UP_BUTTON' |
| 264 }, | 270 }, |
| 265 radioButton: { | 271 radioButton: { |
| 266 msgId: 'role_radio' | 272 msgId: 'role_radio' |
| 267 }, | 273 }, |
| 268 radioGroup: { | 274 radioGroup: { |
| 269 msgId: 'role_radiogroup', | 275 msgId: 'role_radiogroup', |
| 270 }, | 276 }, |
| 277 row: { | |
| 278 msgId: 'role_row', | |
| 279 inherits: 'abstractContainer' | |
| 280 }, | |
| 271 rowHeader: { | 281 rowHeader: { |
| 272 msgId: 'role_rowheader', | 282 msgId: 'role_rowheader', |
| 273 inherits: 'abstractContainer' | 283 inherits: 'cell' |
| 274 }, | 284 }, |
| 275 scrollBar: { | 285 scrollBar: { |
| 276 msgId: 'role_scrollbar', | 286 msgId: 'role_scrollbar', |
| 277 }, | 287 }, |
| 278 search: { | 288 search: { |
| 279 msgId: 'role_search', | 289 msgId: 'role_search', |
| 280 inherits: 'abstractContainer' | 290 inherits: 'abstractContainer' |
| 281 }, | 291 }, |
| 282 separator: { | 292 separator: { |
| 283 msgId: 'role_separator', | 293 msgId: 'role_separator', |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 * Rules specifying format of AutomationNodes for output. | 414 * Rules specifying format of AutomationNodes for output. |
| 405 * @type {!Object<Object<Object<string>>>} | 415 * @type {!Object<Object<Object<string>>>} |
| 406 */ | 416 */ |
| 407 Output.RULES = { | 417 Output.RULES = { |
| 408 navigate: { | 418 navigate: { |
| 409 'default': { | 419 'default': { |
| 410 speak: '$name $value $state $role $description', | 420 speak: '$name $value $state $role $description', |
| 411 braille: '' | 421 braille: '' |
| 412 }, | 422 }, |
| 413 abstractContainer: { | 423 abstractContainer: { |
| 414 enter: '$nameFromNode $role $description', | 424 enter: '$nameFromNode $role $description' |
| 415 leave: '@exited_container($role)' | |
|
dmazzoni
2016/07/13 23:38:28
I think it's particularly useful to have exited_co
David Tseng
2016/07/14 20:24:41
Leaving for another cl where I can do an audit on
| |
| 416 }, | 425 }, |
| 417 alert: { | 426 alert: { |
| 418 speak: '!doNotInterrupt $role $descendants' | 427 speak: '!doNotInterrupt $role $descendants' |
| 419 }, | 428 }, |
| 420 alertDialog: { | 429 alertDialog: { |
| 421 enter: '$nameFromNode $role $description', | 430 enter: '$nameFromNode $role $description', |
| 422 speak: '$name $role $descendants' | 431 speak: '$name $role $descendants' |
| 423 }, | 432 }, |
| 424 cell: { | 433 cell: { |
| 425 enter: '@column_granularity $tableCellColumnIndex' | 434 enter: '@cell_summary($tableCellRowIndex, $tableCellColumnIndex) ' + |
| 435 '$node(tableColumnHeader)', | |
| 436 speak: '@cell_summary($tableCellRowIndex, $tableCellColumnIndex) ' + | |
| 437 '$node(tableColumnHeader)' | |
| 426 }, | 438 }, |
| 427 checkBox: { | 439 checkBox: { |
| 428 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 440 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 429 '$name $role $checked $description' | 441 '$name $role $checked $description' |
| 430 }, | 442 }, |
| 431 dialog: { | 443 dialog: { |
| 432 enter: '$nameFromNode $role $description' | 444 enter: '$nameFromNode $role $description' |
| 433 }, | 445 }, |
| 434 div: { | 446 div: { |
| 435 enter: '$nameFromNode', | 447 enter: '$nameFromNode', |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 507 enter: '$name $role $description' | 519 enter: '$name $role $description' |
| 508 }, | 520 }, |
| 509 rootWebArea: { | 521 rootWebArea: { |
| 510 enter: '$name', | 522 enter: '$name', |
| 511 speak: '$if($name, $name, $docUrl)' | 523 speak: '$if($name, $name, $docUrl)' |
| 512 }, | 524 }, |
| 513 region: { | 525 region: { |
| 514 speak: '$descendants' | 526 speak: '$descendants' |
| 515 }, | 527 }, |
| 516 row: { | 528 row: { |
| 517 enter: '@row_granularity $tableRowIndex' | 529 enter: '$node(tableRowHeader)' |
| 530 }, | |
| 531 rowHeader: { | |
| 532 speak: '$descendants' | |
| 518 }, | 533 }, |
| 519 slider: { | 534 slider: { |
| 520 speak: '$earcon(SLIDER) @describe_slider($value, $name) $description' | 535 speak: '$earcon(SLIDER) @describe_slider($value, $name) $description' |
| 521 }, | 536 }, |
| 522 staticText: { | 537 staticText: { |
| 523 speak: '$name=' | 538 speak: '$name=' |
| 524 }, | 539 }, |
| 525 tab: { | 540 tab: { |
| 526 speak: '@describe_tab($name)' | 541 speak: '@describe_tab($name)' |
| 527 }, | 542 }, |
| 543 table: { | |
| 544 enter: '@table_summary($name, $tableRowCount, $tableColumnCount) ' + | |
| 545 '$node(tableHeader)' | |
| 546 }, | |
| 547 tableHeaderContainer: { | |
| 548 speak: '$descendants' | |
| 549 }, | |
| 528 textField: { | 550 textField: { |
| 529 speak: '$name $value $if($multiline, @tag_textarea, $if(' + | 551 speak: '$name $value $if($multiline, @tag_textarea, $if(' + |
| 530 '$inputType, $inputType, $role)) $description', | 552 '$inputType, $inputType, $role)) $description', |
| 531 braille: '' | 553 braille: '' |
| 532 }, | 554 }, |
| 533 toggleButton: { | 555 toggleButton: { |
| 534 speak: '$if($pressed, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 556 speak: '$if($pressed, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 535 '$name $role $pressed $description' | 557 '$name $role $pressed $description' |
| 536 }, | 558 }, |
| 537 toolbar: { | 559 toolbar: { |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 799 * Output a string literal. | 821 * Output a string literal. |
| 800 * @param {string} value | 822 * @param {string} value |
| 801 * @return {!Output} | 823 * @return {!Output} |
| 802 */ | 824 */ |
| 803 withString: function(value) { | 825 withString: function(value) { |
| 804 this.append_(this.speechBuffer_, value); | 826 this.append_(this.speechBuffer_, value); |
| 805 this.append_(this.brailleBuffer_, value); | 827 this.append_(this.brailleBuffer_, value); |
| 806 return this; | 828 return this; |
| 807 }, | 829 }, |
| 808 | 830 |
| 831 | |
| 832 /** | |
| 833 * Outputs formatting nodes after this will contain context first. | |
| 834 * @return {!Output} | |
| 835 */ | |
| 836 withContextFirst: function() { | |
| 837 this.outputContextFirst_ = true; | |
| 838 return this; | |
| 839 }, | |
| 840 | |
| 809 /** | 841 /** |
| 810 * Apply a format string directly to the output buffer. This lets you | 842 * Apply a format string directly to the output buffer. This lets you |
| 811 * output a message directly to the buffer using the format syntax. | 843 * output a message directly to the buffer using the format syntax. |
| 812 * @param {string} formatStr | 844 * @param {string} formatStr |
| 813 * @param {!AutomationNode=} opt_node An optional node to apply the | 845 * @param {!AutomationNode=} opt_node An optional node to apply the |
| 814 * formatting to. | 846 * formatting to. |
| 815 * @return {!Output} |this| for chaining | 847 * @return {!Output} |this| for chaining |
| 816 */ | 848 */ |
| 817 format: function(formatStr, opt_node) { | 849 format: function(formatStr, opt_node) { |
| 818 return this | 850 return this |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1126 this.append_(buff, msg, options); | 1158 this.append_(buff, msg, options); |
| 1127 } else if (token == 'inputType') { | 1159 } else if (token == 'inputType') { |
| 1128 if (!node.inputType) | 1160 if (!node.inputType) |
| 1129 return; | 1161 return; |
| 1130 options.annotation.push(token); | 1162 options.annotation.push(token); |
| 1131 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || | 1163 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || |
| 1132 'input_type_text'; | 1164 'input_type_text'; |
| 1133 if (this.formatOptions_.braille) | 1165 if (this.formatOptions_.braille) |
| 1134 msgId = msgId + '_brl'; | 1166 msgId = msgId + '_brl'; |
| 1135 this.append_(buff, Msgs.getMsg(msgId), options); | 1167 this.append_(buff, Msgs.getMsg(msgId), options); |
| 1136 } else if (token == 'tableRowIndex' || | 1168 } else if (token == 'tableCellRowIndex' || |
| 1137 token == 'tableCellColumnIndex') { | 1169 token == 'tableCellColumnIndex') { |
| 1138 var value = node[token]; | 1170 var value = node[token]; |
| 1139 if (!value) | 1171 if (value == undefined) |
| 1140 return; | 1172 return; |
| 1141 value = String(value + 1); | 1173 value = String(value + 1); |
| 1142 options.annotation.push(token); | 1174 options.annotation.push(token); |
| 1143 this.append_(buff, value, options); | 1175 this.append_(buff, value, options); |
| 1176 } else if (token == 'node') { | |
| 1177 if (!tree.firstChild || !node[tree.firstChild.value]) | |
| 1178 return; | |
| 1179 var related = node[tree.firstChild.value]; | |
| 1180 this.node_(related, related, Output.EventType.NAVIGATE, buff); | |
| 1144 } else if (node[token] !== undefined) { | 1181 } else if (node[token] !== undefined) { |
| 1145 options.annotation.push(token); | 1182 options.annotation.push(token); |
| 1146 var value = node[token]; | 1183 var value = node[token]; |
| 1147 if (typeof value == 'number') | 1184 if (typeof value == 'number') |
| 1148 value = String(value); | 1185 value = String(value); |
| 1149 this.append_(buff, value, options); | 1186 this.append_(buff, value, options); |
| 1150 } else if (Output.STATE_INFO_[token]) { | 1187 } else if (Output.STATE_INFO_[token]) { |
| 1151 options.annotation.push('state'); | 1188 options.annotation.push('state'); |
| 1152 var stateInfo = Output.STATE_INFO_[token]; | 1189 var stateInfo = Output.STATE_INFO_[token]; |
| 1153 var resolvedInfo = {}; | 1190 var resolvedInfo = {}; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1293 if (!range.start.node || !range.end.node) | 1330 if (!range.start.node || !range.end.node) |
| 1294 return; | 1331 return; |
| 1295 | 1332 |
| 1296 if (!prevRange && range.start.node.root) | 1333 if (!prevRange && range.start.node.root) |
| 1297 prevRange = cursors.Range.fromNode(range.start.node.root); | 1334 prevRange = cursors.Range.fromNode(range.start.node.root); |
| 1298 var cursor = cursors.Cursor.fromNode(range.start.node); | 1335 var cursor = cursors.Cursor.fromNode(range.start.node); |
| 1299 var prevNode = prevRange.start.node; | 1336 var prevNode = prevRange.start.node; |
| 1300 | 1337 |
| 1301 var formatNodeAndAncestors = function(node, prevNode) { | 1338 var formatNodeAndAncestors = function(node, prevNode) { |
| 1302 var buff = []; | 1339 var buff = []; |
| 1303 var outputContextFirst = localStorage['outputContextFirst'] == 'true'; | 1340 |
| 1304 if (outputContextFirst) | 1341 if (this.outputContextFirst_) |
| 1305 this.ancestry_(node, prevNode, type, buff); | 1342 this.ancestry_(node, prevNode, type, buff); |
| 1306 this.node_(node, prevNode, type, buff); | 1343 this.node_(node, prevNode, type, buff); |
| 1307 if (!outputContextFirst) | 1344 if (!this.outputContextFirst_) |
| 1308 this.ancestry_(node, prevNode, type, buff); | 1345 this.ancestry_(node, prevNode, type, buff); |
| 1309 if (node.location) | 1346 if (node.location) |
| 1310 this.locations_.push(node.location); | 1347 this.locations_.push(node.location); |
| 1311 return buff; | 1348 return buff; |
| 1312 }.bind(this); | 1349 }.bind(this); |
| 1313 | 1350 |
| 1314 while (cursor.node != range.end.node) { | 1351 while (cursor.node != range.end.node) { |
| 1315 var node = cursor.node; | 1352 var node = cursor.node; |
| 1316 rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode)); | 1353 rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode)); |
| 1317 prevNode = node; | 1354 prevNode = node; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1441 var selStart = node.textSelStart; | 1478 var selStart = node.textSelStart; |
| 1442 var selEnd = node.textSelEnd; | 1479 var selEnd = node.textSelEnd; |
| 1443 if (selStart !== undefined && | 1480 if (selStart !== undefined && |
| 1444 (selEnd >= startIndex && selStart <= endIndex)) { | 1481 (selEnd >= startIndex && selStart <= endIndex)) { |
| 1445 options.annotation.push(new Output.SelectionSpan( | 1482 options.annotation.push(new Output.SelectionSpan( |
| 1446 selStart - startIndex, | 1483 selStart - startIndex, |
| 1447 selEnd - startIndex, | 1484 selEnd - startIndex, |
| 1448 startIndex)); | 1485 startIndex)); |
| 1449 } | 1486 } |
| 1450 } | 1487 } |
| 1451 var outputContextFirst = localStorage['outputContextFirst'] == 'true'; | 1488 |
| 1452 if (outputContextFirst) | 1489 if (this.outputContextFirst_) |
| 1453 this.ancestry_(node, prevNode, type, buff); | 1490 this.ancestry_(node, prevNode, type, buff); |
| 1454 var earcon = this.findEarcon_(node, prevNode); | 1491 var earcon = this.findEarcon_(node, prevNode); |
| 1455 if (earcon) | 1492 if (earcon) |
| 1456 options.annotation.push(earcon); | 1493 options.annotation.push(earcon); |
| 1457 this.append_(buff, range.start.getText().substring(startIndex, endIndex), | 1494 this.append_(buff, range.start.getText().substring(startIndex, endIndex), |
| 1458 options); | 1495 options); |
| 1459 if (!outputContextFirst) | 1496 if (!this.outputContextFirst_) |
| 1460 this.ancestry_(node, prevNode, type, buff); | 1497 this.ancestry_(node, prevNode, type, buff); |
| 1461 | 1498 |
| 1462 var loc = | 1499 var loc = |
| 1463 range.start.node.boundsForRange(startIndex, endIndex); | 1500 range.start.node.boundsForRange(startIndex, endIndex); |
| 1464 if (loc) | 1501 if (loc) |
| 1465 this.locations_.push(loc); | 1502 this.locations_.push(loc); |
| 1466 }, | 1503 }, |
| 1467 | 1504 |
| 1468 /** | 1505 /** |
| 1469 * Appends output to the |buff|. | 1506 * Appends output to the |buff|. |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1643 break; | 1680 break; |
| 1644 } | 1681 } |
| 1645 earconFinder = earconFinder.parent; | 1682 earconFinder = earconFinder.parent; |
| 1646 } | 1683 } |
| 1647 } | 1684 } |
| 1648 return null; | 1685 return null; |
| 1649 } | 1686 } |
| 1650 }; | 1687 }; |
| 1651 | 1688 |
| 1652 }); // goog.scope | 1689 }); // goog.scope |
| OLD | NEW |