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 |