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 * | 9 * |
10 * Example: | 10 * Example: |
11 * | 11 * |
12 * <settings-section page-title="[[pageTitle]]" section="privacy"> | 12 * <settings-section page-title="[[pageTitle]]" section="privacy"> |
13 * <!-- Insert your section controls here --> | 13 * <!-- Insert your section controls here --> |
14 * </settings-section> | 14 * </settings-section> |
15 * | 15 * |
16 * @group Chrome Settings Elements | 16 * @group Chrome Settings Elements |
17 * @element settings-section | 17 * @element settings-section |
18 */ | 18 */ |
19 Polymer({ | 19 Polymer({ |
20 is: 'settings-section', | 20 is: 'settings-section', |
21 | 21 |
22 behaviors: [ | |
23 Polymer.NeonAnimationRunnerBehavior, | |
24 ], | |
25 | |
26 properties: { | 22 properties: { |
27 /** | 23 /** |
28 * The current active route. | 24 * The current active route. |
29 */ | 25 */ |
30 currentRoute: { | 26 currentRoute: Object, |
31 type: Object, | |
32 observer: 'currentRouteChanged_', | |
33 }, | |
34 | 27 |
35 /** | 28 /** |
36 * The section is expanded to a full-page view when this property matches | 29 * The section is expanded to a full-page view when this property matches |
37 * currentRoute.section. | 30 * currentRoute.section. |
38 * | 31 * |
39 * The section name must match the name specified in settings_router.js. | 32 * The section name must match the name specified in settings_router.js. |
40 */ | 33 */ |
41 section: { | 34 section: { |
42 type: String, | 35 type: String, |
43 }, | 36 }, |
44 | 37 |
45 /** | 38 /** |
46 * Title for the page header and navigation menu. | 39 * Title for the page header and navigation menu. |
47 */ | 40 */ |
48 pageTitle: String, | 41 pageTitle: String, |
49 | |
50 animationConfig: { | |
51 value: function() { | |
52 return { | |
53 collapse: { | |
54 name: 'collapse-card-animation', | |
55 node: this, | |
56 }, | |
57 expand: { | |
58 name: 'expand-card-animation', | |
59 node: this, | |
60 }, | |
61 }; | |
62 }, | |
63 }, | |
64 }, | |
65 | |
66 listeners: { | |
67 'expand-animation-complete': 'onExpandAnimationComplete_', | |
68 }, | |
69 | |
70 /** @private */ | |
71 currentRouteChanged_: function(newRoute, oldRoute) { | |
72 var newExpanded = newRoute.section == this.section; | |
73 var oldExpanded = oldRoute && oldRoute.section == this.section; | |
74 | |
75 var visible = newExpanded || this.currentRoute.section == ''; | |
76 | |
77 // If the user navigates directly to a subpage, skip all the animations. | |
78 if (!oldRoute) { | |
79 if (newExpanded) { | |
80 // If we navigate directly to a subpage, skip animations. | |
81 this.classList.add('expanded'); | |
82 } else if (!visible) { | |
83 this.hidden = true; | |
84 this.$.card.elevation = 0; | |
85 } | |
86 | |
87 return; | |
88 } | |
89 | |
90 if (newExpanded && !oldExpanded) { | |
91 this.playAnimation('expand'); | |
92 } else if (oldExpanded && !newExpanded) { | |
93 // For contraction, we defer the animation to allow | |
94 // settings-animated-pages to reflow the new page correctly. | |
95 this.async(function() { | |
96 this.playAnimation('collapse'); | |
97 }.bind(this)); | |
98 } | |
99 | |
100 this.$.card.elevation = visible ? 1 : 0; | |
101 | |
102 // Remove 'hidden' class immediately, but defer adding it if we are invisble | |
103 // until the animation is complete. | |
104 if (visible) | |
105 this.hidden = false; | |
106 }, | |
107 | |
108 /** @private */ | |
109 onExpandAnimationComplete_: function() { | |
110 this.hidden = this.currentRoute.section != '' && | |
111 this.currentRoute.section != this.section; | |
112 }, | 42 }, |
113 }); | 43 }); |
114 | |
115 Polymer({ | |
116 is: 'expand-card-animation', | |
117 | |
118 behaviors: [ | |
119 Polymer.NeonAnimationBehavior | |
120 ], | |
121 | |
122 configure: function(config) { | |
123 var section = config.node; | |
124 var card = section.$.card; | |
125 var containerRect = section.offsetParent.getBoundingClientRect(); | |
126 var cardRect = card.getBoundingClientRect(); | |
127 | |
128 // Set placeholder height so the page does not reflow during animation. | |
129 // TODO(tommycli): For URLs that directly load subpages, this does not work. | |
130 var placeholder = section.$.placeholder; | |
131 placeholder.style.top = card.offsetTop + 'px'; | |
132 placeholder.style.height = card.offsetHeight + 'px'; | |
133 | |
134 section.classList.add('neon-animating'); | |
135 | |
136 this._effect = new KeyframeEffect(card, [ | |
137 {'top': cardRect.top + 'px', 'height': cardRect.height + 'px'}, | |
138 {'top': containerRect.top + 'px', 'height': containerRect.height + 'px'}, | |
139 ], this.timingFromConfig(config)); | |
140 return this._effect; | |
141 }, | |
142 | |
143 complete: function(config) { | |
144 var section = config.node; | |
145 section.classList.remove('neon-animating'); | |
146 section.classList.add('expanded'); | |
147 | |
148 // This event fires on itself as well, but that is benign. | |
149 var sections = section.parentNode.querySelectorAll('settings-section'); | |
150 for (var i = 0; i < sections.length; ++i) { | |
151 sections[i].fire('expand-animation-complete'); | |
152 } | |
153 } | |
154 }); | |
155 | |
156 Polymer({ | |
157 is: 'collapse-card-animation', | |
158 | |
159 behaviors: [ | |
160 Polymer.NeonAnimationBehavior | |
161 ], | |
162 | |
163 configure: function(config) { | |
164 var section = config.node; | |
165 var oldRect = section.offsetParent.getBoundingClientRect(); | |
166 | |
167 section.classList.remove('expanded'); | |
168 | |
169 var card = section.$.card; | |
170 var placeholder = section.$.placeholder; | |
171 placeholder.style.top = card.offsetTop + 'px'; | |
172 placeholder.style.height = card.offsetHeight + 'px'; | |
173 | |
174 var newRect = card.getBoundingClientRect(); | |
175 | |
176 section.classList.add('neon-animating'); | |
177 | |
178 this._effect = new KeyframeEffect(card, [ | |
179 {'top': oldRect.top + 'px', 'height': oldRect.height + 'px'}, | |
180 {'top': newRect.top + 'px', 'height': newRect.height + 'px'}, | |
181 ], this.timingFromConfig(config)); | |
182 return this._effect; | |
183 }, | |
184 | |
185 complete: function(config) { | |
186 config.node.classList.remove('neon-animating'); | |
187 } | |
188 }); | |
OLD | NEW |