PageSourceSearch

https://drjennelle.com/wp-content/themes/accesspress-parallax/js/isotope.pkgd.js?ver=3.0.4

js drjennelle.com collected 2026-10-05 18:29:55 UTC 91,252 bytes, 3,554 lines download raw bytes

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

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.