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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
70 this.speechProperties_ = {}; | 70 this.speechProperties_ = {}; |
71 }; | 71 }; |
72 | 72 |
73 /** | 73 /** |
74 * Delimiter to use between output values. | 74 * Delimiter to use between output values. |
75 * @type {string} | 75 * @type {string} |
76 */ | 76 */ |
77 Output.SPACE = ' '; | 77 Output.SPACE = ' '; |
78 | 78 |
79 /** | 79 /** |
80 * Metadata about supported automation roles. | |
81 * @const {Object<string, {msgId: string, earcon: (string|undefined)}>} | |
82 */ | |
83 Output.ROLE_INFO = { | |
Peter Lundblad
2015/03/25 08:32:56
Why is this not private?
| |
84 alert: { | |
85 msgId: 'aria_role_alert', | |
86 earcon: 'ALERT_NONMODAL', | |
87 }, | |
88 button: { | |
89 msgId: 'tag_button', | |
90 earcon: 'BUTTON' | |
91 }, | |
92 checkbox: { | |
93 msgId: 'input_type_checkbox' | |
94 }, | |
95 heading: { | |
96 msgId: 'aria_role_heading', | |
97 }, | |
98 link: { | |
99 msgId: 'tag_link', | |
100 earcon: 'LINK' | |
101 }, | |
102 listItem: { | |
103 msgId: 'ARIA_ROLE_LISTITEM', | |
104 earcon: 'list_item' | |
105 }, | |
106 menuListOption: { | |
107 msgId: 'aria_role_menuitem' | |
108 }, | |
109 popUpButton: { | |
110 msgId: 'tag_button' | |
111 }, | |
112 radioButton: { | |
113 msgId: 'input_type_radio' | |
114 }, | |
115 textBox: { | |
116 msgId: 'input_type_text', | |
117 earcon: 'EDITABLE_TEXT' | |
118 }, | |
119 textField: { | |
120 msgId: 'input_type_text', | |
121 earcon: 'EDITABLE_TEXT' | |
122 }, | |
123 toolbar: { | |
124 msgId: 'aria_role_toolbar' | |
125 } | |
126 }; | |
127 | |
128 /** | |
80 * Rules specifying format of AutomationNodes for output. | 129 * Rules specifying format of AutomationNodes for output. |
81 * @type {!Object<string, Object<string, Object<string, string>>>} | 130 * @type {!Object<string, Object<string, Object<string, string>>>} |
82 */ | 131 */ |
83 Output.RULES = { | 132 Output.RULES = { |
84 navigate: { | 133 navigate: { |
85 'default': { | 134 'default': { |
86 speak: '$name $role $value', | 135 speak: '$name $role $value', |
87 braille: '' | 136 braille: '' |
88 }, | 137 }, |
89 alert: { | 138 alert: { |
90 speak: '!doNotInterrupt ' + | 139 speak: '!doNotInterrupt ' + |
91 '@aria_role_alert $name $earcon(ALERT_NONMODAL) $descendants' | 140 '@aria_role_alert $name $earcon(ALERT_NONMODAL) $descendants' |
92 }, | 141 }, |
93 button: { | |
94 speak: '$name $earcon(BUTTON, @tag_button)' | |
95 }, | |
96 checkBox: { | 142 checkBox: { |
97 speak: '$if($checked, @describe_checkbox_checked($name), ' + | 143 speak: '$if($checked, @describe_checkbox_checked($name), ' + |
98 '@describe_checkbox_unchecked($name)) ' + | 144 '@describe_checkbox_unchecked($name)) ' + |
99 '$if($checked, ' + | 145 '$if($checked, ' + |
100 '$earcon(CHECK_ON, @input_type_checkbox), ' + | 146 '$earcon(CHECK_ON, @input_type_checkbox), ' + |
101 '$earcon(CHECK_OFF, @input_type_checkbox))' | 147 '$earcon(CHECK_OFF, @input_type_checkbox))' |
102 }, | 148 }, |
103 dialog: { | 149 dialog: { |
104 enter: '$name $role' | 150 enter: '$name $role' |
105 }, | 151 }, |
106 heading: { | 152 heading: { |
107 enter: '@aria_role_heading', | 153 enter: '@aria_role_heading', |
108 speak: '@aria_role_heading $name=' | 154 speak: '@aria_role_heading $name=' |
109 }, | 155 }, |
110 inlineTextBox: { | 156 inlineTextBox: { |
111 speak: '$value=' | 157 speak: '$value=' |
112 }, | 158 }, |
113 link: { | 159 link: { |
114 enter: '$name= $visited $earcon(LINK, @tag_link)=', | 160 enter: '$name= $visited $earcon(LINK, @tag_link)=', |
115 stay: '$name= $visited @tag_link', | 161 stay: '$name= $visited @tag_link', |
116 speak: '$name= $visited $earcon(LINK, @tag_link)=' | 162 speak: '$name= $visited $earcon(LINK, @tag_link)=' |
117 }, | 163 }, |
118 list: { | 164 list: { |
119 enter: '$role' | 165 enter: '@aria_role_list @list_with_items($parentChildCount)' |
120 }, | 166 }, |
121 listItem: { | 167 listItem: { |
122 enter: '$role' | 168 enter: '$role' |
123 }, | 169 }, |
124 menuItem: { | 170 menuItem: { |
125 speak: '$if($haspopup, @describe_menu_item_with_submenu($name), ' + | 171 speak: '$if($haspopup, @describe_menu_item_with_submenu($name), ' + |
126 '@describe_menu_item($name)) ' + | 172 '@describe_menu_item($name)) ' + |
127 '@describe_index($indexInParent, $parentChildCount)' | 173 '@describe_index($indexInParent, $parentChildCount)' |
128 }, | 174 }, |
129 menuListOption: { | 175 menuListOption: { |
(...skipping 13 matching lines...) Expand all Loading... | |
143 '$if($checked, ' + | 189 '$if($checked, ' + |
144 '$earcon(CHECK_ON, @input_type_radio), ' + | 190 '$earcon(CHECK_ON, @input_type_radio), ' + |
145 '$earcon(CHECK_OFF, @input_type_radio))' | 191 '$earcon(CHECK_OFF, @input_type_radio))' |
146 }, | 192 }, |
147 slider: { | 193 slider: { |
148 speak: '@describe_slider($value, $name)' | 194 speak: '@describe_slider($value, $name)' |
149 }, | 195 }, |
150 staticText: { | 196 staticText: { |
151 speak: '$value' | 197 speak: '$value' |
152 }, | 198 }, |
153 textBox: { | |
154 speak: '$name $value $earcon(EDITABLE_TEXT, @input_type_text)' | |
155 }, | |
156 tab: { | 199 tab: { |
157 speak: '@describe_tab($name)' | 200 speak: '@describe_tab($name)' |
158 }, | 201 }, |
159 textField: { | |
160 speak: '$name $value $earcon(EDITABLE_TEXT, @input_type_text) $protected' | |
161 }, | |
162 toolbar: { | 202 toolbar: { |
163 enter: '$name $role' | 203 enter: '$name $role' |
164 }, | 204 }, |
165 window: { | 205 window: { |
166 enter: '$name', | 206 enter: '$name', |
167 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' | 207 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' |
168 } | 208 } |
169 }, | 209 }, |
170 menuStart: { | 210 menuStart: { |
171 'default': { | 211 'default': { |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 // Process token based on prefix. | 460 // Process token based on prefix. |
421 var prefix = token[0]; | 461 var prefix = token[0]; |
422 token = token.slice(1); | 462 token = token.slice(1); |
423 | 463 |
424 if (opt_exclude[token]) | 464 if (opt_exclude[token]) |
425 return; | 465 return; |
426 | 466 |
427 // All possible tokens based on prefix. | 467 // All possible tokens based on prefix. |
428 if (prefix == '$') { | 468 if (prefix == '$') { |
429 options.annotation = token; | 469 options.annotation = token; |
430 if (token == 'role') { | 470 if (token == 'value') { |
431 // Non-localized role and state obtained by default. | |
432 this.addToSpannable_(buff, node.role, options); | |
433 } else if (token == 'value') { | |
434 var text = node.attributes.value; | 471 var text = node.attributes.value; |
435 if (text) { | 472 if (text) { |
436 var offset = buff.getLength(); | 473 var offset = buff.getLength(); |
437 if (node.attributes.textSelStart !== undefined) { | 474 if (node.attributes.textSelStart !== undefined) { |
438 options.annotation = new Output.SelectionSpan( | 475 options.annotation = new Output.SelectionSpan( |
439 node.attributes.textSelStart, | 476 node.attributes.textSelStart, |
440 node.attributes.textSelEnd); | 477 node.attributes.textSelEnd); |
441 } | 478 } |
442 } else if (node.role == chrome.automation.RoleType.staticText) { | 479 } else if (node.role == chrome.automation.RoleType.staticText) { |
443 // TODO(dtseng): Remove once Blink treats staticText values as | 480 // TODO(dtseng): Remove once Blink treats staticText values as |
(...skipping 29 matching lines...) Expand all Loading... | |
473 node, Dir.FORWARD, AutomationPredicate.leaf); | 510 node, Dir.FORWARD, AutomationPredicate.leaf); |
474 var rightmost = AutomationUtil.findNodePre( | 511 var rightmost = AutomationUtil.findNodePre( |
475 node, Dir.BACKWARD, AutomationPredicate.leaf); | 512 node, Dir.BACKWARD, AutomationPredicate.leaf); |
476 if (!leftmost || !rightmost) | 513 if (!leftmost || !rightmost) |
477 return; | 514 return; |
478 | 515 |
479 var subrange = new cursors.Range( | 516 var subrange = new cursors.Range( |
480 new cursors.Cursor(leftmost, 0), | 517 new cursors.Cursor(leftmost, 0), |
481 new cursors.Cursor(rightmost, 0)); | 518 new cursors.Cursor(rightmost, 0)); |
482 this.range_(subrange, null, 'navigate', buff); | 519 this.range_(subrange, null, 'navigate', buff); |
520 } else if (token == 'role') { | |
521 var msg = node.role; | |
522 var earconId = null; | |
523 var info = Output.ROLE_INFO[node.role]; | |
524 if (info) { | |
525 if (this.formatOptions_.braille) | |
526 msg = cvox.ChromeVox.msgs.getMsg(info.msgId + '_brl'); | |
527 else | |
528 msg = cvox.ChromeVox.msgs.getMsg(info.msgId); | |
529 earconId = info.earcon; | |
530 } else { | |
531 console.error('Missing role info for ' + node.role); | |
532 } | |
533 if (earconId) { | |
534 options.annotation = new Output.Action(function() { | |
535 cvox.ChromeVox.earcons.playEarcon( | |
536 cvox.AbstractEarcons[earconId]); | |
537 }); | |
538 } | |
539 this.addToSpannable_(buff, msg, options); | |
483 } else if (node.attributes[token]) { | 540 } else if (node.attributes[token]) { |
484 this.addToSpannable_(buff, node.attributes[token], options); | 541 this.addToSpannable_(buff, node.attributes[token], options); |
485 } else if (node.state[token]) { | 542 } else if (node.state[token]) { |
486 this.addToSpannable_(buff, token, options); | 543 this.addToSpannable_(buff, token, options); |
487 } else if (tree.firstChild) { | 544 } else if (tree.firstChild) { |
488 // Custom functions. | 545 // Custom functions. |
489 if (token == 'if') { | 546 if (token == 'if') { |
490 var cond = tree.firstChild; | 547 var cond = tree.firstChild; |
491 var attrib = cond.value.slice(1); | 548 var attrib = cond.value.slice(1); |
492 if (node.attributes[attrib] || node.state[attrib]) | 549 if (node.attributes[attrib] || node.state[attrib]) |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
731 } | 788 } |
732 | 789 |
733 if (currentNode != root) | 790 if (currentNode != root) |
734 throw 'Unbalanced parenthesis.'; | 791 throw 'Unbalanced parenthesis.'; |
735 | 792 |
736 return root; | 793 return root; |
737 } | 794 } |
738 }; | 795 }; |
739 | 796 |
740 }); // goog.scope | 797 }); // goog.scope |
OLD | NEW |