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 );
|