3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
11 <link rel=
"import" href=
"../polymer/polymer.html">
16 Polymer.IronFitBehavior fits an element in another element using `max-height` and `max-width`, and
17 optionally centers it in the window or another element.
19 The element will only be sized and/or positioned if it has not already been sized and/or positioned
22 CSS properties | Action
23 -----------------------------|-------------------------------------------
24 `position` set | Element is not centered horizontally or vertically
25 `top` or `bottom` set | Element is not vertically centered
26 `left` or `right` set | Element is not horizontally centered
27 `max-height` or `height` set | Element respects `max-height` or `height`
28 `max-width` or `width` set | Element respects `max-width` or `width`
34 Polymer
.IronFitBehavior
= {
39 * The element that will receive a `max-height`/`width`. By default it is the same as `this`,
40 * but it can be set to a child element. This is useful, for example, for implementing a
41 * scrolling region inside the element.
52 * The element to fit `this` into.
60 * Set to true to auto-fit on attach.
67 /** @type {?Object} */
76 if (this.fitInto
=== window
) {
77 fitWidth
= this.fitInto
.innerWidth
;
79 fitWidth
= this.fitInto
.getBoundingClientRect().width
;
86 if (this.fitInto
=== window
) {
87 fitHeight
= this.fitInto
.innerHeight
;
89 fitHeight
= this.fitInto
.getBoundingClientRect().height
;
96 if (this.fitInto
=== window
) {
99 fitLeft
= this.fitInto
.getBoundingClientRect().left
;
106 if (this.fitInto
=== window
) {
109 fitTop
= this.fitInto
.getBoundingClientRect().top
;
114 attached: function() {
115 if (this.autoFitOnAttach
) {
116 if (window
.getComputedStyle(this).display
=== 'none') {
117 setTimeout(function() {
127 * Fits and optionally centers the element into the window, or `fitInfo` if specified.
130 this._discoverInfo();
136 * Memoize information needed to position and size the target element.
138 _discoverInfo: function() {
142 var target
= window
.getComputedStyle(this);
143 var sizer
= window
.getComputedStyle(this.sizingTarget
);
146 top
: this.style
.top
|| '',
147 left
: this.style
.left
|| ''
150 vertically
: target
.top
!== 'auto' ? 'top' : (target
.bottom
!== 'auto' ?
152 horizontally
: target
.left
!== 'auto' ? 'left' : (target
.right
!== 'auto' ?
157 height
: sizer
.maxHeight
!== 'none',
158 width
: sizer
.maxWidth
!== 'none'
161 top
: parseInt(target
.marginTop
, 10) || 0,
162 right
: parseInt(target
.marginRight
, 10) || 0,
163 bottom
: parseInt(target
.marginBottom
, 10) || 0,
164 left
: parseInt(target
.marginLeft
, 10) || 0
170 * Resets the target element's position and size constraints, and clear
173 resetFit: function() {
174 if (!this._fitInfo
|| !this._fitInfo
.sizedBy
.height
) {
175 this.sizingTarget
.style
.maxHeight
= '';
176 this.style
.top
= this._fitInfo
? this._fitInfo
.inlineStyle
.top
: '';
178 if (!this._fitInfo
|| !this._fitInfo
.sizedBy
.width
) {
179 this.sizingTarget
.style
.maxWidth
= '';
180 this.style
.left
= this._fitInfo
? this._fitInfo
.inlineStyle
.left
: '';
183 this.style
.position
= this._fitInfo
.positionedBy
.css
;
185 this._fitInfo
= null;
189 * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after the element,
190 * the window, or the `fitInfo` element has been resized.
198 * Constrains the size of the element to the window or `fitInfo` by setting `max-height`
199 * and/or `max-width`.
201 constrain: function() {
202 var info
= this._fitInfo
;
203 // position at (0px, 0px) if not already positioned, so we can measure the natural size.
204 if (!this._fitInfo
.positionedBy
.vertically
) {
205 this.style
.top
= '0px';
207 if (!this._fitInfo
.positionedBy
.horizontally
) {
208 this.style
.left
= '0px';
210 // need border-box for margin/padding
211 this.sizingTarget
.style
.boxSizing
= 'border-box';
212 // constrain the width and height if not already set
213 var rect
= this.getBoundingClientRect();
214 if (!info
.sizedBy
.height
) {
215 this._sizeDimension(rect
, info
.positionedBy
.vertically
, 'top', 'bottom', 'Height');
217 if (!info
.sizedBy
.width
) {
218 this._sizeDimension(rect
, info
.positionedBy
.horizontally
, 'left', 'right', 'Width');
222 _sizeDimension: function(rect
, positionedBy
, start
, end
, extent
) {
223 var info
= this._fitInfo
;
224 var max
= extent
=== 'Width' ? this._fitWidth
: this._fitHeight
;
225 var flip
= (positionedBy
=== end
);
226 var offset
= flip
? max
- rect
[end
] : rect
[start
];
227 var margin
= info
.margin
[flip
? start
: end
];
228 var offsetExtent
= 'offset' + extent
;
229 var sizingOffset
= this[offsetExtent
] - this.sizingTarget
[offsetExtent
];
230 this.sizingTarget
.style
['max' + extent
] = (max
- margin
- offset
- sizingOffset
) + 'px';
234 * Centers horizontally and vertically if not already positioned. This also sets
238 if (!this._fitInfo
.positionedBy
.vertically
|| !this._fitInfo
.positionedBy
.horizontally
) {
239 // need position:fixed to center
240 this.style
.position
= 'fixed';
242 if (!this._fitInfo
.positionedBy
.vertically
) {
243 var top
= (this._fitHeight
- this.offsetHeight
) / 2 + this._fitTop
;
244 top
-= this._fitInfo
.margin
.top
;
245 this.style
.top
= top
+ 'px';
247 if (!this._fitInfo
.positionedBy
.horizontally
) {
248 var left
= (this._fitWidth
- this.offsetWidth
) / 2 + this._fitLeft
;
249 left
-= this._fitInfo
.margin
.left
;
250 this.style
.left
= left
+ 'px';