Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / third_party / chromevox / extensions / searchvox / util.js
blob908c3d5836d62e3a59298b8132b21334b5f9e396
1 // Copyright 2012 Google Inc. All Rights Reserved.
3 /**
4  * @fileoverview Helper functions.
5  */
7 goog.provide('cvox.SearchUtil');
9 /** Utility functions. */
10 cvox.SearchUtil = function() {
13 /**
14  * Extracts the first URL from an element.
15  * @param {Node} node DOM element to extract from.
16  * @return {?string} URL.
17  */
18 cvox.SearchUtil.extractURL = function(node) {
19   if (node) {
20     if (node.tagName === 'A') {
21       return node.href;
22     }
23     var anchor = node.querySelector('a');
24     if (anchor) {
25       return anchor.href;
26     }
27   }
28   return null;
31 /**
32  * Indicates whether or not the search widget has been activated.
33  * @return {boolean} Whether or not the search widget is active.
34  */
35 cvox.SearchUtil.isSearchWidgetActive = function() {
36   var SEARCH_WIDGET_SELECT = '#cvox-search';
37   return document.querySelector(SEARCH_WIDGET_SELECT) !== null;
40 /**
41  * Adds one to and index with wrapping.
42  * @param {number} index Index to add to.
43  * @param {number} length Length to wrap at.
44  * @return {number} The new index++, wrapped if exceeding length.
45  */
46 cvox.SearchUtil.addOneWrap = function(index, length) {
47   return (index + 1) % length;
50 /**
51  * Subtracts one to and index with wrapping.
52  * @param {number} index Index to subtract from.
53  * @param {number} length Length to wrap at.
54  * @return {number} The new index--, wrapped if below 0.
55  */
56 cvox.SearchUtil.subOneWrap = function(index, length) {
57   return (index - 1 + length) % length;
60 /**
61  * Returns the id of a node's active descendant
62  * @param {Node} targetNode The node.
63  * @return {?string} The id of the active descendant.
64  * @private
65  */
66 var getActiveDescendantId_ = function(targetNode) {
67   if (!targetNode.getAttribute) {
68     return null;
69   }
71   var activeId = targetNode.getAttribute('aria-activedescendant');
72   if (!activeId) {
73     return null;
74   }
75   return activeId;
78 /**
79  * If the node is an object with an active descendant, returns the
80  * descendant node.
81  *
82  * This function will fully resolve an active descendant chain. If a circular
83  * chain is detected, it will return null.
84  *
85  * @param {Node} targetNode The node to get descendant information for.
86  * @return {Node} The descendant node or null if no node exists.
87  */
88 var getActiveDescendant = function(targetNode) {
89   var seenIds = {};
90   var node = targetNode;
92   while (node) {
93     var activeId = getActiveDescendantId_(node);
94     if (!activeId) {
95       break;
96     }
97     if (activeId in seenIds) {
98       // A circlar activeDescendant is an error, so return null.
99       return null;
100     }
101     seenIds[activeId] = true;
102     node = document.getElementById(activeId);
103   }
105   if (node == targetNode) {
106     return null;
107   }
108   return node;
112  * Dispatches a left click event on the element that is the targetNode.
113  * Clicks go in the sequence of mousedown, mouseup, and click.
114  * @param {Node} targetNode The target node of this operation.
115  * @param {boolean=} shiftKey Specifies if shift is held down.
116  * @param {boolean=} callOnClickDirectly Specifies whether or not to directly
117  * invoke the onclick method if there is one.
118  * @param {boolean=} opt_double True to issue a double click.
119  */
120 cvox.SearchUtil.clickElem = function(
121     targetNode, shiftKey, callOnClickDirectly, opt_double) {
122   // If there is an activeDescendant of the targetNode, then that is where the
123   // click should actually be targeted.
124   var activeDescendant = getActiveDescendant(targetNode);
125   if (activeDescendant) {
126     targetNode = activeDescendant;
127   }
128   if (callOnClickDirectly) {
129     var onClickFunction = null;
130     if (targetNode.onclick) {
131       onClickFunction = targetNode.onclick;
132     }
133     if (!onClickFunction && (targetNode.nodeType != 1) &&
134         targetNode.parentNode && targetNode.parentNode.onclick) {
135       onClickFunction = targetNode.parentNode.onclick;
136     }
137     var keepGoing = true;
138     if (onClickFunction) {
139       try {
140         keepGoing = onClickFunction();
141       } catch (exception) {
142         // Something went very wrong with the onclick method; we'll ignore it
143         // and just dispatch a click event normally.
144       }
145     }
146     if (!keepGoing) {
147       // The onclick method ran successfully and returned false, meaning the
148       // event should not bubble up, so we will return here.
149       return;
150     }
151   }
153   // Send a mousedown (or simply a double click if requested).
154   var evt = document.createEvent('MouseEvents');
155   var evtType = opt_double ? 'dblclick' : 'mousedown';
156   evt.initMouseEvent(evtType, true, true, document.defaultView,
157                      1, 0, 0, 0, 0, false, false, shiftKey, false, 0, null);
158   // Mark any events we generate so we don't try to process our own events.
159   evt.fromCvox = true;
160   try {
161     targetNode.dispatchEvent(evt);
162   } catch (e) {}
163   //Send a mouse up
164   evt = document.createEvent('MouseEvents');
165   evt.initMouseEvent('mouseup', true, true, document.defaultView,
166                      1, 0, 0, 0, 0, false, false, shiftKey, false, 0, null);
167   // Mark any events we generate so we don't try to process our own events.
168   evt.fromCvox = true;
169   try {
170     targetNode.dispatchEvent(evt);
171   } catch (e) {}
172   //Send a click
173   evt = document.createEvent('MouseEvents');
174   evt.initMouseEvent('click', true, true, document.defaultView,
175                      1, 0, 0, 0, 0, false, false, shiftKey, false, 0, null);
176   // Mark any events we generate so we don't try to process our own events.
177   evt.fromCvox = true;
178   try {
179     targetNode.dispatchEvent(evt);
180   } catch (e) {}