Chromium Code Reviews| 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 ChromeVox predicates for the automation extension API. | 6 * @fileoverview ChromeVox predicates for the automation extension API. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 goog.provide('AutomationPredicate'); | 9 goog.provide('AutomationPredicate'); |
| 10 goog.provide('AutomationPredicate.Binary'); | 10 goog.provide('AutomationPredicate.Binary'); |
| 11 goog.provide('AutomationPredicate.Unary'); | 11 goog.provide('AutomationPredicate.Unary'); |
| 12 | 12 |
| 13 goog.require('constants'); | 13 goog.require('constants'); |
| 14 | 14 |
| 15 goog.scope(function() { | 15 goog.scope(function() { |
| 16 var AutomationNode = chrome.automation.AutomationNode; | 16 var AutomationNode = chrome.automation.AutomationNode; |
| 17 var Dir = constants.Dir; | 17 var Dir = constants.Dir; |
| 18 var RoleType = chrome.automation.RoleType; | 18 var Role = chrome.automation.RoleType; |
| 19 | 19 |
| 20 /** | 20 /** |
| 21 * @constructor | 21 * @constructor |
| 22 */ | 22 */ |
| 23 AutomationPredicate = function() {}; | 23 AutomationPredicate = function() {}; |
| 24 | 24 |
| 25 /** | 25 /** |
| 26 * @typedef {function(!AutomationNode) : boolean} | 26 * @typedef {function(!AutomationNode) : boolean} |
| 27 */ | 27 */ |
| 28 AutomationPredicate.Unary; | 28 AutomationPredicate.Unary; |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * @typedef {function(!AutomationNode, !AutomationNode) : boolean} | 31 * @typedef {function(!AutomationNode, !AutomationNode) : boolean} |
| 32 */ | 32 */ |
| 33 AutomationPredicate.Binary; | 33 AutomationPredicate.Binary; |
| 34 | 34 |
| 35 /** | 35 /** |
| 36 * Constructs a predicate given a role. | 36 * Constructs a predicate given a list of roles or predicates. |
| 37 * @param {RoleType} role | 37 * @param {!Array<AutomationPredicate.Unary|Role>} roles |
| 38 * @return {AutomationPredicate.Unary} | 38 * @return {AutomationPredicate.Unary} |
| 39 * @private | |
| 39 */ | 40 */ |
| 40 AutomationPredicate.withRole = function(role) { | 41 AutomationPredicate.roles_ = function(roles) { |
|
dmazzoni
2016/09/23 17:52:57
I think it's a little surprising to have a functio
| |
| 42 if (!roles.length) | |
| 43 throw 'Expected at least one predicate.'; | |
| 41 return function(node) { | 44 return function(node) { |
| 42 return node.role == role; | 45 return roles.some(function(role) { |
| 46 return role == node.role || | |
| 47 (typeof role == 'function' && role(node)); | |
| 48 }); | |
| 43 }; | 49 }; |
| 44 }; | 50 }; |
| 45 | 51 |
| 46 /** @type {AutomationPredicate.Unary} */ | 52 /** @type {AutomationPredicate.Unary} */ |
| 47 AutomationPredicate.checkBox = AutomationPredicate.withRole(RoleType.checkBox); | 53 AutomationPredicate.checkBox = AutomationPredicate.roles_([Role.checkBox]); |
| 48 /** @type {AutomationPredicate.Unary} */ | 54 /** @type {AutomationPredicate.Unary} */ |
| 49 AutomationPredicate.comboBox = AutomationPredicate.withRole(RoleType.comboBox); | 55 AutomationPredicate.comboBox = AutomationPredicate.roles_( |
| 56 [Role.comboBox, Role.popUpButton, Role.menuListPopup]); | |
| 50 /** @type {AutomationPredicate.Unary} */ | 57 /** @type {AutomationPredicate.Unary} */ |
| 51 AutomationPredicate.heading = AutomationPredicate.withRole(RoleType.heading); | 58 AutomationPredicate.heading = AutomationPredicate.roles_([Role.heading]); |
| 52 /** @type {AutomationPredicate.Unary} */ | 59 /** @type {AutomationPredicate.Unary} */ |
| 53 AutomationPredicate.inlineTextBox = | 60 AutomationPredicate.inlineTextBox = |
| 54 AutomationPredicate.withRole(RoleType.inlineTextBox); | 61 AutomationPredicate.roles_([Role.inlineTextBox]); |
| 55 /** @type {AutomationPredicate.Unary} */ | 62 /** @type {AutomationPredicate.Unary} */ |
| 56 AutomationPredicate.link = AutomationPredicate.withRole(RoleType.link); | 63 AutomationPredicate.link = AutomationPredicate.roles_([Role.link]); |
| 57 /** @type {AutomationPredicate.Unary} */ | 64 /** @type {AutomationPredicate.Unary} */ |
| 58 AutomationPredicate.row = AutomationPredicate.withRole(RoleType.row); | 65 AutomationPredicate.row = AutomationPredicate.roles_([Role.row]); |
| 59 /** @type {AutomationPredicate.Unary} */ | 66 /** @type {AutomationPredicate.Unary} */ |
| 60 AutomationPredicate.table = AutomationPredicate.withRole(RoleType.table); | 67 AutomationPredicate.table = AutomationPredicate.roles_([Role.table]); |
| 61 | 68 |
| 62 /** | 69 /** |
| 63 * @param {!AutomationNode} node | 70 * @param {!AutomationNode} node |
| 64 * @return {boolean} | 71 * @return {boolean} |
| 65 */ | 72 */ |
| 66 AutomationPredicate.button = function(node) { | 73 AutomationPredicate.button = function(node) { |
| 67 return /button/i.test(node.role); | 74 return /button/i.test(node.role); |
| 68 }; | 75 }; |
| 69 | 76 |
| 70 | |
| 71 /** | 77 /** |
| 72 * @param {!AutomationNode} node | 78 * @param {!AutomationNode} node |
| 73 * @return {boolean} | 79 * @return {boolean} |
| 74 */ | 80 */ |
| 75 AutomationPredicate.editText = function(node) { | 81 AutomationPredicate.editText = function(node) { |
| 76 return node.state.editable && | 82 return node.state.editable && |
| 77 node.parent && | 83 node.parent && |
| 78 !node.parent.state.editable; | 84 !node.parent.state.editable; |
| 79 }; | 85 }; |
| 80 | 86 |
| 81 /** | 87 /** @type {AutomationPredicate.Unary} */ |
| 82 * @param {!AutomationNode} node | 88 AutomationPredicate.formField = AutomationPredicate.roles_([ |
| 83 * @return {boolean} | 89 AutomationPredicate.button, |
| 84 */ | 90 Role.checkBox, |
| 85 AutomationPredicate.formField = function(node) { | 91 AutomationPredicate.comboBox, |
| 86 switch (node.role) { | 92 AutomationPredicate.editText, |
| 87 case 'button': | 93 Role.listBox, |
| 88 case 'buttonDropDown': | 94 Role.slider, |
| 89 case 'checkBox': | 95 Role.tab, |
| 90 case 'comboBox': | 96 Role.tree]); |
| 91 case 'date': | 97 |
| 92 case 'dateTime': | 98 /** @type {AutomationPredicate.Unary} */ |
| 93 case 'details': | 99 AutomationPredicate.landmark = AutomationPredicate.roles_([ |
| 94 case 'disclosureTriangle': | 100 Role.application, |
| 95 case 'form': | 101 Role.banner, |
| 96 case 'menuButton': | 102 Role.complementary, |
| 97 case 'menuListPopup': | 103 Role.contentInfo, |
| 98 case 'popUpButton': | 104 Role.form, |
| 99 case 'radioButton': | 105 Role.group, |
| 100 case 'searchBox': | 106 Role.main, |
| 101 case 'slider': | 107 Role.navigation, |
| 102 case 'spinButton': | 108 Role.region, |
| 103 case 'switch': | 109 Role.search]); |
| 104 case 'tab': | |
| 105 case 'textField': | |
| 106 case 'time': | |
| 107 case 'toggleButton': | |
| 108 case 'tree': | |
| 109 return true; | |
| 110 } | |
| 111 return false; | |
| 112 }; | |
| 113 | 110 |
| 114 /** | 111 /** |
| 115 * @param {!AutomationNode} node | 112 * @param {!AutomationNode} node |
| 116 * @return {boolean} | |
| 117 */ | |
| 118 AutomationPredicate.landmark = function(node) { | |
| 119 switch (node.role) { | |
| 120 case 'application': | |
| 121 case 'banner': | |
| 122 case 'complementary': | |
| 123 case 'contentInfo': | |
| 124 case 'form': | |
| 125 case 'main': | |
| 126 case 'navigation': | |
| 127 case 'search': | |
| 128 return true; | |
| 129 } | |
| 130 return false; | |
| 131 }; | |
| 132 | |
| 133 /** | |
| 134 * @param {!AutomationNode} node | |
| 135 * @return {boolean} | 113 * @return {boolean} |
| 136 */ | 114 */ |
| 137 AutomationPredicate.visitedLink = function(node) { | 115 AutomationPredicate.visitedLink = function(node) { |
| 138 return node.state.visited; | 116 return node.state.visited; |
| 139 }; | 117 }; |
| 140 | 118 |
| 141 /** | 119 /** |
| 142 * @param {!AutomationNode} node | 120 * @param {!AutomationNode} node |
| 143 * @return {boolean} | 121 * @return {boolean} |
| 144 */ | 122 */ |
| 145 AutomationPredicate.focused = function(node) { | 123 AutomationPredicate.focused = function(node) { |
| 146 return node.state.focused; | 124 return node.state.focused; |
| 147 }; | 125 }; |
| 148 | 126 |
| 149 /** | 127 /** |
| 150 * @param {!AutomationNode} node | 128 * @param {!AutomationNode} node |
| 151 * @return {boolean} | 129 * @return {boolean} |
| 152 */ | 130 */ |
| 153 AutomationPredicate.leaf = function(node) { | 131 AutomationPredicate.leaf = function(node) { |
| 154 return !node.firstChild || | 132 return !node.firstChild || |
| 155 node.role == RoleType.button || | 133 node.role == Role.button || |
| 156 node.role == RoleType.buttonDropDown || | 134 node.role == Role.buttonDropDown || |
| 157 node.role == RoleType.popUpButton || | 135 node.role == Role.popUpButton || |
| 158 node.role == RoleType.slider || | 136 node.role == Role.slider || |
| 159 node.role == RoleType.textField || | 137 node.role == Role.textField || |
| 160 node.state.invisible || | 138 node.state.invisible || |
| 161 node.children.every(function(n) { | 139 node.children.every(function(n) { |
| 162 return n.state.invisible; | 140 return n.state.invisible; |
| 163 }); | 141 }); |
| 164 }; | 142 }; |
| 165 | 143 |
| 166 /** | 144 /** |
| 167 * @param {!AutomationNode} node | 145 * @param {!AutomationNode} node |
| 168 * @return {boolean} | 146 * @return {boolean} |
| 169 */ | 147 */ |
| 170 AutomationPredicate.leafWithText = function(node) { | 148 AutomationPredicate.leafWithText = function(node) { |
| 171 return AutomationPredicate.leaf(node) && | 149 return AutomationPredicate.leaf(node) && |
| 172 !!(node.name || node.value); | 150 !!(node.name || node.value); |
| 173 }; | 151 }; |
| 174 | 152 |
| 175 /** | 153 /** |
| 176 * Matches against leaves or static text nodes. Useful when restricting | 154 * Matches against leaves or static text nodes. Useful when restricting |
| 177 * traversal to non-inline textboxes while still allowing them if navigation | 155 * traversal to non-inline textboxes while still allowing them if navigation |
| 178 * already entered into an inline textbox. | 156 * already entered into an inline textbox. |
| 179 * @param {!AutomationNode} node | 157 * @param {!AutomationNode} node |
| 180 * @return {boolean} | 158 * @return {boolean} |
| 181 */ | 159 */ |
| 182 AutomationPredicate.leafOrStaticText = function(node) { | 160 AutomationPredicate.leafOrStaticText = function(node) { |
| 183 return AutomationPredicate.leaf(node) || | 161 return AutomationPredicate.leaf(node) || |
| 184 node.role == RoleType.staticText; | 162 node.role == Role.staticText; |
| 185 }; | 163 }; |
| 186 | 164 |
| 187 /** | 165 /** |
| 188 * Matches against nodes visited during object navigation. An object as | 166 * Matches against nodes visited during object navigation. An object as |
| 189 * defined below, are all nodes that are focusable or static text. When used in | 167 * defined below, are all nodes that are focusable or static text. When used in |
| 190 * tree walking, it should visit all nodes that tab traversal would as well as | 168 * tree walking, it should visit all nodes that tab traversal would as well as |
| 191 * non-focusable static text. | 169 * non-focusable static text. |
| 192 * @param {!AutomationNode} node | 170 * @param {!AutomationNode} node |
| 193 * @return {boolean} | 171 * @return {boolean} |
| 194 */ | 172 */ |
| 195 AutomationPredicate.object = function(node) { | 173 AutomationPredicate.object = function(node) { |
| 196 // Editable nodes are within a text-like field and don't make sense when | 174 // Editable nodes are within a text-like field and don't make sense when |
| 197 // performing object navigation. Users should use line, word, or character | 175 // performing object navigation. Users should use line, word, or character |
| 198 // navigation. Only navigate to the top level node. | 176 // navigation. Only navigate to the top level node. |
| 199 if (node.parent && node.parent.state.editable) | 177 if (node.parent && node.parent.state.editable) |
| 200 return false; | 178 return false; |
| 201 | 179 |
| 202 return node.state.focusable || | 180 return node.state.focusable || |
| 203 (AutomationPredicate.leafOrStaticText(node) && | 181 (AutomationPredicate.leafOrStaticText(node) && |
| 204 (/\S+/.test(node.name) || | 182 (/\S+/.test(node.name) || |
| 205 (node.role != RoleType.lineBreak && | 183 (node.role != Role.lineBreak && |
| 206 node.role != RoleType.staticText && | 184 node.role != Role.staticText && |
| 207 node.role != RoleType.inlineTextBox))); | 185 node.role != Role.inlineTextBox))); |
| 208 }; | 186 }; |
| 209 | 187 |
| 210 /** | 188 /** |
| 211 * @param {!AutomationNode} first | 189 * @param {!AutomationNode} first |
| 212 * @param {!AutomationNode} second | 190 * @param {!AutomationNode} second |
| 213 * @return {boolean} | 191 * @return {boolean} |
| 214 */ | 192 */ |
| 215 AutomationPredicate.linebreak = function(first, second) { | 193 AutomationPredicate.linebreak = function(first, second) { |
| 216 // TODO(dtseng): Use next/previousOnLin once available. | 194 // TODO(dtseng): Use next/previousOnLin once available. |
| 217 var fl = first.location; | 195 var fl = first.location; |
| 218 var sl = second.location; | 196 var sl = second.location; |
| 219 return fl.top != sl.top || | 197 return fl.top != sl.top || |
| 220 (fl.top + fl.height != sl.top + sl.height); | 198 (fl.top + fl.height != sl.top + sl.height); |
| 221 }; | 199 }; |
| 222 | 200 |
| 223 /** | 201 /** |
| 224 * Matches against a node that contains other interesting nodes. | 202 * Matches against a node that contains other interesting nodes. |
| 225 * These nodes should always have their subtrees scanned when navigating. | 203 * These nodes should always have their subtrees scanned when navigating. |
| 226 * @param {!AutomationNode} node | 204 * @param {!AutomationNode} node |
| 227 * @return {boolean} | 205 * @return {boolean} |
| 228 */ | 206 */ |
| 229 AutomationPredicate.container = function(node) { | 207 AutomationPredicate.container = function(node) { |
| 230 return AutomationPredicate.structuralContainer(node) || | 208 return AutomationPredicate.structuralContainer(node) || |
| 231 node.role == RoleType.div || | 209 node.role == Role.div || |
| 232 node.role == RoleType.document || | 210 node.role == Role.document || |
| 233 node.role == RoleType.group || | 211 node.role == Role.group || |
| 234 node.role == RoleType.listItem || | 212 node.role == Role.listItem || |
| 235 node.role == RoleType.toolbar || | 213 node.role == Role.toolbar || |
| 236 node.role == RoleType.window || | 214 node.role == Role.window || |
| 237 // For example, crosh. | 215 // For example, crosh. |
| 238 (node.role == RoleType.textField && node.state.readOnly) || | 216 (node.role == Role.textField && node.state.readOnly) || |
| 239 (node.state.editable && node.parent && !node.parent.state.editable); | 217 (node.state.editable && node.parent && !node.parent.state.editable); |
| 240 }; | 218 }; |
| 241 | 219 |
| 242 /** | 220 /** |
| 243 * Matches against nodes that contain interesting nodes, but should never be | 221 * Matches against nodes that contain interesting nodes, but should never be |
| 244 * visited. | 222 * visited. |
| 245 * @param {!AutomationNode} node | 223 * @param {!AutomationNode} node |
| 246 * @return {boolean} | 224 * @return {boolean} |
| 247 */ | 225 */ |
| 248 AutomationPredicate.structuralContainer = function(node) { | 226 AutomationPredicate.structuralContainer = function(node) { |
| 249 return node.role == RoleType.rootWebArea || | 227 return node.role == Role.rootWebArea || |
| 250 node.role == RoleType.embeddedObject || | 228 node.role == Role.embeddedObject || |
| 251 node.role == RoleType.iframe || | 229 node.role == Role.iframe || |
| 252 node.role == RoleType.iframePresentational; | 230 node.role == Role.iframePresentational; |
| 253 }; | 231 }; |
| 254 | 232 |
| 255 /** | 233 /** |
| 256 * Returns whether the given node should not be crossed when performing | 234 * Returns whether the given node should not be crossed when performing |
| 257 * traversals up the ancestry chain. | 235 * traversals up the ancestry chain. |
| 258 * @param {AutomationNode} node | 236 * @param {AutomationNode} node |
| 259 * @return {boolean} | 237 * @return {boolean} |
| 260 */ | 238 */ |
| 261 AutomationPredicate.root = function(node) { | 239 AutomationPredicate.root = function(node) { |
| 262 switch (node.role) { | 240 switch (node.role) { |
| 263 case RoleType.dialog: | 241 case Role.dialog: |
| 264 case RoleType.window: | 242 case Role.window: |
| 265 return true; | 243 return true; |
| 266 case RoleType.toolbar: | 244 case Role.toolbar: |
| 267 return node.root.role == RoleType.desktop; | 245 return node.root.role == Role.desktop; |
| 268 case RoleType.rootWebArea: | 246 case Role.rootWebArea: |
| 269 return !node.parent || node.parent.root.role == RoleType.desktop; | 247 return !node.parent || node.parent.root.role == Role.desktop; |
| 270 default: | 248 default: |
| 271 return false; | 249 return false; |
| 272 } | 250 } |
| 273 }; | 251 }; |
| 274 | 252 |
| 275 /** | 253 /** |
| 276 * Nodes that should be ignored while traversing the automation tree. For | 254 * Nodes that should be ignored while traversing the automation tree. For |
| 277 * example, apply this predicate when moving to the next object. | 255 * example, apply this predicate when moving to the next object. |
| 278 * @param {!AutomationNode} node | 256 * @param {!AutomationNode} node |
| 279 * @return {boolean} | 257 * @return {boolean} |
| 280 */ | 258 */ |
| 281 AutomationPredicate.shouldIgnoreNode = function(node) { | 259 AutomationPredicate.shouldIgnoreNode = function(node) { |
| 282 // Ignore invisible nodes. | 260 // Ignore invisible nodes. |
| 283 if (node.state.invisible || | 261 if (node.state.invisible || |
| 284 (node.location.height == 0 && node.location.width == 0)) | 262 (node.location.height == 0 && node.location.width == 0)) |
| 285 return true; | 263 return true; |
| 286 | 264 |
| 287 // Ignore structural containres. | 265 // Ignore structural containres. |
| 288 if (AutomationPredicate.structuralContainer(node)) | 266 if (AutomationPredicate.structuralContainer(node)) |
| 289 return true; | 267 return true; |
| 290 | 268 |
| 291 // Ignore list markers since we already announce listitem role. | 269 // Ignore list markers since we already announce listitem role. |
| 292 if (node.role == RoleType.listMarker) | 270 if (node.role == Role.listMarker) |
| 293 return true; | 271 return true; |
| 294 | 272 |
| 295 // Don't ignore nodes with names. | 273 // Don't ignore nodes with names. |
| 296 if (node.name || node.value || node.description) | 274 if (node.name || node.value || node.description) |
| 297 return false; | 275 return false; |
| 298 | 276 |
| 299 // Ignore some roles. | 277 // Ignore some roles. |
| 300 return AutomationPredicate.leaf(node) && | 278 return AutomationPredicate.leaf(node) && |
| 301 (node.role == RoleType.client || | 279 (node.role == Role.client || |
|
dmazzoni
2016/09/23 17:52:57
This looks like a great opportunity to make it mor
| |
| 302 node.role == RoleType.column || | 280 node.role == Role.column || |
| 303 node.role == RoleType.div || | 281 node.role == Role.div || |
| 304 node.role == RoleType.group || | 282 node.role == Role.group || |
| 305 node.role == RoleType.image || | 283 node.role == Role.image || |
| 306 node.role == RoleType.staticText || | 284 node.role == Role.staticText || |
| 307 node.role == RoleType.tableHeaderContainer); | 285 node.role == Role.tableHeaderContainer); |
| 308 }; | 286 }; |
| 309 | 287 |
| 310 | 288 |
| 311 /** | 289 /** |
| 312 * Returns if the node has a meaningful checked state. | 290 * Returns if the node has a meaningful checked state. |
| 313 * @param {!AutomationNode} node | 291 * @param {!AutomationNode} node |
| 314 * @return {boolean} | 292 * @return {boolean} |
| 315 */ | 293 */ |
| 316 AutomationPredicate.checkable = function(node) { | 294 AutomationPredicate.checkable = function(node) { |
| 317 return node.role == RoleType.checkBox || | 295 return node.role == Role.checkBox || |
| 318 node.role == RoleType.radioButton || | 296 node.role == Role.radioButton || |
| 319 node.role == RoleType.menuItemCheckBox || | 297 node.role == Role.menuItemCheckBox || |
| 320 node.role == RoleType.menuItemRadio || | 298 node.role == Role.menuItemRadio || |
| 321 node.role == RoleType.treeItem; | 299 node.role == Role.treeItem; |
| 322 }; | 300 }; |
| 323 | 301 |
| 324 // Table related predicates. | 302 // Table related predicates. |
| 325 /** | 303 /** |
| 326 * Returns if the node has a cell like role. | 304 * Returns if the node has a cell like role. |
| 327 * @param {!AutomationNode} node | 305 * @param {!AutomationNode} node |
| 328 * @return {boolean} | 306 * @return {boolean} |
| 329 */ | 307 */ |
| 330 AutomationPredicate.cellLike = function(node) { | 308 AutomationPredicate.cellLike = function(node) { |
| 331 return node.role == RoleType.cell || | 309 return node.role == Role.cell || |
| 332 node.role == RoleType.rowHeader || | 310 node.role == Role.rowHeader || |
| 333 node.role == RoleType.columnHeader; | 311 node.role == Role.columnHeader; |
| 334 }; | 312 }; |
| 335 | 313 |
| 336 /** | 314 /** |
| 337 * Returns a predicate that will match against the directed next cell taking | 315 * Returns a predicate that will match against the directed next cell taking |
| 338 * into account the current ancestor cell's position in the table. | 316 * into account the current ancestor cell's position in the table. |
| 339 * @param {AutomationNode} start | 317 * @param {AutomationNode} start |
| 340 * @param {{dir: (Dir|undefined), | 318 * @param {{dir: (Dir|undefined), |
| 341 * row: (boolean|undefined), | 319 * row: (boolean|undefined), |
| 342 * col: (boolean|undefined)}} opts | 320 * col: (boolean|undefined)}} opts |
| 343 * |dir|, specifies direction for |row or/and |col| movement by one cell. | 321 * |dir|, specifies direction for |row or/and |col| movement by one cell. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 }; | 382 }; |
| 405 | 383 |
| 406 /** | 384 /** |
| 407 * Returns a predicate that will match against a heading with a specific | 385 * Returns a predicate that will match against a heading with a specific |
| 408 * hierarchical level. | 386 * hierarchical level. |
| 409 * @param {number} level 1-6 | 387 * @param {number} level 1-6 |
| 410 * @return {AutomationPredicate.Unary} | 388 * @return {AutomationPredicate.Unary} |
| 411 */ | 389 */ |
| 412 AutomationPredicate.makeHeadingPredicate = function(level) { | 390 AutomationPredicate.makeHeadingPredicate = function(level) { |
| 413 return function(node) { | 391 return function(node) { |
| 414 return node.role == RoleType.heading && node.hierarchicalLevel == level; | 392 return node.role == Role.heading && node.hierarchicalLevel == level; |
| 415 }; | 393 }; |
| 416 }; | 394 }; |
| 417 | 395 |
| 418 }); // goog.scope | 396 }); // goog.scope |
| OLD | NEW |