mirror of
				https://github.com/dawidolko/Website-Templates.git
				synced 2025-10-27 16:03:10 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1398 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1398 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
| 
 | |
| 
 | |
| */
 | |
| 
 | |
| (function( window, $, undefined ){
 | |
| 
 | |
|   'use strict';
 | |
| 
 | |
|   // get global vars
 | |
|   var document = window.document;
 | |
|   var Modernizr = window.Modernizr;
 | |
| 
 | |
|   // helper function
 | |
|   var capitalize = function( str ) {
 | |
|     return str.charAt(0).toUpperCase() + str.slice(1);
 | |
|   };
 | |
| 
 | |
|   // ========================= getStyleProperty by kangax ===============================
 | |
|   // http://perfectionkills.com/feature-testing-css-properties/
 | |
| 
 | |
|   var prefixes = 'Moz Webkit O Ms'.split(' ');
 | |
| 
 | |
|   var getStyleProperty = function( propName ) {
 | |
|     var style = document.documentElement.style,
 | |
|         prefixed;
 | |
| 
 | |
|     // test standard property first
 | |
|     if ( typeof style[propName] === 'string' ) {
 | |
|       return propName;
 | |
|     }
 | |
| 
 | |
|     // capitalize
 | |
|     propName = capitalize( propName );
 | |
| 
 | |
|     // test vendor specific properties
 | |
|     for ( var i=0, len = prefixes.length; i < len; i++ ) {
 | |
|       prefixed = prefixes[i] + propName;
 | |
|       if ( typeof style[ prefixed ] === 'string' ) {
 | |
|         return prefixed;
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var transformProp = getStyleProperty('transform'),
 | |
|       transitionProp = getStyleProperty('transitionProperty');
 | |
| 
 | |
| 
 | |
|   // ========================= miniModernizr ===============================
 | |
|   // <3<3<3 and thanks to Faruk and Paul for doing the heavy lifting
 | |
| 
 | |
|   /*!
 | |
|    * Modernizr v1.6ish: miniModernizr for Isotope
 | |
|    * http://www.modernizr.com
 | |
|    *
 | |
|    * Developed by:
 | |
|    * - Faruk Ates  http://farukat.es/
 | |
|    * - Paul Irish  http://paulirish.com/
 | |
|    *
 | |
|    * Copyright (c) 2009-2010
 | |
|    * Dual-licensed under the BSD or MIT licenses.
 | |
|    * http://www.modernizr.com/license/
 | |
|    */
 | |
| 
 | |
|   /*
 | |
|    * This version whittles down the script just to check support for
 | |
|    * CSS transitions, transforms, and 3D transforms.
 | |
|   */
 | |
| 
 | |
|   var tests = {
 | |
|     csstransforms: function() {
 | |
|       return !!transformProp;
 | |
|     },
 | |
| 
 | |
|     csstransforms3d: function() {
 | |
|       var test = !!getStyleProperty('perspective');
 | |
|       // double check for Chrome's false positive
 | |
|       if ( test ) {
 | |
|         var vendorCSSPrefixes = ' -o- -moz- -ms- -webkit- -khtml- '.split(' '),
 | |
|             mediaQuery = '@media (' + vendorCSSPrefixes.join('transform-3d),(') + 'modernizr)',
 | |
|             $style = $('<style>' + mediaQuery + '{#modernizr{height:3px}}' + '</style>')
 | |
|                         .appendTo('head'),
 | |
|             $div = $('<div id="modernizr" />').appendTo('html');
 | |
| 
 | |
|         test = $div.height() === 3;
 | |
| 
 | |
|         $div.remove();
 | |
|         $style.remove();
 | |
|       }
 | |
|       return test;
 | |
|     },
 | |
| 
 | |
|     csstransitions: function() {
 | |
|       return !!transitionProp;
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var testName;
 | |
| 
 | |
|   if ( Modernizr ) {
 | |
|     // if there's a previous Modernzir, check if there are necessary tests
 | |
|     for ( testName in tests) {
 | |
|       if ( !Modernizr.hasOwnProperty( testName ) ) {
 | |
|         // if test hasn't been run, use addTest to run it
 | |
|         Modernizr.addTest( testName, tests[ testName ] );
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     // or create new mini Modernizr that just has the 3 tests
 | |
|     Modernizr = window.Modernizr = {
 | |
|       _version : '1.6ish: miniModernizr for Isotope'
 | |
|     };
 | |
| 
 | |
|     var classes = ' ';
 | |
|     var result;
 | |
| 
 | |
|     // Run through tests
 | |
|     for ( testName in tests) {
 | |
|       result = tests[ testName ]();
 | |
|       Modernizr[ testName ] = result;
 | |
|       classes += ' ' + ( result ?  '' : 'no-' ) + testName;
 | |
|     }
 | |
| 
 | |
|     // Add the new classes to the <html> element.
 | |
|     $('html').addClass( classes );
 | |
|   }
 | |
| 
 | |
| 
 | |
|   // ========================= isoTransform ===============================
 | |
| 
 | |
|   /**
 | |
|    *  provides hooks for .css({ scale: value, translate: [x, y] })
 | |
|    *  Progressively enhanced CSS transforms
 | |
|    *  Uses hardware accelerated 3D transforms for Safari
 | |
|    *  or falls back to 2D transforms.
 | |
|    */
 | |
| 
 | |
|   if ( Modernizr.csstransforms ) {
 | |
| 
 | |
|         // i.e. transformFnNotations.scale(0.5) >> 'scale3d( 0.5, 0.5, 1)'
 | |
|     var transformFnNotations = Modernizr.csstransforms3d ?
 | |
|       { // 3D transform functions
 | |
|         translate : function ( position ) {
 | |
|           return 'translate3d(' + position[0] + 'px, ' + position[1] + 'px, 0) ';
 | |
|         },
 | |
|         scale : function ( scale ) {
 | |
|           return 'scale3d(' + scale + ', ' + scale + ', 1) ';
 | |
|         }
 | |
|       } :
 | |
|       { // 2D transform functions
 | |
|         translate : function ( position ) {
 | |
|           return 'translate(' + position[0] + 'px, ' + position[1] + 'px) ';
 | |
|         },
 | |
|         scale : function ( scale ) {
 | |
|           return 'scale(' + scale + ') ';
 | |
|         }
 | |
|       }
 | |
|     ;
 | |
| 
 | |
|     var setIsoTransform = function ( elem, name, value ) {
 | |
|           // unpack current transform data
 | |
|       var data =  $.data( elem, 'isoTransform' ) || {},
 | |
|           newData = {},
 | |
|           fnName,
 | |
|           transformObj = {},
 | |
|           transformValue;
 | |
| 
 | |
|       // i.e. newData.scale = 0.5
 | |
|       newData[ name ] = value;
 | |
|       // extend new value over current data
 | |
|       $.extend( data, newData );
 | |
| 
 | |
|       for ( fnName in data ) {
 | |
|         transformValue = data[ fnName ];
 | |
|         transformObj[ fnName ] = transformFnNotations[ fnName ]( transformValue );
 | |
|       }
 | |
| 
 | |
|       // get proper order
 | |
|       // ideally, we could loop through this give an array, but since we only have
 | |
|       // a couple transforms we're keeping track of, we'll do it like so
 | |
|       var translateFn = transformObj.translate || '',
 | |
|           scaleFn = transformObj.scale || '',
 | |
|           // sorting so translate always comes first
 | |
|           valueFns = translateFn + scaleFn;
 | |
| 
 | |
|       // set data back in elem
 | |
|       $.data( elem, 'isoTransform', data );
 | |
| 
 | |
|       // set name to vendor specific property
 | |
|       elem.style[ transformProp ] = valueFns;
 | |
|     };
 | |
| 
 | |
|     // ==================== scale ===================
 | |
| 
 | |
|     $.cssNumber.scale = true;
 | |
| 
 | |
|     $.cssHooks.scale = {
 | |
|       set: function( elem, value ) {
 | |
|         // uncomment this bit if you want to properly parse strings
 | |
|         // if ( typeof value === 'string' ) {
 | |
|         //   value = parseFloat( value );
 | |
|         // }
 | |
|         setIsoTransform( elem, 'scale', value );
 | |
|       },
 | |
|       get: function( elem, computed ) {
 | |
|         var transform = $.data( elem, 'isoTransform' );
 | |
|         return transform && transform.scale ? transform.scale : 1;
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     $.fx.step.scale = function( fx ) {
 | |
|       $.cssHooks.scale.set( fx.elem, fx.now+fx.unit );
 | |
|     };
 | |
| 
 | |
| 
 | |
|     // ==================== translate ===================
 | |
| 
 | |
|     $.cssNumber.translate = true;
 | |
| 
 | |
|     $.cssHooks.translate = {
 | |
|       set: function( elem, value ) {
 | |
| 
 | |
|         // uncomment this bit if you want to properly parse strings
 | |
|         // if ( typeof value === 'string' ) {
 | |
|         //   value = value.split(' ');
 | |
|         // }
 | |
|         //
 | |
|         // var i, val;
 | |
|         // for ( i = 0; i < 2; i++ ) {
 | |
|         //   val = value[i];
 | |
|         //   if ( typeof val === 'string' ) {
 | |
|         //     val = parseInt( val );
 | |
|         //   }
 | |
|         // }
 | |
| 
 | |
|         setIsoTransform( elem, 'translate', value );
 | |
|       },
 | |
| 
 | |
|       get: function( elem, computed ) {
 | |
|         var transform = $.data( elem, 'isoTransform' );
 | |
|         return transform && transform.translate ? transform.translate : [ 0, 0 ];
 | |
|       }
 | |
|     };
 | |
| 
 | |
|   }
 | |
| 
 | |
|   // ========================= get transition-end event ===============================
 | |
|   var transitionEndEvent, transitionDurProp;
 | |
| 
 | |
|   if ( Modernizr.csstransitions ) {
 | |
|     transitionEndEvent = {
 | |
|       WebkitTransitionProperty: 'webkitTransitionEnd',  // webkit
 | |
|       MozTransitionProperty: 'transitionend',
 | |
|       OTransitionProperty: 'oTransitionEnd otransitionend',
 | |
|       transitionProperty: 'transitionend'
 | |
|     }[ transitionProp ];
 | |
| 
 | |
|     transitionDurProp = getStyleProperty('transitionDuration');
 | |
|   }
 | |
| 
 | |
|   // ========================= smartresize ===============================
 | |
| 
 | |
|   /*
 | |
|    * smartresize: debounced resize event for jQuery
 | |
|    *
 | |
|    * latest version and complete README available on Github:
 | |
|    * https://github.com/louisremi/jquery.smartresize.js
 | |
|    *
 | |
|    * Copyright 2011 @louis_remi
 | |
|    * Licensed under the MIT license.
 | |
|    */
 | |
| 
 | |
|   var $event = $.event,
 | |
|       dispatchMethod = $.event.handle ? 'handle' : 'dispatch',
 | |
|       resizeTimeout;
 | |
| 
 | |
|   $event.special.smartresize = {
 | |
|     setup: function() {
 | |
|       $(this).bind( "resize", $event.special.smartresize.handler );
 | |
|     },
 | |
|     teardown: function() {
 | |
|       $(this).unbind( "resize", $event.special.smartresize.handler );
 | |
|     },
 | |
|     handler: function( event, execAsap ) {
 | |
|       // Save the context
 | |
|       var context = this,
 | |
|           args = arguments;
 | |
| 
 | |
|       // set correct event type
 | |
|       event.type = "smartresize";
 | |
| 
 | |
|       if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
 | |
|       resizeTimeout = setTimeout(function() {
 | |
|         $event[ dispatchMethod ].apply( context, args );
 | |
|       }, execAsap === "execAsap"? 0 : 100 );
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   $.fn.smartresize = function( fn ) {
 | |
|     return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
 | |
|   };
 | |
| 
 | |
| 
 | |
| 
 | |
| // ========================= Isotope ===============================
 | |
| 
 | |
| 
 | |
|   // our "Widget" object constructor
 | |
|   $.Isotope = function( options, element, callback ){
 | |
|     this.element = $( element );
 | |
| 
 | |
|     this._create( options );
 | |
|     this._init( callback );
 | |
|   };
 | |
| 
 | |
|   // styles of container element we want to keep track of
 | |
|   var isoContainerStyles = [ 'width', 'height' ];
 | |
| 
 | |
|   var $window = $(window);
 | |
| 
 | |
|   $.Isotope.settings = {
 | |
|     resizable: true,
 | |
|     layoutMode : 'masonry',
 | |
|     containerClass : 'isotope',
 | |
|     itemClass : 'isotope-item',
 | |
|     hiddenClass : 'isotope-hidden',
 | |
|     hiddenStyle: { opacity: 0, scale: 0.001 },
 | |
|     visibleStyle: { opacity: 1, scale: 1 },
 | |
|     containerStyle: {
 | |
|       position: 'relative',
 | |
|       overflow: 'hidden'
 | |
|     },
 | |
|     animationEngine: 'best-available',
 | |
|     animationOptions: {
 | |
|       queue: false,
 | |
|       duration: 800
 | |
|     },
 | |
|     sortBy : 'original-order',
 | |
|     sortAscending : true,
 | |
|     resizesContainer : true,
 | |
|     transformsEnabled: true,
 | |
|     itemPositionDataEnabled: false
 | |
|   };
 | |
| 
 | |
|   $.Isotope.prototype = {
 | |
| 
 | |
|     // sets up widget
 | |
|     _create : function( options ) {
 | |
| 
 | |
|       this.options = $.extend( {}, $.Isotope.settings, options );
 | |
| 
 | |
|       this.styleQueue = [];
 | |
|       this.elemCount = 0;
 | |
| 
 | |
|       // get original styles in case we re-apply them in .destroy()
 | |
|       var elemStyle = this.element[0].style;
 | |
|       this.originalStyle = {};
 | |
|       // keep track of container styles
 | |
|       var containerStyles = isoContainerStyles.slice(0);
 | |
|       for ( var prop in this.options.containerStyle ) {
 | |
|         containerStyles.push( prop );
 | |
|       }
 | |
|       for ( var i=0, len = containerStyles.length; i < len; i++ ) {
 | |
|         prop = containerStyles[i];
 | |
|         this.originalStyle[ prop ] = elemStyle[ prop ] || '';
 | |
|       }
 | |
|       // apply container style from options
 | |
|       this.element.css( this.options.containerStyle );
 | |
| 
 | |
|       this._updateAnimationEngine();
 | |
|       this._updateUsingTransforms();
 | |
| 
 | |
|       // sorting
 | |
|       var originalOrderSorter = {
 | |
|         'original-order' : function( $elem, instance ) {
 | |
|           instance.elemCount ++;
 | |
|           return instance.elemCount;
 | |
|         },
 | |
|         random : function() {
 | |
|           return Math.random();
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       this.options.getSortData = $.extend( this.options.getSortData, originalOrderSorter );
 | |
| 
 | |
|       // need to get atoms
 | |
|       this.reloadItems();
 | |
| 
 | |
|       // get top left position of where the bricks should be
 | |
|       this.offset = {
 | |
|         left: parseInt( ( this.element.css('padding-left') || 0 ), 10 ),
 | |
|         top: parseInt( ( this.element.css('padding-top') || 0 ), 10 )
 | |
|       };
 | |
| 
 | |
|       // add isotope class first time around
 | |
|       var instance = this;
 | |
|       setTimeout( function() {
 | |
|         instance.element.addClass( instance.options.containerClass );
 | |
|       }, 0 );
 | |
| 
 | |
|       // bind resize method
 | |
|       if ( this.options.resizable ) {
 | |
|         $window.bind( 'smartresize.isotope', function() {
 | |
|           instance.resize();
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       // dismiss all click events from hidden events
 | |
|       this.element.delegate( '.' + this.options.hiddenClass, 'click', function(){
 | |
|         return false;
 | |
|       });
 | |
| 
 | |
|     },
 | |
| 
 | |
|     _getAtoms : function( $elems ) {
 | |
|       var selector = this.options.itemSelector,
 | |
|           // filter & find
 | |
|           $atoms = selector ? $elems.filter( selector ).add( $elems.find( selector ) ) : $elems,
 | |
|           // base style for atoms
 | |
|           atomStyle = { position: 'absolute' };
 | |
| 
 | |
|       // filter out text nodes
 | |
|       $atoms = $atoms.filter( function( i, atom ) {
 | |
|         return atom.nodeType === 1;
 | |
|       });
 | |
| 
 | |
|       if ( this.usingTransforms ) {
 | |
|         atomStyle.left = 0;
 | |
|         atomStyle.top = 0;
 | |
|       }
 | |
| 
 | |
|       $atoms.css( atomStyle ).addClass( this.options.itemClass );
 | |
| 
 | |
|       this.updateSortData( $atoms, true );
 | |
| 
 | |
|       return $atoms;
 | |
|     },
 | |
| 
 | |
|     // _init fires when your instance is first created
 | |
|     // (from the constructor above), and when you
 | |
|     // attempt to initialize the widget again (by the bridge)
 | |
|     // after it has already been initialized.
 | |
|     _init : function( callback ) {
 | |
| 
 | |
|       this.$filteredAtoms = this._filter( this.$allAtoms );
 | |
|       this._sort();
 | |
|       this.reLayout( callback );
 | |
| 
 | |
|     },
 | |
| 
 | |
|     option : function( opts ){
 | |
|       // change options AFTER initialization:
 | |
|       // signature: $('#foo').bar({ cool:false });
 | |
|       if ( $.isPlainObject( opts ) ){
 | |
|         this.options = $.extend( true, this.options, opts );
 | |
| 
 | |
|         // trigger _updateOptionName if it exists
 | |
|         var updateOptionFn;
 | |
|         for ( var optionName in opts ) {
 | |
|           updateOptionFn = '_update' + capitalize( optionName );
 | |
|           if ( this[ updateOptionFn ] ) {
 | |
|             this[ updateOptionFn ]();
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     // ====================== updaters ====================== //
 | |
|     // kind of like setters
 | |
| 
 | |
|     _updateAnimationEngine : function() {
 | |
|       var animationEngine = this.options.animationEngine.toLowerCase().replace( /[ _\-]/g, '');
 | |
|       var isUsingJQueryAnimation;
 | |
|       // set applyStyleFnName
 | |
|       switch ( animationEngine ) {
 | |
|         case 'css' :
 | |
|         case 'none' :
 | |
|           isUsingJQueryAnimation = false;
 | |
|           break;
 | |
|         case 'jquery' :
 | |
|           isUsingJQueryAnimation = true;
 | |
|           break;
 | |
|         default : // best available
 | |
|           isUsingJQueryAnimation = !Modernizr.csstransitions;
 | |
|       }
 | |
|       this.isUsingJQueryAnimation = isUsingJQueryAnimation;
 | |
|       this._updateUsingTransforms();
 | |
|     },
 | |
| 
 | |
|     _updateTransformsEnabled : function() {
 | |
|       this._updateUsingTransforms();
 | |
|     },
 | |
| 
 | |
|     _updateUsingTransforms : function() {
 | |
|       var usingTransforms = this.usingTransforms = this.options.transformsEnabled &&
 | |
|         Modernizr.csstransforms && Modernizr.csstransitions && !this.isUsingJQueryAnimation;
 | |
| 
 | |
|       // prevent scales when transforms are disabled
 | |
|       if ( !usingTransforms ) {
 | |
|         delete this.options.hiddenStyle.scale;
 | |
|         delete this.options.visibleStyle.scale;
 | |
|       }
 | |
| 
 | |
|       this.getPositionStyles = usingTransforms ? this._translate : this._positionAbs;
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== Filtering ======================
 | |
| 
 | |
|     _filter : function( $atoms ) {
 | |
|       var filter = this.options.filter === '' ? '*' : this.options.filter;
 | |
| 
 | |
|       if ( !filter ) {
 | |
|         return $atoms;
 | |
|       }
 | |
| 
 | |
|       var hiddenClass    = this.options.hiddenClass,
 | |
|           hiddenSelector = '.' + hiddenClass,
 | |
|           $hiddenAtoms   = $atoms.filter( hiddenSelector ),
 | |
|           $atomsToShow   = $hiddenAtoms;
 | |
| 
 | |
|       if ( filter !== '*' ) {
 | |
|         $atomsToShow = $hiddenAtoms.filter( filter );
 | |
|         var $atomsToHide = $atoms.not( hiddenSelector ).not( filter ).addClass( hiddenClass );
 | |
|         this.styleQueue.push({ $el: $atomsToHide, style: this.options.hiddenStyle });
 | |
|       }
 | |
| 
 | |
|       this.styleQueue.push({ $el: $atomsToShow, style: this.options.visibleStyle });
 | |
|       $atomsToShow.removeClass( hiddenClass );
 | |
| 
 | |
|       return $atoms.filter( filter );
 | |
|     },
 | |
| 
 | |
|     // ====================== Sorting ======================
 | |
| 
 | |
|     updateSortData : function( $atoms, isIncrementingElemCount ) {
 | |
|       var instance = this,
 | |
|           getSortData = this.options.getSortData,
 | |
|           $this, sortData;
 | |
|       $atoms.each(function(){
 | |
|         $this = $(this);
 | |
|         sortData = {};
 | |
|         // get value for sort data based on fn( $elem ) passed in
 | |
|         for ( var key in getSortData ) {
 | |
|           if ( !isIncrementingElemCount && key === 'original-order' ) {
 | |
|             // keep original order original
 | |
|             sortData[ key ] = $.data( this, 'isotope-sort-data' )[ key ];
 | |
|           } else {
 | |
|             sortData[ key ] = getSortData[ key ]( $this, instance );
 | |
|           }
 | |
|         }
 | |
|         // apply sort data to element
 | |
|         $.data( this, 'isotope-sort-data', sortData );
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     // used on all the filtered atoms
 | |
|     _sort : function() {
 | |
| 
 | |
|       var sortBy = this.options.sortBy,
 | |
|           getSorter = this._getSorter,
 | |
|           sortDir = this.options.sortAscending ? 1 : -1,
 | |
|           sortFn = function( alpha, beta ) {
 | |
|             var a = getSorter( alpha, sortBy ),
 | |
|                 b = getSorter( beta, sortBy );
 | |
|             // fall back to original order if data matches
 | |
|             if ( a === b && sortBy !== 'original-order') {
 | |
|               a = getSorter( alpha, 'original-order' );
 | |
|               b = getSorter( beta, 'original-order' );
 | |
|             }
 | |
|             return ( ( a > b ) ? 1 : ( a < b ) ? -1 : 0 ) * sortDir;
 | |
|           };
 | |
| 
 | |
|       this.$filteredAtoms.sort( sortFn );
 | |
|     },
 | |
| 
 | |
|     _getSorter : function( elem, sortBy ) {
 | |
|       return $.data( elem, 'isotope-sort-data' )[ sortBy ];
 | |
|     },
 | |
| 
 | |
|     // ====================== Layout Helpers ======================
 | |
| 
 | |
|     _translate : function( x, y ) {
 | |
|       return { translate : [ x, y ] };
 | |
|     },
 | |
| 
 | |
|     _positionAbs : function( x, y ) {
 | |
|       return { left: x, top: y };
 | |
|     },
 | |
| 
 | |
|     _pushPosition : function( $elem, x, y ) {
 | |
|       x = Math.round( x + this.offset.left );
 | |
|       y = Math.round( y + this.offset.top );
 | |
|       var position = this.getPositionStyles( x, y );
 | |
|       this.styleQueue.push({ $el: $elem, style: position });
 | |
|       if ( this.options.itemPositionDataEnabled ) {
 | |
|         $elem.data('isotope-item-position', {x: x, y: y} );
 | |
|       }
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== General Layout ======================
 | |
| 
 | |
|     // used on collection of atoms (should be filtered, and sorted before )
 | |
|     // accepts atoms-to-be-laid-out to start with
 | |
|     layout : function( $elems, callback ) {
 | |
| 
 | |
|       var layoutMode = this.options.layoutMode;
 | |
| 
 | |
|       // layout logic
 | |
|       this[ '_' +  layoutMode + 'Layout' ]( $elems );
 | |
| 
 | |
|       // set the size of the container
 | |
|       if ( this.options.resizesContainer ) {
 | |
|         var containerStyle = this[ '_' +  layoutMode + 'GetContainerSize' ]();
 | |
|         this.styleQueue.push({ $el: this.element, style: containerStyle });
 | |
|       }
 | |
| 
 | |
|       this._processStyleQueue( $elems, callback );
 | |
| 
 | |
|       this.isLaidOut = true;
 | |
|     },
 | |
| 
 | |
|     _processStyleQueue : function( $elems, callback ) {
 | |
|       // are we animating the layout arrangement?
 | |
|       // use plugin-ish syntax for css or animate
 | |
|       var styleFn = !this.isLaidOut ? 'css' : (
 | |
|             this.isUsingJQueryAnimation ? 'animate' : 'css'
 | |
|           ),
 | |
|           animOpts = this.options.animationOptions,
 | |
|           onLayout = this.options.onLayout,
 | |
|           objStyleFn, processor,
 | |
|           triggerCallbackNow, callbackFn;
 | |
| 
 | |
|       // default styleQueue processor, may be overwritten down below
 | |
|       processor = function( i, obj ) {
 | |
|         obj.$el[ styleFn ]( obj.style, animOpts );
 | |
|       };
 | |
| 
 | |
|       if ( this._isInserting && this.isUsingJQueryAnimation ) {
 | |
|         // if using styleQueue to insert items
 | |
|         processor = function( i, obj ) {
 | |
|           // only animate if it not being inserted
 | |
|           objStyleFn = obj.$el.hasClass('no-transition') ? 'css' : styleFn;
 | |
|           obj.$el[ objStyleFn ]( obj.style, animOpts );
 | |
|         };
 | |
| 
 | |
|       } else if ( callback || onLayout || animOpts.complete ) {
 | |
|         // has callback
 | |
|         var isCallbackTriggered = false,
 | |
|             // array of possible callbacks to trigger
 | |
|             callbacks = [ callback, onLayout, animOpts.complete ],
 | |
|             instance = this;
 | |
|         triggerCallbackNow = true;
 | |
|         // trigger callback only once
 | |
|         callbackFn = function() {
 | |
|           if ( isCallbackTriggered ) {
 | |
|             return;
 | |
|           }
 | |
|           var hollaback;
 | |
|           for (var i=0, len = callbacks.length; i < len; i++) {
 | |
|             hollaback = callbacks[i];
 | |
|             if ( typeof hollaback === 'function' ) {
 | |
|               hollaback.call( instance.element, $elems, instance );
 | |
|             }
 | |
|           }
 | |
|           isCallbackTriggered = true;
 | |
|         };
 | |
| 
 | |
|         if ( this.isUsingJQueryAnimation && styleFn === 'animate' ) {
 | |
|           // add callback to animation options
 | |
|           animOpts.complete = callbackFn;
 | |
|           triggerCallbackNow = false;
 | |
| 
 | |
|         } else if ( Modernizr.csstransitions ) {
 | |
|           // detect if first item has transition
 | |
|           var i = 0,
 | |
|               firstItem = this.styleQueue[0],
 | |
|               testElem = firstItem && firstItem.$el,
 | |
|               styleObj;
 | |
|           // get first non-empty jQ object
 | |
|           while ( !testElem || !testElem.length ) {
 | |
|             styleObj = this.styleQueue[ i++ ];
 | |
|             // HACK: sometimes styleQueue[i] is undefined
 | |
|             if ( !styleObj ) {
 | |
|               return;
 | |
|             }
 | |
|             testElem = styleObj.$el;
 | |
|           }
 | |
|           // get transition duration of the first element in that object
 | |
|           // yeah, this is inexact
 | |
|           var duration = parseFloat( getComputedStyle( testElem[0] )[ transitionDurProp ] );
 | |
|           if ( duration > 0 ) {
 | |
|             processor = function( i, obj ) {
 | |
|               obj.$el[ styleFn ]( obj.style, animOpts )
 | |
|                 // trigger callback at transition end
 | |
|                 .one( transitionEndEvent, callbackFn );
 | |
|             };
 | |
|             triggerCallbackNow = false;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // process styleQueue
 | |
|       $.each( this.styleQueue, processor );
 | |
| 
 | |
|       if ( triggerCallbackNow ) {
 | |
|         callbackFn();
 | |
|       }
 | |
| 
 | |
|       // clear out queue for next time
 | |
|       this.styleQueue = [];
 | |
|     },
 | |
| 
 | |
| 
 | |
|     resize : function() {
 | |
|       if ( this[ '_' + this.options.layoutMode + 'ResizeChanged' ]() ) {
 | |
|         this.reLayout();
 | |
|       }
 | |
|     },
 | |
| 
 | |
| 
 | |
|     reLayout : function( callback ) {
 | |
| 
 | |
|       this[ '_' +  this.options.layoutMode + 'Reset' ]();
 | |
|       this.layout( this.$filteredAtoms, callback );
 | |
| 
 | |
|     },
 | |
| 
 | |
|     // ====================== Convenience methods ======================
 | |
| 
 | |
|     // ====================== Adding items ======================
 | |
| 
 | |
|     // adds a jQuery object of items to a isotope container
 | |
|     addItems : function( $content, callback ) {
 | |
|       var $newAtoms = this._getAtoms( $content );
 | |
|       // add new atoms to atoms pools
 | |
|       this.$allAtoms = this.$allAtoms.add( $newAtoms );
 | |
| 
 | |
|       if ( callback ) {
 | |
|         callback( $newAtoms );
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     // convienence method for adding elements properly to any layout
 | |
|     // positions items, hides them, then animates them back in <--- very sezzy
 | |
|     insert : function( $content, callback ) {
 | |
|       // position items
 | |
|       this.element.append( $content );
 | |
| 
 | |
|       var instance = this;
 | |
|       this.addItems( $content, function( $newAtoms ) {
 | |
|         var $newFilteredAtoms = instance._filter( $newAtoms );
 | |
|         instance._addHideAppended( $newFilteredAtoms );
 | |
|         instance._sort();
 | |
|         instance.reLayout();
 | |
|         instance._revealAppended( $newFilteredAtoms, callback );
 | |
|       });
 | |
| 
 | |
|     },
 | |
| 
 | |
|     // convienence method for working with Infinite Scroll
 | |
|     appended : function( $content, callback ) {
 | |
|       var instance = this;
 | |
|       this.addItems( $content, function( $newAtoms ) {
 | |
|         instance._addHideAppended( $newAtoms );
 | |
|         instance.layout( $newAtoms );
 | |
|         instance._revealAppended( $newAtoms, callback );
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     // adds new atoms, then hides them before positioning
 | |
|     _addHideAppended : function( $newAtoms ) {
 | |
|       this.$filteredAtoms = this.$filteredAtoms.add( $newAtoms );
 | |
|       $newAtoms.addClass('no-transition');
 | |
| 
 | |
|       this._isInserting = true;
 | |
| 
 | |
|       // apply hidden styles
 | |
|       this.styleQueue.push({ $el: $newAtoms, style: this.options.hiddenStyle });
 | |
|     },
 | |
| 
 | |
|     // sets visible style on new atoms
 | |
|     _revealAppended : function( $newAtoms, callback ) {
 | |
|       var instance = this;
 | |
|       // apply visible style after a sec
 | |
|       setTimeout( function() {
 | |
|         // enable animation
 | |
|         $newAtoms.removeClass('no-transition');
 | |
|         // reveal newly inserted filtered elements
 | |
|         instance.styleQueue.push({ $el: $newAtoms, style: instance.options.visibleStyle });
 | |
|         instance._isInserting = false;
 | |
|         instance._processStyleQueue( $newAtoms, callback );
 | |
|       }, 10 );
 | |
|     },
 | |
| 
 | |
|     // gathers all atoms
 | |
|     reloadItems : function() {
 | |
|       this.$allAtoms = this._getAtoms( this.element.children() );
 | |
|     },
 | |
| 
 | |
|     // removes elements from Isotope widget
 | |
|     remove: function( $content, callback ) {
 | |
|       // remove elements immediately from Isotope instance
 | |
|       this.$allAtoms = this.$allAtoms.not( $content );
 | |
|       this.$filteredAtoms = this.$filteredAtoms.not( $content );
 | |
|       // remove() as a callback, for after transition / animation
 | |
|       var instance = this;
 | |
|       var removeContent = function() {
 | |
|         $content.remove();
 | |
|         if ( callback ) {
 | |
|           callback.call( instance.element );
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       if ( $content.filter( ':not(.' + this.options.hiddenClass + ')' ).length ) {
 | |
|         // if any non-hidden content needs to be removed
 | |
|         this.styleQueue.push({ $el: $content, style: this.options.hiddenStyle });
 | |
|         this._sort();
 | |
|         this.reLayout( removeContent );
 | |
|       } else {
 | |
|         // remove it now
 | |
|         removeContent();
 | |
|       }
 | |
| 
 | |
|     },
 | |
| 
 | |
|     shuffle : function( callback ) {
 | |
|       this.updateSortData( this.$allAtoms );
 | |
|       this.options.sortBy = 'random';
 | |
|       this._sort();
 | |
|       this.reLayout( callback );
 | |
|     },
 | |
| 
 | |
|     // destroys widget, returns elements and container back (close) to original style
 | |
|     destroy : function() {
 | |
| 
 | |
|       var usingTransforms = this.usingTransforms;
 | |
|       var options = this.options;
 | |
| 
 | |
|       this.$allAtoms
 | |
|         .removeClass( options.hiddenClass + ' ' + options.itemClass )
 | |
|         .each(function(){
 | |
|           var style = this.style;
 | |
|           style.position = '';
 | |
|           style.top = '';
 | |
|           style.left = '';
 | |
|           style.opacity = '';
 | |
|           if ( usingTransforms ) {
 | |
|             style[ transformProp ] = '';
 | |
|           }
 | |
|         });
 | |
| 
 | |
|       // re-apply saved container styles
 | |
|       var elemStyle = this.element[0].style;
 | |
|       for ( var prop in this.originalStyle ) {
 | |
|         elemStyle[ prop ] = this.originalStyle[ prop ];
 | |
|       }
 | |
| 
 | |
|       this.element
 | |
|         .unbind('.isotope')
 | |
|         .undelegate( '.' + options.hiddenClass, 'click' )
 | |
|         .removeClass( options.containerClass )
 | |
|         .removeData('isotope');
 | |
| 
 | |
|       $window.unbind('.isotope');
 | |
| 
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== LAYOUTS ======================
 | |
| 
 | |
|     // calculates number of rows or columns
 | |
|     // requires columnWidth or rowHeight to be set on namespaced object
 | |
|     // i.e. this.masonry.columnWidth = 200
 | |
|     _getSegments : function( isRows ) {
 | |
|       var namespace = this.options.layoutMode,
 | |
|           measure  = isRows ? 'rowHeight' : 'columnWidth',
 | |
|           size     = isRows ? 'height' : 'width',
 | |
|           segmentsName = isRows ? 'rows' : 'cols',
 | |
|           containerSize = this.element[ size ](),
 | |
|           segments,
 | |
|                     // i.e. options.masonry && options.masonry.columnWidth
 | |
|           segmentSize = this.options[ namespace ] && this.options[ namespace ][ measure ] ||
 | |
|                     // or use the size of the first item, i.e. outerWidth
 | |
|                     this.$filteredAtoms[ 'outer' + capitalize(size) ](true) ||
 | |
|                     // if there's no items, use size of container
 | |
|                     containerSize;
 | |
| 
 | |
|       segments = Math.floor( containerSize / segmentSize );
 | |
|       segments = Math.max( segments, 1 );
 | |
| 
 | |
|       // i.e. this.masonry.cols = ....
 | |
|       this[ namespace ][ segmentsName ] = segments;
 | |
|       // i.e. this.masonry.columnWidth = ...
 | |
|       this[ namespace ][ measure ] = segmentSize;
 | |
| 
 | |
|     },
 | |
| 
 | |
|     _checkIfSegmentsChanged : function( isRows ) {
 | |
|       var namespace = this.options.layoutMode,
 | |
|           segmentsName = isRows ? 'rows' : 'cols',
 | |
|           prevSegments = this[ namespace ][ segmentsName ];
 | |
|       // update cols/rows
 | |
|       this._getSegments( isRows );
 | |
|       // return if updated cols/rows is not equal to previous
 | |
|       return ( this[ namespace ][ segmentsName ] !== prevSegments );
 | |
|     },
 | |
| 
 | |
|     // ====================== Masonry ======================
 | |
| 
 | |
|     _masonryReset : function() {
 | |
|       // layout-specific props
 | |
|       this.masonry = {};
 | |
|       // FIXME shouldn't have to call this again
 | |
|       this._getSegments();
 | |
|       var i = this.masonry.cols;
 | |
|       this.masonry.colYs = [];
 | |
|       while (i--) {
 | |
|         this.masonry.colYs.push( 0 );
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     _masonryLayout : function( $elems ) {
 | |
|       var instance = this,
 | |
|           props = instance.masonry;
 | |
|       $elems.each(function(){
 | |
|         var $this  = $(this),
 | |
|             //how many columns does this brick span
 | |
|             colSpan = Math.ceil( $this.outerWidth(true) / props.columnWidth );
 | |
|         colSpan = Math.min( colSpan, props.cols );
 | |
| 
 | |
|         if ( colSpan === 1 ) {
 | |
|           // if brick spans only one column, just like singleMode
 | |
|           instance._masonryPlaceBrick( $this, props.colYs );
 | |
|         } else {
 | |
|           // brick spans more than one column
 | |
|           // how many different places could this brick fit horizontally
 | |
|           var groupCount = props.cols + 1 - colSpan,
 | |
|               groupY = [],
 | |
|               groupColY,
 | |
|               i;
 | |
| 
 | |
|           // for each group potential horizontal position
 | |
|           for ( i=0; i < groupCount; i++ ) {
 | |
|             // make an array of colY values for that one group
 | |
|             groupColY = props.colYs.slice( i, i+colSpan );
 | |
|             // and get the max value of the array
 | |
|             groupY[i] = Math.max.apply( Math, groupColY );
 | |
|           }
 | |
| 
 | |
|           instance._masonryPlaceBrick( $this, groupY );
 | |
|         }
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     // worker method that places brick in the columnSet
 | |
|     //   with the the minY
 | |
|     _masonryPlaceBrick : function( $brick, setY ) {
 | |
|       // get the minimum Y value from the columns
 | |
|       var minimumY = Math.min.apply( Math, setY ),
 | |
|           shortCol = 0;
 | |
| 
 | |
|       // Find index of short column, the first from the left
 | |
|       for (var i=0, len = setY.length; i < len; i++) {
 | |
|         if ( setY[i] === minimumY ) {
 | |
|           shortCol = i;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // position the brick
 | |
|       var x = this.masonry.columnWidth * shortCol,
 | |
|           y = minimumY;
 | |
|       this._pushPosition( $brick, x, y );
 | |
| 
 | |
|       // apply setHeight to necessary columns
 | |
|       var setHeight = minimumY + $brick.outerHeight(true),
 | |
|           setSpan = this.masonry.cols + 1 - len;
 | |
|       for ( i=0; i < setSpan; i++ ) {
 | |
|         this.masonry.colYs[ shortCol + i ] = setHeight;
 | |
|       }
 | |
| 
 | |
|     },
 | |
| 
 | |
|     _masonryGetContainerSize : function() {
 | |
|       var containerHeight = Math.max.apply( Math, this.masonry.colYs );
 | |
|       return { height: containerHeight };
 | |
|     },
 | |
| 
 | |
|     _masonryResizeChanged : function() {
 | |
|       return this._checkIfSegmentsChanged();
 | |
|     },
 | |
| 
 | |
|     // ====================== fitRows ======================
 | |
| 
 | |
|     _fitRowsReset : function() {
 | |
|       this.fitRows = {
 | |
|         x : 0,
 | |
|         y : 0,
 | |
|         height : 0
 | |
|       };
 | |
|     },
 | |
| 
 | |
|     _fitRowsLayout : function( $elems ) {
 | |
|       var instance = this,
 | |
|           containerWidth = this.element.width(),
 | |
|           props = this.fitRows;
 | |
| 
 | |
|       $elems.each( function() {
 | |
|         var $this = $(this),
 | |
|             atomW = $this.outerWidth(true),
 | |
|             atomH = $this.outerHeight(true);
 | |
| 
 | |
|         if ( props.x !== 0 && atomW + props.x > containerWidth ) {
 | |
|           // if this element cannot fit in the current row
 | |
|           props.x = 0;
 | |
|           props.y = props.height;
 | |
|         }
 | |
| 
 | |
|         // position the atom
 | |
|         instance._pushPosition( $this, props.x, props.y );
 | |
| 
 | |
|         props.height = Math.max( props.y + atomH, props.height );
 | |
|         props.x += atomW;
 | |
| 
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _fitRowsGetContainerSize : function () {
 | |
|       return { height : this.fitRows.height };
 | |
|     },
 | |
| 
 | |
|     _fitRowsResizeChanged : function() {
 | |
|       return true;
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== cellsByRow ======================
 | |
| 
 | |
|     _cellsByRowReset : function() {
 | |
|       this.cellsByRow = {
 | |
|         index : 0
 | |
|       };
 | |
|       // get this.cellsByRow.columnWidth
 | |
|       this._getSegments();
 | |
|       // get this.cellsByRow.rowHeight
 | |
|       this._getSegments(true);
 | |
|     },
 | |
| 
 | |
|     _cellsByRowLayout : function( $elems ) {
 | |
|       var instance = this,
 | |
|           props = this.cellsByRow;
 | |
|       $elems.each( function(){
 | |
|         var $this = $(this),
 | |
|             col = props.index % props.cols,
 | |
|             row = Math.floor( props.index / props.cols ),
 | |
|             x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
 | |
|             y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
 | |
|         instance._pushPosition( $this, x, y );
 | |
|         props.index ++;
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _cellsByRowGetContainerSize : function() {
 | |
|       return { height : Math.ceil( this.$filteredAtoms.length / this.cellsByRow.cols ) * this.cellsByRow.rowHeight + this.offset.top };
 | |
|     },
 | |
| 
 | |
|     _cellsByRowResizeChanged : function() {
 | |
|       return this._checkIfSegmentsChanged();
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== straightDown ======================
 | |
| 
 | |
|     _straightDownReset : function() {
 | |
|       this.straightDown = {
 | |
|         y : 0
 | |
|       };
 | |
|     },
 | |
| 
 | |
|     _straightDownLayout : function( $elems ) {
 | |
|       var instance = this;
 | |
|       $elems.each( function( i ){
 | |
|         var $this = $(this);
 | |
|         instance._pushPosition( $this, 0, instance.straightDown.y );
 | |
|         instance.straightDown.y += $this.outerHeight(true);
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _straightDownGetContainerSize : function() {
 | |
|       return { height : this.straightDown.y };
 | |
|     },
 | |
| 
 | |
|     _straightDownResizeChanged : function() {
 | |
|       return true;
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== masonryHorizontal ======================
 | |
| 
 | |
|     _masonryHorizontalReset : function() {
 | |
|       // layout-specific props
 | |
|       this.masonryHorizontal = {};
 | |
|       // FIXME shouldn't have to call this again
 | |
|       this._getSegments( true );
 | |
|       var i = this.masonryHorizontal.rows;
 | |
|       this.masonryHorizontal.rowXs = [];
 | |
|       while (i--) {
 | |
|         this.masonryHorizontal.rowXs.push( 0 );
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     _masonryHorizontalLayout : function( $elems ) {
 | |
|       var instance = this,
 | |
|           props = instance.masonryHorizontal;
 | |
|       $elems.each(function(){
 | |
|         var $this  = $(this),
 | |
|             //how many rows does this brick span
 | |
|             rowSpan = Math.ceil( $this.outerHeight(true) / props.rowHeight );
 | |
|         rowSpan = Math.min( rowSpan, props.rows );
 | |
| 
 | |
|         if ( rowSpan === 1 ) {
 | |
|           // if brick spans only one column, just like singleMode
 | |
|           instance._masonryHorizontalPlaceBrick( $this, props.rowXs );
 | |
|         } else {
 | |
|           // brick spans more than one row
 | |
|           // how many different places could this brick fit horizontally
 | |
|           var groupCount = props.rows + 1 - rowSpan,
 | |
|               groupX = [],
 | |
|               groupRowX, i;
 | |
| 
 | |
|           // for each group potential horizontal position
 | |
|           for ( i=0; i < groupCount; i++ ) {
 | |
|             // make an array of colY values for that one group
 | |
|             groupRowX = props.rowXs.slice( i, i+rowSpan );
 | |
|             // and get the max value of the array
 | |
|             groupX[i] = Math.max.apply( Math, groupRowX );
 | |
|           }
 | |
| 
 | |
|           instance._masonryHorizontalPlaceBrick( $this, groupX );
 | |
|         }
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _masonryHorizontalPlaceBrick : function( $brick, setX ) {
 | |
|       // get the minimum Y value from the columns
 | |
|       var minimumX  = Math.min.apply( Math, setX ),
 | |
|           smallRow  = 0;
 | |
|       // Find index of smallest row, the first from the top
 | |
|       for (var i=0, len = setX.length; i < len; i++) {
 | |
|         if ( setX[i] === minimumX ) {
 | |
|           smallRow = i;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // position the brick
 | |
|       var x = minimumX,
 | |
|           y = this.masonryHorizontal.rowHeight * smallRow;
 | |
|       this._pushPosition( $brick, x, y );
 | |
| 
 | |
|       // apply setHeight to necessary columns
 | |
|       var setWidth = minimumX + $brick.outerWidth(true),
 | |
|           setSpan = this.masonryHorizontal.rows + 1 - len;
 | |
|       for ( i=0; i < setSpan; i++ ) {
 | |
|         this.masonryHorizontal.rowXs[ smallRow + i ] = setWidth;
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     _masonryHorizontalGetContainerSize : function() {
 | |
|       var containerWidth = Math.max.apply( Math, this.masonryHorizontal.rowXs );
 | |
|       return { width: containerWidth };
 | |
|     },
 | |
| 
 | |
|     _masonryHorizontalResizeChanged : function() {
 | |
|       return this._checkIfSegmentsChanged(true);
 | |
|     },
 | |
| 
 | |
| 
 | |
|     // ====================== fitColumns ======================
 | |
| 
 | |
|     _fitColumnsReset : function() {
 | |
|       this.fitColumns = {
 | |
|         x : 0,
 | |
|         y : 0,
 | |
|         width : 0
 | |
|       };
 | |
|     },
 | |
| 
 | |
|     _fitColumnsLayout : function( $elems ) {
 | |
|       var instance = this,
 | |
|           containerHeight = this.element.height(),
 | |
|           props = this.fitColumns;
 | |
|       $elems.each( function() {
 | |
|         var $this = $(this),
 | |
|             atomW = $this.outerWidth(true),
 | |
|             atomH = $this.outerHeight(true);
 | |
| 
 | |
|         if ( props.y !== 0 && atomH + props.y > containerHeight ) {
 | |
|           // if this element cannot fit in the current column
 | |
|           props.x = props.width;
 | |
|           props.y = 0;
 | |
|         }
 | |
| 
 | |
|         // position the atom
 | |
|         instance._pushPosition( $this, props.x, props.y );
 | |
| 
 | |
|         props.width = Math.max( props.x + atomW, props.width );
 | |
|         props.y += atomH;
 | |
| 
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _fitColumnsGetContainerSize : function () {
 | |
|       return { width : this.fitColumns.width };
 | |
|     },
 | |
| 
 | |
|     _fitColumnsResizeChanged : function() {
 | |
|       return true;
 | |
|     },
 | |
| 
 | |
| 
 | |
| 
 | |
|     // ====================== cellsByColumn ======================
 | |
| 
 | |
|     _cellsByColumnReset : function() {
 | |
|       this.cellsByColumn = {
 | |
|         index : 0
 | |
|       };
 | |
|       // get this.cellsByColumn.columnWidth
 | |
|       this._getSegments();
 | |
|       // get this.cellsByColumn.rowHeight
 | |
|       this._getSegments(true);
 | |
|     },
 | |
| 
 | |
|     _cellsByColumnLayout : function( $elems ) {
 | |
|       var instance = this,
 | |
|           props = this.cellsByColumn;
 | |
|       $elems.each( function(){
 | |
|         var $this = $(this),
 | |
|             col = Math.floor( props.index / props.rows ),
 | |
|             row = props.index % props.rows,
 | |
|             x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
 | |
|             y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
 | |
|         instance._pushPosition( $this, x, y );
 | |
|         props.index ++;
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _cellsByColumnGetContainerSize : function() {
 | |
|       return { width : Math.ceil( this.$filteredAtoms.length / this.cellsByColumn.rows ) * this.cellsByColumn.columnWidth };
 | |
|     },
 | |
| 
 | |
|     _cellsByColumnResizeChanged : function() {
 | |
|       return this._checkIfSegmentsChanged(true);
 | |
|     },
 | |
| 
 | |
|     // ====================== straightAcross ======================
 | |
| 
 | |
|     _straightAcrossReset : function() {
 | |
|       this.straightAcross = {
 | |
|         x : 0
 | |
|       };
 | |
|     },
 | |
| 
 | |
|     _straightAcrossLayout : function( $elems ) {
 | |
|       var instance = this;
 | |
|       $elems.each( function( i ){
 | |
|         var $this = $(this);
 | |
|         instance._pushPosition( $this, instance.straightAcross.x, 0 );
 | |
|         instance.straightAcross.x += $this.outerWidth(true);
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     _straightAcrossGetContainerSize : function() {
 | |
|       return { width : this.straightAcross.x };
 | |
|     },
 | |
| 
 | |
|     _straightAcrossResizeChanged : function() {
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|   };
 | |
| 
 | |
| 
 | |
|   // ======================= imagesLoaded Plugin ===============================
 | |
|   /*!
 | |
|    * jQuery imagesLoaded plugin v1.1.0
 | |
|    * http://github.com/desandro/imagesloaded
 | |
|    *
 | |
|    * MIT License. by Paul Irish et al.
 | |
|    */
 | |
| 
 | |
| 
 | |
|   // $('#my-container').imagesLoaded(myFunction)
 | |
|   // or
 | |
|   // $('img').imagesLoaded(myFunction)
 | |
| 
 | |
|   // execute a callback when all images have loaded.
 | |
|   // needed because .load() doesn't work on cached images
 | |
| 
 | |
|   // callback function gets image collection as argument
 | |
|   //  `this` is the container
 | |
| 
 | |
|   $.fn.imagesLoaded = function( callback ) {
 | |
|     var $this = this,
 | |
|         $images = $this.find('img').add( $this.filter('img') ),
 | |
|         len = $images.length,
 | |
|         blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==',
 | |
|         loaded = [];
 | |
| 
 | |
|     function triggerCallback() {
 | |
|       callback.call( $this, $images );
 | |
|     }
 | |
| 
 | |
|     function imgLoaded( event ) {
 | |
|       var img = event.target;
 | |
|       if ( img.src !== blank && $.inArray( img, loaded ) === -1 ){
 | |
|         loaded.push( img );
 | |
|         if ( --len <= 0 ){
 | |
|           setTimeout( triggerCallback );
 | |
|           $images.unbind( '.imagesLoaded', imgLoaded );
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if no images, trigger immediately
 | |
|     if ( !len ) {
 | |
|       triggerCallback();
 | |
|     }
 | |
| 
 | |
|     $images.bind( 'load.imagesLoaded error.imagesLoaded',  imgLoaded ).each( function() {
 | |
|       // cached images don't fire load sometimes, so we reset src.
 | |
|       var src = this.src;
 | |
|       // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
 | |
|       // data uri bypasses webkit log warning (thx doug jones)
 | |
|       this.src = blank;
 | |
|       this.src = src;
 | |
|     });
 | |
| 
 | |
|     return $this;
 | |
|   };
 | |
| 
 | |
| 
 | |
|   // helper function for logging errors
 | |
|   // $.error breaks jQuery chaining
 | |
|   var logError = function( message ) {
 | |
|     if ( window.console ) {
 | |
|       window.console.error( message );
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   // =======================  Plugin bridge  ===============================
 | |
|   // leverages data method to either create or return $.Isotope constructor
 | |
|   // A bit from jQuery UI
 | |
|   //   https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
 | |
|   // A bit from jcarousel
 | |
|   //   https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
 | |
| 
 | |
|   $.fn.isotope = function( options, callback ) {
 | |
|     if ( typeof options === 'string' ) {
 | |
|       // call method
 | |
|       var args = Array.prototype.slice.call( arguments, 1 );
 | |
| 
 | |
|       this.each(function(){
 | |
|         var instance = $.data( this, 'isotope' );
 | |
|         if ( !instance ) {
 | |
|           logError( "cannot call methods on isotope prior to initialization; " +
 | |
|               "attempted to call method '" + options + "'" );
 | |
|           return;
 | |
|         }
 | |
|         if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
 | |
|           logError( "no such method '" + options + "' for isotope instance" );
 | |
|           return;
 | |
|         }
 | |
|         // apply method
 | |
|         instance[ options ].apply( instance, args );
 | |
|       });
 | |
|     } else {
 | |
|       this.each(function() {
 | |
|         var instance = $.data( this, 'isotope' );
 | |
|         if ( instance ) {
 | |
|           // apply options & init
 | |
|           instance.option( options );
 | |
|           instance._init( callback );
 | |
|         } else {
 | |
|           // initialize new instance
 | |
|           $.data( this, 'isotope', new $.Isotope( options, this, callback ) );
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     // return jQuery object
 | |
|     // so plugin methods do not have to
 | |
|     return this;
 | |
|   };
 | |
| 
 | |
| })( window, jQuery ); |