| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 cr.define('cr.ui', function() { | 5 cr.define('cr.ui', function() { |
| 6 /** | 6 /** |
| 7 * Constructor for FocusManager singleton. Checks focus of elements to ensure | 7 * Constructor for FocusManager singleton. Checks focus of elements to ensure |
| 8 * that elements in "background" pages (i.e., those in a dialog that is not | 8 * that elements in "background" pages (i.e., those in a dialog that is not |
| 9 * the topmost overlay) do not receive focus. | 9 * the topmost overlay) do not receive focus. |
| 10 * @constructor | 10 * @constructor |
| 11 */ | 11 */ |
| 12 function FocusManager() { | 12 function FocusManager() {} |
| 13 } | |
| 14 | 13 |
| 15 FocusManager.prototype = { | 14 FocusManager.prototype = { |
| 16 /** | 15 /** |
| 17 * Whether focus is being transferred backward or forward through the DOM. | 16 * Whether focus is being transferred backward or forward through the DOM. |
| 18 * @type {boolean} | 17 * @type {boolean} |
| 19 * @private | 18 * @private |
| 20 */ | 19 */ |
| 21 focusDirBackwards_: false, | 20 focusDirBackwards_: false, |
| 22 | 21 |
| 23 /** | 22 /** |
| 24 * Determines whether the |child| is a descendant of |parent| in the page's | 23 * Determines whether the |child| is a descendant of |parent| in the page's |
| 25 * DOM. | 24 * DOM. |
| 26 * @param {Node} parent The parent element to test. | 25 * @param {Node} parent The parent element to test. |
| 27 * @param {Node} child The child element to test. | 26 * @param {Node} child The child element to test. |
| 28 * @return {boolean} True if |child| is a descendant of |parent|. | 27 * @return {boolean} True if |child| is a descendant of |parent|. |
| 29 * @private | 28 * @private |
| 30 */ | 29 */ |
| 31 isDescendantOf_: function(parent, child) { | 30 isDescendantOf_: function(parent, child) { |
| 32 return !!parent && !(parent === child) && parent.contains(child); | 31 return !!parent && !(parent === child) && parent.contains(child); |
| 33 }, | 32 }, |
| 34 | 33 |
| 35 /** | 34 /** |
| 36 * Returns the parent element containing all elements which should be | 35 * Returns the parent element containing all elements which should be |
| 37 * allowed to receive focus. | 36 * allowed to receive focus. |
| 38 * @return {Element} The element containing focusable elements. | 37 * @return {Element} The element containing focusable elements. |
| 39 */ | 38 */ |
| 40 getFocusParent: function() { | 39 getFocusParent: function() { return document.body; }, |
| 41 return document.body; | |
| 42 }, | |
| 43 | 40 |
| 44 /** | 41 /** |
| 45 * Returns the elements on the page capable of receiving focus. | 42 * Returns the elements on the page capable of receiving focus. |
| 46 * @return {Array<Element>} The focusable elements. | 43 * @return {Array<Element>} The focusable elements. |
| 47 */ | 44 */ |
| 48 getFocusableElements_: function() { | 45 getFocusableElements_: function() { |
| 49 var focusableDiv = this.getFocusParent(); | 46 var focusableDiv = this.getFocusParent(); |
| 50 | 47 |
| 51 // Create a TreeWalker object to traverse the DOM from |focusableDiv|. | 48 // Create a TreeWalker object to traverse the DOM from |focusableDiv|. |
| 52 var treeWalker = document.createTreeWalker( | 49 var treeWalker = document.createTreeWalker( |
| 53 focusableDiv, | 50 focusableDiv, NodeFilter.SHOW_ELEMENT, |
| 54 NodeFilter.SHOW_ELEMENT, | |
| 55 /** @type {NodeFilter} */ | 51 /** @type {NodeFilter} */ |
| 56 ({ | 52 ({ |
| 57 acceptNode: function(node) { | 53 acceptNode: function(node) { |
| 58 var style = window.getComputedStyle(node); | 54 var style = window.getComputedStyle(node); |
| 59 // Reject all hidden nodes. FILTER_REJECT also rejects these | 55 // Reject all hidden nodes. FILTER_REJECT also rejects these |
| 60 // nodes' children, so non-hidden elements that are descendants of | 56 // nodes' children, so non-hidden elements that are descendants of |
| 61 // hidden <div>s will correctly be rejected. | 57 // hidden <div>s will correctly be rejected. |
| 62 if (node.hidden || style.display == 'none' || | 58 if (node.hidden || style.display == 'none' || |
| 63 style.visibility == 'hidden') { | 59 style.visibility == 'hidden') { |
| 64 return NodeFilter.FILTER_REJECT; | 60 return NodeFilter.FILTER_REJECT; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 }, | 139 }, |
| 144 | 140 |
| 145 /** | 141 /** |
| 146 * Handler for focus events on the page. | 142 * Handler for focus events on the page. |
| 147 * @param {Event} event The focus event. | 143 * @param {Event} event The focus event. |
| 148 * @private | 144 * @private |
| 149 */ | 145 */ |
| 150 onDocumentFocus_: function(event) { | 146 onDocumentFocus_: function(event) { |
| 151 // If the element being focused is a descendant of the currently visible | 147 // If the element being focused is a descendant of the currently visible |
| 152 // page, focus is valid. | 148 // page, focus is valid. |
| 153 var targetNode = /** @type {Node} */(event.target); | 149 var targetNode = /** @type {Node} */ (event.target); |
| 154 if (this.isDescendantOf_(this.getFocusParent(), targetNode)) { | 150 if (this.isDescendantOf_(this.getFocusParent(), targetNode)) { |
| 155 this.dispatchFocusEvent_(event.target); | 151 this.dispatchFocusEvent_(event.target); |
| 156 return; | 152 return; |
| 157 } | 153 } |
| 158 | 154 |
| 159 // Focus event handlers for descendant elements might dispatch another | 155 // Focus event handlers for descendant elements might dispatch another |
| 160 // focus event. | 156 // focus event. |
| 161 event.stopPropagation(); | 157 event.stopPropagation(); |
| 162 | 158 |
| 163 // The target of the focus event is not in the topmost visible page and | 159 // The target of the focus event is not in the topmost visible page and |
| (...skipping 16 matching lines...) Expand all Loading... |
| 180 // If the "Shift" key is held, focus is being transferred backward in | 176 // If the "Shift" key is held, focus is being transferred backward in |
| 181 // the page. | 177 // the page. |
| 182 this.focusDirBackwards_ = event.shiftKey ? true : false; | 178 this.focusDirBackwards_ = event.shiftKey ? true : false; |
| 183 } | 179 } |
| 184 }, | 180 }, |
| 185 | 181 |
| 186 /** | 182 /** |
| 187 * Initializes the FocusManager by listening for events in the document. | 183 * Initializes the FocusManager by listening for events in the document. |
| 188 */ | 184 */ |
| 189 initialize: function() { | 185 initialize: function() { |
| 190 document.addEventListener('focus', this.onDocumentFocus_.bind(this), | 186 document.addEventListener( |
| 191 true); | 187 'focus', this.onDocumentFocus_.bind(this), true); |
| 192 document.addEventListener('keydown', this.onDocumentKeyDown_.bind(this), | 188 document.addEventListener( |
| 193 true); | 189 'keydown', this.onDocumentKeyDown_.bind(this), true); |
| 194 }, | 190 }, |
| 195 }; | 191 }; |
| 196 | 192 |
| 197 return { | 193 return { |
| 198 FocusManager: FocusManager, | 194 FocusManager: FocusManager, |
| 199 }; | 195 }; |
| 200 }); | 196 }); |
| OLD | NEW |