| 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 |