| 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 |