Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 (function() { | 5 (function() { |
| 6 | |
| 7 /** | |
| 8 * True if this a Google page and not some other search provider. Used to | |
| 9 * determine whether to show the logo and fakebox. | |
| 10 * @type {boolean} | |
| 11 * @const | |
| 12 */ | |
| 13 var isGooglePage = location.href.indexOf('isGoogle') != -1; | |
| 14 | |
| 15 // ========================================================== | |
| 16 // Enums | |
| 17 // ========================================================== | |
| 18 | |
| 19 /** | |
| 20 * Enum for classnames. | |
| 21 * @enum {string} | |
| 22 * @const | |
| 23 */ | |
| 24 var CLASSES = { | |
| 25 BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation | |
| 26 BLACKLIST_BUTTON: 'mv-x', | |
| 27 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', | |
| 28 DOMAIN: 'mv-domain', | |
| 29 FAKEBOX_ANIMATE: 'fakebox-animate', // triggers fakebox animation | |
| 30 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox | |
| 31 FAVICON: 'mv-favicon', | |
| 32 FILLER: 'mv-filler', // filler tiles | |
| 33 GOOGLE_PAGE: 'google-page', // shows the Google logo and fakebox | |
| 34 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation | |
| 35 HIDE_NOTIFICATION: 'mv-notice-hide', | |
| 36 HIDE_TILE: 'mv-tile-hide', // hides tiles on small browser width | |
| 37 PAGE: 'mv-page', // page tiles | |
| 38 THUMBNAIL: 'mv-thumb', | |
| 39 TILE: 'mv-tile', | |
| 40 TITLE: 'mv-title' | |
| 41 }; | |
| 42 | |
| 43 /** | |
| 44 * Enum for HTML element ids. | |
| 45 * @enum {string} | |
| 46 * @const | |
| 47 */ | |
| 48 var IDS = { | |
| 49 ATTRIBUTION: 'attribution', | |
| 50 CURSOR: 'cursor', | |
| 51 FAKEBOX: 'fakebox', | |
| 52 LOGO: 'logo', | |
| 53 NOTIFICATION: 'mv-notice', | |
| 54 NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x', | |
| 55 NOTIFICATION_MESSAGE: 'mv-msg', | |
| 56 NTP_CONTENTS: 'ntp-contents', | |
| 57 RESTORE_ALL_LINK: 'mv-restore', | |
| 58 SUGGESTIONS_BOX: 'suggestions-box', | |
| 59 SUGGESTIONS_CONTAINER: 'suggestions-box-container', | |
| 60 TILES: 'mv-tiles', | |
| 61 TOP_MARGIN: 'mv-top-margin', | |
| 62 UNDO_LINK: 'mv-undo' | |
| 63 }; | |
| 64 | |
| 65 // ============================================================================= | |
| 66 // NTP implementation | |
| 67 // ============================================================================= | |
| 68 | |
| 6 /** | 69 /** |
| 7 * The element used to vertically position the most visited section on | 70 * The element used to vertically position the most visited section on |
| 8 * window resize. | 71 * window resize. |
| 9 * @type {Element} | 72 * @type {Element} |
| 10 */ | 73 */ |
| 11 var topMarginElement; | 74 var topMarginElement; |
| 12 | 75 |
| 13 /** | 76 /** |
| 14 * The container for the tile elements. | 77 * The container for the tile elements. |
| 15 * @type {Element} | 78 * @type {Element} |
| 16 */ | 79 */ |
| 17 var tilesContainer; | 80 var tilesContainer; |
| 18 | 81 |
| 19 /** | 82 /** |
| 20 * The notification displayed when a page is blacklisted. | 83 * The notification displayed when a page is blacklisted. |
| 21 * @type {Element} | 84 * @type {Element} |
| 22 */ | 85 */ |
| 23 var notification; | 86 var notification; |
| 24 | 87 |
| 25 /** | 88 /** |
| 26 * The container for the theme attribution. | 89 * The container for the theme attribution. |
| 27 * @type {Element} | 90 * @type {Element} |
| 28 */ | 91 */ |
| 29 var attribution; | 92 var attribution; |
| 30 | 93 |
| 31 /** | 94 /** |
| 95 * The "fakebox" - an input field that looks like a regular searchbox. When it | |
| 96 * is focused, any text the user types goes directly into the omnibox. | |
| 97 * @type {Element} | |
| 98 */ | |
| 99 var fakebox; | |
| 100 | |
| 101 /** | |
| 102 * The container for NTP elements that should be hidden when suggestions are | |
| 103 * visible. | |
| 104 * @type {Element} | |
| 105 */ | |
| 106 var ntpContents; | |
| 107 | |
| 108 /** | |
| 32 * The array of rendered tiles, ordered by appearance. | 109 * The array of rendered tiles, ordered by appearance. |
| 33 * @type {Array.<Tile>} | 110 * @type {Array.<Tile>} |
| 34 */ | 111 */ |
| 35 var tiles = []; | 112 var tiles = []; |
| 36 | 113 |
| 37 /** | 114 /** |
| 38 * The last blacklisted tile if any, which by definition should not be filler. | 115 * The last blacklisted tile if any, which by definition should not be filler. |
| 39 * @type {?Tile} | 116 * @type {?Tile} |
| 40 */ | 117 */ |
| 41 var lastBlacklistedTile = null; | 118 var lastBlacklistedTile = null; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 66 /** | 143 /** |
| 67 * Current number of tiles shown based on the window width, including filler. | 144 * Current number of tiles shown based on the window width, including filler. |
| 68 * @type {number} | 145 * @type {number} |
| 69 */ | 146 */ |
| 70 var numTilesShown = 0; | 147 var numTilesShown = 0; |
| 71 | 148 |
| 72 /** | 149 /** |
| 73 * The browser embeddedSearch.newTabPage object. | 150 * The browser embeddedSearch.newTabPage object. |
| 74 * @type {Object} | 151 * @type {Object} |
| 75 */ | 152 */ |
| 76 var apiHandle; | 153 var ntpApiHandle; |
| 77 | 154 |
| 78 /** | 155 /** |
| 79 * Possible background-colors of a non-custom theme. Used to determine whether | 156 * Possible background-colors of a non-custom theme. Used to determine whether |
| 80 * the homepage should be updated to support custom or non-custom themes. | 157 * the homepage should be updated to support custom or non-custom themes. |
| 81 * @type {!Array.<string>} | 158 * @type {!Array.<string>} |
| 82 * @const | 159 * @const |
| 83 */ | 160 */ |
| 84 var WHITE = ['rgba(255,255,255,1)', 'rgba(0,0,0,0)']; | 161 var WHITE = ['rgba(255,255,255,1)', 'rgba(0,0,0,0)']; |
| 85 | 162 |
| 86 /** | 163 /** |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 105 | 182 |
| 106 /** | 183 /** |
| 107 * Minimum total padding to give to the left and right of the most visited | 184 * Minimum total padding to give to the left and right of the most visited |
| 108 * section. Used to determine how many tiles to show. | 185 * section. Used to determine how many tiles to show. |
| 109 * @type {number} | 186 * @type {number} |
| 110 * @const | 187 * @const |
| 111 */ | 188 */ |
| 112 var MIN_TOTAL_HORIZONTAL_PADDING = 188; | 189 var MIN_TOTAL_HORIZONTAL_PADDING = 188; |
| 113 | 190 |
| 114 /** | 191 /** |
| 115 * Enum for classnames. | |
| 116 * @enum {string} | |
| 117 * @const | |
| 118 */ | |
| 119 var CLASSES = { | |
| 120 BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation | |
| 121 BLACKLIST_BUTTON: 'mv-x', | |
| 122 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', | |
| 123 DOMAIN: 'mv-domain', | |
| 124 FAVICON: 'mv-favicon', | |
| 125 FILLER: 'mv-filler', // filler tiles | |
| 126 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation | |
| 127 HIDE_NOTIFICATION: 'mv-notice-hide', | |
| 128 HIDE_TILE: 'mv-tile-hide', // hides tiles on small browser width | |
| 129 PAGE: 'mv-page', // page tiles | |
| 130 THUMBNAIL: 'mv-thumb', | |
| 131 TILE: 'mv-tile', | |
| 132 TITLE: 'mv-title' | |
| 133 }; | |
| 134 | |
| 135 /** | |
| 136 * Enum for HTML element ids. | |
| 137 * @enum {string} | |
| 138 * @const | |
| 139 */ | |
| 140 var IDS = { | |
| 141 ATTRIBUTION: 'attribution', | |
| 142 NOTIFICATION: 'mv-notice', | |
| 143 NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x', | |
| 144 NOTIFICATION_MESSAGE: 'mv-msg', | |
| 145 RESTORE_ALL_LINK: 'mv-restore', | |
| 146 TILES: 'mv-tiles', | |
| 147 TOP_MARGIN: 'mv-top-margin', | |
| 148 UNDO_LINK: 'mv-undo' | |
| 149 }; | |
| 150 | |
| 151 /** | |
| 152 * A Tile is either a rendering of a Most Visited page or "filler" used to | 192 * A Tile is either a rendering of a Most Visited page or "filler" used to |
| 153 * pad out the section when not enough pages exist. | 193 * pad out the section when not enough pages exist. |
| 154 * | 194 * |
| 155 * @param {Element} elem The element for rendering the tile. | 195 * @param {Element} elem The element for rendering the tile. |
| 156 * @param {number=} opt_rid The RID for the corresponding Most Visited page. | 196 * @param {number=} opt_rid The RID for the corresponding Most Visited page. |
| 157 * Should only be left unspecified when creating a filler tile. | 197 * Should only be left unspecified when creating a filler tile. |
| 158 * @constructor | 198 * @constructor |
| 159 */ | 199 */ |
| 160 function Tile(elem, opt_rid) { | 200 function Tile(elem, opt_rid) { |
| 161 /** @type {Element} */ | 201 /** @type {Element} */ |
| 162 this.elem = elem; | 202 this.elem = elem; |
| 163 | 203 |
| 164 /** @type {number|undefined} */ | 204 /** @type {number|undefined} */ |
| 165 this.rid = opt_rid; | 205 this.rid = opt_rid; |
| 166 } | 206 } |
| 167 | 207 |
| 168 /** | 208 /** |
| 169 * Updates the NTP based on the current theme. | 209 * Updates the NTP based on the current theme. |
| 170 * @private | 210 * @private |
| 171 */ | 211 */ |
| 172 function onThemeChange() { | 212 function onThemeChange() { |
| 173 var info = apiHandle.themeBackgroundInfo; | 213 if (!isNtpVisible()) |
| 214 return; | |
| 215 | |
| 216 var info = ntpApiHandle.themeBackgroundInfo; | |
| 174 if (!info) | 217 if (!info) |
| 175 return; | 218 return; |
| 176 var background = [info.colorRgba, | 219 var background = [info.colorRgba, |
| 177 info.imageUrl, | 220 info.imageUrl, |
| 178 info.imageTiling, | 221 info.imageTiling, |
| 179 info.imageHorizontalAlignment, | 222 info.imageHorizontalAlignment, |
| 180 info.imageVerticalAlignment].join(' ').trim(); | 223 info.imageVerticalAlignment].join(' ').trim(); |
| 181 document.body.style.background = background; | 224 document.body.style.background = background; |
| 182 var isCustom = !!background && WHITE.indexOf(background) == -1; | 225 var isCustom = !!background && WHITE.indexOf(background) == -1; |
| 183 document.body.classList.toggle('custom-theme', isCustom); | 226 document.body.classList.toggle('custom-theme', isCustom); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 206 attributionImage.onerror = function() { | 249 attributionImage.onerror = function() { |
| 207 attribution.hidden = true; | 250 attribution.hidden = true; |
| 208 }; | 251 }; |
| 209 attributionImage.src = url; | 252 attributionImage.src = url; |
| 210 } | 253 } |
| 211 | 254 |
| 212 /** | 255 /** |
| 213 * Handles a new set of Most Visited page data. | 256 * Handles a new set of Most Visited page data. |
| 214 */ | 257 */ |
| 215 function onMostVisitedChange() { | 258 function onMostVisitedChange() { |
| 216 var pages = apiHandle.mostVisited; | 259 var pages = ntpApiHandle.mostVisited; |
| 217 | 260 |
| 218 if (isBlacklisting) { | 261 if (isBlacklisting) { |
| 219 // If this was called as a result of a blacklist, add a new replacement | 262 // If this was called as a result of a blacklist, add a new replacement |
| 220 // (possibly filler) tile at the end and trigger the blacklist animation. | 263 // (possibly filler) tile at the end and trigger the blacklist animation. |
| 221 var replacementTile = createTile(pages[MAX_NUM_TILES_TO_SHOW - 1]); | 264 var replacementTile = createTile(pages[MAX_NUM_TILES_TO_SHOW - 1]); |
| 222 | 265 |
| 223 tiles.push(replacementTile); | 266 tiles.push(replacementTile); |
| 224 tilesContainer.appendChild(replacementTile.elem); | 267 tilesContainer.appendChild(replacementTile.elem); |
| 225 | 268 |
| 226 var lastBlacklistedTileElement = lastBlacklistedTile.elem; | 269 var lastBlacklistedTileElement = lastBlacklistedTile.elem; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 function createTile(page) { | 317 function createTile(page) { |
| 275 var tileElement = document.createElement('div'); | 318 var tileElement = document.createElement('div'); |
| 276 tileElement.classList.add(CLASSES.TILE); | 319 tileElement.classList.add(CLASSES.TILE); |
| 277 | 320 |
| 278 if (page) { | 321 if (page) { |
| 279 var rid = page.rid; | 322 var rid = page.rid; |
| 280 tileElement.classList.add(CLASSES.PAGE); | 323 tileElement.classList.add(CLASSES.PAGE); |
| 281 | 324 |
| 282 // The click handler for navigating to the page identified by the RID. | 325 // The click handler for navigating to the page identified by the RID. |
| 283 tileElement.addEventListener('click', function() { | 326 tileElement.addEventListener('click', function() { |
| 284 apiHandle.navigateContentWindow(rid); | 327 ntpApiHandle.navigateContentWindow(rid); |
| 285 }); | 328 }); |
| 286 | 329 |
| 287 // The shadow DOM which renders the page title. | 330 // The shadow DOM which renders the page title. |
| 288 var titleElement = page.titleElement; | 331 var titleElement = page.titleElement; |
| 289 if (titleElement) { | 332 if (titleElement) { |
| 290 titleElement.classList.add(CLASSES.TITLE); | 333 titleElement.classList.add(CLASSES.TITLE); |
| 291 tileElement.appendChild(titleElement); | 334 tileElement.appendChild(titleElement); |
| 292 } | 335 } |
| 293 | 336 |
| 294 // Render the thumbnail if present. Otherwise, fall back to a shadow DOM | 337 // Render the thumbnail if present. Otherwise, fall back to a shadow DOM |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 function generateBlacklistFunction(rid) { | 391 function generateBlacklistFunction(rid) { |
| 349 return function(e) { | 392 return function(e) { |
| 350 // Prevent navigation when the page is being blacklisted. | 393 // Prevent navigation when the page is being blacklisted. |
| 351 e.stopPropagation(); | 394 e.stopPropagation(); |
| 352 | 395 |
| 353 showNotification(); | 396 showNotification(); |
| 354 isBlacklisting = true; | 397 isBlacklisting = true; |
| 355 tilesContainer.classList.add(CLASSES.HIDE_BLACKLIST_BUTTON); | 398 tilesContainer.classList.add(CLASSES.HIDE_BLACKLIST_BUTTON); |
| 356 lastBlacklistedTile = getTileByRid(rid); | 399 lastBlacklistedTile = getTileByRid(rid); |
| 357 lastBlacklistedIndex = tiles.indexOf(lastBlacklistedTile); | 400 lastBlacklistedIndex = tiles.indexOf(lastBlacklistedTile); |
| 358 apiHandle.deleteMostVisitedItem(rid); | 401 ntpApiHandle.deleteMostVisitedItem(rid); |
| 359 }; | 402 }; |
| 360 } | 403 } |
| 361 | 404 |
| 362 /** | 405 /** |
| 363 * Shows the blacklist notification and triggers a delay to hide it. | 406 * Shows the blacklist notification and triggers a delay to hide it. |
| 364 */ | 407 */ |
| 365 function showNotification() { | 408 function showNotification() { |
| 366 notification.classList.remove(CLASSES.HIDE_NOTIFICATION); | 409 notification.classList.remove(CLASSES.HIDE_NOTIFICATION); |
| 367 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION); | 410 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION); |
| 368 notification.scrollTop; | 411 notification.scrollTop; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 391 | 434 |
| 392 /** | 435 /** |
| 393 * Handles a click on the notification undo link by hiding the notification and | 436 * Handles a click on the notification undo link by hiding the notification and |
| 394 * informing Chrome. | 437 * informing Chrome. |
| 395 */ | 438 */ |
| 396 function onUndo() { | 439 function onUndo() { |
| 397 hideNotification(); | 440 hideNotification(); |
| 398 var lastBlacklistedRID = lastBlacklistedTile.rid; | 441 var lastBlacklistedRID = lastBlacklistedTile.rid; |
| 399 if (typeof lastBlacklistedRID != 'undefined') { | 442 if (typeof lastBlacklistedRID != 'undefined') { |
| 400 isUndoing = true; | 443 isUndoing = true; |
| 401 apiHandle.undoMostVisitedDeletion(lastBlacklistedRID); | 444 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedRID); |
| 402 } | 445 } |
| 403 } | 446 } |
| 404 | 447 |
| 405 /** | 448 /** |
| 406 * Handles the end of the undo animation by removing the extraneous end tile. | 449 * Handles the end of the undo animation by removing the extraneous end tile. |
| 407 */ | 450 */ |
| 408 function undoAnimationDone() { | 451 function undoAnimationDone() { |
| 409 isUndoing = false; | 452 isUndoing = false; |
| 410 tiles.splice(tiles.length - 1, 1); | 453 tiles.splice(tiles.length - 1, 1); |
| 411 removeNode(tilesContainer.lastElementChild); | 454 removeNode(tilesContainer.lastElementChild); |
| 412 updateTileVisibility(numTilesShown); | 455 updateTileVisibility(numTilesShown); |
| 413 lastBlacklistedTile.elem.removeEventListener( | 456 lastBlacklistedTile.elem.removeEventListener( |
| 414 'webkitTransitionEnd', undoAnimationDone); | 457 'webkitTransitionEnd', undoAnimationDone); |
| 415 } | 458 } |
| 416 | 459 |
| 417 /** | 460 /** |
| 418 * Handles a click on the restore all notification link by hiding the | 461 * Handles a click on the restore all notification link by hiding the |
| 419 * notification and informing Chrome. | 462 * notification and informing Chrome. |
| 420 */ | 463 */ |
| 421 function onRestoreAll() { | 464 function onRestoreAll() { |
| 422 hideNotification(); | 465 hideNotification(); |
| 423 apiHandle.undoAllMostVisitedDeletions(); | 466 ntpApiHandle.undoAllMostVisitedDeletions(); |
| 424 } | 467 } |
| 425 | 468 |
| 426 /** | 469 /** |
| 427 * Handles a resize by vertically centering the most visited section | 470 * Handles a resize by vertically centering the most visited section |
| 428 * and triggering the tile show/hide animation if necessary. | 471 * and triggering the tile show/hide animation if necessary. |
| 429 */ | 472 */ |
| 430 function onResize() { | 473 function onResize() { |
| 431 var clientHeight = document.documentElement.clientHeight; | 474 // The Google page uses a fixed layout instead. |
| 432 topMarginElement.style.marginTop = | 475 if (!isGooglePage) { |
| 433 Math.max(0, (clientHeight - MOST_VISITED_HEIGHT) / 2) + 'px'; | 476 var clientHeight = document.documentElement.clientHeight; |
| 434 | 477 topMarginElement.style.marginTop = |
| 478 Math.max(0, (clientHeight - MOST_VISITED_HEIGHT) / 2) + 'px'; | |
| 479 } | |
| 435 var clientWidth = document.documentElement.clientWidth; | 480 var clientWidth = document.documentElement.clientWidth; |
| 436 var numTilesToShow = Math.floor( | 481 var numTilesToShow = Math.floor( |
| 437 (clientWidth - MIN_TOTAL_HORIZONTAL_PADDING) / TILE_WIDTH); | 482 (clientWidth - MIN_TOTAL_HORIZONTAL_PADDING) / TILE_WIDTH); |
| 438 numTilesToShow = Math.max(MIN_NUM_TILES_TO_SHOW, numTilesToShow); | 483 numTilesToShow = Math.max(MIN_NUM_TILES_TO_SHOW, numTilesToShow); |
| 439 if (numTilesToShow != numTilesShown) { | 484 if (numTilesToShow != numTilesShown) { |
| 440 updateTileVisibility(numTilesToShow); | 485 updateTileVisibility(numTilesToShow); |
| 441 numTilesShown = numTilesToShow; | 486 numTilesShown = numTilesToShow; |
| 442 } | 487 } |
| 443 } | 488 } |
| 444 | 489 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 461 function getTileByRid(rid) { | 506 function getTileByRid(rid) { |
| 462 for (var i = 0, length = tiles.length; i < length; ++i) { | 507 for (var i = 0, length = tiles.length; i < length; ++i) { |
| 463 var tile = tiles[i]; | 508 var tile = tiles[i]; |
| 464 if (tile.rid == rid) | 509 if (tile.rid == rid) |
| 465 return tile; | 510 return tile; |
| 466 } | 511 } |
| 467 return null; | 512 return null; |
| 468 } | 513 } |
| 469 | 514 |
| 470 /** | 515 /** |
| 516 * @param {boolean} visible True to show the NTP. | |
| 517 */ | |
| 518 function updateNtpVisibility(visible) { | |
| 519 if (visible && !isNtpVisible()) { | |
| 520 if (fakebox) { | |
| 521 // Stop any fakebox animation animation in progress and restore the NTP. | |
| 522 fakebox.removeEventListener('webkitTransitionEnd', fakeboxAnimationDone); | |
| 523 document.body.classList.remove(CLASSES.FAKEBOX_ANIMATE); | |
| 524 } | |
| 525 ntpContents.hidden = false; | |
| 526 onThemeChange(); | |
| 527 } else if (!visible && isNtpVisible()) { | |
| 528 if (fakebox && isFakeboxFocused()) { | |
| 529 // The user has typed in the fakebox - initiate the fakebox animation, | |
| 530 // which upon termination will hide the NTP. | |
| 531 document.body.classList.remove(CLASSES.FAKEBOX_FOCUS); | |
| 532 // Don't show the suggestions until the animation termintes. | |
| 533 $(IDS.SUGGESTIONS_CONTAINER).hidden = true; | |
| 534 fakebox.addEventListener('webkitTransitionEnd', fakeboxAnimationDone); | |
| 535 document.body.classList.add(CLASSES.FAKEBOX_ANIMATE); | |
| 536 } else if (!fakebox || | |
| 537 !document.body.classList.contains(CLASSES.FAKEBOX_ANIMATE)) { | |
| 538 // The user has typed in the omnibox - hide the NTP immediately. | |
| 539 ntpContents.hidden = true; | |
| 540 clearCustomTheme(); | |
| 541 } | |
| 542 } | |
|
Dan Beam
2013/04/17 23:28:58
needs moar \n's
jeremycho
2013/04/18 05:56:21
Done.
| |
| 543 } | |
| 544 | |
| 545 /** | |
| 546 * Clears the custom theme (if any). | |
| 547 */ | |
| 548 function clearCustomTheme() { | |
| 549 document.body.style.background = ''; | |
| 550 document.body.classList.remove('custom-theme'); | |
|
Dan Beam
2013/04/17 23:28:58
CLASSES.CUSTOM_THEME if you're gonna do this every
jeremycho
2013/04/18 05:56:21
Done.
| |
| 551 } | |
| 552 | |
| 553 /** | |
| 554 * @return {boolean} True if the NTP is visible. | |
| 555 */ | |
| 556 function isNtpVisible() { | |
| 557 return !ntpContents.hidden; | |
| 558 } | |
| 559 | |
| 560 /** | |
| 561 * @return {boolean} True if the fakebox has focus. | |
| 562 */ | |
| 563 function isFakeboxFocused() { | |
| 564 return document.body.classList.contains(CLASSES.FAKEBOX_FOCUS); | |
| 565 } | |
| 566 | |
| 567 /** | |
| 568 * @param {Event} event The click event. | |
| 569 * @return {boolean} True if the click occurred in the fakebox. | |
| 570 */ | |
| 571 function isFakeboxClick(event) { | |
|
Dan Beam
2013/04/17 23:28:58
return fakebox.contains(event.target);
jeremycho
2013/04/18 05:56:21
That didn't work - I believe because of the input
Dan Beam
2013/04/18 20:05:14
I don't understand a) why it wouldn't work, and b)
jeremycho
2013/04/18 20:26:18
Sorry, it does actually work (I was trying it over
| |
| 572 var element = event.target; | |
| 573 while (element) { | |
| 574 if (element == fakebox) | |
| 575 return true; | |
| 576 element = element.parentNode; | |
| 577 } | |
| 578 return false; | |
| 579 } | |
| 580 | |
| 581 /** | |
| 582 * Cleans up the fakebox animation, hides the NTP, and shows suggestions. | |
| 583 */ | |
| 584 function fakeboxAnimationDone() { | |
|
Dan Beam
2013/04/17 23:28:58
do you need to check the target or the property th
jeremycho
2013/04/18 05:56:21
Done.
| |
| 585 ntpContents.hidden = true; | |
| 586 $(IDS.SUGGESTIONS_CONTAINER).hidden = false; | |
| 587 clearCustomTheme(); | |
| 588 document.body.classList.remove(CLASSES.FAKEBOX_ANIMATE); | |
| 589 fakebox.removeEventListener('webkitTransitionEnd', fakeboxAnimationDone); | |
| 590 } | |
| 591 | |
| 592 // ============================================================================= | |
| 593 // Dropdown Implementation | |
| 594 // ============================================================================= | |
| 595 | |
| 596 /** | |
| 597 * Possible behaviors for navigateContentWindow. | |
| 598 * @enum {number} | |
| 599 */ | |
| 600 var WindowOpenDisposition = { | |
| 601 CURRENT_TAB: 1, | |
| 602 NEW_BACKGROUND_TAB: 2 | |
| 603 }; | |
| 604 | |
| 605 /** | |
| 606 * The JavaScript button event value for a middle click. | |
| 607 * @type {number} | |
| 608 * @const | |
| 609 */ | |
| 610 var MIDDLE_MOUSE_BUTTON = 1; | |
| 611 | |
| 612 /** | |
| 613 * The maximum number of suggestions to show. | |
| 614 * @type {number} | |
| 615 * @const | |
| 616 */ | |
| 617 var MAX_SUGGESTIONS_TO_SHOW = 5; | |
| 618 | |
| 619 /** | |
| 620 * Assume any native suggestion with a score higher than this value has been | |
| 621 * inlined by the browser. | |
| 622 * @type {number} | |
| 623 * @const | |
| 624 */ | |
| 625 var INLINE_SUGGESTION_THRESHOLD = 1200; | |
| 626 | |
| 627 /** | |
| 628 * Suggestion provider type corresponding to a verbatim URL suggestion. | |
| 629 * @type {string} | |
| 630 * @const | |
| 631 */ | |
| 632 var VERBATIM_URL_TYPE = 'url-what-you-typed'; | |
| 633 | |
| 634 /** | |
| 635 * Suggestion provider type corresponding to a verbatim search suggestion. | |
| 636 * @type {string} | |
| 637 * @const | |
| 638 */ | |
| 639 var VERBATIM_SEARCH_TYPE = 'search-what-you-typed'; | |
| 640 | |
| 641 /** | |
| 642 * The omnibox input value during the last onnativesuggestions event. | |
| 643 * @type {string} | |
| 644 */ | |
| 645 var lastInputValue = ''; | |
| 646 | |
| 647 /** | |
| 648 * The ordered restricted ids of the currently displayed suggestions. Since the | |
| 649 * suggestions contain the user's personal data (browser history) the searchBox | |
| 650 * API embeds the content of the suggestion in a shadow dom, and assigns a | |
| 651 * random restricted id to each suggestion which is accessible to the JS. | |
| 652 * @type {Array.<number>} | |
|
Dan Beam
2013/04/17 23:28:58
!Array
jeremycho
2013/04/18 05:56:21
Done.
| |
| 653 */ | |
| 654 | |
| 655 var restrictedIds = []; | |
| 656 | |
| 657 /** | |
| 658 * The index of the currently selected suggestion or -1 if none are selected. | |
| 659 * @type {number} | |
| 660 */ | |
| 661 var selectedIndex = -1; | |
| 662 | |
| 663 /** | |
| 664 * The browser embeddedSearch.searchBox object. | |
| 665 * @type {Object} | |
| 666 */ | |
| 667 var searchboxApiHandle; | |
| 668 | |
| 669 /** | |
| 670 * Displays a suggestion. | |
| 671 * @param {Object} suggestion The suggestion to render. | |
| 672 * @param {HTMLElement} box The html element to add the suggestion to. | |
| 673 * @param {boolean} select True to select the selection. | |
| 674 */ | |
| 675 function addSuggestionToBox(suggestion, box, select) { | |
| 676 var suggestionDiv = document.createElement('div'); | |
| 677 suggestionDiv.classList.add('suggestion'); | |
| 678 suggestionDiv.classList.toggle('selected', select); | |
| 679 suggestionDiv.classList.toggle('search', suggestion.is_search); | |
| 680 | |
| 681 if (suggestion.destination_url) { // iframes. | |
| 682 var suggestionIframe = document.createElement('iframe'); | |
| 683 suggestionIframe.className = 'contents'; | |
| 684 suggestionIframe.src = suggestion.destination_url; | |
| 685 suggestionIframe.id = suggestion.rid; | |
| 686 suggestionDiv.appendChild(suggestionIframe); | |
| 687 } else { | |
| 688 var contentsContainer = document.createElement('div'); | |
| 689 var contents = suggestion.combinedNode; | |
| 690 contents.classList.add('contents'); | |
| 691 contentsContainer.appendChild(contents); | |
| 692 suggestionDiv.appendChild(contentsContainer); | |
| 693 suggestionDiv.onclick = function(event) { | |
| 694 handleSuggestionClick(suggestion.rid, event.button); | |
| 695 }; | |
| 696 } | |
| 697 | |
| 698 restrictedIds.push(suggestion.rid); | |
| 699 box.appendChild(suggestionDiv); | |
| 700 } | |
| 701 | |
| 702 /** | |
| 703 * Renders the input suggestions. | |
| 704 * @param {Array} nativeSuggestions An array of native suggestions to render. | |
|
Dan Beam
2013/04/17 23:28:58
!Array
jeremycho
2013/04/18 05:56:21
Done.
| |
| 705 */ | |
| 706 function renderSuggestions(nativeSuggestions) { | |
| 707 for (var i = 0, length = nativeSuggestions.length; | |
| 708 i < Math.min(MAX_SUGGESTIONS_TO_SHOW, length); ++i) { | |
| 709 // Don't add the search-what-you-typed suggestion if it's the top match. | |
| 710 if (i > 0 || nativeSuggestions[i].type != VERBATIM_SEARCH_TYPE) { | |
| 711 var box = $(IDS.SUGGESTIONS_BOX); | |
| 712 if (!box) { | |
| 713 box = document.createElement('div'); | |
| 714 box.id = IDS.SUGGESTIONS_BOX; | |
| 715 $(IDS.SUGGESTIONS_CONTAINER).appendChild(box); | |
| 716 } | |
| 717 addSuggestionToBox(nativeSuggestions[i], box, i == selectedIndex); | |
| 718 } | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 /** | |
| 723 * Clears the suggestions being displayed. | |
| 724 */ | |
| 725 function clearSuggestions() { | |
| 726 $(IDS.SUGGESTIONS_CONTAINER).innerHTML = ''; | |
| 727 restrictedIds = []; | |
| 728 selectedIndex = -1; | |
| 729 } | |
| 730 | |
| 731 /** | |
| 732 * @return {number} The height of the dropdown. | |
| 733 */ | |
| 734 function getDropdownHeight() { | |
| 735 return $(IDS.SUGGESTIONS_CONTAINER).offsetHeight; | |
| 736 } | |
| 737 | |
| 738 /** | |
| 739 * @param {Object} suggestion A suggestion. | |
|
Dan Beam
2013/04/17 23:28:58
!Object
jeremycho
2013/04/18 05:56:21
Done.
| |
| 740 * @param {boolean} inVerbatimMode Are we in verbatim mode? | |
| 741 * @return {boolean} True if the suggestion should be selected. | |
| 742 */ | |
| 743 function shouldSelectSuggestion(suggestion, inVerbatimMode) { | |
| 744 var isVerbatimUrl = suggestion.type == VERBATIM_URL_TYPE; | |
| 745 var inlinableSuggestion = suggestion.type != VERBATIM_SEARCH_TYPE && | |
| 746 suggestion.rankingData.relevance > INLINE_SUGGESTION_THRESHOLD; | |
| 747 // Verbatim URLs should always be selected. Otherwise, select suggestions | |
| 748 // with a high enough score unless we are in verbatim mode (e.g. backspacing | |
| 749 // away). | |
| 750 return isVerbatimUrl || (!inVerbatimMode && inlinableSuggestion); | |
| 751 } | |
| 752 | |
| 753 /** | |
| 754 * Updates selectedIndex, bounding it between -1 and the total number of | |
| 755 * of suggestions - 1 (looping as necessary), and selects the corresponding | |
| 756 * suggestion. | |
| 757 * @param {boolean} increment True to increment the selected suggestion, false | |
| 758 * to decrement. | |
| 759 */ | |
| 760 function updateSelectedSuggestion(increment) { | |
| 761 var numSuggestions = restrictedIds.length; | |
| 762 if (!numSuggestions) | |
| 763 return; | |
| 764 | |
| 765 var oldSelection = $(IDS.SUGGESTIONS_BOX).querySelector('.selected'); | |
| 766 if (oldSelection) | |
| 767 oldSelection.classList.remove('selected'); | |
| 768 | |
| 769 if (increment) | |
| 770 selectedIndex = ++selectedIndex > numSuggestions - 1 ? -1 : selectedIndex; | |
| 771 else | |
| 772 selectedIndex = --selectedIndex < -1 ? numSuggestions - 1 : selectedIndex; | |
|
Dan Beam
2013/04/17 23:28:58
nit: this is clearer, IMO
if (increment) {
if (
jeremycho
2013/04/18 05:56:21
Done.
| |
| 773 if (selectedIndex == -1) { | |
| 774 searchboxApiHandle.setValue(lastInputValue); | |
| 775 } else { | |
| 776 var newSelection = $(IDS.SUGGESTIONS_BOX).querySelector( | |
| 777 '.suggestion:nth-of-type(' + (selectedIndex + 1) + ')'); | |
| 778 newSelection.classList.add('selected'); | |
|
Dan Beam
2013/04/17 23:28:58
nit: CLASSES.SELECTED
jeremycho
2013/04/18 05:56:21
Done.
| |
| 779 searchboxApiHandle.setRestrictedValue(restrictedIds[selectedIndex]); | |
| 780 } | |
| 781 } | |
| 782 | |
| 783 /** | |
| 784 * Updates suggestions in response to a onchange or onnativesuggestions call. | |
| 785 */ | |
| 786 function updateSuggestions() { | |
| 787 appendSuggestionStyles(); | |
| 788 lastInputValue = searchboxApiHandle.value; | |
| 789 | |
| 790 // Hide the NTP if input has made it into the omnibox. | |
| 791 var show = lastInputValue == ''; | |
| 792 updateNtpVisibility(show); | |
| 793 | |
| 794 clearSuggestions(); | |
| 795 if (show) { | |
| 796 searchboxApiHandle.showBars(); | |
| 797 return; | |
| 798 } | |
| 799 | |
| 800 var nativeSuggestions = searchboxApiHandle.nativeSuggestions; | |
| 801 if (nativeSuggestions.length) { | |
| 802 nativeSuggestions.sort(function(a, b) { | |
| 803 return b.rankingData.relevance - a.rankingData.relevance; | |
| 804 }); | |
| 805 if (shouldSelectSuggestion( | |
| 806 nativeSuggestions[0], searchboxApiHandle.verbatim)) | |
|
Dan Beam
2013/04/17 23:28:58
if (shouldSelectSuggestion(
nativeSuggesti
jeremycho
2013/04/18 05:56:21
Done.
| |
| 807 selectedIndex = 0; | |
| 808 renderSuggestions(nativeSuggestions); | |
| 809 searchboxApiHandle.hideBars(); | |
| 810 } else { | |
| 811 searchboxApiHandle.showBars(); | |
| 812 } | |
| 813 | |
| 814 var height = getDropdownHeight(); | |
| 815 searchboxApiHandle.showOverlay(height); | |
| 816 } | |
| 817 | |
| 818 /** | |
| 819 * Appends a style node for suggestion properties that depend on apiHandle. | |
| 820 */ | |
| 821 function appendSuggestionStyles() { | |
| 822 if ($('suggestionStyle')) | |
|
Dan Beam
2013/04/17 23:28:58
IDS.SUGGESTION_STYLE
jeremycho
2013/04/18 05:56:21
Done.
| |
| 823 return; | |
| 824 | |
| 825 var isRtl = searchboxApiHandle.rtl; | |
| 826 var startMargin = searchboxApiHandle.startMargin; | |
| 827 var style = document.createElement('style'); | |
| 828 style.type = 'text/css'; | |
| 829 style.id = 'suggestionStyle'; | |
|
Dan Beam
2013/04/17 23:28:58
suggestion-style
jeremycho
2013/04/18 05:56:21
Done.
| |
| 830 style.textContent = | |
| 831 '.suggestion, ' + | |
| 832 '.suggestion.search {' + | |
| 833 ' background-position: ' + | |
| 834 (isRtl ? '-webkit-calc(100% - 5px)' : '5px') + ' 4px;' + | |
| 835 ' -webkit-margin-start: ' + startMargin + 'px;' + | |
| 836 ' -webkit-margin-end: ' + | |
| 837 (window.innerWidth - searchboxApiHandle.width - startMargin) + 'px;' + | |
| 838 ' font: ' + searchboxApiHandle.fontSize + 'px "' + | |
| 839 searchboxApiHandle.font + '";' + | |
| 840 '}'; | |
| 841 document.querySelector('head').appendChild(style); | |
| 842 } | |
| 843 | |
| 844 /** | |
| 845 * Extract the desired navigation behavior from a click button. | |
| 846 * @param {number} button The Event#button property of a click event. | |
| 847 * @return {WindowOpenDisposition} The desired behavior for | |
|
Dan Beam
2013/04/17 23:28:58
!WindowOpenDisposition
jeremycho
2013/04/18 05:56:21
Done.
| |
| 848 * navigateContentWindow. | |
| 849 */ | |
| 850 function getDispositionFromClickButton(button) { | |
| 851 if (button == MIDDLE_MOUSE_BUTTON) | |
| 852 return WindowOpenDisposition.NEW_BACKGROUND_TAB; | |
| 853 return WindowOpenDisposition.CURRENT_TAB; | |
| 854 } | |
| 855 | |
| 856 /** | |
| 857 * Handles suggestion clicks. | |
| 858 * @param {number} restrictedId The restricted id of the suggestion being | |
| 859 * clicked. | |
| 860 * @param {number} button The Event#button property of a click event. | |
| 861 * | |
| 862 */ | |
| 863 function handleSuggestionClick(restrictedId, button) { | |
| 864 clearSuggestions(); | |
| 865 searchboxApiHandle.navigateContentWindow( | |
| 866 restrictedId, getDispositionFromClickButton(button)); | |
| 867 } | |
| 868 | |
| 869 /** | |
| 870 * chrome.searchBox.onkeypress implementation. | |
| 871 * @param {Object} e The key being pressed. | |
|
Dan Beam
2013/04/17 23:28:58
s/Object/!Event/
jeremycho
2013/04/18 05:56:21
Done.
| |
| 872 */ | |
| 873 function handleKeyPress(e) { | |
| 874 switch (e.keyCode) { | |
| 875 case 38: // Up arrow | |
|
Dan Beam
2013/04/17 23:28:58
nit: end with .
jeremycho
2013/04/18 05:56:21
Done.
| |
| 876 updateSelectedSuggestion(false); | |
| 877 break; | |
| 878 case 40: // Down arrow | |
|
Dan Beam
2013/04/17 23:28:58
same
jeremycho
2013/04/18 05:56:21
Done.
| |
| 879 updateSelectedSuggestion(true); | |
| 880 break; | |
| 881 } | |
| 882 } | |
| 883 | |
| 884 /** | |
| 885 * Handles the postMessage calls from the result iframes. | |
| 886 * @param {Object} message The message containing details of clicks the iframes. | |
| 887 */ | |
| 888 function handleMessage(message) { | |
| 889 if (message.origin != 'null' || !message.data || | |
| 890 message.data.eventType != 'click') { | |
| 891 return; | |
| 892 } | |
| 893 | |
| 894 var iframes = document.getElementsByClassName('contents'); | |
| 895 for (var i = 0; i < iframes.length; ++i) { | |
| 896 if (iframes[i].contentWindow == message.source) { | |
| 897 handleSuggestionClick(parseInt(iframes[i].id, 10), | |
| 898 message.data.button); | |
| 899 break; | |
| 900 } | |
| 901 } | |
| 902 } | |
| 903 | |
| 904 // ============================================================================= | |
| 905 // Utils | |
| 906 // ============================================================================= | |
| 907 | |
| 908 /** | |
| 909 * Shortcut for document.getElementById. | |
| 910 * @param {string} id of the element. | |
| 911 * @return {HTMLElement} with the id. | |
| 912 */ | |
| 913 function $(id) { | |
| 914 return document.getElementById(id); | |
| 915 } | |
| 916 | |
| 917 /** | |
| 471 * Utility function which creates an element with an optional classname and | 918 * Utility function which creates an element with an optional classname and |
| 472 * appends it to the specified parent. | 919 * appends it to the specified parent. |
| 473 * @param {Element} parent The parent to append the new element. | 920 * @param {Element} parent The parent to append the new element. |
| 474 * @param {string} name The name of the new element. | 921 * @param {string} name The name of the new element. |
| 475 * @param {string=} opt_class The optional classname of the new element. | 922 * @param {string=} opt_class The optional classname of the new element. |
| 476 * @return {Element} The new element. | 923 * @return {Element} The new element. |
| 477 */ | 924 */ |
| 478 function createAndAppendElement(parent, name, opt_class) { | 925 function createAndAppendElement(parent, name, opt_class) { |
| 479 var child = document.createElement(name); | 926 var child = document.createElement(name); |
| 480 if (opt_class) | 927 if (opt_class) |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 503 * @return {Object} the handle to the embeddedSearch API. | 950 * @return {Object} the handle to the embeddedSearch API. |
| 504 */ | 951 */ |
| 505 function getEmbeddedSearchApiHandle() { | 952 function getEmbeddedSearchApiHandle() { |
| 506 if (window.cideb) | 953 if (window.cideb) |
| 507 return window.cideb; | 954 return window.cideb; |
| 508 if (window.chrome && window.chrome.embeddedSearch) | 955 if (window.chrome && window.chrome.embeddedSearch) |
| 509 return window.chrome.embeddedSearch; | 956 return window.chrome.embeddedSearch; |
| 510 return null; | 957 return null; |
| 511 } | 958 } |
| 512 | 959 |
| 960 // ============================================================================= | |
| 961 // Initialization | |
| 962 // ============================================================================= | |
| 963 | |
| 513 /** | 964 /** |
| 514 * Prepares the New Tab Page by adding listeners, rendering the current | 965 * Prepares the New Tab Page by adding listeners, rendering the current |
| 515 * theme, and the most visited pages section. | 966 * theme, the most visited pages section, and Google-specific elements for a |
| 967 * Google-provided page. | |
| 516 */ | 968 */ |
| 517 function init() { | 969 function init() { |
| 518 topMarginElement = document.getElementById(IDS.TOP_MARGIN); | 970 topMarginElement = $(IDS.TOP_MARGIN); |
| 519 tilesContainer = document.getElementById(IDS.TILES); | 971 tilesContainer = $(IDS.TILES); |
| 520 notification = document.getElementById(IDS.NOTIFICATION); | 972 notification = $(IDS.NOTIFICATION); |
| 521 attribution = document.getElementById(IDS.ATTRIBUTION); | 973 attribution = $(IDS.ATTRIBUTION); |
| 974 ntpContents = $(IDS.NTP_CONTENTS); | |
| 975 | |
| 976 if (isGooglePage) { | |
| 977 document.body.classList.add(CLASSES.GOOGLE_PAGE); | |
| 978 var logo = document.createElement('div'); | |
| 979 logo.id = IDS.LOGO; | |
| 980 | |
| 981 fakebox = document.createElement('div'); | |
| 982 fakebox.id = IDS.FAKEBOX; | |
| 983 fakebox.innerHTML = | |
| 984 '<input autocomplete="off" tabindex="-1" aria-hidden="true">' + | |
| 985 '<div id=cursor></div>'; | |
| 986 | |
| 987 ntpContents.insertBefore(fakebox, ntpContents.firstChild); | |
| 988 ntpContents.insertBefore(logo, ntpContents.firstChild); | |
| 989 } | |
| 990 | |
| 522 | 991 |
| 523 // TODO(jeremycho): i18n. | 992 // TODO(jeremycho): i18n. |
| 524 var notificationMessage = document.getElementById(IDS.NOTIFICATION_MESSAGE); | 993 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); |
| 525 notificationMessage.innerText = 'Thumbnail removed.'; | 994 notificationMessage.innerText = 'Thumbnail removed.'; |
| 526 var undoLink = document.getElementById(IDS.UNDO_LINK); | 995 var undoLink = $(IDS.UNDO_LINK); |
| 527 undoLink.addEventListener('click', onUndo); | 996 undoLink.addEventListener('click', onUndo); |
| 528 undoLink.innerText = 'Undo'; | 997 undoLink.innerText = 'Undo'; |
| 529 var restoreAllLink = document.getElementById(IDS.RESTORE_ALL_LINK); | 998 var restoreAllLink = $(IDS.RESTORE_ALL_LINK); |
| 530 restoreAllLink.addEventListener('click', onRestoreAll); | 999 restoreAllLink.addEventListener('click', onRestoreAll); |
| 531 restoreAllLink.innerText = 'Restore all'; | 1000 restoreAllLink.innerText = 'Restore all'; |
| 532 attribution.innerText = 'Theme created by'; | 1001 attribution.innerText = 'Theme created by'; |
| 533 | 1002 |
| 534 var notificationCloseButton = | 1003 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON); |
| 535 document.getElementById(IDS.NOTIFICATION_CLOSE_BUTTON); | |
| 536 notificationCloseButton.addEventListener('click', hideNotification); | 1004 notificationCloseButton.addEventListener('click', hideNotification); |
| 537 | 1005 |
| 538 window.addEventListener('resize', onResize); | 1006 window.addEventListener('resize', onResize); |
| 539 onResize(); | 1007 onResize(); |
| 540 | 1008 |
| 541 var topLevelHandle = getEmbeddedSearchApiHandle(); | 1009 var topLevelHandle = getEmbeddedSearchApiHandle(); |
| 542 // This is to inform Chrome that the NTP is instant-extended capable i.e. | |
| 543 // it should fire events like onmostvisitedchange. | |
| 544 topLevelHandle.searchBox.onsubmit = function() {}; | |
| 545 | 1010 |
| 546 apiHandle = topLevelHandle.newTabPage; | 1011 ntpApiHandle = topLevelHandle.newTabPage; |
| 547 apiHandle.onthemechange = onThemeChange; | 1012 ntpApiHandle.onthemechange = onThemeChange; |
| 548 apiHandle.onmostvisitedchange = onMostVisitedChange; | 1013 ntpApiHandle.onmostvisitedchange = onMostVisitedChange; |
| 549 | 1014 |
| 550 onThemeChange(); | 1015 onThemeChange(); |
| 551 onMostVisitedChange(); | 1016 onMostVisitedChange(); |
| 1017 | |
| 1018 searchboxApiHandle = topLevelHandle.searchBox; | |
| 1019 searchboxApiHandle.onnativesuggestions = updateSuggestions; | |
| 1020 searchboxApiHandle.onchange = updateSuggestions; | |
| 1021 searchboxApiHandle.onkeypress = handleKeyPress; | |
| 1022 searchboxApiHandle.onsubmit = function() { | |
| 1023 var value = searchboxApiHandle.value; | |
| 1024 if (!value) { | |
| 1025 // Interpret onsubmit with an empty query as an ESC key press. | |
| 1026 clearSuggestions(); | |
| 1027 updateNtpVisibility(true); | |
| 1028 } | |
| 1029 }; | |
| 1030 | |
| 1031 $(IDS.SUGGESTIONS_CONTAINER).dir = searchboxApiHandle.rtl ? 'rtl' : 'ltr'; | |
| 1032 if (searchboxApiHandle.nativeSuggestions.length) | |
| 1033 updateSuggestions(); | |
| 1034 | |
| 1035 if (!document.webkitHidden) | |
| 1036 window.addEventListener('resize', addDelayedTransitions); | |
| 1037 else | |
| 1038 document.addEventListener('webkitvisibilitychange', addDelayedTransitions); | |
| 1039 | |
|
Dan Beam
2013/04/17 23:28:58
^H
jeremycho
2013/04/18 05:56:21
Done.
| |
| 1040 | |
| 1041 if (fakebox) { | |
| 1042 // Listener for updating the fakebox focus. | |
| 1043 document.body.onclick = function(event) { | |
| 1044 if (isFakeboxClick(event)) { | |
| 1045 document.body.classList.add(CLASSES.FAKEBOX_FOCUS); | |
| 1046 searchboxApiHandle.startCapturingKeyStrokes(); | |
| 1047 } else { | |
| 1048 document.body.classList.remove(CLASSES.FAKEBOX_FOCUS); | |
| 1049 searchboxApiHandle.stopCapturingKeyStrokes(); | |
| 1050 } | |
| 1051 }; | |
| 1052 | |
| 1053 // Set the cursor alignment based on language directionality. | |
| 1054 $(IDS.CURSOR).style[searchboxApiHandle.rtl ? 'right' : 'left'] = '9px'; | |
| 1055 } | |
| 1056 } | |
| 1057 | |
| 1058 /** | |
| 1059 * Applies webkit transitions to NTP elements which need to be delayed until | |
| 1060 * after the page is made visible and any initial resize has occurred. This is | |
| 1061 * to prevent animations from triggering when the NTP is shown. | |
| 1062 */ | |
| 1063 function addDelayedTransitions() { | |
|
Dan Beam
2013/04/17 23:28:58
can document.webkitHidden still be true here?
jeremycho
2013/04/18 05:56:21
No - webkitvisibilitychange from a hidden state im
| |
| 1064 if (fakebox) { | |
| 1065 fakebox.style.webkitTransition = | |
| 1066 '-webkit-transform 100ms linear, width 200ms ease'; | |
| 1067 } | |
|
Dan Beam
2013/04/17 23:28:58
\n
jeremycho
2013/04/18 05:56:21
Done.
| |
| 1068 tilesContainer.style.webkitTransition = 'width 200ms'; | |
| 1069 window.removeEventListener('resize', addDelayedTransitions); | |
| 1070 document.removeEventListener('webkitvisibilitychange', addDelayedTransitions); | |
| 552 } | 1071 } |
| 553 | 1072 |
| 554 document.addEventListener('DOMContentLoaded', init); | 1073 document.addEventListener('DOMContentLoaded', init); |
| 1074 window.addEventListener('message', handleMessage, false); | |
| 555 })(); | 1075 })(); |
| OLD | NEW |