OLD | NEW |
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 /** | 5 /** |
6 * @param {Element} container Content container. | 6 * @param {!Element} container Content container. |
7 * @param {ErrorBanner} errorBanner Error banner. | 7 * @param {!ErrorBanner} errorBanner Error banner. |
8 * @param {cr.ui.ArrayDataModel} dataModel Data model. | 8 * @param {!cr.ui.ArrayDataModel} dataModel Data model. |
9 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. | 9 * @param {!cr.ui.ListSelectionModel} selectionModel Selection model. |
10 * @param {!VolumeManager} volumeManager Volume manager. | 10 * @param {!VolumeManager} volumeManager Volume manager. |
11 * @param {function()} toggleMode Function to switch to the Slide mode. | 11 * @param {function()} toggleMode Function to switch to the Slide mode. |
12 * @constructor | 12 * @constructor |
| 13 * @struct |
13 */ | 14 */ |
14 function MosaicMode( | 15 function MosaicMode( |
15 container, errorBanner, dataModel, selectionModel, volumeManager, | 16 container, errorBanner, dataModel, selectionModel, volumeManager, |
16 toggleMode) { | 17 toggleMode) { |
17 this.mosaic_ = new Mosaic(container.ownerDocument, errorBanner, | 18 this.mosaic_ = new Mosaic(assert(container.ownerDocument), errorBanner, |
18 dataModel, selectionModel, volumeManager); | 19 dataModel, selectionModel, volumeManager); |
19 container.appendChild(this.mosaic_); | 20 container.appendChild(this.mosaic_); |
20 | 21 |
21 this.toggleMode_ = toggleMode; | 22 this.toggleMode_ = toggleMode; |
22 this.mosaic_.addEventListener('dblclick', this.toggleMode_); | 23 this.mosaic_.addEventListener('dblclick', this.toggleMode_); |
23 this.showingTimeoutID_ = null; | 24 this.showingTimeoutID_ = null; |
24 } | 25 } |
25 | 26 |
26 /** | 27 /** |
27 * @return {Mosaic} The mosaic control. | 28 * @return {!Mosaic} The mosaic control. |
28 */ | 29 */ |
29 MosaicMode.prototype.getMosaic = function() { return this.mosaic_; }; | 30 MosaicMode.prototype.getMosaic = function() { return this.mosaic_; }; |
30 | 31 |
31 /** | 32 /** |
32 * @return {string} Mode name. | 33 * @return {string} Mode name. |
33 */ | 34 */ |
34 MosaicMode.prototype.getName = function() { return 'mosaic'; }; | 35 MosaicMode.prototype.getName = function() { return 'mosaic'; }; |
35 | 36 |
36 /** | 37 /** |
37 * @return {string} Mode title. | 38 * @return {string} Mode title. |
38 */ | 39 */ |
39 MosaicMode.prototype.getTitle = function() { return 'GALLERY_MOSAIC'; }; | 40 MosaicMode.prototype.getTitle = function() { return 'GALLERY_MOSAIC'; }; |
40 | 41 |
41 /** | 42 /** |
42 * Execute an action (this mode has no busy state). | 43 * Execute an action (this mode has no busy state). |
43 * @param {function()} action Action to execute. | 44 * @param {function()} action Action to execute. |
44 */ | 45 */ |
45 MosaicMode.prototype.executeWhenReady = function(action) { action(); }; | 46 MosaicMode.prototype.executeWhenReady = function(action) { action(); }; |
46 | 47 |
47 /** | 48 /** |
48 * @return {boolean} Always true (no toolbar fading in this mode). | 49 * @return {boolean} Always true (no toolbar fading in this mode). |
49 */ | 50 */ |
50 MosaicMode.prototype.hasActiveTool = function() { return true; }; | 51 MosaicMode.prototype.hasActiveTool = function() { return true; }; |
51 | 52 |
52 /** | 53 /** |
53 * Keydown handler. | 54 * Keydown handler. |
54 * | 55 * |
55 * @param {Event} event Event. | 56 * @param {!Event} event Event. |
56 */ | 57 */ |
57 MosaicMode.prototype.onKeyDown = function(event) { | 58 MosaicMode.prototype.onKeyDown = function(event) { |
58 switch (util.getKeyModifiers(event) + event.keyIdentifier) { | 59 switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
59 case 'Enter': | 60 case 'Enter': |
60 if (!document.activeElement || | 61 if (!document.activeElement || |
61 document.activeElement.localName !== 'button') { | 62 document.activeElement.localName !== 'button') { |
62 this.toggleMode_(); | 63 this.toggleMode_(); |
63 event.preventDefault(); | 64 event.preventDefault(); |
64 } | 65 } |
65 return; | 66 return; |
66 } | 67 } |
67 this.mosaic_.onKeyDown(event); | 68 this.mosaic_.onKeyDown(event); |
68 }; | 69 }; |
69 | 70 |
70 //////////////////////////////////////////////////////////////////////////////// | 71 //////////////////////////////////////////////////////////////////////////////// |
71 | 72 |
72 /** | 73 /** |
73 * Mosaic control. | 74 * Mosaic control. |
74 * | 75 * |
75 * @param {Document} document Document. | 76 * @param {!Document} document Document. |
76 * @param {ErrorBanner} errorBanner Error banner. | 77 * @param {!ErrorBanner} errorBanner Error banner. |
77 * @param {cr.ui.ArrayDataModel} dataModel Data model. | 78 * @param {!cr.ui.ArrayDataModel} dataModel Data model. |
78 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. | 79 * @param {!cr.ui.ListSelectionModel} selectionModel Selection model. |
79 * @param {VolumeManagerWrapper} volumeManager Volume manager. | 80 * @param {!VolumeManager} volumeManager Volume manager. |
80 * @return {Element} Mosaic element. | 81 * @return {!Element} Mosaic element. |
81 * @constructor | 82 * @constructor |
| 83 * @struct |
| 84 * @extends {HTMLDivElement} |
| 85 * @suppress {checkStructDictInheritance} |
82 */ | 86 */ |
83 function Mosaic(document, errorBanner, dataModel, selectionModel, | 87 function Mosaic(document, errorBanner, dataModel, selectionModel, |
84 volumeManager) { | 88 volumeManager) { |
85 var self = document.createElement('div'); | 89 var self = assertInstanceof(document.createElement('div'), HTMLDivElement); |
86 Mosaic.decorate(self, errorBanner, dataModel, selectionModel, volumeManager); | 90 Mosaic.decorate(self, errorBanner, dataModel, selectionModel, volumeManager); |
87 return self; | 91 return self; |
88 } | 92 } |
89 | 93 |
90 /** | 94 /** |
91 * Inherits from HTMLDivElement. | 95 * Inherits from HTMLDivElement. |
92 */ | 96 */ |
93 Mosaic.prototype.__proto__ = HTMLDivElement.prototype; | 97 Mosaic.prototype.__proto__ = HTMLDivElement.prototype; |
94 | 98 |
95 /** | 99 /** |
96 * Default layout delay in ms. | 100 * Default layout delay in ms. |
97 * @const | 101 * @const |
98 * @type {number} | 102 * @type {number} |
99 */ | 103 */ |
100 Mosaic.LAYOUT_DELAY = 200; | 104 Mosaic.LAYOUT_DELAY = 200; |
101 | 105 |
102 /** | 106 /** |
103 * Smooth scroll animation duration when scrolling using keyboard or | 107 * Smooth scroll animation duration when scrolling using keyboard or |
104 * clicking on a partly visible tile. In ms. | 108 * clicking on a partly visible tile. In ms. |
105 * @const | 109 * @const |
106 * @type {number} | 110 * @type {number} |
107 */ | 111 */ |
108 Mosaic.ANIMATED_SCROLL_DURATION = 500; | 112 Mosaic.ANIMATED_SCROLL_DURATION = 500; |
109 | 113 |
110 /** | 114 /** |
111 * Decorates a Mosaic instance. | 115 * Decorates a Mosaic instance. |
112 * | 116 * |
113 * @param {Mosaic} self Self pointer. | 117 * @param {!HTMLDivElement} self Self pointer. |
114 * @param {ErrorBanner} errorBanner Error banner. | 118 * @param {!ErrorBanner} errorBanner Error banner. |
115 * @param {cr.ui.ArrayDataModel} dataModel Data model. | 119 * @param {!cr.ui.ArrayDataModel} dataModel Data model. |
116 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. | 120 * @param {!cr.ui.ListSelectionModel} selectionModel Selection model. |
117 * @param {VolumeManagerWrapper} volumeManager Volume manager. | 121 * @param {!VolumeManager} volumeManager Volume manager. |
118 */ | 122 */ |
119 Mosaic.decorate = function( | 123 Mosaic.decorate = function( |
120 self, errorBanner, dataModel, selectionModel, volumeManager) { | 124 self, errorBanner, dataModel, selectionModel, volumeManager) { |
121 self.__proto__ = Mosaic.prototype; | 125 self.__proto__ = Mosaic.prototype; |
| 126 self = /** @type {!Mosaic} */ (self); |
122 self.className = 'mosaic'; | 127 self.className = 'mosaic'; |
123 | 128 |
124 self.dataModel_ = dataModel; | 129 self.dataModel_ = dataModel; |
125 self.selectionModel_ = selectionModel; | 130 self.selectionModel_ = selectionModel; |
126 self.volumeManager_ = volumeManager; | 131 self.volumeManager_ = volumeManager; |
127 self.errorBanner_ = errorBanner; | 132 self.errorBanner_ = errorBanner; |
128 | 133 |
| 134 /** |
| 135 * @type {Array.<!Mosaic.Tile>} |
| 136 * @private |
| 137 */ |
| 138 self.tiles_ = null; |
| 139 |
| 140 /** |
| 141 * @type {boolean} |
| 142 * @private |
| 143 */ |
| 144 self.loadVisibleTilesSuppressed_ = false; |
| 145 |
| 146 /** |
| 147 * @type {boolean} |
| 148 * @private |
| 149 */ |
| 150 self.loadVisibleTilesScheduled_ = false; |
| 151 |
| 152 /** |
| 153 * @type {number} |
| 154 * @private |
| 155 */ |
| 156 self.showingTimeoutID_ = 0; |
| 157 |
| 158 /** |
| 159 * @type {Mosaic.SelectionController} |
| 160 * @private |
| 161 */ |
| 162 self.selectionController_ = null; |
| 163 |
| 164 /** |
| 165 * @type {Mosaic.Layout} |
| 166 * @private |
| 167 */ |
| 168 self.layoutModel_ = null; |
| 169 |
| 170 /** |
| 171 * @type {boolean} |
| 172 * @private |
| 173 */ |
| 174 self.suppressHovering_ = false; |
| 175 |
| 176 /** |
| 177 * @type {number} |
| 178 * @private |
| 179 */ |
| 180 self.layoutTimer_ = 0; |
| 181 |
| 182 /** |
| 183 * @type {number} |
| 184 * @private |
| 185 */ |
| 186 self.scrollAnimation_ = 0; |
| 187 |
129 // Initialization is completed lazily on the first call to |init|. | 188 // Initialization is completed lazily on the first call to |init|. |
130 }; | 189 }; |
131 | 190 |
132 /** | 191 /** |
133 * Initializes the mosaic element. | 192 * Initializes the mosaic element. |
134 */ | 193 */ |
135 Mosaic.prototype.init = function() { | 194 Mosaic.prototype.init = function() { |
136 if (this.tiles_) | 195 if (this.tiles_) |
137 return; // Already initialized, nothing to do. | 196 return; // Already initialized, nothing to do. |
138 | 197 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 }; | 253 }; |
195 | 254 |
196 /** | 255 /** |
197 * Smoothly scrolls the container to the specified position using | 256 * Smoothly scrolls the container to the specified position using |
198 * f(x) = sqrt(x) speed function normalized to animation duration. | 257 * f(x) = sqrt(x) speed function normalized to animation duration. |
199 * @param {number} targetPosition Horizontal scroll position in pixels. | 258 * @param {number} targetPosition Horizontal scroll position in pixels. |
200 */ | 259 */ |
201 Mosaic.prototype.animatedScrollTo = function(targetPosition) { | 260 Mosaic.prototype.animatedScrollTo = function(targetPosition) { |
202 if (this.scrollAnimation_) { | 261 if (this.scrollAnimation_) { |
203 webkitCancelAnimationFrame(this.scrollAnimation_); | 262 webkitCancelAnimationFrame(this.scrollAnimation_); |
204 this.scrollAnimation_ = null; | 263 this.scrollAnimation_ = 0; |
205 } | 264 } |
206 | 265 |
207 // Mouse move events are fired without touching the mouse because of scrolling | 266 // Mouse move events are fired without touching the mouse because of scrolling |
208 // the container. Therefore, these events have to be suppressed. | 267 // the container. Therefore, these events have to be suppressed. |
209 this.suppressHovering_ = true; | 268 this.suppressHovering_ = true; |
210 | 269 |
211 // Calculates integral area from t1 to t2 of f(x) = sqrt(x) dx. | 270 // Calculates integral area from t1 to t2 of f(x) = sqrt(x) dx. |
212 var integral = function(t1, t2) { | 271 var integral = function(t1, t2) { |
213 return 2.0 / 3.0 * Math.pow(t2, 3.0 / 2.0) - | 272 return 2.0 / 3.0 * Math.pow(t2, 3.0 / 2.0) - |
214 2.0 / 3.0 * Math.pow(t1, 3.0 / 2.0); | 273 2.0 / 3.0 * Math.pow(t1, 3.0 / 2.0); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 /** | 322 /** |
264 * @param {number} index Tile index. | 323 * @param {number} index Tile index. |
265 * @return {ImageRect} Tile's image rectangle. | 324 * @return {ImageRect} Tile's image rectangle. |
266 */ | 325 */ |
267 Mosaic.prototype.getTileRect = function(index) { | 326 Mosaic.prototype.getTileRect = function(index) { |
268 var tile = this.tiles_[index]; | 327 var tile = this.tiles_[index]; |
269 return tile && tile.getImageRect(); | 328 return tile && tile.getImageRect(); |
270 }; | 329 }; |
271 | 330 |
272 /** | 331 /** |
| 332 * Scroll the given tile into the viewport. |
273 * @param {number} index Tile index. | 333 * @param {number} index Tile index. |
274 * Scroll the given tile into the viewport. | |
275 */ | 334 */ |
276 Mosaic.prototype.scrollIntoView = function(index) { | 335 Mosaic.prototype.scrollIntoViewByIndex = function(index) { |
277 var tile = this.tiles_[index]; | 336 var tile = this.tiles_[index]; |
278 if (tile) tile.scrollIntoView(); | 337 if (tile) tile.scrollIntoView(); |
279 }; | 338 }; |
280 | 339 |
281 /** | 340 /** |
282 * Initializes multiple tiles. | 341 * Initializes multiple tiles. |
283 * | 342 * |
284 * @param {Array.<Mosaic.Tile>} tiles Array of tiles. | 343 * @param {!Array.<!Mosaic.Tile>} tiles Array of tiles. |
285 * @private | 344 * @private |
286 */ | 345 */ |
287 Mosaic.prototype.initTiles_ = function(tiles) { | 346 Mosaic.prototype.initTiles_ = function(tiles) { |
288 for (var i = 0; i < tiles.length; i++) { | 347 for (var i = 0; i < tiles.length; i++) { |
289 tiles[i].init(); | 348 tiles[i].init(); |
290 } | 349 } |
291 }; | 350 }; |
292 | 351 |
293 /** | 352 /** |
294 * Reloads all tiles. | 353 * Reloads all tiles. |
295 */ | 354 */ |
296 Mosaic.prototype.reload = function() { | 355 Mosaic.prototype.reload = function() { |
297 this.layoutModel_.reset_(); | 356 this.layoutModel_.reset_(); |
298 this.tiles_.forEach(function(t) { t.markUnloaded(); }); | 357 this.tiles_.forEach(function(t) { t.markUnloaded(); }); |
299 this.initTiles_(this.tiles_); | 358 this.initTiles_(this.tiles_); |
300 }; | 359 }; |
301 | 360 |
302 /** | 361 /** |
303 * Layouts the tiles in the order of their indices. | 362 * Layouts the tiles in the order of their indices. |
304 * | 363 * |
305 * Starts where it last stopped (at #0 the first time). | 364 * Starts where it last stopped (at #0 the first time). |
306 * Stops when all tiles are processed or when the next tile is still loading. | 365 * Stops when all tiles are processed or when the next tile is still loading. |
307 */ | 366 */ |
308 Mosaic.prototype.layout = function() { | 367 Mosaic.prototype.layout = function() { |
309 if (this.layoutTimer_) { | 368 if (this.layoutTimer_) { |
310 clearTimeout(this.layoutTimer_); | 369 clearTimeout(this.layoutTimer_); |
311 this.layoutTimer_ = null; | 370 this.layoutTimer_ = 0; |
312 } | 371 } |
313 while (true) { | 372 while (true) { |
314 var index = this.layoutModel_.getTileCount(); | 373 var index = this.layoutModel_.getTileCount(); |
315 if (index === this.tiles_.length) | 374 if (index === this.tiles_.length) |
316 break; // All tiles done. | 375 break; // All tiles done. |
317 var tile = this.tiles_[index]; | 376 var tile = this.tiles_[index]; |
318 if (!tile.isInitialized()) | 377 if (!tile.isInitialized()) |
319 break; // Next layout will try to restart from here. | 378 break; // Next layout will try to restart from here. |
320 this.layoutModel_.add(tile, index + 1 === this.tiles_.length); | 379 this.layoutModel_.add(tile, index + 1 === this.tiles_.length); |
321 } | 380 } |
322 this.loadVisibleTiles_(); | 381 this.loadVisibleTiles_(); |
323 }; | 382 }; |
324 | 383 |
325 /** | 384 /** |
326 * Schedules the layout. | 385 * Schedules the layout. |
327 * | 386 * |
328 * @param {number=} opt_delay Delay in ms. | 387 * @param {number=} opt_delay Delay in ms. |
329 */ | 388 */ |
330 Mosaic.prototype.scheduleLayout = function(opt_delay) { | 389 Mosaic.prototype.scheduleLayout = function(opt_delay) { |
331 if (!this.layoutTimer_) { | 390 if (!this.layoutTimer_) { |
332 this.layoutTimer_ = setTimeout(function() { | 391 this.layoutTimer_ = setTimeout(function() { |
333 this.layoutTimer_ = null; | 392 this.layoutTimer_ = 0; |
334 this.layout(); | 393 this.layout(); |
335 }.bind(this), opt_delay || 0); | 394 }.bind(this), opt_delay || 0); |
336 } | 395 } |
337 }; | 396 }; |
338 | 397 |
339 /** | 398 /** |
340 * Resize handler. | 399 * Resize handler. |
341 * | 400 * |
342 * @private | 401 * @private |
343 */ | 402 */ |
344 Mosaic.prototype.onResize_ = function() { | 403 Mosaic.prototype.onResize_ = function() { |
345 this.layoutModel_.setViewportSize(this.clientWidth, this.clientHeight - | 404 this.layoutModel_.setViewportSize(this.clientWidth, this.clientHeight - |
346 (Mosaic.Layout.PADDING_TOP + Mosaic.Layout.PADDING_BOTTOM)); | 405 (Mosaic.Layout.PADDING_TOP + Mosaic.Layout.PADDING_BOTTOM)); |
347 this.scheduleLayout(); | 406 this.scheduleLayout(); |
348 }; | 407 }; |
349 | 408 |
350 /** | 409 /** |
351 * Mouse event handler. | 410 * Mouse event handler. |
352 * | 411 * |
353 * @param {Event} event Event. | 412 * @param {!Event} event Event. |
354 * @private | 413 * @private |
355 */ | 414 */ |
356 Mosaic.prototype.onMouseEvent_ = function(event) { | 415 Mosaic.prototype.onMouseEvent_ = function(event) { |
357 // Navigating with mouse, enable hover state. | 416 // Navigating with mouse, enable hover state. |
358 if (!this.suppressHovering_) | 417 if (!this.suppressHovering_) |
359 this.classList.add('hover-visible'); | 418 this.classList.add('hover-visible'); |
360 | 419 |
361 if (event.type === 'mousemove') | 420 if (event.type === 'mousemove') |
362 return; | 421 return; |
363 | 422 |
(...skipping 15 matching lines...) Expand all Loading... |
379 */ | 438 */ |
380 Mosaic.prototype.onScroll_ = function() { | 439 Mosaic.prototype.onScroll_ = function() { |
381 requestAnimationFrame(function() { | 440 requestAnimationFrame(function() { |
382 this.loadVisibleTiles_(); | 441 this.loadVisibleTiles_(); |
383 }.bind(this)); | 442 }.bind(this)); |
384 }; | 443 }; |
385 | 444 |
386 /** | 445 /** |
387 * Selection change handler. | 446 * Selection change handler. |
388 * | 447 * |
389 * @param {Event} event Event. | 448 * @param {!Event} event Event. |
390 * @private | 449 * @private |
391 */ | 450 */ |
392 Mosaic.prototype.onSelection_ = function(event) { | 451 Mosaic.prototype.onSelection_ = function(event) { |
393 for (var i = 0; i !== event.changes.length; i++) { | 452 for (var i = 0; i !== event.changes.length; i++) { |
394 var change = event.changes[i]; | 453 var change = event.changes[i]; |
395 var tile = this.tiles_[change.index]; | 454 var tile = this.tiles_[change.index]; |
396 if (tile) tile.select(change.selected); | 455 if (tile) tile.select(change.selected); |
397 } | 456 } |
398 }; | 457 }; |
399 | 458 |
400 /** | 459 /** |
401 * Leads item change handler. | 460 * Leads item change handler. |
402 * | 461 * |
403 * @param {Event} event Event. | 462 * @param {!Event} event Event. |
404 * @private | 463 * @private |
405 */ | 464 */ |
406 Mosaic.prototype.onLeadChange_ = function(event) { | 465 Mosaic.prototype.onLeadChange_ = function(event) { |
407 var index = event.newValue; | 466 var index = event.newValue; |
408 if (index >= 0) { | 467 if (index >= 0) { |
409 var tile = this.tiles_[index]; | 468 var tile = this.tiles_[index]; |
410 if (tile) tile.scrollIntoView(); | 469 if (tile) tile.scrollIntoView(); |
411 } | 470 } |
412 }; | 471 }; |
413 | 472 |
414 /** | 473 /** |
415 * Splice event handler. | 474 * Splice event handler. |
416 * | 475 * |
417 * @param {Event} event Event. | 476 * @param {!Event} event Event. |
418 * @private | 477 * @private |
419 */ | 478 */ |
420 Mosaic.prototype.onSplice_ = function(event) { | 479 Mosaic.prototype.onSplice_ = function(event) { |
421 var index = event.index; | 480 var index = event.index; |
422 this.layoutModel_.invalidateFromTile_(index); | 481 this.layoutModel_.invalidateFromTile_(index); |
423 | 482 |
424 if (event.removed.length) { | 483 if (event.removed.length) { |
425 for (var t = 0; t !== event.removed.length; t++) { | 484 for (var t = 0; t !== event.removed.length; t++) { |
426 // If the layout for the tile has not done yet, the parent is null. | 485 // If the layout for the tile has not done yet, the parent is null. |
427 // And the layout will not be done after onSplice_ because it is removed | 486 // And the layout will not be done after onSplice_ because it is removed |
(...skipping 21 matching lines...) Expand all Loading... |
449 this.scheduleLayout(Mosaic.LAYOUT_DELAY); | 508 this.scheduleLayout(Mosaic.LAYOUT_DELAY); |
450 } | 509 } |
451 | 510 |
452 if (this.tiles_.length !== this.dataModel_.length) | 511 if (this.tiles_.length !== this.dataModel_.length) |
453 console.error('Mosaic is out of sync'); | 512 console.error('Mosaic is out of sync'); |
454 }; | 513 }; |
455 | 514 |
456 /** | 515 /** |
457 * Content change handler. | 516 * Content change handler. |
458 * | 517 * |
459 * @param {Event} event Event. | 518 * @param {!Event} event Event. |
460 * @private | 519 * @private |
461 */ | 520 */ |
462 Mosaic.prototype.onContentChange_ = function(event) { | 521 Mosaic.prototype.onContentChange_ = function(event) { |
463 if (!this.tiles_) | 522 if (!this.tiles_) |
464 return; | 523 return; |
465 | 524 |
466 if (!event.metadata) | 525 if (!event.metadata) |
467 return; // Thumbnail unchanged, nothing to do. | 526 return; // Thumbnail unchanged, nothing to do. |
468 | 527 |
469 var index = this.dataModel_.indexOf(event.item); | 528 var index = this.dataModel_.indexOf(event.item); |
470 if (index !== this.selectionModel_.selectedIndex) | 529 if (index !== this.selectionModel_.selectedIndex) |
471 console.error('Content changed for unselected item'); | 530 console.error('Content changed for unselected item'); |
472 | 531 |
473 this.layoutModel_.invalidateFromTile_(index); | 532 this.layoutModel_.invalidateFromTile_(index); |
474 this.tiles_[index].init(); | 533 this.tiles_[index].init(); |
475 this.tiles_[index].unload(); | 534 this.tiles_[index].unload(); |
476 this.tiles_[index].load( | 535 this.tiles_[index].load( |
477 Mosaic.Tile.LoadMode.HIGH_DPI, | 536 Mosaic.Tile.LoadMode.HIGH_DPI, |
478 this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY)); | 537 this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY)); |
479 }; | 538 }; |
480 | 539 |
481 /** | 540 /** |
482 * Keydown event handler. | 541 * Keydown event handler. |
483 * | 542 * |
484 * @param {Event} event Event. | 543 * @param {!Event} event Event. |
485 * @return {boolean} True if the event has been consumed. | 544 * @return {boolean} True if the event has been consumed. |
486 */ | 545 */ |
487 Mosaic.prototype.onKeyDown = function(event) { | 546 Mosaic.prototype.onKeyDown = function(event) { |
488 this.selectionController_.handleKeyDown(event); | 547 this.selectionController_.handleKeyDown(event); |
489 if (event.defaultPrevented) // Navigating with keyboard, hide hover state. | 548 if (event.defaultPrevented) // Navigating with keyboard, hide hover state. |
490 this.classList.remove('hover-visible'); | 549 this.classList.remove('hover-visible'); |
491 return event.defaultPrevented; | 550 return event.defaultPrevented; |
492 }; | 551 }; |
493 | 552 |
494 /** | 553 /** |
(...skipping 16 matching lines...) Expand all Loading... |
511 var duration = ImageView.MODE_TRANSITION_DURATION; | 570 var duration = ImageView.MODE_TRANSITION_DURATION; |
512 if (this.canZoom()) { | 571 if (this.canZoom()) { |
513 // Fade in in parallel with the zoom effect. | 572 // Fade in in parallel with the zoom effect. |
514 this.setAttribute('visible', 'zooming'); | 573 this.setAttribute('visible', 'zooming'); |
515 } else { | 574 } else { |
516 // Mosaic is not animating but the large image is. Fade in the mosaic | 575 // Mosaic is not animating but the large image is. Fade in the mosaic |
517 // shortly before the large image animation is done. | 576 // shortly before the large image animation is done. |
518 duration -= 100; | 577 duration -= 100; |
519 } | 578 } |
520 this.showingTimeoutID_ = setTimeout(function() { | 579 this.showingTimeoutID_ = setTimeout(function() { |
521 this.showingTimeoutID_ = null; | 580 this.showingTimeoutID_ = 0; |
522 // Make the selection visible. | 581 // Make the selection visible. |
523 // If the mosaic is not animated it will start fading in now. | 582 // If the mosaic is not animated it will start fading in now. |
524 this.setAttribute('visible', 'normal'); | 583 this.setAttribute('visible', 'normal'); |
525 this.loadVisibleTiles_(); | 584 this.loadVisibleTiles_(); |
526 }.bind(this), duration); | 585 }.bind(this), duration); |
527 }; | 586 }; |
528 | 587 |
529 /** | 588 /** |
530 * Hides the mosaic. | 589 * Hides the mosaic. |
531 */ | 590 */ |
532 Mosaic.prototype.hide = function() { | 591 Mosaic.prototype.hide = function() { |
533 this.errorBanner_.clear(); | 592 this.errorBanner_.clear(); |
534 | 593 |
535 if (this.showingTimeoutID_ !== null) { | 594 if (this.showingTimeoutID_ !== 0) { |
536 clearTimeout(this.showingTimeoutID_); | 595 clearTimeout(this.showingTimeoutID_); |
537 this.showingTimeoutID_ = null; | 596 this.showingTimeoutID_ = 0; |
538 } | 597 } |
539 this.removeAttribute('visible'); | 598 this.removeAttribute('visible'); |
540 }; | 599 }; |
541 | 600 |
542 /** | 601 /** |
543 * Checks if the mosaic view is visible. | 602 * Checks if the mosaic view is visible. |
544 * @return {boolean} True if visible, false otherwise. | 603 * @return {boolean} True if visible, false otherwise. |
545 * @private | 604 * @private |
546 */ | 605 */ |
547 Mosaic.prototype.isVisible_ = function() { | 606 Mosaic.prototype.isVisible_ = function() { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 * @private | 712 * @private |
654 */ | 713 */ |
655 Mosaic.prototype.getItemCount_ = function() { | 714 Mosaic.prototype.getItemCount_ = function() { |
656 return this.dataModel_.length; | 715 return this.dataModel_.length; |
657 }; | 716 }; |
658 | 717 |
659 //////////////////////////////////////////////////////////////////////////////// | 718 //////////////////////////////////////////////////////////////////////////////// |
660 | 719 |
661 /** | 720 /** |
662 * Creates a selection controller that is to be used with grid. | 721 * Creates a selection controller that is to be used with grid. |
663 * @param {cr.ui.ListSelectionModel} selectionModel The selection model to | 722 * @param {!cr.ui.ListSelectionModel} selectionModel The selection model to |
664 * interact with. | 723 * interact with. |
665 * @param {Mosaic.Layout} layoutModel The layout model to use. | 724 * @param {!Mosaic.Layout} layoutModel The layout model to use. |
666 * @constructor | 725 * @constructor |
667 * @extends {!cr.ui.ListSelectionController} | 726 * @struct |
| 727 * @extends {cr.ui.ListSelectionController} |
| 728 * @suppress {checkStructDictInheritance} |
668 */ | 729 */ |
669 Mosaic.SelectionController = function(selectionModel, layoutModel) { | 730 Mosaic.SelectionController = function(selectionModel, layoutModel) { |
670 cr.ui.ListSelectionController.call(this, selectionModel); | 731 cr.ui.ListSelectionController.call(this, selectionModel); |
671 this.layoutModel_ = layoutModel; | 732 this.layoutModel_ = layoutModel; |
672 }; | 733 }; |
673 | 734 |
674 /** | 735 /** |
675 * Extends cr.ui.ListSelectionController. | 736 * Extends cr.ui.ListSelectionController. |
676 */ | 737 */ |
677 Mosaic.SelectionController.prototype.__proto__ = | 738 Mosaic.SelectionController.prototype.__proto__ = |
(...skipping 25 matching lines...) Expand all Loading... |
703 }; | 764 }; |
704 | 765 |
705 //////////////////////////////////////////////////////////////////////////////// | 766 //////////////////////////////////////////////////////////////////////////////// |
706 | 767 |
707 /** | 768 /** |
708 * Mosaic layout. | 769 * Mosaic layout. |
709 * | 770 * |
710 * @param {string=} opt_mode Layout mode. | 771 * @param {string=} opt_mode Layout mode. |
711 * @param {Mosaic.Density=} opt_maxDensity Layout density. | 772 * @param {Mosaic.Density=} opt_maxDensity Layout density. |
712 * @constructor | 773 * @constructor |
| 774 * @struct |
713 */ | 775 */ |
714 Mosaic.Layout = function(opt_mode, opt_maxDensity) { | 776 Mosaic.Layout = function(opt_mode, opt_maxDensity) { |
715 this.mode_ = opt_mode || Mosaic.Layout.MODE_TENTATIVE; | 777 this.mode_ = opt_mode || Mosaic.Layout.Mode.TENTATIVE; |
716 this.maxDensity_ = opt_maxDensity || Mosaic.Density.createHighest(); | 778 this.maxDensity_ = opt_maxDensity || Mosaic.Density.createHighest(); |
| 779 |
| 780 /** |
| 781 * @type {!Array.<!Mosaic.Column>} |
| 782 * @private |
| 783 */ |
| 784 this.columns_ = []; |
| 785 |
| 786 /** |
| 787 * @type {Mosaic.Column} |
| 788 * @private |
| 789 */ |
| 790 this.newColumn_ = null; |
| 791 |
| 792 /** |
| 793 * @type {number} |
| 794 * @private |
| 795 */ |
| 796 this.viewportWidth_ = 0; |
| 797 |
| 798 /** |
| 799 * @type {number} |
| 800 * @private |
| 801 */ |
| 802 this.viewportHeight_ = 0; |
| 803 |
| 804 /** |
| 805 * @type {Mosaic.Density} |
| 806 * @private |
| 807 */ |
| 808 this.density_ = null; |
| 809 |
717 this.reset_(); | 810 this.reset_(); |
718 }; | 811 }; |
719 | 812 |
720 /** | 813 /** |
721 * Blank space at the top of the mosaic element. We do not do that in CSS | 814 * Blank space at the top of the mosaic element. We do not do that in CSS |
722 * to make transition effects easier. | 815 * to make transition effects easier. |
| 816 * @type {number} |
| 817 * @const |
723 */ | 818 */ |
724 Mosaic.Layout.PADDING_TOP = 50; | 819 Mosaic.Layout.PADDING_TOP = 50; |
725 | 820 |
726 /** | 821 /** |
727 * Blank space at the bottom of the mosaic element. | 822 * Blank space at the bottom of the mosaic element. |
| 823 * @type {number} |
| 824 * @const |
728 */ | 825 */ |
729 Mosaic.Layout.PADDING_BOTTOM = 50; | 826 Mosaic.Layout.PADDING_BOTTOM = 50; |
730 | 827 |
731 /** | 828 /** |
732 * Horizontal and vertical spacing between images. Should be kept in sync | 829 * Horizontal and vertical spacing between images. Should be kept in sync |
733 * with the style of .mosaic-item in gallery.css (= 2 * ( 4 + 1)) | 830 * with the style of .mosaic-item in gallery.css (= 2 * ( 4 + 1)) |
| 831 * @type {number} |
| 832 * @const |
734 */ | 833 */ |
735 Mosaic.Layout.SPACING = 10; | 834 Mosaic.Layout.SPACING = 10; |
736 | 835 |
737 /** | 836 /** |
738 * Margin for scrolling using keyboard. Distance between a selected tile | 837 * Margin for scrolling using keyboard. Distance between a selected tile |
739 * and window border. | 838 * and window border. |
| 839 * @type {number} |
| 840 * @const |
740 */ | 841 */ |
741 Mosaic.Layout.SCROLL_MARGIN = 30; | 842 Mosaic.Layout.SCROLL_MARGIN = 30; |
742 | 843 |
743 /** | 844 /** |
744 * Layout mode: commit to DOM immediately. | 845 * Layout mode. |
| 846 * @enum {string} |
745 */ | 847 */ |
746 Mosaic.Layout.MODE_FINAL = 'final'; | 848 Mosaic.Layout.Mode = { |
747 | 849 // Commit to DOM immediately. |
748 /** | 850 FINAL: 'final', |
749 * Layout mode: do not commit layout to DOM until it is complete or the viewport | 851 // Do not commit layout to DOM until it is complete or the viewport |
750 * overflows. | 852 // overflows. |
751 */ | 853 TENTATIVE: 'tentative', |
752 Mosaic.Layout.MODE_TENTATIVE = 'tentative'; | 854 // Never commit layout to DOM. |
753 | 855 DRY_RUN: 'dry_run', |
754 /** | 856 }; |
755 * Layout mode: never commit layout to DOM. | |
756 */ | |
757 Mosaic.Layout.MODE_DRY_RUN = 'dry_run'; | |
758 | 857 |
759 /** | 858 /** |
760 * Resets the layout. | 859 * Resets the layout. |
761 * | 860 * |
762 * @private | 861 * @private |
763 */ | 862 */ |
764 Mosaic.Layout.prototype.reset_ = function() { | 863 Mosaic.Layout.prototype.reset_ = function() { |
765 this.columns_ = []; | 864 this.columns_ = []; |
766 this.newColumn_ = null; | 865 this.newColumn_ = null; |
767 this.density_ = Mosaic.Density.createLowest(); | 866 this.density_ = Mosaic.Density.createLowest(); |
768 if (this.mode_ !== Mosaic.Layout.MODE_DRY_RUN) // DRY_RUN is sticky. | 867 if (this.mode_ !== Mosaic.Layout.Mode.DRY_RUN) // DRY_RUN is sticky. |
769 this.mode_ = Mosaic.Layout.MODE_TENTATIVE; | 868 this.mode_ = Mosaic.Layout.Mode.TENTATIVE; |
770 }; | 869 }; |
771 | 870 |
772 /** | 871 /** |
773 * @param {number} width Viewport width. | 872 * @param {number} width Viewport width. |
774 * @param {number} height Viewport height. | 873 * @param {number} height Viewport height. |
775 */ | 874 */ |
776 Mosaic.Layout.prototype.setViewportSize = function(width, height) { | 875 Mosaic.Layout.prototype.setViewportSize = function(width, height) { |
777 this.viewportWidth_ = width; | 876 this.viewportWidth_ = width; |
778 this.viewportHeight_ = height; | 877 this.viewportHeight_ = height; |
779 this.reset_(); | 878 this.reset_(); |
780 }; | 879 }; |
781 | 880 |
782 /** | 881 /** |
783 * @return {number} Total width of the layout. | 882 * @return {number} Total width of the layout. |
784 */ | 883 */ |
785 Mosaic.Layout.prototype.getWidth = function() { | 884 Mosaic.Layout.prototype.getWidth = function() { |
786 var lastColumn = this.getLastColumn_(); | 885 var lastColumn = this.getLastColumn_(); |
787 return lastColumn ? lastColumn.getRight() : 0; | 886 return lastColumn ? lastColumn.getRight() : 0; |
788 }; | 887 }; |
789 | 888 |
790 /** | 889 /** |
791 * @return {number} Total height of the layout. | 890 * @return {number} Total height of the layout. |
792 */ | 891 */ |
793 Mosaic.Layout.prototype.getHeight = function() { | 892 Mosaic.Layout.prototype.getHeight = function() { |
794 var firstColumn = this.columns_[0]; | 893 var firstColumn = this.columns_[0]; |
795 return firstColumn ? firstColumn.getHeight() : 0; | 894 return firstColumn ? firstColumn.getHeight() : 0; |
796 }; | 895 }; |
797 | 896 |
798 /** | 897 /** |
799 * @return {Array.<Mosaic.Tile>} All tiles in the layout. | 898 * @return {!Array.<!Mosaic.Tile>} All tiles in the layout. |
800 */ | 899 */ |
801 Mosaic.Layout.prototype.getTiles = function() { | 900 Mosaic.Layout.prototype.getTiles = function() { |
802 return Array.prototype.concat.apply([], | 901 return Array.prototype.concat.apply([], |
803 this.columns_.map(function(c) { return c.getTiles(); })); | 902 this.columns_.map(function(c) { return c.getTiles(); })); |
804 }; | 903 }; |
805 | 904 |
806 /** | 905 /** |
807 * @return {number} Total number of tiles added to the layout. | 906 * @return {number} Total number of tiles added to the layout. |
808 */ | 907 */ |
809 Mosaic.Layout.prototype.getTileCount = function() { | 908 Mosaic.Layout.prototype.getTileCount = function() { |
(...skipping 13 matching lines...) Expand all Loading... |
823 * @return {number} Total number of tiles in completed columns. | 922 * @return {number} Total number of tiles in completed columns. |
824 */ | 923 */ |
825 Mosaic.Layout.prototype.getLaidOutTileCount = function() { | 924 Mosaic.Layout.prototype.getLaidOutTileCount = function() { |
826 var lastColumn = this.getLastColumn_(); | 925 var lastColumn = this.getLastColumn_(); |
827 return lastColumn ? lastColumn.getNextTileIndex() : 0; | 926 return lastColumn ? lastColumn.getNextTileIndex() : 0; |
828 }; | 927 }; |
829 | 928 |
830 /** | 929 /** |
831 * Adds a tile to the layout. | 930 * Adds a tile to the layout. |
832 * | 931 * |
833 * @param {Mosaic.Tile} tile The tile to be added. | 932 * @param {!Mosaic.Tile} tile The tile to be added. |
834 * @param {boolean} isLast True if this tile is the last. | 933 * @param {boolean} isLast True if this tile is the last. |
835 */ | 934 */ |
836 Mosaic.Layout.prototype.add = function(tile, isLast) { | 935 Mosaic.Layout.prototype.add = function(tile, isLast) { |
837 var layoutQueue = [tile]; | 936 var layoutQueue = [tile]; |
838 | 937 |
839 // There are two levels of backtracking in the layout algorithm. | 938 // There are two levels of backtracking in the layout algorithm. |
840 // |Mosaic.Layout.density_| tracks the state of the 'global' backtracking | 939 // |Mosaic.Layout.density_| tracks the state of the 'global' backtracking |
841 // which aims to use as much of the viewport space as possible. | 940 // which aims to use as much of the viewport space as possible. |
842 // It starts with the lowest density and increases it until the layout | 941 // It starts with the lowest density and increases it until the layout |
843 // fits into the viewport. If it does not fit even at the highest density, | 942 // fits into the viewport. If it does not fit even at the highest density, |
(...skipping 25 matching lines...) Expand all Loading... |
869 | 968 |
870 if (this.newColumn_.isSuboptimal()) { | 969 if (this.newColumn_.isSuboptimal()) { |
871 layoutQueue = this.newColumn_.getTiles().concat(layoutQueue); | 970 layoutQueue = this.newColumn_.getTiles().concat(layoutQueue); |
872 this.newColumn_.retryWithLowerDensity(); | 971 this.newColumn_.retryWithLowerDensity(); |
873 continue; | 972 continue; |
874 } | 973 } |
875 | 974 |
876 this.columns_.push(this.newColumn_); | 975 this.columns_.push(this.newColumn_); |
877 this.newColumn_ = null; | 976 this.newColumn_ = null; |
878 | 977 |
879 if (this.mode_ === Mosaic.Layout.MODE_FINAL && isFinalColumn) { | 978 if (this.mode_ === Mosaic.Layout.Mode.FINAL && isFinalColumn) { |
880 this.commit_(); | 979 this.commit_(); |
881 continue; | 980 continue; |
882 } | 981 } |
883 | 982 |
884 if (this.getWidth() > this.viewportWidth_) { | 983 if (this.getWidth() > this.viewportWidth_) { |
885 // Viewport completely filled. | 984 // Viewport completely filled. |
886 if (this.density_.equals(this.maxDensity_)) { | 985 if (this.density_.equals(this.maxDensity_)) { |
887 // Max density reached, commit if tentative, just continue if dry run. | 986 // Max density reached, commit if tentative, just continue if dry run. |
888 if (this.mode_ === Mosaic.Layout.MODE_TENTATIVE) | 987 if (this.mode_ === Mosaic.Layout.Mode.TENTATIVE) |
889 this.commit_(); | 988 this.commit_(); |
890 continue; | 989 continue; |
891 } | 990 } |
892 | 991 |
893 // Rollback the entire layout, retry with higher density. | 992 // Rollback the entire layout, retry with higher density. |
894 layoutQueue = this.getTiles().concat(layoutQueue); | 993 layoutQueue = this.getTiles().concat(layoutQueue); |
895 this.columns_ = []; | 994 this.columns_ = []; |
896 this.density_.increase(); | 995 this.density_.increase(); |
897 continue; | 996 continue; |
898 } | 997 } |
899 | 998 |
900 if (isFinalColumn && this.mode_ === Mosaic.Layout.MODE_TENTATIVE) { | 999 if (isFinalColumn && this.mode_ === Mosaic.Layout.Mode.TENTATIVE) { |
901 // The complete tentative layout fits into the viewport. | 1000 // The complete tentative layout fits into the viewport. |
902 var stretched = this.findHorizontalLayout_(); | 1001 var stretched = this.findHorizontalLayout_(); |
903 if (stretched) | 1002 if (stretched) |
904 this.columns_ = stretched.columns_; | 1003 this.columns_ = stretched.columns_; |
905 // Center the layout in the viewport and commit. | 1004 // Center the layout in the viewport and commit. |
906 this.commit_((this.viewportWidth_ - this.getWidth()) / 2, | 1005 this.commit_((this.viewportWidth_ - this.getWidth()) / 2, |
907 (this.viewportHeight_ - this.getHeight()) / 2); | 1006 (this.viewportHeight_ - this.getHeight()) / 2); |
908 } | 1007 } |
909 } | 1008 } |
910 }; | 1009 }; |
911 | 1010 |
912 /** | 1011 /** |
913 * Commits the tentative layout. | 1012 * Commits the tentative layout. |
914 * | 1013 * |
915 * @param {number=} opt_offsetX Horizontal offset. | 1014 * @param {number=} opt_offsetX Horizontal offset. |
916 * @param {number=} opt_offsetY Vertical offset. | 1015 * @param {number=} opt_offsetY Vertical offset. |
917 * @private | 1016 * @private |
918 */ | 1017 */ |
919 Mosaic.Layout.prototype.commit_ = function(opt_offsetX, opt_offsetY) { | 1018 Mosaic.Layout.prototype.commit_ = function(opt_offsetX, opt_offsetY) { |
920 for (var i = 0; i !== this.columns_.length; i++) { | 1019 for (var i = 0; i !== this.columns_.length; i++) { |
921 this.columns_[i].layout(opt_offsetX, opt_offsetY); | 1020 this.columns_[i].layout(opt_offsetX, opt_offsetY); |
922 } | 1021 } |
923 this.mode_ = Mosaic.Layout.MODE_FINAL; | 1022 this.mode_ = Mosaic.Layout.Mode.FINAL; |
924 }; | 1023 }; |
925 | 1024 |
926 /** | 1025 /** |
927 * Finds the most horizontally stretched layout built from the same tiles. | 1026 * Finds the most horizontally stretched layout built from the same tiles. |
928 * | 1027 * |
929 * The main layout algorithm fills the entire available viewport height. | 1028 * The main layout algorithm fills the entire available viewport height. |
930 * If there is too few tiles this results in a layout that is unnaturally | 1029 * If there is too few tiles this results in a layout that is unnaturally |
931 * stretched in the vertical direction. | 1030 * stretched in the vertical direction. |
932 * | 1031 * |
933 * This method tries a number of smaller heights and returns the most | 1032 * This method tries a number of smaller heights and returns the most |
(...skipping 11 matching lines...) Expand all Loading... |
945 | 1044 |
946 var tiles = this.getTiles(); | 1045 var tiles = this.getTiles(); |
947 if (tiles.length === 1) | 1046 if (tiles.length === 1) |
948 return null; // Single tile layout is always the same. | 1047 return null; // Single tile layout is always the same. |
949 | 1048 |
950 var tileHeights = tiles.map(function(t) { return t.getMaxContentHeight(); }); | 1049 var tileHeights = tiles.map(function(t) { return t.getMaxContentHeight(); }); |
951 var minTileHeight = Math.min.apply(null, tileHeights); | 1050 var minTileHeight = Math.min.apply(null, tileHeights); |
952 | 1051 |
953 for (var h = minTileHeight; h < this.viewportHeight_; h += minTileHeight) { | 1052 for (var h = minTileHeight; h < this.viewportHeight_; h += minTileHeight) { |
954 var layout = new Mosaic.Layout( | 1053 var layout = new Mosaic.Layout( |
955 Mosaic.Layout.MODE_DRY_RUN, this.density_.clone()); | 1054 Mosaic.Layout.Mode.DRY_RUN, this.density_.clone()); |
956 layout.setViewportSize(this.viewportWidth_, h); | 1055 layout.setViewportSize(this.viewportWidth_, h); |
957 for (var t = 0; t !== tiles.length; t++) | 1056 for (var t = 0; t !== tiles.length; t++) |
958 layout.add(tiles[t], t + 1 === tiles.length); | 1057 layout.add(tiles[t], t + 1 === tiles.length); |
959 | 1058 |
960 if (layout.getWidth() <= this.viewportWidth_) | 1059 if (layout.getWidth() <= this.viewportWidth_) |
961 return layout; | 1060 return layout; |
962 } | 1061 } |
963 | 1062 |
964 return null; | 1063 return null; |
965 }; | 1064 }; |
966 | 1065 |
967 /** | 1066 /** |
968 * Invalidates the layout after the given tile was modified (added, deleted or | 1067 * Invalidates the layout after the given tile was modified (added, deleted or |
969 * changed dimensions). | 1068 * changed dimensions). |
970 * | 1069 * |
971 * @param {number} index Tile index. | 1070 * @param {number} index Tile index. |
972 * @private | 1071 * @private |
973 */ | 1072 */ |
974 Mosaic.Layout.prototype.invalidateFromTile_ = function(index) { | 1073 Mosaic.Layout.prototype.invalidateFromTile_ = function(index) { |
975 var columnIndex = this.getColumnIndexByTile_(index); | 1074 var columnIndex = this.getColumnIndexByTile_(index); |
976 if (columnIndex < 0) | 1075 if (columnIndex < 0) |
977 return; // Index not in the layout, probably already invalidated. | 1076 return; // Index not in the layout, probably already invalidated. |
978 | 1077 |
979 if (this.columns_[columnIndex].getLeft() >= this.viewportWidth_) { | 1078 if (this.columns_[columnIndex].getLeft() >= this.viewportWidth_) { |
980 // The columns to the right cover the entire viewport width, so there is no | 1079 // The columns to the right cover the entire viewport width, so there is no |
981 // chance that the modified layout would fit into the viewport. | 1080 // chance that the modified layout would fit into the viewport. |
982 // No point in restarting the entire layout, keep the columns to the right. | 1081 // No point in restarting the entire layout, keep the columns to the right. |
983 console.assert(this.mode_ === Mosaic.Layout.MODE_FINAL, | 1082 console.assert(this.mode_ === Mosaic.Layout.Mode.FINAL, |
984 'Expected FINAL layout mode'); | 1083 'Expected FINAL layout mode'); |
985 this.columns_ = this.columns_.slice(0, columnIndex); | 1084 this.columns_ = this.columns_.slice(0, columnIndex); |
986 this.newColumn_ = null; | 1085 this.newColumn_ = null; |
987 } else { | 1086 } else { |
988 // There is a chance that the modified layout would fit into the viewport. | 1087 // There is a chance that the modified layout would fit into the viewport. |
989 this.reset_(); | 1088 this.reset_(); |
990 this.mode_ = Mosaic.Layout.MODE_TENTATIVE; | 1089 this.mode_ = Mosaic.Layout.Mode.TENTATIVE; |
991 } | 1090 } |
992 }; | 1091 }; |
993 | 1092 |
994 /** | 1093 /** |
995 * Gets the index of the tile to the left or to the right from the given tile. | 1094 * Gets the index of the tile to the left or to the right from the given tile. |
996 * | 1095 * |
997 * @param {number} index Tile index. | 1096 * @param {number} index Tile index. |
998 * @param {number} direction -1 for left, 1 for right. | 1097 * @param {number} direction -1 for left, 1 for right. |
999 * @return {number} Adjacent tile index. | 1098 * @return {number} Adjacent tile index. |
1000 */ | 1099 */ |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1092 return -1; | 1191 return -1; |
1093 }; | 1192 }; |
1094 | 1193 |
1095 /** | 1194 /** |
1096 * Scales the given array of size values to satisfy 3 conditions: | 1195 * Scales the given array of size values to satisfy 3 conditions: |
1097 * 1. The new sizes must be integer. | 1196 * 1. The new sizes must be integer. |
1098 * 2. The new sizes must sum up to the given |total| value. | 1197 * 2. The new sizes must sum up to the given |total| value. |
1099 * 3. The relative proportions of the sizes should be as close to the original | 1198 * 3. The relative proportions of the sizes should be as close to the original |
1100 * as possible. | 1199 * as possible. |
1101 * | 1200 * |
1102 * @param {Array.<number>} sizes Array of sizes. | 1201 * @param {!Array.<number>} sizes Array of sizes. |
1103 * @param {number} newTotal New total size. | 1202 * @param {number} newTotal New total size. |
1104 */ | 1203 */ |
1105 Mosaic.Layout.rescaleSizesToNewTotal = function(sizes, newTotal) { | 1204 Mosaic.Layout.rescaleSizesToNewTotal = function(sizes, newTotal) { |
1106 var total = 0; | 1205 var total = 0; |
1107 | 1206 |
1108 var partialTotals = [0]; | 1207 var partialTotals = [0]; |
1109 for (var i = 0; i !== sizes.length; i++) { | 1208 for (var i = 0; i !== sizes.length; i++) { |
1110 total += sizes[i]; | 1209 total += sizes[i]; |
1111 partialTotals.push(total); | 1210 partialTotals.push(total); |
1112 } | 1211 } |
1113 | 1212 |
1114 var scale = newTotal / total; | 1213 var scale = newTotal / total; |
1115 | 1214 |
1116 for (i = 0; i !== sizes.length; i++) { | 1215 for (i = 0; i !== sizes.length; i++) { |
1117 sizes[i] = Math.round(partialTotals[i + 1] * scale) - | 1216 sizes[i] = Math.round(partialTotals[i + 1] * scale) - |
1118 Math.round(partialTotals[i] * scale); | 1217 Math.round(partialTotals[i] * scale); |
1119 } | 1218 } |
1120 }; | 1219 }; |
1121 | 1220 |
1122 //////////////////////////////////////////////////////////////////////////////// | 1221 //////////////////////////////////////////////////////////////////////////////// |
1123 | 1222 |
1124 /** | 1223 /** |
1125 * Representation of the layout density. | 1224 * Representation of the layout density. |
1126 * | 1225 * |
1127 * @param {number} horizontal Horizontal density, number tiles per row. | 1226 * @param {number} horizontal Horizontal density, number tiles per row. |
1128 * @param {number} vertical Vertical density, frequency of rows forced to | 1227 * @param {number} vertical Vertical density, frequency of rows forced to |
1129 * contain a single tile. | 1228 * contain a single tile. |
1130 * @constructor | 1229 * @constructor |
| 1230 * @struct |
1131 */ | 1231 */ |
1132 Mosaic.Density = function(horizontal, vertical) { | 1232 Mosaic.Density = function(horizontal, vertical) { |
1133 this.horizontal = horizontal; | 1233 this.horizontal = horizontal; |
1134 this.vertical = vertical; | 1234 this.vertical = vertical; |
1135 }; | 1235 }; |
1136 | 1236 |
1137 /** | 1237 /** |
1138 * Minimal horizontal density (tiles per row). | 1238 * Minimal horizontal density (tiles per row). |
| 1239 * @type {number} |
| 1240 * @const |
1139 */ | 1241 */ |
1140 Mosaic.Density.MIN_HORIZONTAL = 1; | 1242 Mosaic.Density.MIN_HORIZONTAL = 1; |
1141 | 1243 |
1142 /** | 1244 /** |
1143 * Minimal horizontal density (tiles per row). | 1245 * Minimal horizontal density (tiles per row). |
| 1246 * @type {number} |
| 1247 * @const |
1144 */ | 1248 */ |
1145 Mosaic.Density.MAX_HORIZONTAL = 3; | 1249 Mosaic.Density.MAX_HORIZONTAL = 3; |
1146 | 1250 |
1147 /** | 1251 /** |
1148 * Minimal vertical density: force 1 out of 2 rows to containt a single tile. | 1252 * Minimal vertical density: force 1 out of 2 rows to containt a single tile. |
| 1253 * @type {number} |
| 1254 * @const |
1149 */ | 1255 */ |
1150 Mosaic.Density.MIN_VERTICAL = 2; | 1256 Mosaic.Density.MIN_VERTICAL = 2; |
1151 | 1257 |
1152 /** | 1258 /** |
1153 * Maximal vertical density: force 1 out of 3 rows to containt a single tile. | 1259 * Maximal vertical density: force 1 out of 3 rows to containt a single tile. |
| 1260 * @type {number} |
| 1261 * @const |
1154 */ | 1262 */ |
1155 Mosaic.Density.MAX_VERTICAL = 3; | 1263 Mosaic.Density.MAX_VERTICAL = 3; |
1156 | 1264 |
1157 /** | 1265 /** |
1158 * @return {Mosaic.Density} Lowest density. | 1266 * @return {!Mosaic.Density} Lowest density. |
1159 */ | 1267 */ |
1160 Mosaic.Density.createLowest = function() { | 1268 Mosaic.Density.createLowest = function() { |
1161 return new Mosaic.Density( | 1269 return new Mosaic.Density( |
1162 Mosaic.Density.MIN_HORIZONTAL, | 1270 Mosaic.Density.MIN_HORIZONTAL, |
1163 Mosaic.Density.MIN_VERTICAL /* ignored when horizontal is at min */); | 1271 Mosaic.Density.MIN_VERTICAL /* ignored when horizontal is at min */); |
1164 }; | 1272 }; |
1165 | 1273 |
1166 /** | 1274 /** |
1167 * @return {Mosaic.Density} Highest density. | 1275 * @return {!Mosaic.Density} Highest density. |
1168 */ | 1276 */ |
1169 Mosaic.Density.createHighest = function() { | 1277 Mosaic.Density.createHighest = function() { |
1170 return new Mosaic.Density( | 1278 return new Mosaic.Density( |
1171 Mosaic.Density.MAX_HORIZONTAL, | 1279 Mosaic.Density.MAX_HORIZONTAL, |
1172 Mosaic.Density.MAX_VERTICAL); | 1280 Mosaic.Density.MAX_VERTICAL); |
1173 }; | 1281 }; |
1174 | 1282 |
1175 /** | 1283 /** |
1176 * @return {Mosaic.Density} A clone of this density object. | 1284 * @return {!Mosaic.Density} A clone of this density object. |
1177 */ | 1285 */ |
1178 Mosaic.Density.prototype.clone = function() { | 1286 Mosaic.Density.prototype.clone = function() { |
1179 return new Mosaic.Density(this.horizontal, this.vertical); | 1287 return new Mosaic.Density(this.horizontal, this.vertical); |
1180 }; | 1288 }; |
1181 | 1289 |
1182 /** | 1290 /** |
1183 * @param {Mosaic.Density} that The other object. | 1291 * @param {!Mosaic.Density} that The other object. |
1184 * @return {boolean} True if equal. | 1292 * @return {boolean} True if equal. |
1185 */ | 1293 */ |
1186 Mosaic.Density.prototype.equals = function(that) { | 1294 Mosaic.Density.prototype.equals = function(that) { |
1187 return this.horizontal === that.horizontal && | 1295 return this.horizontal === that.horizontal && |
1188 this.vertical === that.vertical; | 1296 this.vertical === that.vertical; |
1189 }; | 1297 }; |
1190 | 1298 |
1191 /** | 1299 /** |
1192 * Increases the density to the next level. | 1300 * Increases the density to the next level. |
1193 */ | 1301 */ |
(...skipping 28 matching lines...) Expand all Loading... |
1222 //////////////////////////////////////////////////////////////////////////////// | 1330 //////////////////////////////////////////////////////////////////////////////// |
1223 | 1331 |
1224 /** | 1332 /** |
1225 * A column in a mosaic layout. Contains rows. | 1333 * A column in a mosaic layout. Contains rows. |
1226 * | 1334 * |
1227 * @param {number} index Column index. | 1335 * @param {number} index Column index. |
1228 * @param {number} firstRowIndex Global row index. | 1336 * @param {number} firstRowIndex Global row index. |
1229 * @param {number} firstTileIndex Index of the first tile in the column. | 1337 * @param {number} firstTileIndex Index of the first tile in the column. |
1230 * @param {number} left Left edge coordinate. | 1338 * @param {number} left Left edge coordinate. |
1231 * @param {number} maxHeight Maximum height. | 1339 * @param {number} maxHeight Maximum height. |
1232 * @param {Mosaic.Density} density Layout density. | 1340 * @param {!Mosaic.Density} density Layout density. |
1233 * @constructor | 1341 * @constructor |
| 1342 * @struct |
1234 */ | 1343 */ |
1235 Mosaic.Column = function(index, firstRowIndex, firstTileIndex, left, maxHeight, | 1344 Mosaic.Column = function(index, firstRowIndex, firstTileIndex, left, maxHeight, |
1236 density) { | 1345 density) { |
1237 this.index_ = index; | 1346 this.index_ = index; |
1238 this.firstRowIndex_ = firstRowIndex; | 1347 this.firstRowIndex_ = firstRowIndex; |
1239 this.firstTileIndex_ = firstTileIndex; | 1348 this.firstTileIndex_ = firstTileIndex; |
1240 this.left_ = left; | 1349 this.left_ = left; |
1241 this.maxHeight_ = maxHeight; | 1350 this.maxHeight_ = maxHeight; |
1242 this.density_ = density; | 1351 this.density_ = density; |
1243 | 1352 |
| 1353 /** |
| 1354 * @type {number} |
| 1355 * @private |
| 1356 */ |
| 1357 this.width_ = 0; |
| 1358 |
| 1359 /** |
| 1360 * @type {!Array.<!Mosaic.Tile>} |
| 1361 * @private |
| 1362 */ |
| 1363 this.tiles_ = []; |
| 1364 |
| 1365 /** |
| 1366 * @type {!Array.<!Mosaic.Row>} |
| 1367 * @private |
| 1368 */ |
| 1369 this.rows_ = []; |
| 1370 |
| 1371 /** |
| 1372 * @type {Mosaic.Row} |
| 1373 * @private |
| 1374 */ |
| 1375 this.newRow_ = null; |
| 1376 |
| 1377 /** |
| 1378 * @type {!Array.<number>} |
| 1379 * @private |
| 1380 */ |
| 1381 this.rowHeights_ = []; |
| 1382 |
| 1383 /** |
| 1384 * @type {number} |
| 1385 * @private |
| 1386 */ |
| 1387 this.height_ = 0; |
| 1388 |
1244 this.reset_(); | 1389 this.reset_(); |
1245 }; | 1390 }; |
1246 | 1391 |
1247 /** | 1392 /** |
1248 * Resets the layout. | 1393 * Resets the layout. |
1249 * @private | 1394 * @private |
1250 */ | 1395 */ |
1251 Mosaic.Column.prototype.reset_ = function() { | 1396 Mosaic.Column.prototype.reset_ = function() { |
1252 this.tiles_ = []; | 1397 this.tiles_ = []; |
1253 this.rows_ = []; | 1398 this.rows_ = []; |
(...skipping 13 matching lines...) Expand all Loading... |
1267 }; | 1412 }; |
1268 | 1413 |
1269 /** | 1414 /** |
1270 * @return {number} Global index of the last row + 1. | 1415 * @return {number} Global index of the last row + 1. |
1271 */ | 1416 */ |
1272 Mosaic.Column.prototype.getNextRowIndex = function() { | 1417 Mosaic.Column.prototype.getNextRowIndex = function() { |
1273 return this.firstRowIndex_ + this.rows_.length; | 1418 return this.firstRowIndex_ + this.rows_.length; |
1274 }; | 1419 }; |
1275 | 1420 |
1276 /** | 1421 /** |
1277 * @return {Array.<Mosaic.Tile>} Array of tiles in the column. | 1422 * @return {!Array.<!Mosaic.Tile>} Array of tiles in the column. |
1278 */ | 1423 */ |
1279 Mosaic.Column.prototype.getTiles = function() { return this.tiles_ }; | 1424 Mosaic.Column.prototype.getTiles = function() { return this.tiles_ }; |
1280 | 1425 |
1281 /** | 1426 /** |
1282 * @param {number} index Tile index. | 1427 * @param {number} index Tile index. |
1283 * @return {boolean} True if this column contains the tile with the given index. | 1428 * @return {boolean} True if this column contains the tile with the given index. |
1284 */ | 1429 */ |
1285 Mosaic.Column.prototype.hasTile = function(index) { | 1430 Mosaic.Column.prototype.hasTile = function(index) { |
1286 return this.firstTileIndex_ <= index && | 1431 return this.firstTileIndex_ <= index && |
1287 index < (this.firstTileIndex_ + this.getTileCount()); | 1432 index < (this.firstTileIndex_ + this.getTileCount()); |
(...skipping 22 matching lines...) Expand all Loading... |
1310 for (var r = 0; r !== this.rows_.length; r++) { | 1455 for (var r = 0; r !== this.rows_.length; r++) { |
1311 if (this.rows_[r].hasTile(index)) | 1456 if (this.rows_[r].hasTile(index)) |
1312 return this.rows_[r]; | 1457 return this.rows_[r]; |
1313 } | 1458 } |
1314 return null; | 1459 return null; |
1315 }; | 1460 }; |
1316 | 1461 |
1317 /** | 1462 /** |
1318 * Adds a tile to the column. | 1463 * Adds a tile to the column. |
1319 * | 1464 * |
1320 * @param {Mosaic.Tile} tile The tile to add. | 1465 * @param {!Mosaic.Tile} tile The tile to add. |
1321 */ | 1466 */ |
1322 Mosaic.Column.prototype.add = function(tile) { | 1467 Mosaic.Column.prototype.add = function(tile) { |
1323 var rowIndex = this.getNextRowIndex(); | 1468 var rowIndex = this.getNextRowIndex(); |
1324 | 1469 |
1325 if (!this.newRow_) | 1470 if (!this.newRow_) |
1326 this.newRow_ = new Mosaic.Row(this.getNextTileIndex()); | 1471 this.newRow_ = new Mosaic.Row(this.getNextTileIndex()); |
1327 | 1472 |
1328 this.tiles_.push(tile); | 1473 this.tiles_.push(tile); |
1329 this.newRow_.add(tile); | 1474 this.newRow_.add(tile); |
1330 | 1475 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1454 return false; | 1599 return false; |
1455 }; | 1600 }; |
1456 | 1601 |
1457 //////////////////////////////////////////////////////////////////////////////// | 1602 //////////////////////////////////////////////////////////////////////////////// |
1458 | 1603 |
1459 /** | 1604 /** |
1460 * A row in a mosaic layout. Contains tiles. | 1605 * A row in a mosaic layout. Contains tiles. |
1461 * | 1606 * |
1462 * @param {number} firstTileIndex Index of the first tile in the row. | 1607 * @param {number} firstTileIndex Index of the first tile in the row. |
1463 * @constructor | 1608 * @constructor |
| 1609 * @struct |
1464 */ | 1610 */ |
1465 Mosaic.Row = function(firstTileIndex) { | 1611 Mosaic.Row = function(firstTileIndex) { |
1466 this.firstTileIndex_ = firstTileIndex; | 1612 this.firstTileIndex_ = firstTileIndex; |
1467 this.tiles_ = []; | 1613 this.tiles_ = []; |
| 1614 |
| 1615 /** |
| 1616 * @type {number} |
| 1617 * @private |
| 1618 */ |
| 1619 this.top_ = 0; |
| 1620 |
| 1621 /** |
| 1622 * @type {number} |
| 1623 * @private |
| 1624 */ |
| 1625 this.height_ = 0; |
1468 }; | 1626 }; |
1469 | 1627 |
1470 /** | 1628 /** |
1471 * @param {Mosaic.Tile} tile The tile to add. | 1629 * @param {!Mosaic.Tile} tile The tile to add. |
1472 */ | 1630 */ |
1473 Mosaic.Row.prototype.add = function(tile) { | 1631 Mosaic.Row.prototype.add = function(tile) { |
1474 console.assert(this.getTileCount() < Mosaic.Density.MAX_HORIZONTAL); | 1632 console.assert(this.getTileCount() < Mosaic.Density.MAX_HORIZONTAL); |
1475 this.tiles_.push(tile); | 1633 this.tiles_.push(tile); |
1476 }; | 1634 }; |
1477 | 1635 |
1478 /** | 1636 /** |
1479 * @return {Array.<Mosaic.Tile>} Array of tiles in the row. | 1637 * @return {!Array.<!Mosaic.Tile>} Array of tiles in the row. |
1480 */ | 1638 */ |
1481 Mosaic.Row.prototype.getTiles = function() { return this.tiles_ }; | 1639 Mosaic.Row.prototype.getTiles = function() { return this.tiles_ }; |
1482 | 1640 |
1483 /** | 1641 /** |
1484 * Gets a tile by index. | 1642 * Gets a tile by index. |
1485 * @param {number} index Tile index. | 1643 * @param {number} index Tile index. |
1486 * @return {Mosaic.Tile} Requested tile or null if not found. | 1644 * @return {Mosaic.Tile} Requested tile or null if not found. |
1487 */ | 1645 */ |
1488 Mosaic.Row.prototype.getTileByIndex = function(index) { | 1646 Mosaic.Row.prototype.getTileByIndex = function(index) { |
1489 if (!this.hasTile(index)) | 1647 if (!this.hasTile(index)) |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1609 this.tiles_[t].layout(tileLeft, top, tileWidth, height); | 1767 this.tiles_[t].layout(tileLeft, top, tileWidth, height); |
1610 tileLeft += tileWidth; | 1768 tileLeft += tileWidth; |
1611 } | 1769 } |
1612 }; | 1770 }; |
1613 | 1771 |
1614 //////////////////////////////////////////////////////////////////////////////// | 1772 //////////////////////////////////////////////////////////////////////////////// |
1615 | 1773 |
1616 /** | 1774 /** |
1617 * A single tile of the image mosaic. | 1775 * A single tile of the image mosaic. |
1618 * | 1776 * |
1619 * @param {Element} container Container element. | 1777 * @param {!Element} container Container element. |
1620 * @param {Gallery.Item} item Gallery item associated with this tile. | 1778 * @param {!Gallery.Item} item Gallery item associated with this tile. |
1621 * @param {EntryLocation} locationInfo Location information for the tile. | 1779 * @param {EntryLocation=} opt_locationInfo Location information for the tile. |
1622 * @return {Element} The new tile element. | 1780 * @return {!Element} The new tile element. |
1623 * @constructor | 1781 * @constructor |
| 1782 * @extends {HTMLDivElement} |
| 1783 * @struct |
| 1784 * @suppress {checkStructDictInheritance} |
1624 */ | 1785 */ |
1625 Mosaic.Tile = function(container, item, locationInfo) { | 1786 Mosaic.Tile = function(container, item, opt_locationInfo) { |
1626 var self = container.ownerDocument.createElement('div'); | 1787 var self = container.ownerDocument.createElement('div'); |
1627 Mosaic.Tile.decorate(self, container, item, locationInfo); | 1788 Mosaic.Tile.decorate(self, container, item, opt_locationInfo); |
1628 return self; | 1789 return self; |
1629 }; | 1790 }; |
1630 | 1791 |
1631 /** | 1792 /** |
1632 * @param {Element} self Self pointer. | 1793 * @param {!Element} self Self pointer. |
1633 * @param {Element} container Container element. | 1794 * @param {!Element} container Container element. |
1634 * @param {Gallery.Item} item Gallery item associated with this tile. | 1795 * @param {!Gallery.Item} item Gallery item associated with this tile. |
1635 * @param {EntryLocation} locationInfo Location info for the tile image. | 1796 * @param {EntryLocation=} opt_locationInfo Location info for the tile image. |
1636 */ | 1797 */ |
1637 Mosaic.Tile.decorate = function(self, container, item, locationInfo) { | 1798 Mosaic.Tile.decorate = function(self, container, item, opt_locationInfo) { |
1638 self.__proto__ = Mosaic.Tile.prototype; | 1799 self.__proto__ = Mosaic.Tile.prototype; |
| 1800 self = /** @type {!Mosaic.Tile} */ (self); |
1639 self.className = 'mosaic-tile'; | 1801 self.className = 'mosaic-tile'; |
1640 | 1802 |
1641 self.container_ = container; | 1803 self.container_ = container; |
1642 self.item_ = item; | 1804 self.item_ = item; |
| 1805 self.hidpiEmbedded_ = opt_locationInfo && opt_locationInfo.isDriveBased; |
| 1806 |
| 1807 /** |
| 1808 * @type {?number} |
| 1809 * @private |
| 1810 */ |
1643 self.left_ = null; // Mark as not laid out. | 1811 self.left_ = null; // Mark as not laid out. |
1644 self.hidpiEmbedded_ = locationInfo && locationInfo.isDriveBased; | 1812 |
| 1813 /** |
| 1814 * @type {number} |
| 1815 * @private |
| 1816 */ |
| 1817 self.top_ = 0; |
| 1818 |
| 1819 /** |
| 1820 * @type {number} |
| 1821 * @private |
| 1822 */ |
| 1823 self.width_ = 0; |
| 1824 |
| 1825 /** |
| 1826 * @type {number} |
| 1827 * @private |
| 1828 */ |
| 1829 self.height_ = 0; |
| 1830 |
| 1831 /** |
| 1832 * @type {number} |
| 1833 * @private |
| 1834 */ |
| 1835 self.maxContentHeight_ = 0; |
| 1836 |
| 1837 /** |
| 1838 * @type {number} |
| 1839 * @private |
| 1840 */ |
| 1841 self.aspectRatio_ = 0; |
| 1842 |
| 1843 /** |
| 1844 * @type {ThumbnailLoader} |
| 1845 * @private |
| 1846 */ |
| 1847 self.thumbnailPreloader_ = null; |
| 1848 |
| 1849 /** |
| 1850 * @type {ThumbnailLoader} |
| 1851 * @private |
| 1852 */ |
| 1853 self.thumbnailLoader_ = null; |
| 1854 |
| 1855 /** |
| 1856 * @type {boolean} |
| 1857 * @private |
| 1858 */ |
| 1859 self.imagePreloaded_ = false; |
| 1860 |
| 1861 /** |
| 1862 * @type {boolean} |
| 1863 * @private |
| 1864 */ |
| 1865 self.imageLoaded_ = false; |
| 1866 |
| 1867 /** |
| 1868 * @type {boolean} |
| 1869 * @private |
| 1870 */ |
| 1871 self.imagePreloading_ = false; |
| 1872 |
| 1873 /** |
| 1874 * @type {boolean} |
| 1875 * @private |
| 1876 */ |
| 1877 self.imageLoading_ = false; |
| 1878 |
| 1879 /** |
| 1880 * @type {HTMLDivElement} |
| 1881 * @private |
| 1882 */ |
| 1883 self.wrapper_ = null; |
1645 }; | 1884 }; |
1646 | 1885 |
1647 /** | 1886 /** |
1648 * Load mode for the tile's image. | 1887 * Load mode for the tile's image. |
1649 * @enum {number} | 1888 * @enum {number} |
1650 */ | 1889 */ |
1651 Mosaic.Tile.LoadMode = { | 1890 Mosaic.Tile.LoadMode = { |
1652 LOW_DPI: 0, | 1891 LOW_DPI: 0, |
1653 HIGH_DPI: 1 | 1892 HIGH_DPI: 1 |
1654 }; | 1893 }; |
1655 | 1894 |
1656 /** | 1895 /** |
1657 * Inherit from HTMLDivElement. | 1896 * Inherit from HTMLDivElement. |
1658 */ | 1897 */ |
1659 Mosaic.Tile.prototype.__proto__ = HTMLDivElement.prototype; | 1898 Mosaic.Tile.prototype.__proto__ = HTMLDivElement.prototype; |
1660 | 1899 |
1661 /** | 1900 /** |
1662 * Minimum tile content size. | 1901 * Minimum tile content size. |
| 1902 * @type {number} |
| 1903 * @const |
1663 */ | 1904 */ |
1664 Mosaic.Tile.MIN_CONTENT_SIZE = 64; | 1905 Mosaic.Tile.MIN_CONTENT_SIZE = 64; |
1665 | 1906 |
1666 /** | 1907 /** |
1667 * Maximum tile content size. | 1908 * Maximum tile content size. |
| 1909 * @type {number} |
| 1910 * @const |
1668 */ | 1911 */ |
1669 Mosaic.Tile.MAX_CONTENT_SIZE = 512; | 1912 Mosaic.Tile.MAX_CONTENT_SIZE = 512; |
1670 | 1913 |
1671 /** | 1914 /** |
1672 * Default size for a tile with no thumbnail image. | 1915 * Default size for a tile with no thumbnail image. |
| 1916 * @type {number} |
| 1917 * @const |
1673 */ | 1918 */ |
1674 Mosaic.Tile.GENERIC_ICON_SIZE = 128; | 1919 Mosaic.Tile.GENERIC_ICON_SIZE = 128; |
1675 | 1920 |
1676 /** | 1921 /** |
1677 * Max size of an image considered to be 'small'. | 1922 * Max size of an image considered to be 'small'. |
1678 * Small images are laid out slightly differently. | 1923 * Small images are laid out slightly differently. |
| 1924 * @type {number} |
| 1925 * @const |
1679 */ | 1926 */ |
1680 Mosaic.Tile.SMALL_IMAGE_SIZE = 160; | 1927 Mosaic.Tile.SMALL_IMAGE_SIZE = 160; |
1681 | 1928 |
1682 /** | 1929 /** |
1683 * @return {Gallery.Item} The Gallery item. | 1930 * @return {!Gallery.Item} The Gallery item. |
1684 */ | 1931 */ |
1685 Mosaic.Tile.prototype.getItem = function() { return this.item_; }; | 1932 Mosaic.Tile.prototype.getItem = function() { return this.item_; }; |
1686 | 1933 |
1687 /** | 1934 /** |
1688 * @return {number} Maximum content height that this tile can have. | 1935 * @return {number} Maximum content height that this tile can have. |
1689 */ | 1936 */ |
1690 Mosaic.Tile.prototype.getMaxContentHeight = function() { | 1937 Mosaic.Tile.prototype.getMaxContentHeight = function() { |
1691 return this.maxContentHeight_; | 1938 return this.maxContentHeight_; |
1692 }; | 1939 }; |
1693 | 1940 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1836 * Loads an image into the tile. | 2083 * Loads an image into the tile. |
1837 * | 2084 * |
1838 * The mode argument is a hint. Use low-dpi for faster response, and high-dpi | 2085 * The mode argument is a hint. Use low-dpi for faster response, and high-dpi |
1839 * for better output, but possibly affecting performance. | 2086 * for better output, but possibly affecting performance. |
1840 * | 2087 * |
1841 * If the mode is high-dpi, then a the high-dpi image is loaded, but also | 2088 * If the mode is high-dpi, then a the high-dpi image is loaded, but also |
1842 * low-dpi image is loaded for preloading (if available). | 2089 * low-dpi image is loaded for preloading (if available). |
1843 * For the low-dpi mode, only low-dpi image is loaded. If not available, then | 2090 * For the low-dpi mode, only low-dpi image is loaded. If not available, then |
1844 * the high-dpi image is loaded as a fallback. | 2091 * the high-dpi image is loaded as a fallback. |
1845 * | 2092 * |
1846 * @param {Mosaic.Tile.LoadMode} loadMode Loading mode. | 2093 * @param {!Mosaic.Tile.LoadMode} loadMode Loading mode. |
1847 * @param {function(boolean)} onImageLoaded Callback when image is loaded. | 2094 * @param {function(boolean)} onImageLoaded Callback when image is loaded. |
1848 * The argument is true for success, false for failure. | 2095 * The argument is true for success, false for failure. |
1849 */ | 2096 */ |
1850 Mosaic.Tile.prototype.load = function(loadMode, onImageLoaded) { | 2097 Mosaic.Tile.prototype.load = function(loadMode, onImageLoaded) { |
1851 // Attaches the image to the tile and finalizes loading process for the | 2098 // Attaches the image to the tile and finalizes loading process for the |
1852 // specified loader. | 2099 // specified loader. |
1853 var finalizeLoader = function(mode, success, loader) { | 2100 var finalizeLoader = function(mode, success, loader) { |
1854 if (success && this.wrapper_) { | 2101 if (success && this.wrapper_) { |
1855 // Show the fade-in animation only when previously there was no image | 2102 // Show the fade-in animation only when previously there was no image |
1856 // attached in this tile. | 2103 // attached in this tile. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1944 this.height_ = height; | 2191 this.height_ = height; |
1945 | 2192 |
1946 this.style.left = left + 'px'; | 2193 this.style.left = left + 'px'; |
1947 this.style.top = top + 'px'; | 2194 this.style.top = top + 'px'; |
1948 this.style.width = width + 'px'; | 2195 this.style.width = width + 'px'; |
1949 this.style.height = height + 'px'; | 2196 this.style.height = height + 'px'; |
1950 | 2197 |
1951 if (!this.wrapper_) { // First time, create DOM. | 2198 if (!this.wrapper_) { // First time, create DOM. |
1952 this.container_.appendChild(this); | 2199 this.container_.appendChild(this); |
1953 var border = util.createChild(this, 'img-border'); | 2200 var border = util.createChild(this, 'img-border'); |
1954 this.wrapper_ = util.createChild(border, 'img-wrapper'); | 2201 this.wrapper_ = assertInstanceof(util.createChild(border, 'img-wrapper'), |
| 2202 HTMLDivElement); |
1955 } | 2203 } |
1956 if (this.hasAttribute('selected')) | 2204 if (this.hasAttribute('selected')) |
1957 this.scrollIntoView(false); | 2205 this.scrollIntoView(false); |
1958 | 2206 |
1959 if (this.imageLoaded_) { | 2207 if (this.imageLoaded_) { |
1960 this.thumbnailLoader_.attachImage(this.wrapper_, | 2208 this.thumbnailLoader_.attachImage(this.wrapper_, |
1961 ThumbnailLoader.FillMode.OVER_FILL); | 2209 ThumbnailLoader.FillMode.OVER_FILL); |
1962 } | 2210 } |
1963 }; | 2211 }; |
1964 | 2212 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2002 return new ImageRect(this.left_ - this.container_.scrollLeft, this.top_, | 2250 return new ImageRect(this.left_ - this.container_.scrollLeft, this.top_, |
2003 this.width_, this.height_).inflate(-margin, -margin); | 2251 this.width_, this.height_).inflate(-margin, -margin); |
2004 }; | 2252 }; |
2005 | 2253 |
2006 /** | 2254 /** |
2007 * @return {number} X coordinate of the tile center. | 2255 * @return {number} X coordinate of the tile center. |
2008 */ | 2256 */ |
2009 Mosaic.Tile.prototype.getCenterX = function() { | 2257 Mosaic.Tile.prototype.getCenterX = function() { |
2010 return this.left_ + Math.round(this.width_ / 2); | 2258 return this.left_ + Math.round(this.width_ / 2); |
2011 }; | 2259 }; |
OLD | NEW |