Commit 482aa01d authored by dtseng's avatar dtseng Committed by Commit bot

Support alert nodes by introducing $descendant and !ttsProps.

- ! allowed by a tts property will annotate the output with that property
- $descendants(args...) where args... is a comma delimited list of roles, will compute output for the node's descendants that are in the set of roles.
- apply these two new functions to compute utterances for alerts.

TEST=navigate to a page with an alert like
html5demos.com/geo.
BUG=382650

Review URL: https://codereview.chromium.org/816093002

Cr-Commit-Position: refs/heads/master@{#314688}
parent 51f3aacf
...@@ -55,7 +55,9 @@ AutomationPredicate.link = ...@@ -55,7 +55,9 @@ AutomationPredicate.link =
* @return {boolean} * @return {boolean}
*/ */
AutomationPredicate.leaf = function(node) { AutomationPredicate.leaf = function(node) {
return !node.firstChild || node.children.every(function(n) { return !node.firstChild ||
node.role == chrome.automation.RoleType.button ||
node.children.every(function(n) {
return n.state.invisible; return n.state.invisible;
}); });
}; };
......
...@@ -51,17 +51,23 @@ Output = function() { ...@@ -51,17 +51,23 @@ Output = function() {
/** @type {!Array.<Object>} */ /** @type {!Array.<Object>} */
this.locations_ = []; this.locations_ = [];
/** @type {function()} */ /** @type {function()} */
this.speechStartCallback_ = function() {}; this.speechStartCallback_;
/** @type {function()} */ /** @type {function()} */
this.speechEndCallback_ = function() {}; this.speechEndCallback_;
/** @type {function()} */ /** @type {function()} */
this.speechInterruptedCallback_ = function() {}; this.speechInterruptedCallback_;
/** /**
* Current global options. * Current global options.
* @type {{speech: boolean, braille: boolean, location: boolean}} * @type {{speech: boolean, braille: boolean, location: boolean}}
*/ */
this.formatOptions_ = {speech: true, braille: false, location: true}; this.formatOptions_ = {speech: true, braille: false, location: true};
/**
* Speech properties to apply to the entire output.
* @type {!Object.<string, *>}
*/
this.speechProperties_ = {};
}; };
/** /**
...@@ -81,7 +87,8 @@ Output.RULES = { ...@@ -81,7 +87,8 @@ Output.RULES = {
braille: '' braille: ''
}, },
alert: { alert: {
speak: '@aria_role_alert $name $earcon(ALERT_NONMODAL)' speak: '!doNotInterrupt ' +
'@aria_role_alert $name $earcon(ALERT_NONMODAL) $descendants'
}, },
button: { button: {
speak: '$name $earcon(BUTTON, @tag_button)' speak: '$name $earcon(BUTTON, @tag_button)'
...@@ -307,15 +314,26 @@ Output.prototype = { ...@@ -307,15 +314,26 @@ Output.prototype = {
var onEvent = function(evt) { var onEvent = function(evt) {
switch (evt.type) { switch (evt.type) {
case 'start': this.speechStartCallback_(); break; case 'start':
case 'end': this.speechEndCallback_(); break; this.speechStartCallback_();
case 'interrupted': this.speechInterruptedCallback_(); break; break;
case 'end':
this.speechEndCallback_();
break;
case 'interrupted':
this.speechInterruptedCallback_ && this.speechInterruptedCallback_();
break;
} }
}.bind(this); }.bind(this);
if (buff.toString()) { if (buff.toString()) {
if (this.speechStartCallback_ ||
this.speechEndCallback_ ||
this.speechInterruptedCallback_)
this.speechProperties_['onEvent'] = onEvent;
cvox.ChromeVox.tts.speak( cvox.ChromeVox.tts.speak(
buff.toString(), cvox.QueueMode.FLUSH, {onEvent: onEvent}); buff.toString(), cvox.QueueMode.FLUSH, this.speechProperties_);
} }
var actions = buff.getSpansInstanceOf(Output.Action); var actions = buff.getSpansInstanceOf(Output.Action);
...@@ -431,12 +449,18 @@ Output.prototype = { ...@@ -431,12 +449,18 @@ Output.prototype = {
this.addToSpannable_(buff, node.role, options); this.addToSpannable_(buff, node.role, options);
} else if (token == 'value') { } else if (token == 'value') {
var text = node.attributes.value; var text = node.attributes.value;
if (text) {
var offset = buff.getLength(); var offset = buff.getLength();
if (node.attributes.textSelStart !== undefined) { if (node.attributes.textSelStart !== undefined) {
options.annotation = new Output.SelectionSpan( options.annotation = new Output.SelectionSpan(
node.attributes.textSelStart, node.attributes.textSelStart,
node.attributes.textSelEnd); node.attributes.textSelEnd);
} }
} else if (node.role == chrome.automation.RoleType.staticText) {
// TODO(dtseng): Remove once Blink treats staticText values as
// names.
text = node.attributes.name;
}
this.addToSpannable_(buff, text, options); this.addToSpannable_(buff, text, options);
} else if (token == 'indexInParent') { } else if (token == 'indexInParent') {
this.addToSpannable_(buff, node.indexInParent + 1); this.addToSpannable_(buff, node.indexInParent + 1);
...@@ -457,6 +481,22 @@ Output.prototype = { ...@@ -457,6 +481,22 @@ Output.prototype = {
if (node) if (node)
this.format_(node, formatString, buff); this.format_(node, formatString, buff);
} }
} else if (token == 'descendants') {
if (AutomationPredicate.leaf(node))
return;
// Construct a range to the leftmost and rightmost leaves.
var leftmost = AutomationUtil.findNodePre(
node, Dir.FORWARD, AutomationPredicate.leaf);
var rightmost = AutomationUtil.findNodePre(
node, Dir.BACKWARD, AutomationPredicate.leaf);
if (!leftmost || !rightmost)
return;
var subrange = new cursors.Range(
new cursors.Cursor(leftmost, 0),
new cursors.Cursor(rightmost, 0));
this.range_(subrange, null, 'navigate', buff);
} else if (node.attributes[token]) { } else if (node.attributes[token]) {
this.addToSpannable_(buff, node.attributes[token], options); this.addToSpannable_(buff, node.attributes[token], options);
} else if (node.state[token]) { } else if (node.state[token]) {
...@@ -506,6 +546,8 @@ Output.prototype = { ...@@ -506,6 +546,8 @@ Output.prototype = {
if (msg) { if (msg) {
this.addToSpannable_(buff, msg, options); this.addToSpannable_(buff, msg, options);
} }
} else if (prefix == '!') {
this.speechProperties_[token] = true;
} }
}.bind(this)); }.bind(this));
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment