// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. cr.define('ntp4', function() { 'use strict'; /** * Gives the proportion of the row width that is devoted to a single icon. * @param {number} rowTileCount The number of tiles in a row. * @return {number} The ratio between icon width and row width. */ function tileWidthFraction(rowTileCount) { return rowTileCount + (rowTileCount - 1) * TILE_SPACING_FRACTION; } /** * Calculates an assortment of tile-related values for a grid with the * given dimensions. * @param {number} width The pixel width of the grid. * @param {number} numRowTiles The number of tiles in a row. * @return {Object} A mapping of pixel values. */ function tileValuesForGrid(width, numRowTiles) { var tileWidth = width / tileWidthFraction(numRowTiles); var offsetX = tileWidth * (1 + TILE_SPACING_FRACTION); var interTileSpacing = offsetX - tileWidth; return { tileWidth: tileWidth, offsetX: offsetX, interTileSpacing: interTileSpacing, }; } // The proportion of the tile width which will be used as spacing between // tiles. var TILE_SPACING_FRACTION = 1 / 8; // The smallest amount of horizontal blank space to display on the sides when // displaying a wide arrangement. var MIN_WIDE_MARGIN = 100; /** * Creates a new TilePage object. This object contains tiles and controls * their layout. * @param {string} name The display name for the page. * @param {Object} gridValues Pixel values that define the size and layout * of the tile grid. * @constructor * @extends {HTMLDivElement} */ function TilePage(name, gridValues) { var el = cr.doc.createElement('div'); el.pageName = name; el.gridValues_ = gridValues; el.__proto__ = TilePage.prototype; el.initialize(); return el; } /** * Takes a collection of grid layout pixel values and updates them with * additional tiling values that are calculated from TilePage constants. * @param {Object} grid The grid layout pixel values to update. */ TilePage.initGridValues = function(grid) { // The amount of space we need to display a narrow grid (all narrow grids // are this size). grid.narrowWidth = grid.minTileWidth * tileWidthFraction(grid.minColCount); // The minimum amount of space we need to display a wide grid. grid.minWideWidth = grid.minTileWidth * tileWidthFraction(grid.maxColCount); // The largest we will ever display a wide grid. grid.maxWideWidth = grid.maxTileWidth * tileWidthFraction(grid.maxColCount); // Tile-related pixel values for the narrow display. grid.narrowTileValues = tileValuesForGrid(grid.narrowWidth, grid.minColCount); // Tile-related pixel values for the minimum narrow display. grid.wideTileValues = tileValuesForGrid(grid.minWideWidth, grid.maxColCount); }, TilePage.prototype = { __proto__: HTMLDivElement.prototype, initialize: function() { this.className = 'tile-page'; var title = this.ownerDocument.createElement('span'); title.textContent = this.pageName; title.className = 'tile-page-title'; this.appendChild(title); // Div that holds the tiles. this.tileGrid_ = this.ownerDocument.createElement('div'); this.tileGrid_.className = 'tile-grid'; this.appendChild(this.tileGrid_); // Ordered list of our tiles. this.tileElements_ = this.tileGrid_.getElementsByClassName('tile'); this.lastWidth_ = this.clientWidth; this.eventTracker = new EventTracker(); this.eventTracker.add(window, 'resize', this.onResize_.bind(this)); }, /** * Cleans up resources that are no longer needed after this TilePage * instance is removed from the DOM. */ tearDown: function() { this.eventTracker.removeAll(); }, /** * @protected */ appendTile: function(tileElement) { var wrapperDiv = tileElement.ownerDocument.createElement('div'); wrapperDiv.appendChild(tileElement); wrapperDiv.className = 'tile'; this.tileGrid_.appendChild(wrapperDiv); this.positionTile_(this.tileElements_.length - 1); this.classList.remove('resizing-tile-page'); }, /** * Calculates the x/y coordinates for an element and moves it there. * @param {number} The index of the element to be positioned. * @private */ positionTile_: function(index) { var grid = this.gridValues_; var availableSpace = this.tileGrid_.clientWidth - 2 * MIN_WIDE_MARGIN; var wide = availableSpace >= grid.minWideWidth; // Calculate the portion of the tile's position that should be animated. var animatedTileValues = wide ? grid.wideTileValues : grid.narrowTileValues; // Animate the difference between three-wide and six-wide. var animatedLeftMargin = wide ? 0 : (grid.minWideWidth - MIN_WIDE_MARGIN - grid.narrowWidth) / 2; var numRowTiles = wide ? grid.maxColCount : grid.minColCount; var col = index % numRowTiles; var row = Math.floor(index / numRowTiles); var animatedX = col * animatedTileValues.offsetX + animatedLeftMargin; var animatedY = row * (this.heightForWidth(animatedTileValues.tileWidth) + animatedTileValues.interTileSpacing); // Calculate the final on-screen position for the tile. var effectiveGridWidth = wide ? Math.min(Math.max(availableSpace, grid.minWideWidth), grid.maxWideWidth) : grid.narrowWidth; var realTileValues = tileValuesForGrid(effectiveGridWidth, numRowTiles); // leftMargin centers the grid within the avaiable space. var minMargin = wide ? MIN_WIDE_MARGIN : 0; var leftMargin = Math.max(minMargin, (this.tileGrid_.clientWidth - effectiveGridWidth) / 2); var realX = col * realTileValues.offsetX + leftMargin; var realY = row * (this.heightForWidth(realTileValues.tileWidth) + realTileValues.interTileSpacing); var tileWrapper = this.tileElements_[index]; tileWrapper.style.left = animatedX + 'px'; tileWrapper.style.top = animatedY + 'px'; tileWrapper.firstChild.setBounds(realTileValues.tileWidth, realX - animatedX, realY - animatedY); }, /** * Window resize event handler. Window resizes may trigger re-layouts. * @param {Object} e The resize event. */ onResize_: function(e) { // Do nothing if the width didn't change. if (this.lastWidth_ == this.clientWidth) return; this.lastWidth_ = this.clientWidth; this.classList.add('resizing-tile-page'); for (var i = 0; i < this.tileElements_.length; i++) { this.positionTile_(i); } }, /** * Get the height for a tile of a certain width. Override this function to * get non-square tiles. * @param {number} width The pixel width of a tile. * @return {number} The height for |width|. */ heightForWidth: function(width) { return width; }, }; return { TilePage: TilePage, }; });