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

Side by Side Diff: chrome/browser/resources/ntp_search/tile_page.js

Issue 10829131: Refactoring NTP5: new implementation of TilePage and MostVisitedPage (which now inherits from Thumb… (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('ntp', function() { 5 cr.define('ntp', function() {
6 'use strict'; 6 'use strict';
7 7
8
9 function Tile(gridValues) {
10 throw 'Tile is a virtual class and is not supposed to be instantiated';
11 }
12
13 Tile.subclass = function(Subclass) {
14 var Base = Tile.prototype;
15 for (var name in Base) {
16 if (!Subclass.hasOwnProperty(name)) {
17 Subclass[name] = Base[name];
18 }
19 }
20 for (var name in TileGetters) {
21 if (!Subclass.hasOwnProperty(name)) {
22 Subclass.__defineGetter__(name, TileGetters[name]);
23 }
24 }
25 return Subclass;
26 };
27
28 Tile.prototype = {
29 initialize: function(gridValues) {
30 // TODO: rename to tile
31 this.className = 'tile-content ' + gridValues.tileClassName;
32
33 // TODO set using CSS?
34 if (gridValues.reinforceStyles) {
35 var style = this.style;
36 style.width = gridValues.tileWidth + 'px';
37 style.height = gridValues.tileHeight + 'px';
38 style.borderWidth = gridValues.tileBorderWidth + 'px';
39 }
40 },
41
42 tearDown_: function() {
43 },
44 };
45
46 var TileGetters = {
47 'tile': function() {
48 return findAncestorByClass(this, 'tile-cell');
49 },
50 'index': function() {
51 return this.tile.index;
52 }
53 };
54
55
56
8 // We can't pass the currently dragging tile via dataTransfer because of 57 // We can't pass the currently dragging tile via dataTransfer because of
9 // http://crbug.com/31037 58 // http://crbug.com/31037
59 // TODO(xci) drag
10 var currentlyDraggingTile = null; 60 var currentlyDraggingTile = null;
11 function getCurrentlyDraggingTile() { 61 function getCurrentlyDraggingTile() {
12 return currentlyDraggingTile; 62 return currentlyDraggingTile;
13 } 63 }
14 function setCurrentlyDraggingTile(tile) { 64 function setCurrentlyDraggingTile(tile) {
15 currentlyDraggingTile = tile; 65 currentlyDraggingTile = tile;
16 if (tile) 66 if (tile)
17 ntp.enterRearrangeMode(); 67 ntp.enterRearrangeMode();
18 else 68 else
19 ntp.leaveRearrangeMode(); 69 ntp.leaveRearrangeMode();
20 } 70 }
21 71
22 /** 72 /**
23 * Changes the current dropEffect of a drag. This modifies the native cursor 73 * Changes the current dropEffect of a drag. This modifies the native cursor
24 * and serves as an indicator of what we should do at the end of the drag as 74 * and serves as an indicator of what we should do at the end of the drag as
25 * well as give indication to the user if a drop would succeed if they let go. 75 * well as give indication to the user if a drop would succeed if they let go.
26 * @param {DataTransfer} dataTransfer A dataTransfer object from a drag event. 76 * @param {DataTransfer} dataTransfer A dataTransfer object from a drag event.
27 * @param {string} effect A drop effect to change to (i.e. copy, move, none). 77 * @param {string} effect A drop effect to change to (i.e. copy, move, none).
28 */ 78 */
79 // TODO(xci) drag
29 function setCurrentDropEffect(dataTransfer, effect) { 80 function setCurrentDropEffect(dataTransfer, effect) {
30 dataTransfer.dropEffect = effect; 81 dataTransfer.dropEffect = effect;
31 if (currentlyDraggingTile) 82 if (currentlyDraggingTile)
32 currentlyDraggingTile.lastDropEffect = dataTransfer.dropEffect; 83 currentlyDraggingTile.lastDropEffect = dataTransfer.dropEffect;
33 } 84 }
34 85
35 /** 86 /**
36 * Creates a new Tile object. Tiles wrap content on a TilePage, providing 87 * Creates a new TileCell object. Tiles wrap content on a TilePage, providing
37 * some styling and drag functionality. 88 * some styling and drag functionality.
38 * @constructor 89 * @constructor
39 * @extends {HTMLDivElement} 90 * @extends {HTMLDivElement}
40 */ 91 */
41 function Tile(contents) { 92 function TileCell(tile, gridValues) {
jeremycho_google 2012/08/02 00:19:11 Since we're planning to remove drag functionality,
pedrosimonetti2 2012/08/03 18:14:12 No, we need TileCell class because it will handle
42 var tile = cr.doc.createElement('div'); 93 var tileCell = cr.doc.createElement('div');
43 tile.__proto__ = Tile.prototype; 94 tileCell.__proto__ = TileCell.prototype;
44 tile.initialize(contents); 95 tileCell.initialize(tile, gridValues);
45 96
46 return tile; 97 return tileCell;
47 } 98 }
48 99
49 Tile.prototype = { 100 TileCell.prototype = {
50 __proto__: HTMLDivElement.prototype, 101 __proto__: HTMLDivElement.prototype,
51 102
52 initialize: function(contents) { 103 initialize: function(tile, gridValues) {
53 // 'real' as opposed to doppleganger. 104 // 'real' as opposed to doppleganger.
54 this.className = 'tile real'; 105 // TODO: rename to tile-cell
jeremycho_google 2012/08/02 00:19:11 Delete?
pedrosimonetti2 2012/08/03 18:14:12 Done.
55 this.appendChild(contents); 106 this.className = 'tile-cell real';
56 contents.tile = this;
57 107
58 this.addEventListener('dragstart', this.onDragStart_); 108 if (gridValues.reinforceStyles) {
59 this.addEventListener('drag', this.onDragMove_); 109 var style = this.style;
60 this.addEventListener('dragend', this.onDragEnd_); 110 var borderWidth = 2 * gridValues.tileBorderWidth;
111 style.width = gridValues.tileWidth + borderWidth + 'px';
112 style.height = gridValues.tileHeight + borderWidth + 'px';
113 style.marginLeft = gridValues.tileHorMargin + 'px';
jeremycho_google 2012/08/02 00:19:11 i88n?
pedrosimonetti2 2012/08/03 18:14:12 What do you mean here? On 2012/08/02 00:19:11, je
114 style.marginBottom = gridValues.tileVerMargin + 'px';
115 }
61 116
62 this.firstChild.addEventListener( 117 this.assign_(tile);
63 'webkitAnimationEnd', this.onContentsAnimationEnd_.bind(this));
64
65 this.eventTracker = new EventTracker();
66 }, 118 },
67 119
68 get index() { 120 get index() {
69 return Array.prototype.indexOf.call(this.tilePage.tileElements_, this); 121 return Array.prototype.indexOf.call(this.tilePage.tileElements_,
122 this.firstChild);
70 }, 123 },
71 124
72 get tilePage() { 125 get tilePage() {
73 return findAncestorByClass(this, 'tile-page'); 126 return findAncestorByClass(this, 'tile-page');
74 }, 127 },
75 128
76 /** 129 assign_: function(tile) {
77 * Position the tile at |x, y|, and store this as the grid location, i.e. 130 if (this.firstChild) {
78 * where the tile 'belongs' when it's not being dragged. 131 this.replaceChild(tile, this.firstChild);
79 * @param {number} x The x coordinate, in pixels. 132 } else {
80 * @param {number} y The y coordinate, in pixels. 133 this.appendChild(tile);
81 */ 134 }
82 setGridPosition: function(x, y) { 135 },
83 this.gridX = x; 136
84 this.gridY = y; 137 tearDown_: function() {
85 this.moveTo(x, y);
86 }, 138 },
87 139
88 /** 140 /**
89 * Position the tile at |x, y|.
90 * @param {number} x The x coordinate, in pixels.
91 * @param {number} y The y coordinate, in pixels.
92 */
93 moveTo: function(x, y) {
94 // left overrides right in LTR, and right takes precedence in RTL.
95 this.style.left = toCssPx(x);
96 this.style.right = toCssPx(x);
97 this.style.top = toCssPx(y);
98 },
99
100 /**
101 * The handler for dragstart events fired on |this|. 141 * The handler for dragstart events fired on |this|.
102 * @param {Event} e The event for the drag. 142 * @param {Event} e The event for the drag.
103 * @private 143 * @private
104 */ 144 */
145 // TODO(xci) drag
105 onDragStart_: function(e) { 146 onDragStart_: function(e) {
106 // The user may start dragging again during a previous drag's finishing 147 // The user may start dragging again during a previous drag's finishing
107 // animation. 148 // animation.
108 if (this.classList.contains('dragging')) 149 if (this.classList.contains('dragging'))
109 this.finalizeDrag_(); 150 this.finalizeDrag_();
110 151
111 setCurrentlyDraggingTile(this); 152 setCurrentlyDraggingTile(this);
112 153
113 e.dataTransfer.effectAllowed = 'copyMove'; 154 e.dataTransfer.effectAllowed = 'copyMove';
114 this.firstChild.setDragData(e.dataTransfer); 155 this.firstChild.setDragData(e.dataTransfer);
(...skipping 19 matching lines...) Expand all
134 this.parentNode.getBoundingClientRect().top; 175 this.parentNode.getBoundingClientRect().top;
135 176
136 this.onDragMove_(e); 177 this.onDragMove_(e);
137 }, 178 },
138 179
139 /** 180 /**
140 * The handler for drag events fired on |this|. 181 * The handler for drag events fired on |this|.
141 * @param {Event} e The event for the drag. 182 * @param {Event} e The event for the drag.
142 * @private 183 * @private
143 */ 184 */
185 // TODO(xci) drag
144 onDragMove_: function(e) { 186 onDragMove_: function(e) {
145 if (e.view != window || (e.x == 0 && e.y == 0)) { 187 if (e.view != window || (e.x == 0 && e.y == 0)) {
146 this.dragClone.hidden = true; 188 this.dragClone.hidden = true;
147 return; 189 return;
148 } 190 }
149 191
150 this.dragClone.hidden = false; 192 this.dragClone.hidden = false;
151 this.dragClone.style.left = toCssPx(e.x - this.dragOffsetX); 193 this.dragClone.style.left = toCssPx(e.x - this.dragOffsetX);
152 this.dragClone.style.top = toCssPx(e.y - this.dragOffsetY); 194 this.dragClone.style.top = toCssPx(e.y - this.dragOffsetY);
153 }, 195 },
154 196
155 /** 197 /**
156 * The handler for dragend events fired on |this|. 198 * The handler for dragend events fired on |this|.
157 * @param {Event} e The event for the drag. 199 * @param {Event} e The event for the drag.
158 * @private 200 * @private
159 */ 201 */
202 // TODO(xci) drag
160 onDragEnd_: function(e) { 203 onDragEnd_: function(e) {
161 this.dragClone.hidden = false; 204 this.dragClone.hidden = false;
162 this.dragClone.classList.add('placing'); 205 this.dragClone.classList.add('placing');
163 206
164 setCurrentlyDraggingTile(null); 207 setCurrentlyDraggingTile(null);
165 208
166 // tilePage will be null if we've already been removed. 209 // tilePage will be null if we've already been removed.
167 var tilePage = this.tilePage; 210 var tilePage = this.tilePage;
168 if (tilePage) 211 if (tilePage)
169 tilePage.positionTile_(this.index); 212 //tilePage.positionTile_(this.index); // TODO(xci) function was deleted!
170 213
171 // Take an appropriate action with the drag clone. 214 // Take an appropriate action with the drag clone.
172 if (this.landedOnTrash) { 215 if (this.landedOnTrash) {
173 this.dragClone.classList.add('deleting'); 216 this.dragClone.classList.add('deleting');
174 } else if (tilePage) { 217 } else if (tilePage) {
175 // TODO(dbeam): Until we fix dropEffect to the correct behavior it will 218 // TODO(dbeam): Until we fix dropEffect to the correct behavior it will
176 // differ on windows - crbug.com/39399. That's why we use the custom 219 // differ on windows - crbug.com/39399. That's why we use the custom
177 // this.lastDropEffect instead of e.dataTransfer.dropEffect. 220 // this.lastDropEffect instead of e.dataTransfer.dropEffect.
178 if (tilePage.selected && this.lastDropEffect != 'copy') { 221 if (tilePage.selected && this.lastDropEffect != 'copy') {
179 // The drag clone can still be hidden from the last drag move event. 222 // The drag clone can still be hidden from the last drag move event.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 this.landedOnTrash = false; 255 this.landedOnTrash = false;
213 }, 256 },
214 257
215 /** 258 /**
216 * Creates a clone of this node offset by the coordinates. Used for the 259 * Creates a clone of this node offset by the coordinates. Used for the
217 * dragging effect where a tile appears to float off one side of the grid 260 * dragging effect where a tile appears to float off one side of the grid
218 * and re-appear on the other. 261 * and re-appear on the other.
219 * @param {number} x x-axis offset, in pixels. 262 * @param {number} x x-axis offset, in pixels.
220 * @param {number} y y-axis offset, in pixels. 263 * @param {number} y y-axis offset, in pixels.
221 */ 264 */
265 // TODO(xci) drag
222 showDoppleganger: function(x, y) { 266 showDoppleganger: function(x, y) {
223 // We always have to clear the previous doppleganger to make sure we get 267 // We always have to clear the previous doppleganger to make sure we get
224 // style updates for the contents of this tile. 268 // style updates for the contents of this tile.
225 this.clearDoppleganger(); 269 this.clearDoppleganger();
226 270
227 var clone = this.cloneNode(true); 271 var clone = this.cloneNode(true);
228 clone.classList.remove('real'); 272 clone.classList.remove('real');
229 clone.classList.add('doppleganger'); 273 clone.classList.add('doppleganger');
230 var clonelets = clone.querySelectorAll('.real'); 274 var clonelets = clone.querySelectorAll('.real');
231 for (var i = 0; i < clonelets.length; i++) { 275 for (var i = 0; i < clonelets.length; i++) {
232 clonelets[i].classList.remove('real'); 276 clonelets[i].classList.remove('real');
233 } 277 }
234 278
235 this.appendChild(clone); 279 this.appendChild(clone);
236 this.doppleganger_ = clone; 280 this.doppleganger_ = clone;
237 281
238 if (isRTL()) 282 if (isRTL())
239 x *= -1; 283 x *= -1;
240 284
241 this.doppleganger_.style.WebkitTransform = 'translate(' + x + 'px, ' + 285 this.doppleganger_.style.WebkitTransform = 'translate(' + x + 'px, ' +
242 y + 'px)'; 286 y + 'px)';
243 }, 287 },
244 288
245 /** 289 /**
246 * Destroys the current doppleganger. 290 * Destroys the current doppleganger.
247 */ 291 */
292 // TODO(xci) drag
248 clearDoppleganger: function() { 293 clearDoppleganger: function() {
249 if (this.doppleganger_) { 294 if (this.doppleganger_) {
250 this.removeChild(this.doppleganger_); 295 this.removeChild(this.doppleganger_);
251 this.doppleganger_ = null; 296 this.doppleganger_ = null;
252 } 297 }
253 }, 298 },
254 299
255 /** 300 /**
256 * Returns status of doppleganger. 301 * Returns status of doppleganger.
257 * @return {boolean} True if there is a doppleganger showing for |this|. 302 * @return {boolean} True if there is a doppleganger showing for |this|.
258 */ 303 */
304 // TODO(xci) drag
259 hasDoppleganger: function() { 305 hasDoppleganger: function() {
260 return !!this.doppleganger_; 306 return !!this.doppleganger_;
261 }, 307 },
262 308
263 /** 309 /**
264 * Cleans up after the drag is over. This is either called when the 310 * Cleans up after the drag is over. This is either called when the
265 * drag representation finishes animating to the final position, or when 311 * drag representation finishes animating to the final position, or when
266 * the next drag starts (if the user starts a 2nd drag very quickly). 312 * the next drag starts (if the user starts a 2nd drag very quickly).
267 * @private 313 * @private
268 */ 314 */
315 // TODO(xci) drag
269 finalizeDrag_: function() { 316 finalizeDrag_: function() {
270 assert(this.classList.contains('dragging')); 317 assert(this.classList.contains('dragging'));
271 318
272 var clone = this.dragClone; 319 var clone = this.dragClone;
273 this.dragClone = null; 320 this.dragClone = null;
274 321
275 clone.parentNode.removeChild(clone); 322 clone.parentNode.removeChild(clone);
276 this.eventTracker.remove(clone, 'webkitTransitionEnd'); 323 this.eventTracker.remove(clone, 'webkitTransitionEnd');
277 this.classList.remove('dragging'); 324 this.classList.remove('dragging');
278 if (this.firstChild.finalizeDrag) 325 if (this.firstChild.finalizeDrag)
279 this.firstChild.finalizeDrag(); 326 this.firstChild.finalizeDrag();
280 }, 327 },
281 328
282 /** 329 /**
283 * Called when the drag representation node is done migrating to its final 330 * Called when the drag representation node is done migrating to its final
284 * resting spot. 331 * resting spot.
285 * @param {Event} e The transition end event. 332 * @param {Event} e The transition end event.
286 */ 333 */
334 // TODO(xci) drag
287 onDragCloneTransitionEnd_: function(e) { 335 onDragCloneTransitionEnd_: function(e) {
288 if (this.classList.contains('dragging') && 336 if (this.classList.contains('dragging') &&
289 (e.propertyName == 'left' || e.propertyName == 'top' || 337 (e.propertyName == 'left' || e.propertyName == 'top' ||
290 e.propertyName == '-webkit-transform')) { 338 e.propertyName == '-webkit-transform')) {
291 this.finalizeDrag_(); 339 this.finalizeDrag_();
292 } 340 }
293 }, 341 },
294 342
295 /** 343 /**
296 * Called when an app is removed from Chrome. Animates its disappearance. 344 * Called when an app is removed from Chrome. Animates its disappearance.
(...skipping 12 matching lines...) Expand all
309 */ 357 */
310 onContentsAnimationEnd_: function(e) { 358 onContentsAnimationEnd_: function(e) {
311 if (this.firstChild.classList.contains('new-tile-contents')) 359 if (this.firstChild.classList.contains('new-tile-contents'))
312 this.firstChild.classList.remove('new-tile-contents'); 360 this.firstChild.classList.remove('new-tile-contents');
313 if (this.firstChild.classList.contains('removing-tile-contents')) 361 if (this.firstChild.classList.contains('removing-tile-contents'))
314 this.tilePage.removeTile(this, true); 362 this.tilePage.removeTile(this, true);
315 }, 363 },
316 }; 364 };
317 365
318 /** 366 /**
319 * Gives the proportion of the row width that is devoted to a single icon.
320 * @param {number} rowTileCount The number of tiles in a row.
321 * @param {number} tileSpacingFraction The proportion of the tile width which
322 * will be used as spacing between tiles.
323 * @return {number} The ratio between icon width and row width.
324 */
325 function tileWidthFraction(rowTileCount, tileSpacingFraction) {
326 return rowTileCount + (rowTileCount - 1) * tileSpacingFraction;
327 }
328
329 /**
330 * Calculates an assortment of tile-related values for a grid with the
331 * given dimensions.
332 * @param {number} width The pixel width of the grid.
333 * @param {number} numRowTiles The number of tiles in a row.
334 * @param {number} tileSpacingFraction The proportion of the tile width which
335 * will be used as spacing between tiles.
336 * @return {Object} A mapping of pixel values.
337 */
338 function tileValuesForGrid(width, numRowTiles, tileSpacingFraction) {
339 var tileWidth = width / tileWidthFraction(numRowTiles, tileSpacingFraction);
340 var offsetX = tileWidth * (1 + tileSpacingFraction);
341 var interTileSpacing = offsetX - tileWidth;
342
343 return {
344 tileWidth: tileWidth,
345 offsetX: offsetX,
346 interTileSpacing: interTileSpacing,
347 };
348 }
349
350 // The smallest amount of horizontal blank space to display on the sides when
351 // displaying a wide arrangement. There is an additional 26px of margin from
352 // the tile page padding.
353 var MIN_WIDE_MARGIN = 18;
354
355 /**
356 * Creates a new TilePage object. This object contains tiles and controls 367 * Creates a new TilePage object. This object contains tiles and controls
357 * their layout. 368 * their layout.
358 * @param {Object} gridValues Pixel values that define the size and layout 369 * @param {Object} gridValues Pixel values that define the size and layout
jeremycho_google 2012/08/02 00:19:11 Delete
pedrosimonetti2 2012/08/03 18:14:12 Done.
359 * of the tile grid. 370 * of the tile grid.
360 * @constructor 371 * @constructor
361 * @extends {HTMLDivElement} 372 * @extends {HTMLDivElement}
362 */ 373 */
363 function TilePage(gridValues) { 374 function TilePage() {
364 var el = cr.doc.createElement('div'); 375 var el = cr.doc.createElement('div');
365 el.gridValues_ = gridValues;
366 el.__proto__ = TilePage.prototype; 376 el.__proto__ = TilePage.prototype;
367 el.initialize(); 377 el.initialize();
368 378
369 return el; 379 return el;
370 } 380 }
371 381
372 /**
373 * Takes a collection of grid layout pixel values and updates them with
374 * additional tiling values that are calculated from TilePage constants.
375 * @param {Object} grid The grid layout pixel values to update.
376 */
377 TilePage.initGridValues = function(grid) {
378 // The amount of space we need to display a narrow grid (all narrow grids
379 // are this size).
380 grid.narrowWidth =
381 grid.minTileWidth * tileWidthFraction(grid.minColCount,
382 grid.tileSpacingFraction);
383 // The minimum amount of space we need to display a wide grid.
384 grid.minWideWidth =
385 grid.minTileWidth * tileWidthFraction(grid.maxColCount,
386 grid.tileSpacingFraction);
387 // The largest we will ever display a wide grid.
388 grid.maxWideWidth =
389 grid.maxTileWidth * tileWidthFraction(grid.maxColCount,
390 grid.tileSpacingFraction);
391 // Tile-related pixel values for the narrow display.
392 grid.narrowTileValues = tileValuesForGrid(grid.narrowWidth,
393 grid.minColCount,
394 grid.tileSpacingFraction);
395 // Tile-related pixel values for the minimum narrow display.
396 grid.wideTileValues = tileValuesForGrid(grid.minWideWidth,
397 grid.maxColCount,
398 grid.tileSpacingFraction);
399 };
400
401 TilePage.prototype = { 382 TilePage.prototype = {
402 __proto__: HTMLDivElement.prototype, 383 __proto__: HTMLDivElement.prototype,
403 384
385 // The grid values should be defined by each TilePage subclass.
386 gridValues_: {
387 tileWidth: 0,
388 tileHeight: 0,
389 tileHorMargin: 0, // TODO margin with CSS / there's no margin in first col
390 tileVerMargin: 0,
391 tileBorderWidth: 0,
392 bottomPanelHorMargin: 0, // TODO it doesn't make sense having this here.
393
394 tileCount: 0, // TODO remove this dependency. rename it to maxTileCount.
395 tileClassName: '',
396 reinforceStyles: true,
jeremycho_google 2012/08/02 00:19:11 Is there ever a case when this would be false?
pedrosimonetti2 2012/08/03 18:14:12 Yes, if you want to set the TileCell and Tile size
397
398 // debug
399 slowFactor: 1,
jeremycho_google 2012/08/02 00:19:11 Unused?
pedrosimonetti2 2012/08/03 18:14:12 Just for now. I need to add the debug features bac
400 debug: false
401 },
402
404 initialize: function() { 403 initialize: function() {
405 this.className = 'tile-page'; 404 this.className = 'tile-page';
406 405
407 // Div that acts as a custom scrollbar. The scrollbar has to live
408 // outside the content div so it doesn't flicker when scrolling (due to
409 // repainting after the scroll, then repainting again when moved in the
410 // onScroll handler). |scrollbar_| is only aesthetic, and it only
411 // represents the thumb. Actual events are still handled by the invisible
412 // native scrollbars. This div gives us more flexibility with the visuals.
413 this.scrollbar_ = this.ownerDocument.createElement('div');
414 this.scrollbar_.className = 'tile-page-scrollbar';
415 this.scrollbar_.hidden = true;
416 this.appendChild(this.scrollbar_);
417
418 // This contains everything but the scrollbar. 406 // This contains everything but the scrollbar.
419 this.content_ = this.ownerDocument.createElement('div'); 407 this.content_ = this.ownerDocument.createElement('div');
420 this.content_.className = 'tile-page-content'; 408 this.content_.className = 'tile-page-content';
421 this.appendChild(this.content_); 409 this.appendChild(this.content_);
422 410
423 // Div that sets the vertical position of the tile grid.
424 this.topMargin_ = this.ownerDocument.createElement('div');
425 this.topMargin_.className = 'top-margin';
426 this.content_.appendChild(this.topMargin_);
427
428 // Div that holds the tiles. 411 // Div that holds the tiles.
429 this.tileGrid_ = this.ownerDocument.createElement('div'); 412 this.tileGrid_ = this.ownerDocument.createElement('div');
430 this.tileGrid_.className = 'tile-grid'; 413 this.tileGrid_.className = 'tile-grid';
431 this.tileGrid_.style.minWidth = this.gridValues_.narrowWidth + 'px'; 414 // TODO(xci)
415 //this.tileGrid_.style.minWidth = this.gridValues_.narrowWidth + 'px';
432 this.content_.appendChild(this.tileGrid_); 416 this.content_.appendChild(this.tileGrid_);
433 417
418 // TODO(xci) new!
419 this.tileGridContent_ = this.ownerDocument.createElement('div');
420 this.tileGridContent_.className = 'tile-grid-content';
421 this.tileGrid_.appendChild(this.tileGridContent_);
422
423 // TODO(xci) new!
424 this.tileGrid_.addEventListener('webkitTransitionEnd',
425 this.onTileGridAnimationEnd_.bind(this));
426
434 // Ordered list of our tiles. 427 // Ordered list of our tiles.
435 this.tileElements_ = this.tileGrid_.getElementsByClassName('tile real'); 428 //this.tileElements_ = this.tileGrid_.getElementsByClassName('tile real');
jeremycho_google 2012/08/02 00:19:11 Any reason to keep lines like these?
jeremycho_google 2012/08/02 03:00:49 As we discussed, these will be deleted in a future
pedrosimonetti2 2012/08/03 18:14:12 I kept that code commented out as a reminder to re
pedrosimonetti2 2012/08/03 18:14:12 I'll delete this code in a future CL. On 2012/08/
429 this.tileElements_ = [];
430
436 // Ordered list of the elements which want to accept keyboard focus. These 431 // Ordered list of the elements which want to accept keyboard focus. These
437 // elements will not be a part of the normal tab order; the tile grid 432 // elements will not be a part of the normal tab order; the tile grid
438 // initially gets focused and then these elements can be focused via the 433 // initially gets focused and then these elements can be focused via the
439 // arrow keys. 434 // arrow keys.
435 // TODO(xci)
436 /*
440 this.focusableElements_ = 437 this.focusableElements_ =
441 this.tileGrid_.getElementsByClassName('focusable'); 438 this.tileGrid_.getElementsByClassName('focusable');
442 439 */
443 // These are properties used in updateTopMargin.
444 this.animatedTopMarginPx_ = 0;
445 this.topMarginPx_ = 0;
446 440
447 this.eventTracker = new EventTracker(); 441 this.eventTracker = new EventTracker();
448 this.eventTracker.add(window, 'resize', this.onResize_.bind(this)); 442 this.eventTracker.add(window, 'resize', this.onResize_.bind(this));
443 // TODO(xci) new
444 this.eventTracker.add(window, 'keydown', this.onKeyDown_.bind(this));
449 445
450 this.addEventListener('DOMNodeInsertedIntoDocument', 446 // TODO(xci)
451 this.onNodeInsertedIntoDocument_); 447 //this.addEventListener('DOMNodeInsertedIntoDocument',
448 // this.onNodeInsertedIntoDocument_);
452 449
453 this.content_.addEventListener('scroll', this.onScroll_.bind(this)); 450 //this.dragWrapper_ = new cr.ui.DragWrapper(this.tileGrid_, this);
454
455 this.dragWrapper_ = new cr.ui.DragWrapper(this.tileGrid_, this);
456 451
457 this.addEventListener('cardselected', this.handleCardSelection_); 452 this.addEventListener('cardselected', this.handleCardSelection_);
458 this.addEventListener('carddeselected', this.handleCardDeselection_); 453 this.addEventListener('carddeselected', this.handleCardDeselection_);
459 this.addEventListener('focus', this.handleFocus_); 454 //this.addEventListener('focus', this.handleFocus_);
460 this.addEventListener('keydown', this.handleKeyDown_); 455 //this.addEventListener('keydown', this.handleKeyDown_);
461 this.addEventListener('mousedown', this.handleMouseDown_); 456 //this.addEventListener('mousedown', this.handleMouseDown_);
462 457
463 this.focusElementIndex_ = -1; 458 //this.focusElementIndex_ = -1;
464 }, 459 },
465 460
466 get tiles() { 461 get tiles() {
467 return this.tileElements_; 462 return this.tileElements_;
468 }, 463 },
469 464
470 get tileCount() { 465 get tileCount() {
471 return this.tileElements_.length; 466 return this.tileElements_.length;
472 }, 467 },
473 468
474 get selected() { 469 get selected() {
475 return Array.prototype.indexOf.call(this.parentNode.children, this) == 470 return Array.prototype.indexOf.call(this.parentNode.children, this) ==
476 ntp.getCardSlider().currentCard; 471 ntp.getCardSlider().currentCard;
477 }, 472 },
478 473
479 /** 474 /**
480 * The size of the margin (unused space) on the sides of the tile grid, in
481 * pixels.
482 * @type {number}
483 */
484 get sideMargin() {
485 return this.layoutValues_.leftMargin;
486 },
487
488 /**
489 * Returns the width of the scrollbar, in pixels, if it is active, or 0
490 * otherwise.
491 * @type {number}
492 */
493 get scrollbarWidth() {
494 return this.scrollbar_.hidden ? 0 : 13;
495 },
496
497 /**
498 * Returns any extra padding to insert to the bottom of a tile page. By
499 * default there is none, but subclasses can override.
500 * @type {number}
501 */
502 get extraBottomPadding() {
503 return 0;
504 },
505
506 /**
507 * The notification content of this tile (if any, otherwise null). 475 * The notification content of this tile (if any, otherwise null).
508 * @type {!HTMLElement} 476 * @type {!HTMLElement}
509 */ 477 */
510 get notification() { 478 get notification() {
511 return this.topMargin_.nextElementSibling.id == 'notification-container' ? 479 return this.topMargin_.nextElementSibling.id == 'notification-container' ?
512 this.topMargin_.nextElementSibling : null; 480 this.topMargin_.nextElementSibling : null;
513 }, 481 },
514 /** 482 /**
515 * The notification content of this tile (if any, otherwise null). 483 * The notification content of this tile (if any, otherwise null).
516 * @type {!HTMLElement} 484 * @type {!HTMLElement}
517 */ 485 */
518 set notification(node) { 486 set notification(node) {
519 assert(node instanceof HTMLElement, '|node| isn\'t an HTMLElement!'); 487 assert(node instanceof HTMLElement, '|node| isn\'t an HTMLElement!');
520 // NOTE: Implicitly removes from DOM if |node| is inside it. 488 // NOTE: Implicitly removes from DOM if |node| is inside it.
521 this.content_.insertBefore(node, this.topMargin_.nextElementSibling); 489 this.content_.insertBefore(node, this.topMargin_.nextElementSibling);
jeremycho_google 2012/08/02 00:19:11 This line is throwing JS errors, since the code fo
pedrosimonetti2 2012/08/03 18:14:12 Fixed. The notification is working now, even thoug
522 this.positionNotification_(); 490 this.positionNotification_();
523 }, 491 },
524 492
525 /** 493 /**
526 * Fetches the size, in pixels, of the padding-top of the tile contents.
527 * @type {number}
528 */
529 get contentPadding() {
530 if (typeof this.contentPadding_ == 'undefined') {
531 this.contentPadding_ =
532 parseInt(getComputedStyle(this.content_).paddingTop, 10);
533 }
534 return this.contentPadding_;
535 },
536
537 /**
538 * Removes the tilePage from the DOM and cleans up event handlers. 494 * Removes the tilePage from the DOM and cleans up event handlers.
539 */ 495 */
540 remove: function() { 496 remove: function() {
541 // This checks arguments.length as most remove functions have a boolean 497 // This checks arguments.length as most remove functions have a boolean
542 // |opt_animate| argument, but that's not necesarilly applicable to 498 // |opt_animate| argument, but that's not necesarilly applicable to
543 // removing a tilePage. Selecting a different card in an animated way and 499 // removing a tilePage. Selecting a different card in an animated way and
544 // deleting the card afterward is probably a better choice. 500 // deleting the card afterward is probably a better choice.
545 assert(typeof arguments[0] != 'boolean', 501 assert(typeof arguments[0] != 'boolean',
546 'This function takes no |opt_animate| argument.'); 502 'This function takes no |opt_animate| argument.');
547 this.tearDown_(); 503 this.tearDown_();
548 this.parentNode.removeChild(this); 504 this.parentNode.removeChild(this);
549 }, 505 },
550 506
551 /** 507 /**
552 * Cleans up resources that are no longer needed after this TilePage 508 * Cleans up resources that are no longer needed after this TilePage
553 * instance is removed from the DOM. 509 * instance is removed from the DOM.
554 * @private 510 * @private
555 */ 511 */
556 tearDown_: function() { 512 tearDown_: function() {
557 this.eventTracker.removeAll(); 513 this.eventTracker.removeAll();
558 }, 514 },
559 515
560 /** 516 /**
561 * Appends a tile to the end of the tile grid. 517 * Appends a tile to the end of the tile grid.
562 * @param {HTMLElement} tileElement The contents of the tile. 518 * @param {HTMLElement} tileElement The contents of the tile.
563 * @param {boolean} animate If true, the append will be animated. 519 * @param {boolean} animate If true, the append will be animated.
564 * @protected 520 * @protected
565 */ 521 */
522 // TODO(xci)
523 /*
566 appendTile: function(tileElement, animate) { 524 appendTile: function(tileElement, animate) {
567 this.addTileAt(tileElement, this.tileElements_.length, animate); 525 this.addTileAt(tileElement, this.tileElements_.length, animate);
568 }, 526 },
527 */
569 528
570 /** 529 /**
571 * Adds the given element to the tile grid. 530 * Adds the given element to the tile grid.
572 * @param {Node} tileElement The tile object/node to insert. 531 * @param {Node} tileElement The tile object/node to insert.
573 * @param {number} index The location in the tile grid to insert it at. 532 * @param {number} index The location in the tile grid to insert it at.
574 * @param {boolean} animate If true, the tile in question will be 533 * @param {boolean} animate If true, the tile in question will be
575 * animated (other tiles, if they must reposition, do not animate). 534 * animated (other tiles, if they must reposition, do not animate).
576 * @protected 535 * @protected
577 */ 536 */
537 // TODO(xci)
538 /*
578 addTileAt: function(tileElement, index, animate) { 539 addTileAt: function(tileElement, index, animate) {
579 this.classList.remove('animating-tile-page');
580 if (animate)
581 tileElement.classList.add('new-tile-contents');
582
583 // Make sure the index is positive and either in the the bounds of
584 // this.tileElements_ or at the end (meaning append).
585 assert(index >= 0 && index <= this.tileElements_.length);
586
587 var wrapperDiv = new Tile(tileElement);
588 // If is out of the bounds of the tile element list, .insertBefore() will
589 // act just like appendChild().
590 this.tileGrid_.insertBefore(wrapperDiv, this.tileElements_[index]);
591 this.calculateLayoutValues_(); 540 this.calculateLayoutValues_();
592 this.heightChanged_();
593
594 this.repositionTiles_();
595 this.fireAddedEvent(wrapperDiv, index, animate); 541 this.fireAddedEvent(wrapperDiv, index, animate);
596 }, 542 },
543 */
597 544
598 /** 545 /**
599 * Notify interested subscribers that a tile has been removed from this 546 * Notify interested subscribers that a tile has been removed from this
600 * page. 547 * page.
601 * @param {Tile} tile The newly added tile. 548 * @param {TileCell} tile The newly added tile.
602 * @param {number} index The index of the tile that was added. 549 * @param {number} index The index of the tile that was added.
603 * @param {boolean} wasAnimated Whether the removal was animated. 550 * @param {boolean} wasAnimated Whether the removal was animated.
604 */ 551 */
605 fireAddedEvent: function(tile, index, wasAnimated) { 552 fireAddedEvent: function(tile, index, wasAnimated) {
606 var e = document.createEvent('Event'); 553 var e = document.createEvent('Event');
607 e.initEvent('tilePage:tile_added', true, true); 554 e.initEvent('tilePage:tile_added', true, true);
608 e.addedIndex = index; 555 e.addedIndex = index;
609 e.addedTile = tile; 556 e.addedTile = tile;
610 e.wasAnimated = wasAnimated; 557 e.wasAnimated = wasAnimated;
611 this.dispatchEvent(e); 558 this.dispatchEvent(e);
(...skipping 13 matching lines...) Expand all
625 this.calculateLayoutValues_(); 572 this.calculateLayoutValues_();
626 this.cleanupDrag(); 573 this.cleanupDrag();
627 574
628 if (!opt_dontNotify) 575 if (!opt_dontNotify)
629 this.fireRemovedEvent(tile, index, !!opt_animate); 576 this.fireRemovedEvent(tile, index, !!opt_animate);
630 }, 577 },
631 578
632 /** 579 /**
633 * Notify interested subscribers that a tile has been removed from this 580 * Notify interested subscribers that a tile has been removed from this
634 * page. 581 * page.
635 * @param {Tile} tile The tile that was removed. 582 * @param {TileCell} tile The tile that was removed.
636 * @param {number} oldIndex Where the tile was positioned before removal. 583 * @param {number} oldIndex Where the tile was positioned before removal.
637 * @param {boolean} wasAnimated Whether the removal was animated. 584 * @param {boolean} wasAnimated Whether the removal was animated.
638 */ 585 */
639 fireRemovedEvent: function(tile, oldIndex, wasAnimated) { 586 fireRemovedEvent: function(tile, oldIndex, wasAnimated) {
640 var e = document.createEvent('Event'); 587 var e = document.createEvent('Event');
641 e.initEvent('tilePage:tile_removed', true, true); 588 e.initEvent('tilePage:tile_removed', true, true);
642 e.removedIndex = oldIndex; 589 e.removedIndex = oldIndex;
643 e.removedTile = tile; 590 e.removedTile = tile;
644 e.wasAnimated = wasAnimated; 591 e.wasAnimated = wasAnimated;
645 this.dispatchEvent(e); 592 this.dispatchEvent(e);
646 }, 593 },
647 594
648 /** 595 /**
649 * Removes all tiles from the page. 596 * Removes all tiles from the page.
650 */ 597 */
651 removeAllTiles: function() { 598 removeAllTiles: function() {
599 // TODO(xci) dispatch individual tearDown functions
652 this.tileGrid_.innerHTML = ''; 600 this.tileGrid_.innerHTML = '';
653 }, 601 },
654 602
655 /** 603 /**
656 * Called when the page is selected (in the card selector). 604 * Called when the page is selected (in the card selector).
657 * @param {Event} e A custom cardselected event. 605 * @param {Event} e A custom cardselected event.
658 * @private 606 * @private
659 */ 607 */
660 handleCardSelection_: function(e) { 608 handleCardSelection_: function(e) {
661 this.tabIndex = 1; 609 this.tabIndex = 1;
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 }, 738 },
791 739
792 /** 740 /**
793 * Makes some calculations for tile layout. These change depending on 741 * Makes some calculations for tile layout. These change depending on
794 * height, width, and the number of tiles. 742 * height, width, and the number of tiles.
795 * TODO(estade): optimize calls to this function. Do nothing if the page is 743 * TODO(estade): optimize calls to this function. Do nothing if the page is
796 * hidden, but call before being shown. 744 * hidden, but call before being shown.
797 * @private 745 * @private
798 */ 746 */
799 calculateLayoutValues_: function() { 747 calculateLayoutValues_: function() {
800 var grid = this.gridValues_;
801 var availableSpace = this.tileGrid_.clientWidth - 2 * MIN_WIDE_MARGIN;
802 var wide = availableSpace >= grid.minWideWidth;
803 var numRowTiles = wide ? grid.maxColCount : grid.minColCount;
804
805 var effectiveGridWidth = wide ?
806 Math.min(Math.max(availableSpace, grid.minWideWidth),
807 grid.maxWideWidth) :
808 grid.narrowWidth;
809 var realTileValues = tileValuesForGrid(effectiveGridWidth, numRowTiles,
810 grid.tileSpacingFraction);
811
812 // leftMargin centers the grid within the avaiable space.
813 var minMargin = wide ? MIN_WIDE_MARGIN : 0;
814 var leftMargin =
815 Math.max(minMargin,
816 (this.tileGrid_.clientWidth - effectiveGridWidth) / 2);
817
818 var rowHeight = this.heightForWidth(realTileValues.tileWidth) +
819 realTileValues.interTileSpacing;
820
821 this.layoutValues_ = {
822 colWidth: realTileValues.offsetX,
823 gridWidth: effectiveGridWidth,
824 leftMargin: leftMargin,
825 numRowTiles: numRowTiles,
826 rowHeight: rowHeight,
827 tileWidth: realTileValues.tileWidth,
828 wide: wide,
829 };
830 748
831 // We need to update the top margin as well. 749 // We need to update the top margin as well.
832 this.updateTopMargin_(); 750 this.updateTopMargin_();
833 751
752 // TODO(pedrosimonetti): when do we really need to send this message?
834 this.firePageLayoutEvent_(); 753 this.firePageLayoutEvent_();
835 }, 754 },
836 755
837 /** 756 /**
838 * Dispatches the custom pagelayout event. 757 * Dispatches the custom pagelayout event.
839 * @private 758 * @private
840 */ 759 */
841 firePageLayoutEvent_: function() { 760 firePageLayoutEvent_: function() {
842 cr.dispatchSimpleEvent(this, 'pagelayout', true, true); 761 cr.dispatchSimpleEvent(this, 'pagelayout', true, true);
843 }, 762 },
844 763
845 /**
846 * @return {number} The amount of margin that should be animated (in pixels)
847 * for the current grid layout.
848 */
849 getAnimatedLeftMargin_: function() {
850 if (this.layoutValues_.wide)
851 return 0;
852
853 var grid = this.gridValues_;
854 return (grid.minWideWidth - MIN_WIDE_MARGIN - grid.narrowWidth) / 2;
855 },
856
857 /**
858 * Calculates the x/y coordinates for an element and moves it there.
859 * @param {number} index The index of the element to be positioned.
860 * @param {number} indexOffset If provided, this is added to |index| when
861 * positioning the tile. The effect is that the tile will be positioned
862 * in a non-default location.
863 * @private
864 */
865 positionTile_: function(index, indexOffset) {
866 var grid = this.gridValues_;
867 var layout = this.layoutValues_;
868
869 indexOffset = typeof indexOffset != 'undefined' ? indexOffset : 0;
870 // Add the offset _after_ the modulus division. We might want to show the
871 // tile off the side of the grid.
872 var col = index % layout.numRowTiles + indexOffset;
873 var row = Math.floor(index / layout.numRowTiles);
874 // Calculate the final on-screen position for the tile.
875 var realX = col * layout.colWidth + layout.leftMargin;
876 var realY = row * layout.rowHeight;
877
878 // Calculate the portion of the tile's position that should be animated.
879 var animatedTileValues = layout.wide ?
880 grid.wideTileValues : grid.narrowTileValues;
881 // Animate the difference between three-wide and six-wide.
882 var animatedLeftMargin = this.getAnimatedLeftMargin_();
883 var animatedX = col * animatedTileValues.offsetX + animatedLeftMargin;
884 var animatedY = row * (this.heightForWidth(animatedTileValues.tileWidth) +
885 animatedTileValues.interTileSpacing);
886
887 var tile = this.tileElements_[index];
888 tile.setGridPosition(animatedX, animatedY);
889 tile.firstChild.setBounds(layout.tileWidth,
890 realX - animatedX,
891 realY - animatedY);
892
893 // This code calculates whether the tile needs to show a clone of itself
894 // wrapped around the other side of the tile grid.
895 var offTheRight = col == layout.numRowTiles ||
896 (col == layout.numRowTiles - 1 && tile.hasDoppleganger());
897 var offTheLeft = col == -1 || (col == 0 && tile.hasDoppleganger());
898 if (this.isCurrentDragTarget && (offTheRight || offTheLeft)) {
899 var sign = offTheRight ? 1 : -1;
900 tile.showDoppleganger(-layout.numRowTiles * layout.colWidth * sign,
901 layout.rowHeight * sign);
902 } else {
903 tile.clearDoppleganger();
904 }
905
906 if (index == this.tileElements_.length - 1) {
907 this.tileGrid_.style.height = (realY + layout.rowHeight) + 'px';
908 this.queueUpdateScrollbars_();
909 }
910 },
911 764
912 /** 765 /**
913 * Gets the index of the tile that should occupy coordinate (x, y). Note 766 * Gets the index of the tile that should occupy coordinate (x, y). Note
914 * that this function doesn't care where the tiles actually are, and will 767 * that this function doesn't care where the tiles actually are, and will
915 * return an index even for the space between two tiles. This function is 768 * return an index even for the space between two tiles. This function is
916 * effectively the inverse of |positionTile_|. 769 * effectively the inverse of |positionTile_|.
917 * @param {number} x The x coordinate, in pixels, relative to the left of 770 * @param {number} x The x coordinate, in pixels, relative to the left of
918 * |this|. 771 * |this|.
919 * @param {number} y The y coordinate, in pixels, relative to the top of 772 * @param {number} y The y coordinate, in pixels, relative to the top of
920 * |this|. 773 * |this|.
921 * @private 774 * @private
922 */ 775 */
776 // TODO(xci) drag
923 getWouldBeIndexForPoint_: function(x, y) { 777 getWouldBeIndexForPoint_: function(x, y) {
924 var grid = this.gridValues_; 778 var grid = this.gridValues_;
925 var layout = this.layoutValues_; 779 var layout = this.layoutValues_;
926 780
927 var gridClientRect = this.tileGrid_.getBoundingClientRect(); 781 var gridClientRect = this.tileGrid_.getBoundingClientRect();
928 var col = Math.floor((x - gridClientRect.left - layout.leftMargin) / 782 var col = Math.floor((x - gridClientRect.left - layout.leftMargin) /
929 layout.colWidth); 783 layout.colWidth);
930 if (col < 0 || col >= layout.numRowTiles) 784 if (col < 0 || col >= layout.numRowTiles)
931 return -1; 785 return -1;
932 786
933 if (isRTL()) 787 if (isRTL())
934 col = layout.numRowTiles - 1 - col; 788 col = layout.numRowTiles - 1 - col;
935 789
936 var row = Math.floor((y - gridClientRect.top) / layout.rowHeight); 790 var row = Math.floor((y - gridClientRect.top) / layout.rowHeight);
937 return row * layout.numRowTiles + col; 791 return row * layout.numRowTiles + col;
938 }, 792 },
939 793
940 /** 794 /**
941 * Window resize event handler. Window resizes may trigger re-layouts.
942 * @param {Object} e The resize event.
943 */
944 onResize_: function(e) {
945 if (this.lastWidth_ == this.clientWidth &&
946 this.lastHeight_ == this.clientHeight) {
947 return;
948 }
949
950 this.calculateLayoutValues_();
951
952 this.lastWidth_ = this.clientWidth;
953 this.lastHeight_ = this.clientHeight;
954 this.classList.add('animating-tile-page');
955 this.heightChanged_();
956
957 this.positionNotification_();
958 this.repositionTiles_();
959 },
960
961 /**
962 * The tile grid has an image mask which fades at the edges. We only show 795 * The tile grid has an image mask which fades at the edges. We only show
963 * the mask when there is an active drag; it obscures doppleganger tiles 796 * the mask when there is an active drag; it obscures doppleganger tiles
964 * as they enter or exit the grid. 797 * as they enter or exit the grid.
965 * @private 798 * @private
966 */ 799 */
800 // TODO(xci) drag
967 updateMask_: function() { 801 updateMask_: function() {
968 if (!this.isCurrentDragTarget) { 802 if (!this.isCurrentDragTarget) {
969 this.tileGrid_.style.WebkitMaskBoxImage = ''; 803 this.tileGrid_.style.WebkitMaskBoxImage = '';
970 return; 804 return;
971 } 805 }
972 806
973 var leftMargin = this.layoutValues_.leftMargin; 807 var leftMargin = this.layoutValues_.leftMargin;
974 // The fade distance is the space between tiles. 808 // The fade distance is the space between tiles.
975 var fadeDistance = (this.gridValues_.tileSpacingFraction * 809 var fadeDistance = (this.gridValues_.tileSpacingFraction *
976 this.layoutValues_.tileWidth); 810 this.layoutValues_.tileWidth);
977 fadeDistance = Math.min(leftMargin, fadeDistance); 811 fadeDistance = Math.min(leftMargin, fadeDistance);
978 // On Skia we don't use any fade because it works very poorly. See 812 // On Skia we don't use any fade because it works very poorly. See
979 // http://crbug.com/99373 813 // http://crbug.com/99373
980 if (!cr.isMac) 814 if (!cr.isMac)
981 fadeDistance = 1; 815 fadeDistance = 1;
982 var gradient = 816 var gradient =
983 '-webkit-linear-gradient(left,' + 817 '-webkit-linear-gradient(left,' +
984 'transparent, ' + 818 'transparent, ' +
985 'transparent ' + (leftMargin - fadeDistance) + 'px, ' + 819 'transparent ' + (leftMargin - fadeDistance) + 'px, ' +
986 'black ' + leftMargin + 'px, ' + 820 'black ' + leftMargin + 'px, ' +
987 'black ' + (this.tileGrid_.clientWidth - leftMargin) + 'px, ' + 821 'black ' + (this.tileGrid_.clientWidth - leftMargin) + 'px, ' +
988 'transparent ' + (this.tileGrid_.clientWidth - leftMargin + 822 'transparent ' + (this.tileGrid_.clientWidth - leftMargin +
989 fadeDistance) + 'px, ' + 823 fadeDistance) + 'px, ' +
990 'transparent)'; 824 'transparent)';
991 this.tileGrid_.style.WebkitMaskBoxImage = gradient; 825 this.tileGrid_.style.WebkitMaskBoxImage = gradient;
992 }, 826 },
993 827
828 // TODO(xci) delete (used by drag and drop)
994 updateTopMargin_: function() { 829 updateTopMargin_: function() {
995 var layout = this.layoutValues_; 830 return;
996
997 // The top margin is set so that the vertical midpoint of the grid will
998 // be 1/3 down the page.
999 var numTiles = this.tileCount +
1000 (this.isCurrentDragTarget && !this.withinPageDrag_ ? 1 : 0);
1001 var numRows = Math.max(1, Math.ceil(numTiles / layout.numRowTiles));
1002 var usedHeight = layout.rowHeight * numRows;
1003 var newMargin = document.documentElement.clientHeight / 3 -
1004 usedHeight / 3 - this.contentPadding;
1005 // The 'height' style attribute of topMargin is non-zero to work around
1006 // webkit's collapsing margin behavior, so we have to factor that into
1007 // our calculations here.
1008 newMargin = Math.max(newMargin, 0) - this.topMargin_.offsetHeight;
1009
1010 // |newMargin| is the final margin we actually want to show. However,
1011 // part of that should be animated and part should not (for the same
1012 // reason as with leftMargin). The approach is to consider differences
1013 // when the layout changes from wide to narrow or vice versa as
1014 // 'animatable'. These differences accumulate in animatedTopMarginPx_,
1015 // while topMarginPx_ caches the real (total) margin. Either of these
1016 // calculations may come out to be negative, so we use margins as the
1017 // css property.
1018
1019 if (typeof this.topMarginIsForWide_ == 'undefined')
1020 this.topMarginIsForWide_ = layout.wide;
1021 if (this.topMarginIsForWide_ != layout.wide) {
1022 this.animatedTopMarginPx_ += newMargin - this.topMarginPx_;
1023 this.topMargin_.style.marginBottom = toCssPx(this.animatedTopMarginPx_);
1024 }
1025
1026 this.topMarginIsForWide_ = layout.wide;
1027 this.topMarginPx_ = newMargin;
1028 this.topMargin_.style.marginTop =
1029 toCssPx(this.topMarginPx_ - this.animatedTopMarginPx_);
1030 }, 831 },
1031 832
1032 /** 833 /**
1033 * Position the notification if there's one showing. 834 * Position the notification if there's one showing.
1034 */ 835 */
1035 positionNotification_: function() { 836 positionNotification_: function() {
1036 var notification = this.notification; 837 if (this.notification && !this.notification.hidden) {
1037 if (!notification || notification.hidden) 838 this.notification.style.margin =
1038 return; 839 -this.notification.offsetHeight + 'px ' +
1039 840 this.layoutValues_.leftMargin + 'px 0';
1040 // Update the horizontal position. 841 }
1041 var animatedLeftMargin = this.getAnimatedLeftMargin_();
1042 notification.style.WebkitMarginStart = animatedLeftMargin + 'px';
1043 var leftOffset = (this.layoutValues_.leftMargin - animatedLeftMargin) *
1044 (isRTL() ? -1 : 1);
1045 notification.style.WebkitTransform = 'translateX(' + leftOffset + 'px)';
1046
1047 // Update the allowable widths of the text.
1048 var buttonWidth = notification.querySelector('button').offsetWidth + 8;
1049 notification.querySelector('span').style.maxWidth =
1050 this.layoutValues_.gridWidth - buttonWidth + 'px';
1051
1052 // This makes sure the text doesn't condense smaller than the narrow size
1053 // of the grid (e.g. when a user makes the window really small).
1054 notification.style.minWidth =
1055 this.gridValues_.narrowWidth - buttonWidth + 'px';
1056
1057 // Update the top position.
1058 notification.style.marginTop = -notification.offsetHeight + 'px';
1059 }, 842 },
1060 843
1061 /** 844 /**
1062 * Handles final setup that can only happen after |this| is inserted into 845 * Handles final setup that can only happen after |this| is inserted into
1063 * the page. 846 * the page.
1064 * @private 847 * @private
1065 */ 848 */
1066 onNodeInsertedIntoDocument_: function(e) { 849 onNodeInsertedIntoDocument_: function(e) {
1067 this.calculateLayoutValues_(); 850 this.calculateLayoutValues_();
1068 this.heightChanged_();
1069 },
1070
1071 /**
1072 * Called when the height of |this| has changed: update the size of
1073 * tileGrid.
1074 * @private
1075 */
1076 heightChanged_: function() {
1077 // The tile grid will expand to the bottom footer, or enough to hold all
1078 // the tiles, whichever is greater. It would be nicer if tilePage were
1079 // a flex box, and the tile grid could be box-flex: 1, but this exposes a
1080 // bug where repositioning tiles will cause the scroll position to reset.
1081 this.tileGrid_.style.minHeight = (this.clientHeight -
1082 this.tileGrid_.offsetTop - this.content_.offsetTop -
1083 this.extraBottomPadding -
1084 (this.footerNode_ ? this.footerNode_.clientHeight : 0)) + 'px';
1085 }, 851 },
1086 852
1087 /** 853 /**
1088 * Places an element at the bottom of the content div. Used in bare-minimum 854 * Places an element at the bottom of the content div. Used in bare-minimum
1089 * mode to hold #footer. 855 * mode to hold #footer.
1090 * @param {HTMLElement} footerNode The node to append to content. 856 * @param {HTMLElement} footerNode The node to append to content.
1091 */ 857 */
1092 appendFooter: function(footerNode) { 858 appendFooter: function(footerNode) {
1093 this.footerNode_ = footerNode; 859 this.footerNode_ = footerNode;
1094 this.content_.appendChild(footerNode); 860 this.content_.appendChild(footerNode);
(...skipping 10 matching lines...) Expand all
1105 * @param {Event} e The mousewheel event. 871 * @param {Event} e The mousewheel event.
1106 */ 872 */
1107 handleMouseWheel: function(e) { 873 handleMouseWheel: function(e) {
1108 if (e.wheelDeltaY == 0) 874 if (e.wheelDeltaY == 0)
1109 return false; 875 return false;
1110 876
1111 this.content_.scrollTop -= e.wheelDeltaY / 3; 877 this.content_.scrollTop -= e.wheelDeltaY / 3;
1112 return true; 878 return true;
1113 }, 879 },
1114 880
1115 /**
1116 * Handler for the 'scroll' event on |content_|.
1117 * @param {Event} e The scroll event.
1118 * @private
1119 */
1120 onScroll_: function(e) {
1121 this.queueUpdateScrollbars_();
1122 },
1123
1124 /**
1125 * ID of scrollbar update timer. If 0, there's no scrollbar re-calc queued.
1126 * @private
1127 */
1128 scrollbarUpdate_: 0,
1129
1130 /**
1131 * Queues an update on the custom scrollbar. Used for two reasons: first,
1132 * coalescing of multiple updates, and second, because action like
1133 * repositioning a tile can require a delay before they affect values
1134 * like clientHeight.
1135 * @private
1136 */
1137 queueUpdateScrollbars_: function() {
1138 if (this.scrollbarUpdate_)
1139 return;
1140
1141 this.scrollbarUpdate_ = window.setTimeout(
1142 this.doUpdateScrollbars_.bind(this), 0);
1143 },
1144
1145 /**
1146 * Does the work of calculating the visibility, height and position of the
1147 * scrollbar thumb (there is no track or buttons).
1148 * @private
1149 */
1150 doUpdateScrollbars_: function() {
1151 this.scrollbarUpdate_ = 0;
1152
1153 var content = this.content_;
1154
1155 // Adjust scroll-height to account for possible header-bar.
1156 var adjustedScrollHeight = content.scrollHeight - content.offsetTop;
1157
1158 if (adjustedScrollHeight <= content.clientHeight) {
1159 this.scrollbar_.hidden = true;
1160 return;
1161 } else {
1162 this.scrollbar_.hidden = false;
1163 }
1164
1165 var thumbTop = content.offsetTop +
1166 content.scrollTop / adjustedScrollHeight * content.clientHeight;
1167 var thumbHeight = content.clientHeight / adjustedScrollHeight *
1168 this.clientHeight;
1169
1170 this.scrollbar_.style.top = thumbTop + 'px';
1171 this.scrollbar_.style.height = thumbHeight + 'px';
1172 this.firePageLayoutEvent_();
1173 },
1174
1175 /**
1176 * Get the height for a tile of a certain width. Override this function to
1177 * get non-square tiles.
1178 * @param {number} width The pixel width of a tile.
1179 * @return {number} The height for |width|.
1180 */
1181 heightForWidth: function(width) {
1182 return width;
1183 },
1184
1185 /** Dragging **/ 881 /** Dragging **/
1186 882
883 // TODO(xci) drag
1187 get isCurrentDragTarget() { 884 get isCurrentDragTarget() {
1188 return this.dragWrapper_.isCurrentDragTarget; 885 return this.dragWrapper_.isCurrentDragTarget;
1189 }, 886 },
1190 887
1191 /** 888 /**
1192 * Thunk for dragleave events fired on |tileGrid_|. 889 * Thunk for dragleave events fired on |tileGrid_|.
1193 * @param {Event} e A MouseEvent for the drag. 890 * @param {Event} e A MouseEvent for the drag.
1194 */ 891 */
892 // TODO(xci) drag
1195 doDragLeave: function(e) { 893 doDragLeave: function(e) {
1196 this.cleanupDrag(); 894 this.cleanupDrag();
1197 }, 895 },
1198 896
1199 /** 897 /**
1200 * Performs all actions necessary when a drag enters the tile page. 898 * Performs all actions necessary when a drag enters the tile page.
1201 * @param {Event} e A mouseover event for the drag enter. 899 * @param {Event} e A mouseover event for the drag enter.
1202 */ 900 */
901 // TODO(xci) drag
1203 doDragEnter: function(e) { 902 doDragEnter: function(e) {
1204 // Applies the mask so doppleganger tiles disappear into the fog. 903 // Applies the mask so doppleganger tiles disappear into the fog.
1205 this.updateMask_(); 904 this.updateMask_();
1206 905
1207 this.classList.add('animating-tile-page'); 906 this.classList.add('animating-tile-page');
1208 this.withinPageDrag_ = this.contains(currentlyDraggingTile); 907 this.withinPageDrag_ = this.contains(currentlyDraggingTile);
1209 this.dragItemIndex_ = this.withinPageDrag_ ? 908 this.dragItemIndex_ = this.withinPageDrag_ ?
1210 currentlyDraggingTile.index : this.tileElements_.length; 909 currentlyDraggingTile.index : this.tileElements_.length;
1211 this.currentDropIndex_ = this.dragItemIndex_; 910 this.currentDropIndex_ = this.dragItemIndex_;
1212 911
1213 // The new tile may change the number of rows, hence the top margin 912 // The new tile may change the number of rows, hence the top margin
1214 // will change. 913 // will change.
1215 if (!this.withinPageDrag_) 914 if (!this.withinPageDrag_)
915 // TODO(xci) this function does nothing now!
1216 this.updateTopMargin_(); 916 this.updateTopMargin_();
1217 917
1218 this.doDragOver(e); 918 this.doDragOver(e);
1219 }, 919 },
1220 920
1221 /** 921 /**
1222 * Performs all actions necessary when the user moves the cursor during 922 * Performs all actions necessary when the user moves the cursor during
1223 * a drag over the tile page. 923 * a drag over the tile page.
1224 * @param {Event} e A mouseover event for the drag over. 924 * @param {Event} e A mouseover event for the drag over.
1225 */ 925 */
926 // TODO(xci) drag
1226 doDragOver: function(e) { 927 doDragOver: function(e) {
1227 e.preventDefault(); 928 e.preventDefault();
1228 929
1229 this.setDropEffect(e.dataTransfer); 930 this.setDropEffect(e.dataTransfer);
1230 var newDragIndex = this.getWouldBeIndexForPoint_(e.pageX, e.pageY); 931 var newDragIndex = this.getWouldBeIndexForPoint_(e.pageX, e.pageY);
1231 if (newDragIndex < 0 || newDragIndex >= this.tileElements_.length) 932 if (newDragIndex < 0 || newDragIndex >= this.tileElements_.length)
1232 newDragIndex = this.dragItemIndex_; 933 newDragIndex = this.dragItemIndex_;
1233 this.updateDropIndicator_(newDragIndex); 934 this.updateDropIndicator_(newDragIndex);
1234 }, 935 },
1235 936
1236 /** 937 /**
1237 * Performs all actions necessary when the user completes a drop. 938 * Performs all actions necessary when the user completes a drop.
1238 * @param {Event} e A mouseover event for the drag drop. 939 * @param {Event} e A mouseover event for the drag drop.
1239 */ 940 */
941 // TODO(xci) drag
1240 doDrop: function(e) { 942 doDrop: function(e) {
1241 e.stopPropagation(); 943 e.stopPropagation();
1242 e.preventDefault(); 944 e.preventDefault();
1243 945
1244 var index = this.currentDropIndex_; 946 var index = this.currentDropIndex_;
1245 // Only change data if this was not a 'null drag'. 947 // Only change data if this was not a 'null drag'.
1246 if (!((index == this.dragItemIndex_) && this.withinPageDrag_)) { 948 if (!((index == this.dragItemIndex_) && this.withinPageDrag_)) {
1247 var adjustedIndex = this.currentDropIndex_ + 949 var adjustedIndex = this.currentDropIndex_ +
1248 (index > this.dragItemIndex_ ? 1 : 0); 950 (index > this.dragItemIndex_ ? 1 : 0);
1249 if (this.withinPageDrag_) { 951 if (this.withinPageDrag_) {
(...skipping 16 matching lines...) Expand all
1266 } 968 }
1267 969
1268 this.classList.remove('animating-tile-page'); 970 this.classList.remove('animating-tile-page');
1269 this.cleanupDrag(); 971 this.cleanupDrag();
1270 }, 972 },
1271 973
1272 /** 974 /**
1273 * Appends the currently dragged tile to the end of the page. Called 975 * Appends the currently dragged tile to the end of the page. Called
1274 * from outside the page, e.g. when dropping on a nav dot. 976 * from outside the page, e.g. when dropping on a nav dot.
1275 */ 977 */
978 // TODO(xci) drag
1276 appendDraggingTile: function() { 979 appendDraggingTile: function() {
1277 var originalPage = currentlyDraggingTile.tilePage; 980 var originalPage = currentlyDraggingTile.tilePage;
1278 if (originalPage == this) 981 if (originalPage == this)
1279 return; 982 return;
1280 983
1281 this.addDragData(null, this.tileElements_.length); 984 this.addDragData(null, this.tileElements_.length);
1282 if (originalPage) 985 if (originalPage)
1283 originalPage.cleanupDrag(); 986 originalPage.cleanupDrag();
1284 }, 987 },
1285 988
1286 /** 989 /**
1287 * Makes sure all the tiles are in the right place after a drag is over. 990 * Makes sure all the tiles are in the right place after a drag is over.
1288 */ 991 */
992 // TODO(xci) drag
1289 cleanupDrag: function() { 993 cleanupDrag: function() {
1290 this.repositionTiles_(currentlyDraggingTile); 994 this.repositionTiles_(currentlyDraggingTile);
1291 // Remove the drag mask. 995 // Remove the drag mask.
1292 this.updateMask_(); 996 this.updateMask_();
1293 }, 997 },
1294 998
1295 /** 999 /**
1296 * Reposition all the tiles (possibly ignoring one). 1000 * Reposition all the tiles (possibly ignoring one).
1297 * @param {?Node} ignoreNode An optional node to ignore. 1001 * @param {?Node} ignoreNode An optional node to ignore.
1298 * @private 1002 * @private
1299 */ 1003 */
1004 // TODO(xci) drag
1300 repositionTiles_: function(ignoreNode) { 1005 repositionTiles_: function(ignoreNode) {
1006 /*
1301 for (var i = 0; i < this.tileElements_.length; i++) { 1007 for (var i = 0; i < this.tileElements_.length; i++) {
1302 if (!ignoreNode || ignoreNode !== this.tileElements_[i]) 1008 if (!ignoreNode || ignoreNode !== this.tileElements_[i])
1303 this.positionTile_(i); 1009 ;//this.positionTile_(i); TODO(xci) this function was deleted!
1304 } 1010 }
1011 */
1305 }, 1012 },
1306 1013
1307 /** 1014 /**
1308 * Updates the visual indicator for the drop location for the active drag. 1015 * Updates the visual indicator for the drop location for the active drag.
1309 * @param {Event} e A MouseEvent for the drag. 1016 * @param {Event} e A MouseEvent for the drag.
1310 * @private 1017 * @private
1311 */ 1018 */
1019 // TODO(xci) drag
1312 updateDropIndicator_: function(newDragIndex) { 1020 updateDropIndicator_: function(newDragIndex) {
1313 var oldDragIndex = this.currentDropIndex_; 1021 var oldDragIndex = this.currentDropIndex_;
1314 if (newDragIndex == oldDragIndex) 1022 if (newDragIndex == oldDragIndex)
1315 return; 1023 return;
1316 1024
1317 var repositionStart = Math.min(newDragIndex, oldDragIndex); 1025 var repositionStart = Math.min(newDragIndex, oldDragIndex);
1318 var repositionEnd = Math.max(newDragIndex, oldDragIndex); 1026 var repositionEnd = Math.max(newDragIndex, oldDragIndex);
1319 1027
1320 for (var i = repositionStart; i <= repositionEnd; i++) { 1028 for (var i = repositionStart; i <= repositionEnd; i++) {
1321 if (i == this.dragItemIndex_) 1029 if (i == this.dragItemIndex_)
1322 continue; 1030 continue;
1323 else if (i > this.dragItemIndex_) 1031 else if (i > this.dragItemIndex_)
1324 var adjustment = i <= newDragIndex ? -1 : 0; 1032 var adjustment = i <= newDragIndex ? -1 : 0;
1325 else 1033 else
1326 var adjustment = i >= newDragIndex ? 1 : 0; 1034 var adjustment = i >= newDragIndex ? 1 : 0;
1327 1035
1328 this.positionTile_(i, adjustment); 1036 //this.positionTile_(i, adjustment); TODO(xci) function was deleted!
1329 } 1037 }
1330 this.currentDropIndex_ = newDragIndex; 1038 this.currentDropIndex_ = newDragIndex;
1331 }, 1039 },
1332 1040
1333 /** 1041 /**
1334 * Checks if a page can accept a drag with the given data. 1042 * Checks if a page can accept a drag with the given data.
1335 * @param {Event} e The drag event if the drag object. Implementations will 1043 * @param {Event} e The drag event if the drag object. Implementations will
1336 * likely want to check |e.dataTransfer|. 1044 * likely want to check |e.dataTransfer|.
1337 * @return {boolean} True if this page can handle the drag. 1045 * @return {boolean} True if this page can handle the drag.
1338 */ 1046 */
1047 // TODO(xci) drag
1339 shouldAcceptDrag: function(e) { 1048 shouldAcceptDrag: function(e) {
1340 return false; 1049 return false;
1341 }, 1050 },
1342 1051
1343 /** 1052 /**
1344 * Called to accept a drag drop. Will not be called for in-page drops. 1053 * Called to accept a drag drop. Will not be called for in-page drops.
1345 * @param {Object} dataTransfer The data transfer object that holds the drop 1054 * @param {Object} dataTransfer The data transfer object that holds the drop
1346 * data. This should only be used if currentlyDraggingTile is null. 1055 * data. This should only be used if currentlyDraggingTile is null.
1347 * @param {number} index The tile index at which the drop occurred. 1056 * @param {number} index The tile index at which the drop occurred.
1348 */ 1057 */
1058 // TODO(xci) drag
1349 addDragData: function(dataTransfer, index) { 1059 addDragData: function(dataTransfer, index) {
1350 assert(false); 1060 assert(false);
1351 }, 1061 },
1352 1062
1353 /** 1063 /**
1354 * Called when a tile has been moved (via dragging). Override this to make 1064 * Called when a tile has been moved (via dragging). Override this to make
1355 * backend updates. 1065 * backend updates.
1356 * @param {Node} draggedTile The tile that was dropped. 1066 * @param {Node} draggedTile The tile that was dropped.
1357 * @param {number} prevIndex The previous index of the tile. 1067 * @param {number} prevIndex The previous index of the tile.
1358 */ 1068 */
1359 tileMoved: function(draggedTile, prevIndex) { 1069 tileMoved: function(draggedTile, prevIndex) {
1360 }, 1070 },
1361 1071
1362 /** 1072 /**
1363 * Sets the drop effect on |dataTransfer| to the desired value (e.g. 1073 * Sets the drop effect on |dataTransfer| to the desired value (e.g.
1364 * 'copy'). 1074 * 'copy').
1365 * @param {Object} dataTransfer The drag event dataTransfer object. 1075 * @param {Object} dataTransfer The drag event dataTransfer object.
1366 */ 1076 */
1077 // TODO(xci) drag
1367 setDropEffect: function(dataTransfer) { 1078 setDropEffect: function(dataTransfer) {
1368 assert(false); 1079 assert(false);
1369 }, 1080 },
1081
1082
1083 // #########################################################################
1084 // XCI - Extended Chrome Instant
1085 // #########################################################################
1086
1087
1088 // properties
1089 // -------------------------------------------------------------------------
1090 colCount: 5,
1091 rowCount: 2,
1092
1093 numOfVisibleRows: 0,
1094 animatingColCount: 5, // TODO initialize
jeremycho_google 2012/08/02 03:00:49 Delete TODO?
pedrosimonetti2 2012/08/03 18:14:12 No, I clarified what to do. On 2012/08/02 03:00:4
1095
1096 // TODO move to layout?
1097 pageOffset: 0,
1098
1099 appendTile: function(tile) {
jeremycho_google 2012/08/02 00:19:11 Can this be factored into addTileAt?
pedrosimonetti2 2012/08/03 18:14:12 The addTileAt() implementation was wrong, and I fi
1100 this.tileElements_.push(tile);
1101 this.renderGrid_();
1102 },
1103
1104 addTileAt: function(tile) {
1105 this.appendTile(tile);
1106 },
1107
1108 // internal helpers
1109 // -------------------------------------------------------------------------
1110
1111 // TODO move to layout?
1112 getNumOfVisibleRows: function() {
jeremycho_google 2012/08/02 03:00:49 getNumOfVisibleRows_
pedrosimonetti2 2012/08/03 18:14:12 Done.
1113 return this.numOfVisibleRows;
1114 },
1115
1116 getTileRequiredWidth_: function() {
1117 var grid = this.gridValues_;
1118 return grid.tileWidth + 2 * grid.tileBorderWidth + grid.tileHorMargin;
1119 },
1120
1121 getColCountForWidth_: function(width) {
1122 var availableWidth = width + this.gridValues_.tileHorMargin;
1123 var requiredWidth = this.getTileRequiredWidth_();
1124 var colCount = Math.floor(availableWidth / requiredWidth);
1125 return colCount;
1126 },
1127
1128 getWidthForColCount_: function(colCount) {
1129 var requiredWidth = this.getTileRequiredWidth_();
1130 var width = colCount * requiredWidth - this.gridValues_.tileHorMargin;
1131 return width;
1132 },
1133
1134 getBottomPanelWidth_: function() {
1135 var windowWidth = cr.doc.documentElement.clientWidth;
1136 var width;
1137 if (windowWidth >= 948) {
jeremycho_google 2012/08/02 00:19:11 Should these numbers be made parameters?
pedrosimonetti2 2012/08/03 18:14:12 Maybe, added a TODO. This will depend on the WebVi
1138 width = 748;
1139 } else if (windowWidth >= 500) {
1140 width = windowWidth - 2 * this.gridValues_.bottomPanelHorMargin;
1141 } else if (windowWidth >= 300) {
1142 // TODO(pedrosimonetti): check math and document
1143 width = Math.floor(((windowWidth - 300) / 200) * 100 + 200);
1144 } else {
1145 width = 200;
1146 }
1147 return width;
1148 },
1149
1150 getAvailableColCount_: function() {
1151 return this.getColCountForWidth_(this.getBottomPanelWidth_());
1152 },
1153
1154 // rendering
1155 // -------------------------------------------------------------------------
1156
1157 renderGrid_: function(colCount, tileElements) {
jeremycho_google 2012/08/02 00:19:11 Please provide brief function-level comment for no
jeremycho_google 2012/08/02 03:00:49 Never called with tileElements?
pedrosimonetti2 2012/08/03 18:14:12 Maybe I'll have to change this function soon, so I
pedrosimonetti2 2012/08/03 18:14:12 It was being called with tileElements in the old p
1158 //if (window.xc > 5) debugger;
1159 //window.xc = window.xc || 1, console.log('renderGrid' + window.xc++);
1160 colCount = colCount || this.colCount;
1161
1162 var tileGridContent = this.tileGridContent_;
1163
1164 tileElements = tileElements || this.tileElements_;
1165
1166 var tileCount = tileElements.length;
1167 var rowCount = Math.ceil(tileCount / colCount);
1168
1169 var tileRows = tileGridContent.getElementsByClassName('tile-row');
1170 var tileRow;
1171 var tileRowTiles;
1172 var tileCell;
1173 var tileElement;
1174 var maxColCount;
1175
1176 var numOfVisibleRows = this.getNumOfVisibleRows();
1177 var pageOffset = this.pageOffset;
1178
1179 for (var tile = 0, row = 0; row < rowCount; row++) {
1180 // Get the current tile row.
jeremycho_google 2012/08/02 03:00:49 I think you can drop comments like these if it's f
pedrosimonetti2 2012/08/03 18:14:12 Done.
1181 tileRow = tileRows[row];
1182
1183 // Create tile row if there's no one yet.
1184 if (!tileRow) {
1185 tileRow = cr.doc.createElement('div');
1186 tileRow.className = 'tile-row tile-row-' + row;// TODO do we need id?
1187 tileGridContent.appendChild(tileRow);
1188 }
1189
1190 // Adjust row visibility.
1191 var rowVisible = (row >= pageOffset &&
jeremycho_google 2012/08/02 03:00:49 Make the hide-row add/remove a helper function and
pedrosimonetti2 2012/08/03 18:14:12 Done.
1192 row <= (pageOffset + numOfVisibleRows - 1));
1193 tileRow.classList[rowVisible ? 'remove' : 'add']('hide-row');
1194
1195 // The tiles inside the current row.
1196 tileRowTiles = tileRow.childNodes;
1197
1198 // Remove excessive columns from a particular tile row.
1199 maxColCount = Math.min(colCount, tileCount - tile);
1200 while (tileRowTiles.length > maxColCount) {
1201 tileRow.removeChild(tileRow.lastElementChild);
1202 }
1203
1204 // For each column in the current row.
1205 for (var col = 0; col < colCount; col++, tile++) {
1206
jeremycho_google 2012/08/02 03:00:49 Delete newline
pedrosimonetti2 2012/08/03 18:14:12 Done.
1207 if (tileRowTiles[col]) {
1208 tileCell = tileRowTiles[col];
1209 } else {
1210 var span = cr.doc.createElement('span');
1211 tileCell = new TileCell(span, this.gridValues_);
1212 }
1213
1214 // Reset column class.
1215 this.resetTileCol_(tileCell, col);
1216
1217 // Render Tiles.
1218 if (tile < tileCount) {
1219 tileCell.classList.remove('filler');
1220 tileElement = tileElements[tile];
1221 if (tileCell.firstChild) {
jeremycho_google 2012/08/02 03:00:49 Factor out duplicate code here and in the else?
pedrosimonetti2 2012/08/03 18:14:12 They are slightly different so I don't think we ca
1222 if (tileElement != tileCell.firstChild) {
1223 tileCell.replaceChild(tileElement, tileCell.firstChild);
1224 }
1225 } else {
1226 tileCell.appendChild(tileElement);
1227 }
1228 } else {
1229 // TODO create filler and method to
jeremycho_google 2012/08/02 03:00:49 Please clarify comment.
pedrosimonetti2 2012/08/03 18:14:12 Done.
1230 if (!tileCell.classList.contains('filler')) {
1231 tileCell.classList.add('filler');
1232 tileElement = cr.doc.createElement('span');
1233 if (tileCell.firstChild)
1234 tileCell.replaceChild(tileElement, tileCell.firstChild);
1235 else
1236 tileCell.appendChild(tileElement);
1237 }
1238 }
1239
1240 if (!tileRowTiles[col]) {
1241 tileRow.appendChild(tileCell);
jeremycho_google 2012/08/02 03:00:49 Move to the L1209 else?
pedrosimonetti2 2012/08/03 18:14:12 No, because when we are creating new TileCells, we
1242 }
1243 }
1244 }
1245
1246 // Remove excessive tile rows from the tile grid.
1247 while (tileRows.length > rowCount) {
1248 tileGridContent.removeChild(tileGridContent.lastElementChild);
1249 }
1250
1251 this.colCount = colCount;
1252 this.rowCount = rowCount;
1253 },
1254
1255 layout_: function() {
1256 var pageList = $('page-list');
1257 var panel = this.content_;
1258 var menu = $('page-list-menu');
1259 var tileGrid = this.tileGrid_;
1260 var tileGridContent = this.tileGridContent_;
1261 var tileRows = tileGridContent.getElementsByClassName('tile-row');
1262
1263 tileGridContent.classList.add('animate-tile');
1264
1265 var bottomPanelWidth = this.getBottomPanelWidth_();
1266 var colCount = this.getColCountForWidth_(bottomPanelWidth);
1267 var lastColCount = this.colCount;
1268 var animatingColCount = this.animatingColCount;
1269
1270 var windowHeight = cr.doc.documentElement.clientHeight;
1271
1272 // TODO better handling of height state
1273 // changeVisibleRows
1274 // TODO need to call paginate when height changes
1275 var numOfVisibleRows = this.numOfVisibleRows;
1276 if (windowHeight > 500) {
1277 numOfVisibleRows = 2;
1278 } else {
1279 numOfVisibleRows = 1;
1280 }
1281
1282 if (numOfVisibleRows != this.numOfVisibleRows) {
1283 this.numOfVisibleRows = numOfVisibleRows;
1284 this.paginate(null, true);
1285 pageList.style.height = (107 * numOfVisibleRows) + 'px';
1286 //tileGrid.style.height = (107 * numOfVisibleRows) + 'px';
1287 }
1288
1289 // changeVisibleCols
1290 if (colCount != animatingColCount) {
1291
1292 var newWidth = this.getWidthForColCount_(colCount);
1293 if (colCount > animatingColCount) {
1294
1295 // TODO actual size check
1296 if (colCount != lastColCount) {
1297 this.renderGrid_(colCount);
1298 //this.renderTiles_(colCount);
1299 }
1300
1301 this.showTileCols_(animatingColCount, false);
1302
1303 var self = this;
1304 setTimeout((function(animatingColCount) {
jeremycho_google 2012/08/02 03:00:49 Comment why this is necessary?
pedrosimonetti2 2012/08/03 18:14:12 I was having a problem with this code a while ago,
1305 return function() {
1306 self.showTileCols_(animatingColCount, true);
1307 }
1308 })(animatingColCount), 0);
1309
1310 } else {
1311 this.showTileCols_(colCount, false);
1312 }
1313
1314 tileGrid.style.width = newWidth + 'px';
1315 menu.style.width = newWidth + 'px';
1316
1317 // TODO: listen animateEnd
1318 var self = this;
1319 this.onTileGridAnimationEndHandler_ = function() {
1320 if (colCount < lastColCount) {
1321 self.renderGrid_(colCount);
1322 //self.renderTiles_(colCount);
1323 } else {
1324 self.showTileCols_(0, true);
1325 }
1326 };
1327
1328 this.paginate();
1329
1330 }
1331
1332 panel.style.width = bottomPanelWidth + 'px';
1333
1334 this.animatingColCount = colCount;
1335 },
1336
1337 // animation helpers
1338 // -------------------------------------------------------------------------
1339
1340 // TODO make it local?
1341 showTileCols_: function(col, show) {
1342 var prop = show ? 'remove' : 'add';
1343 var max = 10; // TODO(pedrosimonetti) const?
1344 var tileGridContent = this.tileGridContent_;
1345 for (var i = col; i < max; i++) {
1346 tileGridContent.classList[prop]('hide-col-' + i);
1347 }
1348 },
1349
1350 // TODO make it local?
1351 resetTileCol_: function(tileCell, col) {
1352 var max = 10;
1353 for (var i = 0; i < max; i++) {
1354 if (i != col) {
1355 tileCell.classList.remove('tile-col-' + i);
1356 }
1357 }
1358 tileCell.classList.add('tile-col-' + col);
1359 },
1360
1361 // pagination
1362 // -------------------------------------------------------------------------
1363
1364 paginate: function(pageOffset, force) {
jeremycho_google 2012/08/02 03:00:49 paginate_
pedrosimonetti2 2012/08/03 18:14:12 Done.
1365 var numOfVisibleRows = this.getNumOfVisibleRows();
1366 var pageOffset = typeof pageOffset == 'number' ?
1367 pageOffset : this.pageOffset;
1368
1369 pageOffset = Math.max(0, pageOffset);
1370 pageOffset = Math.min(this.rowCount - numOfVisibleRows, pageOffset);
1371
1372 if (pageOffset != this.pageOffset || force) {
1373 var rows = this.tileGridContent_.getElementsByClassName('tile-row');
1374 for (var i = 0, l = rows.length; i < l; i++) {
1375 var row = rows[i];
1376 if (i >= pageOffset && i <= (pageOffset + numOfVisibleRows - 1)) {
1377 row.classList.remove('hide-row');
1378 } else {
1379 row.classList.add('hide-row');
1380 }
1381 }
1382
1383 this.pageOffset = pageOffset;
1384 this.tileGridContent_.style.webkitTransform = 'translate3d(0, ' +
1385 (-pageOffset * 106) + 'px, 0)';
1386 }
1387 },
1388
1389 // event handlers
1390 // -------------------------------------------------------------------------
1391
1392 onResize_: function() {
1393 this.layout_();
1394 },
1395
1396 onTileGridAnimationEnd_: function() {
1397 // TODO figure out how to cleanup each kind animation properly
1398 //console.log('AnimEnd', event.target.className, event.target, event);
1399 //console.log('--------------------------------------------------------');
1400 if (event.target == this.tileGrid_ &&
1401 this.onTileGridAnimationEndHandler_) {
1402 if (this.tileGridContent_.classList.contains('animate-tile')) {
1403 this.onTileGridAnimationEndHandler_();
1404 //this.tileGridContent_.classList.remove('animate-tile')
jeremycho_google 2012/08/02 00:19:11 This class never gets removed, intentional?
pedrosimonetti2 2012/08/03 18:14:12 We need to refactor this piece of code later. On
1405 }
1406 }
1407 },
1408
1409 onKeyDown_: function(e) {
jeremycho_google 2012/08/02 00:19:11 Should this be onKeyUp instead (if the user holds
pedrosimonetti2 2012/08/03 18:14:12 Done.
1410 var pageOffset = this.pageOffset;
1411
1412 var keyCode = e.keyCode;
1413 if (keyCode == 40 /* down */) {
1414 pageOffset++;
1415 } else if (keyCode == 38 /* up */) {
1416 pageOffset--;
1417 }
1418
1419 if (pageOffset != this.pageOffset) {
1420 this.paginate(pageOffset);
1421 }
1422 }
1423
1370 }; 1424 };
1371 1425
1426
1427 var duration = 200;
1428 var defaultDuration = 200;
1429 var animatedProperties = [
1430 '#card-slider-frame .tile-grid',
1431 '#card-slider-frame .tile-grid-content',
1432 '#card-slider-frame .tile-row',
1433 '.animate-tile .tile-cell',
1434 '.debug .animate-tile .tile-cell'
1435 ];
1436
1437 function adjustAnimationTiming(slownessFactor, selectors) {
1438 slownessFactor = slownessFactor || 1;
1439 duration = defaultDuration * slownessFactor;
1440 for (var i = 0, l = selectors.length; i < l; i++) {
1441 var selector = selectors[i];
1442 var rule = findCSSRule(selector);
1443 if (rule) {
1444 rule.style.webkitTransitionDuration = duration + 'ms';
1445 } else {
1446 throw 'Could not find the CSS rule "' + selector + '"';
1447 }
1448 }
1449 }
1450
1451 function findCSSRule(selectorText) {
1452 var rules = document.styleSheets[0].rules;
1453 for (var i = 0, l = rules.length; i < l; i++) {
1454 var rule = rules[i];
1455 if (rule.selectorText == selectorText)
1456 {
1457 return rule;
1458 }
1459 }
1460 }
1461
1462 function changeSlowFactor(el) {
jeremycho_google 2012/08/02 00:19:11 Unused?
pedrosimonetti2 2012/08/03 18:14:12 I'll add the debugging features later. On 2012/08
1463 if (el.value)
1464 adjustAnimationTiming(el.value - 0, animatedProperties);
1465 }
1466
1467 function changeDebugMode(el) {
jeremycho_google 2012/08/02 00:19:11 Unused?
pedrosimonetti2 2012/08/03 18:14:12 I'll add the debugging features later. On 2012/08
1468 var prop = el.checked ? 'add' : 'remove';
1469 document.body.classList[prop]('debug');
1470 }
1471
1372 return { 1472 return {
1373 getCurrentlyDraggingTile: getCurrentlyDraggingTile, 1473 // TODO(xci) drag
1374 setCurrentDropEffect: setCurrentDropEffect, 1474 //getCurrentlyDraggingTile2: getCurrentlyDraggingTile,
1375 TilePage: TilePage, 1475 //setCurrentDropEffect2: setCurrentDropEffect,
1476 Tile2: Tile,
1477 TilePage2: TilePage,
1376 }; 1478 };
1377 }); 1479 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698