// 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'; var TilePage = ntp4.TilePage; /** * Creates a new Most Visited object for tiling. * @constructor * @extends {HTMLAnchorElement} */ function MostVisited() { var el = cr.doc.createElement('a'); el.__proto__ = MostVisited.prototype; el.initialize(); return el; } MostVisited.prototype = { __proto__: HTMLAnchorElement.prototype, initialize: function() { this.reset(); this.addEventListener('click', this.handleClick_.bind(this)); this.addEventListener('keydown', this.handleKeyDown_.bind(this)); }, /** * Clears the DOM hierarchy for this node, setting it back to the default * for a blank thumbnail. */ reset: function() { this.className = 'most-visited filler'; // TODO(estade): why do we need edit-mode-border? this.innerHTML = '<div class="edit-mode-border fills-parent">' + '<div class="edit-bar-wrapper">' + '<div class="edit-bar">' + '<div class="pin"></div>' + '<div class="spacer"></div>' + '<div class="remove"></div>' + '</div>' + '</div>' + '<span class="thumbnail-wrapper fills-parent">' + '<span class="thumbnail fills-parent">' + // thumbnail-shield provides a gradient fade effect. '<div class="thumbnail-shield fills-parent"></div>' + '</span>' + '<span class="title"></span>' + '</span>' + '</div>'; this.tabIndex = -1; }, /** * Update the appearance of this tile according to |data|. * @param {Object} data A dictionary of relevant data for the page. */ updateForData: function(data) { if (data.filler) { this.reset(); return; } this.data_ = data; this.tabIndex = 0; this.classList.remove('filler'); var title = this.querySelector('.title'); title.textContent = data.title; var faviconUrl = data.faviconUrl || 'chrome://favicon/' + data.url; title.style.backgroundImage = url(faviconUrl); title.dir = data.direction; var thumbnailUrl = data.thumbnailUrl || 'chrome://thumb/' + data.url; this.querySelector('.thumbnail').style.backgroundImage = url(thumbnailUrl); this.href = data.url; this.updatePinnedState_(); }, /** * Handles a click on the tile. * @param {Event} e The click event. */ handleClick_: function(e) { var target = e.target; if (target.classList.contains('pin')) { this.togglePinned_(); e.preventDefault(); } else if (target.classList.contains('remove')) { this.blacklist_(); e.preventDefault(); } else { var index = Array.prototype.indexOf.call(this.parentNode.children, this); if (index != -1) chrome.send('metrics', ['NTP_MostVisited' + index]); } }, /** * Allow blacklisting most visited site using the keyboard. */ handleKeyDown_: function(e) { if (!IS_MAC && e.keyCode == 46 || // Del IS_MAC && e.metaKey && e.keyCode == 8) { // Cmd + Backspace this.blacklist_(); } }, /** * Changes the visual state of the page and updates the model. */ togglePinned_: function() { var data = this.data_; data.pinned = !data.pinned; if (data.pinned) { chrome.send('addPinnedURL', [ data.url, data.title, data.faviconUrl || '', data.thumbnailUrl || '', // TODO(estade): should not need to convert index to string. String(data.index) ]); } else { chrome.send('removePinnedURL', [data.url]); } this.updatePinnedState_(); }, /** * Updates the DOM for the current pinned state. */ updatePinnedState_: function() { if (this.data_.pinned) { this.classList.add('pinned'); this.querySelector('.pin').title = templateData.unpinthumbnailtooltip; } else { this.classList.remove('pinned'); this.querySelector('.pin').title = templateData.pinthumbnailtooltip; } }, /** * Permanently removes a page from Most Visited. */ blacklist_: function() { chrome.send('blacklistURLFromMostVisited', [url]); this.reset(); // TODO(estade): request a replacement site. }, /** * Set the size and position of the most visited tile. * @param {number} size The total size of |this|. * @param {number} x The x-position. * @param {number} y The y-position. * animate. */ setBounds: function(size, x, y) { this.style.width = size + 'px'; this.style.height = heightForWidth(size) + 'px'; this.style.left = x + 'px'; this.style.top = y + 'px'; }, }; var mostVisitedPageGridValues = { // The fewest tiles we will show in a row. minColCount: 2, // The most tiles we will show in a row. maxColCount: 4, // TODO(estade): Change these to real values. // The smallest a tile can be. minTileWidth: 200, // The biggest a tile can be. maxTileWidth: 240, }; TilePage.initGridValues(mostVisitedPageGridValues); /** * Calculates the height for a Most Visited tile for a given width. The size * is based on the thumbnail, which should have a 212:132 ratio (the rest of * the arithmetic accounts for padding). * @return {number} The height. */ function heightForWidth(width) { return (width - 6) * 132 / 212 + 29; } var THUMBNAIL_COUNT = 8; /** * Creates a new MostVisitedPage object. * @param {string} name The display name for the page. * @constructor * @extends {TilePage} */ function MostVisitedPage(name) { var el = new TilePage(name, mostVisitedPageGridValues); el.__proto__ = MostVisitedPage.prototype; el.initialize(); return el; } MostVisitedPage.prototype = { __proto__: TilePage.prototype, initialize: function() { this.classList.add('most-visited-page'); this.data_ = null; this.mostVisitedTiles_ = this.getElementsByClassName('most-visited'); }, /** * Create blank (filler) tiles. * @private */ createTiles_: function() { for (var i = 0; i < THUMBNAIL_COUNT; i++) { this.appendTile(new MostVisited()); } }, /** * Update the tiles after a change to |data_|. */ updateTiles_: function() { for (var i = 0; i < THUMBNAIL_COUNT; i++) { var page = this.data_[i]; page.index = i; var tile = this.mostVisitedTiles_[i]; if (i >= this.data_.length) tile.reset(); else tile.updateForData(page); } }, /** * Array of most visited data objects. * @type {Array} */ get data() { return this.data_; }, set data(data) { // The first time data is set, create the tiles. if (!this.data_) this.createTiles_(); // We append the class name with the "filler" so that we can style fillers // differently. this.data_ = data.slice(0, THUMBNAIL_COUNT); this.updateTiles_(); }, /** @inheritDoc */ heightForWidth: heightForWidth, }; return { MostVisitedPage: MostVisitedPage, }; });