PageSourceSearch

http://wrongbarber.ru/javascripts/jquery.mixitup.js

js wrongbarber.ru collected 2026-09-24 14:28:03 UTC 35,602 bytes, 1,337 lines download raw bytes

1/*
2* MIXITUP - A CSS3 and JQuery Filter & Sort Plugin
3* Version: 1.5.4
4* License: Creative Commons Attribution-NoDerivs 3.0 Unported - CC BY-ND 3.0
5* http://creativecommons.org/licenses/by-nd/3.0/
6* This software may be used freely on commercial and non-commercial projects with attribution to the author/copyright holder.
7* Author: Patrick Kunka
8* Copyright 2012-2013 Patrick Kunka, Barrel LLC, All Rights Reserved
9* 
10* http://mixitup.io
11*/
12
13(function($){
14	
15	// DECLARE METHODS
16 
17	var methods = {
18
19		// "INIT" METHOD
20	
21	    init: function(settings){
22
23			return this.each(function(){
24				
25				// BUILD CONFIG OBJECT
26
27				var config = {
28					
29					// PUBLIC PROPERTIES
30					
31					targetSelector : '.mix',
32					filterSelector : '.filter',
33					sortSelector : '.sort',
34					buttonEvent: 'click',
35					effects : ['fade', 'scale'],
36					listEffects : null,
37					easing : 'smooth',
38					layoutMode: 'grid',
39					targetDisplayGrid : 'inline-block',
40					targetDisplayList: 'block',
41					listClass : '',
42					gridClass : '',
43					transitionSpeed : 600,
44					showOnLoad : 'all',
45					sortOnLoad : false,
46					multiFilter : false,
47					filterLogic : 'or',
48					resizeContainer : true,
49					minHeight : 0,
50					failClass : 'fail',
51					perspectiveDistance : '3000',
52					perspectiveOrigin : '50% 50%',
53					animateGridList : true,
54					onMixLoad: null,
55					onMixStart : null,
56					onMixEnd : null,
57
58					// MISC
59
60					container : null,
61					origOrder : [],
62					startOrder : [],
63					newOrder : [],
64					origSort: [],
65					checkSort: [],
66					filter : '',
67					mixing : false,
68					origDisplay : '',
69					origLayout: '',
70					origHeight : 0, 
71					newHeight : 0,
72					isTouch : false,
73					resetDelay : 0,
74					failsafe : null,
75
76					// CSS
77					
78					prefix : '',
79					easingFallback : 'ease-in-out',
80					transition : {}, 
81					perspective : {}, 
82					clean : {},
83					fade : '1',
84					scale : '',
85					rotateX : '',
86					rotateY : '',
87					rotateZ : '',
88					blur : '',
89					grayscale : ''
90				};
91				
92				if(settings){
93					$.extend(config, settings);
94				};
95
96				// ADD CONFIG OBJECT TO CONTAINER OBJECT PER INSTANTIATION
97				
98				this.config = config;
99				
100				// DETECT TOUCH
101				
102				$.support.touch = 'ontouchend' in document;
103
104				if ($.support.touch) {
105					config.isTouch = true;
106					config.resetDelay = 350;
107				};
108				
109				// LOCALIZE CONTAINER
110	
111				config.container = $(this);
112				var $cont = config.container;
113				
114				// GET VENDOR PREFIX
115				
116				config.prefix = prefix($cont[0]);
117				config.prefix = config.prefix ? '-'+config.prefix.toLowerCase()+'-' : '';
118				
119				// CACHE 'DEFAULT' SORTING ORDER
120			
121				$cont.find(config.targetSelector).each(function(){
122					config.origOrder.push($(this));
123				});
124				
125				// PERFORM SORT ON LOAD 
126				
127				if(config.sortOnLoad){
128					var sortby, order;
129					if($.isArray(config.sortOnLoad)){
130						sortby = config.sortOnLoad[0], order = config.sortOnLoad[1];
131						$(config.sortSelector+'[data-sort='+config.sortOnLoad[0]+'][data-order='+config.sortOnLoad[1]+']').addClass('active');
132					} else {
133						$(config.sortSelector+'[data-sort='+config.sortOnLoad+']').addClass('active');
134						sortby = config.sortOnLoad, config.sortOnLoad = 'desc';
135					};
136					sort(sortby, order, $cont, config);
137				};
138				
139				// BUILD TRANSITION AND PERSPECTIVE OBJECTS
140				
141				for(var i = 0; i<2; i++){
142					var a = i==0 ? a = config.prefix : '';
143					config.transition[a+'transition'] = 'all '+config.transitionSpeed+'ms ease-in-out';
144					config.perspective[a+'perspective'] = config.perspectiveDistance+'px';
145					config.perspective[a+'perspective-origin'] = config.perspectiveOrigin;
146				};
147				
148				// BUILD TRANSITION CLEANER
149				
150				for(var i = 0; i<2; i++){
151					var a = i==0 ? a = config.prefix : '';
152					config.clean[a+'transition'] = 'none';
153				};
154	
155				// CHOOSE GRID OR LIST
156	
157				if(config.layoutMode == 'list'){
158					$cont.addClass(config.listClass);
159					config.origDisplay = config.targetDisplayList;
160				} else {
161					$cont.addClass(config.gridClass);
162					config.origDisplay = config.targetDisplayGrid;
163				};
164				config.origLayout = config.layoutMode;
165				
166				// PARSE 'SHOWONLOAD'
167				
168				var showOnLoadArray = config.showOnLoad.split(' ');
169				
170				// GIVE ACTIVE FILTER ACTIVE CLASS
171				
172				$.each(showOnLoadArray, function(){
173					$(config.filterSelector+'[data-filter="'+this+'"]').addClass('active');
174				});
175				
176				// RENAME "ALL" CATEGORY TO "MIX_ALL"
177	
178				$cont.find(config.targetSelector).addClass('mix_all');
179				if(showOnLoadArray[0]  == 'all'){
180					showOnLoadArray[0] = 'mix_all',
181					config.showOnLoad = 'mix_all';
182				};
183				
184				// FADE IN 'SHOWONLOAD'
185				
186				var $showOnLoad = $();
187				$.each(showOnLoadArray, function(){
188					$showOnLoad = $showOnLoad.add($('.'+this))
189				});
190				
191				$showOnLoad.each(function(){
192					var $t = $(this);
193					if(config.layoutMode == 'list'){
194						$t.css('display',config.targetDisplayList);
195					} else {
196						$t.css('display',config.targetDisplayGrid);
197					};
198					$t.css(config.transition);
199				});
200				
201				// WRAP FADE-IN TO PREVENT RACE CONDITION
202				
203				var delay = setTimeout(function(){
204					
205					config.mixing = true;
206					
207					$showOnLoad.css('opacity','1');
208					
209					// CLEAN UP
210					
211					var reset = setTimeout(function(){
212						if(config.layoutMode == 'list'){
213							$showOnLoad.removeStyle(config.prefix+'transition, transition').css({
214								display: config.targetDisplayList,
215								opacity: 1
216							});
217						} else {
218							$showOnLoad.removeStyle(config.prefix+'transition, transition').css({
219								display: config.targetDisplayGrid,
220								opacity: 1
221							});
222						};
223						
224						// FIRE "ONMIXLOAD" CALLBACK
225						
226						config.mixing = false;
227
228						if(typeof config.onMixLoad == 'function') {
229							var output = config.onMixLoad.call(this, config);
230
231							// UPDATE CONFIG IF DATA RETURNED
232
233							config = output ? output : config;
234						};
235						
236					},config.transitionSpeed);
237				},10);
238				
239				// PRESET ACTIVE FILTER
240				
241				config.filter = config.showOnLoad;
242			
243				// BIND SORT CLICK HANDLERS
244			
245				$(config.sortSelector).bind(config.buttonEvent,function(){
246					
247					if(!config.mixing){
248						
249						// PARSE SORT ARGUMENTS FROM BUTTON CLASSES
250						
251						var $t = $(this),
252						sortby = $t.attr('data-sort'),
253						order = $t.attr('data-order');
254						
255						if(!$t.hasClass('active')){
256							$(config.sortSelector).removeClass('active');
257							$t.addClass('active');
258						} else {
259							if(sortby != 'random')return false;
260						};
261						
262						$cont.find(config.targetSelector).each(function(){
263							config.startOrder.push($(this));
264						});
265				
266						goMix(config.filter,sortby,order,$cont, config);
267				
268					};
269				
270				});
271
272				// BIND FILTER CLICK HANDLERS
273
274				$(config.filterSelector).bind(config.buttonEvent,function(){
275				
276					if(!config.mixing){
277						
278						var $t = $(this);
279						
280						// PARSE FILTER ARGUMENTS FROM BUTTON CLASSES
281		
282						if(config.multiFilter == false){
283							
284							// SINGLE ACTIVE BUTTON
285							
286							$(config.filterSelector).removeClass('active');
287							$t.addClass('active');
288						
289							config.filter = $t.attr('data-filter');
290						
291							$(config.filterSelector+'[data-filter="'+config.filter+'"]').addClass('active');
292
293						} else {
294						
295							// MULTIPLE ACTIVE BUTTONS
296							
297							var thisFilter = $t.attr('data-filter'); 
298						
299							if($t.hasClass('active')){
300								$t.removeClass('active');
301								
302								// REMOVE FILTER FROM SPACE-SEPERATED STRING
303								
304								var re = new RegExp('(\\s|^)'+thisFilter);
305								config.filter = config.filter.replace(re,'');
306							} else {
307								
308								// ADD FILTER TO SPACE-SEPERATED STRING
309								
310								$t.addClass('active');
311								config.filter = config.filter+' '+thisFilter;
312								
313							};
314						};
315						
316						// GO MIX
317						
318						goMix(config.filter, null, null, $cont, config);
319
320					};
321				
322				});
323					
324			});
325		},
326	
327		// "TOGRID" METHOD
328	
329		toGrid: function(){
330			return this.each(function(){
331				var config = this.config;
332				if(config.layoutMode != 'grid'){
333					config.layoutMode = 'grid';
334					goMix(config.filter, null, null, $(this), config);
335				};
336			});
337		},
338	
339		// "TOLIST" METHOD
340	
341		toList: function(){
342			return this.each(function(){
343				var config = this.config;
344				if(config.layoutMode != 'list'){
345					config.layoutMode = 'list';
346					goMix(config.filter, null, null, $(this), config);
347				};
348			});
349		},
350	
351		// "FILTER" METHOD
352	
353		filter: function(arg){
354			return this.each(function(){
355				var config = this.config;
356				if(!config.mixing){	
357					$(config.filterSelector).removeClass('active');
358					$(config.filterSelector+'[data-filter="'+arg+'"]').addClass('active');
359					goMix(arg, null, null, $(this), config);
360				};
361			});	
362		},
363	
364		// "SORT" METHOD
365	
366		sort: function(args){
367			return this.each(function(){
368				var config = this.config,
369					$t = $(this);
370				if(!config.mixing){
371					$(config.sortSelector).removeClass('active');
372					if($.isArray(args)){
373						var sortby = args[0], order = args[1];
374						$(config.sortSelector+'[data-sort="'+args[0]+'"][data-order="'+args[1]+'"]').addClass('active');
375					} else {
376						$(config.sortSelector+'[data-sort="'+args+'"]').addClass('active');
377						var sortby = args, order = 'desc';
378					};
379					$t.find(config.targetSelector).each(function(){
380						config.startOrder.push($(this));
381					});
382					
383					goMix(config.filter,sortby,order, $t, config);
384				
385				};
386			});
387		},
388		
389		// "MULTIMIX" METHOD
390		
391		multimix: function(args){
392			return this.each(function(){
393				var config = this.config,
394					$t = $(this);
395					multiOut = {
396						filter: config.filter,
397						sort: null,
398						order: 'desc',
399						layoutMode: config.layoutMode
400					};
401				$.extend(multiOut, args);
402				if(!config.mixing){
403					$(config.filterSelector).add(config.sortSelector).removeClass('active');
404					$(config.filterSelector+'[data-filter="'+multiOut.filter+'"]').addClass('active');
405					if(typeof multiOut.sort !== 'undefined'){
406						$(config.sortSelector+'[data-sort="'+multiOut.sort+'"][data-order="'+multiOut.order+'"]').addClass('active');
407						$t.find(config.targetSelector).each(function(){
408							config.startOrder.push($(this));
409						});
410					};
411					config.layoutMode = multiOut.layoutMode;
412					goMix(multiOut.filter,multiOut.sort,multiOut.order, $t, config);
413				};
414			});
415		},
416		
417		// "REMIX" METHOD
418
419		remix: function(arg){
420			return this.each(function(){
421				var config = this.config,
422					$t = $(this);	
423				config.origOrder = [];
424				$t.find(config.targetSelector).each(function(){
425					var $th = $(this);
426					$th.addClass('mix_all'); 
427				    config.origOrder.push($th);
428				});
429				if(!config.mixing && typeof arg !== 'undefined'){
430					$(config.filterSelector).removeClass('active');
431					$(config.filterSelector+'[data-filter="'+arg+'"]').addClass('active');
432					goMix(arg, null, null, $t, config);
433				};
434			});
435		}
436	};
437	
438	// DECLARE PLUGIN
439
440	$.fn.mixitup = function(method, arg){
441		if (methods[method]) {
442			return methods[method].apply( this, Array.prototype.slice.call(arguments,1
442));
443		} else if (typeof method === 'object' || ! method){
444			return methods.init.apply( this, arguments );
445		};
446	};
447	
448	/* ==== THE MAGIC ==== */
449	
450	function goMix(filter, sortby, order, $cont, config){
451		
452		// WE ARE NOW MIXING
453
454		clearInterval(config.failsafe);
455		config.mixing = true;	
456		
457		// APPLY ARGS TO CONFIG
458		
459		config.filter = filter;
460		
461		// FIRE "ONMIXSTART" CALLBACK
462		
463		if(typeof config.onMixStart == 'function') {
464			var output = config.onMixStart.call(this, config);
465			
466			// UPDATE CONFIG IF DATA RETURNED
467			
468			config = output ? output : config;
469		};
470		
471		// SHORT LOCAL VARS
472		
473		var speed = config.transitionSpeed;
474		
475		// REBUILD TRANSITION AND PERSPECTIVE OBJECTS
476		
477		for(var i = 0; i<2; i++){
478			var a = i==0 ? a = config.prefix : '';
479			config.transition[a+'transition'] = 'all '+speed+'ms linear';
480			config.transition[a+'transform'] = a+'translate3d(0,0,0)';
481			config.perspective[a+'perspective'] = config.perspectiveDistance+'px';
482			config.perspective[a+'perspective-origin'] = config.perspectiveOrigin;
483		};
484		
485		// CACHE TARGET ELEMENTS FOR QUICK ACCESS
486		
487		var mixSelector = config.targetSelector,
488		$targets = $cont.find(mixSelector);
489		
490		// ADD DATA OBJECT TO EACH TARGET
491		
492		$targets.each(function(){
493			this.data = {};
494		});
495		
496		// RE-DEFINE CONTAINER INCASE NOT IMMEDIATE PARENT OF TARGET ELEMENTS 
497		
498		var $par = $targets.parent();
499	
500		// ADD PERSPECTIVE TO CONTAINER 
501		
502		$par.css(config.perspective);
503		
504		// SETUP EASING
505
506		config.easingFallback = 'ease-in-out';
507		if(config.easing == 'smooth')config.easing = 'cubic-bezier(0.25, 0.46, 0.45, 0.94)';
508		if(config.easing == 'snap')config.easing = 'cubic-bezier(0.77, 0, 0.175, 1)';
509		if(config.easing == 'windback'){
510			config.easing = 'cubic-bezier(0.175, 0.885, 0.320, 1.275)',
511			config.easingFallback = 'cubic-bezier(0.175, 0.885, 0.320, 1)'; // Fall-back for old webkit, with no values > 1 or < 1
512		};
513		if(config.easing == 'windup'){
514			config.easing = 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',
515			config.easingFallback = 'cubic-bezier(0.6, 0.28, 0.735, 0.045)';
516		};
517		
518		// USE LIST SPECIFIC EFFECTS IF DECLARED
519		
520		var effectsOut = config.layoutMode == 'list' && config.listEffects != null ? config.listEffects : config.effects;
521	
522		// BUILD EFFECTS STRINGS & SKIP IF IE8
523	
524		if (Array.prototype.indexOf){
525			config.fade = effectsOut.indexOf('fade') > -1 ? '0' : '';
526			config.scale = effectsOut.indexOf('scale') > -1 ? 'scale(.01)' : '';
527			config.rotateZ = effectsOut.indexOf('rotateZ') > -1 ? 'rotate(180deg)' : '';
528			config.rotateY = effectsOut.indexOf('rotateY') > -1 ? 'rotateY(90deg)' : '';
529			config.rotateX = effectsOut.indexOf('rotateX') > -1 ? 'rotateX(90deg)' : '';
530			config.blur = effectsOut.indexOf('blur') > -1 ? 'blur(8px)' : '';
531			config.grayscale = effectsOut.indexOf('grayscale') > -1 ? 'grayscale(100%)' : '';
532		};
533		
534		// DECLARE NEW JQUERY OBJECTS FOR GROUPING
535		
536		var $show = $(), 
537		$hide = $(),
538		filterArray = [],
539		multiDimensional = false;
540		
541		// BUILD FILTER ARRAY(S)
542		
543		if(typeof filter === 'string'){
544			
545			// SINGLE DIMENSIONAL FILTERING
546			
547			filterArray = buildFilterArray(filter);
548			
549		} else {
550			
551			// MULTI DIMENSIONAL FILTERING
552			
553			multiDimensional = true;
554			
555			$.each(filter,function(i){
556				filterArray[i] = buildFilterArray(this);
557			});
558		};
559
560		// "OR" LOGIC (DEFAULT)
561		
562		if(config.filterLogic == 'or'){
563			
564			if(filterArray[0] == '') filterArray.shift(); // IF FIRST ITEM IN ARRAY IS AN EMPTY SPACE, DELETE
565			
566			// IF NO ELEMENTS ARE DESIRED THEN HIDE ALL VISIBLE ELEMENTS
567		
568			if(filterArray.length < 1){
569				
570				$hide = $hide.add($cont.find(mixSelector+':visible'));
571				
572			} else {
573
574			// ELSE CHECK EACH TARGET ELEMENT FOR ANY FILTER CATEGORY:
575			
576				$targets.each(function(){
577					var $t = $(this);
578					if(!multiDimensional){
579						// IF HAS ANY FILTER, ADD TO "SHOW" OBJECT
580						if($t.is('.'+filterArray.join(', .'))){
581							$show = $show.add($t);
582						// ELSE IF HAS NO FILTERS, ADD TO "HIDE" OBJECT
583						} else {
584							$hide = $hide.add($t);
585						};
586					} else {
587						
588						var pass = 0;
589						// FOR EACH DIMENSION
590						
591						$.each(filterArray,function(i){
592							if(this.length){
593								if($t.is('.'+this.join(', .'))){
594									pass++
595								};
596							} else if(pass > 0){
597								pass++;
598							};
599						});
600						// IF PASSES ALL DIMENSIONS, SHOW
601						if(pass == filterArray.length){
602							$show = $show.add($t);
603						// ELSE HIDE
604						} else {
605							$hide = $hide.add($t);
606						};
607					};
608				});
609			
610			};
611	
612		} else {
613			
614		// "AND" LOGIC
615			
616			// ADD "MIX_SHOW" CLASS TO ELEMENTS THAT HAVE ALL FILTERS
617			
618			$show = $show.add($par.find(mixSelector+'.'+filterArray.join('.')));
619			
620			// ADD "MIX_HIDE" CLASS TO EVERYTHING ELSE
621			
622			$hide = $hide.add($par.find(mixSelector+':not(.'+filterArray.join('.')+'):visible'));
623		};
624		
625		// GET TOTAL NUMBER OF ELEMENTS TO SHOW
626		
627		var total = $show.length;
628		
629		// DECLARE NEW JQUERY OBJECTS
630
631		var $tohide = $(),
632		$toshow = $(),
633		$pre = $();
634		
635		// FOR ELEMENTS TO BE HIDDEN, IF NOT ALREADY HIDDEN THEN ADD TO OBJECTS "TOHIDE" AND "PRE" 
636		// TO INDICATE PRE-EXISTING ELEMENTS TO BE HIDDEN
637		
638		$hide.each(function(){
639			var $t = $(this);
640			if($t.css('display') != 'none'){
641				$tohide = $tohide.add($t);
642				$pre = $pre.add($t);
643			};
644		});
645		
646		// IF ALL ELEMENTS ARE ALREADY SHOWN AND THERE IS NOTHING TO HIDE, AND NOT PERFORMING A LAYOUT CHANGE OR SORT:
647		
648		if($show.filter(':visible').length == total && !$tohide.length && !sortby){
649			
650			if(config.origLayout == config.layoutMode){
651				
652				// THEN CLEAN UP AND GO HOME
653
654				resetFilter();
655				return false;
656			} else {
657				
658				// IF ONLY ONE ITEM AND CHANGING FORM GRID TO LIST, MOST LIKELY POSITION WILL NOT CHANGE SO WE'RE DONE
659			
660				if($show.length == 1){ 
661					
662					if(config.layoutMode == 'list'){ 
663						$cont.addClass(config.listClass);
664						$cont.removeClass(config.gridClass);
665						$pre.css('display',config.targetDisplayList);
666					} else {
667						$cont.addClass(config.gridClass);
668						$cont.removeClass(config.listClass);
669						$pre.css('display',config.targetDisplayGrid);
670					};
671					
672					// THEN CLEAN UP AND GO HOME
673
674					resetFilter();
675					return false;
676				}
677			};
678		};
679		
680		// GET CONTAINER'S STARTING HEIGHT
681
682		config.origHeight = $par.height();
683		
684		// IF THERE IS SOMETHING TO BE SHOWN:
685
686		if($show.length){
687			
688			// REMOVE "FAIL CLASS" FROM CONTAINER IF EXISTS
689			
690			$cont.removeClass(config.failClass);
691			
692			
693			// FOR ELEMENTS TO BE SHOWN, IF NOT ALREADY SHOWN THEN ADD TO OBJECTS "TOSHOW" ELSE ADD CLASS "MIX_PRE"
694			// TO INDICATE PRE-EXISTING ELEMENT
695
696			$show.each(function(){ 
697				var $t = $(this);
698				if($t.css('display') == 'none'){
699					$toshow = $toshow.add($t)
700				} else {
701					$pre = $pre.add($t);
702				};
703			});
704	
705			// IF NON-ANIMATED LAYOUT MODE TRANSITION:
706		
707			if((config.origLayout != config.layoutMode) && config.animateGridList == false){ 
708			
709				// ADD NEW DISPLAY TYPES, CLEAN UP AND GO HOME
710				
711				if(config.layoutMode == 'list'){ 
712					$cont.addClass(config.listClass);
713					$cont.removeClass(config.gridClass);
714					$pre.css('display',config.targetDisplayList);
715				} else {
716					$cont.addClass(config.gridClass);
717					$cont.removeClass(config.listClass);
718					$pre.css('display',config.targetDisplayGrid);
719				};
720				
721				resetFilter();
722				return false;
723			};
724			
725			// IF IE, FUCK OFF, AND THEN CLEAN UP AND GO HOME
726		
727			if(!window.atob){
728				resetFilter();
729				return false;
730			};
731			
732			// OVERRIDE ANY EXISTING TRANSITION TIMING FOR CALCULATIONS
733			
734			$targets.css(config.clean);
735			
736			// FOR EACH PRE-EXISTING ELEMENT, ADD STARTING POSITION TO 'ORIGPOS' ARRAY
737			
738			$pre.each(function(){
739				this.data.origPos = $(this).offset();
740			});
741	
742			// TEMPORARILY SHOW ALL ELEMENTS TO SHOW (THAT ARE NOT ALREADY SHOWN), WITHOUT HIDING ELEMENTS TO HIDE
743			// AND ADD/REMOVE GRID AND LIST CLASSES FROM CONTAINER
744	
745			if(config.layoutMode == 'list'){
746				$cont.addClass(config.listClass);
747				$cont.removeClass(config.gridClass);
748				$toshow.css('display',config.targetDisplayList);
749			} else {
750				$cont.addClass(config.gridClass);
751				$cont.removeClass(config.listClass);
752				$toshow.css('display',config.targetDisplayGrid);
753			};
754			
755			// FOR EACH ELEMENT NOW SHOWN, ADD ITS INTERMEDIATE POSITION TO 'SHOWINTERPOS' ARRAY
756	
757			$toshow.each(function(){
758				this.data.showInterPos = $(this).offset();
759			});
760			
761			// FOR EACH ELEMENT TO BE HIDDEN, BUT NOT YET HIDDEN, AND NOW MOVED DUE TO SHOWN ELEMENTS,
762			// ADD ITS INTERMEDIATE POSITION TO 'HIDEINTERPOS' ARRAY
763
764			$tohide.each(function(){
765				this.data.hideInterPos = $(this).offset();
766			});
767			
768			// FOR EACH PRE-EXISTING ELEMENT, NOW MOVED DUE TO SHOWN ELEMENTS, ADD ITS POSITION TO 'PREINTERPOS' ARRAY
769	
770			$pre.each(function(){
771				this.data.preInterPos = $(this).offset();
772			});
773			
774			// SET DISPLAY PROPERTY OF PRE-EXISTING ELEMENTS INCASE WE ARE CHANGING LAYOUT MODE
775	
776			if(config.layoutMode == 'list'){
777				$pre.css('display',config.targetDisplayList);
778			} else {
779				$pre.css('display',config.targetDisplayGrid);
780			};
781			
782			// IF A SORT ARGUMENT HAS BEEN SENT, RUN SORT FUNCTION SO OBJECTS WILL MOVE TO THEIR FINAL ORDER
783			
784			if(sortby){
785				sort(sortby, order, $cont, config);	
786			};
787			
788			// IF VISIBLE SORT ORDER IS THE SAME (WHICH WOULD NOT TRIGGER A TRANSITION EVENT)
789		
790			if(sortby && compareArr(config.origSort, config.checkSort)){
791				
792				// THEN CLEAN UP AND GO HOME
793				resetFilter();
794				return false;
795			};
796			
797			// TEMPORARILY HIDE ALL SHOWN ELEMENTS TO HIDE
798
799			$tohide.hide();
800			
801			// FOR EACH ELEMENT TO SHOW, AND NOW MOVED DUE TO HIDDEN ELEMENTS BEING REMOVED, 
802			// ADD ITS POSITION TO 'FINALPOS' ARRAY
803			
804			$toshow.each(function(i){
805				this.data.finalPos = $(this).offset();
806			});
807			
808			// FOR EACH PRE-EXISTING ELEMENT NOW MOVED DUE TO HIDDEN ELEMENTS BEING REMOVED,
809			// ADD ITS POSITION TO 'FINALPREPOS' ARRAY
810	
811			$pre.each(function(){
812				this.data.finalPrePos = $(this).offset();
813			});
814			
815			// SINCE WE ARE IN OUT FINAL STATE, GET NEW HEIGHT OF CONTAINER
816	
817			config.newHeight = $par.height();
818			
819			// IF A SORT ARGUMENT AS BEEN SENT, RUN SORT FUNCTION 'RESET' TO MOVE ELEMENTS BACK TO THEIR STARTING ORDER
820			
821			if(sortby){
822				sort('reset', null, $cont, config);
823			};
824			
825			// RE-HIDE ALL ELEMENTS TEMPORARILY SHOWN
826			
827			$toshow.hide();
828			
829			// SET DISPLAY PROPERTY OF PRE-EXISTING ELEMENTS BACK TO THEIR 
830			// ORIGINAL PROPERTY, INCASE WE ARE CHANGING LAYOUT MODE
831			
832			$pre.css('display',config.origDisplay);
833			
834			// ADD/REMOVE GRID AND LIST CLASSES FROM CONTAINER
835	
836			if(config.origDisplay == 'block'){
837				$cont.addClass(config.listClass);
838				$toshow.css('display', config.targetDisplayList);
839			} else {
840				$cont.removeClass(config.listClass);
841				$toshow.css('display', config.targetDisplayGrid);
842			};
843			
844			// IF WE ARE ANIMATING CONTAINER, RESET IT TO ITS STARTING HEIGHT
845		
846			if(config.resizeContainer)$par.css('height', config.origHeight+'px');
847	
848			// ADD TRANSFORMS TO ALL ELEMENTS TO SHOW
849			
850			var toShowCSS = {};
851			
852			for(var i = 0; i<2; i++){
853				var a = i==0 ? a = config.prefix : '';
854				toShowCSS[a+'transform'] = config.scale+' '+config.rotateX+' '+config.rotateY+' '+config.rotateZ;
855				toShowCSS[a+'filter'] = config.blur+' '+config.grayscale;
856			};
857			
858			$toshow.css(toShowCSS);
859	
860			// FOR EACH PRE-EXISTING ELEMENT, SUBTRACT ITS INTERMEDIATE POSITION FROM ITS ORIGINAL POSITION 
861			// TO GET ITS STARTING OFFSET
862	
863			$pre.each(function(){
864				var data = this.data,
865				$t = $(this);
866				
867				if ($t.hasClass('mix_tohide')){
868					data.preTX = data.origPos.left - data.hideInterPos.left;
869					data.preTY = data.origPos.top - data.hideInterPos.top;
870				} else {
871					data.preTX = data.origPos.left - data.preInterPos.left;
872					data.preTY = data.origPos.top - data.preInterPos.top;
873				};
874				var preCSS = {};
875				for(var i = 0; i<2; i++){
876					var a = i==0 ? a = config.prefix : '';
877					preCSS[a+'transform'] = 'translate('+data.preTX+'px,'+data.preTY+'px)';
878				};
879				
880				$t.css(preCSS);	
881			});
882			
883			// ADD/REMOVE GRID AND LIST CLASSES FROM CONTAINER
884	
885			if(config.layoutMode == 'list'){
886				$cont.addClass(config.listClass);
887				$cont.removeClass(config.gridClass);
888			} else {
889				$cont.addClass(config.gridClass);
890				$cont.removeClass(config.listClass);
891			};
892			
893			// WRAP ANIMATION FUNCTIONS IN 10ms TIMEOUT TO PREVENT RACE CONDITION
894			
895			var delay = setTimeout(function(){
896		
897				// APPLY TRANSITION TIMING TO CONTAINER, AND BEGIN ANIMATION TO NEW HEIGHT
898				
899				if(config.resizeContainer){
900					var containerCSS = {};
901					for(var i = 0; i<2; i++){
902						var a = i==0 ? a = config.prefix : '';
903						containerCSS[a+'transition'] = 'all '+speed+'ms ease-in-out';
904						containerCSS['height'] = config.newHeight+'px';
905					};
906					$par.css(containerCSS);
907				};
908	
909				// BEGIN FADING IN/OUT OF ALL ELEMENTS TO SHOW/HIDE
910				$tohide.css('opacity',config.fade);
911				$toshow.css('opacity',1);
912	
913				// FOR EACH ELEMENT BEING SHOWN, CALCULATE ITS TRAJECTORY BY SUBTRACTING
914				// ITS INTERMEDIATE POSITION FROM ITS FINAL POSITION.
915				// ALSO ADD SPEED AND EASING
916				
917				$toshow.each(function(){
918					var data = this.data;
919					data.tX = data.finalPos.left - data.showInterPos.left;
920					data.tY = data.finalPos.top - data.showInterPos.top;
921					
922					var toShowCSS = {};
923					for(var i = 0; i<2; i++){
924						var a = i==0 ? a = config.prefix : '';
925						toShowCSS[a+'transition-property'] = a+'transform, '+a+'filter, opacity';
926						toShowCSS[a+'transition-timing-function'] = config.easing+', linear, linear';
927						toShowCSS[a+'transition-duration'] = speed+'ms';
928						toShowCSS[a+'transition-delay'] = '0';
929						toShowCSS[a+'transform'] = 'translate('+data.tX+'px,'+data.tY+'px)';
930						toShowCSS[a+'filter'] = 'none';
931					};
932					
933					$(this).css('-webkit-transition', 'all '+speed+'ms '+config.easingFallback).css(toShowCSS);
934				});
935				
936				// FOR EACH PRE-EXISTING ELEMENT, IF IT HAS A FINAL POSITION, CALCULATE 
937				// ITS TRAJETORY BY SUBTRACTING ITS INTERMEDIATE POSITION FROM ITS FINAL POSITION.
938				// ALSO ADD SPEED AND EASING
939				
940				$pre.each(function(){
941					var data = this.data
942					data.tX = data.finalPrePos.left != 0 ? data.finalPrePos.left - data.preInterPos.left : 0;
943					data.tY = data.finalPrePos.left != 0 ? data.finalPrePos.top - data.preInterPos.top : 0;
944					
945					var preCSS = {};
946					for(var i = 0; i<2; i++){
947						var a = i==0 ? a = config.prefix : '';
948						preCSS[a+'transition'] = 'all '+speed+'ms '+config.easing;
949						preCSS[a+'transform'] = 'translate('+data.tX+'px,'+data.tY+'px)';
950					};
951					
952					$(this).css('-webkit-transition', 'all '+speed+'ms '+config.easingFallback).css(preCSS);
953				});
954		
955				// BEGIN TRANSFORMS ON ALL ELEMENTS TO BE HIDDEN
956				
957				var toHideCSS = {};
958				for(var i = 0; i<2; i++){
959					var a = i==0 ? a = config.prefix : '';
960					toHideCSS[a+'transition'] = 'all '+speed+'ms '+config.easing+', '+a+'filter '+speed+'ms linear, opacity '+speed+'ms linear';
961					toHideCSS[a+'transform'] = config.scale+' '+config.rotateX+' '+config.rotateY+' '+config.rotateZ;
962					toHideCSS[a+'filter'] = config.blur+' '+config.grayscale;
963					toHideCSS['opacity'] = config.fade;
964				};
965				
966				$tohide.css(toHideCSS);
967				
968				// ALL ANIMATIONS HAVE NOW BEEN STARTED, NOW LISTEN FOR TRANSITION END:
969				
970				$par.bind('webkitTransitionEnd transitionend otransitionend oTransitionEnd',function(e){
971					
972					if (e.originalEvent.propertyName.indexOf('transform') > -1 || e.originalEvent.propertyName.indexOf('opacity') > -1){
973						
974						if(mixSelector.indexOf('.') > -1){
975						
976						// IF MIXSELECTOR IS A CLASS NAME
977						
978							if($(e.target).hasClass(mixSelector.replace('.',''))){
979								resetFilter();
980							};
981						
982						} else {
983							
984						// IF MIXSELECTOR IS A TAG
985						
986							if($(e.target).is(mixSelector)){
987								resetFilter();
988							};
989							
990						};
991						
992					};
993				});	
994	
995			},10);
996			
997			// LAST RESORT EMERGENCY FAILSAFE
998			
999			config.failsafe = setTimeout(function(){
1000				if(config.mixing){
1001					resetFilter();
1002				};
1003			}, speed + 400);
1004	
1005		} else {
1006			
1007		// ELSE IF NOTHING TO SHOW, AND EVERYTHING TO BE HIDDEN
1008		
1009			// IF WE ARE RESIZING CONTAINER, SET ITS STARTING HEIGHT
1010	
1011			if(config.resizeContainer)$par.css('height', config.origHeight+'px');
1012			
1013			// IF IE, FUCK OFF, AND THEN GO HOME
1014			
1015			if(!window.atob){
1016				resetFilter();
1017				return false;
1018			};
1019			
1020			// GROUP ALL ELEMENTS TO HIDE INTO JQUERY OBJECT
1021			
1022			$tohide = $hide;
1023			
1024			// WRAP ANIMATION FUNCTIONS IN A 10ms DELAY TO PREVENT RACE CONDITION
1025	
1026			var delay = setTimeout(function(){
1027				
1028				// APPLY PERSPECTIVE TO CONTAINER
1029	
1030				$par.css(config.perspective);
1031				
1032				// APPLY TRANSITION TIMING TO CONTAINER, AND BEGIN ANIMATION TO NEW HEIGHT
1033		
1034				if(config.resizeContainer){
1035					var containerCSS = {};
1036					for(var i = 0; i<2; i++){
1037						var a = i==0 ? a = config.prefix : '';
1038						containerCSS[a+'transition'] = 'height '+speed+'ms ease-in-out';
1039						containerCSS['height'] = config.minHeight+'px';
1040					};
1041					$par.css(containerCSS);
1042				};
1043	
1044				// APPLY TRANSITION TIMING TO ALL TARGET ELEMENTS
1045				
1046				$targets.css(config.transition);
1047				
1048				// GET TOTAL NUMBER OF ELEMENTS TO HIDE
1049	
1050				var totalHide = $hide.length;
1051				
1052				// IF SOMETHING TO HIDE:
1053	
1054				if(totalHide){
1055					
1056					// BEGIN TRANSFORMS ON ALL ELEMENTS TO BE HIDDEN
1057
1058					var toHideCSS = {};
1059					for(var i = 0; i<2; i++){
1060						var a = i==0 ? a = config.prefix : '';
1061						toHideCSS[a+'transform'] = config.scale+' '+config.rotateX+' '+config.rotateY+' '+config.rotateZ;
1062						toHideCSS[a+'filter'] = config.blur+' '+config.grayscale;
1063						toHideCSS['opacity'] = config.fade;
1064					};
1065
1066					$tohide.css(toHideCSS);
1067					
1068					// ALL ANIMATIONS HAVE NOW BEEN STARTED, NOW LISTEN FOR TRANSITION END:
1069
1070					$par.bind('webkitTransitionEnd transitionend otransitionend oTransitionEnd',function(e){
1071						if (e.originalEvent.propertyName.indexOf('transform') > -1 || e.originalEvent.propertyName.indexOf('opacity') > -1){
1072							$cont.addClass(config.failClass);
1073							resetFilter();
1074						};
1075					});
1076		
1077				} else {
1078					
1079				// ELSE, WE'RE DONE MIXING
1080				 	
1081					config.mixing = false;
1082				};
1083	
1084			}, 10);
1085		}; 
1086		
1087		// CLEAN UP AND RESET FUNCTION
1088
1089		function resetFilter(){
1090			
1091			// UNBIND TRANSITION END EVENTS FROM CONTAINER
1092			
1093			$par.unbind('webkitTransitionEnd transitionend otransitionend oTransitionEnd');
1094			
1095			// IF A SORT ARGUMENT HAS BEEN SENT, SORT ELEMENTS TO THEIR FINAL ORDER
1096			
1097			if(sortby){
1098				sort(sortby, order, $cont, config);
1099			};
1100			
1101			// EMPTY SORTING ARRAYS
1102		
1103			config.startOrder = [], config.newOrder = [], config.origSort = [], config.checkSort = [];
1104		
1105			// REMOVE INLINE STYLES FROM ALL TARGET ELEMENTS AND SLAM THE BRAKES ON
1106			
1107			$targets.removeStyle(
1108				config.prefix+'filter, filter, '+config.prefix+'transform, transform, opacity, display'
1109			).css(config.clean).removeAttr('data-checksum');
1110			
1111			// BECAUSE IE SUCKS
1112			
1113			if(!window.atob){
1114				$targets.css({
1115					display: 'none',
1116					opacity: '0'
1117				});
1118			};
1119			
1120			// REMOVE HEIGHT FROM CONTAINER ONLY IF RESIZING
1121			
1122			var remH = config.resizeContainer ? 'height' : '';
1123			
1124			// REMOVE INLINE STYLES FROM CONTAINER
1125		
1126			$par.removeStyle(
1127				config.prefix+'transition, transition, '+config.prefix+'perspective, perspective, '+config.prefix+'perspective-origin, perspective-origin, '+remH
1128			);
1129			
1130			// ADD FINAL DISPLAY PROPERTIES AND OPACITY TO ALL SHOWN ELEMENTS
1131			// CACHE CURRENT LAYOUT MODE & SORT FOR NEXT MIX
1132			
1133			if(config.layoutMode == 'list'){
1134				$show.css({display:config.targetDisplayList, opacity:'1'});
1135				config.origDisplay = config.targetDisplayList;
1136			} else {
1137				$show.css({display:config.targetDisplayGrid, opacity:'1'});
1138				config.origDisplay = config.targetDisplayGrid;
1139			};
1140			config.origLayout = config.layoutMode;
1141				
1142			var wait = setTimeout(function(){
1143				
1144				// LET GO OF THE BRAKES
1145				
1146				$targets.removeStyle(config.prefix+'transition, transition');
1147			
1148				// WE'RE DONE MIXING
1149			
1150				config.mixing = false;
1151			
1152				// FIRE "ONMIXEND" CALLBACK
1153			
1154				if(typeof config.onMixEnd == 'function') {
1155					var output = config.onMixEnd.call(this, config);
1156				
1157					// UPDATE CONFIG IF DATA RETURNED
1158				
1159					config = output ? output : config;
1160				};
1161			});
1162		};
1163	};
1164	
1165	// SORT FUNCTION
1166	
1167	function sort(sortby, order, $cont, config){
1168
1169		// COMPARE BY ATTRIBUTE
1170
1171		function compare(a,b) {
1172			var sortAttrA = isNaN(a.attr(sortby) * 1) ? a.attr(sortby).toLowerCase() : a.attr(sortby) * 1,
1173				sortAttrB = isNaN(b.attr(sortby) * 1) ? b.attr(sortby).toLowerCase() : b.attr(sortby) * 1;
1174		  	if (sortAttrA < sortAttrB)
1175		    	return -1;
1176		  	if (sortAttrA > sortAttrB)
1177		    	return 1;
1178		  	return 0;
1179		};
1180		
1181		// REBUILD DOM
1182
1183		function rebuild(element){
1184			if(order == 'asc'){
1185				$sortWrapper.prepend(element).prepend(' ');
1186			} else {
1187				$sortWrapper.append(element).append(' ');
1188			};
1189		};
1190		
1191		// RANDOMIZE ARRAY
1192
1193		function arrayShuffle(oldArray){
1194			var newArray = oldArray.slice();
1195		 	var len = newArray.length;
1196			var i = len;
1197			while (i--){
1198			 	var p = parseInt(Math.random()*len);
1199				var t = newArray[i];
1200		  		newArray[i] = newArray[p];
1201			  	newArray[p] = t;
1202		 	};
1203			return newArray; 
1204		};
1205		
1206		// SORT
1207		
1208		$cont.find(config.targetSelector).wrapAll('<div class="mix_sorter"/>');
1209		
1210		var $sortWrapper = $cont.find('.mix_sorter');
1211		
1212		if(!config.origSort.length){
1213			$sortWrapper.find(config.targetSelector+':visible').each(function(){
1214				$(this).wrap('<s/>');
1215				config.origSort.push($(this).parent().html().replace(/\s+/g, ''));
1216				$(this).unwrap();
1217			});
1218		};
1219		
1220		
1221		
1222		$sortWrapper.empty();
1223		
1224		if(sortby == 'reset'){
1225			$.each(config.startOrder,function(){
1226				$sortWrapper.append(this).append(' ');
1227			});
1228		} else if(sortby == 'default'){
1229			$.each(config.origOrder,function(){
1230				rebuild(this);
1231			});
1232		} else if(sortby == 'random'){
1233			if(!config.newOrder.length){
1234				config.newOrder = arrayShuffle(config.startOrder);
1235			};
1236			$.each(config.newOrder,function(){
1237				$sortWrapper.append(this).append(' ');
1238			});	
1239		} else if(sortby == 'custom'){
1240			$.each(order, function(){
1241				rebuild(this);
1242			});
1243		} else { 
1244			// SORT BY ATTRIBUTE
1245			
1246			if(typeof config.origOrder[0].attr(sortby) === 'undefined'){
1247				console.log('No such attribute found. Terminating');
1248				return false;
1249			};
1250			
1251			if(!config.newOrder.length){
1252				$.each(config.origOrder,function(){
1253					config.newOrder.push($(this));
1254				});
1255				config.newOrder.sort(compare);
1256			};
1257			$.each(config.newOrder,function(){
1258				rebuild(this);
1259			});
1260			
1261		};
1262		config.checkSort = [];
1263		$sortWrapper.find(config.targetSelector+':visible').each(function(i){
1264			var $t = $(this);
1265			if(i == 0){
1266				
1267				// PREVENT COMPARE RETURNING FALSE POSITIVES ON ELEMENTS WITH NO CLASS/ATTRIBUTES
1268				
1269				$t.attr('data-checksum','1');
1270			};
1271			$t.wrap('<s/>');
1272			config.checkSort.push($t.parent().html().replace(/\s+/g, ''));
1273			$t.unwrap();
1274		});
1275		
1276		$cont.find(config.targetSelector).unwrap();
1277	};
1278	
1279	// FIND VENDOR PREFIX
1280
1281	function prefix(el) {
1282	    var prefixes = ["Webkit", "Moz", "O", "ms"];
1283	    for (var i = 0; i < prefixes.length; i++){
1284	        if (prefixes[i] + "Transition" in el.style){
1285	            return prefixes[i];
1286	        };
1287	    };
1288	    return "transition" in el.style ? "" : false;
1289	};
1290	
1291	// REMOVE SPECIFIC STYLES
1292	
1293	$.fn.removeStyle = function(style){
1294		return this.each(function(){
1295			var obj = $(this);
1296			style = style.replace(/\s+/g, '');
1297			var styles = style.split(',');
1298			$.each(styles,function(){
1299				
1300				var search = new RegExp(this.toString() + '[^;]+;?', 'g');
1301				obj.attr('style', function(i, style){
1302					if(style) return style.replace(search, '');
1303			    });
1304			});
1305		});
1306    };
1307
1308	// COMPARE ARRAYS 
1309	
1310	function compareArr(a,b){
1311	    if (a.length != b.length) return false;
1312	    for (var i = 0; i < b.length; i++){
1313	        if (a[i].compare) { 
1314	            if (!a[i].compare(b[i])) return false;
1315	        };
1316	        if (a[i] !== b[i]) return false;
1317	    };
1318	    return true;
1319	};
1320	
1321	// BUILD FILTER ARRAY(S)
1322	
1323	function buildFilterArray(str){
1324		// CLEAN FILTER STRING
1325		str = str.replace(/\s{2,}/g, ' ');
1326		// FOR EACH PEROID SEPERATED CLASS NAME, ADD STRING TO FILTER ARRAY
1327		var arr = str.split(' ');
1328		// IF ALL, REPLACE WITH MIX_ALL
1329		$.each(arr,function(i){
1330			if(this == 'all')arr[i] = 'mix_all';
1331		});
1332		if(arr[0] == "")arr.shift(); 
1333		return arr;
1334	};
1335
1336	
1337})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.