Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js

Issue 816093002: Support alert nodes by introducing $descendant and !ttsProps. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 */ 44 */
45 Output = function() { 45 Output = function() {
46 // TODO(dtseng): Include braille specific rules. 46 // TODO(dtseng): Include braille specific rules.
47 /** @type {!cvox.Spannable} */ 47 /** @type {!cvox.Spannable} */
48 this.buffer_ = new cvox.Spannable(); 48 this.buffer_ = new cvox.Spannable();
49 /** @type {!cvox.Spannable} */ 49 /** @type {!cvox.Spannable} */
50 this.brailleBuffer_ = new cvox.Spannable(); 50 this.brailleBuffer_ = new cvox.Spannable();
51 /** @type {!Array.<Object>} */ 51 /** @type {!Array.<Object>} */
52 this.locations_ = []; 52 this.locations_ = [];
53 /** @type {function()} */ 53 /** @type {function()} */
54 this.speechStartCallback_ = function() {}; 54 this.speechStartCallback_;
55 /** @type {function()} */ 55 /** @type {function()} */
56 this.speechEndCallback_ = function() {}; 56 this.speechEndCallback_;
57 /** @type {function()} */ 57 /** @type {function()} */
58 this.speechInterruptedCallback_ = function() {}; 58 this.speechInterruptedCallback_;
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 /**
67 * Speech properties to apply to the entire output.
68 * @type {!Object.<string, *>}
69 */
70 this.speechProperties_ = {};
65 }; 71 };
66 72
67 /** 73 /**
68 * Delimiter to use between output values. 74 * Delimiter to use between output values.
69 * @type {string} 75 * @type {string}
70 */ 76 */
71 Output.SPACE = ' '; 77 Output.SPACE = ' ';
72 78
73 /** 79 /**
74 * Rules specifying format of AutomationNodes for output. 80 * Rules specifying format of AutomationNodes for output.
75 * @type {!Object.<string, Object.<string, Object.<string, string>>>} 81 * @type {!Object.<string, Object.<string, Object.<string, string>>>}
76 */ 82 */
77 Output.RULES = { 83 Output.RULES = {
78 navigate: { 84 navigate: {
79 'default': { 85 'default': {
80 speak: '$name $role $value', 86 speak: '$name $role $value',
81 braille: '' 87 braille: ''
82 }, 88 },
83 alert: { 89 alert: {
84 speak: '@aria_role_alert $name $earcon(ALERT_NONMODAL)' 90 speak: '!doNotInterrupt ' +
91 '@aria_role_alert $name $earcon(ALERT_NONMODAL) $descendants'
85 }, 92 },
86 button: { 93 button: {
87 speak: '$name $earcon(BUTTON, @tag_button)' 94 speak: '$name $earcon(BUTTON, @tag_button)'
88 }, 95 },
89 checkBox: { 96 checkBox: {
90 speak: '$or($checked, @describe_checkbox_checked($name), ' + 97 speak: '$or($checked, @describe_checkbox_checked($name), ' +
91 '@describe_checkbox_unchecked($name)) ' + 98 '@describe_checkbox_unchecked($name)) ' +
92 '$or($checked, ' + 99 '$or($checked, ' +
93 '$earcon(CHECK_ON, @input_type_checkbox), ' + 100 '$earcon(CHECK_ON, @input_type_checkbox), ' +
94 '$earcon(CHECK_OFF, @input_type_checkbox))' 101 '$earcon(CHECK_OFF, @input_type_checkbox))'
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 307
301 /** 308 /**
302 * Executes all specified output. 309 * Executes all specified output.
303 */ 310 */
304 go: function() { 311 go: function() {
305 // Speech. 312 // Speech.
306 var buff = this.buffer_; 313 var buff = this.buffer_;
307 314
308 var onEvent = function(evt) { 315 var onEvent = function(evt) {
309 switch (evt.type) { 316 switch (evt.type) {
310 case 'start': this.speechStartCallback_(); break; 317 case 'start':
311 case 'end': this.speechEndCallback_(); break; 318 this.speechStartCallback_();
312 case 'interrupted': this.speechInterruptedCallback_(); break; 319 break;
320 case 'end':
321 this.speechEndCallback_();
322 break;
323 case 'interrupted':
324 this.speechInterruptedCallback_ && this.speechInterruptedCallback_();
325 break;
313 } 326 }
314 }.bind(this); 327 }.bind(this);
315 328
316 if (buff.toString()) { 329 if (buff.toString()) {
330 if (this.speechStartCallback_ ||
331 this.speechEndCallback_ ||
332 this.speechInterruptedCallback_)
333 this.speechProperties_['onEvent'] = onEvent;
334
317 cvox.ChromeVox.tts.speak( 335 cvox.ChromeVox.tts.speak(
318 buff.toString(), cvox.QueueMode.FLUSH, {onEvent: onEvent}); 336 buff.toString(), cvox.QueueMode.FLUSH, this.speechProperties_);
319 } 337 }
320 338
321 var actions = buff.getSpansInstanceOf(Output.Action); 339 var actions = buff.getSpansInstanceOf(Output.Action);
322 if (actions) { 340 if (actions) {
323 actions.forEach(function(a) { 341 actions.forEach(function(a) {
324 a.run(); 342 a.run();
325 }); 343 });
326 } 344 }
327 345
328 // Braille. 346 // Braille.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 return; 442 return;
425 443
426 // All possible tokens based on prefix. 444 // All possible tokens based on prefix.
427 if (prefix == '$') { 445 if (prefix == '$') {
428 options.annotation = token; 446 options.annotation = token;
429 if (token == 'role') { 447 if (token == 'role') {
430 // Non-localized role and state obtained by default. 448 // Non-localized role and state obtained by default.
431 this.addToSpannable_(buff, node.role, options); 449 this.addToSpannable_(buff, node.role, options);
432 } else if (token == 'value') { 450 } else if (token == 'value') {
433 var text = node.attributes.value; 451 var text = node.attributes.value;
434 var offset = buff.getLength(); 452 if (text) {
435 if (node.attributes.textSelStart !== undefined) { 453 var offset = buff.getLength();
436 options.annotation = new Output.SelectionSpan( 454 if (node.attributes.textSelStart !== undefined) {
437 node.attributes.textSelStart, 455 options.annotation = new Output.SelectionSpan(
438 node.attributes.textSelEnd); 456 node.attributes.textSelStart,
457 node.attributes.textSelEnd);
458 }
459 } else if (node.role == chrome.automation.RoleType.staticText) {
460 // TODO(dtseng): Remove once Blink treats staticText values as
461 // names.
462 text = node.attributes.name;
439 } 463 }
440 this.addToSpannable_(buff, text, options); 464 this.addToSpannable_(buff, text, options);
441 } else if (token == 'indexInParent') { 465 } else if (token == 'indexInParent') {
442 this.addToSpannable_(buff, node.indexInParent + 1); 466 this.addToSpannable_(buff, node.indexInParent + 1);
443 } else if (token == 'parentChildCount') { 467 } else if (token == 'parentChildCount') {
444 if (node.parent) 468 if (node.parent)
445 this.addToSpannable_(buff, node.parent.children.length); 469 this.addToSpannable_(buff, node.parent.children.length);
446 } else if (token == 'state') { 470 } else if (token == 'state') {
447 Object.getOwnPropertyNames(node.state).forEach(function(s) { 471 Object.getOwnPropertyNames(node.state).forEach(function(s) {
448 this.addToSpannable_(buff, s, options); 472 this.addToSpannable_(buff, s, options);
449 }.bind(this)); 473 }.bind(this));
450 } else if (token == 'find') { 474 } else if (token == 'find') {
451 // Find takes two arguments: JSON query string and format string. 475 // Find takes two arguments: JSON query string and format string.
452 if (tree.firstChild) { 476 if (tree.firstChild) {
453 var jsonQuery = tree.firstChild.value; 477 var jsonQuery = tree.firstChild.value;
454 node = node.find( 478 node = node.find(
455 /** @type {Object}*/(JSON.parse(jsonQuery))); 479 /** @type {Object}*/(JSON.parse(jsonQuery)));
456 var formatString = tree.firstChild.nextSibling; 480 var formatString = tree.firstChild.nextSibling;
457 if (node) 481 if (node)
458 this.format_(node, formatString, buff); 482 this.format_(node, formatString, buff);
459 } 483 }
484 } else if (token == 'descendants') {
485 if (AutomationPredicate.leaf(node))
486 return;
487
488 // Construct a range to the leftmost and rightmost leaves.
489 var leftmost = AutomationUtil.findNodePre(
490 node, Dir.FORWARD, AutomationPredicate.leaf);
491 var rightmost = AutomationUtil.findNodePre(
492 node, Dir.BACKWARD, AutomationPredicate.leaf);
493 if (!leftmost || !rightmost)
494 return;
495
496 var subrange = new cursors.Range(
497 new cursors.Cursor(leftmost, 0),
498 new cursors.Cursor(rightmost, 0));
499 this.range_(subrange, null, 'navigate', buff);
460 } else if (node.attributes[token]) { 500 } else if (node.attributes[token]) {
461 this.addToSpannable_(buff, node.attributes[token], options); 501 this.addToSpannable_(buff, node.attributes[token], options);
462 } else if (node.state[token]) { 502 } else if (node.state[token]) {
463 this.addToSpannable_(buff, token, options); 503 this.addToSpannable_(buff, token, options);
464 } else if (tree.firstChild) { 504 } else if (tree.firstChild) {
465 // Custom functions. 505 // Custom functions.
466 if (token == 'or') { 506 if (token == 'or') {
467 var cond = tree.firstChild; 507 var cond = tree.firstChild;
468 var attrib = cond.value.slice(1); 508 var attrib = cond.value.slice(1);
469 if (node.attributes[attrib] || node.state[attrib]) 509 if (node.attributes[attrib] || node.state[attrib])
(...skipping 29 matching lines...) Expand all
499 } 539 }
500 var msg = cvox.ChromeVox.msgs.getMsg(msgId, msgArgs); 540 var msg = cvox.ChromeVox.msgs.getMsg(msgId, msgArgs);
501 try { 541 try {
502 if (this.formatOptions_.braille) 542 if (this.formatOptions_.braille)
503 msg = cvox.ChromeVox.msgs.getMsg(msgId + '_brl', msgArgs) || msg; 543 msg = cvox.ChromeVox.msgs.getMsg(msgId + '_brl', msgArgs) || msg;
504 } catch(e) {} 544 } catch(e) {}
505 545
506 if (msg) { 546 if (msg) {
507 this.addToSpannable_(buff, msg, options); 547 this.addToSpannable_(buff, msg, options);
508 } 548 }
549 } else if (prefix == '!') {
550 this.speechProperties_[token] = true;
509 } 551 }
510 }.bind(this)); 552 }.bind(this));
511 }, 553 },
512 554
513 /** 555 /**
514 * @param {!cursors.Range} range 556 * @param {!cursors.Range} range
515 * @param {cursors.Range} prevRange 557 * @param {cursors.Range} prevRange
516 * @param {chrome.automation.EventType|string} type 558 * @param {chrome.automation.EventType|string} type
517 * @param {!cvox.Spannable} rangeBuff 559 * @param {!cvox.Spannable} rangeBuff
518 * @private 560 * @private
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 } 748 }
707 749
708 if (currentNode != root) 750 if (currentNode != root)
709 throw 'Unbalanced parenthesis.'; 751 throw 'Unbalanced parenthesis.';
710 752
711 return root; 753 return root;
712 } 754 }
713 }; 755 };
714 756
715 }); // goog.scope 757 }); // goog.scope
OLDNEW
« no previous file with comments | « chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698