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

Side by Side Diff: chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js

Issue 1028513003: Decrease the lag when switching between different categories in the Cros wallpaper selector. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix the failed tests. Created 5 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
« no previous file with comments | « no previous file | chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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('wallpapers', function() { 5 cr.define('wallpapers', function() {
6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; 6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
7 /** @const */ var Grid = cr.ui.Grid; 7 /** @const */ var Grid = cr.ui.Grid;
8 /** @const */ var GridItem = cr.ui.GridItem; 8 /** @const */ var GridItem = cr.ui.GridItem;
9 /** @const */ var GridSelectionController = cr.ui.GridSelectionController; 9 /** @const */ var GridSelectionController = cr.ui.GridSelectionController;
10 /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel; 10 /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
11 /** @const */ var ThumbnailSuffix = '_thumbnail.png'; 11 /** @const */ var ThumbnailSuffix = '_thumbnail.png';
12 /** @const */ var ShowSpinnerDelayMs = 500; 12 /** @const */ var ShowSpinnerDelayMs = 500;
13 13
14 /** 14 /**
15 * Creates a new wallpaper thumbnails grid item. 15 * Creates a new wallpaper thumbnails grid item.
16 * @param {{baseURL: string, layout: string, source: string, 16 * @param {{wallpaperId: number, baseURL: string, layout: string,
17 * availableOffline: boolean, opt_dynamicURL: string, 17 * source: string, availableOffline: boolean,
18 * opt_author: string, opt_authorWebsite: string}} 18 * opt_dynamicURL: string, opt_author: string,
19 * opt_authorWebsite: string}}
19 * wallpaperInfo Wallpaper data item in WallpaperThumbnailsGrid's data 20 * wallpaperInfo Wallpaper data item in WallpaperThumbnailsGrid's data
20 * model. 21 * model.
21 * @param {number} dataModelId A unique ID that this item associated to. 22 * @param {number} dataModelId A unique ID that this item associated to.
23 * @param {object} thumbnail The thumbnail image Object associated with this
24 * grid item.
22 * @param {function} callback The callback function when decoration finished. 25 * @param {function} callback The callback function when decoration finished.
23 * @constructor 26 * @constructor
24 * @extends {cr.ui.GridItem} 27 * @extends {cr.ui.GridItem}
25 */ 28 */
26 function WallpaperThumbnailsGridItem(wallpaperInfo, dataModelId, callback) { 29 function WallpaperThumbnailsGridItem(wallpaperInfo,
30 dataModelId,
31 thumbnail,
32 callback) {
27 var el = new GridItem(wallpaperInfo); 33 var el = new GridItem(wallpaperInfo);
28 el.__proto__ = WallpaperThumbnailsGridItem.prototype; 34 el.__proto__ = WallpaperThumbnailsGridItem.prototype;
29 el.dataModelId = dataModelId; 35 el.dataModelId_ = dataModelId;
30 el.callback = callback; 36 el.thumbnail_ = thumbnail;
37 el.callback_ = callback;
31 return el; 38 return el;
32 } 39 }
33 40
34 WallpaperThumbnailsGridItem.prototype = { 41 WallpaperThumbnailsGridItem.prototype = {
35 __proto__: GridItem.prototype, 42 __proto__: GridItem.prototype,
36 43
37 /** 44 /**
38 * The unique ID this thumbnail grid associated to. 45 * The unique ID this thumbnail grid associated to.
39 * @type {number} 46 * @type {number}
40 */ 47 */
41 dataModelId: null, 48 dataModelId_: null,
49
50 /**
51 * The thumbnail image associated with the current grid item.
52 */
53 thumbnail_: null,
42 54
43 /** 55 /**
44 * Called when the WallpaperThumbnailsGridItem is decorated or failed to 56 * Called when the WallpaperThumbnailsGridItem is decorated or failed to
45 * decorate. If the decoration contains image, the callback function should 57 * decorate. If the decoration contains image, the callback function should
46 * be called after image loaded. 58 * be called after image loaded.
47 * @type {function} 59 * @type {function}
48 */ 60 */
49 callback: null, 61 callback_: null,
50 62
51 /** @override */ 63 /** @override */
52 decorate: function() { 64 decorate: function() {
53 GridItem.prototype.decorate.call(this); 65 GridItem.prototype.decorate.call(this);
54 // Removes garbage created by GridItem. 66 // Removes garbage created by GridItem.
55 this.innerText = ''; 67 this.innerText = '';
68
69 if (this.thumbnail_) {
70 this.appendChild(this.thumbnail_);
71 this.callback_(this.dataModelId_);
72 return;
73 }
74
56 var imageEl = cr.doc.createElement('img'); 75 var imageEl = cr.doc.createElement('img');
57 imageEl.classList.add('thumbnail'); 76 imageEl.classList.add('thumbnail');
58 cr.defineProperty(imageEl, 'offline', cr.PropertyKind.BOOL_ATTR); 77 cr.defineProperty(imageEl, 'offline', cr.PropertyKind.BOOL_ATTR);
59 imageEl.offline = this.dataItem.availableOffline; 78 imageEl.offline = this.dataItem.availableOffline;
60 this.appendChild(imageEl); 79 this.appendChild(imageEl);
61 var self = this; 80 var self = this;
62 81
63 switch (this.dataItem.source) { 82 switch (this.dataItem.source) {
64 case Constants.WallpaperSourceEnum.AddNew: 83 case Constants.WallpaperSourceEnum.AddNew:
65 this.id = 'add-new'; 84 this.id = 'add-new';
66 this.addEventListener('click', function(e) { 85 this.addEventListener('click', function(e) {
67 var checkbox = $('surprise-me').querySelector('#checkbox'); 86 var checkbox = $('surprise-me').querySelector('#checkbox');
68 if (!checkbox.classList.contains('checked')) 87 if (!checkbox.classList.contains('checked'))
69 $('wallpaper-selection-container').hidden = false; 88 $('wallpaper-selection-container').hidden = false;
70 }); 89 });
71 // Delay dispatching the completion callback until all items have 90 // Delay dispatching the completion callback until all items have
72 // begun loading and are tracked. 91 // begun loading and are tracked.
73 window.setTimeout(this.callback.bind(this, this.dataModelId), 0); 92 window.setTimeout(this.callback_.bind(this, this.dataModelId_), 0);
74 break; 93 break;
75 case Constants.WallpaperSourceEnum.Custom: 94 case Constants.WallpaperSourceEnum.Custom:
76 var errorHandler = function(e) { 95 var errorHandler = function(e) {
77 self.callback(self.dataModelId); 96 self.callback_(self.dataModelId_);
78 console.error('Can not access file system.'); 97 console.error('Can not access file system.');
79 }; 98 };
80 var wallpaperDirectories = WallpaperDirectories.getInstance(); 99 var wallpaperDirectories = WallpaperDirectories.getInstance();
81 var getThumbnail = function(fileName) { 100 var getThumbnail = function(fileName) {
82 var setURL = function(fileEntry) { 101 var setURL = function(fileEntry) {
83 imageEl.src = fileEntry.toURL(); 102 imageEl.src = fileEntry.toURL();
84 self.callback(self.dataModelId); 103 self.callback_(self.dataModelId_,
104 self.dataItem.wallpaperId,
105 imageEl);
85 }; 106 };
86 var fallback = function() { 107 var fallback = function() {
87 wallpaperDirectories.getDirectory( 108 wallpaperDirectories.getDirectory(
88 Constants.WallpaperDirNameEnum.ORIGINAL, function(dirEntry) { 109 Constants.WallpaperDirNameEnum.ORIGINAL, function(dirEntry) {
89 dirEntry.getFile(fileName, {create: false}, setURL, 110 dirEntry.getFile(fileName, {create: false}, setURL,
90 errorHandler); 111 errorHandler);
91 }, errorHandler); 112 }, errorHandler);
92 }; 113 };
93 var success = function(dirEntry) { 114 var success = function(dirEntry) {
94 dirEntry.getFile(fileName, {create: false}, setURL, fallback); 115 dirEntry.getFile(fileName, {create: false}, setURL, fallback);
95 }; 116 };
96 wallpaperDirectories.getDirectory( 117 wallpaperDirectories.getDirectory(
97 Constants.WallpaperDirNameEnum.THUMBNAIL, success, errorHandler); 118 Constants.WallpaperDirNameEnum.THUMBNAIL, success, errorHandler);
98 }; 119 };
99 getThumbnail(self.dataItem.baseURL); 120 getThumbnail(self.dataItem.baseURL);
100 break; 121 break;
101 case Constants.WallpaperSourceEnum.OEM: 122 case Constants.WallpaperSourceEnum.OEM:
102 case Constants.WallpaperSourceEnum.Online: 123 case Constants.WallpaperSourceEnum.Online:
103 chrome.wallpaperPrivate.getThumbnail(this.dataItem.baseURL, 124 chrome.wallpaperPrivate.getThumbnail(this.dataItem.baseURL,
104 this.dataItem.source, 125 this.dataItem.source,
105 function(data) { 126 function(data) {
106 if (data) { 127 if (data) {
107 var blob = new Blob([new Int8Array(data)], 128 var blob = new Blob([new Int8Array(data)],
108 {'type': 'image\/png'}); 129 {'type': 'image\/png'});
109 imageEl.src = window.URL.createObjectURL(blob); 130 imageEl.src = window.URL.createObjectURL(blob);
110 imageEl.addEventListener('load', function(e) { 131 imageEl.addEventListener('load', function(e) {
111 self.callback(self.dataModelId); 132 self.callback_(self.dataModelId_,
133 self.dataItem.wallpaperId,
134 imageEl);
112 window.URL.revokeObjectURL(this.src); 135 window.URL.revokeObjectURL(this.src);
113 }); 136 });
114 } else if (self.dataItem.source == 137 } else if (self.dataItem.source ==
115 Constants.WallpaperSourceEnum.Online) { 138 Constants.WallpaperSourceEnum.Online) {
116 var xhr = new XMLHttpRequest(); 139 var xhr = new XMLHttpRequest();
117 xhr.open('GET', self.dataItem.baseURL + ThumbnailSuffix, true); 140 xhr.open('GET', self.dataItem.baseURL + ThumbnailSuffix, true);
118 xhr.responseType = 'arraybuffer'; 141 xhr.responseType = 'arraybuffer';
119 xhr.send(null); 142 xhr.send(null);
120 xhr.addEventListener('load', function(e) { 143 xhr.addEventListener('load', function(e) {
121 if (xhr.status === 200) { 144 if (xhr.status === 200) {
122 chrome.wallpaperPrivate.saveThumbnail(self.dataItem.baseURL, 145 chrome.wallpaperPrivate.saveThumbnail(self.dataItem.baseURL,
123 xhr.response); 146 xhr.response);
124 var blob = new Blob([new Int8Array(xhr.response)], 147 var blob = new Blob([new Int8Array(xhr.response)],
125 {'type' : 'image\/png'}); 148 {'type' : 'image\/png'});
126 imageEl.src = window.URL.createObjectURL(blob); 149 imageEl.src = window.URL.createObjectURL(blob);
127 // TODO(bshe): We currently use empty div to reserve space for 150 // TODO(bshe): We currently use empty div to reserve space for
128 // thumbnail. Use a placeholder like "loading" image may 151 // thumbnail. Use a placeholder like "loading" image may
129 // better. 152 // better.
130 imageEl.addEventListener('load', function(e) { 153 imageEl.addEventListener('load', function(e) {
131 self.callback(self.dataModelId); 154 self.callback_(self.dataModelId_,
155 self.dataItem.wallpaperId,
156 this);
132 window.URL.revokeObjectURL(this.src); 157 window.URL.revokeObjectURL(this.src);
133 }); 158 });
134 } else { 159 } else {
135 self.callback(self.dataModelId); 160 self.callback_(self.dataModelId_);
136 } 161 }
137 }); 162 });
138 } 163 }
139 }); 164 });
140 break; 165 break;
141 default: 166 default:
142 console.error('Unsupported image source.'); 167 console.error('Unsupported image source.');
143 // Delay dispatching the completion callback until all items have 168 // Delay dispatching the completion callback until all items have
144 // begun loading and are tracked. 169 // begun loading and are tracked.
145 window.setTimeout(this.callback.bind(this, this.dataModelId), 0); 170 window.setTimeout(this.callback_.bind(this, this.dataModelId_), 0);
146 } 171 }
147 }, 172 },
148 }; 173 };
149 174
150 /** 175 /**
151 * Creates a selection controller that wraps selection on grid ends 176 * Creates a selection controller that wraps selection on grid ends
152 * and translates Enter presses into 'activate' events. 177 * and translates Enter presses into 'activate' events.
153 * @param {cr.ui.ListSelectionModel} selectionModel The selection model to 178 * @param {cr.ui.ListSelectionModel} selectionModel The selection model to
154 * interact with. 179 * interact with.
155 * @param {cr.ui.Grid} grid The grid to interact with. 180 * @param {cr.ui.Grid} grid The grid to interact with.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 * id wont increase if the new dataModel is null or empty. 257 * id wont increase if the new dataModel is null or empty.
233 */ 258 */
234 dataModelId_: 0, 259 dataModelId_: 0,
235 260
236 /** 261 /**
237 * The number of items that need to be generated after a new dataModel is 262 * The number of items that need to be generated after a new dataModel is
238 * set. 263 * set.
239 */ 264 */
240 pendingItems_: 0, 265 pendingItems_: 0,
241 266
267 /**
268 * Maintains all grid items' thumbnail images for quickly switching between
269 * different categories.
270 */
271 thumbnailList_: undefined,
272
242 /** @override */ 273 /** @override */
243 set dataModel(dataModel) { 274 set dataModel(dataModel) {
244 if (this.dataModel_ == dataModel) 275 if (this.dataModel_ == dataModel)
245 return; 276 return;
246 277
247 if (dataModel && dataModel.length != 0) { 278 if (dataModel && dataModel.length != 0) {
248 this.dataModelId_++; 279 this.dataModelId_++;
249 // Clears old pending items. The new pending items will be counted when 280 // Clears old pending items. The new pending items will be counted when
250 // item is constructed in function itemConstructor below. 281 // item is constructed in function itemConstructor below.
251 this.pendingItems_ = 0; 282 this.pendingItems_ = 0;
(...skipping 23 matching lines...) Expand all
275 createSelectionController: function(sm) { 306 createSelectionController: function(sm) {
276 return new WallpaperThumbnailsGridSelectionController(sm, this); 307 return new WallpaperThumbnailsGridSelectionController(sm, this);
277 }, 308 },
278 309
279 /** 310 /**
280 * Check if new thumbnail grid finished loading. This reduces the count of 311 * Check if new thumbnail grid finished loading. This reduces the count of
281 * remaining items to be loaded and when 0, shows the thumbnail grid. Note 312 * remaining items to be loaded and when 0, shows the thumbnail grid. Note
282 * it does not reduce the count on a previous |dataModelId|. 313 * it does not reduce the count on a previous |dataModelId|.
283 * @param {number} dataModelId A unique ID that a thumbnail item is 314 * @param {number} dataModelId A unique ID that a thumbnail item is
284 * associated to. 315 * associated to.
316 * @param {number} opt_wallpaperId The unique wallpaper ID that associated
317 * with this thumbnail gird item.
318 * @param {object} opt_thumbnail The thumbnail image that associated with
319 * the opt_wallpaperId.
285 */ 320 */
286 pendingItemComplete: function(dataModelId) { 321 pendingItemComplete: function(dataModelId,
322 opt_wallpaperId,
323 opt_thumbnail) {
287 if (dataModelId != this.dataModelId_) 324 if (dataModelId != this.dataModelId_)
288 return; 325 return;
289 this.pendingItems_--; 326 this.pendingItems_--;
327 if (opt_wallpaperId != null)
328 this.thumbnailList_[opt_wallpaperId] = opt_thumbnail;
290 if (this.pendingItems_ == 0) { 329 if (this.pendingItems_ == 0) {
291 this.style.visibility = 'visible'; 330 this.style.visibility = 'visible';
292 window.clearTimeout(this.spinnerTimeout_); 331 window.clearTimeout(this.spinnerTimeout_);
293 this.spinnerTimeout_ = 0; 332 this.spinnerTimeout_ = 0;
294 $('spinner-container').hidden = true; 333 $('spinner-container').hidden = true;
295 } 334 }
296 }, 335 },
297 336
298 /** @override */ 337 /** @override */
299 decorate: function() { 338 decorate: function() {
300 Grid.prototype.decorate.call(this); 339 Grid.prototype.decorate.call(this);
301 // checkmark_ needs to be initialized before set data model. Otherwise, we 340 // checkmark_ needs to be initialized before set data model. Otherwise, we
302 // may try to access checkmark before initialization in 341 // may try to access checkmark before initialization in
303 // updateActiveThumb_(). 342 // updateActiveThumb_().
304 this.checkmark_ = cr.doc.createElement('div'); 343 this.checkmark_ = cr.doc.createElement('div');
305 this.checkmark_.classList.add('check'); 344 this.checkmark_.classList.add('check');
306 this.dataModel = new ArrayDataModel([]); 345 this.dataModel = new ArrayDataModel([]);
346 this.thumbnailList_ = new ArrayDataModel([]);
307 var self = this; 347 var self = this;
308 this.itemConstructor = function(value) { 348 this.itemConstructor = function(value) {
309 var dataModelId = self.dataModelId_; 349 var dataModelId = self.dataModelId_;
310 self.pendingItems_++; 350 self.pendingItems_++;
311 return WallpaperThumbnailsGridItem(value, dataModelId, 351 return WallpaperThumbnailsGridItem(value, dataModelId,
352 self.thumbnailList_[value.wallpaperId],
312 self.pendingItemComplete.bind(self)); 353 self.pendingItemComplete.bind(self));
313 }; 354 };
314 this.selectionModel = new ListSingleSelectionModel(); 355 this.selectionModel = new ListSingleSelectionModel();
315 this.inProgramSelection_ = false; 356 this.inProgramSelection_ = false;
316 }, 357 },
317 358
318 /** 359 /**
319 * Should only be queried from the 'change' event listener, true if the 360 * Should only be queried from the 'change' event listener, true if the
320 * change event was triggered by a programmatical selection change. 361 * change event was triggered by a programmatical selection change.
321 * @type {boolean} 362 * @type {boolean}
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 // The active thumbnail maybe deleted in the above redraw(). Sets it again 431 // The active thumbnail maybe deleted in the above redraw(). Sets it again
391 // to make sure checkmark shows correctly. 432 // to make sure checkmark shows correctly.
392 this.updateActiveThumb_(); 433 this.updateActiveThumb_();
393 } 434 }
394 }; 435 };
395 436
396 return { 437 return {
397 WallpaperThumbnailsGrid: WallpaperThumbnailsGrid 438 WallpaperThumbnailsGrid: WallpaperThumbnailsGrid
398 }; 439 };
399 }); 440 });
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698