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

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

Issue 1035983003: Split spoken feedback up on a per format rule basis. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 5 years, 9 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 msgId: 'aria_role_alert', 86 msgId: 'aria_role_alert',
87 earcon: 'ALERT_NONMODAL', 87 earcon: 'ALERT_NONMODAL',
88 }, 88 },
89 button: { 89 button: {
90 msgId: 'tag_button', 90 msgId: 'tag_button',
91 earcon: 'BUTTON' 91 earcon: 'BUTTON'
92 }, 92 },
93 checkbox: { 93 checkbox: {
94 msgId: 'input_type_checkbox' 94 msgId: 'input_type_checkbox'
95 }, 95 },
96 dialog: {
97 msgId: 'dialog'
98 },
96 heading: { 99 heading: {
97 msgId: 'aria_role_heading', 100 msgId: 'aria_role_heading',
98 }, 101 },
99 link: { 102 link: {
100 msgId: 'tag_link', 103 msgId: 'tag_link',
101 earcon: 'LINK' 104 earcon: 'LINK'
102 }, 105 },
103 listItem: { 106 listItem: {
104 msgId: 'ARIA_ROLE_LISTITEM', 107 msgId: 'ARIA_ROLE_LISTITEM',
105 earcon: 'list_item' 108 earcon: 'list_item'
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 toolbar: { 206 toolbar: {
204 enter: '$name $role' 207 enter: '$name $role'
205 }, 208 },
206 window: { 209 window: {
207 enter: '$name', 210 enter: '$name',
208 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' 211 speak: '@describe_window($name) $earcon(OBJECT_OPEN)'
209 } 212 }
210 }, 213 },
211 menuStart: { 214 menuStart: {
212 'default': { 215 'default': {
213 speak: '@chrome_menu_opened($name) $role $earcon(OBJECT_OPEN)' 216 speak: '@chrome_menu_opened($name) $earcon(OBJECT_OPEN)'
214 } 217 }
215 }, 218 },
216 menuEnd: { 219 menuEnd: {
217 'default': { 220 'default': {
218 speak: '$earcon(OBJECT_CLOSE)' 221 speak: '$earcon(OBJECT_CLOSE)'
219 } 222 }
220 }, 223 },
221 menuListValueChanged: { 224 menuListValueChanged: {
222 'default': { 225 'default': {
223 speak: '$value $name ' + 226 speak: '$value $name ' +
(...skipping 27 matching lines...) Expand all
251 this.action_ = action; 254 this.action_ = action;
252 }; 255 };
253 256
254 Output.Action.prototype = { 257 Output.Action.prototype = {
255 run: function() { 258 run: function() {
256 this.action_(); 259 this.action_();
257 } 260 }
258 }; 261 };
259 262
260 /** 263 /**
264 * Annotation for string splitting.
265 * @constructor
266 */
267 Output.StringSplit = function() {};
268
269 /**
261 * Annotation for selection. 270 * Annotation for selection.
262 * @param {number} startIndex 271 * @param {number} startIndex
263 * @param {number} endIndex 272 * @param {number} endIndex
264 * @constructor 273 * @constructor
265 */ 274 */
266 Output.SelectionSpan = function(startIndex, endIndex) { 275 Output.SelectionSpan = function(startIndex, endIndex) {
267 // TODO(dtseng): Direction lost below; should preserve for braille panning. 276 // TODO(dtseng): Direction lost below; should preserve for braille panning.
268 this.startIndex = startIndex < endIndex ? startIndex : endIndex; 277 this.startIndex = startIndex < endIndex ? startIndex : endIndex;
269 this.endIndex = endIndex > startIndex ? endIndex : startIndex; 278 this.endIndex = endIndex > startIndex ? endIndex : startIndex;
270 }; 279 };
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 return this; 352 return this;
344 }, 353 },
345 354
346 /** 355 /**
347 * Executes all specified output. 356 * Executes all specified output.
348 */ 357 */
349 go: function() { 358 go: function() {
350 // Speech. 359 // Speech.
351 var buff = this.buffer_; 360 var buff = this.buffer_;
352 if (buff.toString()) { 361 if (buff.toString()) {
353 if (this.speechStartCallback_) 362 var splits =
354 this.speechProperties_['startCallback'] = this.speechStartCallback_; 363 buff.getSpansInstanceOf(Output.StringSplit).map(function(split) {
355 if (this.speechEndCallback_) { 364 return buff.getSpanStart(split);
356 this.speechProperties_['endCallback'] = this.speechEndCallback_; 365 });
366
367 if (splits.length == 0) {
368 cvox.ChromeVox.tts.speak(buff.toString(),
369 cvox.QueueMode.FLUSH, this.speechProperties_);
370 } else {
371 var start = -1;
372 var seen = {};
373 splits = splits.filter(function(i) {
Peter Lundblad 2015/03/30 15:27:46 When are we going to have duplicates here?
374 if (seen[i])
375 return false;
376 seen[i] = true;
377 return true;
378 });
379 var queueMode = cvox.QueueMode.FLUSH;
380 do {
381 start++;
382 if (this.speechStartCallback_ && start == 0)
383 this.speechProperties_['startCallback'] = this.speechStartCallback_;
384 else
385 this.speechProperties_['startCallback'] = null;
386 if (this.speechEndCallback_ && start == splits.length - 1)
387 this.speechProperties_['endCallback'] = this.speechEndCallback_;
388 else
389 this.speechProperties_['endCallback'] = null;
390 var startIndex = splits[start];
391 var endIndex = splits[start + 1] || buff.getLength();
392
393 cvox.ChromeVox.tts.speak(buff.substring(startIndex,
394 endIndex).toString(), queueMode, this.speechProperties_);
395 queueMode = cvox.QueueMode.QUEUE;
396 } while (start < splits.length - 1);
357 } 397 }
358
359 cvox.ChromeVox.tts.speak(
360 buff.toString(), cvox.QueueMode.FLUSH, this.speechProperties_);
361 } 398 }
362 399
363 var actions = buff.getSpansInstanceOf(Output.Action); 400 var actions = buff.getSpansInstanceOf(Output.Action);
364 if (actions) { 401 if (actions) {
365 actions.forEach(function(a) { 402 actions.forEach(function(a) {
366 a.run(); 403 a.run();
367 }); 404 });
368 } 405 }
369 406
370 // Braille. 407 // Braille.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 466
430 // Hacky way to support args. 467 // Hacky way to support args.
431 if (typeof(format) == 'string') { 468 if (typeof(format) == 'string') {
432 format = format.replace(/([,:])\W/g, '$1'); 469 format = format.replace(/([,:])\W/g, '$1');
433 tokens = format.split(' '); 470 tokens = format.split(' ');
434 } else { 471 } else {
435 tokens = [format]; 472 tokens = [format];
436 } 473 }
437 474
438 tokens.forEach(function(token) { 475 tokens.forEach(function(token) {
476 // Always split at the beginning of each token for speech.
477 var splitOptions = {};
478 splitOptions.annotation = new Output.StringSplit();
479 this.addToSpannable_(buff, new cvox.Spannable(), splitOptions);
480
439 // Ignore empty tokens. 481 // Ignore empty tokens.
440 if (!token) 482 if (!token)
441 return; 483 return;
442 484
443 // Parse the token. 485 // Parse the token.
444 var tree; 486 var tree;
445 if (typeof(token) == 'string') 487 if (typeof(token) == 'string')
446 tree = this.createParseTree(token); 488 tree = this.createParseTree(token);
447 else 489 else
448 tree = token; 490 tree = token;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 }.bind(this); 657 }.bind(this);
616 658
617 while (cursor.getNode() != range.getEnd().getNode()) { 659 while (cursor.getNode() != range.getEnd().getNode()) {
618 var node = cursor.getNode(); 660 var node = cursor.getNode();
619 this.addToSpannable_( 661 this.addToSpannable_(
620 rangeBuff, formatNodeAndAncestors(node, prevNode)); 662 rangeBuff, formatNodeAndAncestors(node, prevNode));
621 prevNode = node; 663 prevNode = node;
622 cursor = cursor.move(cursors.Unit.NODE, 664 cursor = cursor.move(cursors.Unit.NODE,
623 cursors.Movement.DIRECTIONAL, 665 cursors.Movement.DIRECTIONAL,
624 Dir.FORWARD); 666 Dir.FORWARD);
667 var options = {};
668 options.annotation = new Output.StringSplit();
669 this.addToSpannable_(rangeBuff, new cvox.Spannable(), options);
625 } 670 }
626 var lastNode = range.getEnd().getNode(); 671 var lastNode = range.getEnd().getNode();
627 this.addToSpannable_(rangeBuff, formatNodeAndAncestors(lastNode, prevNode)); 672 this.addToSpannable_(rangeBuff, formatNodeAndAncestors(lastNode, prevNode));
628 }, 673 },
629 674
630 /** 675 /**
631 * @param {!chrome.automation.AutomationNode} node 676 * @param {!chrome.automation.AutomationNode} node
632 * @param {!chrome.automation.AutomationNode} prevNode 677 * @param {!chrome.automation.AutomationNode} prevNode
633 * @param {chrome.automation.EventType|string} type 678 * @param {chrome.automation.EventType|string} type
634 * @param {!cvox.Spannable} buff 679 * @param {!cvox.Spannable} buff
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
720 if (startIndex === endIndex) 765 if (startIndex === endIndex)
721 endIndex++; 766 endIndex++;
722 this.addToSpannable_( 767 this.addToSpannable_(
723 buff, range.getStart().getText().substring(startIndex, endIndex)); 768 buff, range.getStart().getText().substring(startIndex, endIndex));
724 }, 769 },
725 770
726 /** 771 /**
727 * Adds to the given buffer with proper delimiters added. 772 * Adds to the given buffer with proper delimiters added.
728 * @param {!cvox.Spannable} spannable 773 * @param {!cvox.Spannable} spannable
729 * @param {string|!cvox.Spannable} value 774 * @param {string|!cvox.Spannable} value
730 * @param {{ifEmpty: boolean, 775 * @param {{ifEmpty: (boolean|undefined),
731 * annotation: (string|Output.Action|undefined)}=} opt_options 776 * annotation: *}=} opt_options
732 */ 777 */
733 addToSpannable_: function(spannable, value, opt_options) { 778 addToSpannable_: function(spannable, value, opt_options) {
734 opt_options = opt_options || {ifEmpty: false, annotation: undefined}; 779 opt_options = opt_options || {ifEmpty: false, annotation: undefined};
735 if ((!value || value.length == 0) && !opt_options.annotation) 780 if ((!value || value.length == 0) && !opt_options.annotation)
736 return; 781 return;
737 782
738 var spannableToAdd = new cvox.Spannable(value, opt_options.annotation); 783 var spannableToAdd = new cvox.Spannable(value, opt_options.annotation);
739 if (spannable.getLength() == 0) { 784 if (spannable.getLength() == 0) {
740 spannable.append(spannableToAdd); 785 spannable.append(spannableToAdd);
741 return; 786 return;
742 } 787 }
743 788
744 if (opt_options.ifEmpty && 789 if (opt_options.ifEmpty &&
745 opt_options.annotation && 790 opt_options.annotation &&
746 (spannable.getSpanStart(opt_options.annotation) != undefined || 791 (spannable.getSpanStart(opt_options.annotation) != undefined ||
747 spannable.getSpanStart( 792 spannable.getSpanStart(
748 Output.ATTRIBUTE_ALIAS[opt_options.annotation]) != undefined)) 793 Output.ATTRIBUTE_ALIAS[opt_options.annotation]) != undefined))
749 return; 794 return;
750 795
751 var prefixed = new cvox.Spannable(Output.SPACE); 796 // Figure out if we need to add the spacing prefix.
797 var needsPrefix = this.formatOptions_.braille;
798 if (needsPrefix) {
Peter Lundblad 2015/03/30 15:27:46 Indentation.
799 needsPrefix = value instanceof cvox.Spannable ?
800 value.getLength() > 0 : value.length > 0;
801 }
802 var prefixed = new cvox.Spannable(needsPrefix ? Output.SPACE : '');
752 prefixed.append(spannableToAdd); 803 prefixed.append(spannableToAdd);
753 spannable.append(prefixed); 804 spannable.append(prefixed);
754 }, 805 },
755 806
756 /** 807 /**
757 * Parses the token containing a custom function and returns a tree. 808 * Parses the token containing a custom function and returns a tree.
758 * @param {string} inputStr 809 * @param {string} inputStr
759 * @return {Object} 810 * @return {Object}
760 */ 811 */
761 createParseTree: function(inputStr) { 812 createParseTree: function(inputStr) {
(...skipping 25 matching lines...) Expand all
787 } 838 }
788 839
789 if (currentNode != root) 840 if (currentNode != root)
790 throw 'Unbalanced parenthesis.'; 841 throw 'Unbalanced parenthesis.';
791 842
792 return root; 843 return root;
793 } 844 }
794 }; 845 };
795 846
796 }); // goog.scope 847 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698