PageSourceSearch

https://bg-ndk.de/js/jquery.mixitup.js

js bg-ndk.de collected 2026-10-07 05:28:59 UTC 36,235 bytes, 1,356 lines download raw bytes

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