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 <include src="window_disposition_util.js"> 12 13 14 /** 15 * The different types of events that are logged from the NTP. This enum is 16 * used to transfer information from the NTP javascript to the renderer and is 17 * not used as a UMA enum histogram's logged value. 18 * Note: Keep in sync with common/ntp_logging_events.h 19 * @enum {number} 20 * @const 21 */ 22 var NTP_LOGGING_EVENT_TYPE = { 23 // The suggestion is coming from the server. 24 NTP_SERVER_SIDE_SUGGESTION: 0, 25 // The suggestion is coming from the client. 26 NTP_CLIENT_SIDE_SUGGESTION: 1, 27 // Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile 28 // or an external tile. 29 NTP_TILE: 2, 30 // The tile uses a local thumbnail image. 31 NTP_THUMBNAIL_TILE: 3, 32 // Used when no thumbnail is specified and a gray tile with the domain is used 33 // as the main tile. 34 NTP_GRAY_TILE: 4, 35 // The visuals of that tile are handled externally by the page itself. 36 NTP_EXTERNAL_TILE: 5, 37 // There was an error in loading both the thumbnail image and the fallback 38 // (if it was provided), resulting in a grey tile. 39 NTP_THUMBNAIL_ERROR: 6, 40 // Used a gray tile with the domain as the fallback for a failed thumbnail. 41 NTP_GRAY_TILE_FALLBACK: 7, 42 // The visuals of that tile's fallback are handled externally. 43 NTP_EXTERNAL_TILE_FALLBACK: 8, 44 // The user moused over an NTP tile or title. 45 NTP_MOUSEOVER: 9 46 }; 47 48 49 /** 50 * Type of the impression provider for a generic client-provided suggestion. 51 * @type {string} 52 * @const 53 */ 54 var CLIENT_PROVIDER_NAME = 'client'; 55 56 /** 57 * Type of the impression provider for a generic server-provided suggestion. 58 * @type {string} 59 * @const 60 */ 61 var SERVER_PROVIDER_NAME = 'server'; 62 63 /** 64 * Parses query parameters from Location. 65 * @param {string} location The URL to generate the CSS url for. 66 * @return {Object} Dictionary containing name value pairs for URL. 67 */ 68 function parseQueryParams(location) { 69 var params = Object.create(null); 70 var query = location.search.substring(1); 71 var vars = query.split('&'); 72 for (var i = 0; i < vars.length; i++) { 73 var pair = vars[i].split('='); 74 var k = decodeURIComponent(pair[0]); 75 if (k in params) { 76 // Duplicate parameters are not allowed to prevent attackers who can 77 // append things to |location| from getting their parameter values to 78 // override legitimate ones. 79 return Object.create(null); 80 } else { 81 params[k] = decodeURIComponent(pair[1]); 82 } 83 } 84 return params; 85 } 86 87 88 /** 89 * Creates a new most visited link element. 90 * @param {Object} params URL parameters containing styles for the link. 91 * @param {string} href The destination for the link. 92 * @param {string} title The title for the link. 93 * @param {string|undefined} text The text for the link or none. 94 * @param {string|undefined} provider A provider name (max 8 alphanumeric 95 * characters) used for logging. Undefined if suggestion is not coming from 96 * the server. 97 * @return {HTMLAnchorElement} A new link element. 98 */ 99 function createMostVisitedLink(params, href, title, text, provider) { 100 var styles = getMostVisitedStyles(params, !!text); 101 var link = document.createElement('a'); 102 link.style.color = styles.color; 103 link.style.fontSize = styles.fontSize + 'px'; 104 if (styles.fontFamily) 105 link.style.fontFamily = styles.fontFamily; 106 107 link.href = href; 108 link.title = title; 109 link.target = '_top'; 110 // Exclude links from the tab order. The tabIndex is added to the thumbnail 111 // parent container instead. 112 link.tabIndex = '-1'; 113 if (text) 114 link.textContent = text; 115 link.addEventListener('mouseover', function() { 116 var ntpApiHandle = chrome.embeddedSearch.newTabPage; 117 ntpApiHandle.logEvent(NTP_LOGGING_EVENT_TYPE.NTP_MOUSEOVER); 118 }); 119 120 // Webkit's security policy prevents some Most Visited thumbnails from 121 // working (those with schemes different from http and https). Therefore, 122 // navigateContentWindow is being used in order to get all schemes working. 123 link.addEventListener('click', function handleNavigation(e) { 124 var ntpApiHandle = chrome.embeddedSearch.newTabPage; 125 if ('pos' in params && isFinite(params.pos)) { 126 ntpApiHandle.logMostVisitedNavigation(parseInt(params.pos, 10), 127 provider || ''); 128 } 129 var isServerSuggestion = 'url' in params; 130 if (!isServerSuggestion) { 131 e.preventDefault(); 132 ntpApiHandle.navigateContentWindow(href, getDispositionFromEvent(e)); 133 } 134 // Else follow <a> normally, so transition type would be LINK. 135 }); 136 137 return link; 138 } 139 140 141 /** 142 * Decodes most visited styles from URL parameters. 143 * - f: font-family 144 * - fs: font-size as a number in pixels. 145 * - c: A hexadecimal number interpreted as a hex color code. 146 * @param {Object.<string, string>} params URL parameters specifying style. 147 * @param {boolean} isTitle if the style is for the Most Visited Title. 148 * @return {Object} Styles suitable for CSS interpolation. 149 */ 150 function getMostVisitedStyles(params, isTitle) { 151 var styles = { 152 color: '#777', 153 fontFamily: '', 154 fontSize: 11 155 }; 156 var apiHandle = chrome.embeddedSearch.newTabPage; 157 var themeInfo = apiHandle.themeBackgroundInfo; 158 if (isTitle && themeInfo && !themeInfo.usingDefaultTheme) { 159 styles.color = convertArrayToRGBAColor(themeInfo.textColorRgba) || 160 styles.color; 161 } else if ('c' in params) { 162 styles.color = convertToHexColor(parseInt(params.c, 16)) || styles.color; 163 } 164 if ('f' in params && /^[-0-9a-zA-Z ,]+$/.test(params.f)) 165 styles.fontFamily = params.f; 166 if ('fs' in params && isFinite(parseInt(params.fs, 10))) 167 styles.fontSize = parseInt(params.fs, 10); 168 return styles; 169 } 170 171 172 /** 173 * @param {string} location A location containing URL parameters. 174 * @param {function(Object, Object)} fill A function called with styles and 175 * data to fill. 176 */ 177 function fillMostVisited(location, fill) { 178 var params = parseQueryParams(document.location); 179 params.rid = parseInt(params.rid, 10); 180 if (!isFinite(params.rid) && !params.url) 181 return; 182 // Log whether the suggestion was obtained from the server or the client. 183 chrome.embeddedSearch.newTabPage.logEvent(params.url ? 184 NTP_LOGGING_EVENT_TYPE.NTP_SERVER_SIDE_SUGGESTION : 185 NTP_LOGGING_EVENT_TYPE.NTP_CLIENT_SIDE_SUGGESTION); 186 var data = {}; 187 if (params.url) { 188 // Means that the suggestion data comes from the server. Create data object. 189 data.url = params.url; 190 data.thumbnailUrl = params.tu || ''; 191 data.title = params.ti || ''; 192 data.direction = params.di || ''; 193 data.domain = params.dom || ''; 194 data.provider = params.pr || SERVER_PROVIDER_NAME; 195 196 // Log the fact that suggestion was obtained from the server. 197 var ntpApiHandle = chrome.embeddedSearch.newTabPage; 198 ntpApiHandle.logEvent(NTP_LOGGING_EVENT_TYPE.NTP_SERVER_SIDE_SUGGESTION); 199 } else { 200 var apiHandle = chrome.embeddedSearch.searchBox; 201 data = apiHandle.getMostVisitedItemData(params.rid); 202 if (!data) 203 return; 204 // Allow server-side provider override. 205 data.provider = params.pr || CLIENT_PROVIDER_NAME; 206 } 207 if (/^javascript:/i.test(data.url) || 208 /^javascript:/i.test(data.thumbnailUrl) || 209 !/^[a-z0-9]{0,8}$/i.test(data.provider)) 210 return; 211 if (data.direction) 212 document.body.dir = data.direction; 213 fill(params, data); 214 } 215