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