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 22 matching lines...) Expand all Loading... |
33 * an AutomationNode. Specialized values include role and state. Attributes | 33 * an AutomationNode. Specialized values include role and state. Attributes |
34 * available for substitution are AutomationNode.prototype.attributes and | 34 * available for substitution are AutomationNode.prototype.attributes and |
35 * AutomationNode.prototype.state. | 35 * AutomationNode.prototype.state. |
36 * For example, $value $role $enabled | 36 * For example, $value $role $enabled |
37 * @ prefix: used to substitute a message. Note the ability to specify params to | 37 * @ prefix: used to substitute a message. Note the ability to specify params to |
38 * the message. For example, '@tag_html' '@selected_index($text_sel_start, | 38 * the message. For example, '@tag_html' '@selected_index($text_sel_start, |
39 * $text_sel_end'). | 39 * $text_sel_end'). |
40 * = suffix: used to specify substitution only if not previously appended. | 40 * = suffix: used to specify substitution only if not previously appended. |
41 * For example, $name= would insert the name attribute only if no name | 41 * For example, $name= would insert the name attribute only if no name |
42 * attribute had been inserted previously. | 42 * attribute had been inserted previously. |
43 * @param {!cursors.Range} range | |
44 * @param {cursors.Range} prevRange | |
45 * @param {chrome.automation.EventType|Output.EventType} type | |
46 * @param {{braille: (boolean|undefined), speech: (boolean|undefined)}=} | |
47 * opt_options | |
48 * @constructor | 43 * @constructor |
49 */ | 44 */ |
50 Output = function(range, prevRange, type, opt_options) { | 45 Output = function() { |
51 opt_options = opt_options || {braille: true, speech: true}; | |
52 // TODO(dtseng): Include braille specific rules. | 46 // TODO(dtseng): Include braille specific rules. |
53 /** @type {!cvox.Spannable} */ | 47 /** @type {!cvox.Spannable} */ |
54 this.buffer_ = new cvox.Spannable(); | 48 this.buffer_ = new cvox.Spannable(); |
55 /** @type {!cvox.Spannable} */ | 49 /** @type {!cvox.Spannable} */ |
56 this.brailleBuffer_ = new cvox.Spannable(); | 50 this.brailleBuffer_ = new cvox.Spannable(); |
57 /** @type {!Array.<Object>} */ | 51 /** @type {!Array.<Object>} */ |
58 this.locations_ = []; | 52 this.locations_ = []; |
| 53 /** @type {function()} */ |
| 54 this.speechStartCallback_ = function() {}; |
| 55 /** @type {function()} */ |
| 56 this.speechEndCallback_ = function() {}; |
| 57 /** @type {function()} */ |
| 58 this.speechInterruptedCallback_ = function() {}; |
59 | 59 |
60 /** | 60 /** |
61 * Current global options. | 61 * Current global options. |
62 * @type {{speech: boolean, braille: boolean, location: boolean}} | 62 * @type {{speech: boolean, braille: boolean, location: boolean}} |
63 */ | 63 */ |
64 this.formatOptions_ = {speech: true, braille: false, location: true}; | 64 this.formatOptions_ = {speech: true, braille: false, location: true}; |
65 | |
66 this.render_(range, prevRange, type); | |
67 if (opt_options.speech) | |
68 this.handleSpeech(); | |
69 if (opt_options.braille) | |
70 this.handleBraille(); | |
71 this.handleDisplay(); | |
72 }; | 65 }; |
73 | 66 |
74 /** | 67 /** |
75 * Delimiter to use between output values. | 68 * Delimiter to use between output values. |
76 * @type {string} | 69 * @type {string} |
77 */ | 70 */ |
78 Output.SPACE = ' '; | 71 Output.SPACE = ' '; |
79 | 72 |
80 /** | 73 /** |
81 * Rules specifying format of AutomationNodes for output. | 74 * Rules specifying format of AutomationNodes for output. |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 Output.prototype = { | 226 Output.prototype = { |
234 /** | 227 /** |
235 * Gets the output buffer for speech. | 228 * Gets the output buffer for speech. |
236 * @return {!cvox.Spannable} | 229 * @return {!cvox.Spannable} |
237 */ | 230 */ |
238 getBuffer: function() { | 231 getBuffer: function() { |
239 return this.buffer_; | 232 return this.buffer_; |
240 }, | 233 }, |
241 | 234 |
242 /** | 235 /** |
243 * Handle output to speech. | 236 * Specify ranges for speech. |
| 237 * @param {!cursors.Range} range |
| 238 * @param {cursors.Range} prevRange |
| 239 * @param {chrome.automation.EventType|Output.EventType} type |
| 240 * @return {!Output} |
244 */ | 241 */ |
245 handleSpeech: function() { | 242 withSpeech: function(range, prevRange, type) { |
| 243 this.formatOptions_ = {speech: true, braille: false, location: true}; |
| 244 this.render_(range, prevRange, type, this.buffer_); |
| 245 return this; |
| 246 }, |
| 247 |
| 248 /** |
| 249 * Specify ranges for braille. |
| 250 * @param {!cursors.Range} range |
| 251 * @param {cursors.Range} prevRange |
| 252 * @param {chrome.automation.EventType|Output.EventType} type |
| 253 * @return {!Output} |
| 254 */ |
| 255 withBraille: function(range, prevRange, type) { |
| 256 this.formatOptions_ = {speech: false, braille: true, location: false}; |
| 257 this.render_(range, prevRange, type, this.brailleBuffer_); |
| 258 return this; |
| 259 }, |
| 260 |
| 261 /** |
| 262 * Specify the same ranges for speech and braille. |
| 263 * @param {!cursors.Range} range |
| 264 * @param {cursors.Range} prevRange |
| 265 * @param {chrome.automation.EventType|Output.EventType} type |
| 266 * @return {!Output} |
| 267 */ |
| 268 withSpeechAndBraille: function(range, prevRange, type) { |
| 269 this.withSpeech(range, prevRange, type); |
| 270 this.withBraille(range, prevRange, type); |
| 271 return this; |
| 272 }, |
| 273 |
| 274 /** |
| 275 * Triggers callback for a speech event. |
| 276 * @param {function()} callback |
| 277 */ |
| 278 onSpeechStart: function(callback) { |
| 279 this.speechStartCallback_ = callback; |
| 280 return this; |
| 281 }, |
| 282 |
| 283 /** |
| 284 * Triggers callback for a speech event. |
| 285 * @param {function()} callback |
| 286 */ |
| 287 onSpeechEnd: function(callback) { |
| 288 this.speechEndCallback_ = callback; |
| 289 return this; |
| 290 }, |
| 291 |
| 292 /** |
| 293 * Triggers callback for a speech event. |
| 294 * @param {function()} callback |
| 295 */ |
| 296 onSpeechInterrupted: function(callback) { |
| 297 this.speechInterruptedCallback_ = callback; |
| 298 return this; |
| 299 }, |
| 300 |
| 301 /** |
| 302 * Executes all specified output. |
| 303 */ |
| 304 go: function() { |
| 305 // Speech. |
246 var buff = this.buffer_; | 306 var buff = this.buffer_; |
247 if (!buff.toString()) | |
248 return; | |
249 | 307 |
250 cvox.ChromeVox.tts.speak(buff.toString(), cvox.QueueMode.FLUSH); | 308 var onEvent = function(evt) { |
| 309 switch (evt.type) { |
| 310 case 'start': this.speechStartCallback_(); break; |
| 311 case 'end': this.speechEndCallback_(); break; |
| 312 case 'interrupted': this.speechInterruptedCallback_(); break; |
| 313 } |
| 314 }.bind(this); |
| 315 |
| 316 if (buff.toString()) { |
| 317 cvox.ChromeVox.tts.speak( |
| 318 buff.toString(), cvox.QueueMode.FLUSH, {onEvent: onEvent}); |
| 319 } |
| 320 |
251 var actions = buff.getSpansInstanceOf(Output.Action); | 321 var actions = buff.getSpansInstanceOf(Output.Action); |
252 if (actions) { | 322 if (actions) { |
253 actions.forEach(function(a) { | 323 actions.forEach(function(a) { |
254 a.run(); | 324 a.run(); |
255 }); | 325 }); |
256 } | 326 } |
257 }, | |
258 | 327 |
259 /** | 328 // Braille. |
260 * Handles output to braille. | |
261 */ | |
262 handleBraille: function() { | |
263 var selSpan = | 329 var selSpan = |
264 this.brailleBuffer_.getSpanInstanceOf(Output.SelectionSpan); | 330 this.brailleBuffer_.getSpanInstanceOf(Output.SelectionSpan); |
265 var startIndex = -1, endIndex = -1; | 331 var startIndex = -1, endIndex = -1; |
266 if (selSpan) { | 332 if (selSpan) { |
267 var valueStart = this.brailleBuffer_.getSpanStart(selSpan); | 333 var valueStart = this.brailleBuffer_.getSpanStart(selSpan); |
268 var valueEnd = this.brailleBuffer_.getSpanEnd(selSpan); | 334 var valueEnd = this.brailleBuffer_.getSpanEnd(selSpan); |
269 if (valueStart === undefined || valueEnd === undefined) { | 335 if (valueStart === undefined || valueEnd === undefined) { |
270 valueStart = -1; | 336 valueStart = -1; |
271 valueEnd = -1; | 337 valueEnd = -1; |
272 } else { | 338 } else { |
273 startIndex = valueStart + selSpan.startIndex; | 339 startIndex = valueStart + selSpan.startIndex; |
274 endIndex = valueStart + selSpan.endIndex; | 340 endIndex = valueStart + selSpan.endIndex; |
275 this.brailleBuffer_.setSpan(new cvox.BrailleUtil.ValueSpan(valueStart), | 341 this.brailleBuffer_.setSpan(new cvox.BrailleUtil.ValueSpan(valueStart), |
276 valueStart, valueEnd); | 342 valueStart, valueEnd); |
277 this.brailleBuffer_.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), | 343 this.brailleBuffer_.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), |
278 startIndex, endIndex); | 344 startIndex, endIndex); |
279 } | 345 } |
280 } | 346 } |
281 | 347 |
282 var output = new cvox.NavBraille({ | 348 var output = new cvox.NavBraille({ |
283 text: this.brailleBuffer_, | 349 text: this.brailleBuffer_, |
284 startIndex: startIndex, | 350 startIndex: startIndex, |
285 endIndex: endIndex | 351 endIndex: endIndex |
286 }); | 352 }); |
287 | 353 |
288 cvox.ChromeVox.braille.write(output); | 354 if (this.brailleBuffer_) |
289 }, | 355 cvox.ChromeVox.braille.write(output); |
290 | 356 |
291 /** | 357 // Display. |
292 * Handles output to visual display. | |
293 */ | |
294 handleDisplay: function() { | |
295 chrome.accessibilityPrivate.setFocusRing(this.locations_); | 358 chrome.accessibilityPrivate.setFocusRing(this.locations_); |
296 }, | 359 }, |
297 | 360 |
298 /** | 361 /** |
299 * Renders the given range using optional context previous range and event | 362 * Renders the given range using optional context previous range and event |
300 * type. | 363 * type. |
301 * @param {!cursors.Range} range | 364 * @param {!cursors.Range} range |
302 * @param {cursors.Range} prevRange | 365 * @param {cursors.Range} prevRange |
303 * @param {chrome.automation.EventType|string} type | 366 * @param {chrome.automation.EventType|string} type |
| 367 * @param {!cvox.Spannable} buff Buffer to receive rendered output. |
304 * @private | 368 * @private |
305 */ | 369 */ |
306 render_: function(range, prevRange, type) { | 370 render_: function(range, prevRange, type, buff) { |
307 var buff = new cvox.Spannable(); | |
308 var brailleBuff = new cvox.Spannable(); | |
309 if (range.isSubNode()) | 371 if (range.isSubNode()) |
310 this.subNode_(range, prevRange, type, buff); | 372 this.subNode_(range, prevRange, type, buff); |
311 else | 373 else |
312 this.range_(range, prevRange, type, buff); | 374 this.range_(range, prevRange, type, buff); |
313 | |
314 this.formatOptions_.braille = true; | |
315 this.formatOptions_.location = false; | |
316 if (range.isSubNode()) | |
317 this.subNode_(range, prevRange, type, brailleBuff); | |
318 else | |
319 this.range_(range, prevRange, type, brailleBuff); | |
320 | |
321 this.buffer_ = buff; | |
322 this.brailleBuffer_ = brailleBuff; | |
323 }, | 375 }, |
324 | 376 |
325 /** | 377 /** |
326 * Format the node given the format specifier. | 378 * Format the node given the format specifier. |
327 * @param {!chrome.automation.AutomationNode} node | 379 * @param {!chrome.automation.AutomationNode} node |
328 * @param {string|!Object} format The output format either specified as an | 380 * @param {string|!Object} format The output format either specified as an |
329 * output template string or a parsed output format tree. | 381 * output template string or a parsed output format tree. |
330 * @param {!Object=} opt_exclude A set of attributes to exclude. | 382 * @param {!Object=} opt_exclude A set of attributes to exclude. |
331 * @private | 383 * @private |
332 */ | 384 */ |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 } | 706 } |
655 | 707 |
656 if (currentNode != root) | 708 if (currentNode != root) |
657 throw 'Unbalanced parenthesis.'; | 709 throw 'Unbalanced parenthesis.'; |
658 | 710 |
659 return root; | 711 return root; |
660 } | 712 } |
661 }; | 713 }; |
662 | 714 |
663 }); // goog.scope | 715 }); // goog.scope |
OLD | NEW |