|
1 YUI.add('transition', function (Y, NAME) { |
|
2 |
|
3 /** |
|
4 * Provides the transition method for Node. |
|
5 * Transition has no API of its own, but adds the transition method to Node. |
|
6 * |
|
7 * @module transition |
|
8 * @requires node-style |
|
9 */ |
|
10 |
|
11 var CAMEL_VENDOR_PREFIX = '', |
|
12 VENDOR_PREFIX = '', |
|
13 DOCUMENT = Y.config.doc, |
|
14 DOCUMENT_ELEMENT = 'documentElement', |
|
15 DOCUMENT_STYLE = DOCUMENT[DOCUMENT_ELEMENT].style, |
|
16 TRANSITION_CAMEL = 'transition', |
|
17 TRANSITION_PROPERTY_CAMEL = 'transitionProperty', |
|
18 TRANSITION_PROPERTY, |
|
19 TRANSITION_DURATION, |
|
20 TRANSITION_TIMING_FUNCTION, |
|
21 TRANSITION_DELAY, |
|
22 TRANSITION_END, |
|
23 ON_TRANSITION_END, |
|
24 |
|
25 EMPTY_OBJ = {}, |
|
26 |
|
27 VENDORS = [ |
|
28 'Webkit', |
|
29 'Moz' |
|
30 ], |
|
31 |
|
32 VENDOR_TRANSITION_END = { |
|
33 Webkit: 'webkitTransitionEnd' |
|
34 }, |
|
35 |
|
36 /** |
|
37 * A class for constructing transition instances. |
|
38 * Adds the "transition" method to Node. |
|
39 * @class Transition |
|
40 * @constructor |
|
41 */ |
|
42 |
|
43 Transition = function() { |
|
44 this.init.apply(this, arguments); |
|
45 }; |
|
46 |
|
47 // One off handling of transform-prefixing. |
|
48 Transition._TRANSFORM = 'transform'; |
|
49 |
|
50 Transition._toCamel = function(property) { |
|
51 property = property.replace(/-([a-z])/gi, function(m0, m1) { |
|
52 return m1.toUpperCase(); |
|
53 }); |
|
54 |
|
55 return property; |
|
56 }; |
|
57 |
|
58 Transition._toHyphen = function(property) { |
|
59 property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) { |
|
60 var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2; |
|
61 |
|
62 if (m3) { |
|
63 str += '-' + m3.toLowerCase(); |
|
64 } |
|
65 |
|
66 return str; |
|
67 }); |
|
68 |
|
69 return property; |
|
70 }; |
|
71 |
|
72 Transition.SHOW_TRANSITION = 'fadeIn'; |
|
73 Transition.HIDE_TRANSITION = 'fadeOut'; |
|
74 |
|
75 Transition.useNative = false; |
|
76 |
|
77 // Map transition properties to vendor-specific versions. |
|
78 if ('transition' in DOCUMENT_STYLE |
|
79 && 'transitionProperty' in DOCUMENT_STYLE |
|
80 && 'transitionDuration' in DOCUMENT_STYLE |
|
81 && 'transitionTimingFunction' in DOCUMENT_STYLE |
|
82 && 'transitionDelay' in DOCUMENT_STYLE) { |
|
83 Transition.useNative = true; |
|
84 Transition.supported = true; // TODO: remove |
|
85 } else { |
|
86 Y.Array.each(VENDORS, function(val) { // then vendor specific |
|
87 var property = val + 'Transition'; |
|
88 if (property in DOCUMENT[DOCUMENT_ELEMENT].style) { |
|
89 CAMEL_VENDOR_PREFIX = val; |
|
90 VENDOR_PREFIX = Transition._toHyphen(val) + '-'; |
|
91 |
|
92 Transition.useNative = true; |
|
93 Transition.supported = true; // TODO: remove |
|
94 Transition._VENDOR_PREFIX = val; |
|
95 } |
|
96 }); |
|
97 } |
|
98 |
|
99 // Map transform property to vendor-specific versions. |
|
100 // One-off required for cssText injection. |
|
101 if (typeof DOCUMENT_STYLE.transform === 'undefined') { |
|
102 Y.Array.each(VENDORS, function(val) { // then vendor specific |
|
103 var property = val + 'Transform'; |
|
104 if (typeof DOCUMENT_STYLE[property] !== 'undefined') { |
|
105 Transition._TRANSFORM = property; |
|
106 } |
|
107 }); |
|
108 } |
|
109 |
|
110 if (CAMEL_VENDOR_PREFIX) { |
|
111 TRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + 'Transition'; |
|
112 TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty'; |
|
113 } |
|
114 |
|
115 TRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property'; |
|
116 TRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration'; |
|
117 TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function'; |
|
118 TRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay'; |
|
119 |
|
120 TRANSITION_END = 'transitionend'; |
|
121 ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend'; |
|
122 TRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END; |
|
123 |
|
124 Transition.fx = {}; |
|
125 Transition.toggles = {}; |
|
126 |
|
127 Transition._hasEnd = {}; |
|
128 |
|
129 Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i; |
|
130 |
|
131 Y.Node.DOM_EVENTS[TRANSITION_END] = 1; |
|
132 |
|
133 Transition.NAME = 'transition'; |
|
134 |
|
135 Transition.DEFAULT_EASING = 'ease'; |
|
136 Transition.DEFAULT_DURATION = 0.5; |
|
137 Transition.DEFAULT_DELAY = 0; |
|
138 |
|
139 Transition._nodeAttrs = {}; |
|
140 |
|
141 Transition.prototype = { |
|
142 constructor: Transition, |
|
143 init: function(node, config) { |
|
144 var anim = this; |
|
145 anim._node = node; |
|
146 if (!anim._running && config) { |
|
147 anim._config = config; |
|
148 node._transition = anim; // cache for reuse |
|
149 |
|
150 anim._duration = ('duration' in config) ? |
|
151 config.duration: anim.constructor.DEFAULT_DURATION; |
|
152 |
|
153 anim._delay = ('delay' in config) ? |
|
154 config.delay: anim.constructor.DEFAULT_DELAY; |
|
155 |
|
156 anim._easing = config.easing || anim.constructor.DEFAULT_EASING; |
|
157 anim._count = 0; // track number of animated properties |
|
158 anim._running = false; |
|
159 |
|
160 } |
|
161 |
|
162 return anim; |
|
163 }, |
|
164 |
|
165 addProperty: function(prop, config) { |
|
166 var anim = this, |
|
167 node = this._node, |
|
168 uid = Y.stamp(node), |
|
169 nodeInstance = Y.one(node), |
|
170 attrs = Transition._nodeAttrs[uid], |
|
171 computed, |
|
172 compareVal, |
|
173 dur, |
|
174 attr, |
|
175 val; |
|
176 |
|
177 if (!attrs) { |
|
178 attrs = Transition._nodeAttrs[uid] = {}; |
|
179 } |
|
180 |
|
181 attr = attrs[prop]; |
|
182 |
|
183 // might just be a value |
|
184 if (config && config.value !== undefined) { |
|
185 val = config.value; |
|
186 } else if (config !== undefined) { |
|
187 val = config; |
|
188 config = EMPTY_OBJ; |
|
189 } |
|
190 |
|
191 if (typeof val === 'function') { |
|
192 val = val.call(nodeInstance, nodeInstance); |
|
193 } |
|
194 |
|
195 if (attr && attr.transition) { |
|
196 // take control if another transition owns this property |
|
197 if (attr.transition !== anim) { |
|
198 attr.transition._count--; // remapping attr to this transition |
|
199 } |
|
200 } |
|
201 |
|
202 anim._count++; // properties per transition |
|
203 |
|
204 // make 0 async and fire events |
|
205 dur = ((typeof config.duration !== 'undefined') ? config.duration : |
|
206 anim._duration) || 0.0001; |
|
207 |
|
208 attrs[prop] = { |
|
209 value: val, |
|
210 duration: dur, |
|
211 delay: (typeof config.delay !== 'undefined') ? config.delay : |
|
212 anim._delay, |
|
213 |
|
214 easing: config.easing || anim._easing, |
|
215 |
|
216 transition: anim |
|
217 }; |
|
218 |
|
219 // native end event doesnt fire when setting to same value |
|
220 // supplementing with timer |
|
221 // val may be a string or number (height: 0, etc), but computedStyle is always string |
|
222 computed = Y.DOM.getComputedStyle(node, prop); |
|
223 compareVal = (typeof val === 'string') ? computed : parseFloat(computed); |
|
224 |
|
225 if (Transition.useNative && compareVal === val) { |
|
226 setTimeout(function() { |
|
227 anim._onNativeEnd.call(node, { |
|
228 propertyName: prop, |
|
229 elapsedTime: dur |
|
230 }); |
|
231 }, dur * 1000); |
|
232 } |
|
233 }, |
|
234 |
|
235 removeProperty: function(prop) { |
|
236 var anim = this, |
|
237 attrs = Transition._nodeAttrs[Y.stamp(anim._node)]; |
|
238 |
|
239 if (attrs && attrs[prop]) { |
|
240 delete attrs[prop]; |
|
241 anim._count--; |
|
242 } |
|
243 |
|
244 }, |
|
245 |
|
246 initAttrs: function(config) { |
|
247 var attr, |
|
248 node = this._node; |
|
249 |
|
250 if (config.transform && !config[Transition._TRANSFORM]) { |
|
251 config[Transition._TRANSFORM] = config.transform; |
|
252 delete config.transform; // TODO: copy |
|
253 } |
|
254 |
|
255 for (attr in config) { |
|
256 if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) { |
|
257 this.addProperty(attr, config[attr]); |
|
258 |
|
259 // when size is auto or % webkit starts from zero instead of computed |
|
260 // (https://bugs.webkit.org/show_bug.cgi?id=16020) |
|
261 // TODO: selective set |
|
262 if (node.style[attr] === '') { |
|
263 Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr)); |
|
264 } |
|
265 } |
|
266 } |
|
267 }, |
|
268 |
|
269 /** |
|
270 * Starts or an animation. |
|
271 * @method run |
|
272 * @chainable |
|
273 * @private |
|
274 */ |
|
275 run: function(callback) { |
|
276 var anim = this, |
|
277 node = anim._node, |
|
278 config = anim._config, |
|
279 data = { |
|
280 type: 'transition:start', |
|
281 config: config |
|
282 }; |
|
283 |
|
284 |
|
285 if (!anim._running) { |
|
286 anim._running = true; |
|
287 |
|
288 if (config.on && config.on.start) { |
|
289 config.on.start.call(Y.one(node), data); |
|
290 } |
|
291 |
|
292 anim.initAttrs(anim._config); |
|
293 |
|
294 anim._callback = callback; |
|
295 anim._start(); |
|
296 } |
|
297 |
|
298 |
|
299 return anim; |
|
300 }, |
|
301 |
|
302 _start: function() { |
|
303 this._runNative(); |
|
304 }, |
|
305 |
|
306 _prepDur: function(dur) { |
|
307 dur = parseFloat(dur) * 1000; |
|
308 |
|
309 return dur + 'ms'; |
|
310 }, |
|
311 |
|
312 _runNative: function() { |
|
313 var anim = this, |
|
314 node = anim._node, |
|
315 uid = Y.stamp(node), |
|
316 style = node.style, |
|
317 computed = node.ownerDocument.defaultView.getComputedStyle(node), |
|
318 attrs = Transition._nodeAttrs[uid], |
|
319 cssText = '', |
|
320 cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)], |
|
321 |
|
322 transitionText = TRANSITION_PROPERTY + ': ', |
|
323 duration = TRANSITION_DURATION + ': ', |
|
324 easing = TRANSITION_TIMING_FUNCTION + ': ', |
|
325 delay = TRANSITION_DELAY + ': ', |
|
326 hyphy, |
|
327 attr, |
|
328 name; |
|
329 |
|
330 // preserve existing transitions |
|
331 if (cssTransition !== 'all') { |
|
332 transitionText += cssTransition + ','; |
|
333 duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ','; |
|
334 easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ','; |
|
335 delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ','; |
|
336 |
|
337 } |
|
338 |
|
339 // run transitions mapped to this instance |
|
340 for (name in attrs) { |
|
341 hyphy = Transition._toHyphen(name); |
|
342 attr = attrs[name]; |
|
343 if ((attr = attrs[name]) && attr.transition === anim) { |
|
344 if (name in node.style) { // only native styles allowed |
|
345 duration += anim._prepDur(attr.duration) + ','; |
|
346 delay += anim._prepDur(attr.delay) + ','; |
|
347 easing += (attr.easing) + ','; |
|
348 |
|
349 transitionText += hyphy + ','; |
|
350 cssText += hyphy + ': ' + attr.value + '; '; |
|
351 } else { |
|
352 this.removeProperty(name); |
|
353 } |
|
354 } |
|
355 } |
|
356 |
|
357 transitionText = transitionText.replace(/,$/, ';'); |
|
358 duration = duration.replace(/,$/, ';'); |
|
359 easing = easing.replace(/,$/, ';'); |
|
360 delay = delay.replace(/,$/, ';'); |
|
361 |
|
362 // only one native end event per node |
|
363 if (!Transition._hasEnd[uid]) { |
|
364 node.addEventListener(TRANSITION_END, anim._onNativeEnd, ''); |
|
365 Transition._hasEnd[uid] = true; |
|
366 |
|
367 } |
|
368 |
|
369 style.cssText += transitionText + duration + easing + delay + cssText; |
|
370 |
|
371 }, |
|
372 |
|
373 _end: function(elapsed) { |
|
374 var anim = this, |
|
375 node = anim._node, |
|
376 callback = anim._callback, |
|
377 config = anim._config, |
|
378 data = { |
|
379 type: 'transition:end', |
|
380 config: config, |
|
381 elapsedTime: elapsed |
|
382 }, |
|
383 |
|
384 nodeInstance = Y.one(node); |
|
385 |
|
386 anim._running = false; |
|
387 anim._callback = null; |
|
388 |
|
389 if (node) { |
|
390 if (config.on && config.on.end) { |
|
391 setTimeout(function() { // IE: allow previous update to finish |
|
392 config.on.end.call(nodeInstance, data); |
|
393 |
|
394 // nested to ensure proper fire order |
|
395 if (callback) { |
|
396 callback.call(nodeInstance, data); |
|
397 } |
|
398 |
|
399 }, 1); |
|
400 } else if (callback) { |
|
401 setTimeout(function() { // IE: allow previous update to finish |
|
402 callback.call(nodeInstance, data); |
|
403 }, 1); |
|
404 } |
|
405 } |
|
406 |
|
407 }, |
|
408 |
|
409 _endNative: function(name) { |
|
410 var node = this._node, |
|
411 value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)]; |
|
412 |
|
413 name = Transition._toHyphen(name); |
|
414 if (typeof value === 'string') { |
|
415 value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ','); |
|
416 value = value.replace(/^,|,$/, ''); |
|
417 node.style[TRANSITION_CAMEL] = value; |
|
418 } |
|
419 }, |
|
420 |
|
421 _onNativeEnd: function(e) { |
|
422 var node = this, |
|
423 uid = Y.stamp(node), |
|
424 event = e,//e._event, |
|
425 name = Transition._toCamel(event.propertyName), |
|
426 elapsed = event.elapsedTime, |
|
427 attrs = Transition._nodeAttrs[uid], |
|
428 attr = attrs[name], |
|
429 anim = (attr) ? attr.transition : null, |
|
430 data, |
|
431 config; |
|
432 |
|
433 if (anim) { |
|
434 anim.removeProperty(name); |
|
435 anim._endNative(name); |
|
436 config = anim._config[name]; |
|
437 |
|
438 data = { |
|
439 type: 'propertyEnd', |
|
440 propertyName: name, |
|
441 elapsedTime: elapsed, |
|
442 config: config |
|
443 }; |
|
444 |
|
445 if (config && config.on && config.on.end) { |
|
446 config.on.end.call(Y.one(node), data); |
|
447 } |
|
448 |
|
449 if (anim._count <= 0) { // after propertyEnd fires |
|
450 anim._end(elapsed); |
|
451 node.style[TRANSITION_PROPERTY_CAMEL] = ''; // clean up style |
|
452 } |
|
453 } |
|
454 }, |
|
455 |
|
456 destroy: function() { |
|
457 var anim = this, |
|
458 node = anim._node; |
|
459 |
|
460 if (node) { |
|
461 node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false); |
|
462 anim._node = null; |
|
463 } |
|
464 } |
|
465 }; |
|
466 |
|
467 Y.Transition = Transition; |
|
468 Y.TransitionNative = Transition; // TODO: remove |
|
469 |
|
470 /** |
|
471 * Animate one or more css properties to a given value. Requires the "transition" module. |
|
472 * <pre>example usage: |
|
473 * Y.one('#demo').transition({ |
|
474 * duration: 1, // in seconds, default is 0.5 |
|
475 * easing: 'ease-out', // default is 'ease' |
|
476 * delay: '1', // delay start for 1 second, default is 0 |
|
477 * |
|
478 * height: '10px', |
|
479 * width: '10px', |
|
480 * |
|
481 * opacity: { // per property |
|
482 * value: 0, |
|
483 * duration: 2, |
|
484 * delay: 2, |
|
485 * easing: 'ease-in' |
|
486 * } |
|
487 * }); |
|
488 * </pre> |
|
489 * @for Node |
|
490 * @method transition |
|
491 * @param {Object} config An object containing one or more style properties, a duration and an easing. |
|
492 * @param {Function} callback A function to run after the transition has completed. |
|
493 * @chainable |
|
494 */ |
|
495 Y.Node.prototype.transition = function(name, config, callback) { |
|
496 var |
|
497 transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)], |
|
498 anim = (transitionAttrs) ? transitionAttrs.transition || null : null, |
|
499 fxConfig, |
|
500 prop; |
|
501 |
|
502 if (typeof name === 'string') { // named effect, pull config from registry |
|
503 if (typeof config === 'function') { |
|
504 callback = config; |
|
505 config = null; |
|
506 } |
|
507 |
|
508 fxConfig = Transition.fx[name]; |
|
509 |
|
510 if (config && typeof config === 'object') { |
|
511 config = Y.clone(config); |
|
512 |
|
513 for (prop in fxConfig) { |
|
514 if (fxConfig.hasOwnProperty(prop)) { |
|
515 if (! (prop in config)) { |
|
516 config[prop] = fxConfig[prop]; |
|
517 } |
|
518 } |
|
519 } |
|
520 } else { |
|
521 config = fxConfig; |
|
522 } |
|
523 |
|
524 } else { // name is a config, config is a callback or undefined |
|
525 callback = config; |
|
526 config = name; |
|
527 } |
|
528 |
|
529 if (anim && !anim._running) { |
|
530 anim.init(this, config); |
|
531 } else { |
|
532 anim = new Transition(this._node, config); |
|
533 } |
|
534 |
|
535 anim.run(callback); |
|
536 return this; |
|
537 }; |
|
538 |
|
539 Y.Node.prototype.show = function(name, config, callback) { |
|
540 this._show(); // show prior to transition |
|
541 if (name && Y.Transition) { |
|
542 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default |
|
543 if (typeof config === 'function') { |
|
544 callback = config; |
|
545 config = name; |
|
546 } |
|
547 name = Transition.SHOW_TRANSITION; |
|
548 } |
|
549 this.transition(name, config, callback); |
|
550 } |
|
551 else if (name && !Y.Transition) { Y.log('unable to transition show; missing transition module', 'warn', 'node'); } |
|
552 return this; |
|
553 }; |
|
554 |
|
555 Y.NodeList.prototype.show = function(name, config, callback) { |
|
556 var nodes = this._nodes, |
|
557 i = 0, |
|
558 node; |
|
559 |
|
560 while ((node = nodes[i++])) { |
|
561 Y.one(node).show(name, config, callback); |
|
562 } |
|
563 |
|
564 return this; |
|
565 }; |
|
566 |
|
567 |
|
568 |
|
569 var _wrapCallBack = function(anim, fn, callback) { |
|
570 return function() { |
|
571 if (fn) { |
|
572 fn.call(anim); |
|
573 } |
|
574 if (callback && typeof callback === 'function') { |
|
575 callback.apply(anim._node, arguments); |
|
576 } |
|
577 }; |
|
578 }; |
|
579 |
|
580 Y.Node.prototype.hide = function(name, config, callback) { |
|
581 if (name && Y.Transition) { |
|
582 if (typeof config === 'function') { |
|
583 callback = config; |
|
584 config = null; |
|
585 } |
|
586 |
|
587 callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback |
|
588 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default |
|
589 if (typeof config === 'function') { |
|
590 callback = config; |
|
591 config = name; |
|
592 } |
|
593 name = Transition.HIDE_TRANSITION; |
|
594 } |
|
595 this.transition(name, config, callback); |
|
596 } else if (name && !Y.Transition) { Y.log('unable to transition hide; missing transition module', 'warn', 'node'); |
|
597 } else { |
|
598 this._hide(); |
|
599 } |
|
600 return this; |
|
601 }; |
|
602 |
|
603 Y.NodeList.prototype.hide = function(name, config, callback) { |
|
604 var nodes = this._nodes, |
|
605 i = 0, |
|
606 node; |
|
607 |
|
608 while ((node = nodes[i++])) { |
|
609 Y.one(node).hide(name, config, callback); |
|
610 } |
|
611 |
|
612 return this; |
|
613 }; |
|
614 |
|
615 /** |
|
616 * Animate one or more css properties to a given value. Requires the "transition" module. |
|
617 * <pre>example usage: |
|
618 * Y.all('.demo').transition({ |
|
619 * duration: 1, // in seconds, default is 0.5 |
|
620 * easing: 'ease-out', // default is 'ease' |
|
621 * delay: '1', // delay start for 1 second, default is 0 |
|
622 * |
|
623 * height: '10px', |
|
624 * width: '10px', |
|
625 * |
|
626 * opacity: { // per property |
|
627 * value: 0, |
|
628 * duration: 2, |
|
629 * delay: 2, |
|
630 * easing: 'ease-in' |
|
631 * } |
|
632 * }); |
|
633 * </pre> |
|
634 * @for NodeList |
|
635 * @method transition |
|
636 * @param {Object} config An object containing one or more style properties, a duration and an easing. |
|
637 * @param {Function} callback A function to run after the transition has completed. The callback fires |
|
638 * once per item in the NodeList. |
|
639 * @param {Boolean} callbackOnce If true, the callback will be called only after the |
|
640 * last transition has completed |
|
641 * @chainable |
|
642 */ |
|
643 Y.NodeList.prototype.transition = function(config, callback, callbackOnce) { |
|
644 var nodes = this._nodes, |
|
645 size = this.size(), |
|
646 i = 0, |
|
647 callbackOnce = callbackOnce === true, |
|
648 node; |
|
649 |
|
650 while ((node = nodes[i++])) { |
|
651 if (i < size && callbackOnce){ |
|
652 Y.one(node).transition(config); |
|
653 } else { |
|
654 Y.one(node).transition(config, callback); |
|
655 } |
|
656 } |
|
657 |
|
658 return this; |
|
659 }; |
|
660 |
|
661 Y.Node.prototype.toggleView = function(name, on, callback) { |
|
662 this._toggles = this._toggles || []; |
|
663 callback = arguments[arguments.length - 1]; |
|
664 |
|
665 if (typeof name !== 'string') { // no transition, just toggle |
|
666 on = name; |
|
667 this._toggleView(on, callback); // call original _toggleView in Y.Node |
|
668 return; |
|
669 } |
|
670 |
|
671 if (typeof on === 'function') { // Ignore "on" if used for callback argument. |
|
672 on = undefined; |
|
673 } |
|
674 |
|
675 if (typeof on === 'undefined' && name in this._toggles) { // reverse current toggle |
|
676 on = ! this._toggles[name]; |
|
677 } |
|
678 |
|
679 on = (on) ? 1 : 0; |
|
680 if (on) { |
|
681 this._show(); |
|
682 } else { |
|
683 callback = _wrapCallBack(this, this._hide, callback); |
|
684 } |
|
685 |
|
686 this._toggles[name] = on; |
|
687 this.transition(Y.Transition.toggles[name][on], callback); |
|
688 |
|
689 return this; |
|
690 }; |
|
691 |
|
692 Y.NodeList.prototype.toggleView = function(name, on, callback) { |
|
693 var nodes = this._nodes, |
|
694 i = 0, |
|
695 node; |
|
696 |
|
697 while ((node = nodes[i++])) { |
|
698 node = Y.one(node); |
|
699 node.toggleView.apply(node, arguments); |
|
700 } |
|
701 |
|
702 return this; |
|
703 }; |
|
704 |
|
705 Y.mix(Transition.fx, { |
|
706 fadeOut: { |
|
707 opacity: 0, |
|
708 duration: 0.5, |
|
709 easing: 'ease-out' |
|
710 }, |
|
711 |
|
712 fadeIn: { |
|
713 opacity: 1, |
|
714 duration: 0.5, |
|
715 easing: 'ease-in' |
|
716 }, |
|
717 |
|
718 sizeOut: { |
|
719 height: 0, |
|
720 width: 0, |
|
721 duration: 0.75, |
|
722 easing: 'ease-out' |
|
723 }, |
|
724 |
|
725 sizeIn: { |
|
726 height: function(node) { |
|
727 return node.get('scrollHeight') + 'px'; |
|
728 }, |
|
729 width: function(node) { |
|
730 return node.get('scrollWidth') + 'px'; |
|
731 }, |
|
732 duration: 0.5, |
|
733 easing: 'ease-in', |
|
734 |
|
735 on: { |
|
736 start: function() { |
|
737 var overflow = this.getStyle('overflow'); |
|
738 if (overflow !== 'hidden') { // enable scrollHeight/Width |
|
739 this.setStyle('overflow', 'hidden'); |
|
740 this._transitionOverflow = overflow; |
|
741 } |
|
742 }, |
|
743 |
|
744 end: function() { |
|
745 if (this._transitionOverflow) { // revert overridden value |
|
746 this.setStyle('overflow', this._transitionOverflow); |
|
747 delete this._transitionOverflow; |
|
748 } |
|
749 } |
|
750 } |
|
751 } |
|
752 }); |
|
753 |
|
754 Y.mix(Transition.toggles, { |
|
755 size: ['sizeOut', 'sizeIn'], |
|
756 fade: ['fadeOut', 'fadeIn'] |
|
757 }); |
|
758 |
|
759 |
|
760 }, '@VERSION@', {"requires": ["node-style"]}); |