balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

mixitup.js (52224B)


      1 /**!
      2  * MixItUp v2.1.10
      3  *
      4  * @copyright Copyright 2015 KunkaLabs Limited.
      5  * @author    KunkaLabs Limited.
      6  * @link      https://mixitup.kunkalabs.com
      7  *
      8  * @license   Commercial use requires a commercial license.
      9  *            https://mixitup.kunkalabs.com/licenses/
     10  *
     11  *            Non-commercial use permitted under terms of CC-BY-NC license.
     12  *            http://creativecommons.org/licenses/by-nc/3.0/
     13  */
     14 
     15 (function($, undf){
     16 	'use strict';
     17 	
     18 	/**
     19 	 * MixItUp Constructor Function
     20 	 * @constructor
     21 	 * @extends jQuery
     22 	 */
     23 	
     24 	$.MixItUp = function(){
     25 		var self = this;
     26 		
     27 		self._execAction('_constructor', 0);
     28 		
     29 		$.extend(self, {
     30 			
     31 			/* Public Properties
     32 			---------------------------------------------------------------------- */
     33 			
     34 			selectors: {
     35 				target: '.mix',
     36 				filter: '.filter',
     37 				sort: '.sort'
     38 			},
     39 				
     40 			animation: {
     41 				enable: true,
     42 				effects: 'fade scale',
     43 				duration: 600,
     44 				easing: 'ease',
     45 				perspectiveDistance: '3000',
     46 				perspectiveOrigin: '50% 50%',
     47 				queue: true,
     48 				queueLimit: 1,
     49 				animateChangeLayout: false,
     50 				animateResizeContainer: true,
     51 				animateResizeTargets: false,
     52 				staggerSequence: false,
     53 				reverseOut: false
     54 			},
     55 				
     56 			callbacks: {
     57 				onMixLoad: false,
     58 				onMixStart: false,
     59 				onMixBusy: false,
     60 				onMixEnd: false,
     61 				onMixFail: false,
     62 				_user: false
     63 			},
     64 				
     65 			controls: {
     66 				enable: true,
     67 				live: false,
     68 				toggleFilterButtons: false,
     69 				toggleLogic: 'or',
     70 				activeClass: 'active'
     71 			},
     72 
     73 			layout: {
     74 				display: 'inline-block',
     75 				containerClass: '',
     76 				containerClassFail: 'fail'
     77 			},
     78 			
     79 			load: {
     80 				filter: 'all',
     81 				sort: false
     82 			},
     83 			
     84 			/* Private Properties
     85 			---------------------------------------------------------------------- */
     86 				
     87 			_$body: null,
     88 			_$container: null,
     89 			_$targets: null,
     90 			_$parent: null,
     91 			_$sortButtons: null,
     92 			_$filterButtons: null,
     93 		
     94 			_suckMode: false,
     95 			_mixing: false,
     96 			_sorting: false,
     97 			_clicking: false,
     98 			_loading: true,
     99 			_changingLayout: false,
    100 			_changingClass: false,
    101 			_changingDisplay: false,
    102 			
    103 			_origOrder: [],
    104 			_startOrder: [],
    105 			_newOrder: [],
    106 			_activeFilter: null,
    107 			_toggleArray: [],
    108 			_toggleString: '',
    109 			_activeSort: 'default:asc',
    110 			_newSort: null,
    111 			_startHeight: null,
    112 			_newHeight: null,
    113 			_incPadding: true,
    114 			_newDisplay: null,
    115 			_newClass: null,
    116 			_targetsBound: 0,
    117 			_targetsDone: 0,
    118 			_queue: [],
    119 				
    120 			_$show: $(),
    121 			_$hide: $()
    122 		});
    123 	
    124 		self._execAction('_constructor', 1);
    125 	};
    126 	
    127 	/**
    128 	 * MixItUp Prototype
    129 	 * @override
    130 	 */
    131 	
    132 	$.MixItUp.prototype = {
    133 		constructor: $.MixItUp,
    134 		
    135 		/* Static Properties
    136 		---------------------------------------------------------------------- */
    137 		
    138 		_instances: {},
    139 		_handled: {
    140 			_filter: {},
    141 			_sort: {}
    142 		},
    143 		_bound: {
    144 			_filter: {},
    145 			_sort: {}
    146 		},
    147 		_actions: {},
    148 		_filters: {},
    149 		
    150 		/* Static Methods
    151 		---------------------------------------------------------------------- */
    152 		
    153 		/**
    154 		 * Extend
    155 		 * @since 2.1.0
    156 		 * @param {object} new properties/methods
    157 		 * @extends {object} prototype
    158 		 */
    159 		
    160 		extend: function(extension){
    161 			for(var key in extension){
    162 				$.MixItUp.prototype[key] = extension[key];
    163 			}
    164 		},
    165 		
    166 		/**
    167 		 * Add Action
    168 		 * @since 2.1.0
    169 		 * @param {string} hook name
    170 		 * @param {string} namespace
    171 		 * @param {function} function to execute
    172 		 * @param {number} priority
    173 		 * @extends {object} $.MixItUp.prototype._actions
    174 		 */
    175 		
    176 		addAction: function(hook, name, func, priority){
    177 			$.MixItUp.prototype._addHook('_actions', hook, name, func, priority);
    178 		},
    179 		
    180 		/**
    181 		 * Add Filter
    182 		 * @since 2.1.0
    183 		 * @param {string} hook name
    184 		 * @param {string} namespace
    185 		 * @param {function} function to execute
    186 		 * @param {number} priority
    187 		 * @extends {object} $.MixItUp.prototype._filters
    188 		 */
    189 		
    190 		addFilter: function(hook, name, func, priority){
    191 			$.MixItUp.prototype._addHook('_filters', hook, name, func, priority);
    192 		},
    193 		
    194 		/**
    195 		 * Add Hook
    196 		 * @since 2.1.0
    197 		 * @param {string} type of hook
    198 		 * @param {string} hook name
    199 		 * @param {function} function to execute
    200 		 * @param {number} priority
    201 		 * @extends {object} $.MixItUp.prototype._filters
    202 		 */
    203 		
    204 		_addHook: function(type, hook, name, func, priority){
    205 			var collection = $.MixItUp.prototype[type],
    206 				obj = {};
    207 				
    208 			priority = (priority === 1 || priority === 'post') ? 'post' : 'pre';
    209 				
    210 			obj[hook] = {};
    211 			obj[hook][priority] = {};
    212 			obj[hook][priority][name] = func;
    213 
    214 			$.extend(true, collection, obj);
    215 		},
    216 		
    217 		
    218 		/* Private Methods
    219 		---------------------------------------------------------------------- */
    220 		
    221 		/**
    222 		 * Initialise
    223 		 * @since 2.0.0
    224 		 * @param {object} domNode
    225 		 * @param {object} config
    226 		 */
    227 		
    228 		_init: function(domNode, config){
    229 			var self = this;
    230 			
    231 			self._execAction('_init', 0, arguments);
    232 			
    233 			config && $.extend(true, self, config);
    234 			
    235 			self._$body = $('body');
    236 			self._domNode = domNode;
    237 			self._$container = $(domNode);
    238 			self._$container.addClass(self.layout.containerClass);
    239 			self._id = domNode.id;
    240 			
    241 			self._platformDetect();
    242 			
    243 			self._brake = self._getPrefixedCSS('transition', 'none');
    244 			
    245 			self._refresh(true);
    246 			
    247 			self._$parent = self._$targets.parent().length ? self._$targets.parent() : self._$container;
    248 			
    249 			if(self.load.sort){
    250 				self._newSort = self._parseSort(self.load.sort);
    251 				self._newSortString = self.load.sort;
    252 				self._activeSort = self.load.sort;
    253 				self._sort();
    254 				self._printSort();
    255 			}
    256 			
    257 			self._activeFilter = self.load.filter === 'all' ? 
    258 				self.selectors.target : 
    259 				self.load.filter === 'none' ?
    260 					'' :
    261 					self.load.filter;
    262 			
    263 			self.controls.enable && self._bindHandlers();
    264 			
    265 			if(self.controls.toggleFilterButtons){
    266 				self._buildToggleArray();
    267 				
    268 				for(var i = 0; i < self._toggleArray.length; i++){
    269 					self._updateControls({filter: self._toggleArray[i], sort: self._activeSort}, true);
    270 				};
    271 			} else if(self.controls.enable){
    272 				self._updateControls({filter: self._activeFilter, sort: self._activeSort});
    273 			}
    274 			
    275 			self._filter();
    276 			
    277 			self._init = true;
    278 			
    279 			self._$container.data('mixItUp',self);
    280 			
    281 			self._execAction('_init', 1, arguments);
    282 			
    283 			self._buildState();
    284 			
    285 			self._$targets.css(self._brake);
    286 		
    287 			self._goMix(self.animation.enable);
    288 		},
    289 		
    290 		/**
    291 		 * Platform Detect
    292 		 * @since 2.0.0
    293 		 */
    294 		
    295 		_platformDetect: function(){
    296 			var self = this,
    297 				vendorsTrans = ['Webkit', 'Moz', 'O', 'ms'],
    298 				vendorsRAF = ['webkit', 'moz'],
    299 				chrome = window.navigator.appVersion.match(/Chrome\/(\d+)\./) || false,
    300 				ff = typeof InstallTrigger !== 'undefined',
    301 				prefix = function(el){
    302 					for (var i = 0; i < vendorsTrans.length; i++){
    303 						if (vendorsTrans[i] + 'Transition' in el.style){
    304 							return {
    305 								prefix: '-'+vendorsTrans[i].toLowerCase()+'-',
    306 								vendor: vendorsTrans[i]
    307 							};
    308 						};
    309 					}; 
    310 					return 'transition' in el.style ? '' : false;
    311 				},
    312 				transPrefix = prefix(self._domNode);
    313 				
    314 			self._execAction('_platformDetect', 0);
    315 			
    316 			self._chrome = chrome ? parseInt(chrome[1], 10) : false;
    317 			self._ff = ff ? parseInt(window.navigator.userAgent.match(/rv:([^)]+)\)/)[1]) : false;
    318 			self._prefix = transPrefix.prefix;
    319 			self._vendor = transPrefix.vendor;
    320 			self._suckMode = window.atob && self._prefix ? false : true;
    321 
    322 			self._suckMode && (self.animation.enable = false);
    323 			(self._ff && self._ff <= 4) && (self.animation.enable = false);
    324 			
    325 			/* Polyfills
    326 			---------------------------------------------------------------------- */
    327 			
    328 			/**
    329 			 * window.requestAnimationFrame
    330 			 */
    331 			
    332 			for(var x = 0; x < vendorsRAF.length && !window.requestAnimationFrame; x++){
    333 				window.requestAnimationFrame = window[vendorsRAF[x]+'RequestAnimationFrame'];
    334 			}
    335 
    336 			/**
    337 			 * Object.getPrototypeOf
    338 			 */
    339 
    340 			if(typeof Object.getPrototypeOf !== 'function'){
    341 				if(typeof 'test'.__proto__ === 'object'){
    342 					Object.getPrototypeOf = function(object){
    343 						return object.__proto__;
    344 					};
    345 				} else {
    346 					Object.getPrototypeOf = function(object){
    347 						return object.constructor.prototype;
    348 					};
    349 				}
    350 			}
    351 
    352 			/**
    353 			 * Element.nextElementSibling
    354 			 */
    355 			
    356 			if(self._domNode.nextElementSibling === undf){
    357 				Object.defineProperty(Element.prototype, 'nextElementSibling',{
    358 					get: function(){
    359 						var el = this.nextSibling;
    360 						
    361 						while(el){
    362 							if(el.nodeType ===1){
    363 								return el;
    364 							}
    365 							el = el.nextSibling;
    366 						}
    367 						return null;
    368 					}
    369 				});
    370 			}
    371 			
    372 			self._execAction('_platformDetect', 1);
    373 		},
    374 		
    375 		/**
    376 		 * Refresh
    377 		 * @since 2.0.0
    378 		 * @param {boolean} init
    379 		 * @param {boolean} force
    380 		 */
    381 		
    382 		_refresh: function(init, force){
    383 			var self = this;
    384 				
    385 			self._execAction('_refresh', 0, arguments);
    386 
    387 			self._$targets = self._$container.find(self.selectors.target);
    388 			
    389 			for(var i = 0; i < self._$targets.length; i++){
    390 				var target = self._$targets[i];
    391 					
    392 				if(target.dataset === undf || force){
    393 						
    394 					target.dataset = {};
    395 					
    396 					for(var j = 0; j < target.attributes.length; j++){
    397 						
    398 						var attr = target.attributes[j],
    399 							name = attr.name,
    400 							val = attr.value;
    401 							
    402 						if(name.indexOf('data-') > -1){
    403 							var dataName = self._helpers._camelCase(name.substring(5,name.length));
    404 							target.dataset[dataName] = val;
    405 						}
    406 					}
    407 				}
    408 				
    409 				if(target.mixParent === undf){
    410 					target.mixParent = self._id;
    411 				}
    412 			}
    413 			
    414 			if(
    415 				(self._$targets.length && init) ||
    416 				(!self._origOrder.length && self._$targets.length)
    417 			){
    418 				self._origOrder = [];
    419 				
    420 				for(var i = 0; i < self._$targets.length; i++){
    421 					var target = self._$targets[i];
    422 					
    423 					self._origOrder.push(target);
    424 				}
    425 			}
    426 			
    427 			self._execAction('_refresh', 1, arguments);
    428 		},
    429 		
    430 		/**
    431 		 * Bind Handlers
    432 		 * @since 2.0.0
    433 		 */
    434 		
    435 		_bindHandlers: function(){
    436 			var self = this,
    437 				filters = $.MixItUp.prototype._bound._filter,
    438 				sorts = $.MixItUp.prototype._bound._sort;
    439 			
    440 			self._execAction('_bindHandlers', 0);
    441 			
    442 			if(self.controls.live){
    443 				self._$body
    444 					.on('click.mixItUp.'+self._id, self.selectors.sort, function(){
    445 						self._processClick($(this), 'sort');
    446 					})
    447 					.on('click.mixItUp.'+self._id, self.selectors.filter, function(){
    448 						self._processClick($(this), 'filter');
    449 					});
    450 			} else {
    451 				self._$sortButtons = $(self.selectors.sort);
    452 				self._$filterButtons = $(self.selectors.filter);
    453 				
    454 				self._$sortButtons.on('click.mixItUp.'+self._id, function(){
    455 					self._processClick($(this), 'sort');
    456 				});
    457 				
    458 				self._$filterButtons.on('click.mixItUp.'+self._id, function(){
    459 					self._processClick($(this), 'filter');
    460 				});
    461 			}
    462 
    463 			filters[self.selectors.filter] = (filters[self.selectors.filter] === undf) ? 1 : filters[self.selectors.filter] + 1;
    464 			sorts[self.selectors.sort] = (sorts[self.selectors.sort] === undf) ? 1 : sorts[self.selectors.sort] + 1;
    465 			
    466 			self._execAction('_bindHandlers', 1);
    467 		},
    468 		
    469 		/**
    470 		 * Process Click
    471 		 * @since 2.0.0
    472 		 * @param {object} $button
    473 		 * @param {string} type
    474 		 */
    475 		
    476 		_processClick: function($button, type){
    477 			var self = this,
    478 				trackClick = function($button, type, off){
    479 					var proto = $.MixItUp.prototype;
    480 						
    481 					proto._handled['_'+type][self.selectors[type]] = (proto._handled['_'+type][self.selectors[type]] === undf) ? 
    482 						1 : 
    483 						proto._handled['_'+type][self.selectors[type]] + 1;
    484 
    485 					if(proto._handled['_'+type][self.selectors[type]] === proto._bound['_'+type][self.selectors[type]]){
    486 						$button[(off ? 'remove' : 'add')+'Class'](self.controls.activeClass);
    487 						delete proto._handled['_'+type][self.selectors[type]];
    488 					}
    489 				};
    490 			
    491 			self._execAction('_processClick', 0, arguments);
    492 			
    493 			if(!self._mixing || (self.animation.queue && self._queue.length < self.animation.queueLimit)){
    494 				self._clicking = true;
    495 				
    496 				if(type === 'sort'){
    497 					var sort = $button.attr('data-sort');
    498 					
    499 					if(!$button.hasClass(self.controls.activeClass) || sort.indexOf('random') > -1){
    500 						$(self.selectors.sort).removeClass(self.controls.activeClass);
    501 						trackClick($button, type);
    502 						self.sort(sort);
    503 					}
    504 				}
    505 				
    506 				if(type === 'filter') {
    507 					var filter = $button.attr('data-filter'),
    508 						ndx,
    509 						seperator = self.controls.toggleLogic === 'or' ? ',' : '';
    510 					
    511 					if(!self.controls.toggleFilterButtons){
    512 						if(!$button.hasClass(self.controls.activeClass)){
    513 							$(self.selectors.filter).removeClass(self.controls.activeClass);
    514 							trackClick($button, type);
    515 							self.filter(filter);
    516 						}
    517 					} else {
    518 						self._buildToggleArray();
    519 						
    520 						if(!$button.hasClass(self.controls.activeClass)){
    521 							trackClick($button, type);
    522 							
    523 							self._toggleArray.push(filter);
    524 						} else {
    525 							trackClick($button, type, true);
    526 							ndx = self._toggleArray.indexOf(filter);
    527 							self._toggleArray.splice(ndx, 1);
    528 						}
    529 						
    530 						self._toggleArray = $.grep(self._toggleArray,function(n){return(n);});
    531 						
    532 						self._toggleString = self._toggleArray.join(seperator);
    533 
    534 						self.filter(self._toggleString);
    535 					}
    536 				}
    537 				
    538 				self._execAction('_processClick', 1, arguments);
    539 			} else {
    540 				if(typeof self.callbacks.onMixBusy === 'function'){
    541 					self.callbacks.onMixBusy.call(self._domNode, self._state, self);
    542 				}
    543 				self._execAction('_processClickBusy', 1, arguments);
    544 			}
    545 		},
    546 		
    547 		/**
    548 		 * Build Toggle Array
    549 		 * @since 2.0.0
    550 		 */
    551 		
    552 		_buildToggleArray: function(){
    553 			var self = this,
    554 				activeFilter = self._activeFilter.replace(/\s/g, '');
    555 			
    556 			self._execAction('_buildToggleArray', 0, arguments);
    557 			
    558 			if(self.controls.toggleLogic === 'or'){
    559 				self._toggleArray = activeFilter.split(',');
    560 			} else {
    561 				self._toggleArray = activeFilter.split('.');
    562 				
    563 				!self._toggleArray[0] && self._toggleArray.shift();
    564 				
    565 				for(var i = 0, filter; filter = self._toggleArray[i]; i++){
    566 					self._toggleArray[i] = '.'+filter;
    567 				}
    568 			}
    569 			
    570 			self._execAction('_buildToggleArray', 1, arguments);
    571 		},
    572 		
    573 		/**
    574 		 * Update Controls
    575 		 * @since 2.0.0
    576 		 * @param {object} command
    577 		 * @param {boolean} multi
    578 		 */
    579 		
    580 		_updateControls: function(command, multi){
    581 			var self = this,
    582 				output = {
    583 					filter: command.filter,
    584 					sort: command.sort
    585 				},
    586 				update = function($el, filter){
    587 					try {
    588 						(multi && type === 'filter' && !(output.filter === 'none' || output.filter === '')) ?
    589 								$el.filter(filter).addClass(self.controls.activeClass) :
    590 								$el.removeClass(self.controls.activeClass).filter(filter).addClass(self.controls.activeClass);
    591 					} catch(e) {}
    592 				},
    593 				type = 'filter',
    594 				$el = null;
    595 				
    596 			self._execAction('_updateControls', 0, arguments);
    597 				
    598 			(command.filter === undf) && (output.filter = self._activeFilter);
    599 			(command.sort === undf) && (output.sort = self._activeSort);
    600 			(output.filter === self.selectors.target) && (output.filter = 'all');
    601 			
    602 			for(var i = 0; i < 2; i++){
    603 				$el = self.controls.live ? $(self.selectors[type]) : self['_$'+type+'Buttons'];
    604 				$el && update($el, '[data-'+type+'="'+output[type]+'"]');
    605 				type = 'sort';
    606 			}
    607 			
    608 			self._execAction('_updateControls', 1, arguments);
    609 		},
    610 		
    611 		/**
    612 		 * Filter (private)
    613 		 * @since 2.0.0
    614 		 */
    615 		
    616 		_filter: function(){
    617 			var self = this;
    618 			
    619 			self._execAction('_filter', 0);
    620 			
    621 			for(var i = 0; i < self._$targets.length; i++){
    622 				var $target = $(self._$targets[i]);
    623 				
    624 				if($target.is(self._activeFilter)){
    625 					self._$show = self._$show.add($target);
    626 				} else {
    627 					self._$hide = self._$hide.add($target);
    628 				}
    629 			}
    630 			
    631 			self._execAction('_filter', 1);
    632 		},
    633 		
    634 		/**
    635 		 * Sort (private)
    636 		 * @since 2.0.0
    637 		 */
    638 		
    639 		_sort: function(){
    640 			var self = this,
    641 				arrayShuffle = function(oldArray){
    642 					var newArray = oldArray.slice(),
    643 						len = newArray.length,
    644 						i = len;
    645 
    646 					while(i--){
    647 						var p = parseInt(Math.random()*len);
    648 						var t = newArray[i];
    649 						newArray[i] = newArray[p];
    650 						newArray[p] = t;
    651 					};
    652 					return newArray; 
    653 				};
    654 				
    655 			self._execAction('_sort', 0);
    656 			
    657 			self._startOrder = [];
    658 			
    659 			for(var i = 0; i < self._$targets.length; i++){
    660 				var target = self._$targets[i];
    661 				
    662 				self._startOrder.push(target);
    663 			}
    664 			
    665 			switch(self._newSort[0].sortBy){
    666 				case 'default':
    667 					self._newOrder = self._origOrder;
    668 					break;
    669 				case 'random':
    670 					self._newOrder = arrayShuffle(self._startOrder);
    671 					break;
    672 				case 'custom':
    673 					self._newOrder = self._newSort[0].order;
    674 					break;
    675 				default:
    676 					self._newOrder = self._startOrder.concat().sort(function(a, b){
    677 						return self._compare(a, b);
    678 					});
    679 			}
    680 			
    681 			self._execAction('_sort', 1);
    682 		},
    683 		
    684 		/**
    685 		 * Compare Algorithm
    686 		 * @since 2.0.0
    687 		 * @param {string|number} a
    688 		 * @param {string|number} b
    689 		 * @param {number} depth (recursion)
    690 		 * @return {number}
    691 		 */
    692 		
    693 		_compare: function(a, b, depth){
    694 			depth = depth ? depth : 0;
    695 		
    696 			var self = this,
    697 				order = self._newSort[depth].order,
    698 				getData = function(el){
    699 					return el.dataset[self._newSort[depth].sortBy] || 0;
    700 				},
    701 				attrA = isNaN(getData(a) * 1) ? getData(a).toLowerCase() : getData(a) * 1,
    702 				attrB = isNaN(getData(b) * 1) ? getData(b).toLowerCase() : getData(b) * 1;
    703 				
    704 			if(attrA < attrB)
    705 				return order === 'asc' ? -1 : 1;
    706 			if(attrA > attrB)
    707 				return order === 'asc' ? 1 : -1;
    708 			if(attrA === attrB && self._newSort.length > depth+1)
    709 				return self._compare(a, b, depth+1);
    710 
    711 			return 0;
    712 		},
    713 		
    714 		/**
    715 		 * Print Sort
    716 		 * @since 2.0.0
    717 		 * @param {boolean} reset
    718 		 */
    719 		
    720 		_printSort: function(reset){
    721 			var self = this,
    722 				order = reset ? self._startOrder : self._newOrder,
    723 				targets = self._$parent[0].querySelectorAll(self.selectors.target),
    724 				nextSibling = targets.length ? targets[targets.length -1].nextElementSibling : null,
    725 				frag = document.createDocumentFragment();
    726 				
    727 			self._execAction('_printSort', 0, arguments);
    728 			
    729 			for(var i = 0; i < targets.length; i++){
    730 				var target = targets[i],
    731 					whiteSpace = target.nextSibling;
    732 
    733 				if(target.style.position === 'absolute') continue;
    734 			
    735 				if(whiteSpace && whiteSpace.nodeName === '#text'){
    736 					self._$parent[0].removeChild(whiteSpace);
    737 				}
    738 				
    739 				self._$parent[0].removeChild(target);
    740 			}
    741 			
    742 			for(var i = 0; i < order.length; i++){
    743 				var el = order[i];
    744 
    745 				if(self._newSort[0].sortBy === 'default' && self._newSort[0].order === 'desc' && !reset){
    746 					var firstChild = frag.firstChild;
    747 					frag.insertBefore(el, firstChild);
    748 					frag.insertBefore(document.createTextNode(' '), el);
    749 				} else {
    750 					frag.appendChild(el);
    751 					frag.appendChild(document.createTextNode(' '));
    752 				}
    753 			}
    754 			
    755 			nextSibling ? 
    756 				self._$parent[0].insertBefore(frag, nextSibling) :
    757 				self._$parent[0].appendChild(frag);
    758 				
    759 			self._execAction('_printSort', 1, arguments);
    760 		},
    761 		
    762 		/**
    763 		 * Parse Sort
    764 		 * @since 2.0.0
    765 		 * @param {string} sortString
    766 		 * @return {array} newSort
    767 		 */
    768 		
    769 		_parseSort: function(sortString){
    770 			var self = this,
    771 				rules = typeof sortString === 'string' ? sortString.split(' ') : [sortString],
    772 				newSort = [];
    773 				
    774 			for(var i = 0; i < rules.length; i++){
    775 				var rule = typeof sortString === 'string' ? rules[i].split(':') : ['custom', rules[i]],
    776 					ruleObj = {
    777 						sortBy: self._helpers._camelCase(rule[0]),
    778 						order: rule[1] || 'asc'
    779 					};
    780 					
    781 				newSort.push(ruleObj);
    782 				
    783 				if(ruleObj.sortBy === 'default' || ruleObj.sortBy === 'random') break;
    784 			}
    785 			
    786 			return self._execFilter('_parseSort', newSort, arguments);
    787 		},
    788 		
    789 		/**
    790 		 * Parse Effects
    791 		 * @since 2.0.0
    792 		 * @return {object} effects
    793 		 */
    794 		
    795 		_parseEffects: function(){
    796 			var self = this,
    797 				effects = {
    798 					opacity: '',
    799 					transformIn: '',
    800 					transformOut: '',
    801 					filter: ''
    802 				},
    803 				parse = function(effect, extract, reverse){
    804 					if(self.animation.effects.indexOf(effect) > -1){
    805 						if(extract){
    806 							var propIndex = self.animation.effects.indexOf(effect+'(');
    807 							if(propIndex > -1){
    808 								var str = self.animation.effects.substring(propIndex),
    809 									match = /\(([^)]+)\)/.exec(str),
    810 									val = match[1];
    811 
    812 									return {val: val};
    813 							}
    814 						}
    815 						return true;
    816 					} else {
    817 						return false;
    818 					}
    819 				},
    820 				negate = function(value, invert){
    821 					if(invert){
    822 						return value.charAt(0) === '-' ? value.substr(1, value.length) : '-'+value;
    823 					} else {
    824 						return value;
    825 					}
    826 				},
    827 				buildTransform = function(key, invert){
    828 					var transforms = [
    829 						['scale', '.01'],
    830 						['translateX', '20px'],
    831 						['translateY', '20px'],
    832 						['translateZ', '20px'],
    833 						['rotateX', '90deg'],
    834 						['rotateY', '90deg'],
    835 						['rotateZ', '180deg'],
    836 					];
    837 					
    838 					for(var i = 0; i < transforms.length; i++){
    839 						var prop = transforms[i][0],
    840 							def = transforms[i][1],
    841 							inverted = invert && prop !== 'scale';
    842 							
    843 						effects[key] += parse(prop) ? prop+'('+negate(parse(prop, true).val || def, inverted)+') ' : '';
    844 					}
    845 				};
    846 			
    847 			effects.opacity = parse('fade') ? parse('fade',true).val || '0' : '1';
    848 			
    849 			buildTransform('transformIn');
    850 			
    851 			self.animation.reverseOut ? buildTransform('transformOut', true) : (effects.transformOut = effects.transformIn);
    852 
    853 			effects.transition = {};
    854 			
    855 			effects.transition = self._getPrefixedCSS('transition','all '+self.animation.duration+'ms '+self.animation.easing+', opacity '+self.animation.duration+'ms linear');
    856 		
    857 			self.animation.stagger = parse('stagger') ? true : false;
    858 			self.animation.staggerDuration = parseInt(parse('stagger') ? (parse('stagger',true).val ? parse('stagger',true).val : 100) : 100);
    859 
    860 			return self._execFilter('_parseEffects', effects);
    861 		},
    862 		
    863 		/**
    864 		 * Build State
    865 		 * @since 2.0.0
    866 		 * @param {boolean} future
    867 		 * @return {object} futureState
    868 		 */
    869 		
    870 		_buildState: function(future){
    871 			var self = this,
    872 				state = {};
    873 			
    874 			self._execAction('_buildState', 0);
    875 			
    876 			state = {
    877 				activeFilter: self._activeFilter === '' ? 'none' : self._activeFilter,
    878 				activeSort: future && self._newSortString ? self._newSortString : self._activeSort,
    879 				fail: !self._$show.length && self._activeFilter !== '',
    880 				$targets: self._$targets,
    881 				$show: self._$show,
    882 				$hide: self._$hide,
    883 				totalTargets: self._$targets.length,
    884 				totalShow: self._$show.length,
    885 				totalHide: self._$hide.length,
    886 				display: future && self._newDisplay ? self._newDisplay : self.layout.display
    887 			};
    888 			
    889 			if(future){
    890 				return self._execFilter('_buildState', state);
    891 			} else {
    892 				self._state = state;
    893 				
    894 				self._execAction('_buildState', 1);
    895 			}
    896 		},
    897 		
    898 		/**
    899 		 * Go Mix
    900 		 * @since 2.0.0
    901 		 * @param {boolean} animate
    902 		 */
    903 		
    904 		_goMix: function(animate){
    905 			var self = this,
    906 				phase1 = function(){
    907 					if(self._chrome && (self._chrome === 31)){
    908 						chromeFix(self._$parent[0]);
    909 					}
    910 					
    911 					self._setInter();
    912 					
    913 					phase2();
    914 				},
    915 				phase2 = function(){
    916 					var scrollTop = window.pageYOffset,
    917 						scrollLeft = window.pageXOffset,
    918 						docHeight = document.documentElement.scrollHeight;
    919 
    920 					self._getInterMixData();
    921 					
    922 					self._setFinal();
    923 
    924 					self._getFinalMixData();
    925 
    926 					(window.pageYOffset !== scrollTop) && window.scrollTo(scrollLeft, scrollTop);
    927 
    928 					self._prepTargets();
    929 					
    930 					if(window.requestAnimationFrame){
    931 						requestAnimationFrame(phase3);
    932 					} else {
    933 						setTimeout(function(){
    934 							phase3();
    935 						},20);
    936 					}
    937 				},
    938 				phase3 = function(){
    939 					self._animateTargets();
    940 
    941 					if(self._targetsBound === 0){
    942 						self._cleanUp();
    943 					}
    944 				},
    945 				chromeFix = function(grid){
    946 					var parent = grid.parentElement,
    947 						placeholder = document.createElement('div'),
    948 						frag = document.createDocumentFragment();
    949 
    950 					parent.insertBefore(placeholder, grid);
    951 					frag.appendChild(grid);
    952 					parent.replaceChild(grid, placeholder);
    953 				},
    954 				futureState = self._buildState(true);
    955 				
    956 			self._execAction('_goMix', 0, arguments);
    957 				
    958 			!self.animation.duration && (animate = false);
    959 
    960 			self._mixing = true;
    961 			
    962 			self._$container.removeClass(self.layout.containerClassFail);
    963 			
    964 			if(typeof self.callbacks.onMixStart === 'function'){
    965 				self.callbacks.onMixStart.call(self._domNode, self._state, futureState, self);
    966 			}
    967 			
    968 			self._$container.trigger('mixStart', [self._state, futureState, self]);
    969 			
    970 			self._getOrigMixData();
    971 			
    972 			if(animate && !self._suckMode){
    973 			
    974 				window.requestAnimationFrame ?
    975 					requestAnimationFrame(phase1) :
    976 					phase1();
    977 			
    978 			} else {
    979 				self._cleanUp();
    980 			}
    981 			
    982 			self._execAction('_goMix', 1, arguments);
    983 		},
    984 		
    985 		/**
    986 		 * Get Target Data
    987 		 * @since 2.0.0
    988 		 */
    989 		
    990 		_getTargetData: function(el, stage){
    991 			var self = this,
    992 				elStyle;
    993 			
    994 			el.dataset[stage+'PosX'] = el.offsetLeft;
    995 			el.dataset[stage+'PosY'] = el.offsetTop;
    996 
    997 			if(self.animation.animateResizeTargets){
    998 				elStyle = !self._suckMode ? 
    999 					window.getComputedStyle(el) : 
   1000 					{
   1001 						marginBottom: '',
   1002 						marginRight: ''
   1003 					};
   1004 			
   1005 				el.dataset[stage+'MarginBottom'] = parseInt(elStyle.marginBottom);
   1006 				el.dataset[stage+'MarginRight'] = parseInt(elStyle.marginRight);
   1007 				el.dataset[stage+'Width'] = el.offsetWidth;
   1008 				el.dataset[stage+'Height'] = el.offsetHeight;
   1009 			}
   1010 		},
   1011 		
   1012 		/**
   1013 		 * Get Original Mix Data
   1014 		 * @since 2.0.0
   1015 		 */
   1016 		
   1017 		_getOrigMixData: function(){
   1018 			var self = this,
   1019 				parentStyle = !self._suckMode ? window.getComputedStyle(self._$parent[0]) : {boxSizing: ''},
   1020 				parentBS = parentStyle.boxSizing || parentStyle[self._vendor+'BoxSizing'];
   1021 	
   1022 			self._incPadding = (parentBS === 'border-box');
   1023 			
   1024 			self._execAction('_getOrigMixData', 0);
   1025 			
   1026 			!self._suckMode && (self.effects = self._parseEffects());
   1027 		
   1028 			self._$toHide = self._$hide.filter(':visible');
   1029 			self._$toShow = self._$show.filter(':hidden');
   1030 			self._$pre = self._$targets.filter(':visible');
   1031 
   1032 			self._startHeight = self._incPadding ? 
   1033 				self._$parent.outerHeight() : 
   1034 				self._$parent.height();
   1035 				
   1036 			for(var i = 0; i < self._$pre.length; i++){
   1037 				var el = self._$pre[i];
   1038 				
   1039 				self._getTargetData(el, 'orig');
   1040 			}
   1041 			
   1042 			self._execAction('_getOrigMixData', 1);
   1043 		},
   1044 		
   1045 		/**
   1046 		 * Set Intermediate Positions
   1047 		 * @since 2.0.0
   1048 		 */
   1049 		
   1050 		_setInter: function(){
   1051 			var self = this;
   1052 			
   1053 			self._execAction('_setInter', 0);
   1054 			
   1055 			if(self._changingLayout && self.animation.animateChangeLayout){
   1056 				self._$toShow.css('display',self._newDisplay);
   1057 
   1058 				if(self._changingClass){
   1059 					self._$container
   1060 						.removeClass(self.layout.containerClass)
   1061 						.addClass(self._newClass);
   1062 				}
   1063 			} else {
   1064 				self._$toShow.css('display', self.layout.display);
   1065 			}
   1066 			
   1067 			self._execAction('_setInter', 1);
   1068 		},
   1069 		
   1070 		/**
   1071 		 * Get Intermediate Mix Data
   1072 		 * @since 2.0.0
   1073 		 */
   1074 		
   1075 		_getInterMixData: function(){
   1076 			var self = this;
   1077 			
   1078 			self._execAction('_getInterMixData', 0);
   1079 			
   1080 			for(var i = 0; i < self._$toShow.length; i++){
   1081 				var el = self._$toShow[i];
   1082 					
   1083 				self._getTargetData(el, 'inter');
   1084 			}
   1085 			
   1086 			for(var i = 0; i < self._$pre.length; i++){
   1087 				var el = self._$pre[i];
   1088 					
   1089 				self._getTargetData(el, 'inter');
   1090 			}
   1091 			
   1092 			self._execAction('_getInterMixData', 1);
   1093 		},
   1094 		
   1095 		/**
   1096 		 * Set Final Positions
   1097 		 * @since 2.0.0
   1098 		 */
   1099 		
   1100 		_setFinal: function(){
   1101 			var self = this;
   1102 			
   1103 			self._execAction('_setFinal', 0);
   1104 			
   1105 			self._sorting && self._printSort();
   1106 
   1107 			self._$toHide.removeStyle('display');
   1108 			
   1109 			if(self._changingLayout && self.animation.animateChangeLayout){
   1110 				self._$pre.css('display',self._newDisplay);
   1111 			}
   1112 			
   1113 			self._execAction('_setFinal', 1);
   1114 		},
   1115 		
   1116 		/**
   1117 		 * Get Final Mix Data
   1118 		 * @since 2.0.0
   1119 		 */
   1120 		
   1121 		_getFinalMixData: function(){
   1122 			var self = this;
   1123 			
   1124 			self._execAction('_getFinalMixData', 0);
   1125 	
   1126 			for(var i = 0; i < self._$toShow.length; i++){
   1127 				var el = self._$toShow[i];
   1128 					
   1129 				self._getTargetData(el, 'final');
   1130 			}
   1131 			
   1132 			for(var i = 0; i < self._$pre.length; i++){
   1133 				var el = self._$pre[i];
   1134 					
   1135 				self._getTargetData(el, 'final');
   1136 			}
   1137 			
   1138 			self._newHeight = self._incPadding ? 
   1139 				self._$parent.outerHeight() : 
   1140 				self._$parent.height();
   1141 
   1142 			self._sorting && self._printSort(true);
   1143 	
   1144 			self._$toShow.removeStyle('display');
   1145 			
   1146 			self._$pre.css('display',self.layout.display);
   1147 			
   1148 			if(self._changingClass && self.animation.animateChangeLayout){
   1149 				self._$container
   1150 					.removeClass(self._newClass)
   1151 					.addClass(self.layout.containerClass);
   1152 			}
   1153 			
   1154 			self._execAction('_getFinalMixData', 1);
   1155 		},
   1156 		
   1157 		/**
   1158 		 * Prepare Targets
   1159 		 * @since 2.0.0
   1160 		 */
   1161 		
   1162 		_prepTargets: function(){
   1163 			var self = this,
   1164 				transformCSS = {
   1165 					_in: self._getPrefixedCSS('transform', self.effects.transformIn),
   1166 					_out: self._getPrefixedCSS('transform', self.effects.transformOut)
   1167 				};
   1168 
   1169 			self._execAction('_prepTargets', 0);
   1170 			
   1171 			if(self.animation.animateResizeContainer){
   1172 				self._$parent.css('height',self._startHeight+'px');
   1173 			}
   1174 			
   1175 			for(var i = 0; i < self._$toShow.length; i++){
   1176 				var el = self._$toShow[i],
   1177 					$el = $(el);
   1178 				
   1179 				el.style.opacity = self.effects.opacity;
   1180 				el.style.display = (self._changingLayout && self.animation.animateChangeLayout) ?
   1181 					self._newDisplay :
   1182 					self.layout.display;
   1183 					
   1184 				$el.css(transformCSS._in);
   1185 				
   1186 				if(self.animation.animateResizeTargets){
   1187 					el.style.width = el.dataset.finalWidth+'px';
   1188 					el.style.height = el.dataset.finalHeight+'px';
   1189 					el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth) + (el.dataset.finalMarginRight * 1)+'px';
   1190 					el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight) + (el.dataset.finalMarginBottom * 1)+'px';
   1191 				}
   1192 			}
   1193 
   1194 			for(var i = 0; i < self._$pre.length; i++){
   1195 				var el = self._$pre[i],
   1196 					$el = $(el),
   1197 					translate = {
   1198 						x: el.dataset.origPosX - el.dataset.interPosX,
   1199 						y: el.dataset.origPosY - el.dataset.interPosY
   1200 					},
   1201 					transformCSS = self._getPrefixedCSS('transform','translate('+translate.x+'px,'+translate.y+'px)');
   1202 
   1203 				$el.css(transformCSS);
   1204 				
   1205 				if(self.animation.animateResizeTargets){
   1206 					el.style.width = el.dataset.origWidth+'px';
   1207 					el.style.height = el.dataset.origHeight+'px';
   1208 					
   1209 					if(el.dataset.origWidth - el.dataset.finalWidth){
   1210 						el.style.marginRight = -(el.dataset.origWidth - el.dataset.interWidth) + (el.dataset.origMarginRight * 1)+'px';
   1211 					}
   1212 					
   1213 					if(el.dataset.origHeight - el.dataset.finalHeight){
   1214 						el.style.marginBottom = -(el.dataset.origHeight - el.dataset.interHeight) + (el.dataset.origMarginBottom * 1) +'px';
   1215 					}
   1216 				}
   1217 			}
   1218 			
   1219 			self._execAction('_prepTargets', 1);
   1220 		},
   1221 		
   1222 		/**
   1223 		 * Animate Targets
   1224 		 * @since 2.0.0
   1225 		 */
   1226 		
   1227 		_animateTargets: function(){
   1228 			var self = this;
   1229 
   1230 			self._execAction('_animateTargets', 0);
   1231 			
   1232 			self._targetsDone = 0;
   1233 			self._targetsBound = 0;
   1234 			
   1235 			self._$parent
   1236 				.css(self._getPrefixedCSS('perspective', self.animation.perspectiveDistance+'px'))
   1237 				.css(self._getPrefixedCSS('perspective-origin', self.animation.perspectiveOrigin));
   1238 			
   1239 			if(self.animation.animateResizeContainer){
   1240 				self._$parent
   1241 					.css(self._getPrefixedCSS('transition','height '+self.animation.duration+'ms ease'))
   1242 					.css('height',self._newHeight+'px');
   1243 			}
   1244 			
   1245 			for(var i = 0; i < self._$toShow.length; i++){
   1246 				var el = self._$toShow[i],
   1247 					$el = $(el),
   1248 					translate = {
   1249 						x: el.dataset.finalPosX - el.dataset.interPosX,
   1250 						y: el.dataset.finalPosY - el.dataset.interPosY
   1251 					},
   1252 					delay = self._getDelay(i),
   1253 					toShowCSS = {};
   1254 				
   1255 				el.style.opacity = '';
   1256 				
   1257 				for(var j = 0; j < 2; j++){
   1258 					var a = j === 0 ? a = self._prefix : '';
   1259 					
   1260 					if(self._ff && self._ff <= 20){
   1261 						toShowCSS[a+'transition-property'] = 'all';
   1262 						toShowCSS[a+'transition-timing-function'] = self.animation.easing+'ms';
   1263 						toShowCSS[a+'transition-duration'] = self.animation.duration+'ms';
   1264 					}
   1265 					
   1266 					toShowCSS[a+'transition-delay'] = delay+'ms';
   1267 					toShowCSS[a+'transform'] = 'translate('+translate.x+'px,'+translate.y+'px)';
   1268 				}
   1269 				
   1270 				if(self.effects.transform || self.effects.opacity){
   1271 					self._bindTargetDone($el);
   1272 				}
   1273 				
   1274 				(self._ff && self._ff <= 20) ? 
   1275 					$el.css(toShowCSS) : 
   1276 					$el.css(self.effects.transition).css(toShowCSS);
   1277 			}
   1278 			
   1279 			for(var i = 0; i < self._$pre.length; i++){
   1280 				var el = self._$pre[i],
   1281 					$el = $(el),
   1282 					translate = {
   1283 						x: el.dataset.finalPosX - el.dataset.interPosX,
   1284 						y: el.dataset.finalPosY - el.dataset.interPosY
   1285 					},
   1286 					delay = self._getDelay(i);
   1287 					
   1288 				if(!(
   1289 					el.dataset.finalPosX === el.dataset.origPosX &&
   1290 					el.dataset.finalPosY === el.dataset.origPosY
   1291 				)){
   1292 					self._bindTargetDone($el);
   1293 				}
   1294 				
   1295 				$el.css(self._getPrefixedCSS('transition', 'all '+self.animation.duration+'ms '+self.animation.easing+' '+delay+'ms'));
   1296 				$el.css(self._getPrefixedCSS('transform', 'translate('+translate.x+'px,'+translate.y+'px)'));
   1297 				
   1298 				if(self.animation.animateResizeTargets){
   1299 					if(el.dataset.origWidth - el.dataset.finalWidth && el.dataset.finalWidth * 1){
   1300 						el.style.width = el.dataset.finalWidth+'px';
   1301 						el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth)+(el.dataset.finalMarginRight * 1)+'px';
   1302 					}
   1303 					
   1304 					if(el.dataset.origHeight - el.dataset.finalHeight && el.dataset.finalHeight * 1){
   1305 						el.style.height = el.dataset.finalHeight+'px';
   1306 						el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight)+(el.dataset.finalMarginBottom * 1) +'px';
   1307 					}
   1308 				}
   1309 			}
   1310 			
   1311 			if(self._changingClass){
   1312 				self._$container
   1313 					.removeClass(self.layout.containerClass)
   1314 					.addClass(self._newClass);
   1315 			}
   1316 			
   1317 			for(var i = 0; i < self._$toHide.length; i++){
   1318 				var el = self._$toHide[i],
   1319 					$el = $(el),
   1320 					delay = self._getDelay(i),
   1321 					toHideCSS = {};
   1322 
   1323 				for(var j = 0; j<2; j++){
   1324 					var a = j === 0 ? a = self._prefix : '';
   1325 
   1326 					toHideCSS[a+'transition-delay'] = delay+'ms';
   1327 					toHideCSS[a+'transform'] = self.effects.transformOut;
   1328 					toHideCSS.opacity = self.effects.opacity;
   1329 				}
   1330 				
   1331 				$el.css(self.effects.transition).css(toHideCSS);
   1332 			
   1333 				if(self.effects.transform || self.effects.opacity){
   1334 					self._bindTargetDone($el);
   1335 				};
   1336 			}
   1337 			
   1338 			self._execAction('_animateTargets', 1);
   1339 
   1340 		},
   1341 		
   1342 		/**
   1343 		 * Bind Targets TransitionEnd
   1344 		 * @since 2.0.0
   1345 		 * @param {object} $el
   1346 		 */
   1347 		
   1348 		_bindTargetDone: function($el){
   1349 			var self = this,
   1350 				el = $el[0];
   1351 				
   1352 			self._execAction('_bindTargetDone', 0, arguments);
   1353 			
   1354 			if(!el.dataset.bound){
   1355 				
   1356 				el.dataset.bound = true;
   1357 				self._targetsBound++;
   1358 			
   1359 				$el.on('webkitTransitionEnd.mixItUp transitionend.mixItUp',function(e){
   1360 					if(
   1361 						(e.originalEvent.propertyName.indexOf('transform') > -1 || 
   1362 						e.originalEvent.propertyName.indexOf('opacity') > -1) &&
   1363 						$(e.originalEvent.target).is(self.selectors.target)
   1364 					){
   1365 						$el.off('.mixItUp');
   1366 						delete el.dataset.bound;
   1367 						self._targetDone();
   1368 					}
   1369 				});
   1370 			}
   1371 			
   1372 			self._execAction('_bindTargetDone', 1, arguments);
   1373 		},
   1374 		
   1375 		/**
   1376 		 * Target Done
   1377 		 * @since 2.0.0
   1378 		 */
   1379 		
   1380 		_targetDone: function(){
   1381 			var self = this;
   1382 			
   1383 			self._execAction('_targetDone', 0);
   1384 			
   1385 			self._targetsDone++;
   1386 			
   1387 			(self._targetsDone === self._targetsBound) && self._cleanUp();
   1388 			
   1389 			self._execAction('_targetDone', 1);
   1390 		},
   1391 		
   1392 		/**
   1393 		 * Clean Up
   1394 		 * @since 2.0.0
   1395 		 */
   1396 		
   1397 		_cleanUp: function(){
   1398 			var self = this,
   1399 				targetStyles = self.animation.animateResizeTargets ? 
   1400 					'transform opacity width height margin-bottom margin-right' :
   1401 					'transform opacity',
   1402 				unBrake = function(){
   1403 					self._$targets.removeStyle('transition', self._prefix);
   1404 				};
   1405 				
   1406 			self._execAction('_cleanUp', 0);
   1407 			
   1408 			!self._changingLayout ?
   1409 				self._$show.css('display',self.layout.display) :
   1410 				self._$show.css('display',self._newDisplay);
   1411 			
   1412 			self._$targets.css(self._brake);
   1413 			
   1414 			self._$targets
   1415 				.removeStyle(targetStyles, self._prefix)
   1416 				.removeAttr('data-inter-pos-x data-inter-pos-y data-final-pos-x data-final-pos-y data-orig-pos-x data-orig-pos-y data-orig-height data-orig-width data-final-height data-final-width data-inter-width data-inter-height data-orig-margin-right data-orig-margin-bottom data-inter-margin-right data-inter-margin-bottom data-final-margin-right data-final-margin-bottom');
   1417 				
   1418 			self._$hide.removeStyle('display');
   1419 			
   1420 			self._$parent.removeStyle('height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin', self._prefix);
   1421 			
   1422 			if(self._sorting){
   1423 				self._printSort();
   1424 				self._activeSort = self._newSortString;
   1425 				self._sorting = false;
   1426 			}
   1427 			
   1428 			if(self._changingLayout){
   1429 				if(self._changingDisplay){
   1430 					self.layout.display = self._newDisplay;
   1431 					self._changingDisplay = false;
   1432 				}
   1433 				
   1434 				if(self._changingClass){
   1435 					self._$parent.removeClass(self.layout.containerClass).addClass(self._newClass);
   1436 					self.layout.containerClass = self._newClass;
   1437 					self._changingClass = false;
   1438 				}
   1439 				
   1440 				self._changingLayout = false;
   1441 			}
   1442 			
   1443 			self._refresh();
   1444 			
   1445 			self._buildState();
   1446 			
   1447 			if(self._state.fail){
   1448 				self._$container.addClass(self.layout.containerClassFail);
   1449 			}
   1450 			
   1451 			self._$show = $();
   1452 			self._$hide = $();
   1453 			
   1454 			if(window.requestAnimationFrame){
   1455 				requestAnimationFrame(unBrake);
   1456 			}
   1457 			
   1458 			self._mixing = false;
   1459 			
   1460 			if(typeof self.callbacks._user === 'function'){
   1461 				self.callbacks._user.call(self._domNode, self._state, self);
   1462 			}
   1463 			
   1464 			if(typeof self.callbacks.onMixEnd === 'function'){
   1465 				self.callbacks.onMixEnd.call(self._domNode, self._state, self);
   1466 			}
   1467 			
   1468 			self._$container.trigger('mixEnd', [self._state, self]);
   1469 			
   1470 			if(self._state.fail){
   1471 				(typeof self.callbacks.onMixFail === 'function') && self.callbacks.onMixFail.call(self._domNode, self._state, self);
   1472 				self._$container.trigger('mixFail', [self._state, self]);
   1473 			}
   1474 			
   1475 			if(self._loading){
   1476 				(typeof self.callbacks.onMixLoad === 'function') && self.callbacks.onMixLoad.call(self._domNode, self._state, self);
   1477 				self._$container.trigger('mixLoad', [self._state, self]);
   1478 			}
   1479 			
   1480 			if(self._queue.length){
   1481 				self._execAction('_queue', 0);
   1482 				
   1483 				self.multiMix(self._queue[0][0],self._queue[0][1],self._queue[0][2]);
   1484 				self._queue.splice(0, 1);
   1485 			}
   1486 			
   1487 			self._execAction('_cleanUp', 1);
   1488 			
   1489 			self._loading = false;
   1490 		},
   1491 		
   1492 		/**
   1493 		 * Get Prefixed CSS
   1494 		 * @since 2.0.0
   1495 		 * @param {string} property
   1496 		 * @param {string} value
   1497 		 * @param {boolean} prefixValue
   1498 		 * @return {object} styles
   1499 		 */
   1500 		
   1501 		_getPrefixedCSS: function(property, value, prefixValue){
   1502 			var self = this,
   1503 				styles = {},
   1504 				prefix = '',
   1505 				i = -1;
   1506 		
   1507 			for(i = 0; i < 2; i++){
   1508 				prefix = i === 0 ? self._prefix : '';
   1509 				prefixValue ? styles[prefix+property] = prefix+value : styles[prefix+property] = value;
   1510 			}
   1511 			
   1512 			return self._execFilter('_getPrefixedCSS', styles, arguments);
   1513 		},
   1514 		
   1515 		/**
   1516 		 * Get Delay
   1517 		 * @since 2.0.0
   1518 		 * @param {number} i
   1519 		 * @return {number} delay
   1520 		 */
   1521 		
   1522 		_getDelay: function(i){
   1523 			var self = this,
   1524 				n = typeof self.animation.staggerSequence === 'function' ? self.animation.staggerSequence.call(self._domNode, i, self._state) : i,
   1525 				delay = self.animation.stagger ? n * self.animation.staggerDuration : 0;
   1526 				
   1527 			return self._execFilter('_getDelay', delay, arguments);
   1528 		},
   1529 		
   1530 		/**
   1531 		 * Parse MultiMix Arguments
   1532 		 * @since 2.0.0
   1533 		 * @param {array} args
   1534 		 * @return {object} output
   1535 		 */
   1536 		
   1537 		_parseMultiMixArgs: function(args){
   1538 			var self = this,
   1539 				output = {
   1540 					command: null,
   1541 					animate: self.animation.enable,
   1542 					callback: null
   1543 				};
   1544 				
   1545 			for(var i = 0; i < args.length; i++){
   1546 				var arg = args[i];
   1547 
   1548 				if(arg !== null){
   1549 					if(typeof arg === 'object' || typeof arg === 'string'){
   1550 						output.command = arg;
   1551 					} else if(typeof arg === 'boolean'){
   1552 						output.animate = arg;
   1553 					} else if(typeof arg === 'function'){
   1554 						output.callback = arg;
   1555 					}
   1556 				}
   1557 			}
   1558 			
   1559 			return self._execFilter('_parseMultiMixArgs', output, arguments);
   1560 		},
   1561 		
   1562 		/**
   1563 		 * Parse Insert Arguments
   1564 		 * @since 2.0.0
   1565 		 * @param {array} args
   1566 		 * @return {object} output
   1567 		 */
   1568 		
   1569 		_parseInsertArgs: function(args){
   1570 			var self = this,
   1571 				output = {
   1572 					index: 0,
   1573 					$object: $(),
   1574 					multiMix: {filter: self._state.activeFilter},
   1575 					callback: null
   1576 				};
   1577 			
   1578 			for(var i = 0; i < args.length; i++){
   1579 				var arg = args[i];
   1580 				
   1581 				if(typeof arg === 'number'){
   1582 					output.index = arg;
   1583 				} else if(typeof arg === 'object' && arg instanceof $){
   1584 					output.$object = arg;
   1585 				} else if(typeof arg === 'object' && self._helpers._isElement(arg)){
   1586 					output.$object = $(arg);
   1587 				} else if(typeof arg === 'object' && arg !== null){
   1588 					output.multiMix = arg;
   1589 				} else if(typeof arg === 'boolean' && !arg){
   1590 					output.multiMix = false;
   1591 				} else if(typeof arg === 'function'){
   1592 					output.callback = arg;
   1593 				}
   1594 			}
   1595 			
   1596 			return self._execFilter('_parseInsertArgs', output, arguments);
   1597 		},
   1598 		
   1599 		/**
   1600 		 * Execute Action
   1601 		 * @since 2.0.0
   1602 		 * @param {string} methodName
   1603 		 * @param {boolean} isPost
   1604 		 * @param {array} args
   1605 		 */
   1606 		
   1607 		_execAction: function(methodName, isPost, args){
   1608 			var self = this,
   1609 				context = isPost ? 'post' : 'pre';
   1610 
   1611 			if(!self._actions.isEmptyObject && self._actions.hasOwnProperty(methodName)){
   1612 				for(var key in self._actions[methodName][context]){
   1613 					self._actions[methodName][context][key].call(self, args);
   1614 				}
   1615 			}
   1616 		},
   1617 		
   1618 		/**
   1619 		 * Execute Filter
   1620 		 * @since 2.0.0
   1621 		 * @param {string} methodName
   1622 		 * @param {mixed} value
   1623 		 * @return {mixed} value
   1624 		 */
   1625 		
   1626 		_execFilter: function(methodName, value, args){
   1627 			var self = this;
   1628 			
   1629 			if(!self._filters.isEmptyObject && self._filters.hasOwnProperty(methodName)){
   1630 				for(var key in self._filters[methodName]){
   1631 					return self._filters[methodName][key].call(self, args);
   1632 				}
   1633 			} else {
   1634 				return value;
   1635 			}
   1636 		},
   1637 		
   1638 		/* Helpers
   1639 		---------------------------------------------------------------------- */
   1640 
   1641 		_helpers: {
   1642 			
   1643 			/**
   1644 			 * CamelCase
   1645 			 * @since 2.0.0
   1646 			 * @param {string}
   1647 			 * @return {string}
   1648 			 */
   1649 
   1650 			_camelCase: function(string){
   1651 				return string.replace(/-([a-z])/g, function(g){
   1652 						return g[1].toUpperCase();
   1653 				});
   1654 			},
   1655 			
   1656 			/**
   1657 			 * Is Element
   1658 			 * @since 2.1.3
   1659 			 * @param {object} element to test
   1660 			 * @return {boolean}
   1661 			 */
   1662 			
   1663 			_isElement: function(el){
   1664 				if(window.HTMLElement){
   1665 					return el instanceof HTMLElement;
   1666 				} else {
   1667 					return (
   1668 						el !== null && 
   1669 						el.nodeType === 1 &&
   1670 						el.nodeName === 'string'
   1671 					);
   1672 				}
   1673 			}
   1674 		},
   1675 		
   1676 		/* Public Methods
   1677 		---------------------------------------------------------------------- */
   1678 		
   1679 		/**
   1680 		 * Is Mixing
   1681 		 * @since 2.0.0
   1682 		 * @return {boolean}
   1683 		 */
   1684 		
   1685 		isMixing: function(){
   1686 			var self = this;
   1687 			
   1688 			return self._execFilter('isMixing', self._mixing);
   1689 		},
   1690 		
   1691 		/**
   1692 		 * Filter (public)
   1693 		 * @since 2.0.0
   1694 		 * @param {array} arguments
   1695 		 */
   1696 		
   1697 		filter: function(){
   1698 			var self = this,
   1699 				args = self._parseMultiMixArgs(arguments);
   1700 
   1701 			self._clicking && (self._toggleString = '');
   1702 			
   1703 			self.multiMix({filter: args.command}, args.animate, args.callback);
   1704 		},
   1705 		
   1706 		/**
   1707 		 * Sort (public)
   1708 		 * @since 2.0.0
   1709 		 * @param {array} arguments
   1710 		 */
   1711 		
   1712 		sort: function(){
   1713 			var self = this,
   1714 				args = self._parseMultiMixArgs(arguments);
   1715 
   1716 			self.multiMix({sort: args.command}, args.animate, args.callback);
   1717 		},
   1718 
   1719 		/**
   1720 		 * Change Layout (public)
   1721 		 * @since 2.0.0
   1722 		 * @param {array} arguments
   1723 		 */
   1724 		
   1725 		changeLayout: function(){
   1726 			var self = this,
   1727 				args = self._parseMultiMixArgs(arguments);
   1728 				
   1729 			self.multiMix({changeLayout: args.command}, args.animate, args.callback);
   1730 		},
   1731 		
   1732 		/**
   1733 		 * MultiMix
   1734 		 * @since 2.0.0
   1735 		 * @param {array} arguments
   1736 		 */
   1737 		
   1738 		multiMix: function(){
   1739 			var self = this,
   1740 				args = self._parseMultiMixArgs(arguments);
   1741 
   1742 			self._execAction('multiMix', 0, arguments);
   1743 
   1744 			if(!self._mixing){
   1745 				if(self.controls.enable && !self._clicking){
   1746 					self.controls.toggleFilterButtons && self._buildToggleArray();
   1747 					self._updateControls(args.command, self.controls.toggleFilterButtons);
   1748 				}
   1749 				
   1750 				(self._queue.length < 2) && (self._clicking = false);
   1751 			
   1752 				delete self.callbacks._user;
   1753 				if(args.callback) self.callbacks._user = args.callback;
   1754 			
   1755 				var sort = args.command.sort,
   1756 					filter = args.command.filter,
   1757 					changeLayout = args.command.changeLayout;
   1758 
   1759 				self._refresh();
   1760 
   1761 				if(sort){
   1762 					self._newSort = self._parseSort(sort);
   1763 					self._newSortString = sort;
   1764 					
   1765 					self._sorting = true;
   1766 					self._sort();
   1767 				}
   1768 				
   1769 				if(filter !== undf){
   1770 					filter = (filter === 'all') ? self.selectors.target : filter;
   1771 	
   1772 					self._activeFilter = filter;
   1773 				}
   1774 				
   1775 				self._filter();
   1776 				
   1777 				if(changeLayout){
   1778 					self._newDisplay = (typeof changeLayout === 'string') ? changeLayout : changeLayout.display || self.layout.display;
   1779 					self._newClass = changeLayout.containerClass || '';
   1780 
   1781 					if(
   1782 						self._newDisplay !== self.layout.display ||
   1783 						self._newClass !== self.layout.containerClass
   1784 					){
   1785 						self._changingLayout = true;
   1786 						
   1787 						self._changingClass = (self._newClass !== self.layout.containerClass);
   1788 						self._changingDisplay = (self._newDisplay !== self.layout.display);
   1789 					}
   1790 				}
   1791 				
   1792 				self._$targets.css(self._brake);
   1793 				
   1794 				self._goMix(args.animate ^ self.animation.enable ? args.animate : self.animation.enable);
   1795 				
   1796 				self._execAction('multiMix', 1, arguments);
   1797 				
   1798 			} else {
   1799 				if(self.animation.queue && self._queue.length < self.animation.queueLimit){
   1800 					self._queue.push(arguments);
   1801 					
   1802 					(self.controls.enable && !self._clicking) && self._updateControls(args.command);
   1803 					
   1804 					self._execAction('multiMixQueue', 1, arguments);
   1805 					
   1806 				} else {
   1807 					if(typeof self.callbacks.onMixBusy === 'function'){
   1808 						self.callbacks.onMixBusy.call(self._domNode, self._state, self);
   1809 					}
   1810 					self._$container.trigger('mixBusy', [self._state, self]);
   1811 					
   1812 					self._execAction('multiMixBusy', 1, arguments);
   1813 				}
   1814 			}
   1815 		},
   1816 		
   1817 		/**
   1818 		 * Insert
   1819 		 * @since 2.0.0
   1820 		 * @param {array} arguments
   1821 		 */
   1822 		
   1823 		insert: function(){
   1824 			var self = this,
   1825 				args = self._parseInsertArgs(arguments),
   1826 				callback = (typeof args.callback === 'function') ? args.callback : null,
   1827 				frag = document.createDocumentFragment(),
   1828 				target = (function(){
   1829 					self._refresh();
   1830 					
   1831 					if(self._$targets.length){
   1832 						return (args.index < self._$targets.length || !self._$targets.length) ? 
   1833 							self._$targets[args.index] :
   1834 							self._$targets[self._$targets.length-1].nextElementSibling;
   1835 					} else {
   1836 						return self._$parent[0].children[0];
   1837 					}
   1838 				})();
   1839 						
   1840 			self._execAction('insert', 0, arguments);
   1841 				
   1842 			if(args.$object){
   1843 				for(var i = 0; i < args.$object.length; i++){
   1844 					var el = args.$object[i];
   1845 					
   1846 					frag.appendChild(el);
   1847 					frag.appendChild(document.createTextNode(' '));
   1848 				}
   1849 
   1850 				self._$parent[0].insertBefore(frag, target);
   1851 			}
   1852 			
   1853 			self._execAction('insert', 1, arguments);
   1854 			
   1855 			if(typeof args.multiMix === 'object'){
   1856 				self.multiMix(args.multiMix, callback);
   1857 			}
   1858 		},
   1859 
   1860 		/**
   1861 		 * Prepend
   1862 		 * @since 2.0.0
   1863 		 * @param {array} arguments
   1864 		 */
   1865 		
   1866 		prepend: function(){
   1867 			var self = this,
   1868 				args = self._parseInsertArgs(arguments);
   1869 				
   1870 			self.insert(0, args.$object, args.multiMix, args.callback);
   1871 		},
   1872 		
   1873 		/**
   1874 		 * Append
   1875 		 * @since 2.0.0
   1876 		 * @param {array} arguments
   1877 		 */
   1878 		
   1879 		append: function(){
   1880 			var self = this,
   1881 				args = self._parseInsertArgs(arguments);
   1882 		
   1883 			self.insert(self._state.totalTargets, args.$object, args.multiMix, args.callback);
   1884 		},
   1885 		
   1886 		/**
   1887 		 * Get Option
   1888 		 * @since 2.0.0
   1889 		 * @param {string} string
   1890 		 * @return {mixed} value
   1891 		 */
   1892 		
   1893 		getOption: function(string){
   1894 			var self = this,
   1895 				getProperty = function(obj, prop){
   1896 					var parts = prop.split('.'),
   1897 						last = parts.pop(),
   1898 						l = parts.length,
   1899 						i = 1,
   1900 						current = parts[0] || prop;
   1901 
   1902 					while((obj = obj[current]) && i < l){
   1903 						current = parts[i];
   1904 						i++;
   1905 					}
   1906 
   1907 					if(obj !== undf){
   1908 						return obj[last] !== undf ? obj[last] : obj;
   1909 					}
   1910 				};
   1911 
   1912 			return string ? self._execFilter('getOption', getProperty(self, string), arguments) : self;
   1913 		},
   1914 		
   1915 		/**
   1916 		 * Set Options
   1917 		 * @since 2.0.0
   1918 		 * @param {object} config
   1919 		 */
   1920 		
   1921 		setOptions: function(config){
   1922 			var self = this;
   1923 			
   1924 			self._execAction('setOptions', 0, arguments);
   1925 			
   1926 			typeof config === 'object' && $.extend(true, self, config);
   1927 			
   1928 			self._execAction('setOptions', 1, arguments);
   1929 		},
   1930 		
   1931 		/**
   1932 		 * Get State
   1933 		 * @since 2.0.0
   1934 		 * @return {object} state
   1935 		 */
   1936 		
   1937 		getState: function(){
   1938 			var self = this;
   1939 			
   1940 			return self._execFilter('getState', self._state, self);
   1941 		},
   1942 		
   1943 		/**
   1944 		 * Force Refresh
   1945 		 * @since 2.1.2
   1946 		 */
   1947 		
   1948 		forceRefresh: function(){
   1949 			var self = this;
   1950 			
   1951 			self._refresh(false, true);
   1952 		},
   1953 		
   1954 		/**
   1955 		 * Destroy
   1956 		 * @since 2.0.0
   1957 		 * @param {boolean} hideAll
   1958 		 */
   1959 		
   1960 		destroy: function(hideAll){
   1961 			var self = this,
   1962 				filters = $.MixItUp.prototype._bound._filter,
   1963 				sorts = $.MixItUp.prototype._bound._sort;
   1964 			
   1965 			self._execAction('destroy', 0, arguments);
   1966 		
   1967 			self._$body
   1968 				.add($(self.selectors.sort))
   1969 				.add($(self.selectors.filter))
   1970 				.off('.mixItUp');
   1971 			
   1972 			for(var i = 0; i < self._$targets.length; i++){
   1973 				var target = self._$targets[i];
   1974 
   1975 				hideAll && (target.style.display = '');
   1976 
   1977 				delete target.mixParent;
   1978 			}
   1979 			
   1980 			self._execAction('destroy', 1, arguments);
   1981 
   1982 			if(filters[self.selectors.filter] && filters[self.selectors.filter] > 1) {
   1983 				filters[self.selectors.filter]--;
   1984 			} else if(filters[self.selectors.filter] === 1) {
   1985 				delete filters[self.selectors.filter];
   1986 			}
   1987 
   1988 			if(sorts[self.selectors.sort] && sorts[self.selectors.sort] > 1) {
   1989 				sorts[self.selectors.sort]--;
   1990 			} else if(sorts[self.selectors.sort] === 1) {
   1991 				delete sorts[self.selectors.sort];
   1992 			}
   1993 
   1994 			delete $.MixItUp.prototype._instances[self._id];
   1995 		}
   1996 		
   1997 	};
   1998 	
   1999 	/* jQuery Methods
   2000 	---------------------------------------------------------------------- */
   2001 	
   2002 	/**
   2003 	 * jQuery .mixItUp() method
   2004 	 * @since 2.0.0
   2005 	 * @extends $.fn
   2006 	 */
   2007 	
   2008 	$.fn.mixItUp = function(){
   2009 		var args = arguments,
   2010 			dataReturn = [],
   2011 			eachReturn,
   2012 			_instantiate = function(domNode, settings){
   2013 				var instance = new $.MixItUp(),
   2014 					rand = function(){
   2015 						return ('00000'+(Math.random()*16777216<<0).toString(16)).substr(-6).toUpperCase();
   2016 					};
   2017 					
   2018 				instance._execAction('_instantiate', 0, arguments);
   2019 
   2020 				domNode.id = !domNode.id ? 'MixItUp'+rand() : domNode.id;
   2021 				
   2022 				if(!instance._instances[domNode.id]){
   2023 					instance._instances[domNode.id] = instance;
   2024 					instance._init(domNode, settings);
   2025 				}
   2026 				
   2027 				instance._execAction('_instantiate', 1, arguments);
   2028 			};
   2029 			
   2030 		eachReturn = this.each(function(){
   2031 			if(args && typeof args[0] === 'string'){
   2032 				var instance = $.MixItUp.prototype._instances[this.id];
   2033 				if(args[0] === 'isLoaded'){
   2034 					dataReturn.push(instance ? true : false);
   2035 				} else {
   2036 					var data = instance[args[0]](args[1], args[2], args[3]);
   2037 					if(data !== undf)dataReturn.push(data);
   2038 				}
   2039 			} else {
   2040 				_instantiate(this, args[0]);
   2041 			}
   2042 		});
   2043 		
   2044 		if(dataReturn.length){
   2045 			return dataReturn.length > 1 ? dataReturn : dataReturn[0];
   2046 		} else {
   2047 			return eachReturn;
   2048 		}
   2049 	};
   2050 	
   2051 	/**
   2052 	 * jQuery .removeStyle() method
   2053 	 * @since 2.0.0
   2054 	 * @extends $.fn
   2055 	 */
   2056 	
   2057 	$.fn.removeStyle = function(style, prefix){
   2058 		prefix = prefix ? prefix : '';
   2059 	
   2060 		return this.each(function(){
   2061 			var el = this,
   2062 				styles = style.split(' ');
   2063 				
   2064 			for(var i = 0; i < styles.length; i++){
   2065 				for(var j = 0; j < 4; j++){
   2066 					switch (j) {
   2067 						case 0:
   2068 							var prop = styles[i];
   2069 							break;
   2070 						case 1:
   2071 							var prop = $.MixItUp.prototype._helpers._camelCase(prop);
   2072 							break;
   2073 						case 2:
   2074 							var prop = prefix+styles[i];
   2075 							break;
   2076 						case 3:
   2077 							var prop = $.MixItUp.prototype._helpers._camelCase(prefix+styles[i]);
   2078 					}
   2079 					
   2080 					if(
   2081 						el.style[prop] !== undf && 
   2082 						typeof el.style[prop] !== 'unknown' &&
   2083 						el.style[prop].length > 0
   2084 					){
   2085 						el.style[prop] = '';
   2086 					}
   2087 					
   2088 					if(!prefix && j === 1)break;
   2089 				}
   2090 			}
   2091 			
   2092 			if(el.attributes && el.attributes.style && el.attributes.style !== undf && el.attributes.style.value === ''){
   2093 				el.attributes.removeNamedItem('style');
   2094 			}
   2095 		});
   2096 	};
   2097 	
   2098 })(jQuery);