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