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 |