PageSourceSearch

https://www.cra.ac.th//assets/frontend/js/isotope.pkgd.js

js cra.ac.th collected 2026-10-02 14:31:23 UTC 98,485 bytes, 3,563 lines download raw bytes

vendor: 30,654 bytes, lines 1-1112
1/*!
2 * Isotope PACKAGED v3.0.6
3 *
4 * Licensed GPLv3 for open source use
5 * or Isotope Commercial License for commercial use
6 *
7 * https://isotope.metafizzy.co
8 * Copyright 2010-2018 Metafizzy
9 */
10
11/**
12 * Bridget makes jQuery widgets
13 * v2.0.1
14 * MIT license
15 */
16
17/* jshint browser: true, strict: true, undef: true, unused: true */
18
19( function( window, factory ) {
20    // universal module definition
21    /*jshint strict: false */ /* globals define, module, require */
22    if ( typeof define == 'function' && define.amd ) {
23      // AMD
24      define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
25        return factory( window, jQuery );
26      });
27    } else if ( typeof module == 'object' && module.exports ) {
28      // CommonJS
29      module.exports = factory(
30        window,
31        require('jquery')
32      );
33    } else {
34      // browser global
35      window.jQueryBridget = factory(
36        window,
37        window.jQuery
38      );
39    }
40  
41  }( window, function factory( window, jQuery ) {
42  'use strict';
43  
44  // ----- utils ----- //
45  
46  var arraySlice = Array.prototype.slice;
47  
48  // helper function for logging errors
49  // $.error breaks jQuery chaining
50  var console = window.console;
51  var logError = typeof console == 'undefined' ? function() {} :
52    function( message ) {
53      console.error( message );
54    };
55  
56  // ----- jQueryBridget ----- //
57  
58  function jQueryBridget( namespace, PluginClass, $ ) {
59    $ = $ || jQuery || window.jQuery;
60    if ( !$ ) {
61      return;
62    }
63  
64    // add option method -> $().plugin('option', {...})
65    if ( !PluginClass.prototype.option ) {
66      // option setter
67      PluginClass.prototype.option = function( opts ) {
68        // bail out if not an object
69        if ( !$.isPlainObject( opts ) ){
70          return;
71        }
72        this.options = $.extend( true, this.options, opts );
73      };
74    }
75  
76    // make jQuery plugin
77    $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
78      if ( typeof arg0 == 'string' ) {
79        // method call $().plugin( 'methodName', { options } )
80        // shift arguments by 1
81        var args = arraySlice.call( arguments, 1 );
82        return methodCall( this, arg0, args );
83      }
84      // just $().plugin({ options })
85      plainCall( this, arg0 );
86      return this;
87    };
88  
89    // $().plugin('methodName')
90    function methodCall( $elems, methodName, args ) {
91      var returnValue;
92      var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
93  
94      $elems.each( function( i, elem ) {
95        // get instance
96        var instance = $.data( elem, namespace );
97        if ( !instance ) {
98          logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
99            pluginMethodStr );
100          return;
101        }
102  
103        var method = instance[ methodName ];
104        if ( !method || methodName.charAt(0) == '_' ) {
105          logError( pluginMethodStr + ' is not a valid method' );
106          return;
107        }
108  
109        // apply method, get return value
110        var value = method.apply( instance, args );
111        // set return value if value is returned, use only first value
112        returnValue = returnValue === undefined ? value : returnValue;
113      });
114  
115      return returnValue !== undefined ? returnValue : $elems;
116    }
117  
118    function plainCall( $elems, options ) {
119      $elems.each( function( i, elem ) {
120        var instance = $.data( elem, namespace );
121        if ( instance ) {
122          // set options & init
123          instance.option( options );
124          instance._init();
125        } else {
126          // initialize new instance
127          instance = new PluginClass( elem, options );
128          $.data( elem, namespace, instance );
129        }
130      });
131    }
132  
133    updateJQuery( $ );
134  
135  }
136  
137  // ----- updateJQuery ----- //
138  
139  // set $.bridget for v1 backwards compatibility
140  function updateJQuery( $ ) {
141    if ( !$ || ( $ && $.bridget ) ) {
142      return;
143    }
144    $.bridget = jQueryBridget;
145  }
146  
147  updateJQuery( jQuery || window.jQuery );
148  
149  // -----  ----- //
150  
151  return jQueryBridget;
152  
153  }));
154  
155  /**
156   * EvEmitter v1.1.0
157   * Lil' event emitter
158   * MIT License
159   */
160  
161  /* jshint unused: true, undef: true, strict: true */
162  
163  ( function( global, factory ) {
164    // universal module definition
165    /* jshint strict: false */ /* globals define, module, window */
166    if ( typeof define == 'function' && define.amd ) {
167      // AMD - RequireJS
168      define( 'ev-emitter/ev-emitter',factory );
169    } else if ( typeof module == 'object' && module.exports ) {
170      // CommonJS - Browserify, Webpack
171      module.exports = factory();
172    } else {
173      // Browser globals
174      global.EvEmitter = factory();
175    }
176  
177  }( typeof window != 'undefined' ? window : this, function() {
178  
179  
180  
181  function EvEmitter() {}
182  
183  var proto = EvEmitter.prototype;
184  
185  proto.on = function( eventName, listener ) {
186    if ( !eventName || !listener ) {
187      return;
188    }
189    // set events hash
190    var events = this._events = this._events || {};
191    // set listeners array
192    var listeners = events[ eventName ] = events[ eventName ] || [];
193    // only add once
194    if ( listeners.indexOf( listener ) == -1 ) {
195      listeners.push( listener );
196    }
197  
198    return this;
199  };
200  
201  proto.once = function( eventName, listener ) {
202    if ( !eventName || !listener ) {
203      return;
204    }
205    // add event
206    this.on( eventName, listener );
207    // set once flag
208    // set onceEvents hash
209    var onceEvents = this._onceEvents = this._onceEvents || {};
210    // set onceListeners object
211    var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
212    // set flag
213    onceListeners[ listener ] = true;
214  
215    return this;
216  };
217  
218  proto.off = function( eventName, listener ) {
219    var listeners = this._events && this._events[ eventName ];
220    if ( !listeners || !listeners.length ) {
221      return;
222    }
223    var index = listeners.indexOf( listener );
224    if ( index != -1 ) {
225      listeners.splice( index, 1 );
226    }
227  
228    return this;
229  };
230  
231  proto.emitEvent = function( eventName, args ) {
232    var listeners = this._events && this._events[ eventName ];
233    if ( !listeners || !listeners.length ) {
234      return;
235    }
236    // copy over to avoid interference if .off() in listener
237    listeners = listeners.slice(0);
238    args = args || [];
239    // once stuff
240    var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
241  
242    for ( var i=0; i < listeners.length; i++ ) {
243      var listener = listeners[i]
244      var isOnce = onceListeners && onceListeners[ listener ];
245      if ( isOnce ) {
246        // remove listener
247        // remove before trigger to prevent recursion
248        this.off( eventName, listener );
249        // unset once flag
250        delete onceListeners[ listener ];
251      }
252      // trigger listener
253      listener.apply( this, args );
254    }
255  
256    return this;
257  };
258  
259  proto.allOff = function() {
260    delete this._events;
261    delete this._onceEvents;
262  };
263  
264  return EvEmitter;
265  
266  }));
267  
268  /*!
269   * getSize v2.0.3
270   * measure size of elements
271   * MIT license
272   */
273  
274  /* jshint browser: true, strict: true, undef: true, unused: true */
275  /* globals console: false */
276  
277  ( function( window, factory ) {
278    /* jshint strict: false */ /* globals define, module */
279    if ( typeof define == 'function' && define.amd ) {
280      // AMD
281      define( 'get-size/get-size',factory );
282    } else if ( typeof module == 'object' && module.exports ) {
283      // CommonJS
284      module.exports = factory();
285    } else {
286      // browser global
287      window.getSize = factory();
288    }
289  
290  })( window, function factory() {
291  'use strict';
292  
293  // -------------------------- helpers -------------------------- //
294  
295  // get a number from a string, not a percentage
296  function getStyleSize( value ) {
297    var num = parseFloat( value );
298    // not a percent like '100%', and a number
299    var isValid = value.indexOf('%') == -1 && !isNaN( num );
300    return isValid && num;
301  }
302  
303  function noop() {}
304  
305  var logError = typeof console == 'undefined' ? noop :
306    function( message ) {
307      console.error( message );
308    };
309  
310  // -------------------------- measurements -------------------------- //
311  
312  var measurements = [
313    'paddingLeft',
314    'paddingRight',
315    'paddingTop',
316    'paddingBottom',
317    'marginLeft',
318    'marginRight',
319    'marginTop',
320    'marginBottom',
321    'borderLeftWidth',
322    'borderRightWidth',
323    'borderTopWidth',
324    'borderBottomWidth'
325  ];
326  
327  var measurementsLength = measurements.length;
328  
329  function getZeroSize() {
330    var size = {
331      width: 0,
332      height: 0,
333      innerWidth: 0,
334      innerHeight: 0,
335      outerWidth: 0,
336      outerHeight: 0
337    };
338    for ( var i=0; i < measurementsLength; i++ ) {
339      var measurement = measurements[i];
340      size[ measurement ] = 0;
341    }
342    return size;
343  }
344  
345  // -------------------------- getStyle -------------------------- //
346  
347  /**
348   * getStyle, get style of element, check for Firefox bug
349   * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
350   */
351  function getStyle( elem ) {
352    var style = getComputedStyle( elem );
353    if ( !style ) {
354      logError( 'Style returned ' + style +
355        '. Are you running this code in a hidden iframe on Firefox? ' +
356        'See https://bit.ly/getsizebug1' );
357    }
358    return style;
359  }
360  
361  // -------------------------- setup -------------------------- //
362  
363  var isSetup = false;
364  
365  var isBoxSizeOuter;
366  
367  /**
368   * setup
369   * check isBoxSizerOuter
370   * do on first getSize() rather than on page load for Firefox bug
371   */
372  function setup() {
373    // setup once
374    if ( isSetup ) {
375      return;
376    }
377    isSetup = true;
378  
379    // -------------------------- box sizing -------------------------- //
380  
381    /**
382     * Chrome & Safari measure the outer-width on style.width on border-box elems
383     * IE11 & Firefox<29 measures the inner-width
384     */
385    var div = document.createElement('div');
386    div.style.width = '200px';
387    div.style.padding = '1px 2px 3px 4px';
388    div.style.borderStyle = 'solid';
389    div.style.borderWidth = '1px 2px 3px 4px';
390    div.style.boxSizing = 'border-box';
391  
392    var body = document.body || document.documentElement;
393    body.appendChild( div );
394    var style = getStyle( div );
395    // round value for browser zoom. desandro/masonry#928
396    isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
397    getSize.isBoxSizeOuter = isBoxSizeOuter;
398  
399    body.removeChild( div );
400  }
401  
402  // -------------------------- getSize -------------------------- //
403  
404  function getSize( elem ) {
405    setup();
406  
407    // use querySeletor if elem is string
408    if ( typeof elem == 'string' ) {
409      elem = document.querySelector( elem );
410    }
411  
412    // do not proceed on non-objects
413    if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
414      return;
415    }
416  
417    var style = getStyle( elem );
418  
419    // if hidden, everything is 0
420    if ( style.display == 'none' ) {
421      return getZeroSize();
422    }
423  
424    var size = {};
425    size.width = elem.offsetWidth;
426    size.height = elem.offsetHeight;
427  
428    var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
429  
430    // get all measurements
431    for ( var i=0; i < measurementsLength; i++ ) {
432      var measurement = measurements[i];
433      var value = style[ measurement ];
434      var num = parseFloat( value );
435      // any 'auto', 'medium' value will be 0
436      size[ measurement ] = !isNaN( num ) ? num : 0;
437    }
438  
439    var paddingWidth = size.paddingLeft + size.paddingRight;
440    var paddingHeight = size.paddingTop + size.paddingBottom;
441    var marginWidth = size.marginLeft + size.marginRight;
442    var marginHeight = size.marginTop + size.marginBottom;
443    var borderWidth = size.borderLeftWidth + size.borderRightWidth;
444    var borderHeight = size.borderTopWidth + size.borderBottomWidth;
445  
446    var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
447  
448    // overwrite width and height if we can get it from style
449    var styleWidth = getStyleSize( style.width );
450    if ( styleWidth !== false ) {
451      size.width = styleWidth +
452        // add padding and border unless it's already including it
453        ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
454    }
455  
456    var styleHeight = getStyleSize( style.height );
457    if ( styleHeight !== false ) {
458      size.height = styleHeight +
459        // add padding and border unless it's already including it
460        ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
461    }
462  
463    size.innerWidth = size.width - ( paddingWidth + borderWidth );
464    size.innerHeight = size.height - ( paddingHeight + borderHeight );
465  
466    size.outerWidth = size.width + marginWidth;
467    size.outerHeight = size.height + marginHeight;
468  
469    return size;
470  }
471  
472  return getSize;
473  
474  });
475  
476  /**
477   * matchesSelector v2.0.2
478   * matchesSelector( element, '.selector' )
479   * MIT license
480   */
481  
482  /*jshint browser: true, strict: true, undef: true, unused: true */
483  
484  ( function( window, factory ) {
485    /*global define: false, module: false */
486    'use strict';
487    // universal module definition
488    if ( typeof define == 'function' && define.amd ) {
489      // AMD
490      define( 'desandro-matches-selector/matches-selector',factory );
491    } else if ( typeof module == 'object' && module.exports ) {
492      // CommonJS
493      module.exports = factory();
494    } else {
495      // browser global
496      window.matchesSelector = factory();
497    }
498  
499  }( window, function factory() {
500    'use strict';
501  
502    var matchesMethod = ( function() {
503      var ElemProto = window.Element.prototype;
504      // check for the standard method name first
505      if ( ElemProto.matches ) {
506        return 'matches';
507      }
508      // check un-prefixed
509      if ( ElemProto.matchesSelector ) {
510        return 'matchesSelector';
511      }
512      // check vendor prefixes
513      var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
514  
515      for ( var i=0; i < prefixes.length; i++ ) {
516        var prefix = prefixes[i];
517        var method = prefix + 'MatchesSelector';
518        if ( ElemProto[ method ] ) {
519          return method;
520        }
521      }
522    })();
523  
524    return function matchesSelector( elem, selector ) {
525      return elem[ matchesMethod ]( selector );
526    };
527  
528  }));
529  
530  /**
531   * Fizzy UI utils v2.0.7
532   * MIT license
533   */
534  
535  /*jshint browser: true, undef: true, unused: true, strict: true */
536  
537  ( function( window, factory ) {
538    // universal module definition
539    /*jshint strict: false */ /*globals define, module, require */
540  
541    if ( typeof define == 'function' && define.amd ) {
542      // AMD
543      define( 'fizzy-ui-utils/utils',[
544        'desandro-matches-selector/matches-selector'
545      ], function( matchesSelector ) {
546        return factory( window, matchesSelector );
547      });
548    } else if ( typeof module == 'object' && module.exports ) {
549      // CommonJS
550      module.exports = factory(
551        window,
552        require('desandro-matches-selector')
553      );
554    } else {
555      // browser global
556      window.fizzyUIUtils = factory(
557        window,
558        window.matchesSelector
559      );
560    }
561  
562  }( window, function factory( window, matchesSelector ) {
563  
564  
565  
566  var utils = {};
567  
568  // ----- extend ----- //
569  
570  // extends objects
571  utils.extend = function( a, b ) {
572    for ( var prop in b ) {
573      a[ prop ] = b[ prop ];
574    }
575    return a;
576  };
577  
578  // ----- modulo ----- //
579  
580  utils.modulo = function( num, div ) {
581    return ( ( num % div ) + div ) % div;
582  };
583  
584  // ----- makeArray ----- //
585  
586  var arraySlice = Array.prototype.slice;
587  
588  // turn element or nodeList into an array
589  utils.makeArray = function( obj ) {
590    if ( Array.isArray( obj ) ) {
591      // use object if already an array
592      return obj;
593    }
594    // return empty array if undefined or null. #6
595    if ( obj === null || obj === undefined ) {
596      return [];
597    }
598  
599    var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
600    if ( isArrayLike ) {
601      // convert nodeList to array
602      return arraySlice.call( obj );
603    }
604  
605    // array of single index
606    return [ obj ];
607  };
608  
609  // ----- removeFrom ----- //
610  
611  utils.removeFrom = function( ary, obj ) {
612    var index = ary.indexOf( obj );
613    if ( index != -1 ) {
614      ary.splice( index, 1 );
615    }
616  };
617  
618  // ----- getParent ----- //
619  
620  utils.getParent = function( elem, selector ) {
621    while ( elem.parentNode && elem != document.body ) {
622      elem = elem.parentNode;
623      if ( matchesSelector( elem, selector ) ) {
624        return elem;
625      }
626    }
627  };
628  
629  // ----- getQueryElement ----- //
630  
631  // use element as selector string
632  utils.getQueryElement = function( elem ) {
633    if ( typeof elem == 'string' ) {
634      return document.querySelector( elem );
635    }
636    return elem;
637  };
638  
639  // ----- handleEvent ----- //
640  
641  // enable .ontype to trigger from .addEventListener( elem, 'type' )
642  utils.handleEvent = function( event ) {
643    var method = 'on' + event.type;
644    if ( this[ method ] ) {
645      this[ method ]( event );
646    }
647  };
648  
649  // ----- filterFindElements ----- //
650  
651  utils.filterFindElements = function( elems, selector ) {
652    // make array of elems
653    elems = utils.makeArray( elems );
654    var ffElems = [];
655  
656    elems.forEach( function( elem ) {
657      // check that elem is an actual element
658      if ( !( elem instanceof HTMLElement ) ) {
659        return;
660      }
661      // add elem if no selector
662      if ( !selector ) {
663        ffElems.push( elem );
664        return;
665      }
666      // filter & find items if we have a selector
667      // filter
668      if ( matchesSelector( elem, selector ) ) {
669        ffElems.push( elem );
670      }
671      // find children
672      var childElems = elem.querySelectorAll( selector );
673      // concat childElems to filterFound array
674      for ( var i=0; i < childElems.length; i++ ) {
675        ffElems.push( childElems[i] );
676      }
677    });
678  
679    return ffElems;
680  };
681  
682  // ----- debounceMethod ----- //
683  
684  utils.debounceMethod = function( _class, methodName, threshold ) {
685    threshold = threshold || 100;
686    // original method
687    var method = _class.prototype[ methodName ];
688    var timeoutName = methodName + 'Timeout';
689  
690    _class.prototype[ methodName ] = function() {
691      var timeout = this[ timeoutName ];
692      clearTimeout( timeout );
693  
694      var args = arguments;
695      var _this = this;
696      this[ timeoutName ] = setTimeout( function() {
697        method.apply( _this, args );
698        delete _this[ timeoutName ];
699      }, threshold );
700    };
701  };
702  
703  // ----- docReady ----- //
704  
705  utils.docReady = function( callback ) {
706    var readyState = document.readyState;
707    if ( readyState == 'complete' || readyState == 'interactive' ) {
708      // do async to allow for other scripts to run. metafizzy/flickity#441
709      setTimeout( callback );
710    } else {
711      document.addEventListener( 'DOMContentLoaded', callback );
712    }
713  };
714  
715  // ----- htmlInit ----- //
716  
717  // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
718  utils.toDashed = function( str ) {
719    return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
720      return $1 + '-' + $2;
721    }).toLowerCase();
722  };
723  
724  var console = window.console;
725  /**
726   * allow user to initialize classes via [data-namespace] or .js-namespace class
727   * htmlInit( Widget, 'widgetName' )
728   * options are parsed from data-namespace-options
729   */
730  utils.htmlInit = function( WidgetClass, namespace ) {
731    utils.docReady( function() {
732      var dashedNamespace = utils.toDashed( namespace );
733      var dataAttr = 'data-' + dashedNamespace;
734      var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
735      var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
736      var elems = utils.makeArray( dataAttrElems )
737        .concat( utils.makeArray( jsDashElems ) );
738      var dataOptionsAttr = dataAttr + '-options';
739      var jQuery = window.jQuery;
740  
741      elems.forEach( function( elem ) {
742        var attr = elem.getAttribute( dataAttr ) ||
743          elem.getAttribute( dataOptionsAttr );
744        var options;
745        try {
746          options = attr && JSON.parse( attr );
747        } catch ( error ) {
748          // log error, do not initialize
749          if ( console ) {
750            console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
751            ': ' + error );
752          }
753          return;
754        }
755        // initialize
756        var instance = new WidgetClass( elem, options );
757        // make available via $().data('namespace')
758        if ( jQuery ) {
759          jQuery.data( elem, namespace, instance );
760        }
761      });
762  
763    });
764  };
765  
766  // -----  ----- //
767  
768  return utils;
769  
770  }));
771  
772  /**
773   * Outlayer Item
774   */
775  
776  ( function( window, factory ) {
777    // universal module definition
778    /* jshint strict: false */ /* globals define, module, require */
779    if ( typeof define == 'function' && define.amd ) {
780      // AMD - RequireJS
781      define( 'outlayer/item',[
782          'ev-emitter/ev-emitter',
783          'get-size/get-size'
784        ],
785        factory
786      );
787    } else if ( typeof module == 'object' && module.exports ) {
788      // CommonJS - Browserify, Webpack
789      module.exports = factory(
790        require('ev-emitter'),
791        require('get-size')
792      );
793    } else {
794      // browser global
795      window.Outlayer = {};
796      window.Outlayer.Item = factory(
797        window.EvEmitter,
798        window.getSize
799      );
800    }
801  
802  }( window, function factory( EvEmitter, getSize ) {
803  'use strict';
804  
805  // ----- helpers ----- //
806  
807  function isEmptyObj( obj ) {
808    for ( var prop in obj ) {
809      return false;
810    }
811    prop = null;
812    return true;
813  }
814  
815  // -------------------------- CSS3 support -------------------------- //
816  
817  
818  var docElemStyle = document.documentElement.style;
819  
820  var transitionProperty = typeof docElemStyle.transition == 'string' ?
821    'transition' : 'WebkitTransition';
822  var transformProperty = typeof docElemStyle.transform == 'string' ?
823    'transform' : 'WebkitTransform';
824  
825  var transitionEndEvent = {
826    WebkitTransition: 'webkitTransitionEnd',
827    transition: 'transitionend'
828  }[ transitionProperty ];
829  
830  // cache all vendor properties that could have vendor prefix
831  var vendorProperties = {
832    transform: transformProperty,
833    transition: transitionProperty,
834    transitionDuration: transitionProperty + 'Duration',
835    transitionProperty: transitionProperty + 'Property',
836    transitionDelay: transitionProperty + 'Delay'
837  };
838  
839  // -------------------------- Item -------------------------- //
840  
841  function Item( element, layout ) {
842    if ( !element ) {
843      return;
844    }
845  
846    this.element = element;
847    // parent layout class, i.e. Masonry, Isotope, or Packery
848    this.layout = layout;
849    this.position = {
850      x: 0,
851      y: 0
852    };
853  
854    this._create();
855  }
856  
857  // inherit EvEmitter
858  var proto = Item.prototype = Object.create( EvEmitter.prototype );
859  proto.constructor = Item;
860  
861  proto._create = function() {
862    // transition objects
863    this._transn = {
864      ingProperties: {},
865      clean: {},
866      onEnd: {}
867    };
868  
869    this.css({
870      position: 'absolute'
871    });
872  };
873  
874  // trigger specified handler for event type
875  proto.handleEvent = function( event ) {
876    var method = 'on' + event.type;
877    if ( this[ method ] ) {
878      this[ method ]( event );
879    }
880  };
881  
882  proto.getSize = function() {
883    this.size = getSize( this.element );
884  };
885  
886  /**
887   * apply CSS styles to element
888   * @param {Object} style
889   */
890  proto.css = function( style ) {
891    var elemStyle = this.element.style;
892  
893    for ( var prop in style ) {
894      // use vendor property if available
895      var supportedProp = vendorProperties[ prop ] || prop;
896      elemStyle[ supportedProp ] = style[ prop ];
897    }
898  };
899  
900   // measure position, and sets it
901  proto.getPosition = function() {
902    var style = getComputedStyle( this.element );
903    var isOriginLeft = this.layout._getOption('originLeft');
904    var isOriginTop = this.layout._getOption('originTop');
905    var xValue = style[ isOriginLeft ? 'left' : 'right' ];
906    var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
907    var x = parseFloat( xValue );
908    var y = parseFloat( yValue );
909    // convert percent to pixels
910    var layoutSize = this.layout.size;
911    if ( xValue.indexOf('%') != -1 ) {
912      x = ( x / 100 ) * layoutSize.width;
913    }
914    if ( yValue.indexOf('%') != -1 ) {
915      y = ( y / 100 ) * layoutSize.height;
916    }
917    // clean up 'auto' or other non-integer values
918    x = isNaN( x ) ? 0 : x;
919    y = isNaN( y ) ? 0 : y;
920    // remove padding from measurement
921    x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
922    y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
923  
924    this.position.x = x;
925    this.position.y = y;
926  };
927  
928  // set settled position, apply padding
929  proto.layoutPosition = function() {
930    var layoutSize = this.layout.size;
931    var style = {};
932    var isOriginLeft = this.layout._getOption('originLeft');
933    var isOriginTop = this.layout._getOption('originTop');
934  
935    // x
936    var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
937    var xProperty = isOriginLeft ? 'left' : 'right';
938    var xResetProperty = isOriginLeft ? 'right' : 'left';
939  
940    var x = this.position.x + layoutSize[ xPadding ];
941    // set in percentage or pixels
942    style[ xProperty ] = this.getXValue( x );
943    // reset other property
944    style[ xResetProperty ] = '';
945  
946    // y
947    var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
948    var yProperty = isOriginTop ? 'top' : 'bottom';
949    var yResetProperty = isOriginTop ? 'bottom' : 'top';
950  
951    var y = this.position.y + layoutSize[ yPadding ];
952    // set in percentage or pixels
953    style[ yProperty ] = this.getYValue( y );
954    // reset other property
955    style[ yResetProperty ] = '';
956  
957    this.css( style );
958    this.emitEvent( 'layout', [ this ] );
959  };
960  
961  proto.getXValue = function( x ) {
962    var isHorizontal = this.layout._getOption('horizontal');
963    return this.layout.options.percentPosition && !isHorizontal ?
964      ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
965  };
966  
967  proto.getYValue = function( y ) {
968    var isHorizontal = this.layout._getOption('horizontal');
969    return this.layout.options.percentPosition && isHorizontal ?
970      ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
971  };
972  
973  proto._transitionTo = function( x, y ) {
974    this.getPosition();
975    // get current x & y from top/left
976    var curX = this.position.x;
977    var curY = this.position.y;
978  
979    var didNotMove = x == this.position.x && y == this.position.y;
980  
981    // save end position
982    this.setPosition( x, y );
983  
984    // if did not move and not transitioning, just go to layout
985    if ( didNotMove && !this.isTransitioning ) {
986      this.layoutPosition();
987      return;
988    }
989  
990    var transX = x - curX;
991    var transY = y - curY;
992    var transitionStyle = {};
993    transitionStyle.transform = this.getTranslate( transX, transY );
994  
995    this.transition({
996      to: transitionStyle,
997      onTransitionEnd: {
998        transform: this.layoutPosition
999      },
1000      isCleaning: true
1001    });
1002  };
1003  
1004  proto.getTranslate = function( x, y ) {
1005    // flip cooridinates if origin on right or bottom
1006    var isOriginLeft = this.layout._getOption('originLeft');
1007    var isOriginTop = this.layout._getOption('originTop');
1008    x = isOriginLeft ? x : -x;
1009    y = isOriginTop ? y : -y;
1010    return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1011  };
1012  
1013  // non transition + transform support
1014  proto.goTo = function( x, y ) {
1015    this.setPosition( x, y );
1016    this.layoutPosition();
1017  };
1018  
1019  proto.moveTo = proto._transitionTo;
1020  
1021  proto.setPosition = function( x, y ) {
1022    this.position.x = parseFloat( x );
1023    this.position.y = parseFloat( y );
1024  };
1025  
1026  // ----- transition ----- //
1027  
1028  /**
1029   * @param {Object} style - CSS
1030   * @param {Function} onTransitionEnd
1031   */
1032  
1033  // non transition, just trigger callback
1034  proto._nonTransition = function( args ) {
1035    this.css( args.to );
1036    if ( args.isCleaning ) {
1037      this._removeStyles( args.to );
1038    }
1039    for ( var prop in args.onTransitionEnd ) {
1040      args.onTransitionEnd[ prop ].call( this );
1041    }
1042  };
1043  
1044  /**
1045   * proper transition
1046   * @param {Object} args - arguments
1047   *   @param {Object} to - style to transition to
1048   *   @param {Object} from - style to start transition from
1049   *   @param {Boolean} isCleaning - removes transition styles after transition
1050   *   @param {Function} onTransitionEnd - callback
1051   */
1052  proto.transition = function( args ) {
1053    // redirect to nonTransition if no transition duration
1054    if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1055      this._nonTransition( args );
1056      return;
1057    }
1058  
1059    var _transition = this._transn;
1060    // keep track of onTransitionEnd callback by css property
1061    for ( var prop in args.onTransitionEnd ) {
1062      _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1063    }
1064    // keep track of properties that are transitioning
1065    for ( prop in args.to ) {
1066      _transition.ingProperties[ prop ] = true;
1067      // keep track of properties to clean up when transition is done
1068      if ( args.isCleaning ) {
1069        _transition.clean[ prop ] = true;
1070      }
1071    }
1072  
1073    // set from styles
1074    if ( args.from ) {
1075      this.css( args.from );
1076      // force redraw. http://blog.alexmaccaw.com/css-transitions
1077      var h = this.element.offsetHeight;
1078      // hack for JSHint to hush about unused var
1079      h = null;
1080    }
1081    // enable transition
1082    this.enableTransition( args.to );
1083    // set styles that are transitioning
1084    this.css( args.to );
1085  
1086    this.isTransitioning = true;
1087  
1088  };
1089  
1090  // dash before all cap letters, including first for
1091  // WebkitTransform => -webkit-transform
1092  function toDashedAll( str ) {
1093    return str.replace( /([A-Z])/g, function( $1 ) {
1094      return '-' + $1.toLowerCase();
1095    });
1096  }
1097  
1098  var transitionProps = 'opacity,' + toDashedAll( transformProperty );
1099  
1100  proto.enableTransition = function(/* style */) {
1101    // HACK changing transitionProperty during a transition
1102    // will cause transition to jump
1103    if ( this.isTransitioning ) {
1104      return;
1105    }
1106  
1107    // make `transition: foo, bar, baz` from style object
1108    // HACK un-comment this when enableTransition can work
1109    // while a transition is happening
1110    // var transitionValues = [];
1111    // for ( var prop in style ) {
1112    //   // dash-ify camelCased properties like WebkitTransition
vendor: 2,890 bytes, lines 1113-1208
1113    //   prop = vendorProperties[ prop ] || prop;
1114    //   transitionValues.push( toDashedAll( prop ) );
1115    // }
1116    // munge number to millisecond, to match stagger
1117    var duration = this.layout.options.transitionDuration;
1118    duration = typeof duration == 'number' ? duration + 'ms' : duration;
1119    // enable transition styles
1120    this.css({
1121      transitionProperty: transitionProps,
1122      transitionDuration: duration,
1123      transitionDelay: this.staggerDelay || 0
1124    });
1125    // listen for transition end event
1126    this.element.addEventListener( transitionEndEvent, this, false );
1127  };
1128  
1129  // ----- events ----- //
1130  
1131  proto.onwebkitTransitionEnd = function( event ) {
1132    this.ontransitionend( event );
1133  };
1134  
1135  proto.onotransitionend = function( event ) {
1136    this.ontransitionend( event );
1137  };
1138  
1139  // properties that I munge to make my life easier
1140  var dashedVendorProperties = {
1141    '-webkit-transform': 'transform'
1142  };
1143  
1144  proto.ontransitionend = function( event ) {
1145    // disregard bubbled events from children
1146    if ( event.target !== this.element ) {
1147      return;
1148    }
1149    var _transition = this._transn;
1150    // get property name of transitioned property, convert to prefix-free
1151    var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1152  
1153    // remove property that has completed transitioning
1154    delete _transition.ingProperties[ propertyName ];
1155    // check if any properties are still transitioning
1156    if ( isEmptyObj( _transition.ingProperties ) ) {
1157      // all properties have completed transitioning
1158      this.disableTransition();
1159    }
1160    // clean style
1161    if ( propertyName in _transition.clean ) {
1162      // clean up style
1163      this.element.style[ event.propertyName ] = '';
1164      delete _transition.clean[ propertyName ];
1165    }
1166    // trigger onTransitionEnd callback
1167    if ( propertyName in _transition.onEnd ) {
1168      var onTransitionEnd = _transition.onEnd[ propertyName ];
1169      onTransitionEnd.call( this );
1170      delete _transition.onEnd[ propertyName ];
1171    }
1172  
1173    this.emitEvent( 'transitionEnd', [ this ] );
1174  };
1175  
1176  proto.disableTransition = function() {
1177    this.removeTransitionStyles();
1178    this.element.removeEventListener( transitionEndEvent, this, false );
1179    this.isTransitioning = false;
1180  };
1181  
1182  /**
1183   * removes style property from element
1184   * @param {Object} style
1185  **/
1186  proto._removeStyles = function( style ) {
1187    // clean up transition styles
1188    var cleanStyle = {};
1189    for ( var prop in style ) {
1190      cleanStyle[ prop ] = '';
1191    }
1192    this.css( cleanStyle );
1193  };
1194  
1195  var cleanTransitionStyle = {
1196    transitionProperty: '',
1197    transitionDuration: '',
1198    transitionDelay: ''
1199  };
1200  
1201  proto.removeTransitionStyles = function() {
1202    // remove transition
1203    this.css( cleanTransitionStyle );
1204  };
1205  
1206  // ----- stagger ----- //
1207  
1208  proto.stagger = function( delay ) {
vendor: 9,172 bytes, lines 1209-1570
1209    delay = isNaN( delay ) ? 0 : delay;
1210    this.staggerDelay = delay + 'ms';
1211  };
1212  
1213  // ----- show/hide/remove ----- //
1214  
1215  // remove element from DOM
1216  proto.removeElem = function() {
1217    this.element.parentNode.removeChild( this.element );
1218    // remove display: none
1219    this.css({ display: '' });
1220    this.emitEvent( 'remove', [ this ] );
1221  };
1222  
1223  proto.remove = function() {
1224    // just remove element if no transition support or no transition
1225    if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1226      this.removeElem();
1227      return;
1228    }
1229  
1230    // start transition
1231    this.once( 'transitionEnd', function() {
1232      this.removeElem();
1233    });
1234    this.hide();
1235  };
1236  
1237  proto.reveal = function() {
1238    delete this.isHidden;
1239    // remove display: none
1240    this.css({ display: '' });
1241  
1242    var options = this.layout.options;
1243  
1244    var onTransitionEnd = {};
1245    var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1246    onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
1247  
1248    this.transition({
1249      from: options.hiddenStyle,
1250      to: options.visibleStyle,
1251      isCleaning: true,
1252      onTransitionEnd: onTransitionEnd
1253    });
1254  };
1255  
1256  proto.onRevealTransitionEnd = function() {
1257    // check if still visible
1258    // during transition, item may have been hidden
1259    if ( !this.isHidden ) {
1260      this.emitEvent('reveal');
1261    }
1262  };
1263  
1264  /**
1265   * get style property use for hide/reveal transition end
1266   * @param {String} styleProperty - hiddenStyle/visibleStyle
1267   * @returns {String}
1268   */
1269  proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
1270    var optionStyle = this.layout.options[ styleProperty ];
1271    // use opacity
1272    if ( optionStyle.opacity ) {
1273      return 'opacity';
1274    }
1275    // get first property
1276    for ( var prop in optionStyle ) {
1277      return prop;
1278    }
1279  };
1280  
1281  proto.hide = function() {
1282    // set flag
1283    this.isHidden = true;
1284    // remove display: none
1285    this.css({ display: '' });
1286  
1287    var options = this.layout.options;
1288  
1289    var onTransitionEnd = {};
1290    var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
1291    onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
1292  
1293    this.transition({
1294      from: options.visibleStyle,
1295      to: options.hiddenStyle,
1296      // keep hidden stuff hidden
1297      isCleaning: true,
1298      onTransitionEnd: onTransitionEnd
1299    });
1300  };
1301  
1302  proto.onHideTransitionEnd = function() {
1303    // check if still hidden
1304    // during transition, item may have been un-hidden
1305    if ( this.isHidden ) {
1306      this.css({ display: 'none' });
1307      this.emitEvent('hide');
1308    }
1309  };
1310  
1311  proto.destroy = function() {
1312    this.css({
1313      position: '',
1314      left: '',
1315      right: '',
1316      top: '',
1317      bottom: '',
1318      transition: '',
1319      transform: ''
1320    });
1321  };
1322  
1323  return Item;
1324  
1325  }));
1326  
1327  /*!
1328   * Outlayer v2.1.1
1329   * the brains and guts of a layout library
1330   * MIT license
1331   */
1332  
1333  ( function( window, factory ) {
1334    'use strict';
1335    // universal module definition
1336    /* jshint strict: false */ /* globals define, module, require */
1337    if ( typeof define == 'function' && define.amd ) {
1338      // AMD - RequireJS
1339      define( 'outlayer/outlayer',[
1340          'ev-emitter/ev-emitter',
1341          'get-size/get-size',
1342          'fizzy-ui-utils/utils',
1343          './item'
1344        ],
1345        function( EvEmitter, getSize, utils, Item ) {
1346          return factory( window, EvEmitter, getSize, utils, Item);
1347        }
1348      );
1349    } else if ( typeof module == 'object' && module.exports ) {
1350      // CommonJS - Browserify, Webpack
1351      module.exports = factory(
1352        window,
1353        require('ev-emitter'),
1354        require('get-size'),
1355        require('fizzy-ui-utils'),
1356        require('./item')
1357      );
1358    } else {
1359      // browser global
1360      window.Outlayer = factory(
1361        window,
1362        window.EvEmitter,
1363        window.getSize,
1364        window.fizzyUIUtils,
1365        window.Outlayer.Item
1366      );
1367    }
1368  
1369  }( window, function factory( window, EvEmitter, getSize, utils, Item ) {
1370  'use strict';
1371  
1372  // ----- vars ----- //
1373  
1374  var console = window.console;
1375  var jQuery = window.jQuery;
1376  var noop = function() {};
1377  
1378  // -------------------------- Outlayer -------------------------- //
1379  
1380  // globally unique identifiers
1381  var GUID = 0;
1382  // internal store of all Outlayer intances
1383  var instances = {};
1384  
1385  
1386  /**
1387   * @param {Element, String} element
1388   * @param {Object} options
1389   * @constructor
1390   */
1391  function Outlayer( element, options ) {
1392    var queryElement = utils.getQueryElement( element );
1393    if ( !queryElement ) {
1394      if ( console ) {
1395        console.error( 'Bad element for ' + this.constructor.namespace +
1396          ': ' + ( queryElement || element ) );
1397      }
1398      return;
1399    }
1400    this.element = queryElement;
1401    // add jQuery
1402    if ( jQuery ) {
1403      this.$element = jQuery( this.element );
1404    }
1405  
1406    // options
1407    this.options = utils.extend( {}, this.constructor.defaults );
1408    this.option( options );
1409  
1410    // add id for Outlayer.getFromElement
1411    var id = ++GUID;
1412    this.element.outlayerGUID = id; // expando
1413    instances[ id ] = this; // associate via id
1414  
1415    // kick it off
1416    this._create();
1417  
1418    var isInitLayout = this._getOption('initLayout');
1419    if ( isInitLayout ) {
1420      this.layout();
1421    }
1422  }
1423  
1424  // settings are for internal use only
1425  Outlayer.namespace = 'outlayer';
1426  Outlayer.Item = Item;
1427  
1428  // default options
1429  Outlayer.defaults = {
1430    containerStyle: {
1431      position: 'relative'
1432    },
1433    initLayout: true,
1434    originLeft: true,
1435    originTop: true,
1436    resize: true,
1437    resizeContainer: true,
1438    // item options
1439    transitionDuration: '0.4s',
1440    hiddenStyle: {
1441      opacity: 0,
1442      transform: 'scale(0.001)'
1443    },
1444    visibleStyle: {
1445      opacity: 1,
1446      transform: 'scale(1)'
1447    }
1448  };
1449  
1450  var proto = Outlayer.prototype;
1451  // inherit EvEmitter
1452  utils.extend( proto, EvEmitter.prototype );
1453  
1454  /**
1455   * set options
1456   * @param {Object} opts
1457   */
1458  proto.option = function( opts ) {
1459    utils.extend( this.options, opts );
1460  };
1461  
1462  /**
1463   * get backwards compatible option value, check old name
1464   */
1465  proto._getOption = function( option ) {
1466    var oldOption = this.constructor.compatOptions[ option ];
1467    return oldOption && this.options[ oldOption ] !== undefined ?
1468      this.options[ oldOption ] : this.options[ option ];
1469  };
1470  
1471  Outlayer.compatOptions = {
1472    // currentName: oldName
1473    initLayout: 'isInitLayout',
1474    horizontal: 'isHorizontal',
1475    layoutInstant: 'isLayoutInstant',
1476    originLeft: 'isOriginLeft',
1477    originTop: 'isOriginTop',
1478    resize: 'isResizeBound',
1479    resizeContainer: 'isResizingContainer'
1480  };
1481  
1482  proto._create = function() {
1483    // get items from children
1484    this.reloadItems();
1485    // elements that affect layout, but are not laid out
1486    this.stamps = [];
1487    this.stamp( this.options.stamp );
1488    // set container style
1489    utils.extend( this.element.style, this.options.containerStyle );
1490  
1491    // bind resize method
1492    var canBindResize = this._getOption('resize');
1493    if ( canBindResize ) {
1494      this.bindResize();
1495    }
1496  };
1497  
1498  // goes through all children again and gets bricks in proper order
1499  proto.reloadItems = function() {
1500    // collection of item elements
1501    this.items = this._itemize( this.element.children );
1502  };
1503  
1504  
1505  /**
1506   * turn elements into Outlayer.Items to be used in layout
1507   * @param {Array or NodeList or HTMLElement} elems
1508   * @returns {Array} items - collection of new Outlayer Items
1509   */
1510  proto._itemize = function( elems ) {
1511  
1512    var itemElems = this._filterFindItemElements( elems );
1513    var Item = this.constructor.Item;
1514  
1515    // create new Outlayer Items for collection
1516    var items = [];
1517    for ( var i=0; i < itemElems.length; i++ ) {
1518      var elem = itemElems[i];
1519      var item = new Item( elem, this );
1520      items.push( item );
1521    }
1522  
1523    return items;
1524  };
1525  
1526  /**
1527   * get item elements to be used in layout
1528   * @param {Array or NodeList or HTMLElement} elems
1529   * @returns {Array} items - item elements
1530   */
1531  proto._filterFindItemElements = function( elems ) {
1532    return utils.filterFindElements( elems, this.options.itemSelector );
1533  };
1534  
1535  /**
1536   * getter method for getting item elements
1537   * @returns {Array} elems - collection of item elements
1538   */
1539  proto.getItemElements = function() {
1540    return this.items.map( function( item ) {
1541      return item.element;
1542    });
1543  };
1544  
1545  // ----- init & layout ----- //
1546  
1547  /**
1548   * lays out all items
1549   */
1550  proto.layout = function() {
1551    this._resetLayout();
1552    this._manageStamps();
1553  
1554    // don't animate first layout
1555    var layoutInstant = this._getOption('layoutInstant');
1556    var isInstant = layoutInstant !== undefined ?
1557      layoutInstant : !this._isLayoutInited;
1558    this.layoutItems( this.items, isInstant );
1559  
1560    // flag for initalized
1561    this._isLayoutInited = true;
1562  };
1563  
1564  // _init is alias for layout
1565  proto._init = proto.layout;
1566  
1567  /**
1568   * logic before any new layout
1569   */
1570  proto._resetLayout = function() {
vendor: 14,286 bytes, lines 1571-2126
1571    this.getSize();
1572  };
1573  
1574  
1575  proto.getSize = function() {
1576    this.size = getSize( this.element );
1577  };
1578  
1579  /**
1580   * get measurement from option, for columnWidth, rowHeight, gutter
1581   * if option is String -> get element from selector string, & get size of element
1582   * if option is Element -> get size of element
1583   * else use option as a number
1584   *
1585   * @param {String} measurement
1586   * @param {String} size - width or height
1587   * @private
1588   */
1589  proto._getMeasurement = function( measurement, size ) {
1590    var option = this.options[ measurement ];
1591    var elem;
1592    if ( !option ) {
1593      // default to 0
1594      this[ measurement ] = 0;
1595    } else {
1596      // use option as an element
1597      if ( typeof option == 'string' ) {
1598        elem = this.element.querySelector( option );
1599      } else if ( option instanceof HTMLElement ) {
1600        elem = option;
1601      }
1602      // use size of element, if element
1603      this[ measurement ] = elem ? getSize( elem )[ size ] : option;
1604    }
1605  };
1606  
1607  /**
1608   * layout a collection of item elements
1609   * @api public
1610   */
1611  proto.layoutItems = function( items, isInstant ) {
1612    items = this._getItemsForLayout( items );
1613  
1614    this._layoutItems( items, isInstant );
1615  
1616    this._postLayout();
1617  };
1618  
1619  /**
1620   * get the items to be laid out
1621   * you may want to skip over some items
1622   * @param {Array} items
1623   * @returns {Array} items
1624   */
1625  proto._getItemsForLayout = function( items ) {
1626    return items.filter( function( item ) {
1627      return !item.isIgnored;
1628    });
1629  };
1630  
1631  /**
1632   * layout items
1633   * @param {Array} items
1634   * @param {Boolean} isInstant
1635   */
1636  proto._layoutItems = function( items, isInstant ) {
1637    this._emitCompleteOnItems( 'layout', items );
1638  
1639    if ( !items || !items.length ) {
1640      // no items, emit event with empty array
1641      return;
1642    }
1643  
1644    var queue = [];
1645  
1646    items.forEach( function( item ) {
1647      // get x/y object from method
1648      var position = this._getItemLayoutPosition( item );
1649      // enqueue
1650      position.item = item;
1651      position.isInstant = isInstant || item.isLayoutInstant;
1652      queue.push( position );
1653    }, this );
1654  
1655    this._processLayoutQueue( queue );
1656  };
1657  
1658  /**
1659   * get item layout position
1660   * @param {Outlayer.Item} item
1661   * @returns {Object} x and y position
1662   */
1663  proto._getItemLayoutPosition = function( /* item */ ) {
1664    return {
1665      x: 0,
1666      y: 0
1667    };
1668  };
1669  
1670  /**
1671   * iterate over array and position each item
1672   * Reason being - separating this logic prevents 'layout invalidation'
1673   * thx @paul_irish
1674   * @param {Array} queue
1675   */
1676  proto._processLayoutQueue = function( queue ) {
1677    this.updateStagger();
1678    queue.forEach( function( obj, i ) {
1679      this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
1680    }, this );
1681  };
1682  
1683  // set stagger from option in milliseconds number
1684  proto.updateStagger = function() {
1685    var stagger = this.options.stagger;
1686    if ( stagger === null || stagger === undefined ) {
1687      this.stagger = 0;
1688      return;
1689    }
1690    this.stagger = getMilliseconds( stagger );
1691    return this.stagger;
1692  };
1693  
1694  /**
1695   * Sets position of item in DOM
1696   * @param {Outlayer.Item} item
1697   * @param {Number} x - horizontal position
1698   * @param {Number} y - vertical position
1699   * @param {Boolean} isInstant - disables transitions
1700   */
1701  proto._positionItem = function( item, x, y, isInstant, i ) {
1702    if ( isInstant ) {
1703      // if not transition, just set CSS
1704      item.goTo( x, y );
1705    } else {
1706      item.stagger( i * this.stagger );
1707      item.moveTo( x, y );
1708    }
1709  };
1710  
1711  /**
1712   * Any logic you want to do after each layout,
1713   * i.e. size the container
1714   */
1715  proto._postLayout = function() {
1716    this.resizeContainer();
1717  };
1718  
1719  proto.resizeContainer = function() {
1720    var isResizingContainer = this._getOption('resizeContainer');
1721    if ( !isResizingContainer ) {
1722      return;
1723    }
1724    var size = this._getContainerSize();
1725    if ( size ) {
1726      this._setContainerMeasure( size.width, true );
1727      this._setContainerMeasure( size.height, false );
1728    }
1729  };
1730  
1731  /**
1732   * Sets width or height of container if returned
1733   * @returns {Object} size
1734   *   @param {Number} width
1735   *   @param {Number} height
1736   */
1737  proto._getContainerSize = noop;
1738  
1739  /**
1740   * @param {Number} measure - size of width or height
1741   * @param {Boolean} isWidth
1742   */
1743  proto._setContainerMeasure = function( measure, isWidth ) {
1744    if ( measure === undefined ) {
1745      return;
1746    }
1747  
1748    var elemSize = this.size;
1749    // add padding and border width if border box
1750    if ( elemSize.isBorderBox ) {
1751      measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
1752        elemSize.borderLeftWidth + elemSize.borderRightWidth :
1753        elemSize.paddingBottom + elemSize.paddingTop +
1754        elemSize.borderTopWidth + elemSize.borderBottomWidth;
1755    }
1756  
1757    measure = Math.max( measure, 0 );
1758    this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
1759  };
1760  
1761  /**
1762   * emit eventComplete on a collection of items events
1763   * @param {String} eventName
1764   * @param {Array} items - Outlayer.Items
1765   */
1766  proto._emitCompleteOnItems = function( eventName, items ) {
1767    var _this = this;
1768    function onComplete() {
1769      _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
1770    }
1771  
1772    var count = items.length;
1773    if ( !items || !count ) {
1774      onComplete();
1775      return;
1776    }
1777  
1778    var doneCount = 0;
1779    function tick() {
1780      doneCount++;
1781      if ( doneCount == count ) {
1782        onComplete();
1783      }
1784    }
1785  
1786    // bind callback
1787    items.forEach( function( item ) {
1788      item.once( eventName, tick );
1789    });
1790  };
1791  
1792  /**
1793   * emits events via EvEmitter and jQuery events
1794   * @param {String} type - name of event
1795   * @param {Event} event - original event
1796   * @param {Array} args - extra arguments
1797   */
1798  proto.dispatchEvent = function( type, event, args ) {
1799    // add original event to arguments
1800    var emitArgs = event ? [ event ].concat( args ) : args;
1801    this.emitEvent( type, emitArgs );
1802  
1803    if ( jQuery ) {
1804      // set this.$element
1805      this.$element = this.$element || jQuery( this.element );
1806      if ( event ) {
1807        // create jQuery event
1808        var $event = jQuery.Event( event );
1809        $event.type = type;
1810        this.$element.trigger( $event, args );
1811      } else {
1812        // just trigger with type if no event available
1813        this.$element.trigger( type, args );
1814      }
1815    }
1816  };
1817  
1818  // -------------------------- ignore & stamps -------------------------- //
1819  
1820  
1821  /**
1822   * keep item in collection, but do not lay it out
1823   * ignored items do not get skipped in layout
1824   * @param {Element} elem
1825   */
1826  proto.ignore = function( elem ) {
1827    var item = this.getItem( elem );
1828    if ( item ) {
1829      item.isIgnored = true;
1830    }
1831  };
1832  
1833  /**
1834   * return item to layout collection
1835   * @param {Element} elem
1836   */
1837  proto.unignore = function( elem ) {
1838    var item = this.getItem( elem );
1839    if ( item ) {
1840      delete item.isIgnored;
1841    }
1842  };
1843  
1844  /**
1845   * adds elements to stamps
1846   * @param {NodeList, Array, Element, or String} elems
1847   */
1848  proto.stamp = function( elems ) {
1849    elems = this._find( elems );
1850    if ( !elems ) {
1851      return;
1852    }
1853  
1854    this.stamps = this.stamps.concat( elems );
1855    // ignore
1856    elems.forEach( this.ignore, this );
1857  };
1858  
1859  /**
1860   * removes elements to stamps
1861   * @param {NodeList, Array, or Element} elems
1862   */
1863  proto.unstamp = function( elems ) {
1864    elems = this._find( elems );
1865    if ( !elems ){
1866      return;
1867    }
1868  
1869    elems.forEach( function( elem ) {
1870      // filter out removed stamp elements
1871      utils.removeFrom( this.stamps, elem );
1872      this.unignore( elem );
1873    }, this );
1874  };
1875  
1876  /**
1877   * finds child elements
1878   * @param {NodeList, Array, Element, or String} elems
1879   * @returns {Array} elems
1880   */
1881  proto._find = function( elems ) {
1882    if ( !elems ) {
1883      return;
1884    }
1885    // if string, use argument as selector string
1886    if ( typeof elems == 'string' ) {
1887      elems = this.element.querySelectorAll( elems );
1888    }
1889    elems = utils.makeArray( elems );
1890    return elems;
1891  };
1892  
1893  proto._manageStamps = function() {
1894    if ( !this.stamps || !this.stamps.length ) {
1895      return;
1896    }
1897  
1898    this._getBoundingRect();
1899  
1900    this.stamps.forEach( this._manageStamp, this );
1901  };
1902  
1903  // update boundingLeft / Top
1904  proto._getBoundingRect = function() {
1905    // get bounding rect for container element
1906    var boundingRect = this.element.getBoundingClientRect();
1907    var size = this.size;
1908    this._boundingRect = {
1909      left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
1910      top: boundingRect.top + size.paddingTop + size.borderTopWidth,
1911      right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
1912      bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
1913    };
1914  };
1915  
1916  /**
1917   * @param {Element} stamp
1918  **/
1919  proto._manageStamp = noop;
1920  
1921  /**
1922   * get x/y position of element relative to container element
1923   * @param {Element} elem
1924   * @returns {Object} offset - has left, top, right, bottom
1925   */
1926  proto._getElementOffset = function( elem ) {
1927    var boundingRect = elem.getBoundingClientRect();
1928    var thisRect = this._boundingRect;
1929    var size = getSize( elem );
1930    var offset = {
1931      left: boundingRect.left - thisRect.left - size.marginLeft,
1932      top: boundingRect.top - thisRect.top - size.marginTop,
1933      right: thisRect.right - boundingRect.right - size.marginRight,
1934      bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
1935    };
1936    return offset;
1937  };
1938  
1939  // -------------------------- resize -------------------------- //
1940  
1941  // enable event handlers for listeners
1942  // i.e. resize -> onresize
1943  proto.handleEvent = utils.handleEvent;
1944  
1945  /**
1946   * Bind layout to window resizing
1947   */
1948  proto.bindResize = function() {
1949    window.addEventListener( 'resize', this );
1950    this.isResizeBound = true;
1951  };
1952  
1953  /**
1954   * Unbind layout to window resizing
1955   */
1956  proto.unbindResize = function() {
1957    window.removeEventListener( 'resize', this );
1958    this.isResizeBound = false;
1959  };
1960  
1961  proto.onresize = function() {
1962    this.resize();
1963  };
1964  
1965  utils.debounceMethod( Outlayer, 'onresize', 100 );
1966  
1967  proto.resize = function() {
1968    // don't trigger if size did not change
1969    // or if resize was unbound. See #9
1970    if ( !this.isResizeBound || !this.needsResizeLayout() ) {
1971      return;
1972    }
1973  
1974    this.layout();
1975  };
1976  
1977  /**
1978   * check if layout is needed post layout
1979   * @returns Boolean
1980   */
1981  proto.needsResizeLayout = function() {
1982    var size = getSize( this.element );
1983    // check that this.size and size are there
1984    // IE8 triggers resize on body size change, so they might not be
1985    var hasSizes = this.size && size;
1986    return hasSizes && size.innerWidth !== this.size.innerWidth;
1987  };
1988  
1989  // -------------------------- methods -------------------------- //
1990  
1991  /**
1992   * add items to Outlayer instance
1993   * @param {Array or NodeList or Element} elems
1994   * @returns {Array} items - Outlayer.Items
1995  **/
1996  proto.addItems = function( elems ) {
1997    var items = this._itemize( elems );
1998    // add items to collection
1999    if ( items.length ) {
2000      this.items = this.items.concat( items );
2001    }
2002    return items;
2003  };
2004  
2005  /**
2006   * Layout newly-appended item elements
2007   * @param {Array or NodeList or Element} elems
2008   */
2009  proto.appended = function( elems ) {
2010    var items = this.addItems( elems );
2011    if ( !items.length ) {
2012      return;
2013    }
2014    // layout and reveal just the new items
2015    this.layoutItems( items, true );
2016    this.reveal( items );
2017  };
2018  
2019  /**
2020   * Layout prepended elements
2021   * @param {Array or NodeList or Element} elems
2022   */
2023  proto.prepended = function( elems ) {
2024    var items = this._itemize( elems );
2025    if ( !items.length ) {
2026      return;
2027    }
2028    // add items to beginning of collection
2029    var previousItems = this.items.slice(0);
2030    this.items = items.concat( previousItems );
2031    // start new layout
2032    this._resetLayout();
2033    this._manageStamps();
2034    // layout new stuff without transition
2035    this.layoutItems( items, true );
2036    this.reveal( items );
2037    // layout previous items
2038    this.layoutItems( previousItems );
2039  };
2040  
2041  /**
2042   * reveal a collection of items
2043   * @param {Array of Outlayer.Items} items
2044   */
2045  proto.reveal = function( items ) {
2046    this._emitCompleteOnItems( 'reveal', items );
2047    if ( !items || !items.length ) {
2048      return;
2049    }
2050    var stagger = this.updateStagger();
2051    items.forEach( function( item, i ) {
2052      item.stagger( i * stagger );
2053      item.reveal();
2054    });
2055  };
2056  
2057  /**
2058   * hide a collection of items
2059   * @param {Array of Outlayer.Items} items
2060   */
2061  proto.hide = function( items ) {
2062    this._emitCompleteOnItems( 'hide', items );
2063    if ( !items || !items.length ) {
2064      return;
2065    }
2066    var stagger = this.updateStagger();
2067    items.forEach( function( item, i ) {
2068      item.stagger( i * stagger );
2069      item.hide();
2070    });
2071  };
2072  
2073  /**
2074   * reveal item elements
2075   * @param {Array}, {Element}, {NodeList} items
2076   */
2077  proto.revealItemElements = function( elems ) {
2078    var items = this.getItems( elems );
2079    this.reveal( items );
2080  };
2081  
2082  /**
2083   * hide item elements
2084   * @param {Array}, {Element}, {NodeList} items
2085   */
2086  proto.hideItemElements = function( elems ) {
2087    var items = this.getItems( elems );
2088    this.hide( items );
2089  };
2090  
2091  /**
2092   * get Outlayer.Item, given an Element
2093   * @param {Element} elem
2094   * @param {Function} callback
2095   * @returns {Outlayer.Item} item
2096   */
2097  proto.getItem = function( elem ) {
2098    // loop through items to get the one that matches
2099    for ( var i=0; i < this.items.length; i++ ) {
2100      var item = this.items[i];
2101      if ( item.element == elem ) {
2102        // return item
2103        return item;
2104      }
2105    }
2106  };
2107  
2108  /**
2109   * get collection of Outlayer.Items, given Elements
2110   * @param {Array} elems
2111   * @returns {Array} items - Outlayer.Items
2112   */
2113  proto.getItems = function( elems ) {
2114    elems = utils.makeArray( elems );
2115    var items = [];
2116    elems.forEach( function( elem ) {
2117      var item = this.getItem( elem );
2118      if ( item ) {
2119        items.push( item );
2120      }
2121    }, this );
2122  
2123    return items;
2124  };
2125  
2126  /**
vendor: 29,710 bytes, lines 2127-3177
2127   * remove element(s) from instance and DOM
2128   * @param {Array or NodeList or Element} elems
2129   */
2130  proto.remove = function( elems ) {
2131    var removeItems = this.getItems( elems );
2132  
2133    this._emitCompleteOnItems( 'remove', removeItems );
2134  
2135    // bail if no items to remove
2136    if ( !removeItems || !removeItems.length ) {
2137      return;
2138    }
2139  
2140    removeItems.forEach( function( item ) {
2141      item.remove();
2142      // remove item from collection
2143      utils.removeFrom( this.items, item );
2144    }, this );
2145  };
2146  
2147  // ----- destroy ----- //
2148  
2149  // remove and disable Outlayer instance
2150  proto.destroy = function() {
2151    // clean up dynamic styles
2152    var style = this.element.style;
2153    style.height = '';
2154    style.position = '';
2155    style.width = '';
2156    // destroy items
2157    this.items.forEach( function( item ) {
2158      item.destroy();
2159    });
2160  
2161    this.unbindResize();
2162  
2163    var id = this.element.outlayerGUID;
2164    delete instances[ id ]; // remove reference to instance by id
2165    delete this.element.outlayerGUID;
2166    // remove data for jQuery
2167    if ( jQuery ) {
2168      jQuery.removeData( this.element, this.constructor.namespace );
2169    }
2170  
2171  };
2172  
2173  // -------------------------- data -------------------------- //
2174  
2175  /**
2176   * get Outlayer instance from element
2177   * @param {Element} elem
2178   * @returns {Outlayer}
2179   */
2180  Outlayer.data = function( elem ) {
2181    elem = utils.getQueryElement( elem );
2182    var id = elem && elem.outlayerGUID;
2183    return id && instances[ id ];
2184  };
2185  
2186  
2187  // -------------------------- create Outlayer class -------------------------- //
2188  
2189  /**
2190   * create a layout class
2191   * @param {String} namespace
2192   */
2193  Outlayer.create = function( namespace, options ) {
2194    // sub-class Outlayer
2195    var Layout = subclass( Outlayer );
2196    // apply new options and compatOptions
2197    Layout.defaults = utils.extend( {}, Outlayer.defaults );
2198    utils.extend( Layout.defaults, options );
2199    Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );
2200  
2201    Layout.namespace = namespace;
2202  
2203    Layout.data = Outlayer.data;
2204  
2205    // sub-class Item
2206    Layout.Item = subclass( Item );
2207  
2208    // -------------------------- declarative -------------------------- //
2209  
2210    utils.htmlInit( Layout, namespace );
2211  
2212    // -------------------------- jQuery bridge -------------------------- //
2213  
2214    // make into jQuery plugin
2215    if ( jQuery && jQuery.bridget ) {
2216      jQuery.bridget( namespace, Layout );
2217    }
2218  
2219    return Layout;
2220  };
2221  
2222  function subclass( Parent ) {
2223    function SubClass() {
2224      Parent.apply( this, arguments );
2225    }
2226  
2227    SubClass.prototype = Object.create( Parent.prototype );
2228    SubClass.prototype.constructor = SubClass;
2229  
2230    return SubClass;
2231  }
2232  
2233  // ----- helpers ----- //
2234  
2235  // how many milliseconds are in each unit
2236  var msUnits = {
2237    ms: 1,
2238    s: 1000
2239  };
2240  
2241  // munge time-like parameter into millisecond number
2242  // '0.4s' -> 40
2243  function getMilliseconds( time ) {
2244    if ( typeof time == 'number' ) {
2245      return time;
2246    }
2247    var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
2248    var num = matches && matches[1];
2249    var unit = matches && matches[2];
2250    if ( !num.length ) {
2251      return 0;
2252    }
2253    num = parseFloat( num );
2254    var mult = msUnits[ unit ] || 1;
2255    return num * mult;
2256  }
2257  
2258  // ----- fin ----- //
2259  
2260  // back in global
2261  Outlayer.Item = Item;
2262  
2263  return Outlayer;
2264  
2265  }));
2266  
2267  /**
2268   * Isotope Item
2269  **/
2270  
2271  ( function( window, factory ) {
2272    // universal module definition
2273    /* jshint strict: false */ /*globals define, module, require */
2274    if ( typeof define == 'function' && define.amd ) {
2275      // AMD
2276      define( 'isotope-layout/js/item',[
2277          'outlayer/outlayer'
2278        ],
2279        factory );
2280    } else if ( typeof module == 'object' && module.exports ) {
2281      // CommonJS
2282      module.exports = factory(
2283        require('outlayer')
2284      );
2285    } else {
2286      // browser global
2287      window.Isotope = window.Isotope || {};
2288      window.Isotope.Item = factory(
2289        window.Outlayer
2290      );
2291    }
2292  
2293  }( window, function factory( Outlayer ) {
2294  'use strict';
2295  
2296  // -------------------------- Item -------------------------- //
2297  
2298  // sub-class Outlayer Item
2299  function Item() {
2300    Outlayer.Item.apply( this, arguments );
2301  }
2302  
2303  var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
2304  
2305  var _create = proto._create;
2306  proto._create = function() {
2307    // assign id, used for original-order sorting
2308    this.id = this.layout.itemGUID++;
2309    _create.call( this );
2310    this.sortData = {};
2311  };
2312  
2313  proto.updateSortData = function() {
2314    if ( this.isIgnored ) {
2315      return;
2316    }
2317    // default sorters
2318    this.sortData.id = this.id;
2319    // for backward compatibility
2320    this.sortData['original-order'] = this.id;
2321    this.sortData.random = Math.random();
2322    // go thru getSortData obj and apply the sorters
2323    var getSortData = this.layout.options.getSortData;
2324    var sorters = this.layout._sorters;
2325    for ( var key in getSortData ) {
2326      var sorter = sorters[ key ];
2327      this.sortData[ key ] = sorter( this.element, this );
2328    }
2329  };
2330  
2331  var _destroy = proto.destroy;
2332  proto.destroy = function() {
2333    // call super
2334    _destroy.apply( this, arguments );
2335    // reset display, #741
2336    this.css({
2337      display: ''
2338    });
2339  };
2340  
2341  return Item;
2342  
2343  }));
2344  
2345  /**
2346   * Isotope LayoutMode
2347   */
2348  
2349  ( function( window, factory ) {
2350    // universal module definition
2351    /* jshint strict: false */ /*globals define, module, require */
2352    if ( typeof define == 'function' && define.amd ) {
2353      // AMD
2354      define( 'isotope-layout/js/layout-mode',[
2355          'get-size/get-size',
2356          'outlayer/outlayer'
2357        ],
2358        factory );
2359    } else if ( typeof module == 'object' && module.exports ) {
2360      // CommonJS
2361      module.exports = factory(
2362        require('get-size'),
2363        require('outlayer')
2364      );
2365    } else {
2366      // browser global
2367      window.Isotope = window.Isotope || {};
2368      window.Isotope.LayoutMode = factory(
2369        window.getSize,
2370        window.Outlayer
2371      );
2372    }
2373  
2374  }( window, function factory( getSize, Outlayer ) {
2375    'use strict';
2376  
2377    // layout mode class
2378    function LayoutMode( isotope ) {
2379      this.isotope = isotope;
2380      // link properties
2381      if ( isotope ) {
2382        this.options = isotope.options[ this.namespace ];
2383        this.element = isotope.element;
2384        this.items = isotope.filteredItems;
2385        this.size = isotope.size;
2386      }
2387    }
2388  
2389    var proto = LayoutMode.prototype;
2390  
2391    /**
2392     * some methods should just defer to default Outlayer method
2393     * and reference the Isotope instance as `this`
2394    **/
2395    var facadeMethods = [
2396      '_resetLayout',
2397      '_getItemLayoutPosition',
2398      '_manageStamp',
2399      '_getContainerSize',
2400      '_getElementOffset',
2401      'needsResizeLayout',
2402      '_getOption'
2403    ];
2404  
2405    facadeMethods.forEach( function( methodName ) {
2406      proto[ methodName ] = function() {
2407        return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
2408      };
2409    });
2410  
2411    // -----  ----- //
2412  
2413    // for horizontal layout modes, check vertical size
2414    proto.needsVerticalResizeLayout = function() {
2415      // don't trigger if size did not change
2416      var size = getSize( this.isotope.element );
2417      // check that this.size and size are there
2418      // IE8 triggers resize on body size change, so they might not be
2419      var hasSizes = this.isotope.size && size;
2420      return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
2421    };
2422  
2423    // ----- measurements ----- //
2424  
2425    proto._getMeasurement = function() {
2426      this.isotope._getMeasurement.apply( this, arguments );
2427    };
2428  
2429    proto.getColumnWidth = function() {
2430      this.getSegmentSize( 'column', 'Width' );
2431    };
2432  
2433    proto.getRowHeight = function() {
2434      this.getSegmentSize( 'row', 'Height' );
2435    };
2436  
2437    /**
2438     * get columnWidth or rowHeight
2439     * segment: 'column' or 'row'
2440     * size 'Width' or 'Height'
2441    **/
2442    proto.getSegmentSize = function( segment, size ) {
2443      var segmentName = segment + size;
2444      var outerSize = 'outer' + size;
2445      // columnWidth / outerWidth // rowHeight / outerHeight
2446      this._getMeasurement( segmentName, outerSize );
2447      // got rowHeight or columnWidth, we can chill
2448      if ( this[ segmentName ] ) {
2449        return;
2450      }
2451      // fall back to item of first element
2452      var firstItemSize = this.getFirstItemSize();
2453      this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
2454        // or size of container
2455        this.isotope.size[ 'inner' + size ];
2456    };
2457  
2458    proto.getFirstItemSize = function() {
2459      var firstItem = this.isotope.filteredItems[0];
2460      return firstItem && firstItem.element && getSize( firstItem.element );
2461    };
2462  
2463    // ----- methods that should reference isotope ----- //
2464  
2465    proto.layout = function() {
2466      this.isotope.layout.apply( this.isotope, arguments );
2467    };
2468  
2469    proto.getSize = function() {
2470      this.isotope.getSize();
2471      this.size = this.isotope.size;
2472    };
2473  
2474    // -------------------------- create -------------------------- //
2475  
2476    LayoutMode.modes = {};
2477  
2478    LayoutMode.create = function( namespace, options ) {
2479  
2480      function Mode() {
2481        LayoutMode.apply( this, arguments );
2482      }
2483  
2484      Mode.prototype = Object.create( proto );
2485      Mode.prototype.constructor = Mode;
2486  
2487      // default options
2488      if ( options ) {
2489        Mode.options = options;
2490      }
2491  
2492      Mode.prototype.namespace = namespace;
2493      // register in Isotope
2494      LayoutMode.modes[ namespace ] = Mode;
2495  
2496      return Mode;
2497    };
2498  
2499    return LayoutMode;
2500  
2501  }));
2502  
2503  /*!
2504   * Masonry v4.2.1
2505   * Cascading grid layout library
2506   * https://masonry.desandro.com
2507   * MIT License
2508   * by David DeSandro
2509   */
2510  
2511  ( function( window, factory ) {
2512    // universal module definition
2513    /* jshint strict: false */ /*globals define, module, require */
2514    if ( typeof define == 'function' && define.amd ) {
2515      // AMD
2516      define( 'masonry-layout/masonry',[
2517          'outlayer/outlayer',
2518          'get-size/get-size'
2519        ],
2520        factory );
2521    } else if ( typeof module == 'object' && module.exports ) {
2522      // CommonJS
2523      module.exports = factory(
2524        require('outlayer'),
2525        require('get-size')
2526      );
2527    } else {
2528      // browser global
2529      window.Masonry = factory(
2530        window.Outlayer,
2531        window.getSize
2532      );
2533    }
2534  
2535  }( window, function factory( Outlayer, getSize ) {
2536  
2537  
2538  
2539  // -------------------------- masonryDefinition -------------------------- //
2540  
2541    // create an Outlayer layout class
2542    var Masonry = Outlayer.create('masonry');
2543    // isFitWidth -> fitWidth
2544    Masonry.compatOptions.fitWidth = 'isFitWidth';
2545  
2546    var proto = Masonry.prototype;
2547  
2548    proto._resetLayout = function() {
2549      this.getSize();
2550      this._getMeasurement( 'columnWidth', 'outerWidth' );
2551      this._getMeasurement( 'gutter', 'outerWidth' );
2552      this.measureColumns();
2553  
2554      // reset column Y
2555      this.colYs = [];
2556      for ( var i=0; i < this.cols; i++ ) {
2557        this.colYs.push( 0 );
2558      }
2559  
2560      this.maxY = 0;
2561      this.horizontalColIndex = 0;
2562    };
2563  
2564    proto.measureColumns = function() {
2565      this.getContainerWidth();
2566      // if columnWidth is 0, default to outerWidth of first item
2567      if ( !this.columnWidth ) {
2568        var firstItem = this.items[0];
2569        var firstItemElem = firstItem && firstItem.element;
2570        // columnWidth fall back to item of first element
2571        this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
2572          // if first elem has no width, default to size of container
2573          this.containerWidth;
2574      }
2575  
2576      var columnWidth = this.columnWidth += this.gutter;
2577  
2578      // calculate columns
2579      var containerWidth = this.containerWidth + this.gutter;
2580      var cols = containerWidth / columnWidth;
2581      // fix rounding errors, typically with gutters
2582      var excess = columnWidth - containerWidth % columnWidth;
2583      // if overshoot is less than a pixel, round up, otherwise floor it
2584      var mathMethod = excess && excess < 1 ? 'round' : 'floor';
2585      cols = Math[ mathMethod ]( cols );
2586      this.cols = Math.max( cols, 1 );
2587    };
2588  
2589    proto.getContainerWidth = function() {
2590      // container is parent if fit width
2591      var isFitWidth = this._getOption('fitWidth');
2592      var container = isFitWidth ? this.element.parentNode : this.element;
2593      // check that this.size and size are there
2594      // IE8 triggers resize on body size change, so they might not be
2595      var size = getSize( container );
2596      this.containerWidth = size && size.innerWidth;
2597    };
2598  
2599    proto._getItemLayoutPosition = function( item ) {
2600      item.getSize();
2601      // how many columns does this brick span
2602      var remainder = item.size.outerWidth % this.columnWidth;
2603      var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
2604      // round if off by 1 pixel, otherwise use ceil
2605      var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
2606      colSpan = Math.min( colSpan, this.cols );
2607      // use horizontal or top column position
2608      var colPosMethod = this.options.horizontalOrder ?
2609        '_getHorizontalColPosition' : '_getTopColPosition';
2610      var colPosition = this[ colPosMethod ]( colSpan, item );
2611      // position the brick
2612      var position = {
2613        x: this.columnWidth * colPosition.col,
2614        y: colPosition.y
2615      };
2616      // apply setHeight to necessary columns
2617      var setHeight = colPosition.y + item.size.outerHeight;
2618      var setMax = colSpan + colPosition.col;
2619      for ( var i = colPosition.col; i < setMax; i++ ) {
2620        this.colYs[i] = setHeight;
2621      }
2622  
2623      return position;
2624    };
2625  
2626    proto._getTopColPosition = function( colSpan ) {
2627      var colGroup = this._getTopColGroup( colSpan );
2628      // get the minimum Y value from the columns
2629      var minimumY = Math.min.apply( Math, colGroup );
2630  
2631      return {
2632        col: colGroup.indexOf( minimumY ),
2633        y: minimumY,
2634      };
2635    };
2636  
2637    /**
2638     * @param {Number} colSpan - number of columns the element spans
2639     * @returns {Array} colGroup
2640     */
2641    proto._getTopColGroup = function( colSpan ) {
2642      if ( colSpan < 2 ) {
2643        // if brick spans only one column, use all the column Ys
2644        return this.colYs;
2645      }
2646  
2647      var colGroup = [];
2648      // how many different places could this brick fit horizontally
2649      var groupCount = this.cols + 1 - colSpan;
2650      // for each group potential horizontal position
2651      for ( var i = 0; i < groupCount; i++ ) {
2652        colGroup[i] = this._getColGroupY( i, colSpan );
2653      }
2654      return colGroup;
2655    };
2656  
2657    proto._getColGroupY = function( col, colSpan ) {
2658      if ( colSpan < 2 ) {
2659        return this.colYs[ col ];
2660      }
2661      // make an array of colY values for that one group
2662      var groupColYs = this.colYs.slice( col, col + colSpan );
2663      // and get the max value of the array
2664      return Math.max.apply( Math, groupColYs );
2665    };
2666  
2667    // get column position based on horizontal index. #873
2668    proto._getHorizontalColPosition = function( colSpan, item ) {
2669      var col = this.horizontalColIndex % this.cols;
2670      var isOver = colSpan > 1 && col + colSpan > this.cols;
2671      // shift to next row if item can't fit on current row
2672      col = isOver ? 0 : col;
2673      // don't let zero-size items take up space
2674      var hasSize = item.size.outerWidth && item.size.outerHeight;
2675      this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
2676  
2677      return {
2678        col: col,
2679        y: this._getColGroupY( col, colSpan ),
2680      };
2681    };
2682  
2683    proto._manageStamp = function( stamp ) {
2684      var stampSize = getSize( stamp );
2685      var offset = this._getElementOffset( stamp );
2686      // get the columns that this stamp affects
2687      var isOriginLeft = this._getOption('originLeft');
2688      var firstX = isOriginLeft ? offset.left : offset.right;
2689      var lastX = firstX + stampSize.outerWidth;
2690      var firstCol = Math.floor( firstX / this.columnWidth );
2691      firstCol = Math.max( 0, firstCol );
2692      var lastCol = Math.floor( lastX / this.columnWidth );
2693      // lastCol should not go over if multiple of columnWidth #425
2694      lastCol -= lastX % this.columnWidth ? 0 : 1;
2695      lastCol = Math.min( this.cols - 1, lastCol );
2696      // set colYs to bottom of the stamp
2697  
2698      var isOriginTop = this._getOption('originTop');
2699      var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
2700        stampSize.outerHeight;
2701      for ( var i = firstCol; i <= lastCol; i++ ) {
2702        this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
2703      }
2704    };
2705  
2706    proto._getContainerSize = function() {
2707      this.maxY = Math.max.apply( Math, this.colYs );
2708      var size = {
2709        height: this.maxY
2710      };
2711  
2712      if ( this._getOption('fitWidth') ) {
2713        size.width = this._getContainerFitWidth();
2714      }
2715  
2716      return size;
2717    };
2718  
2719    proto._getContainerFitWidth = function() {
2720      var unusedCols = 0;
2721      // count unused columns
2722      var i = this.cols;
2723      while ( --i ) {
2724        if ( this.colYs[i] !== 0 ) {
2725          break;
2726        }
2727        unusedCols++;
2728      }
2729      // fit container to columns that have been used
2730      return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
2731    };
2732  
2733    proto.needsResizeLayout = function() {
2734      var previousWidth = this.containerWidth;
2735      this.getContainerWidth();
2736      return previousWidth != this.containerWidth;
2737    };
2738  
2739    return Masonry;
2740  
2741  }));
2742  
2743  /*!
2744   * Masonry layout mode
2745   * sub-classes Masonry
2746   * https://masonry.desandro.com
2747   */
2748  
2749  ( function( window, factory ) {
2750    // universal module definition
2751    /* jshint strict: false */ /*globals define, module, require */
2752    if ( typeof define == 'function' && define.amd ) {
2753      // AMD
2754      define( 'isotope-layout/js/layout-modes/masonry',[
2755          '../layout-mode',
2756          'masonry-layout/masonry'
2757        ],
2758        factory );
2759    } else if ( typeof module == 'object' && module.exports ) {
2760      // CommonJS
2761      module.exports = factory(
2762        require('../layout-mode'),
2763        require('masonry-layout')
2764      );
2765    } else {
2766      // browser global
2767      factory(
2768        window.Isotope.LayoutMode,
2769        window.Masonry
2770      );
2771    }
2772  
2773  }( window, function factory( LayoutMode, Masonry ) {
2774  'use strict';
2775  
2776  // -------------------------- masonryDefinition -------------------------- //
2777  
2778    // create an Outlayer layout class
2779    var MasonryMode = LayoutMode.create('masonry');
2780  
2781    var proto = MasonryMode.prototype;
2782  
2783    var keepModeMethods = {
2784      _getElementOffset: true,
2785      layout: true,
2786      _getMeasurement: true
2787    };
2788  
2789    // inherit Masonry prototype
2790    for ( var method in Masonry.prototype ) {
2791      // do not inherit mode methods
2792      if ( !keepModeMethods[ method ] ) {
2793        proto[ method ] = Masonry.prototype[ method ];
2794      }
2795    }
2796  
2797    var measureColumns = proto.measureColumns;
2798    proto.measureColumns = function() {
2799      // set items, used if measuring first item
2800      this.items = this.isotope.filteredItems;
2801      measureColumns.call( this );
2802    };
2803  
2804    // point to mode options for fitWidth
2805    var _getOption = proto._getOption;
2806    proto._getOption = function( option ) {
2807      if ( option == 'fitWidth' ) {
2808        return this.options.isFitWidth !== undefined ?
2809          this.options.isFitWidth : this.options.fitWidth;
2810      }
2811      return _getOption.apply( this.isotope, arguments );
2812    };
2813  
2814    return MasonryMode;
2815  
2816  }));
2817  
2818  /**
2819   * fitRows layout mode
2820   */
2821  
2822  ( function( window, factory ) {
2823    // universal module definition
2824    /* jshint strict: false */ /*globals define, module, require */
2825    if ( typeof define == 'function' && define.amd ) {
2826      // AMD
2827      define( 'isotope-layout/js/layout-modes/fit-rows',[
2828          '../layout-mode'
2829        ],
2830        factory );
2831    } else if ( typeof exports == 'object' ) {
2832      // CommonJS
2833      module.exports = factory(
2834        require('../layout-mode')
2835      );
2836    } else {
2837      // browser global
2838      factory(
2839        window.Isotope.LayoutMode
2840      );
2841    }
2842  
2843  }( window, function factory( LayoutMode ) {
2844  'use strict';
2845  
2846  var FitRows = LayoutMode.create('fitRows');
2847  
2848  var proto = FitRows.prototype;
2849  
2850  proto._resetLayout = function() {
2851    this.x = 0;
2852    this.y = 0;
2853    this.maxY = 0;
2854    this._getMeasurement( 'gutter', 'outerWidth' );
2855  };
2856  
2857  proto._getItemLayoutPosition = function( item ) {
2858    item.getSize();
2859  
2860    var itemWidth = item.size.outerWidth + this.gutter;
2861    // if this element cannot fit in the current row
2862    var containerWidth = this.isotope.size.innerWidth + this.gutter;
2863    if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
2864      this.x = 0;
2865      this.y = this.maxY;
2866    }
2867  
2868    var position = {
2869      x: this.x,
2870      y: this.y
2871    };
2872  
2873    this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
2874    this.x += itemWidth;
2875  
2876    return position;
2877  };
2878  
2879  proto._getContainerSize = function() {
2880    return { height: this.maxY };
2881  };
2882  
2883  return FitRows;
2884  
2885  }));
2886  
2887  /**
2888   * vertical layout mode
2889   */
2890  
2891  ( function( window, factory ) {
2892    // universal module definition
2893    /* jshint strict: false */ /*globals define, module, require */
2894    if ( typeof define == 'function' && define.amd ) {
2895      // AMD
2896      define( 'isotope-layout/js/layout-modes/vertical',[
2897          '../layout-mode'
2898        ],
2899        factory );
2900    } else if ( typeof module == 'object' && module.exports ) {
2901      // CommonJS
2902      module.exports = factory(
2903        require('../layout-mode')
2904      );
2905    } else {
2906      // browser global
2907      factory(
2908        window.Isotope.LayoutMode
2909      );
2910    }
2911  
2912  }( window, function factory( LayoutMode ) {
2913  'use strict';
2914  
2915  var Vertical = LayoutMode.create( 'vertical', {
2916    horizontalAlignment: 0
2917  });
2918  
2919  var proto = Vertical.prototype;
2920  
2921  proto._resetLayout = function() {
2922    this.y = 0;
2923  };
2924  
2925  proto._getItemLayoutPosition = function( item ) {
2926    item.getSize();
2927    var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
2928      this.options.horizontalAlignment;
2929    var y = this.y;
2930    this.y += item.size.outerHeight;
2931    return { x: x, y: y };
2932  };
2933  
2934  proto._getContainerSize = function() {
2935    return { height: this.y };
2936  };
2937  
2938  return Vertical;
2939  
2940  }));
2941  
2942  /*!
2943   * Isotope v3.0.6
2944   *
2945   * Licensed GPLv3 for open source use
2946   * or Isotope Commercial License for commercial use
2947   *
2948   * https://isotope.metafizzy.co
2949   * Copyright 2010-2018 Metafizzy
2950   */
2951  
2952  ( function( window, factory ) {
2953    // universal module definition
2954    /* jshint strict: false */ /*globals define, module, require */
2955    if ( typeof define == 'function' && define.amd ) {
2956      // AMD
2957      define( [
2958          'outlayer/outlayer',
2959          'get-size/get-size',
2960          'desandro-matches-selector/matches-selector',
2961          'fizzy-ui-utils/utils',
2962          'isotope-layout/js/item',
2963          'isotope-layout/js/layout-mode',
2964          // include default layout modes
2965          'isotope-layout/js/layout-modes/masonry',
2966          'isotope-layout/js/layout-modes/fit-rows',
2967          'isotope-layout/js/layout-modes/vertical'
2968        ],
2969        function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
2970          return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
2971        });
2972    } else if ( typeof module == 'object' && module.exports ) {
2973      // CommonJS
2974      module.exports = factory(
2975        window,
2976        require('outlayer'),
2977        require('get-size'),
2978        require('desandro-matches-selector'),
2979        require('fizzy-ui-utils'),
2980        require('isotope-layout/js/item'),
2981        require('isotope-layout/js/layout-mode'),
2982        // include default layout modes
2983        require('isotope-layout/js/layout-modes/masonry'),
2984        require('isotope-layout/js/layout-modes/fit-rows'),
2985        require('isotope-layout/js/layout-modes/vertical')
2986      );
2987    } else {
2988      // browser global
2989      window.Isotope = factory(
2990        window,
2991        window.Outlayer,
2992        window.getSize,
2993        window.matchesSelector,
2994        window.fizzyUIUtils,
2995        window.Isotope.Item,
2996        window.Isotope.LayoutMode
2997      );
2998    }
2999  
3000  }( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
3001    Item, LayoutMode ) {
3002  
3003  
3004  
3005  // -------------------------- vars -------------------------- //
3006  
3007  var jQuery = window.jQuery;
3008  
3009  // -------------------------- helpers -------------------------- //
3010  
3011  var trim = String.prototype.trim ?
3012    function( str ) {
3013      return str.trim();
3014    } :
3015    function( str ) {
3016      return str.replace( /^\s+|\s+$/g, '' );
3017    };
3018  
3019  // -------------------------- isotopeDefinition -------------------------- //
3020  
3021    // create an Outlayer layout class
3022    var Isotope = Outlayer.create( 'isotope', {
3023      layoutMode: 'masonry',
3024      isJQueryFiltering: true,
3025      sortAscending: true
3026    });
3027  
3028    Isotope.Item = Item;
3029    Isotope.LayoutMode = LayoutMode;
3030  
3031    var proto = Isotope.prototype;
3032  
3033    proto._create = function() {
3034      this.itemGUID = 0;
3035      // functions that sort items
3036      this._sorters = {};
3037      this._getSorters();
3038      // call super
3039      Outlayer.prototype._create.call( this );
3040  
3041      // create layout modes
3042      this.modes = {};
3043      // start filteredItems with all items
3044      this.filteredItems = this.items;
3045      // keep of track of sortBys
3046      this.sortHistory = [ 'original-order' ];
3047      // create from registered layout modes
3048      for ( var name in LayoutMode.modes ) {
3049        this._initLayoutMode( name );
3050      }
3051    };
3052  
3053    proto.reloadItems = function() {
3054      // reset item ID counter
3055      this.itemGUID = 0;
3056      // call super
3057      Outlayer.prototype.reloadItems.call( this );
3058    };
3059  
3060    proto._itemize = function() {
3061      var items = Outlayer.prototype._itemize.apply( this, arguments );
3062      // assign ID for original-order
3063      for ( var i=0; i < items.length; i++ ) {
3064        var item = items[i];
3065        item.id = this.itemGUID++;
3066      }
3067      this._updateItemsSortData( items );
3068      return items;
3069    };
3070  
3071  
3072    // -------------------------- layout -------------------------- //
3073  
3074    proto._initLayoutMode = function( name ) {
3075      var Mode = LayoutMode.modes[ name ];
3076      // set mode options
3077      // HACK extend initial options, back-fill in default options
3078      var initialOpts = this.options[ name ] || {};
3079      this.options[ name ] = Mode.options ?
3080        utils.extend( Mode.options, initialOpts ) : initialOpts;
3081      // init layout mode instance
3082      this.modes[ name ] = new Mode( this );
3083    };
3084  
3085  
3086    proto.layout = function() {
3087      // if first time doing layout, do all magic
3088      if ( !this._isLayoutInited && this._getOption('initLayout') ) {
3089        this.arrange();
3090        return;
3091      }
3092      this._layout();
3093    };
3094  
3095    // private method to be used in layout() & magic()
3096    proto._layout = function() {
3097      // don't animate first layout
3098      var isInstant = this._getIsInstant();
3099      // layout flow
3100      this._resetLayout();
3101      this._manageStamps();
3102      this.layoutItems( this.filteredItems, isInstant );
3103  
3104      // flag for initalized
3105      this._isLayoutInited = true;
3106    };
3107  
3108    // filter + sort + layout
3109    proto.arrange = function( opts ) {
3110      // set any options pass
3111      this.option( opts );
3112      this._getIsInstant();
3113      // filter, sort, and layout
3114  
3115      // filter
3116      var filtered = this._filter( this.items );
3117      this.filteredItems = filtered.matches;
3118  
3119      this._bindArrangeComplete();
3120  
3121      if ( this._isInstant ) {
3122        this._noTransition( this._hideReveal, [ filtered ] );
3123      } else {
3124        this._hideReveal( filtered );
3125      }
3126  
3127      this._sort();
3128      this._layout();
3129    };
3130    // alias to _init for main plugin method
3131    proto._init = proto.arrange;
3132  
3133    proto._hideReveal = function( filtered ) {
3134      this.reveal( filtered.needReveal );
3135      this.hide( filtered.needHide );
3136    };
3137  
3138    // HACK
3139    // Don't animate/transition first layout
3140    // Or don't animate/transition other layouts
3141    proto._getIsInstant = function() {
3142      var isLayoutInstant = this._getOption('layoutInstant');
3143      var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
3144        !this._isLayoutInited;
3145      this._isInstant = isInstant;
3146      return isInstant;
3147    };
3148  
3149    // listen for layoutComplete, hideComplete and revealComplete
3150    // to trigger arrangeComplete
3151    proto._bindArrangeComplete = function() {
3152      // listen for 3 events to trigger arrangeComplete
3153      var isLayoutComplete, isHideComplete, isRevealComplete;
3154      var _this = this;
3155      function arrangeParallelCallback() {
3156        if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
3157          _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
3158        }
3159      }
3160      this.once( 'layoutComplete', function() {
3161        isLayoutComplete = true;
3162        arrangeParallelCallback();
3163      });
3164      this.once( 'hideComplete', function() {
3165        isHideComplete = true;
3166        arrangeParallelCallback();
3167      });
3168      this.once( 'revealComplete', function() {
3169        isRevealComplete = true;
3170        arrangeParallelCallback();
3171      });
3172    };
3173  
3174    // -------------------------- filter -------------------------- //
3175  
3176    proto._filter = function( items ) {
3177      var filter = this.options.filter;
vendor: 11,773 bytes, lines 3178-3563
3178      filter = filter || '*';
3179      var matches = [];
3180      var hiddenMatched = [];
3181      var visibleUnmatched = [];
3182  
3183      var test = this._getFilterTest( filter );
3184  
3185      // test each item
3186      for ( var i=0; i < items.length; i++ ) {
3187        var item = items[i];
3188        if ( item.isIgnored ) {
3189          continue;
3190        }
3191        // add item to either matched or unmatched group
3192        var isMatched = test( item );
3193        // item.isFilterMatched = isMatched;
3194        // add to matches if its a match
3195        if ( isMatched ) {
3196          matches.push( item );
3197        }
3198        // add to additional group if item needs to be hidden or revealed
3199        if ( isMatched && item.isHidden ) {
3200          hiddenMatched.push( item );
3201        } else if ( !isMatched && !item.isHidden ) {
3202          visibleUnmatched.push( item );
3203        }
3204      }
3205  
3206      // return collections of items to be manipulated
3207      return {
3208        matches: matches,
3209        needReveal: hiddenMatched,
3210        needHide: visibleUnmatched
3211      };
3212    };
3213  
3214    // get a jQuery, function, or a matchesSelector test given the filter
3215    proto._getFilterTest = function( filter ) {
3216      if ( jQuery && this.options.isJQueryFiltering ) {
3217        // use jQuery
3218        return function( item ) {
3219          return jQuery( item.element ).is( filter );
3220        };
3221      }
3222      if ( typeof filter == 'function' ) {
3223        // use filter as function
3224        return function( item ) {
3225          return filter( item.element );
3226        };
3227      }
3228      // default, use filter as selector string
3229      return function( item ) {
3230        return matchesSelector( item.element, filter );
3231      };
3232    };
3233  
3234    // -------------------------- sorting -------------------------- //
3235  
3236    /**
3237     * @params {Array} elems
3238     * @public
3239     */
3240    proto.updateSortData = function( elems ) {
3241      // get items
3242      var items;
3243      if ( elems ) {
3244        elems = utils.makeArray( elems );
3245        items = this.getItems( elems );
3246      } else {
3247        // update all items if no elems provided
3248        items = this.items;
3249      }
3250  
3251      this._getSorters();
3252      this._updateItemsSortData( items );
3253    };
3254  
3255    proto._getSorters = function() {
3256      var getSortData = this.options.getSortData;
3257      for ( var key in getSortData ) {
3258        var sorter = getSortData[ key ];
3259        this._sorters[ key ] = mungeSorter( sorter );
3260      }
3261    };
3262  
3263    /**
3264     * @params {Array} items - of Isotope.Items
3265     * @private
3266     */
3267    proto._updateItemsSortData = function( items ) {
3268      // do not update if no items
3269      var len = items && items.length;
3270  
3271      for ( var i=0; len && i < len; i++ ) {
3272        var item = items[i];
3273        item.updateSortData();
3274      }
3275    };
3276  
3277    // ----- munge sorter ----- //
3278  
3279    // encapsulate this, as we just need mungeSorter
3280    // other functions in here are just for munging
3281    var mungeSorter = ( function() {
3282      // add a magic layer to sorters for convienent shorthands
3283      // `.foo-bar` will use the text of .foo-bar querySelector
3284      // `[foo-bar]` will use attribute
3285      // you can also add parser
3286      // `.foo-bar parseInt` will parse that as a number
3287      function mungeSorter( sorter ) {
3288        // if not a string, return function or whatever it is
3289        if ( typeof sorter != 'string' ) {
3290          return sorter;
3291        }
3292        // parse the sorter string
3293        var args = trim( sorter ).split(' ');
3294        var query = args[0];
3295        // check if query looks like [an-attribute]
3296        var attrMatch = query.match( /^\[(.+)\]$/ );
3297        var attr = attrMatch && attrMatch[1];
3298        var getValue = getValueGetter( attr, query );
3299        // use second argument as a parser
3300        var parser = Isotope.sortDataParsers[ args[1] ];
3301        // parse the value, if there was a parser
3302        sorter = parser ? function( elem ) {
3303          return elem && parser( getValue( elem ) );
3304        } :
3305        // otherwise just return value
3306        function( elem ) {
3307          return elem && getValue( elem );
3308        };
3309  
3310        return sorter;
3311      }
3312  
3313      // get an attribute getter, or get text of the querySelector
3314      function getValueGetter( attr, query ) {
3315        // if query looks like [foo-bar], get attribute
3316        if ( attr ) {
3317          return function getAttribute( elem ) {
3318            return elem.getAttribute( attr );
3319          };
3320        }
3321  
3322        // otherwise, assume its a querySelector, and get its text
3323        return function getChildText( elem ) {
3324          var child = elem.querySelector( query );
3325          return child && child.textContent;
3326        };
3327      }
3328  
3329      return mungeSorter;
3330    })();
3331  
3332    // parsers used in getSortData shortcut strings
3333    Isotope.sortDataParsers = {
3334      'parseInt': function( val ) {
3335        return parseInt( val, 10 );
3336      },
3337      'parseFloat': function( val ) {
3338        return parseFloat( val );
3339      }
3340    };
3341  
3342    // ----- sort method ----- //
3343  
3344    // sort filteredItem order
3345    proto._sort = function() {
3346      if ( !this.options.sortBy ) {
3347        return;
3348      }
3349      // keep track of sortBy History
3350      var sortBys = utils.makeArray( this.options.sortBy );
3351      if ( !this._getIsSameSortBy( sortBys ) ) {
3352        // concat all sortBy and sortHistory, add to front, oldest goes in last
3353        this.sortHistory = sortBys.concat( this.sortHistory );
3354      }
3355      // sort magic
3356      var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
3357      this.filteredItems.sort( itemSorter );
3358    };
3359  
3360    // check if sortBys is same as start of sortHistory
3361    proto._getIsSameSortBy = function( sortBys ) {
3362      for ( var i=0; i < sortBys.length; i++ ) {
3363        if ( sortBys[i] != this.sortHistory[i] ) {
3364          return false;
3365        }
3366      }
3367      return true;
3368    };
3369  
3370    // returns a function used for sorting
3371    function getItemSorter( sortBys, sortAsc ) {
3372      return function sorter( itemA, itemB ) {
3373        // cycle through all sortKeys
3374        for ( var i = 0; i < sortBys.length; i++ ) {
3375          var sortBy = sortBys[i];
3376          var a = itemA.sortData[ sortBy ];
3377          var b = itemB.sortData[ sortBy ];
3378          if ( a > b || a < b ) {
3379            // if sortAsc is an object, use the value given the sortBy key
3380            var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
3381            var direction = isAscending ? 1 : -1;
3382            return ( a > b ? 1 : -1 ) * direction;
3383          }
3384        }
3385        return 0;
3386      };
3387    }
3388  
3389    // -------------------------- methods -------------------------- //
3390  
3391    // get layout mode
3392    proto._mode = function() {
3393      var layoutMode = this.options.layoutMode;
3394      var mode = this.modes[ layoutMode ];
3395      if ( !mode ) {
3396        // TODO console.error
3397        throw new Error( 'No layout mode: ' + layoutMode );
3398      }
3399      // HACK sync mode's options
3400      // any options set after init for layout mode need to be synced
3401      mode.options = this.options[ layoutMode ];
3402      return mode;
3403    };
3404  
3405    proto._resetLayout = function() {
3406      // trigger original reset layout
3407      Outlayer.prototype._resetLayout.call( this );
3408      this._mode()._resetLayout();
3409    };
3410  
3411    proto._getItemLayoutPosition = function( item  ) {
3412      return this._mode()._getItemLayoutPosition( item );
3413    };
3414  
3415    proto._manageStamp = function( stamp ) {
3416      this._mode()._manageStamp( stamp );
3417    };
3418  
3419    proto._getContainerSize = function() {
3420      return this._mode()._getContainerSize();
3421    };
3422  
3423    proto.needsResizeLayout = function() {
3424      return this._mode().needsResizeLayout();
3425    };
3426  
3427    // -------------------------- adding & removing -------------------------- //
3428  
3429    // HEADS UP overwrites default Outlayer appended
3430    proto.appended = function( elems ) {
3431      var items = this.addItems( elems );
3432      if ( !items.length ) {
3433        return;
3434      }
3435      // filter, layout, reveal new items
3436      var filteredItems = this._filterRevealAdded( items );
3437      // add to filteredItems
3438      this.filteredItems = this.filteredItems.concat( filteredItems );
3439    };
3440  
3441    // HEADS UP overwrites default Outlayer prepended
3442    proto.prepended = function( elems ) {
3443      var items = this._itemize( elems );
3444      if ( !items.length ) {
3445        return;
3446      }
3447      // start new layout
3448      this._resetLayout();
3449      this._manageStamps();
3450      // filter, layout, reveal new items
3451      var filteredItems = this._filterRevealAdded( items );
3452      // layout previous items
3453      this.layoutItems( this.filteredItems );
3454      // add to items and filteredItems
3455      this.filteredItems = filteredItems.concat( this.filteredItems );
3456      this.items = items.concat( this.items );
3457    };
3458  
3459    proto._filterRevealAdded = function( items ) {
3460      var filtered = this._filter( items );
3461      this.hide( filtered.needHide );
3462      // reveal all new items
3463      this.reveal( filtered.matches );
3464      // layout new items, no transition
3465      this.layoutItems( filtered.matches, true );
3466      return filtered.matches;
3467    };
3468  
3469    /**
3470     * Filter, sort, and layout newly-appended item elements
3471     * @param {Array or NodeList or Element} elems
3472     */
3473    proto.insert = function( elems ) {
3474      var items = this.addItems( elems );
3475      if ( !items.length ) {
3476        return;
3477      }
3478      // append item elements
3479      var i, item;
3480      var len = items.length;
3481      for ( i=0; i < len; i++ ) {
3482        item = items[i];
3483        this.element.appendChild( item.element );
3484      }
3485      // filter new stuff
3486      var filteredInsertItems = this._filter( items ).matches;
3487      // set flag
3488      for ( i=0; i < len; i++ ) {
3489        items[i].isLayoutInstant = true;
3490      }
3491      this.arrange();
3492      // reset flag
3493      for ( i=0; i < len; i++ ) {
3494        delete items[i].isLayoutInstant;
3495      }
3496      this.reveal( filteredInsertItems );
3497    };
3498  
3499    var _remove = proto.remove;
3500    proto.remove = function( elems ) {
3501      elems = utils.makeArray( elems );
3502      var removeItems = this.getItems( elems );
3503      // do regular thing
3504      _remove.call( this, elems );
3505      // bail if no items to remove
3506      var len = removeItems && removeItems.length;
3507      // remove elems from filteredItems
3508      for ( var i=0; len && i < len; i++ ) {
3509        var item = removeItems[i];
3510        // remove item from collection
3511        utils.removeFrom( this.filteredItems, item );
3512      }
3513    };
3514  
3515    proto.shuffle = function() {
3516      // update random sortData
3517      for ( var i=0; i < this.items.length; i++ ) {
3518        var item = this.items[i];
3519        item.sortData.random = Math.random();
3520      }
3521      this.options.sortBy = 'random';
3522      this._sort();
3523      this._layout();
3524    };
3525  
3526    /**
3527     * trigger fn without transition
3528     * kind of hacky to have this in the first place
3529     * @param {Function} fn
3530     * @param {Array} args
3531     * @returns ret
3532     * @private
3533     */
3534    proto._noTransition = function( fn, args ) {
3535      // save transitionDuration before disabling
3536      var transitionDuration = this.options.transitionDuration;
3537      // disable transition
3538      this.options.transitionDuration = 0;
3539      // do it
3540      var returnValue = fn.apply( this, args );
3541      // re-enable transition for reveal
3542      this.options.transitionDuration = transitionDuration;
3543      return returnValue;
3544    };
3545  
3546    // ----- helper methods ----- //
3547  
3548    /**
3549     * getter method for getting filtered item elements
3550     * @returns {Array} elems - collection of item elements
3551     */
3552    proto.getFilteredItemElements = function() {
3553      return this.filteredItems.map( function( item ) {
3554        return item.element;
3555      });
3556    };
3557  
3558    // -----  ----- //
3559  
3560    return Isotope;
3561  
3562  }));
3563  

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.