| 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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 * earconId: (string|undefined), | 108 * earconId: (string|undefined), |
| 109 * inherits: (string|undefined), | 109 * inherits: (string|undefined), |
| 110 * outputContextFirst: (boolean|undefined)}>} | 110 * outputContextFirst: (boolean|undefined)}>} |
| 111 * msgId: the message id of the role. | 111 * msgId: the message id of the role. |
| 112 * earconId: an optional earcon to play when encountering the role. | 112 * earconId: an optional earcon to play when encountering the role. |
| 113 * inherits: inherits rules from this role. | 113 * inherits: inherits rules from this role. |
| 114 * outputContextFirst: where to place the context output. | 114 * outputContextFirst: where to place the context output. |
| 115 * @private | 115 * @private |
| 116 */ | 116 */ |
| 117 Output.ROLE_INFO_ = { | 117 Output.ROLE_INFO_ = { |
| 118 alert: { | 118 alert: {msgId: 'role_alert'}, |
| 119 msgId: 'role_alert' | 119 alertDialog: {msgId: 'role_alertdialog', outputContextFirst: true}, |
| 120 }, | 120 article: {msgId: 'role_article', inherits: 'abstractContainer'}, |
| 121 alertDialog: { | 121 application: {msgId: 'role_application', inherits: 'abstractContainer'}, |
| 122 msgId: 'role_alertdialog', | 122 banner: {msgId: 'role_banner', inherits: 'abstractContainer'}, |
| 123 outputContextFirst: true | 123 button: {msgId: 'role_button', earconId: 'BUTTON'}, |
| 124 }, | 124 buttonDropDown: {msgId: 'role_button', earconId: 'BUTTON'}, |
| 125 article: { | 125 checkBox: {msgId: 'role_checkbox'}, |
| 126 msgId: 'role_article', | 126 columnHeader: {msgId: 'role_columnheader', inherits: 'cell'}, |
| 127 inherits: 'abstractContainer' | 127 comboBox: {msgId: 'role_combobox', earconId: 'LISTBOX'}, |
| 128 }, | 128 complementary: {msgId: 'role_complementary', inherits: 'abstractContainer'}, |
| 129 application: { | 129 contentInfo: {msgId: 'role_contentinfo', inherits: 'abstractContainer'}, |
| 130 msgId: 'role_application', | 130 date: {msgId: 'input_type_date', inherits: 'abstractContainer'}, |
| 131 inherits: 'abstractContainer' | 131 definition: {msgId: 'role_definition', inherits: 'abstractContainer'}, |
| 132 }, | 132 dialog: {msgId: 'role_dialog', outputContextFirst: true}, |
| 133 banner: { | 133 directory: {msgId: 'role_directory', inherits: 'abstractContainer'}, |
| 134 msgId: 'role_banner', | 134 document: {msgId: 'role_document', inherits: 'abstractContainer'}, |
| 135 inherits: 'abstractContainer' | 135 form: {msgId: 'role_form', inherits: 'abstractContainer'}, |
| 136 }, | 136 grid: {msgId: 'role_grid'}, |
| 137 button: { | 137 group: {msgId: 'role_group', inherits: 'abstractContainer'}, |
| 138 msgId: 'role_button', | |
| 139 earconId: 'BUTTON' | |
| 140 }, | |
| 141 buttonDropDown: { | |
| 142 msgId: 'role_button', | |
| 143 earconId: 'BUTTON' | |
| 144 }, | |
| 145 checkBox: { | |
| 146 msgId: 'role_checkbox' | |
| 147 }, | |
| 148 columnHeader: { | |
| 149 msgId: 'role_columnheader', | |
| 150 inherits: 'cell' | |
| 151 }, | |
| 152 comboBox: { | |
| 153 msgId: 'role_combobox', | |
| 154 earconId: 'LISTBOX' | |
| 155 }, | |
| 156 complementary: { | |
| 157 msgId: 'role_complementary', | |
| 158 inherits: 'abstractContainer' | |
| 159 }, | |
| 160 contentInfo: { | |
| 161 msgId: 'role_contentinfo', | |
| 162 inherits: 'abstractContainer' | |
| 163 }, | |
| 164 date: { | |
| 165 msgId: 'input_type_date', | |
| 166 inherits: 'abstractContainer' | |
| 167 }, | |
| 168 definition: { | |
| 169 msgId: 'role_definition', | |
| 170 inherits: 'abstractContainer' | |
| 171 }, | |
| 172 dialog: { | |
| 173 msgId: 'role_dialog', | |
| 174 outputContextFirst: true | |
| 175 }, | |
| 176 directory: { | |
| 177 msgId: 'role_directory', | |
| 178 inherits: 'abstractContainer' | |
| 179 }, | |
| 180 document: { | |
| 181 msgId: 'role_document', | |
| 182 inherits: 'abstractContainer' | |
| 183 }, | |
| 184 form: { | |
| 185 msgId: 'role_form', | |
| 186 inherits: 'abstractContainer' | |
| 187 }, | |
| 188 grid: { | |
| 189 msgId: 'role_grid' | |
| 190 }, | |
| 191 group: { | |
| 192 msgId: 'role_group', | |
| 193 inherits: 'abstractContainer' | |
| 194 }, | |
| 195 heading: { | 138 heading: { |
| 196 msgId: 'role_heading', | 139 msgId: 'role_heading', |
| 197 }, | 140 }, |
| 198 image: { | 141 image: { |
| 199 msgId: 'role_img', | 142 msgId: 'role_img', |
| 200 }, | 143 }, |
| 201 inputTime: { | 144 inputTime: {msgId: 'input_type_time', inherits: 'abstractContainer'}, |
| 202 msgId: 'input_type_time', | 145 link: {msgId: 'role_link', earconId: 'LINK'}, |
| 203 inherits: 'abstractContainer' | 146 listBox: {msgId: 'role_listbox', earconId: 'LISTBOX'}, |
| 204 }, | 147 listBoxOption: {msgId: 'role_listitem', earconId: 'LIST_ITEM'}, |
| 205 link: { | 148 listItem: {msgId: 'role_listitem', earconId: 'LIST_ITEM'}, |
| 206 msgId: 'role_link', | |
| 207 earconId: 'LINK' | |
| 208 }, | |
| 209 listBox: { | |
| 210 msgId: 'role_listbox', | |
| 211 earconId: 'LISTBOX' | |
| 212 }, | |
| 213 listBoxOption: { | |
| 214 msgId: 'role_listitem', | |
| 215 earconId: 'LIST_ITEM' | |
| 216 }, | |
| 217 listItem: { | |
| 218 msgId: 'role_listitem', | |
| 219 earconId: 'LIST_ITEM' | |
| 220 }, | |
| 221 log: { | 149 log: { |
| 222 msgId: 'role_log', | 150 msgId: 'role_log', |
| 223 }, | 151 }, |
| 224 main: { | 152 main: {msgId: 'role_main', inherits: 'abstractContainer'}, |
| 225 msgId: 'role_main', | |
| 226 inherits: 'abstractContainer' | |
| 227 }, | |
| 228 marquee: { | 153 marquee: { |
| 229 msgId: 'role_marquee', | 154 msgId: 'role_marquee', |
| 230 }, | 155 }, |
| 231 math: { | 156 math: {msgId: 'role_math', inherits: 'abstractContainer'}, |
| 232 msgId: 'role_math', | 157 menu: {msgId: 'role_menu', outputContextFirst: true}, |
| 233 inherits: 'abstractContainer' | |
| 234 }, | |
| 235 menu: { | |
| 236 msgId: 'role_menu', | |
| 237 outputContextFirst: true | |
| 238 }, | |
| 239 menuBar: { | 158 menuBar: { |
| 240 msgId: 'role_menubar', | 159 msgId: 'role_menubar', |
| 241 }, | 160 }, |
| 242 menuItem: { | 161 menuItem: {msgId: 'role_menuitem'}, |
| 243 msgId: 'role_menuitem' | 162 menuItemCheckBox: {msgId: 'role_menuitemcheckbox'}, |
| 244 }, | 163 menuItemRadio: {msgId: 'role_menuitemradio'}, |
| 245 menuItemCheckBox: { | 164 menuListOption: {msgId: 'role_menuitem'}, |
| 246 msgId: 'role_menuitemcheckbox' | 165 menuListPopup: {msgId: 'role_menu'}, |
| 247 }, | 166 meter: {msgId: 'role_meter', inherits: 'abstractRange'}, |
| 248 menuItemRadio: { | 167 navigation: {msgId: 'role_navigation', inherits: 'abstractContainer'}, |
| 249 msgId: 'role_menuitemradio' | 168 note: {msgId: 'role_note', inherits: 'abstractContainer'}, |
| 250 }, | 169 progressIndicator: |
| 251 menuListOption: { | 170 {msgId: 'role_progress_indicator', inherits: 'abstractRange'}, |
| 252 msgId: 'role_menuitem' | 171 popUpButton: {msgId: 'role_button', earconId: 'POP_UP_BUTTON'}, |
| 253 }, | 172 radioButton: {msgId: 'role_radio'}, |
| 254 menuListPopup: { | |
| 255 msgId: 'role_menu' | |
| 256 }, | |
| 257 meter: { | |
| 258 msgId: 'role_meter', | |
| 259 inherits: 'abstractRange' | |
| 260 }, | |
| 261 navigation: { | |
| 262 msgId: 'role_navigation', | |
| 263 inherits: 'abstractContainer' | |
| 264 }, | |
| 265 note: { | |
| 266 msgId: 'role_note', | |
| 267 inherits: 'abstractContainer' | |
| 268 }, | |
| 269 progressIndicator: { | |
| 270 msgId: 'role_progress_indicator', | |
| 271 inherits: 'abstractRange' | |
| 272 }, | |
| 273 popUpButton: { | |
| 274 msgId: 'role_button', | |
| 275 earconId: 'POP_UP_BUTTON' | |
| 276 }, | |
| 277 radioButton: { | |
| 278 msgId: 'role_radio' | |
| 279 }, | |
| 280 radioGroup: { | 173 radioGroup: { |
| 281 msgId: 'role_radiogroup', | 174 msgId: 'role_radiogroup', |
| 282 }, | 175 }, |
| 283 rootWebArea: { | 176 rootWebArea: {outputContextFirst: true}, |
| 284 outputContextFirst: true | 177 row: {msgId: 'role_row', inherits: 'abstractContainer'}, |
| 285 }, | 178 rowHeader: {msgId: 'role_rowheader', inherits: 'cell'}, |
| 286 row: { | 179 scrollBar: {msgId: 'role_scrollbar', inherits: 'abstractRange'}, |
| 287 msgId: 'role_row', | 180 search: {msgId: 'role_search', inherits: 'abstractContainer'}, |
| 288 inherits: 'abstractContainer' | 181 separator: {msgId: 'role_separator', inherits: 'abstractContainer'}, |
| 289 }, | 182 slider: {msgId: 'role_slider', inherits: 'abstractRange', earconId: 'SLIDER'}, |
| 290 rowHeader: { | |
| 291 msgId: 'role_rowheader', | |
| 292 inherits: 'cell' | |
| 293 }, | |
| 294 scrollBar: { | |
| 295 msgId: 'role_scrollbar', | |
| 296 inherits: 'abstractRange' | |
| 297 }, | |
| 298 search: { | |
| 299 msgId: 'role_search', | |
| 300 inherits: 'abstractContainer' | |
| 301 }, | |
| 302 separator: { | |
| 303 msgId: 'role_separator', | |
| 304 inherits: 'abstractContainer' | |
| 305 }, | |
| 306 slider: { | |
| 307 msgId: 'role_slider', | |
| 308 inherits: 'abstractRange', | |
| 309 earconId: 'SLIDER' | |
| 310 }, | |
| 311 spinButton: { | 183 spinButton: { |
| 312 msgId: 'role_spinbutton', | 184 msgId: 'role_spinbutton', |
| 313 inherits: 'abstractRange', | 185 inherits: 'abstractRange', |
| 314 earconId: 'LISTBOX' | 186 earconId: 'LISTBOX' |
| 315 }, | 187 }, |
| 316 status: { | 188 status: {msgId: 'role_status'}, |
| 317 msgId: 'role_status' | 189 tab: {msgId: 'role_tab'}, |
| 318 }, | 190 tabList: {msgId: 'role_tablist'}, |
| 319 tab: { | 191 tabPanel: {msgId: 'role_tabpanel'}, |
| 320 msgId: 'role_tab' | 192 textBox: {msgId: 'input_type_text', earconId: 'EDITABLE_TEXT'}, |
| 321 }, | 193 textField: {msgId: 'input_type_text', earconId: 'EDITABLE_TEXT'}, |
| 322 tabList: { | 194 time: {msgId: 'tag_time', inherits: 'abstractContainer'}, |
| 323 msgId: 'role_tablist' | 195 timer: {msgId: 'role_timer'}, |
| 324 }, | 196 toolbar: {msgId: 'role_toolbar'}, |
| 325 tabPanel: { | 197 toggleButton: {msgId: 'role_button', inherits: 'checkBox'}, |
| 326 msgId: 'role_tabpanel' | 198 tree: {msgId: 'role_tree'}, |
| 327 }, | 199 treeItem: {msgId: 'role_treeitem'} |
| 328 textBox: { | |
| 329 msgId: 'input_type_text', | |
| 330 earconId: 'EDITABLE_TEXT' | |
| 331 }, | |
| 332 textField: { | |
| 333 msgId: 'input_type_text', | |
| 334 earconId: 'EDITABLE_TEXT' | |
| 335 }, | |
| 336 time: { | |
| 337 msgId: 'tag_time', | |
| 338 inherits: 'abstractContainer' | |
| 339 }, | |
| 340 timer: { | |
| 341 msgId: 'role_timer' | |
| 342 }, | |
| 343 toolbar: { | |
| 344 msgId: 'role_toolbar' | |
| 345 }, | |
| 346 toggleButton: { | |
| 347 msgId: 'role_button', | |
| 348 inherits: 'checkBox' | |
| 349 }, | |
| 350 tree: { | |
| 351 msgId: 'role_tree' | |
| 352 }, | |
| 353 treeItem: { | |
| 354 msgId: 'role_treeitem' | |
| 355 } | |
| 356 }; | 200 }; |
| 357 | 201 |
| 358 /** | 202 /** |
| 359 * Metadata about supported automation states. | 203 * Metadata about supported automation states. |
| 360 * @const {!Object<string, {on: {msgId: string, earconId: string}, | 204 * @const {!Object<string, {on: {msgId: string, earconId: string}, |
| 361 * off: {msgId: string, earconId: string}, | 205 * off: {msgId: string, earconId: string}, |
| 362 * isRoleSpecific: (boolean|undefined)}>} | 206 * isRoleSpecific: (boolean|undefined)}>} |
| 363 * on: info used to describe a state that is set to true. | 207 * on: info used to describe a state that is set to true. |
| 364 * off: info used to describe a state that is set to undefined. | 208 * off: info used to describe a state that is set to undefined. |
| 365 * isRoleSpecific: info used for specific roles. | 209 * isRoleSpecific: info used for specific roles. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 'false': 'aria_pressed_false', | 257 'false': 'aria_pressed_false', |
| 414 'mixed': 'aria_pressed_mixed' | 258 'mixed': 'aria_pressed_mixed' |
| 415 }; | 259 }; |
| 416 | 260 |
| 417 /** | 261 /** |
| 418 * Rules specifying format of AutomationNodes for output. | 262 * Rules specifying format of AutomationNodes for output. |
| 419 * @type {!Object<Object<Object<string>>>} | 263 * @type {!Object<Object<Object<string>>>} |
| 420 */ | 264 */ |
| 421 Output.RULES = { | 265 Output.RULES = { |
| 422 navigate: { | 266 navigate: { |
| 423 'default': { | 267 'default': {speak: '$name $value $state $role $description', braille: ''}, |
| 424 speak: '$name $value $state $role $description', | |
| 425 braille: '' | |
| 426 }, | |
| 427 abstractContainer: { | 268 abstractContainer: { |
| 428 enter: '$nameFromNode $role $state $description', | 269 enter: '$nameFromNode $role $state $description', |
| 429 leave: '@exited_container($role)' | 270 leave: '@exited_container($role)' |
| 430 }, | 271 }, |
| 431 abstractRange: { | 272 abstractRange: { |
| 432 speak: | 273 speak: '$if($valueForRange, $valueForRange, $value) ' + |
| 433 '$if($valueForRange, $valueForRange, $value) ' + | |
| 434 '$if($minValueForRange, @aria_value_min($minValueForRange)) ' + | 274 '$if($minValueForRange, @aria_value_min($minValueForRange)) ' + |
| 435 '$if($maxValueForRange, @aria_value_max($maxValueForRange)) ' + | 275 '$if($maxValueForRange, @aria_value_max($maxValueForRange)) ' + |
| 436 '$name $role $description $state' | 276 '$name $role $description $state' |
| 437 }, | 277 }, |
| 438 alert: { | 278 alert: { |
| 439 enter: '$name $role $state', | 279 enter: '$name $role $state', |
| 440 speak: '$earcon(ALERT_NONMODAL) $role $nameOrTextContent $state' | 280 speak: '$earcon(ALERT_NONMODAL) $role $nameOrTextContent $state' |
| 441 }, | 281 }, |
| 442 alertDialog: { | 282 alertDialog: { |
| 443 enter: '$earcon(ALERT_MODAL) $name $state', | 283 enter: '$earcon(ALERT_MODAL) $name $state', |
| 444 speak: '$earcon(ALERT_MODAL) $name $nameOrTextContent $state $role' | 284 speak: '$earcon(ALERT_MODAL) $name $nameOrTextContent $state $role' |
| 445 }, | 285 }, |
| 446 cell: { | 286 cell: { |
| 447 enter: '@cell_summary($if($ariaCellRowIndex, $ariaCellRowIndex, ' + | 287 enter: '@cell_summary($if($ariaCellRowIndex, $ariaCellRowIndex, ' + |
| 448 '$tableCellRowIndex), ' + | 288 '$tableCellRowIndex), ' + |
| 449 '$if($ariaCellColumnIndex, $ariaCellColumnIndex, ' + | 289 '$if($ariaCellColumnIndex, $ariaCellColumnIndex, ' + |
| 450 '$tableCellColumnIndex)) $node(tableColumnHeader)', | 290 '$tableCellColumnIndex)) $node(tableColumnHeader)', |
| 451 speak: '$name @cell_summary($if($ariaCellRowIndex, $ariaCellRowIndex, ' + | 291 speak: '$name @cell_summary($if($ariaCellRowIndex, $ariaCellRowIndex, ' + |
| 452 '$tableCellRowIndex), ' + | 292 '$tableCellRowIndex), ' + |
| 453 '$if($ariaCellColumnIndex, $ariaCellColumnIndex, ' + | 293 '$if($ariaCellColumnIndex, $ariaCellColumnIndex, ' + |
| 454 '$tableCellColumnIndex)) $node(tableColumnHeader) $state' | 294 '$tableCellColumnIndex)) $node(tableColumnHeader) $state' |
| 455 }, | 295 }, |
| 456 checkBox: { | 296 checkBox: { |
| 457 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 297 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 458 '$name $role $checked $description $state' | 298 '$name $role $checked $description $state' |
| 459 }, | 299 }, |
| 460 client: { | 300 client: {speak: '$name'}, |
| 461 speak: '$name' | 301 date: {enter: '$nameFromNode $role $description'}, |
| 462 }, | 302 dialog: {enter: '$nameFromNode $role $description'}, |
| 463 date: { | 303 genericContainer: |
| 464 enter: '$nameFromNode $role $description' | 304 {enter: '$nameFromNode', speak: '$nameOrTextContent $description'}, |
| 465 }, | 305 embeddedObject: {speak: '$name'}, |
| 466 dialog: { | 306 grid: {enter: '$nameFromNode $role $description'}, |
| 467 enter: '$nameFromNode $role $description' | |
| 468 }, | |
| 469 genericContainer: { | |
| 470 enter: '$nameFromNode', | |
| 471 speak: '$nameOrTextContent $description' | |
| 472 }, | |
| 473 embeddedObject: { | |
| 474 speak: '$name' | |
| 475 }, | |
| 476 grid: { | |
| 477 enter: '$nameFromNode $role $description' | |
| 478 }, | |
| 479 group: { | 307 group: { |
| 480 enter: '$nameFromNode $state $description', | 308 enter: '$nameFromNode $state $description', |
| 481 speak: '$nameOrDescendants $value $state $description', | 309 speak: '$nameOrDescendants $value $state $description', |
| 482 leave: '' | 310 leave: '' |
| 483 }, | 311 }, |
| 484 heading: { | 312 heading: { |
| 485 enter: '!relativePitch(hierarchicalLevel) ' + | 313 enter: '!relativePitch(hierarchicalLevel) ' + |
| 486 '$nameFromNode= ' + | 314 '$nameFromNode= ' + |
| 487 '$if($hierarchicalLevel, @tag_h+$hierarchicalLevel, $role) $state', | 315 '$if($hierarchicalLevel, @tag_h+$hierarchicalLevel, $role) $state', |
| 488 speak: '!relativePitch(hierarchicalLevel) ' + | 316 speak: '!relativePitch(hierarchicalLevel) ' + |
| 489 '$nameOrDescendants= ' + | 317 '$nameOrDescendants= ' + |
| 490 '$if($hierarchicalLevel, @tag_h+$hierarchicalLevel, $role) $state' | 318 '$if($hierarchicalLevel, @tag_h+$hierarchicalLevel, $role) $state' |
| 491 }, | 319 }, |
| 492 image: { | 320 image: { |
| 493 speak: '$if($name, $name, $urlFilename) ' + | 321 speak: '$if($name, $name, $urlFilename) ' + |
| 494 '$value $state $role $description', | 322 '$value $state $role $description', |
| 495 }, | 323 }, |
| 496 inlineTextBox: { | 324 inlineTextBox: {speak: '$name='}, |
| 497 speak: '$name=' | 325 inputTime: {enter: '$nameFromNode $role $description'}, |
| 498 }, | |
| 499 inputTime: { | |
| 500 enter: '$nameFromNode $role $description' | |
| 501 }, | |
| 502 link: { | 326 link: { |
| 503 enter: '$nameFromNode= $role $state', | 327 enter: '$nameFromNode= $role $state', |
| 504 speak: '$name $value $state ' + | 328 speak: '$name $value $state ' + |
| 505 '$if($inPageLinkTarget, @internal_link, $role) $description', | 329 '$if($inPageLinkTarget, @internal_link, $role) $description', |
| 506 }, | 330 }, |
| 507 list: { | 331 list: { |
| 508 enter: '$role @@list_with_items($countChildren(listItem))', | 332 enter: '$role @@list_with_items($countChildren(listItem))', |
| 509 speak: '$descendants $role @@list_with_items($countChildren(listItem))' | 333 speak: '$descendants $role @@list_with_items($countChildren(listItem))' |
| 510 }, | 334 }, |
| 511 listBox: { | 335 listBox: { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 538 menuItemRadio: { | 362 menuItemRadio: { |
| 539 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 363 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 540 '$if($checked, @describe_radio_selected($name), ' + | 364 '$if($checked, @describe_radio_selected($name), ' + |
| 541 '@describe_radio_unselected($name)) $description ' + | 365 '@describe_radio_unselected($name)) $description ' + |
| 542 '@describe_index($indexInParent, $parentChildCount) ' | 366 '@describe_index($indexInParent, $parentChildCount) ' |
| 543 }, | 367 }, |
| 544 menuListOption: { | 368 menuListOption: { |
| 545 speak: '$name @role_menuitem ' + | 369 speak: '$name @role_menuitem ' + |
| 546 '@describe_index($indexInParent, $parentChildCount) $description' | 370 '@describe_index($indexInParent, $parentChildCount) $description' |
| 547 }, | 371 }, |
| 548 paragraph: { | 372 paragraph: {speak: '$descendants'}, |
| 549 speak: '$descendants' | |
| 550 }, | |
| 551 popUpButton: { | 373 popUpButton: { |
| 552 speak: '$value $name $role @aria_has_popup ' + | 374 speak: '$value $name $role @aria_has_popup ' + |
| 553 '$state $description' | 375 '$state $description' |
| 554 }, | 376 }, |
| 555 radioButton: { | 377 radioButton: { |
| 556 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 378 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 557 '$if($checked, @describe_radio_selected($name), ' + | 379 '$if($checked, @describe_radio_selected($name), ' + |
| 558 '@describe_radio_unselected($name)) $description' | 380 '@describe_radio_unselected($name)) $description' |
| 559 }, | 381 }, |
| 560 radioGroup: { | 382 radioGroup: {enter: '$name $role $description'}, |
| 561 enter: '$name $role $description' | 383 rootWebArea: {enter: '$name', speak: '$if($name, $name, $docUrl)'}, |
| 562 }, | 384 region: {speak: '$nameOrTextContent'}, |
| 563 rootWebArea: { | 385 row: {enter: '$node(tableRowHeader)'}, |
| 564 enter: '$name', | 386 rowHeader: {speak: '$nameOrTextContent $state'}, |
| 565 speak: '$if($name, $name, $docUrl)' | 387 staticText: {speak: '$name='}, |
| 566 }, | |
| 567 region: { | |
| 568 speak: '$nameOrTextContent' | |
| 569 }, | |
| 570 row: { | |
| 571 enter: '$node(tableRowHeader)' | |
| 572 }, | |
| 573 rowHeader: { | |
| 574 speak: '$nameOrTextContent $state' | |
| 575 }, | |
| 576 staticText: { | |
| 577 speak: '$name=' | |
| 578 }, | |
| 579 switch: { | 388 switch: { |
| 580 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 389 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 581 '$if($checked, @describe_switch_on($name), ' + | 390 '$if($checked, @describe_switch_on($name), ' + |
| 582 '@describe_switch_off($name)) $description $state' | 391 '@describe_switch_off($name)) $description $state' |
| 583 }, | 392 }, |
| 584 tab: { | 393 tab: { |
| 585 speak: '@describe_tab($name) $state $description ' + | 394 speak: '@describe_tab($name) $state $description ' + |
| 586 '$if($setSize, @describe_index($posInSet, $setSize))', | 395 '$if($setSize, @describe_index($posInSet, $setSize))', |
| 587 }, | 396 }, |
| 588 table: { | 397 table: { |
| 589 enter: '@table_summary($name, ' + | 398 enter: '@table_summary($name, ' + |
| 590 '$if($ariaRowCount, $ariaRowCount, $tableRowCount), ' + | 399 '$if($ariaRowCount, $ariaRowCount, $tableRowCount), ' + |
| 591 '$if($ariaColumnCount, $ariaColumnCount, $tableColumnCount)) ' + | 400 '$if($ariaColumnCount, $ariaColumnCount, $tableColumnCount)) ' + |
| 592 '$node(tableHeader)' | 401 '$node(tableHeader)' |
| 593 }, | 402 }, |
| 594 tableHeaderContainer: { | 403 tableHeaderContainer: {speak: '$nameOrTextContent $state $description'}, |
| 595 speak: '$nameOrTextContent $state $description' | |
| 596 }, | |
| 597 textField: { | 404 textField: { |
| 598 speak: '$name $value $if($multiline, @tag_textarea, $if(' + | 405 speak: '$name $value $if($multiline, @tag_textarea, $if(' + |
| 599 '$inputType, $inputType, $role)) $description $state', | 406 '$inputType, $inputType, $role)) $description $state', |
| 600 braille: '' | 407 braille: '' |
| 601 }, | 408 }, |
| 602 timer: { | 409 timer: {speak: '$nameFromNode $descendants $value $state $description'}, |
| 603 speak: '$nameFromNode $descendants $value $state $description' | |
| 604 }, | |
| 605 toggleButton: { | 410 toggleButton: { |
| 606 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + | 411 speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' + |
| 607 '$name $role $pressed $description $state' | 412 '$name $role $pressed $description $state' |
| 608 }, | 413 }, |
| 609 toolbar: { | 414 toolbar: {enter: '$name $role $description'}, |
| 610 enter: '$name $role $description' | 415 tree: {enter: '$name $role @@list_with_items($countChildren(treeItem))'}, |
| 611 }, | |
| 612 tree: { | |
| 613 enter: '$name $role @@list_with_items($countChildren(treeItem))' | |
| 614 }, | |
| 615 treeItem: { | 416 treeItem: { |
| 616 enter: '$role $expanded $collapsed ' + | 417 enter: '$role $expanded $collapsed ' + |
| 617 '@describe_index($indexInParent, $parentChildCount) ' + | 418 '@describe_index($indexInParent, $parentChildCount) ' + |
| 618 '@describe_depth($hierarchicalLevel)', | 419 '@describe_depth($hierarchicalLevel)', |
| 619 speak: '$name ' + | 420 speak: '$name ' + |
| 620 '$role $state ' + | 421 '$role $state ' + |
| 621 '@describe_index($indexInParent, $parentChildCount) ' + | 422 '@describe_index($indexInParent, $parentChildCount) ' + |
| 622 '@describe_depth($hierarchicalLevel)' | 423 '@describe_depth($hierarchicalLevel)' |
| 623 }, | 424 }, |
| 624 window: { | 425 window: { |
| 625 enter: '@describe_window($name)', | 426 enter: '@describe_window($name)', |
| 626 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' | 427 speak: '@describe_window($name) $earcon(OBJECT_OPEN)' |
| 627 } | 428 } |
| 628 }, | 429 }, |
| 629 menuStart: { | 430 menuStart: |
| 630 'default': { | 431 {'default': {speak: '@chrome_menu_opened($name) $earcon(OBJECT_OPEN)'}}, |
| 631 speak: '@chrome_menu_opened($name) $earcon(OBJECT_OPEN)' | 432 menuEnd: {'default': {speak: '@chrome_menu_closed $earcon(OBJECT_CLOSE)'}}, |
| 632 } | |
| 633 }, | |
| 634 menuEnd: { | |
| 635 'default': { | |
| 636 speak: '@chrome_menu_closed $earcon(OBJECT_CLOSE)' | |
| 637 } | |
| 638 }, | |
| 639 menuListValueChanged: { | 433 menuListValueChanged: { |
| 640 'default': { | 434 'default': { |
| 641 speak: '$value $name ' + | 435 speak: '$value $name ' + |
| 642 '$find({"state": {"selected": true, "invisible": false}}, ' + | 436 '$find({"state": {"selected": true, "invisible": false}}, ' + |
| 643 '@describe_index($indexInParent, $parentChildCount)) ' | 437 '@describe_index($indexInParent, $parentChildCount)) ' |
| 644 } | 438 } |
| 645 }, | 439 }, |
| 646 alert: { | 440 alert: { |
| 647 default: { | 441 default: { |
| 648 speak: '$earcon(ALERT_NONMODAL) @role_alert ' + | 442 speak: '$earcon(ALERT_NONMODAL) @role_alert ' + |
| 649 '$nameOrTextContent $description' | 443 '$nameOrTextContent $description' |
| 650 } | 444 } |
| 651 } | 445 } |
| 652 }; | 446 }; |
| 653 | 447 |
| 654 /** | 448 /** |
| 655 * Used to annotate utterances with speech properties. | 449 * Used to annotate utterances with speech properties. |
| 656 * @constructor | 450 * @constructor |
| 657 */ | 451 */ |
| 658 Output.SpeechProperties = function() {}; | 452 Output.SpeechProperties = function() {}; |
| 659 | 453 |
| 660 /** | 454 /** |
| 661 * Custom actions performed while rendering an output string. | 455 * Custom actions performed while rendering an output string. |
| 662 * @constructor | 456 * @constructor |
| 663 */ | 457 */ |
| 664 Output.Action = function() { | 458 Output.Action = function() {}; |
| 665 }; | |
| 666 | 459 |
| 667 Output.Action.prototype = { | 460 Output.Action.prototype = { |
| 668 run: function() { | 461 run: function() {} |
| 669 } | |
| 670 }; | 462 }; |
| 671 | 463 |
| 672 /** | 464 /** |
| 673 * Action to play an earcon. | 465 * Action to play an earcon. |
| 674 * @param {string} earconId | 466 * @param {string} earconId |
| 675 * @param {chrome.automation.Rect=} opt_location | 467 * @param {chrome.automation.Rect=} opt_location |
| 676 * @constructor | 468 * @constructor |
| 677 * @extends {Output.Action} | 469 * @extends {Output.Action} |
| 678 */ | 470 */ |
| 679 Output.EarconAction = function(earconId, opt_location) { | 471 Output.EarconAction = function(earconId, opt_location) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 * queueing mode. | 527 * queueing mode. |
| 736 * @type {cvox.QueueMode|undefined} | 528 * @type {cvox.QueueMode|undefined} |
| 737 * @private | 529 * @private |
| 738 */ | 530 */ |
| 739 Output.forceModeForNextSpeechUtterance_; | 531 Output.forceModeForNextSpeechUtterance_; |
| 740 | 532 |
| 741 /** | 533 /** |
| 742 * Calling this will make the next speech utterance use |mode| even if it would | 534 * Calling this will make the next speech utterance use |mode| even if it would |
| 743 * normally queue or do a category flush. This differs from the |withQueueMode| | 535 * normally queue or do a category flush. This differs from the |withQueueMode| |
| 744 * instance method as it can apply to future output. | 536 * instance method as it can apply to future output. |
| 745 * @param {cvox.QueueMode} mode | 537 * @param {cvox.QueueMode} mode |
| 746 */ | 538 */ |
| 747 Output.forceModeForNextSpeechUtterance = function(mode) { | 539 Output.forceModeForNextSpeechUtterance = function(mode) { |
| 748 Output.forceModeForNextSpeechUtterance_ = mode; | 540 Output.forceModeForNextSpeechUtterance_ = mode; |
| 749 }; | 541 }; |
| 750 | 542 |
| 751 /** | 543 /** |
| 752 * For a given automation property, return true if the value | 544 * For a given automation property, return true if the value |
| 753 * represents something 'truthy', e.g.: for checked: | 545 * represents something 'truthy', e.g.: for checked: |
| 754 * 'true'|'mixed' -> true | 546 * 'true'|'mixed' -> true |
| 755 * 'false'|undefined -> false | 547 * 'false'|undefined -> false |
| 756 */ | 548 */ |
| 757 Output.isTruthy = function(node, attrib) { | 549 Output.isTruthy = function(node, attrib) { |
| 758 switch(attrib) { | 550 switch (attrib) { |
| 759 case 'checked': | 551 case 'checked': |
| 760 return node.checked && node.checked !== 'false'; | 552 return node.checked && node.checked !== 'false'; |
| 761 default: | 553 default: |
| 762 return node[attrib] !== undefined || node.state[attrib]; | 554 return node[attrib] !== undefined || node.state[attrib]; |
| 763 } | 555 } |
| 764 }; | 556 }; |
| 765 | 557 |
| 766 Output.prototype = { | 558 Output.prototype = { |
| 767 /** | 559 /** |
| 768 * @return {boolean} True if there's any speech that will be output. | 560 * @return {boolean} True if there's any speech that will be output. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 781 * @param {cursors.Range} prevRange | 573 * @param {cursors.Range} prevRange |
| 782 * @param {EventType|Output.EventType} type | 574 * @param {EventType|Output.EventType} type |
| 783 * @return {!Output} | 575 * @return {!Output} |
| 784 */ | 576 */ |
| 785 withSpeech: function(range, prevRange, type) { | 577 withSpeech: function(range, prevRange, type) { |
| 786 this.formatOptions_ = {speech: true, braille: false, auralStyle: false}; | 578 this.formatOptions_ = {speech: true, braille: false, auralStyle: false}; |
| 787 this.render_(range, prevRange, type, this.speechBuffer_); | 579 this.render_(range, prevRange, type, this.speechBuffer_); |
| 788 return this; | 580 return this; |
| 789 }, | 581 }, |
| 790 | 582 |
| 791 /** | 583 /** |
| 792 * Specify ranges for aurally styled speech. | 584 * Specify ranges for aurally styled speech. |
| 793 * @param {!cursors.Range} range | 585 * @param {!cursors.Range} range |
| 794 * @param {cursors.Range} prevRange | 586 * @param {cursors.Range} prevRange |
| 795 * @param {EventType|Output.EventType} type | 587 * @param {EventType|Output.EventType} type |
| 796 * @return {!Output} | 588 * @return {!Output} |
| 797 */ | 589 */ |
| 798 withRichSpeech: function(range, prevRange, type) { | 590 withRichSpeech: function(range, prevRange, type) { |
| 799 this.formatOptions_ = {speech: true, braille: false, auralStyle: true}; | 591 this.formatOptions_ = {speech: true, braille: false, auralStyle: true}; |
| 800 this.render_(range, prevRange, type, this.speechBuffer_); | 592 this.render_(range, prevRange, type, this.speechBuffer_); |
| 801 return this; | 593 return this; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 833 * @param {cursors.Range} prevRange | 625 * @param {cursors.Range} prevRange |
| 834 * @param {EventType|Output.EventType} type | 626 * @param {EventType|Output.EventType} type |
| 835 * @return {!Output} | 627 * @return {!Output} |
| 836 */ | 628 */ |
| 837 withSpeechAndBraille: function(range, prevRange, type) { | 629 withSpeechAndBraille: function(range, prevRange, type) { |
| 838 this.withSpeech(range, prevRange, type); | 630 this.withSpeech(range, prevRange, type); |
| 839 this.withBraille(range, prevRange, type); | 631 this.withBraille(range, prevRange, type); |
| 840 return this; | 632 return this; |
| 841 }, | 633 }, |
| 842 | 634 |
| 843 /** | 635 /** |
| 844 * Specify the same ranges for aurally styled speech and braille. | 636 * Specify the same ranges for aurally styled speech and braille. |
| 845 * @param {!cursors.Range} range | 637 * @param {!cursors.Range} range |
| 846 * @param {cursors.Range} prevRange | 638 * @param {cursors.Range} prevRange |
| 847 * @param {EventType|Output.EventType} type | 639 * @param {EventType|Output.EventType} type |
| 848 * @return {!Output} | 640 * @return {!Output} |
| 849 */ | 641 */ |
| 850 withRichSpeechAndBraille: function(range, prevRange, type) { | 642 withRichSpeechAndBraille: function(range, prevRange, type) { |
| 851 this.withRichSpeech(range, prevRange, type); | 643 this.withRichSpeech(range, prevRange, type); |
| 852 this.withBraille(range, prevRange, type); | 644 this.withBraille(range, prevRange, type); |
| 853 return this; | 645 return this; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 896 | 688 |
| 897 /** | 689 /** |
| 898 * Apply a format string directly to the output buffer. This lets you | 690 * Apply a format string directly to the output buffer. This lets you |
| 899 * output a message directly to the buffer using the format syntax. | 691 * output a message directly to the buffer using the format syntax. |
| 900 * @param {string} formatStr | 692 * @param {string} formatStr |
| 901 * @param {!AutomationNode=} opt_node An optional node to apply the | 693 * @param {!AutomationNode=} opt_node An optional node to apply the |
| 902 * formatting to. | 694 * formatting to. |
| 903 * @return {!Output} |this| for chaining | 695 * @return {!Output} |this| for chaining |
| 904 */ | 696 */ |
| 905 format: function(formatStr, opt_node) { | 697 format: function(formatStr, opt_node) { |
| 906 return this | 698 return this.formatForSpeech(formatStr, opt_node) |
| 907 .formatForSpeech(formatStr, opt_node) | |
| 908 .formatForBraille(formatStr, opt_node); | 699 .formatForBraille(formatStr, opt_node); |
| 909 }, | 700 }, |
| 910 | 701 |
| 911 /** | 702 /** |
| 912 * Apply a format string directly to the speech output buffer. This lets you | 703 * Apply a format string directly to the speech output buffer. This lets you |
| 913 * output a message directly to the buffer using the format syntax. | 704 * output a message directly to the buffer using the format syntax. |
| 914 * @param {string} formatStr | 705 * @param {string} formatStr |
| 915 * @param {!AutomationNode=} opt_node An optional node to apply the | 706 * @param {!AutomationNode=} opt_node An optional node to apply the |
| 916 * formatting to. | 707 * formatting to. |
| 917 * @return {!Output} |this| for chaining | 708 * @return {!Output} |this| for chaining |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 963 if (Output.forceModeForNextSpeechUtterance_ !== undefined) | 754 if (Output.forceModeForNextSpeechUtterance_ !== undefined) |
| 964 queueMode = Output.forceModeForNextSpeechUtterance_; | 755 queueMode = Output.forceModeForNextSpeechUtterance_; |
| 965 else if (this.queueMode_ !== undefined) | 756 else if (this.queueMode_ !== undefined) |
| 966 queueMode = this.queueMode_; | 757 queueMode = this.queueMode_; |
| 967 | 758 |
| 968 if (this.speechBuffer_.length > 0) | 759 if (this.speechBuffer_.length > 0) |
| 969 Output.forceModeForNextSpeechUtterance_ = undefined; | 760 Output.forceModeForNextSpeechUtterance_ = undefined; |
| 970 | 761 |
| 971 for (var i = 0; i < this.speechBuffer_.length; i++) { | 762 for (var i = 0; i < this.speechBuffer_.length; i++) { |
| 972 var buff = this.speechBuffer_[i]; | 763 var buff = this.speechBuffer_[i]; |
| 973 var speechProps = /** @type {Object} */( | 764 var speechProps = /** @type {Object} */ ( |
| 974 buff.getSpanInstanceOf(Output.SpeechProperties)) || {}; | 765 buff.getSpanInstanceOf(Output.SpeechProperties)) || |
| 766 {}; |
| 975 | 767 |
| 976 speechProps.category = this.speechCategory_; | 768 speechProps.category = this.speechCategory_; |
| 977 | 769 |
| 978 (function() { | 770 (function() { |
| 979 var scopedBuff = buff; | 771 var scopedBuff = buff; |
| 980 speechProps['startCallback'] = function() { | 772 speechProps['startCallback'] = function() { |
| 981 var actions = scopedBuff.getSpansInstanceOf(Output.Action); | 773 var actions = scopedBuff.getSpansInstanceOf(Output.Action); |
| 982 if (actions) { | 774 if (actions) { |
| 983 actions.forEach(function(a) { | 775 actions.forEach(function(a) { |
| 984 a.run(); | 776 a.run(); |
| 985 }); | 777 }); |
| 986 } | 778 } |
| 987 }; | 779 }; |
| 988 }()); | 780 }()); |
| 989 | 781 |
| 990 if (i == this.speechBuffer_.length - 1) | 782 if (i == this.speechBuffer_.length - 1) |
| 991 speechProps['endCallback'] = this.speechEndCallback_; | 783 speechProps['endCallback'] = this.speechEndCallback_; |
| 992 | 784 |
| 993 cvox.ChromeVox.tts.speak( | 785 cvox.ChromeVox.tts.speak(buff.toString(), queueMode, speechProps); |
| 994 buff.toString(), queueMode, speechProps); | |
| 995 queueMode = cvox.QueueMode.QUEUE; | 786 queueMode = cvox.QueueMode.QUEUE; |
| 996 } | 787 } |
| 997 | 788 |
| 998 // Braille. | 789 // Braille. |
| 999 if (this.brailleBuffer_.length) { | 790 if (this.brailleBuffer_.length) { |
| 1000 var buff = this.mergeBraille_(this.brailleBuffer_); | 791 var buff = this.mergeBraille_(this.brailleBuffer_); |
| 1001 var selSpan = | 792 var selSpan = buff.getSpanInstanceOf(Output.SelectionSpan); |
| 1002 buff.getSpanInstanceOf(Output.SelectionSpan); | |
| 1003 var startIndex = -1, endIndex = -1; | 793 var startIndex = -1, endIndex = -1; |
| 1004 if (selSpan) { | 794 if (selSpan) { |
| 1005 var valueStart = buff.getSpanStart(selSpan); | 795 var valueStart = buff.getSpanStart(selSpan); |
| 1006 var valueEnd = buff.getSpanEnd(selSpan); | 796 var valueEnd = buff.getSpanEnd(selSpan); |
| 1007 startIndex = valueStart + selSpan.startIndex; | 797 startIndex = valueStart + selSpan.startIndex; |
| 1008 endIndex = valueStart + selSpan.endIndex; | 798 endIndex = valueStart + selSpan.endIndex; |
| 1009 buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd); | 799 buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd); |
| 1010 buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); | 800 buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); |
| 1011 } | 801 } |
| 1012 | 802 |
| 1013 var output = new cvox.NavBraille({ | 803 var output = new cvox.NavBraille( |
| 1014 text: buff, | 804 {text: buff, startIndex: startIndex, endIndex: endIndex}); |
| 1015 startIndex: startIndex, | |
| 1016 endIndex: endIndex | |
| 1017 }); | |
| 1018 | 805 |
| 1019 cvox.ChromeVox.braille.write(output); | 806 cvox.ChromeVox.braille.write(output); |
| 1020 } | 807 } |
| 1021 | 808 |
| 1022 // Display. | 809 // Display. |
| 1023 if (this.speechCategory_ != cvox.TtsCategory.LIVE) | 810 if (this.speechCategory_ != cvox.TtsCategory.LIVE) |
| 1024 chrome.accessibilityPrivate.setFocusRing(this.locations_); | 811 chrome.accessibilityPrivate.setFocusRing(this.locations_); |
| 1025 }, | 812 }, |
| 1026 | 813 |
| 1027 /** | 814 /** |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1110 // All possible tokens based on prefix. | 897 // All possible tokens based on prefix. |
| 1111 if (prefix == '$') { | 898 if (prefix == '$') { |
| 1112 if (token == 'value') { | 899 if (token == 'value') { |
| 1113 var text = node.value || ''; | 900 var text = node.value || ''; |
| 1114 if (!node.state[StateType.EDITABLE] && node.name == text) | 901 if (!node.state[StateType.EDITABLE] && node.name == text) |
| 1115 return; | 902 return; |
| 1116 | 903 |
| 1117 var selectedText = ''; | 904 var selectedText = ''; |
| 1118 if (node.textSelStart !== undefined) { | 905 if (node.textSelStart !== undefined) { |
| 1119 options.annotation.push(new Output.SelectionSpan( | 906 options.annotation.push(new Output.SelectionSpan( |
| 1120 node.textSelStart || 0, | 907 node.textSelStart || 0, node.textSelEnd || 0)); |
| 1121 node.textSelEnd || 0)); | |
| 1122 | 908 |
| 1123 selectedText = | 909 selectedText = node.value.substring( |
| 1124 node.value.substring(node.textSelStart || 0, | 910 node.textSelStart || 0, node.textSelEnd || 0); |
| 1125 node.textSelEnd || 0); | |
| 1126 } | 911 } |
| 1127 options.annotation.push(token); | 912 options.annotation.push(token); |
| 1128 if (selectedText && !this.formatOptions_.braille) { | 913 if (selectedText && !this.formatOptions_.braille) { |
| 1129 this.append_(buff, selectedText, options); | 914 this.append_(buff, selectedText, options); |
| 1130 this.append_(buff, Msgs.getMsg('selected')); | 915 this.append_(buff, Msgs.getMsg('selected')); |
| 1131 } else { | 916 } else { |
| 1132 this.append_(buff, text, options); | 917 this.append_(buff, text, options); |
| 1133 } | 918 } |
| 1134 } else if (token == 'name') { | 919 } else if (token == 'name') { |
| 1135 options.annotation.push(token); | 920 options.annotation.push(token); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1146 } else if (token == 'urlFilename') { | 931 } else if (token == 'urlFilename') { |
| 1147 options.annotation.push('name'); | 932 options.annotation.push('name'); |
| 1148 var url = node.url || ''; | 933 var url = node.url || ''; |
| 1149 var filename = ''; | 934 var filename = ''; |
| 1150 if (url.substring(0, 4) != 'data') { | 935 if (url.substring(0, 4) != 'data') { |
| 1151 filename = | 936 filename = |
| 1152 url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.')); | 937 url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.')); |
| 1153 | 938 |
| 1154 // Hack to not speak the filename if it's ridiculously long. | 939 // Hack to not speak the filename if it's ridiculously long. |
| 1155 if (filename.length >= 30) | 940 if (filename.length >= 30) |
| 1156 filename = filename.substring(0, 16) + '...'; | 941 filename = filename.substring(0, 16) + '...'; |
| 1157 } | 942 } |
| 1158 this.append_(buff, filename, options); | 943 this.append_(buff, filename, options); |
| 1159 } else if (token == 'nameFromNode') { | 944 } else if (token == 'nameFromNode') { |
| 1160 if (node.nameFrom == chrome.automation.NameFromType.CONTENTS) | 945 if (node.nameFrom == chrome.automation.NameFromType.CONTENTS) |
| 1161 return; | 946 return; |
| 1162 | 947 |
| 1163 options.annotation.push('name'); | 948 options.annotation.push('name'); |
| 1164 this.append_(buff, node.name || '', options); | 949 this.append_(buff, node.name || '', options); |
| 1165 } else if (token == 'nameOrDescendants') { | 950 } else if (token == 'nameOrDescendants') { |
| 1166 options.annotation.push(token); | 951 options.annotation.push(token); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1181 if (node.role == child.role) | 966 if (node.role == child.role) |
| 1182 count++; | 967 count++; |
| 1183 if (node === child) | 968 if (node === child) |
| 1184 break; | 969 break; |
| 1185 } | 970 } |
| 1186 this.append_(buff, String(count)); | 971 this.append_(buff, String(count)); |
| 1187 } | 972 } |
| 1188 } else if (token == 'parentChildCount') { | 973 } else if (token == 'parentChildCount') { |
| 1189 if (node.parent) { | 974 if (node.parent) { |
| 1190 options.annotation.push(token); | 975 options.annotation.push(token); |
| 1191 var count = node.parent.children.filter(function(child) { | 976 var count = node.parent.children |
| 1192 return node.role == child.role; | 977 .filter(function(child) { |
| 1193 }).length; | 978 return node.role == child.role; |
| 979 }) |
| 980 .length; |
| 1194 this.append_(buff, String(count)); | 981 this.append_(buff, String(count)); |
| 1195 } | 982 } |
| 1196 } else if (token == 'checked') { | 983 } else if (token == 'checked') { |
| 1197 var msg = Output.CHECKED_STATE_MAP[node.checked]; | 984 var msg = Output.CHECKED_STATE_MAP[node.checked]; |
| 1198 if (msg) { | 985 if (msg) { |
| 1199 this.format_(node, '@' + msg, buff); | 986 this.format_(node, '@' + msg, buff); |
| 1200 } | 987 } |
| 1201 } else if (token == 'pressed') { | 988 } else if (token == 'pressed') { |
| 1202 var msg = Output.PRESSED_STATE_MAP[node.checked]; | 989 var msg = Output.PRESSED_STATE_MAP[node.checked]; |
| 1203 if (msg) { | 990 if (msg) { |
| 1204 this.format_(node, '@' + msg, buff); | 991 this.format_(node, '@' + msg, buff); |
| 1205 } | 992 } |
| 1206 } else if (token == 'state') { | 993 } else if (token == 'state') { |
| 1207 if (node.state) { | 994 if (node.state) { |
| 1208 Object.getOwnPropertyNames(node.state).forEach(function(s) { | 995 Object.getOwnPropertyNames(node.state).forEach(function(s) { |
| 1209 var stateInfo = Output.STATE_INFO_[s]; | 996 var stateInfo = Output.STATE_INFO_[s]; |
| 1210 if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) | 997 if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) |
| 1211 this.format_(node, '@' + stateInfo.on.msgId, buff); | 998 this.format_(node, '@' + stateInfo.on.msgId, buff); |
| 1212 }.bind(this)); | 999 }.bind(this)); |
| 1213 } | 1000 } |
| 1214 } else if (token == 'find') { | 1001 } else if (token == 'find') { |
| 1215 // Find takes two arguments: JSON query string and format string. | 1002 // Find takes two arguments: JSON query string and format string. |
| 1216 if (tree.firstChild) { | 1003 if (tree.firstChild) { |
| 1217 var jsonQuery = tree.firstChild.value; | 1004 var jsonQuery = tree.firstChild.value; |
| 1218 node = node.find( | 1005 node = node.find( |
| 1219 /** @type {chrome.automation.FindParams}*/( | 1006 /** @type {chrome.automation.FindParams}*/ ( |
| 1220 JSON.parse(jsonQuery))); | 1007 JSON.parse(jsonQuery))); |
| 1221 var formatString = tree.firstChild.nextSibling; | 1008 var formatString = tree.firstChild.nextSibling; |
| 1222 if (node) | 1009 if (node) |
| 1223 this.format_(node, formatString, buff); | 1010 this.format_(node, formatString, buff); |
| 1224 } | 1011 } |
| 1225 } else if (token == 'descendants') { | 1012 } else if (token == 'descendants') { |
| 1226 if (!node || AutomationPredicate.leafOrStaticText(node)) | 1013 if (!node || AutomationPredicate.leafOrStaticText(node)) |
| 1227 return; | 1014 return; |
| 1228 | 1015 |
| 1229 // Construct a range to the leftmost and rightmost leaves. | 1016 // Construct a range to the leftmost and rightmost leaves. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1269 this.append_(buff, msg || '', options); | 1056 this.append_(buff, msg || '', options); |
| 1270 } else if (token == 'inputType') { | 1057 } else if (token == 'inputType') { |
| 1271 if (!node.inputType) | 1058 if (!node.inputType) |
| 1272 return; | 1059 return; |
| 1273 options.annotation.push(token); | 1060 options.annotation.push(token); |
| 1274 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || | 1061 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || |
| 1275 'input_type_text'; | 1062 'input_type_text'; |
| 1276 if (this.formatOptions_.braille) | 1063 if (this.formatOptions_.braille) |
| 1277 msgId = msgId + '_brl'; | 1064 msgId = msgId + '_brl'; |
| 1278 this.append_(buff, Msgs.getMsg(msgId), options); | 1065 this.append_(buff, Msgs.getMsg(msgId), options); |
| 1279 } else if (token == 'tableCellRowIndex' || | 1066 } else if ( |
| 1280 token == 'tableCellColumnIndex') { | 1067 token == 'tableCellRowIndex' || token == 'tableCellColumnIndex') { |
| 1281 var value = node[token]; | 1068 var value = node[token]; |
| 1282 if (value == undefined) | 1069 if (value == undefined) |
| 1283 return; | 1070 return; |
| 1284 value = String(value + 1); | 1071 value = String(value + 1); |
| 1285 options.annotation.push(token); | 1072 options.annotation.push(token); |
| 1286 this.append_(buff, value, options); | 1073 this.append_(buff, value, options); |
| 1287 } else if (token == 'node') { | 1074 } else if (token == 'node') { |
| 1288 if (!tree.firstChild || !node[tree.firstChild.value]) | 1075 if (!tree.firstChild || !node[tree.firstChild.value]) |
| 1289 return; | 1076 return; |
| 1290 var related = node[tree.firstChild.value]; | 1077 var related = node[tree.firstChild.value]; |
| 1291 this.node_(related, related, Output.EventType.NAVIGATE, buff); | 1078 this.node_(related, related, Output.EventType.NAVIGATE, buff); |
| 1292 } else if (token == 'nameOrTextContent') { | 1079 } else if (token == 'nameOrTextContent') { |
| 1293 if (node.name) { | 1080 if (node.name) { |
| 1294 this.format_(node, '$name', buff); | 1081 this.format_(node, '$name', buff); |
| 1295 } else { | 1082 } else { |
| 1296 var walker = new AutomationTreeWalker(node, | 1083 var walker = new AutomationTreeWalker(node, Dir.FORWARD, { |
| 1297 Dir.FORWARD, | 1084 visit: AutomationPredicate.leafOrStaticText, |
| 1298 {visit: AutomationPredicate.leafOrStaticText, | 1085 leaf: AutomationPredicate.leafOrStaticText |
| 1299 leaf: AutomationPredicate.leafOrStaticText}); | 1086 }); |
| 1300 var outputStrings = []; | 1087 var outputStrings = []; |
| 1301 while (walker.next().node && | 1088 while (walker.next().node && |
| 1302 walker.phase == AutomationTreeWalkerPhase.DESCENDANT) { | 1089 walker.phase == AutomationTreeWalkerPhase.DESCENDANT) { |
| 1303 if (walker.node.name) | 1090 if (walker.node.name) |
| 1304 outputStrings.push(walker.node.name); | 1091 outputStrings.push(walker.node.name); |
| 1305 } | 1092 } |
| 1306 var joinedOutput = outputStrings.join(' '); | 1093 var joinedOutput = outputStrings.join(' '); |
| 1307 this.append_(buff, joinedOutput, options); | 1094 this.append_(buff, joinedOutput, options); |
| 1308 } | 1095 } |
| 1309 } else if (node[token] !== undefined) { | 1096 } else if (node[token] !== undefined) { |
| 1310 options.annotation.push(token); | 1097 options.annotation.push(token); |
| 1311 var value = node[token]; | 1098 var value = node[token]; |
| 1312 if (typeof value == 'number') | 1099 if (typeof value == 'number') |
| 1313 value = String(value); | 1100 value = String(value); |
| 1314 this.append_(buff, value, options); | 1101 this.append_(buff, value, options); |
| 1315 } else if (Output.STATE_INFO_[token]) { | 1102 } else if (Output.STATE_INFO_[token]) { |
| 1316 options.annotation.push('state'); | 1103 options.annotation.push('state'); |
| 1317 var stateInfo = Output.STATE_INFO_[token]; | 1104 var stateInfo = Output.STATE_INFO_[token]; |
| 1318 var resolvedInfo = {}; | 1105 var resolvedInfo = {}; |
| 1319 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; | 1106 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; |
| 1320 if (!resolvedInfo) | 1107 if (!resolvedInfo) |
| 1321 return; | 1108 return; |
| 1322 if (this.formatOptions_.speech && resolvedInfo.earconId) { | 1109 if (this.formatOptions_.speech && resolvedInfo.earconId) { |
| 1323 options.annotation.push( | 1110 options.annotation.push( |
| 1324 new Output.EarconAction(resolvedInfo.earconId), | 1111 new Output.EarconAction(resolvedInfo.earconId), |
| 1325 node.location || undefined); | 1112 node.location || undefined); |
| 1326 } | 1113 } |
| 1327 var msgId = | 1114 var msgId = this.formatOptions_.braille ? |
| 1328 this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' : | 1115 resolvedInfo.msgId + '_brl' : |
| 1329 resolvedInfo.msgId; | 1116 resolvedInfo.msgId; |
| 1330 var msg = Msgs.getMsg(msgId); | 1117 var msg = Msgs.getMsg(msgId); |
| 1331 this.append_(buff, msg, options); | 1118 this.append_(buff, msg, options); |
| 1332 } else if (tree.firstChild) { | 1119 } else if (tree.firstChild) { |
| 1333 // Custom functions. | 1120 // Custom functions. |
| 1334 if (token == 'if') { | 1121 if (token == 'if') { |
| 1335 var cond = tree.firstChild; | 1122 var cond = tree.firstChild; |
| 1336 var attrib = cond.value.slice(1); | 1123 var attrib = cond.value.slice(1); |
| 1337 if (Output.isTruthy(node, attrib)) | 1124 if (Output.isTruthy(node, attrib)) |
| 1338 this.format_(node, cond.nextSibling, buff); | 1125 this.format_(node, cond.nextSibling, buff); |
| 1339 else | 1126 else |
| 1340 this.format_(node, cond.nextSibling.nextSibling, buff); | 1127 this.format_(node, cond.nextSibling.nextSibling, buff); |
| 1341 } else if (token == 'earcon') { | 1128 } else if (token == 'earcon') { |
| 1342 // Ignore unless we're generating speech output. | 1129 // Ignore unless we're generating speech output. |
| 1343 if (!this.formatOptions_.speech) | 1130 if (!this.formatOptions_.speech) |
| 1344 return; | 1131 return; |
| 1345 | 1132 |
| 1346 options.annotation.push( | 1133 options.annotation.push(new Output.EarconAction( |
| 1347 new Output.EarconAction(tree.firstChild.value, | 1134 tree.firstChild.value, node.location || undefined)); |
| 1348 node.location || undefined)); | |
| 1349 this.append_(buff, '', options); | 1135 this.append_(buff, '', options); |
| 1350 } else if (token == 'countChildren') { | 1136 } else if (token == 'countChildren') { |
| 1351 var role = tree.firstChild.value; | 1137 var role = tree.firstChild.value; |
| 1352 var count = node.children.filter(function(e) { | 1138 var count = node.children |
| 1353 return e.role == role; | 1139 .filter(function(e) { |
| 1354 }).length; | 1140 return e.role == role; |
| 1141 }) |
| 1142 .length; |
| 1355 this.append_(buff, String(count)); | 1143 this.append_(buff, String(count)); |
| 1356 } | 1144 } |
| 1357 } | 1145 } |
| 1358 } else if (prefix == '@') { | 1146 } else if (prefix == '@') { |
| 1359 if (this.formatOptions_.auralStyle) { | 1147 if (this.formatOptions_.auralStyle) { |
| 1360 speechProps = new Output.SpeechProperties(); | 1148 speechProps = new Output.SpeechProperties(); |
| 1361 speechProps['relativePitch'] = -0.2; | 1149 speechProps['relativePitch'] = -0.2; |
| 1362 } | 1150 } |
| 1363 var isPluralized = (token[0] == '@'); | 1151 var isPluralized = (token[0] == '@'); |
| 1364 if (isPluralized) | 1152 if (isPluralized) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1386 if (!msgBuff.length) | 1174 if (!msgBuff.length) |
| 1387 msgBuff = ['']; | 1175 msgBuff = ['']; |
| 1388 msgArgs = msgArgs.concat(msgBuff); | 1176 msgArgs = msgArgs.concat(msgBuff); |
| 1389 curArg = curArg.nextSibling; | 1177 curArg = curArg.nextSibling; |
| 1390 } | 1178 } |
| 1391 } | 1179 } |
| 1392 var msg = Msgs.getMsg(msgId, msgArgs); | 1180 var msg = Msgs.getMsg(msgId, msgArgs); |
| 1393 try { | 1181 try { |
| 1394 if (this.formatOptions_.braille) | 1182 if (this.formatOptions_.braille) |
| 1395 msg = Msgs.getMsg(msgId + '_brl', msgArgs) || msg; | 1183 msg = Msgs.getMsg(msgId + '_brl', msgArgs) || msg; |
| 1396 } catch(e) {} | 1184 } catch (e) { |
| 1185 } |
| 1397 | 1186 |
| 1398 if (!msg) { | 1187 if (!msg) { |
| 1399 console.error('Could not get message ' + msgId); | 1188 console.error('Could not get message ' + msgId); |
| 1400 return; | 1189 return; |
| 1401 } | 1190 } |
| 1402 | 1191 |
| 1403 if (isPluralized) { | 1192 if (isPluralized) { |
| 1404 var arg = tree.firstChild; | 1193 var arg = tree.firstChild; |
| 1405 if (!arg || arg.nextSibling) { | 1194 if (!arg || arg.nextSibling) { |
| 1406 console.error('Pluralized messages take exactly one argument'); | 1195 console.error('Pluralized messages take exactly one argument'); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1472 this.ancestry_(node, prevNode, type, buff); | 1261 this.ancestry_(node, prevNode, type, buff); |
| 1473 this.node_(node, prevNode, type, buff); | 1262 this.node_(node, prevNode, type, buff); |
| 1474 if (!this.outputContextFirst_) | 1263 if (!this.outputContextFirst_) |
| 1475 this.ancestry_(node, prevNode, type, buff); | 1264 this.ancestry_(node, prevNode, type, buff); |
| 1476 if (node.location) | 1265 if (node.location) |
| 1477 this.locations_.push(node.location); | 1266 this.locations_.push(node.location); |
| 1478 return buff; | 1267 return buff; |
| 1479 }.bind(this); | 1268 }.bind(this); |
| 1480 | 1269 |
| 1481 var unit = range.isInlineText() ? cursors.Unit.TEXT : cursors.Unit.NODE; | 1270 var unit = range.isInlineText() ? cursors.Unit.TEXT : cursors.Unit.NODE; |
| 1482 while (cursor.node && | 1271 while (cursor.node && range.end.node && |
| 1483 range.end.node && | 1272 AutomationUtil.getDirection(cursor.node, range.end.node) == |
| 1484 AutomationUtil.getDirection(cursor.node, range.end.node) == | 1273 Dir.FORWARD) { |
| 1485 Dir.FORWARD) { | |
| 1486 var node = cursor.node; | 1274 var node = cursor.node; |
| 1487 rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode)); | 1275 rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode)); |
| 1488 prevNode = node; | 1276 prevNode = node; |
| 1489 cursor = cursor.move(unit, | 1277 cursor = cursor.move(unit, cursors.Movement.DIRECTIONAL, Dir.FORWARD); |
| 1490 cursors.Movement.DIRECTIONAL, | |
| 1491 Dir.FORWARD); | |
| 1492 | 1278 |
| 1493 // Reached a boundary. | 1279 // Reached a boundary. |
| 1494 if (cursor.node == prevNode) | 1280 if (cursor.node == prevNode) |
| 1495 break; | 1281 break; |
| 1496 } | 1282 } |
| 1497 }, | 1283 }, |
| 1498 | 1284 |
| 1499 /** | 1285 /** |
| 1500 * @param {!AutomationNode} node | 1286 * @param {!AutomationNode} node |
| 1501 * @param {!AutomationNode} prevNode | 1287 * @param {!AutomationNode} prevNode |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1516 contextFirst = []; | 1302 contextFirst = []; |
| 1517 rest = []; | 1303 rest = []; |
| 1518 } | 1304 } |
| 1519 if ((Output.ROLE_INFO_[node.role] || {}).outputContextFirst) | 1305 if ((Output.ROLE_INFO_[node.role] || {}).outputContextFirst) |
| 1520 contextFirst.push(node); | 1306 contextFirst.push(node); |
| 1521 else | 1307 else |
| 1522 rest.push(node); | 1308 rest.push(node); |
| 1523 } | 1309 } |
| 1524 return rest.concat(contextFirst.reverse()); | 1310 return rest.concat(contextFirst.reverse()); |
| 1525 } | 1311 } |
| 1526 var prevUniqueAncestors = byContextFirst(AutomationUtil.getUniqueAncestors( | 1312 var prevUniqueAncestors = |
| 1527 node, prevNode)); | 1313 byContextFirst(AutomationUtil.getUniqueAncestors(node, prevNode)); |
| 1528 var uniqueAncestors = byContextFirst(AutomationUtil.getUniqueAncestors( | 1314 var uniqueAncestors = |
| 1529 prevNode, node)); | 1315 byContextFirst(AutomationUtil.getUniqueAncestors(prevNode, node)); |
| 1530 | 1316 |
| 1531 // First, look up the event type's format block. | 1317 // First, look up the event type's format block. |
| 1532 // Navigate is the default event. | 1318 // Navigate is the default event. |
| 1533 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; | 1319 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; |
| 1534 | 1320 |
| 1535 var getMergedRoleBlock = function(role) { | 1321 var getMergedRoleBlock = function(role) { |
| 1536 var parentRole = (Output.ROLE_INFO_[role] || {}).inherits; | 1322 var parentRole = (Output.ROLE_INFO_[role] || {}).inherits; |
| 1537 var roleBlock = eventBlock[role] || eventBlock['default']; | 1323 var roleBlock = eventBlock[role] || eventBlock['default']; |
| 1538 var parentRoleBlock = parentRole ? eventBlock[parentRole] : {}; | 1324 var parentRoleBlock = parentRole ? eventBlock[parentRole] : {}; |
| 1539 var mergedRoleBlock = {}; | 1325 var mergedRoleBlock = {}; |
| 1540 for (var key in parentRoleBlock) | 1326 for (var key in parentRoleBlock) |
| 1541 mergedRoleBlock[key] = parentRoleBlock[key]; | 1327 mergedRoleBlock[key] = parentRoleBlock[key]; |
| 1542 for (var key in roleBlock) | 1328 for (var key in roleBlock) |
| 1543 mergedRoleBlock[key] = roleBlock[key]; | 1329 mergedRoleBlock[key] = roleBlock[key]; |
| 1544 return mergedRoleBlock; | 1330 return mergedRoleBlock; |
| 1545 }; | 1331 }; |
| 1546 | 1332 |
| 1547 // Hash the roles we've entered. | 1333 // Hash the roles we've entered. |
| 1548 var enteredRoleSet = {}; | 1334 var enteredRoleSet = {}; |
| 1549 for (var j = uniqueAncestors.length - 1, hashNode; | 1335 for (var j = uniqueAncestors.length - 1, hashNode; |
| 1550 (hashNode = uniqueAncestors[j]); | 1336 (hashNode = uniqueAncestors[j]); j--) |
| 1551 j--) | |
| 1552 enteredRoleSet[hashNode.role] = true; | 1337 enteredRoleSet[hashNode.role] = true; |
| 1553 | 1338 |
| 1554 for (var i = 0, formatPrevNode; | 1339 for (var i = 0, formatPrevNode; (formatPrevNode = prevUniqueAncestors[i]); |
| 1555 (formatPrevNode = prevUniqueAncestors[i]); | |
| 1556 i++) { | 1340 i++) { |
| 1557 // This prevents very repetitive announcements. | 1341 // This prevents very repetitive announcements. |
| 1558 if (enteredRoleSet[formatPrevNode.role] || | 1342 if (enteredRoleSet[formatPrevNode.role] || |
| 1559 node.role == formatPrevNode.role || | 1343 node.role == formatPrevNode.role || |
| 1560 localStorage['useVerboseMode'] == 'false') | 1344 localStorage['useVerboseMode'] == 'false') |
| 1561 continue; | 1345 continue; |
| 1562 | 1346 |
| 1563 var roleBlock = getMergedRoleBlock(formatPrevNode.role); | 1347 var roleBlock = getMergedRoleBlock(formatPrevNode.role); |
| 1564 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') | 1348 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') |
| 1565 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode); | 1349 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode); |
| 1566 } | 1350 } |
| 1567 | 1351 |
| 1568 // Customize for braille node annotations. | 1352 // Customize for braille node annotations. |
| 1569 var originalBuff = buff; | 1353 var originalBuff = buff; |
| 1570 var enterRole = {}; | 1354 var enterRole = {}; |
| 1571 for (var j = uniqueAncestors.length - 1, formatNode; | 1355 for (var j = uniqueAncestors.length - 1, formatNode; |
| 1572 (formatNode = uniqueAncestors[j]); | 1356 (formatNode = uniqueAncestors[j]); j--) { |
| 1573 j--) { | |
| 1574 var roleBlock = getMergedRoleBlock(formatNode.role); | 1357 var roleBlock = getMergedRoleBlock(formatNode.role); |
| 1575 if (roleBlock.enter) { | 1358 if (roleBlock.enter) { |
| 1576 if (enterRole[formatNode.role]) | 1359 if (enterRole[formatNode.role]) |
| 1577 continue; | 1360 continue; |
| 1578 | 1361 |
| 1579 if (this.formatOptions_.braille) | 1362 if (this.formatOptions_.braille) |
| 1580 buff = []; | 1363 buff = []; |
| 1581 | 1364 |
| 1582 enterRole[formatNode.role] = true; | 1365 enterRole[formatNode.role] = true; |
| 1583 this.format_(formatNode, roleBlock.enter, buff, prevNode); | 1366 this.format_(formatNode, roleBlock.enter, buff, prevNode); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1602 var originalBuff = buff; | 1385 var originalBuff = buff; |
| 1603 | 1386 |
| 1604 if (this.formatOptions_.braille) | 1387 if (this.formatOptions_.braille) |
| 1605 buff = []; | 1388 buff = []; |
| 1606 | 1389 |
| 1607 // Navigate is the default event. | 1390 // Navigate is the default event. |
| 1608 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; | 1391 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; |
| 1609 var roleBlock = eventBlock[node.role] || {}; | 1392 var roleBlock = eventBlock[node.role] || {}; |
| 1610 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; | 1393 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; |
| 1611 var parentRoleBlock = eventBlock[parentRole || ''] || {}; | 1394 var parentRoleBlock = eventBlock[parentRole || ''] || {}; |
| 1612 var speakFormat = roleBlock.speak || | 1395 var speakFormat = |
| 1613 parentRoleBlock.speak || | 1396 roleBlock.speak || parentRoleBlock.speak || eventBlock['default'].speak; |
| 1614 eventBlock['default'].speak; | |
| 1615 | 1397 |
| 1616 this.format_(node, speakFormat, buff, prevNode); | 1398 this.format_(node, speakFormat, buff, prevNode); |
| 1617 | 1399 |
| 1618 // Restore braille and add an annotation for this node. | 1400 // Restore braille and add an annotation for this node. |
| 1619 if (this.formatOptions_.braille) { | 1401 if (this.formatOptions_.braille) { |
| 1620 var nodeSpan = this.mergeBraille_(buff); | 1402 var nodeSpan = this.mergeBraille_(buff); |
| 1621 nodeSpan.setSpan(new Output.NodeSpan(node), 0, nodeSpan.length); | 1403 nodeSpan.setSpan(new Output.NodeSpan(node), 0, nodeSpan.length); |
| 1622 originalBuff.push(nodeSpan); | 1404 originalBuff.push(nodeSpan); |
| 1623 } | 1405 } |
| 1624 }, | 1406 }, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1640 return; | 1422 return; |
| 1641 | 1423 |
| 1642 var options = {annotation: ['name'], isUnique: true}; | 1424 var options = {annotation: ['name'], isUnique: true}; |
| 1643 var rangeStart = range.start.index; | 1425 var rangeStart = range.start.index; |
| 1644 var rangeEnd = range.end.index; | 1426 var rangeEnd = range.end.index; |
| 1645 if (this.formatOptions_.braille) { | 1427 if (this.formatOptions_.braille) { |
| 1646 options.annotation.push(new Output.NodeSpan(node)); | 1428 options.annotation.push(new Output.NodeSpan(node)); |
| 1647 var selStart = node.textSelStart; | 1429 var selStart = node.textSelStart; |
| 1648 var selEnd = node.textSelEnd; | 1430 var selEnd = node.textSelEnd; |
| 1649 | 1431 |
| 1650 if (selStart !== undefined && | 1432 if (selStart !== undefined && selEnd >= rangeStart && |
| 1651 selEnd >= rangeStart && selStart <= rangeEnd) { | 1433 selStart <= rangeEnd) { |
| 1652 // Editable text selection. | 1434 // Editable text selection. |
| 1653 | 1435 |
| 1654 // |rangeStart| and |rangeEnd| are indices set by the caller and are | 1436 // |rangeStart| and |rangeEnd| are indices set by the caller and are |
| 1655 // assumed to be inside of the range. In braille, we only ever expect to | 1437 // assumed to be inside of the range. In braille, we only ever expect to |
| 1656 // get ranges surrounding a line as anything smaller doesn't make sense. | 1438 // get ranges surrounding a line as anything smaller doesn't make sense. |
| 1657 | 1439 |
| 1658 // |selStart| and |selEnd| reflect the editable selection. The relative | 1440 // |selStart| and |selEnd| reflect the editable selection. The relative |
| 1659 // selStart and relative selEnd for the current line are then just the | 1441 // selStart and relative selEnd for the current line are then just the |
| 1660 // difference between |selStart|, |selEnd| with |rangeStart|. | 1442 // difference between |selStart|, |selEnd| with |rangeStart|. |
| 1661 // See editing_test.js for examples. | 1443 // See editing_test.js for examples. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1683 } else { | 1465 } else { |
| 1684 // This is output for speech or editable braille. | 1466 // This is output for speech or editable braille. |
| 1685 text = range.start.getText().substring(rangeStart, rangeEnd); | 1467 text = range.start.getText().substring(rangeStart, rangeEnd); |
| 1686 } | 1468 } |
| 1687 | 1469 |
| 1688 this.append_(buff, text, options); | 1470 this.append_(buff, text, options); |
| 1689 | 1471 |
| 1690 if (!this.outputContextFirst_) | 1472 if (!this.outputContextFirst_) |
| 1691 this.ancestry_(node, prevNode, type, buff); | 1473 this.ancestry_(node, prevNode, type, buff); |
| 1692 | 1474 |
| 1693 var loc = | 1475 var loc = range.start.node.boundsForRange(rangeStart, rangeEnd); |
| 1694 range.start.node.boundsForRange(rangeStart, rangeEnd); | |
| 1695 if (loc) | 1476 if (loc) |
| 1696 this.locations_.push(loc); | 1477 this.locations_.push(loc); |
| 1697 }, | 1478 }, |
| 1698 | 1479 |
| 1699 /** | 1480 /** |
| 1700 * Appends output to the |buff|. | 1481 * Appends output to the |buff|. |
| 1701 * @param {!Array<Spannable>} buff | 1482 * @param {!Array<Spannable>} buff |
| 1702 * @param {string|!Spannable} value | 1483 * @param {string|!Spannable} value |
| 1703 * @param {{isUnique: (boolean|undefined), | 1484 * @param {{isUnique: (boolean|undefined), |
| 1704 * annotation: !Array<*>}=} opt_options | 1485 * annotation: !Array<*>}=} opt_options |
| 1705 */ | 1486 */ |
| 1706 append_: function(buff, value, opt_options) { | 1487 append_: function(buff, value, opt_options) { |
| 1707 opt_options = opt_options || {isUnique: false, annotation: []}; | 1488 opt_options = opt_options || {isUnique: false, annotation: []}; |
| 1708 | 1489 |
| 1709 // Reject empty values without meaningful annotations. | 1490 // Reject empty values without meaningful annotations. |
| 1710 if ((!value || value.length == 0) && opt_options.annotation.every( | 1491 if ((!value || value.length == 0) && |
| 1711 function(a) { | 1492 opt_options.annotation.every(function(a) { |
| 1712 return !(a instanceof Output.Action) && | 1493 return !(a instanceof Output.Action) && |
| 1713 !(a instanceof Output.SelectionSpan); | 1494 !(a instanceof Output.SelectionSpan); |
| 1714 | 1495 |
| 1715 })) | 1496 })) |
| 1716 return; | 1497 return; |
| 1717 | 1498 |
| 1718 var spannableToAdd = new Spannable(value); | 1499 var spannableToAdd = new Spannable(value); |
| 1719 opt_options.annotation.forEach(function(a) { | 1500 opt_options.annotation.forEach(function(a) { |
| 1720 spannableToAdd.setSpan(a, 0, spannableToAdd.length); | 1501 spannableToAdd.setSpan(a, 0, spannableToAdd.length); |
| 1721 }); | 1502 }); |
| 1722 | 1503 |
| 1723 // |isUnique| specifies an annotation that cannot be duplicated. | 1504 // |isUnique| specifies an annotation that cannot be duplicated. |
| 1724 if (opt_options.isUnique) { | 1505 if (opt_options.isUnique) { |
| 1725 var annotationSansNodes = opt_options.annotation.filter( | 1506 var annotationSansNodes = |
| 1726 function(annotation) { | 1507 opt_options.annotation.filter(function(annotation) { |
| 1727 return !(annotation instanceof Output.NodeSpan); | 1508 return !(annotation instanceof Output.NodeSpan); |
| 1728 }); | 1509 }); |
| 1729 | 1510 |
| 1730 var alreadyAnnotated = buff.some(function(s) { | 1511 var alreadyAnnotated = buff.some(function(s) { |
| 1731 return annotationSansNodes.some(function(annotation) { | 1512 return annotationSansNodes.some(function(annotation) { |
| 1732 if (!s.hasSpan(annotation)) | 1513 if (!s.hasSpan(annotation)) |
| 1733 return false; | 1514 return false; |
| 1734 var start = s.getSpanStart(annotation); | 1515 var start = s.getSpanStart(annotation); |
| 1735 var end = s.getSpanEnd(annotation); | 1516 var end = s.getSpanEnd(annotation); |
| 1736 var substr = s.substring(start, end); | 1517 var substr = s.substring(start, end); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1807 // showing the braille cursor. | 1588 // showing the braille cursor. |
| 1808 if (cur.length == 0 && hasSelection) { | 1589 if (cur.length == 0 && hasSelection) { |
| 1809 result.append(cur); | 1590 result.append(cur); |
| 1810 result.append(Output.SPACE); | 1591 result.append(Output.SPACE); |
| 1811 separator = ''; | 1592 separator = ''; |
| 1812 return result; | 1593 return result; |
| 1813 } | 1594 } |
| 1814 | 1595 |
| 1815 // Keep track of if there's an inline node associated with | 1596 // Keep track of if there's an inline node associated with |
| 1816 // |cur|. | 1597 // |cur|. |
| 1817 var hasInlineNode = cur.getSpansInstanceOf(Output.NodeSpan) | 1598 var hasInlineNode = |
| 1818 .some(function(s) { | 1599 cur.getSpansInstanceOf(Output.NodeSpan).some(function(s) { |
| 1819 if (!s.node) | 1600 if (!s.node) |
| 1820 return false; | 1601 return false; |
| 1821 return s.node.display == 'inline' || | 1602 return s.node.display == 'inline' || |
| 1822 s.node.role == RoleType.INLINE_TEXT_BOX; | 1603 s.node.role == RoleType.INLINE_TEXT_BOX; |
| 1823 }); | 1604 }); |
| 1824 | 1605 |
| 1825 var isName = cur.hasSpan('name'); | 1606 var isName = cur.hasSpan('name'); |
| 1826 | 1607 |
| 1827 // Now, decide whether we should include separators between the previous | 1608 // Now, decide whether we should include separators between the previous |
| 1828 // span and |cur|. | 1609 // span and |cur|. |
| 1829 // Never separate chunks without something already there at this point. | 1610 // Never separate chunks without something already there at this point. |
| 1830 | 1611 |
| 1831 // The only case where we know for certain that a separator is not needed | 1612 // The only case where we know for certain that a separator is not needed |
| 1832 // is when the previous and current values are in-lined and part of the | 1613 // is when the previous and current values are in-lined and part of the |
| 1833 // node's name. In all other cases, use the surrounding whitespace to | 1614 // node's name. In all other cases, use the surrounding whitespace to |
| 1834 // ensure we only have one separator between the node text. | 1615 // ensure we only have one separator between the node text. |
| 1835 if (result.length == 0 || | 1616 if (result.length == 0 || |
| 1836 (hasInlineNode && prevHasInlineNode && isName && prevIsName)) | 1617 (hasInlineNode && prevHasInlineNode && isName && prevIsName)) |
| 1837 separator = ''; | 1618 separator = ''; |
| 1838 else if (result.toString()[result.length - 1] == Output.SPACE || | 1619 else if ( |
| 1620 result.toString()[result.length - 1] == Output.SPACE || |
| 1839 cur.toString()[0] == Output.SPACE) | 1621 cur.toString()[0] == Output.SPACE) |
| 1840 separator = ''; | 1622 separator = ''; |
| 1841 else | 1623 else |
| 1842 separator = Output.SPACE; | 1624 separator = Output.SPACE; |
| 1843 | 1625 |
| 1844 prevHasInlineNode = hasInlineNode; | 1626 prevHasInlineNode = hasInlineNode; |
| 1845 prevIsName = isName; | 1627 prevIsName = isName; |
| 1846 result.append(separator); | 1628 result.append(separator); |
| 1847 result.append(cur); | 1629 result.append(cur); |
| 1848 return result; | 1630 return result; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1863 var earconFinder = node; | 1645 var earconFinder = node; |
| 1864 var ancestors; | 1646 var ancestors; |
| 1865 if (opt_prevNode) | 1647 if (opt_prevNode) |
| 1866 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); | 1648 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); |
| 1867 else | 1649 else |
| 1868 ancestors = AutomationUtil.getAncestors(node); | 1650 ancestors = AutomationUtil.getAncestors(node); |
| 1869 | 1651 |
| 1870 while (earconFinder = ancestors.pop()) { | 1652 while (earconFinder = ancestors.pop()) { |
| 1871 var info = Output.ROLE_INFO_[earconFinder.role]; | 1653 var info = Output.ROLE_INFO_[earconFinder.role]; |
| 1872 if (info && info.earconId) { | 1654 if (info && info.earconId) { |
| 1873 return new Output.EarconAction(info.earconId, | 1655 return new Output.EarconAction( |
| 1874 node.location || undefined); | 1656 info.earconId, node.location || undefined); |
| 1875 break; | 1657 break; |
| 1876 } | 1658 } |
| 1877 earconFinder = earconFinder.parent; | 1659 earconFinder = earconFinder.parent; |
| 1878 } | 1660 } |
| 1879 } | 1661 } |
| 1880 return null; | 1662 return null; |
| 1881 }, | 1663 }, |
| 1882 | 1664 |
| 1883 /** | 1665 /** |
| 1884 * Gets a human friendly string with the contents of output. | 1666 * Gets a human friendly string with the contents of output. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1910 /** | 1692 /** |
| 1911 * Gets the output buffer for braille. | 1693 * Gets the output buffer for braille. |
| 1912 * @return {!Spannable} | 1694 * @return {!Spannable} |
| 1913 */ | 1695 */ |
| 1914 get brailleOutputForTest() { | 1696 get brailleOutputForTest() { |
| 1915 return this.mergeBraille_(this.brailleBuffer_); | 1697 return this.mergeBraille_(this.brailleBuffer_); |
| 1916 } | 1698 } |
| 1917 }; | 1699 }; |
| 1918 | 1700 |
| 1919 }); // goog.scope | 1701 }); // goog.scope |
| OLD | NEW |