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

Side by Side Diff: resources/bookmark_manager/js/cr/ui/listselectionmodel.js

Issue 853002: Updating the Chromium reference build for Windows. The continuous... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/reference_builds/chrome/
Patch Set: Added the symbol files back. Created 10 years, 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 cr.define('cr.ui', function() {
6 const Event = cr.Event;
7 const EventTarget = cr.EventTarget;
8
9 /**
10 * Creates a new selection model that is to be used with lists. This is
11 * implemented for vertical lists but changing the behavior for horizontal
12 * lists or icon views is a matter of overriding {@code getItemBefore},
13 * {@code getItemAfter}, {@code getItemAbove} as well as {@code getItemBelow}.
14 *
15 * @constructor
16 * @extends {!cr.EventTarget}
17 */
18 function ListSelectionModel(list) {
19 this.list = list;
20 this.selectedItems_ = {};
21 }
22
23 ListSelectionModel.prototype = {
24 __proto__: EventTarget.prototype,
25
26 /**
27 * Returns the item below (y axis) the given element.
28 * @param {*} item The item to get the item below.
29 * @return {*} The item below or null if not found.
30 */
31 getItemBelow: function(item) {
32 return item.nextElementSibling;
33 },
34
35 /**
36 * Returns the item above (y axis) the given element.
37 * @param {*} item The item to get the item above.
38 * @return {*} The item below or null if not found.
39 */
40 getItemAbove: function(item) {
41 return item.previousElementSibling;
42 },
43
44 /**
45 * Returns the item before (x axis) the given element. This returns null
46 * by default but override this for icon view and horizontal selection
47 * models.
48 *
49 * @param {*} item The item to get the item before.
50 * @return {*} The item before or null if not found.
51 */
52 getItemBefore: function(item) {
53 return null;
54 },
55
56 /**
57 * Returns the item after (x axis) the given element. This returns null
58 * by default but override this for icon view and horizontal selection
59 * models.
60 *
61 * @param {*} item The item to get the item after.
62 * @return {*} The item after or null if not found.
63 */
64 getItemAfter: function(item) {
65 return null;
66 },
67
68 /**
69 * Returns the next list item. This is the next logical and should not
70 * depend on any kind of layout of the list.
71 * @param {*} item The item to get the next item for.
72 * @return {*} The next item or null if not found.
73 */
74 getNextItem: function(item) {
75 return item.nextElementSibling;
76 },
77
78 /**
79 * Returns the prevous list item. This is the previous logical and should
80 * not depend on any kind of layout of the list.
81 * @param {*} item The item to get the previous item for.
82 * @return {*} The previous item or null if not found.
83 */
84 getPreviousItem: function(item) {
85 return item.previousElementSibling;
86 },
87
88 /**
89 * @return {*} The first item.
90 */
91 getFirstItem: function() {
92 return this.list.firstElementChild;
93 },
94
95 /**
96 * @return {*} The last item.
97 */
98 getLastItem: function() {
99 return this.list.lastElementChild;
100 },
101
102 /**
103 * Called by the view when the user does a mousedown or mouseup on the list.
104 * @param {!Event} e The browser mousedown event.
105 * @param {*} item The item that was under the mouse pointer, null if none.
106 */
107 handleMouseDownUp: function(e, item) {
108 var anchorItem = this.anchorItem;
109
110 this.beginChange_();
111
112 if (!item && !e.ctrlKey && !e.shiftKey && !e.metaKey) {
113 this.clear();
114 } else {
115 var isDown = e.type == 'mousedown';
116 if (!cr.isMac && e.ctrlKey) {
117 // Handle ctrlKey on mouseup
118 if (!isDown) {
119 // toggle the current one and make it anchor item
120 this.setItemSelected(item, !this.getItemSelected(item));
121 this.leadItem = item;
122 this.anchorItem = item;
123 }
124 } else if (e.shiftKey && anchorItem && anchorItem != item) {
125 // Shift is done in mousedown
126 if (isDown) {
127 this.clearAllSelected_();
128 this.leadItem = item;
129 this.selectRange(anchorItem, item);
130 }
131 } else {
132 // Right click for a context menu need to not clear the selection.
133 var isRightClick = e.button == 2;
134
135 // If the item is selected this is handled in mouseup.
136 var itemSelected = this.getItemSelected(item);
137 if ((itemSelected && !isDown || !itemSelected && isDown) &&
138 !(itemSelected && isRightClick)) {
139 this.clearAllSelected_();
140 this.setItemSelected(item, true);
141 this.leadItem = item;
142 this.anchorItem = item;
143 }
144 }
145 }
146
147 this.endChange_();
148 },
149
150 /**
151 * Called by the view when it recieves a keydown event.
152 * @param {Event} e The keydown event.
153 */
154 handleKeyDown: function(e) {
155 var newItem = null;
156 var leadItem = this.leadItem;
157 var prevent = true;
158
159 // Ctrl/Meta+A
160 if (e.keyCode == 65 &&
161 (cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey)) {
162 this.selectAll();
163 e.preventDefault();
164 return;
165 }
166
167 // Space
168 if (e.keyCode == 32) {
169 if (leadItem != null) {
170 var selected = this.getItemSelected(leadItem);
171 if (e.ctrlKey || !selected) {
172 this.beginChange_();
173 this.setItemSelected(leadItem, !selected);
174 this.endChange_();
175 return;
176 }
177 }
178 }
179
180 switch (e.keyIdentifier) {
181 case 'Home':
182 newItem = this.getFirstItem();
183 break;
184 case 'End':
185 newItem = this.getLastItem();
186 break;
187 case 'Up':
188 newItem = !leadItem ?
189 this.getLastItem() : this.getItemAbove(leadItem);
190 break;
191 case 'Down':
192 newItem = !leadItem ?
193 this.getFirstItem() : this.getItemBelow(leadItem);
194 break;
195 case 'Left':
196 newItem = !leadItem ?
197 this.getLastItem() : this.getItemBefore(leadItem);
198 break;
199 case 'Right':
200 newItem = !leadItem ?
201 this.getFirstItem() : this.getItemAfter(leadItem);
202 break;
203 default:
204 prevent = false;
205 }
206
207 if (newItem) {
208 this.beginChange_();
209
210 this.leadItem = newItem;
211 if (e.shiftKey) {
212 var anchorItem = this.anchorItem;
213 this.clearAllSelected_();
214 if (!anchorItem) {
215 this.setItemSelected(newItem, true);
216 this.anchorItem = newItem;
217 } else {
218 this.selectRange(anchorItem, newItem);
219 }
220 } else if (e.ctrlKey && !cr.isMac) {
221 // Setting the lead item is done above
222 // Mac does not allow you to change the lead.
223 } else {
224 this.clearAllSelected_();
225 this.setItemSelected(newItem, true);
226 this.anchorItem = newItem;
227 }
228
229 this.endChange_();
230
231 if (prevent)
232 e.preventDefault();
233 }
234 },
235
236 /**
237 * @type {!Array} The selected items.
238 */
239 get selectedItems() {
240 return Object.keys(this.selectedItems_).map(function(uid) {
241 return this.selectedItems_[uid];
242 }, this);
243 },
244 set selectedItems(selectedItems) {
245 this.beginChange_();
246 this.clearAllSelected_();
247 for (var i = 0; i < selectedItems.length; i++) {
248 this.setItemSelected(selectedItems[i], true);
249 }
250 this.leadItem = this.anchorItem = selectedItems[0] || null;
251 this.endChange_();
252 },
253
254 /**
255 * Convenience getter which returns the first selected item.
256 * @type {*}
257 */
258 get selectedItem() {
259 for (var uid in this.selectedItems_) {
260 return this.selectedItems_[uid];
261 }
262 return null;
263 },
264 set selectedItem(selectedItem) {
265 this.beginChange_();
266 this.clearAllSelected_();
267 if (selectedItem) {
268 this.selectedItems = [selectedItem];
269 } else {
270 this.leadItem = this.anchorItem = null;
271 }
272 this.endChange_();
273 },
274
275 /**
276 * Selects a range of items, starting with {@code start} and ends with
277 * {@code end}.
278 * @param {*} start The first item to select.
279 * @param {*} end The last item to select.
280 */
281 selectRange: function(start, end) {
282 // Swap if starts comes after end.
283 if (start.compareDocumentPosition(end) & Node.DOCUMENT_POSITION_PRECEDING) {
284 var tmp = start;
285 start = end;
286 end = tmp;
287 }
288
289 this.beginChange_();
290
291 for (var item = start; item != end; item = this.getNextItem(item)) {
292 this.setItemSelected(item, true);
293 }
294 this.setItemSelected(end, true);
295
296 this.endChange_();
297 },
298
299 /**
300 * Selects all items.
301 */
302 selectAll: function() {
303 this.selectRange(this.getFirstItem(), this.getLastItem());
304 },
305
306 /**
307 * Clears the selection
308 */
309 clear: function() {
310 this.beginChange_();
311 this.clearAllSelected_();
312 this.endChange_();
313 },
314
315 /**
316 * Clears the selection and updates the view.
317 * @private
318 */
319 clearAllSelected_: function() {
320 for (var uid in this.selectedItems_) {
321 this.setItemSelected(this.selectedItems_[uid], false);
322 }
323 },
324
325 /**
326 * Sets the selecte state for an item.
327 * @param {*} item The item to set the selected state for.
328 * @param {boolean} b Whether to select the item or not.
329 */
330 setItemSelected: function(item, b) {
331 var uid = this.list.itemToUid(item);
332 var oldSelected = uid in this.selectedItems_;
333 if (oldSelected == b)
334 return;
335
336 if (b)
337 this.selectedItems_[uid] = item;
338 else
339 delete this.selectedItems_[uid];
340
341 this.beginChange_();
342
343 // Changing back?
344 if (uid in this.changedUids_ && this.changedUids_[uid] == !b) {
345 delete this.changedUids_[uid];
346 } else {
347 this.changedUids_[uid] = b;
348 }
349
350 // End change dispatches an event which in turn may update the view.
351 this.endChange_();
352 },
353
354 /**
355 * Whether a given item is selected or not.
356 * @param {*} item The item to check.
357 * @return {boolean} Whether an item is selected.
358 */
359 getItemSelected: function(item) {
360 var uid = this.list.itemToUid(item);
361 return uid in this.selectedItems_;
362 },
363
364 /**
365 * This is used to begin batching changes. Call {@code endChange_} when you
366 * are done making changes.
367 * @private
368 */
369 beginChange_: function() {
370 if (!this.changeCount_) {
371 this.changeCount_ = 0;
372 this.changedUids_ = {};
373 }
374 this.changeCount_++;
375 },
376
377 /**
378 * Call this after changes are done and it will dispatch a change event if
379 * any changes were actually done.
380 * @private
381 */
382 endChange_: function() {
383 this.changeCount_--;
384 if (!this.changeCount_) {
385 var uids = Object.keys(this.changedUids_);
386 if (uids.length) {
387 var e = new Event('change');
388 e.changes = uids.map(function(uid) {
389 return {
390 uid: uid,
391 selected: this.changedUids_[uid]
392 };
393 }, this);
394 this.dispatchEvent(e);
395 }
396 delete this.changedUids_;
397 delete this.changeCount_;
398 }
399 },
400
401 /**
402 * Called when an item is removed from the lisst.
403 * @param {cr.ui.ListItem} item The list item that was removed.
404 */
405 remove: function(item) {
406 if (item == this.leadItem)
407 this.leadItem = this.getNextItem(item) || this.getPreviousItem(item);
408 if (item == this.anchorItem)
409 this.anchorItem = this.getNextItem(item) || this.getPreviousItem(item);
410
411 // Deselect when removing items.
412 if (this.getItemSelected(item))
413 this.setItemSelected(item, false);
414 },
415
416 /**
417 * Called when an item was added to the list.
418 * @param {cr.ui.ListItem} item The list item to add.
419 */
420 add: function(item) {
421 // We could (should?) check if the item is selected here and update the
422 // selection model.
423 }
424 };
425
426 /**
427 * The anchorItem is used with multiple selection.
428 * @type {*}
429 */
430 cr.defineProperty(ListSelectionModel, 'anchorItem', cr.PropertyKind.JS, null);
431
432 /**
433 * The leadItem is used with multiple selection and it is the item that the
434 * user is moving uysing the arrow keys.
435 * @type {*}
436 */
437 cr.defineProperty(ListSelectionModel, 'leadItem', cr.PropertyKind.JS, null);
438
439 return {
440 ListSelectionModel: ListSelectionModel
441 };
442 });
OLDNEW
« no previous file with comments | « resources/bookmark_manager/js/cr/ui/listitem.js ('k') | resources/bookmark_manager/js/cr/ui/menu.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698