/*
// jQuery tools
// GPL/MIT License - @molokoloco 2011 - http://b2bweb.fr
// Dependancy to moderniz.js for $.fn.crossCss
*/
// I use this for debuging ^^
var db = function() { 'console' in window && console.log.call(console, arguments); };
(function($, window) {
$.toolsLoaded = true; // Declare tools.js as loaded...
// Beziers equation approximations from Matthew Lein's Ceaser: http://matthewlein.com/ceaser/
// Remixed for this use : "transition:'all 3000ms '+$.cubicBeziers.easeInOutQuad;"
// If values outside range 0>=X=<1 can produce a bug, in chrome for example
var qbo = 'cubic-bezier(', qbc = ')';
$.cubicBeziers = {
bounce: qbo+'0.000,0.350,0.500,1.300'+qbc, // !
snap: qbo+'0.000,1.000,0.500,1.000'+qbc,
easeInQuad: qbo+'0.550,0.085,0.680,0.530'+qbc,
easeInCubic: qbo+'0.550,0.055,0.675,0.190'+qbc,
easeInQuart: qbo+'0.895,0.030,0.685,0.220'+qbc,
easeInQuint: qbo+'0.755,0.050,0.855,0.060'+qbc,
easeInSine: qbo+'0.470,0.000,0.745,0.715'+qbc,
easeInExpo: qbo+'0.950,0.050,0.795,0.035'+qbc,
easeInCirc: qbo+'0.600,0.040,0.980,0.335'+qbc,
easeOutQuad: qbo+'0.250,0.460,0.450,0.940'+qbc,
easeOutCubic: qbo+'0.215,0.610,0.355,1.000'+qbc,
easeOutQuart: qbo+'0.165,0.840,0.440,1.000'+qbc,
easeOutQuint: qbo+'0.230,1.000,0.320,1.000'+qbc,
easeOutSine: qbo+'0.390,0.575,0.565,1.000'+qbc,
easeOutExpo: qbo+'0.190,1.000,0.220,1.000'+qbc,
easeOutCirc: qbo+'0.075,0.820,0.165,1.000'+qbc,
easeInOutQuad: qbo+'0.455,0.030,0.515,0.955'+qbc,
easeInOutCubic: qbo+'0.645,0.045,0.355,1.000'+qbc,
easeInOutQuart: qbo+'0.770,0.000,0.175,1.000'+qbc,
easeInOutQuint: qbo+'0.860,0.000,0.070,1.000'+qbc,
easeInOutSine: qbo+'0.445,0.050,0.550,0.950'+qbc,
easeInOutExpo: qbo+'1.000,0.000,0.000,1.000'+qbc,
easeInOutCirc: qbo+'0.785,0.135,0.150,0.860'+qbc
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Somes prototyping utilities...
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// "border-radius" -> "borderRadius"
String.prototype.toCamel = function() {
return this.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
};
// "borderRadius" -> "border-radius"
String.prototype.toDash = function(){
return this.replace(/([A-Z])/g, function($1){return '-'+$1.toLowerCase();});
};
// Cross-browsers requestAnimationFrame
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Somes utilities, setted as public through the jQuery obj
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Generate random numbers...
$.getRand = function(miin, maax) {
return parseInt(miin + (Math.random() * (maax - miin)), 10);
};
// Lightest TPL // $.getTpl('
#title#
', {title:'toto'}) // 'toto
'
$.getTpl = function(tpl, val) {
for (var p in val)
tpl = tpl.replace(new RegExp('#'+p+'#', 'gi'), val[p] || ''); // jQuery Bug for "{" into attributes, so now i use #name#
return tpl;
};
var uniqueId = null;
$.getUniqueName = function(prefix) {
if (!uniqueId) uniqueId = (new Date()).getTime();
return (prefix ? prefix : 'id_') + uniqueId++;
};
// Deep clean obj keys when set with "null" or empty values (config/CSS/...)
$.removeObjEmptyValue = function(obj) {
$.each(obj, function(i, val) {
if (!val && val !== 0 && val !== false) delete obj[i];
else if (typeof obj[i] == 'object') $.removeObjEmptyValue(obj[i]);
});
};
$.getJs = function(jsPath, async) { // getJS('http://other.com/new.js'); // External link
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = jsPath;
if (async) script.async = true;
document.getElementsByTagName('head')[0].appendChild(script);
};
// jQuery come with :
// $.getScript('./test.js', function(data, textStatus){});
// But i need something more flexy
/* $.loadJs = function(src, async, callback) { // loadJs('./new.js', function() { ok(); }); // On-demand same domain JS
return $.ajax({
url:src, async:async || 0, dataType:'script', cache:1,
error:function(){ alert('Sorry, some JS file not found : '+src); },
success:function() { if (callback && typeof callback == 'function') callback(); }
});
}; */ // Commented : Already in index.html
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// CROSS-BROWSERS
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Inspired by my old work here http://goo.gl/hL3om
$.browserPrefix = (function(browser) { // Closure for putting result in cache
var browsers = {firefox:'moz', applewebkit:'webkit', webkit:'webkit', opera:'o', msie:'ms'};
for (var p in browsers)
if (browser.indexOf(p) !== -1)
return browsers[p];
return false;
})(navigator.userAgent.toLowerCase());
// Cf Modernizr doc // "Static" fct
// Waiting some crazy guy to implements this
var setEventPrefix = function() { // Todo : add support for animationstart, animationend, animationiteration
switch(Modernizr.prefixed('transition')) {
case 'WebkitTransition' :
$.transitionEnd = 'webkitTransitionEnd'; // Set in accessible jQuery obj
$.animationStart = 'webkitAnimationStart';
$.animationEnd = 'webkitAnimationEnd';
break;
case 'MozTransition' :
$.transitionEnd = 'transitionend';
$.animationStart = 'animationstart';
$.animationEnd = 'animationend';
break;
case 'OTransition' :
$.transitionEnd = 'oTransitionEnd';
$.animationStart = 'oAnimationStart';
$.animationEnd = 'oAnimationEnd';
break;
case 'msTransition' :
$.transitionEnd = 'msTransitionEnd';
$.animationStart = 'msAnimationStart';
$.animationEnd = 'msAnimationEnd';
break;
case 'transition' :
$.transitionEnd = 'transitionEnd';
$.animationStart = 'animationStart';
$.animationEnd = 'animationEnd';
break;
}
};
setEventPrefix();
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// jQuery "plugins"
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fix and apply styles on element with correct browsers prefix
// $(e).crossCss({borderRadius:'10px'}) >>> $(e).css({WebkitBorderRadius:'10px'})
// Use Modernizr : https://github.com/Modernizr/Modernizr/blob/master/modernizr.js
// Modernizr.prefixed("borderRadius"); // e.g FF3.6 'MozBorderRadius', FF4 'borderRadius'
$.fn.crossCss = function(css) {
return this.each(function() {
var $this = $(this);
if (typeof css != 'object') return $this;
for (var p in css) {
if (Modernizr.prefixed(p))
css[Modernizr.prefixed(p)] = css[p]; // Add prefix ?
}
return $this.css(css);
});
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// boxFx config and CSS manipulations
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Time with unit : 'ms' | 's' // return int(ms)
$.getMsDuration = function(val) {
var ms = parseFloat(val, 10);
if (val.substr(-2) != 'ms')
ms = (ms * 1000); // convert s in ms
return ms;
};
// Here somes (css) properties units that can be related to a % of parent box
// The plugin deal with "px" and "%" units. They are converted and all units are stripped
// 10, '10px' or '0.5%' >>> (int/float)10 (px)
$.getSize = function(size, sizeContainer) {
if (size && String(size).substr(-1) == '%') // /\%/.test(size))
size = (parseFloat(size) / 100) * sizeContainer;
return parseInt(size, 10); // int for starting/ending positions (better pixel alias affect)
};
// Measurement properties workables by the plugin : convert settings unit in px
var cssWidthPropsWithPix = 'width minWidth maxWidth left right marginLeft marginRight maxSize'.split(' '),
cssHeightPropsWithPix = 'height minHeight maxHeight top bottom marginTop marginBottom'.split(' ');
$.fixCssUnit = function(css, parentW, parentH) { // Work by reference on the orignal obj (no values return)
$.each(cssWidthPropsWithPix, function(i, key) {
if (key in css && css[key]) css[key] = $.getSize(css[key], parentW);
});
$.each(cssHeightPropsWithPix, function(i, key) {
if (key in css && css[key]) css[key] = $.getSize(css[key], parentH);
});
};
$.addCssUnit = function(css) {
$.each(cssWidthPropsWithPix, function(i, key) {
if (key in css && css[key] && typeof css[key] == 'number') css[key] = css[key]+'px';
});
$.each(cssHeightPropsWithPix, function(i, key) {
if (key in css && css[key] && typeof css[key] == 'number') css[key] = css[key]+'px';
});
};
// Set or update a new CSS style in // TODO - BETTER !!!
var $cssAnimation = $('style#cssAnimation');
$.setCssClass = function(clss) {
if (!$cssAnimation || $cssAnimation.length < 1)
$cssAnimation = $('').appendTo('head');
// var currentStyle = ($cssOveride.html()).replace(new RegExp('('+clss+'{'+p+'})', 'g'), val[p] || ''); // TODO
// div#sprite > div { background-color:'+value+'; }\
$cssAnimation.html($cssAnimation.html() + clss);
};
// Building CSS animation(s) from 'options.keyframes' OBJ (cf. ./jquery.boxFx.presets.js)
// Convert JS obj to cross-browsers CSS3 keyframes anim
// Inject keyframes class in stylesheet
// Return "obj" with 'animation' et 'animationFillMode' (to apply on a element)
// http://jsfiddle.net/molokoloco/rf8zt/
$.buildKeyframeClass = function(keyframes) {
var cssKeyframes = [], cssAnimations = [], cssAnimationsFillMode = [];
$.each(keyframes, function(i, animation) {
if (!animation.name) animation.name = $.getUniqueName('boxFxAnim');
if (!animation.delay || parseInt(animation.delay, 10) < 1) animation.delay = '';
cssAnimations.push(animation.name+' '+animation.duration+' '+animation.timingFunction+' '+animation.delay+' '+animation.iterationCount+' '+animation.direction);
cssAnimationsFillMode.push(animation.fillMode); // http://www.w3.org/TR/css3-animations/#the-animation-shorthand-property-
var cssSteps = [];
$.each(animation.steps, function(j, stepObj) {
var stepObjPropsString = (typeof stepObj.step == 'number' ? stepObj.step+'%' : stepObj.step)+' { '; // stepObj.step == 0 | '0%' | '0%, 100%'
$.each(stepObj, function(k, step) {
if (k == 'step') return; // continue : only non CSS properties
stepObjPropsString += String(Modernizr.prefixed(k) || k).toDash()+': '+step+'; ';
});
stepObjPropsString += ' } ';
cssSteps.push(stepObjPropsString );
});
cssKeyframes.push('@-'+$.browserPrefix+'-keyframes '+animation.name+' { '+cssSteps.join(' ')+' }');
});
$.setCssClass(cssKeyframes.join('\n')); // addCssClass ?
return {animation:cssAnimations.join(','), animationFillMode: cssAnimationsFillMode.join(',')}; // apply this to element, with 'crossCss()', to trigger keyframe
};
})(jQuery, window);