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.
7 * @fileoverview Helper functions.
10 goog
.provide('cvox.SearchUtil');
12 /** Utility functions. */
13 cvox
.SearchUtil = function() {
17 * Extracts the first URL from an element.
18 * @param {Node} node DOM element to extract from.
19 * @return {?string} URL.
21 cvox
.SearchUtil
.extractURL = function(node
) {
23 if (node
.tagName
=== 'A') {
26 var anchor
= node
.querySelector('a');
35 * Indicates whether or not the search widget has been activated.
36 * @return {boolean} Whether or not the search widget is active.
38 cvox
.SearchUtil
.isSearchWidgetActive = function() {
39 var SEARCH_WIDGET_SELECT
= '#cvox-search';
40 return document
.querySelector(SEARCH_WIDGET_SELECT
) !== null;
44 * Adds one to and index with wrapping.
45 * @param {number} index Index to add to.
46 * @param {number} length Length to wrap at.
47 * @return {number} The new index++, wrapped if exceeding length.
49 cvox
.SearchUtil
.addOneWrap = function(index
, length
) {
50 return (index
+ 1) % length
;
54 * Subtracts one to and index with wrapping.
55 * @param {number} index Index to subtract from.
56 * @param {number} length Length to wrap at.
57 * @return {number} The new index--, wrapped if below 0.
59 cvox
.SearchUtil
.subOneWrap = function(index
, length
) {
60 return (index
- 1 + length
) % length
;
64 * Returns the id of a node's active descendant
65 * @param {Node} targetNode The node.
66 * @return {?string} The id of the active descendant.
69 var getActiveDescendantId_ = function(targetNode
) {
70 if (!targetNode
.getAttribute
) {
74 var activeId
= targetNode
.getAttribute('aria-activedescendant');
82 * If the node is an object with an active descendant, returns the
85 * This function will fully resolve an active descendant chain. If a circular
86 * chain is detected, it will return null.
88 * @param {Node} targetNode The node to get descendant information for.
89 * @return {Node} The descendant node or null if no node exists.
91 var getActiveDescendant = function(targetNode
) {
93 var node
= targetNode
;
96 var activeId
= getActiveDescendantId_(node
);
100 if (activeId
in seenIds
) {
101 // A circlar activeDescendant is an error, so return null.
104 seenIds
[activeId
] = true;
105 node
= document
.getElementById(activeId
);
108 if (node
== targetNode
) {
115 * Dispatches a left click event on the element that is the targetNode.
116 * Clicks go in the sequence of mousedown, mouseup, and click.
117 * @param {Node} targetNode The target node of this operation.
118 * @param {boolean=} shiftKey Specifies if shift is held down.
119 * @param {boolean=} callOnClickDirectly Specifies whether or not to directly
120 * invoke the onclick method if there is one.
121 * @param {boolean=} opt_double True to issue a double click.
123 cvox
.SearchUtil
.clickElem = function(
124 targetNode
, shiftKey
, callOnClickDirectly
, opt_double
) {
125 // If there is an activeDescendant of the targetNode, then that is where the
126 // click should actually be targeted.
127 var activeDescendant
= getActiveDescendant(targetNode
);
128 if (activeDescendant
) {
129 targetNode
= activeDescendant
;
131 if (callOnClickDirectly
) {
132 var onClickFunction
= null;
133 if (targetNode
.onclick
) {
134 onClickFunction
= targetNode
.onclick
;
136 if (!onClickFunction
&& (targetNode
.nodeType
!= 1) &&
137 targetNode
.parentNode
&& targetNode
.parentNode
.onclick
) {
138 onClickFunction
= targetNode
.parentNode
.onclick
;
140 var keepGoing
= true;
141 if (onClickFunction
) {
143 keepGoing
= onClickFunction();
144 } catch (exception
) {
145 // Something went very wrong with the onclick method; we'll ignore it
146 // and just dispatch a click event normally.
150 // The onclick method ran successfully and returned false, meaning the
151 // event should not bubble up, so we will return here.
156 // Send a mousedown (or simply a double click if requested).
157 var evt
= document
.createEvent('MouseEvents');
158 var evtType
= opt_double
? 'dblclick' : 'mousedown';
159 evt
.initMouseEvent(evtType
, true, true, document
.defaultView
,
160 1, 0, 0, 0, 0, false, false, shiftKey
, false, 0, null);
161 // Mark any events we generate so we don't try to process our own events.
164 targetNode
.dispatchEvent(evt
);
167 evt
= document
.createEvent('MouseEvents');
168 evt
.initMouseEvent('mouseup', true, true, document
.defaultView
,
169 1, 0, 0, 0, 0, false, false, shiftKey
, false, 0, null);
170 // Mark any events we generate so we don't try to process our own events.
173 targetNode
.dispatchEvent(evt
);
176 evt
= document
.createEvent('MouseEvents');
177 evt
.initMouseEvent('click', true, true, document
.defaultView
,
178 1, 0, 0, 0, 0, false, false, shiftKey
, false, 0, null);
179 // Mark any events we generate so we don't try to process our own events.
182 targetNode
.dispatchEvent(evt
);