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 var AutomationEvent = require('automationEvent').AutomationEvent; | 5 var AutomationEvent = require('automationEvent').AutomationEvent; |
| 6 var automationInternal = | 6 var automationInternal = |
| 7 require('binding').Binding.create('automationInternal').generate(); | 7 require('binding').Binding.create('automationInternal').generate(); |
| 8 var IsInteractPermitted = | 8 var IsInteractPermitted = |
| 9 requireNative('automationInternal').IsInteractPermitted; | 9 requireNative('automationInternal').IsInteractPermitted; |
| 10 | 10 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 190 'during phase ' + eventPhase + ': ' + | 190 'during phase ' + eventPhase + ': ' + |
| 191 e.message + '\nStack trace: ' + e.stack); | 191 e.message + '\nStack trace: ' + e.stack); |
| 192 } | 192 } |
| 193 } | 193 } |
| 194 }, | 194 }, |
| 195 | 195 |
| 196 performAction_: function(actionType, opt_args) { | 196 performAction_: function(actionType, opt_args) { |
| 197 // Not yet initialized. | 197 // Not yet initialized. |
| 198 if (this.rootImpl.processID === undefined || | 198 if (this.rootImpl.processID === undefined || |
| 199 this.rootImpl.routingID === undefined || | 199 this.rootImpl.routingID === undefined || |
| 200 this.wrapper.id === undefined) { | 200 this.id === undefined) { |
| 201 return; | 201 return; |
| 202 } | 202 } |
| 203 | 203 |
| 204 // Check permissions. | 204 // Check permissions. |
| 205 if (!IsInteractPermitted()) { | 205 if (!IsInteractPermitted()) { |
| 206 throw new Error(actionType + ' requires {"desktop": true} or' + | 206 throw new Error(actionType + ' requires {"desktop": true} or' + |
| 207 ' {"interact": true} in the "automation" manifest key.'); | 207 ' {"interact": true} in the "automation" manifest key.'); |
| 208 } | 208 } |
| 209 | 209 |
| 210 automationInternal.performAction({ processID: this.rootImpl.processID, | 210 automationInternal.performAction({ processID: this.rootImpl.processID, |
| 211 routingID: this.rootImpl.routingID, | 211 routingID: this.rootImpl.routingID, |
| 212 automationNodeID: this.wrapper.id, | 212 automationNodeID: this.id, |
| 213 actionType: actionType }, | 213 actionType: actionType }, |
| 214 opt_args || {}); | 214 opt_args || {}); |
| 215 } | 215 } |
| 216 }; | 216 }; |
| 217 | 217 |
| 218 // Maps an attribute to its default value in an invalidated node. | 218 // Maps an attribute to its default value in an invalidated node. |
| 219 // These attributes are taken directly from the Automation idl. | 219 // These attributes are taken directly from the Automation idl. |
| 220 var AutomationAttributeDefaults = { | 220 var AutomationAttributeDefaults = { |
| 221 'id': -1, | 221 'id': -1, |
| 222 'role': '', | 222 'role': '', |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 null, | 322 null, |
| 323 chrome); | 323 chrome); |
| 324 return false; | 324 return false; |
| 325 } | 325 } |
| 326 if (nodeToClear === this.wrapper) { | 326 if (nodeToClear === this.wrapper) { |
| 327 this.invalidate_(nodeToClear); | 327 this.invalidate_(nodeToClear); |
| 328 } else { | 328 } else { |
| 329 var children = nodeToClear.children(); | 329 var children = nodeToClear.children(); |
| 330 for (var i = 0; i < children.length; i++) | 330 for (var i = 0; i < children.length; i++) |
| 331 this.invalidate_(children[i]); | 331 this.invalidate_(children[i]); |
| 332 privates(nodeToClear).impl.childIds = [] | 332 var nodeToClearImpl = privates(nodeToClear).impl; |
| 333 updateState.pendingNodes[nodeToClear.id] = nodeToClear; | 333 nodeToClearImpl.childIds = [] |
| 334 updateState.pendingNodes[nodeToClearImpl.id] = nodeToClear; | |
| 334 } | 335 } |
| 335 } | 336 } |
| 336 | 337 |
| 337 for (var i = 0; i < update.nodes.length; i++) { | 338 for (var i = 0; i < update.nodes.length; i++) { |
| 338 if (!this.updateNode_(update.nodes[i], updateState)) | 339 if (!this.updateNode_(update.nodes[i], updateState)) |
| 339 return false; | 340 return false; |
| 340 } | 341 } |
| 341 | 342 |
| 342 if (Object.keys(updateState.pendingNodes).length > 0) { | 343 if (Object.keys(updateState.pendingNodes).length > 0) { |
| 343 logging.WARNING('Nodes left pending by the update: ' + | 344 logging.WARNING('Nodes left pending by the update: ' + |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 395 return; | 396 return; |
| 396 var children = node.children(); | 397 var children = node.children(); |
| 397 | 398 |
| 398 for (var i = 0, child; child = children[i]; i++) | 399 for (var i = 0, child; child = children[i]; i++) |
| 399 this.invalidate_(child); | 400 this.invalidate_(child); |
| 400 | 401 |
| 401 // Retrieve the internal AutomationNodeImpl instance for this node. | 402 // Retrieve the internal AutomationNodeImpl instance for this node. |
| 402 // This object is not accessible outside of bindings code, but we can access | 403 // This object is not accessible outside of bindings code, but we can access |
| 403 // it here. | 404 // it here. |
| 404 var nodeImpl = privates(node).impl; | 405 var nodeImpl = privates(node).impl; |
| 405 var id = node.id; | 406 var id = nodeImpl.id; |
| 406 for (var key in AutomationAttributeDefaults) { | 407 for (var key in AutomationAttributeDefaults) { |
| 407 nodeImpl[key] = AutomationAttributeDefaults[key]; | 408 nodeImpl[key] = AutomationAttributeDefaults[key]; |
| 408 } | 409 } |
| 409 nodeImpl.childIds = []; | 410 nodeImpl.childIds = []; |
| 410 nodeImpl.loaded = false; | 411 nodeImpl.loaded = false; |
| 411 nodeImpl.id = id; | 412 nodeImpl.id = id; |
| 412 delete this.axNodeDataCache_[id]; | 413 delete this.axNodeDataCache_[id]; |
| 413 }, | 414 }, |
| 414 | 415 |
| 415 load: function(callback) { | 416 load: function(callback) { |
| 416 // TODO(dtseng/aboxhall): Implement. | 417 // TODO(dtseng/aboxhall): Implement. |
| 417 if (!this.loaded) | 418 if (!this.loaded) |
| 418 throw 'Unsupported state: root node is not loaded.'; | 419 throw 'Unsupported state: root node is not loaded.'; |
| 419 | 420 |
| 420 setTimeout(callback, 0); | 421 setTimeout(callback, 0); |
| 421 }, | 422 }, |
| 422 | 423 |
| 423 deleteOldChildren_: function(node, newChildIds) { | 424 deleteOldChildren_: function(node, newChildIds) { |
| 424 // Create a set of child ids in |src| for fast lookup, and return false | 425 // Create a set of child ids in |src| for fast lookup, and return false |
| 425 // if a duplicate is found; | 426 // if a duplicate is found; |
| 426 var newChildIdSet = {}; | 427 var newChildIdSet = {}; |
| 427 for (var i = 0; i < newChildIds.length; i++) { | 428 for (var i = 0; i < newChildIds.length; i++) { |
| 428 var childId = newChildIds[i]; | 429 var childId = newChildIds[i]; |
| 429 if (newChildIdSet[childId]) { | 430 if (newChildIdSet[childId]) { |
| 430 logging.WARNING('Node ' + node.id + ' has duplicate child id ' + | 431 logging.WARNING('Node ' + privates(node).impl.id + |
| 431 childId); | 432 ' has duplicate child id ' + childId); |
| 432 lastError.set('automation', | 433 lastError.set('automation', |
| 433 'Bad update received on automation tree', | 434 'Bad update received on automation tree', |
| 434 null, | 435 null, |
| 435 chrome); | 436 chrome); |
| 436 return false; | 437 return false; |
| 437 } | 438 } |
| 438 newChildIdSet[newChildIds[i]] = true; | 439 newChildIdSet[newChildIds[i]] = true; |
| 439 } | 440 } |
| 440 | 441 |
| 441 // Delete the old children. | 442 // Delete the old children. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 456 }, | 457 }, |
| 457 | 458 |
| 458 createNewChildren_: function(node, newChildIds, updateState) { | 459 createNewChildren_: function(node, newChildIds, updateState) { |
| 459 logging.CHECK(node); | 460 logging.CHECK(node); |
| 460 var success = true; | 461 var success = true; |
| 461 for (var i = 0; i < newChildIds.length; i++) { | 462 for (var i = 0; i < newChildIds.length; i++) { |
| 462 var childId = newChildIds[i]; | 463 var childId = newChildIds[i]; |
| 463 var childNode = this.axNodeDataCache_[childId]; | 464 var childNode = this.axNodeDataCache_[childId]; |
| 464 if (childNode) { | 465 if (childNode) { |
| 465 if (childNode.parent() != node) { | 466 if (childNode.parent() != node) { |
| 466 var parentId = 0; | 467 var parentId = 0; |
|
David Tseng
2014/08/29 22:02:23
nit: We use 0 elsewhere as a valid id. Maybe -1?
aboxhall
2014/08/30 17:46:41
Done.
| |
| 467 if (childNode.parent()) parentId = childNode.parent().id; | 468 var parentImpl = privates(childNode.parent()).impl; |
|
David Tseng
2014/08/29 22:02:23
This should be in the if clause's body right?
aboxhall
2014/08/30 17:46:42
Done.
| |
| 469 if (childNode.parent()) parentId = parentImpl.id; | |
|
David Tseng
2014/08/29 22:02:23
if (...)
...
(the one line if is pretty hard to
aboxhall
2014/08/30 17:46:42
Done.
| |
| 468 // This is a serious error - nodes should never be reparented. | 470 // This is a serious error - nodes should never be reparented. |
| 469 // If this case occurs, continue so this node isn't left in an | 471 // If this case occurs, continue so this node isn't left in an |
| 470 // inconsistent state, but return failure at the end. | 472 // inconsistent state, but return failure at the end. |
| 471 logging.WARNING('Node ' + childId + ' reparented from ' + | 473 logging.WARNING('Node ' + childId + ' reparented from ' + |
| 472 parentId + ' to ' + node.id); | 474 parentId + ' to ' + privates(node).impl.id); |
| 473 lastError.set('automation', | 475 lastError.set('automation', |
| 474 'Bad update received on automation tree', | 476 'Bad update received on automation tree', |
| 475 null, | 477 null, |
| 476 chrome); | 478 chrome); |
| 477 success = false; | 479 success = false; |
| 478 continue; | 480 continue; |
| 479 } | 481 } |
| 480 } else { | 482 } else { |
| 481 childNode = new AutomationNode(this); | 483 childNode = new AutomationNode(this); |
| 482 this.axNodeDataCache_[childId] = childNode; | 484 this.axNodeDataCache_[childId] = childNode; |
| 483 privates(childNode).impl.id = childId; | 485 privates(childNode).impl.id = childId; |
| 484 updateState.pendingNodes[childNode.id] = childNode; | 486 updateState.pendingNodes[childId] = childNode; |
| 485 updateState.newNodes[childNode.id] = childNode; | 487 updateState.newNodes[childId] = childNode; |
| 486 } | 488 } |
| 487 privates(childNode).impl.indexInParent = i; | 489 privates(childNode).impl.indexInParent = i; |
| 488 privates(childNode).impl.parentID = node.id; | 490 privates(childNode).impl.parentID = privates(node).impl.id; |
| 489 } | 491 } |
| 490 | 492 |
| 491 return success; | 493 return success; |
| 492 }, | 494 }, |
| 493 | 495 |
| 494 setData_: function(node, nodeData) { | 496 setData_: function(node, nodeData) { |
| 495 var nodeImpl = privates(node).impl; | 497 var nodeImpl = privates(node).impl; |
| 496 for (var key in AutomationAttributeDefaults) { | 498 for (var key in AutomationAttributeDefaults) { |
| 497 if (key in nodeData) { | 499 if (key in nodeData) { |
| 498 if (key == 'id' && nodeImpl[key] != nodeData[key]) { | 500 if (key == 'id' && nodeImpl[key] != nodeData[key]) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 } | 543 } |
| 542 return node.attributesInternal[attributeName]; | 544 return node.attributesInternal[attributeName]; |
| 543 }.bind(this), | 545 }.bind(this), |
| 544 }); | 546 }); |
| 545 }, | 547 }, |
| 546 | 548 |
| 547 updateNode_: function(nodeData, updateState) { | 549 updateNode_: function(nodeData, updateState) { |
| 548 var node = this.axNodeDataCache_[nodeData.id]; | 550 var node = this.axNodeDataCache_[nodeData.id]; |
| 549 var didUpdateRoot = false; | 551 var didUpdateRoot = false; |
| 550 if (node) { | 552 if (node) { |
| 551 delete updateState.pendingNodes[node.id]; | 553 delete updateState.pendingNodes[privates(node).impl.id]; |
| 552 } else { | 554 } else { |
| 553 if (nodeData.role != schema.RoleType.rootWebArea && | 555 if (nodeData.role != schema.RoleType.rootWebArea && |
| 554 nodeData.role != schema.RoleType.desktop) { | 556 nodeData.role != schema.RoleType.desktop) { |
| 555 logging.WARNING(String(nodeData.id) + | 557 logging.WARNING(String(nodeData.id) + |
| 556 ' is not in the cache and not the new root.'); | 558 ' is not in the cache and not the new root.'); |
| 557 lastError.set('automation', | 559 lastError.set('automation', |
| 558 'Bad update received on automation tree', | 560 'Bad update received on automation tree', |
| 559 null, | 561 null, |
| 560 chrome); | 562 chrome); |
| 561 return false; | 563 return false; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 575 this.invalidate_(this.wrapper); | 577 this.invalidate_(this.wrapper); |
| 576 } | 578 } |
| 577 return false; | 579 return false; |
| 578 } | 580 } |
| 579 var nodeImpl = privates(node).impl; | 581 var nodeImpl = privates(node).impl; |
| 580 | 582 |
| 581 var success = this.createNewChildren_(node, | 583 var success = this.createNewChildren_(node, |
| 582 nodeData.childIds, | 584 nodeData.childIds, |
| 583 updateState); | 585 updateState); |
| 584 nodeImpl.childIds = nodeData.childIds; | 586 nodeImpl.childIds = nodeData.childIds; |
| 585 this.axNodeDataCache_[node.id] = node; | 587 this.axNodeDataCache_[nodeImpl.id] = node; |
| 586 | 588 |
| 587 return success; | 589 return success; |
| 588 } | 590 } |
| 589 }; | 591 }; |
| 590 | 592 |
| 591 | 593 |
| 592 var AutomationNode = utils.expose('AutomationNode', | 594 var AutomationNode = utils.expose('AutomationNode', |
| 593 AutomationNodeImpl, | 595 AutomationNodeImpl, |
| 594 { functions: ['parent', | 596 { functions: ['parent', |
| 595 'firstChild', | 597 'firstChild', |
| 596 'lastChild', | 598 'lastChild', |
| 597 'children', | 599 'children', |
| 598 'previousSibling', | 600 'previousSibling', |
| 599 'nextSibling', | 601 'nextSibling', |
| 600 'doDefault', | 602 'doDefault', |
| 601 'focus', | 603 'focus', |
| 602 'makeVisible', | 604 'makeVisible', |
| 603 'setSelection', | 605 'setSelection', |
| 604 'addEventListener', | 606 'addEventListener', |
| 605 'removeEventListener', | 607 'removeEventListener'], |
| 606 'toString'], | |
| 607 readonly: ['isRootNode', | 608 readonly: ['isRootNode', |
| 608 'id', | |
| 609 'role', | 609 'role', |
| 610 'state', | 610 'state', |
| 611 'location', | 611 'location', |
| 612 'attributes', | 612 'attributes', |
| 613 'root', | 613 'root'] }); |
| 614 'toString'] }); | |
| 615 | 614 |
| 616 var AutomationRootNode = utils.expose('AutomationRootNode', | 615 var AutomationRootNode = utils.expose('AutomationRootNode', |
| 617 AutomationRootNodeImpl, | 616 AutomationRootNodeImpl, |
| 618 { superclass: AutomationNode, | 617 { superclass: AutomationNode, |
| 619 functions: ['load'], | 618 functions: ['load'], |
| 620 readonly: ['loaded'] }); | 619 readonly: ['loaded'] }); |
| 621 | 620 |
| 622 exports.AutomationNode = AutomationNode; | 621 exports.AutomationNode = AutomationNode; |
| 623 exports.AutomationRootNode = AutomationRootNode; | 622 exports.AutomationRootNode = AutomationRootNode; |
| OLD | NEW |