| 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 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 /** | 38 /** |
| 39 * Total number of tiles to show at any time. If the host page doesn't send | 39 * Total number of tiles to show at any time. If the host page doesn't send |
| 40 * enough tiles, we fill them blank. | 40 * enough tiles, we fill them blank. |
| 41 * @const {number} | 41 * @const {number} |
| 42 */ | 42 */ |
| 43 var NUMBER_OF_TILES = 8; | 43 var NUMBER_OF_TILES = 8; |
| 44 | 44 |
| 45 | 45 |
| 46 /** | 46 /** |
| 47 * Whether to use icons instead of thumbnails. | |
| 48 * @type {boolean} | |
| 49 */ | |
| 50 var USE_ICONS = false; | |
| 51 | |
| 52 | |
| 53 /** | |
| 54 * Number of lines to display in titles. | 47 * Number of lines to display in titles. |
| 55 * @type {number} | 48 * @type {number} |
| 56 */ | 49 */ |
| 57 var NUM_TITLE_LINES = 1; | 50 var NUM_TITLE_LINES = 1; |
| 58 | 51 |
| 59 | 52 |
| 60 /** | 53 /** |
| 61 * The origin of this request. | 54 * The origin of this request. |
| 62 * @const {string} | 55 * @const {string} |
| 63 */ | 56 */ |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 'rgb(51,51,51) 60%, transparent); }'); | 184 'rgb(51,51,51) 60%, transparent); }'); |
| 192 themeStyle.push('html[dir=rtl] .thumb-ntp .mv-x { ' + | 185 themeStyle.push('html[dir=rtl] .thumb-ntp .mv-x { ' + |
| 193 'background: linear-gradient(to right, ' + | 186 'background: linear-gradient(to right, ' + |
| 194 'rgb(51,51,51) 60%, transparent); }'); | 187 'rgb(51,51,51) 60%, transparent); }'); |
| 195 themeStyle.push('.thumb-ntp .mv-x::after { ' + | 188 themeStyle.push('.thumb-ntp .mv-x::after { ' + |
| 196 'background-color: rgba(255,255,255,0.7); }'); | 189 'background-color: rgba(255,255,255,0.7); }'); |
| 197 themeStyle.push('.thumb-ntp .mv-x:hover::after { ' + | 190 themeStyle.push('.thumb-ntp .mv-x:hover::after { ' + |
| 198 'background-color: #fff; }'); | 191 'background-color: #fff; }'); |
| 199 themeStyle.push('.thumb-ntp .mv-x:active::after { ' + | 192 themeStyle.push('.thumb-ntp .mv-x:active::after { ' + |
| 200 'background-color: rgba(255,255,255,0.5); }'); | 193 'background-color: rgba(255,255,255,0.5); }'); |
| 201 themeStyle.push('.icon-ntp .mv-tile:focus { ' + | |
| 202 'background: rgba(255,255,255,0.2); }'); | |
| 203 } | 194 } |
| 204 if (info.tileTitleColor) { | 195 if (info.tileTitleColor) { |
| 205 themeStyle.push('body { color: ' + info.tileTitleColor + '; }'); | 196 themeStyle.push('body { color: ' + info.tileTitleColor + '; }'); |
| 206 } | 197 } |
| 207 | 198 |
| 208 document.querySelector('#custom-theme').textContent = themeStyle.join('\n'); | 199 document.querySelector('#custom-theme').textContent = themeStyle.join('\n'); |
| 209 }; | 200 }; |
| 210 | 201 |
| 211 | 202 |
| 212 /** | 203 /** |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 return tile; | 345 return tile; |
| 355 } | 346 } |
| 356 | 347 |
| 357 // The tile will be appended to tiles. | 348 // The tile will be appended to tiles. |
| 358 var position = tiles.children.length; | 349 var position = tiles.children.length; |
| 359 logMostVisitedImpression(position, data.tileSource); | 350 logMostVisitedImpression(position, data.tileSource); |
| 360 | 351 |
| 361 tile.className = 'mv-tile'; | 352 tile.className = 'mv-tile'; |
| 362 tile.setAttribute('data-tid', data.tid); | 353 tile.setAttribute('data-tid', data.tid); |
| 363 var html = []; | 354 var html = []; |
| 364 if (!USE_ICONS) { | 355 html.push('<div class="mv-favicon"></div>'); |
| 365 html.push('<div class="mv-favicon"></div>'); | |
| 366 } | |
| 367 html.push('<div class="mv-title"></div><div class="mv-thumb"></div>'); | 356 html.push('<div class="mv-title"></div><div class="mv-thumb"></div>'); |
| 368 html.push('<div class="mv-x" role="button"></div>'); | 357 html.push('<div class="mv-x" role="button"></div>'); |
| 369 tile.innerHTML = html.join(''); | 358 tile.innerHTML = html.join(''); |
| 370 tile.lastElementChild.title = queryArgs['removeTooltip'] || ''; | 359 tile.lastElementChild.title = queryArgs['removeTooltip'] || ''; |
| 371 | 360 |
| 372 if (isSchemeAllowed(data.url)) { | 361 if (isSchemeAllowed(data.url)) { |
| 373 tile.href = data.url; | 362 tile.href = data.url; |
| 374 } | 363 } |
| 375 tile.setAttribute('aria-label', data.title); | 364 tile.setAttribute('aria-label', data.title); |
| 376 tile.title = data.title; | 365 tile.title = data.title; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 } | 410 } |
| 422 }); | 411 }); |
| 423 | 412 |
| 424 var title = tile.querySelector('.mv-title'); | 413 var title = tile.querySelector('.mv-title'); |
| 425 title.innerText = data.title; | 414 title.innerText = data.title; |
| 426 title.style.direction = data.direction || 'ltr'; | 415 title.style.direction = data.direction || 'ltr'; |
| 427 if (NUM_TITLE_LINES > 1) { | 416 if (NUM_TITLE_LINES > 1) { |
| 428 title.classList.add('multiline'); | 417 title.classList.add('multiline'); |
| 429 } | 418 } |
| 430 | 419 |
| 431 if (USE_ICONS) { | 420 // We keep track of the outcome of loading possible thumbnails for this |
| 432 var thumb = tile.querySelector('.mv-thumb'); | 421 // tile. Possible values: |
| 433 if (data.largeIconUrl) { | 422 // - null: waiting for load/error |
| 434 var img = document.createElement('img'); | 423 // - false: error |
| 435 img.title = data.title; | 424 // - a string: URL that loaded correctly. |
| 436 img.src = data.largeIconUrl; | 425 // This is populated by acceptImage/rejectImage and loadBestImage |
| 437 img.classList.add('large-icon'); | 426 // decides the best one to load. |
| 438 loadedCounter += 1; | 427 var results = []; |
| 439 img.addEventListener('load', countLoad); | 428 var thumb = tile.querySelector('.mv-thumb'); |
| 440 img.addEventListener('load', function(ev) { | 429 var img = document.createElement('img'); |
| 441 thumb.classList.add('large-icon-outer'); | 430 var loaded = false; |
| 442 }); | 431 |
| 443 img.addEventListener('error', countLoad); | 432 var loadBestImage = function() { |
| 444 img.addEventListener('error', function(ev) { | 433 if (loaded) { |
| 445 thumb.classList.add('failed-img'); | 434 return; |
| 446 thumb.removeChild(img); | |
| 447 }); | |
| 448 thumb.appendChild(img); | |
| 449 } else { | |
| 450 thumb.classList.add('failed-img'); | |
| 451 } | 435 } |
| 452 } else { // THUMBNAILS | 436 for (var i = 0; i < results.length; ++i) { |
| 453 // We keep track of the outcome of loading possible thumbnails for this | 437 if (results[i] === null) { |
| 454 // tile. Possible values: | |
| 455 // - null: waiting for load/error | |
| 456 // - false: error | |
| 457 // - a string: URL that loaded correctly. | |
| 458 // This is populated by acceptImage/rejectImage and loadBestImage | |
| 459 // decides the best one to load. | |
| 460 var results = []; | |
| 461 var thumb = tile.querySelector('.mv-thumb'); | |
| 462 var img = document.createElement('img'); | |
| 463 var loaded = false; | |
| 464 | |
| 465 var loadBestImage = function() { | |
| 466 if (loaded) { | |
| 467 return; | 438 return; |
| 468 } | 439 } |
| 469 for (var i = 0; i < results.length; ++i) { | 440 if (results[i] != false) { |
| 470 if (results[i] === null) { | 441 img.src = results[i]; |
| 471 return; | 442 loaded = true; |
| 472 } | 443 return; |
| 473 if (results[i] != false) { | |
| 474 img.src = results[i]; | |
| 475 loaded = true; | |
| 476 return; | |
| 477 } | |
| 478 } | |
| 479 thumb.classList.add('failed-img'); | |
| 480 thumb.removeChild(img); | |
| 481 countLoad(); | |
| 482 }; | |
| 483 | |
| 484 var acceptImage = function(idx, url) { | |
| 485 return function(ev) { | |
| 486 results[idx] = url; | |
| 487 loadBestImage(); | |
| 488 }; | |
| 489 }; | |
| 490 | |
| 491 var rejectImage = function(idx) { | |
| 492 return function(ev) { | |
| 493 results[idx] = false; | |
| 494 loadBestImage(); | |
| 495 }; | |
| 496 }; | |
| 497 | |
| 498 img.title = data.title; | |
| 499 img.classList.add('thumbnail'); | |
| 500 loadedCounter += 1; | |
| 501 img.addEventListener('load', countLoad); | |
| 502 img.addEventListener('error', countLoad); | |
| 503 img.addEventListener('error', function(ev) { | |
| 504 thumb.classList.add('failed-img'); | |
| 505 thumb.removeChild(img); | |
| 506 }); | |
| 507 thumb.appendChild(img); | |
| 508 | |
| 509 if (data.thumbnailUrl) { | |
| 510 img.src = data.thumbnailUrl; | |
| 511 } else { | |
| 512 // Get all thumbnailUrls for the tile. | |
| 513 // They are ordered from best one to be used to worst. | |
| 514 for (var i = 0; i < data.thumbnailUrls.length; ++i) { | |
| 515 results.push(null); | |
| 516 } | |
| 517 for (var i = 0; i < data.thumbnailUrls.length; ++i) { | |
| 518 if (data.thumbnailUrls[i]) { | |
| 519 var image = new Image(); | |
| 520 image.src = data.thumbnailUrls[i]; | |
| 521 image.onload = acceptImage(i, data.thumbnailUrls[i]); | |
| 522 image.onerror = rejectImage(i); | |
| 523 } else { | |
| 524 rejectImage(i)(null); | |
| 525 } | |
| 526 } | 444 } |
| 527 } | 445 } |
| 446 thumb.classList.add('failed-img'); |
| 447 thumb.removeChild(img); |
| 448 countLoad(); |
| 449 }; |
| 528 | 450 |
| 529 var favicon = tile.querySelector('.mv-favicon'); | 451 var acceptImage = function(idx, url) { |
| 530 if (data.faviconUrl) { | 452 return function(ev) { |
| 531 var fi = document.createElement('img'); | 453 results[idx] = url; |
| 532 fi.src = data.faviconUrl; | 454 loadBestImage(); |
| 533 // Set the title to empty so screen readers won't say the image name. | 455 }; |
| 534 fi.title = ''; | 456 }; |
| 535 loadedCounter += 1; | 457 |
| 536 fi.addEventListener('load', countLoad); | 458 var rejectImage = function(idx) { |
| 537 fi.addEventListener('error', countLoad); | 459 return function(ev) { |
| 538 fi.addEventListener('error', function(ev) { | 460 results[idx] = false; |
| 539 favicon.classList.add('failed-favicon'); | 461 loadBestImage(); |
| 540 }); | 462 }; |
| 541 favicon.appendChild(fi); | 463 }; |
| 542 } else { | 464 |
| 543 favicon.classList.add('failed-favicon'); | 465 img.title = data.title; |
| 466 img.classList.add('thumbnail'); |
| 467 loadedCounter += 1; |
| 468 img.addEventListener('load', countLoad); |
| 469 img.addEventListener('error', countLoad); |
| 470 img.addEventListener('error', function(ev) { |
| 471 thumb.classList.add('failed-img'); |
| 472 thumb.removeChild(img); |
| 473 }); |
| 474 thumb.appendChild(img); |
| 475 |
| 476 if (data.thumbnailUrl) { |
| 477 img.src = data.thumbnailUrl; |
| 478 } else { |
| 479 // Get all thumbnailUrls for the tile. |
| 480 // They are ordered from best one to be used to worst. |
| 481 for (var i = 0; i < data.thumbnailUrls.length; ++i) { |
| 482 results.push(null); |
| 483 } |
| 484 for (var i = 0; i < data.thumbnailUrls.length; ++i) { |
| 485 if (data.thumbnailUrls[i]) { |
| 486 var image = new Image(); |
| 487 image.src = data.thumbnailUrls[i]; |
| 488 image.onload = acceptImage(i, data.thumbnailUrls[i]); |
| 489 image.onerror = rejectImage(i); |
| 490 } else { |
| 491 rejectImage(i)(null); |
| 492 } |
| 544 } | 493 } |
| 545 } | 494 } |
| 546 | 495 |
| 496 var favicon = tile.querySelector('.mv-favicon'); |
| 497 if (data.faviconUrl) { |
| 498 var fi = document.createElement('img'); |
| 499 fi.src = data.faviconUrl; |
| 500 // Set the title to empty so screen readers won't say the image name. |
| 501 fi.title = ''; |
| 502 loadedCounter += 1; |
| 503 fi.addEventListener('load', countLoad); |
| 504 fi.addEventListener('error', countLoad); |
| 505 fi.addEventListener('error', function(ev) { |
| 506 favicon.classList.add('failed-favicon'); |
| 507 }); |
| 508 favicon.appendChild(fi); |
| 509 } else { |
| 510 favicon.classList.add('failed-favicon'); |
| 511 } |
| 512 |
| 547 var mvx = tile.querySelector('.mv-x'); | 513 var mvx = tile.querySelector('.mv-x'); |
| 548 mvx.addEventListener('click', function(ev) { | 514 mvx.addEventListener('click', function(ev) { |
| 549 removeAllOldTiles(); | 515 removeAllOldTiles(); |
| 550 blacklistTile(tile); | 516 blacklistTile(tile); |
| 551 ev.preventDefault(); | 517 ev.preventDefault(); |
| 552 ev.stopPropagation(); | 518 ev.stopPropagation(); |
| 553 }); | 519 }); |
| 554 | 520 |
| 555 return tile; | 521 return tile; |
| 556 }; | 522 }; |
| 557 | 523 |
| 558 | 524 |
| 559 /** | 525 /** |
| 560 * Do some initialization and parses the query arguments passed to the iframe. | 526 * Do some initialization and parses the query arguments passed to the iframe. |
| 561 */ | 527 */ |
| 562 var init = function() { | 528 var init = function() { |
| 563 // Creates a new DOM element to hold the tiles. | 529 // Creates a new DOM element to hold the tiles. |
| 564 tiles = document.createElement('div'); | 530 tiles = document.createElement('div'); |
| 565 | 531 |
| 566 // Parse query arguments. | 532 // Parse query arguments. |
| 567 var query = window.location.search.substring(1).split('&'); | 533 var query = window.location.search.substring(1).split('&'); |
| 568 queryArgs = {}; | 534 queryArgs = {}; |
| 569 for (var i = 0; i < query.length; ++i) { | 535 for (var i = 0; i < query.length; ++i) { |
| 570 var val = query[i].split('='); | 536 var val = query[i].split('='); |
| 571 if (val[0] == '') continue; | 537 if (val[0] == '') continue; |
| 572 queryArgs[decodeURIComponent(val[0])] = decodeURIComponent(val[1]); | 538 queryArgs[decodeURIComponent(val[0])] = decodeURIComponent(val[1]); |
| 573 } | 539 } |
| 574 | 540 |
| 575 // Apply class for icon NTP, if specified. | |
| 576 USE_ICONS = queryArgs['icons'] == '1'; | |
| 577 if ('ntl' in queryArgs) { | 541 if ('ntl' in queryArgs) { |
| 578 var ntl = parseInt(queryArgs['ntl'], 10); | 542 var ntl = parseInt(queryArgs['ntl'], 10); |
| 579 if (isFinite(ntl)) | 543 if (isFinite(ntl)) |
| 580 NUM_TITLE_LINES = ntl; | 544 NUM_TITLE_LINES = ntl; |
| 581 } | 545 } |
| 582 | 546 |
| 583 // Duplicating NTP_DESIGN.mainClass. | 547 document.querySelector('#most-visited').classList.add('thumb-ntp'); |
| 584 document.querySelector('#most-visited').classList.add( | |
| 585 USE_ICONS ? 'icon-ntp' : 'thumb-ntp'); | |
| 586 | 548 |
| 587 // Enable RTL. | 549 // Enable RTL. |
| 588 if (queryArgs['rtl'] == '1') { | 550 if (queryArgs['rtl'] == '1') { |
| 589 var html = document.querySelector('html'); | 551 var html = document.querySelector('html'); |
| 590 html.dir = 'rtl'; | 552 html.dir = 'rtl'; |
| 591 } | 553 } |
| 592 | 554 |
| 593 window.addEventListener('message', handlePostMessage); | 555 window.addEventListener('message', handlePostMessage); |
| 594 }; | 556 }; |
| 595 | 557 |
| 596 | 558 |
| 597 window.addEventListener('DOMContentLoaded', init); | 559 window.addEventListener('DOMContentLoaded', init); |
| 598 })(); | 560 })(); |
| OLD | NEW |