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