Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* Copyright 2015 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 // Single iframe for NTP tiles. | |
| 6 (function() { | |
| 7 'use strict'; | |
| 8 | |
| 9 <include src="../../../../ui/webui/resources/js/util.js"> | |
| 10 | |
| 11 /** | |
| 12 * The different types of events that are logged from the NTP. This enum is | |
| 13 * used to transfer information from the NTP javascript to the renderer and is | |
|
Mathieu
2015/03/12 15:53:26
nit: JavaScript
fserb
2015/03/12 16:05:34
OMG
| |
| 14 * not used as a UMA enum histogram's logged value. | |
| 15 * Note: Keep in sync with common/ntp_logging_events.h | |
| 16 * @enum {number} | |
| 17 * @const | |
| 18 */ | |
| 19 var LOGTYPE = { | |
|
huangs
2015/03/12 06:16:56
NIT: LOG_TYPE?
fserb
2015/03/12 16:05:33
Done.
| |
| 20 // The suggestion is coming from the server. | |
| 21 NTP_SERVER_SIDE_SUGGESTION: 0, | |
|
huangs
2015/03/12 06:16:56
The following are unused:
NTP_SERVER_SIDE_SUGGES
fserb
2015/03/12 16:05:33
Done.
| |
| 22 // The suggestion is coming from the client. | |
| 23 NTP_CLIENT_SIDE_SUGGESTION: 1, | |
| 24 // Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile | |
| 25 // or an external tile. | |
| 26 NTP_TILE: 2, | |
| 27 // The tile uses a local thumbnail image. | |
| 28 NTP_THUMBNAIL_TILE: 3, | |
| 29 // Used when no thumbnail is specified and a gray tile with the domain is used | |
| 30 // as the main tile. | |
| 31 NTP_GRAY_TILE: 4, | |
| 32 // The visuals of that tile are handled externally by the page itself. | |
| 33 NTP_EXTERNAL_TILE: 5, | |
| 34 // There was an error in loading both the thumbnail image and the fallback | |
| 35 // (if it was provided), resulting in a grey tile. | |
|
huangs
2015/03/12 06:16:56
NIT: grey
fserb
2015/03/12 16:05:34
Done.
| |
| 36 NTP_THUMBNAIL_ERROR: 6, | |
| 37 // Used a gray tile with the domain as the fallback for a failed thumbnail. | |
| 38 NTP_GRAY_TILE_FALLBACK: 7, | |
| 39 // The visuals of that tile's fallback are handled externally. | |
| 40 NTP_EXTERNAL_TILE_FALLBACK: 8, | |
| 41 // The user moused over an NTP tile or title. | |
| 42 NTP_MOUSEOVER: 9 | |
| 43 }; | |
| 44 | |
| 45 /** | |
| 46 * The origin of this request. | |
| 47 * @const {string} | |
| 48 */ | |
| 49 var DOMAIN_ORIGIN = '{{ORIGIN}}'; | |
| 50 | |
| 51 /** | |
| 52 * Counter for DOM elements that we are waiting to finish loading. | |
| 53 * @type {number} | |
| 54 */ | |
| 55 var loadedCounter = 1; | |
| 56 | |
| 57 /** | |
| 58 * DOM element containing the tiles we are going to present next. | |
| 59 * Works as a double-buffer that is shown when we receive a "show" postMessage. | |
| 60 * @type {DOM} | |
|
huangs
2015/03/12 06:16:56
Note that {DOMNode} appears below, which is incons
fserb
2015/03/12 16:05:34
Done.
| |
| 61 */ | |
| 62 var tiles = null; | |
| 63 | |
| 64 /** | |
| 65 * Log an event on the NTP | |
|
huangs
2015/03/12 06:16:56
NIT: "." at end.
fserb
2015/03/12 16:05:33
Done.
| |
| 66 * @param {number} eventName Event from NTP_LOGGING_EVENT_TYPE. | |
|
huangs
2015/03/12 06:16:56
NIT: |eventType| instead of |eventName|?
Also NTP
fserb
2015/03/12 16:05:33
Done.
| |
| 67 */ | |
| 68 var logEvent = function(eventName) { | |
| 69 chrome.embeddedSearch.newTabPage.logEvent(eventName); | |
| 70 }; | |
| 71 | |
|
Mathieu
2015/03/12 15:53:26
nit: either choose 2 lines between functions or 1
fserb
2015/03/12 16:05:34
I
decided
on
two
lines.
| |
| 72 | |
| 73 /** | |
| 74 * Down count the DOM elements that we are waiting for the page to load. | |
| 75 * When we get to 0, we send a message to the parent window. | |
| 76 * This is usually used as an EventListener of onload/onerror. | |
| 77 */ | |
| 78 var countLoad = function() { | |
| 79 loadedCounter--; | |
| 80 if (loadedCounter <= 0) { | |
| 81 window.parent.postMessage({cmd: 'loaded' }, DOMAIN_ORIGIN); | |
|
huangs
2015/03/12 06:16:56
NIT: extra space before "}"?
fserb
2015/03/12 16:05:33
Done.
| |
| 82 loadedCounter = 1; | |
| 83 } | |
| 84 }; | |
| 85 | |
| 86 | |
| 87 /** | |
| 88 * Handle postMessages coming from the host page to the iframe. | |
| 89 * We try to keep the logic here to a minimum and just dispatch to the relevant | |
| 90 * functions. | |
| 91 **/ | |
| 92 var handlePostMessage = function(event) { | |
| 93 var cmd = event.data.cmd; | |
| 94 var args = event.data; | |
|
huangs
2015/03/12 06:16:56
|args| is used only once, and in the "else" case y
fserb
2015/03/12 16:05:33
Done.
| |
| 95 | |
| 96 if (cmd == 'tile') { | |
| 97 addTile(args); | |
| 98 } else if (cmd == 'show') { | |
| 99 showTiles(); | |
| 100 countLoad(); | |
| 101 } else { | |
| 102 console.error('Unknown command: ' + event.data); | |
| 103 } | |
| 104 }; | |
| 105 | |
| 106 /** | |
| 107 * Called when the host page has finished sending us tile information and | |
| 108 * we are ready to show the new tiles and drop the old ones. | |
| 109 */ | |
| 110 var showTiles = function() { | |
| 111 // store the tiles on the current closure. | |
|
huangs
2015/03/12 06:16:56
Nit: Capitalize "Store".
fserb
2015/03/12 16:05:34
Done.
| |
| 112 var cur = tiles; | |
| 113 | |
| 114 // Create empty tiles until we have 8. | |
| 115 while (cur.childNodes.length < 8) { | |
|
huangs
2015/03/12 06:16:56
Magic number 8.
fserb
2015/03/12 16:05:34
Done.
| |
| 116 addTile({}); | |
| 117 } | |
| 118 | |
| 119 var parent = $('most-visited'); | |
|
huangs
2015/03/12 06:16:56
Why not
document.querySelector('#most-visited')?
fserb
2015/03/12 16:05:34
Done.
| |
| 120 | |
| 121 // Mark old tile DIV for removal after the transition animation is done. | |
| 122 var old = parent.querySelector('#mv-tiles'); | |
| 123 if (old) { | |
| 124 old.id = 'mv-tiles-old'; | |
| 125 cur.addEventListener('webkitTransitionEnd', function(ev) { | |
| 126 if (ev.target === cur) { | |
| 127 parent.removeChild(old); | |
| 128 } | |
| 129 }); | |
| 130 } | |
| 131 | |
| 132 // Add new tileset. | |
| 133 cur.id = 'mv-tiles'; | |
| 134 parent.appendChild(cur); | |
| 135 // We want the CSS transition to trigger, so need to add to the DOM before | |
| 136 // setting the style. | |
| 137 setTimeout(function() { | |
| 138 cur.style.opacity = 1.0; | |
| 139 }, 0); | |
| 140 | |
| 141 // Make sure the tiles variable contain the next tileset we may use. | |
| 142 tiles = document.createElement('div'); | |
| 143 }; | |
| 144 | |
| 145 | |
| 146 /** | |
| 147 * Called when the host page wants to add a suggestion tile. | |
| 148 * For Most Visited, it grabs the data from Chrome and pass on. | |
| 149 * For host page generated it just passes the data. | |
| 150 * @param {object} args Data for the tile to be rendered. | |
| 151 */ | |
| 152 var addTile = function(args) { | |
| 153 if (args.rid) { | |
| 154 var data = chrome.embeddedSearch.searchBox.getMostVisitedItemData(args.rid); | |
| 155 tiles.appendChild(renderTile(data)); | |
| 156 logEvent(LOGTYPE.NTP_CLIENT_SIDE_SUGGESTION); | |
| 157 } else { | |
| 158 tiles.appendChild(renderTile(null)); | |
| 159 } | |
| 160 }; | |
| 161 | |
| 162 | |
| 163 /** | |
| 164 * Called when the user decided to add a tile to the blacklist. | |
| 165 * It sets of the animation for the blacklist and sends the blacklisted id | |
| 166 * to the host page. | |
| 167 * @param {DOMNode} tile DOM node of the tile we want to remove. | |
| 168 */ | |
| 169 var blacklistTile = function(tile) { | |
| 170 tile.classList.add('blacklisted'); | |
| 171 var sent = false; | |
| 172 tile.addEventListener('webkitTransitionEnd', function() { | |
| 173 if (sent) return; | |
| 174 sent = true; | |
| 175 window.parent.postMessage({cmd: 'tileBlacklisted', | |
| 176 rid: Number(tile.getAttribute('rid'))}, | |
|
huangs
2015/03/12 06:16:56
HTML custom attributes should have '-', so 'data-r
fserb
2015/03/12 16:05:34
Done.
| |
| 177 DOMAIN_ORIGIN); | |
| 178 }); | |
| 179 }; | |
| 180 | |
| 181 | |
| 182 /** | |
| 183 * Renders a MostVisited tile to the DOM. | |
| 184 * @param {object} data Object containing rid, url, title, favicon, thumbnail. | |
| 185 * data is null if you want to construct an empty tile. | |
| 186 */ | |
| 187 var renderTile = function(data) { | |
| 188 var tile = document.createElement('a'); | |
| 189 tile.className = 'mv-tile'; | |
| 190 | |
| 191 if (data == null) { | |
| 192 tile.className = 'mv-empty-tile'; | |
| 193 return tile; | |
| 194 } | |
| 195 | |
| 196 logEvent(LOGTYPE.NTP_TILE); | |
| 197 | |
| 198 tile.setAttribute('rid', data.rid); | |
|
huangs
2015/03/12 06:16:56
HTML custom attributes should have '-', so 'data-r
fserb
2015/03/12 16:05:34
Done.
| |
| 199 tile.innerHTML = '<div class="mv-favicon"></div>' + | |
| 200 '<div class="mv-title"></div><div class="mv-thumb"></div>' + | |
| 201 '<div title="Don\'t show on this page" class="mv-x"></div>'; | |
| 202 | |
| 203 tile.href = data.url; | |
| 204 tile.title = data.title; | |
| 205 tile.onkeypress = function(ev) { | |
|
huangs
2015/03/12 06:16:56
Use
tile.addEventListener('keypress', function() {
fserb
2015/03/12 16:05:33
Done.
| |
| 206 if (ev.keyCode == 127) { // DELETE | |
| 207 blacklistTile(tile); | |
| 208 ev.stopPropagation(); | |
| 209 return false; | |
| 210 } | |
| 211 }; | |
| 212 tile.addEventListener('mouseover', function() { | |
| 213 logEvent(LOGTYPE.NTP_MOUSEOVER); | |
|
huangs
2015/03/12 06:16:56
I'm a bit concerned with using mouseover; could yo
fserb
2015/03/12 16:05:33
Acknowledged.
| |
| 214 }); | |
| 215 | |
| 216 var title = tile.querySelectorAll('.mv-title')[0]; | |
|
huangs
2015/03/12 06:16:55
title.querySelector('.mv-title') is cleaner (takes
fserb
2015/03/12 16:05:34
Done.
| |
| 217 title.innerHTML = data.title; | |
|
huangs
2015/03/12 06:16:55
Is data.title already escape entities? Otherwise
fserb
2015/03/12 16:05:34
Done.
| |
| 218 title.style.direction = data.direction || 'ltr'; | |
| 219 | |
| 220 var thumb = tile.querySelectorAll('.mv-thumb')[0]; | |
| 221 | |
| 222 var img = document.createElement('img'); | |
|
huangs
2015/03/12 06:16:55
Move these 2 lines inside "if" since it's unused o
fserb
2015/03/12 16:05:33
Done.
| |
| 223 img.title = data.title; | |
| 224 if (data.thumbnailUrl) { | |
| 225 img.src = data.thumbnailUrl; | |
| 226 loadedCounter += 1; | |
|
huangs
2015/03/12 06:16:55
Nit: Inconsistent with "loadedCounter--" you used
fserb
2015/03/12 16:05:34
Done.
| |
| 227 img.addEventListener('load', countLoad); | |
| 228 img.addEventListener('error', countLoad); | |
| 229 img.addEventListener('error', function(ev) { | |
| 230 thumb.classList.add('failed-img'); | |
| 231 thumb.removeChild(img); | |
| 232 logEvent(LOGTYPE.NTP_THUMBNAIL_ERROR); | |
| 233 }); | |
| 234 thumb.appendChild(img); | |
| 235 logEvent(LOGTYPE.NTP_THUMBNAIL_TILE); | |
| 236 } else { | |
| 237 thumb.classList.add('failed-img'); | |
| 238 } | |
| 239 | |
| 240 var favicon = tile.querySelectorAll('.mv-favicon')[0]; | |
| 241 if (data.faviconUrl) { | |
| 242 var fi = document.createElement('img'); | |
| 243 fi.src = '../' + data.faviconUrl; | |
| 244 fi.title = ''; | |
|
huangs
2015/03/12 06:16:56
Wouldn't |ti.title| be empty already? Please comm
fserb
2015/03/12 16:05:33
Done.
Mathieu
2015/03/12 17:39:18
I don't see the results of this comment.
| |
| 245 loadedCounter += 1; | |
| 246 fi.addEventListener('load', countLoad); | |
| 247 fi.addEventListener('error', countLoad); | |
| 248 fi.addEventListener('error', function(ev) { | |
| 249 favicon.classList.add('failed-favicon'); | |
| 250 }); | |
| 251 favicon.appendChild(fi); | |
| 252 } else { | |
| 253 favicon.classList.add('failed-favicon'); | |
| 254 } | |
| 255 | |
| 256 var mvx = tile.querySelectorAll('.mv-x')[0]; | |
| 257 mvx.onclick = function(ev) { | |
|
huangs
2015/03/12 06:16:55
mvx.addEventListener('click', ...) ?
fserb
2015/03/12 16:05:34
Done.
| |
| 258 blacklistTile(tile); | |
| 259 ev.stopPropagation(); | |
| 260 return false; | |
| 261 }; | |
| 262 | |
| 263 return tile; | |
| 264 }; | |
| 265 | |
| 266 | |
| 267 /** | |
| 268 * Do some initialization and parses the query arguments passed to the iframe. | |
| 269 */ | |
| 270 var init = function() { | |
| 271 // Creates a new DOM element to hold the tiles. | |
| 272 tiles = document.createElement('div'); | |
| 273 | |
| 274 // Parse query arguments. | |
|
Mathieu
2015/03/12 15:53:26
are we only doing this for RTL? consider early bre
fserb
2015/03/12 16:05:34
We are only using it for RTL for now, but I expect
Mathieu
2015/03/12 17:39:18
Then consider moving to a private function, it cle
| |
| 275 var query = window.location.search.substring(1).split('&'); | |
| 276 var args = {}; | |
| 277 for (var i = 0; i < query.length; ++i) { | |
| 278 var val = query[i].split('='); | |
| 279 if (val[0] == '') continue; | |
| 280 args[decodeURIComponent(val[0])] = decodeURIComponent(val[1]); | |
| 281 } | |
| 282 | |
| 283 // Enable RTL. | |
| 284 if (args['rtl'] == '1') { | |
| 285 var html = document.querySelector('html'); | |
| 286 html.dir = 'rtl'; | |
| 287 } | |
| 288 | |
| 289 window.addEventListener('message', handlePostMessage); | |
| 290 }; | |
| 291 | |
| 292 window.addEventListener('DOMContentLoaded', init); | |
| 293 })(); | |
| OLD | NEW |