PageSourceSearch

https://lavra.ua/wp-content/themes/lavra/bower_components/isotope/dist/isotope.pkgd.js

js lavra.ua collected 2026-10-02 07:42:05 UTC 115,731 bytes, 4,259 lines download raw bytes

1/*!
2 * Isotope PACKAGED v2.2.0
3 *
4 * Licensed GPLv3 for open source use
5 * or Isotope Commercial License for commercial use
6 *
7 * http://isotope.metafizzy.co
8 * Copyright 2015 Metafizzy
9 */
10
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
vendor: 16,384 bytes, lines 277-680
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.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
680._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  } :
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  var x = parseInt( xValue, 10 );
1641  var y = parseInt( yValue, 10 );
1642  // convert percent to pixels
1643  var layoutSize = this.layout.size;
1644  x = xValue.indexOf('%') != -1 ? ( x / 100 ) * layoutSize.width : x;
1645  y = yValue.indexOf('%') != -1 ? ( y / 100 ) * layoutSize.height : y;
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  x = this.getXValue( x );
1742  y = this.getYValue( y );
1743
1744  if ( is3d ) {
1745    return 'translate3d(' + x + ', ' + y + ', 0)';
1746  }
1747
1748  return 'translate(' + x + ', ' + y + ')';
1749};
1750
1751// non transition + transform support
1752Item.prototype.goTo = function( x, y ) {
1753  this.setPosition( x, y );
1754  this.layoutPosition();
1755};
1756
1757// use transition and transforms if supported
1758Item.prototype.moveTo = supportsCSS3 ?
1759  Item.prototype._transitionTo : Item.prototype.goTo;
1760
1761Item.prototype.setPosition = function( x, y ) {
1762  this.position.x = parseInt( x, 10 );
1763  this.position.y = parseInt( y, 10 );
1764};
1765
1766// ----- transition ----- //
1767
1768/**
1769 * @param {Object} style - CSS
1770 * @param {Function} onTransitionEnd
1771 */
1772
1773// non transition, just trigger callback
1774Item.prototype._nonTransition = function( args ) {
1775  this.css( args.to );
1776  if ( args.isCleaning ) {
1777    this._removeStyles( args.to );
1778  }
1779  for ( var prop in args.onTransitionEnd ) {
1780    args.onTransitionEnd[ prop ].call( this );
1781  }
1782};
1783
1784/**
1785 * proper transition
1786 * @param {Object} args - arguments
1787 *   @param {Object} to - style to transition to
1788 *   @param {Object} from - style to start transition from
1789 *   @param {Boolean} isCleaning - removes transition styles after transition
1790 *   @param {Function} onTransitionEnd - callback
1791 */
1792Item.prototype._transition = function( args ) {
1793  // redirect to nonTransition if no transition duration
1794  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1795    this._nonTransition( args );
1796    return;
1797  }
1798
1799  var _transition = this._transn;
1800  // keep track of onTransitionEnd callback by css property
1801  for ( var prop in args.onTransitionEnd ) {
1802    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1803  }
1804  // keep track of properties that are transitioning
1805  for ( prop in args.to ) {
1806    _transition.ingProperties[ prop ] = true;
1807    // keep track of properties to clean up when transition is done
1808    if ( args.isCleaning ) {
1809      _transition.clean[ prop ] = true;
1810    }
1811  }
1812
1813  // set from styles
1814  if ( args.from ) {
1815    this.css( args.from );
1816    // force redraw. http://blog.alexmaccaw.com/css-transitions
1817    var h = this.element.offsetHeight;
1818    // hack for JSHint to hush about unused var
1819    h = null;
1820  }
1821  // enable transition
1822  this.enableTransition( args.to );
1823  // set styles that are transitioning
1824  this.css( args.to );
1825
1826  this.isTransitioning = true;
1827
1828};
1829
1830// dash before all cap letters, including first for
1831// WebkitTransform => -webkit-transform
1832function toDashedAll( str ) {
1833  return str.replace( /([A-Z])/g, function( $1 ) {
1834    return '-' + $1.toLowerCase();
1835  });
1836}
1837
1838var transitionProps = 'opacity,' +
vendor: 11,190 bytes, lines 1839-2285
1839  toDashedAll( vendorProperties.transform || 'transform' );
1840
1841Item.prototype.enableTransition = function(/* style */) {
1842  // HACK changing transitionProperty during a transition
1843  // will cause transition to jump
1844  if ( this.isTransitioning ) {
1845    return;
1846  }
1847
1848  // make `transition: foo, bar, baz` from style object
1849  // HACK un-comment this when enableTransition can work
1850  // while a transition is happening
1851  // var transitionValues = [];
1852  // for ( var prop in style ) {
1853  //   // dash-ify camelCased properties like WebkitTransition
1854  //   prop = vendorProperties[ prop ] || prop;
1855  //   transitionValues.push( toDashedAll( prop ) );
1856  // }
1857  // enable transition styles
1858  this.css({
1859    transitionProperty: transitionProps,
1860    transitionDuration: this.layout.options.transitionDuration
1861  });
1862  // listen for transition end event
1863  this.element.addEventListener( transitionEndEvent, this, false );
1864};
1865
1866Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
1867
1868// ----- events ----- //
1869
1870Item.prototype.onwebkitTransitionEnd = function( event ) {
1871  this.ontransitionend( event );
1872};
1873
1874Item.prototype.onotransitionend = function( event ) {
1875  this.ontransitionend( event );
1876};
1877
1878// properties that I munge to make my life easier
1879var dashedVendorProperties = {
1880  '-webkit-transform': 'transform',
1881  '-moz-transform': 'transform',
1882  '-o-transform': 'transform'
1883};
1884
1885Item.prototype.ontransitionend = function( event ) {
1886  // disregard bubbled events from children
1887  if ( event.target !== this.element ) {
1888    return;
1889  }
1890  var _transition = this._transn;
1891  // get property name of transitioned property, convert to prefix-free
1892  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1893
1894  // remove property that has completed transitioning
1895  delete _transition.ingProperties[ propertyName ];
1896  // check if any properties are still transitioning
1897  if ( isEmptyObj( _transition.ingProperties ) ) {
1898    // all properties have completed transitioning
1899    this.disableTransition();
1900  }
1901  // clean style
1902  if ( propertyName in _transition.clean ) {
1903    // clean up style
1904    this.element.style[ event.propertyName ] = '';
1905    delete _transition.clean[ propertyName ];
1906  }
1907  // trigger onTransitionEnd callback
1908  if ( propertyName in _transition.onEnd ) {
1909    var onTransitionEnd = _transition.onEnd[ propertyName ];
1910    onTransitionEnd.call( this );
1911    delete _transition.onEnd[ propertyName ];
1912  }
1913
1914  this.emitEvent( 'transitionEnd', [ this ] );
1915};
1916
1917Item.prototype.disableTransition = function() {
1918  this.removeTransitionStyles();
1919  this.element.removeEventListener( transitionEndEvent, this, false );
1920  this.isTransitioning = false;
1921};
1922
1923/**
1924 * removes style property from element
1925 * @param {Object} style
1926**/
1927Item.prototype._removeStyles = function( style ) {
1928  // clean up transition styles
1929  var cleanStyle = {};
1930  for ( var prop in style ) {
1931    cleanStyle[ prop ] = '';
1932  }
1933  this.css( cleanStyle );
1934};
1935
1936var cleanTransitionStyle = {
1937  transitionProperty: '',
1938  transitionDuration: ''
1939};
1940
1941Item.prototype.removeTransitionStyles = function() {
1942  // remove transition
1943  this.css( cleanTransitionStyle );
1944};
1945
1946// ----- show/hide/remove ----- //
1947
1948// remove element from DOM
1949Item.prototype.removeElem = function() {
1950  this.element.parentNode.removeChild( this.element );
1951  // remove display: none
1952  this.css({ display: '' });
1953  this.emitEvent( 'remove', [ this ] );
1954};
1955
1956Item.prototype.remove = function() {
1957  // just remove element if no transition support or no transition
1958  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1959    this.removeElem();
1960    return;
1961  }
1962
1963  // start transition
1964  var _this = this;
1965  this.once( 'transitionEnd', function() {
1966    _this.removeElem();
1967  });
1968  this.hide();
1969};
1970
1971Item.prototype.reveal = function() {
1972  delete this.isHidden;
1973  // remove display: none
1974  this.css({ display: '' });
1975
1976  var options = this.layout.options;
1977
1978  var onTransitionEnd = {};
1979  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1980  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
1981
1982  this.transition({
1983    from: options.hiddenStyle,
1984    to: options.visibleStyle,
1985    isCleaning: true,
1986    onTransitionEnd: onTransitionEnd
1987  });
1988};
1989
1990Item.prototype.onRevealTransitionEnd = function() {
1991  // check if still visible
1992  // during transition, item may have been hidden
1993  if ( !this.isHidden ) {
1994    this.emitEvent('reveal');
1995  }
1996};
1997
1998/**
1999 * get style property use for hide/reveal transition end
2000 * @param {String} styleProperty - hiddenStyle/visibleStyle
2001 * @returns {String}
2002 */
2003Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) {
2004  var optionStyle = this.layout.options[ styleProperty ];
2005  // use opacity
2006  if ( optionStyle.opacity ) {
2007    return 'opacity';
2008  }
2009  // get first property
2010  for ( var prop in optionStyle ) {
2011    return prop;
2012  }
2013};
2014
2015Item.prototype.hide = function() {
2016  // set flag
2017  this.isHidden = true;
2018  // remove display: none
2019  this.css({ display: '' });
2020
2021  var options = this.layout.options;
2022
2023  var onTransitionEnd = {};
2024  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
2025  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
2026
2027  this.transition({
2028    from: options.visibleStyle,
2029    to: options.hiddenStyle,
2030    // keep hidden stuff hidden
2031    isCleaning: true,
2032    onTransitionEnd: onTransitionEnd
2033  });
2034};
2035
2036Item.prototype.onHideTransitionEnd = function() {
2037  // check if still hidden
2038  // during transition, item may have been un-hidden
2039  if ( this.isHidden ) {
2040    this.css({ display: 'none' });
2041    this.emitEvent('hide');
2042  }
2043};
2044
2045Item.prototype.destroy = function() {
2046  this.css({
2047    position: '',
2048    left: '',
2049    right: '',
2050    top: '',
2051    bottom: '',
2052    transition: '',
2053    transform: ''
2054  });
2055};
2056
2057return Item;
2058
2059}));
2060
2061/*!
2062 * Outlayer v1.4.1
2063 * the brains and guts of a layout library
2064 * MIT license
2065 */
2066
2067( function( window, factory ) {
2068  'use strict';
2069  // universal module definition
2070
2071  if ( typeof define == 'function' && define.amd ) {
2072    // AMD
2073    define( 'outlayer/outlayer',[
2074        'eventie/eventie',
2075        'eventEmitter/EventEmitter',
2076        'get-size/get-size',
2077        'fizzy-ui-utils/utils',
2078        './item'
2079      ],
2080      function( eventie, EventEmitter, getSize, utils, Item ) {
2081        return factory( window, eventie, EventEmitter, getSize, utils, Item);
2082      }
2083    );
2084  } else if ( typeof exports == 'object' ) {
2085    // CommonJS
2086    module.exports = factory(
2087      window,
2088      require('eventie'),
2089      require('wolfy87-eventemitter'),
2090      require('get-size'),
2091      require('fizzy-ui-utils'),
2092      require('./item')
2093    );
2094  } else {
2095    // browser global
2096    window.Outlayer = factory(
2097      window,
2098      window.eventie,
2099      window.EventEmitter,
2100      window.getSize,
2101      window.fizzyUIUtils,
2102      window.Outlayer.Item
2103    );
2104  }
2105
2106}( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) {
2107'use strict';
2108
2109// ----- vars ----- //
2110
2111var console = window.console;
2112var jQuery = window.jQuery;
2113var noop = function() {};
2114
2115// -------------------------- Outlayer -------------------------- //
2116
2117// globally unique identifiers
2118var GUID = 0;
2119// internal store of all Outlayer intances
2120var instances = {};
2121
2122
2123/**
2124 * @param {Element, String} element
2125 * @param {Object} options
2126 * @constructor
2127 */
2128function Outlayer( element, options ) {
2129  var queryElement = utils.getQueryElement( element );
2130  if ( !queryElement ) {
2131    if ( console ) {
2132      console.error( 'Bad element for ' + this.constructor.namespace +
2133        ': ' + ( queryElement || element ) );
2134    }
2135    return;
2136  }
2137  this.element = queryElement;
2138  // add jQuery
2139  if ( jQuery ) {
2140    this.$element = jQuery( this.element );
2141  }
2142
2143  // options
2144  this.options = utils.extend( {}, this.constructor.defaults );
2145  this.option( options );
2146
2147  // add id for Outlayer.getFromElement
2148  var id = ++GUID;
2149  this.element.outlayerGUID = id; // expando
2150  instances[ id ] = this; // associate via id
2151
2152  // kick it off
2153  this._create();
2154
2155  if ( this.options.isInitLayout ) {
2156    this.layout();
2157  }
2158}
2159
2160// settings are for internal use only
2161Outlayer.namespace = 'outlayer';
2162Outlayer.Item = Item;
2163
2164// default options
2165Outlayer.defaults = {
2166  containerStyle: {
2167    position: 'relative'
2168  },
2169  isInitLayout: true,
2170  isOriginLeft: true,
2171  isOriginTop: true,
2172  isResizeBound: true,
2173  isResizingContainer: true,
2174  // item options
2175  transitionDuration: '0.4s',
2176  hiddenStyle: {
2177    opacity: 0,
2178    transform: 'scale(0.001)'
2179  },
2180  visibleStyle: {
2181    opacity: 1,
2182    transform: 'scale(1)'
2183  }
2184};
2185
2186// inherit EventEmitter
2187utils.extend( Outlayer.prototype, EventEmitter.prototype );
2188
2189/**
2190 * set options
2191 * @param {Object} opts
2192 */
2193Outlayer.prototype.option = function( opts ) {
2194  utils.extend( this.options, opts );
2195};
2196
2197Outlayer.prototype._create = function() {
2198  // get items from children
2199  this.reloadItems();
2200  // elements that affect layout, but are not laid out
2201  this.stamps = [];
2202  this.stamp( this.options.stamp );
2203  // set container style
2204  utils.extend( this.element.style, this.options.containerStyle );
2205
2206  // bind resize method
2207  if ( this.options.isResizeBound ) {
2208    this.bindResize();
2209  }
2210};
2211
2212// goes through all children again and gets bricks in proper order
2213Outlayer.prototype.reloadItems = function() {
2214  // collection of item elements
2215  this.items = this._itemize( this.element.children );
2216};
2217
2218
2219/**
2220 * turn elements into Outlayer.Items to be used in layout
2221 * @param {Array or NodeList or HTMLElement} elems
2222 * @returns {Array} items - collection of new Outlayer Items
2223 */
2224Outlayer.prototype._itemize = function( elems ) {
2225
2226  var itemElems = this._filterFindItemElements( elems );
2227  var Item = this.constructor.Item;
2228
2229  // create new Outlayer Items for collection
2230  var items = [];
2231  for ( var i=0, len = itemElems.length; i < len; i++ ) {
2232    var elem = itemElems[i];
2233    var item = new Item( elem, this );
2234    items.push( item );
2235  }
2236
2237  return items;
2238};
2239
2240/**
2241 * get item elements to be used in layout
2242 * @param {Array or NodeList or HTMLElement} elems
2243 * @returns {Array} items - item elements
2244 */
2245Outlayer.prototype._filterFindItemElements = function( elems ) {
2246  return utils.filterFindElements( elems, this.options.itemSelector );
2247};
2248
2249/**
2250 * getter method for getting item elements
2251 * @returns {Array} elems - collection of item elements
2252 */
2253Outlayer.prototype.getItemElements = function() {
2254  var elems = [];
2255  for ( var i=0, len = this.items.length; i < len; i++ ) {
2256    elems.push( this.items[i].element );
2257  }
2258  return elems;
2259};
2260
2261// ----- init & layout ----- //
2262
2263/**
2264 * lays out all items
2265 */
2266Outlayer.prototype.layout = function() {
2267  this._resetLayout();
2268  this._manageStamps();
2269
2270  // don't animate first layout
2271  var isInstant = this.options.isLayoutInstant !== undefined ?
2272    this.options.isLayoutInstant : !this._isLayoutInited;
2273  this.layoutItems( this.items, isInstant );
2274
2275  // flag for initalized
2276  this._isLayoutInited = true;
2277};
2278
2279// _init is alias for layout
2280Outlayer.prototype._init = Outlayer.prototype.layout;
2281
2282/**
2283 * logic before any new layout
2284 */
2285Outlayer.prototype._resetLayout = function() {
vendor: 6,719 bytes, lines 2286-2562
2286  this.getSize();
2287};
2288
2289
2290Outlayer.prototype.getSize = function() {
2291  this.size = getSize( this.element );
2292};
2293
2294/**
2295 * get measurement from option, for columnWidth, rowHeight, gutter
2296 * if option is String -> get element from selector string, & get size of element
2297 * if option is Element -> get size of element
2298 * else use option as a number
2299 *
2300 * @param {String} measurement
2301 * @param {String} size - width or height
2302 * @private
2303 */
2304Outlayer.prototype._getMeasurement = function( measurement, size ) {
2305  var option = this.options[ measurement ];
2306  var elem;
2307  if ( !option ) {
2308    // default to 0
2309    this[ measurement ] = 0;
2310  } else {
2311    // use option as an element
2312    if ( typeof option === 'string' ) {
2313      elem = this.element.querySelector( option );
2314    } else if ( utils.isElement( option ) ) {
2315      elem = option;
2316    }
2317    // use size of element, if element
2318    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
2319  }
2320};
2321
2322/**
2323 * layout a collection of item elements
2324 * @api public
2325 */
2326Outlayer.prototype.layoutItems = function( items, isInstant ) {
2327  items = this._getItemsForLayout( items );
2328
2329  this._layoutItems( items, isInstant );
2330
2331  this._postLayout();
2332};
2333
2334/**
2335 * get the items to be laid out
2336 * you may want to skip over some items
2337 * @param {Array} items
2338 * @returns {Array} items
2339 */
2340Outlayer.prototype._getItemsForLayout = function( items ) {
2341  var layoutItems = [];
2342  for ( var i=0, len = items.length; i < len; i++ ) {
2343    var item = items[i];
2344    if ( !item.isIgnored ) {
2345      layoutItems.push( item );
2346    }
2347  }
2348  return layoutItems;
2349};
2350
2351/**
2352 * layout items
2353 * @param {Array} items
2354 * @param {Boolean} isInstant
2355 */
2356Outlayer.prototype._layoutItems = function( items, isInstant ) {
2357  this._emitCompleteOnItems( 'layout', items );
2358
2359  if ( !items || !items.length ) {
2360    // no items, emit event with empty array
2361    return;
2362  }
2363
2364  var queue = [];
2365
2366  for ( var i=0, len = items.length; i < len; i++ ) {
2367    var item = items[i];
2368    // get x/y object from method
2369    var position = this._getItemLayoutPosition( item );
2370    // enqueue
2371    position.item = item;
2372    position.isInstant = isInstant || item.isLayoutInstant;
2373    queue.push( position );
2374  }
2375
2376  this._processLayoutQueue( queue );
2377};
2378
2379/**
2380 * get item layout position
2381 * @param {Outlayer.Item} item
2382 * @returns {Object} x and y position
2383 */
2384Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2385  return {
2386    x: 0,
2387    y: 0
2388  };
2389};
2390
2391/**
2392 * iterate over array and position each item
2393 * Reason being - separating this logic prevents 'layout invalidation'
2394 * thx @paul_irish
2395 * @param {Array} queue
2396 */
2397Outlayer.prototype._processLayoutQueue = function( queue ) {
2398  for ( var i=0, len = queue.length; i < len; i++ ) {
2399    var obj = queue[i];
2400    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2401  }
2402};
2403
2404/**
2405 * Sets position of item in DOM
2406 * @param {Outlayer.Item} item
2407 * @param {Number} x - horizontal position
2408 * @param {Number} y - vertical position
2409 * @param {Boolean} isInstant - disables transitions
2410 */
2411Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2412  if ( isInstant ) {
2413    // if not transition, just set CSS
2414    item.goTo( x, y );
2415  } else {
2416    item.moveTo( x, y );
2417  }
2418};
2419
2420/**
2421 * Any logic you want to do after each layout,
2422 * i.e. size the container
2423 */
2424Outlayer.prototype._postLayout = function() {
2425  this.resizeContainer();
2426};
2427
2428Outlayer.prototype.resizeContainer = function() {
2429  if ( !this.options.isResizingContainer ) {
2430    return;
2431  }
2432  var size = this._getContainerSize();
2433  if ( size ) {
2434    this._setContainerMeasure( size.width, true );
2435    this._setContainerMeasure( size.height, false );
2436  }
2437};
2438
2439/**
2440 * Sets width or height of container if returned
2441 * @returns {Object} size
2442 *   @param {Number} width
2443 *   @param {Number} height
2444 */
2445Outlayer.prototype._getContainerSize = noop;
2446
2447/**
2448 * @param {Number} measure - size of width or height
2449 * @param {Boolean} isWidth
2450 */
2451Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2452  if ( measure === undefined ) {
2453    return;
2454  }
2455
2456  var elemSize = this.size;
2457  // add padding and border width if border box
2458  if ( elemSize.isBorderBox ) {
2459    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2460      elemSize.borderLeftWidth + elemSize.borderRightWidth :
2461      elemSize.paddingBottom + elemSize.paddingTop +
2462      elemSize.borderTopWidth + elemSize.borderBottomWidth;
2463  }
2464
2465  measure = Math.max( measure, 0 );
2466  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2467};
2468
2469/**
2470 * emit eventComplete on a collection of items events
2471 * @param {String} eventName
2472 * @param {Array} items - Outlayer.Items
2473 */
2474Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) {
2475  var _this = this;
2476  function onComplete() {
2477    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
2478  }
2479
2480  var count = items.length;
2481  if ( !items || !count ) {
2482    onComplete();
2483    return;
2484  }
2485
2486  var doneCount = 0;
2487  function tick() {
2488    doneCount++;
2489    if ( doneCount === count ) {
2490      onComplete();
2491    }
2492  }
2493
2494  // bind callback
2495  for ( var i=0, len = items.length; i < len; i++ ) {
2496    var item = items[i];
2497    item.once( eventName, tick );
2498  }
2499};
2500
2501/**
2502 * emits events via eventEmitter and jQuery events
2503 * @param {String} type - name of event
2504 * @param {Event} event - original event
2505 * @param {Array} args - extra arguments
2506 */
2507Outlayer.prototype.dispatchEvent = function( type, event, args ) {
2508  // add original event to arguments
2509  var emitArgs = event ? [ event ].concat( args ) : args;
2510  this.emitEvent( type, emitArgs );
2511
2512  if ( jQuery ) {
2513    // set this.$element
2514    this.$element = this.$element || jQuery( this.element );
2515    if ( event ) {
2516      // create jQuery event
2517      var $event = jQuery.Event( event );
2518      $event.type = type;
2519      this.$element.trigger( $event, args );
2520    } else {
2521      // just trigger with type if no event available
2522      this.$element.trigger( type, args );
2523    }
2524  }
2525};
2526
2527// -------------------------- ignore & stamps -------------------------- //
2528
2529
2530/**
2531 * keep item in collection, but do not lay it out
2532 * ignored items do not get skipped in layout
2533 * @param {Element} elem
2534 */
2535Outlayer.prototype.ignore = function( elem ) {
2536  var item = this.getItem( elem );
2537  if ( item ) {
2538    item.isIgnored = true;
2539  }
2540};
2541
2542/**
2543 * return item to layout collection
2544 * @param {Element} elem
2545 */
2546Outlayer.prototype.unignore = function( elem ) {
2547  var item = this.getItem( elem );
2548  if ( item ) {
2549    delete item.isIgnored;
2550  }
2551};
2552
2553/**
2554 * adds elements to stamps
2555 * @param {NodeList, Array, Element, or String} elems
2556 */
2557Outlayer.prototype.stamp = function( elems ) {
2558  elems = this._find( elems );
2559  if ( !elems ) {
2560    return;
2561  }
2562
2563  this.stamps = this.stamps.concat( elems );
2564  // ignore
2565  for ( var i=0, len = elems.length; i < len; i++ ) {
2566    var elem = elems[i];
2567    this.ignore( elem );
2568  }
2569};
2570
2571/**
2572 * removes elements to stamps
2573 * @param {NodeList, Array, or Element} elems
2574 */
2575Outlayer.prototype.unstamp = function( elems ) {
2576  elems = this._find( elems );
2577  if ( !elems ){
2578    return;
2579  }
2580
2581  for ( var i=0, len = elems.length; i < len; i++ ) {
2582    var elem = elems[i];
2583    // filter out removed stamp elements
2584    utils.removeFrom( this.stamps, elem );
2585    this.unignore( elem );
2586  }
2587
2588};
2589
2590/**
2591 * finds child elements
2592 * @param {NodeList, Array, Element, or String} elems
2593 * @returns {Array} elems
2594 */
2595Outlayer.prototype._find = function( elems ) {
2596  if ( !elems ) {
2597    return;
2598  }
2599  // if string, use argument as selector string
2600  if ( typeof elems === 'string' ) {
2601    elems = this.element.querySelectorAll( elems );
2602  }
2603  elems = utils.makeArray( elems );
2604  return elems;
2605};
2606
2607Outlayer.prototype._manageStamps = function() {
2608  if ( !this.stamps || !this.stamps.length ) {
2609    return;
2610  }
2611
2612  this._getBoundingRect();
2613
2614  for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2615    var stamp = this.stamps[i];
2616    this._manageStamp( stamp );
2617  }
2618};
2619
2620// update boundingLeft / Top
2621Outlayer.prototype._getBoundingRect = function() {
2622  // get bounding rect for container element
2623  var boundingRect = this.element.getBoundingClientRect();
2624  var size = this.size;
2625  this._boundingRect = {
2626    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2627    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2628    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2629    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2630  };
2631};
2632
2633/**
2634 * @param {Element} stamp
2635**/
2636Outlayer.prototype._manageStamp = noop;
2637
2638/**
2639 * get x/y position of element relative to container element
2640 * @param {Element} elem
2641 * @returns {Object} offset - has left, top, right, bottom
2642 */
2643Outlayer.prototype._getElementOffset = function( elem ) {
2644  var boundingRect = elem.getBoundingClientRect();
2645  var thisRect = this._boundingRect;
2646  var size = getSize( elem );
2647  var offset = {
2648    left: boundingRect.left - thisRect.left - size.marginLeft,
2649    top: boundingRect.top - thisRect.top - size.marginTop,
2650    right: thisRect.right - boundingRect.right - size.marginRight,
2651    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2652  };
2653  return offset;
2654};
2655
2656// -------------------------- resize -------------------------- //
2657
2658// enable event handlers for listeners
2659// i.e. resize -> onresize
2660Outlayer.prototype.handleEvent = function( event ) {
2661  var method = 'on' + event.type;
2662  if ( this[ method ] ) {
2663    this[ method ]( event );
2664  }
2665};
2666
2667/**
2668 * Bind layout to window resizing
2669 */
2670Outlayer.prototype.bindResize = function() {
2671  // bind just one listener
2672  if ( this.isResizeBound ) {
2673    return;
2674  }
2675  eventie.bind( window, 'resize', this );
2676  this.isResizeBound = true;
2677};
2678
2679/**
2680 * Unbind layout to window resizing
2681 */
2682Outlayer.prototype.unbindResize = function() {
2683  if ( this.isResizeBound ) {
2684    eventie.unbind( window, 'resize', this );
2685  }
2686  this.isResizeBound = false;
2687};
2688
2689// original debounce by John Hann
2690// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2691
2692// this fires every resize
2693Outlayer.prototype.onresize = function() {
2694  if ( this.resizeTimeout ) {
2695    clearTimeout( this.resizeTimeout );
2696  }
2697
2698  var _this = this;
2699  function delayed() {
2700    _this.resize();
2701    delete _this.resizeTimeout;
2702  }
2703
2704  this.resizeTimeout = setTimeout( delayed, 100 );
2705};
2706
2707// debounced, layout on resize
2708Outlayer.prototype.resize = function() {
2709  // don't trigger if size did not change
2710  // or if resize was unbound. See #9
2711  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2712    return;
2713  }
2714
2715  this.layout();
2716};
2717
2718/**
2719 * check if layout is needed post layout
2720 * @returns Boolean
2721 */
2722Outlayer.prototype.needsResizeLayout = function() {
2723  var size = getSize( this.element );
2724  // check that this.size and size are there
2725  // IE8 triggers resize on body size change, so they might not be
2726  var hasSizes = this.size && size;
2727  return hasSizes && size.innerWidth !== this.size.innerWidth;
2728};
2729
2730// -------------------------- methods -------------------------- //
2731
2732/**
2733 * add items to Outlayer instance
2734 * @param {Array or NodeList or Element} elems
2735 * @returns {Array} items - Outlayer.Items
2736**/
2737Outlayer.prototype.addItems = function( elems ) {
2738  var items = this._itemize( elems );
2739  // add items to collection
2740  if ( items.length ) {
2741    this.items = this.items.concat( items );
2742  }
2743  return items;
2744};
2745
2746/**
2747 * Layout newly-appended item elements
2748 * @param {Array or NodeList or Element} elems
2749 */
2750Outlayer.prototype.appended = function( elems ) {
2751  var items = this.addItems( elems );
2752  if ( !items.length ) {
2753    return;
2754  }
2755  // layout and reveal just the new items
2756  this.layoutItems( items, true );
2757  this.reveal( items );
2758};
2759
2760/**
2761 * Layout prepended elements
2762 * @param {Array or NodeList or Element} elems
2763 */
2764Outlayer.prototype.prepended = function( elems ) {
2765  var items = this._itemize( elems );
2766  if ( !items.length ) {
2767    return;
2768  }
2769  // add items to beginning of collection
2770  var previousItems = this.items.slice(0);
2771  this.items = items.concat( previousItems );
2772  // start new layout
2773  this._resetLayout();
2774  this._manageStamps();
2775  // layout new stuff without transition
2776  this.layoutItems( items, true );
2777  this.reveal( items );
2778  // layout previous items
2779  this.layoutItems( previousItems );
2780};
2781
2782/**
2783 * reveal a collection of items
2784 * @param {Array of Outlayer.Items} items
2785 */
2786Outlayer.prototype.reveal = function( items ) {
2787  this._emitCompleteOnItems( 'reveal', items );
2788
2789  var len = items && items.length;
2790  for ( var i=0; len && i < len; i++ ) {
2791    var item = items[i];
2792    item.reveal();
2793  }
2794};
2795
2796/**
2797 * hide a collection of items
2798 * @param {Array of Outlayer.Items} items
2799 */
2800Outlayer.prototype.hide = function( items ) {
2801  this._emitCompleteOnItems( 'hide', items );
2802
2803  var len = items && items.length;
2804  for ( var i=0; len && i < len; i++ ) {
2805    var item = items[i];
2806    item.hide();
2807  }
2808};
2809
2810/**
2811 * reveal item elements
2812 * @param {Array}, {Element}, {NodeList} items
2813 */
2814Outlayer.prototype.revealItemElements = function( elems ) {
2815  var items = this.getItems( elems );
2816  this.reveal( items );
2817};
2818
2819/**
2820 * hide item elements
2821 * @param {Array}, {Element}, {NodeList} items
2822 */
2823Outlayer.prototype.hideItemElements = function( elems ) {
2824  var items = this.getItems( elems );
2825  this.hide( items );
2826};
2827
2828/**
2829 * get Outlayer.Item, given an Element
2830 * @param {Element} elem
2831 * @param {Function} callback
2832 * @returns {Outlayer.Item} item
2833 */
2834Outlayer.prototype.getItem = function( elem ) {
2835  // loop through items to get the one that matches
2836  for ( var i=0, len = this.items.length; i < len; i++ ) {
2837    var item = this.items[i];
2838    if ( item.element === elem ) {
2839      // return item
2840      return item;
2841    }
2842  }
2843};
2844
2845/**
2846 * get collection of Outlayer.Items, given Elements
2847 * @param {Array} elems
2848 * @returns {Array} items - Outlayer.Items
2849 */
2850Outlayer.prototype.getItems = function( elems ) {
2851  elems = utils.makeArray( elems );
2852  var items = [];
2853  for ( var i=0, len = elems.length; i < len; i++ ) {
2854    var elem = elems[i];
2855    var item = this.getItem( elem );
2856    if ( item ) {
2857      items.push( item );
2858    }
2859  }
2860
2861  return items;
2862};
2863
2864/**
vendor: 26,526 bytes, lines 2865-3875
2865 * remove element(s) from instance and DOM
2866 * @param {Array or NodeList or Element} elems
2867 */
2868Outlayer.prototype.remove = function( elems ) {
2869  var removeItems = this.getItems( elems );
2870
2871  this._emitCompleteOnItems( 'remove', removeItems );
2872
2873  // bail if no items to remove
2874  if ( !removeItems || !removeItems.length ) {
2875    return;
2876  }
2877
2878  for ( var i=0, len = removeItems.length; i < len; i++ ) {
2879    var item = removeItems[i];
2880    item.remove();
2881    // remove item from collection
2882    utils.removeFrom( this.items, item );
2883  }
2884};
2885
2886// ----- destroy ----- //
2887
2888// remove and disable Outlayer instance
2889Outlayer.prototype.destroy = function() {
2890  // clean up dynamic styles
2891  var style = this.element.style;
2892  style.height = '';
2893  style.position = '';
2894  style.width = '';
2895  // destroy items
2896  for ( var i=0, len = this.items.length; i < len; i++ ) {
2897    var item = this.items[i];
2898    item.destroy();
2899  }
2900
2901  this.unbindResize();
2902
2903  var id = this.element.outlayerGUID;
2904  delete instances[ id ]; // remove reference to instance by id
2905  delete this.element.outlayerGUID;
2906  // remove data for jQuery
2907  if ( jQuery ) {
2908    jQuery.removeData( this.element, this.constructor.namespace );
2909  }
2910
2911};
2912
2913// -------------------------- data -------------------------- //
2914
2915/**
2916 * get Outlayer instance from element
2917 * @param {Element} elem
2918 * @returns {Outlayer}
2919 */
2920Outlayer.data = function( elem ) {
2921  elem = utils.getQueryElement( elem );
2922  var id = elem && elem.outlayerGUID;
2923  return id && instances[ id ];
2924};
2925
2926
2927// -------------------------- create Outlayer class -------------------------- //
2928
2929/**
2930 * create a layout class
2931 * @param {String} namespace
2932 */
2933Outlayer.create = function( namespace, options ) {
2934  // sub-class Outlayer
2935  function Layout() {
2936    Outlayer.apply( this, arguments );
2937  }
2938  // inherit Outlayer prototype, use Object.create if there
2939  if ( Object.create ) {
2940    Layout.prototype = Object.create( Outlayer.prototype );
2941  } else {
2942    utils.extend( Layout.prototype, Outlayer.prototype );
2943  }
2944  // set contructor, used for namespace and Item
2945  Layout.prototype.constructor = Layout;
2946
2947  Layout.defaults = utils.extend( {}, Outlayer.defaults );
2948  // apply new options
2949  utils.extend( Layout.defaults, options );
2950  // keep prototype.settings for backwards compatibility (Packery v1.2.0)
2951  Layout.prototype.settings = {};
2952
2953  Layout.namespace = namespace;
2954
2955  Layout.data = Outlayer.data;
2956
2957  // sub-class Item
2958  Layout.Item = function LayoutItem() {
2959    Item.apply( this, arguments );
2960  };
2961
2962  Layout.Item.prototype = new Item();
2963
2964  // -------------------------- declarative -------------------------- //
2965
2966  utils.htmlInit( Layout, namespace );
2967
2968  // -------------------------- jQuery bridge -------------------------- //
2969
2970  // make into jQuery plugin
2971  if ( jQuery && jQuery.bridget ) {
2972    jQuery.bridget( namespace, Layout );
2973  }
2974
2975  return Layout;
2976};
2977
2978// ----- fin ----- //
2979
2980// back in global
2981Outlayer.Item = Item;
2982
2983return Outlayer;
2984
2985}));
2986
2987
2988/**
2989 * Isotope Item
2990**/
2991
2992( function( window, factory ) {
2993'use strict';
2994  // universal module definition
2995  if ( typeof define == 'function' && define.amd ) {
2996    // AMD
2997    define( 'isotope/js/item',[
2998        'outlayer/outlayer'
2999      ],
3000      factory );
3001  } else if ( typeof exports == 'object' ) {
3002    // CommonJS
3003    module.exports = factory(
3004      require('outlayer')
3005    );
3006  } else {
3007    // browser global
3008    window.Isotope = window.Isotope || {};
3009    window.Isotope.Item = factory(
3010      window.Outlayer
3011    );
3012  }
3013
3014}( window, function factory( Outlayer ) {
3015'use strict';
3016
3017// -------------------------- Item -------------------------- //
3018
3019// sub-class Outlayer Item
3020function Item() {
3021  Outlayer.Item.apply( this, arguments );
3022}
3023
3024Item.prototype = new Outlayer.Item();
3025
3026Item.prototype._create = function() {
3027  // assign id, used for original-order sorting
3028  this.id = this.layout.itemGUID++;
3029  Outlayer.Item.prototype._create.call( this );
3030  this.sortData = {};
3031};
3032
3033Item.prototype.updateSortData = function() {
3034  if ( this.isIgnored ) {
3035    return;
3036  }
3037  // default sorters
3038  this.sortData.id = this.id;
3039  // for backward compatibility
3040  this.sortData['original-order'] = this.id;
3041  this.sortData.random = Math.random();
3042  // go thru getSortData obj and apply the sorters
3043  var getSortData = this.layout.options.getSortData;
3044  var sorters = this.layout._sorters;
3045  for ( var key in getSortData ) {
3046    var sorter = sorters[ key ];
3047    this.sortData[ key ] = sorter( this.element, this );
3048  }
3049};
3050
3051var _destroy = Item.prototype.destroy;
3052Item.prototype.destroy = function() {
3053  // call super
3054  _destroy.apply( this, arguments );
3055  // reset display, #741
3056  this.css({
3057    display: ''
3058  });
3059};
3060
3061return Item;
3062
3063}));
3064
3065/**
3066 * Isotope LayoutMode
3067 */
3068
3069( function( window, factory ) {
3070  'use strict';
3071  // universal module definition
3072
3073  if ( typeof define == 'function' && define.amd ) {
3074    // AMD
3075    define( 'isotope/js/layout-mode',[
3076        'get-size/get-size',
3077        'outlayer/outlayer'
3078      ],
3079      factory );
3080  } else if ( typeof exports == 'object' ) {
3081    // CommonJS
3082    module.exports = factory(
3083      require('get-size'),
3084      require('outlayer')
3085    );
3086  } else {
3087    // browser global
3088    window.Isotope = window.Isotope || {};
3089    window.Isotope.LayoutMode = factory(
3090      window.getSize,
3091      window.Outlayer
3092    );
3093  }
3094
3095}( window, function factory( getSize, Outlayer ) {
3096  'use strict';
3097
3098  // layout mode class
3099  function LayoutMode( isotope ) {
3100    this.isotope = isotope;
3101    // link properties
3102    if ( isotope ) {
3103      this.options = isotope.options[ this.namespace ];
3104      this.element = isotope.element;
3105      this.items = isotope.filteredItems;
3106      this.size = isotope.size;
3107    }
3108  }
3109
3110  /**
3111   * some methods should just defer to default Outlayer method
3112   * and reference the Isotope instance as `this`
3113  **/
3114  ( function() {
3115    var facadeMethods = [
3116      '_resetLayout',
3117      '_getItemLayoutPosition',
3118      '_manageStamp',
3119      '_getContainerSize',
3120      '_getElementOffset',
3121      'needsResizeLayout'
3122    ];
3123
3124    for ( var i=0, len = facadeMethods.length; i < len; i++ ) {
3125      var methodName = facadeMethods[i];
3126      LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName );
3127    }
3128
3129    function getOutlayerMethod( methodName ) {
3130      return function() {
3131        return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
3132      };
3133    }
3134  })();
3135
3136  // -----  ----- //
3137
3138  // for horizontal layout modes, check vertical size
3139  LayoutMode.prototype.needsVerticalResizeLayout = function() {
3140    // don't trigger if size did not change
3141    var size = getSize( this.isotope.element );
3142    // check that this.size and size are there
3143    // IE8 triggers resize on body size change, so they might not be
3144    var hasSizes = this.isotope.size && size;
3145    return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
3146  };
3147
3148  // ----- measurements ----- //
3149
3150  LayoutMode.prototype._getMeasurement = function() {
3151    this.isotope._getMeasurement.apply( this, arguments );
3152  };
3153
3154  LayoutMode.prototype.getColumnWidth = function() {
3155    this.getSegmentSize( 'column', 'Width' );
3156  };
3157
3158  LayoutMode.prototype.getRowHeight = function() {
3159    this.getSegmentSize( 'row', 'Height' );
3160  };
3161
3162  /**
3163   * get columnWidth or rowHeight
3164   * segment: 'column' or 'row'
3165   * size 'Width' or 'Height'
3166  **/
3167  LayoutMode.prototype.getSegmentSize = function( segment, size ) {
3168    var segmentName = segment + size;
3169    var outerSize = 'outer' + size;
3170    // columnWidth / outerWidth // rowHeight / outerHeight
3171    this._getMeasurement( segmentName, outerSize );
3172    // got rowHeight or columnWidth, we can chill
3173    if ( this[ segmentName ] ) {
3174      return;
3175    }
3176    // fall back to item of first element
3177    var firstItemSize = this.getFirstItemSize();
3178    this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
3179      // or size of container
3180      this.isotope.size[ 'inner' + size ];
3181  };
3182
3183  LayoutMode.prototype.getFirstItemSize = function() {
3184    var firstItem = this.isotope.filteredItems[0];
3185    return firstItem && firstItem.element && getSize( firstItem.element );
3186  };
3187
3188  // ----- methods that should reference isotope ----- //
3189
3190  LayoutMode.prototype.layout = function() {
3191    this.isotope.layout.apply( this.isotope, arguments );
3192  };
3193
3194  LayoutMode.prototype.getSize = function() {
3195    this.isotope.getSize();
3196    this.size = this.isotope.size;
3197  };
3198
3199  // -------------------------- create -------------------------- //
3200
3201  LayoutMode.modes = {};
3202
3203  LayoutMode.create = function( namespace, options ) {
3204
3205    function Mode() {
3206      LayoutMode.apply( this, arguments );
3207    }
3208
3209    Mode.prototype = new LayoutMode();
3210
3211    // default options
3212    if ( options ) {
3213      Mode.options = options;
3214    }
3215
3216    Mode.prototype.namespace = namespace;
3217    // register in Isotope
3218    LayoutMode.modes[ namespace ] = Mode;
3219
3220    return Mode;
3221  };
3222
3223  return LayoutMode;
3224
3225}));
3226
3227/*!
3228 * Masonry v3.3.0
3229 * Cascading grid layout library
3230 * http://masonry.desandro.com
3231 * MIT License
3232 * by David DeSandro
3233 */
3234
3235( function( window, factory ) {
3236  'use strict';
3237  // universal module definition
3238  if ( typeof define === 'function' && define.amd ) {
3239    // AMD
3240    define( 'masonry/masonry',[
3241        'outlayer/outlayer',
3242        'get-size/get-size',
3243        'fizzy-ui-utils/utils'
3244      ],
3245      factory );
3246  } else if ( typeof exports === 'object' ) {
3247    // CommonJS
3248    module.exports = factory(
3249      require('outlayer'),
3250      require('get-size'),
3251      require('fizzy-ui-utils')
3252    );
3253  } else {
3254    // browser global
3255    window.Masonry = factory(
3256      window.Outlayer,
3257      window.getSize,
3258      window.fizzyUIUtils
3259    );
3260  }
3261
3262}( window, function factory( Outlayer, getSize, utils ) {
3263
3264
3265
3266// -------------------------- masonryDefinition -------------------------- //
3267
3268  // create an Outlayer layout class
3269  var Masonry = Outlayer.create('masonry');
3270
3271  Masonry.prototype._resetLayout = function() {
3272    this.getSize();
3273    this._getMeasurement( 'columnWidth', 'outerWidth' );
3274    this._getMeasurement( 'gutter', 'outerWidth' );
3275    this.measureColumns();
3276
3277    // reset column Y
3278    var i = this.cols;
3279    this.colYs = [];
3280    while (i--) {
3281      this.colYs.push( 0 );
3282    }
3283
3284    this.maxY = 0;
3285  };
3286
3287  Masonry.prototype.measureColumns = function() {
3288    this.getContainerWidth();
3289    // if columnWidth is 0, default to outerWidth of first item
3290    if ( !this.columnWidth ) {
3291      var firstItem = this.items[0];
3292      var firstItemElem = firstItem && firstItem.element;
3293      // columnWidth fall back to item of first element
3294      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
3295        // if first elem has no width, default to size of container
3296        this.containerWidth;
3297    }
3298
3299    var columnWidth = this.columnWidth += this.gutter;
3300
3301    // calculate columns
3302    var containerWidth = this.containerWidth + this.gutter;
3303    var cols = containerWidth / columnWidth;
3304    // fix rounding errors, typically with gutters
3305    var excess = columnWidth - containerWidth % columnWidth;
3306    // if overshoot is less than a pixel, round up, otherwise floor it
3307    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
3308    cols = Math[ mathMethod ]( cols );
3309    this.cols = Math.max( cols, 1 );
3310  };
3311
3312  Masonry.prototype.getContainerWidth = function() {
3313    // container is parent if fit width
3314    var container = this.options.isFitWidth ? this.element.parentNode : this.element;
3315    // check that this.size and size are there
3316    // IE8 triggers resize on body size change, so they might not be
3317    var size = getSize( container );
3318    this.containerWidth = size && size.innerWidth;
3319  };
3320
3321  Masonry.prototype._getItemLayoutPosition = function( item ) {
3322    item.getSize();
3323    // how many columns does this brick span
3324    var remainder = item.size.outerWidth % this.columnWidth;
3325    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
3326    // round if off by 1 pixel, otherwise use ceil
3327    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
3328    colSpan = Math.min( colSpan, this.cols );
3329
3330    var colGroup = this._getColGroup( colSpan );
3331    // get the minimum Y value from the columns
3332    var minimumY = Math.min.apply( Math, colGroup );
3333    var shortColIndex = utils.indexOf( colGroup, minimumY );
3334
3335    // position the brick
3336    var position = {
3337      x: this.columnWidth * shortColIndex,
3338      y: minimumY
3339    };
3340
3341    // apply setHeight to necessary columns
3342    var setHeight = minimumY + item.size.outerHeight;
3343    var setSpan = this.cols + 1 - colGroup.length;
3344    for ( var i = 0; i < setSpan; i++ ) {
3345      this.colYs[ shortColIndex + i ] = setHeight;
3346    }
3347
3348    return position;
3349  };
3350
3351  /**
3352   * @param {Number} colSpan - number of columns the element spans
3353   * @returns {Array} colGroup
3354   */
3355  Masonry.prototype._getColGroup = function( colSpan ) {
3356    if ( colSpan < 2 ) {
3357      // if brick spans only one column, use all the column Ys
3358      return this.colYs;
3359    }
3360
3361    var colGroup = [];
3362    // how many different places could this brick fit horizontally
3363    var groupCount = this.cols + 1 - colSpan;
3364    // for each group potential horizontal position
3365    for ( var i = 0; i < groupCount; i++ ) {
3366      // make an array of colY values for that one group
3367      var groupColYs = this.colYs.slice( i, i + colSpan );
3368      // and get the max value of the array
3369      colGroup[i] = Math.max.apply( Math, groupColYs );
3370    }
3371    return colGroup;
3372  };
3373
3374  Masonry.prototype._manageStamp = function( stamp ) {
3375    var stampSize = getSize( stamp );
3376    var offset = this._getElementOffset( stamp );
3377    // get the columns that this stamp affects
3378    var firstX = this.options.isOriginLeft ? offset.left : offset.right;
3379    var lastX = firstX + stampSize.outerWidth;
3380    var firstCol = Math.floor( firstX / this.columnWidth );
3381    firstCol = Math.max( 0, firstCol );
3382    var lastCol = Math.floor( lastX / this.columnWidth );
3383    // lastCol should not go over if multiple of columnWidth #425
3384    lastCol -= lastX % this.columnWidth ? 0 : 1;
3385    lastCol = Math.min( this.cols - 1, lastCol );
3386    // set colYs to bottom of the stamp
3387    var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
3388      stampSize.outerHeight;
3389    for ( var i = firstCol; i <= lastCol; i++ ) {
3390      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
3391    }
3392  };
3393
3394  Masonry.prototype._getContainerSize = function() {
3395    this.maxY = Math.max.apply( Math, this.colYs );
3396    var size = {
3397      height: this.maxY
3398    };
3399
3400    if ( this.options.isFitWidth ) {
3401      size.width = this._getContainerFitWidth();
3402    }
3403
3404    return size;
3405  };
3406
3407  Masonry.prototype._getContainerFitWidth = function() {
3408    var unusedCols = 0;
3409    // count unused columns
3410    var i = this.cols;
3411    while ( --i ) {
3412      if ( this.colYs[i] !== 0 ) {
3413        break;
3414      }
3415      unusedCols++;
3416    }
3417    // fit container to columns that have been used
3418    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
3419  };
3420
3421  Masonry.prototype.needsResizeLayout = function() {
3422    var previousWidth = this.containerWidth;
3423    this.getContainerWidth();
3424    return previousWidth !== this.containerWidth;
3425  };
3426
3427  return Masonry;
3428
3429}));
3430
3431/*!
3432 * Masonry layout mode
3433 * sub-classes Masonry
3434 * http://masonry.desandro.com
3435 */
3436
3437( function( window, factory ) {
3438  'use strict';
3439  // universal module definition
3440  if ( typeof define == 'function' && define.amd ) {
3441    // AMD
3442    define( 'isotope/js/layout-modes/masonry',[
3443        '../layout-mode',
3444        'masonry/masonry'
3445      ],
3446      factory );
3447  } else if ( typeof exports == 'object' ) {
3448    // CommonJS
3449    module.exports = factory(
3450      require('../layout-mode'),
3451      require('masonry-layout')
3452    );
3453  } else {
3454    // browser global
3455    factory(
3456      window.Isotope.LayoutMode,
3457      window.Masonry
3458    );
3459  }
3460
3461}( window, function factory( LayoutMode, Masonry ) {
3462'use strict';
3463
3464// -------------------------- helpers -------------------------- //
3465
3466// extend objects
3467function extend( a, b ) {
3468  for ( var prop in b ) {
3469    a[ prop ] = b[ prop ];
3470  }
3471  return a;
3472}
3473
3474// -------------------------- masonryDefinition -------------------------- //
3475
3476  // create an Outlayer layout class
3477  var MasonryMode = LayoutMode.create('masonry');
3478
3479  // save on to these methods
3480  var _getElementOffset = MasonryMode.prototype._getElementOffset;
3481  var layout = MasonryMode.prototype.layout;
3482  var _getMeasurement = MasonryMode.prototype._getMeasurement;
3483
3484  // sub-class Masonry
3485  extend( MasonryMode.prototype, Masonry.prototype );
3486
3487  // set back, as it was overwritten by Masonry
3488  MasonryMode.prototype._getElementOffset = _getElementOffset;
3489  MasonryMode.prototype.layout = layout;
3490  MasonryMode.prototype._getMeasurement = _getMeasurement;
3491
3492  var measureColumns = MasonryMode.prototype.measureColumns;
3493  MasonryMode.prototype.measureColumns = function() {
3494    // set items, used if measuring first item
3495    this.items = this.isotope.filteredItems;
3496    measureColumns.call( this );
3497  };
3498
3499  // HACK copy over isOriginLeft/Top options
3500  var _manageStamp = MasonryMode.prototype._manageStamp;
3501  MasonryMode.prototype._manageStamp = function() {
3502    this.options.isOriginLeft = this.isotope.options.isOriginLeft;
3503    this.options.isOriginTop = this.isotope.options.isOriginTop;
3504    _manageStamp.apply( this, arguments );
3505  };
3506
3507  return MasonryMode;
3508
3509}));
3510
3511/**
3512 * fitRows layout mode
3513 */
3514
3515( function( window, factory ) {
3516  'use strict';
3517  // universal module definition
3518  if ( typeof define == 'function' && define.amd ) {
3519    // AMD
3520    define( 'isotope/js/layout-modes/fit-rows',[
3521        '../layout-mode'
3522      ],
3523      factory );
3524  } else if ( typeof exports == 'object' ) {
3525    // CommonJS
3526    module.exports = factory(
3527      require('../layout-mode')
3528    );
3529  } else {
3530    // browser global
3531    factory(
3532      window.Isotope.LayoutMode
3533    );
3534  }
3535
3536}( window, function factory( LayoutMode ) {
3537'use strict';
3538
3539var FitRows = LayoutMode.create('fitRows');
3540
3541FitRows.prototype._resetLayout = function() {
3542  this.x = 0;
3543  this.y = 0;
3544  this.maxY = 0;
3545  this._getMeasurement( 'gutter', 'outerWidth' );
3546};
3547
3548FitRows.prototype._getItemLayoutPosition = function( item ) {
3549  item.getSize();
3550
3551  var itemWidth = item.size.outerWidth + this.gutter;
3552  // if this element cannot fit in the current row
3553  var containerWidth = this.isotope.size.innerWidth + this.gutter;
3554  if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
3555    this.x = 0;
3556    this.y = this.maxY;
3557  }
3558
3559  var position = {
3560    x: this.x,
3561    y: this.y
3562  };
3563
3564  this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
3565  this.x += itemWidth;
3566
3567  return position;
3568};
3569
3570FitRows.prototype._getContainerSize = function() {
3571  return { height: this.maxY };
3572};
3573
3574return FitRows;
3575
3576}));
3577
3578/**
3579 * vertical layout mode
3580 */
3581
3582( function( window, factory ) {
3583  'use strict';
3584  // universal module definition
3585  if ( typeof define == 'function' && define.amd ) {
3586    // AMD
3587    define( 'isotope/js/layout-modes/vertical',[
3588        '../layout-mode'
3589      ],
3590      factory );
3591  } else if ( typeof exports == 'object' ) {
3592    // CommonJS
3593    module.exports = factory(
3594      require('../layout-mode')
3595    );
3596  } else {
3597    // browser global
3598    factory(
3599      window.Isotope.LayoutMode
3600    );
3601  }
3602
3603}( window, function factory( LayoutMode ) {
3604'use strict';
3605
3606var Vertical = LayoutMode.create( 'vertical', {
3607  horizontalAlignment: 0
3608});
3609
3610Vertical.prototype._resetLayout = function() {
3611  this.y = 0;
3612};
3613
3614Vertical.prototype._getItemLayoutPosition = function( item ) {
3615  item.getSize();
3616  var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
3617    this.options.horizontalAlignment;
3618  var y = this.y;
3619  this.y += item.size.outerHeight;
3620  return { x: x, y: y };
3621};
3622
3623Vertical.prototype._getContainerSize = function() {
3624  return { height: this.y };
3625};
3626
3627return Vertical;
3628
3629}));
3630
3631/*!
3632 * Isotope v2.2.0
3633 *
3634 * Licensed GPLv3 for open source use
3635 * or Isotope Commercial License for commercial use
3636 *
3637 * http://isotope.metafizzy.co
3638 * Copyright 2015 Metafizzy
3639 */
3640
3641( function( window, factory ) {
3642  'use strict';
3643  // universal module definition
3644
3645  if ( typeof define == 'function' && define.amd ) {
3646    // AMD
3647    define( [
3648        'outlayer/outlayer',
3649        'get-size/get-size',
3650        'matches-selector/matches-selector',
3651        'fizzy-ui-utils/utils',
3652        'isotope/js/item',
3653        'isotope/js/layout-mode',
3654        // include default layout modes
3655        'isotope/js/layout-modes/masonry',
3656        'isotope/js/layout-modes/fit-rows',
3657        'isotope/js/layout-modes/vertical'
3658      ],
3659      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
3660        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
3661      });
3662  } else if ( typeof exports == 'object' ) {
3663    // CommonJS
3664    module.exports = factory(
3665      window,
3666      require('outlayer'),
3667      require('get-size'),
3668      require('desandro-matches-selector'),
3669      require('fizzy-ui-utils'),
3670      require('./item'),
3671      require('./layout-mode'),
3672      // include default layout modes
3673      require('./layout-modes/masonry'),
3674      require('./layout-modes/fit-rows'),
3675      require('./layout-modes/vertical')
3676    );
3677  } else {
3678    // browser global
3679    window.Isotope = factory(
3680      window,
3681      window.Outlayer,
3682      window.getSize,
3683      window.matchesSelector,
3684      window.fizzyUIUtils,
3685      window.Isotope.Item,
3686      window.Isotope.LayoutMode
3687    );
3688  }
3689
3690}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
3691  Item, LayoutMode ) {
3692
3693
3694
3695// -------------------------- vars -------------------------- //
3696
3697var jQuery = window.jQuery;
3698
3699// -------------------------- helpers -------------------------- //
3700
3701var trim = String.prototype.trim ?
3702  function( str ) {
3703    return str.trim();
3704  } :
3705  function( str ) {
3706    return str.replace( /^\s+|\s+$/g, '' );
3707  };
3708
3709var docElem = document.documentElement;
3710
3711var getText = docElem.textContent ?
3712  function( elem ) {
3713    return elem.textContent;
3714  } :
3715  function( elem ) {
3716    return elem.innerText;
3717  };
3718
3719// -------------------------- isotopeDefinition -------------------------- //
3720
3721  // create an Outlayer layout class
3722  var Isotope = Outlayer.create( 'isotope', {
3723    layoutMode: "masonry",
3724    isJQueryFiltering: true,
3725    sortAscending: true
3726  });
3727
3728  Isotope.Item = Item;
3729  Isotope.LayoutMode = LayoutMode;
3730
3731  Isotope.prototype._create = function() {
3732    this.itemGUID = 0;
3733    // functions that sort items
3734    this._sorters = {};
3735    this._getSorters();
3736    // call super
3737    Outlayer.prototype._create.call( this );
3738
3739    // create layout modes
3740    this.modes = {};
3741    // start filteredItems with all items
3742    this.filteredItems = this.items;
3743    // keep of track of sortBys
3744    this.sortHistory = [ 'original-order' ];
3745    // create from registered layout modes
3746    for ( var name in LayoutMode.modes ) {
3747      this._initLayoutMode( name );
3748    }
3749  };
3750
3751  Isotope.prototype.reloadItems = function() {
3752    // reset item ID counter
3753    this.itemGUID = 0;
3754    // call super
3755    Outlayer.prototype.reloadItems.call( this );
3756  };
3757
3758  Isotope.prototype._itemize = function() {
3759    var items = Outlayer.prototype._itemize.apply( this, arguments );
3760    // assign ID for original-order
3761    for ( var i=0, len = items.length; i < len; i++ ) {
3762      var item = items[i];
3763      item.id = this.itemGUID++;
3764    }
3765    this._updateItemsSortData( items );
3766    return items;
3767  };
3768
3769
3770  // -------------------------- layout -------------------------- //
3771
3772  Isotope.prototype._initLayoutMode = function( name ) {
3773    var Mode = LayoutMode.modes[ name ];
3774    // set mode options
3775    // HACK extend initial options, back-fill in default options
3776    var initialOpts = this.options[ name ] || {};
3777    this.options[ name ] = Mode.options ?
3778      utils.extend( Mode.options, initialOpts ) : initialOpts;
3779    // init layout mode instance
3780    this.modes[ name ] = new Mode( this );
3781  };
3782
3783
3784  Isotope.prototype.layout = function() {
3785    // if first time doing layout, do all magic
3786    if ( !this._isLayoutInited && this.options.isInitLayout ) {
3787      this.arrange();
3788      return;
3789    }
3790    this._layout();
3791  };
3792
3793  // private method to be used in layout() & magic()
3794  Isotope.prototype._layout = function() {
3795    // don't animate first layout
3796    var isInstant = this._getIsInstant();
3797    // layout flow
3798    this._resetLayout();
3799    this._manageStamps();
3800    this.layoutItems( this.filteredItems, isInstant );
3801
3802    // flag for initalized
3803    this._isLayoutInited = true;
3804  };
3805
3806  // filter + sort + layout
3807  Isotope.prototype.arrange = function( opts ) {
3808    // set any options pass
3809    this.option( opts );
3810    this._getIsInstant();
3811    // filter, sort, and layout
3812
3813    // filter
3814    var filtered = this._filter( this.items );
3815    this.filteredItems = filtered.matches;
3816
3817    var _this = this;
3818    function hideReveal() {
3819      _this.reveal( filtered.needReveal );
3820      _this.hide( filtered.needHide );
3821    }
3822
3823    this._bindArrangeComplete();
3824
3825    if ( this._isInstant ) {
3826      this._noTransition( hideReveal );
3827    } else {
3828      hideReveal();
3829    }
3830
3831    this._sort();
3832    this._layout();
3833  };
3834  // alias to _init for main plugin method
3835  Isotope.prototype._init = Isotope.prototype.arrange;
3836
3837  // HACK
3838  // Don't animate/transition first layout
3839  // Or don't animate/transition other layouts
3840  Isotope.prototype._getIsInstant = function() {
3841    var isInstant = this.options.isLayoutInstant !== undefined ?
3842      this.options.isLayoutInstant : !this._isLayoutInited;
3843    this._isInstant = isInstant;
3844    return isInstant;
3845  };
3846
3847  // listen for layoutComplete, hideComplete and revealComplete
3848  // to trigger arrangeComplete
3849  Isotope.prototype._bindArrangeComplete = function() {
3850    // listen for 3 events to trigger arrangeComplete
3851    var isLayoutComplete, isHideComplete, isRevealComplete;
3852    var _this = this;
3853    function arrangeParallelCallback() {
3854      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
3855        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
3856      }
3857    }
3858    this.once( 'layoutComplete', function() {
3859      isLayoutComplete = true;
3860      arrangeParallelCallback();
3861    });
3862    this.once( 'hideComplete', function() {
3863      isHideComplete = true;
3864      arrangeParallelCallback();
3865    });
3866    this.once( 'revealComplete', function() {
3867      isRevealComplete = true;
3868      arrangeParallelCallback();
3869    });
3870  };
3871
3872  // -------------------------- filter -------------------------- //
3873
3874  Isotope.prototype._filter = function( items ) {
3875    var filter = this.options.filter;
vendor: 11,152 bytes, lines 3876-4259
3876    filter = filter || '*';
3877    var matches = [];
3878    var hiddenMatched = [];
3879    var visibleUnmatched = [];
3880
3881    var test = this._getFilterTest( filter );
3882
3883    // test each item
3884    for ( var i=0, len = items.length; i < len; i++ ) {
3885      var item = items[i];
3886      if ( item.isIgnored ) {
3887        continue;
3888      }
3889      // add item to either matched or unmatched group
3890      var isMatched = test( item );
3891      // item.isFilterMatched = isMatched;
3892      // add to matches if its a match
3893      if ( isMatched ) {
3894        matches.push( item );
3895      }
3896      // add to additional group if item needs to be hidden or revealed
3897      if ( isMatched && item.isHidden ) {
3898        hiddenMatched.push( item );
3899      } else if ( !isMatched && !item.isHidden ) {
3900        visibleUnmatched.push( item );
3901      }
3902    }
3903
3904    // return collections of items to be manipulated
3905    return {
3906      matches: matches,
3907      needReveal: hiddenMatched,
3908      needHide: visibleUnmatched
3909    };
3910  };
3911
3912  // get a jQuery, function, or a matchesSelector test given the filter
3913  Isotope.prototype._getFilterTest = function( filter ) {
3914    if ( jQuery && this.options.isJQueryFiltering ) {
3915      // use jQuery
3916      return function( item ) {
3917        return jQuery( item.element ).is( filter );
3918      };
3919    }
3920    if ( typeof filter == 'function' ) {
3921      // use filter as function
3922      return function( item ) {
3923        return filter( item.element );
3924      };
3925    }
3926    // default, use filter as selector string
3927    return function( item ) {
3928      return matchesSelector( item.element, filter );
3929    };
3930  };
3931
3932  // -------------------------- sorting -------------------------- //
3933
3934  /**
3935   * @params {Array} elems
3936   * @public
3937   */
3938  Isotope.prototype.updateSortData = function( elems ) {
3939    // get items
3940    var items;
3941    if ( elems ) {
3942      elems = utils.makeArray( elems );
3943      items = this.getItems( elems );
3944    } else {
3945      // update all items if no elems provided
3946      items = this.items;
3947    }
3948
3949    this._getSorters();
3950    this._updateItemsSortData( items );
3951  };
3952
3953  Isotope.prototype._getSorters = function() {
3954    var getSortData = this.options.getSortData;
3955    for ( var key in getSortData ) {
3956      var sorter = getSortData[ key ];
3957      this._sorters[ key ] = mungeSorter( sorter );
3958    }
3959  };
3960
3961  /**
3962   * @params {Array} items - of Isotope.Items
3963   * @private
3964   */
3965  Isotope.prototype._updateItemsSortData = function( items ) {
3966    // do not update if no items
3967    var len = items && items.length;
3968
3969    for ( var i=0; len && i < len; i++ ) {
3970      var item = items[i];
3971      item.updateSortData();
3972    }
3973  };
3974
3975  // ----- munge sorter ----- //
3976
3977  // encapsulate this, as we just need mungeSorter
3978  // other functions in here are just for munging
3979  var mungeSorter = ( function() {
3980    // add a magic layer to sorters for convienent shorthands
3981    // `.foo-bar` will use the text of .foo-bar querySelector
3982    // `[foo-bar]` will use attribute
3983    // you can also add parser
3984    // `.foo-bar parseInt` will parse that as a number
3985    function mungeSorter( sorter ) {
3986      // if not a string, return function or whatever it is
3987      if ( typeof sorter != 'string' ) {
3988        return sorter;
3989      }
3990      // parse the sorter string
3991      var args = trim( sorter ).split(' ');
3992      var query = args[0];
3993      // check if query looks like [an-attribute]
3994      var attrMatch = query.match( /^\[(.+)\]$/ );
3995      var attr = attrMatch && attrMatch[1];
3996      var getValue = getValueGetter( attr, query );
3997      // use second argument as a parser
3998      var parser = Isotope.sortDataParsers[ args[1] ];
3999      // parse the value, if there was a parser
4000      sorter = parser ? function( elem ) {
4001        return elem && parser( getValue( elem ) );
4002      } :
4003      // otherwise just return value
4004      function( elem ) {
4005        return elem && getValue( elem );
4006      };
4007
4008      return sorter;
4009    }
4010
4011    // get an attribute getter, or get text of the querySelector
4012    function getValueGetter( attr, query ) {
4013      var getValue;
4014      // if query looks like [foo-bar], get attribute
4015      if ( attr ) {
4016        getValue = function( elem ) {
4017          return elem.getAttribute( attr );
4018        };
4019      } else {
4020        // otherwise, assume its a querySelector, and get its text
4021        getValue = function( elem ) {
4022          var child = elem.querySelector( query );
4023          return child && getText( child );
4024        };
4025      }
4026      return getValue;
4027    }
4028
4029    return mungeSorter;
4030  })();
4031
4032  // parsers used in getSortData shortcut strings
4033  Isotope.sortDataParsers = {
4034    'parseInt': function( val ) {
4035      return parseInt( val, 10 );
4036    },
4037    'parseFloat': function( val ) {
4038      return parseFloat( val );
4039    }
4040  };
4041
4042  // ----- sort method ----- //
4043
4044  // sort filteredItem order
4045  Isotope.prototype._sort = function() {
4046    var sortByOpt = this.options.sortBy;
4047    if ( !sortByOpt ) {
4048      return;
4049    }
4050    // concat all sortBy and sortHistory
4051    var sortBys = [].concat.apply( sortByOpt, this.sortHistory );
4052    // sort magic
4053    var itemSorter = getItemSorter( sortBys, this.options.sortAscending );
4054    this.filteredItems.sort( itemSorter );
4055    // keep track of sortBy History
4056    if ( sortByOpt != this.sortHistory[0] ) {
4057      // add to front, oldest goes in last
4058      this.sortHistory.unshift( sortByOpt );
4059    }
4060  };
4061
4062  // returns a function used for sorting
4063  function getItemSorter( sortBys, sortAsc ) {
4064    return function sorter( itemA, itemB ) {
4065      // cycle through all sortKeys
4066      for ( var i = 0, len = sortBys.length; i < len; i++ ) {
4067        var sortBy = sortBys[i];
4068        var a = itemA.sortData[ sortBy ];
4069        var b = itemB.sortData[ sortBy ];
4070        if ( a > b || a < b ) {
4071          // if sortAsc is an object, use the value given the sortBy key
4072          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
4073          var direction = isAscending ? 1 : -1;
4074          return ( a > b ? 1 : -1 ) * direction;
4075        }
4076      }
4077      return 0;
4078    };
4079  }
4080
4081  // -------------------------- methods -------------------------- //
4082
4083  // get layout mode
4084  Isotope.prototype._mode = function() {
4085    var layoutMode = this.options.layoutMode;
4086    var mode = this.modes[ layoutMode ];
4087    if ( !mode ) {
4088      // TODO console.error
4089      throw new Error( 'No layout mode: ' + layoutMode );
4090    }
4091    // HACK sync mode's options
4092    // any options set after init for layout mode need to be synced
4093    mode.options = this.options[ layoutMode ];
4094    return mode;
4095  };
4096
4097  Isotope.prototype._resetLayout = function() {
4098    // trigger original reset layout
4099    Outlayer.prototype._resetLayout.call( this );
4100    this._mode()._resetLayout();
4101  };
4102
4103  Isotope.prototype._getItemLayoutPosition = function( item  ) {
4104    return this._mode()._getItemLayoutPosition( item );
4105  };
4106
4107  Isotope.prototype._manageStamp = function( stamp ) {
4108    this._mode()._manageStamp( stamp );
4109  };
4110
4111  Isotope.prototype._getContainerSize = function() {
4112    return this._mode()._getContainerSize();
4113  };
4114
4115  Isotope.prototype.needsResizeLayout = function() {
4116    return this._mode().needsResizeLayout();
4117  };
4118
4119  // -------------------------- adding & removing -------------------------- //
4120
4121  // HEADS UP overwrites default Outlayer appended
4122  Isotope.prototype.appended = function( elems ) {
4123    var items = this.addItems( elems );
4124    if ( !items.length ) {
4125      return;
4126    }
4127    // filter, layout, reveal new items
4128    var filteredItems = this._filterRevealAdded( items );
4129    // add to filteredItems
4130    this.filteredItems = this.filteredItems.concat( filteredItems );
4131  };
4132
4133  // HEADS UP overwrites default Outlayer prepended
4134  Isotope.prototype.prepended = function( elems ) {
4135    var items = this._itemize( elems );
4136    if ( !items.length ) {
4137      return;
4138    }
4139    // start new layout
4140    this._resetLayout();
4141    this._manageStamps();
4142    // filter, layout, reveal new items
4143    var filteredItems = this._filterRevealAdded( items );
4144    // layout previous items
4145    this.layoutItems( this.filteredItems );
4146    // add to items and filteredItems
4147    this.filteredItems = filteredItems.concat( this.filteredItems );
4148    this.items = items.concat( this.items );
4149  };
4150
4151  Isotope.prototype._filterRevealAdded = function( items ) {
4152    var filtered = this._filter( items );
4153    this.hide( filtered.needHide );
4154    // reveal all new items
4155    this.reveal( filtered.matches );
4156    // layout new items, no transition
4157    this.layoutItems( filtered.matches, true );
4158    return filtered.matches;
4159  };
4160
4161  /**
4162   * Filter, sort, and layout newly-appended item elements
4163   * @param {Array or NodeList or Element} elems
4164   */
4165  Isotope.prototype.insert = function( elems ) {
4166    var items = this.addItems( elems );
4167    if ( !items.length ) {
4168      return;
4169    }
4170    // append item elements
4171    var i, item;
4172    var len = items.length;
4173    for ( i=0; i < len; i++ ) {
4174      item = items[i];
4175      this.element.appendChild( item.element );
4176    }
4177    // filter new stuff
4178    var filteredInsertItems = this._filter( items ).matches;
4179    // set flag
4180    for ( i=0; i < len; i++ ) {
4181      items[i].isLayoutInstant = true;
4182    }
4183    this.arrange();
4184    // reset flag
4185    for ( i=0; i < len; i++ ) {
4186      delete items[i].isLayoutInstant;
4187    }
4188    this.reveal( filteredInsertItems );
4189  };
4190
4191  var _remove = Isotope.prototype.remove;
4192  Isotope.prototype.remove = function( elems ) {
4193    elems = utils.makeArray( elems );
4194    var removeItems = this.getItems( elems );
4195    // do regular thing
4196    _remove.call( this, elems );
4197    // bail if no items to remove
4198    var len = removeItems && removeItems.length;
4199    if ( !len ) {
4200      return;
4201    }
4202    // remove elems from filteredItems
4203    for ( var i=0; i < len; i++ ) {
4204      var item = removeItems[i];
4205      // remove item from collection
4206      utils.removeFrom( this.filteredItems, item );
4207    }
4208  };
4209
4210  Isotope.prototype.shuffle = function() {
4211    // update random sortData
4212    for ( var i=0, len = this.items.length; i < len; i++ ) {
4213      var item = this.items[i];
4214      item.sortData.random = Math.random();
4215    }
4216    this.options.sortBy = 'random';
4217    this._sort();
4218    this._layout();
4219  };
4220
4221  /**
4222   * trigger fn without transition
4223   * kind of hacky to have this in the first place
4224   * @param {Function} fn
4225   * @returns ret
4226   * @private
4227   */
4228  Isotope.prototype._noTransition = function( fn ) {
4229    // save transitionDuration before disabling
4230    var transitionDuration = this.options.transitionDuration;
4231    // disable transition
4232    this.options.transitionDuration = 0;
4233    // do it
4234    var returnValue = fn.call( this );
4235    // re-enable transition for reveal
4236    this.options.transitionDuration = transitionDuration;
4237    return returnValue;
4238  };
4239
4240  // ----- helper methods ----- //
4241
4242  /**
4243   * getter method for getting filtered item elements
4244   * @returns {Array} elems - collection of item elements
4245   */
4246  Isotope.prototype.getFilteredItemElements = function() {
4247    var elems = [];
4248    for ( var i=0, len = this.filteredItems.length; i < len; i++ ) {
4249      elems.push( this.filteredItems[i].element );
4250    }
4251    return elems;
4252  };
4253
4254  // -----  ----- //
4255
4256  return Isotope;
4257
4258}));
4259

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.