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 |