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

Unified Diff: chrome/browser/resources/file_manager/js/photo/mosaic_mode.js

Issue 12316118: Enabled Mosaic view on each volume. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased. Created 7 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/resources/file_manager/js/photo/gallery.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
diff --git a/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js b/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
index 16036d09766dcc0d9c9e9d4a42b017aa0ae87c4b..e1dd380f70bbe7813483bcef57a581fad2c2fd95 100644
--- a/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
+++ b/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
@@ -85,12 +85,16 @@ Mosaic.prototype.__proto__ = HTMLDivElement.prototype;
/**
* Default layout delay in ms.
+ * @const
+ * @type {number}
*/
Mosaic.LAYOUT_DELAY = 200;
/**
* Smooth scroll animation duration when scrolling using keyboard or
* clicking on a partly visible tile. In ms.
+ * @const
+ * @type {number}
*/
Mosaic.ANIMATED_SCROLL_DURATION = 500;
@@ -137,7 +141,7 @@ Mosaic.prototype.init = function() {
this.tiles_[index].select(true);
}.bind(this));
- this.loadTiles_(this.tiles_);
+ this.initTiles_(this.tiles_);
// The listeners might be called while some tiles are still loading.
this.initListeners_();
@@ -166,6 +170,7 @@ Mosaic.prototype.initListeners_ = function() {
this.addEventListener('mousemove', mouseEventBound);
this.addEventListener('mousedown', mouseEventBound);
this.addEventListener('mouseup', mouseEventBound);
+ this.addEventListener('scroll', this.onScroll_.bind(this));
this.selectionModel_.addEventListener('change', this.onSelection_.bind(this));
this.selectionModel_.addEventListener('leadIndexChange',
@@ -261,13 +266,13 @@ Mosaic.prototype.scrollIntoView = function(index) {
};
/**
- * Load multiple tiles.
+ * Initializes multiple tiles.
*
* @param {Array.<Mosaic.Tile>} tiles Array of tiles.
- * @param {function=} opt_callback Completion callback.
+ * @param {function()=} opt_callback Completion callback.
* @private
*/
-Mosaic.prototype.loadTiles_ = function(tiles, opt_callback) {
+Mosaic.prototype.initTiles_ = function(tiles, opt_callback) {
// We do not want to use tile indices in asynchronous operations because they
// do not survive data model splices. Copy tile references instead.
tiles = tiles.slice();
@@ -283,7 +288,7 @@ Mosaic.prototype.loadTiles_ = function(tiles, opt_callback) {
var chunkSize = Math.min(tiles.length, MAX_CHUNK_SIZE);
var loaded = 0;
for (var i = 0; i != chunkSize; i++) {
- this.loadTile_(tiles.shift(), function() {
+ this.initTile_(tiles.shift(), function() {
if (++loaded == chunkSize) {
this.layout();
loadChunk();
@@ -296,22 +301,19 @@ Mosaic.prototype.loadTiles_ = function(tiles, opt_callback) {
};
/**
- * Load a single tile.
+ * Initializes a single tile.
*
* @param {Mosaic.Tile} tile Tile.
- * @param {function} callback Completion callback.
+ * @param {function()} callback Completion callback.
* @private
*/
-Mosaic.prototype.loadTile_ = function(tile, callback) {
+Mosaic.prototype.initTile_ = function(tile, callback) {
var url = tile.getItem().getUrl();
- var onImageLoaded = function(success) {
- if (!success && this.onThumbnailError_) {
- this.onThumbnailError_(url);
- }
- callback();
- }.bind(this);
+ var onImageMeasured = callback;
this.metadataCache_.get(url, Gallery.METADATA_TYPE,
- function(metadata) { tile.load(metadata, onImageLoaded) });
+ function(metadata) {
+ tile.init(metadata, onImageMeasured);
+ });
};
/**
@@ -320,7 +322,7 @@ Mosaic.prototype.loadTile_ = function(tile, callback) {
Mosaic.prototype.reload = function() {
this.layoutModel_.reset_();
this.tiles_.forEach(function(t) { t.markUnloaded() });
- this.loadTiles_(this.tiles_);
+ this.initTiles_(this.tiles_);
};
/**
@@ -339,10 +341,11 @@ Mosaic.prototype.layout = function() {
if (index == this.tiles_.length)
break; // All tiles done.
var tile = this.tiles_[index];
- if (!tile.isLoaded())
+ if (!tile.isInitialized())
break; // Next layout will try to restart from here.
this.layoutModel_.add(tile, index + 1 == this.tiles_.length);
}
+ this.loadVisibleTiles_();
};
/**
@@ -397,6 +400,14 @@ Mosaic.prototype.onMouseEvent_ = function(event) {
};
/**
+ * Scroll handler.
+ * @private
+ */
+Mosaic.prototype.onScroll_ = function() {
+ this.loadVisibleTiles_();
+};
+
+/**
* Selection change handler.
*
* @param {Event} event Event.
@@ -448,7 +459,7 @@ Mosaic.prototype.onSplice_ = function(event) {
newTiles.push(new Mosaic.Tile(this, this.dataModel_.item(index + t)));
this.tiles_.splice.apply(this.tiles_, [index, 0].concat(newTiles));
- this.loadTiles_(newTiles);
+ this.initTiles_(newTiles);
}
if (this.tiles_.length != this.dataModel_.length)
@@ -473,8 +484,11 @@ Mosaic.prototype.onContentChange_ = function(event) {
console.error('Content changed for unselected item');
this.layoutModel_.invalidateFromTile_(index);
- this.tiles_[index].load(
- event.metadata, this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY));
+ this.tiles_[index].init(event.metadata, function() {
+ this.tiles_[index].load(
+ this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY),
+ this.onThumbnailError_);
+ }.bind(this));
};
/**
@@ -528,6 +542,29 @@ Mosaic.prototype.hide = function() {
};
/**
+ * Loads visible tiles. Ignores consecutive calls. Does not reload already
+ * loaded images.
+ * @private
+ */
+Mosaic.prototype.loadVisibleTiles_ = function() {
+ if (this.loadVisibleTilesTimer_) {
+ clearTimeout(this.loadVisibleTilesTimer_);
+ this.loadVisibleTilesTimer_ = null;
+ }
+ this.loadVisibleTilesTimer_ = setTimeout(function() {
+ var viewportRect = new Rect(0, 0, this.clientWidth, this.clientHeight);
+ for (var index = 0; index < this.tiles_.length; index++) {
+ var tile = this.tiles_[index];
+ var imageRect = tile.getImageRect();
+ if (!tile.isLoading() && !tile.isLoaded() && imageRect &&
+ imageRect.intersects(viewportRect)) {
+ tile.load(function() {}, this.onThumbnailError_);
+ }
+ }
+ }.bind(this), 100);
+};
+
+/**
* Apply or reset the zoom transform.
*
* @param {Rect} tileRect Tile rectangle. Reset the transform if null.
@@ -1588,54 +1625,107 @@ Mosaic.Tile.prototype.getMaxContentHeight = function() {
Mosaic.Tile.prototype.getAspectRatio = function() { return this.aspectRatio_ };
/**
+ * @return {boolean} True if the tile is initialized.
+ */
+Mosaic.Tile.prototype.isInitialized = function() {
+ return !!this.maxContentHeight_;
+};
+
+/**
* @return {boolean} True if the tile is loaded.
*/
-Mosaic.Tile.prototype.isLoaded = function() { return !!this.maxContentHeight_ };
+Mosaic.Tile.prototype.isLoaded = function() {
+ return this.imageLoaded_;
+};
+
+/**
+ * @return {boolean} True if the tile is being loaded.
+ */
+Mosaic.Tile.prototype.isLoading = function() {
+ return this.imageLoading_;
+};
/**
* Mark the tile as not loaded to prevent it from participating in the layout.
*/
Mosaic.Tile.prototype.markUnloaded = function() {
this.maxContentHeight_ = 0;
+ if (this.thumbnailLoader_) {
+ this.thumbnailLoader_.cancel();
+ this.imageLoaded_ = false;
+ this.imageLoading_ = false;
+ }
};
/**
- * Load the thumbnail image into the tile.
+ * Initializes the thumbnail in the tile. Does not load an image, but sets
+ * target dimensions using metadata.
*
* @param {Object} metadata Metadata object.
- * @param {function} callback Completion callback.
+ * @param {function()} onImageMeasured Image measured callback.
*/
-Mosaic.Tile.prototype.load = function(metadata, callback) {
+Mosaic.Tile.prototype.init = function(metadata, onImageMeasured) {
this.markUnloaded();
this.left_ = null; // Mark as not laid out.
- this.thumbnailLoader_ = new ThumbnailLoader(this.getItem().getUrl(),
- ThumbnailLoader.LoaderType.CANVAS,
- metadata);
-
- this.thumbnailLoader_.loadDetachedImage(function(success) {
- if (this.thumbnailLoader_.hasValidImage()) {
- var width = this.thumbnailLoader_.getWidth();
- var height = this.thumbnailLoader_.getHeight();
- if (width > height) {
- if (width > Mosaic.Tile.MAX_CONTENT_SIZE) {
- height = Math.round(height * Mosaic.Tile.MAX_CONTENT_SIZE / width);
- width = Mosaic.Tile.MAX_CONTENT_SIZE;
- }
- } else {
- if (height > Mosaic.Tile.MAX_CONTENT_SIZE) {
- width = Math.round(width * Mosaic.Tile.MAX_CONTENT_SIZE / height);
- height = Mosaic.Tile.MAX_CONTENT_SIZE;
- }
+ this.thumbnailLoader_ = new ThumbnailLoader(
+ this.getItem().getUrl(),
+ ThumbnailLoader.LoaderType.CANVAS,
+ metadata,
+ undefined, // Media type.
+ ThumbnailLoader.UseEmbedded.NO_EMBEDDED);
+
+ var setDimensions = function(width, height) {
+ if (width > height) {
+ if (width > Mosaic.Tile.MAX_CONTENT_SIZE) {
+ height = Math.round(height * Mosaic.Tile.MAX_CONTENT_SIZE / width);
+ width = Mosaic.Tile.MAX_CONTENT_SIZE;
}
- this.maxContentHeight_ = Math.max(Mosaic.Tile.MIN_CONTENT_SIZE, height);
- this.aspectRatio_ = width / height;
} else {
- this.maxContentHeight_ = Mosaic.Tile.GENERIC_ICON_SIZE;
- this.aspectRatio_ = 1;
+ if (height > Mosaic.Tile.MAX_CONTENT_SIZE) {
+ width = Math.round(width * Mosaic.Tile.MAX_CONTENT_SIZE / height);
+ height = Mosaic.Tile.MAX_CONTENT_SIZE;
+ }
}
+ this.maxContentHeight_ = Math.max(Mosaic.Tile.MIN_CONTENT_SIZE, height);
+ this.aspectRatio_ = width / height;
+ onImageMeasured();
+ }.bind(this);
- callback(success);
+ // Dimensions are always acquired from the metadata. If it is not available,
+ // then the image will not be displayed.
+ if (metadata.media && metadata.media.width) {
+ setDimensions(metadata.media.width, metadata.media.height);
+ } else {
+ // No dimensions in metadata, then display the generic icon instead.
+ // TODO(mtomasz): Display a gneric icon instead of a black rectangle.
+ setDimensions(Mosaic.Tile.GENERIC_ICON_SIZE,
+ Mosaic.Tile.GENERIC_ICON_SIZE);
+ }
+};
+
+/**
+ * Loads an image into the tile.
+ *
+ * @param {function(boolean)} onImageLoaded Callback when image is loaded.
+ * The argument is true for success, false for failure.
+ * @param {function()=} opt_onThumbnailError Callback for image loading error.
+ */
+Mosaic.Tile.prototype.load = function(onImageLoaded, opt_onThumbnailError) {
+ this.imageLoaded_ = false;
+ this.imageLoading_ = true;
+ this.thumbnailLoader_.loadDetachedImage(function(success) {
+ if (!success) {
+ if (opt_onThumbnailError)
+ opt_onThumbnailError();
+ }
+ if (this.wrapper_) {
+ this.thumbnailLoader_.attachImage(this.wrapper_,
+ ThumbnailLoader.FillMode.FILL);
+ }
+ onImageLoaded(success);
+ this.imageLoaded_ = true;
+ this.imageLoading_ = false;
}.bind(this));
};
@@ -1678,8 +1768,10 @@ Mosaic.Tile.prototype.layout = function(left, top, width, height) {
if (this.hasAttribute('selected'))
this.scrollIntoView(false);
- this.thumbnailLoader_.attachImage(this.wrapper_,
- ThumbnailLoader.FillMode.FILL);
+ if (this.imageLoaded_) {
+ this.thumbnailLoader_.attachImage(this.wrapper_,
+ ThumbnailLoader.FillMode.FILL);
+ }
};
/**
« no previous file with comments | « chrome/browser/resources/file_manager/js/photo/gallery.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698