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

Side by Side Diff: ui/file_manager/gallery/js/gallery.js

Issue 470983002: Gallery: Load gallery items by chunk on startup. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed. Created 6 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | ui/file_manager/gallery/js/mosaic_mode.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 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 'use strict'; 5 'use strict';
6 6
7 /** 7 /**
8 * Called from the main frame when unloading. 8 * Called from the main frame when unloading.
9 * @param {boolean=} opt_exiting True if the app is exiting. 9 * @param {boolean=} opt_exiting True if the app is exiting.
10 */ 10 */
11 function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting); } 11 function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting); }
12 12
13 /** 13 /**
14 * Overrided metadata worker's path. 14 * Overrided metadata worker's path.
15 * @type {string} 15 * @type {string}
16 * @const 16 * @const
17 */ 17 */
18 ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; 18 ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js';
19 19
20 /** 20 /**
21 * Data model for gallery. 21 * Data model for gallery.
22 * 22 *
23 * @param {MetadataCache} metadataCache Metadata cache.
23 * @constructor 24 * @constructor
24 * @extends {cr.ui.ArrayDataModel} 25 * @extends {cr.ui.ArrayDataModel}
25 */ 26 */
26 function GalleryDataModel() { 27 function GalleryDataModel(metadataCache) {
27 cr.ui.ArrayDataModel.call(this, []); 28 cr.ui.ArrayDataModel.call(this, []);
28 this.metadataCache_ = null; 29 this.metadataCache_ = metadataCache;
29 } 30 }
30 31
31 /** 32 /**
32 * Maximum number of full size image cache. 33 * Maximum number of full size image cache.
33 * @type {number} 34 * @type {number}
34 * @const 35 * @const
35 * @private 36 * @private
36 */ 37 */
37 GalleryDataModel.MAX_FULL_IMAGE_CACHE_ = 3; 38 GalleryDataModel.MAX_FULL_IMAGE_CACHE_ = 3;
38 39
39 /** 40 /**
40 * Maximum number of screen size image cache. 41 * Maximum number of screen size image cache.
41 * @type {number} 42 * @type {number}
42 * @const 43 * @const
43 * @private 44 * @private
44 */ 45 */
45 GalleryDataModel.MAX_SCREEN_IMAGE_CACHE_ = 5; 46 GalleryDataModel.MAX_SCREEN_IMAGE_CACHE_ = 5;
46 47
47 GalleryDataModel.prototype = { 48 GalleryDataModel.prototype = {
48 __proto__: cr.ui.ArrayDataModel.prototype 49 __proto__: cr.ui.ArrayDataModel.prototype
49 }; 50 };
50 51
51 /** 52 /**
52 * Initializes the data model.
53 *
54 * @param {MetadataCache} metadataCache Metadata cache.
55 * @param {Array.<FileEntry>} entries Image entries.
56 * @return {Promise} Promise to be fulfilled with after initialization.
57 */
58 GalleryDataModel.prototype.initialize = function(metadataCache, entries) {
59 // Store metadata cache.
60 this.metadataCache_ = metadataCache;
61
62 // Obtain metadata.
63 var metadataPromise = new Promise(function(fulfill) {
64 this.metadataCache_.get(entries, Gallery.METADATA_TYPE, fulfill);
65 }.bind(this));
66
67 // Initialize the gallery by using the metadata.
68 return metadataPromise.then(function(metadata) {
69 // Check the length of metadata.
70 if (entries.length !== metadata.length)
71 return Promise.reject('Failed to obtain metadata for the entries.');
72
73 // Obtains items.
74 var items = entries.map(function(entry, i) {
75 var clonedMetadata = MetadataCache.cloneMetadata(metadata[i]);
76 return new Gallery.Item(
77 entry, clonedMetadata, metadataCache, /* original */ true);
78 });
79
80 // Update the models.
81 this.push.apply(this, items);
82 }.bind(this));
83 };
84
85 /**
86 * Saves new image. 53 * Saves new image.
87 * 54 *
88 * @param {Gallery.Item} item Original gallery item. 55 * @param {Gallery.Item} item Original gallery item.
89 * @param {Canvas} canvas Canvas containing new image. 56 * @param {Canvas} canvas Canvas containing new image.
90 * @param {boolean} overwrite Whether to overwrite the image to the item or not. 57 * @param {boolean} overwrite Whether to overwrite the image to the item or not.
91 * @return {Promise} Promise to be fulfilled with when the operation completes. 58 * @return {Promise} Promise to be fulfilled with when the operation completes.
92 */ 59 */
93 GalleryDataModel.prototype.saveItem = function(item, canvas, overwrite) { 60 GalleryDataModel.prototype.saveItem = function(item, canvas, overwrite) {
94 var oldEntry = item.getEntry(); 61 var oldEntry = item.getEntry();
95 var oldMetadata = item.getMetadata(); 62 var oldMetadata = item.getMetadata();
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 loadTimeData: {} 183 loadTimeData: {}
217 }; 184 };
218 this.container_ = document.querySelector('.gallery'); 185 this.container_ = document.querySelector('.gallery');
219 this.document_ = document; 186 this.document_ = document;
220 this.metadataCache_ = this.context_.metadataCache; 187 this.metadataCache_ = this.context_.metadataCache;
221 this.volumeManager_ = volumeManager; 188 this.volumeManager_ = volumeManager;
222 this.selectedEntry_ = null; 189 this.selectedEntry_ = null;
223 this.metadataCacheObserverId_ = null; 190 this.metadataCacheObserverId_ = null;
224 this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this); 191 this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this);
225 192
226 this.dataModel_ = new GalleryDataModel(); 193 this.dataModel_ = new GalleryDataModel(this.context_.metadataCache);
227 this.selectionModel_ = new cr.ui.ListSelectionModel(); 194 this.selectionModel_ = new cr.ui.ListSelectionModel();
228 195
229 this.initDom_(); 196 this.initDom_();
230 this.initListeners_(); 197 this.initListeners_();
231 } 198 }
232 199
233 /** 200 /**
234 * Gallery extends cr.EventTarget. 201 * Gallery extends cr.EventTarget.
235 */ 202 */
236 Gallery.prototype.__proto__ = cr.EventTarget.prototype; 203 Gallery.prototype.__proto__ = cr.EventTarget.prototype;
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 return button; 396 return button;
430 }; 397 };
431 398
432 /** 399 /**
433 * Loads the content. 400 * Loads the content.
434 * 401 *
435 * @param {!Array.<Entry>} entries Array of entries. 402 * @param {!Array.<Entry>} entries Array of entries.
436 * @param {!Array.<Entry>} selectedEntries Array of selected entries. 403 * @param {!Array.<Entry>} selectedEntries Array of selected entries.
437 */ 404 */
438 Gallery.prototype.load = function(entries, selectedEntries) { 405 Gallery.prototype.load = function(entries, selectedEntries) {
439 this.dataModel_.initialize(this.metadataCache_, entries).then(function() { 406 // Obtains max chank size.
440 // Apply selection. 407 var maxChunkSize = 20;
441 this.selectionModel_.adjustLength(this.dataModel_.length); 408 var volumeInfo = this.volumeManager_.getVolumeInfo(entries[0]);
442 var entryIndexesByURLs = {}; 409 if (volumeInfo &&
443 for (var index = 0; index < entries.length; index++) { 410 volumeInfo.volumeType === VolumeManagerCommon.VolumeType.MTP) {
444 entryIndexesByURLs[entries[index].toURL()] = index; 411 maxChunkSize = 1;
445 } 412 }
446 for (var i = 0; i !== selectedEntries.length; i++) {
447 var selectedIndex = entryIndexesByURLs[selectedEntries[i].toURL()];
448 if (selectedIndex !== undefined)
449 this.selectionModel_.setIndexSelected(selectedIndex, true);
450 else
451 console.error('Cannot select ' + selectedEntries[i]);
452 }
453 if (this.selectionModel_.selectedIndexes.length === 0)
454 this.onSelection_();
455 413
456 // Determine the initial mode. 414 // Make loading list.
457 var shouldShowMosaic = selectedEntries.length > 1 || 415 var entrySet = {};
458 (this.context_.pageState && 416 for (var i = 0; i < entries.length; i++) {
459 this.context_.pageState.gallery === 'mosaic'); 417 var entry = entries[i];
460 this.setCurrentMode_(shouldShowMosaic ? this.mosaicMode_ : this.slideMode_); 418 entrySet[entry.toURL()] = {
419 entry: entry,
420 selected: false,
421 index: i
422 };
423 }
424 for (var i = 0; i < selectedEntries.length; i++) {
425 var entry = selectedEntries[i];
426 entrySet[entry.toURL()] = {
427 entry: entry,
428 selected: true,
429 index: i
430 };
431 }
432 var loadingList = [];
433 for (var url in entrySet) {
434 loadingList.push(entrySet[url]);
435 }
436 loadingList = loadingList.sort(function(a, b) {
437 if (a.selected && !b.selected)
438 return -1;
439 else if (!a.selected && b.selected)
440 return 1;
441 else
442 return a.index - b.index;
443 });
461 444
462 // Init mosaic mode. 445 // Load entries.
463 var mosaic = this.mosaicMode_.getMosaic(); 446 // Use the self variable capture-by-closure because it is faster than bind.
464 mosaic.init(); 447 var self = this;
448 var loadChunk = function(firstChunk) {
449 // Extract chunk.
450 var chunk = loadingList.splice(0, maxChunkSize);
451 if (!chunk.length)
452 return;
465 453
466 // Do the initialization for each mode. 454 return new Promise(function(fulfill) {
467 if (shouldShowMosaic) { 455 // Obtains metadata for chunk.
468 mosaic.show(); 456 var entries = chunk.map(function(chunkItem) {
469 this.inactivityWatcher_.check(); // Show the toolbar. 457 return chunkItem.entry;
470 cr.dispatchSimpleEvent(this, 'loaded'); 458 });
471 } else { 459 self.metadataCache_.get(entries, Gallery.METADATA_TYPE, fulfill);
472 this.slideMode_.enter( 460 }).then(function(metadataList) {
473 null, 461 if (chunk.length !== metadataList.length)
474 function() { 462 return Promise.reject('Failed to load metadata.');
475 // Flash the toolbar briefly to show it is there. 463
476 this.inactivityWatcher_.kick(Gallery.FIRST_FADE_TIMEOUT); 464 // Add items to the model.
477 }.bind(this), 465 var items = chunk.map(function(chunkItem, index) {
478 function() { 466 var clonedMetadata = MetadataCache.cloneMetadata(metadataList[index]);
479 cr.dispatchSimpleEvent(this, 'loaded'); 467 return new Gallery.Item(
480 }.bind(this)); 468 chunkItem.entry,
481 } 469 clonedMetadata,
482 }.bind(this)).catch(function(error) { 470 self.metadataCache_,
471 /* original */ true);
472 });
473 self.dataModel_.push.apply(self.dataModel_, items);
474
475 // Apply the selection.
476 var selectionUpdated = false;
477 for (var i = 0; i < chunk.length; i++) {
478 if (!chunk[i].selected)
479 continue;
480 var index = self.dataModel_.indexOf(items[i]);
481 if (index < 0)
482 continue;
483 self.selectionModel_.setIndexSelected(index);
484 selectionUpdated = true;
485 }
486 if (selectionUpdated)
487 self.onSelection_();
488
489 // Init modes after the first chunk is loaded.
490 if (firstChunk) {
491 // Determine the initial mode.
492 var shouldShowMosaic = selectedEntries.length > 1 ||
493 (self.context_.pageState &&
494 self.context_.pageState.gallery === 'mosaic');
495 self.setCurrentMode_(
496 shouldShowMosaic ? self.mosaicMode_ : self.slideMode_);
497
498 // Init mosaic mode.
499 var mosaic = self.mosaicMode_.getMosaic();
500 mosaic.init();
501
502 // Do the initialization for each mode.
503 if (shouldShowMosaic) {
504 mosaic.show();
505 self.inactivityWatcher_.check(); // Show the toolbar.
506 cr.dispatchSimpleEvent(self, 'loaded');
507 } else {
508 self.slideMode_.enter(
509 null,
510 function() {
511 // Flash the toolbar briefly to show it is there.
512 self.inactivityWatcher_.kick(Gallery.FIRST_FADE_TIMEOUT);
513 },
514 function() {
515 cr.dispatchSimpleEvent(self, 'loaded');
516 });
517 }
518 }
519
520 // Continue to load chunks.
521 return loadChunk(/* firstChunk */ false);
522 });
523 };
524 loadChunk(/* firstChunk */ true).catch(function(error) {
483 console.error(error.stack || error); 525 console.error(error.stack || error);
484 }); 526 });
485 }; 527 };
486 528
487 /** 529 /**
488 * Handles user's 'Close' action. 530 * Handles user's 'Close' action.
489 * @private 531 * @private
490 */ 532 */
491 Gallery.prototype.onClose_ = function() { 533 Gallery.prototype.onClose_ = function() {
492 this.executeWhenReady(this.context_.onClose); 534 this.executeWhenReady(this.context_.onClose);
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after
941 window.loadTimeData.data = backgroundComponents.stringData; 983 window.loadTimeData.data = backgroundComponents.stringData;
942 gallery = new Gallery(backgroundComponents.volumeManager); 984 gallery = new Gallery(backgroundComponents.volumeManager);
943 }; 985 };
944 986
945 /** 987 /**
946 * Loads entries. 988 * Loads entries.
947 */ 989 */
948 window.loadEntries = function(entries, selectedEntries) { 990 window.loadEntries = function(entries, selectedEntries) {
949 gallery.load(entries, selectedEntries); 991 gallery.load(entries, selectedEntries);
950 }; 992 };
OLDNEW
« no previous file with comments | « no previous file | ui/file_manager/gallery/js/mosaic_mode.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698