summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/chromeos/chromevox/common/focuser.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/chromeos/chromevox/common/focuser.js')
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/common/focuser.js120
1 files changed, 120 insertions, 0 deletions
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/focuser.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/focuser.js
new file mode 100644
index 00000000000..f0a29d87c43
--- /dev/null
+++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/focuser.js
@@ -0,0 +1,120 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Implements the setFocus function.
+ */
+
+goog.provide('cvox.Focuser');
+
+goog.require('cvox.ChromeVoxEventSuspender');
+goog.require('cvox.DomUtil');
+
+
+/**
+ * Sets the browser focus to the targetNode or its closest ancestor that is
+ * focusable.
+ *
+ * @param {Node} targetNode The node to move the browser focus to.
+ * @param {boolean=} opt_focusDescendants Whether or not we check descendants
+ * of the target node to see if they are focusable. If true, sets focus on the
+ * first focusable descendant. If false, only sets focus on the targetNode or
+ * its closest ancestor. Default is false.
+ */
+cvox.Focuser.setFocus = function(targetNode, opt_focusDescendants) {
+ // Save the selection because Chrome will lose it if there's a focus or blur.
+ var sel = window.getSelection();
+ var range;
+ if (sel.rangeCount > 0) {
+ range = sel.getRangeAt(0);
+ }
+ // Blur the currently-focused element if the target node is not a descendant.
+ if (document.activeElement &&
+ !cvox.DomUtil.isDescendantOfNode(targetNode, document.activeElement)) {
+ document.activeElement.blur();
+ }
+
+ // Video elements should always be focusable.
+ if (targetNode && (targetNode.constructor == HTMLVideoElement)) {
+ if (!cvox.DomUtil.isFocusable(targetNode)) {
+ targetNode.setAttribute('tabIndex', 0);
+ }
+ }
+
+ if (opt_focusDescendants && !cvox.DomUtil.isFocusable(targetNode)) {
+ var focusableDescendant = cvox.DomUtil.findFocusableDescendant(targetNode);
+ if (focusableDescendant) {
+ targetNode = focusableDescendant;
+ }
+ } else {
+ // Search up the parent chain until a focusable node is found.
+ while (targetNode && !cvox.DomUtil.isFocusable(targetNode)) {
+ targetNode = targetNode.parentNode;
+ }
+ }
+
+ // If we found something focusable, focus it - otherwise, blur it.
+ if (cvox.DomUtil.isFocusable(targetNode)) {
+ // Don't let the instance of ChromeVox in the parent focus iframe children
+ // - instead, let the instance of ChromeVox in the iframe focus itself to
+ // avoid getting trapped in iframes that have no ChromeVox in them.
+ // This self focusing is performed by calling window.focus() in
+ // cvox.NavigationManager.prototype.addInterframeListener_
+ if (targetNode.tagName != 'IFRAME') {
+ // setTimeout must be used because there's a bug (in Chrome, I think)
+ // with .focus() which causes the page to be redrawn incorrectly if
+ // not in setTimeout.
+ if (cvox.ChromeVoxEventSuspender.areEventsSuspended()) {
+ if (cvox.Focuser.shouldEnterSuspendEvents_(targetNode)) {
+ cvox.ChromeVoxEventSuspender.enterSuspendEvents();
+ }
+ window.setTimeout(function() {
+ targetNode.focus();
+ cvox.ChromeVoxEventSuspender.exitSuspendEvents();
+ }, 0);
+ }
+ else {
+ window.setTimeout(function() {
+ targetNode.focus();
+ }, 0);
+ }
+ }
+ } else if (document.activeElement &&
+ document.activeElement.tagName != 'BODY') {
+ document.activeElement.blur();
+ }
+
+ // Restore the selection, unless the focused item is a text box.
+ if (cvox.DomUtil.isInputTypeText(targetNode)) {
+ targetNode.select();
+ } else if (range) {
+ sel.removeAllRanges();
+ sel.addRange(range);
+ }
+};
+
+/**
+ * Rules for whether or not enterSuspendEvents should be called.
+ * In general, we should not enterSuspendEvents if the targetNode will get some
+ * special handlers attached when a focus event is received for it; otherwise,
+ * the special handlers will not get attached.
+ *
+ * @param {Node} targetNode The node that is being focused.
+ * @return {boolean} True if enterSuspendEvents should be called.
+ */
+cvox.Focuser.shouldEnterSuspendEvents_ = function(targetNode){
+ if (targetNode.constructor && targetNode.constructor == HTMLVideoElement) {
+ return false;
+ }
+ if (targetNode.hasAttribute) {
+ switch (targetNode.getAttribute('type')) {
+ case 'time':
+ case 'date':
+ case 'week':
+ case 'month':
+ return false;
+ }
+ }
+ return true;
+};