});
};
config.layoutMode = multiOut.layoutMode;
goMix(multiOut.filter,multiOut.sort,multiOut.order, $t, config);
};
});
},
// "REMIX" METHOD
remix: function(arg){
return this.each(function(){
var config = this.config,
$t = $(this);
config.origOrder = [];
$t.find(config.targetSelector).each(function(){
var $th = $(this);
$th.addClass('mix_all');
config.origOrder.push($th);
});
if(!config.mixing && typeof arg !== 'undefined'){
$(config.filterSelector).removeClass('active');
$(config.filterSelector+'[data-filter="'+arg+'"]').addClass('active');
goMix(arg, null, null, $t, config);
};
});
}
};
// DECLARE PLUGIN
$.fn.mixitup = function(method, arg){
if (methods[method]) {
return methods[method].apply( this, Array.prototype.slice.call(arguments,1));
} else if (typeof method === 'object' || ! method){
return methods.init.apply( this, arguments );
};
};
/* ==== THE MAGIC ==== */
function goMix(filter, sortby, order, $cont, config){
// WE ARE NOW MIXING
clearInterval(config.failsafe);
config.mixing = true;
// APPLY ARGS TO CONFIG
config.filter = filter;
// FIRE "ONMIXSTART" CALLBACK
if(typeof config.onMixStart == 'function') {
var output = config.onMixStart.call(this, config);
// UPDATE CONFIG IF DATA RETURNED
config = output ? output : config;
};
// SHORT LOCAL VARS
var speed = config.transitionSpeed;
// REBUILD TRANSITION AND PERSPECTIVE OBJECTS
for(var i = 0; i<2; i++){
var a = i==0 ? a = config.prefix : '';
config.transition[a+'transition'] = 'all '+speed+'ms linear';
config.transition[a+'transform'] = a+'translate3d(0,0,0)';
config.perspective[a+'perspective'] = config.perspectiveDistance+'px';
config.perspective[a+'perspective-origin'] = config.perspectiveOrigin;
};
// CACHE TARGET ELEMENTS FOR QUICK ACCESS
var mixSelector = config.targetSelector,
$targets = $cont.find(mixSelector);
// ADD DATA OBJECT TO EACH TARGET
$targets.each(function(){
this.data = {};
});
// RE-DEFINE CONTAINER INCASE NOT IMMEDIATE PARENT OF TARGET ELEMENTS
var $par = $targets.parent();
// ADD PERSPECTIVE TO CONTAINER
$par.css(config.perspective);
// SETUP EASING
config.easingFallback = 'ease-in-out';
if(config.easing == 'smooth')config.easing = 'cubic-bezier(0.25, 0.46, 0.45, 0.94)';
if(config.easing == 'snap')config.easing = 'cubic-bezier(0.77, 0, 0.175, 1)';
if(config.easing == 'windback'){
config.easing = 'cubic-bezier(0.175, 0.885, 0.320, 1.275)',
config.easingFallback = 'cubic-bezier(0.175, 0.885, 0.320, 1)'; // Fall-back for old webkit, with no values > 1 or < 1
};
if(config.easing == 'windup'){
config.easing = 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',
config.easingFallback = 'cubic-bezier(0.6, 0.28, 0.735, 0.045)';
};
// USE LIST SPECIFIC EFFECTS IF DECLARED
var effectsOut = config.layoutMode == 'list' && config.listEffects != null ? config.listEffects : config.effects;
// BUILD EFFECTS STRINGS & SKIP IF IE8
if (Array.prototype.indexOf){
config.fade = effectsOut.indexOf('fade') > -1 ? '0' : '';
config.scale = effectsOut.indexOf('scale') > -1 ? 'scale(.01)' : '';
config.rotateZ = effectsOut.indexOf('rotateZ') > -1 ? 'rotate(180deg)' : '';
config.rotateY = effectsOut.indexOf('rotateY') > -1 ? 'rotateY(90deg)' : '';
config.rotateX = effectsOut.indexOf('rotateX') > -1 ? 'rotateX(90deg)' : '';
config.blur = effectsOut.indexOf('blur') > -1 ? 'blur(8px)' : '';
config.grayscale = effectsOut.indexOf('grayscale') > -1 ? 'grayscale(100%)' : '';
};
// DECLARE NEW JQUERY OBJECTS FOR GROUPING
var $show = $(),
$hide = $(),
filterArray = [],
multiDimensional = false;
// BUILD FILTER ARRAY(S)
if(typeof filter === 'string'){
// SINGLE DIMENSIONAL FILTERING
filterArray = buildFilterArray(filter);
} else {
// MULTI DIMENSIONAL FILTERING
multiDimensional = true;
$.each(filter,function(i){
filterArray[i] = buildFilterArray(this);
});
};
// "OR" LOGIC (DEFAULT)
if(config.filterLogic == 'or'){
if(filterArray[0] == '') filterArray.shift(); // IF FIRST ITEM IN ARRAY IS AN EMPTY SPACE, DELETE
// IF NO ELEMENTS ARE DESIRED THEN HIDE ALL VISIBLE ELEMENTS
if(filterArray.length < 1){
$hide = $hide.add($cont.find(mixSelector+':visible'));
} else {
// ELSE CHECK EACH TARGET ELEMENT FOR ANY FILTER CATEGORY:
$targets.each(function(){
var $t = $(this);
if(!multiDimensional){
// IF HAS ANY FILTER, ADD TO "SHOW" OBJECT
if($t.is('.'+filterArray.join(', .'))){
$show = $show.add($t);
// ELSE IF HAS NO FILTERS, ADD TO "HIDE" OBJECT
} else {
$hide = $hide.add($t);
};
} else {
var pass = 0;
// FOR EACH DIMENSION
$.each(filterArray,function(i){
if(this.length){
if($t.is('.'+this.join(', .'))){
pass++
};
} else if(pass > 0){
pass++;
};
});
// IF PASSES ALL DIMENSIONS, SHOW
if(pass == filterArray.length){
$show = $show.add($t);
// ELSE HIDE
} else {
$hide = $hide.add($t);
};
};
});
};
} else {
// "AND" LOGIC
// ADD "MIX_SHOW" CLASS TO ELEMENTS THAT HAVE ALL FILTERS
$show = $show.add($par.find(mixSelector+'.'+filterArray.join('.')));
// ADD "MIX_HIDE" CLASS TO EVERYTHING ELSE
$hide = $hide.add($par.find(mixSelector+':not(.'+filterArray.join('.')+'):visible'));
};
// GET TOTAL NUMBER OF ELEMENTS TO SHOW
var total = $show.length;
// DECLARE NEW JQUERY OBJECTS
var $tohide = $(),
$toshow = $(),
$pre = $();
// FOR ELEMENTS TO BE HIDDEN, IF NOT ALREADY HIDDEN THEN ADD TO OBJECTS "TOHIDE" AND "PRE"
// TO INDICATE PRE-EXISTING ELEMENTS TO BE HIDDEN
$hide.each(function(){
var $t = $(this);
if($t.css('display') != 'none'){
$tohide = $tohide.add($t);
$pre = $pre.add($t);
};
});
// IF ALL ELEMENTS ARE ALREADY SHOWN AND THERE IS NOTHING TO HIDE, AND NOT PERFORMING A LAYOUT CHANGE OR SORT:
if($show.filter(':visible').length == total && !$tohide.length && !sortby){
if(config.origLayout == config.layoutMode){
// THEN CLEAN UP AND GO HOME
resetFilter();
return false;
} else {
// IF ONLY ONE ITEM AND CHANGING FORM GRID TO LIST, MOST LIKELY POSITION WILL NOT CHANGE SO WE'RE DONE
if($show.length == 1){
if(config.layoutMode == 'list'){
$cont.addClass(config.listClass);
$cont.removeClass(config.gridClass);
$pre.css('display',config.targetDisplayList);
} else {
$cont.addClass(config.gridClass);
$cont.removeClass(config.listClass);
$pre.css('display',config.targetDisplayGrid);
};
// THEN CLEAN UP AND GO HOME
resetFilter();
return false;
}
};
};
// GET CONTAINER'S STARTING HEIGHT
config.origHeight = $par.height();
// IF THERE IS SOMETHING TO BE SHOWN:
if($show.length){
// REMOVE "FAIL CLASS" FROM CONTAINER IF EXISTS
$cont.removeClass(config.failClass);
// FOR ELEMENTS TO BE SHOWN, IF NOT ALREADY SHOWN THEN ADD TO OBJECTS "TOSHOW" ELSE ADD CLASS "MIX_PRE"
// TO INDICATE PRE-EXISTING ELEMENT
$show.each(function(){
var $t = $(this);
if($t.css('display') == 'none'){
$toshow = $toshow.add($t)
} else {
$pre = $pre.add($t);
};
});
// IF NON-ANIMATED LAYOUT MODE TRANSITION:
if((config.origLayout != config.layoutMode) && config.animateGridList == false){
// ADD NEW DISPLAY TYPES, CLEAN UP AND GO HOME
if(config.layoutMode == 'list'){
$cont.addClass(config.listClass);
$cont.removeClass(config.gridClass);
$pre.css('display',config.targetDisplayList);
} else {
$cont.addClass(config.gridClass);
$cont.removeClass(config.listClass);
$pre.css('display',config.targetDisplayGrid);
};
resetFilter();
return false;
};
// IF IE, FUCK OFF, AND THEN CLEAN UP AND GO HOME
if(!window.atob){
resetFilter();
return false;
};
// OVERRIDE ANY EXISTING TRANSITION TIMING FOR CALCULATIONS
$targets.css(config.clean);
// FOR EACH PRE-EXISTING ELEMENT, ADD STARTING POSITION TO 'ORIGPOS' ARRAY
$pre.each(function(){
this.data.origPos = $(this).offset();
});
// TEMPORARILY SHOW ALL ELEMENTS TO SHOW (THAT ARE NOT ALREADY SHOWN), WITHOUT HIDING ELEMENTS TO HIDE
// AND ADD/REMOVE GRID AND LIST CLASSES FROM CONTAINER
if(config.layoutMode == 'list'){
$cont.addClass(config.listClass);
$cont.removeClass(config.gridClass);
$toshow.css('display',config.targetDisplayList);
} else {
$cont.addClass(config.gridClass);
$cont.removeClass(config.listClass);
$toshow.css('display',config.targetDisplayGrid);
};
// FOR EACH ELEMENT NOW SHOWN, ADD ITS INTERMEDIATE POSITION TO 'SHOWINTERPOS' ARRAY
$toshow.each(function(){
this.data.showInterPos = $(this).offset();
});
// FOR EACH ELEMENT TO BE HIDDEN, BUT NOT YET HIDDEN, AND NOW MOVED DUE TO SHOWN ELEMENTS,
// ADD ITS INTERMEDIATE POSITION TO 'HIDEINTERPOS' ARRAY
$tohide.each(function(){
this.data.hideInterPos = $(this).offset();
});
// FOR EACH PRE-EXISTING ELEMENT, NOW MOVED DUE TO SHOWN ELEMENTS, ADD ITS POSITION TO 'PREINTERPOS' ARRAY
$pre.each(function(){
this.data.preInterPos = $(this).offset();
});
// SET DISPLAY PROPERTY OF PRE-EXISTING ELEMENTS INCASE WE ARE CHANGING LAYOUT MODE
if(config.layoutMode == 'list'){
$pre.css('display',config.targetDisplayList);
} else {
$pre.css('display',config.targetDisplayGrid);
};
// IF A SORT ARGUMENT HAS BEEN SENT, RUN SORT FUNCTION SO OBJECTS WILL MOVE TO THEIR FINAL ORDER
if(sortby){
sort(sortby, order, $cont, config);
};
// IF VISIBLE SORT ORDER IS THE SAME (WHICH WOULD NOT TRIGGER A TRANSITION EVENT)
if(sortby && compareArr(config.origSort, config.checkSort)){
// THEN CLEAN UP AND GO HOME
resetFilter();
return false;
};
// TEMPORARILY HIDE ALL SHOWN ELEMENTS TO HIDE
$tohide.hide();
// FOR EACH ELEMENT TO SHOW, AND NOW MOVED DUE TO HIDDEN ELEMENTS BEING REMOVED,
// ADD ITS POSITION TO 'FINALPOS' ARRAY
$toshow.each(function(i){
this.data.finalPos = $(this).offset();
});
// FOR EACH PRE-EXISTING ELEMENT NOW MOVED DUE TO HIDDEN ELEMENTS BEING REMOVED,
// ADD ITS POSITION TO 'FINALPREPOS' ARRAY
$pre.each(function(){
this.data.finalPrePos = $(this).offset();
});
// SINCE WE ARE IN OUT FINAL STATE, GET NEW HEIGHT OF CONTAINER
config.newHeight = $par.height();
// IF A SORT ARGUMENT AS BEEN SENT, RUN SORT FUNCTION 'RESET' TO MOVE ELEMENTS BACK TO THEIR STARTING ORDER
if(sortby){
sort('reset', null, $cont, config);
};
// RE-HIDE ALL ELEMENTS TEMPORARILY SHOWN
$toshow.hide();
// SET DISPLAY PROPERTY OF PRE-EXISTING ELEMENTS BACK TO THEIR
// ORIGINAL PROPERTY, INCASE WE ARE CHANGING LAYOUT MODE
$pre.css('display',config.origDisplay);
// ADD/REMOVE GRID AND LIST CLASSES FROM CONTAINER
if(config.origDisplay == 'block'){
$cont.addClass(config.listClass);
$toshow.css('display', config.targetDisplayList);
} else {
$cont.removeClass(config.listClass);
$toshow.css('display', config.targetDisplayGrid);
};
// IF WE ARE ANIMATING CONTAINER, RESET IT TO ITS STARTING HEIGHT
if(config.resizeContainer)$par.css('height', config.origHeight+'px');
// ADD TRANSFORMS TO ALL ELEMENTS TO SHOW
var toShowCSS = {};
for(var i = 0; i<2; i++){
var a = i==0 ? a = config.prefix : '';
toShowCSS[a+'transform'] = config.scale+' '+config.rotateX+' '+config.rotateY+' '+config.rotateZ;
toShowCSS[a+'filter'] = config.blur+' '+config.grayscale;
};
$toshow.css(toShowCSS);
// FOR EACH PRE-EXISTING ELEMENT, SUBTRACT ITS INTERMEDIATE POSITION FROM ITS ORIGINAL POSITION
// TO GET ITS STARTING OFFSET
$pre.each(function(){
var data = this.data,
$t = $(this);
if ($t.hasClass('mix_tohide')){
data.preTX = data.origPos.left - data.hideInterPos.left;
data.preTY = data.origPos.top - data.hideInterPos.top;
} else {
data.preTX = data.origPos.left - data.preInterPos.left;
data.preTY = data.origPos.top - data.preInterPos.top;
};
var preCSS = {};
for(var i = 0; i<2; i++){
var a = i==0 ? a = config.prefix : '';
preCSS[a+'transform'] = 'translate('+data.preTX+'px,'+data.preTY+'px)';
};
$t.css(preCSS);
});
// ADD/REMOVE GRID AND LIST CLASSES FROM CONTAINER
if(config.layoutMode == 'list'){
$cont.addClass(config.listClass);
$cont.removeClass(config.gridClass);
} else {
$cont.addClass(config.gridClass);
$cont.removeClass(config.listClass);
};
// WRAP ANIMATION FUNCTIONS IN 10ms TIMEOUT TO PREVENT RACE CONDITION
var delay = setTimeout(function(){
// APPLY TRANSITION TIMING TO CONTAINER, AND BEGIN ANIMATION TO NEW HEIGHT
if(config.resizeContainer){
var containerCSS = {};
for(var i = 0; i<2; i++){
var a = i==0 ? a = config.prefix : '';
containerCSS[a+'transition'] = 'all '+speed+'ms ease-in-out';
containerCSS['height'] = config.newHeight+'px';
};
$par.css(containerCSS);
};
// BEGIN FADING IN/OUT OF ALL ELEMENTS TO SHOW/HIDE
$tohide.css('opacity',config.fade);
$toshow.css('opacity',1);
// FOR EACH ELEMENT BEING SHOWN, CALCULATE ITS TRAJECTORY BY SUBTRACTING
// ITS INTERMEDIATE POSITION FROM ITS FINAL POSITION.
// ALSO ADD SPEED AND EASING
$toshow.each(function(){
var data = this.data;
data.tX = data.finalPos.left - data.showInterPos.left;
data.tY = data.finalPos.top - data.showInterPos.top;
var toShowCSS = {};
for(var i = 0; i<2; i++){
var a = i==0 ? a = config.prefix : '';
toShowCSS[a+'transition-property'] = a+'transform, '+a+'filter, opacity';
toShowCSS[a+'transition-timing-function'] = config.easing+', linear, linear';
toShowCSS[a+'transition-duration'] = speed+'ms';
toShowCSS[a+'transition-delay'] = '0';
toShowCSS[a+'transform'] = 'translate('+data.tX+'px,'+data.tY+'px)';
toShowCSS[a+'filter'] = 'none';
};
$(this).css('-webkit-transition', 'all '+speed+'ms '+config.easingFallback).css(toShowCSS);
});
// FOR EACH PRE-EXISTING ELEMENT, IF IT HAS A FINAL POSITION, CALCULATE