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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
147 speak: '$if($checked, @describe_checkbox_checked($name), ' + | 147 speak: '$if($checked, @describe_checkbox_checked($name), ' + |
148 '@describe_checkbox_unchecked($name)) ' + | 148 '@describe_checkbox_unchecked($name)) ' + |
149 '$if($checked, ' + | 149 '$if($checked, ' + |
150 '$earcon(CHECK_ON, @input_type_checkbox), ' + | 150 '$earcon(CHECK_ON, @input_type_checkbox), ' + |
151 '$earcon(CHECK_OFF, @input_type_checkbox))' | 151 '$earcon(CHECK_OFF, @input_type_checkbox))' |
152 }, | 152 }, |
153 dialog: { | 153 dialog: { |
154 enter: '$name $role' | 154 enter: '$name $role' |
155 }, | 155 }, |
156 heading: { | 156 heading: { |
157 enter: '@aria_role_heading', | 157 enter: '@aria_role_heading -$hierarchicalLevel', |
Peter Lundblad
2015/04/02 09:43:54
Need to add this prefix to the documentation in th
| |
158 speak: '@aria_role_heading $name=' | 158 speak: '@aria_role_heading -$hierarchicalLevel $name=' |
159 }, | 159 }, |
160 inlineTextBox: { | 160 inlineTextBox: { |
161 speak: '$value=' | 161 speak: '$value=' |
162 }, | 162 }, |
163 link: { | 163 link: { |
164 enter: '$name= $visited $earcon(LINK, @tag_link)=', | 164 enter: '$name= $visited $earcon(LINK, @tag_link)=', |
165 stay: '$name= $visited @tag_link', | 165 stay: '$name= $visited @tag_link', |
166 speak: '$name= $visited $earcon(LINK, @tag_link)=' | 166 speak: '$name= $visited $earcon(LINK, @tag_link)=' |
167 }, | 167 }, |
168 list: { | 168 list: { |
169 enter: '@aria_role_list @list_with_items($parentChildCount)' | 169 enter: '@aria_role_list -@list_with_items($parentChildCount)' |
170 }, | 170 }, |
171 listItem: { | 171 listItem: { |
172 enter: '$role' | 172 enter: '$role' |
173 }, | 173 }, |
174 menuItem: { | 174 menuItem: { |
175 speak: '$if($haspopup, @describe_menu_item_with_submenu($name), ' + | 175 speak: '$if($haspopup, @describe_menu_item_with_submenu($name), ' + |
176 '@describe_menu_item($name)) ' + | 176 '@describe_menu_item($name)) ' + |
177 '@describe_index($indexInParent, $parentChildCount)' | 177 '@describe_index($indexInParent, $parentChildCount)' |
178 }, | 178 }, |
179 menuListOption: { | 179 menuListOption: { |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
466 | 466 |
467 // Hacky way to support args. | 467 // Hacky way to support args. |
468 if (typeof(format) == 'string') { | 468 if (typeof(format) == 'string') { |
469 format = format.replace(/([,:])\W/g, '$1'); | 469 format = format.replace(/([,:])\W/g, '$1'); |
470 tokens = format.split(' '); | 470 tokens = format.split(' '); |
471 } else { | 471 } else { |
472 tokens = [format]; | 472 tokens = [format]; |
473 } | 473 } |
474 | 474 |
475 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 | |
481 // Ignore empty tokens. | 476 // Ignore empty tokens. |
482 if (!token) | 477 if (!token) |
483 return; | 478 return; |
484 | 479 |
485 // Parse the token. | 480 // Parse the token. |
486 var tree; | 481 var tree; |
487 if (typeof(token) == 'string') | 482 if (typeof(token) == 'string') |
488 tree = this.createParseTree(token); | 483 tree = this.createParseTree(token); |
489 else | 484 else |
490 tree = token; | 485 tree = token; |
491 | 486 |
492 // Obtain the operator token. | 487 // Obtain the operator token. |
493 token = tree.value; | 488 token = tree.value; |
494 | 489 |
495 // Set suffix options. | 490 // Set suffix options. |
496 var options = {}; | 491 var options = {}; |
497 options.ifEmpty = token[token.length - 1] == '='; | 492 options.ifEmpty = token[token.length - 1] == '='; |
498 if (options.ifEmpty) | 493 if (options.ifEmpty) |
499 token = token.substring(0, token.length - 1); | 494 token = token.substring(0, token.length - 1); |
500 | 495 |
501 // Process token based on prefix. | 496 // Process token based on prefix. |
502 var prefix = token[0]; | 497 var prefix = token[0]; |
503 token = token.slice(1); | 498 token = token.slice(1); |
504 | 499 |
500 // Split up the utterance if there isn't a continuation prefix. | |
501 if (prefix == '-') { | |
Peter Lundblad
2015/04/02 09:43:54
There's an implicit ordering of prefixes here. Sh
David Tseng
2015/04/02 23:50:49
You're probably right. I can take a look at some j
| |
502 prefix = token[0]; | |
503 token = token.slice(1); | |
504 options.needsPrefix = true; | |
505 } else { | |
506 var splitOptions = {}; | |
507 splitOptions.annotation = new Output.StringSplit(); | |
508 this.addToSpannable_(buff, new cvox.Spannable(), splitOptions); | |
509 } | |
510 | |
505 if (opt_exclude[token]) | 511 if (opt_exclude[token]) |
506 return; | 512 return; |
507 | 513 |
508 // All possible tokens based on prefix. | 514 // All possible tokens based on prefix. |
509 if (prefix == '$') { | 515 if (prefix == '$') { |
510 options.annotation = token; | 516 options.annotation = token; |
511 if (token == 'value') { | 517 if (token == 'value') { |
512 var text = node.attributes.value; | 518 var text = node.attributes.value; |
513 if (text !== undefined) { | 519 if (text !== undefined) { |
514 var offset = buff.getLength(); | 520 var offset = buff.getLength(); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
572 console.error('Missing role info for ' + node.role); | 578 console.error('Missing role info for ' + node.role); |
573 } | 579 } |
574 if (earconId) { | 580 if (earconId) { |
575 options.annotation = new Output.Action(function() { | 581 options.annotation = new Output.Action(function() { |
576 cvox.ChromeVox.earcons.playEarcon( | 582 cvox.ChromeVox.earcons.playEarcon( |
577 cvox.AbstractEarcons[earconId]); | 583 cvox.AbstractEarcons[earconId]); |
578 }); | 584 }); |
579 } | 585 } |
580 this.addToSpannable_(buff, msg, options); | 586 this.addToSpannable_(buff, msg, options); |
581 } else if (node.attributes[token]) { | 587 } else if (node.attributes[token]) { |
582 this.addToSpannable_(buff, node.attributes[token], options); | 588 var value = node.attributes[token]; |
589 if (typeof(value) != 'string') | |
590 value = String(value); | |
591 this.addToSpannable_(buff, value, options); | |
583 } else if (node.state[token]) { | 592 } else if (node.state[token]) { |
584 this.addToSpannable_(buff, token, options); | 593 this.addToSpannable_(buff, token, options); |
585 } else if (tree.firstChild) { | 594 } else if (tree.firstChild) { |
586 // Custom functions. | 595 // Custom functions. |
587 if (token == 'if') { | 596 if (token == 'if') { |
588 var cond = tree.firstChild; | 597 var cond = tree.firstChild; |
589 var attrib = cond.value.slice(1); | 598 var attrib = cond.value.slice(1); |
590 if (node.attributes[attrib] || node.state[attrib]) | 599 if (node.attributes[attrib] || node.state[attrib]) |
591 this.format_(node, cond.nextSibling, buff); | 600 this.format_(node, cond.nextSibling, buff); |
592 else | 601 else |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
766 endIndex++; | 775 endIndex++; |
767 this.addToSpannable_( | 776 this.addToSpannable_( |
768 buff, range.getStart().getText().substring(startIndex, endIndex)); | 777 buff, range.getStart().getText().substring(startIndex, endIndex)); |
769 }, | 778 }, |
770 | 779 |
771 /** | 780 /** |
772 * Adds to the given buffer with proper delimiters added. | 781 * Adds to the given buffer with proper delimiters added. |
773 * @param {!cvox.Spannable} spannable | 782 * @param {!cvox.Spannable} spannable |
774 * @param {string|!cvox.Spannable} value | 783 * @param {string|!cvox.Spannable} value |
775 * @param {{ifEmpty: (boolean|undefined), | 784 * @param {{ifEmpty: (boolean|undefined), |
776 * annotation: *}=} opt_options | 785 * annotation: *, |
786 * needsPrefix: (boolean|undefined)}=} opt_options | |
777 */ | 787 */ |
778 addToSpannable_: function(spannable, value, opt_options) { | 788 addToSpannable_: function(spannable, value, opt_options) { |
779 opt_options = opt_options || {ifEmpty: false, annotation: undefined}; | 789 opt_options = opt_options || |
790 {ifEmpty: false, annotation: undefined, needsPrefix: false}; | |
780 if ((!value || value.length == 0) && !opt_options.annotation) | 791 if ((!value || value.length == 0) && !opt_options.annotation) |
781 return; | 792 return; |
782 | 793 |
783 var spannableToAdd = new cvox.Spannable(value, opt_options.annotation); | 794 var spannableToAdd = new cvox.Spannable(value, opt_options.annotation); |
784 if (spannable.getLength() == 0) { | 795 if (spannable.getLength() == 0) { |
785 spannable.append(spannableToAdd); | 796 spannable.append(spannableToAdd); |
786 return; | 797 return; |
787 } | 798 } |
788 | 799 |
789 if (opt_options.ifEmpty && | 800 if (opt_options.ifEmpty && |
790 opt_options.annotation && | 801 opt_options.annotation && |
791 (spannable.getSpanStart(opt_options.annotation) != undefined || | 802 (spannable.getSpanStart(opt_options.annotation) != undefined || |
792 spannable.getSpanStart( | 803 spannable.getSpanStart( |
793 Output.ATTRIBUTE_ALIAS[opt_options.annotation]) != undefined)) | 804 Output.ATTRIBUTE_ALIAS[opt_options.annotation]) != undefined)) |
794 return; | 805 return; |
795 | 806 |
796 // Figure out if we need to add the spacing prefix. | 807 // Figure out if we need to add the spacing prefix. |
797 var needsPrefix = this.formatOptions_.braille; | 808 var needsPrefix = this.formatOptions_.braille || opt_options.needsPrefix; |
798 if (needsPrefix) { | 809 if (needsPrefix) { |
799 needsPrefix = value instanceof cvox.Spannable ? | 810 needsPrefix = value instanceof cvox.Spannable ? |
800 value.getLength() > 0 : value.length > 0; | 811 value.getLength() > 0 : value.length > 0; |
801 } | 812 } |
802 var prefixed = new cvox.Spannable(needsPrefix ? Output.SPACE : ''); | 813 var prefixed = new cvox.Spannable(needsPrefix ? Output.SPACE : ''); |
803 prefixed.append(spannableToAdd); | 814 prefixed.append(spannableToAdd); |
804 spannable.append(prefixed); | 815 spannable.append(prefixed); |
805 }, | 816 }, |
806 | 817 |
807 /** | 818 /** |
(...skipping 30 matching lines...) Expand all Loading... | |
838 } | 849 } |
839 | 850 |
840 if (currentNode != root) | 851 if (currentNode != root) |
841 throw 'Unbalanced parenthesis.'; | 852 throw 'Unbalanced parenthesis.'; |
842 | 853 |
843 return root; | 854 return root; |
844 } | 855 } |
845 }; | 856 }; |
846 | 857 |
847 }); // goog.scope | 858 }); // goog.scope |
OLD | NEW |