Home | History | Annotate | Download | only in local_ntp
      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