PageSourceSearch

https://davidbarlowservices.co.uk/grasscutting/wp-content/themes/square-plus/js/isotope.pkgd.js?ver=1.6.8

js davidbarlowservices.co.uk collected 2026-10-07 20:51:18 UTC 126,175 bytes, 3,563 lines download raw bytes

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

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.