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 | |
dschuyler
2016/08/04 18:36:51
Maybe remove blank line or add an '*'?
| |
10 * The section can expand vertically to to 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 Polymer({ |
17 is: 'settings-section', | 19 is: 'settings-section', |
18 | 20 |
19 properties: { | 21 properties: { |
20 /** | 22 /** |
21 * The current active route. | 23 * The current active route. |
22 */ | 24 */ |
23 currentRoute: Object, | 25 currentRoute: Object, |
24 | 26 |
25 /** | 27 /** |
26 * The section is expanded to a full-page view when this property matches | 28 * The section name should match a name specified in route.js. The |
29 * MainPageBehavior will expand this section if this section name matches | |
27 * currentRoute.section. | 30 * currentRoute.section. |
28 * | |
29 * The section name must match the name specified in settings_router.js. | |
30 */ | 31 */ |
31 section: { | 32 section: String, |
32 type: String, | 33 |
33 }, | 34 /** Title for the section header. */ |
35 pageTitle: String, | |
34 | 36 |
35 /** | 37 /** |
36 * Title for the page header and navigation menu. | 38 * Original height of the collapsed section, used as the target height when |
39 * collapsing after being expanded. | |
40 * TODO(michaelpg): Get the height dynamically when collapsing using the | |
41 * card's main page. | |
42 * @private | |
37 */ | 43 */ |
38 pageTitle: String, | 44 collapsedHeight_: { |
45 type: Number, | |
46 value: NaN, | |
47 }, | |
48 }, | |
49 | |
50 /** | |
51 * @return {boolean} True if the section is currently rendered and not | |
52 * already expanded or transitioning. | |
53 */ | |
54 canAnimateExpand: function() { | |
55 return !this.classList.contains('expanding') && | |
56 !this.classList.contains('expanded') && this.$.card.clientHeight > 0; | |
57 }, | |
58 | |
59 /** | |
60 * Animates the section expanding to fill the container. The section is fixed | |
61 * in the viewport during the animation, making it safe to adjust the rest of | |
62 * the DOM after calling this. The section adds the 'expanding' class while | |
63 * the animation plays and 'expanded' after it finishes. | |
64 * | |
65 * The animation does not "last", so the parent must properly position it | |
66 * afterwards in its container. | |
67 * | |
68 * @param {!HTMLElement} container The scrolling container to fill. | |
69 * @return {!settings.animation.Animation} | |
70 */ | |
71 animateExpand: function(container) { | |
72 // Set the section's height so its card can be removed from the flow | |
73 // without affecting the surrounding sections during the animation. | |
74 this.collapsedHeight_ = this.clientHeight; | |
75 this.style.height = this.collapsedHeight_ + 'px'; | |
76 | |
77 this.classList.add('expanding'); | |
78 | |
79 // Start the card in place, at its distance from the container's padding. | |
80 var startTop = this.$.card.getBoundingClientRect().top + 'px'; | |
81 var startHeight = this.$.card.clientHeight + 'px'; | |
82 | |
83 // Target position is the container's top edge in the viewport. | |
84 var containerTop = container.getBoundingClientRect().top; | |
85 var endTop = containerTop + 'px'; | |
86 // The card should stretch from the bottom of the toolbar to the bottom of | |
87 // the page. calc(100% - top) lets the card resize if the window resizes. | |
88 var endHeight = 'calc(100% - ' + containerTop + 'px)'; | |
89 | |
90 var animation = | |
91 this.animateCard_('fixed', startTop, endTop, startHeight, endHeight); | |
92 | |
93 // Whether the animation fails or succeeds, clean up the properties we set. | |
94 animation.finished.catch(function() {}).then(function() { | |
95 this.classList.remove('expanding'); | |
96 this.style.height = ''; | |
97 }.bind(this)); | |
98 return animation; | |
99 }, | |
100 | |
101 /** @return {boolean} True if the section is currently expanded. */ | |
102 canAnimateCollapse: function() { | |
103 return this.classList.contains('expanded') && this.clientHeight > 0 && | |
104 !Number.isNaN(this.collapsedHeight_); | |
105 }, | |
106 | |
107 /** | |
108 * Prepares for the animation before the other sections become visible. | |
109 * Call before animateCollapse(). | |
110 */ | |
111 setUpAnimateCollapse: function(container) { | |
112 // Prepare the dimensions and set position: fixed. | |
113 this.$.card.style.width = this.$.card.clientWidth + 'px'; | |
114 this.$.card.style.height = this.$.card.clientHeight + 'px'; | |
115 this.$.card.style.top = container.getBoundingClientRect().top + 'px'; | |
116 this.$.card.style.position = 'fixed'; | |
117 | |
118 // The section can now collapse back into its original height the page so | |
119 // the other sections appear in the right places. | |
120 this.classList.add('collapsing'); | |
121 this.style.height = this.collapsedHeight_ + 'px'; | |
122 }, | |
123 | |
124 /** | |
125 * Collapses an expanded section's card back into position in the main page. | |
126 * Call after calling animateCollapse(), unhiding other content and scrolling. | |
127 * @param {!HTMLElement} container The scrolling container the card fills. | |
128 * @return {!settings.animation.Animation} | |
129 */ | |
130 animateCollapse: function(container) { | |
131 // Make the card position: absolute, so scrolling is less of a crapshoot. | |
132 // First find the current distance between this section and the card using | |
133 // fixed coordinates; the absolute distance will be the same. | |
134 var fixedCardTop = this.$.card.getBoundingClientRect().top; | |
135 var fixedSectionTop = this.getBoundingClientRect().top; | |
136 var distance = fixedCardTop - fixedSectionTop; | |
137 | |
138 // The target position is right below our header. | |
139 var headerStyle = getComputedStyle(this.$.header); | |
140 var cardTargetTop = this.$.header.offsetHeight + | |
141 parseFloat(headerStyle.marginBottom) + | |
142 parseFloat(headerStyle.marginTop); | |
143 | |
144 // Start the card at its current height and distance from our top. | |
145 var startTop = distance + 'px'; | |
146 var startHeight = this.$.card.style.height; | |
147 | |
148 // End at the bottom of our header. | |
149 var endTop = cardTargetTop + 'px'; | |
150 var endHeight = (this.collapsedHeight_ - cardTargetTop) + 'px'; | |
151 | |
152 // The card no longer needs position: fixed. | |
153 this.$.card.style.position = ''; | |
154 | |
155 // Collapse this section, animate the card into place, and remove its | |
156 // other properties. | |
157 var animation = | |
158 this.animateCard_('absolute', startTop, endTop, startHeight, endHeight); | |
159 this.$.card.style.width = ''; | |
160 this.$.card.style.height = ''; | |
161 this.$.card.style.top = ''; | |
162 | |
163 // Whether the animation fails or succeeds, clean up the properties we set. | |
164 animation.finished.catch(function() {}).then(function() { | |
165 // The card now determines the section's height automatically. | |
166 this.style.height = ''; | |
167 this.classList.remove('collapsing'); | |
168 }.bind(this)); | |
169 return animation; | |
170 }, | |
171 | |
172 /** | |
173 * Helper function to animate the card's position and height. | |
174 * @param {string} position CSS position property. | |
175 * @param {string} startTop Initial top value. | |
176 * @param {string} endTop Target top value. | |
177 * @param {string} startHeight Initial height value. | |
178 * @param {string} endHeight Target height value. | |
179 * @return {!settings.animation.Animation} | |
180 * @private | |
181 */ | |
182 animateCard_: function(position, startTop, endTop, startHeight, endHeight) { | |
183 // Width does not change. | |
184 var width = this.$.card.clientWidth + 'px'; | |
185 | |
186 var startFrame = { | |
187 position: position, | |
188 width: width, | |
189 top: startTop, | |
190 height: startHeight, | |
191 }; | |
192 | |
193 var endFrame = { | |
194 position: position, | |
195 width: width, | |
196 top: endTop, | |
197 height: endHeight, | |
198 }; | |
199 | |
200 var options = /** @type {!KeyframeEffectOptions} */({ | |
201 duration: settings.animation.Timing.DURATION, | |
202 easing: settings.animation.Timing.EASING, | |
203 }); | |
204 | |
205 return new settings.animation.Animation( | |
206 this.$.card, [startFrame, endFrame], options); | |
39 }, | 207 }, |
40 }); | 208 }); |
OLD | NEW |