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