| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356 | /** * Isotope v1.5.03 * An exquisite jQuery plugin for magical layouts * http://isotope.metafizzy.co * * Commercial use requires one-time license fee * http://metafizzy.co/#licenses * * Copyright 2011 David DeSandro / Metafizzy *//*jshint curly: true, eqeqeq: true, forin: false, immed: false, newcap: true, noempty: true, undef: true *//*global Modernizr: true, jQuery: true */(function( window, $, undefined ){  'use strict';  // 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 Khtml 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;    }  };  if ( window.Modernizr ) {    // if there's a previous Modernzir, check if there are necessary tests    for ( var 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    window.Modernizr = (function(){      var miniModernizr = {            _version : '1.6ish: miniModernizr for Isotope'          },          classes = ' ',          result, testName;      // Run through tests      for ( testName in tests) {        result = tests[ testName ]();        miniModernizr[ testName ] = result;        classes += ' ' + ( result ?  '' : 'no-' ) + testName;      }      // Add the new classes to the <html> element.      $('html').addClass( classes );      return miniModernizr;    })();  }  // ========================= 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',      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,      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() {        jQuery.event.handle.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 = [ 'overflow', 'position', 'width', 'height' ];    $.Isotope.settings = {    resizable: true,    layoutMode : 'masonry',    containerClass : 'isotope',    itemClass : 'isotope-item',    hiddenClass : 'isotope-hidden',    hiddenStyle : Modernizr.csstransforms && !$.browser.opera ?       { opacity : 0, scale : 0.001 } : // browsers support CSS transforms, not Opera      { opacity : 0 }, // other browsers, including Opera    visibleStyle : Modernizr.csstransforms && !$.browser.opera ?       { opacity : 1, scale : 1 } : // browsers support CSS transforms, not Opera      { opacity : 1 },  // other browsers, including Opera    animationEngine : $.browser.opera ? 'jquery' : '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 = {};      for ( var i=0, len = isoContainerStyles.length; i < len; i++ ) {        var prop = isoContainerStyles[i];        this.originalStyle[ prop ] = elemStyle[ prop ] || '';      }            this.element.css({        overflow : 'hidden',        position : 'relative'      });            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      var $cursor = $( document.createElement('div') ).prependTo( this.element );      this.offset = $cursor.position();      $cursor.remove();      // 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' };                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, '');      // set applyStyleFnName      switch ( animationEngine ) {        case 'css' :        case 'none' :          this.isUsingJQueryAnimation = false;          break;        case 'jquery' :          this.isUsingJQueryAnimation = true;          break;        default : // best available          this.isUsingJQueryAnimation = !Modernizr.csstransitions;      }            this._updateUsingTransforms();    },        _updateTransformsEnabled : function() {      this._updateUsingTransforms();    },        _updateUsingTransforms : function() {      this.usingTransforms = this.options.transformsEnabled && Modernizr.csstransforms && Modernizr.csstransitions && !this.isUsingJQueryAnimation;      this.getPositionStyles = this.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 += this.offset.left;      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,          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 ) {        // has callback        var isCallbackTriggered = false,            instance = this;        triggerCallbackNow = true;        // trigger callback only once        callbackFn = function() {          if ( isCallbackTriggered ) {            return;          }          callback.call( instance.element, $elems );          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,              testElem = this.styleQueue[0].$el,              styleObj;          // get first non-empty jQ object          while ( !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, true );        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 ) {      this.$allAtoms = this.$allAtoms.not( $content );      this.$filteredAtoms = this.$filteredAtoms.not( $content );      $content.remove();          },        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;      this.$allAtoms        .removeClass( this.options.hiddenClass + ' ' + this.options.itemClass )        .each(function(){          this.style.position = '';          this.style.top = '';          this.style.left = '';          this.style.opacity = '';          if ( usingTransforms ) {            this.style[ transformProp ] = '';          }        });            // re-apply saved container styles      var elemStyle = this.element[0].style;      for ( var i=0, len = isoContainerStyles.length; i < len; i++ ) {        var prop = isoContainerStyles[i];        elemStyle[ prop ] = this.originalStyle[ prop ];      }            this.element        .unbind('.isotope')        .undelegate( '.' + this.options.hiddenClass, 'click' )        .removeClass( this.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 = Math.round( ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2 ),            y = Math.round( ( 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 = Math.round( ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2 ),            y = Math.round( ( 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.0.3   * 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==';    function triggerCallback() {      callback.call( $this, $images );    }    function imgLoaded( event ) {      if ( --len <= 0 && event.target.src !== blank ){        setTimeout( triggerCallback );        $images.unbind( 'load error', imgLoaded );      }    }    if ( !len ) {      triggerCallback();    }    $images.bind( 'load error',  imgLoaded ).each( function() {      // cached images don't fire load sometimes, so we reset src.      if (this.complete || this.complete === undefined){        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 );
 |