PageSourceSearch

https://musicfolk.com/wp-content/themes/organic-natural/js/jquery.isotope.js?ver=20130729

js musicfolk.com collected 2026-09-25 23:54:04 UTC 43,330 bytes, 1,409 lines download raw bytes

1/**
2 * Isotope v1.5.25
3 * An exquisite jQuery plugin for magical layouts
4 * http://isotope.metafizzy.co
5 *
6 * Commercial use requires one-time purchase of a commercial license
7 * http://isotope.metafizzy.co/docs/license.html
8 *
9 * Non-commercial use is licensed under the MIT License
10 *
11 * Copyright 2013 Metafizzy
12 */
13
14/*jshint asi: true, browser: true, curly: true, eqeqeq: true, forin: false, immed: false, newcap: true, noempty: true, strict: true, undef: true */
15/*global jQuery: false */
16
17(function( window, $, undefined ){
18
19  'use strict';
20
21  // get global vars
22  var document = window.document;
23  var Modernizr = window.Modernizr;
24
25  // helper function
26  var capitalize = function( str ) {
27    return str.charAt(0).toUpperCase() + str.slice(1);
28  };
29
30  // ========================= getStyleProperty by kangax ===============================
31  // http://perfectionkills.com/feature-testing-css-properties/
32
33  var prefixes = 'Moz Webkit O Ms'.split(' ');
34
35  var getStyleProperty = function( propName ) {
36    var style = document.documentElement.style,
37        prefixed;
38
39    // test standard property first
40    if ( typeof style[propName] === 'string' ) {
41      return propName;
42    }
43
44    // capitalize
45    propName = capitalize( propName );
46
47    // test vendor specific properties
48    for ( var i=0, len = prefixes.length; i < len; i++ ) {
49      prefixed = prefixes[i] + propName;
50      if ( typeof style[ prefixed ] === 'string' ) {
51        return prefixed;
52      }
53    }
54  };
55
56  var transformProp = getStyleProperty('transform'),
57      transitionProp = getStyleProperty('transitionProperty');
58
59
60  // ========================= miniModernizr ===============================
61  // <3<3<3 and thanks to Faruk and Paul for doing the heavy lifting
62
63  /*!
64   * Modernizr v1.6ish: miniModernizr for Isotope
65   * http://www.modernizr.com
66   *
67   * Developed by:
68   * - Faruk Ates  http://farukat.es/
69   * - Paul Irish  http://paulirish.com/
70   *
71   * Copyright (c) 2009-2010
72   * Dual-licensed under the BSD or MIT licenses.
73   * http://www.modernizr.com/license/
74   */
75
76  /*
77   * This version whittles down the script just to check support for
78   * CSS transitions, transforms, and 3D transforms.
79  */
80
81  var tests = {
82    csstransforms: function() {
83      return !!transformProp;
84    },
85
86    csstransforms3d: function() {
87      var test = !!getStyleProperty('perspective');
88      // double check for Chrome's false positive
89      if ( test ) {
90        var vendorCSSPrefixes = ' -o- -moz- -ms- -webkit- -khtml- '.split(' '),
91            mediaQuery = '@media (' + vendorCSSPrefixes.join('transform-3d),(') + 'modernizr)',
92            $style = $('<style>' + mediaQuery + '{#modernizr{height:3px}}' + '</style>')
93                        .appendTo('head'),
94            $div = $('<div id="modernizr" />').appendTo('html');
95
96        test = $div.height() === 3;
97
98        $div.remove();
99        $style.remove();
100      }
101      return test;
102    },
103
104    csstransitions: function() {
105      return !!transitionProp;
106    }
107  };
108
109  var testName;
110
111  if ( Modernizr ) {
112    // if there's a previous Modernzir, check if there are necessary tests
113    for ( testName in tests) {
114      if ( !Modernizr.hasOwnProperty( testName ) ) {
115        // if test hasn't been run, use addTest to run it
116        Modernizr.addTest( testName, tests[ testName ] );
117      }
118    }
119  } else {
120    // or create new mini Modernizr that just has the 3 tests
121    Modernizr = window.Modernizr = {
122      _version : '1.6ish: miniModernizr for Isotope'
123    };
124
125    var classes = ' ';
126    var result;
127
128    // Run through tests
129    for ( testName in tests) {
130      result = tests[ testName ]();
131      Modernizr[ testName ] = result;
132      classes += ' ' + ( result ?  '' : 'no-' ) + testName;
133    }
134
135    // Add the new classes to the <html> element.
136    $('html').addClass( classes );
137  }
138
139
140  // ========================= isoTransform ===============================
141
142  /**
143   *  provides hooks for .css({ scale: value, translate: [x, y] })
144   *  Progressively enhanced CSS transforms
145   *  Uses hardware accelerated 3D transforms for Safari
146   *  or falls back to 2D transforms.
147   */
148
149  if ( Modernizr.csstransforms ) {
150
151        // i.e. transformFnNotations.scale(0.5) >> 'scale3d( 0.5, 0.5, 1)'
152    var transformFnNotations = Modernizr.csstransforms3d ?
153      { // 3D transform functions
154        translate : function ( position ) {
155          return 'translate3d(' + position[0] + 'px, ' + position[1] + 'px, 0) ';
156        },
157        scale : function ( scale ) {
158          return 'scale3d(' + scale + ', ' + scale + ', 1) ';
159        }
160      } :
161      { // 2D transform functions
162        translate : function ( position ) {
163          return 'translate(' + position[0] + 'px, ' + position[1] + 'px) ';
164        },
165        scale : function ( scale ) {
166          return 'scale(' + scale + ') ';
167        }
168      }
169    ;
170
171    var setIsoTransform = function ( elem, name, value ) {
172          // unpack current transform data
173      var data =  $.data( elem, 'isoTransform' ) || {},
174          newData = {},
175          fnName,
176          transformObj = {},
177          transformValue;
178
179      // i.e. newData.scale = 0.5
180      newData[ name ] = value;
181      // extend new value over current data
182      $.extend( data, newData );
183
184      for ( fnName in data ) {
185        transformValue = data[ fnName ];
186        transformObj[ fnName ] = transformFnNotations[ fnName ]( transformValue );
187      }
188
189      // get proper order
190      // ideally, we could loop through this give an array, but since we only have
191      // a couple transforms we're keeping track of, we'll do it like so
192      var translateFn = transformObj.translate || '',
193          scaleFn = transformObj.scale || '',
194          // sorting so translate always comes first
195          valueFns = translateFn + scaleFn;
196
197      // set data back in elem
198      $.data( elem, 'isoTransform', data );
199
200      // set name to vendor specific property
201      elem.style[ transformProp ] = valueFns;
202    };
203
204    // ==================== scale ===================
205
206    $.cssNumber.scale = true;
207
208    $.cssHooks.scale = {
209      set: function( elem, value ) {
210        // uncomment this bit if you want to properly parse strings
211        // if ( typeof value === 'string' ) {
212        //   value = parseFloat( value );
213        // }
214        setIsoTransform( elem, 'scale', value );
215      },
216      get: function( elem, computed ) {
217        var transform = $.data( elem, 'isoTransform' );
218        return transform && transform.scale ? transform.scale : 1;
219      }
220    };
221
222    $.fx.step.scale = function( fx ) {
223      $.cssHooks.scale.set( fx.elem, fx.now+fx.unit );
224    };
225
226
227    // ==================== translate ===================
228
229    $.cssNumber.translate = true;
230
231    $.cssHooks.translate = {
232      set: function( elem, value ) {
233
234        // uncomment this bit if you want to properly parse strings
235        // if ( typeof value === 'string' ) {
236        //   value = value.split(' ');
237        // }
238        //
239        // var i, val;
240        // for ( i = 0; i < 2; i++ ) {
241        //   val = value[i];
242        //   if ( typeof val === 'string' ) {
243        //     val = parseInt( val );
244        //   }
245        // }
246
247        setIsoTransform( elem, 'translate', value );
248      },
249
250      get: function( elem, computed ) {
251        var transform = $.data( elem, 'isoTransform' );
252        return transform && transform.translate ? transform.translate : [ 0, 0 ];
253      }
254    };
255
256  }
257
258  // ========================= get transition-end event ===============================
259  var transitionEndEvent, transitionDurProp;
260
261  if ( Modernizr.csstransitions ) {
262    transitionEndEvent = {
263      WebkitTransitionProperty: 'webkitTransitionEnd',  // webkit
264      MozTransitionProperty: 'transitionend',
265      OTransitionProperty: 'oTransitionEnd otransitionend',
266      transitionProperty: 'transitionend'
267    }[ transitionProp ];
268
269    transitionDurProp = getStyleProperty('transitionDuration');
270  }
271
272  // ========================= smartresize ===============================
273
274  /*
275   * smartresize: debounced resize event for jQuery
276   *
277   * latest version and complete README available on Github:
278   * https://github.com/louisremi/jquery.smartresize.js
279   *
280   * Copyright 2011 @louis_remi
281   * Licensed under the MIT license.
282   */
283
284  var $event = $.event,
285      dispatchMethod = $.event.handle ? 'handle' : 'dispatch',
286      resizeTimeout;
287
288  $event.special.smartresize = {
289    setup: function() {
290      $(this).bind( "resize", $event.special.smartresize.handler );
291    },
292    teardown: function() {
293      $(this).unbind( "resize", $event.special.smartresize.handler );
294    },
295    handler: function( event, execAsap ) {
296      // Save the context
297      var context = this,
298          args = arguments;
299
300      // set correct event type
301      event.type = "smartresize";
302
303      if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
304      resizeTimeout = setTimeout(function() {
305        $event[ dispatchMethod ].apply( context, args );
306      }, execAsap === "execAsap"? 0 : 100 );
307    }
308  };
309
310  $.fn.smartresize = function( fn ) {
311    return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
312  };
313
314
315
316// ========================= Isotope ===============================
317
318
319  // our "Widget" object constructor
320  $.Isotope = function( options, element, callback ){
321    this.element = $( element );
322
323    this._create( options );
324    this._init( callback );
325  };
326
327  // styles of container element we want to keep track of
328  var isoContainerStyles = [ 'width', 'height' ];
329
330  var $window = $(window);
331
332  $.Isotope.settings = {
333    resizable: true,
334    layoutMode : 'masonry',
335    containerClass : 'isotope',
336    itemClass : 'isotope-item',
337    hiddenClass : 'isotope-hidden',
338    hiddenStyle: { opacity: 0, scale: 0.001 },
339    visibleStyle: { opacity: 1, scale: 1 },
340    containerStyle: {
341      position: 'relative',
342      overflow: 'hidden'
343    },
344    animationEngine: 'best-available',
345    animationOptions: {
346      queue: false,
347      duration: 800
348    },
349    sortBy : 'original-order',
350    sortAscending : true,
351    resizesContainer : true,
352    transformsEnabled: true,
353    itemPositionDataEnabled: false
354  };
355
356  $.Isotope.prototype = {
357
358    // sets up widget
359    _create : function( options ) {
360
361      this.options = $.extend( {}, $.Isotope.settings, options );
362
363      this.styleQueue = [];
364      this.elemCount = 0;
365
366      // get original styles in case we re-apply them in .destroy()
367      var elemStyle = this.element[0].style;
368      this.originalStyle = {};
369      // keep track of container styles
370      var containerStyles = isoContainerStyles.slice(0);
371      for ( var prop in this.options.containerStyle ) {
372        containerStyles.push( prop );
373      }
374      for ( var i=0, len = containerStyles.length; i < len; i++ ) {
375        prop = containerStyles[i];
376        this.originalStyle[ prop ] = elemStyle[ prop ] || '';
377      }
378      // apply container style from options
379      this.element.css( this.options.containerStyle );
380
381      this._updateAnimationEngine();
382      this._updateUsingTransforms();
383
384      // sorting
385      var originalOrderSorter = {
386        'original-order' : function( $elem, instance ) {
387          instance.elemCount ++;
388          return instance.elemCount;
389        },
390        random : function() {
391          return Math.random();
392        }
393      };
394
395      this.options.getSortData = $.extend( this.options.getSortData, originalOrderSorter );
396
397      // need to get atoms
398      this.reloadItems();
399
400      // get top left position of where the bricks should be
401      this.offset = {
402        left: parseInt( ( this.element.css('padding-left') || 0 ), 10 ),
403        top: parseInt( ( this.element.css('padding-top') || 0 ), 10 )
404      };
405
406      // add isotope class first time around
407      var instance = this;
408      setTimeout( function() {
409        instance.element.addClass( instance.options.containerClass );
410      }, 0 );
411
412      // bind resize method
413      if ( this.options.resizable ) {
414        $window.bind( 'smartresize.isotope', function() {
415          instance.resize();
416        });
417      }
418
419      // dismiss all click events from hidden events
420      this.element.delegate( '.' + this.options.hiddenClass, 'click', function(){
421        return false;
422      });
423
424    },
425
426    _getAtoms : function( $elems ) {
427      var selector = this.options.itemSelector,
428          // filter & find
429          $atoms = selector ? $elems.filter( selector ).add( $elems.find( selector ) ) : $elems,
430          // base style for atoms
431          atomStyle = { position: 'absolute' };
432
433      // filter out text nodes
434      $atoms = $atoms.filter( function( i, atom ) {
435        return atom.nodeType === 1;
436      });
437
438      if ( this.usingTransforms ) {
439        atomStyle.left = 0;
440        atomStyle.top = 0;
441      }
442
443      $atoms.css( atomStyle ).addClass( this.options.itemClass );
444
445      this.updateSortData( $atoms, true );
446
447      return $atoms;
448    },
449
450    // _init fires when your instance is first created
451    // (from the constructor above), and when you
452    // attempt to initialize the widget again (by the bridge)
453    // after it has already been initialized.
454    _init : function( callback ) {
455
456      this.$filteredAtoms = this._filter( this.$allAtoms );
457      this._sort();
458      this.reLayout( callback );
459
460    },
461
462    option : function( opts ){
463      // change options AFTER initialization:
464      // signature: $('#foo').bar({ cool:false });
465      if ( $.isPlainObject( opts ) ){
466        this.options = $.extend( true, this.options, opts );
467
468        // trigger _updateOptionName if it exists
469        var updateOptionFn;
470        for ( var optionName in opts ) {
471          updateOptionFn = '_update' + capitalize( optionName );
472          if ( this[ updateOptionFn ] ) {
473            this[ updateOptionFn ]();
474          }
475        }
476      }
477    },
478
479    // ====================== updaters ====================== //
480    // kind of like setters
481
482    _updateAnimationEngine : function() {
483      var animationEngine = this.options.animationEngine.toLowerCase().replace( /[ _\-]/g, '');
484      var isUsingJQueryAnimation;
485      // set applyStyleFnName
486      switch ( animationEngine ) {
487        case 'css' :
488        case 'none' :
489          isUsingJQueryAnimation = false;
490          break;
491        case 'jquery' :
492          isUsingJQueryAnimation = true;
493          break;
494        default : // best available
495          isUsingJQueryAnimation = !Modernizr.csstransitions;
496      }
497      this.isUsingJQueryAnimation = isUsingJQueryAnimation;
498      this._updateUsingTransforms();
499    },
500
501    _updateTransformsEnabled : function() {
502      this._updateUsingTransforms();
503    },
504
505    _updateUsingTransforms : function() {
506      var usingTransforms = this.usingTransforms = this.options.transformsEnabled &&
507        Modernizr.csstransforms && Modernizr.csstransitions && !this.isUsingJQueryAnimation;
508
509      // prevent scales when transforms are disabled
510      if ( !usingTransforms ) {
511        delete this.options.hiddenStyle.scale;
512        delete this.options.visibleStyle.scale;
513      }
514
515      this.getPositionStyles = usingTransforms ? this._translate : this._positionAbs;
516    },
517
518
519    // ====================== Filtering ======================
520
521    _filter : function( $atoms ) {
522      var filter = this.options.filter === '' ? '*' : this.options.filter;
523
524      if ( !filter ) {
525        return $atoms;
526      }
527
528      var hiddenClass    = this.options.hiddenClass,
529          hiddenSelector = '.' + hiddenClass,
530          $hiddenAtoms   = $atoms.filter( hiddenSelector ),
531          $atomsToShow   = $hiddenAtoms;
532
533      if ( filter !== '*' ) {
534        $atomsToShow = $hiddenAtoms.filter( filter );
535        var $atomsToHide = $atoms.not( hiddenSelector ).not( filter ).addClass( hiddenClass );
536        this.styleQueue.push({ $el: $atomsToHide, style: this.options.hiddenStyle });
537      }
538
539      this.styleQueue.push({ $el: $atomsToShow, style: this.options.visibleStyle });
540      $atomsToShow.removeClass( hiddenClass );
541
542      return $atoms.filter( filter );
543    },
544
545    // ====================== Sorting ======================
546
547    updateSortData : function( $atoms, isIncrementingElemCount ) {
548      var instance = this,
549          getSortData = this.options.getSortData,
550          $this, sortData;
551      $atoms.each(function(){
552        $this = $(this);
553        sortData = {};
554        // get value for sort data based on fn( $elem ) passed in
555        for ( var key in getSortData ) {
556          if ( !isIncrementingElemCount && key === 'original-order' ) {
557            // keep original order original
558            sortData[ key ] = $.data( this, 'isotope-sort-data' )[ key ];
559          } else {
560            sortData[ key ] = getSortData[ key ]( $this, instance );
561          }
562        }
563        // apply sort data to element
564        $.data( this, 'isotope-sort-data', sortData );
565      });
566    },
567
568    // used on all the filtered atoms
569    _sort : function() {
570
571      var sortBy = this.options.sortBy,
572          getSorter = this._getSorter,
573          sortDir = this.options.sortAscending ? 1 : -1,
574          sortFn = function( alpha, beta ) {
575            var a = getSorter( alpha, sortBy ),
576                b = getSorter( beta, sortBy );
577            // fall back to original order if data matches
578            if ( a === b && sortBy !== 'original-order') {
579              a = getSorter( alpha, 'original-order' );
580              b = getSorter( beta, 'original-order' );
581            }
582            return ( ( a > b ) ? 1 : ( a < b ) ? -1 : 0 ) * sortDir;
583          };
584
585      this.$filteredAtoms.sort( sortFn );
586    },
587
588    _getSorter : function( elem, sortBy ) {
589      return $.data( elem, 'isotope-sort-data' )[ sortBy ];
590    },
591
592    // ====================== Layout Helpers ======================
593
594    _translate : function( x, y ) {
595      return { translate : [ x, y ] };
596    },
597
598    _positionAbs : function( x, y ) {
599      return { left: x, top: y };
600    },
601
602    _pushPosition : function( $elem, x, y ) {
603      x = Math.round( x + this.offset.left );
604      y = Math.round( y + this.offset.top );
605      var position = this.getPositionStyles( x, y );
606      this.styleQueue.push({ $el: $elem, style: position });
607      if ( this.options.itemPositionDataEnabled ) {
608        $elem.data('isotope-item-position', {x: x, y: y} );
609      }
610    },
611
612
613    // ====================== General Layout ======================
614
615    // used on collection of atoms (should be filtered, and sorted before )
616    // accepts atoms-to-be-laid-out to start with
617    layout : function( $elems, callback ) {
618
619      var layoutMode = this.options.layoutMode;
620
621      // layout logic
622      this[ '_' +  layoutMode + 'Layout' ]( $elems );
623
624      // set the size of the container
625      if ( this.options.resizesContainer ) {
626        var containerStyle = this[ '_' +  layoutMode + 'GetContainerSize' ]();
627        this.styleQueue.push({ $el: this.element, style: containerStyle });
628      }
629
630      this._processStyleQueue( $elems, callback );
631
632      this.isLaidOut = true;
633    },
634
635    _processStyleQueue : function( $elems, callback ) {
636      // are we animating the layout arrangement?
637      // use plugin-ish syntax for css or animate
638      var styleFn = !this.isLaidOut ? 'css' : (
639            this.isUsingJQueryAnimation ? 'animate' : 'css'
640          ),
641          animOpts = this.options.animationOptions,
642          onLayout = this.options.onLayout,
643          objStyleFn, processor,
644          triggerCallbackNow, callbackFn;
645
646      // default styleQueue processor, may be overwritten down below
647      processor = function( i, obj ) {
648        obj.$el[ styleFn ]( obj.style, animOpts );
649      };
650
651      if ( this._isInserting && this.isUsingJQueryAnimation ) {
652        // if using styleQueue to insert items
653        processor = function( i, obj ) {
654          // only animate if it not being inserted
655          objStyleFn = obj.$el.hasClass('no-transition') ? 'css' : styleFn;
656          obj.$el[ objStyleFn ]( obj.style, animOpts );
657        };
658
659      } else if ( callback || onLayout || animOpts.complete ) {
660        // has callback
661        var isCallbackTriggered = false,
662            // array of possible callbacks to trigger
663            callbacks = [ callback, onLayout, animOpts.complete ],
664            instance = this;
665        triggerCallbackNow = true;
666        // trigger callback only once
667        callbackFn = function() {
668          if ( isCallbackTriggered ) {
669            return;
670          }
671          var hollaback;
672          for (var i=0, len = callbacks.length; i < len; i++) {
673            hollaback = callbacks[i];
674            if ( typeof hollaback === 'function' ) {
675              hollaback.call( instance.element, $elems, instance );
676            }
677          }
678          isCallbackTriggered = true;
679        };
680
681        if ( this.isUsingJQueryAnimation && styleFn === 'animate' ) {
682          // add callback to animation options
683          animOpts.complete = callbackFn;
684          triggerCallbackNow = false;
685
686        } else if ( Modernizr.csstransitions ) {
687          // detect if first item has transition
688          var i = 0,
689              firstItem = this.styleQueue[0],
690              testElem = firstItem && firstItem.$el,
691              styleObj;
692          // get first non-empty jQ object
693          while ( !testElem || !testElem.length ) {
694            styleObj = this.styleQueue[ i++ ];
695            // HACK: sometimes styleQueue[i] is undefined
696            if ( !styleObj ) {
697              return;
698            }
699            testElem = styleObj.$el;
700          }
701          // get transition duration of the first element in that object
702          // yeah, this is inexact
703          var duration = parseFloat( getComputedStyle( testElem[0] )[ transitionDurProp ] );
704          if ( duration > 0 ) {
705            processor = function( i, obj ) {
706              obj.$el[ styleFn ]( obj.style, animOpts )
707                // trigger callback at transition end
708                .one( transitionEndEvent, callbackFn );
709            };
710            triggerCallbackNow = false;
711          }
712        }
713      }
714
715      // process styleQueue
716      $.each( this.styleQueue, processor );
717
718      if ( triggerCallbackNow ) {
719        callbackFn();
720      }
721
722      // clear out queue for next time
723      this.styleQueue = [];
724    },
725
726
727    resize : function() {
728      if ( this[ '_' + this.options.layoutMode + 'ResizeChanged' ]() ) {
729        this.reLayout();
730      }
731    },
732
733
734    reLayout : function( callback ) {
735
736      this[ '_' +  this.options.layoutMode + 'Reset' ]();
737      this.layout( this.$filteredAtoms, callback );
738
739    },
740
741    // ====================== Convenience methods ======================
742
743    // ====================== Adding items ======================
744
745    // adds a jQuery object of items to a isotope container
746    addItems : function( $content, callback ) {
747      var $newAtoms = this._getAtoms( $content );
748      // add new atoms to atoms pools
749      this.$allAtoms = this.$allAtoms.add( $newAtoms );
750
751      if ( callback ) {
752        callback( $newAtoms );
753      }
754    },
755
756    // convienence method for adding elements properly to any layout
757    // positions items, hides them, then animates them back in <--- very sezzy
758    insert : function( $content, callback ) {
759      // position items
760      this.element.append( $content );
761
762      var instance = this;
763      this.addItems( $content, function( $newAtoms ) {
764        var $newFilteredAtoms = instance._filter( $newAtoms );
765        instance._addHideAppended( $newFilteredAtoms );
766        instance._sort();
767        instance.reLayout();
768        instance._revealAppended( $newFilteredAtoms, callback );
769      });
770
771    },
772
773    // convienence method for working with Infinite Scroll
774    appended : function( $content, callback ) {
775      var instance = this;
776      this.addItems( $content, function( $newAtoms ) {
777        instance._addHideAppended( $newAtoms );
778        instance.layout( $newAtoms );
779        instance._revealAppended( $newAtoms, callback );
780      });
781    },
782
783    // adds new atoms, then hides them before positioning
784    _addHideAppended : function( $newAtoms ) {
785      this.$filteredAtoms = this.$filteredAtoms.add( $newAtoms );
786      $newAtoms.addClass('no-transition');
787
788      this._isInserting = true;
789
790      // apply hidden styles
791      this.styleQueue.push({ $el: $newAtoms, style: this.options.hiddenStyle });
792    },
793
794    // sets visible style on new atoms
795    _revealAppended : function( $newAtoms, callback ) {
796      var instance = this;
797      // apply visible style after a sec
798      setTimeout( function() {
799        // enable animation
800        $newAtoms.removeClass('no-transition');
801        // reveal newly inserted filtered elements
802        instance.styleQueue.push({ $el: $newAtoms, style: instance.options.visibleStyle });
803        instance._isInserting = false;
804        instance._processStyleQueue( $newAtoms, callback );
805      }, 10 );
806    },
807
808    // gathers all atoms
809    reloadItems : function() {
810      this.$allAtoms = this._getAtoms( this.element.children() );
811    },
812
813    // removes elements from Isotope widget
814    remove: function( $content, callback ) {
815      // remove elements immediately from Isotope instance
816      this.$allAtoms = this.$allAtoms.not( $content );
817      this.$filteredAtoms = this.$filteredAtoms.not( $content );
818      // remove() as a callback, for after transition / animation
819      var instance = this;
820      var removeContent = function() {
821        $content.remove();
822        if ( callback ) {
823          callback.call( instance.element );
824        }
825      };
826
827      if ( $content.filter( ':not(.' + this.options.hiddenClass + ')' ).length ) {
828        // if any non-hidden content needs to be removed
829        this.styleQueue.push({ $el: $content, style: this.options.hiddenStyle });
830        this._sort();
831        this.reLayout( removeContent );
832      } else {
833        // remove it now
834        removeContent();
835      }
836
837    },
838
839    shuffle : function( callback ) {
840      this.updateSortData( this.$allAtoms );
841      this.options.sortBy = 'random';
842      this._sort();
843      this.reLayout( callback );
844    },
845
846    // destroys widget, returns elements and container back (close) to original style
847    destroy : function() {
848
849      var usingTransforms = this.usingTransforms;
850      var options = this.options;
851
852      this.$allAtoms
853        .removeClass( options.hiddenClass + ' ' + options.itemClass )
854        .each(function(){
855          var style = this.style;
856          style.position = '';
857          style.top = '';
858          style.left = '';
859          style.opacity = '';
860          if ( usingTransforms ) {
861            style[ transformProp ] = '';
862          }
863        });
864
865      // re-apply saved container styles
866      var elemStyle = this.element[0].style;
867      for ( var prop in this.originalStyle ) {
868        elemStyle[ prop ] = this.originalStyle[ prop ];
869      }
870
871      this.element
872        .unbind('.isotope')
873        .undelegate( '.' + options.hiddenClass, 'click' )
874        .removeClass( options.containerClass )
875        .removeData('isotope');
876
877      $window.unbind('.isotope');
878
879    },
880
881
882    // ====================== LAYOUTS ======================
883
884    // calculates number of rows or columns
885    // requires columnWidth or rowHeight to be set on namespaced object
886    // i.e. this.masonry.columnWidth = 200
887    _getSegments : function( isRows ) {
888      var namespace = this.options.layoutMode,
889          measure  = isRows ? 'rowHeight' : 'columnWidth',
890          size     = isRows ? 'height' : 'width',
891          segmentsName = isRows ? 'rows' : 'cols',
892          containerSize = this.element[ size ](),
893          segments,
894                    // i.e. options.masonry && options.masonry.columnWidth
895          segmentSize = this.options[ namespace ] && this.options[ namespace ][ measure ] ||
896                    // or use the size of the first item, i.e. outerWidth
897                    this.$filteredAtoms[ 'outer' + capitalize(size) ](true) ||
898                    // if there's no items, use size of container
899                    containerSize;
900
901      segments = Math.floor( containerSize / segmentSize );
902      segments = Math.max( segments, 1 );
903
904      // i.e. this.masonry.cols = ....
905      this[ namespace ][ segmentsName ] = segments;
906      // i.e. this.masonry.columnWidth = ...
907      this[ namespace ][ measure ] = segmentSize;
908
909    },
910
911    _checkIfSegmentsChanged : function( isRows ) {
912      var namespace = this.options.layoutMode,
913          segmentsName = isRows ? 'rows' : 'cols',
914          prevSegments = this[ namespace ][ segmentsName ];
915      // update cols/rows
916      this._getSegments( isRows );
917      // return if updated cols/rows is not equal to previous
918      return ( this[ namespace ][ segmentsName ] !== prevSegments );
919    },
920
921    // ====================== Masonry ======================
922
923    _masonryReset : function() {
924      // layout-specific props
925      this.masonry = {};
926      // FIXME shouldn't have to call this again
927      this._getSegments();
928      var i = this.masonry.cols;
929      this.masonry.colYs = [];
930      while (i--) {
931        this.masonry.colYs.push( 0 );
932      }
933    },
934
935    _masonryLayout : function( $elems ) {
936      var instance = this,
937          props = instance.masonry;
938      $elems.each(function(){
939        var $this  = $(this),
940            //how many columns does this brick span
941            colSpan = Math.ceil( $this.outerWidth(true) / props.columnWidth );
942        colSpan = Math.min( colSpan, props.cols );
943
944        if ( colSpan === 1 ) {
945          // if brick spans only one column, just like singleMode
946          instance._masonryPlaceBrick( $this, props.colYs );
947        } else {
948          // brick spans more than one column
949          // how many different places could this brick fit horizontally
950          var groupCount = props.cols + 1 - colSpan,
951              groupY = [],
952              groupColY,
953              i;
954
955          // for each group potential horizontal position
956          for ( i=0; i < groupCount; i++ ) {
957            // make an array of colY values for that one group
958            groupColY = props.colYs.slice( i, i+colSpan );
959            // and get the max value of the array
960            groupY[i] = Math.max.apply( Math, groupColY );
961          }
962
963          instance._masonryPlaceBrick( $this, groupY );
964        }
965      });
966    },
967
968    // worker method that places brick in the columnSet
969    //   with the the minY
970    _masonryPlaceBrick : function( $brick, setY ) {
971      // get the minimum Y value from the columns
972      var minimumY = Math.min.apply( Math, setY ),
973          shortCol = 0;
974
975      // Find index of short column, the first from the left
976      for (var i=0, len = setY.length; i < len; i++) {
977        if ( setY[i] === minimumY ) {
978          shortCol = i;
979          break;
980        }
981      }
982
983      // position the brick
984      var x = this.masonry.columnWidth * shortCol,
985          y = minimumY;
986      this._pushPosition( $brick, x, y );
987
988      // apply setHeight to necessary columns
989      var setHeight = minimumY + $brick.outerHeight(true),
990          setSpan = this.masonry.cols + 1 - len;
991      for ( i=0; i < setSpan; i++ ) {
992        this.masonry.colYs[ shortCol + i ] = setHeight;
993      }
994
995    },
996
997    _masonryGetContainerSize : function() {
998      var containerHeight = Math.max.apply( Math, this.masonry.colYs );
999      return { height: containerHeight };
1000    },
1001
1002    _masonryResizeChanged : function() {
1003      return this._checkIfSegmentsChanged();
1004    },
1005
1006    // ====================== fitRows ======================
1007
1008    _fitRowsReset : function() {
1009      this.fitRows = {
1010        x : 0,
1011        y : 0,
1012        height : 0
1013      };
1014    },
1015
1016    _fitRowsLayout : function( $elems ) {
1017      var instance = this,
1018          containerWidth = this.element.width(),
1019          props = this.fitRows;
1020
1021      $elems.each( function() {
1022        var $this = $(this),
1023            atomW = $this.outerWidth(true),
1024            atomH = $this.outerHeight(true);
1025
1026        if ( props.x !== 0 && atomW + props.x > containerWidth ) {
1027          // if this element cannot fit in the current row
1028          props.x = 0;
1029          props.y = props.height;
1030        }
1031
1032        // position the atom
1033        instance._pushPosition( $this, props.x, props.y );
1034
1035        props.height = Math.max( props.y + atomH, props.height );
1036        props.x += atomW;
1037
1038      });
1039    },
1040
1041    _fitRowsGetContainerSize : function () {
1042      return { height : this.fitRows.height };
1043    },
1044
1045    _fitRowsResizeChanged : function() {
1046      return true;
1047    },
1048
1049
1050    // ====================== cellsByRow ======================
1051
1052    _cellsByRowReset : function() {
1053      this.cellsByRow = {
1054        index : 0
1055      };
1056      // get this.cellsByRow.columnWidth
1057      this._getSegments();
1058      // get this.cellsByRow.rowHeight
1059      this._getSegments(true);
1060    },
1061
1062    _cellsByRowLayout : function( $elems ) {
1063      var instance = this,
1064          props = this.cellsByRow;
1065      $elems.each( function(){
1066        var $this = $(this),
1067            col = props.index % props.cols,
1068            row = Math.floor( props.index / props.cols ),
1069            x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
1070            y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
1071        instance._pushPosition( $this, x, y );
1072        props.index ++;
1073      });
1074    },
1075
1076    _cellsByRowGetContainerSize : function() {
1077      return { height : Math.ceil( this.$filteredAtoms.length / this.cellsByRow.cols ) * this.cellsByRow.rowHeight + this.offset.top };
1078    },
1079
1080    _cellsByRowResizeChanged : function() {
1081      return this._checkIfSegmentsChanged();
1082    },
1083
1084
1085    // ====================== straightDown ======================
1086
1087    _straightDownReset : function() {
1088      this.straightDown = {
1089        y : 0
1090      };
1091    },
1092
1093    _straightDownLayout : function( $elems ) {
1094      var instance = this;
1095      $elems.each( function( i ){
1096        var $this = $(this);
1097        instance._pushPosition( $this, 0, instance.straightDown.y );
1098        instance.straightDown.y += $this.outerHeight(true);
1099      });
1100    },
1101
1102    _straightDownGetContainerSize : function() {
1103      return { height : this.straightDown.y };
1104    },
1105
1106    _straightDownResizeChanged : function() {
1107      return true;
1108    },
1109
1110
1111    // ====================== masonryHorizontal ======================
1112
1113    _masonryHorizontalReset : function() {
1114      // layout-specific props
1115      this.masonryHorizontal = {};
1116      // FIXME shouldn't have to call this again
1117      this._getSegments( true );
1118      var i = this.masonryHorizontal.rows;
1119      this.masonryHorizontal.rowXs = [];
1120      while (i--) {
1121        this.masonryHorizontal.rowXs.push( 0 );
1122      }
1123    },
1124
1125    _masonryHorizontalLayout : function( $elems ) {
1126      var instance = this,
1127          props = instance.masonryHorizontal;
1128      $elems.each(function(){
1129        var $this  = $(this),
1130            //how many rows does this brick span
1131            rowSpan = Math.ceil( $this.outerHeight(true) / props.rowHeight );
1132        rowSpan = Math.min( rowSpan, props.rows );
1133
1134        if ( rowSpan === 1 ) {
1135          // if brick spans only one column, just like singleMode
1136          instance._masonryHorizontalPlaceBrick( $this, props.rowXs );
1137        } else {
1138          // brick spans more than one row
1139          // how many different places could this brick fit horizontally
1140          var groupCount = props.rows + 1 - rowSpan,
1141              groupX = [],
1142              groupRowX, i;
1143
1144          // for each group potential horizontal position
1145          for ( i=0; i < groupCount; i++ ) {
1146            // make an array of colY values for that one group
1147            groupRowX = props.rowXs.slice( i, i+rowSpan );
1148            // and get the max value of the array
1149            groupX[i] = Math.max.apply( Math, groupRowX );
1150          }
1151
1152          instance._masonryHorizontalPlaceBrick( $this, groupX );
1153        }
1154      });
1155    },
1156
1157    _masonryHorizontalPlaceBrick : function( $brick, setX ) {
1158      // get the minimum Y value from the columns
1159      var minimumX  = Math.min.apply( Math, setX ),
1160          smallRow  = 0;
1161      // Find index of smallest row, the first from the top
1162      for (var i=0, len = setX.length; i < len; i++) {
1163        if ( setX[i] === minimumX ) {
1164          smallRow = i;
1165          break;
1166        }
1167      }
1168
1169      // position the brick
1170      var x = minimumX,
1171          y = this.masonryHorizontal.rowHeight * smallRow;
1172      this._pushPosition( $brick, x, y );
1173
1174      // apply setHeight to necessary columns
1175      var setWidth = minimumX + $brick.outerWidth(true),
1176          setSpan = this.masonryHorizontal.rows + 1 - len;
1177      for ( i=0; i < setSpan; i++ ) {
1178        this.masonryHorizontal.rowXs[ smallRow + i ] = setWidth;
1179      }
1180    },
1181
1182    _masonryHorizontalGetContainerSize : function() {
1183      var containerWidth = Math.max.apply( Math, this.masonryHorizontal.rowXs );
1184      return { width: containerWidth };
1185    },
1186
1187    _masonryHorizontalResizeChanged : function() {
1188      return this._checkIfSegmentsChanged(true);
1189    },
1190
1191
1192    // ====================== fitColumns ======================
1193
1194    _fitColumnsReset : function() {
1195      this.fitColumns = {
1196        x : 0,
1197        y : 0,
1198        width : 0
1199      };
1200    },
1201
1202    _fitColumnsLayout : function( $elems ) {
1203      var instance = this,
1204          containerHeight = this.element.height(),
1205          props = this.fitColumns;
1206      $elems.each( function() {
1207        var $this = $(this),
1208            atomW = $this.outerWidth(true),
1209            atomH = $this.outerHeight(true);
1210
1211        if ( props.y !== 0 && atomH + props.y > containerHeight ) {
1212          // if this element cannot fit in the current column
1213          props.x = props.width;
1214          props.y = 0;
1215        }
1216
1217        // position the atom
1218        instance._pushPosition( $this, props.x, props.y );
1219
1220        props.width = Math.max( props.x + atomW, props.width );
1221        props.y += atomH;
1222
1223      });
1224    },
1225
1226    _fitColumnsGetContainerSize : function () {
1227      return { width : this.fitColumns.width };
1228    },
1229
1230    _fitColumnsResizeChanged : function() {
1231      return true;
1232    },
1233
1234
1235
1236    // ====================== cellsByColumn ======================
1237
1238    _cellsByColumnReset : function() {
1239      this.cellsByColumn = {
1240        index : 0
1241      };
1242      // get this.cellsByColumn.columnWidth
1243      this._getSegments();
1244      // get this.cellsByColumn.rowHeight
1245      this._getSegments(true);
1246    },
1247
1248    _cellsByColumnLayout : function( $elems ) {
1249      var instance = this,
1250          props = this.cellsByColumn;
1251      $elems.each( function(){
1252        var $this = $(this),
1253            col = Math.floor( props.index / props.rows ),
1254            row = props.index % props.rows,
1255            x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
1256            y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
1257        instance._pushPosition( $this, x, y );
1258        props.index ++;
1259      });
1260    },
1261
1262    _cellsByColumnGetContainerSize : function() {
1263      return { width : Math.ceil( this.$filteredAtoms.length / this.cellsByColumn.rows ) * this.cellsByColumn.columnWidth };
1264    },
1265
1266    _cellsByColumnResizeChanged : function() {
1267      return this._checkIfSegmentsChanged(true);
1268    },
1269
1270    // ====================== straightAcross ======================
1271
1272    _straightAcrossReset : function() {
1273      this.straightAcross = {
1274        x : 0
1275      };
1276    },
1277
1278    _straightAcrossLayout : function( $elems ) {
1279      var instance = this;
1280      $elems.each( function( i ){
1281        var $this = $(this);
1282        instance._pushPosition( $this, instance.straightAcross.x, 0 );
1283        instance.straightAcross.x += $this.outerWidth(true);
1284      });
1285    },
1286
1287    _straightAcrossGetContainerSize : function() {
1288      return { width : this.straightAcross.x };
1289    },
1290
1291    _straightAcrossResizeChanged : function() {
1292      return true;
1293    }
1294
1295  };
1296
1297
1298  // ======================= imagesLoaded Plugin ===============================
1299  /*!
1300   * jQuery imagesLoaded plugin v1.1.0
1301   * http://github.com/desandro/imagesloaded
1302   *
1303   * MIT License. by Paul Irish et al.
1304   */
1305
1306
1307  // $('#my-container').imagesLoaded(myFunction)
1308  // or
1309  // $('img').imagesLoaded(myFunction)
1310
1311  // execute a callback when all images have loaded.
1312  // needed because .load() doesn't work on cached images
1313
1314  // callback function gets image collection as argument
1315  //  `this` is the container
1316
1317  $.fn.imagesLoaded = function( callback ) {
1318    var $this = this,
1319        $images = $this.find('img').add( $this.filter('img') ),
1320        len = $images.length,
1321        blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==',
1322        loaded = [];
1323
1324    function triggerCallback() {
1325      callback.call( $this, $images );
1326    }
1327
1328    function imgLoaded( event ) {
1329      var img = event.target;
1330      if ( img.src !== blank && $.inArray( img, loaded ) === -1 ){
1331        loaded.push( img );
1332        if ( --len <= 0 ){
1333          setTimeout( triggerCallback );
1334          $images.unbind( '.imagesLoaded', imgLoaded );
1335        }
1336      }
1337    }
1338
1339    // if no images, trigger immediately
1340    if ( !len ) {
1341      triggerCallback();
1342    }
1343
1344    $images.bind( 'load.imagesLoaded error.imagesLoaded',  imgLoaded ).each( function() {
1345      // cached images don't fire load sometimes, so we reset src.
1346      var src = this.src;
1347      // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
1348      // data uri bypasses webkit log warning (thx doug jones)
1349      this.src = blank;
1350      this.src = src;
1351    });
1352
1353    return $this;
1354  };
1355
1356
1357  // helper function for logging errors
1358  // $.error breaks jQuery chaining
1359  var logError = function( message ) {
1360    if ( window.console ) {
1361      window.console.error( message );
1362    }
1363  };
1364
1365  // =======================  Plugin bridge  ===============================
1366  // leverages data method to either create or return $.Isotope constructor
1367  // A bit from jQuery UI
1368  //   https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
1369  // A bit from jcarousel
1370  //   https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarou
1370sel.js
1371
1372  $.fn.isotope = function( options, callback ) {
1373    if ( typeof options === 'string' ) {
1374      // call method
1375      var args = Array.prototype.slice.call( arguments, 1 );
1376
1377      this.each(function(){
1378        var instance = $.data( this, 'isotope' );
1379        if ( !instance ) {
1380          logError( "cannot call methods on isotope prior to initialization; " +
1381              "attempted to call method '" + options + "'" );
1382          return;
1383        }
1384        if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
1385          logError( "no such method '" + options + "' for isotope instance" );
1386          return;
1387        }
1388        // apply method
1389        instance[ options ].apply( instance, args );
1390      });
1391    } else {
1392      this.each(function() {
1393        var instance = $.data( this, 'isotope' );
1394        if ( instance ) {
1395          // apply options & init
1396          instance.option( options );
1397          instance._init( callback );
1398        } else {
1399          // initialize new instance
1400          $.data( this, 'isotope', new $.Isotope( options, this, callback ) );
1401        }
1402      });
1403    }
1404    // return jQuery object
1405    // so plugin methods do not have to
1406    return this;
1407  };
1408
1409})( window, jQuery );

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