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

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

Issue 805723003: Add type annotations to gallery/js/mosaic_mode.js. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed annotations of Mosaic.transform. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 };
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698