| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 * @unrestricted | 5 * @unrestricted |
| 6 */ | 6 */ |
| 7 WebInspector.AccessibilityNode = class extends WebInspector.SDKObject { | 7 WebInspector.AccessibilityNode = class extends WebInspector.SDKObject { |
| 8 /** | 8 /** |
| 9 * @param {!WebInspector.AccessibilityModel} accessibilityModel | 9 * @param {!WebInspector.AccessibilityModel} accessibilityModel |
| 10 * @param {!AccessibilityAgent.AXNode} payload | 10 * @param {!AccessibilityAgent.AXNode} payload |
| 11 */ | 11 */ |
| 12 constructor(accessibilityModel, payload) { | 12 constructor(accessibilityModel, payload) { |
| 13 super(accessibilityModel.target()); | 13 super(accessibilityModel.target()); |
| 14 this._accessibilityModel = accessibilityModel; | 14 this._accessibilityModel = accessibilityModel; |
| 15 this._agent = accessibilityModel._agent; | 15 this._agent = accessibilityModel._agent; |
| 16 | 16 |
| 17 this._id = payload.nodeId; | 17 this._id = payload.nodeId; |
| 18 accessibilityModel._setAXNodeForAXId(this._id, this); | 18 accessibilityModel._setAXNodeForAXId(this._id, this); |
| 19 | 19 |
| 20 this._ignored = payload.ignored; | 20 this._ignored = payload.ignored; |
| 21 if (this._ignored && 'ignoredReasons' in payload) | 21 if (this._ignored && 'ignoredReasons' in payload) |
| 22 this._ignoredReasons = payload.ignoredReasons; | 22 this._ignoredReasons = payload.ignoredReasons; |
| 23 | 23 |
| 24 this._role = payload.role || null; | 24 this._role = payload.role || null; |
| 25 this._name = payload.name || null; | 25 this._name = payload.name || null; |
| 26 this._description = payload.description || null; | 26 this._description = payload.description || null; |
| 27 this._value = payload.value || null; | 27 this._value = payload.value || null; |
| 28 this._properties = payload.properties || null; | 28 this._properties = payload.properties || null; |
| 29 this._parentId = payload.parentId || null; | |
| 30 this._childIds = payload.childIds || null; | 29 this._childIds = payload.childIds || null; |
| 31 this._domNodeId = payload.domNodeId || null; | 30 this._backendDomNodeId = payload.backendDomNodeId || null; |
| 31 this._parentNode = null; |
| 32 } | 32 } |
| 33 | 33 |
| 34 /** | 34 /** |
| 35 * @return {boolean} | 35 * @return {boolean} |
| 36 */ | 36 */ |
| 37 ignored() { | 37 ignored() { |
| 38 return this._ignored; | 38 return this._ignored; |
| 39 } | 39 } |
| 40 | 40 |
| 41 /** | 41 /** |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 * @return {?Array<!AccessibilityAgent.AXProperty>} | 93 * @return {?Array<!AccessibilityAgent.AXProperty>} |
| 94 */ | 94 */ |
| 95 properties() { | 95 properties() { |
| 96 return this._properties || null; | 96 return this._properties || null; |
| 97 } | 97 } |
| 98 | 98 |
| 99 /** | 99 /** |
| 100 * @return {?WebInspector.AccessibilityNode} | 100 * @return {?WebInspector.AccessibilityNode} |
| 101 */ | 101 */ |
| 102 parentNode() { | 102 parentNode() { |
| 103 if (!this._parentId) | 103 return this._parentNode; |
| 104 return null; | 104 } |
| 105 return this._accessibilityModel.axNodeForId(this._parentId); | 105 |
| 106 /** |
| 107 * @param {?WebInspector.AccessibilityNode} parentNode |
| 108 */ |
| 109 _setParentNode(parentNode) { |
| 110 this._parentNode = parentNode; |
| 111 } |
| 112 |
| 113 /** |
| 114 * @return {boolean} |
| 115 */ |
| 116 isDOMNode() { |
| 117 return !!this._backendDomNodeId; |
| 118 } |
| 119 |
| 120 /** |
| 121 * @return {?WebInspector.DOMNode} |
| 122 */ |
| 123 domNode() { |
| 124 return this._domNode || null; |
| 125 } |
| 126 |
| 127 /** |
| 128 * @param {?WebInspector.DOMNode} domNode |
| 129 */ |
| 130 _setDOMNode(domNode) { |
| 131 this._domNode = domNode; |
| 132 if (domNode) |
| 133 this._accessibilityModel.setAXNodeForDOMNode(domNode, this); |
| 134 } |
| 135 |
| 136 /** |
| 137 * @return {!Promise<?WebInspector.DOMNode>} |
| 138 */ |
| 139 resolveDOMNode() { |
| 140 if (this._domNode) |
| 141 return Promise.resolve(this._domNode); |
| 142 if (!this._backendDomNodeId) |
| 143 return Promise.resolve(/** @type {?WebInspector.DOMNode} */ (null)); |
| 144 |
| 145 var deferredNode = new WebInspector.DeferredDOMNode(this.target(), this._bac
kendDomNodeId); |
| 146 return deferredNode.resolvePromise().then((domNode) => { |
| 147 this._setDOMNode(domNode); |
| 148 return domNode; |
| 149 }); |
| 150 } |
| 151 |
| 152 /** |
| 153 * @return {!Array<!WebInspector.AccessibilityNode>} |
| 154 */ |
| 155 children() { |
| 156 var children = []; |
| 157 if (!this._childIds) |
| 158 return children; |
| 159 |
| 160 for (var childId of this._childIds) { |
| 161 var child = this._accessibilityModel.axNodeForId(childId); |
| 162 if (child) |
| 163 children.push(child); |
| 164 } |
| 165 |
| 166 return children; |
| 167 } |
| 168 |
| 169 /** |
| 170 * @return {number} |
| 171 */ |
| 172 numChildren() { |
| 173 if (!this._childIds) |
| 174 return 0; |
| 175 return this._childIds.length; |
| 176 } |
| 177 |
| 178 /** |
| 179 * @return {boolean} |
| 180 */ |
| 181 hasOnlyUnloadedChildren() { |
| 182 if (!this._childIds || !this._childIds.length) |
| 183 return false; |
| 184 |
| 185 return !this._childIds.some((id) => this._accessibilityModel.axNodeForId(id)
!== undefined); |
| 186 } |
| 187 |
| 188 /** |
| 189 * TODO(aboxhall): Remove once protocol is stable. |
| 190 * @param {!WebInspector.AccessibilityNode} inspectedNode |
| 191 * @param {string=} leadingSpace |
| 192 * @return {string} |
| 193 */ |
| 194 printSelfAndChildren(inspectedNode, leadingSpace) { |
| 195 var string = leadingSpace || ''; |
| 196 if (this._role) |
| 197 string += this._role.value; |
| 198 else |
| 199 string += '<no role>'; |
| 200 string += (this._name ? ' ' + this._name.value : ''); |
| 201 string += ' ' + this._id; |
| 202 if (this._domNode) |
| 203 string += ' (' + this._domNode.nodeName() + ')'; |
| 204 if (this === inspectedNode) |
| 205 string += ' *'; |
| 206 for (var child of this.children()) |
| 207 string += '\n' + child.printSelfAndChildren(inspectedNode, (leadingSpace |
| '') + ' '); |
| 208 return string; |
| 106 } | 209 } |
| 107 }; | 210 }; |
| 108 | 211 |
| 109 /** | 212 /** |
| 110 * @unrestricted | 213 * @unrestricted |
| 111 */ | 214 */ |
| 112 WebInspector.AccessibilityModel = class extends WebInspector.SDKModel { | 215 WebInspector.AccessibilityModel = class extends WebInspector.SDKModel { |
| 113 /** | 216 /** |
| 114 * @param {!WebInspector.Target} target | 217 * @param {!WebInspector.Target} target |
| 115 */ | 218 */ |
| 116 constructor(target) { | 219 constructor(target) { |
| 117 super(WebInspector.AccessibilityModel, target); | 220 super(WebInspector.AccessibilityModel, target); |
| 118 this._agent = target.accessibilityAgent(); | 221 this._agent = target.accessibilityAgent(); |
| 119 | 222 |
| 120 /** @type {!Map<string, !WebInspector.AccessibilityNode>} */ | 223 /** @type {!Map<string, !WebInspector.AccessibilityNode>} */ |
| 121 this._axIdToAXNode = new Map(); | 224 this._axIdToAXNode = new Map(); |
| 225 this._domNodeToAXNode = new Map(); |
| 122 } | 226 } |
| 123 | 227 |
| 124 /** | 228 /** |
| 125 * @param {!WebInspector.Target} target | 229 * @param {!WebInspector.Target} target |
| 126 * @return {!WebInspector.AccessibilityModel} | 230 * @return {!WebInspector.AccessibilityModel} |
| 127 */ | 231 */ |
| 128 static fromTarget(target) { | 232 static fromTarget(target) { |
| 129 if (!target[WebInspector.AccessibilityModel._symbol]) | 233 if (!target[WebInspector.AccessibilityModel._symbol]) |
| 130 target[WebInspector.AccessibilityModel._symbol] = new WebInspector.Accessi
bilityModel(target); | 234 target[WebInspector.AccessibilityModel._symbol] = new WebInspector.Accessi
bilityModel(target); |
| 131 | 235 |
| 132 return target[WebInspector.AccessibilityModel._symbol]; | 236 return target[WebInspector.AccessibilityModel._symbol]; |
| 133 } | 237 } |
| 134 | 238 |
| 135 /** | 239 /** |
| 136 * @param {string} axId | |
| 137 * @return {?WebInspector.AccessibilityNode} | |
| 138 */ | |
| 139 axNodeForId(axId) { | |
| 140 return this._axIdToAXNode.get(axId); | |
| 141 } | |
| 142 | |
| 143 /** | |
| 144 * @param {string} axId | |
| 145 * @param {!WebInspector.AccessibilityNode} axNode | |
| 146 */ | |
| 147 _setAXNodeForAXId(axId, axNode) { | |
| 148 this._axIdToAXNode.set(axId, axNode); | |
| 149 } | |
| 150 | |
| 151 /** | |
| 152 * @param {!WebInspector.DOMNode} node | 240 * @param {!WebInspector.DOMNode} node |
| 153 * @return {!Promise<?Array<!WebInspector.AccessibilityNode>>} | 241 * @return {!Promise<?WebInspector.AccessibilityNode>} |
| 154 */ | 242 */ |
| 155 getAXNodeChain(node) { | 243 setDOMNode(node) { |
| 156 this._axIdToAXNode.clear(); | 244 this._axIdToAXNode.clear(); |
| 245 this._inspectedDOMNode = node; |
| 157 | 246 |
| 247 return this._requestPartialAXTree(node); |
| 248 } |
| 249 |
| 250 /** |
| 251 * @param {!WebInspector.DOMNode} node |
| 252 * @return {!Promise} |
| 253 */ |
| 254 _requestPartialAXTree(node) { |
| 158 /** | 255 /** |
| 159 * @this {WebInspector.AccessibilityModel} | 256 * @this {WebInspector.AccessibilityModel} |
| 160 * @param {?string} error | 257 * @param {?string} error |
| 161 * @param {!Array<!AccessibilityAgent.AXNode>=} payloads | 258 * @param {!Array<!AccessibilityAgent.AXNode>=} payloads |
| 162 * @return {?Array<!WebInspector.AccessibilityNode>} | |
| 163 */ | 259 */ |
| 164 function parsePayload(error, payloads) { | 260 function parsePayload(error, payloads) { |
| 165 if (error) { | 261 if (error) { |
| 166 console.error('AccessibilityAgent.getAXNodeChain(): ' + error); | 262 console.error('AccessibilityAgent.getAXNodeChain(): ' + error); |
| 167 return null; | 263 return null; |
| 168 } | 264 } |
| 169 | 265 |
| 170 if (!payloads) | 266 if (!payloads) |
| 171 return null; | 267 return; |
| 172 | 268 |
| 173 var nodes = []; | |
| 174 for (var payload of payloads) | 269 for (var payload of payloads) |
| 175 nodes.push(new WebInspector.AccessibilityNode(this, payload)); | 270 new WebInspector.AccessibilityNode(this, payload); |
| 176 | 271 |
| 177 return nodes; | 272 for (var axNode of this._axIdToAXNode.values()) { |
| 273 for (var axChild of axNode.children()) { |
| 274 axChild._setParentNode(axNode); |
| 275 } |
| 276 } |
| 178 } | 277 } |
| 179 return this._agent.getAXNodeChain(node.id, true, parsePayload.bind(this)); | 278 return this._agent.getPartialAXTree(node.id, true, parsePayload.bind(this)); |
| 279 } |
| 280 |
| 281 /** |
| 282 * @return {?WebInspector.AccessibilityNode} |
| 283 */ |
| 284 getInspectedAXNode() { |
| 285 return this._domNodeToAXNode.get(this._inspectedDOMNode); |
| 286 } |
| 287 |
| 288 /** |
| 289 * @param {string} axId |
| 290 * @return {?WebInspector.AccessibilityNode} |
| 291 */ |
| 292 axNodeForId(axId) { |
| 293 return this._axIdToAXNode.get(axId); |
| 294 } |
| 295 |
| 296 /** |
| 297 * @param {string} axId |
| 298 * @param {!WebInspector.AccessibilityNode} axNode |
| 299 */ |
| 300 _setAXNodeForAXId(axId, axNode) { |
| 301 this._axIdToAXNode.set(axId, axNode); |
| 302 } |
| 303 |
| 304 /** |
| 305 * @param {!WebInspector.DOMNode} domNode |
| 306 * @return {?WebInspector.AccessibilityNode} |
| 307 */ |
| 308 axNodeForDOMNode(domNode) { |
| 309 return this._domNodeToAXNode.get(domNode); |
| 310 } |
| 311 |
| 312 /** |
| 313 * @param {!WebInspector.DOMNode} domNode |
| 314 * @param {!WebInspector.AccessibilityNode} axNode |
| 315 */ |
| 316 setAXNodeForDOMNode(domNode, axNode) { |
| 317 this._domNodeToAXNode.set(domNode, axNode); |
| 318 } |
| 319 |
| 320 // TODO(aboxhall): Remove once protocol is stable. |
| 321 logTree() { |
| 322 var inspectedNode = this._domNodeToAXNode.get(this._inspectedDOMNode); |
| 323 if (!inspectedNode) |
| 324 return; |
| 325 var rootNode = inspectedNode; |
| 326 while (rootNode.parentNode()) |
| 327 rootNode = rootNode.parentNode(); |
| 328 console.log(rootNode.printSelfAndChildren(inspectedNode)); |
| 329 } |
| 330 |
| 331 /** |
| 332 * @return {!Promise} |
| 333 */ |
| 334 resolveAllDOMNodes() { |
| 335 var promises = []; |
| 336 for (var axNode of this._axIdToAXNode.values()) |
| 337 promises.push(axNode.resolveDOMNode()); |
| 338 return Promise.all(promises); |
| 180 } | 339 } |
| 181 }; | 340 }; |
| 182 | 341 |
| 183 WebInspector.AccessibilityModel._symbol = Symbol('AccessibilityModel'); | 342 WebInspector.AccessibilityModel._symbol = Symbol('AccessibilityModel'); |
| OLD | NEW |