Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: ui/webui/resources/js/cr/ui/focus_grid.js

Issue 1313453002: Make cr.ui.Focus* play nice with Shadow DOM and MD chrome://downloads (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 * A class to manage grid of focusable elements in a 2D grid. For example, 7 * A class to manage grid of focusable elements in a 2D grid. For example,
8 * given this grid: 8 * given this grid:
9 * 9 *
10 * focusable [focused] focusable (row: 0, col: 1) 10 * focusable [focused] focusable (row: 0, col: 1)
11 * focusable focusable focusable 11 * focusable focusable focusable
12 * focusable focusable focusable 12 * focusable focusable focusable
13 * 13 *
14 * Pressing the down arrow would result in the focus moving down 1 row and 14 * Pressing the down arrow would result in the focus moving down 1 row and
15 * keeping the same column: 15 * keeping the same column:
16 * 16 *
17 * focusable focusable focusable 17 * focusable focusable focusable
18 * focusable [focused] focusable (row: 1, col: 1) 18 * focusable [focused] focusable (row: 1, col: 1)
19 * focusable focusable focusable 19 * focusable focusable focusable
20 * 20 *
21 * And pressing right or tab at this point would move the focus to: 21 * And pressing right or tab at this point would move the focus to:
22 * 22 *
23 * focusable focusable focusable 23 * focusable focusable focusable
24 * focusable focusable [focused] (row: 1, col: 2) 24 * focusable focusable [focused] (row: 1, col: 2)
25 * focusable focusable focusable 25 * focusable focusable focusable
26 * 26 *
27 * @constructor 27 * @constructor
28 * @implements {cr.ui.FocusRow.Delegate}
28 */ 29 */
29 function FocusGrid() { 30 function FocusGrid() {
30 /** @type {!Array<!cr.ui.FocusRow>} */ 31 /** @type {!Array<!cr.ui.FocusRow>} */
31 this.rows = []; 32 this.rows = [];
32
33 /** @private {!EventTracker} */
34 this.eventTracker_ = new EventTracker;
35 this.eventTracker_.add(cr.doc, 'keydown', this.onKeydown_.bind(this));
36 this.eventTracker_.add(cr.doc, 'focusin', this.onFocusin_.bind(this));
37
38 /** @private {cr.ui.FocusRow.Delegate} */
39 this.delegate_ = new FocusGrid.RowDelegate(this);
40 } 33 }
41 34
42 /** 35 FocusGrid.prototype = {
43 * Row delegate to overwrite the behavior of a mouse click to deselect any row 36 /** @private {boolean} */
44 * that wasn't clicked. 37 ignoreFocusChange_: false,
45 * @param {cr.ui.FocusGrid} focusGrid
46 * @constructor
47 * @implements {cr.ui.FocusRow.Delegate}
48 */
49 FocusGrid.RowDelegate = function(focusGrid) {
50 /** @private {cr.ui.FocusGrid} */
51 this.focusGrid_ = focusGrid;
52 };
53
54 FocusGrid.RowDelegate.prototype = {
55 /** @override */
56 onKeydown: function(row, e) { return false; },
57 38
58 /** @override */ 39 /** @override */
59 onMousedown: function(row, e) { 40 onFocus: function(row, e) {
60 // Only care about left mouse click. 41 if (this.ignoreFocusChange_)
61 if (e.button) 42 this.ignoreFocusChange_ = false;
62 return false; 43 else
44 this.lastFocused_ = e.currentTarget;
63 45
64 // Only the clicked row should be active. 46 this.rows.forEach(function(r) { r.makeActive(r == row); });
65 var target = assertInstanceof(e.target, Node); 47 },
66 this.focusGrid_.rows.forEach(function(row) {
67 row.makeActive(row.root.contains(target));
68 });
69 48
70 return true; 49 /** @override */
50 onKeydown: function(row, e) {
51 var rowIndex = this.rows.indexOf(row);
52 assert(rowIndex >= 0);
53
54 var newRow = -1;
55
56 if (e.keyIdentifier == 'Up')
57 newRow = rowIndex - 1;
58 else if (e.keyIdentifier == 'Down')
59 newRow = rowIndex + 1;
60 else if (e.keyIdentifier == 'PageUp')
61 newRow = 0;
62 else if (e.keyIdentifier == 'PageDown')
63 newRow = this.rows.length - 1;
64
65 var rowToFocus = this.rows[newRow];
66 if (rowToFocus) {
67 this.ignoreFocusChange_ = true;
68 rowToFocus.getEquivalentElement(this.lastFocused_).focus();
69 e.preventDefault();
70 return true;
71 }
72
73 return false;
71 }, 74 },
72 };
73 75
74 FocusGrid.prototype = {
75 /** 76 /**
76 * Unregisters event handlers and removes all |this.rows|. 77 * Unregisters event handlers and removes all |this.rows|.
77 */ 78 */
78 destroy: function() { 79 destroy: function() {
79 this.rows.forEach(function(row) { row.destroy(); }); 80 this.rows.forEach(function(row) { row.destroy(); });
80 this.rows.length = 0; 81 this.rows.length = 0;
81 }, 82 },
82 83
83 /** 84 /**
84 * @param {Node} target A target item to find in this grid. 85 * @param {Node} target A target item to find in this grid.
(...skipping 13 matching lines...) Expand all
98 */ 99 */
99 getRowForRoot: function(root) { 100 getRowForRoot: function(root) {
100 for (var i = 0; i < this.rows.length; ++i) { 101 for (var i = 0; i < this.rows.length; ++i) {
101 if (this.rows[i].root == root) 102 if (this.rows[i].root == root)
102 return this.rows[i]; 103 return this.rows[i];
103 } 104 }
104 return null; 105 return null;
105 }, 106 },
106 107
107 /** 108 /**
108 * Handles keyboard shortcuts to move up/down in the grid.
109 * @param {Event} e The key event.
110 * @private
111 */
112 onKeydown_: function(e) {
113 var target = assertInstanceof(e.target, Node);
114 var rowIndex = this.getRowIndexForTarget(target);
115 if (rowIndex == -1)
116 return;
117
118 var row = -1;
119
120 if (e.keyIdentifier == 'Up')
121 row = rowIndex - 1;
122 else if (e.keyIdentifier == 'Down')
123 row = rowIndex + 1;
124 else if (e.keyIdentifier == 'PageUp')
125 row = 0;
126 else if (e.keyIdentifier == 'PageDown')
127 row = this.rows.length - 1;
128
129 var rowToFocus = this.rows[row];
130 if (rowToFocus) {
131 this.ignoreFocusChange_ = true;
132 rowToFocus.getEquivalentElement(this.lastFocused).focus();
133 e.preventDefault();
134 }
135 },
136
137 /**
138 * Keep track of the last column that the user manually focused.
139 * @param {Event} e The focusin event.
140 * @private
141 */
142 onFocusin_: function(e) {
143 if (this.ignoreFocusChange_) {
144 this.ignoreFocusChange_ = false;
145 return;
146 }
147
148 var target = assertInstanceof(e.target, Node);
149 if (this.getRowIndexForTarget(target) != -1)
150 this.lastFocused = target;
151 },
152
153 /**
154 * Adds |row| to the end of this list. 109 * Adds |row| to the end of this list.
155 * @param {!cr.ui.FocusRow} row The row that needs to be added to this grid. 110 * @param {!cr.ui.FocusRow} row The row that needs to be added to this grid.
156 */ 111 */
157 addRow: function(row) { 112 addRow: function(row) {
158 this.addRowBefore(row, null); 113 this.addRowBefore(row, null);
159 }, 114 },
160 115
161 /** 116 /**
162 * Adds |row| before |nextRow|. If |nextRow| is not in the list or it's 117 * Adds |row| before |nextRow|. If |nextRow| is not in the list or it's
163 * null, |row| is added to the end. 118 * null, |row| is added to the end.
164 * @param {!cr.ui.FocusRow} row The row that needs to be added to this grid. 119 * @param {!cr.ui.FocusRow} row The row that needs to be added to this grid.
165 * @param {cr.ui.FocusRow} nextRow The row that should follow |row|. 120 * @param {cr.ui.FocusRow} nextRow The row that should follow |row|.
166 */ 121 */
167 addRowBefore: function(row, nextRow) { 122 addRowBefore: function(row, nextRow) {
168 row.delegate = row.delegate || this.delegate_; 123 row.delegate = row.delegate || this;
169 124
170 var nextRowIndex = this.rows.indexOf(nextRow); 125 var nextRowIndex = this.rows.indexOf(nextRow);
171 if (nextRowIndex == -1) 126 if (nextRowIndex == -1)
172 this.rows.push(row); 127 this.rows.push(row);
173 else 128 else
174 this.rows.splice(nextRowIndex, 0, row); 129 this.rows.splice(nextRowIndex, 0, row);
175 }, 130 },
176 131
177 /** 132 /**
178 * Removes a row from the focus row. No-op if row is not in the grid. 133 * Removes a row from the focus row. No-op if row is not in the grid.
(...skipping 19 matching lines...) Expand all
198 } 153 }
199 154
200 this.rows[0].makeActive(true); 155 this.rows[0].makeActive(true);
201 }, 156 },
202 }; 157 };
203 158
204 return { 159 return {
205 FocusGrid: FocusGrid, 160 FocusGrid: FocusGrid,
206 }; 161 };
207 }); 162 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698