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 e0e3afd11a6021b48301e9320e1f14bb1459b0fd..7833f39ba8b31db0bb47bbe0c20c88c58ed6ad2b 100644 |
--- a/chrome/browser/resources/settings/settings_page/settings_section.js |
+++ b/chrome/browser/resources/settings/settings_page/settings_section.js |
@@ -16,10 +16,6 @@ |
* </settings-section> |
*/ |
-// 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', |
@@ -43,6 +39,18 @@ var SettingsSectionElement = Polymer({ |
value: false, |
reflectToAttribute: true, |
}, |
+ |
+ /** |
+ * Original height of the collapsed section, used as the target height when |
+ * collapsing after being expanded. |
+ * TODO(michaelpg): Get the height dynamically when collapsing using the |
+ * card's main page. |
+ * @private |
+ */ |
+ collapsedHeight_: { |
+ type: Number, |
+ value: NaN, |
+ }, |
}, |
/** |
@@ -61,18 +69,9 @@ var SettingsSectionElement = Polymer({ |
// 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; |
- |
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 |
@@ -96,138 +95,158 @@ var SettingsSectionElement = Polymer({ |
* already expanded or transitioning. |
*/ |
canAnimateExpand: function() { |
- return !this.classList.contains('expanded'); |
+ return !this.classList.contains('expanding') && |
+ !this.classList.contains('expanded') && this.$.card.clientHeight > 0; |
}, |
/** |
* 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. |
+ * in the viewport during the animation, making it safe to adjust the rest of |
+ * the DOM after calling this. The section adds the "expanding" class while |
+ * the animation plays and "expanded" after it finishes. |
* |
* @param {!HTMLElement} container The scrolling container to fill. |
- * @return {?settings.animation.Animation} Animation played, if any. |
+ * @return {!settings.animation.Animation} |
*/ |
animateExpand: function(container) { |
- var card = this.$.card; |
- |
- // The card should start at the top of the page. |
- var targetTop = container.getBoundingClientRect().top; |
+ // Set the section's height so its card can be removed from the flow |
+ // without affecting the surrounding sections during the animation. |
+ this.collapsedHeight_ = this.clientHeight; |
+ this.style.height = this.collapsedHeight_ + 'px'; |
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 new settings.animation.Animation(card, keyframes, options); |
- }, |
+ // Start the card in place, at its distance from the container's padding. |
+ var startTop = this.$.card.getBoundingClientRect().top + 'px'; |
+ var startHeight = this.$.card.clientHeight + 'px'; |
- /** |
- * Cleans up after animateExpand(). |
- * @param {boolean} finished Whether the animation finished successfully. |
- */ |
- cleanUpAnimateExpand: function(finished) { |
- if (finished) { |
+ // Target position is the container's top edge in the viewport. |
+ var containerTop = container.getBoundingClientRect().top; |
+ var endTop = containerTop + 'px'; |
+ // The card should stretch from the bottom of the toolbar to the bottom of |
+ // the page. calc(100% - top) lets the card resize if the window resizes. |
+ var endHeight = 'calc(100% - ' + containerTop + 'px)'; |
+ |
+ var animation = |
+ this.animateCard_('fixed', startTop, endTop, startHeight, endHeight); |
+ animation.finished.then(function() { |
this.classList.add('expanded'); |
- this.$.card.style.top = ''; |
- this.$.header.hidden = true; |
+ }.bind(this), function() {}).then(function() { |
+ // Unset these changes whether the animation finished or canceled. |
+ this.classList.remove('expanding'); |
this.style.height = ''; |
- } |
- |
- this.classList.remove('expanding'); |
- this.$.card.style.height = ''; |
- this.$.card.style.width = ''; |
+ }.bind(this)); |
+ return animation; |
}, |
/** @return {boolean} True if the section is currently expanded. */ |
canAnimateCollapse: function() { |
- return this.classList.contains('expanded'); |
+ return this.classList.contains('expanded') && this.clientHeight > 0 && |
+ !Number.isNaN(this.collapsedHeight_); |
+ }, |
+ |
+ /** |
+ * Prepares for the animation before the other sections become visible. |
+ * Call before animateCollapse(). |
+ * @param {!HTMLElement} container |
+ */ |
+ setUpAnimateCollapse: function(container) { |
+ // Prepare the dimensions and set position: fixed. |
+ this.$.card.style.width = this.$.card.clientWidth + 'px'; |
+ this.$.card.style.height = this.$.card.clientHeight + 'px'; |
+ this.$.card.style.top = container.getBoundingClientRect().top + 'px'; |
+ this.$.card.style.position = 'fixed'; |
+ |
+ // The section can now collapse back into its original height the page so |
+ // the other sections appear in the right places. |
+ this.classList.remove('expanded'); |
+ this.classList.add('collapsing'); |
+ this.style.height = this.collapsedHeight_ + 'px'; |
}, |
/** |
* Collapses an expanded section's card back into position in the main page. |
- * Adds the "expanding" class during the animation. |
+ * Call after calling animateCollapse(), unhiding other content and scrolling. |
* @param {!HTMLElement} container The scrolling container the card fills. |
- * @param {number} prevScrollTop scrollTop of the container before this |
- * section expanded. |
- * @return {?settings.animation.Animation} Animation played, if any. |
+ * @return {!settings.animation.Animation} |
*/ |
- animateCollapse: function(container, prevScrollTop) { |
- this.$.header.hidden = false; |
+ animateCollapse: function(container) { |
+ // Make the card position: absolute, so scrolling is less of a crapshoot. |
+ // First find the current distance between this section and the card using |
+ // fixed coordinates; the absolute distance will be the same. |
+ var fixedCardTop = this.$.card.getBoundingClientRect().top; |
+ var fixedSectionTop = this.getBoundingClientRect().top; |
+ var distance = fixedCardTop - fixedSectionTop; |
+ |
+ // The target position is right below our header. |
+ var headerStyle = getComputedStyle(this.$.header); |
+ var cardTargetTop = this.$.header.offsetHeight + |
+ parseFloat(headerStyle.marginBottom) + |
+ parseFloat(headerStyle.marginTop); |
- var startingTop = container.getBoundingClientRect().top; |
+ // Start the card at its current height and distance from our top. |
+ var startTop = distance + 'px'; |
+ var startHeight = this.$.card.style.height; |
- var card = this.$.card; |
- var cardHeightStart = card.clientHeight; |
- var cardWidthStart = card.clientWidth; |
+ // End at the bottom of our header. |
+ var endTop = cardTargetTop + 'px'; |
+ var endHeight = (this.collapsedHeight_ - cardTargetTop) + 'px'; |
- this.classList.add('collapsing'); |
- this.classList.remove('expanding', 'expanded'); |
+ // The card no longer needs position: fixed. |
+ this.$.card.style.position = ''; |
- // 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 (Number.isNaN(card.origHeight_)) |
- return null; |
- |
- // Restore the section to its proper height to make room for the card. |
- this.style.height = (this.clientHeight + card.origHeight_) + 'px'; |
+ // Collapse this section, animate the card into place, and remove its |
+ // other properties. |
+ var animation = |
+ this.animateCard_('absolute', startTop, endTop, startHeight, endHeight); |
+ this.$.card.style.width = ''; |
+ this.$.card.style.height = ''; |
+ this.$.card.style.top = ''; |
- // 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; |
+ animation.finished.then(function() { |
+ this.classList.remove('expanded'); |
+ }.bind(this), function() {}).then(function() { |
+ // The card now determines the section's height automatically. |
+ this.style.height = ''; |
+ this.classList.remove('collapsing'); |
+ }.bind(this)); |
+ return animation; |
+ }, |
- // The card is unpositioned, so use its position as the ending state, |
- // but account for scroll. |
- var targetTop = card.getBoundingClientRect().top - container.scrollTop; |
+ /** |
+ * Helper function to animate the card's position and height. |
+ * @param {string} position CSS position property. |
+ * @param {string} startTop Initial top value. |
+ * @param {string} endTop Target top value. |
+ * @param {string} startHeight Initial height value. |
+ * @param {string} endHeight Target height value. |
+ * @return {!settings.animation.Animation} |
+ * @private |
+ */ |
+ animateCard_: function(position, startTop, endTop, startHeight, endHeight) { |
+ // Width does not change. |
+ var width = this.$.card.clientWidth + 'px'; |
+ |
+ var startFrame = { |
+ position: position, |
+ width: width, |
+ top: startTop, |
+ height: startHeight, |
+ }; |
+ |
+ var endFrame = { |
+ position: position, |
+ width: width, |
+ top: endTop, |
+ height: endHeight, |
+ }; |
- // 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 |
+ duration: settings.animation.Timing.DURATION, |
+ easing: settings.animation.Timing.EASING, |
}); |
- card.style.width = cardWidthStart + 'px'; |
- |
- return new settings.animation.Animation(card, keyframes, options); |
- }, |
- |
- /** |
- * Cleans up after animateCollapse(). |
- * @param {boolean} finished Whether the animation finished successfully. |
- */ |
- cleanUpAnimateCollapse: function(finished) { |
- if (finished) |
- this.$.card.style.width = ''; |
+ return new settings.animation.Animation( |
+ this.$.card, [startFrame, endFrame], options); |
}, |
}); |