diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 06:00:59 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 06:00:59 +0000 |
commit | e8450483095b2b40ae8f78f33d2d2487ee1d1aa6 (patch) | |
tree | 23f1c42e290ce35dfd9c06bfb55d81b0b1f353aa /chrome/browser/resources | |
parent | 91ffbb3a177fb38b831b2a1fdec21de376f5403e (diff) | |
download | chromium_src-e8450483095b2b40ae8f78f33d2d2487ee1d1aa6.zip chromium_src-e8450483095b2b40ae8f78f33d2d2487ee1d1aa6.tar.gz chromium_src-e8450483095b2b40ae8f78f33d2d2487ee1d1aa6.tar.bz2 |
Add an accordian effect to NTP.
BUG=53248
Review URL: http://codereview.chromium.org/3250002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57966 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/resources')
-rw-r--r-- | chrome/browser/resources/new_new_tab.css | 128 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.html | 43 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.js | 198 | ||||
-rw-r--r-- | chrome/browser/resources/new_tab_theme.css | 50 | ||||
-rw-r--r-- | chrome/browser/resources/ntp/apps.js | 2 | ||||
-rw-r--r-- | chrome/browser/resources/ntp/most_visited.css | 2 |
6 files changed, 304 insertions, 119 deletions
diff --git a/chrome/browser/resources/new_new_tab.css b/chrome/browser/resources/new_new_tab.css index 5f27622..ef82016 100644 --- a/chrome/browser/resources/new_new_tab.css +++ b/chrome/browser/resources/new_new_tab.css @@ -20,8 +20,6 @@ html[mode=app-launcher] { -webkit-transition: width .15s; margin: 0 auto; min-height: 100%; - padding:10px 0 20px; - position: relative; width: 920px; } @@ -217,38 +215,11 @@ html[dir=rtl] .item { pointer-events: none; } -#option-button { - -webkit-appearance: none; - background-color: transparent; - width: 19px; - height: 17px; - position: absolute; - right: 0; - left: auto; - top: 20px; - border: 0; - padding: 0; - vertical-align: top; - -webkit-margin-start: 10px; - /* Do not show focus outline */ - outline: none; - background-image: url(chrome://theme/IDR_NEWTAB_OPTION); -} - -#option-button:hover, -#option-button:focus { - background-image: url(chrome://theme/IDR_NEWTAB_OPTION_H); -} - -#option-button:active, -#option-button.open { - background-image: url(chrome://theme/IDR_NEWTAB_OPTION_P); -} - #option-menu { right: 0; left: auto; min-width: 175px; + z-index: 3; } html[dir=rtl] #option-button, @@ -322,6 +293,7 @@ html[dir=rtl] #option-menu > [command=hide]:before { .section > * { font-size: 12px; + width: 920px; } .section.disabled { @@ -329,49 +301,104 @@ html[dir=rtl] #option-menu > [command=hide]:before { } .section > div { - margin-bottom: 15px; + padding-bottom: 20px; } #apps-section-content { /* This one is special because the app buttons already have a lot of empty space around them. */ - margin-bottom: 5px; + margin-top: -5px; + padding-bottom: 5px; } .section > h2 { - background-position: 0 center; - background-repeat: no-repeat; - -webkit-background-size: 100% 26px; display: block; font-family: Helvetica, Arial, sans-serif; font-size: 16px; font-weight: normal; - margin:10px 0; - -webkit-margin-collapse: separate; + margin: 0; + padding: 15px 0; + position: fixed; + z-index: 2; +} + +.section:not(.hidden) > h2 { + background-position: 0 0, 0 100%; + background-repeat: no-repeat; + background-size: 100% 39px, 100% 10px; +} + +.section:not(.hidden) + .section > h2 { + background-position: 0 0, 0 100%; + background-repeat: no-repeat; + background-size: 100% 10px, 100% 39px; } .section:not([noexpand]) > h2 { cursor: pointer; } -.section > h2 > img { - margin-left:-13px; - padding-right:4px; +/* The first one is special because we want a little extra space at the top of +the layout. */ +.section:first-child > h2 { + padding-top: 20px; + background-size: 100% 44px, 100% 10px; +} + +.section > h2 > .disclosure { + margin-left: -13px; + padding-right: 4px; } -.section:not(.hidden) > h2 > img { +.section:not(.hidden) > h2 > .disclosure { -webkit-transform:rotate(90deg); } +.section > h2 > .back { + position: absolute; + bottom: 5px; + left: 0; + width: 100%; + height: 19px; + background-repeat: no-repeat; + z-index: 1; +} + .section > h2 > span { - padding-right: 4px; + padding-right: 5px; + position: relative; + z-index: 2; +} + +.section > h2 > .settings { + position: absolute; + top: 18px; + right: 0; + width: 11px; + height: 11px; + /* TODO(aa): Need a better image. This one is semi-transparent. Also, I think + a gear would be better. */ + background-image: url(chrome://theme/IDR_BALLOON_WRENCH); + background-position: center center; + background-repeat: no-repeat; + background-size: 100%; + border-style: solid; + border-width: 0 5px 0 6px; + z-index: 2; +} + +.section.hidden > h2 > .settings { + display: none; +} + +.section > .maxiview { + position: absolute; } .section > .miniview { display: none; - /* Because the items have 10px horizontal margins. */ - margin-left:-10px; - margin-right:-10px; + position: fixed; + z-index: 2; } .section.hidden > * { @@ -402,11 +429,20 @@ html[dir=rtl] #option-menu > [command=hide]:before { margin: 0 10px; } +.miniview > span:first-child { + margin-left: 0; +} + +.miniview > span:last-child { + margin-right: 0; +} + /* small */ @media (max-width: 940px) { - #main { + #main, + .section > * { width: 692px; } diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html index cf93d2d..f14d019 100644 --- a/chrome/browser/resources/new_new_tab.html +++ b/chrome/browser/resources/new_new_tab.html @@ -90,13 +90,6 @@ function isRtl() { return templateData['textdirection'] == 'rtl'; } -// This will get overridden in new_new_tab.js -function updateSimpleSection(id, section) { - // All sections start off shown. - if (!(shownSections & section)) - document.getElementById(id).className += ' hidden'; -} - // Parse any name value pairs passed through the URL hash. var hashParams = (function() { var result = {}; @@ -127,9 +120,6 @@ if ('mode' in hashParams) { <div id="main"> <menu id="option-menu"> - <div command="hide" section="THUMB" i18n-content="mostvisited"></div> - <div command="hide" section="RECENT" i18n-content="recentlyclosed"></div> - <hr> <div command="clear-all-blacklisted" i18n-content="restorethumbnails"></div> </menu> @@ -141,16 +131,17 @@ if ('mode' in hashParams) { <div class="sections"> <div class="section" section="APPS" id="apps-section"> - <h2><img src="ntp/ntp_disclosure_triangle.png" - ><span i18n-content="apps"></span></h2> - <div id="apps-section-content"></div> + <h2><img class="disclosure" img src="ntp/ntp_disclosure_triangle.png" + ><span i18n-content="apps"></span><div class="back"></div></h2> + <div class="maxiview" id="apps-section-content"></div> <div class="miniview"></div> </div> <div id="most-visited-section" class="section" section="THUMB"> - <h2><img src="ntp/ntp_disclosure_triangle.png" - ><span i18n-content="mostvisited"></span></h2> - <div id="most-visited"></div> + <h2><img class="disclosure" src="ntp/ntp_disclosure_triangle.png" + ><span i18n-content="mostvisited"></span + ><div class="settings"></div><div class="back"></div></h2> + <div class="maxiview" id="most-visited"></div> <div class="miniview"></div> </div> @@ -158,10 +149,12 @@ if ('mode' in hashParams) { silly without any. --> <div id="recently-closed" class="section hidden disabled" section="RECENT" noexpand="true"> - <h2><span i18n-content="recentlyclosed"></span></h2> + <h2><span i18n-content="recentlyclosed"></span + ><div class="back"></div></h2> <div class="miniview"></div> </div> + <!-- TODO(aa): Remove this -- we don't use it anymore. --> <div id="debug" class="section disabled" section="DEBUG"> <h2><span>Debug</span></h2> <div id="apps-launch-control"> @@ -178,13 +171,6 @@ if ('mode' in hashParams) { </div> </div> - <script> - updateSimpleSection('apps-section', Section.APPS); - updateSimpleSection('most-visited-section', Section.THUMB); - updateSimpleSection('recently-closed', Section.RECENT); - updateSimpleSection('debug', Section.DEBUG); - </script> - <div id="sync-status"> <h2></h2> <span></span> @@ -212,4 +198,13 @@ i18nTemplate.process(document, templateData); <script src="ntp/most_visited.js"></script> <script src="new_new_tab.js"></script> <script src="ntp/apps.js"></script> + +<script> + updateSimpleSection('apps-section', Section.APPS); + updateSimpleSection('most-visited-section', Section.THUMB); + updateSimpleSection('recently-closed', Section.RECENT); + updateSimpleSection('debug', Section.DEBUG); + + layoutSections(); +</script> </html> diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js index 2255005..f780837 100644 --- a/chrome/browser/resources/new_new_tab.js +++ b/chrome/browser/resources/new_new_tab.js @@ -20,6 +20,7 @@ function recentlyClosedTabs(data) { // We need to store the recent items so we can update the layout on a resize. recentItems = data; renderRecentlyClosed(); + layoutSections(); } var recentItems = []; @@ -87,6 +88,141 @@ function handleWindowResize() { mostVisited.layout(); renderRecentlyClosed(); } + + layoutSections(); +} + +// Stores some information about each section necessary to layout. A new +// instance is constructed for each section on each layout. +function SectionLayoutInfo(section) { + this.section = section; + this.header = section.getElementsByTagName('h2')[0]; + this.miniview = section.getElementsByClassName('miniview')[0]; + this.maxiview = section.getElementsByClassName('maxiview')[0]; + this.expanded = !section.classList.contains('hidden'); + this.fixedHeight = this.header.offsetHeight; + this.scrollingHeight = 0; + + if (this.expanded) { + this.scrollingHeight = this.maxiview.offsetHeight; + } else if (this.miniview) { + this.fixedHeight += this.miniview.offsetHeight; + } +} + +// Get all sections to be layed out. +SectionLayoutInfo.getAll = function() { + var sections = document.querySelectorAll('.section:not(.disabled)'); + var result = []; + for (var i = 0, section; section = sections[i]; i++) { + result.push(new SectionLayoutInfo(section)); + } + return result; +}; + +// Layout the sections in a modified accordian. The header and miniview, if +// visible are fixed within the viewport. If there is an expanded section, its +// it scrolls. +// +// ============================= +// | collapsed section | <- Any collapsed sections are fixed position. +// | and miniview | +// |---------------------------| +// | expanded section | +// | | <- There can be one expanded section and it +// | and maxiview | is absolutely positioned so that it can +// | | scroll "underneath" the fixed elements. +// | | +// |---------------------------| +// | another collapsed section | +// |---------------------------| +// +// We want the main frame scrollbar to be the one that scrolls the expanded +// region. To get this effect, we make the fixed elements position:fixed and the +// scrollable element position:absolute. We also artificially increase the +// height of the document so that it is possible to scroll down enough to +// display the end of the document, even with any fixed elements at the bottom +// of the viewport. +// +// There is a final twist: If the intrinsic height of the expanded section is +// less than the available height (because the window is tall), any collapsed +// sections sinch up and sit below the expanded section. This is so that we +// don't have a bunch of dead whitespace in the case of expanded sections that +// aren't very tall. +function layoutSections() { + var sections = SectionLayoutInfo.getAll(); + var expandedSection = null; + var headerHeight = 0; + var footerHeight = 0; + + // Calculate the height of the fixed elements above the expanded section. Also + // take note of the expanded section, if there is one. + var i; + var section; + for (i = 0; section = sections[i]; i++) { + headerHeight += section.fixedHeight; + if (section.expanded) { + expandedSection = section; + i++; + break; + } + } + + // Calculate the height of the fixed elements below the expanded section, if + // any. + for (; section = sections[i]; i++) { + footerHeight += section.fixedHeight; + } + + // 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 + // height. Otherwise, we use the intrinsic height of the expanded section. + var expandedSectionHeight; + if (expandedSection) { + var flexHeight = window.innerHeight - headerHeight - footerHeight; + if (flexHeight < expandedSection.scrollingHeight) { + expandedSectionHeight = flexHeight; + + // Also, artificially expand the height of the document so that we can see + // the entire expanded section. + // + // TODO(aa): Where does this come from? It is the difference between what + // we set document.body.style.height to and what + // document.body.scrollHeight measures afterward. I expect them to be the + // same if document.body has no margins. + var fudge = 44; + document.body.style.height = + headerHeight + + expandedSection.scrollingHeight + + footerHeight + + fudge + + 'px'; + } else { + expandedSectionHeight = expandedSection.scrollingHeight; + document.body.style.height = ''; + } + } + + // Now position all the elements. + var y = 0; + for (i = 0, section; section = sections[i]; i++) { + section.header.style.top = y + 'px'; + y += section.header.offsetHeight; + + if (section.miniview) { + section.miniview.style.top = y + 'px'; + if (section != expandedSection) { + y += section.miniview.offsetHeight; + } + } + + if (section.maxiview) { + section.maxiview.style.top = y + 'px'; + if (section == expandedSection) { + y += expandedSectionHeight; + } + } + } } window.addEventListener('resize', handleWindowResize); @@ -147,6 +283,7 @@ function setShownSections(newShownSections) { else hideSection(Section[key]); } + layoutSections(); } // Recently closed @@ -303,20 +440,6 @@ function viewLog() { console.log(lines.join('\n')); } -// Updates the visibility of the menu items. -function updateOptionMenu() { - var menuItems = $('option-menu').children; - for (var i = 0; i < menuItems.length; i++) { - var item = menuItems[i]; - var command = item.getAttribute('command'); - if (command == 'show' || command == 'hide') { - var section = Section[item.getAttribute('section')]; - var visible = shownSections & section; - item.setAttribute('command', visible ? 'hide' : 'show'); - } - } -} - // We apply the size class here so that we don't trigger layout animations // onload. @@ -416,6 +539,7 @@ function showFirstRunNotification() { function OptionMenu(button, menu) { this.button = button; this.menu = menu; + this.button.onclick = bind(this.handleClick, this); this.button.onmousedown = bind(this.handleMouseDown, this); this.button.onkeydown = bind(this.handleKeyDown, this); this.boundHideMenu_ = bind(this.hide, this); @@ -427,7 +551,6 @@ function OptionMenu(button, menu) { OptionMenu.prototype = { show: function() { - updateOptionMenu(); this.positionMenu_(); this.menu.style.display = 'block'; this.button.classList.add('open'); @@ -440,7 +563,9 @@ OptionMenu.prototype = { }, positionMenu_: function() { - this.menu.style.top = this.button.getBoundingClientRect().bottom + 'px'; + var rect = this.button.getBoundingClientRect(); + this.menu.style.top = rect.bottom + 'px'; + this.menu.style.right = (document.body.clientWidth - rect.right) + 'px' }, hide: function() { @@ -476,6 +601,10 @@ OptionMenu.prototype = { } }, + handleClick: function(e) { + e.stopPropagation(); + }, + handleMouseOver: function(e) { var el = e.target; if (!el.hasAttribute('command')) { @@ -587,27 +716,15 @@ OptionMenu.prototype = { } }; -// TODO(aa): The 'clear-all-blacklisted' feature needs to move into a menu in -// the most visited section. -/* -var optionMenu = new OptionMenu($('option-button'), $('option-menu')); +var optionMenu = new OptionMenu( + document.querySelector('#most-visited-section h2 .settings'), + $('option-menu')); optionMenu.commands = { 'clear-all-blacklisted' : function() { mostVisited.clearAllBlacklisted(); chrome.send('getMostVisited'); - }, - 'show': function(item) { - var section = Section[item.getAttribute('section')]; - showSection(section); - saveShownSections(); - }, - 'hide': function(item) { - var section = Section[item.getAttribute('section')]; - hideSection(section); - saveShownSections(); } }; -*/ $('main').addEventListener('click', function(e) { var p = e.target; @@ -626,10 +743,17 @@ $('main').addEventListener('click', function(e) { var section = p.getAttribute('section'); if (section) { - if (shownSections & Section[section]) + if (shownSections & Section[section]) { hideSection(Section[section]); - else - showSection(Section[section]); + } else { + for (var p in Section) { + if (p == section) + showSection(Section[p]); + else + hideSection(Section[p]); + } + } + layoutSections(); saveShownSections(); } }); @@ -821,8 +945,7 @@ function callGetSyncMessageIfSyncIsPresent() { } function hideAllMenus() { - // TODO(aa): See comment in definition of optionMenu. - //optionMenu.hide(); + optionMenu.hide(); } window.addEventListener('blur', hideAllMenus); @@ -878,7 +1001,7 @@ updateAttribution(); var mostVisited = new MostVisited( $('most-visited'), - $('most-visited-section').getElementsByClassName('miniview')[0], + document.querySelector('#most-visited-section .miniview'), useSmallGrid(), shownSections & Section.THUMB); @@ -887,6 +1010,7 @@ function mostVisitedPages(data, firstRun) { mostVisited.data = data; mostVisited.layout(); + layoutSections(); loading = false; diff --git a/chrome/browser/resources/new_tab_theme.css b/chrome/browser/resources/new_tab_theme.css index 40225de..790516a 100644 --- a/chrome/browser/resources/new_tab_theme.css +++ b/chrome/browser/resources/new_tab_theme.css @@ -3,7 +3,6 @@ html { background-color: $2; /* COLOR_NTP_BACKGROUND */ background-position: $3; background-repeat: $5; - overflow: hidden; } html[bookmarkbarattached='true'] { @@ -66,11 +65,6 @@ body { background-color: $$1; /* COLOR_NTP_SECTION */ } -#option-button { - background-color: $7; /* color_header_gradient_light */ - -webkit-mask-image: url(chrome://theme/IDR_NEWTAB_MENU_MASK); -} - .miniview { color: $8; /* COLOR_NTP_TEXT */ } @@ -106,24 +100,58 @@ body { } .section > h2 { + background-color: $2; /* COLOR_NTP_BACKGROUND */ + color: $$8; /* COLOR_NTP_SECTION_HEADER_TEXT */ +} + +.section:not(.hidden) > h2 { + background-color: transparent; + background-image: + -webkit-gradient(linear, 0% 0%, 0% 100%, from($2), to($2)), + -webkit-gradient(linear, 0% 0%, 0% 100%, from($2), to($$$1)); color: $$9; - background-image: url(chrome://theme/IDR_NEWTAB_SECTION_HEADER_BACKGROUND_A); } -.section.hidden > h2 { - color: $$8; /* COLOR_NTP_SECTION_HEADER_TEXT */ - background-image: url(chrome://theme/IDR_NEWTAB_SECTION_HEADER_BACKGROUND); +.section:not(.hidden) + .section > h2 { + background-color: transparent; + background-image: + -webkit-gradient(linear, 0% 0%, 0% 100%, from($$$1), to($2)), + -webkit-gradient(linear, 0% 0%, 0% 100%, from($2), to($2)); } .section.hidden:not([noexpand]) > h2:hover { color: $$9; - background-image: url(chrome://theme/IDR_NEWTAB_SECTION_HEADER_BACKGROUND_H); } .section > h2 > span { background: $2; /* COLOR_NTP_BACKGROUND */ } +.section > h2 > .back { + background-image: + -webkit-gradient(radial, 50% -1753, 1750, 50% -1753, 1770, + from($$$2), to($$$1)); + border-top: 1px solid $$$2; /* COLOR_NTP_SECTION_HEADER_RULE */ +} + +.section.hidden > h2 > .back { + background: none; + border-color-top: $$$3; /* COLOR_NTP_SECTION_HEADER_RULE_LIGHT */ +} + +.section.hidden:hover > h2 > .back { + border-color-top: $$$2; /* COLOR_NTP_SECTION_HEADER_RULE */ +} + +.section > h2 > .settings { + background-color: $2; /* COLOR_NTP_BACKGROUND */ + border-color: $2; /* COLOR_NTP_BACKGROUND */ +} + +.section > .miniview { + background: $2; /* COLOR_NTP_BACKGROUND */ +} + #apps-section .app a { color: $8; /* COLOR_NTP_TEXT */ } diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js index 61712e4..5735b61 100644 --- a/chrome/browser/resources/ntp/apps.js +++ b/chrome/browser/resources/ntp/apps.js @@ -19,6 +19,8 @@ function getAppsCallback(data) { data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) { appsMiniview.appendChild(apps.createMiniviewElement(app)); }); + + layoutSections(); } var apps = { diff --git a/chrome/browser/resources/ntp/most_visited.css b/chrome/browser/resources/ntp/most_visited.css index 25366b8..0bb6735 100644 --- a/chrome/browser/resources/ntp/most_visited.css +++ b/chrome/browser/resources/ntp/most_visited.css @@ -4,7 +4,7 @@ position: relative; padding: 0; height: 366px; - margin-top: -10px; + margin-top: 0; -webkit-user-select: none; } |