| 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 12 matching lines...) Expand all Loading... |
| 23 goog.require('cvox.TtsCategory'); | 23 goog.require('cvox.TtsCategory'); |
| 24 goog.require('cvox.ValueSelectionSpan'); | 24 goog.require('cvox.ValueSelectionSpan'); |
| 25 goog.require('cvox.ValueSpan'); | 25 goog.require('cvox.ValueSpan'); |
| 26 goog.require('goog.i18n.MessageFormat'); | 26 goog.require('goog.i18n.MessageFormat'); |
| 27 | 27 |
| 28 goog.scope(function() { | 28 goog.scope(function() { |
| 29 var AutomationNode = chrome.automation.AutomationNode; | 29 var AutomationNode = chrome.automation.AutomationNode; |
| 30 var Dir = constants.Dir; | 30 var Dir = constants.Dir; |
| 31 var EventType = chrome.automation.EventType; | 31 var EventType = chrome.automation.EventType; |
| 32 var RoleType = chrome.automation.RoleType; | 32 var RoleType = chrome.automation.RoleType; |
| 33 var StateType = chrome.automation.StateType; |
| 33 | 34 |
| 34 /** | 35 /** |
| 35 * An Output object formats a cursors.Range into speech, braille, or both | 36 * An Output object formats a cursors.Range into speech, braille, or both |
| 36 * representations. This is typically a |Spannable|. | 37 * representations. This is typically a |Spannable|. |
| 37 * | 38 * |
| 38 * The translation from Range to these output representations rely upon format | 39 * The translation from Range to these output representations rely upon format |
| 39 * rules which specify how to convert AutomationNode objects into annotated | 40 * rules which specify how to convert AutomationNode objects into annotated |
| 40 * strings. | 41 * strings. |
| 41 * The format of these rules is as follows. | 42 * The format of these rules is as follows. |
| 42 * | 43 * |
| (...skipping 953 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 996 if (prevRange && !prevRange.isValid()) | 997 if (prevRange && !prevRange.isValid()) |
| 997 prevRange = null; | 998 prevRange = null; |
| 998 | 999 |
| 999 // Scan unique ancestors to get the value of |outputContextFirst|. | 1000 // Scan unique ancestors to get the value of |outputContextFirst|. |
| 1000 var parent = range.start.node; | 1001 var parent = range.start.node; |
| 1001 var prevParent = prevRange ? prevRange.start.node : parent; | 1002 var prevParent = prevRange ? prevRange.start.node : parent; |
| 1002 if (!parent || !prevParent) | 1003 if (!parent || !prevParent) |
| 1003 return; | 1004 return; |
| 1004 var uniqueAncestors = AutomationUtil.getUniqueAncestors(prevParent, parent); | 1005 var uniqueAncestors = AutomationUtil.getUniqueAncestors(prevParent, parent); |
| 1005 for (var i = 0; parent = uniqueAncestors[i]; i++) { | 1006 for (var i = 0; parent = uniqueAncestors[i]; i++) { |
| 1006 if (parent.role == RoleType.window) | 1007 if (parent.role == RoleType.WINDOW) |
| 1007 break; | 1008 break; |
| 1008 if (Output.ROLE_INFO_[parent.role] && | 1009 if (Output.ROLE_INFO_[parent.role] && |
| 1009 Output.ROLE_INFO_[parent.role].outputContextFirst) { | 1010 Output.ROLE_INFO_[parent.role].outputContextFirst) { |
| 1010 this.outputContextFirst_ = true; | 1011 this.outputContextFirst_ = true; |
| 1011 break; | 1012 break; |
| 1012 } | 1013 } |
| 1013 } | 1014 } |
| 1014 | 1015 |
| 1015 if (range.isSubNode()) | 1016 if (range.isSubNode()) |
| 1016 this.subNode_(range, prevRange, type, buff); | 1017 this.subNode_(range, prevRange, type, buff); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1062 if (options.isUnique) | 1063 if (options.isUnique) |
| 1063 token = token.substring(0, token.length - 1); | 1064 token = token.substring(0, token.length - 1); |
| 1064 | 1065 |
| 1065 // Process token based on prefix. | 1066 // Process token based on prefix. |
| 1066 var prefix = token[0]; | 1067 var prefix = token[0]; |
| 1067 token = token.slice(1); | 1068 token = token.slice(1); |
| 1068 | 1069 |
| 1069 // All possible tokens based on prefix. | 1070 // All possible tokens based on prefix. |
| 1070 if (prefix == '$') { | 1071 if (prefix == '$') { |
| 1071 if (token == 'value') { | 1072 if (token == 'value') { |
| 1072 var text = node.value; | 1073 var text = node.value || ''; |
| 1073 if (!node.state.editable && node.name == text) | 1074 if (!node.state[StateType.EDITABLE] && node.name == text) |
| 1074 return; | 1075 return; |
| 1075 | 1076 |
| 1076 var selectedText = ''; | 1077 var selectedText = ''; |
| 1077 if (text !== undefined) { | 1078 if (node.textSelStart !== undefined) { |
| 1078 if (node.textSelStart !== undefined) { | 1079 options.annotation.push(new Output.SelectionSpan( |
| 1079 options.annotation.push(new Output.SelectionSpan( | 1080 node.textSelStart || 0, |
| 1080 node.textSelStart, | 1081 node.textSelEnd || 0)); |
| 1081 node.textSelEnd)); | |
| 1082 | 1082 |
| 1083 selectedText = | 1083 selectedText = |
| 1084 node.value.substring(node.textSelStart, node.textSelEnd); | 1084 node.value.substring(node.textSelStart || 0, |
| 1085 } | 1085 node.textSelEnd || 0); |
| 1086 } | 1086 } |
| 1087 options.annotation.push(token); | 1087 options.annotation.push(token); |
| 1088 if (selectedText && !this.formatOptions_.braille) { | 1088 if (selectedText && !this.formatOptions_.braille) { |
| 1089 this.append_(buff, selectedText, options); | 1089 this.append_(buff, selectedText, options); |
| 1090 this.append_(buff, Msgs.getMsg('selected')); | 1090 this.append_(buff, Msgs.getMsg('selected')); |
| 1091 } else { | 1091 } else { |
| 1092 this.append_(buff, text, options); | 1092 this.append_(buff, text, options); |
| 1093 } | 1093 } |
| 1094 } else if (token == 'name') { | 1094 } else if (token == 'name') { |
| 1095 options.annotation.push(token); | 1095 options.annotation.push(token); |
| 1096 var earcon = node ? this.findEarcon_(node, opt_prevNode) : null; | 1096 var earcon = node ? this.findEarcon_(node, opt_prevNode) : null; |
| 1097 if (earcon) | 1097 if (earcon) |
| 1098 options.annotation.push(earcon); | 1098 options.annotation.push(earcon); |
| 1099 this.append_(buff, node.name || '', options); | 1099 this.append_(buff, node.name || '', options); |
| 1100 } else if (token == 'description') { | 1100 } else if (token == 'description') { |
| 1101 if (node.name == node.description) | 1101 if (node.name == node.description) |
| 1102 return; | 1102 return; |
| 1103 | 1103 |
| 1104 options.annotation.push(token); | 1104 options.annotation.push(token); |
| 1105 this.append_(buff, node.description || '', options); | 1105 this.append_(buff, node.description || '', options); |
| 1106 } else if (token == 'urlFilename') { | 1106 } else if (token == 'urlFilename') { |
| 1107 options.annotation.push('name'); | 1107 options.annotation.push('name'); |
| 1108 var url = node.url; | 1108 var url = node.url || ''; |
| 1109 var filename = ''; | 1109 var filename = ''; |
| 1110 if (url.substring(0, 4) != 'data') { | 1110 if (url.substring(0, 4) != 'data') { |
| 1111 filename = | 1111 filename = |
| 1112 url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.')); | 1112 url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.')); |
| 1113 | 1113 |
| 1114 // Hack to not speak the filename if it's ridiculously long. | 1114 // Hack to not speak the filename if it's ridiculously long. |
| 1115 if (filename.length >= 30) | 1115 if (filename.length >= 30) |
| 1116 filename = filename.substring(0, 16) + '...'; | 1116 filename = filename.substring(0, 16) + '...'; |
| 1117 } | 1117 } |
| 1118 this.append_(buff, filename, options); | 1118 this.append_(buff, filename, options); |
| 1119 } else if (token == 'nameFromNode') { | 1119 } else if (token == 'nameFromNode') { |
| 1120 if (chrome.automation.NameFromType[node.nameFrom] == | 1120 if (node.nameFrom == chrome.automation.NameFromType.CONTENTS) |
| 1121 'contents') | |
| 1122 return; | 1121 return; |
| 1123 | 1122 |
| 1124 options.annotation.push('name'); | 1123 options.annotation.push('name'); |
| 1125 this.append_(buff, node.name, options); | 1124 this.append_(buff, node.name || '', options); |
| 1126 } else if (token == 'nameOrDescendants') { | 1125 } else if (token == 'nameOrDescendants') { |
| 1127 options.annotation.push(token); | 1126 options.annotation.push(token); |
| 1128 if (node.name) | 1127 if (node.name) |
| 1129 this.append_(buff, node.name, options); | 1128 this.append_(buff, node.name || '', options); |
| 1130 else | 1129 else |
| 1131 this.format_(node, '$descendants', buff); | 1130 this.format_(node, '$descendants', buff); |
| 1132 } else if (token == 'description') { | 1131 } else if (token == 'description') { |
| 1133 if (node.name == node.description || node.value == node.description) | 1132 if (node.name == node.description || node.value == node.description) |
| 1134 return; | 1133 return; |
| 1135 options.annotation.push(token); | 1134 options.annotation.push(token); |
| 1136 this.append_(buff, node.description, options); | 1135 this.append_(buff, node.description || '', options); |
| 1137 } else if (token == 'indexInParent') { | 1136 } else if (token == 'indexInParent') { |
| 1138 if (node.parent) { | 1137 if (node.parent) { |
| 1139 options.annotation.push(token); | 1138 options.annotation.push(token); |
| 1140 var count = 0; | 1139 var count = 0; |
| 1141 for (var i = 0, child; child = node.parent.children[i]; i++) { | 1140 for (var i = 0, child; child = node.parent.children[i]; i++) { |
| 1142 if (node.role == child.role) | 1141 if (node.role == child.role) |
| 1143 count++; | 1142 count++; |
| 1144 if (node === child) | 1143 if (node === child) |
| 1145 break; | 1144 break; |
| 1146 } | 1145 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1161 case 'mixed': | 1160 case 'mixed': |
| 1162 msg = 'aria_checked_mixed'; | 1161 msg = 'aria_checked_mixed'; |
| 1163 break; | 1162 break; |
| 1164 case 'true': | 1163 case 'true': |
| 1165 msg = 'aria_checked_true'; | 1164 msg = 'aria_checked_true'; |
| 1166 break; | 1165 break; |
| 1167 case 'false': | 1166 case 'false': |
| 1168 msg = 'aria_checked_false'; | 1167 msg = 'aria_checked_false'; |
| 1169 break; | 1168 break; |
| 1170 default: | 1169 default: |
| 1171 msg = | 1170 msg = node.state[StateType.CHECKED] ? |
| 1172 node.state.checked ? 'aria_checked_true' : 'aria_checked_false'; | 1171 'aria_checked_true' : 'aria_checked_false'; |
| 1173 } | 1172 } |
| 1174 this.format_(node, '@' + msg, buff); | 1173 this.format_(node, '@' + msg, buff); |
| 1175 } else if (token == 'state') { | 1174 } else if (token == 'state') { |
| 1176 Object.getOwnPropertyNames(node.state).forEach(function(s) { | 1175 if (node.state) { |
| 1177 var stateInfo = Output.STATE_INFO_[s]; | 1176 Object.getOwnPropertyNames(node.state).forEach(function(s) { |
| 1178 if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) | 1177 var stateInfo = Output.STATE_INFO_[s]; |
| 1178 if (stateInfo && !stateInfo.isRoleSpecific && stateInfo.on) |
| 1179 this.format_(node, '@' + stateInfo.on.msgId, buff); | 1179 this.format_(node, '@' + stateInfo.on.msgId, buff); |
| 1180 }.bind(this)); | 1180 }.bind(this)); |
| 1181 } |
| 1181 } else if (token == 'find') { | 1182 } else if (token == 'find') { |
| 1182 // Find takes two arguments: JSON query string and format string. | 1183 // Find takes two arguments: JSON query string and format string. |
| 1183 if (tree.firstChild) { | 1184 if (tree.firstChild) { |
| 1184 var jsonQuery = tree.firstChild.value; | 1185 var jsonQuery = tree.firstChild.value; |
| 1185 node = node.find( | 1186 node = node.find( |
| 1186 /** @type {Object}*/(JSON.parse(jsonQuery))); | 1187 /** @type {chrome.automation.FindParams}*/( |
| 1188 JSON.parse(jsonQuery))); |
| 1187 var formatString = tree.firstChild.nextSibling; | 1189 var formatString = tree.firstChild.nextSibling; |
| 1188 if (node) | 1190 if (node) |
| 1189 this.format_(node, formatString, buff); | 1191 this.format_(node, formatString, buff); |
| 1190 } | 1192 } |
| 1191 } else if (token == 'descendants') { | 1193 } else if (token == 'descendants') { |
| 1192 if (!node || AutomationPredicate.leafOrStaticText(node)) | 1194 if (!node || AutomationPredicate.leafOrStaticText(node)) |
| 1193 return; | 1195 return; |
| 1194 | 1196 |
| 1195 // Construct a range to the leftmost and rightmost leaves. | 1197 // Construct a range to the leftmost and rightmost leaves. |
| 1196 var leftmost = AutomationUtil.findNodePre( | 1198 var leftmost = AutomationUtil.findNodePre( |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1223 var msg = node.role; | 1225 var msg = node.role; |
| 1224 var info = Output.ROLE_INFO_[node.role]; | 1226 var info = Output.ROLE_INFO_[node.role]; |
| 1225 if (info) { | 1227 if (info) { |
| 1226 if (this.formatOptions_.braille) | 1228 if (this.formatOptions_.braille) |
| 1227 msg = Msgs.getMsg(info.msgId + '_brl'); | 1229 msg = Msgs.getMsg(info.msgId + '_brl'); |
| 1228 else | 1230 else |
| 1229 msg = Msgs.getMsg(info.msgId); | 1231 msg = Msgs.getMsg(info.msgId); |
| 1230 } else { | 1232 } else { |
| 1231 console.error('Missing role info for ' + node.role); | 1233 console.error('Missing role info for ' + node.role); |
| 1232 } | 1234 } |
| 1233 this.append_(buff, msg, options); | 1235 this.append_(buff, msg || '', options); |
| 1234 } else if (token == 'inputType') { | 1236 } else if (token == 'inputType') { |
| 1235 if (!node.inputType) | 1237 if (!node.inputType) |
| 1236 return; | 1238 return; |
| 1237 options.annotation.push(token); | 1239 options.annotation.push(token); |
| 1238 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || | 1240 var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] || |
| 1239 'input_type_text'; | 1241 'input_type_text'; |
| 1240 if (this.formatOptions_.braille) | 1242 if (this.formatOptions_.braille) |
| 1241 msgId = msgId + '_brl'; | 1243 msgId = msgId + '_brl'; |
| 1242 this.append_(buff, Msgs.getMsg(msgId), options); | 1244 this.append_(buff, Msgs.getMsg(msgId), options); |
| 1243 } else if (token == 'tableCellRowIndex' || | 1245 } else if (token == 'tableCellRowIndex' || |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1278 this.append_(buff, value, options); | 1280 this.append_(buff, value, options); |
| 1279 } else if (Output.STATE_INFO_[token]) { | 1281 } else if (Output.STATE_INFO_[token]) { |
| 1280 options.annotation.push('state'); | 1282 options.annotation.push('state'); |
| 1281 var stateInfo = Output.STATE_INFO_[token]; | 1283 var stateInfo = Output.STATE_INFO_[token]; |
| 1282 var resolvedInfo = {}; | 1284 var resolvedInfo = {}; |
| 1283 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; | 1285 resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off; |
| 1284 if (!resolvedInfo) | 1286 if (!resolvedInfo) |
| 1285 return; | 1287 return; |
| 1286 if (this.formatOptions_.speech && resolvedInfo.earconId) { | 1288 if (this.formatOptions_.speech && resolvedInfo.earconId) { |
| 1287 options.annotation.push( | 1289 options.annotation.push( |
| 1288 new Output.EarconAction(resolvedInfo.earconId), node.location); | 1290 new Output.EarconAction(resolvedInfo.earconId), |
| 1291 node.location || undefined); |
| 1289 } | 1292 } |
| 1290 var msgId = | 1293 var msgId = |
| 1291 this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' : | 1294 this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' : |
| 1292 resolvedInfo.msgId; | 1295 resolvedInfo.msgId; |
| 1293 var msg = Msgs.getMsg(msgId); | 1296 var msg = Msgs.getMsg(msgId); |
| 1294 this.append_(buff, msg, options); | 1297 this.append_(buff, msg, options); |
| 1295 } else if (tree.firstChild) { | 1298 } else if (tree.firstChild) { |
| 1296 // Custom functions. | 1299 // Custom functions. |
| 1297 if (token == 'if') { | 1300 if (token == 'if') { |
| 1298 var cond = tree.firstChild; | 1301 var cond = tree.firstChild; |
| 1299 var attrib = cond.value.slice(1); | 1302 var attrib = cond.value.slice(1); |
| 1300 if (node[attrib] !== undefined || node.state[attrib]) | 1303 if (node[attrib] !== undefined || node.state[attrib]) |
| 1301 this.format_(node, cond.nextSibling, buff); | 1304 this.format_(node, cond.nextSibling, buff); |
| 1302 else | 1305 else |
| 1303 this.format_(node, cond.nextSibling.nextSibling, buff); | 1306 this.format_(node, cond.nextSibling.nextSibling, buff); |
| 1304 } else if (token == 'earcon') { | 1307 } else if (token == 'earcon') { |
| 1305 // Ignore unless we're generating speech output. | 1308 // Ignore unless we're generating speech output. |
| 1306 if (!this.formatOptions_.speech) | 1309 if (!this.formatOptions_.speech) |
| 1307 return; | 1310 return; |
| 1308 | 1311 |
| 1309 options.annotation.push( | 1312 options.annotation.push( |
| 1310 new Output.EarconAction(tree.firstChild.value, node.location)); | 1313 new Output.EarconAction(tree.firstChild.value, |
| 1314 node.location || undefined)); |
| 1311 this.append_(buff, '', options); | 1315 this.append_(buff, '', options); |
| 1312 } else if (token == 'countChildren') { | 1316 } else if (token == 'countChildren') { |
| 1313 var role = tree.firstChild.value; | 1317 var role = tree.firstChild.value; |
| 1314 var count = node.children.filter(function(e) { | 1318 var count = node.children.filter(function(e) { |
| 1315 return e.role == role; | 1319 return e.role == role; |
| 1316 }).length; | 1320 }).length; |
| 1317 this.append_(buff, String(count)); | 1321 this.append_(buff, String(count)); |
| 1318 } | 1322 } |
| 1319 } | 1323 } |
| 1320 } else if (prefix == '@') { | 1324 } else if (prefix == '@') { |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1467 */ | 1471 */ |
| 1468 ancestry_: function(node, prevNode, type, buff) { | 1472 ancestry_: function(node, prevNode, type, buff) { |
| 1469 // Expects |ancestors| to be ordered from root down to leaf. Outputs in | 1473 // Expects |ancestors| to be ordered from root down to leaf. Outputs in |
| 1470 // reverse; place context first nodes at the end. | 1474 // reverse; place context first nodes at the end. |
| 1471 function byContextFirst(ancestors) { | 1475 function byContextFirst(ancestors) { |
| 1472 var contextFirst = []; | 1476 var contextFirst = []; |
| 1473 var rest = []; | 1477 var rest = []; |
| 1474 for (i = 0; i < ancestors.length - 1; i++) { | 1478 for (i = 0; i < ancestors.length - 1; i++) { |
| 1475 var node = ancestors[i]; | 1479 var node = ancestors[i]; |
| 1476 // Discard ancestors of deepest window. | 1480 // Discard ancestors of deepest window. |
| 1477 if (node.role == RoleType.window) { | 1481 if (node.role == RoleType.WINDOW) { |
| 1478 contextFirst = []; | 1482 contextFirst = []; |
| 1479 rest = []; | 1483 rest = []; |
| 1480 } | 1484 } |
| 1481 if ((Output.ROLE_INFO_[node.role] || {}).outputContextFirst) | 1485 if ((Output.ROLE_INFO_[node.role] || {}).outputContextFirst) |
| 1482 contextFirst.push(node); | 1486 contextFirst.push(node); |
| 1483 else | 1487 else |
| 1484 rest.push(node); | 1488 rest.push(node); |
| 1485 } | 1489 } |
| 1486 return rest.concat(contextFirst.reverse()); | 1490 return rest.concat(contextFirst.reverse()); |
| 1487 } | 1491 } |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1631 } | 1635 } |
| 1632 } | 1636 } |
| 1633 | 1637 |
| 1634 if (this.outputContextFirst_) | 1638 if (this.outputContextFirst_) |
| 1635 this.ancestry_(node, prevNode, type, buff); | 1639 this.ancestry_(node, prevNode, type, buff); |
| 1636 var earcon = this.findEarcon_(node, prevNode); | 1640 var earcon = this.findEarcon_(node, prevNode); |
| 1637 if (earcon) | 1641 if (earcon) |
| 1638 options.annotation.push(earcon); | 1642 options.annotation.push(earcon); |
| 1639 var text = ''; | 1643 var text = ''; |
| 1640 | 1644 |
| 1641 if (this.formatOptions_.braille && !node.state.editable) { | 1645 if (this.formatOptions_.braille && !node.state[StateType.EDITABLE]) { |
| 1642 // In braille, we almost always want to show the entire contents and | 1646 // In braille, we almost always want to show the entire contents and |
| 1643 // simply place the cursor under the SelectionSpan we set above. | 1647 // simply place the cursor under the SelectionSpan we set above. |
| 1644 text = range.start.getText(); | 1648 text = range.start.getText(); |
| 1645 } else { | 1649 } else { |
| 1646 // This is output for speech or editable braille. | 1650 // This is output for speech or editable braille. |
| 1647 text = range.start.getText().substring(rangeStart, rangeEnd); | 1651 text = range.start.getText().substring(rangeStart, rangeEnd); |
| 1648 } | 1652 } |
| 1649 | 1653 |
| 1650 this.append_(buff, text, options); | 1654 this.append_(buff, text, options); |
| 1651 | 1655 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1774 return result; | 1778 return result; |
| 1775 } | 1779 } |
| 1776 | 1780 |
| 1777 // Keep track of if there's an inline node associated with | 1781 // Keep track of if there's an inline node associated with |
| 1778 // |cur|. | 1782 // |cur|. |
| 1779 var hasInlineNode = cur.getSpansInstanceOf(Output.NodeSpan) | 1783 var hasInlineNode = cur.getSpansInstanceOf(Output.NodeSpan) |
| 1780 .some(function(s) { | 1784 .some(function(s) { |
| 1781 if (!s.node) | 1785 if (!s.node) |
| 1782 return false; | 1786 return false; |
| 1783 return s.node.display == 'inline' || | 1787 return s.node.display == 'inline' || |
| 1784 s.node.role == RoleType.inlineTextBox; | 1788 s.node.role == RoleType.INLINE_TEXT_BOX; |
| 1785 }); | 1789 }); |
| 1786 | 1790 |
| 1787 var isName = cur.hasSpan('name'); | 1791 var isName = cur.hasSpan('name'); |
| 1788 | 1792 |
| 1789 // Now, decide whether we should include separators between the previous | 1793 // Now, decide whether we should include separators between the previous |
| 1790 // span and |cur|. | 1794 // span and |cur|. |
| 1791 // Never separate chunks without something already there at this point. | 1795 // Never separate chunks without something already there at this point. |
| 1792 | 1796 |
| 1793 // The only case where we know for certain that a separator is not needed | 1797 // The only case where we know for certain that a separator is not needed |
| 1794 // is when the previous and current values are in-lined and part of the | 1798 // is when the previous and current values are in-lined and part of the |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1825 var earconFinder = node; | 1829 var earconFinder = node; |
| 1826 var ancestors; | 1830 var ancestors; |
| 1827 if (opt_prevNode) | 1831 if (opt_prevNode) |
| 1828 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); | 1832 ancestors = AutomationUtil.getUniqueAncestors(opt_prevNode, node); |
| 1829 else | 1833 else |
| 1830 ancestors = AutomationUtil.getAncestors(node); | 1834 ancestors = AutomationUtil.getAncestors(node); |
| 1831 | 1835 |
| 1832 while (earconFinder = ancestors.pop()) { | 1836 while (earconFinder = ancestors.pop()) { |
| 1833 var info = Output.ROLE_INFO_[earconFinder.role]; | 1837 var info = Output.ROLE_INFO_[earconFinder.role]; |
| 1834 if (info && info.earconId) { | 1838 if (info && info.earconId) { |
| 1835 return new Output.EarconAction(info.earconId, node.location); | 1839 return new Output.EarconAction(info.earconId, |
| 1840 node.location || undefined); |
| 1836 break; | 1841 break; |
| 1837 } | 1842 } |
| 1838 earconFinder = earconFinder.parent; | 1843 earconFinder = earconFinder.parent; |
| 1839 } | 1844 } |
| 1840 } | 1845 } |
| 1841 return null; | 1846 return null; |
| 1842 }, | 1847 }, |
| 1843 | 1848 |
| 1844 /** | 1849 /** |
| 1845 * Gets a human friendly string with the contents of output. | 1850 * Gets a human friendly string with the contents of output. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1871 /** | 1876 /** |
| 1872 * Gets the output buffer for braille. | 1877 * Gets the output buffer for braille. |
| 1873 * @return {!Spannable} | 1878 * @return {!Spannable} |
| 1874 */ | 1879 */ |
| 1875 get brailleOutputForTest() { | 1880 get brailleOutputForTest() { |
| 1876 return this.mergeBraille_(this.brailleBuffer_); | 1881 return this.mergeBraille_(this.brailleBuffer_); |
| 1877 } | 1882 } |
| 1878 }; | 1883 }; |
| 1879 | 1884 |
| 1880 }); // goog.scope | 1885 }); // goog.scope |
| OLD | NEW |