Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/browser/resources/local_ntp/most_visited_single.js

Issue 997203003: Adds a new NTP endpoint for the single frame of the fast NTP (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
10 /**
11 * The different types of events that are logged from the NTP. This enum is
12 * used to transfer information from the NTP JavaScript to the renderer and is
13 * not used as a UMA enum histogram's logged value.
14 * Note: Keep in sync with common/ntp_logging_events.h
15 * @enum {number}
16 * @const
17 */
18 var LOG_TYPE = {
19 // The suggestion is coming from the server. Unused here.
20 NTP_SERVER_SIDE_SUGGESTION: 0,
21 // The suggestion is coming from the client.
22 NTP_CLIENT_SIDE_SUGGESTION: 1,
23 // Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile
24 // or an external tile.
25 NTP_TILE: 2,
26 // The tile uses a local thumbnail image.
27 NTP_THUMBNAIL_TILE: 3,
28 // Used when no thumbnail is specified and a gray tile with the domain is used
29 // as the main tile. Unused here.
30 NTP_GRAY_TILE: 4,
31 // The visuals of that tile are handled externally by the page itself.
32 // Unused here.
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 gray tile.
36 NTP_THUMBNAIL_ERROR: 6,
37 // Used a gray tile with the domain as the fallback for a failed thumbnail.
38 // Unused here.
39 NTP_GRAY_TILE_FALLBACK: 7,
40 // The visuals of that tile's fallback are handled externally. Unused here.
41 NTP_EXTERNAL_TILE_FALLBACK: 8,
42 // The user moused over an NTP tile or title.
huangs 2015/03/13 03:49:52 Can remove "or title".
fserb 2015/03/13 17:22:44 Done.
43 NTP_MOUSEOVER: 9
44 };
45
46
47 /**
48 * Total number of tiles to show at any time. If the host page doesn't send
49 * enough tiles, we fill them blank.
50 * @const {number}
51 */
52 var NUMBER_OF_TILES = 8;
53
54
55 /**
56 * The origin of this request.
57 * @const {string}
58 */
59 var DOMAIN_ORIGIN = '{{ORIGIN}}';
60
61
62 /**
63 * Counter for DOM elements that we are waiting to finish loading.
64 * @type {number}
65 */
66 var loadedCounter = 1;
67
68
69 /**
70 * DOM element containing the tiles we are going to present next.
71 * Works as a double-buffer that is shown when we receive a "show" postMessage.
72 * @type {Element}
73 */
74 var tiles = null;
75
76
77 /**
78 * Log an event on the NTP.
79 * @param {number} eventType Event from NTP_LOGGING_EVENT_TYPE.
huangs 2015/03/13 03:49:52 NTP_LOGGING_EVENT_TYPE => LOG_TYPE
fserb 2015/03/13 17:22:45 Done.
80 */
81 var logEvent = function(eventType) {
82 chrome.embeddedSearch.newTabPage.logEvent(eventType);
83 };
84
85
86 /**
87 * Down count the DOM elements that we are waiting for the page to load.
huangs 2015/03/13 03:49:52 NIT: "Down counts" -- if a function comment starts
fserb 2015/03/13 17:22:45 Done.
88 * When we get to 0, we send a message to the parent window.
89 * This is usually used as an EventListener of onload/onerror.
90 */
91 var countLoad = function() {
92 loadedCounter -= 1;
93 if (loadedCounter <= 0) {
94 window.parent.postMessage({cmd: 'loaded'}, DOMAIN_ORIGIN);
95 loadedCounter = 1;
96 }
97 };
98
99
100 /**
101 * Handle postMessages coming from the host page to the iframe.
huangs 2015/03/13 03:49:52 NIT: Handles
fserb 2015/03/13 17:22:45 Done.
102 * We try to keep the logic here to a minimum and just dispatch to the relevant
103 * functions.
104 **/
105 var handlePostMessage = function(event) {
106 var cmd = event.data.cmd;
107
108 if (cmd == 'tile') {
109 addTile(event.data);
110 } else if (cmd == 'show') {
111 showTiles();
112 countLoad();
113 } else {
114 console.error('Unknown command: ' + event.data);
115 }
116 };
117
118
119 /**
120 * Called when the host page has finished sending us tile information and
121 * we are ready to show the new tiles and drop the old ones.
122 */
123 var showTiles = function() {
124 // Store the tiles on the current closure.
125 var cur = tiles;
126
127 // Create empty tiles until we have NUMBER_OF_TILES.
128 while (cur.childNodes.length < NUMBER_OF_TILES) {
129 addTile({});
130 }
131
132 var parent = document.querySelector('#most-visited');
133
134 // Mark old tile DIV for removal after the transition animation is done.
135 var old = parent.querySelector('#mv-tiles');
136 if (old) {
137 old.id = 'mv-tiles-old';
138 cur.addEventListener('webkitTransitionEnd', function(ev) {
139 if (ev.target === cur) {
140 parent.removeChild(old);
141 }
142 });
143 }
144
145 // Add new tileset.
146 cur.id = 'mv-tiles';
147 parent.appendChild(cur);
148 // We want the CSS transition to trigger, so need to add to the DOM before
149 // setting the style.
150 setTimeout(function() {
huangs 2015/03/13 03:49:52 Would requestAnimationFrame() do the same thing?
fserb 2015/03/13 17:22:45 not the same thing.
151 cur.style.opacity = 1.0;
152 }, 0);
153
154 // Make sure the tiles variable contain the next tileset we may use.
155 tiles = document.createElement('div');
156 };
157
158
159 /**
160 * Called when the host page wants to add a suggestion tile.
161 * For Most Visited, it grabs the data from Chrome and pass on.
162 * For host page generated it just passes the data.
163 * @param {object} args Data for the tile to be rendered.
164 */
165 var addTile = function(args) {
166 if (args.rid) {
167 var data = chrome.embeddedSearch.searchBox.getMostVisitedItemData(args.rid);
168 tiles.appendChild(renderTile(data));
169 logEvent(LOG_TYPE.NTP_CLIENT_SIDE_SUGGESTION);
170 } else {
171 tiles.appendChild(renderTile(null));
huangs 2015/03/13 03:49:52 Would you need to log NTP_SERVER_SIDE_SUGGESTION ?
fserb 2015/03/13 17:22:45 When I handle it, yes.
172 }
173 };
174
175
176 /**
177 * Called when the user decided to add a tile to the blacklist.
178 * It sets of the animation for the blacklist and sends the blacklisted id
179 * to the host page.
180 * @param {Element} tile DOM node of the tile we want to remove.
181 */
182 var blacklistTile = function(tile) {
183 tile.classList.add('blacklisted');
184 var sent = false;
185 tile.addEventListener('webkitTransitionEnd', function() {
186 if (sent) return;
187 sent = true;
188 window.parent.postMessage({cmd: 'tileBlacklisted',
189 rid: Number(tile.getAttribute('data-rid'))},
190 DOMAIN_ORIGIN);
191 });
192 };
193
194
195 /**
196 * Renders a MostVisited tile to the DOM.
197 * @param {object} data Object containing rid, url, title, favicon, thumbnail.
198 * data is null if you want to construct an empty tile.
199 */
200 var renderTile = function(data) {
201 var tile = document.createElement('a');
202
203 if (data == null) {
204 tile.className = 'mv-empty-tile';
205 return tile;
206 }
207
208 logEvent(LOG_TYPE.NTP_TILE);
209
210 tile.className = 'mv-tile';
211 tile.setAttribute('data-rid', data.rid);
212 tile.innerHTML = '<div class="mv-favicon"></div>' +
213 '<div class="mv-title"></div><div class="mv-thumb"></div>' +
214 '<div title="' + configData['removeThumbnailTooltip'] +
215 '" class="mv-x"></div>';
216
217 tile.href = data.url;
218 tile.title = data.title;
219 tile.addEventListener('keypress', function(ev) {
220 if (ev.keyCode == 127) { // DELETE
221 blacklistTile(tile);
222 ev.stopPropagation();
223 return false;
224 }
225 });
226 // TODO(fserb): remove this or at least change to mouseenter.
227 tile.addEventListener('mouseover', function() {
228 logEvent(LOG_TYPE.NTP_MOUSEOVER);
229 });
230
231 var title = tile.querySelector('.mv-title');
232 title.innerText = data.title;
233 title.style.direction = data.direction || 'ltr';
234
235 var thumb = tile.querySelectorAll('.mv-thumb')[0];
huangs 2015/03/13 03:49:52 querySelector
fserb 2015/03/13 17:22:44 Done.
236
huangs 2015/03/13 03:49:52 NIT: Don't need this new line.
fserb 2015/03/13 17:22:45 Done.
237 if (data.thumbnailUrl) {
238 var img = document.createElement('img');
239 img.title = data.title;
240 img.src = data.thumbnailUrl;
241 loadedCounter += 1;
242 img.addEventListener('load', countLoad);
243 img.addEventListener('error', countLoad);
244 img.addEventListener('error', function(ev) {
245 thumb.classList.add('failed-img');
246 thumb.removeChild(img);
247 logEvent(LOG_TYPE.NTP_THUMBNAIL_ERROR);
248 });
249 thumb.appendChild(img);
250 logEvent(LOG_TYPE.NTP_THUMBNAIL_TILE);
251 } else {
252 thumb.classList.add('failed-img');
253 }
254
255 var favicon = tile.querySelectorAll('.mv-favicon')[0];
huangs 2015/03/13 03:49:52 querySelector
fserb 2015/03/13 17:22:45 Done.
256 if (data.faviconUrl) {
257 var fi = document.createElement('img');
258 fi.src = '../' + data.faviconUrl;
259 // We set the title to empty, so it doesn't say the image name on chromevox.
huangs 2015/03/13 03:49:52 NIT: // Set title to empty so screen readers won't
fserb 2015/03/13 17:22:45 Done.
260 fi.title = '';
261 loadedCounter += 1;
262 fi.addEventListener('load', countLoad);
263 fi.addEventListener('error', countLoad);
264 fi.addEventListener('error', function(ev) {
265 favicon.classList.add('failed-favicon');
266 });
267 favicon.appendChild(fi);
268 } else {
269 favicon.classList.add('failed-favicon');
270 }
271
272 var mvx = tile.querySelectorAll('.mv-x')[0];
huangs 2015/03/13 03:49:52 querySelector
fserb 2015/03/13 17:22:44 Done.
273 mvx.addEventListener('click', function(ev) {
274 blacklistTile(tile);
275 ev.stopPropagation();
276 return false;
277 });
278
279 return tile;
280 };
281
282
283 /**
284 * Do some initialization and parses the query arguments passed to the iframe.
285 */
286 var init = function() {
287 // Creates a new DOM element to hold the tiles.
288 tiles = document.createElement('div');
289
290 // Parse query arguments.
291 var query = window.location.search.substring(1).split('&');
292 var args = {};
293 for (var i = 0; i < query.length; ++i) {
294 var val = query[i].split('=');
295 if (val[0] == '') continue;
296 args[decodeURIComponent(val[0])] = decodeURIComponent(val[1]);
297 }
298
299 // Enable RTL.
300 if (args['rtl'] == '1') {
301 var html = document.querySelector('html');
302 html.dir = 'rtl';
303 }
304
305 window.addEventListener('message', handlePostMessage);
306 };
307
308
309 window.addEventListener('DOMContentLoaded', init);
310 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698