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 * Creates a selection controller that is to be used with lists. This is | 7 * Creates a selection controller that is to be used with lists. This is |
8 * implemented for vertical lists but changing the behavior for horizontal | 8 * implemented for vertical lists but changing the behavior for horizontal |
9 * lists or icon views is a matter of overriding {@code getIndexBefore}, | 9 * lists or icon views is a matter of overriding {@code getIndexBefore}, |
10 * {@code getIndexAfter}, {@code getIndexAbove} as well as | 10 * {@code getIndexAfter}, {@code getIndexAbove} as well as |
11 * {@code getIndexBelow}. | 11 * {@code getIndexBelow}. |
12 * | 12 * |
13 * @param {cr.ui.ListSelectionModel} selectionModel The selection model to | 13 * @param {cr.ui.ListSelectionModel} selectionModel The selection model to |
14 * interact with. | 14 * interact with. |
15 * | 15 * |
16 * @constructor | 16 * @constructor |
17 * @extends {cr.EventTarget} | 17 * @extends {cr.EventTarget} |
18 */ | 18 */ |
19 function ListSelectionController(selectionModel) { | 19 function ListSelectionController(selectionModel) { |
20 this.selectionModel_ = selectionModel; | 20 this.selectionModel_ = selectionModel; |
21 } | 21 } |
22 | 22 |
23 ListSelectionController.prototype = { | 23 ListSelectionController.prototype = { |
24 | 24 |
25 /** | 25 /** |
26 * The selection model we are interacting with. | 26 * The selection model we are interacting with. |
27 * @type {cr.ui.ListSelectionModel} | 27 * @type {cr.ui.ListSelectionModel} |
28 */ | 28 */ |
29 get selectionModel() { | 29 get selectionModel() { return this.selectionModel_; }, |
30 return this.selectionModel_; | |
31 }, | |
32 | 30 |
33 /** | 31 /** |
34 * Returns the index below (y axis) the given element. | 32 * Returns the index below (y axis) the given element. |
35 * @param {number} index The index to get the index below. | 33 * @param {number} index The index to get the index below. |
36 * @return {number} The index below or -1 if not found. | 34 * @return {number} The index below or -1 if not found. |
37 */ | 35 */ |
38 getIndexBelow: function(index) { | 36 getIndexBelow: function(index) { |
39 if (index == this.getLastIndex()) | 37 if (index == this.getLastIndex()) |
40 return -1; | 38 return -1; |
41 return index + 1; | 39 return index + 1; |
42 }, | 40 }, |
43 | 41 |
44 /** | 42 /** |
45 * Returns the index above (y axis) the given element. | 43 * Returns the index above (y axis) the given element. |
46 * @param {number} index The index to get the index above. | 44 * @param {number} index The index to get the index above. |
47 * @return {number} The index below or -1 if not found. | 45 * @return {number} The index below or -1 if not found. |
48 */ | 46 */ |
49 getIndexAbove: function(index) { | 47 getIndexAbove: function(index) { return index - 1; }, |
50 return index - 1; | |
51 }, | |
52 | 48 |
53 /** | 49 /** |
54 * Returns the index before (x axis) the given element. This returns -1 | 50 * Returns the index before (x axis) the given element. This returns -1 |
55 * by default but override this for icon view and horizontal selection | 51 * by default but override this for icon view and horizontal selection |
56 * models. | 52 * models. |
57 * | 53 * |
58 * @param {number} index The index to get the index before. | 54 * @param {number} index The index to get the index before. |
59 * @return {number} The index before or -1 if not found. | 55 * @return {number} The index before or -1 if not found. |
60 */ | 56 */ |
61 getIndexBefore: function(index) { | 57 getIndexBefore: function(index) { return -1; }, |
62 return -1; | |
63 }, | |
64 | 58 |
65 /** | 59 /** |
66 * Returns the index after (x axis) the given element. This returns -1 | 60 * Returns the index after (x axis) the given element. This returns -1 |
67 * by default but override this for icon view and horizontal selection | 61 * by default but override this for icon view and horizontal selection |
68 * models. | 62 * models. |
69 * | 63 * |
70 * @param {number} index The index to get the index after. | 64 * @param {number} index The index to get the index after. |
71 * @return {number} The index after or -1 if not found. | 65 * @return {number} The index after or -1 if not found. |
72 */ | 66 */ |
73 getIndexAfter: function(index) { | 67 getIndexAfter: function(index) { return -1; }, |
74 return -1; | |
75 }, | |
76 | 68 |
77 /** | 69 /** |
78 * Returns the next list index. This is the next logical and should not | 70 * Returns the next list index. This is the next logical and should not |
79 * depend on any kind of layout of the list. | 71 * depend on any kind of layout of the list. |
80 * @param {number} index The index to get the next index for. | 72 * @param {number} index The index to get the next index for. |
81 * @return {number} The next index or -1 if not found. | 73 * @return {number} The next index or -1 if not found. |
82 */ | 74 */ |
83 getNextIndex: function(index) { | 75 getNextIndex: function(index) { |
84 if (index == this.getLastIndex()) | 76 if (index == this.getLastIndex()) |
85 return -1; | 77 return -1; |
86 return index + 1; | 78 return index + 1; |
87 }, | 79 }, |
88 | 80 |
89 /** | 81 /** |
90 * Returns the prevous list index. This is the previous logical and should | 82 * Returns the prevous list index. This is the previous logical and should |
91 * not depend on any kind of layout of the list. | 83 * not depend on any kind of layout of the list. |
92 * @param {number} index The index to get the previous index for. | 84 * @param {number} index The index to get the previous index for. |
93 * @return {number} The previous index or -1 if not found. | 85 * @return {number} The previous index or -1 if not found. |
94 */ | 86 */ |
95 getPreviousIndex: function(index) { | 87 getPreviousIndex: function(index) { return index - 1; }, |
96 return index - 1; | |
97 }, | |
98 | 88 |
99 /** | 89 /** |
100 * @return {number} The first index. | 90 * @return {number} The first index. |
101 */ | 91 */ |
102 getFirstIndex: function() { | 92 getFirstIndex: function() { return 0; }, |
103 return 0; | |
104 }, | |
105 | 93 |
106 /** | 94 /** |
107 * @return {number} The last index. | 95 * @return {number} The last index. |
108 */ | 96 */ |
109 getLastIndex: function() { | 97 getLastIndex: function() { return this.selectionModel.length - 1; }, |
110 return this.selectionModel.length - 1; | |
111 }, | |
112 | 98 |
113 /** | 99 /** |
114 * Called by the view when the user does a mousedown or mouseup on the | 100 * Called by the view when the user does a mousedown or mouseup on the |
115 * list. | 101 * list. |
116 * @param {!Event} e The browser mouse event. | 102 * @param {!Event} e The browser mouse event. |
117 * @param {number} index The index that was under the mouse pointer, -1 if | 103 * @param {number} index The index that was under the mouse pointer, -1 if |
118 * none. | 104 * none. |
119 */ | 105 */ |
120 handlePointerDownUp: function(e, index) { | 106 handlePointerDownUp: function(e, index) { |
121 var sm = this.selectionModel; | 107 var sm = this.selectionModel; |
122 var anchorIndex = sm.anchorIndex; | 108 var anchorIndex = sm.anchorIndex; |
123 var isDown = (e.type == 'mousedown'); | 109 var isDown = (e.type == 'mousedown'); |
124 | 110 |
125 sm.beginChange(); | 111 sm.beginChange(); |
126 | 112 |
127 if (index == -1) { | 113 if (index == -1) { |
128 // On Mac we always clear the selection if the user clicks a blank area. | 114 // On Mac we always clear the selection if the user clicks a blank area. |
129 // On Windows, we only clear the selection if neither Shift nor Ctrl are | 115 // On Windows, we only clear the selection if neither Shift nor Ctrl are |
130 // pressed. | 116 // pressed. |
131 if (cr.isMac || cr.isChromeOS) { | 117 if (cr.isMac || cr.isChromeOS) { |
132 sm.leadIndex = sm.anchorIndex = -1; | 118 sm.leadIndex = sm.anchorIndex = -1; |
133 sm.unselectAll(); | 119 sm.unselectAll(); |
134 } else if (!isDown && !e.shiftKey && !e.ctrlKey) | 120 } else if (!isDown && !e.shiftKey && !e.ctrlKey) |
135 // Keep anchor and lead indexes. Note that this is intentionally | 121 // Keep anchor and lead indexes. Note that this is intentionally |
136 // different than on the Mac. | 122 // different than on the Mac. |
137 if (sm.multiple) | 123 if (sm.multiple) |
138 sm.unselectAll(); | 124 sm.unselectAll(); |
139 } else { | 125 } else { |
140 if (sm.multiple && (cr.isMac ? e.metaKey : | 126 if (sm.multiple && |
141 (e.ctrlKey && !e.shiftKey))) { | 127 (cr.isMac ? e.metaKey : (e.ctrlKey && !e.shiftKey))) { |
142 // Selection is handled at mouseUp on windows/linux, mouseDown on mac. | 128 // Selection is handled at mouseUp on windows/linux, mouseDown on mac. |
143 if (cr.isMac ? isDown : !isDown) { | 129 if (cr.isMac ? isDown : !isDown) { |
144 // Toggle the current one and make it anchor index. | 130 // Toggle the current one and make it anchor index. |
145 sm.setIndexSelected(index, !sm.getIndexSelected(index)); | 131 sm.setIndexSelected(index, !sm.getIndexSelected(index)); |
146 sm.leadIndex = index; | 132 sm.leadIndex = index; |
147 sm.anchorIndex = index; | 133 sm.anchorIndex = index; |
148 } | 134 } |
149 } else if (e.shiftKey && anchorIndex != -1 && anchorIndex != index) { | 135 } else if (e.shiftKey && anchorIndex != -1 && anchorIndex != index) { |
150 // Shift is done in mousedown. | 136 // Shift is done in mousedown. |
151 if (isDown) { | 137 if (isDown) { |
(...skipping 28 matching lines...) Expand all Loading... |
180 var tagName = e.target.tagName; | 166 var tagName = e.target.tagName; |
181 // If focus is in an input field of some kind, only handle navigation keys | 167 // If focus is in an input field of some kind, only handle navigation keys |
182 // that aren't likely to conflict with input interaction (e.g., text | 168 // that aren't likely to conflict with input interaction (e.g., text |
183 // editing, or changing the value of a checkbox or select). | 169 // editing, or changing the value of a checkbox or select). |
184 if (tagName == 'INPUT') { | 170 if (tagName == 'INPUT') { |
185 var inputType = e.target.type; | 171 var inputType = e.target.type; |
186 // Just protect space (for toggling) for checkbox and radio. | 172 // Just protect space (for toggling) for checkbox and radio. |
187 if (inputType == 'checkbox' || inputType == 'radio') { | 173 if (inputType == 'checkbox' || inputType == 'radio') { |
188 if (e.key == ' ') | 174 if (e.key == ' ') |
189 return; | 175 return; |
190 // Protect all but the most basic navigation commands in anything else. | 176 // Protect all but the most basic navigation commands in anything |
| 177 // else. |
191 } else if (e.key != 'ArrowUp' && e.key != 'ArrowDown') { | 178 } else if (e.key != 'ArrowUp' && e.key != 'ArrowDown') { |
192 return; | 179 return; |
193 } | 180 } |
194 } | 181 } |
195 // Similarly, don't interfere with select element handling. | 182 // Similarly, don't interfere with select element handling. |
196 if (tagName == 'SELECT') | 183 if (tagName == 'SELECT') |
197 return; | 184 return; |
198 | 185 |
199 var sm = this.selectionModel; | 186 var sm = this.selectionModel; |
200 var newIndex = -1; | 187 var newIndex = -1; |
(...skipping 19 matching lines...) Expand all Loading... |
220 } | 207 } |
221 | 208 |
222 switch (e.key) { | 209 switch (e.key) { |
223 case 'Home': | 210 case 'Home': |
224 newIndex = this.getFirstIndex(); | 211 newIndex = this.getFirstIndex(); |
225 break; | 212 break; |
226 case 'End': | 213 case 'End': |
227 newIndex = this.getLastIndex(); | 214 newIndex = this.getLastIndex(); |
228 break; | 215 break; |
229 case 'ArrowUp': | 216 case 'ArrowUp': |
230 newIndex = leadIndex == -1 ? | 217 newIndex = leadIndex == -1 ? this.getLastIndex() : |
231 this.getLastIndex() : this.getIndexAbove(leadIndex); | 218 this.getIndexAbove(leadIndex); |
232 break; | 219 break; |
233 case 'ArrowDown': | 220 case 'ArrowDown': |
234 newIndex = leadIndex == -1 ? | 221 newIndex = leadIndex == -1 ? this.getFirstIndex() : |
235 this.getFirstIndex() : this.getIndexBelow(leadIndex); | 222 this.getIndexBelow(leadIndex); |
236 break; | 223 break; |
237 case 'ArrowLeft': | 224 case 'ArrowLeft': |
238 case 'MediaPreviousTrack': | 225 case 'MediaPreviousTrack': |
239 newIndex = leadIndex == -1 ? | 226 newIndex = leadIndex == -1 ? this.getLastIndex() : |
240 this.getLastIndex() : this.getIndexBefore(leadIndex); | 227 this.getIndexBefore(leadIndex); |
241 break; | 228 break; |
242 case 'ArrowRight': | 229 case 'ArrowRight': |
243 case 'MediaNextTrack': | 230 case 'MediaNextTrack': |
244 newIndex = leadIndex == -1 ? | 231 newIndex = leadIndex == -1 ? this.getFirstIndex() : |
245 this.getFirstIndex() : this.getIndexAfter(leadIndex); | 232 this.getIndexAfter(leadIndex); |
246 break; | 233 break; |
247 default: | 234 default: |
248 prevent = false; | 235 prevent = false; |
249 } | 236 } |
250 | 237 |
251 if (newIndex != -1) { | 238 if (newIndex != -1) { |
252 sm.beginChange(); | 239 sm.beginChange(); |
253 | 240 |
254 sm.leadIndex = newIndex; | 241 sm.leadIndex = newIndex; |
255 if (e.shiftKey) { | 242 if (e.shiftKey) { |
(...skipping 17 matching lines...) Expand all Loading... |
273 } | 260 } |
274 | 261 |
275 sm.endChange(); | 262 sm.endChange(); |
276 | 263 |
277 if (prevent) | 264 if (prevent) |
278 e.preventDefault(); | 265 e.preventDefault(); |
279 } | 266 } |
280 } | 267 } |
281 }; | 268 }; |
282 | 269 |
283 return { | 270 return {ListSelectionController: ListSelectionController}; |
284 ListSelectionController: ListSelectionController | |
285 }; | |
286 }); | 271 }); |
OLD | NEW |