OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * 'settings-section' shows a paper material themed section with a header | 7 * 'settings-section' shows a paper material themed section with a header |
8 * which shows its page title. | 8 * which shows its page title. |
9 | |
Dan Beam
2016/08/05 04:14:38
*
michaelpg
2016/08/05 05:16:08
Done.
| |
10 * The section can expand vertically to fill its container's padding edge. | |
9 * | 11 * |
10 * Example: | 12 * Example: |
11 * | 13 * |
12 * <settings-section page-title="[[pageTitle]]" section="privacy"> | 14 * <settings-section page-title="[[pageTitle]]" section="privacy"> |
13 * <!-- Insert your section controls here --> | 15 * <!-- Insert your section controls here --> |
14 * </settings-section> | 16 * </settings-section> |
15 */ | 17 */ |
16 Polymer({ | 18 |
19 // Fast out, slow in. | |
20 var EASING_FUNCTION = 'cubic-bezier(0.4, 0, 0.2, 1)'; | |
21 var EXPAND_DURATION = 350; | |
22 | |
23 var SettingsSectionElement = Polymer({ | |
17 is: 'settings-section', | 24 is: 'settings-section', |
18 | 25 |
19 properties: { | 26 properties: { |
20 /** | 27 /** |
21 * The current active route. | 28 * The current active route. |
22 */ | 29 */ |
23 currentRoute: Object, | 30 currentRoute: Object, |
24 | 31 |
25 /** | 32 /** |
26 * The section is expanded to a full-page view when this property matches | 33 * The section name should match a name specified in route.js. The |
34 * MainPageBehavior will expand this section if this section name matches | |
27 * currentRoute.section. | 35 * currentRoute.section. |
28 * | |
29 * The section name must match the name specified in settings_router.js. | |
30 */ | 36 */ |
31 section: { | 37 section: String, |
32 type: String, | 38 |
33 }, | 39 /** Title for the section header. */ |
34 | |
35 /** | |
36 * Title for the page header and navigation menu. | |
37 */ | |
38 pageTitle: String, | 40 pageTitle: String, |
39 }, | 41 }, |
42 | |
43 /** | |
44 * Freezes the section's height so its card can be removed from the flow | |
45 * without affecting the layout of the surrounding sections. | |
46 * @private | |
47 */ | |
48 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.
| |
49 var card = this.$.card; | |
50 this.style.height = this.clientHeight + 'px'; | |
51 | |
52 var cardHeight = card.offsetHeight; | |
53 var cardWidth = card.offsetWidth; | |
54 // If the section is not displayed yet (e.g., navigated directly to a | |
55 // sub-page), cardHeight and cardWidth are 0, so do not set the height or | |
56 // width explicitly. | |
57 // TODO(michaelpg): Improve this logic when refactoring | |
58 // settings-animated-pages. | |
59 if (cardHeight && cardWidth) { | |
60 // TODO(michaelpg): Temporary hack to store the height the section should | |
61 // collapse to when it closes. | |
62 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.
| |
63 | |
64 card.style.height = cardHeight + 'px'; | |
65 card.style.width = cardWidth + 'px'; | |
66 } else { | |
67 // Set an invalid value so we don't try to use it later. | |
68 card.origHeight_ = NaN; | |
69 } | |
70 | |
71 // Place the section's card at its current position but removed from the | |
72 // flow. | |
73 card.style.top = card.getBoundingClientRect().top + 'px'; | |
74 this.classList.add('frozen'); | |
75 }, | |
76 | |
77 /** After freezeDimensions, restores the section to its normal height. */ | |
78 unfreezeDimensions: function() { | |
79 if (!this.classList.contains('frozen')) | |
80 return; | |
81 this.classList.remove('frozen'); | |
82 this.$.card.style.top = ''; | |
83 this.$.card.style.height = ''; | |
84 this.$.card.style.width = ''; | |
85 this.style.height = ''; | |
86 }, | |
87 | |
88 /** | |
89 * @return {boolean} True if the section is currently rendered and not | |
90 * already expanded or transitioning. | |
91 */ | |
92 canAnimateExpand: function() { | |
93 return !this.classList.contains('expanded'); | |
94 }, | |
95 | |
96 /** | |
97 * Animates the section expanding to fill the container. The section is fixed | |
98 * in the viewport during the animation. The section adds the "expanding" | |
99 * class while the animation plays. | |
100 * | |
101 * @param {!HTMLElement} container The scrolling container to fill. | |
102 * @return {?SettingsSectionElement.AnimationConfig} | |
103 */ | |
104 animateExpand: function(container) { | |
105 var card = this.$.card; | |
106 | |
107 // The card should start at the top of the page. | |
108 var targetTop = container.getBoundingClientRect().top; | |
109 | |
110 this.classList.add('expanding'); | |
111 | |
112 // Nothing to animate. | |
113 if (!card.style.top || !card.style.height) | |
114 return null; | |
115 | |
116 // Expand the card, using minHeight. (The card must span the container's | |
117 // client height, so it must be at least 100% in case the card is too short. | |
118 // If the card is already taller than the container's client height, we | |
119 // don't want to shrink the card to 100% or the content will overflow, so | |
120 // we can't use height, and animating height wouldn't look right anyway.) | |
121 var keyframes = [{ | |
122 top: card.style.top, | |
123 minHeight: card.style.height, | |
124 easing: EASING_FUNCTION, | |
125 }, { | |
126 top: targetTop + 'px', | |
127 minHeight: 'calc(100% - ' + targetTop + 'px)', | |
128 }]; | |
129 var options = /** @type {!KeyframeEffectOptions} */({ | |
130 duration: EXPAND_DURATION | |
131 }); | |
132 // TODO(michaelpg): Change elevation of sections. | |
133 return {card: card, keyframes: keyframes, options: options}; | |
134 }, | |
135 | |
136 /** | |
137 * Cleans up after animateExpand(). | |
138 * @param {boolean} finished Whether the animation finished successfully. | |
139 */ | |
140 cleanUpAnimateExpand: function(finished) { | |
141 if (finished) { | |
142 this.classList.add('expanded'); | |
143 this.$.card.style.top = ''; | |
144 this.$.header.hidden = true; | |
145 this.style.height = ''; | |
146 } | |
147 | |
148 this.classList.remove('expanding'); | |
149 this.$.card.style.height = ''; | |
150 this.$.card.style.width = ''; | |
151 }, | |
152 | |
153 /** @return {boolean} True if the section is currently expanded. */ | |
154 canAnimateCollapse: function() { | |
155 return this.classList.contains('expanded'); | |
156 }, | |
157 | |
158 /** | |
159 * Collapses an expanded section's card back into position in the main page. | |
160 * Adds the "expanding" class during the animation. | |
161 * @param {!HTMLElement} container The scrolling container the card fills. | |
162 * @param {number} prevScrollTop scrollTop of the container before this | |
163 * section expanded. | |
164 * @return {?SettingsSectionElement.AnimationConfig} | |
165 */ | |
166 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.
| |
167 this.$.header.hidden = false; | |
168 | |
169 var startingTop = container.getBoundingClientRect().top; | |
170 | |
171 var card = this.$.card; | |
172 var cardHeightStart = card.clientHeight; | |
173 var cardWidthStart = card.clientWidth; | |
174 | |
175 this.classList.add('collapsing'); | |
176 this.classList.remove('expanding', 'expanded'); | |
177 | |
178 // If we navigated here directly, we don't know the original height of the | |
179 // section, so we skip the animation. | |
180 // TODO(michaelpg): remove this condition once sliding is implemented. | |
181 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
| |
182 return null; | |
183 | |
184 // Restore the section to its proper height to make room for the card. | |
185 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)
| |
186 | |
187 // TODO(michaelpg): this should be in MainPageBehavior(), but we need to | |
188 // wait until the full page height is available (setting the section | |
189 // height). | |
190 container.scrollTop = prevScrollTop; | |
191 | |
192 // The card is unpositioned, so use its position as the ending state, | |
193 // but account for scroll. | |
194 var targetTop = card.getBoundingClientRect().top - container.scrollTop; | |
195 | |
196 // Account for the section header. | |
197 var headerStyle = getComputedStyle(this.$.header); | |
198 targetTop += this.$.header.offsetHeight + | |
199 parseInt(headerStyle.marginBottom, 10) + | |
200 parseInt(headerStyle.marginTop, 10); | |
201 | |
202 var keyframes = [{ | |
203 top: startingTop + 'px', | |
204 minHeight: cardHeightStart + 'px', | |
205 easing: EASING_FUNCTION, | |
206 }, { | |
207 top: targetTop + 'px', | |
208 minHeight: card.origHeight_ + 'px', | |
209 }]; | |
210 var options = /** @type {!KeyframeEffectOptions} */({ | |
211 duration: EXPAND_DURATION | |
212 }); | |
213 | |
214 card.style.width = cardWidthStart + 'px'; | |
215 | |
216 return {card: card, keyframes: keyframes, options: options}; | |
217 }, | |
218 | |
219 /** | |
220 * Cleans up after animateCollapse(). | |
221 * @param {boolean} finished Whether the animation finished successfully. | |
222 */ | |
223 cleanUpAnimateCollapse: function(finished) { | |
224 if (finished) | |
225 this.$.card.style.width = ''; | |
226 }, | |
40 }); | 227 }); |
228 | |
229 /** | |
230 * Information needed by TransitionBehavior to schedule animations. | |
231 * @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.
| |
232 * card: !HTMLElement, | |
233 * keyframes: !Array<!Object>, | |
234 * options: !KeyframeEffectOptions | |
235 * }} | |
236 */ | |
237 SettingsSectionElement.AnimationConfig; | |
OLD | NEW |