PageSourceSearch

https://www.aifsfoundation.org/assets/js/isotope.js

js aifsfoundation.org collected 2026-09-29 16:06:06 UTC 118,190 bytes, 4,204 lines download raw bytes

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

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.