Skip to content

Instantly share code, notes, and snippets.

@dougwollison
Last active February 23, 2016 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dougwollison/c21f05eac188f20863dc to your computer and use it in GitHub Desktop.
Save dougwollison/c21f05eac188f20863dc to your computer and use it in GitHub Desktop.
jQuery cssAnimate and cssTransition plugins.
(function( $ ) {
// Convert a className string into a classList array
function makeList( string ) {
// trim whitespace
string = ( string || '' ).replace( /^\s+|\s+$/g,'' );
if ( string ) {
return string.split( /\s+/ );
} else {
return [];
}
}
// Return entries from the second list that show up in the first
function matchList( list1, list2 ) {
var diff = [];
for ( var i in list2 ) {
if ( $.inArray( list2[ i ], list1 ) !== -1 ) {
diff.push( list2[ i ] );
}
}
return diff;
}
// Return entries from the second list that DO NOT show up in the first
function diffList( list1, list2 ) {
var diff = [];
for ( var i in list2 ) {
if ( $.inArray( list2[ i ], list1 ) === -1 ) {
diff.push( list2[ i ] );
}
}
return diff;
}
// CSS Property tester adapted from https://gist.github.com/jackfuchs/556448
function cssSupports( property ) {
var style = document.createElement( 'div' ).style;
// Ensure CSS is supported at all
if ( typeof style === 'undefined' ) {
return false;
}
// Test for standard version of property
if ( typeof style[ property ] === 'string' ) {
return true;
}
// Test for vendor specific version of property
var vendors = [ 'Moz', 'Webkit', 'Khtml', 'O', 'ms', 'Icab' ];
property = property.charAt( 0 ).toUpperCase() + property.substr( 1 ); // Capitalize
for ( var i in vendors ) {
if ( typeof style[ vendors[ i ] + property ] === 'string' ) {
// Return the matched prefix
return vendors[ i ];
}
}
// Otherwise return false
return false;
}
// CSS End Event guesser
function cssEndEvent( property, supported ) {
var prefixes = {
Moz: 'moz',
Webkit: 'webkit',
O: 'o',
ms: 'MS',
};
var event = property + 'end';
if(typeof supported === 'string' && typeof prefixes[ supported ] === 'string' ) {
event = prefixes[ supported ] + property.charAt( 0 ).toUpperCase() + property.substr( 1 ) + 'End';
}
return event;
}
var supports = {
animation: cssSupports( 'animation' ),
transition: cssSupports( 'transition' )
};
var endEvents = {
animation: cssEndEvent( 'animation', supports.animation ),
transition: cssEndEvent( 'transition', supports.transition )
};
function cssAnimateOrTransition( method, args ) {
var addClasses = '', removeClasses = '', endCallback;
if ( args.length === 0 ) {
// Abort
return;
}
// Check if first argument is the callback or the classes to add
if ( typeof args[0] === 'function' ) {
endCallback = args[0];
} else {
addClasses = args[0];
}
// Check if second argument exists and if it's the callback or the classes to remove
if ( args.length >= 2 ) {
if ( typeof args[1] === 'function' ) {
endCallback = args[1];
} else {
removeClasses = args[1];
}
}
// Check if third argument exists and if it's the callback
if ( args.length === 3 && typeof args[ 2 ] === 'function' ) {
endCallback = args[ 2 ];
}
// Get the support result and end event
var supported = supports[ method ] !== false;
var endEvent = endEvents[ method ];
return $( this ).each(function() {
// Get the current class list
var classList = this.classList || makeList( this.className );
var addList = makeList( addClasses );
var removeList = makeList( removeClasses );
// Check that at least one of the classes being added doesn't exist yet
var toAdd = diffList( classList, addList );
// Check that at least one of the classes being removed already exists
var toRemove = matchList( classList, removeList );
var doEvent = supported && ( toAdd.length > 0 || toRemove.length > 0 );
// Setup a onetime callback if supported, assuming there are classes to add/remove
if ( doEvent && endCallback ) {
$( this ).one( endEvent, endCallback );
}
// Add/Remove the desired classes
$( this ).addClass( addClasses ).removeClass( removeClasses );
// Fallback, trigger the callback now that the classes have been added
if ( ! doEvent && endCallback ) {
endCallback.apply( this );
}
});
}
$.fn.cssAnimate = function(){
return cssAnimateOrTransition.call( this, 'animation', arguments );
};
$.fn.cssTransition = function(){
return cssAnimateOrTransition.call( this, 'transition', arguments );
};
})( jQuery );
/*
Examples
========
// Trigger out animation on div1, then in animation on div2
$('#div1').cssAnimate('out', function(){
$('#div2').cssAnimate('in');
});
// Remove class to trigger transition
$('#mydiv').cssTransition(null, 'active', function(){
// Do something
});
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment