OLD | NEW |
1 /* Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. */ | 3 * found in the LICENSE file. */ |
4 | 4 |
5 // Single iframe for NTP tiles. | 5 // Single iframe for NTP tiles. |
6 (function() { | 6 (function() { |
7 'use strict'; | 7 'use strict'; |
8 | 8 |
9 | 9 |
10 /** | 10 /** |
(...skipping 10 matching lines...) Expand all Loading... |
21 // The data for all NTP tiles (title, URL, etc, but not the thumbnail image) | 21 // The data for all NTP tiles (title, URL, etc, but not the thumbnail image) |
22 // has been received. In contrast to NTP_ALL_TILES_LOADED, this is recorded | 22 // has been received. In contrast to NTP_ALL_TILES_LOADED, this is recorded |
23 // before the actual DOM elements have loaded (in particular the thumbnail | 23 // before the actual DOM elements have loaded (in particular the thumbnail |
24 // images). | 24 // images). |
25 NTP_ALL_TILES_RECEIVED: 12, | 25 NTP_ALL_TILES_RECEIVED: 12, |
26 }; | 26 }; |
27 | 27 |
28 | 28 |
29 /** | 29 /** |
30 * The different sources that an NTP tile can have. | 30 * The different sources that an NTP tile can have. |
31 * Note: Keep in sync with components/ntp_tiles/ntp_tile_source.h | 31 * Note: Keep in sync with components/ntp_tiles/tile_source.h |
32 * @enum {number} | 32 * @enum {number} |
33 * @const | 33 * @const |
34 */ | 34 */ |
35 var NTPTileSource = { | 35 var TileSource = { |
36 TOP_SITES: 0, | 36 TOP_SITES: 0, |
37 SUGGESTIONS_SERVICE: 1, | 37 SUGGESTIONS_SERVICE: 1, |
38 POPULAR: 3, | 38 POPULAR: 3, |
39 WHITELIST: 4, | 39 WHITELIST: 4, |
40 }; | 40 }; |
41 | 41 |
42 | 42 |
43 /** | 43 /** |
| 44 * The different (visual) types that an NTP tile can have. |
| 45 * Note: Keep in sync with components/ntp_tiles/tile_visual_type.h |
| 46 * @enum {number} |
| 47 * @const |
| 48 */ |
| 49 var TileVisualType = { |
| 50 NONE: 0, |
| 51 ICON_REAL: 1, |
| 52 ICON_COLOR: 2, |
| 53 ICON_DEFAULT: 3, |
| 54 THUMBNAIL: 4, |
| 55 THUMBNAIL_FAILED: 5, |
| 56 }; |
| 57 |
| 58 |
| 59 /** |
44 * Total number of tiles to show at any time. If the host page doesn't send | 60 * Total number of tiles to show at any time. If the host page doesn't send |
45 * enough tiles, we fill them blank. | 61 * enough tiles, we fill them blank. |
46 * @const {number} | 62 * @const {number} |
47 */ | 63 */ |
48 var NUMBER_OF_TILES = 8; | 64 var NUMBER_OF_TILES = 8; |
49 | 65 |
50 | 66 |
51 /** | 67 /** |
52 * Number of lines to display in titles. | 68 * Number of lines to display in titles. |
53 * @type {number} | 69 * @type {number} |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 * Log an event on the NTP. | 105 * Log an event on the NTP. |
90 * @param {number} eventType Event from LOG_TYPE. | 106 * @param {number} eventType Event from LOG_TYPE. |
91 */ | 107 */ |
92 var logEvent = function(eventType) { | 108 var logEvent = function(eventType) { |
93 chrome.embeddedSearch.newTabPage.logEvent(eventType); | 109 chrome.embeddedSearch.newTabPage.logEvent(eventType); |
94 }; | 110 }; |
95 | 111 |
96 /** | 112 /** |
97 * Log impression of an NTP tile. | 113 * Log impression of an NTP tile. |
98 * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES. | 114 * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES. |
99 * @param {number} tileSource The source from NTPTileSource. | 115 * @param {number} tileSource The source from TileSource. |
| 116 * @param {number} tileType The type from TileVisualType. |
100 */ | 117 */ |
101 function logMostVisitedImpression(tileIndex, tileSource) { | 118 function logMostVisitedImpression(tileIndex, tileSource, tileType) { |
102 chrome.embeddedSearch.newTabPage.logMostVisitedImpression(tileIndex, | 119 chrome.embeddedSearch.newTabPage.logMostVisitedImpression(tileIndex, |
103 tileSource); | 120 tileSource, |
| 121 tileType); |
104 } | 122 } |
105 | 123 |
106 /** | 124 /** |
107 * Log click on an NTP tile. | 125 * Log click on an NTP tile. |
108 * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES. | 126 * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES. |
109 * @param {number} tileSource The source from NTPTileSource. | 127 * @param {number} tileSource The source from TileSource. |
| 128 * @param {number} tileType The type from TileVisualType. |
110 */ | 129 */ |
111 function logMostVisitedNavigation(tileIndex, tileSource) { | 130 function logMostVisitedNavigation(tileIndex, tileSource, tileType) { |
112 chrome.embeddedSearch.newTabPage.logMostVisitedNavigation(tileIndex, | 131 chrome.embeddedSearch.newTabPage.logMostVisitedNavigation(tileIndex, |
113 tileSource); | 132 tileSource, |
| 133 tileType); |
114 } | 134 } |
115 | 135 |
116 /** | 136 /** |
117 * Down counts the DOM elements that we are waiting for the page to load. | 137 * Down counts the DOM elements that we are waiting for the page to load. |
118 * When we get to 0, we send a message to the parent window. | 138 * When we get to 0, we send a message to the parent window. |
119 * This is usually used as an EventListener of onload/onerror. | 139 * This is usually used as an EventListener of onload/onerror. |
120 */ | 140 */ |
121 var countLoad = function() { | 141 var countLoad = function() { |
122 loadedCounter -= 1; | 142 loadedCounter -= 1; |
123 if (loadedCounter <= 0) { | 143 if (loadedCounter <= 0) { |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 return; | 330 return; |
311 | 331 |
312 data.tid = data.rid; | 332 data.tid = data.rid; |
313 if (!data.faviconUrl) { | 333 if (!data.faviconUrl) { |
314 data.faviconUrl = 'chrome-search://favicon/size/16@' + | 334 data.faviconUrl = 'chrome-search://favicon/size/16@' + |
315 window.devicePixelRatio + 'x/' + data.renderViewId + '/' + data.tid; | 335 window.devicePixelRatio + 'x/' + data.renderViewId + '/' + data.tid; |
316 } | 336 } |
317 tiles.appendChild(renderTile(data)); | 337 tiles.appendChild(renderTile(data)); |
318 } else if (args.url) { | 338 } else if (args.url) { |
319 // If a URL is passed: a server-side suggestion. | 339 // If a URL is passed: a server-side suggestion. |
320 args.tileSource = NTPTileSource.SUGGESTIONS_SERVICE; | 340 args.tileSource = TileSource.SUGGESTIONS_SERVICE; |
321 // check sanity of the arguments | 341 // check sanity of the arguments |
322 if (/^javascript:/i.test(args.url) || | 342 if (/^javascript:/i.test(args.url) || |
323 /^javascript:/i.test(args.thumbnailUrl)) | 343 /^javascript:/i.test(args.thumbnailUrl)) |
324 return; | 344 return; |
325 tiles.appendChild(renderTile(args)); | 345 tiles.appendChild(renderTile(args)); |
326 } else { // an empty tile | 346 } else { // an empty tile |
327 tiles.appendChild(renderTile(null)); | 347 tiles.appendChild(renderTile(null)); |
328 } | 348 } |
329 }; | 349 }; |
330 | 350 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 var renderTile = function(data) { | 384 var renderTile = function(data) { |
365 var tile = document.createElement('a'); | 385 var tile = document.createElement('a'); |
366 | 386 |
367 if (data == null) { | 387 if (data == null) { |
368 tile.className = 'mv-empty-tile'; | 388 tile.className = 'mv-empty-tile'; |
369 return tile; | 389 return tile; |
370 } | 390 } |
371 | 391 |
372 // The tile will be appended to tiles. | 392 // The tile will be appended to tiles. |
373 var position = tiles.children.length; | 393 var position = tiles.children.length; |
374 logMostVisitedImpression(position, data.tileSource); | 394 |
| 395 // This is set in the load/error event for the thumbnail image. |
| 396 var tileType = TileVisualType.NONE; |
375 | 397 |
376 tile.className = 'mv-tile'; | 398 tile.className = 'mv-tile'; |
377 tile.setAttribute('data-tid', data.tid); | 399 tile.setAttribute('data-tid', data.tid); |
378 var html = []; | 400 var html = []; |
379 html.push('<div class="mv-favicon"></div>'); | 401 html.push('<div class="mv-favicon"></div>'); |
380 html.push('<div class="mv-title"></div><div class="mv-thumb"></div>'); | 402 html.push('<div class="mv-title"></div><div class="mv-thumb"></div>'); |
381 html.push('<div class="mv-x" role="button"></div>'); | 403 html.push('<div class="mv-x" role="button"></div>'); |
382 tile.innerHTML = html.join(''); | 404 tile.innerHTML = html.join(''); |
383 tile.lastElementChild.title = queryArgs['removeTooltip'] || ''; | 405 tile.lastElementChild.title = queryArgs['removeTooltip'] || ''; |
384 | 406 |
385 if (isSchemeAllowed(data.url)) { | 407 if (isSchemeAllowed(data.url)) { |
386 tile.href = data.url; | 408 tile.href = data.url; |
387 } | 409 } |
388 tile.setAttribute('aria-label', data.title); | 410 tile.setAttribute('aria-label', data.title); |
389 tile.title = data.title; | 411 tile.title = data.title; |
390 | 412 |
391 tile.addEventListener('click', function(ev) { | 413 tile.addEventListener('click', function(ev) { |
392 logMostVisitedNavigation(position, data.tileSource); | 414 logMostVisitedNavigation(position, data.tileSource, tileType); |
393 }); | 415 }); |
394 | 416 |
395 tile.addEventListener('keydown', function(event) { | 417 tile.addEventListener('keydown', function(event) { |
396 if (event.keyCode == 46 /* DELETE */ || | 418 if (event.keyCode == 46 /* DELETE */ || |
397 event.keyCode == 8 /* BACKSPACE */) { | 419 event.keyCode == 8 /* BACKSPACE */) { |
398 event.preventDefault(); | 420 event.preventDefault(); |
399 event.stopPropagation(); | 421 event.stopPropagation(); |
400 blacklistTile(this); | 422 blacklistTile(this); |
401 } else if (event.keyCode == 13 /* ENTER */ || | 423 } else if (event.keyCode == 13 /* ENTER */ || |
402 event.keyCode == 32 /* SPACE */) { | 424 event.keyCode == 32 /* SPACE */) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 title.style.direction = data.direction || 'ltr'; | 461 title.style.direction = data.direction || 'ltr'; |
440 if (NUM_TITLE_LINES > 1) { | 462 if (NUM_TITLE_LINES > 1) { |
441 title.classList.add('multiline'); | 463 title.classList.add('multiline'); |
442 } | 464 } |
443 | 465 |
444 var thumb = tile.querySelector('.mv-thumb'); | 466 var thumb = tile.querySelector('.mv-thumb'); |
445 var img = document.createElement('img'); | 467 var img = document.createElement('img'); |
446 img.title = data.title; | 468 img.title = data.title; |
447 img.src = data.thumbnailUrl; | 469 img.src = data.thumbnailUrl; |
448 loadedCounter += 1; | 470 loadedCounter += 1; |
449 img.addEventListener('load', countLoad); | 471 img.addEventListener('load', function(ev) { |
450 img.addEventListener('error', countLoad); | 472 // Store the type for a potential later navigation. |
| 473 tileType = TileVisualType.THUMBNAIL; |
| 474 logMostVisitedImpression(position, data.tileSource, tileType); |
| 475 // Note: It's important to call countLoad last, because that might emit the |
| 476 // NTP_ALL_TILES_LOADED event, which must happen after the impression log. |
| 477 countLoad(); |
| 478 }); |
451 img.addEventListener('error', function(ev) { | 479 img.addEventListener('error', function(ev) { |
452 thumb.classList.add('failed-img'); | 480 thumb.classList.add('failed-img'); |
453 thumb.removeChild(img); | 481 thumb.removeChild(img); |
| 482 // Store the type for a potential later navigation. |
| 483 tileType = TileVisualType.THUMBNAIL_FAILED; |
| 484 logMostVisitedImpression(position, data.tileSource, tileType); |
| 485 // Note: It's important to call countLoad last, because that might emit the |
| 486 // NTP_ALL_TILES_LOADED event, which must happen after the impression log. |
| 487 countLoad(); |
454 }); | 488 }); |
455 thumb.appendChild(img); | 489 thumb.appendChild(img); |
456 | 490 |
457 var favicon = tile.querySelector('.mv-favicon'); | 491 var favicon = tile.querySelector('.mv-favicon'); |
458 if (data.faviconUrl) { | 492 if (data.faviconUrl) { |
459 var fi = document.createElement('img'); | 493 var fi = document.createElement('img'); |
460 fi.src = data.faviconUrl; | 494 fi.src = data.faviconUrl; |
461 // Set the title to empty so screen readers won't say the image name. | 495 // Set the title to empty so screen readers won't say the image name. |
462 fi.title = ''; | 496 fi.title = ''; |
463 loadedCounter += 1; | 497 loadedCounter += 1; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 var html = document.querySelector('html'); | 547 var html = document.querySelector('html'); |
514 html.dir = 'rtl'; | 548 html.dir = 'rtl'; |
515 } | 549 } |
516 | 550 |
517 window.addEventListener('message', handlePostMessage); | 551 window.addEventListener('message', handlePostMessage); |
518 }; | 552 }; |
519 | 553 |
520 | 554 |
521 window.addEventListener('DOMContentLoaded', init); | 555 window.addEventListener('DOMContentLoaded', init); |
522 })(); | 556 })(); |
OLD | NEW |