diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-30 19:47:05 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-30 19:47:05 +0000 |
commit | 23b7ec676e36ff858b11997bb70d262b315c5010 (patch) | |
tree | 1fbc01e663709fbc36dbfcf6190d695d3d72f0b7 | |
parent | 9d5d932a17ca43eca60cd7755526daa58d7b4472 (diff) | |
download | chromium_src-23b7ec676e36ff858b11997bb70d262b315c5010.zip chromium_src-23b7ec676e36ff858b11997bb70d262b315c5010.tar.gz chromium_src-23b7ec676e36ff858b11997bb70d262b315c5010.tar.bz2 |
Make it possible to hide "most visited" on nnnnnnntp
This implements http://folder/glen/chrome/spec/101_ntp/8_wish&sidebar mocks 2, 5, 6
It's a bit lame to use a bit in the "sections" bitmask to serialize the "should show?" information, but the damage here was done when someone decided to that "THUBMS bit missing" should mean "show a list instead" (instead of adding another bit for that).
BUG=55148
TEST=Hover "Most Visited" bar. Close button should appear. Clicking it should hide "Most Visited" area and add a button at the window edge. That button should have a menu that makes it possible to make the "Most Visited" area visible again. Also do this while multiple NTPs are open; the changes made in the front NTP should be synced to the background NTPs.
Review URL: http://codereview.chromium.org/3455007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61095 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/dom_ui/shown_sections_handler.cc | 5 | ||||
-rw-r--r-- | chrome/browser/dom_ui/shown_sections_handler.h | 12 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.css | 61 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.html | 58 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.js | 149 | ||||
-rw-r--r-- | chrome/browser/resources/ntp/apps.js | 20 | ||||
-rw-r--r-- | chrome/browser/resources/ntp/most_visited.js | 17 |
7 files changed, 305 insertions, 17 deletions
diff --git a/chrome/browser/dom_ui/shown_sections_handler.cc b/chrome/browser/dom_ui/shown_sections_handler.cc index e32511d..381ea32 100644 --- a/chrome/browser/dom_ui/shown_sections_handler.cc +++ b/chrome/browser/dom_ui/shown_sections_handler.cc @@ -21,10 +21,11 @@ namespace { // Will cause an UMA notification if the mode of the new tab page // was changed to hide/show the most visited thumbnails. +// TODO(aa): Needs to be updated to match newest NTP - http://crbug.com/57440 void NotifySectionDisabled(int new_mode, int old_mode, Profile *profile) { // If the oldmode HAD either thumbs or lists visible. - bool old_had_it = old_mode & THUMB; - bool new_has_it = new_mode & THUMB; + bool old_had_it = (old_mode & THUMB) && !(old_mode & MINIMIZED_THUMB); + bool new_has_it = (new_mode & THUMB) && !(new_mode & MINIMIZED_THUMB); if (old_had_it && !new_has_it) { UserMetrics::RecordAction( diff --git a/chrome/browser/dom_ui/shown_sections_handler.h b/chrome/browser/dom_ui/shown_sections_handler.h index a281346..be07735 100644 --- a/chrome/browser/dom_ui/shown_sections_handler.h +++ b/chrome/browser/dom_ui/shown_sections_handler.h @@ -18,8 +18,16 @@ class PrefService; // Currently, only the THUMB and APPS sections can be toggled by the user. Other // sections are shown automatically if they have data, and hidden otherwise. enum Section { - THUMB = 1, - APPS = 64 + // If one of these is set, the corresponding section shows large thumbnails, + // else it shows only a small overview list. + THUMB = 1 << 0, + APPS = 1 << 6, + + // If one of these is set, then the corresponding section is shown minimized + // at the bottom of the NTP and no data is directly visible on the NTP. + MINIMIZED_THUMB = 1 << (0 + 16), + MINIMIZED_RECENT = 1 << (2 + 16), + MINIMIZED_APPS = 1 << (6 + 16), }; class ShownSectionsHandler : public DOMMessageHandler, diff --git a/chrome/browser/resources/new_new_tab.css b/chrome/browser/resources/new_new_tab.css index b3bfd35..cb3c784 100644 --- a/chrome/browser/resources/new_new_tab.css +++ b/chrome/browser/resources/new_new_tab.css @@ -279,7 +279,8 @@ html[anim=true][enable-section-animations=true] .section { -webkit-transition: top .15s; } -.section.disabled { +.section.disabled, +#closed-sections-bar .disabled { display: none !important; } @@ -313,7 +314,7 @@ html[anim=true] .section > h2 > .disclosure { } .section:not(.hidden) > h2 > .disclosure { - -webkit-transform:rotate(90deg); + -webkit-transform: rotate(90deg); } .section > h2 .back { @@ -331,6 +332,62 @@ html[anim=true] .section > h2 > .disclosure { z-index: 2; } +.section-close-button { + -webkit-appearance: none; + -webkit-transition: opacity .15s; + background-color: transparent; + background-image: url(chrome://theme/IDR_CLOSE_BAR); + background-position: center center; + background-repeat no-repeat; + border: 0; + height: 21px; + margin-top: -10px; + position: absolute; + right: -21px; + top: 50%; + width: 21px; + opacity: 0; + z-index: 3; +} + +html[dir=rtl] .section-close-button { + left: -21px; + right: auto; +} + +.section > h2:hover .section-close-button, +.section-close-button:hover { + opacity: 1; +} + +.section-close-button:hover { + background-image: url(chrome://theme/IDR_CLOSE_BAR_H); +} + +#closed-sections-bar { + position: fixed; + bottom: 5px; +} + +#closed-sections-bar > button { + -webkit-appearance: none; + background: none; + border: 0; + font: inherit; + margin: 0; + margin-right: 10px; + padding: 0; + + /* from .section > h2 */ + font-family: Helvetica, Arial, sans-serif; + font-size: 133%; + font-weight: normal; +} + +#closed-sections-bar > button > img { + -webkit-transform: rotate(90deg); +} + .maxiview { padding: 5px 0 30px; position: absolute; diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html index 7290e32..6f15bb4 100644 --- a/chrome/browser/resources/new_new_tab.html +++ b/chrome/browser/resources/new_new_tab.html @@ -67,10 +67,16 @@ registerCallback('setShownSections'); * @enum {number} */ var Section = { - THUMB: 1, - APPS: 64 + THUMB: 1 << 0, + APPS: 1 << 6 }; +// These are used to hide sections and are part of the |shownSections| bitmask, +// but are not sections themselves. +var MINIMIZED_THUMB = 1 << (0 + 16); +var MINIMIZED_RECENT = 1 << (2 + 16); +var MINIMIZED_APPS = 1 << (6 + 16); + var shownSections = templateData['shown_sections']; // Until themes can clear the cache, force-reload the theme stylesheet. @@ -135,6 +141,7 @@ if ('mode' in hashParams) { <img class="disclosure" img src="ntp/ntp_disclosure_triangle.png"> <div class="back"></div> <span i18n-content="apps"></span> + <button class="section-close-button"></button> </h2> <div class="miniview"></div> </div> @@ -146,6 +153,7 @@ if ('mode' in hashParams) { <span i18n-content="mostvisited"></span> <button id="most-visited-settings" i18n-content="restorethumbnails"> </button> + <button class="section-close-button"></button> </h2> <div class="miniview"></div> </div> @@ -157,6 +165,7 @@ if ('mode' in hashParams) { <h2> <div class="back"></div> <span i18n-content="recentlyclosed"></span> + <button class="section-close-button"></button> </h2> <div class="miniview"></div> </div> @@ -168,6 +177,27 @@ if ('mode' in hashParams) { </div> </div> </div> + + <div id="closed-sections-bar"> + <!-- The default visibility of these buttons needs to be the opposite of the + default visibility of the corresponding sections. --> + <button id="apps-button" + menu="#apps-menu"> + <span i18n-content="apps"></span> + <img src="ntp/ntp_disclosure_triangle.png"> + </button> + <button id="most-visited-button" + class="disabled" + menu="#most-visited-menu"> + <span i18n-content="mostvisited"></span> + <img src="ntp/ntp_disclosure_triangle.png"> + </button> + <button id="recently-closed-button" + menu="#recently-closed-menu"> + <span i18n-content="recentlyclosed"></span> + <img src="ntp/ntp_disclosure_triangle.png"> + </button> + </div> </div> <!-- main --> <div class="window-menu" id="window-tooltip"></div> @@ -194,6 +224,11 @@ if ('mode' in hashParams) { <button command="#apps-uninstall-command"></button> </menu> +<!-- These are populated dynamically --> +<menu id="apps-menu"></menu> +<menu id="most-visited-menu"></menu> +<menu id="recently-closed-menu"></menu> + </body> <script src="shared/js/i18n_template.js"></script> @@ -226,8 +261,27 @@ cr.ui.decorate('button[menu]', cr.ui.MenuButton); </script> <script> + initializeSection('apps', MINIMIZED_APPS, Section.APPS); + initializeSection('most-visited', MINIMIZED_THUMB, Section.THUMB); + initializeSection('recently-closed', MINIMIZED_RECENT); + updateSimpleSection('apps', Section.APPS); updateSimpleSection('most-visited', Section.THUMB); + var appsInitiallyVisible = !(shownSections & MINIMIZED_APPS); + var mostVisitedInitiallyVisible = !(shownSections & MINIMIZED_THUMB); + var recentlyClosedInitiallyVisible = !(shownSections & MINIMIZED_RECENT); + // Apps and recently closed start as hidden in the HTML, most visited is + // initially visible. Adapt to the change received from the prefs by forcing + // all three sections to update. + shownSections &= ~MINIMIZED_THUMB; + shownSections |= MINIMIZED_APPS | MINIMIZED_RECENT; + setSectionVisible('apps', Section.APPS, appsInitiallyVisible, MINIMIZED_APPS); + setSectionVisible( + 'most-visited', Section.THUMB, + mostVisitedInitiallyVisible, MINIMIZED_THUMB); + setSectionVisible( + 'recently-closed', undefined, + recentlyClosedInitiallyVisible, MINIMIZED_RECENT); layoutSections(); </script> </html> diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js index 99cb712..39c7718 100644 --- a/chrome/browser/resources/new_new_tab.js +++ b/chrome/browser/resources/new_new_tab.js @@ -9,6 +9,95 @@ var MAX_MINIVIEW_ITEMS = 15; // Extra spacing at the top of the layout. var LAYOUT_SPACING_TOP = 25; +function getSectionCloseButton(sectionId) { + return document.querySelector('#' + sectionId + ' .section-close-button'); +} + +function getSectionMenuButton(sectionId) { + return $(sectionId + '-button'); +} + +function getSectionMenuButtonTextId(sectionId) { + return sectionId.replace(/-/g, ''); +} + +function setSectionVisible(sectionId, section, visible, hideMask) { + if (visible && !(shownSections & hideMask) || + !visible && (shownSections & hideMask)) + return; + + if (visible) { + if (section) { + showOnlySection(section); + } + var el = $(sectionId); + el.classList.remove('disabled'); + el = getSectionMenuButton(sectionId); + el.classList.add('disabled'); + shownSections &= ~hideMask; + } else { + if (section) { + hideSection(section); + } + var el = $(sectionId); + el.classList.add('disabled'); + el = getSectionMenuButton(sectionId); + el.classList.remove('disabled'); + shownSections |= hideMask; + } + layoutSections(); +} + +function clearClosedMenu(menu) { + menu.innerHTML = ''; +} + +function addClosedMenuEntryWithLink(menu, a) { + var span = document.createElement('span'); + a.className += ' item menuitem'; + span.appendChild(a); + menu.appendChild(span); +} + +function addClosedMenuEntry(menu, url, title, imageUrl) { + var a = document.createElement('a'); + a.href = url; + a.textContent = title; + a.style.backgroundImage = 'url(' + imageUrl + ')'; + addClosedMenuEntryWithLink(menu, a); +} + +function addClosedMenuFooter(menu, sectionId, mask, opt_section) { + menu.appendChild(document.createElement('hr')); + + var span = document.createElement('span'); + var a = span.appendChild(document.createElement('a')); + a.href = ''; + a.textContent = + localStrings.getString(getSectionMenuButtonTextId(sectionId)); + a.className = 'item'; + a.addEventListener( + 'click', + function(e) { + getSectionMenuButton(sectionId).hideMenu(); + e.preventDefault(); + setSectionVisible(sectionId, opt_section, true, mask); + shownSections &= ~mask; + saveShownSections(); + }); + menu.appendChild(span); +} + +function initializeSection(sectionId, mask, opt_section) { + var button = getSectionCloseButton(sectionId); + button.addEventListener( + 'click', + function() { + setSectionVisible(sectionId, opt_section, false, mask); + saveShownSections(); + }); +} + function updateSimpleSection(id, section) { var elm = $(id); var maxiview = getSectionMaxiview(elm); @@ -38,10 +127,14 @@ function renderRecentlyClosed() { var recentElement = $('recently-closed'); var parentEl = recentElement.lastElementChild; parentEl.textContent = ''; + var recentMenu = $('recently-closed-menu'); + clearClosedMenu(recentMenu); recentItems.forEach(function(item) { parentEl.appendChild(createRecentItem(item)); + addRecentMenuItem(recentMenu, item); }); + addClosedMenuFooter(recentMenu, 'recently-closed', MINIMIZED_RECENT); layoutRecentlyClosed(); } @@ -70,6 +163,26 @@ function createRecentItem(data) { return wrapperEl; } +function addRecentMenuItem(menu, data) { + var isWindow = data.type == 'window'; + var a = document.createElement('a'); + if (isWindow) { + a.textContent = formatTabsText(data.tabs.length); + a.className = 'window'; // To get the icon from the CSS .window rule. + a.href = ''; // To make underline show up. + } else { + a.href = data.url; + a.style.backgroundImage = 'url(chrome://favicon/' + data.url + ')'; + a.textContent = data.title; + } + function clickHandler(e) { + chrome.send('reopenTab', [String(data.sessionId)]); + e.preventDefault(); + } + a.addEventListener('click', clickHandler); + addClosedMenuEntryWithLink(menu, a); +} + function saveShownSections() { chrome.send('setShownSections', [String(shownSections)]); } @@ -202,6 +315,9 @@ function layoutSections() { for (; section = sections[i]; i++) { footerHeight += section.fixedHeight; } + // Leave room for bottom bar if it's visible. + footerHeight += $('closed-sections-bar').offsetHeight; + // Determine the height to use for the expanded section. If there isn't enough // space to show the expanded section completely, this will be the available @@ -305,6 +421,7 @@ function getSectionMaxiview(section) { return $(section.id + '-maxiview'); } +// You usually want to call |showOnlySection()| instead of this. function showSection(section) { if (!(section & shownSections)) { shownSections |= section; @@ -328,6 +445,17 @@ function showSection(section) { } } +// Show this section and hide all other sections - at most one section can +// be open at one time. +function showOnlySection(section) { + for (var p in Section) { + if (p == section) + showSection(Section[p]); + else + hideSection(Section[p]); + } +} + function hideSection(section) { if (section & shownSections) { shownSections &= ~section; @@ -374,6 +502,15 @@ function setShownSections(newShownSections) { else hideSection(Section[key]); } + setSectionVisible( + 'apps', Section.APPS, + !(newShownSections & MINIMIZED_APPS), MINIMIZED_APPS); + setSectionVisible( + 'most-visited', Section.THUMB, + !(newShownSections & MINIMIZED_THUMB), MINIMIZED_THUMB); + setSectionVisible( + 'recently-closed', undefined, + !(newShownSections & MINIMIZED_RECENT), MINIMIZED_RECENT); layoutSections(); } @@ -399,7 +536,9 @@ function layoutRecentlyClosed() { }); if (parentEl.hasChildNodes()) { - recentElement.classList.remove('disabled'); + if (!(shownSections & MINIMIZED_RECENT)) { + recentElement.classList.remove('disabled'); + } } else { recentElement.classList.add('disabled'); } @@ -698,12 +837,7 @@ function toggleSectionVisibilityAndAnimate(section) { if (shownSections & Section[section]) { hideSection(Section[section]); } else { - for (var p in Section) { - if (p == section) - showSection(Section[p]); - else - hideSection(Section[p]); - } + showOnlySection(section); } layoutSections(); saveShownSections(); @@ -941,6 +1075,7 @@ updateAttribution(); var mostVisited = new MostVisited( $('most-visited-maxiview'), document.querySelector('#most-visited .miniview'), + $('most-visited-menu'), useSmallGrid(), shownSections & Section.THUMB); diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js index b128f05..4f577db 100644 --- a/chrome/browser/resources/ntp/apps.js +++ b/chrome/browser/resources/ntp/apps.js @@ -10,6 +10,7 @@ function getAppsCallback(data) { appsSectionContent.textContent = ''; appsMiniview.textContent = ''; + clearClosedMenu(apps.menu); if (data.apps.length == 0) { appsSection.classList.add('disabled'); setShownSections(Section.THUMB); @@ -22,10 +23,14 @@ function getAppsCallback(data) { data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) { appsMiniview.appendChild(apps.createMiniviewElement(app)); + addClosedMenuEntryWithLink(apps.menu, apps.createClosedMenuElement(app)); }); - appsSection.classList.remove('disabled'); + if (!(shownSections & MINIMIZED_APPS)) { + appsSection.classList.remove('disabled'); + } } + addClosedMenuFooter(apps.menu, 'apps', MINIMIZED_APPS, Section.APPS); apps.loaded = true; maybeDoneLoading(); @@ -199,6 +204,8 @@ var apps = (function() { return { loaded: false, + menu: $('apps-menu'), + createElement: function(app) { var div = createElement(app); var a = div.firstChild; @@ -251,6 +258,17 @@ var apps = (function() { return span; }, + createClosedMenuElement: function(app) { + var a = document.createElement('a'); + a.setAttribute('app-id', app['id']); + a.textContent = app['name']; + a.href = app['launch_url']; + a.onclick = handleClick; + a.style.backgroundImage = url(app['icon_small']); + a.className = 'item'; + return a; + }, + createWebStoreElement: function() { return createElement({ 'id': 'web-store-entry', diff --git a/chrome/browser/resources/ntp/most_visited.js b/chrome/browser/resources/ntp/most_visited.js index 98f3317..72557ac 100644 --- a/chrome/browser/resources/ntp/most_visited.js +++ b/chrome/browser/resources/ntp/most_visited.js @@ -41,9 +41,10 @@ var MostVisited = (function() { return Array.prototype.indexOf.call(nodes, el); } - function MostVisited(el, miniview, useSmallGrid, visible) { + function MostVisited(el, miniview, menu, useSmallGrid, visible) { this.element = el; this.miniview = miniview; + this.menu = menu; this.useSmallGrid_ = useSmallGrid; this.visible_ = visible; @@ -536,6 +537,7 @@ var MostVisited = (function() { this.data_ = data; this.updateMostVisited_(); this.updateMiniview_(); + this.updateMenu_(); }, updateMostVisited_: function() { @@ -609,6 +611,19 @@ var MostVisited = (function() { updateMiniviewClipping(this.miniview); }, + updateMenu_: function() { + clearClosedMenu(this.menu); + var data = this.data.slice(0, MAX_MINIVIEW_ITEMS); + for (var i = 0, item; item = data[i]; i++) { + if (!item.filler) { + addClosedMenuEntry( + this.menu, item.url, item.title, 'chrome://favicon/' + item.url); + } + } + addClosedMenuFooter( + this.menu, 'most-visited', MINIMIZED_THUMB, Section.THUMB); + }, + handleClick_: function(e) { var target = e.target; if (target.classList.contains('pin')) { |