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

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

Issue 2132123002: Complete table support in ChromeVox Next. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Ignore some roles. Created 4 years, 5 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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698