Index: chrome/renderer/resources/extensions/automation/automation_node.js |
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js |
index fb851690585913880b3ba70de3c1a2f1ea4dbd09..f2600add1c21b5c98808429ea77cc7adefad34eb 100644 |
--- a/chrome/renderer/resources/extensions/automation/automation_node.js |
+++ b/chrome/renderer/resources/extensions/automation/automation_node.js |
@@ -14,6 +14,14 @@ var schema = requireNative('automationInternal').GetSchemaAdditions(); |
var utils = require('utils'); |
/** |
+ * Maps an id in the form: |
+ * <process_id>_<routing_id> |
+ * to an AutomationNode with role type webArea. |
+ * @type {!Object.<string, string>} |
+ */ |
+var idToWebArea_ = {}; |
+ |
+/** |
* A single node in the Automation tree. |
* @param {AutomationRootNodeImpl} root The root of the tree. |
* @constructor |
@@ -40,18 +48,24 @@ AutomationNodeImpl.prototype = { |
}, |
parent: function() { |
+ if (this.role == schema.RoleType.rootWebArea) { |
+ var parentId = automationUtil.createAutomationRootNodeID(this.processID, |
+ this.routingID); |
+ |
+ if (idToWebArea_[parentId]) |
+ return idToWebArea_[parentId]; |
+ } |
return this.rootImpl.get(this.parentID); |
}, |
firstChild: function() { |
- var node = this.rootImpl.get(this.childIds[0]); |
- return node; |
+ return this.lookupWebAreaChild_() || this.rootImpl.get(this.childIds[0]); |
}, |
lastChild: function() { |
var childIds = this.childIds; |
- var node = this.rootImpl.get(childIds[childIds.length - 1]); |
- return node; |
+ return this.lookupWebAreaChild_() || |
+ this.rootImpl.get(childIds[childIds.length - 1]); |
}, |
children: function() { |
@@ -118,7 +132,6 @@ AutomationNodeImpl.prototype = { |
var parent = this.parent(); |
while (parent) { |
path.push(parent); |
- // TODO(aboxhall/dtseng): handle unloaded parent node |
parent = parent.parent(); |
} |
var event = new AutomationEvent(eventType, this.wrapper); |
@@ -144,6 +157,15 @@ AutomationNodeImpl.prototype = { |
' attributes=' + $JSON.stringify(this.attributes); |
}, |
+ lookupWebAreaChild_: function() { |
+ if (this.role != schema.RoleType.webArea) |
+ return null; |
+ |
+ return automationUtil.idToAutomationRootNode[ |
+ automationUtil.createAutomationRootNodeID( |
+ this.processID, this.routingID)]; |
+ }, |
+ |
dispatchEventAtCapturing_: function(event, path) { |
privates(event).impl.eventPhase = Event.CAPTURING_PHASE; |
for (var i = path.length - 1; i >= 0; i--) { |
@@ -292,6 +314,10 @@ AutomationRootNodeImpl.prototype = { |
isRootNode: true, |
+ loaded: false, |
+ |
+ role: 'rootWebArea', |
+ |
get: function(id) { |
if (id == undefined) |
return undefined; |
@@ -353,6 +379,8 @@ AutomationRootNodeImpl.prototype = { |
destroy: function() { |
this.dispatchEvent(schema.EventType.destroyed); |
this.invalidate_(this.wrapper); |
+ idToWebArea_[automationUtil.createAutomationRootNodeID(this.processID, |
+ this.routingID)] = undefined; |
}, |
onAccessibilityEvent: function(eventParams) { |
@@ -406,19 +434,10 @@ AutomationRootNodeImpl.prototype = { |
nodeImpl[key] = AutomationAttributeDefaults[key]; |
} |
nodeImpl.childIds = []; |
- nodeImpl.loaded = false; |
nodeImpl.id = id; |
delete this.axNodeDataCache_[id]; |
}, |
- load: function(callback) { |
- // TODO(dtseng/aboxhall): Implement. |
- if (!this.loaded) |
- throw 'Unsupported state: root node is not loaded.'; |
- |
- setTimeout(callback, 0); |
- }, |
- |
deleteOldChildren_: function(node, newChildIds) { |
// Create a set of child ids in |src| for fast lookup, and return false |
// if a duplicate is found; |
@@ -457,6 +476,16 @@ AutomationRootNodeImpl.prototype = { |
createNewChildren_: function(node, newChildIds, updateState) { |
logging.CHECK(node); |
var success = true; |
+ |
+ if (node.role == schema.RoleType.webArea && node.children().length == 0) { |
+ var pid = privates(node).impl.processID; |
dmazzoni
2014/10/31 18:28:35
I think it'd be more clear if this was childProces
|
+ var rid = privates(node).impl.routingID; |
+ var id = automationUtil.createAutomationRootNodeID(pid, rid); |
+ var targetTree = automationUtil.idToAutomationRootNode[id]; |
dmazzoni
2014/10/31 18:28:35
targetTree -> childTree
|
+ if (!targetTree) |
+ targetTree = new AutomationRootNode(pid, rid); |
+ automationUtil.idToAutomationRootNode[id] = targetTree; |
+ } |
for (var i = 0; i < newChildIds.length; i++) { |
var childId = newChildIds[i]; |
var childNode = this.axNodeDataCache_[childId]; |
@@ -495,6 +524,15 @@ AutomationRootNodeImpl.prototype = { |
setData_: function(node, nodeData) { |
var nodeImpl = privates(node).impl; |
+ |
+ if (nodeData.role == schema.RoleType.webArea) { |
+ nodeImpl.processID = nodeData.intAttributes.frameId; |
+ nodeImpl.routingID = nodeData.intAttributes.childFrameId; |
+ idToWebArea_[automationUtil.createAutomationRootNodeID(nodeImpl.processID, |
+ nodeImpl.routingID)] = node; |
+ delete nodeData.intAttributes['processId']; |
dmazzoni
2014/10/31 18:28:35
this doesn't match, should be nodeData.intAttribut
|
+ delete nodeData.intAttributes['routingId']; |
+ } |
for (var key in AutomationAttributeDefaults) { |
if (key in nodeData) |
nodeImpl[key] = nodeData[key]; |
@@ -541,6 +579,19 @@ AutomationRootNodeImpl.prototype = { |
}); |
}, |
+ load: function(callback) { |
+ if (!this.loaded) |
+ automationInternal.enableFrame(this.processID, this.routingID); |
+ |
+ automationUtil.storeTreeCallback(this.processID, |
+ this.routingID, |
+ function(root) { |
+ privates(root).impl.loaded = true; |
+ if (callback) |
+ callback(root); |
+ }); |
+ }, |
+ |
updateNode_: function(nodeData, updateState) { |
var node = this.axNodeDataCache_[nodeData.id]; |
var didUpdateRoot = false; |
@@ -599,7 +650,8 @@ var AutomationNode = utils.expose('AutomationNode', |
'makeVisible', |
'setSelection', |
'addEventListener', |
- 'removeEventListener'], |
+ 'removeEventListener', |
+ 'load'], |
readonly: ['isRootNode', |
'role', |
'state', |