| 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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 * queueing mode. | 529 * queueing mode. |
| 738 * @type {cvox.QueueMode|undefined} | 530 * @type {cvox.QueueMode|undefined} |
| 739 * @private | 531 * @private |
| 740 */ | 532 */ |
| 741 Output.forceModeForNextSpeechUtterance_; | 533 Output.forceModeForNextSpeechUtterance_; |
| 742 | 534 |
| 743 /** | 535 /** |
| 744 * Calling this will make the next speech utterance use |mode| even if it would | 536 * Calling this will make the next speech utterance use |mode| even if it would |
| 745 * normally queue or do a category flush. This differs from the |withQueueMode| | 537 * normally queue or do a category flush. This differs from the |withQueueMode| |
| 746 * instance method as it can apply to future output. | 538 * instance method as it can apply to future output. |
| 747 * @param {cvox.QueueMode} mode | 539 * @param {cvox.QueueMode} mode |
| 748 */ | 540 */ |
| 749 Output.forceModeForNextSpeechUtterance = function(mode) { | 541 Output.forceModeForNextSpeechUtterance = function(mode) { |
| 750 Output.forceModeForNextSpeechUtterance_ = mode; | 542 Output.forceModeForNextSpeechUtterance_ = mode; |
| 751 }; | 543 }; |
| 752 | 544 |
| 753 /** | 545 /** |
| 754 * For a given automation property, return true if the value | 546 * For a given automation property, return true if the value |
| 755 * represents something 'truthy', e.g.: for checked: | 547 * represents something 'truthy', e.g.: for checked: |
| 756 * 'true'|'mixed' -> true | 548 * 'true'|'mixed' -> true |
| 757 * 'false'|undefined -> false | 549 * 'false'|undefined -> false |
| 758 */ | 550 */ |
| 759 Output.isTruthy = function(node, attrib) { | 551 Output.isTruthy = function(node, attrib) { |
| 760 switch(attrib) { | 552 switch (attrib) { |
| 761 case 'checked': | 553 case 'checked': |
| 762 return node.checked && node.checked !== 'false'; | 554 return node.checked && node.checked !== 'false'; |
| 763 default: | 555 default: |
| 764 return node[attrib] !== undefined || node.state[attrib]; | 556 return node[attrib] !== undefined || node.state[attrib]; |
| 765 } | 557 } |
| 766 }; | 558 }; |
| 767 | 559 |
| 768 Output.prototype = { | 560 Output.prototype = { |
| 769 /** | 561 /** |
| 770 * @return {boolean} True if there's any speech that will be output. | 562 * @return {boolean} True if there's any speech that will be output. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 783 * @param {cursors.Range} prevRange | 575 * @param {cursors.Range} prevRange |
| 784 * @param {EventType|Output.EventType} type | 576 * @param {EventType|Output.EventType} type |
| 785 * @return {!Output} | 577 * @return {!Output} |
| 786 */ | 578 */ |
| 787 withSpeech: function(range, prevRange, type) { | 579 withSpeech: function(range, prevRange, type) { |
| 788 this.formatOptions_ = {speech: true, braille: false, auralStyle: false}; | 580 this.formatOptions_ = {speech: true, braille: false, auralStyle: false}; |
| 789 this.render_(range, prevRange, type, this.speechBuffer_); | 581 this.render_(range, prevRange, type, this.speechBuffer_); |
| 790 return this; | 582 return this; |
| 791 }, | 583 }, |
| 792 | 584 |
| 793 /** | 585 /** |
| 794 * Specify ranges for aurally styled speech. | 586 * Specify ranges for aurally styled speech. |
| 795 * @param {!cursors.Range} range | 587 * @param {!cursors.Range} range |
| 796 * @param {cursors.Range} prevRange | 588 * @param {cursors.Range} prevRange |
| 797 * @param {EventType|Output.EventType} type | 589 * @param {EventType|Output.EventType} type |
| 798 * @return {!Output} | 590 * @return {!Output} |
| 799 */ | 591 */ |
| 800 withRichSpeech: function(range, prevRange, type) { | 592 withRichSpeech: function(range, prevRange, type) { |
| 801 this.formatOptions_ = {speech: true, braille: false, auralStyle: true}; | 593 this.formatOptions_ = {speech: true, braille: false, auralStyle: true}; |
| 802 this.render_(range, prevRange, type, this.speechBuffer_); | 594 this.render_(range, prevRange, type, this.speechBuffer_); |
| 803 return this; | 595 return this; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 * @param {cursors.Range} prevRange | 627 * @param {cursors.Range} prevRange |
| 836 * @param {EventType|Output.EventType} type | 628 * @param {EventType|Output.EventType} type |
| 837 * @return {!Output} | 629 * @return {!Output} |
| 838 */ | 630 */ |
| 839 withSpeechAndBraille: function(range, prevRange, type) { | 631 withSpeechAndBraille: function(range, prevRange, type) { |
| 840 this.withSpeech(range, prevRange, type); | 632 this.withSpeech(range, prevRange, type); |
| 841 this.withBraille(range, prevRange, type); | 633 this.withBraille(range, prevRange, type); |
| 842 return this; | 634 return this; |
| 843 }, | 635 }, |
| 844 | 636 |
| 845 /** | 637 /** |
| 846 * Specify the same ranges for aurally styled speech and braille. | 638 * Specify the same ranges for aurally styled speech and braille. |
| 847 * @param {!cursors.Range} range | 639 * @param {!cursors.Range} range |
| 848 * @param {cursors.Range} prevRange | 640 * @param {cursors.Range} prevRange |
| 849 * @param {EventType|Output.EventType} type | 641 * @param {EventType|Output.EventType} type |
| 850 * @return {!Output} | 642 * @return {!Output} |
| 851 */ | 643 */ |
| 852 withRichSpeechAndBraille: function(range, prevRange, type) { | 644 withRichSpeechAndBraille: function(range, prevRange, type) { |
| 853 this.withRichSpeech(range, prevRange, type); | 645 this.withRichSpeech(range, prevRange, type); |
| 854 this.withBraille(range, prevRange, type); | 646 this.withBraille(range, prevRange, type); |
| 855 return this; | 647 return this; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 | 690 |
| 899 /** | 691 /** |
| 900 * Apply a format string directly to the output buffer. This lets you | 692 * Apply a format string directly to the output buffer. This lets you |
| 901 * output a message directly to the buffer using the format syntax. | 693 * output a message directly to the buffer using the format syntax. |
| 902 * @param {string} formatStr | 694 * @param {string} formatStr |
| 903 * @param {!AutomationNode=} opt_node An optional node to apply the | 695 * @param {!AutomationNode=} opt_node An optional node to apply the |
| 904 * formatting to. | 696 * formatting to. |
| 905 * @return {!Output} |this| for chaining | 697 * @return {!Output} |this| for chaining |
| 906 */ | 698 */ |
| 907 format: function(formatStr, opt_node) { | 699 format: function(formatStr, opt_node) { |
| 908 return this | 700 return this.formatForSpeech(formatStr, opt_node) |
| 909 .formatForSpeech(formatStr, opt_node) | |
| 910 .formatForBraille(formatStr, opt_node); | 701 .formatForBraille(formatStr, opt_node); |
| 911 }, | 702 }, |
| 912 | 703 |
| 913 /** | 704 /** |
| 914 * Apply a format string directly to the speech output buffer. This lets you | 705 * Apply a format string directly to the speech output buffer. This lets you |
| 915 * output a message directly to the buffer using the format syntax. | 706 * output a message directly to the buffer using the format syntax. |
| 916 * @param {string} formatStr | 707 * @param {string} formatStr |
| 917 * @param {!AutomationNode=} opt_node An optional node to apply the | 708 * @param {!AutomationNode=} opt_node An optional node to apply the |
| 918 * formatting to. | 709 * formatting to. |
| 919 * @return {!Output} |this| for chaining | 710 * @return {!Output} |this| for chaining |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 965 if (Output.forceModeForNextSpeechUtterance_ !== undefined) | 756 if (Output.forceModeForNextSpeechUtterance_ !== undefined) |
| 966 queueMode = Output.forceModeForNextSpeechUtterance_; | 757 queueMode = Output.forceModeForNextSpeechUtterance_; |
| 967 else if (this.queueMode_ !== undefined) | 758 else if (this.queueMode_ !== undefined) |
| 968 queueMode = this.queueMode_; | 759 queueMode = this.queueMode_; |
| 969 | 760 |
| 970 if (this.speechBuffer_.length > 0) | 761 if (this.speechBuffer_.length > 0) |
| 971 Output.forceModeForNextSpeechUtterance_ = undefined; | 762 Output.forceModeForNextSpeechUtterance_ = undefined; |
| 972 | 763 |
| 973 for (var i = 0; i < this.speechBuffer_.length; i++) { | 764 for (var i = 0; i < this.speechBuffer_.length; i++) { |
| 974 var buff = this.speechBuffer_[i]; | 765 var buff = this.speechBuffer_[i]; |
| 975 var speechProps = /** @type {Object} */( | 766 var speechProps = /** @type {Object} */ ( |
| 976 buff.getSpanInstanceOf(Output.SpeechProperties)) || {}; | 767 buff.getSpanInstanceOf(Output.SpeechProperties)) || |
| 768 {}; |
| 977 | 769 |
| 978 speechProps.category = this.speechCategory_; | 770 speechProps.category = this.speechCategory_; |
| 979 | 771 |
| 980 (function() { | 772 (function() { |
| 981 var scopedBuff = buff; | 773 var scopedBuff = buff; |
| 982 speechProps['startCallback'] = function() { | 774 speechProps['startCallback'] = function() { |
| 983 var actions = scopedBuff.getSpansInstanceOf(Output.Action); | 775 var actions = scopedBuff.getSpansInstanceOf(Output.Action); |
| 984 if (actions) { | 776 if (actions) { |
| 985 actions.forEach(function(a) { | 777 actions.forEach(function(a) { |
| 986 a.run(); | 778 a.run(); |
| 987 }); | 779 }); |
| 988 } | 780 } |
| 989 }; | 781 }; |
| 990 }()); | 782 }()); |
| 991 | 783 |
| 992 if (i == this.speechBuffer_.length - 1) | 784 if (i == this.speechBuffer_.length - 1) |
| 993 speechProps['endCallback'] = this.speechEndCallback_; | 785 speechProps['endCallback'] = this.speechEndCallback_; |
| 994 | 786 |
| 995 cvox.ChromeVox.tts.speak( | 787 cvox.ChromeVox.tts.speak(buff.toString(), queueMode, speechProps); |
| 996 buff.toString(), queueMode, speechProps); | |
| 997 queueMode = cvox.QueueMode.QUEUE; | 788 queueMode = cvox.QueueMode.QUEUE; |
| 998 } | 789 } |
| 999 | 790 |
| 1000 // Braille. | 791 // Braille. |
| 1001 if (this.brailleBuffer_.length) { | 792 if (this.brailleBuffer_.length) { |
| 1002 var buff = this.mergeBraille_(this.brailleBuffer_); | 793 var buff = this.mergeBraille_(this.brailleBuffer_); |
| 1003 var selSpan = | 794 var selSpan = buff.getSpanInstanceOf(Output.SelectionSpan); |
| 1004 buff.getSpanInstanceOf(Output.SelectionSpan); | |
| 1005 var startIndex = -1, endIndex = -1; | 795 var startIndex = -1, endIndex = -1; |
| 1006 if (selSpan) { | 796 if (selSpan) { |
| 1007 var valueStart = buff.getSpanStart(selSpan); | 797 var valueStart = buff.getSpanStart(selSpan); |
| 1008 var valueEnd = buff.getSpanEnd(selSpan); | 798 var valueEnd = buff.getSpanEnd(selSpan); |
| 1009 startIndex = valueStart + selSpan.startIndex; | 799 startIndex = valueStart + selSpan.startIndex; |
| 1010 endIndex = valueStart + selSpan.endIndex; | 800 endIndex = valueStart + selSpan.endIndex; |
| 1011 buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd); | 801 buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd); |
| 1012 buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); | 802 buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); |
| 1013 } | 803 } |
| 1014 | 804 |
| 1015 var output = new cvox.NavBraille({ | 805 var output = new cvox.NavBraille( |
| 1016 text: buff, | 806 {text: buff, startIndex: startIndex, endIndex: endIndex}); |
| 1017 startIndex: startIndex, | |
| 1018 endIndex: endIndex | |
| 1019 }); | |
| 1020 | 807 |
| 1021 cvox.ChromeVox.braille.write(output); | 808 cvox.ChromeVox.braille.write(output); |
| 1022 } | 809 } |
| 1023 | 810 |
| 1024 // Display. | 811 // Display. |
| 1025 if (this.speechCategory_ != cvox.TtsCategory.LIVE) | 812 if (this.speechCategory_ != cvox.TtsCategory.LIVE) |
| 1026 chrome.accessibilityPrivate.setFocusRing(this.locations_); | 813 chrome.accessibilityPrivate.setFocusRing(this.locations_); |
| 1027 }, | 814 }, |
| 1028 | 815 |
| 1029 /** | 816 /** |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 // All possible tokens based on prefix. | 899 // All possible tokens based on prefix. |
| 1113 if (prefix == '$') { | 900 if (prefix == '$') { |
| 1114 if (token == 'value') { | 901 if (token == 'value') { |
| 1115 var text = node.value || ''; | 902 var text = node.value || ''; |
| 1116 if (!node.state[StateType.EDITABLE] && node.name == text) | 903 if (!node.state[StateType.EDITABLE] && node.name == text) |
| 1117 return; | 904 return; |
| 1118 | 905 |
| 1119 var selectedText = ''; | 906 var selectedText = ''; |
| 1120 if (node.textSelStart !== undefined) { | 907 if (node.textSelStart !== undefined) { |
| 1121 options.annotation.push(new Output.SelectionSpan( | 908 options.annotation.push(new Output.SelectionSpan( |
| 1122 node.textSelStart || 0, | 909 node.textSelStart || 0, node.textSelEnd || 0)); |
| 1123 node.textSelEnd || 0)); | |
| 1124 | 910 |
| 1125 selectedText = | 911 selectedText = node.value.substring( |
| 1126 node.value.substring(node.textSelStart || 0, | 912 node.textSelStart || 0, node.textSelEnd || 0); |
| 1127 node.textSelEnd || 0); | |
| 1128 } | 913 } |
| 1129 options.annotation.push(token); | 914 options.annotation.push(token); |
| 1130 if (selectedText && !this.formatOptions_.braille) { | 915 if (selectedText && !this.formatOptions_.braille) { |
| 1131 this.append_(buff, selectedText, options); | 916 this.append_(buff, selectedText, options); |
| 1132 this.append_(buff, Msgs.getMsg('selected')); | 917 this.append_(buff, Msgs.getMsg('selected')); |
| 1133 } else { | 918 } else { |
| 1134 this.append_(buff, text, options); | 919 this.append_(buff, text, options); |
| 1135 } | 920 } |
| 1136 } else if (token == 'name') { | 921 } else if (token == 'name') { |
| 1137 options.annotation.push(token); | 922 options.annotation.push(token); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1148 } else if (token == 'urlFilename') { | 933 } else if (token == 'urlFilename') { |
| 1149 options.annotation.push('name'); | 934 options.annotation.push('name'); |
| 1150 var url = node.url || ''; | 935 var url = node.url || ''; |
| 1151 var filename = ''; | 936 var filename = ''; |
| 1152 if (url.substring(0, 4) != 'data') { | 937 if (url.substring(0, 4) != 'data') { |
| 1153 filename = | 938 filename = |
| 1154 url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.')); | 939 url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.')); |
| 1155 | 940 |
| 1156 // Hack to not speak the filename if it's ridiculously long. | 941 // Hack to not speak the filename if it's ridiculously long. |
| 1157 if (filename.length >= 30) | 942 if (filename.length >= 30) |
| 1158 filename = filename.substring(0, 16) + '...'; | 943 filename = filename.substring(0, 16) + '...'; |
| 1159 } | 944 } |
| 1160 this.append_(buff, filename, options); | 945 this.append_(buff, filename, options); |
| 1161 } else if (token == 'nameFromNode') { | 946 } else if (token == 'nameFromNode') { |
| 1162 if (node.nameFrom == chrome.automation.NameFromType.CONTENTS) | 947 if (node.nameFrom == chrome.automation.NameFromType.CONTENTS) |
| 1163 return; | 948 return; |
| 1164 | 949 |
| 1165 options.annotation.push('name'); | 950 options.annotation.push('name'); |
| 1166 this.append_(buff, node.name || '', options); | 951 this.append_(buff, node.name || '', options); |
| 1167 } else if (token == 'nameOrDescendants') { | 952 } else if (token == 'nameOrDescendants') { |
| 1168 options.annotation.push(token); | 953 options.annotation.push(token); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1183 if (node.role == child.role) | 968 if (node.role == child.role) |
| 1184 count++; | 969 count++; |
| 1185 if (node === child) | 970 if (node === child) |
| 1186 break; | 971 break; |
| 1187 } | 972 } |
| 1188 this.append_(buff, String(count)); | 973 this.append_(buff, String(count)); |
| 1189 } | 974 } |
| 1190 } else if (token == 'parentChildCount') { | 975 } else if (token == 'parentChildCount') { |
| 1191 if (node.parent) { | 976 if (node.parent) { |
| 1192 options.annotation.push(token); | 977 options.annotation.push(token); |
| 1193 var count = node.parent.children.filter(function(child) { | 978 var count = node.parent.children |
| 1194 return node.role == child.role; | 979 .filter(function(child) { |
| 1195 }).length; | 980 return node.role == child.role; |
| 981 }) |
| 982 .length; |
| 1196 this.append_(buff, String(count)); | 983 this.append_(buff, String(count)); |
| 1197 } | 984 } |
| 1198 } else if (token == 'checked') { | 985 } else if (token == 'checked') { |
| 1199 var msg = Output.CHECKED_STATE_MAP[node.checked]; | 986 var msg = Output.CHECKED_STATE_MAP[node.checked]; |
| 1200 if (msg) { | 987 if (msg) { |
| 1201 this.format_(node, '@' + msg, buff); | 988 this.format_(node, '@' + msg, buff); |
| 1202 } | 989 } |
| 1203 } else if (token == 'pressed') { | 990 } else if (token == 'pressed') { |
| 1204 var msg = Output.PRESSED_STATE_MAP[node.checked]; | 991 var msg = Output.PRESSED_STATE_MAP[node.checked]; |
| 1205 if (msg) { | 992 if (msg) { |
| 1206 this.format_(node, '@' + msg, buff); | 993 this.format_(node, '@' + msg, buff); |
| 1207 } | 994 } |
| 1208 } else if (token == 'state') { | 995 } else if (token == 'state') { |
| 1209 if (node.state) { | 996 if (node.state) { |
| 1210 Object.getOwnPropertyNames(node.state).forEach(function(s) { | 997 Object.getOwnPropertyNames(node.state).forEach(function(s) { |
| 1211 var stateInfo = Output.STATE_INFO_[s]; | 998 var stateInfo = Output.STATE_INFO_[s]; |
| 1212 if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) | 999 if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) |
| 1213 this.format_(node, '@' + stateInfo.on.msgId, buff); | 1000 this.format_(node, '@' + stateInfo.on.msgId, buff); |
| 1214 }.bind(this)); | 1001 }.bind(this)); |
| 1215 } | 1002 } |
| 1216 } else if (token == 'find') { | 1003 } else if (token == 'find') { |
| 1217 // Find takes two arguments: JSON query string and format string. | 1004 // Find takes two arguments: JSON query string and format string. |
| 1218 if (tree.firstChild) { | 1005 if (tree.firstChild) { |
| 1219 var jsonQuery = tree.firstChild.value; | 1006 var jsonQuery = tree.firstChild.value; |
| 1220 node = node.find( | 1007 node = node.find( |
| 1221 /** @type {chrome.automation.FindParams}*/( | 1008 /** @type {chrome.automation.FindParams}*/ ( |
| 1222 JSON.parse(jsonQuery))); | 1009 JSON.parse(jsonQuery))); |
| 1223 var formatString = tree.firstChild.nextSibling; | 1010 var formatString = tree.firstChild.nextSibling; |
| 1224 if (node) | 1011 if (node) |
| 1225 this.format_(node, formatString, buff); | 1012 this.format_(node, formatString, buff); |
| 1226 } | 1013 } |
| 1227 } else if (token == 'descendants') { | 1014 } else if (token == 'descendants') { |
| 1228 if (!node || AutomationPredicate.leafOrStaticText(node)) | 1015 if (!node || AutomationPredicate.leafOrStaticText(node)) |
| 1229 return; | 1016 return; |
| 1230 | 1017 |
| 1231 // Construct a range to the leftmost and rightmost leaves. | 1018 // Construct a range to the leftmost and rightmost leaves. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1271 this.append_(buff, msg || '', options); | 1058 this.append_(buff, msg || '', options); |
| 1272 } else if (token == 'inputType') { | 1059 } else if (token == 'inputType') { |
| 1273 if (!node.inputType) | 1060 if (!node.inputType) |
| 1274 return; | 1061 return; |
| 1275 options.annotation.push(token); | 1062 options.annotation.push(token); |
| 1276 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || | 1063 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || |
| 1277 'input_type_text'; | 1064 'input_type_text'; |
| 1278 if (this.formatOptions_.braille) | 1065 if (this.formatOptions_.braille) |
| 1279 msgId = msgId + '_brl'; | 1066 msgId = msgId + '_brl'; |
| 1280 this.append_(buff, Msgs.getMsg(msgId), options); | 1067 this.append_(buff, Msgs.getMsg(msgId), options); |
| 1281 } else if (token == 'tableCellRowIndex' || | 1068 } else if ( |
| 1282 token == 'tableCellColumnIndex') { | 1069 token == 'tableCellRowIndex' || token == 'tableCellColumnIndex') { |
| 1283 var value = node[token]; | 1070 var value = node[token]; |
| 1284 if (value == undefined) | 1071 if (value == undefined) |
| 1285 return; | 1072 return; |
| 1286 value = String(value + 1); | 1073 value = String(value + 1); |
| 1287 options.annotation.push(token); | 1074 options.annotation.push(token); |
| 1288 this.append_(buff, value, options); | 1075 this.append_(buff, value, options); |
| 1289 } else if (token == 'node') { | 1076 } else if (token == 'node') { |
| 1290 if (!tree.firstChild || !node[tree.firstChild.value]) | 1077 if (!tree.firstChild || !node[tree.firstChild.value]) |
| 1291 return; | 1078 return; |
| 1292 var related = node[tree.firstChild.value]; | 1079 var related = node[tree.firstChild.value]; |
| 1293 this.node_(related, related, Output.EventType.NAVIGATE, buff); | 1080 this.node_(related, related, Output.EventType.NAVIGATE, buff); |
| 1294 } else if (token == 'nameOrTextContent') { | 1081 } else if (token == 'nameOrTextContent') { |
| 1295 if (node.name) { | 1082 if (node.name) { |
| 1296 this.format_(node, '$name', buff); | 1083 this.format_(node, '$name', buff); |
| 1297 } else { | 1084 } else { |
| 1298 var walker = new AutomationTreeWalker(node, | 1085 var walker = new AutomationTreeWalker(node, Dir.FORWARD, { |
| 1299 Dir.FORWARD, | 1086 visit: AutomationPredicate.leafOrStaticText, |
| 1300 {visit: AutomationPredicate.leafOrStaticText, | 1087 leaf: AutomationPredicate.leafOrStaticText |
| 1301 leaf: AutomationPredicate.leafOrStaticText}); | 1088 }); |
| 1302 var outputStrings = []; | 1089 var outputStrings = []; |
| 1303 while (walker.next().node && | 1090 while (walker.next().node && |
| 1304 walker.phase == AutomationTreeWalkerPhase.DESCENDANT) { | 1091 walker.phase == AutomationTreeWalkerPhase.DESCENDANT) { |
| 1305 if (walker.node.name) | 1092 if (walker.node.name) |
| 1306 outputStrings.push(walker.node.name); | 1093 outputStrings.push(walker.node.name); |
| 1307 } | 1094 } |
| 1308 var joinedOutput = outputStrings.join(' '); | 1095 var joinedOutput = outputStrings.join(' '); |
| 1309 this.append_(buff, joinedOutput, options); | 1096 this.append_(buff, joinedOutput, options); |
| 1310 } | 1097 } |
| 1311 } else if (node[token] !== undefined) { | 1098 } else if (node[token] !== undefined) { |
| 1312 options.annotation.push(token); | 1099 options.annotation.push(token); |
| 1313 var value = node[token]; | 1100 var value = node[token]; |
| 1314 if (typeof value == 'number') | 1101 if (typeof value == 'number') |
| 1315 value = String(value); | 1102 value = String(value); |
| 1316 this.append_(buff, value, options); | 1103 this.append_(buff, value, options); |
| 1317 } else if (Output.STATE_INFO_[token]) { | 1104 } else if (Output.STATE_INFO_[token]) { |
| 1318 options.annotation.push('state'); | 1105 options.annotation.push('state'); |
| 1319 var stateInfo = Output.STATE_INFO_[token]; | 1106 var stateInfo = Output.STATE_INFO_[token]; |
| 1320 var resolvedInfo = {}; | 1107 var resolvedInfo = {}; |
| 1321 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; | 1108 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; |
| 1322 if (!resolvedInfo) | 1109 if (!resolvedInfo) |
| 1323 return; | 1110 return; |
| 1324 if (this.formatOptions_.speech && resolvedInfo.earconId) { | 1111 if (this.formatOptions_.speech && resolvedInfo.earconId) { |
| 1325 options.annotation.push( | 1112 options.annotation.push( |
| 1326 new Output.EarconAction(resolvedInfo.earconId), | 1113 new Output.EarconAction(resolvedInfo.earconId), |
| 1327 node.location || undefined); | 1114 node.location || undefined); |
| 1328 } | 1115 } |
| 1329 var msgId = | 1116 var msgId = this.formatOptions_.braille ? |
| 1330 this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' : | 1117 resolvedInfo.msgId + '_brl' : |
| 1331 resolvedInfo.msgId; | 1118 resolvedInfo.msgId; |
| 1332 var msg = Msgs.getMsg(msgId); | 1119 var msg = Msgs.getMsg(msgId); |
| 1333 this.append_(buff, msg, options); | 1120 this.append_(buff, msg, options); |
| 1334 } else if (tree.firstChild) { | 1121 } else if (tree.firstChild) { |
| 1335 // Custom functions. | 1122 // Custom functions. |
| 1336 if (token == 'if') { | 1123 if (token == 'if') { |
| 1337 var cond = tree.firstChild; | 1124 var cond = tree.firstChild; |
| 1338 var attrib = cond.value.slice(1); | 1125 var attrib = cond.value.slice(1); |
| 1339 if (Output.isTruthy(node, attrib)) | 1126 if (Output.isTruthy(node, attrib)) |
| 1340 this.format_(node, cond.nextSibling, buff); | 1127 this.format_(node, cond.nextSibling, buff); |
| 1341 else | 1128 else |
| 1342 this.format_(node, cond.nextSibling.nextSibling, buff); | 1129 this.format_(node, cond.nextSibling.nextSibling, buff); |
| 1343 } else if (token == 'earcon') { | 1130 } else if (token == 'earcon') { |
| 1344 // Ignore unless we're generating speech output. | 1131 // Ignore unless we're generating speech output. |
| 1345 if (!this.formatOptions_.speech) | 1132 if (!this.formatOptions_.speech) |
| 1346 return; | 1133 return; |
| 1347 | 1134 |
| 1348 options.annotation.push( | 1135 options.annotation.push(new Output.EarconAction( |
| 1349 new Output.EarconAction(tree.firstChild.value, | 1136 tree.firstChild.value, node.location || undefined)); |
| 1350 node.location || undefined)); | |
| 1351 this.append_(buff, '', options); | 1137 this.append_(buff, '', options); |
| 1352 } else if (token == 'countChildren') { | 1138 } else if (token == 'countChildren') { |
| 1353 var role = tree.firstChild.value; | 1139 var role = tree.firstChild.value; |
| 1354 var count = node.children.filter(function(e) { | 1140 var count = node.children |
| 1355 return e.role == role; | 1141 .filter(function(e) { |
| 1356 }).length; | 1142 return e.role == role; |
| 1143 }) |
| 1144 .length; |
| 1357 this.append_(buff, String(count)); | 1145 this.append_(buff, String(count)); |
| 1358 } | 1146 } |
| 1359 } | 1147 } |
| 1360 } else if (prefix == '@') { | 1148 } else if (prefix == '@') { |
| 1361 if (this.formatOptions_.auralStyle) { | 1149 if (this.formatOptions_.auralStyle) { |
| 1362 speechProps = new Output.SpeechProperties(); | 1150 speechProps = new Output.SpeechProperties(); |
| 1363 speechProps['relativePitch'] = -0.2; | 1151 speechProps['relativePitch'] = -0.2; |
| 1364 } | 1152 } |
| 1365 var isPluralized = (token[0] == '@'); | 1153 var isPluralized = (token[0] == '@'); |
| 1366 if (isPluralized) | 1154 if (isPluralized) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1388 if (!msgBuff.length) | 1176 if (!msgBuff.length) |
| 1389 msgBuff = ['']; | 1177 msgBuff = ['']; |
| 1390 msgArgs = msgArgs.concat(msgBuff); | 1178 msgArgs = msgArgs.concat(msgBuff); |
| 1391 curArg = curArg.nextSibling; | 1179 curArg = curArg.nextSibling; |
| 1392 } | 1180 } |
| 1393 } | 1181 } |
| 1394 var msg = Msgs.getMsg(msgId, msgArgs); | 1182 var msg = Msgs.getMsg(msgId, msgArgs); |
| 1395 try { | 1183 try { |
| 1396 if (this.formatOptions_.braille) | 1184 if (this.formatOptions_.braille) |
| 1397 msg = Msgs.getMsg(msgId + '_brl', msgArgs) || msg; | 1185 msg = Msgs.getMsg(msgId + '_brl', msgArgs) || msg; |
| 1398 } catch(e) {} | 1186 } catch (e) { |
| 1187 } |
| 1399 | 1188 |
| 1400 if (!msg) { | 1189 if (!msg) { |
| 1401 console.error('Could not get message ' + msgId); | 1190 console.error('Could not get message ' + msgId); |
| 1402 return; | 1191 return; |
| 1403 } | 1192 } |
| 1404 | 1193 |
| 1405 if (isPluralized) { | 1194 if (isPluralized) { |
| 1406 var arg = tree.firstChild; | 1195 var arg = tree.firstChild; |
| 1407 if (!arg || arg.nextSibling) { | 1196 if (!arg || arg.nextSibling) { |
| 1408 console.error('Pluralized messages take exactly one argument'); | 1197 console.error('Pluralized messages take exactly one argument'); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1474 this.ancestry_(node, prevNode, type, buff); | 1263 this.ancestry_(node, prevNode, type, buff); |
| 1475 this.node_(node, prevNode, type, buff); | 1264 this.node_(node, prevNode, type, buff); |
| 1476 if (!this.outputContextFirst_) | 1265 if (!this.outputContextFirst_) |
| 1477 this.ancestry_(node, prevNode, type, buff); | 1266 this.ancestry_(node, prevNode, type, buff); |
| 1478 if (node.location) | 1267 if (node.location) |
| 1479 this.locations_.push(node.location); | 1268 this.locations_.push(node.location); |
| 1480 return buff; | 1269 return buff; |
| 1481 }.bind(this); | 1270 }.bind(this); |
| 1482 | 1271 |
| 1483 var unit = range.isInlineText() ? cursors.Unit.TEXT : cursors.Unit.NODE; | 1272 var unit = range.isInlineText() ? cursors.Unit.TEXT : cursors.Unit.NODE; |
| 1484 while (cursor.node && | 1273 while (cursor.node && range.end.node && |
| 1485 range.end.node && | 1274 AutomationUtil.getDirection(cursor.node, range.end.node) == |
| 1486 AutomationUtil.getDirection(cursor.node, range.end.node) == | 1275 Dir.FORWARD) { |
| 1487 Dir.FORWARD) { | |
| 1488 var node = cursor.node; | 1276 var node = cursor.node; |
| 1489 rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode)); | 1277 rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode)); |
| 1490 prevNode = node; | 1278 prevNode = node; |
| 1491 cursor = cursor.move(unit, | 1279 cursor = cursor.move(unit, cursors.Movement.DIRECTIONAL, Dir.FORWARD); |
| 1492 cursors.Movement.DIRECTIONAL, | |
| 1493 Dir.FORWARD); | |
| 1494 | 1280 |
| 1495 // Reached a boundary. | 1281 // Reached a boundary. |
| 1496 if (cursor.node == prevNode) | 1282 if (cursor.node == prevNode) |
| 1497 break; | 1283 break; |
| 1498 } | 1284 } |
| 1499 }, | 1285 }, |
| 1500 | 1286 |
| 1501 /** | 1287 /** |
| 1502 * @param {!AutomationNode} node | 1288 * @param {!AutomationNode} node |
| 1503 * @param {!AutomationNode} prevNode | 1289 * @param {!AutomationNode} prevNode |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1518 contextFirst = []; | 1304 contextFirst = []; |
| 1519 rest = []; | 1305 rest = []; |
| 1520 } | 1306 } |
| 1521 if ((Output.ROLE_INFO_[node.role] || {}).outputContextFirst) | 1307 if ((Output.ROLE_INFO_[node.role] || {}).outputContextFirst) |
| 1522 contextFirst.push(node); | 1308 contextFirst.push(node); |
| 1523 else | 1309 else |
| 1524 rest.push(node); | 1310 rest.push(node); |
| 1525 } | 1311 } |
| 1526 return rest.concat(contextFirst.reverse()); | 1312 return rest.concat(contextFirst.reverse()); |
| 1527 } | 1313 } |
| 1528 var prevUniqueAncestors = byContextFirst(AutomationUtil.getUniqueAncestors( | 1314 var prevUniqueAncestors = |
| 1529 node, prevNode)); | 1315 byContextFirst(AutomationUtil.getUniqueAncestors(node, prevNode)); |
| 1530 var uniqueAncestors = byContextFirst(AutomationUtil.getUniqueAncestors( | 1316 var uniqueAncestors = |
| 1531 prevNode, node)); | 1317 byContextFirst(AutomationUtil.getUniqueAncestors(prevNode, node)); |
| 1532 | 1318 |
| 1533 // First, look up the event type's format block. | 1319 // First, look up the event type's format block. |
| 1534 // Navigate is the default event. | 1320 // Navigate is the default event. |
| 1535 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; | 1321 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; |
| 1536 | 1322 |
| 1537 var getMergedRoleBlock = function(role) { | 1323 var getMergedRoleBlock = function(role) { |
| 1538 var parentRole = (Output.ROLE_INFO_[role] || {}).inherits; | 1324 var parentRole = (Output.ROLE_INFO_[role] || {}).inherits; |
| 1539 var roleBlock = eventBlock[role] || eventBlock['default']; | 1325 var roleBlock = eventBlock[role] || eventBlock['default']; |
| 1540 var parentRoleBlock = parentRole ? eventBlock[parentRole] : {}; | 1326 var parentRoleBlock = parentRole ? eventBlock[parentRole] : {}; |
| 1541 var mergedRoleBlock = {}; | 1327 var mergedRoleBlock = {}; |
| 1542 for (var key in parentRoleBlock) | 1328 for (var key in parentRoleBlock) |
| 1543 mergedRoleBlock[key] = parentRoleBlock[key]; | 1329 mergedRoleBlock[key] = parentRoleBlock[key]; |
| 1544 for (var key in roleBlock) | 1330 for (var key in roleBlock) |
| 1545 mergedRoleBlock[key] = roleBlock[key]; | 1331 mergedRoleBlock[key] = roleBlock[key]; |
| 1546 return mergedRoleBlock; | 1332 return mergedRoleBlock; |
| 1547 }; | 1333 }; |
| 1548 | 1334 |
| 1549 // Hash the roles we've entered. | 1335 // Hash the roles we've entered. |
| 1550 var enteredRoleSet = {}; | 1336 var enteredRoleSet = {}; |
| 1551 for (var j = uniqueAncestors.length - 1, hashNode; | 1337 for (var j = uniqueAncestors.length - 1, hashNode; |
| 1552 (hashNode = uniqueAncestors[j]); | 1338 (hashNode = uniqueAncestors[j]); j--) |
| 1553 j--) | |
| 1554 enteredRoleSet[hashNode.role] = true; | 1339 enteredRoleSet[hashNode.role] = true; |
| 1555 | 1340 |
| 1556 for (var i = 0, formatPrevNode; | 1341 for (var i = 0, formatPrevNode; (formatPrevNode = prevUniqueAncestors[i]); |
| 1557 (formatPrevNode = prevUniqueAncestors[i]); | |
| 1558 i++) { | 1342 i++) { |
| 1559 // This prevents very repetitive announcements. | 1343 // This prevents very repetitive announcements. |
| 1560 if (enteredRoleSet[formatPrevNode.role] || | 1344 if (enteredRoleSet[formatPrevNode.role] || |
| 1561 node.role == formatPrevNode.role || | 1345 node.role == formatPrevNode.role || |
| 1562 localStorage['useVerboseMode'] == 'false') | 1346 localStorage['useVerboseMode'] == 'false') |
| 1563 continue; | 1347 continue; |
| 1564 | 1348 |
| 1565 var roleBlock = getMergedRoleBlock(formatPrevNode.role); | 1349 var roleBlock = getMergedRoleBlock(formatPrevNode.role); |
| 1566 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') | 1350 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') |
| 1567 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode); | 1351 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode); |
| 1568 } | 1352 } |
| 1569 | 1353 |
| 1570 // Customize for braille node annotations. | 1354 // Customize for braille node annotations. |
| 1571 var originalBuff = buff; | 1355 var originalBuff = buff; |
| 1572 var enterRole = {}; | 1356 var enterRole = {}; |
| 1573 for (var j = uniqueAncestors.length - 1, formatNode; | 1357 for (var j = uniqueAncestors.length - 1, formatNode; |
| 1574 (formatNode = uniqueAncestors[j]); | 1358 (formatNode = uniqueAncestors[j]); j--) { |
| 1575 j--) { | |
| 1576 var roleBlock = getMergedRoleBlock(formatNode.role); | 1359 var roleBlock = getMergedRoleBlock(formatNode.role); |
| 1577 if (roleBlock.enter) { | 1360 if (roleBlock.enter) { |
| 1578 if (enterRole[formatNode.role]) | 1361 if (enterRole[formatNode.role]) |
| 1579 continue; | 1362 continue; |
| 1580 | 1363 |
| 1581 if (this.formatOptions_.braille) | 1364 if (this.formatOptions_.braille) |
| 1582 buff = []; | 1365 buff = []; |
| 1583 | 1366 |
| 1584 enterRole[formatNode.role] = true; | 1367 enterRole[formatNode.role] = true; |
| 1585 this.format_(formatNode, roleBlock.enter, buff, prevNode); | 1368 this.format_(formatNode, roleBlock.enter, buff, prevNode); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1604 var originalBuff = buff; | 1387 var originalBuff = buff; |
| 1605 | 1388 |
| 1606 if (this.formatOptions_.braille) | 1389 if (this.formatOptions_.braille) |
| 1607 buff = []; | 1390 buff = []; |
| 1608 | 1391 |
| 1609 // Navigate is the default event. | 1392 // Navigate is the default event. |
| 1610 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; | 1393 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; |
| 1611 var roleBlock = eventBlock[node.role] || {}; | 1394 var roleBlock = eventBlock[node.role] || {}; |
| 1612 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; | 1395 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; |
| 1613 var parentRoleBlock = eventBlock[parentRole || ''] || {}; | 1396 var parentRoleBlock = eventBlock[parentRole || ''] || {}; |
| 1614 var speakFormat = roleBlock.speak || | 1397 var speakFormat = |
| 1615 parentRoleBlock.speak || | 1398 roleBlock.speak || parentRoleBlock.speak || eventBlock['default'].speak; |
| 1616 eventBlock['default'].speak; | |
| 1617 | 1399 |
| 1618 this.format_(node, speakFormat, buff, prevNode); | 1400 this.format_(node, speakFormat, buff, prevNode); |
| 1619 | 1401 |
| 1620 // Restore braille and add an annotation for this node. | 1402 // Restore braille and add an annotation for this node. |
| 1621 if (this.formatOptions_.braille) { | 1403 if (this.formatOptions_.braille) { |
| 1622 var nodeSpan = this.mergeBraille_(buff); | 1404 var nodeSpan = this.mergeBraille_(buff); |
| 1623 nodeSpan.setSpan(new Output.NodeSpan(node), 0, nodeSpan.length); | 1405 nodeSpan.setSpan(new Output.NodeSpan(node), 0, nodeSpan.length); |
| 1624 originalBuff.push(nodeSpan); | 1406 originalBuff.push(nodeSpan); |
| 1625 } | 1407 } |
| 1626 }, | 1408 }, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1642 return; | 1424 return; |
| 1643 | 1425 |
| 1644 var options = {annotation: ['name'], isUnique: true}; | 1426 var options = {annotation: ['name'], isUnique: true}; |
| 1645 var rangeStart = range.start.index; | 1427 var rangeStart = range.start.index; |
| 1646 var rangeEnd = range.end.index; | 1428 var rangeEnd = range.end.index; |
| 1647 if (this.formatOptions_.braille) { | 1429 if (this.formatOptions_.braille) { |
| 1648 options.annotation.push(new Output.NodeSpan(node)); | 1430 options.annotation.push(new Output.NodeSpan(node)); |
| 1649 var selStart = node.textSelStart; | 1431 var selStart = node.textSelStart; |
| 1650 var selEnd = node.textSelEnd; | 1432 var selEnd = node.textSelEnd; |
| 1651 | 1433 |
| 1652 if (selStart !== undefined && | 1434 if (selStart !== undefined && selEnd >= rangeStart && |
| 1653 selEnd >= rangeStart && selStart <= rangeEnd) { | 1435 selStart <= rangeEnd) { |
| 1654 // Editable text selection. | 1436 // Editable text selection. |
| 1655 | 1437 |
| 1656 // |rangeStart| and |rangeEnd| are indices set by the caller and are | 1438 // |rangeStart| and |rangeEnd| are indices set by the caller and are |
| 1657 // assumed to be inside of the range. In braille, we only ever expect to | 1439 // assumed to be inside of the range. In braille, we only ever expect to |
| 1658 // get ranges surrounding a line as anything smaller doesn't make sense. | 1440 // get ranges surrounding a line as anything smaller doesn't make sense. |
| 1659 | 1441 |
| 1660 // |selStart| and |selEnd| reflect the editable selection. The relative | 1442 // |selStart| and |selEnd| reflect the editable selection. The relative |
| 1661 // selStart and relative selEnd for the current line are then just the | 1443 // selStart and relative selEnd for the current line are then just the |
| 1662 // difference between |selStart|, |selEnd| with |rangeStart|. | 1444 // difference between |selStart|, |selEnd| with |rangeStart|. |
| 1663 // See editing_test.js for examples. | 1445 // See editing_test.js for examples. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1685 } else { | 1467 } else { |
| 1686 // This is output for speech or editable braille. | 1468 // This is output for speech or editable braille. |
| 1687 text = range.start.getText().substring(rangeStart, rangeEnd); | 1469 text = range.start.getText().substring(rangeStart, rangeEnd); |
| 1688 } | 1470 } |
| 1689 | 1471 |
| 1690 this.append_(buff, text, options); | 1472 this.append_(buff, text, options); |
| 1691 | 1473 |
| 1692 if (!this.outputContextFirst_) | 1474 if (!this.outputContextFirst_) |
| 1693 this.ancestry_(node, prevNode, type, buff); | 1475 this.ancestry_(node, prevNode, type, buff); |
| 1694 | 1476 |
| 1695 var loc = | 1477 var loc = range.start.node.boundsForRange(rangeStart, rangeEnd); |
| 1696 range.start.node.boundsForRange(rangeStart, rangeEnd); | |
| 1697 if (loc) | 1478 if (loc) |
| 1698 this.locations_.push(loc); | 1479 this.locations_.push(loc); |
| 1699 }, | 1480 }, |
| 1700 | 1481 |
| 1701 /** | 1482 /** |
| 1702 * Appends output to the |buff|. | 1483 * Appends output to the |buff|. |
| 1703 * @param {!Array<Spannable>} buff | 1484 * @param {!Array<Spannable>} buff |
| 1704 * @param {string|!Spannable} value | 1485 * @param {string|!Spannable} value |
| 1705 * @param {{isUnique: (boolean|undefined), | 1486 * @param {{isUnique: (boolean|undefined), |
| 1706 * annotation: !Array<*>}=} opt_options | 1487 * annotation: !Array<*>}=} opt_options |
| 1707 */ | 1488 */ |
| 1708 append_: function(buff, value, opt_options) { | 1489 append_: function(buff, value, opt_options) { |
| 1709 opt_options = opt_options || {isUnique: false, annotation: []}; | 1490 opt_options = opt_options || {isUnique: false, annotation: []}; |
| 1710 | 1491 |
| 1711 // Reject empty values without meaningful annotations. | 1492 // Reject empty values without meaningful annotations. |
| 1712 if ((!value || value.length == 0) && opt_options.annotation.every( | 1493 if ((!value || value.length == 0) && |
| 1713 function(a) { | 1494 opt_options.annotation.every(function(a) { |
| 1714 return !(a instanceof Output.Action) && | 1495 return !(a instanceof Output.Action) && |
| 1715 !(a instanceof Output.SelectionSpan); | 1496 !(a instanceof Output.SelectionSpan); |
| 1716 | 1497 |
| 1717 })) | 1498 })) |
| 1718 return; | 1499 return; |
| 1719 | 1500 |
| 1720 var spannableToAdd = new Spannable(value); | 1501 var spannableToAdd = new Spannable(value); |
| 1721 opt_options.annotation.forEach(function(a) { | 1502 opt_options.annotation.forEach(function(a) { |
| 1722 spannableToAdd.setSpan(a, 0, spannableToAdd.length); | 1503 spannableToAdd.setSpan(a, 0, spannableToAdd.length); |
| 1723 }); | 1504 }); |
| 1724 | 1505 |
| 1725 // |isUnique| specifies an annotation that cannot be duplicated. | 1506 // |isUnique| specifies an annotation that cannot be duplicated. |
| 1726 if (opt_options.isUnique) { | 1507 if (opt_options.isUnique) { |
| 1727 var annotationSansNodes = opt_options.annotation.filter( | 1508 var annotationSansNodes = |
| 1728 function(annotation) { | 1509 opt_options.annotation.filter(function(annotation) { |
| 1729 return !(annotation instanceof Output.NodeSpan); | 1510 return !(annotation instanceof Output.NodeSpan); |
| 1730 }); | 1511 }); |
| 1731 | 1512 |
| 1732 var alreadyAnnotated = buff.some(function(s) { | 1513 var alreadyAnnotated = buff.some(function(s) { |
| 1733 return annotationSansNodes.some(function(annotation) { | 1514 return annotationSansNodes.some(function(annotation) { |
| 1734 if (!s.hasSpan(annotation)) | 1515 if (!s.hasSpan(annotation)) |
| 1735 return false; | 1516 return false; |
| 1736 var start = s.getSpanStart(annotation); | 1517 var start = s.getSpanStart(annotation); |
| 1737 var end = s.getSpanEnd(annotation); | 1518 var end = s.getSpanEnd(annotation); |
| 1738 var substr = s.substring(start, end); | 1519 var substr = s.substring(start, end); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1809 // showing the braille cursor. | 1590 // showing the braille cursor. |
| 1810 if (cur.length == 0 && hasSelection) { | 1591 if (cur.length == 0 && hasSelection) { |
| 1811 result.append(cur); | 1592 result.append(cur); |
| 1812 result.append(Output.SPACE); | 1593 result.append(Output.SPACE); |
| 1813 separator = ''; | 1594 separator = ''; |
| 1814 return result; | 1595 return result; |
| 1815 } | 1596 } |
| 1816 | 1597 |
| 1817 // Keep track of if there's an inline node associated with | 1598 // Keep track of if there's an inline node associated with |
| 1818 // |cur|. | 1599 // |cur|. |
| 1819 var hasInlineNode = cur.getSpansInstanceOf(Output.NodeSpan) | 1600 var hasInlineNode = |
| 1820 .some(function(s) { | 1601 cur.getSpansInstanceOf(Output.NodeSpan).some(function(s) { |
| 1821 if (!s.node) | 1602 if (!s.node) |
| 1822 return false; | 1603 return false; |
| 1823 return s.node.display == 'inline' || | 1604 return s.node.display == 'inline' || |
| 1824 s.node.role == RoleType.INLINE_TEXT_BOX; | 1605 s.node.role == RoleType.INLINE_TEXT_BOX; |
| 1825 }); | 1606 }); |
| 1826 | 1607 |
| 1827 var isName = cur.hasSpan('name'); | 1608 var isName = cur.hasSpan('name'); |
| 1828 | 1609 |
| 1829 // Now, decide whether we should include separators between the previous | 1610 // Now, decide whether we should include separators between the previous |
| 1830 // span and |cur|. | 1611 // span and |cur|. |
| 1831 // Never separate chunks without something already there at this point. | 1612 // Never separate chunks without something already there at this point. |
| 1832 | 1613 |
| 1833 // The only case where we know for certain that a separator is not needed | 1614 // The only case where we know for certain that a separator is not needed |
| 1834 // is when the previous and current values are in-lined and part of the | 1615 // is when the previous and current values are in-lined and part of the |
| 1835 // node's name. In all other cases, use the surrounding whitespace to | 1616 // node's name. In all other cases, use the surrounding whitespace to |
| 1836 // ensure we only have one separator between the node text. | 1617 // ensure we only have one separator between the node text. |
| 1837 if (result.length == 0 || | 1618 if (result.length == 0 || |
| 1838 (hasInlineNode && prevHasInlineNode && isName && prevIsName)) | 1619 (hasInlineNode && prevHasInlineNode && isName && prevIsName)) |
| 1839 separator = ''; | 1620 separator = ''; |
| 1840 else if (result.toString()[result.length - 1] == Output.SPACE || | 1621 else if ( |
| 1622 result.toString()[result.length - 1] == Output.SPACE || |
| 1841 cur.toString()[0] == Output.SPACE) | 1623 cur.toString()[0] == Output.SPACE) |
| 1842 separator = ''; | 1624 separator = ''; |
| 1843 else | 1625 else |
| 1844 separator = Output.SPACE; | 1626 separator = Output.SPACE; |
| 1845 | 1627 |
| 1846 prevHasInlineNode = hasInlineNode; | 1628 prevHasInlineNode = hasInlineNode; |
| 1847 prevIsName = isName; | 1629 prevIsName = isName; |
| 1848 result.append(separator); | 1630 result.append(separator); |
| 1849 result.append(cur); | 1631 result.append(cur); |
| 1850 return result; | 1632 return result; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1865 var earconFinder = node; | 1647 var earconFinder = node; |
| 1866 var ancestors; | 1648 var ancestors; |
| 1867 if (opt_prevNode) | 1649 if (opt_prevNode) |
| 1868 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); | 1650 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); |
| 1869 else | 1651 else |
| 1870 ancestors = AutomationUtil.getAncestors(node); | 1652 ancestors = AutomationUtil.getAncestors(node); |
| 1871 | 1653 |
| 1872 while (earconFinder = ancestors.pop()) { | 1654 while (earconFinder = ancestors.pop()) { |
| 1873 var info = Output.ROLE_INFO_[earconFinder.role]; | 1655 var info = Output.ROLE_INFO_[earconFinder.role]; |
| 1874 if (info && info.earconId) { | 1656 if (info && info.earconId) { |
| 1875 return new Output.EarconAction(info.earconId, | 1657 return new Output.EarconAction( |
| 1876 node.location || undefined); | 1658 info.earconId, node.location || undefined); |
| 1877 break; | 1659 break; |
| 1878 } | 1660 } |
| 1879 earconFinder = earconFinder.parent; | 1661 earconFinder = earconFinder.parent; |
| 1880 } | 1662 } |
| 1881 } | 1663 } |
| 1882 return null; | 1664 return null; |
| 1883 }, | 1665 }, |
| 1884 | 1666 |
| 1885 /** | 1667 /** |
| 1886 * Gets a human friendly string with the contents of output. | 1668 * Gets a human friendly string with the contents of output. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1912 /** | 1694 /** |
| 1913 * Gets the output buffer for braille. | 1695 * Gets the output buffer for braille. |
| 1914 * @return {!Spannable} | 1696 * @return {!Spannable} |
| 1915 */ | 1697 */ |
| 1916 get brailleOutputForTest() { | 1698 get brailleOutputForTest() { |
| 1917 return this.mergeBraille_(this.brailleBuffer_); | 1699 return this.mergeBraille_(this.brailleBuffer_); |
| 1918 } | 1700 } |
| 1919 }; | 1701 }; |
| 1920 | 1702 |
| 1921 }); // goog.scope | 1703 }); // goog.scope |
| OLD | NEW |