PageSourceSearch

https://kdabrow.com/wp-content/themes/portfolio-web/assets/library/isotop/isotope.pkgd.js?ver=3.0.1

js kdabrow.com collected 2026-10-04 19:31:10 UTC 105,793 bytes, 3,557 lines download raw bytes

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

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.