Chromium Code Reviews| Index: chrome/browser/resources/settings/settings_page/expand_card_transition.js |
| diff --git a/chrome/browser/resources/settings/settings_page/expand_card_transition.js b/chrome/browser/resources/settings/settings_page/expand_card_transition.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..886b485be4a82be66df74b902b229ebef0062f10 |
| --- /dev/null |
| +++ b/chrome/browser/resources/settings/settings_page/expand_card_transition.js |
| @@ -0,0 +1,182 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +cr.define('settings', function() { |
| + /** |
| + * Expands a card to fill its container's client height, so it covers the |
| + * container from the top padding edge to the bottom padding edge. |
| + * @see https://www.w3.org/TR/cssom-view-1/#terminology |
| + * @constructor |
| + * @implements {settings.animation.AnimationGroup} |
| + * @param {!HTMLElement} card Card to expand. |
| + * @param {!HTMLElement} container Container whose height the card will span. |
| + */ |
| + function ExpandCardTransition(card, container) { |
| + /** @private */ |
| + this.card_ = card; |
| + /** @private */ |
| + this.container_ = container; |
| + } |
| + |
| + ExpandCardTransition.prototype = { |
| + __proto__: settings.animation.AnimationGroup.prototype, |
| + |
| + /** @override */ |
| + play: function() { |
| + // If we're running this transition before anything else, we won't have |
| + // the information we need, so just expand immediately and finish. |
| + if (typeof this.card_.origHeight_ == 'undefined' || |
| + this.card_.style.top == '' || this.card_.style.height == '') { |
| + this.finished = Promise.resolve(); |
| + return this.finished; |
| + } |
| + |
| + // Align the card with the container's padding edge. |
| + var startingTop = this.card_.getBoundingClientRect().top; |
| + |
| + // Target position is the container's top edge in the viewport. |
| + var targetTop = this.container_.getBoundingClientRect().top; |
| + |
| + // The target height shouldn't use the container's current height, because |
| + // the container may resize when the window resizes. And height: 100% |
| + // wouldn't use the container's height because we're position: fixed. |
| + // |
| + // Instead, find the part of the window height *not* used by the container |
| + // (e.g., for a toolbar) and calc the height dynamically. This assumes the |
| + // excluded height stays constant. |
| + var excludedHeight = window.innerHeight - this.container_.clientHeight; |
| + var targetHeight = 'calc(100% - ' + excludedHeight + 'px)'; |
| + |
| + // Expand the card. The card's height must be 100% of the container's |
| + // height or taller, so we use minHeight rather than height. |
| + var keyframes = [{ |
| + top: startingTop + 'px', |
| + minHeight: this.card_.style.height, |
| + easing: settings.animation.Timing.EASING, |
| + }, { |
| + top: targetTop + 'px', |
| + minHeight: 'calc(100% - ' + targetTop + 'px)', |
| + }]; |
| + var options = /** @type {!KeyframeEffectOptions} */({ |
| + duration: settings.animation.Timing.DURATION, |
| + }); |
| + |
| + /** @type {?settings.animation.Animation} */ |
| + this.animation_ = |
| + new settings.animation.Animation(this.card_, keyframes, options); |
| + this.finished = this.animation_.finished; |
| + return this.finished; |
| + }, |
| + |
| + /** @override */ |
| + finish: function() { |
| + if (!this.animation_) |
| + return; |
| + this.animation_.finish(); |
| + this.animation_ = null; |
| + }, |
| + |
| + /** @override */ |
| + cancel: function() { |
| + if (!this.animation_) |
| + return; |
| + this.animation_.cancel(); |
| + this.animation_ = null; |
| + }, |
| + |
| + /** @override */ |
| + finished: null, |
| + }; |
| + |
| + /** |
| + * Collapses an expanded card back into its original section. |
| + * @constructor |
| + * @implements {settings.animation.AnimationGroup} |
| + * @param {!SettingsSectionElement} section Section that contains the card. |
| + * @param {!HTMLElement} container Container the card currently spans. |
| + */ |
| + function CollapseCardTransition(section, container) { |
| + /** @private {!HTMLElement} */ |
| + this.card_ = assert(section.$['card']); |
|
Dan Beam
2016/07/12 02:01:54
can you make this not poke into $.idName? can we
michaelpg
2016/07/20 22:10:57
Done.
|
| + /** @private */ |
| + this.section_ = section; |
| + /** @private */ |
| + this.container_ = container; |
| + } |
| + |
| + CollapseCardTransition.prototype = { |
| + __proto__: settings.animation.AnimationGroup.prototype, |
| + |
| + /** Sets up the transition before other page content has been unhidden. */ |
|
Dan Beam
2016/07/12 02:01:54
can you note how this should be used? i.e. call b
michaelpg
2016/07/20 22:10:57
Done.
|
| + setUp: function() { |
| + this.card_.style.width = this.card_.clientWidth + 'px'; |
| + this.card_.style.height = this.card_.clientHeight + 'px'; |
| + }, |
| + |
| + /** @override */ |
| + play: function() { |
| + var startingTop = this.container_.getBoundingClientRect().top; |
| + |
| + // The card is unpositioned, so use its position as the ending state, |
| + // but account for scroll. |
| + var targetTop = this.card_.getBoundingClientRect().top - |
| + this.container_.scrollTop; |
| + |
| + // Account for the section header. |
| + var headerStyle = getComputedStyle(this.section_.$['header']); |
|
Dan Beam
2016/07/12 02:01:54
same here: can we expose header rather than use th
michaelpg
2016/07/20 22:10:57
Done.
|
| + targetTop += this.section_.$['header'].offsetHeight + |
| + parseFloat(headerStyle.marginBottom) + |
| + parseFloat(headerStyle.marginTop); |
| + |
| + var keyframes = [{ |
| + top: startingTop + 'px', |
| + minHeight: this.card_.style.height, |
| + easing: settings.animation.Timing.EASING, |
| + }, { |
| + top: targetTop + 'px', |
| + minHeight: |
| + /** @type {{origHeight_: number}} */(this.card_).origHeight_ + 'px', |
| + }]; |
| + var options = /** @type {!KeyframeEffectOptions} */({ |
| + duration: settings.animation.Timing.DURATION, |
| + }); |
| + |
| + this.card_.style.height = ''; |
| + |
| + /** @type {?settings.animation.Animation} */ |
| + this.animation_ = |
| + new settings.animation.Animation(this.card_, keyframes, options); |
| + this.finished = this.animation_.finished; |
| + // Clean up after the animation finishes or cancels. |
| + this.finished.catch(function() {}).then(function() { |
| + this.card_.style.width = ''; |
| + }.bind(this)); |
| + return this.finished; |
| + }, |
| + |
| + /** @override */ |
| + finish: function() { |
| + if (!this.animation_) |
| + return; |
| + this.animation_.finish(); |
| + this.animation_ = null; |
| + }, |
| + |
| + /** @override */ |
| + cancel: function() { |
| + if (!this.animation_) |
| + return; |
| + this.animation_.cancel(); |
| + this.animation_ = null; |
| + }, |
| + |
| + /** @override */ |
| + finished: null, |
| + }; |
| + |
| + return { |
| + CollapseCardTransition: CollapseCardTransition, |
| + ExpandCardTransition: ExpandCardTransition, |
| + }; |
| +}); |