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 /** | |
10 * The maximum gap from the edge of the scrolling area which will display | |
11 * the shadow with transparency. After this point the shadow will become | |
12 * 100% opaque. | |
13 * @type {number} | |
14 * @const | |
15 */ | |
16 var MAX_SCROLL_SHADOW_GAP = 16; | |
17 | |
18 /** | |
19 * @type {number} | |
20 * @const | |
21 */ | |
22 var TILE_ROW_HEIGHT = 92; | |
23 | |
24 /** | |
25 * @type {number} | |
26 * @const | |
27 */ | |
28 var SCROLL_BAR_WIDTH = 12; | |
29 | |
8 //---------------------------------------------------------------------------- | 30 //---------------------------------------------------------------------------- |
9 // Tile | 31 // Tile |
10 //---------------------------------------------------------------------------- | 32 //---------------------------------------------------------------------------- |
11 | 33 |
12 /** | 34 /** |
13 * A virtual Tile class. Each TilePage subclass should have its own Tile | 35 * A virtual Tile class. Each TilePage subclass should have its own Tile |
14 * subclass implemented too (e.g. MostVisitedPage contains MostVisited | 36 * subclass implemented too (e.g. MostVisitedPage contains MostVisited |
15 * tiles, and MostVisited is a Tile subclass). | 37 * tiles, and MostVisited is a Tile subclass). |
16 * @constructor | 38 * @constructor |
17 * @param {Object} config TilePage configuration object. | 39 * @param {Object} config TilePage configuration object. |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
190 | 212 |
191 /** | 213 /** |
192 * Creates a new TilePage object. This object contains tiles and controls | 214 * Creates a new TilePage object. This object contains tiles and controls |
193 * their layout. | 215 * their layout. |
194 * @constructor | 216 * @constructor |
195 * @extends {HTMLDivElement} | 217 * @extends {HTMLDivElement} |
196 */ | 218 */ |
197 function TilePage() { | 219 function TilePage() { |
198 var el = cr.doc.createElement('div'); | 220 var el = cr.doc.createElement('div'); |
199 el.__proto__ = TilePage.prototype; | 221 el.__proto__ = TilePage.prototype; |
200 el.initialize(); | |
201 | 222 |
202 return el; | 223 return el; |
203 } | 224 } |
204 | 225 |
205 TilePage.prototype = { | 226 TilePage.prototype = { |
206 __proto__: HTMLDivElement.prototype, | 227 __proto__: HTMLDivElement.prototype, |
207 | 228 |
208 /** | 229 /** |
209 * Reference to the Tile subclass that will be used to create the tiles. | 230 * Reference to the Tile subclass that will be used to create the tiles. |
210 * @constructor | 231 * @constructor |
211 * @extends {Tile} | 232 * @extends {Tile} |
212 */ | 233 */ |
213 TileClass: Tile, | 234 TileClass: Tile, |
214 | 235 |
215 // The config object should be defined by a TilePage subclass if it | 236 // The config object should be defined by a TilePage subclass if it |
216 // wants the non-default behavior. | 237 // wants the non-default behavior. |
217 config: { | 238 config: { |
218 // The width of a cell. | 239 // The width of a cell. |
219 cellWidth: 110, | 240 cellWidth: 110, |
220 // The start margin of a cell (left or right according to text direction). | 241 // The start margin of a cell (left or right according to text direction). |
221 cellMarginStart: 12, | 242 cellMarginStart: 12, |
222 // The maximum number of Tiles to be displayed. | 243 // The maximum number of Tiles to be displayed. |
223 maxTileCount: 6 | 244 maxTileCount: 6, |
245 // Whether the TilePage content will be scrollable. | |
246 scrollable: false, | |
224 }, | 247 }, |
225 | 248 |
226 /** | 249 /** |
227 * Initializes a TilePage. | 250 * Initializes a TilePage. |
228 */ | 251 */ |
229 initialize: function() { | 252 initialize: function() { |
230 this.className = 'tile-page'; | 253 this.className = 'tile-page'; |
231 | 254 |
232 // The content defines the actual space a page has to display tiles. | 255 // The div that wraps the scrollable element. |
256 this.frame_ = this.ownerDocument.createElement('div'); | |
257 this.frame_.className = 'tile-page-frame'; | |
258 this.appendChild(this.frame_); | |
259 | |
260 // The content/scrollable element. | |
233 this.content_ = this.ownerDocument.createElement('div'); | 261 this.content_ = this.ownerDocument.createElement('div'); |
234 this.content_.className = 'tile-page-content'; | 262 this.content_.className = 'tile-page-content'; |
235 this.appendChild(this.content_); | 263 this.frame_.appendChild(this.content_); |
264 | |
265 if (this.config.scrollable) { | |
266 this.content_.classList.add('scrollable'); | |
267 | |
268 // The scrollable shadow top. | |
269 this.shadowTop_ = this.ownerDocument.createElement('div'); | |
270 this.shadowTop_.className = 'shadow-top'; | |
271 this.content_.appendChild(this.shadowTop_); | |
272 | |
273 // The scrollable shadow bottom. | |
274 this.shadowBottom_ = this.ownerDocument.createElement('div'); | |
275 this.shadowBottom_.className = 'shadow-bottom'; | |
276 this.content_.appendChild(this.shadowBottom_); | |
277 } | |
236 | 278 |
237 // The div that defines the tile grid viewport. | 279 // The div that defines the tile grid viewport. |
238 this.tileGrid_ = this.ownerDocument.createElement('div'); | 280 this.tileGrid_ = this.ownerDocument.createElement('div'); |
239 this.tileGrid_.className = 'tile-grid'; | 281 this.tileGrid_.className = 'tile-grid'; |
240 this.content_.appendChild(this.tileGrid_); | 282 this.content_.appendChild(this.tileGrid_); |
241 | 283 |
242 // The tile grid contents, which can be scrolled. | 284 // The tile grid contents, which can be scrolled. |
243 this.tileGridContent_ = this.ownerDocument.createElement('div'); | 285 this.tileGridContent_ = this.ownerDocument.createElement('div'); |
244 this.tileGridContent_.className = 'tile-grid-content'; | 286 this.tileGridContent_.className = 'tile-grid-content'; |
245 this.tileGrid_.appendChild(this.tileGridContent_); | 287 this.tileGrid_.appendChild(this.tileGridContent_); |
246 | 288 |
247 // The list of Tile elements which is used to fill the TileGrid cells. | 289 // The list of Tile elements which is used to fill the TileGrid cells. |
248 this.tiles_ = []; | 290 this.tiles_ = []; |
249 | 291 |
250 // TODO(pedrosimonetti): Check duplication of these methods. | 292 // TODO(pedrosimonetti): Check duplication of these methods. |
251 this.addEventListener('cardselected', this.handleCardSelection_); | 293 this.addEventListener('cardselected', this.handleCardSelection_); |
252 this.addEventListener('carddeselected', this.handleCardDeselection_); | 294 this.addEventListener('carddeselected', this.handleCardDeselection_); |
253 | 295 |
254 this.tileGrid_.addEventListener('webkitTransitionEnd', | 296 this.tileGrid_.addEventListener('webkitTransitionEnd', |
255 this.onTileGridTransitionEnd_.bind(this)); | 297 this.onTileGridTransitionEnd_.bind(this)); |
298 | |
299 this.content_.addEventListener('scroll', this.onScroll.bind(this)); | |
256 }, | 300 }, |
257 | 301 |
258 /** | 302 /** |
259 * The list of Tile elements. | 303 * The list of Tile elements. |
260 * @type {Array<Tile>} | 304 * @type {Array<Tile>} |
261 */ | 305 */ |
262 get tiles() { | 306 get tiles() { |
263 return this.tiles_; | 307 return this.tiles_; |
264 }, | 308 }, |
265 | 309 |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
491 var config = this.config; | 535 var config = this.config; |
492 return config.cellWidth + config.cellMarginStart; | 536 return config.cellWidth + config.cellMarginStart; |
493 }, | 537 }, |
494 | 538 |
495 /** | 539 /** |
496 * Gets the the maximum number of columns that can fit in a given width. | 540 * Gets the the maximum number of columns that can fit in a given width. |
497 * @param {number} width The width in pixels. | 541 * @param {number} width The width in pixels. |
498 * @private | 542 * @private |
499 */ | 543 */ |
500 getColCountForWidth_: function(width) { | 544 getColCountForWidth_: function(width) { |
501 var availableWidth = width + this.config.cellMarginStart; | 545 var scrollBarIsVisible = this.config.scrollable && |
546 this.content_.scrollHeight > this.content_.clientHeight; | |
547 var scrollBarWidth = scrollBarIsVisible ? SCROLL_BAR_WIDTH : 0; | |
548 var availableWidth = width + this.config.cellMarginStart - scrollBarWidth; | |
549 | |
502 var requiredWidth = this.getTileRequiredWidth_(); | 550 var requiredWidth = this.getTileRequiredWidth_(); |
503 var colCount = Math.floor(availableWidth / requiredWidth); | 551 var colCount = Math.floor(availableWidth / requiredWidth); |
504 return colCount; | 552 return colCount; |
505 }, | 553 }, |
506 | 554 |
507 /** | 555 /** |
508 * Gets the width for a given number of columns. | 556 * Gets the width for a given number of columns. |
509 * @param {number} colCount The number of columns. | 557 * @param {number} colCount The number of columns. |
510 * @private | 558 * @private |
511 */ | 559 */ |
512 getWidthForColCount_: function(colCount) { | 560 getWidthForColCount_: function(colCount) { |
513 var requiredWidth = this.getTileRequiredWidth_(); | 561 var requiredWidth = this.getTileRequiredWidth_(); |
514 var width = colCount * requiredWidth - this.config.cellMarginStart; | 562 var width = colCount * requiredWidth - this.config.cellMarginStart; |
515 return width; | 563 return width; |
516 }, | 564 }, |
517 | 565 |
518 /** | 566 /** |
519 * Returns the position of the tile at |index|. | 567 * Returns the position of the tile at |index|. |
520 * @param {number} index Tile index. | 568 * @param {number} index Tile index. |
521 * @private | 569 * @private |
522 * @return {!{top: number, left: number}} Position. | 570 * @return {!{top: number, left: number}} Position. |
523 */ | 571 */ |
524 getTilePosition_: function(index) { | 572 getTilePosition_: function(index) { |
525 var colCount = this.colCount_; | 573 var colCount = this.colCount_; |
574 var row = Math.floor(index / colCount); | |
526 var col = index % colCount; | 575 var col = index % colCount; |
527 if (isRTL()) | 576 if (isRTL()) |
528 col = colCount - col - 1; | 577 col = colCount - col - 1; |
529 var config = this.config; | 578 var config = this.config; |
579 var top = TILE_ROW_HEIGHT * row; | |
530 var left = col * (config.cellWidth + config.cellMarginStart); | 580 var left = col * (config.cellWidth + config.cellMarginStart); |
531 return {top: 0, left: left}; | 581 return {top: top, left: left}; |
532 }, | 582 }, |
533 | 583 |
534 // rendering | 584 // rendering |
535 // ------------------------------------------------------------------------- | 585 // ------------------------------------------------------------------------- |
536 | 586 |
537 /** | 587 /** |
538 * Renders the tile grid, and the individual tiles. Rendering the grid | 588 * Renders the tile grid, and the individual tiles. Rendering the grid |
539 * consists of adding/removing tile rows and tile cells according to the | 589 * consists of adding/removing tile rows and tile cells according to the |
540 * specified size (defined by the number of columns in the grid). While | 590 * specified size (defined by the number of columns in the grid). While |
541 * rendering the grid, the tiles are rendered in order in their respective | 591 * rendering the grid, the tiles are rendered in order in their respective |
(...skipping 21 matching lines...) Expand all Loading... | |
563 for (var tile = 0, row = 0; row < rowCount; row++) { | 613 for (var tile = 0, row = 0; row < rowCount; row++) { |
564 var tileRow = tileRows[row]; | 614 var tileRow = tileRows[row]; |
565 | 615 |
566 // Create tile row if there's no one yet. | 616 // Create tile row if there's no one yet. |
567 if (!tileRow) { | 617 if (!tileRow) { |
568 tileRow = cr.doc.createElement('div'); | 618 tileRow = cr.doc.createElement('div'); |
569 tileRow.className = 'tile-row'; | 619 tileRow.className = 'tile-row'; |
570 tileGridContent.appendChild(tileRow); | 620 tileGridContent.appendChild(tileRow); |
571 } | 621 } |
572 | 622 |
573 // Adjust row visibility. | |
574 var rowVisible = row >= pageOffset && | |
575 row <= (pageOffset + numOfVisibleRows - 1); | |
576 this.showTileRow_(tileRow, rowVisible); | |
577 | |
578 // The tiles inside the current row. | 623 // The tiles inside the current row. |
579 var tileRowTiles = tileRow.childNodes; | 624 var tileRowTiles = tileRow.childNodes; |
580 | 625 |
581 // Remove excessive columns from a particular tile row. | 626 // Remove excessive columns from a particular tile row. |
582 var maxColCount = Math.min(colCount, tileCount - tile); | 627 var maxColCount = Math.min(colCount, tileCount - tile); |
583 maxColCount = Math.max(0, maxColCount); | 628 maxColCount = Math.max(0, maxColCount); |
584 while (tileRowTiles.length > maxColCount) { | 629 while (tileRowTiles.length > maxColCount) { |
585 tileRow.removeChild(tileRow.lastElementChild); | 630 tileRow.removeChild(tileRow.lastElementChild); |
586 } | 631 } |
587 | 632 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
619 } | 664 } |
620 } | 665 } |
621 | 666 |
622 // Remove excessive tile rows from the tile grid. | 667 // Remove excessive tile rows from the tile grid. |
623 while (tileRows.length > rowCount) { | 668 while (tileRows.length > rowCount) { |
624 tileGridContent.removeChild(tileGridContent.lastElementChild); | 669 tileGridContent.removeChild(tileGridContent.lastElementChild); |
625 } | 670 } |
626 | 671 |
627 this.colCount_ = colCount; | 672 this.colCount_ = colCount; |
628 this.rowCount_ = rowCount; | 673 this.rowCount_ = rowCount; |
674 | |
675 if (this.onScroll) | |
Dan Beam
2012/11/30 23:41:45
nit: same nit re: if (this.onScroll)
pedro (no code reviews)
2012/12/01 00:02:29
Done.
| |
676 this.onScroll(); | |
629 }, | 677 }, |
630 | 678 |
631 // layout | 679 // layout |
632 // ------------------------------------------------------------------------- | 680 // ------------------------------------------------------------------------- |
633 | 681 |
634 /** | 682 /** |
635 * Calculates the layout of the tile page according to the current Bottom | 683 * Calculates the layout of the tile page according to the current Bottom |
636 * Panel's size. This method will resize the containers of the tile page, | 684 * Panel's size. This method will resize the containers of the tile page, |
637 * and re-render the grid when its dimension changes (number of columns or | 685 * and re-render the grid when its dimension changes (number of columns or |
638 * visible rows changes). This method also sets the private properties | 686 * visible rows changes). This method also sets the private properties |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
674 // TODO(pedrosimonetti): move to handler below. | 722 // TODO(pedrosimonetti): move to handler below. |
675 var self = this; | 723 var self = this; |
676 this.onTileGridTransitionEndHandler_ = function() { | 724 this.onTileGridTransitionEndHandler_ = function() { |
677 if (colCount < lastColCount) | 725 if (colCount < lastColCount) |
678 self.renderGrid_(colCount); | 726 self.renderGrid_(colCount); |
679 else | 727 else |
680 self.showTileCols_(0, true); | 728 self.showTileCols_(0, true); |
681 }; | 729 }; |
682 } | 730 } |
683 | 731 |
684 this.content_.style.width = contentWidth + 'px'; | 732 this.animatingColCount_ = colCount; |
685 | 733 |
686 this.animatingColCount_ = colCount; | 734 this.frame_.style.width = contentWidth + 'px'; |
735 | |
736 this.onScroll(); | |
687 }, | 737 }, |
688 | 738 |
689 // tile repositioning animation | 739 // tile repositioning animation |
690 // ------------------------------------------------------------------------- | 740 // ------------------------------------------------------------------------- |
691 | 741 |
692 /** | 742 /** |
693 * Tile repositioning state. | 743 * Tile repositioning state. |
694 * @type {{index: number, isRemoving: number}} | 744 * @type {{index: number, isRemoving: number}} |
695 */ | 745 */ |
696 tileRepositioningState_: null, | 746 tileRepositioningState_: null, |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
945 var positionDiff = isRemoving ? -1 : 1; | 995 var positionDiff = isRemoving ? -1 : 1; |
946 for (var i = startIndex; i < endIndex; i++) { | 996 for (var i = startIndex; i < endIndex; i++) { |
947 var tile = tiles[i]; | 997 var tile = tiles[i]; |
948 this.resetTilePosition_(tile); | 998 this.resetTilePosition_(tile); |
949 tile.style.zIndex = ''; | 999 tile.style.zIndex = ''; |
950 tileCells[i + positionDiff].assign(tile); | 1000 tileCells[i + positionDiff].assign(tile); |
951 } | 1001 } |
952 }, | 1002 }, |
953 | 1003 |
954 /** | 1004 /** |
955 * Animates the display of a row. TODO(pedrosimonetti): Make it local? | 1005 * Animates the display of columns. |
956 * @param {HTMLElement} row The row element. | |
957 * @param {boolean} show Whether or not to show the row. | |
958 */ | |
959 showTileRow_: function(row, show) { | |
960 row.classList[show ? 'remove' : 'add']('hide-row'); | |
961 }, | |
962 | |
963 /** | |
964 * Animates the display of columns. TODO(pedrosimonetti): Make it local? | |
965 * @param {number} col The column number. | 1006 * @param {number} col The column number. |
966 * @param {boolean} show Whether or not to show the row. | 1007 * @param {boolean} show Whether or not to show the row. |
967 */ | 1008 */ |
968 showTileCols_: function(col, show) { | 1009 showTileCols_: function(col, show) { |
969 var prop = show ? 'remove' : 'add'; | 1010 var prop = show ? 'remove' : 'add'; |
970 var max = 10; // TODO(pedrosimonetti): Add const? | 1011 var max = 10; // TODO(pedrosimonetti): Add const? |
971 var tileGridContent = this.tileGridContent_; | 1012 var tileGridContent = this.tileGridContent_; |
972 for (var i = col; i < max; i++) { | 1013 for (var i = col; i < max; i++) { |
973 tileGridContent.classList[prop]('hide-col-' + i); | 1014 tileGridContent.classList[prop]('hide-col-' + i); |
974 } | 1015 } |
975 }, | 1016 }, |
976 | 1017 |
977 // event handlers | 1018 // event handlers |
978 // ------------------------------------------------------------------------- | 1019 // ------------------------------------------------------------------------- |
979 | 1020 |
980 /** | 1021 /** |
1022 * Handles the scroll event. | |
1023 * @protected | |
1024 */ | |
1025 onScroll: function() { | |
1026 // If the TilePage is scrollable, then the opacity of shadow top and | |
1027 // bottom must adjusted, indicating when there's an overflow content. | |
1028 if (this.config.scrollable) { | |
1029 var content = this.content_; | |
1030 var topGap = Math.min(MAX_SCROLL_SHADOW_GAP, content.scrollTop); | |
1031 var bottomGap = Math.min(MAX_SCROLL_SHADOW_GAP, content.scrollHeight - | |
1032 content.scrollTop - content.clientHeight); | |
1033 | |
1034 this.shadowTop_.style.opacity = topGap / MAX_SCROLL_SHADOW_GAP; | |
1035 this.shadowBottom_.style.opacity = bottomGap / MAX_SCROLL_SHADOW_GAP; | |
1036 } | |
1037 }, | |
1038 | |
1039 /** | |
981 * Handles the end of the horizontal tile grid transition. | 1040 * Handles the end of the horizontal tile grid transition. |
982 * @param {Event} e The tile grid webkitTransitionEnd event. | 1041 * @param {Event} e The tile grid webkitTransitionEnd event. |
983 */ | 1042 */ |
984 onTileGridTransitionEnd_: function(e) { | 1043 onTileGridTransitionEnd_: function(e) { |
985 if (!this.selected) | 1044 if (!this.selected) |
986 return; | 1045 return; |
987 | 1046 |
988 // We should remove the classes that control transitions when the | 1047 // We should remove the classes that control transitions when the |
989 // transition ends so when the text is resized (Ctrl + '+'), no other | 1048 // transition ends so when the text is resized (Ctrl + '+'), no other |
990 // transition should happen except those defined in the specification. | 1049 // transition should happen except those defined in the specification. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1043 tile.scrollTop; | 1102 tile.scrollTop; |
1044 tile.classList.remove(className); | 1103 tile.classList.remove(className); |
1045 } | 1104 } |
1046 } | 1105 } |
1047 | 1106 |
1048 return { | 1107 return { |
1049 Tile: Tile, | 1108 Tile: Tile, |
1050 TilePage: TilePage, | 1109 TilePage: TilePage, |
1051 }; | 1110 }; |
1052 }); | 1111 }); |
OLD | NEW |