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 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 |