Fix OOP <webview> resize and autosize.
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / paper-header-panel / paper-header-panel-extracted.js
bloba8db4e51030d3a92fef571be2a20b93532404144
1 (function() {
3     'use strict';
5     var SHADOW_WHEN_SCROLLING = 1;
6     var SHADOW_ALWAYS = 2;
9     var MODE_CONFIGS = {
11       outerScroll: {
12         'scroll': true
13       },
15       shadowMode: {
16         'standard': SHADOW_ALWAYS,
17         'waterfall': SHADOW_WHEN_SCROLLING,
18         'waterfall-tall': SHADOW_WHEN_SCROLLING
19       },
21       tallMode: {
22         'waterfall-tall': true
23       }
24     };
26     Polymer({
28       is: 'paper-header-panel',
30       /**
31        * Fired when the content has been scrolled.  `event.detail.target` returns
32        * the scrollable element which you can use to access scroll info such as
33        * `scrollTop`.
34        *
35        *     <paper-header-panel on-content-scroll="scrollHandler">
36        *       ...
37        *     </paper-header-panel>
38        *
39        *
40        *     scrollHandler: function(event) {
41        *       var scroller = event.detail.target;
42        *       console.log(scroller.scrollTop);
43        *     }
44        *
45        * @event content-scroll
46        */
48       properties: {
50         /**
51          * Controls header and scrolling behavior. Options are
52          * `standard`, `seamed`, `waterfall`, `waterfall-tall`, `scroll` and
53          * `cover`. Default is `standard`.
54          *
55          * `standard`: The header is a step above the panel. The header will consume the
56          * panel at the point of entry, preventing it from passing through to the
57          * opposite side.
58          *
59          * `seamed`: The header is presented as seamed with the panel.
60          *
61          * `waterfall`: Similar to standard mode, but header is initially presented as
62          * seamed with panel, but then separates to form the step.
63          *
64          * `waterfall-tall`: The header is initially taller (`tall` class is added to
65          * the header).  As the user scrolls, the header separates (forming an edge)
66          * while condensing (`tall` class is removed from the header).
67          *
68          * `scroll`: The header keeps its seam with the panel, and is pushed off screen.
69          *
70          * `cover`: The panel covers the whole `paper-header-panel` including the
71          * header. This allows user to style the panel in such a way that the panel is
72          * partially covering the header.
73          *
74          *     <paper-header-panel mode="cover">
75          *       <paper-toolbar class="tall">
76          *         <core-icon-button icon="menu"></core-icon-button>
77          *       </paper-toolbar>
78          *       <div class="content"></div>
79          *     </paper-header-panel>
80          */
81         mode: {
82           type: String,
83           value: 'standard',
84           observer: '_modeChanged',
85           reflectToAttribute: true
86         },
88         /**
89          * If true, the drop-shadow is always shown no matter what mode is set to.
90          */
91         shadow: {
92           type: Boolean,
93           value: false
94         },
96         /**
97          * The class used in waterfall-tall mode.  Change this if the header
98          * accepts a different class for toggling height, e.g. "medium-tall"
99          */
100         tallClass: {
101           type: String,
102           value: 'tall'
103         },
105         /**
106          * If true, the scroller is at the top
107          */
108         atTop: {
109           type: Boolean,
110           value: true,
111           readOnly: true
112         }
113       },
115       observers: [
116         '_computeDropShadowHidden(atTop, mode, shadow)'
117       ],
119       ready: function() {
120         this.scrollHandler = this._scroll.bind(this);
121         this._addListener();
123         // Run `scroll` logic once to initialze class names, etc.
124         this._keepScrollingState();
125       },
127       detached: function() {
128         this._removeListener();
129       },
131       /**
132        * Returns the header element
133        *
134        * @property header
135        * @type Object
136        */
137       get header() {
138         return Polymer.dom(this.$.headerContent).getDistributedNodes()[0];
139       },
141       /**
142        * Returns the scrollable element.
143        *
144        * @property scroller
145        * @type Object
146        */
147       get scroller() {
148         return this._getScrollerForMode(this.mode);
149       },
151       /**
152        * Returns true if the scroller has a visible shadow.
153        *
154        * @property visibleShadow
155        * @type Boolean
156        */
157       get visibleShadow() {
158         return this.$.dropShadow.classList.contains('has-shadow');
159       },
161       _computeDropShadowHidden: function(atTop, mode, shadow) {
163         var shadowMode = MODE_CONFIGS.shadowMode[mode];
165         if (this.shadow) {
166           this.toggleClass('has-shadow', true, this.$.dropShadow);
168         } else if (shadowMode === SHADOW_ALWAYS) {
169           this.toggleClass('has-shadow', true, this.$.dropShadow);
171         } else if (shadowMode === SHADOW_WHEN_SCROLLING && !atTop) {
172           this.toggleClass('has-shadow', true, this.$.dropShadow);
174         } else {
175           this.toggleClass('has-shadow', false, this.$.dropShadow);
177         }
178       },
180       _computeMainContainerClass: function(mode) {
181         // TODO:  It will be useful to have a utility for classes
182         // e.g. Polymer.Utils.classes({ foo: true });
184         var classes = {};
186         classes['flex'] = mode !== 'cover';
188         return Object.keys(classes).filter(
189           function(className) {
190             return classes[className];
191           }).join(' ');
192       },
194       _addListener: function() {
195         this.scroller.addEventListener('scroll', this.scrollHandler, false);
196       },
198       _removeListener: function() {
199         this.scroller.removeEventListener('scroll', this.scrollHandler);
200       },
202       _modeChanged: function(newMode, oldMode) {
203         var configs = MODE_CONFIGS;
204         var header = this.header;
205         var animateDuration = 200;
207         if (header) {
208           // in tallMode it may add tallClass to the header; so do the cleanup
209           // when mode is changed from tallMode to not tallMode
210           if (configs.tallMode[oldMode] && !configs.tallMode[newMode]) {
211             header.classList.remove(this.tallClass);
212             this.async(function() {
213               header.classList.remove('animate');
214             }, animateDuration);
215           } else {
216             header.classList.toggle('animate', configs.tallMode[newMode]);
217           }
218         }
219         this._keepScrollingState();
220       },
222       _keepScrollingState: function() {
223         var main = this.scroller;
224         var header = this.header;
226         this._setAtTop(main.scrollTop === 0);
228         if (header && this.tallClass && MODE_CONFIGS.tallMode[this.mode]) {
229           this.toggleClass(this.tallClass, this.atTop ||
230               header.classList.contains(this.tallClass) &&
231               main.scrollHeight < this.offsetHeight, header);
232         }
233       },
235       _scroll: function() {
236         this._keepScrollingState();
237         this.fire('content-scroll', {target: this.scroller}, {bubbles: false});
238       },
240       _getScrollerForMode: function(mode) {
241         return MODE_CONFIGS.outerScroll[mode] ?
242             this : this.$.mainContainer;
243       }
245     });
247   })();