| 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 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 }); | 322 }); |
| 323 }; | 323 }; |
| 324 | 324 |
| 325 | 325 |
| 326 /** | 326 /** |
| 327 * Returns whether the given URL has a known, safe scheme. | 327 * Returns whether the given URL has a known, safe scheme. |
| 328 * @param {string} url URL to check. | 328 * @param {string} url URL to check. |
| 329 */ | 329 */ |
| 330 var isSchemeAllowed = function(url) { | 330 var isSchemeAllowed = function(url) { |
| 331 return url.startsWith('http://') || url.startsWith('https://') || | 331 return url.startsWith('http://') || url.startsWith('https://') || |
| 332 url.startsWith('ftp://') || url.startsWith('file://') || | 332 url.startsWith('ftp://') || url.startsWith('chrome-extension://'); |
| 333 url.startsWith('chrome-extension://'); | |
| 334 }; | 333 }; |
| 335 | 334 |
| 336 | 335 |
| 337 /** | 336 /** |
| 338 * Renders a MostVisited tile to the DOM. | 337 * Renders a MostVisited tile to the DOM. |
| 339 * @param {object} data Object containing rid, url, title, favicon, thumbnail. | 338 * @param {object} data Object containing rid, url, title, favicon, thumbnail. |
| 340 * data is null if you want to construct an empty tile. | 339 * data is null if you want to construct an empty tile. |
| 341 */ | 340 */ |
| 342 var renderTile = function(data) { | 341 var renderTile = function(data) { |
| 343 var tile = document.createElement('a'); | 342 var tile = document.createElement('a'); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 title.style.direction = data.direction || 'ltr'; | 416 title.style.direction = data.direction || 'ltr'; |
| 418 if (NUM_TITLE_LINES > 1) { | 417 if (NUM_TITLE_LINES > 1) { |
| 419 title.classList.add('multiline'); | 418 title.classList.add('multiline'); |
| 420 } | 419 } |
| 421 | 420 |
| 422 // We keep track of the outcome of loading possible thumbnails for this | 421 // We keep track of the outcome of loading possible thumbnails for this |
| 423 // tile. Possible values: | 422 // tile. Possible values: |
| 424 // - null: waiting for load/error | 423 // - null: waiting for load/error |
| 425 // - false: error | 424 // - false: error |
| 426 // - a string: URL that loaded correctly. | 425 // - a string: URL that loaded correctly. |
| 427 // This is populated by acceptImage/rejectImage and loadBestImage | 426 // This is populated by imageLoaded/imageLoadFailed, and selectBestImage |
| 428 // decides the best one to load. | 427 // selects the best one to display. |
| 429 var results = []; | 428 var results = []; |
| 430 var thumb = tile.querySelector('.mv-thumb'); | 429 var thumb = tile.querySelector('.mv-thumb'); |
| 431 var img = document.createElement('img'); | 430 var img = document.createElement('img'); |
| 432 var loaded = false; | 431 var loaded = false; |
| 433 | 432 |
| 434 var loadBestImage = function() { | 433 var selectBestImage = function() { |
| 435 if (loaded) { | 434 if (loaded) { |
| 436 return; | 435 return; |
| 437 } | 436 } |
| 437 // |results| is ordered from best candidate to worst. |
| 438 for (var i = 0; i < results.length; ++i) { | 438 for (var i = 0; i < results.length; ++i) { |
| 439 if (results[i] === null) { | 439 if (results[i] === null) { |
| 440 // A better candidate is still waiting to be loaded; defer. |
| 440 return; | 441 return; |
| 441 } | 442 } |
| 442 if (results[i] != false) { | 443 if (results[i] != false) { |
| 444 // This is the best (non-failed) candidate. Use it! |
| 443 img.src = results[i]; | 445 img.src = results[i]; |
| 444 loaded = true; | 446 loaded = true; |
| 445 return; | 447 return; |
| 446 } | 448 } |
| 447 } | 449 } |
| 450 // If we get here, then all candidates failed to load. |
| 448 thumb.classList.add('failed-img'); | 451 thumb.classList.add('failed-img'); |
| 449 thumb.removeChild(img); | 452 thumb.removeChild(img); |
| 453 // Usually we count the load once the img element gets either a 'load' or |
| 454 // an 'error' event. Since we have removed the img element, instead count |
| 455 // the load here. |
| 450 countLoad(); | 456 countLoad(); |
| 451 }; | 457 }; |
| 452 | 458 |
| 453 var acceptImage = function(idx, url) { | 459 var imageLoaded = function(idx, url) { |
| 454 return function(ev) { | 460 return function(ev) { |
| 455 results[idx] = url; | 461 results[idx] = url; |
| 456 loadBestImage(); | 462 selectBestImage(); |
| 457 }; | 463 }; |
| 458 }; | 464 }; |
| 459 | 465 |
| 460 var rejectImage = function(idx) { | 466 var imageLoadFailed = function(idx) { |
| 461 return function(ev) { | 467 return function(ev) { |
| 462 results[idx] = false; | 468 results[idx] = false; |
| 463 loadBestImage(); | 469 selectBestImage(); |
| 464 }; | 470 }; |
| 465 }; | 471 }; |
| 466 | 472 |
| 467 img.title = data.title; | 473 img.title = data.title; |
| 468 img.classList.add('thumbnail'); | 474 img.classList.add('thumbnail'); |
| 469 loadedCounter += 1; | 475 loadedCounter += 1; |
| 470 img.addEventListener('load', countLoad); | 476 img.addEventListener('load', countLoad); |
| 471 img.addEventListener('error', countLoad); | 477 img.addEventListener('error', countLoad); |
| 472 img.addEventListener('error', function(ev) { | 478 img.addEventListener('error', function(ev) { |
| 473 thumb.classList.add('failed-img'); | 479 thumb.classList.add('failed-img'); |
| 474 thumb.removeChild(img); | 480 thumb.removeChild(img); |
| 475 }); | 481 }); |
| 476 thumb.appendChild(img); | 482 thumb.appendChild(img); |
| 477 | 483 |
| 478 if (data.thumbnailUrl) { | 484 if (data.thumbnailUrl) { |
| 479 img.src = data.thumbnailUrl; | 485 img.src = data.thumbnailUrl; |
| 480 } else { | 486 } else { |
| 481 // Get all thumbnailUrls for the tile. | 487 // Get all thumbnailUrls for the tile. |
| 482 // They are ordered from best one to be used to worst. | 488 // They are ordered from best one to be used to worst. |
| 483 for (var i = 0; i < data.thumbnailUrls.length; ++i) { | 489 for (var i = 0; i < data.thumbnailUrls.length; ++i) { |
| 484 results.push(null); | 490 results.push(null); |
| 485 } | 491 } |
| 486 for (var i = 0; i < data.thumbnailUrls.length; ++i) { | 492 for (var i = 0; i < data.thumbnailUrls.length; ++i) { |
| 487 if (data.thumbnailUrls[i]) { | 493 if (data.thumbnailUrls[i]) { |
| 488 var image = new Image(); | 494 var image = new Image(); |
| 489 image.src = data.thumbnailUrls[i]; | 495 image.src = data.thumbnailUrls[i]; |
| 490 image.onload = acceptImage(i, data.thumbnailUrls[i]); | 496 image.onload = imageLoaded(i, data.thumbnailUrls[i]); |
| 491 image.onerror = rejectImage(i); | 497 image.onerror = imageLoadFailed(i); |
| 492 } else { | 498 } else { |
| 493 rejectImage(i)(null); | 499 imageLoadFailed(i)(/*ev=*/null); |
| 494 } | 500 } |
| 495 } | 501 } |
| 496 } | 502 } |
| 497 | 503 |
| 498 var favicon = tile.querySelector('.mv-favicon'); | 504 var favicon = tile.querySelector('.mv-favicon'); |
| 499 if (data.faviconUrl) { | 505 if (data.faviconUrl) { |
| 500 var fi = document.createElement('img'); | 506 var fi = document.createElement('img'); |
| 501 fi.src = data.faviconUrl; | 507 fi.src = data.faviconUrl; |
| 502 // Set the title to empty so screen readers won't say the image name. | 508 // Set the title to empty so screen readers won't say the image name. |
| 503 fi.title = ''; | 509 fi.title = ''; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 518 blacklistTile(tile); | 524 blacklistTile(tile); |
| 519 ev.preventDefault(); | 525 ev.preventDefault(); |
| 520 ev.stopPropagation(); | 526 ev.stopPropagation(); |
| 521 }); | 527 }); |
| 522 | 528 |
| 523 return tile; | 529 return tile; |
| 524 }; | 530 }; |
| 525 | 531 |
| 526 | 532 |
| 527 /** | 533 /** |
| 528 * Do some initialization and parses the query arguments passed to the iframe. | 534 * Does some initialization and parses the query arguments passed to the iframe. |
| 529 */ | 535 */ |
| 530 var init = function() { | 536 var init = function() { |
| 531 // Creates a new DOM element to hold the tiles. | 537 // Create a new DOM element to hold the tiles. The tiles will be added |
| 538 // one-by-one via addTile, and the whole thing will be inserted into the page |
| 539 // in showTiles, after the parent has sent us the 'show' message, and all |
| 540 // thumbnails and favicons have loaded. |
| 532 tiles = document.createElement('div'); | 541 tiles = document.createElement('div'); |
| 533 | 542 |
| 534 // Parse query arguments. | 543 // Parse query arguments. |
| 535 var query = window.location.search.substring(1).split('&'); | 544 var query = window.location.search.substring(1).split('&'); |
| 536 queryArgs = {}; | 545 queryArgs = {}; |
| 537 for (var i = 0; i < query.length; ++i) { | 546 for (var i = 0; i < query.length; ++i) { |
| 538 var val = query[i].split('='); | 547 var val = query[i].split('='); |
| 539 if (val[0] == '') continue; | 548 if (val[0] == '') continue; |
| 540 queryArgs[decodeURIComponent(val[0])] = decodeURIComponent(val[1]); | 549 queryArgs[decodeURIComponent(val[0])] = decodeURIComponent(val[1]); |
| 541 } | 550 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 553 var html = document.querySelector('html'); | 562 var html = document.querySelector('html'); |
| 554 html.dir = 'rtl'; | 563 html.dir = 'rtl'; |
| 555 } | 564 } |
| 556 | 565 |
| 557 window.addEventListener('message', handlePostMessage); | 566 window.addEventListener('message', handlePostMessage); |
| 558 }; | 567 }; |
| 559 | 568 |
| 560 | 569 |
| 561 window.addEventListener('DOMContentLoaded', init); | 570 window.addEventListener('DOMContentLoaded', init); |
| 562 })(); | 571 })(); |
| OLD | NEW |