Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / automation / automation_node.js
bloba8dcdf63fb28af724447a3be800e5136fb339b18
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 var AutomationEvent = require('automationEvent').AutomationEvent;
6 var automationInternal =
7 require('binding').Binding.create('automationInternal').generate();
8 var IsInteractPermitted =
9 requireNative('automationInternal').IsInteractPermitted;
11 /**
12 * @param {number} axTreeID The id of the accessibility tree.
13 * @return {?number} The id of the root node.
15 var GetRootID = requireNative('automationInternal').GetRootID;
17 /**
18 * @param {number} axTreeID The id of the accessibility tree.
19 * @param {number} nodeID The id of a node.
20 * @return {?number} The id of the node's parent, or undefined if it's the
21 * root of its tree or if the tree or node wasn't found.
23 var GetParentID = requireNative('automationInternal').GetParentID;
25 /**
26 * @param {number} axTreeID The id of the accessibility tree.
27 * @param {number} nodeID The id of a node.
28 * @return {?number} The number of children of the node, or undefined if
29 * the tree or node wasn't found.
31 var GetChildCount = requireNative('automationInternal').GetChildCount;
33 /**
34 * @param {number} axTreeID The id of the accessibility tree.
35 * @param {number} nodeID The id of a node.
36 * @param {number} childIndex An index of a child of this node.
37 * @return {?number} The id of the child at the given index, or undefined
38 * if the tree or node or child at that index wasn't found.
40 var GetChildIDAtIndex = requireNative('automationInternal').GetChildIDAtIndex;
42 /**
43 * @param {number} axTreeID The id of the accessibility tree.
44 * @param {number} nodeID The id of a node.
45 * @return {?number} The index of this node in its parent, or undefined if
46 * the tree or node or node parent wasn't found.
48 var GetIndexInParent = requireNative('automationInternal').GetIndexInParent;
50 /**
51 * @param {number} axTreeID The id of the accessibility tree.
52 * @param {number} nodeID The id of a node.
53 * @return {?Object} An object with a string key for every state flag set,
54 * or undefined if the tree or node or node parent wasn't found.
56 var GetState = requireNative('automationInternal').GetState;
58 /**
59 * @param {number} axTreeID The id of the accessibility tree.
60 * @param {number} nodeID The id of a node.
61 * @return {string} The role of the node, or undefined if the tree or
62 * node wasn't found.
64 var GetRole = requireNative('automationInternal').GetRole;
66 /**
67 * @param {number} axTreeID The id of the accessibility tree.
68 * @param {number} nodeID The id of a node.
69 * @return {?automation.Rect} The location of the node, or undefined if
70 * the tree or node wasn't found.
72 var GetLocation = requireNative('automationInternal').GetLocation;
74 /**
75 * @param {number} axTreeID The id of the accessibility tree.
76 * @param {number} nodeID The id of a node.
77 * @param {string} attr The name of a string attribute.
78 * @return {?string} The value of this attribute, or undefined if the tree,
79 * node, or attribute wasn't found.
81 var GetStringAttribute = requireNative('automationInternal').GetStringAttribute;
83 /**
84 * @param {number} axTreeID The id of the accessibility tree.
85 * @param {number} nodeID The id of a node.
86 * @param {string} attr The name of an attribute.
87 * @return {?boolean} The value of this attribute, or undefined if the tree,
88 * node, or attribute wasn't found.
90 var GetBoolAttribute = requireNative('automationInternal').GetBoolAttribute;
92 /**
93 * @param {number} axTreeID The id of the accessibility tree.
94 * @param {number} nodeID The id of a node.
95 * @param {string} attr The name of an attribute.
96 * @return {?number} The value of this attribute, or undefined if the tree,
97 * node, or attribute wasn't found.
99 var GetIntAttribute = requireNative('automationInternal').GetIntAttribute;
102 * @param {number} axTreeID The id of the accessibility tree.
103 * @param {number} nodeID The id of a node.
104 * @param {string} attr The name of an attribute.
105 * @return {?number} The value of this attribute, or undefined if the tree,
106 * node, or attribute wasn't found.
108 var GetFloatAttribute = requireNative('automationInternal').GetFloatAttribute;
111 * @param {number} axTreeID The id of the accessibility tree.
112 * @param {number} nodeID The id of a node.
113 * @param {string} attr The name of an attribute.
114 * @return {?Array.<number>} The value of this attribute, or undefined
115 * if the tree, node, or attribute wasn't found.
117 var GetIntListAttribute =
118 requireNative('automationInternal').GetIntListAttribute;
121 * @param {number} axTreeID The id of the accessibility tree.
122 * @param {number} nodeID The id of a node.
123 * @param {string} attr The name of an HTML attribute.
124 * @return {?string} The value of this attribute, or undefined if the tree,
125 * node, or attribute wasn't found.
127 var GetHtmlAttribute = requireNative('automationInternal').GetHtmlAttribute;
129 var lastError = require('lastError');
130 var logging = requireNative('logging');
131 var schema = requireNative('automationInternal').GetSchemaAdditions();
132 var utils = require('utils');
135 * A single node in the Automation tree.
136 * @param {AutomationRootNodeImpl} root The root of the tree.
137 * @constructor
139 function AutomationNodeImpl(root) {
140 this.rootImpl = root;
141 // Public attributes. No actual data gets set on this object.
142 this.listeners = {};
145 AutomationNodeImpl.prototype = {
146 treeID: -1,
147 id: -1,
148 role: '',
149 state: { busy: true },
150 isRootNode: false,
152 get root() {
153 return this.rootImpl.wrapper;
156 get parent() {
157 if (this.hostNode_)
158 return this.hostNode_;
159 var parentID = GetParentID(this.treeID, this.id);
160 return this.rootImpl.get(parentID);
163 get state() {
164 return GetState(this.treeID, this.id);
167 get role() {
168 return GetRole(this.treeID, this.id);
171 get location() {
172 return GetLocation(this.treeID, this.id);
175 get indexInParent() {
176 return GetIndexInParent(this.treeID, this.id);
179 get childTree() {
180 var childTreeID = GetIntAttribute(this.treeID, this.id, 'childTreeId');
181 if (childTreeID)
182 return AutomationRootNodeImpl.get(childTreeID);
185 get firstChild() {
186 if (this.childTree)
187 return this.childTree;
188 if (!GetChildCount(this.treeID, this.id))
189 return undefined;
190 var firstChildID = GetChildIDAtIndex(this.treeID, this.id, 0);
191 return this.rootImpl.get(firstChildID);
194 get lastChild() {
195 if (this.childTree)
196 return this.childTree;
197 var count = GetChildCount(this.treeID, this.id);
198 if (!count)
199 return undefined;
200 var lastChildID = GetChildIDAtIndex(this.treeID, this.id, count - 1);
201 return this.rootImpl.get(lastChildID);
204 get children() {
205 if (this.childTree)
206 return [this.childTree];
208 var children = [];
209 var count = GetChildCount(this.treeID, this.id);
210 for (var i = 0; i < count; ++i) {
211 var childID = GetChildIDAtIndex(this.treeID, this.id, i);
212 var child = this.rootImpl.get(childID);
213 children.push(child);
215 return children;
218 get previousSibling() {
219 var parent = this.parent;
220 var indexInParent = GetIndexInParent(this.treeID, this.id);
221 if (parent && indexInParent > 0)
222 return parent.children[indexInParent - 1];
223 return undefined;
226 get nextSibling() {
227 var parent = this.parent;
228 var indexInParent = GetIndexInParent(this.treeID, this.id);
229 if (parent && indexInParent < parent.children.length)
230 return parent.children[indexInParent + 1];
231 return undefined;
234 doDefault: function() {
235 this.performAction_('doDefault');
238 focus: function() {
239 this.performAction_('focus');
242 makeVisible: function() {
243 this.performAction_('makeVisible');
246 setSelection: function(startIndex, endIndex) {
247 this.performAction_('setSelection',
248 { startIndex: startIndex,
249 endIndex: endIndex });
252 showContextMenu: function() {
253 this.performAction_('showContextMenu');
256 domQuerySelector: function(selector, callback) {
257 automationInternal.querySelector(
258 { treeID: this.rootImpl.treeID,
259 automationNodeID: this.id,
260 selector: selector },
261 this.domQuerySelectorCallback_.bind(this, callback));
264 find: function(params) {
265 return this.findInternal_(params);
268 findAll: function(params) {
269 return this.findInternal_(params, []);
272 matches: function(params) {
273 return this.matchInternal_(params);
276 addEventListener: function(eventType, callback, capture) {
277 this.removeEventListener(eventType, callback);
278 if (!this.listeners[eventType])
279 this.listeners[eventType] = [];
280 this.listeners[eventType].push({callback: callback, capture: !!capture});
283 // TODO(dtseng/aboxhall): Check this impl against spec.
284 removeEventListener: function(eventType, callback) {
285 if (this.listeners[eventType]) {
286 var listeners = this.listeners[eventType];
287 for (var i = 0; i < listeners.length; i++) {
288 if (callback === listeners[i].callback)
289 listeners.splice(i, 1);
294 toJSON: function() {
295 return { treeID: this.treeID,
296 id: this.id,
297 role: this.role,
298 attributes: this.attributes };
301 dispatchEvent: function(eventType) {
302 var path = [];
303 var parent = this.parent;
304 while (parent) {
305 path.push(parent);
306 parent = parent.parent;
308 var event = new AutomationEvent(eventType, this.wrapper);
310 // Dispatch the event through the propagation path in three phases:
311 // - capturing: starting from the root and going down to the target's parent
312 // - targeting: dispatching the event on the target itself
313 // - bubbling: starting from the target's parent, going back up to the root.
314 // At any stage, a listener may call stopPropagation() on the event, which
315 // will immediately stop event propagation through this path.
316 if (this.dispatchEventAtCapturing_(event, path)) {
317 if (this.dispatchEventAtTargeting_(event, path))
318 this.dispatchEventAtBubbling_(event, path);
322 toString: function() {
323 var parentID = GetParentID(this.treeID, this.id);
324 var childTreeID = GetIntAttribute(this.treeID, this.id, 'childTreeId');
325 var count = GetChildCount(this.treeID, this.id);
326 var childIDs = [];
327 for (var i = 0; i < count; ++i) {
328 var childID = GetChildIDAtIndex(this.treeID, this.id, i);
329 childIDs.push(childID);
332 var result = 'node id=' + this.id +
333 ' role=' + this.role +
334 ' state=' + $JSON.stringify(this.state) +
335 ' parentID=' + parentID +
336 ' childIds=' + $JSON.stringify(childIDs);
337 if (this.hostNode_) {
338 var hostNodeImpl = privates(this.hostNode_).impl;
339 result += ' host treeID=' + hostNodeImpl.treeID +
340 ' host nodeID=' + hostNodeImpl.id;
342 if (childTreeID)
343 result += ' childTreeID=' + childTreeID;
344 return result;
347 dispatchEventAtCapturing_: function(event, path) {
348 privates(event).impl.eventPhase = Event.CAPTURING_PHASE;
349 for (var i = path.length - 1; i >= 0; i--) {
350 this.fireEventListeners_(path[i], event);
351 if (privates(event).impl.propagationStopped)
352 return false;
354 return true;
357 dispatchEventAtTargeting_: function(event) {
358 privates(event).impl.eventPhase = Event.AT_TARGET;
359 this.fireEventListeners_(this.wrapper, event);
360 return !privates(event).impl.propagationStopped;
363 dispatchEventAtBubbling_: function(event, path) {
364 privates(event).impl.eventPhase = Event.BUBBLING_PHASE;
365 for (var i = 0; i < path.length; i++) {
366 this.fireEventListeners_(path[i], event);
367 if (privates(event).impl.propagationStopped)
368 return false;
370 return true;
373 fireEventListeners_: function(node, event) {
374 var nodeImpl = privates(node).impl;
375 var listeners = nodeImpl.listeners[event.type];
376 if (!listeners)
377 return;
378 var eventPhase = event.eventPhase;
379 for (var i = 0; i < listeners.length; i++) {
380 if (eventPhase == Event.CAPTURING_PHASE && !listeners[i].capture)
381 continue;
382 if (eventPhase == Event.BUBBLING_PHASE && listeners[i].capture)
383 continue;
385 try {
386 listeners[i].callback(event);
387 } catch (e) {
388 logging.WARNING('Error in event handler for ' + event.type +
389 ' during phase ' + eventPhase + ': ' +
390 e.message + '\nStack trace: ' + e.stack);
395 performAction_: function(actionType, opt_args) {
396 // Not yet initialized.
397 if (this.rootImpl.treeID === undefined ||
398 this.id === undefined) {
399 return;
402 // Check permissions.
403 if (!IsInteractPermitted()) {
404 throw new Error(actionType + ' requires {"desktop": true} or' +
405 ' {"interact": true} in the "automation" manifest key.');
408 automationInternal.performAction({ treeID: this.rootImpl.treeID,
409 automationNodeID: this.id,
410 actionType: actionType },
411 opt_args || {});
414 domQuerySelectorCallback_: function(userCallback, resultAutomationNodeID) {
415 // resultAutomationNodeID could be zero or undefined or (unlikely) null;
416 // they all amount to the same thing here, which is that no node was
417 // returned.
418 if (!resultAutomationNodeID) {
419 userCallback(null);
420 return;
422 var resultNode = this.rootImpl.get(resultAutomationNodeID);
423 if (!resultNode) {
424 logging.WARNING('Query selector result not in tree: ' +
425 resultAutomationNodeID);
426 userCallback(null);
428 userCallback(resultNode);
431 findInternal_: function(params, opt_results) {
432 var result = null;
433 this.forAllDescendants_(function(node) {
434 if (privates(node).impl.matchInternal_(params)) {
435 if (opt_results)
436 opt_results.push(node);
437 else
438 result = node;
439 return !opt_results;
442 if (opt_results)
443 return opt_results;
444 return result;
448 * Executes a closure for all of this node's descendants, in pre-order.
449 * Early-outs if the closure returns true.
450 * @param {Function(AutomationNode):boolean} closure Closure to be executed
451 * for each node. Return true to early-out the traversal.
453 forAllDescendants_: function(closure) {
454 var stack = this.wrapper.children.reverse();
455 while (stack.length > 0) {
456 var node = stack.pop();
457 if (closure(node))
458 return;
460 var children = node.children;
461 for (var i = children.length - 1; i >= 0; i--)
462 stack.push(children[i]);
466 matchInternal_: function(params) {
467 if (Object.keys(params).length == 0)
468 return false;
470 if ('role' in params && this.role != params.role)
471 return false;
473 if ('state' in params) {
474 for (var state in params.state) {
475 if (params.state[state] != (state in this.state))
476 return false;
479 if ('attributes' in params) {
480 for (var attribute in params.attributes) {
481 var attrValue = params.attributes[attribute];
482 if (typeof attrValue != 'object') {
483 if (this[attribute] !== attrValue)
484 return false;
485 } else if (attrValue instanceof RegExp) {
486 if (typeof this[attribute] != 'string')
487 return false;
488 if (!attrValue.test(this[attribute]))
489 return false;
490 } else {
491 // TODO(aboxhall): handle intlist case.
492 return false;
496 return true;
500 var stringAttributes = [
501 'accessKey',
502 'action',
503 'ariaInvalidValue',
504 'autoComplete',
505 'containerLiveRelevant',
506 'containerLiveStatus',
507 'description',
508 'display',
509 'docDoctype',
510 'docMimetype',
511 'docTitle',
512 'docUrl',
513 'dropeffect',
514 'help',
515 'htmlTag',
516 'liveRelevant',
517 'liveStatus',
518 'name',
519 'placeholder',
520 'shortcut',
521 'textInputType',
522 'url',
523 'value'];
525 var boolAttributes = [
526 'ariaReadonly',
527 'buttonMixed',
528 'canSetValue',
529 'canvasHasFallback',
530 'containerLiveAtomic',
531 'containerLiveBusy',
532 'docLoaded',
533 'grabbed',
534 'isAxTreeHost',
535 'liveAtomic',
536 'liveBusy',
537 'updateLocationOnly'];
539 var intAttributes = [
540 'anchorOffset',
541 'backgroundColor',
542 'color',
543 'colorValue',
544 'focusOffset',
545 'hierarchicalLevel',
546 'invalidState',
547 'posInSet',
548 'scrollX',
549 'scrollXMax',
550 'scrollXMin',
551 'scrollY',
552 'scrollYMax',
553 'scrollYMin',
554 'setSize',
555 'sortDirection',
556 'tableCellColumnIndex',
557 'tableCellColumnSpan',
558 'tableCellRowIndex',
559 'tableCellRowSpan',
560 'tableColumnCount',
561 'tableColumnIndex',
562 'tableRowCount',
563 'tableRowIndex',
564 'textDirection',
565 'textSelEnd',
566 'textSelStart',
567 'textStyle'];
569 var nodeRefAttributes = [
570 ['activedescendantId', 'activedescendant'],
571 ['anchorObjectId', 'anchorObject'],
572 ['focusObjectId', 'focusObject'],
573 ['tableColumnHeaderId', 'tableColumnHeader'],
574 ['tableHeaderId', 'tableHeader'],
575 ['tableRowHeaderId', 'tableRowHeader'],
576 ['titleUiElement', 'titleUIElement']];
578 var intListAttributes = [
579 'characterOffsets',
580 'lineBreaks',
581 'wordEnds',
582 'wordStarts'];
584 var nodeRefListAttributes = [
585 ['cellIds', 'cells'],
586 ['controlsIds', 'controls'],
587 ['describedbyIds', 'describedBy'],
588 ['flowtoIds', 'flowTo'],
589 ['labelledbyIds', 'labelledBy'],
590 ['uniqueCellIds', 'uniqueCells']];
592 var floatAttributes = [
593 'docLoadingProgress',
594 'valueForRange',
595 'minValueForRange',
596 'maxValueForRange',
597 'fontSize'];
599 var htmlAttributes = [
600 ['type', 'inputType']];
602 var publicAttributes = [];
604 stringAttributes.forEach(function (attributeName) {
605 publicAttributes.push(attributeName);
606 Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
607 get: function() {
608 return GetStringAttribute(this.treeID, this.id, attributeName);
613 boolAttributes.forEach(function (attributeName) {
614 publicAttributes.push(attributeName);
615 Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
616 get: function() {
617 return GetBoolAttribute(this.treeID, this.id, attributeName);
622 intAttributes.forEach(function (attributeName) {
623 publicAttributes.push(attributeName);
624 Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
625 get: function() {
626 return GetIntAttribute(this.treeID, this.id, attributeName);
631 nodeRefAttributes.forEach(function (params) {
632 var srcAttributeName = params[0];
633 var dstAttributeName = params[1];
634 publicAttributes.push(dstAttributeName);
635 Object.defineProperty(AutomationNodeImpl.prototype, dstAttributeName, {
636 get: function() {
637 var id = GetIntAttribute(this.treeID, this.id, srcAttributeName);
638 if (id)
639 return this.rootImpl.get(id);
640 else
641 return undefined;
646 intListAttributes.forEach(function (attributeName) {
647 publicAttributes.push(attributeName);
648 Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
649 get: function() {
650 return GetIntListAttribute(this.treeID, this.id, attributeName);
655 nodeRefListAttributes.forEach(function (params) {
656 var srcAttributeName = params[0];
657 var dstAttributeName = params[1];
658 publicAttributes.push(dstAttributeName);
659 Object.defineProperty(AutomationNodeImpl.prototype, dstAttributeName, {
660 get: function() {
661 var ids = GetIntListAttribute(this.treeID, this.id, srcAttributeName);
662 if (!ids)
663 return undefined;
664 var result = [];
665 for (var i = 0; i < ids.length; ++i) {
666 var node = this.rootImpl.get(ids[i]);
667 if (node)
668 result.push(node);
670 return result;
675 floatAttributes.forEach(function (attributeName) {
676 publicAttributes.push(attributeName);
677 Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
678 get: function() {
679 return GetFloatAttribute(this.treeID, this.id, attributeName);
684 htmlAttributes.forEach(function (params) {
685 var srcAttributeName = params[0];
686 var dstAttributeName = params[1];
687 publicAttributes.push(dstAttributeName);
688 Object.defineProperty(AutomationNodeImpl.prototype, dstAttributeName, {
689 get: function() {
690 return GetHtmlAttribute(this.treeID, this.id, srcAttributeName);
696 * AutomationRootNode.
698 * An AutomationRootNode is the javascript end of an AXTree living in the
699 * browser. AutomationRootNode handles unserializing incremental updates from
700 * the source AXTree. Each update contains node data that form a complete tree
701 * after applying the update.
703 * A brief note about ids used through this class. The source AXTree assigns
704 * unique ids per node and we use these ids to build a hash to the actual
705 * AutomationNode object.
706 * Thus, tree traversals amount to a lookup in our hash.
708 * The tree itself is identified by the accessibility tree id of the
709 * renderer widget host.
710 * @constructor
712 function AutomationRootNodeImpl(treeID) {
713 AutomationNodeImpl.call(this, this);
714 this.treeID = treeID;
715 this.axNodeDataCache_ = {};
718 AutomationRootNodeImpl.idToAutomationRootNode_ = {};
720 AutomationRootNodeImpl.get = function(treeID) {
721 var result = AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
722 return result || undefined;
725 AutomationRootNodeImpl.getOrCreate = function(treeID) {
726 if (AutomationRootNodeImpl.idToAutomationRootNode_[treeID])
727 return AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
728 var result = new AutomationRootNode(treeID);
729 AutomationRootNodeImpl.idToAutomationRootNode_[treeID] = result;
730 return result;
733 AutomationRootNodeImpl.destroy = function(treeID) {
734 delete AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
737 AutomationRootNodeImpl.prototype = {
738 __proto__: AutomationNodeImpl.prototype,
741 * @type {boolean}
743 isRootNode: true,
746 * @type {number}
748 treeID: -1,
751 * The parent of this node from a different tree.
752 * @type {?AutomationNode}
753 * @private
755 hostNode_: null,
758 * A map from id to AutomationNode.
759 * @type {Object.<number, AutomationNode>}
760 * @private
762 axNodeDataCache_: null,
764 get id() {
765 var result = GetRootID(this.treeID);
767 // Don't return undefined, because the id is often passed directly
768 // as an argument to a native binding that expects only a valid number.
769 if (result === undefined)
770 return -1;
772 return result;
775 get: function(id) {
776 if (id == undefined)
777 return undefined;
779 if (id == this.id)
780 return this.wrapper;
782 var obj = this.axNodeDataCache_[id];
783 if (obj)
784 return obj;
786 obj = new AutomationNode(this);
787 privates(obj).impl.treeID = this.treeID;
788 privates(obj).impl.id = id;
789 this.axNodeDataCache_[id] = obj;
791 return obj;
794 remove: function(id) {
795 delete this.axNodeDataCache_[id];
798 destroy: function() {
799 this.dispatchEvent(schema.EventType.destroyed);
802 setHostNode(hostNode) {
803 this.hostNode_ = hostNode;
806 onAccessibilityEvent: function(eventParams) {
807 var targetNode = this.get(eventParams.targetID);
808 if (targetNode) {
809 var targetNodeImpl = privates(targetNode).impl;
810 targetNodeImpl.dispatchEvent(eventParams.eventType);
811 } else {
812 logging.WARNING('Got ' + eventParams.eventType +
813 ' event on unknown node: ' + eventParams.targetID +
814 '; this: ' + this.id);
816 return true;
819 toString: function() {
820 function toStringInternal(nodeImpl, indent) {
821 if (!nodeImpl)
822 return '';
823 var output = '';
824 if (nodeImpl.isRootNode)
825 output += indent + 'tree id=' + nodeImpl.treeID + '\n';
826 output += indent +
827 AutomationNodeImpl.prototype.toString.call(nodeImpl) +
828 '\n';
829 indent += ' ';
830 var children = nodeImpl.children;
831 for (var i = 0; i < children.length; ++i)
832 output += toStringInternal(privates(children[i]).impl, indent);
833 return output;
835 return toStringInternal(this, '');
839 var AutomationNode = utils.expose('AutomationNode',
840 AutomationNodeImpl,
841 { functions: ['doDefault',
842 'find',
843 'findAll',
844 'focus',
845 'makeVisible',
846 'matches',
847 'setSelection',
848 'showContextMenu',
849 'addEventListener',
850 'removeEventListener',
851 'domQuerySelector',
852 'toString' ],
853 readonly: publicAttributes.concat(
854 ['parent',
855 'firstChild',
856 'lastChild',
857 'children',
858 'previousSibling',
859 'nextSibling',
860 'isRootNode',
861 'role',
862 'state',
863 'location',
864 'indexInParent',
865 'root']) });
867 var AutomationRootNode = utils.expose('AutomationRootNode',
868 AutomationRootNodeImpl,
869 { superclass: AutomationNode });
871 AutomationRootNode.get = function(treeID) {
872 return AutomationRootNodeImpl.get(treeID);
875 AutomationRootNode.getOrCreate = function(treeID) {
876 return AutomationRootNodeImpl.getOrCreate(treeID);
879 AutomationRootNode.destroy = function(treeID) {
880 AutomationRootNodeImpl.destroy(treeID);
883 exports.AutomationNode = AutomationNode;
884 exports.AutomationRootNode = AutomationRootNode;