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 */ | |
43 sizingTarget: { | |
44 type: Object, | |
45 value: function() { | |
46 return this; | |
47 } | |
48 }, | |
49 | |
50 /** | |
51 * The element to fit `this` into. | |
52 */ | |
53 fitInto: { | |
54 type: Object, | |
55 value: window | |
56 }, | |
57 | |
58 /** | |
59 * Set to true to auto-fit on attach. | |
60 */ | |
61 autoFitOnAttach: { | |
62 type: Boolean, | |
63 value: false | |
64 }, | |
65 | |
66 _fitInfo: { | |
67 type: Object | |
68 } | |
69 | |
70 }, | |
71 | |
72 get _fitWidth() { | |
73 var fitWidth; | |
74 if (this.fitInto === window) { | |
75 fitWidth = this.fitInto.innerWidth; | |
76 } else { | |
77 fitWidth = this.fitInto.getBoundingClientRect().width; | |
78 } | |
79 return fitWidth; | |
80 }, | |
81 | |
82 get _fitHeight() { | |
83 var fitHeight; | |
84 if (this.fitInto === window) { | |
85 fitHeight = this.fitInto.innerHeight; | |
86 } else { | |
87 fitHeight = this.fitInto.getBoundingClientRect().height; | |
88 } | |
89 return fitHeight; | |
90 }, | |
91 | |
92 attached: function() { | |
93 if (this.autoFitOnAttach) { | |
94 if (window.getComputedStyle(this).display === 'none') { | |
95 setTimeout(function() { | |
96 this.fit(); | |
97 }.bind(this)); | |
98 } else { | |
99 this.fit(); | |
100 } | |
101 } | |
102 }, | |
103 | |
104 /** | |
105 * Fits and optionally centers the element into the window, or `fitInfo` if
specified. | |
106 */ | |
107 fit: function() { | |
108 this._discoverInfo(); | |
109 this.constrain(); | |
110 this.center(); | |
111 }, | |
112 | |
113 /** | |
114 * Memoize information needed to position and size the target element. | |
115 */ | |
116 _discoverInfo: function() { | |
117 if (this._fitInfo) { | |
118 return; | |
119 } | |
120 var target = window.getComputedStyle(this); | |
121 var sizer = window.getComputedStyle(this.sizingTarget); | |
122 this._fitInfo = { | |
123 positionedBy: { | |
124 vertically: target.top !== 'auto' ? 'top' : (target.bottom !== 'auto'
? | |
125 'bottom' : null), | |
126 horizontally: target.left !== 'auto' ? 'left' : (target.right !== 'aut
o' ? | |
127 'right' : null), | |
128 css: target.position | |
129 }, | |
130 sizedBy: { | |
131 height: sizer.maxHeight !== 'none', | |
132 width: sizer.maxWidth !== 'none' | |
133 }, | |
134 margin: { | |
135 top: parseInt(target.marginTop, 10) || 0, | |
136 right: parseInt(target.marginRight, 10) || 0, | |
137 bottom: parseInt(target.marginBottom, 10) || 0, | |
138 left: parseInt(target.marginLeft, 10) || 0 | |
139 } | |
140 }; | |
141 }, | |
142 | |
143 /** | |
144 * Resets the target element's position and size constraints, and clear | |
145 * the memoized data. | |
146 */ | |
147 resetFit: function() { | |
148 if (!this._fitInfo || !this._fitInfo.sizedBy.height) { | |
149 this.sizingTarget.style.maxHeight = ''; | |
150 this.style.top = ''; | |
151 } | |
152 if (!this._fitInfo || !this._fitInfo.sizedBy.width) { | |
153 this.sizingTarget.style.maxWidth = ''; | |
154 this.style.left = ''; | |
155 } | |
156 if (this._fitInfo) { | |
157 this.style.position = this._fitInfo.positionedBy.css; | |
158 } | |
159 this._fitInfo = null; | |
160 }, | |
161 | |
162 /** | |
163 * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after
the element, | |
164 * the window, or the `fitInfo` element has been resized. | |
165 */ | |
166 refit: function() { | |
167 this.resetFit(); | |
168 this.fit(); | |
169 }, | |
170 | |
171 /** | |
172 * Constrains the size of the element to the window or `fitInfo` by setting
`max-height` | |
173 * and/or `max-width`. | |
174 */ | |
175 constrain: function() { | |
176 var info = this._fitInfo; | |
177 // position at (0px, 0px) if not already positioned, so we can measure the
natural size. | |
178 if (!this._fitInfo.positionedBy.vertically) { | |
179 this.style.top = '0px'; | |
180 } | |
181 if (!this._fitInfo.positionedBy.horizontally) { | |
182 this.style.left = '0px'; | |
183 } | |
184 // need border-box for margin/padding | |
185 this.sizingTarget.style.boxSizing = 'border-box'; | |
186 // constrain the width and height if not already set | |
187 var rect = this.getBoundingClientRect(); | |
188 if (!info.sizedBy.height) { | |
189 this._sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom',
'Height'); | |
190 } | |
191 if (!info.sizedBy.width) { | |
192 this._sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right
', 'Width'); | |
193 } | |
194 }, | |
195 | |
196 _sizeDimension: function(rect, positionedBy, start, end, extent) { | |
197 var info = this._fitInfo; | |
198 var max = extent === 'Width' ? this._fitWidth : this._fitHeight; | |
199 var flip = (positionedBy === end); | |
200 var offset = flip ? max - rect[end] : rect[start]; | |
201 var margin = info.margin[flip ? start : end]; | |
202 var offsetExtent = 'offset' + extent; | |
203 var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent]; | |
204 this.sizingTarget.style['max' + extent] = (max - margin - offset - sizingO
ffset) + 'px'; | |
205 }, | |
206 | |
207 /** | |
208 * Centers horizontally and vertically if not already positioned. This also
sets | |
209 * `position:fixed`. | |
210 */ | |
211 center: function() { | |
212 if (!this._fitInfo.positionedBy.vertically || !this._fitInfo.positionedBy.
horizontally) { | |
213 // need position:fixed to center | |
214 this.style.position = 'fixed'; | |
215 } | |
216 if (!this._fitInfo.positionedBy.vertically) { | |
217 var top = (this._fitHeight - this.offsetHeight) / 2; | |
218 top -= this._fitInfo.margin.top; | |
219 this.style.top = top + 'px'; | |
220 } | |
221 if (!this._fitInfo.positionedBy.horizontally) { | |
222 var left = (this._fitWidth - this.offsetWidth) / 2; | |
223 left -= this._fitInfo.margin.left; | |
224 this.style.left = left + 'px'; | |
225 } | |
226 } | |
227 | |
228 }; | |
229 | |
230 </script> | |
OLD | NEW |