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
3 // found in the LICENSE file.
5 // Custom bindings for the automation API.
6 var automation = require('binding').Binding.create('automation');
7 var automationInternal =
8 require('binding').Binding.create('automationInternal').generate();
9 var eventBindings = require('event_bindings');
10 var Event = eventBindings.Event;
11 var AutomationNode = require('automationNode').AutomationNode;
12 var AutomationTree = require('automationTree').AutomationTree;
14 // TODO(aboxhall): Look into using WeakMap
15 var routingIdToAutomationTree = {};
16 var routingIdToCallback = {};
18 automation.registerCustomHook(function(bindingsAPI) {
19 var apiFunctions = bindingsAPI.apiFunctions;
21 apiFunctions.setHandleRequest('getTree', function(callback) {
22 // enableCurrentTab() ensures the renderer for the current tab has
23 // accessibility enabled, and fetches its routing id to use as a key in the
24 // routingIdToAutomationTree map. The callback to enableCurrentTab is bound
25 // to the callback passed in to getTree(), so that once the tree is
26 // available (either due to having been cached earlier, or after an
27 // accessibility event occurs which causes the tree to be populated), the
28 // callback can be called.
29 automationInternal.enableCurrentTab(function(rid) {
30 var targetTree = routingIdToAutomationTree[rid];
32 // If we haven't cached the tree, hold the callback until the tree is
33 // populated by the initial onAccessibilityEvent call.
34 if (rid in routingIdToCallback)
35 routingIdToCallback[rid].push(callback);
37 routingIdToCallback[rid] = [callback];
45 // Listen to the automationInternal.onaccessibilityEvent event, which is
46 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the
48 automationInternal.onAccessibilityEvent.addListener(function(data) {
49 var rid = data.routing_id;
50 var targetTree = routingIdToAutomationTree[rid];
52 // If this is the first time we've gotten data for this tree, it will
53 // contain all of the tree's data, so create a new tree which will be
54 // bootstrapped from |data|.
55 targetTree = new AutomationTree(rid);
56 routingIdToAutomationTree[rid] = targetTree;
58 if (privates(targetTree).impl.update(data)) {
59 // TODO(aboxhall/dtseng): remove and replace with EventListener style API
60 targetTree.onUpdate.dispatch();
63 // TODO(aboxhall/dtseng): call appropriate event listeners based on
66 // If the tree wasn't available when getTree() was called, the callback will
67 // have been cached in routingIdToCallback, so call and delete it now that we
69 if (rid in routingIdToCallback) {
70 for (var i = 0; i < routingIdToCallback[rid].length; i++) {
71 var callback = routingIdToCallback[rid][i];
74 delete routingIdToCallback[rid];
78 exports.binding = automation.generate();