PageSourceSearch

https://www.pieas.edu.pk/js/isotope.pkgd.js

js pieas.edu.pk collected 2026-09-24 09:57:53 UTC 119,970 bytes, 4,257 lines download raw bytes

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

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.