OLD | NEW |
| (Empty) |
1 <!-- | |
2 @license | |
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.g
ithub.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/CONTRI
BUTORS.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/PATEN
TS.txt | |
9 --> | |
10 | |
11 <link rel="import" href="../polymer/polymer.html"> | |
12 | |
13 <script> | |
14 | |
15 /** | |
16 Polymer.IronFitBehavior fits an element in another element using `max-height` an
d `max-width`, and | |
17 optionally centers it in the window or another element. | |
18 | |
19 The element will only be sized and/or positioned if it has not already been size
d and/or positioned | |
20 by CSS. | |
21 | |
22 CSS properties | Action | |
23 -----------------------------|------------------------------------------- | |
24 `position` set | Element is not centered horizontally or verticall
y | |
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` | |
29 | |
30 @demo demo/index.html | |
31 @polymerBehavior | |
32 */ | |
33 | |
34 Polymer.IronFitBehavior = { | |
35 | |
36 properties: { | |
37 | |
38 /** | |
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. | |
42 * @type {!Element} | |
43 */ | |
44 sizingTarget: { | |
45 type: Object, | |
46 value: function() { | |
47 return this; | |
48 } | |
49 }, | |
50 | |
51 /** | |
52 * The element to fit `this` into. | |
53 */ | |
54 fitInto: { | |
55 type: Object, | |
56 value: window | |
57 }, | |
58 | |
59 /** | |
60 * Set to true to auto-fit on attach. | |
61 */ | |
62 autoFitOnAttach: { | |
63 type: Boolean, | |
64 value: false | |
65 }, | |
66 | |
67 /** @type {?Object} */ | |
68 _fitInfo: { | |
69 type: Object | |
70 } | |
71 | |
72 }, | |
73 | |
74 get _fitWidth() { | |
75 var fitWidth; | |
76 if (this.fitInto === window) { | |
77 fitWidth = this.fitInto.innerWidth; | |
78 } else { | |
79 fitWidth = this.fitInto.getBoundingClientRect().width; | |
80 } | |
81 return fitWidth; | |
82 }, | |
83 | |
84 get _fitHeight() { | |
85 var fitHeight; | |
86 if (this.fitInto === window) { | |
87 fitHeight = this.fitInto.innerHeight; | |
88 } else { | |
89 fitHeight = this.fitInto.getBoundingClientRect().height; | |
90 } | |
91 return fitHeight; | |
92 }, | |
93 | |
94 get _fitLeft() { | |
95 var fitLeft; | |
96 if (this.fitInto === window) { | |
97 fitLeft = 0; | |
98 } else { | |
99 fitLeft = this.fitInto.getBoundingClientRect().left; | |
100 } | |
101 return fitLeft; | |
102 }, | |
103 | |
104 get _fitTop() { | |
105 var fitTop; | |
106 if (this.fitInto === window) { | |
107 fitTop = 0; | |
108 } else { | |
109 fitTop = this.fitInto.getBoundingClientRect().top; | |
110 } | |
111 return fitTop; | |
112 }, | |
113 | |
114 attached: function() { | |
115 if (this.autoFitOnAttach) { | |
116 if (window.getComputedStyle(this).display === 'none') { | |
117 setTimeout(function() { | |
118 this.fit(); | |
119 }.bind(this)); | |
120 } else { | |
121 this.fit(); | |
122 } | |
123 } | |
124 }, | |
125 | |
126 /** | |
127 * Fits and optionally centers the element into the window, or `fitInfo` if
specified. | |
128 */ | |
129 fit: function() { | |
130 this._discoverInfo(); | |
131 this.constrain(); | |
132 this.center(); | |
133 }, | |
134 | |
135 /** | |
136 * Memoize information needed to position and size the target element. | |
137 */ | |
138 _discoverInfo: function() { | |
139 if (this._fitInfo) { | |
140 return; | |
141 } | |
142 var target = window.getComputedStyle(this); | |
143 var sizer = window.getComputedStyle(this.sizingTarget); | |
144 this._fitInfo = { | |
145 inlineStyle: { | |
146 top: this.style.top || '', | |
147 left: this.style.left || '' | |
148 }, | |
149 positionedBy: { | |
150 vertically: target.top !== 'auto' ? 'top' : (target.bottom !== 'auto'
? | |
151 'bottom' : null), | |
152 horizontally: target.left !== 'auto' ? 'left' : (target.right !== 'aut
o' ? | |
153 'right' : null), | |
154 css: target.position | |
155 }, | |
156 sizedBy: { | |
157 height: sizer.maxHeight !== 'none', | |
158 width: sizer.maxWidth !== 'none' | |
159 }, | |
160 margin: { | |
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 | |
165 } | |
166 }; | |
167 }, | |
168 | |
169 /** | |
170 * Resets the target element's position and size constraints, and clear | |
171 * the memoized data. | |
172 */ | |
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 : ''; | |
177 } | |
178 if (!this._fitInfo || !this._fitInfo.sizedBy.width) { | |
179 this.sizingTarget.style.maxWidth = ''; | |
180 this.style.left = this._fitInfo ? this._fitInfo.inlineStyle.left : ''; | |
181 } | |
182 if (this._fitInfo) { | |
183 this.style.position = this._fitInfo.positionedBy.css; | |
184 } | |
185 this._fitInfo = null; | |
186 }, | |
187 | |
188 /** | |
189 * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after
the element, | |
190 * the window, or the `fitInfo` element has been resized. | |
191 */ | |
192 refit: function() { | |
193 this.resetFit(); | |
194 this.fit(); | |
195 }, | |
196 | |
197 /** | |
198 * Constrains the size of the element to the window or `fitInfo` by setting
`max-height` | |
199 * and/or `max-width`. | |
200 */ | |
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'; | |
206 } | |
207 if (!this._fitInfo.positionedBy.horizontally) { | |
208 this.style.left = '0px'; | |
209 } | |
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'); | |
216 } | |
217 if (!info.sizedBy.width) { | |
218 this._sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right
', 'Width'); | |
219 } | |
220 }, | |
221 | |
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 - sizingO
ffset) + 'px'; | |
231 }, | |
232 | |
233 /** | |
234 * Centers horizontally and vertically if not already positioned. This also
sets | |
235 * `position:fixed`. | |
236 */ | |
237 center: function() { | |
238 if (!this._fitInfo.positionedBy.vertically || !this._fitInfo.positionedBy.
horizontally) { | |
239 // need position:fixed to center | |
240 this.style.position = 'fixed'; | |
241 } | |
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'; | |
246 } | |
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'; | |
251 } | |
252 } | |
253 | |
254 }; | |
255 | |
256 </script> | |
OLD | NEW |