OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright 2013 The Polymer Authors. All rights reserved. | |
3 Use of this source code is governed by a BSD-style | |
4 license that can be found in the LICENSE file. | |
5 --> | |
6 <!-- | |
7 /** | |
8 * @module Polymer Elements | |
9 */ | |
10 /** | |
11 * polymer-collapse is used to add collapsible behavior to the | |
12 * target element. It adjusts the height or width of the target element | |
13 * to make the element collapse and expand. | |
14 * | |
15 * Example: | |
16 * | |
17 * <button on-click="{{toggle}}">toggle collapse</button> | |
18 * <div id="demo"> | |
19 * ... | |
20 * </div> | |
21 * <polymer-collapse id="collapse" targetId="demo"></polymer-collapse> | |
22 * | |
23 * ... | |
24 * | |
25 * toggle: function() { | |
26 * this.$.collapse.toggle(); | |
27 * } | |
28 * | |
29 * @class polymer-collapse | |
30 */ | |
31 --> | |
32 <link rel="import" href="../polymer/polymer.html"> | |
33 | |
34 <polymer-element name="polymer-collapse" attributes="targetId target horizontal
closed duration fixedSize size"> | |
35 <template> | |
36 <link rel="stylesheet" polymer-scope="controller" href="polymer-collapse.css
"> | |
37 <link rel="stylesheet" href="polymer-collapse.css"> | |
38 <style> | |
39 :host { | |
40 display: none; | |
41 } | |
42 </style> | |
43 </template> | |
44 <script> | |
45 Polymer('polymer-collapse', { | |
46 /** | |
47 * The id of the target element. | |
48 * | |
49 * @attribute targetId | |
50 * @type string | |
51 * @default '' | |
52 */ | |
53 targetId: '', | |
54 /** | |
55 * The target element. | |
56 * | |
57 * @attribute target | |
58 * @type object | |
59 * @default null | |
60 */ | |
61 target: null, | |
62 /** | |
63 * If true, the orientation is horizontal; otherwise is vertical. | |
64 * | |
65 * @attribute horizontal | |
66 * @type boolean | |
67 * @default false | |
68 */ | |
69 horizontal: false, | |
70 /** | |
71 * If true, the target element is hidden/collapsed. | |
72 * | |
73 * @attribute closed | |
74 * @type boolean | |
75 * @default false | |
76 */ | |
77 closed: false, | |
78 /** | |
79 * Collapsing/expanding animation duration in second. | |
80 * | |
81 * @attribute duration | |
82 * @type number | |
83 * @default 0.33 | |
84 */ | |
85 duration: 0.33, | |
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 size: null, | |
98 attached: function() { | |
99 this.installControllerStyles(); | |
100 this.async(function() { | |
101 this.afterInitialUpdate = true; | |
102 }); | |
103 }, | |
104 detached: function() { | |
105 if (this.target) { | |
106 this.removeListeners(this.target); | |
107 } | |
108 }, | |
109 targetIdChanged: function() { | |
110 var p = this.parentNode; | |
111 while (p.parentNode) { | |
112 p = p.parentNode; | |
113 } | |
114 this.target = p.querySelector('#' + this.targetId); | |
115 }, | |
116 targetChanged: function(old) { | |
117 if (old) { | |
118 this.removeListeners(old); | |
119 } | |
120 this.horizontalChanged(); | |
121 this.isTargetReady = !!this.target; | |
122 if (this.target) { | |
123 this.target.style.overflow = 'hidden'; | |
124 this.addListeners(this.target); | |
125 // set polymer-collapse-closed class initially to hide the target | |
126 this.toggleClosedClass(true); | |
127 } | |
128 // don't need to update if the size is already set and it's opened | |
129 if (!this.fixedSize || !this.closed) { | |
130 this.update(); | |
131 } | |
132 }, | |
133 addListeners: function(node) { | |
134 this.transitionEndListener = this.transitionEndListener || | |
135 this.transitionEnd.bind(this); | |
136 node.addEventListener('webkitTransitionEnd', this.transitionEndListener)
; | |
137 node.addEventListener('transitionend', this.transitionEndListener); | |
138 }, | |
139 removeListeners: function(node) { | |
140 node.removeEventListener('webkitTransitionEnd', this.transitionEndListen
er); | |
141 node.removeEventListener('transitionend', this.transitionEndListener); | |
142 }, | |
143 horizontalChanged: function() { | |
144 this.dimension = this.horizontal ? 'width' : 'height'; | |
145 }, | |
146 closedChanged: function() { | |
147 this.update(); | |
148 }, | |
149 /** | |
150 * Toggle the closed state of the collapsible. | |
151 * | |
152 * @method toggle | |
153 */ | |
154 toggle: function() { | |
155 this.closed = !this.closed; | |
156 }, | |
157 setTransitionDuration: function(duration) { | |
158 var s = this.target.style; | |
159 s.webkitTransition = s.transition = duration ? | |
160 (this.dimension + ' ' + duration + 's') : null; | |
161 if (duration === 0) { | |
162 this.async('transitionEnd'); | |
163 } | |
164 }, | |
165 transitionEnd: function() { | |
166 if (!this.closed && !this.fixedSize) { | |
167 this.updateSize('auto', null); | |
168 } | |
169 this.setTransitionDuration(null); | |
170 this.toggleClosedClass(this.closed); | |
171 }, | |
172 toggleClosedClass: function(add) { | |
173 this.hasClosedClass = add; | |
174 this.target.classList.toggle('polymer-collapse-closed', add); | |
175 }, | |
176 updateSize: function(size, duration, forceEnd) { | |
177 if (duration) { | |
178 this.calcSize(); | |
179 } | |
180 this.setTransitionDuration(duration); | |
181 var s = this.target.style; | |
182 var nochange = s[this.dimension] === size; | |
183 s[this.dimension] = size; | |
184 // transitonEnd will not be called if the size has not changed | |
185 if (forceEnd && nochange) { | |
186 this.transitionEnd(); | |
187 } | |
188 }, | |
189 update: function() { | |
190 if (!this.target) { | |
191 return; | |
192 } | |
193 if (!this.isTargetReady) { | |
194 this.targetChanged(); | |
195 } | |
196 this.horizontalChanged(); | |
197 this[this.closed ? 'hide' : 'show'](); | |
198 }, | |
199 calcSize: function() { | |
200 return this.target.getBoundingClientRect()[this.dimension] + 'px'; | |
201 }, | |
202 getComputedSize: function() { | |
203 return getComputedStyle(this.target)[this.dimension]; | |
204 }, | |
205 show: function() { | |
206 this.toggleClosedClass(false); | |
207 // for initial update, skip the expanding animation to optimize | |
208 // performance e.g. skip calcSize | |
209 if (!this.afterInitialUpdate) { | |
210 this.transitionEnd(); | |
211 return; | |
212 } | |
213 if (!this.fixedSize) { | |
214 this.updateSize('auto', null); | |
215 var s = this.calcSize(); | |
216 this.updateSize(0, null); | |
217 } | |
218 this.async(function() { | |
219 this.updateSize(this.size || s, this.duration, true); | |
220 }); | |
221 }, | |
222 hide: function() { | |
223 // don't need to do anything if it's already hidden | |
224 if (this.hasClosedClass && !this.fixedSize) { | |
225 return; | |
226 } | |
227 if (this.fixedSize) { | |
228 // save the size before hiding it | |
229 this.size = this.getComputedSize(); | |
230 } else { | |
231 this.updateSize(this.calcSize(), null); | |
232 } | |
233 this.async(function() { | |
234 this.updateSize(0, this.duration); | |
235 }); | |
236 } | |
237 }); | |
238 </script> | |
239 </polymer-element> | |
OLD | NEW |