| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // To avoid creating tons of unnecessary nodes. We assume we cannot fit more | 5 // To avoid creating tons of unnecessary nodes. We assume we cannot fit more |
| 6 // than this many items in the miniview. | 6 // than this many items in the miniview. |
| 7 var MAX_MINIVIEW_ITEMS = 15; | 7 var MAX_MINIVIEW_ITEMS = 15; |
| 8 | 8 |
| 9 // Extra spacing at the top of the layout. | 9 // Extra spacing at the top of the layout. |
| 10 var LAYOUT_SPACING_TOP = 25; | 10 var LAYOUT_SPACING_TOP = 25; |
| 11 | 11 |
| 12 function getSectionCloseButton(sectionId) { |
| 13 return document.querySelector('#' + sectionId + ' .section-close-button'); |
| 14 } |
| 15 |
| 16 function getSectionMenuButton(sectionId) { |
| 17 return $(sectionId + '-button'); |
| 18 } |
| 19 |
| 20 function getSectionMenuButtonTextId(sectionId) { |
| 21 return sectionId.replace(/-/g, ''); |
| 22 } |
| 23 |
| 24 function setSectionVisible(sectionId, section, visible, hideMask) { |
| 25 if (visible && !(shownSections & hideMask) || |
| 26 !visible && (shownSections & hideMask)) |
| 27 return; |
| 28 |
| 29 if (visible) { |
| 30 // Because sections are collapsed when they are minimized, it is not |
| 31 // necessary to restore the maxiview here. It will happen if the section |
| 32 // header is clicked. |
| 33 var el = $(sectionId); |
| 34 el.classList.remove('disabled'); |
| 35 el = getSectionMenuButton(sectionId); |
| 36 el.classList.add('disabled'); |
| 37 shownSections &= ~hideMask; |
| 38 } else { |
| 39 if (section) { |
| 40 hideSection(section); // To hide the maxiview. |
| 41 } |
| 42 var el = $(sectionId); |
| 43 el.classList.add('disabled'); |
| 44 el = getSectionMenuButton(sectionId); |
| 45 el.classList.remove('disabled'); |
| 46 shownSections |= hideMask; |
| 47 } |
| 48 layoutSections(); |
| 49 } |
| 50 |
| 51 function clearClosedMenu(menu) { |
| 52 menu.innerHTML = ''; |
| 53 } |
| 54 |
| 55 function addClosedMenuEntryWithLink(menu, a) { |
| 56 var span = document.createElement('span'); |
| 57 a.className += ' item menuitem'; |
| 58 span.appendChild(a); |
| 59 menu.appendChild(span); |
| 60 } |
| 61 |
| 62 function addClosedMenuEntry(menu, url, title, imageUrl) { |
| 63 var a = document.createElement('a'); |
| 64 a.href = url; |
| 65 a.textContent = title; |
| 66 a.style.backgroundImage = 'url(' + imageUrl + ')'; |
| 67 addClosedMenuEntryWithLink(menu, a); |
| 68 } |
| 69 |
| 70 function addClosedMenuFooter(menu, sectionId, mask, opt_section) { |
| 71 menu.appendChild(document.createElement('hr')); |
| 72 |
| 73 var span = document.createElement('span'); |
| 74 var a = span.appendChild(document.createElement('a')); |
| 75 a.href = ''; |
| 76 a.textContent = |
| 77 localStrings.getString(getSectionMenuButtonTextId(sectionId)); |
| 78 a.className = 'item'; |
| 79 a.addEventListener( |
| 80 'click', |
| 81 function(e) { |
| 82 getSectionMenuButton(sectionId).hideMenu(); |
| 83 e.preventDefault(); |
| 84 setSectionVisible(sectionId, opt_section, true, mask); |
| 85 shownSections &= ~mask; |
| 86 saveShownSections(); |
| 87 }); |
| 88 menu.appendChild(span); |
| 89 } |
| 90 |
| 91 function initializeSection(sectionId, mask, opt_section) { |
| 92 var button = getSectionCloseButton(sectionId); |
| 93 button.addEventListener( |
| 94 'click', |
| 95 function() { |
| 96 setSectionVisible(sectionId, opt_section, false, mask); |
| 97 saveShownSections(); |
| 98 }); |
| 99 } |
| 100 |
| 12 function updateSimpleSection(id, section) { | 101 function updateSimpleSection(id, section) { |
| 13 var elm = $(id); | 102 var elm = $(id); |
| 14 var maxiview = getSectionMaxiview(elm); | 103 var maxiview = getSectionMaxiview(elm); |
| 15 if (shownSections & section) { | 104 if (shownSections & section) { |
| 16 $(id).classList.remove('hidden'); | 105 $(id).classList.remove('hidden'); |
| 17 if (maxiview) | 106 if (maxiview) |
| 18 maxiview.classList.remove('hidden'); | 107 maxiview.classList.remove('hidden'); |
| 19 } else { | 108 } else { |
| 20 $(id).classList.add('hidden'); | 109 $(id).classList.add('hidden'); |
| 21 if (maxiview) | 110 if (maxiview) |
| 22 maxiview.classList.add('hidden'); | 111 maxiview.classList.add('hidden'); |
| 23 } | 112 } |
| 24 } | 113 } |
| 25 | 114 |
| 26 function recentlyClosedTabs(data) { | 115 function recentlyClosedTabs(data) { |
| 27 logEvent('received recently closed tabs'); | 116 logEvent('received recently closed tabs'); |
| 28 // We need to store the recent items so we can update the layout on a resize. | 117 // We need to store the recent items so we can update the layout on a resize. |
| 29 recentItems = data; | 118 recentItems = data; |
| 30 renderRecentlyClosed(); | 119 renderRecentlyClosed(); |
| 31 layoutSections(); | 120 layoutSections(); |
| 32 } | 121 } |
| 33 | 122 |
| 34 var recentItems = []; | 123 var recentItems = []; |
| 35 | 124 |
| 36 function renderRecentlyClosed() { | 125 function renderRecentlyClosed() { |
| 37 // Remove all existing items and create new items. | 126 // Remove all existing items and create new items. |
| 38 var recentElement = $('recently-closed'); | 127 var recentElement = $('recently-closed'); |
| 39 var parentEl = recentElement.lastElementChild; | 128 var parentEl = recentElement.lastElementChild; |
| 40 parentEl.textContent = ''; | 129 parentEl.textContent = ''; |
| 130 var recentMenu = $('recently-closed-menu'); |
| 131 clearClosedMenu(recentMenu); |
| 41 | 132 |
| 42 recentItems.forEach(function(item) { | 133 recentItems.forEach(function(item) { |
| 43 parentEl.appendChild(createRecentItem(item)); | 134 parentEl.appendChild(createRecentItem(item)); |
| 135 addRecentMenuItem(recentMenu, item); |
| 44 }); | 136 }); |
| 137 addClosedMenuFooter(recentMenu, 'recently-closed', MINIMIZED_RECENT); |
| 45 | 138 |
| 46 layoutRecentlyClosed(); | 139 layoutRecentlyClosed(); |
| 47 } | 140 } |
| 48 | 141 |
| 49 function createRecentItem(data) { | 142 function createRecentItem(data) { |
| 50 var isWindow = data.type == 'window'; | 143 var isWindow = data.type == 'window'; |
| 51 var el; | 144 var el; |
| 52 if (isWindow) { | 145 if (isWindow) { |
| 53 el = document.createElement('span'); | 146 el = document.createElement('span'); |
| 54 el.className = 'item link window'; | 147 el.className = 'item link window'; |
| 55 el.tabItems = data.tabs; | 148 el.tabItems = data.tabs; |
| 56 el.tabIndex = 0; | 149 el.tabIndex = 0; |
| 57 el.textContent = formatTabsText(data.tabs.length); | 150 el.textContent = formatTabsText(data.tabs.length); |
| 58 } else { | 151 } else { |
| 59 el = document.createElement('a'); | 152 el = document.createElement('a'); |
| 60 el.className = 'item'; | 153 el.className = 'item'; |
| 61 el.href = data.url; | 154 el.href = data.url; |
| 62 el.style.backgroundImage = url('chrome://favicon/' + data.url); | 155 el.style.backgroundImage = url('chrome://favicon/' + data.url); |
| 63 el.dir = data.direction; | 156 el.dir = data.direction; |
| 64 el.textContent = data.title; | 157 el.textContent = data.title; |
| 65 } | 158 } |
| 66 el.sessionId = data.sessionId; | 159 el.sessionId = data.sessionId; |
| 67 el.xtitle = data.title; | 160 el.xtitle = data.title; |
| 68 var wrapperEl = document.createElement('span'); | 161 var wrapperEl = document.createElement('span'); |
| 69 wrapperEl.appendChild(el); | 162 wrapperEl.appendChild(el); |
| 70 return wrapperEl; | 163 return wrapperEl; |
| 71 } | 164 } |
| 72 | 165 |
| 166 function addRecentMenuItem(menu, data) { |
| 167 var isWindow = data.type == 'window'; |
| 168 var a = document.createElement('a'); |
| 169 if (isWindow) { |
| 170 a.textContent = formatTabsText(data.tabs.length); |
| 171 a.className = 'window'; // To get the icon from the CSS .window rule. |
| 172 a.href = ''; // To make underline show up. |
| 173 } else { |
| 174 a.href = data.url; |
| 175 a.style.backgroundImage = 'url(chrome://favicon/' + data.url + ')'; |
| 176 a.textContent = data.title; |
| 177 } |
| 178 function clickHandler(e) { |
| 179 chrome.send('reopenTab', [String(data.sessionId)]); |
| 180 e.preventDefault(); |
| 181 } |
| 182 a.addEventListener('click', clickHandler); |
| 183 addClosedMenuEntryWithLink(menu, a); |
| 184 } |
| 185 |
| 73 function saveShownSections() { | 186 function saveShownSections() { |
| 74 chrome.send('setShownSections', [String(shownSections)]); | 187 chrome.send('setShownSections', [String(shownSections)]); |
| 75 } | 188 } |
| 76 | 189 |
| 77 var LayoutMode = { | 190 var LayoutMode = { |
| 78 SMALL: 1, | 191 SMALL: 1, |
| 79 NORMAL: 2 | 192 NORMAL: 2 |
| 80 }; | 193 }; |
| 81 | 194 |
| 82 var layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL; | 195 var layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 i++; | 308 i++; |
| 196 break; | 309 break; |
| 197 } | 310 } |
| 198 } | 311 } |
| 199 | 312 |
| 200 // Calculate the height of the fixed elements below the expanded section, if | 313 // Calculate the height of the fixed elements below the expanded section, if |
| 201 // any. | 314 // any. |
| 202 for (; section = sections[i]; i++) { | 315 for (; section = sections[i]; i++) { |
| 203 footerHeight += section.fixedHeight; | 316 footerHeight += section.fixedHeight; |
| 204 } | 317 } |
| 318 // Leave room for bottom bar if it's visible. |
| 319 footerHeight += $('closed-sections-bar').offsetHeight; |
| 320 |
| 205 | 321 |
| 206 // Determine the height to use for the expanded section. If there isn't enough | 322 // Determine the height to use for the expanded section. If there isn't enough |
| 207 // space to show the expanded section completely, this will be the available | 323 // space to show the expanded section completely, this will be the available |
| 208 // height. Otherwise, we use the intrinsic height of the expanded section. | 324 // height. Otherwise, we use the intrinsic height of the expanded section. |
| 209 var expandedSectionHeight; | 325 var expandedSectionHeight; |
| 210 if (expandedSection) { | 326 if (expandedSection) { |
| 211 var flexHeight = window.innerHeight - headerHeight - footerHeight; | 327 var flexHeight = window.innerHeight - headerHeight - footerHeight; |
| 212 if (flexHeight < expandedSection.scrollingHeight) { | 328 if (flexHeight < expandedSection.scrollingHeight) { |
| 213 expandedSectionHeight = flexHeight; | 329 expandedSectionHeight = flexHeight; |
| 214 | 330 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 document.querySelector('.section[section=' + key + ']'); | 414 document.querySelector('.section[section=' + key + ']'); |
| 299 } | 415 } |
| 300 } | 416 } |
| 301 return sectionToElementMap[section]; | 417 return sectionToElementMap[section]; |
| 302 } | 418 } |
| 303 | 419 |
| 304 function getSectionMaxiview(section) { | 420 function getSectionMaxiview(section) { |
| 305 return $(section.id + '-maxiview'); | 421 return $(section.id + '-maxiview'); |
| 306 } | 422 } |
| 307 | 423 |
| 424 // You usually want to call |showOnlySection()| instead of this. |
| 308 function showSection(section) { | 425 function showSection(section) { |
| 309 if (!(section & shownSections)) { | 426 if (!(section & shownSections)) { |
| 310 shownSections |= section; | 427 shownSections |= section; |
| 311 var el = getSectionElement(section); | 428 var el = getSectionElement(section); |
| 312 if (el) { | 429 if (el) { |
| 313 el.classList.remove('hidden'); | 430 el.classList.remove('hidden'); |
| 314 | 431 |
| 315 var maxiview = getSectionMaxiview(el); | 432 var maxiview = getSectionMaxiview(el); |
| 316 if (maxiview) { | 433 if (maxiview) { |
| 317 maxiview.classList.remove('hiding'); | 434 maxiview.classList.remove('hiding'); |
| 318 maxiview.classList.remove('hidden'); | 435 maxiview.classList.remove('hidden'); |
| 319 } | 436 } |
| 320 } | 437 } |
| 321 | 438 |
| 322 switch (section) { | 439 switch (section) { |
| 323 case Section.THUMB: | 440 case Section.THUMB: |
| 324 mostVisited.visible = true; | 441 mostVisited.visible = true; |
| 325 mostVisited.layout(); | 442 mostVisited.layout(); |
| 326 break; | 443 break; |
| 327 } | 444 } |
| 328 } | 445 } |
| 329 } | 446 } |
| 330 | 447 |
| 448 // Show this section and hide all other sections - at most one section can |
| 449 // be open at one time. |
| 450 function showOnlySection(section) { |
| 451 for (var p in Section) { |
| 452 if (p == section) |
| 453 showSection(Section[p]); |
| 454 else |
| 455 hideSection(Section[p]); |
| 456 } |
| 457 } |
| 458 |
| 331 function hideSection(section) { | 459 function hideSection(section) { |
| 332 if (section & shownSections) { | 460 if (section & shownSections) { |
| 333 shownSections &= ~section; | 461 shownSections &= ~section; |
| 334 | 462 |
| 335 switch (section) { | 463 switch (section) { |
| 336 case Section.THUMB: | 464 case Section.THUMB: |
| 337 mostVisited.visible = false; | 465 mostVisited.visible = false; |
| 338 mostVisited.layout(); | 466 mostVisited.layout(); |
| 339 break; | 467 break; |
| 340 } | 468 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 367 * Callback when the shown sections changes in another NTP. | 495 * Callback when the shown sections changes in another NTP. |
| 368 * @param {number} newShownSections Bitmask of the shown sections. | 496 * @param {number} newShownSections Bitmask of the shown sections. |
| 369 */ | 497 */ |
| 370 function setShownSections(newShownSections) { | 498 function setShownSections(newShownSections) { |
| 371 for (var key in Section) { | 499 for (var key in Section) { |
| 372 if (newShownSections & Section[key]) | 500 if (newShownSections & Section[key]) |
| 373 showSection(Section[key]); | 501 showSection(Section[key]); |
| 374 else | 502 else |
| 375 hideSection(Section[key]); | 503 hideSection(Section[key]); |
| 376 } | 504 } |
| 505 setSectionVisible( |
| 506 'apps', Section.APPS, |
| 507 !(newShownSections & MINIMIZED_APPS), MINIMIZED_APPS); |
| 508 setSectionVisible( |
| 509 'most-visited', Section.THUMB, |
| 510 !(newShownSections & MINIMIZED_THUMB), MINIMIZED_THUMB); |
| 511 setSectionVisible( |
| 512 'recently-closed', undefined, |
| 513 !(newShownSections & MINIMIZED_RECENT), MINIMIZED_RECENT); |
| 377 layoutSections(); | 514 layoutSections(); |
| 378 } | 515 } |
| 379 | 516 |
| 380 // Recently closed | 517 // Recently closed |
| 381 | 518 |
| 382 function layoutRecentlyClosed() { | 519 function layoutRecentlyClosed() { |
| 383 var recentElement = $('recently-closed'); | 520 var recentElement = $('recently-closed'); |
| 384 var miniview = recentElement.getElementsByClassName('miniview')[0]; | 521 var miniview = recentElement.getElementsByClassName('miniview')[0]; |
| 385 | 522 |
| 386 updateMiniviewClipping(miniview); | 523 updateMiniviewClipping(miniview); |
| 387 | 524 |
| 388 if (miniview.hasChildNodes()) { | 525 if (miniview.hasChildNodes()) { |
| 389 recentElement.classList.remove('disabled'); | 526 if (!(shownSections & MINIMIZED_RECENT)) { |
| 527 recentElement.classList.remove('disabled'); |
| 528 } |
| 390 } else { | 529 } else { |
| 391 recentElement.classList.add('disabled'); | 530 recentElement.classList.add('disabled'); |
| 392 } | 531 } |
| 393 } | 532 } |
| 394 | 533 |
| 395 /** | 534 /** |
| 396 * This function is called by the backend whenever the sync status section | 535 * This function is called by the backend whenever the sync status section |
| 397 * needs to be updated to reflect recent sync state changes. The backend passes | 536 * needs to be updated to reflect recent sync state changes. The backend passes |
| 398 * the new status information in the newMessage parameter. The state includes | 537 * the new status information in the newMessage parameter. The state includes |
| 399 * the following: | 538 * the following: |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 return; | 817 return; |
| 679 | 818 |
| 680 // It looks better to return the scroll to the top when toggling sections. | 819 // It looks better to return the scroll to the top when toggling sections. |
| 681 document.body.scrollTop = 0; | 820 document.body.scrollTop = 0; |
| 682 | 821 |
| 683 // We set it back in webkitTransitionEnd. | 822 // We set it back in webkitTransitionEnd. |
| 684 document.documentElement.setAttribute('enable-section-animations', 'true'); | 823 document.documentElement.setAttribute('enable-section-animations', 'true'); |
| 685 if (shownSections & Section[section]) { | 824 if (shownSections & Section[section]) { |
| 686 hideSection(Section[section]); | 825 hideSection(Section[section]); |
| 687 } else { | 826 } else { |
| 688 for (var p in Section) { | 827 showOnlySection(section); |
| 689 if (p == section) | |
| 690 showSection(Section[p]); | |
| 691 else | |
| 692 hideSection(Section[p]); | |
| 693 } | |
| 694 } | 828 } |
| 695 layoutSections(); | 829 layoutSections(); |
| 696 saveShownSections(); | 830 saveShownSections(); |
| 697 } | 831 } |
| 698 | 832 |
| 699 function handleIfEnterKey(f) { | 833 function handleIfEnterKey(f) { |
| 700 return function(e) { | 834 return function(e) { |
| 701 if (e.keyIdentifier == 'Enter') | 835 if (e.keyIdentifier == 'Enter') |
| 702 f(e); | 836 f(e); |
| 703 }; | 837 }; |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 span.appendChild(el.firstChild); | 1055 span.appendChild(el.firstChild); |
| 922 } | 1056 } |
| 923 el.appendChild(span); | 1057 el.appendChild(span); |
| 924 } | 1058 } |
| 925 | 1059 |
| 926 updateAttribution(); | 1060 updateAttribution(); |
| 927 | 1061 |
| 928 var mostVisited = new MostVisited( | 1062 var mostVisited = new MostVisited( |
| 929 $('most-visited-maxiview'), | 1063 $('most-visited-maxiview'), |
| 930 document.querySelector('#most-visited .miniview'), | 1064 document.querySelector('#most-visited .miniview'), |
| 1065 $('most-visited-menu'), |
| 931 useSmallGrid(), | 1066 useSmallGrid(), |
| 932 shownSections & Section.THUMB); | 1067 shownSections & Section.THUMB); |
| 933 | 1068 |
| 934 function mostVisitedPages(data, firstRun, hasBlacklistedUrls) { | 1069 function mostVisitedPages(data, firstRun, hasBlacklistedUrls) { |
| 935 logEvent('received most visited pages'); | 1070 logEvent('received most visited pages'); |
| 936 | 1071 |
| 937 mostVisited.updateSettingsLink(hasBlacklistedUrls); | 1072 mostVisited.updateSettingsLink(hasBlacklistedUrls); |
| 938 mostVisited.data = data; | 1073 mostVisited.data = data; |
| 939 mostVisited.layout(); | 1074 mostVisited.layout(); |
| 940 layoutSections(); | 1075 layoutSections(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 953 } | 1088 } |
| 954 | 1089 |
| 955 function maybeDoneLoading() { | 1090 function maybeDoneLoading() { |
| 956 if (mostVisited.data && apps.loaded) | 1091 if (mostVisited.data && apps.loaded) |
| 957 document.body.classList.remove('loading'); | 1092 document.body.classList.remove('loading'); |
| 958 } | 1093 } |
| 959 | 1094 |
| 960 function isDoneLoading() { | 1095 function isDoneLoading() { |
| 961 return !document.body.classList.contains('loading'); | 1096 return !document.body.classList.contains('loading'); |
| 962 } | 1097 } |
| OLD | NEW |