Chromium Code Reviews| Index: chrome/browser/resources/settings/settings_page/settings_section.js |
| diff --git a/chrome/browser/resources/settings/settings_page/settings_section.js b/chrome/browser/resources/settings/settings_page/settings_section.js |
| index 1149e2ea81b7aa0fd017246548977f7e8916be2b..be96b4c8d3e1a7a5dd99b7a71fe71f2faa3eb114 100644 |
| --- a/chrome/browser/resources/settings/settings_page/settings_section.js |
| +++ b/chrome/browser/resources/settings/settings_page/settings_section.js |
| @@ -6,6 +6,8 @@ |
| * @fileoverview |
| * 'settings-section' shows a paper material themed section with a header |
| * which shows its page title. |
| + |
|
Dan Beam
2016/08/05 04:14:38
*
michaelpg
2016/08/05 05:16:08
Done.
|
| + * The section can expand vertically to fill its container's padding edge. |
| * |
| * Example: |
| * |
| @@ -13,7 +15,12 @@ |
| * <!-- Insert your section controls here --> |
| * </settings-section> |
| */ |
| -Polymer({ |
| + |
| +// Fast out, slow in. |
| +var EASING_FUNCTION = 'cubic-bezier(0.4, 0, 0.2, 1)'; |
| +var EXPAND_DURATION = 350; |
| + |
| +var SettingsSectionElement = Polymer({ |
| is: 'settings-section', |
| properties: { |
| @@ -23,18 +30,208 @@ Polymer({ |
| currentRoute: Object, |
| /** |
| - * The section is expanded to a full-page view when this property matches |
| + * The section name should match a name specified in route.js. The |
| + * MainPageBehavior will expand this section if this section name matches |
| * currentRoute.section. |
| - * |
| - * The section name must match the name specified in settings_router.js. |
| */ |
| - section: { |
| - type: String, |
| - }, |
| + section: String, |
| - /** |
| - * Title for the page header and navigation menu. |
| - */ |
| + /** Title for the section header. */ |
| pageTitle: String, |
| }, |
| + |
| + /** |
| + * Freezes the section's height so its card can be removed from the flow |
| + * without affecting the layout of the surrounding sections. |
| + * @private |
| + */ |
| + freezeDimensions: function() { |
|
michaelpg
2016/08/05 02:09:11
The contents of the following functions were moved
Dan Beam
2016/08/05 04:14:38
does this need a
if (this.classList.contains('fro
michaelpg
2016/08/05 05:16:08
Probably? I'm reluctant to make changes like that.
|
| + var card = this.$.card; |
| + this.style.height = this.clientHeight + 'px'; |
| + |
| + var cardHeight = card.offsetHeight; |
| + var cardWidth = card.offsetWidth; |
| + // If the section is not displayed yet (e.g., navigated directly to a |
| + // sub-page), cardHeight and cardWidth are 0, so do not set the height or |
| + // width explicitly. |
| + // TODO(michaelpg): Improve this logic when refactoring |
| + // settings-animated-pages. |
| + if (cardHeight && cardWidth) { |
| + // TODO(michaelpg): Temporary hack to store the height the section should |
| + // collapse to when it closes. |
| + card.origHeight_ = cardHeight; |
|
michaelpg
2016/08/05 02:09:11
I could take care of this TODO now with a property
Dan Beam
2016/08/05 04:14:38
Acknowledged.
|
| + |
| + card.style.height = cardHeight + 'px'; |
| + card.style.width = cardWidth + 'px'; |
| + } else { |
| + // Set an invalid value so we don't try to use it later. |
| + card.origHeight_ = NaN; |
| + } |
| + |
| + // Place the section's card at its current position but removed from the |
| + // flow. |
| + card.style.top = card.getBoundingClientRect().top + 'px'; |
| + this.classList.add('frozen'); |
| + }, |
| + |
| + /** After freezeDimensions, restores the section to its normal height. */ |
| + unfreezeDimensions: function() { |
| + if (!this.classList.contains('frozen')) |
| + return; |
| + this.classList.remove('frozen'); |
| + this.$.card.style.top = ''; |
| + this.$.card.style.height = ''; |
| + this.$.card.style.width = ''; |
| + this.style.height = ''; |
| + }, |
| + |
| + /** |
| + * @return {boolean} True if the section is currently rendered and not |
| + * already expanded or transitioning. |
| + */ |
| + canAnimateExpand: function() { |
| + return !this.classList.contains('expanded'); |
| + }, |
| + |
| + /** |
| + * Animates the section expanding to fill the container. The section is fixed |
| + * in the viewport during the animation. The section adds the "expanding" |
| + * class while the animation plays. |
| + * |
| + * @param {!HTMLElement} container The scrolling container to fill. |
| + * @return {?SettingsSectionElement.AnimationConfig} |
| + */ |
| + animateExpand: function(container) { |
| + var card = this.$.card; |
| + |
| + // The card should start at the top of the page. |
| + var targetTop = container.getBoundingClientRect().top; |
| + |
| + this.classList.add('expanding'); |
| + |
| + // Nothing to animate. |
| + if (!card.style.top || !card.style.height) |
| + return null; |
| + |
| + // Expand the card, using minHeight. (The card must span the container's |
| + // client height, so it must be at least 100% in case the card is too short. |
| + // If the card is already taller than the container's client height, we |
| + // don't want to shrink the card to 100% or the content will overflow, so |
| + // we can't use height, and animating height wouldn't look right anyway.) |
| + var keyframes = [{ |
| + top: card.style.top, |
| + minHeight: card.style.height, |
| + easing: EASING_FUNCTION, |
| + }, { |
| + top: targetTop + 'px', |
| + minHeight: 'calc(100% - ' + targetTop + 'px)', |
| + }]; |
| + var options = /** @type {!KeyframeEffectOptions} */({ |
| + duration: EXPAND_DURATION |
| + }); |
| + // TODO(michaelpg): Change elevation of sections. |
| + return {card: card, keyframes: keyframes, options: options}; |
| + }, |
| + |
| + /** |
| + * Cleans up after animateExpand(). |
| + * @param {boolean} finished Whether the animation finished successfully. |
| + */ |
| + cleanUpAnimateExpand: function(finished) { |
| + if (finished) { |
| + this.classList.add('expanded'); |
| + this.$.card.style.top = ''; |
| + this.$.header.hidden = true; |
| + this.style.height = ''; |
| + } |
| + |
| + this.classList.remove('expanding'); |
| + this.$.card.style.height = ''; |
| + this.$.card.style.width = ''; |
| + }, |
| + |
| + /** @return {boolean} True if the section is currently expanded. */ |
| + canAnimateCollapse: function() { |
| + return this.classList.contains('expanded'); |
| + }, |
| + |
| + /** |
| + * Collapses an expanded section's card back into position in the main page. |
| + * Adds the "expanding" class during the animation. |
| + * @param {!HTMLElement} container The scrolling container the card fills. |
| + * @param {number} prevScrollTop scrollTop of the container before this |
| + * section expanded. |
| + * @return {?SettingsSectionElement.AnimationConfig} |
| + */ |
| + animateCollapse: function(container, prevScrollTop) { |
|
Dan Beam
2016/08/05 04:14:38
both animateCollapse and animateExpand are weird t
michaelpg
2016/08/05 05:16:08
Acknowledged. I'll work on that in a followup CL.
|
| + this.$.header.hidden = false; |
| + |
| + var startingTop = container.getBoundingClientRect().top; |
| + |
| + var card = this.$.card; |
| + var cardHeightStart = card.clientHeight; |
| + var cardWidthStart = card.clientWidth; |
| + |
| + this.classList.add('collapsing'); |
| + this.classList.remove('expanding', 'expanded'); |
| + |
| + // If we navigated here directly, we don't know the original height of the |
| + // section, so we skip the animation. |
| + // TODO(michaelpg): remove this condition once sliding is implemented. |
| + if (isNaN(card.origHeight_)) |
|
Dan Beam
2016/08/05 04:14:38
nit: use isNaN or Number.isNan() consistently (I v
michaelpg
2016/08/05 05:16:08
Done (cut and pasted code)
I prefer Number.isNaN
|
| + return null; |
| + |
| + // Restore the section to its proper height to make room for the card. |
| + this.style.height = this.clientHeight + card.origHeight_ + 'px'; |
|
Dan Beam
2016/08/05 04:14:38
nit: use parens with differently typed args that e
michaelpg
2016/08/05 05:16:08
Done (cut and pasted code)
|
| + |
| + // TODO(michaelpg): this should be in MainPageBehavior(), but we need to |
| + // wait until the full page height is available (setting the section |
| + // height). |
| + container.scrollTop = prevScrollTop; |
| + |
| + // The card is unpositioned, so use its position as the ending state, |
| + // but account for scroll. |
| + var targetTop = card.getBoundingClientRect().top - container.scrollTop; |
| + |
| + // Account for the section header. |
| + var headerStyle = getComputedStyle(this.$.header); |
| + targetTop += this.$.header.offsetHeight + |
| + parseInt(headerStyle.marginBottom, 10) + |
| + parseInt(headerStyle.marginTop, 10); |
| + |
| + var keyframes = [{ |
| + top: startingTop + 'px', |
| + minHeight: cardHeightStart + 'px', |
| + easing: EASING_FUNCTION, |
| + }, { |
| + top: targetTop + 'px', |
| + minHeight: card.origHeight_ + 'px', |
| + }]; |
| + var options = /** @type {!KeyframeEffectOptions} */({ |
| + duration: EXPAND_DURATION |
| + }); |
| + |
| + card.style.width = cardWidthStart + 'px'; |
| + |
| + return {card: card, keyframes: keyframes, options: options}; |
| + }, |
| + |
| + /** |
| + * Cleans up after animateCollapse(). |
| + * @param {boolean} finished Whether the animation finished successfully. |
| + */ |
| + cleanUpAnimateCollapse: function(finished) { |
| + if (finished) |
| + this.$.card.style.width = ''; |
| + }, |
| }); |
| + |
| +/** |
| + * Information needed by TransitionBehavior to schedule animations. |
| + * @typedef {{ |
|
michaelpg
2016/08/05 02:09:11
This typedef is temporary, the animations will eve
Dan Beam
2016/08/05 04:14:38
Acknowledged.
|
| + * card: !HTMLElement, |
| + * keyframes: !Array<!Object>, |
| + * options: !KeyframeEffectOptions |
| + * }} |
| + */ |
| +SettingsSectionElement.AnimationConfig; |