OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 }); |
OLD | NEW |