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 |