UNPKG

skylark-utils

Version:

An Elegant HTML5 JavaScript Library.

287 lines (242 loc) 8.25 kB
define([ "./skylark", "./langx", "./browser", "./styler", "./eventer" ], function(skylark, langx, browser, styler, eventer) { var animationName, animationDuration, animationTiming, animationDelay, transitionProperty, transitionDuration, transitionTiming, transitionDelay, animationEnd = browser.normalizeCssEvent('AnimationEnd'), transitionEnd = browser.normalizeCssEvent('TransitionEnd'), supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, transform = browser.css3PropPrefix + "transform", cssReset = {}; cssReset[animationName = browser.normalizeCssProperty("animation-name")] = cssReset[animationDuration = browser.normalizeCssProperty("animation-duration")] = cssReset[animationDelay = browser.normalizeCssProperty("animation-delay")] = cssReset[animationTiming = browser.normalizeCssProperty("animation-timing-function")] = ""; cssReset[transitionProperty = browser.normalizeCssProperty("transition-property")] = cssReset[transitionDuration = browser.normalizeCssProperty("transition-duration")] = cssReset[transitionDelay = browser.normalizeCssProperty("transition-delay")] = cssReset[transitionTiming = browser.normalizeCssProperty("transition-timing-function")] = ""; function animate(elm, properties, duration, ease, callback, delay) { var key, cssValues = {}, cssProperties = [], transforms = "", that = this, endEvent, wrappedCallback, fired = false, hasScrollTop = false; if (langx.isPlainObject(duration)) { ease = duration.easing; callback = duration.complete; delay = duration.delay; duration = duration.duration; } if (langx.isString(duration)) { duration = fx.speeds[duration]; } if (duration === undefined) { duration = fx.speeds.normal; } duration = duration / 1000; if (fx.off) { duration = 0; } if (langx.isFunction(ease)) { callback = ease; eace = "swing"; } else { ease = ease || "swing"; } if (delay) { delay = delay / 1000; } else { delay = 0; } if (langx.isString(properties)) { // keyframe animation cssValues[animationName] = properties; cssValues[animationDuration] = duration + "s"; cssValues[animationTiming] = ease; endEvent = animationEnd; } else { // CSS transitions for (key in properties) { if (supportedTransforms.test(key)) { transforms += key + "(" + properties[key] + ") "; } else { if (key === "scrollTop") { hasScrollTop = true; } cssValues[key] = properties[key]; cssProperties.push(langx.dasherize(key)); } } endEvent = transitionEnd; } if (transforms) { cssValues[transform] = transforms; cssProperties.push(transform); } if (duration > 0 && langx.isPlainObject(properties)) { cssValues[transitionProperty] = cssProperties.join(", "); cssValues[transitionDuration] = duration + "s"; cssValues[transitionDelay] = delay + "s"; cssValues[transitionTiming] = ease; } wrappedCallback = function(event) { fired = true; if (event) { if (event.target !== event.currentTarget) { return // makes sure the event didn't bubble from "below" } eventer.off(event.target, endEvent, wrappedCallback) } else { eventer.off(elm, animationEnd, wrappedCallback) // triggered by setTimeout } styler.css(elm, cssReset); callback && callback.call(this); }; if (duration > 0) { eventer.on(elm, endEvent, wrappedCallback); // transitionEnd is not always firing on older Android phones // so make sure it gets fired langx.debounce(function() { if (fired) { return; } wrappedCallback.call(that); }, ((duration + delay) * 1000) + 25)(); } // trigger page reflow so new elements can animate elm.clientLeft; styler.css(elm, cssValues); if (duration <= 0) { langx.debounce(function() { if (fired) { return; } wrappedCallback.call(that); }, 0)(); } if (hasScrollTop) { scrollToTop(elm, properties["scrollTop"], duration, callback); } return this; } function show(elm, speed, callback) { styler.show(elm); if (speed) { if (!callback && langx.isFunction(speed)) { callback = speed; speed = "normal"; } styler.css(elm, "opacity", 0) animate(elm, { opacity: 1, scale: "1,1" }, speed, callback); } return this; } function hide(elm, speed, callback) { if (speed) { if (!callback && langx.isFunction(speed)) { callback = speed; speed = "normal"; } animate(elm, { opacity: 0, scale: "0,0" }, speed, function() { styler.hide(elm); if (callback) { callback.call(elm); } }); } else { styler.hide(elm); } return this; } function scrollToTop(elm, pos, speed, callback) { var scrollFrom = parseInt(elm.scrollTop), i = 0, runEvery = 5, // run every 5ms freq = speed * 1000 / runEvery, scrollTo = parseInt(pos); var interval = setInterval(function() { i++; if(i<=freq) elm.scrollTop = (scrollTo - scrollFrom) / freq * i + scrollFrom; if (i >= freq + 1) { clearInterval(interval); if (callback) langx.debounce(callback, 1000)(); } }, runEvery); } function toggle(elm, speed, callback) { if (styler.isInvisible(elm)) { show(elm, speed, callback); } else { hide(elm, speed, callback); } return this; } function fadeTo(elm, speed, opacity, callback) { animate(elm, { opacity: opacity }, speed, callback); return this; } function fadeIn(elm, speed, callback) { var target = styler.css(elm, "opacity"); if (target > 0) { styler.css(elm, "opacity", 0); } else { target = 1; } styler.show(elm); fadeTo(elm, speed, target, callback); return this; } function fadeOut(elm, speed, callback) { fadeTo(elm, speed, 0, function() { styler.hide(elm); if (callback) { callback.call(elm); } }); return this; } function fadeToggle(elm, speed, callback) { if (styler.isInvisible(elm)) { fadeIn(elm, speed, callback); } else { fadeOut(elm, speed, callback); } return this; } function fx() { return fx; } langx.mixin(fx, { off: false, speeds: { normal: 400, fast: 200, slow: 600 }, animate: animate, fadeIn: fadeIn, fadeOut: fadeOut, fadeTo: fadeTo, fadeToggle: fadeToggle, hide: hide, scrollToTop: scrollToTop, show: show, toggle: toggle }); return skylark.fx = fx; });