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