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

Side by Side 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, 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
« no previous file with comments | « chrome/browser/resources/file_manager/js/photo/gallery.js ('k') | no next file » | 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) 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 /** 5 /**
6 * @param {Element} container Content container. 6 * @param {Element} container Content container.
7 * @param {cr.ui.ArrayDataModel} dataModel Data model. 7 * @param {cr.ui.ArrayDataModel} dataModel Data model.
8 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. 8 * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
9 * @param {MetadataCache} metadataCache Metadata cache. 9 * @param {MetadataCache} metadataCache Metadata cache.
10 * @param {function} toggleMode Function to switch to the Slide mode. 10 * @param {function} toggleMode Function to switch to the Slide mode.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 return self; 78 return self;
79 } 79 }
80 80
81 /** 81 /**
82 * Inherit from HTMLDivElement. 82 * Inherit from HTMLDivElement.
83 */ 83 */
84 Mosaic.prototype.__proto__ = HTMLDivElement.prototype; 84 Mosaic.prototype.__proto__ = HTMLDivElement.prototype;
85 85
86 /** 86 /**
87 * Default layout delay in ms. 87 * Default layout delay in ms.
88 * @const
89 * @type {number}
88 */ 90 */
89 Mosaic.LAYOUT_DELAY = 200; 91 Mosaic.LAYOUT_DELAY = 200;
90 92
91 /** 93 /**
92 * Smooth scroll animation duration when scrolling using keyboard or 94 * Smooth scroll animation duration when scrolling using keyboard or
93 * clicking on a partly visible tile. In ms. 95 * clicking on a partly visible tile. In ms.
96 * @const
97 * @type {number}
94 */ 98 */
95 Mosaic.ANIMATED_SCROLL_DURATION = 500; 99 Mosaic.ANIMATED_SCROLL_DURATION = 500;
96 100
97 /** 101 /**
98 * Decorate a Mosaic instance. 102 * Decorate a Mosaic instance.
99 * 103 *
100 * @param {Mosaic} self Self pointer. 104 * @param {Mosaic} self Self pointer.
101 * @param {cr.ui.ArrayDataModel} dataModel Data model. 105 * @param {cr.ui.ArrayDataModel} dataModel Data model.
102 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. 106 * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
103 * @param {MetadataCache} metadataCache Metadata cache. 107 * @param {MetadataCache} metadataCache Metadata cache.
(...skipping 26 matching lines...) Expand all
130 new Mosaic.SelectionController(this.selectionModel_, this.layoutModel_); 134 new Mosaic.SelectionController(this.selectionModel_, this.layoutModel_);
131 135
132 this.tiles_ = []; 136 this.tiles_ = [];
133 for (var i = 0; i != this.dataModel_.length; i++) 137 for (var i = 0; i != this.dataModel_.length; i++)
134 this.tiles_.push(new Mosaic.Tile(this, this.dataModel_.item(i))); 138 this.tiles_.push(new Mosaic.Tile(this, this.dataModel_.item(i)));
135 139
136 this.selectionModel_.selectedIndexes.forEach(function(index) { 140 this.selectionModel_.selectedIndexes.forEach(function(index) {
137 this.tiles_[index].select(true); 141 this.tiles_[index].select(true);
138 }.bind(this)); 142 }.bind(this));
139 143
140 this.loadTiles_(this.tiles_); 144 this.initTiles_(this.tiles_);
141 145
142 // The listeners might be called while some tiles are still loading. 146 // The listeners might be called while some tiles are still loading.
143 this.initListeners_(); 147 this.initListeners_();
144 }; 148 };
145 149
146 /** 150 /**
147 * @return {boolean} Whether mosaic is initialized. 151 * @return {boolean} Whether mosaic is initialized.
148 */ 152 */
149 Mosaic.prototype.isInitialized = function() { 153 Mosaic.prototype.isInitialized = function() {
150 return !!this.tiles_; 154 return !!this.tiles_;
151 }; 155 };
152 156
153 /** 157 /**
154 * Start listening to events. 158 * Start listening to events.
155 * 159 *
156 * We keep listening to events even when the mosaic is hidden in order to 160 * We keep listening to events even when the mosaic is hidden in order to
157 * keep the layout up to date. 161 * keep the layout up to date.
158 * 162 *
159 * @private 163 * @private
160 */ 164 */
161 Mosaic.prototype.initListeners_ = function() { 165 Mosaic.prototype.initListeners_ = function() {
162 this.ownerDocument.defaultView.addEventListener( 166 this.ownerDocument.defaultView.addEventListener(
163 'resize', this.onResize_.bind(this)); 167 'resize', this.onResize_.bind(this));
164 168
165 var mouseEventBound = this.onMouseEvent_.bind(this); 169 var mouseEventBound = this.onMouseEvent_.bind(this);
166 this.addEventListener('mousemove', mouseEventBound); 170 this.addEventListener('mousemove', mouseEventBound);
167 this.addEventListener('mousedown', mouseEventBound); 171 this.addEventListener('mousedown', mouseEventBound);
168 this.addEventListener('mouseup', mouseEventBound); 172 this.addEventListener('mouseup', mouseEventBound);
173 this.addEventListener('scroll', this.onScroll_.bind(this));
169 174
170 this.selectionModel_.addEventListener('change', this.onSelection_.bind(this)); 175 this.selectionModel_.addEventListener('change', this.onSelection_.bind(this));
171 this.selectionModel_.addEventListener('leadIndexChange', 176 this.selectionModel_.addEventListener('leadIndexChange',
172 this.onLeadChange_.bind(this)); 177 this.onLeadChange_.bind(this));
173 178
174 this.dataModel_.addEventListener('splice', this.onSplice_.bind(this)); 179 this.dataModel_.addEventListener('splice', this.onSplice_.bind(this));
175 this.dataModel_.addEventListener('content', this.onContentChange_.bind(this)); 180 this.dataModel_.addEventListener('content', this.onContentChange_.bind(this));
176 }; 181 };
177 182
178 /** 183 /**
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 /** 259 /**
255 * @param {number} index Tile index. 260 * @param {number} index Tile index.
256 * Scroll the given tile into the viewport. 261 * Scroll the given tile into the viewport.
257 */ 262 */
258 Mosaic.prototype.scrollIntoView = function(index) { 263 Mosaic.prototype.scrollIntoView = function(index) {
259 var tile = this.tiles_[index]; 264 var tile = this.tiles_[index];
260 if (tile) tile.scrollIntoView(); 265 if (tile) tile.scrollIntoView();
261 }; 266 };
262 267
263 /** 268 /**
264 * Load multiple tiles. 269 * Initializes multiple tiles.
265 * 270 *
266 * @param {Array.<Mosaic.Tile>} tiles Array of tiles. 271 * @param {Array.<Mosaic.Tile>} tiles Array of tiles.
267 * @param {function=} opt_callback Completion callback. 272 * @param {function()=} opt_callback Completion callback.
268 * @private 273 * @private
269 */ 274 */
270 Mosaic.prototype.loadTiles_ = function(tiles, opt_callback) { 275 Mosaic.prototype.initTiles_ = function(tiles, opt_callback) {
271 // We do not want to use tile indices in asynchronous operations because they 276 // We do not want to use tile indices in asynchronous operations because they
272 // do not survive data model splices. Copy tile references instead. 277 // do not survive data model splices. Copy tile references instead.
273 tiles = tiles.slice(); 278 tiles = tiles.slice();
274 279
275 // Throttle the metadata access so that we do not overwhelm the file system. 280 // Throttle the metadata access so that we do not overwhelm the file system.
276 var MAX_CHUNK_SIZE = 10; 281 var MAX_CHUNK_SIZE = 10;
277 282
278 var loadChunk = function() { 283 var loadChunk = function() {
279 if (!tiles.length) { 284 if (!tiles.length) {
280 if (opt_callback) opt_callback(); 285 if (opt_callback) opt_callback();
281 return; 286 return;
282 } 287 }
283 var chunkSize = Math.min(tiles.length, MAX_CHUNK_SIZE); 288 var chunkSize = Math.min(tiles.length, MAX_CHUNK_SIZE);
284 var loaded = 0; 289 var loaded = 0;
285 for (var i = 0; i != chunkSize; i++) { 290 for (var i = 0; i != chunkSize; i++) {
286 this.loadTile_(tiles.shift(), function() { 291 this.initTile_(tiles.shift(), function() {
287 if (++loaded == chunkSize) { 292 if (++loaded == chunkSize) {
288 this.layout(); 293 this.layout();
289 loadChunk(); 294 loadChunk();
290 } 295 }
291 }.bind(this)); 296 }.bind(this));
292 } 297 }
293 }.bind(this); 298 }.bind(this);
294 299
295 loadChunk(); 300 loadChunk();
296 }; 301 };
297 302
298 /** 303 /**
299 * Load a single tile. 304 * Initializes a single tile.
300 * 305 *
301 * @param {Mosaic.Tile} tile Tile. 306 * @param {Mosaic.Tile} tile Tile.
302 * @param {function} callback Completion callback. 307 * @param {function()} callback Completion callback.
303 * @private 308 * @private
304 */ 309 */
305 Mosaic.prototype.loadTile_ = function(tile, callback) { 310 Mosaic.prototype.initTile_ = function(tile, callback) {
306 var url = tile.getItem().getUrl(); 311 var url = tile.getItem().getUrl();
307 var onImageLoaded = function(success) { 312 var onImageMeasured = callback;
308 if (!success && this.onThumbnailError_) {
309 this.onThumbnailError_(url);
310 }
311 callback();
312 }.bind(this);
313 this.metadataCache_.get(url, Gallery.METADATA_TYPE, 313 this.metadataCache_.get(url, Gallery.METADATA_TYPE,
314 function(metadata) { tile.load(metadata, onImageLoaded) }); 314 function(metadata) {
315 tile.init(metadata, onImageMeasured);
316 });
315 }; 317 };
316 318
317 /** 319 /**
318 * Reload all tiles. 320 * Reload all tiles.
319 */ 321 */
320 Mosaic.prototype.reload = function() { 322 Mosaic.prototype.reload = function() {
321 this.layoutModel_.reset_(); 323 this.layoutModel_.reset_();
322 this.tiles_.forEach(function(t) { t.markUnloaded() }); 324 this.tiles_.forEach(function(t) { t.markUnloaded() });
323 this.loadTiles_(this.tiles_); 325 this.initTiles_(this.tiles_);
324 }; 326 };
325 327
326 /** 328 /**
327 * Layout the tiles in the order of their indices. 329 * Layout the tiles in the order of their indices.
328 * 330 *
329 * Starts where it last stopped (at #0 the first time). 331 * Starts where it last stopped (at #0 the first time).
330 * Stops when all tiles are processed or when the next tile is still loading. 332 * Stops when all tiles are processed or when the next tile is still loading.
331 */ 333 */
332 Mosaic.prototype.layout = function() { 334 Mosaic.prototype.layout = function() {
333 if (this.layoutTimer_) { 335 if (this.layoutTimer_) {
334 clearTimeout(this.layoutTimer_); 336 clearTimeout(this.layoutTimer_);
335 this.layoutTimer_ = null; 337 this.layoutTimer_ = null;
336 } 338 }
337 while (true) { 339 while (true) {
338 var index = this.layoutModel_.getTileCount(); 340 var index = this.layoutModel_.getTileCount();
339 if (index == this.tiles_.length) 341 if (index == this.tiles_.length)
340 break; // All tiles done. 342 break; // All tiles done.
341 var tile = this.tiles_[index]; 343 var tile = this.tiles_[index];
342 if (!tile.isLoaded()) 344 if (!tile.isInitialized())
343 break; // Next layout will try to restart from here. 345 break; // Next layout will try to restart from here.
344 this.layoutModel_.add(tile, index + 1 == this.tiles_.length); 346 this.layoutModel_.add(tile, index + 1 == this.tiles_.length);
345 } 347 }
348 this.loadVisibleTiles_();
346 }; 349 };
347 350
348 /** 351 /**
349 * Schedule the layout. 352 * Schedule the layout.
350 * 353 *
351 * @param {number=} opt_delay Delay in ms. 354 * @param {number=} opt_delay Delay in ms.
352 */ 355 */
353 Mosaic.prototype.scheduleLayout = function(opt_delay) { 356 Mosaic.prototype.scheduleLayout = function(opt_delay) {
354 if (!this.layoutTimer_) { 357 if (!this.layoutTimer_) {
355 this.layoutTimer_ = setTimeout(function() { 358 this.layoutTimer_ = setTimeout(function() {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 target = target.parentNode) { 393 target = target.parentNode) {
391 if (target.classList.contains('mosaic-tile')) { 394 if (target.classList.contains('mosaic-tile')) {
392 index = this.dataModel_.indexOf(target.getItem()); 395 index = this.dataModel_.indexOf(target.getItem());
393 break; 396 break;
394 } 397 }
395 } 398 }
396 this.selectionController_.handlePointerDownUp(event, index); 399 this.selectionController_.handlePointerDownUp(event, index);
397 }; 400 };
398 401
399 /** 402 /**
403 * Scroll handler.
404 * @private
405 */
406 Mosaic.prototype.onScroll_ = function() {
407 this.loadVisibleTiles_();
408 };
409
410 /**
400 * Selection change handler. 411 * Selection change handler.
401 * 412 *
402 * @param {Event} event Event. 413 * @param {Event} event Event.
403 * @private 414 * @private
404 */ 415 */
405 Mosaic.prototype.onSelection_ = function(event) { 416 Mosaic.prototype.onSelection_ = function(event) {
406 for (var i = 0; i != event.changes.length; i++) { 417 for (var i = 0; i != event.changes.length; i++) {
407 var change = event.changes[i]; 418 var change = event.changes[i];
408 var tile = this.tiles_[change.index]; 419 var tile = this.tiles_[change.index];
409 if (tile) tile.select(change.selected); 420 if (tile) tile.select(change.selected);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 this.tiles_.splice(index, event.removed.length); 452 this.tiles_.splice(index, event.removed.length);
442 this.scheduleLayout(Mosaic.LAYOUT_DELAY); 453 this.scheduleLayout(Mosaic.LAYOUT_DELAY);
443 } 454 }
444 455
445 if (event.added.length) { 456 if (event.added.length) {
446 var newTiles = []; 457 var newTiles = [];
447 for (var t = 0; t != event.added.length; t++) 458 for (var t = 0; t != event.added.length; t++)
448 newTiles.push(new Mosaic.Tile(this, this.dataModel_.item(index + t))); 459 newTiles.push(new Mosaic.Tile(this, this.dataModel_.item(index + t)));
449 460
450 this.tiles_.splice.apply(this.tiles_, [index, 0].concat(newTiles)); 461 this.tiles_.splice.apply(this.tiles_, [index, 0].concat(newTiles));
451 this.loadTiles_(newTiles); 462 this.initTiles_(newTiles);
452 } 463 }
453 464
454 if (this.tiles_.length != this.dataModel_.length) 465 if (this.tiles_.length != this.dataModel_.length)
455 console.error('Mosaic is out of sync'); 466 console.error('Mosaic is out of sync');
456 }; 467 };
457 468
458 /** 469 /**
459 * Content change handler. 470 * Content change handler.
460 * 471 *
461 * @param {Event} event Event. 472 * @param {Event} event Event.
462 * @private 473 * @private
463 */ 474 */
464 Mosaic.prototype.onContentChange_ = function(event) { 475 Mosaic.prototype.onContentChange_ = function(event) {
465 if (!this.tiles_) 476 if (!this.tiles_)
466 return; 477 return;
467 478
468 if (!event.metadata) 479 if (!event.metadata)
469 return; // Thumbnail unchanged, nothing to do. 480 return; // Thumbnail unchanged, nothing to do.
470 481
471 var index = this.dataModel_.indexOf(event.item); 482 var index = this.dataModel_.indexOf(event.item);
472 if (index != this.selectionModel_.selectedIndex) 483 if (index != this.selectionModel_.selectedIndex)
473 console.error('Content changed for unselected item'); 484 console.error('Content changed for unselected item');
474 485
475 this.layoutModel_.invalidateFromTile_(index); 486 this.layoutModel_.invalidateFromTile_(index);
476 this.tiles_[index].load( 487 this.tiles_[index].init(event.metadata, function() {
477 event.metadata, this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY)); 488 this.tiles_[index].load(
489 this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY),
490 this.onThumbnailError_);
491 }.bind(this));
478 }; 492 };
479 493
480 /** 494 /**
481 * Keydown event handler. 495 * Keydown event handler.
482 * 496 *
483 * @param {Event} event Event. 497 * @param {Event} event Event.
484 * @return {boolean} True if the event has been consumed. 498 * @return {boolean} True if the event has been consumed.
485 */ 499 */
486 Mosaic.prototype.onKeyDown = function(event) { 500 Mosaic.prototype.onKeyDown = function(event) {
487 this.selectionController_.handleKeyDown(event); 501 this.selectionController_.handleKeyDown(event);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 }; 535 };
522 536
523 /** 537 /**
524 * Hide the mosaic. 538 * Hide the mosaic.
525 */ 539 */
526 Mosaic.prototype.hide = function() { 540 Mosaic.prototype.hide = function() {
527 this.removeAttribute('visible'); 541 this.removeAttribute('visible');
528 }; 542 };
529 543
530 /** 544 /**
545 * Loads visible tiles. Ignores consecutive calls. Does not reload already
546 * loaded images.
547 * @private
548 */
549 Mosaic.prototype.loadVisibleTiles_ = function() {
550 if (this.loadVisibleTilesTimer_) {
551 clearTimeout(this.loadVisibleTilesTimer_);
552 this.loadVisibleTilesTimer_ = null;
553 }
554 this.loadVisibleTilesTimer_ = setTimeout(function() {
555 var viewportRect = new Rect(0, 0, this.clientWidth, this.clientHeight);
556 for (var index = 0; index < this.tiles_.length; index++) {
557 var tile = this.tiles_[index];
558 var imageRect = tile.getImageRect();
559 if (!tile.isLoading() && !tile.isLoaded() && imageRect &&
560 imageRect.intersects(viewportRect)) {
561 tile.load(function() {}, this.onThumbnailError_);
562 }
563 }
564 }.bind(this), 100);
565 };
566
567 /**
531 * Apply or reset the zoom transform. 568 * Apply or reset the zoom transform.
532 * 569 *
533 * @param {Rect} tileRect Tile rectangle. Reset the transform if null. 570 * @param {Rect} tileRect Tile rectangle. Reset the transform if null.
534 * @param {Rect} imageRect Large image rectangle. Reset the transform if null. 571 * @param {Rect} imageRect Large image rectangle. Reset the transform if null.
535 * @param {boolean=} opt_instant True of the transition should be instant. 572 * @param {boolean=} opt_instant True of the transition should be instant.
536 */ 573 */
537 Mosaic.prototype.transform = function(tileRect, imageRect, opt_instant) { 574 Mosaic.prototype.transform = function(tileRect, imageRect, opt_instant) {
538 if (opt_instant) { 575 if (opt_instant) {
539 this.style.webkitTransitionDuration = '0'; 576 this.style.webkitTransitionDuration = '0';
540 } else { 577 } else {
(...skipping 1040 matching lines...) Expand 10 before | Expand all | Expand 10 after
1581 Mosaic.Tile.prototype.getMaxContentHeight = function() { 1618 Mosaic.Tile.prototype.getMaxContentHeight = function() {
1582 return this.maxContentHeight_; 1619 return this.maxContentHeight_;
1583 }; 1620 };
1584 1621
1585 /** 1622 /**
1586 * @return {number} The aspect ratio of the tile image. 1623 * @return {number} The aspect ratio of the tile image.
1587 */ 1624 */
1588 Mosaic.Tile.prototype.getAspectRatio = function() { return this.aspectRatio_ }; 1625 Mosaic.Tile.prototype.getAspectRatio = function() { return this.aspectRatio_ };
1589 1626
1590 /** 1627 /**
1628 * @return {boolean} True if the tile is initialized.
1629 */
1630 Mosaic.Tile.prototype.isInitialized = function() {
1631 return !!this.maxContentHeight_;
1632 };
1633
1634 /**
1591 * @return {boolean} True if the tile is loaded. 1635 * @return {boolean} True if the tile is loaded.
1592 */ 1636 */
1593 Mosaic.Tile.prototype.isLoaded = function() { return !!this.maxContentHeight_ }; 1637 Mosaic.Tile.prototype.isLoaded = function() {
1638 return this.imageLoaded_;
1639 };
1640
1641 /**
1642 * @return {boolean} True if the tile is being loaded.
1643 */
1644 Mosaic.Tile.prototype.isLoading = function() {
1645 return this.imageLoading_;
1646 };
1594 1647
1595 /** 1648 /**
1596 * Mark the tile as not loaded to prevent it from participating in the layout. 1649 * Mark the tile as not loaded to prevent it from participating in the layout.
1597 */ 1650 */
1598 Mosaic.Tile.prototype.markUnloaded = function() { 1651 Mosaic.Tile.prototype.markUnloaded = function() {
1599 this.maxContentHeight_ = 0; 1652 this.maxContentHeight_ = 0;
1653 if (this.thumbnailLoader_) {
1654 this.thumbnailLoader_.cancel();
1655 this.imageLoaded_ = false;
1656 this.imageLoading_ = false;
1657 }
1600 }; 1658 };
1601 1659
1602 /** 1660 /**
1603 * Load the thumbnail image into the tile. 1661 * Initializes the thumbnail in the tile. Does not load an image, but sets
1662 * target dimensions using metadata.
1604 * 1663 *
1605 * @param {Object} metadata Metadata object. 1664 * @param {Object} metadata Metadata object.
1606 * @param {function} callback Completion callback. 1665 * @param {function()} onImageMeasured Image measured callback.
1607 */ 1666 */
1608 Mosaic.Tile.prototype.load = function(metadata, callback) { 1667 Mosaic.Tile.prototype.init = function(metadata, onImageMeasured) {
1609 this.markUnloaded(); 1668 this.markUnloaded();
1610 this.left_ = null; // Mark as not laid out. 1669 this.left_ = null; // Mark as not laid out.
1611 1670
1612 this.thumbnailLoader_ = new ThumbnailLoader(this.getItem().getUrl(), 1671 this.thumbnailLoader_ = new ThumbnailLoader(
1613 ThumbnailLoader.LoaderType.CANVAS, 1672 this.getItem().getUrl(),
1614 metadata); 1673 ThumbnailLoader.LoaderType.CANVAS,
1674 metadata,
1675 undefined, // Media type.
1676 ThumbnailLoader.UseEmbedded.NO_EMBEDDED);
1615 1677
1678 var setDimensions = function(width, height) {
1679 if (width > height) {
1680 if (width > Mosaic.Tile.MAX_CONTENT_SIZE) {
1681 height = Math.round(height * Mosaic.Tile.MAX_CONTENT_SIZE / width);
1682 width = Mosaic.Tile.MAX_CONTENT_SIZE;
1683 }
1684 } else {
1685 if (height > Mosaic.Tile.MAX_CONTENT_SIZE) {
1686 width = Math.round(width * Mosaic.Tile.MAX_CONTENT_SIZE / height);
1687 height = Mosaic.Tile.MAX_CONTENT_SIZE;
1688 }
1689 }
1690 this.maxContentHeight_ = Math.max(Mosaic.Tile.MIN_CONTENT_SIZE, height);
1691 this.aspectRatio_ = width / height;
1692 onImageMeasured();
1693 }.bind(this);
1694
1695 // Dimensions are always acquired from the metadata. If it is not available,
1696 // then the image will not be displayed.
1697 if (metadata.media && metadata.media.width) {
1698 setDimensions(metadata.media.width, metadata.media.height);
1699 } else {
1700 // No dimensions in metadata, then display the generic icon instead.
1701 // TODO(mtomasz): Display a gneric icon instead of a black rectangle.
1702 setDimensions(Mosaic.Tile.GENERIC_ICON_SIZE,
1703 Mosaic.Tile.GENERIC_ICON_SIZE);
1704 }
1705 };
1706
1707 /**
1708 * Loads an image into the tile.
1709 *
1710 * @param {function(boolean)} onImageLoaded Callback when image is loaded.
1711 * The argument is true for success, false for failure.
1712 * @param {function()=} opt_onThumbnailError Callback for image loading error.
1713 */
1714 Mosaic.Tile.prototype.load = function(onImageLoaded, opt_onThumbnailError) {
1715 this.imageLoaded_ = false;
1716 this.imageLoading_ = true;
1616 this.thumbnailLoader_.loadDetachedImage(function(success) { 1717 this.thumbnailLoader_.loadDetachedImage(function(success) {
1617 if (this.thumbnailLoader_.hasValidImage()) { 1718 if (!success) {
1618 var width = this.thumbnailLoader_.getWidth(); 1719 if (opt_onThumbnailError)
1619 var height = this.thumbnailLoader_.getHeight(); 1720 opt_onThumbnailError();
1620 if (width > height) {
1621 if (width > Mosaic.Tile.MAX_CONTENT_SIZE) {
1622 height = Math.round(height * Mosaic.Tile.MAX_CONTENT_SIZE / width);
1623 width = Mosaic.Tile.MAX_CONTENT_SIZE;
1624 }
1625 } else {
1626 if (height > Mosaic.Tile.MAX_CONTENT_SIZE) {
1627 width = Math.round(width * Mosaic.Tile.MAX_CONTENT_SIZE / height);
1628 height = Mosaic.Tile.MAX_CONTENT_SIZE;
1629 }
1630 }
1631 this.maxContentHeight_ = Math.max(Mosaic.Tile.MIN_CONTENT_SIZE, height);
1632 this.aspectRatio_ = width / height;
1633 } else {
1634 this.maxContentHeight_ = Mosaic.Tile.GENERIC_ICON_SIZE;
1635 this.aspectRatio_ = 1;
1636 } 1721 }
1637 1722 if (this.wrapper_) {
1638 callback(success); 1723 this.thumbnailLoader_.attachImage(this.wrapper_,
1724 ThumbnailLoader.FillMode.FILL);
1725 }
1726 onImageLoaded(success);
1727 this.imageLoaded_ = true;
1728 this.imageLoading_ = false;
1639 }.bind(this)); 1729 }.bind(this));
1640 }; 1730 };
1641 1731
1642 /** 1732 /**
1643 * Select/unselect the tile. 1733 * Select/unselect the tile.
1644 * 1734 *
1645 * @param {boolean} on True if selected. 1735 * @param {boolean} on True if selected.
1646 */ 1736 */
1647 Mosaic.Tile.prototype.select = function(on) { 1737 Mosaic.Tile.prototype.select = function(on) {
1648 if (on) 1738 if (on)
(...skipping 22 matching lines...) Expand all
1671 this.style.height = height + 'px'; 1761 this.style.height = height + 'px';
1672 1762
1673 if (!this.wrapper_) { // First time, create DOM. 1763 if (!this.wrapper_) { // First time, create DOM.
1674 this.container_.appendChild(this); 1764 this.container_.appendChild(this);
1675 var border = util.createChild(this, 'img-border'); 1765 var border = util.createChild(this, 'img-border');
1676 this.wrapper_ = util.createChild(border, 'img-wrapper'); 1766 this.wrapper_ = util.createChild(border, 'img-wrapper');
1677 } 1767 }
1678 if (this.hasAttribute('selected')) 1768 if (this.hasAttribute('selected'))
1679 this.scrollIntoView(false); 1769 this.scrollIntoView(false);
1680 1770
1681 this.thumbnailLoader_.attachImage(this.wrapper_, 1771 if (this.imageLoaded_) {
1682 ThumbnailLoader.FillMode.FILL); 1772 this.thumbnailLoader_.attachImage(this.wrapper_,
1773 ThumbnailLoader.FillMode.FILL);
1774 }
1683 }; 1775 };
1684 1776
1685 /** 1777 /**
1686 * If the tile is not fully visible scroll the parent to make it fully visible. 1778 * If the tile is not fully visible scroll the parent to make it fully visible.
1687 * @param {boolean=} opt_animated True, if scroll should be animated, 1779 * @param {boolean=} opt_animated True, if scroll should be animated,
1688 * default: true. 1780 * default: true.
1689 */ 1781 */
1690 Mosaic.Tile.prototype.scrollIntoView = function(opt_animated) { 1782 Mosaic.Tile.prototype.scrollIntoView = function(opt_animated) {
1691 if (this.left_ == null) // Not laid out. 1783 if (this.left_ == null) // Not laid out.
1692 return; 1784 return;
(...skipping 29 matching lines...) Expand all
1722 return new Rect(this.left_ - this.container_.scrollLeft, this.top_, 1814 return new Rect(this.left_ - this.container_.scrollLeft, this.top_,
1723 this.width_, this.height_).inflate(-margin, -margin); 1815 this.width_, this.height_).inflate(-margin, -margin);
1724 }; 1816 };
1725 1817
1726 /** 1818 /**
1727 * @return {number} X coordinate of the tile center. 1819 * @return {number} X coordinate of the tile center.
1728 */ 1820 */
1729 Mosaic.Tile.prototype.getCenterX = function() { 1821 Mosaic.Tile.prototype.getCenterX = function() {
1730 return this.left_ + Math.round(this.width_ / 2); 1822 return this.left_ + Math.round(this.width_ / 2);
1731 }; 1823 };
OLDNEW
« 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