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-collapse` creates a collapsible block of content. By default, the content | |
12 will be collapsed. Use `opened` to show/hide the content. | |
13 | |
14 <button on-click="{{toggle}}">toggle collapse</button> | |
15 | |
16 <core-collapse id="collapse"> | |
17 ... | |
18 </core-collapse> | |
19 | |
20 ... | |
21 | |
22 toggle: function() { | |
23 this.$.collapse.toggle(); | |
24 } | |
25 | |
26 @group Polymer Core Elements | |
27 @element core-collapse | |
28 --> | |
29 | |
30 <link rel="import" href="../polymer/polymer.html"> | |
31 | |
32 <link rel="stylesheet" href="core-collapse.css" shim-shadowdom> | |
33 | |
34 <polymer-element name="core-collapse" attributes="target horizontal opened durat
ion fixedSize"> | |
35 <template> | |
36 | |
37 <content></content> | |
38 | |
39 </template> | |
40 <script> | |
41 | |
42 Polymer('core-collapse', { | |
43 /** | |
44 * Fired when the target element has been resized as a result of the opened | |
45 * state changing. | |
46 * | |
47 * @event core-resize | |
48 */ | |
49 | |
50 /** | |
51 * The target element. | |
52 * | |
53 * @attribute target | |
54 * @type object | |
55 * @default null | |
56 */ | |
57 target: null, | |
58 | |
59 /** | |
60 * If true, the orientation is horizontal; otherwise is vertical. | |
61 * | |
62 * @attribute horizontal | |
63 * @type boolean | |
64 * @default false | |
65 */ | |
66 horizontal: false, | |
67 | |
68 /** | |
69 * Set opened to true to show the collapse element and to false to hide it. | |
70 * | |
71 * @attribute opened | |
72 * @type boolean | |
73 * @default false | |
74 */ | |
75 opened: false, | |
76 | |
77 /** | |
78 * Collapsing/expanding animation duration in second. | |
79 * | |
80 * @attribute duration | |
81 * @type number | |
82 * @default 0.33 | |
83 */ | |
84 duration: 0.33, | |
85 | |
86 /** | |
87 * If true, the size of the target element is fixed and is set | |
88 * on the element. Otherwise it will try to | |
89 * use auto to determine the natural size to use | |
90 * for collapsing/expanding. | |
91 * | |
92 * @attribute fixedSize | |
93 * @type boolean | |
94 * @default false | |
95 */ | |
96 fixedSize: false, | |
97 | |
98 created: function() { | |
99 this.transitionEndListener = this.transitionEnd.bind(this); | |
100 }, | |
101 | |
102 ready: function() { | |
103 this.target = this.target || this; | |
104 }, | |
105 | |
106 domReady: function() { | |
107 this.async(function() { | |
108 this.afterInitialUpdate = true; | |
109 }); | |
110 }, | |
111 | |
112 detached: function() { | |
113 if (this.target) { | |
114 this.removeListeners(this.target); | |
115 } | |
116 }, | |
117 | |
118 targetChanged: function(old) { | |
119 if (old) { | |
120 this.removeListeners(old); | |
121 } | |
122 if (!this.target) { | |
123 return; | |
124 } | |
125 this.isTargetReady = !!this.target; | |
126 this.classList.toggle('core-collapse-closed', this.target !== this); | |
127 this.target.style.overflow = 'hidden'; | |
128 this.horizontalChanged(); | |
129 this.addListeners(this.target); | |
130 // set core-collapse-closed class initially to hide the target | |
131 this.toggleClosedClass(true); | |
132 this.update(); | |
133 }, | |
134 | |
135 addListeners: function(node) { | |
136 node.addEventListener('transitionend', this.transitionEndListener); | |
137 }, | |
138 | |
139 removeListeners: function(node) { | |
140 node.removeEventListener('transitionend', this.transitionEndListener); | |
141 }, | |
142 | |
143 horizontalChanged: function() { | |
144 this.dimension = this.horizontal ? 'width' : 'height'; | |
145 }, | |
146 | |
147 openedChanged: function() { | |
148 this.update(); | |
149 }, | |
150 | |
151 /** | |
152 * Toggle the opened state. | |
153 * | |
154 * @method toggle | |
155 */ | |
156 toggle: function() { | |
157 this.opened = !this.opened; | |
158 }, | |
159 | |
160 setTransitionDuration: function(duration) { | |
161 var s = this.target.style; | |
162 s.transition = duration ? (this.dimension + ' ' + duration + 's') : null; | |
163 if (duration === 0) { | |
164 this.async('transitionEnd'); | |
165 } | |
166 }, | |
167 | |
168 transitionEnd: function() { | |
169 if (this.opened && !this.fixedSize) { | |
170 this.updateSize('auto', null); | |
171 } | |
172 this.setTransitionDuration(null); | |
173 this.toggleClosedClass(!this.opened); | |
174 this.asyncFire('core-resize', null, this.target); | |
175 }, | |
176 | |
177 toggleClosedClass: function(closed) { | |
178 this.hasClosedClass = closed; | |
179 this.target.classList.toggle('core-collapse-closed', closed); | |
180 }, | |
181 | |
182 updateSize: function(size, duration, forceEnd) { | |
183 this.setTransitionDuration(duration); | |
184 this.calcSize(); | |
185 var s = this.target.style; | |
186 var nochange = s[this.dimension] === size; | |
187 s[this.dimension] = size; | |
188 // transitonEnd will not be called if the size has not changed | |
189 if (forceEnd && nochange) { | |
190 this.transitionEnd(); | |
191 } | |
192 }, | |
193 | |
194 update: function() { | |
195 if (!this.target) { | |
196 return; | |
197 } | |
198 if (!this.isTargetReady) { | |
199 this.targetChanged(); | |
200 } | |
201 this.horizontalChanged(); | |
202 this[this.opened ? 'show' : 'hide'](); | |
203 }, | |
204 | |
205 calcSize: function() { | |
206 return this.target.getBoundingClientRect()[this.dimension] + 'px'; | |
207 }, | |
208 | |
209 getComputedSize: function() { | |
210 return getComputedStyle(this.target)[this.dimension]; | |
211 }, | |
212 | |
213 show: function() { | |
214 this.toggleClosedClass(false); | |
215 // for initial update, skip the expanding animation to optimize | |
216 // performance e.g. skip calcSize | |
217 if (!this.afterInitialUpdate) { | |
218 this.transitionEnd(); | |
219 return; | |
220 } | |
221 if (!this.fixedSize) { | |
222 this.updateSize('auto', null); | |
223 var s = this.calcSize(); | |
224 this.updateSize(0, null); | |
225 } | |
226 this.async(function() { | |
227 this.updateSize(this.size || s, this.duration, true); | |
228 }); | |
229 }, | |
230 | |
231 hide: function() { | |
232 // don't need to do anything if it's already hidden | |
233 if (this.hasClosedClass && !this.fixedSize) { | |
234 return; | |
235 } | |
236 if (this.fixedSize) { | |
237 // save the size before hiding it | |
238 this.size = this.getComputedSize(); | |
239 } else { | |
240 this.updateSize(this.calcSize(), null); | |
241 } | |
242 this.async(function() { | |
243 this.updateSize(0, this.duration); | |
244 }); | |
245 } | |
246 | |
247 }); | |
248 | |
249 </script> | |
250 </polymer-element> | |
OLD | NEW |