| 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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 dialog: { | 99 dialog: { |
| 100 msgId: 'dialog' | 100 msgId: 'dialog' |
| 101 }, | 101 }, |
| 102 heading: { | 102 heading: { |
| 103 msgId: 'aria_role_heading', | 103 msgId: 'aria_role_heading', |
| 104 }, | 104 }, |
| 105 link: { | 105 link: { |
| 106 msgId: 'tag_link', | 106 msgId: 'tag_link', |
| 107 earcon: 'LINK' | 107 earcon: 'LINK' |
| 108 }, | 108 }, |
| 109 listBox: { |
| 110 msgId: 'aria_role_listbox', |
| 111 earcon: 'LISTBOX' |
| 112 }, |
| 113 listBoxOption: { |
| 114 msgId: 'aria_role_listitem', |
| 115 earcon: 'LIST_ITEM' |
| 116 }, |
| 109 listItem: { | 117 listItem: { |
| 110 msgId: 'ARIA_ROLE_LISTITEM', | 118 msgId: 'ARIA_ROLE_LISTITEM', |
| 111 earcon: 'list_item' | 119 earcon: 'list_item' |
| 112 }, | 120 }, |
| 121 menu: { |
| 122 msgId: 'aria_role_menu' |
| 123 }, |
| 124 menuItem: { |
| 125 msgId: 'aria_role_menuitem' |
| 126 }, |
| 113 menuListOption: { | 127 menuListOption: { |
| 114 msgId: 'aria_role_menuitem' | 128 msgId: 'aria_role_menuitem' |
| 115 }, | 129 }, |
| 130 menuListPopup: { |
| 131 msgId: 'aria_role_menu' |
| 132 }, |
| 116 popUpButton: { | 133 popUpButton: { |
| 117 msgId: 'tag_button' | 134 msgId: 'tag_button' |
| 118 }, | 135 }, |
| 119 radioButton: { | 136 radioButton: { |
| 120 msgId: 'input_type_radio' | 137 msgId: 'input_type_radio' |
| 121 }, | 138 }, |
| 122 spinButton: { | 139 spinButton: { |
| 123 msgId: 'aria_role_combobox', | 140 msgId: 'aria_role_combobox', |
| 124 earcon: 'LISTBOX' | 141 earcon: 'LISTBOX' |
| 125 }, | 142 }, |
| 126 textBox: { | 143 textBox: { |
| 127 msgId: 'input_type_text', | 144 msgId: 'input_type_text', |
| 128 earcon: 'EDITABLE_TEXT' | 145 earcon: 'EDITABLE_TEXT' |
| 129 }, | 146 }, |
| 130 textField: { | 147 textField: { |
| 131 msgId: 'input_type_text', | 148 msgId: 'input_type_text', |
| 132 earcon: 'EDITABLE_TEXT' | 149 earcon: 'EDITABLE_TEXT' |
| 133 }, | 150 }, |
| 134 time: { | 151 time: { |
| 135 msgId: 'tag_time' | 152 msgId: 'tag_time' |
| 136 }, | 153 }, |
| 137 toolbar: { | 154 toolbar: { |
| 138 msgId: 'aria_role_toolbar' | 155 msgId: 'aria_role_toolbar' |
| 156 }, |
| 157 tree: { |
| 158 msgId: 'aria_role_tree' |
| 159 }, |
| 160 treeItem: { |
| 161 msgId: 'aria_role_treeitem' |
| 139 } | 162 } |
| 140 }; | 163 }; |
| 141 | 164 |
| 142 /** | 165 /** |
| 143 * Metadata about supported automation states. | 166 * Metadata about supported automation states. |
| 144 * @const {!Object<string, | 167 * @const {!Object<string, |
| 145 * {on: {msgId: string, earconId: string}, | 168 * {on: {msgId: string, earconId: string}, |
| 146 * off: {msgId: string, earconId: string}}>} | 169 * off: {msgId: string, earconId: string}, |
| 170 * omitted: {msgId: string, earconId: string}}>} |
| 171 * on: info used to describe a state that is set to true. |
| 172 * off: info used to describe a state that is set to false. |
| 173 * omitted: info used to describe a state that is undefined. |
| 147 * @private | 174 * @private |
| 148 */ | 175 */ |
| 149 Output.STATE_INFO_ = { | 176 Output.STATE_INFO_ = { |
| 150 checked: { | 177 checked: { |
| 151 on: { | 178 on: { |
| 152 earconId: 'CHECK_ON', | 179 earconId: 'CHECK_ON', |
| 153 msgId: 'checkbox_checked_state' | 180 msgId: 'checkbox_checked_state' |
| 154 }, | 181 }, |
| 155 off: { | 182 off: { |
| 156 earconId: 'CHECK_OFF', | 183 earconId: 'CHECK_OFF', |
| 157 msgId: 'checkbox_unchecked_state' | 184 msgId: 'checkbox_unchecked_state' |
| 185 }, |
| 186 omitted: { |
| 187 earconId: 'CHECK_OFF', |
| 188 msgId: 'checkbox_unchecked_state' |
| 189 } |
| 190 }, |
| 191 collapsed: { |
| 192 on: { |
| 193 msgId: 'aria_expanded_false' |
| 194 }, |
| 195 off: { |
| 196 msgId: 'aria_expanded_true' |
| 197 } |
| 198 }, |
| 199 expanded: { |
| 200 on: { |
| 201 msgId: 'aria_expanded_true' |
| 202 }, |
| 203 off: { |
| 204 msgId: 'aria_expanded_false' |
| 158 } | 205 } |
| 159 } | 206 } |
| 160 }; | 207 }; |
| 161 | 208 |
| 162 /** | 209 /** |
| 163 * Rules specifying format of AutomationNodes for output. | 210 * Rules specifying format of AutomationNodes for output. |
| 164 * @type {!Object<string, Object<string, Object<string, string>>>} | 211 * @type {!Object<string, Object<string, Object<string, string>>>} |
| 165 */ | 212 */ |
| 166 Output.RULES = { | 213 Output.RULES = { |
| 167 navigate: { | 214 navigate: { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 188 }, | 235 }, |
| 189 inlineTextBox: { | 236 inlineTextBox: { |
| 190 speak: '$value=' | 237 speak: '$value=' |
| 191 }, | 238 }, |
| 192 link: { | 239 link: { |
| 193 enter: '$name $visited $role', | 240 enter: '$name $visited $role', |
| 194 stay: '$name= $visited $role', | 241 stay: '$name= $visited $role', |
| 195 speak: '$name= $visited $role' | 242 speak: '$name= $visited $role' |
| 196 }, | 243 }, |
| 197 list: { | 244 list: { |
| 198 enter: '@aria_role_list @list_with_items($parentChildCount)' | 245 enter: '$role @list_with_items($countChildren(listItem))' |
| 246 }, |
| 247 listBox: { |
| 248 enter: '$name $role @list_with_items($countChildren(listBoxOption))' |
| 249 }, |
| 250 listBoxOption: { |
| 251 speak: '$name $role @describe_index($indexInParent, $parentChildCount)' |
| 199 }, | 252 }, |
| 200 listItem: { | 253 listItem: { |
| 201 enter: '$role' | 254 enter: '$role' |
| 202 }, | 255 }, |
| 256 menu: { |
| 257 enter: '$name $role @list_with_items($countChildren(menuItem))' |
| 258 }, |
| 203 menuItem: { | 259 menuItem: { |
| 204 speak: '$if($haspopup, @describe_menu_item_with_submenu($name), ' + | 260 speak: '$if($haspopup, @describe_menu_item_with_submenu($name), ' + |
| 205 '@describe_menu_item($name)) ' + | 261 '@describe_menu_item($name)) ' + |
| 206 '@describe_index($indexInParent, $parentChildCount)' | 262 '@describe_index($indexInParent, $parentChildCount)' |
| 207 }, | 263 }, |
| 208 menuListOption: { | 264 menuListOption: { |
| 209 speak: '$name $value @aria_role_menuitem ' + | 265 speak: '$name $value @aria_role_menuitem ' + |
| 210 '@describe_index($indexInParent, $parentChildCount)' | 266 '@describe_index($indexInParent, $parentChildCount)' |
| 211 }, | 267 }, |
| 212 paragraph: { | 268 paragraph: { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 235 '$earcon(EDITABLE_TEXT)', | 291 '$earcon(EDITABLE_TEXT)', |
| 236 braille: '' | 292 braille: '' |
| 237 }, | 293 }, |
| 238 time: { | 294 time: { |
| 239 enter: '$name $role', | 295 enter: '$name $role', |
| 240 leave: '@exited_container($role)' | 296 leave: '@exited_container($role)' |
| 241 }, | 297 }, |
| 242 toolbar: { | 298 toolbar: { |
| 243 enter: '$name $role' | 299 enter: '$name $role' |
| 244 }, | 300 }, |
| 301 tree: { |
| 302 enter: '$name $role @list_with_items($countChildren(treeItem))' |
| 303 }, |
| 304 treeItem: { |
| 305 enter: '$role $expanded $collapsed ' + |
| 306 '@describe_index($indexInParent, $parentChildCount) ' + |
| 307 '@describe_depth($hierarchicalLevel)' |
| 308 }, |
| 245 window: { | 309 window: { |
| 246 enter: '$name', | 310 enter: '$name', |
| 247 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' | 311 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' |
| 248 } | 312 } |
| 249 }, | 313 }, |
| 250 menuStart: { | 314 menuStart: { |
| 251 'default': { | 315 'default': { |
| 252 speak: '@chrome_menu_opened($name) $earcon(OBJECT_OPEN)' | 316 speak: '@chrome_menu_opened($name) $earcon(OBJECT_OPEN)' |
| 253 } | 317 } |
| 254 }, | 318 }, |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 msg = cvox.ChromeVox.msgs.getMsg(info.msgId); | 685 msg = cvox.ChromeVox.msgs.getMsg(info.msgId); |
| 622 earconId = info.earcon; | 686 earconId = info.earcon; |
| 623 } else { | 687 } else { |
| 624 console.error('Missing role info for ' + node.role); | 688 console.error('Missing role info for ' + node.role); |
| 625 } | 689 } |
| 626 if (earconId) | 690 if (earconId) |
| 627 options.annotation.push(new Output.EarconAction(earconId)); | 691 options.annotation.push(new Output.EarconAction(earconId)); |
| 628 this.append_(buff, msg, options); | 692 this.append_(buff, msg, options); |
| 629 } else if (node.attributes[token] !== undefined) { | 693 } else if (node.attributes[token] !== undefined) { |
| 630 options.annotation.push(token); | 694 options.annotation.push(token); |
| 631 this.append_(buff, node.attributes[token], options); | 695 var value = node.attributes[token]; |
| 696 if (typeof value == 'number') |
| 697 value = String(value); |
| 698 this.append_(buff, value, options); |
| 632 } else if (Output.STATE_INFO_[token]) { | 699 } else if (Output.STATE_INFO_[token]) { |
| 633 options.annotation.push('state'); | 700 options.annotation.push('state'); |
| 634 var stateInfo = Output.STATE_INFO_[token]; | 701 var stateInfo = Output.STATE_INFO_[token]; |
| 635 var resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; | 702 var resolvedInfo = {}; |
| 636 options.annotation.push( | 703 if (node.state[token] === undefined) |
| 637 new Output.EarconAction(resolvedInfo.earconId)); | 704 resolvedInfo = stateInfo.omitted; |
| 705 else |
| 706 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; |
| 707 if (!resolvedInfo) |
| 708 return; |
| 709 if (resolvedInfo.earconId) { |
| 710 options.annotation.push( |
| 711 new Output.EarconAction(resolvedInfo.earconId)); |
| 712 } |
| 638 var msgId = | 713 var msgId = |
| 639 this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' : | 714 this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' : |
| 640 resolvedInfo.msgId; | 715 resolvedInfo.msgId; |
| 641 var msg = cvox.ChromeVox.msgs.getMsg(msgId); | 716 var msg = cvox.ChromeVox.msgs.getMsg(msgId); |
| 642 this.append_(buff, msg, options); | 717 this.append_(buff, msg, options); |
| 643 } else if (tree.firstChild) { | 718 } else if (tree.firstChild) { |
| 644 // Custom functions. | 719 // Custom functions. |
| 645 if (token == 'if') { | 720 if (token == 'if') { |
| 646 var cond = tree.firstChild; | 721 var cond = tree.firstChild; |
| 647 var attrib = cond.value.slice(1); | 722 var attrib = cond.value.slice(1); |
| 648 if (node.attributes[attrib] || node.state[attrib]) | 723 if (node.attributes[attrib] || node.state[attrib]) |
| 649 this.format_(node, cond.nextSibling, buff); | 724 this.format_(node, cond.nextSibling, buff); |
| 650 else | 725 else |
| 651 this.format_(node, cond.nextSibling.nextSibling, buff); | 726 this.format_(node, cond.nextSibling.nextSibling, buff); |
| 652 } else if (token == 'earcon') { | 727 } else if (token == 'earcon') { |
| 653 // Assumes there's existing output in our buffer. | 728 // Assumes there's existing output in our buffer. |
| 654 var lastBuff = buff[buff.length - 1]; | 729 var lastBuff = buff[buff.length - 1]; |
| 655 if (!lastBuff) | 730 if (!lastBuff) |
| 656 return; | 731 return; |
| 657 | 732 |
| 658 lastBuff.setSpan( | 733 lastBuff.setSpan( |
| 659 new Output.EarconAction(tree.firstChild.value), 0, 0); | 734 new Output.EarconAction(tree.firstChild.value), 0, 0); |
| 735 } else if (token == 'countChildren') { |
| 736 var role = tree.firstChild.value; |
| 737 var count = node.children.filter(function(e) { |
| 738 return e.role == role; |
| 739 }).length; |
| 740 this.append_(buff, String(count)); |
| 660 } | 741 } |
| 661 } | 742 } |
| 662 } else if (prefix == '@') { | 743 } else if (prefix == '@') { |
| 663 // Tokens can have substitutions. | 744 // Tokens can have substitutions. |
| 664 var pieces = token.split('+'); | 745 var pieces = token.split('+'); |
| 665 token = pieces.reduce(function(prev, cur) { | 746 token = pieces.reduce(function(prev, cur) { |
| 666 var lookup = cur; | 747 var lookup = cur; |
| 667 if (cur[0] == '$') | 748 if (cur[0] == '$') |
| 668 lookup = node.attributes[cur.slice(1)]; | 749 lookup = node.attributes[cur.slice(1)]; |
| 669 return prev + lookup; | 750 return prev + lookup; |
| 670 }.bind(this), ''); | 751 }.bind(this), ''); |
| 671 var msgId = token; | 752 var msgId = token; |
| 672 var msgArgs = []; | 753 var msgArgs = []; |
| 673 var curMsg = tree.firstChild; | 754 var curMsg = tree.firstChild; |
| 674 | 755 |
| 675 while (curMsg) { | 756 while (curMsg) { |
| 676 var arg = curMsg.value; | 757 var arg = curMsg.value; |
| 677 if (arg[0] != '$') { | 758 if (arg[0] != '$') { |
| 678 console.error('Unexpected value: ' + arg); | 759 console.error('Unexpected value: ' + arg); |
| 679 return; | 760 return; |
| 680 } | 761 } |
| 681 var msgBuff = []; | 762 var msgBuff = []; |
| 682 this.format_(node, arg, msgBuff); | 763 this.format_(node, curMsg, msgBuff); |
| 683 msgArgs = msgArgs.concat(msgBuff); | 764 msgArgs = msgArgs.concat(msgBuff); |
| 684 curMsg = curMsg.nextSibling; | 765 curMsg = curMsg.nextSibling; |
| 685 } | 766 } |
| 686 var msg = cvox.ChromeVox.msgs.getMsg(msgId, msgArgs); | 767 var msg = cvox.ChromeVox.msgs.getMsg(msgId, msgArgs); |
| 687 try { | 768 try { |
| 688 if (this.formatOptions_.braille) | 769 if (this.formatOptions_.braille) |
| 689 msg = cvox.ChromeVox.msgs.getMsg(msgId + '_brl', msgArgs) || msg; | 770 msg = cvox.ChromeVox.msgs.getMsg(msgId + '_brl', msgArgs) || msg; |
| 690 } catch(e) {} | 771 } catch(e) {} |
| 691 | 772 |
| 692 if (msg) { | 773 if (msg) { |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 904 } | 985 } |
| 905 | 986 |
| 906 if (currentNode != root) | 987 if (currentNode != root) |
| 907 throw 'Unbalanced parenthesis.'; | 988 throw 'Unbalanced parenthesis.'; |
| 908 | 989 |
| 909 return root; | 990 return root; |
| 910 } | 991 } |
| 911 }; | 992 }; |
| 912 | 993 |
| 913 }); // goog.scope | 994 }); // goog.scope |
| OLD | NEW |