Commit 06cb031d authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox: Refactor Output.format_ to take parameters object.

This change refactors Output.format_ to take a parameters object. This
helps maintain code readability in instances where optional parameters
need to be passed in.

Change-Id: I3e24f9d809b745aaef1bef16d376a16c35742a89
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1820044
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#713265}
parent 72053d5a
...@@ -978,7 +978,12 @@ Output.prototype = { ...@@ -978,7 +978,12 @@ Output.prototype = {
var node = opt_node || null; var node = opt_node || null;
this.formatOptions_ = {speech: true, braille: false, auralStyle: false}; this.formatOptions_ = {speech: true, braille: false, auralStyle: false};
this.format_(node, formatStr, this.speechBuffer_, this.speechRulesStr_); this.format_({
node: node,
outputFormat: formatStr,
outputBuffer: this.speechBuffer_,
outputRuleString: this.speechRulesStr_
});
return this; return this;
}, },
...@@ -995,7 +1000,12 @@ Output.prototype = { ...@@ -995,7 +1000,12 @@ Output.prototype = {
var node = opt_node || null; var node = opt_node || null;
this.formatOptions_ = {speech: false, braille: true, auralStyle: false}; this.formatOptions_ = {speech: false, braille: true, auralStyle: false};
this.format_(node, formatStr, this.brailleBuffer_, this.brailleRulesStr_); this.format_({
node: node,
outputFormat: formatStr,
outputBuffer: this.brailleBuffer_,
outputRuleString: this.brailleRulesStr_
});
return this; return this;
}, },
...@@ -1181,17 +1191,34 @@ Output.prototype = { ...@@ -1181,17 +1191,34 @@ Output.prototype = {
/** /**
* Format the node given the format specifier. * Format the node given the format specifier.
* @param {AutomationNode} node * Please see below for more information on arguments.
* @param {string|!Object} format The output format either specified as an * node: The AutomationNode of interest.
* output template string or a parsed output format tree. * outputFormat: The output format either specified as an output template
* @param {!Array<Spannable>} buff Buffer to receive rendered output. * string or a parsed output format tree.
* @param {!OutputRulesStr} ruleStr * outputBuffer: Buffer to receive rendered output.
* @param {!AutomationNode=} opt_prevNode * outputRuleString: Used for logging and recording output.
* @param {!Object<string,(string|number|boolean|Function|Array<string>)>=} * opt_prevNode: Optional argument. Helps provide context for certain speech
* opt_properties * output.
* opt_speechProps: Optional argument. Used to specify how speech should be
* verbalized; can specify pitch, rate, language, etc.
* @param {!{
* node: AutomationNode,
* outputFormat: (string|!Object),
* outputBuffer: !Array<Spannable>,
* outputRuleString: !OutputRulesStr,
* opt_prevNode: (!AutomationNode|undefined),
* opt_speechProps: (!Output.SpeechProperties|undefined)
* }} params An object containing all required and optional parameters.
* @private * @private
*/ */
format_: function(node, format, buff, ruleStr, opt_prevNode, opt_properties) { format_: function(params) {
var node = params['node'];
var format = params['outputFormat'];
var buff = params['outputBuffer'];
var ruleStr = params['outputRuleString'];
var prevNode = params['opt_prevNode'];
var speechProps = params['opt_speechProps'];
var tokens = []; var tokens = [];
var args = null; var args = null;
...@@ -1203,7 +1230,6 @@ Output.prototype = { ...@@ -1203,7 +1230,6 @@ Output.prototype = {
tokens = [format]; tokens = [format];
} }
var speechProps = opt_properties || null;
tokens.forEach(function(token) { tokens.forEach(function(token) {
// Ignore empty tokens. // Ignore empty tokens.
if (!token) { if (!token) {
...@@ -1268,7 +1294,7 @@ Output.prototype = { ...@@ -1268,7 +1294,7 @@ Output.prototype = {
} }
} else if (token == 'name') { } else if (token == 'name') {
options.annotation.push(token); options.annotation.push(token);
var earcon = node ? this.findEarcon_(node, opt_prevNode) : null; var earcon = node ? this.findEarcon_(node, prevNode) : null;
if (earcon) { if (earcon) {
options.annotation.push(earcon); options.annotation.push(earcon);
} }
...@@ -1360,7 +1386,12 @@ Output.prototype = { ...@@ -1360,7 +1386,12 @@ Output.prototype = {
ruleStr.writeTokenWithValue(token, node.name); ruleStr.writeTokenWithValue(token, node.name);
} else { } else {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '$descendants', buff, ruleStr); this.format_({
node: node,
outputFormat: '$descendants',
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'indexInParent') { } else if (token == 'indexInParent') {
if (node.parent) { if (node.parent) {
...@@ -1389,19 +1420,34 @@ Output.prototype = { ...@@ -1389,19 +1420,34 @@ Output.prototype = {
var msg = Output.RESTRICTION_STATE_MAP[node.restriction]; var msg = Output.RESTRICTION_STATE_MAP[node.restriction];
if (msg) { if (msg) {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '@' + msg, buff, ruleStr); this.format_({
node: node,
outputFormat: '@' + msg,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'checked') { } else if (token == 'checked') {
var msg = Output.CHECKED_STATE_MAP[node.checked]; var msg = Output.CHECKED_STATE_MAP[node.checked];
if (msg) { if (msg) {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '@' + msg, buff, ruleStr); this.format_({
node: node,
outputFormat: '@' + msg,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'pressed') { } else if (token == 'pressed') {
var msg = Output.PRESSED_STATE_MAP[node.checked]; var msg = Output.PRESSED_STATE_MAP[node.checked];
if (msg) { if (msg) {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '@' + msg, buff, ruleStr); this.format_({
node: node,
outputFormat: '@' + msg,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'state') { } else if (token == 'state') {
if (node.state) { if (node.state) {
...@@ -1409,7 +1455,12 @@ Output.prototype = { ...@@ -1409,7 +1455,12 @@ Output.prototype = {
var stateInfo = Output.STATE_INFO_[s]; var stateInfo = Output.STATE_INFO_[s];
if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) { if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '$' + s, buff, ruleStr); this.format_({
node: node,
outputFormat: '$' + s,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
}.bind(this)); }.bind(this));
} }
...@@ -1423,7 +1474,12 @@ Output.prototype = { ...@@ -1423,7 +1474,12 @@ Output.prototype = {
var formatString = tree.firstChild.nextSibling; var formatString = tree.firstChild.nextSibling;
if (node) { if (node) {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, formatString, buff, ruleStr); this.format_({
node: node,
outputFormat: formatString,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} }
} else if (token == 'descendants') { } else if (token == 'descendants') {
...@@ -1466,7 +1522,12 @@ Output.prototype = { ...@@ -1466,7 +1522,12 @@ Output.prototype = {
} else if (token == 'joinedDescendants') { } else if (token == 'joinedDescendants') {
var unjoined = []; var unjoined = [];
ruleStr.write('joinedDescendants {'); ruleStr.write('joinedDescendants {');
this.format_(node, '$descendants', unjoined, ruleStr); this.format_({
node: node,
outputFormat: '$descendants',
outputBuffer: unjoined,
outputRuleString: ruleStr
});
this.append_(buff, unjoined.join(' '), options); this.append_(buff, unjoined.join(' '), options);
ruleStr.write( ruleStr.write(
'}: ' + (unjoined.length ? unjoined.join(' ') : 'EMPTY') + '\n'); '}: ' + (unjoined.length ? unjoined.join(' ') : 'EMPTY') + '\n');
...@@ -1533,12 +1594,15 @@ Output.prototype = { ...@@ -1533,12 +1594,15 @@ Output.prototype = {
ruleStr.writeTokenWithValue(token, value); ruleStr.writeTokenWithValue(token, value);
} else { } else {
ruleStr.write(token); ruleStr.write(token);
this.format_( this.format_({
node, `@cell_summary($if($tableCellAriaRowIndex, node: node,
$tableCellAriaRowIndex, $tableCellRowIndex), outputFormat: ` @cell_summary($if($tableCellAriaRowIndex,
$tableCellAriaRowIndex, $tableCellRowIndex),
$if($tableCellAriaColumnIndex, $tableCellAriaColumnIndex, $if($tableCellAriaColumnIndex, $tableCellAriaColumnIndex,
$tableCellColumnIndex))`, $tableCellColumnIndex))`,
buff, ruleStr); outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'node') { } else if (token == 'node') {
if (!tree.firstChild) { if (!tree.firstChild) {
...@@ -1548,13 +1612,11 @@ Output.prototype = { ...@@ -1548,13 +1612,11 @@ Output.prototype = {
var relationName = tree.firstChild.value; var relationName = tree.firstChild.value;
if (relationName == 'tableCellColumnHeaders') { if (relationName == 'tableCellColumnHeaders') {
// Skip output when previous position falls on the same column. // Skip output when previous position falls on the same column.
while (opt_prevNode && while (prevNode && !AutomationPredicate.cellLike(prevNode)) {
!AutomationPredicate.cellLike(opt_prevNode)) { prevNode = prevNode.parent;
opt_prevNode = opt_prevNode.parent;
} }
if (opt_prevNode && if (prevNode &&
opt_prevNode.tableCellColumnIndex == prevNode.tableCellColumnIndex == node.tableCellColumnIndex) {
node.tableCellColumnIndex) {
return; return;
} }
...@@ -1587,7 +1649,12 @@ Output.prototype = { ...@@ -1587,7 +1649,12 @@ Output.prototype = {
} else if (token == 'nameOrTextContent') { } else if (token == 'nameOrTextContent') {
if (node.name && node.nameFrom != NameFromType.CONTENTS) { if (node.name && node.nameFrom != NameFromType.CONTENTS) {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '$name', buff, ruleStr); this.format_({
node: node,
outputFormat: '$name',
outputBuffer: buff,
outputRuleString: ruleStr
});
return; return;
} }
...@@ -1647,7 +1714,12 @@ Output.prototype = { ...@@ -1647,7 +1714,12 @@ Output.prototype = {
ruleStr.writeTokenWithValue(token, String(node.posInSet)); ruleStr.writeTokenWithValue(token, String(node.posInSet));
} else { } else {
ruleStr.writeToken(token); ruleStr.writeToken(token);
this.format_(node, '$indexInParent', buff, ruleStr); this.format_({
node: node,
outputFormat: '$indexInParent',
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'setSize') { } else if (token == 'setSize') {
var size = node.setSize ? node.setSize : 0; var size = node.setSize ? node.setSize : 0;
...@@ -1661,10 +1733,20 @@ Output.prototype = { ...@@ -1661,10 +1733,20 @@ Output.prototype = {
var attrib = cond.value.slice(1); var attrib = cond.value.slice(1);
if (Output.isTruthy(node, attrib)) { if (Output.isTruthy(node, attrib)) {
ruleStr.write(attrib + '==true => '); ruleStr.write(attrib + '==true => ');
this.format_(node, cond.nextSibling, buff, ruleStr); this.format_({
node: node,
outputFormat: cond.nextSibling,
outputBuffer: buff,
outputRuleString: ruleStr
});
} else if (Output.isFalsey(node, attrib)) { } else if (Output.isFalsey(node, attrib)) {
ruleStr.write(attrib + '==false => '); ruleStr.write(attrib + '==false => ');
this.format_(node, cond.nextSibling.nextSibling, buff, ruleStr); this.format_({
node: node,
outputFormat: cond.nextSibling.nextSibling,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'nif') { } else if (token == 'nif') {
ruleStr.writeToken(token); ruleStr.writeToken(token);
...@@ -1672,10 +1754,20 @@ Output.prototype = { ...@@ -1672,10 +1754,20 @@ Output.prototype = {
var attrib = cond.value.slice(1); var attrib = cond.value.slice(1);
if (Output.isFalsey(node, attrib)) { if (Output.isFalsey(node, attrib)) {
ruleStr.write(attrib + '==false => '); ruleStr.write(attrib + '==false => ');
this.format_(node, cond.nextSibling, buff, ruleStr); this.format_({
node: node,
outputFormat: cond.nextSibling,
outputBuffer: buff,
outputRuleString: ruleStr
});
} else if (Output.isTruthy(node, attrib)) { } else if (Output.isTruthy(node, attrib)) {
ruleStr.write(attrib + '==true => '); ruleStr.write(attrib + '==true => ');
this.format_(node, cond.nextSibling.nextSibling, buff, ruleStr); this.format_({
node: node,
outputFormat: cond.nextSibling.nextSibling,
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
} else if (token == 'earcon') { } else if (token == 'earcon') {
// Ignore unless we're generating speech output. // Ignore unless we're generating speech output.
...@@ -1723,7 +1815,12 @@ Output.prototype = { ...@@ -1723,7 +1815,12 @@ Output.prototype = {
return; return;
} }
var msgBuff = []; var msgBuff = [];
this.format_(node, curArg, msgBuff, ruleStr); this.format_({
node: node,
outputFormat: curArg,
outputBuffer: msgBuff,
outputRuleString: ruleStr
});
// Fill in empty string if nothing was formatted. // Fill in empty string if nothing was formatted.
if (!msgBuff.length) { if (!msgBuff.length) {
msgBuff = ['']; msgBuff = [''];
...@@ -1762,7 +1859,12 @@ Output.prototype = { ...@@ -1762,7 +1859,12 @@ Output.prototype = {
return; return;
} }
var argBuff = []; var argBuff = [];
this.format_(node, arg, argBuff, ruleStr); this.format_({
node: node,
outputFormat: arg,
outputBuffer: argBuff,
outputRuleString: ruleStr
});
var namedArgs = {COUNT: Number(argBuff[0])}; var namedArgs = {COUNT: Number(argBuff[0])};
msg = new goog.i18n.MessageFormat(msg).format(namedArgs); msg = new goog.i18n.MessageFormat(msg).format(namedArgs);
} }
...@@ -1960,9 +2062,13 @@ Output.prototype = { ...@@ -1960,9 +2062,13 @@ Output.prototype = {
localStorage['useVerboseMode'] == 'true') { localStorage['useVerboseMode'] == 'true') {
rule.navigation = 'leave'; rule.navigation = 'leave';
ruleStr.writeRule(rule); ruleStr.writeRule(rule);
this.format_( this.format_({
formatPrevNode, eventBlock[rule.role].leave, buff, ruleStr, node: formatPrevNode,
prevNode); outputFormat: eventBlock[rule.role].leave,
outputBuffer: buff,
outputRuleString: ruleStr,
opt_prevNode: prevNode
});
} }
} }
...@@ -1996,7 +2102,13 @@ Output.prototype = { ...@@ -1996,7 +2102,13 @@ Output.prototype = {
var enterFormat = rule.output ? var enterFormat = rule.output ?
eventBlock[rule.role]['enter'][rule.output] : eventBlock[rule.role]['enter'][rule.output] :
eventBlock[rule.role]['enter']; eventBlock[rule.role]['enter'];
this.format_(formatNode, enterFormat, buff, ruleStr, prevNode); this.format_({
node: formatNode,
outputFormat: enterFormat,
outputBuffer: buff,
outputRuleString: ruleStr,
opt_prevNode: prevNode
});
if (this.formatOptions_.braille && buff.length) { if (this.formatOptions_.braille && buff.length) {
var nodeSpan = this.mergeBraille_(buff); var nodeSpan = this.mergeBraille_(buff);
...@@ -2053,8 +2165,13 @@ Output.prototype = { ...@@ -2053,8 +2165,13 @@ Output.prototype = {
} }
} }
ruleStr.writeRule(rule); ruleStr.writeRule(rule);
this.format_( this.format_({
node, eventBlock[rule.role][rule.output], buff, ruleStr, prevNode); node: node,
outputFormat: eventBlock[rule.role][rule.output],
outputBuffer: buff,
outputRuleString: ruleStr,
opt_prevNode: prevNode
});
// Restore braille and add an annotation for this node. // Restore braille and add an annotation for this node.
if (this.formatOptions_.braille) { if (this.formatOptions_.braille) {
...@@ -2185,7 +2302,12 @@ Output.prototype = { ...@@ -2185,7 +2302,12 @@ Output.prototype = {
// Undelayed hints. // Undelayed hints.
if (node.errorMessage) { if (node.errorMessage) {
this.format_(node, '$node(errorMessage)', buff, ruleStr, undefined, {}); this.format_({
node: node,
outputFormat: '$node(errorMessage)',
outputBuffer: buff,
outputRuleString: ruleStr
});
} }
// Hints should be delayed. // Hints should be delayed.
...@@ -2195,44 +2317,66 @@ Output.prototype = { ...@@ -2195,44 +2317,66 @@ Output.prototype = {
ruleStr.write('hint_: '); ruleStr.write('hint_: ');
if (EventSourceState.get() == EventSourceType.TOUCH_GESTURE) { if (EventSourceState.get() == EventSourceType.TOUCH_GESTURE) {
if (node.state[StateType.EDITABLE]) { if (node.state[StateType.EDITABLE]) {
this.format_( this.format_({
node, node: node,
node.state[StateType.FOCUSED] ? '@hint_is_editing' : outputFormat: node.state[StateType.FOCUSED] ?
'@hint_double_tap_to_edit', '@hint_is_editing' :
buff, ruleStr, undefined, hintProperties); '@hint_double_tap_to_edit',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
return; return;
} }
var isWithinVirtualKeyboard = AutomationUtil.getAncestors(node).find( var isWithinVirtualKeyboard = AutomationUtil.getAncestors(node).find(
(n) => n.role == RoleType.KEYBOARD); (n) => n.role == RoleType.KEYBOARD);
if (node.defaultActionVerb != 'none' && !isWithinVirtualKeyboard) { if (node.defaultActionVerb != 'none' && !isWithinVirtualKeyboard) {
this.format_( this.format_({
node, '@hint_double_tap', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_double_tap',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
var enteredVirtualKeyboard = var enteredVirtualKeyboard =
uniqueAncestors.find((n) => n.role == RoleType.KEYBOARD); uniqueAncestors.find((n) => n.role == RoleType.KEYBOARD);
if (enteredVirtualKeyboard) { if (enteredVirtualKeyboard) {
this.format_( this.format_({
node, '@hint_touch_type', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_touch_type',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
return; return;
} }
if (node.state[StateType.EDITABLE] && cvox.ChromeVox.isStickyPrefOn) { if (node.state[StateType.EDITABLE] && cvox.ChromeVox.isStickyPrefOn) {
this.format_( this.format_({
node, '@sticky_mode_enabled', buff, ruleStr, undefined, node: node,
hintProperties); outputFormat: '@sticky_mode_enabled',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (node.state[StateType.EDITABLE] && node.state[StateType.FOCUSED] && if (node.state[StateType.EDITABLE] && node.state[StateType.FOCUSED] &&
!this.formatOptions_.braille) { !this.formatOptions_.braille) {
if (node.state[StateType.MULTILINE] || if (node.state[StateType.MULTILINE] ||
node.state[StateType.RICHLY_EDITABLE]) node.state[StateType.RICHLY_EDITABLE])
this.format_( this.format_({
node, '@hint_search_within_text_field', buff, ruleStr, undefined, node: node,
hintProperties); outputFormat: '@hint_search_within_text_field',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (node.placeholder) { if (node.placeholder) {
...@@ -2247,23 +2391,41 @@ Output.prototype = { ...@@ -2247,23 +2391,41 @@ Output.prototype = {
} }
if (AutomationPredicate.checkable(node)) { if (AutomationPredicate.checkable(node)) {
this.format_( this.format_({
node, '@hint_checkable', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_checkable',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} else if (AutomationPredicate.clickable(node)) { } else if (AutomationPredicate.clickable(node)) {
this.format_( this.format_({
node, '@hint_clickable', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_clickable',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (node.autoComplete == 'list' || node.autoComplete == 'both' || if (node.autoComplete == 'list' || node.autoComplete == 'both' ||
node.state[StateType.AUTOFILL_AVAILABLE]) { node.state[StateType.AUTOFILL_AVAILABLE]) {
this.format_( this.format_({
node, '@hint_autocomplete_list', buff, ruleStr, undefined, node: node,
hintProperties); outputFormat: '@hint_autocomplete_list',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (node.autoComplete == 'inline' || node.autoComplete == 'both') { if (node.autoComplete == 'inline' || node.autoComplete == 'both') {
this.format_( this.format_({
node, '@hint_autocomplete_inline', buff, ruleStr, undefined, node: node,
hintProperties); outputFormat: '@hint_autocomplete_inline',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (node.accessKey) { if (node.accessKey) {
this.append_(buff, Msgs.getMsg('access_key', [node.accessKey])); this.append_(buff, Msgs.getMsg('access_key', [node.accessKey]));
...@@ -2273,19 +2435,34 @@ Output.prototype = { ...@@ -2273,19 +2435,34 @@ Output.prototype = {
// Ancestry based hints. // Ancestry based hints.
if (uniqueAncestors.find( if (uniqueAncestors.find(
/** @type {function(?) : boolean} */ (AutomationPredicate.table))) { /** @type {function(?) : boolean} */ (AutomationPredicate.table))) {
this.format_( this.format_({
node, '@hint_table', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_table',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (uniqueAncestors.find(/** @type {function(?) : boolean} */ ( if (uniqueAncestors.find(/** @type {function(?) : boolean} */ (
AutomationPredicate.roles([RoleType.MENU, RoleType.MENU_BAR])))) { AutomationPredicate.roles([RoleType.MENU, RoleType.MENU_BAR])))) {
this.format_( this.format_({
node, '@hint_menu', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_menu',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
if (uniqueAncestors.find(/** @type {function(?) : boolean} */ (function(n) { if (uniqueAncestors.find(/** @type {function(?) : boolean} */ (function(n) {
return !!n.details; return !!n.details;
}))) { }))) {
this.format_( this.format_({
node, '@hint_details', buff, ruleStr, undefined, hintProperties); node: node,
outputFormat: '@hint_details',
outputBuffer: buff,
outputRuleString: ruleStr,
opt_speechProps: hintProperties
});
} }
}, },
......
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