1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5 6/** 7 * @fileoverview Utilities for rendering most visited thumbnails and titles. 8 */ 9 10<include src="instant_iframe_validation.js"> 11 12/** 13 * Enum for the different types of events that are logged from the NTP. 14 * @enum {number} 15 * @const 16 */ 17var NTP_LOGGING_EVENT_TYPE = { 18 // The user moused over an NTP tile or title. 19 NTP_MOUSEOVER: 0, 20 // The page attempted to load a thumbnail image. 21 NTP_THUMBNAIL_ATTEMPT: 1, 22 // There was an error in loading both the thumbnail image and the fallback 23 // (if it was provided), resulting in a grey tile. 24 NTP_THUMBNAIL_ERROR: 2, 25 // The page attempted to load a thumbnail URL while a fallback thumbnail was 26 // provided. 27 NTP_FALLBACK_THUMBNAIL_REQUESTED: 3, 28 // The primary thumbnail image failed to load and caused us to use the 29 // secondary thumbnail as a fallback. 30 NTP_FALLBACK_THUMBNAIL_USED: 4, 31 // The suggestion is coming from the server. 32 NTP_SERVER_SIDE_SUGGESTION: 5, 33 // The suggestion is coming from the client. 34 NTP_CLIENT_SIDE_SUGGESTION: 6, 35 // The visuals of that tile are handled externally by the page itself. 36 NTP_EXTERNAL_TILE: 7 37}; 38 39/** 40 * Type of the impression provider for a generic client-provided suggestion. 41 * @type {string} 42 * @const 43 */ 44var CLIENT_PROVIDER_NAME = 'client'; 45 46/** 47 * Type of the impression provider for a generic server-provided suggestion. 48 * @type {string} 49 * @const 50 */ 51var SERVER_PROVIDER_NAME = 'server'; 52 53/** 54 * Parses query parameters from Location. 55 * @param {string} location The URL to generate the CSS url for. 56 * @return {Object} Dictionary containing name value pairs for URL. 57 */ 58function parseQueryParams(location) { 59 var params = Object.create(null); 60 var query = location.search.substring(1); 61 var vars = query.split('&'); 62 for (var i = 0; i < vars.length; i++) { 63 var pair = vars[i].split('='); 64 var k = decodeURIComponent(pair[0]); 65 if (k in params) { 66 // Duplicate parameters are not allowed to prevent attackers who can 67 // append things to |location| from getting their parameter values to 68 // override legitimate ones. 69 return Object.create(null); 70 } else { 71 params[k] = decodeURIComponent(pair[1]); 72 } 73 } 74 return params; 75} 76 77 78/** 79 * Creates a new most visited link element. 80 * @param {Object} params URL parameters containing styles for the link. 81 * @param {string} href The destination for the link. 82 * @param {string} title The title for the link. 83 * @param {string|undefined} text The text for the link or none. 84 * @param {string|undefined} ping If specified, a location relative to the 85 * referrer of this iframe, to ping when the link is clicked. Only works if 86 * the referrer is HTTPS. 87 * @param {string|undefined} provider A provider name (max 8 alphanumeric 88 * characters) used for logging. Undefined if suggestion is not coming from 89 * the server. 90 * @return {HTMLAnchorElement} A new link element. 91 */ 92function createMostVisitedLink(params, href, title, text, ping, provider) { 93 var styles = getMostVisitedStyles(params, !!text); 94 var link = document.createElement('a'); 95 link.style.color = styles.color; 96 link.style.fontSize = styles.fontSize + 'px'; 97 if (styles.fontFamily) 98 link.style.fontFamily = styles.fontFamily; 99 link.href = href; 100 if ('pos' in params && isFinite(params.pos)) { 101 link.ping = '/log.html?pos=' + params.pos; 102 if (provider) 103 link.ping += '&pr=' + provider; 104 // If a ping parameter was specified, add it to the list of pings, relative 105 // to the referrer of this iframe, which is the default search provider. 106 if (ping) { 107 var parentUrl = document.createElement('a'); 108 parentUrl.href = document.referrer; 109 if (parentUrl.protocol == 'https:') { 110 link.ping += ' ' + parentUrl.origin + '/' + ping; 111 } 112 } 113 } 114 link.title = title; 115 link.target = '_top'; 116 // Exclude links from the tab order. The tabIndex is added to the thumbnail 117 // parent container instead. 118 link.tabIndex = '-1'; 119 if (text) 120 link.textContent = text; 121 link.addEventListener('mouseover', function() { 122 var ntpApiHandle = chrome.embeddedSearch.newTabPage; 123 ntpApiHandle.logEvent(NTP_LOGGING_EVENT_TYPE.NTP_MOUSEOVER); 124 }); 125 return link; 126} 127 128 129/** 130 * Decodes most visited styles from URL parameters. 131 * - f: font-family 132 * - fs: font-size as a number in pixels. 133 * - c: A hexadecimal number interpreted as a hex color code. 134 * @param {Object.<string, string>} params URL parameters specifying style. 135 * @param {boolean} isTitle if the style is for the Most Visited Title. 136 * @return {Object} Styles suitable for CSS interpolation. 137 */ 138function getMostVisitedStyles(params, isTitle) { 139 var styles = { 140 color: '#777', 141 fontFamily: '', 142 fontSize: 11 143 }; 144 var apiHandle = chrome.embeddedSearch.newTabPage; 145 var themeInfo = apiHandle.themeBackgroundInfo; 146 if (isTitle && themeInfo && !themeInfo.usingDefaultTheme) { 147 styles.color = convertArrayToRGBAColor(themeInfo.textColorRgba) || 148 styles.color; 149 } else if ('c' in params) { 150 styles.color = convertToHexColor(parseInt(params.c, 16)) || styles.color; 151 } 152 if ('f' in params && /^[-0-9a-zA-Z ,]+$/.test(params.f)) 153 styles.fontFamily = params.f; 154 if ('fs' in params && isFinite(parseInt(params.fs, 10))) 155 styles.fontSize = parseInt(params.fs, 10); 156 return styles; 157} 158 159 160/** 161 * @param {string} location A location containing URL parameters. 162 * @param {function(Object, Object)} fill A function called with styles and 163 * data to fill. 164 */ 165function fillMostVisited(location, fill) { 166 var params = parseQueryParams(document.location); 167 params.rid = parseInt(params.rid, 10); 168 if (!isFinite(params.rid) && !params.url) 169 return; 170 // Log whether the suggestion was obtained from the server or the client. 171 chrome.embeddedSearch.newTabPage.logEvent(params.url ? 172 NTP_LOGGING_EVENT_TYPE.NTP_SERVER_SIDE_SUGGESTION : 173 NTP_LOGGING_EVENT_TYPE.NTP_CLIENT_SIDE_SUGGESTION); 174 var data = {}; 175 if (params.url) { 176 // Means that the suggestion data comes from the server. Create data object. 177 data.url = params.url; 178 data.thumbnailUrl = params.tu || ''; 179 data.thumbnailUrl2 = params.tu2 || ''; 180 data.title = params.ti || ''; 181 data.direction = params.di || ''; 182 data.domain = params.dom || ''; 183 data.ping = params.ping || ''; 184 data.provider = params.pr || SERVER_PROVIDER_NAME; 185 186 // Log the fact that suggestion was obtained from the server. 187 var ntpApiHandle = chrome.embeddedSearch.newTabPage; 188 ntpApiHandle.logEvent(NTP_LOGGING_EVENT_TYPE.NTP_SERVER_SIDE_SUGGESTION); 189 } else { 190 var apiHandle = chrome.embeddedSearch.searchBox; 191 data = apiHandle.getMostVisitedItemData(params.rid); 192 if (!data) 193 return; 194 data.provider = CLIENT_PROVIDER_NAME; 195 delete data.ping; 196 } 197 if (/^javascript:/i.test(data.url) || 198 /^javascript:/i.test(data.thumbnailUrl) || 199 /^javascript:/i.test(data.thumbnailUrl2) || 200 !/^[a-z0-9]{0,8}$/i.test(data.provider)) 201 return; 202 if (data.direction) 203 document.body.dir = data.direction; 204 fill(params, data); 205} 206