OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
6 Code distributed by Google as part of the polymer project is also | |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
8 --> | |
9 | |
10 <!-- | |
11 `core-scroll-header-panel` contains a header section and a content section. The | |
12 header is initially on the top part of the view but it scrolls away with the | |
13 rest of the scrollable content. Upon scrolling slightly up at any point, the | |
14 header scrolls back into view. This saves screen space and allows users to | |
15 access important controls by easily moving them back to the view. | |
16 | |
17 __Important:__ The `core-scroll-header-panel` will not display if its parent doe
s not have a height. | |
18 | |
19 Using [layout attributes](http://www.polymer-project.org/docs/polymer/layout-att
rs.html), you can easily make the `core-scroll-header-panel` fill the screen | |
20 | |
21 <body fullbleed layout vertical> | |
22 <core-scroll-header-panel flex> | |
23 <core-toolbar> | |
24 <div>Hello World!</div> | |
25 </core-toolbar> | |
26 </core-scroll-header-panel> | |
27 </body> | |
28 | |
29 or, if you would prefer to do it in CSS, just give `html`, `body`, and `core-scr
oll-header-panel` a height of 100%: | |
30 | |
31 html, body { | |
32 height: 100%; | |
33 margin: 0; | |
34 } | |
35 core-scroll-header-panel { | |
36 height: 100%; | |
37 } | |
38 | |
39 `core-scroll-header-panel` works well with `core-toolbar` but can use any elemen
t | |
40 that represents a header by adding a `core-header` class to it. Use the attribu
te | |
41 or class `content` to delineate the content section. | |
42 | |
43 <core-scroll-header-panel> | |
44 <core-toolbar>Header</core-toolbar> | |
45 <div content>Content goes here...</div> | |
46 </core-scroll-header-panel> | |
47 | |
48 @group Polymer Core Elements | |
49 @element core-scroll-header-panel | |
50 @homepage github.io | |
51 --> | |
52 | |
53 <link rel="import" href="../polymer/polymer.html"> | |
54 | |
55 <polymer-element name="core-scroll-header-panel"> | |
56 <template> | |
57 | |
58 <link rel="stylesheet" href="core-scroll-header-panel.css"> | |
59 | |
60 <div id="mainContainer"> | |
61 | |
62 <content id="mainContent" select="[content], .content"></content> | |
63 | |
64 </div> | |
65 | |
66 <div id="headerContainer"> | |
67 | |
68 <div class="bg-container"> | |
69 <div id="condensedHeaderBg"></div> | |
70 <div id="headerBg"></div> | |
71 </div> | |
72 | |
73 <content id="headerContent" select="core-toolbar, .core-header"></content> | |
74 | |
75 </div> | |
76 | |
77 </template> | |
78 <script> | |
79 (function() { | |
80 | |
81 Polymer('core-scroll-header-panel', { | |
82 | |
83 /** | |
84 * Fired when the content has been scrolled. | |
85 * | |
86 * @event scroll | |
87 */ | |
88 | |
89 /** | |
90 * Fired when the header is transformed. | |
91 * | |
92 * @event core-header-transform | |
93 */ | |
94 | |
95 publish: { | |
96 /** | |
97 * If true, the header's height will condense to `_condensedHeaderHeight` | |
98 * as the user scrolls down from the top of the content area. | |
99 * | |
100 * @attribute condenses | |
101 * @type boolean | |
102 * @default false | |
103 */ | |
104 condenses: false, | |
105 | |
106 /** | |
107 * If true, no cross-fade transition from one background to another. | |
108 * | |
109 * @attribute noDissolve | |
110 * @type boolean | |
111 * @default false | |
112 */ | |
113 noDissolve: false, | |
114 | |
115 /** | |
116 * If true, the header doesn't slide back in when scrolling back up. | |
117 * | |
118 * @attribute noReveal | |
119 * @type boolean | |
120 * @default false | |
121 */ | |
122 noReveal: false, | |
123 | |
124 /** | |
125 * If true, the header is fixed to the top and never moves away. | |
126 * | |
127 * @attribute fixed | |
128 * @type boolean | |
129 * @default false | |
130 */ | |
131 fixed: false, | |
132 | |
133 /** | |
134 * If true, the condensed header is always shown and does not move away. | |
135 * | |
136 * @attribute keepCondensedHeader | |
137 * @type boolean | |
138 * @default false | |
139 */ | |
140 keepCondensedHeader: false, | |
141 | |
142 /** | |
143 * The height of the header when it is at its full size. | |
144 * | |
145 * By default, the height will be measured when it is ready. If the heigh
t | |
146 * changes later the user needs to either set this value to reflect the | |
147 * new height or invoke `measureHeaderHeight()`. | |
148 * | |
149 * @attribute headerHeight | |
150 * @type number | |
151 * @default 0 | |
152 */ | |
153 headerHeight: 0, | |
154 | |
155 /** | |
156 * The height of the header when it is condensed. | |
157 * | |
158 * By default, `_condensedHeaderHeight` is 1/3 of `headerHeight` unless | |
159 * this is specified. | |
160 * | |
161 * @attribute condensedHeaderHeight | |
162 * @type number | |
163 * @default 0 | |
164 */ | |
165 condensedHeaderHeight: 0, | |
166 | |
167 /** | |
168 * By default, the top part of the header stays when the header is being | |
169 * condensed. Set this to true if you want the top part of the header | |
170 * to be scrolled away. | |
171 * | |
172 * @attribute scrollAwayTopbar | |
173 * @type boolean | |
174 * @default false | |
175 */ | |
176 scrollAwayTopbar: false | |
177 }, | |
178 | |
179 prevScrollTop: 0, | |
180 | |
181 headerMargin: 0, | |
182 | |
183 y: 0, | |
184 | |
185 observe: { | |
186 'headerMargin fixed': 'setup' | |
187 }, | |
188 | |
189 ready: function() { | |
190 this._scrollHandler = this.scroll.bind(this); | |
191 this.scroller.addEventListener('scroll', this._scrollHandler); | |
192 }, | |
193 | |
194 detached: function() { | |
195 this.scroller.removeEventListener('scroll', this._scrollHandler); | |
196 }, | |
197 | |
198 domReady: function() { | |
199 this.async('measureHeaderHeight'); | |
200 }, | |
201 | |
202 get header() { | |
203 return this.$.headerContent.getDistributedNodes()[0]; | |
204 }, | |
205 | |
206 /** | |
207 * Returns the scrollable element. | |
208 * | |
209 * @property scroller | |
210 * @type Object | |
211 */ | |
212 get scroller() { | |
213 return this.$.mainContainer; | |
214 }, | |
215 | |
216 /** | |
217 * Invoke this to tell `core-scroll-header-panel` to re-measure the header's | |
218 * height. | |
219 * | |
220 * @method measureHeaderHeight | |
221 */ | |
222 measureHeaderHeight: function() { | |
223 var header = this.header; | |
224 if (header && header.offsetHeight) { | |
225 this.headerHeight = header.offsetHeight; | |
226 } | |
227 }, | |
228 | |
229 headerHeightChanged: function() { | |
230 if (!this.condensedHeaderHeight) { | |
231 // assume _condensedHeaderHeight is 1/3 of the headerHeight | |
232 this._condensedHeaderHeight = this.headerHeight * 1 / 3; | |
233 } | |
234 this.condensedHeaderHeightChanged(); | |
235 }, | |
236 | |
237 condensedHeaderHeightChanged: function() { | |
238 if (this.condensedHeaderHeight) { | |
239 this._condensedHeaderHeight = this.condensedHeaderHeight; | |
240 } | |
241 if (this.headerHeight) { | |
242 this.headerMargin = this.headerHeight - this._condensedHeaderHeight; | |
243 } | |
244 }, | |
245 | |
246 condensesChanged: function() { | |
247 if (this.condenses) { | |
248 this.scroll(); | |
249 } else { | |
250 // reset transform/opacity set on the header | |
251 this.condenseHeader(null); | |
252 } | |
253 }, | |
254 | |
255 setup: function() { | |
256 var s = this.scroller.style; | |
257 s.paddingTop = this.fixed ? '' : this.headerHeight + 'px'; | |
258 s.top = this.fixed ? this.headerHeight + 'px' : ''; | |
259 if (this.fixed) { | |
260 this.transformHeader(null); | |
261 } else { | |
262 this.scroll(); | |
263 } | |
264 }, | |
265 | |
266 transformHeader: function(y) { | |
267 var s = this.$.headerContainer.style; | |
268 this.translateY(s, -y); | |
269 | |
270 if (this.condenses) { | |
271 this.condenseHeader(y); | |
272 } | |
273 | |
274 this.fire('core-header-transform', {y: y, height: this.headerHeight, | |
275 condensedHeight: this._condensedHeaderHeight}); | |
276 }, | |
277 | |
278 condenseHeader: function(y) { | |
279 var reset = y == null; | |
280 // adjust top bar in core-header so the top bar stays at the top | |
281 if (!this.scrollAwayTopbar && this.header.$ && this.header.$.topBar) { | |
282 this.translateY(this.header.$.topBar.style, | |
283 reset ? null : Math.min(y, this.headerMargin)); | |
284 } | |
285 // transition header bg | |
286 var hbg = this.$.headerBg.style; | |
287 if (!this.noDissolve) { | |
288 hbg.opacity = reset ? '' : (this.headerMargin - y) / this.headerMargin; | |
289 } | |
290 // adjust header bg so it stays at the center | |
291 this.translateY(hbg, reset ? null : y / 2); | |
292 // transition condensed header bg | |
293 var chbg = this.$.condensedHeaderBg.style; | |
294 if (!this.noDissolve) { | |
295 chbg = this.$.condensedHeaderBg.style; | |
296 chbg.opacity = reset ? '' : y / this.headerMargin; | |
297 // adjust condensed header bg so it stays at the center | |
298 this.translateY(chbg, reset ? null : y / 2); | |
299 } | |
300 }, | |
301 | |
302 translateY: function(s, y) { | |
303 var t = y == null ? '' : 'translate3d(0, ' + y + 'px, 0)'; | |
304 setTransform(s, t); | |
305 }, | |
306 | |
307 scroll: function(event) { | |
308 if (!this.header) { | |
309 return; | |
310 } | |
311 | |
312 var sTop = this.scroller.scrollTop; | |
313 | |
314 var y = Math.min(this.keepCondensedHeader ? | |
315 this.headerMargin : this.headerHeight, Math.max(0, | |
316 (this.noReveal ? sTop : this.y + sTop - this.prevScrollTop))); | |
317 | |
318 if (this.condenses && this.prevScrollTop >= sTop && sTop > this.headerMarg
in) { | |
319 y = Math.max(y, this.headerMargin); | |
320 } | |
321 | |
322 if (!event || !this.fixed && y !== this.y) { | |
323 this.transformHeader(y); | |
324 } | |
325 | |
326 this.prevScrollTop = Math.max(sTop, 0); | |
327 this.y = y; | |
328 | |
329 if (event) { | |
330 this.fire('scroll', {target: this.scroller}, this, false); | |
331 } | |
332 } | |
333 | |
334 }); | |
335 | |
336 //determine proper transform mechanizm | |
337 if (document.documentElement.style.transform !== undefined) { | |
338 var setTransform = function(style, string) { | |
339 style.transform = string; | |
340 } | |
341 } else { | |
342 var setTransform = function(style, string) { | |
343 style.webkitTransform = string; | |
344 } | |
345 } | |
346 | |
347 })(); | |
348 | |
349 </script> | |
350 </polymer-element> | |
OLD | NEW |