PageSourceSearch

https://happyholidays.am/wp-content/themes/traveler/v2/js/flickity.pkgd.min.js

js happyholidays.am collected 2026-10-04 08:37:29 UTC 147,006 bytes, 4,670 lines download raw bytes

vendor: 19,414 bytes, lines 1-656
1/*!
2 * Flickity PACKAGED v2.1.2
3 * Touch, responsive, flickable carousels
4 *
5 * Licensed GPLv3 for open source use
6 * or Flickity Commercial License for commercial use
7 *
8 * https://flickity.metafizzy.co
9 * Copyright 2015-2018 Metafizzy
10 */
11
12/**
13 * Bridget makes jQuery widgets
14 * v2.0.1
15 * MIT license
16 */
17
18/* jshint browser: true, strict: true, undef: true, unused: true */
19
20( function( window, factory ) {
21    // universal module definition
22    /*jshint strict: false */ /* globals define, module, require */
23    if ( typeof define == 'function' && define.amd ) {
24        // AMD
25        define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
26            return factory( window, jQuery );
27        });
28    } else if ( typeof module == 'object' && module.exports ) {
29        // CommonJS
30        module.exports = factory(
31            window,
32            require('jquery')
33        );
34    } else {
35        // browser global
36        window.jQueryBridget = factory(
37            window,
38            window.jQuery
39        );
40    }
41
42}( window, function factory( window, jQuery ) {
43    'use strict';
44
45// ----- utils ----- //
46
47    var arraySlice = Array.prototype.slice;
48
49// helper function for logging errors
50// $.error breaks jQuery chaining
51    var console = window.console;
52    var logError = typeof console == 'undefined' ? function() {} :
53        function( message ) {
54            console.error( message );
55        };
56
57// ----- jQueryBridget ----- //
58
59    function jQueryBridget( namespace, PluginClass, $ ) {
60        $ = $ || jQuery || window.jQuery;
61        if ( !$ ) {
62            return;
63        }
64
65        // add option method -> $().plugin('option', {...})
66        if ( !PluginClass.prototype.option ) {
67            // option setter
68            PluginClass.prototype.option = function( opts ) {
69                // bail out if not an object
70                if ( !$.isPlainObject( opts ) ){
71                    return;
72                }
73                this.options = $.extend( true, this.options, opts );
74            };
75        }
76
77        // make jQuery plugin
78        $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
79            if ( typeof arg0 == 'string' ) {
80                // method call $().plugin( 'methodName', { options } )
81                // shift arguments by 1
82                var args = arraySlice.call( arguments, 1 );
83                return methodCall( this, arg0, args );
84            }
85            // just $().plugin({ options })
86            plainCall( this, arg0 );
87            return this;
88        };
89
90        // $().plugin('methodName')
91        function methodCall( $elems, methodName, args ) {
92            var returnValue;
93            var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
94
95            $elems.each( function( i, elem ) {
96                // get instance
97                var instance = $.data( elem, namespace );
98                if ( !instance ) {
99                    logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
100                        pluginMethodStr );
101                    return;
102                }
103
104                var method = instance[ methodName ];
105                if ( !method || methodName.charAt(0) == '_' ) {
106                    logError( pluginMethodStr + ' is not a valid method' );
107                    return;
108                }
109
110                // apply method, get return value
111                var value = method.apply( instance, args );
112                // set return value if value is returned, use only first value
113                returnValue = returnValue === undefined ? value : returnValue;
114            });
115
116            return returnValue !== undefined ? returnValue : $elems;
117        }
118
119        function plainCall( $elems, options ) {
120            $elems.each( function( i, elem ) {
121                var instance = $.data( elem, namespace );
122                if ( instance ) {
123                    // set options & init
124                    instance.option( options );
125                    instance._init();
126                } else {
127                    // initialize new instance
128                    instance = new PluginClass( elem, options );
129                    $.data( elem, namespace, instance );
130                }
131            });
132        }
133
134        updateJQuery( $ );
135
136    }
137
138// ----- updateJQuery ----- //
139
140// set $.bridget for v1 backwards compatibility
141    function updateJQuery( $ ) {
142        if ( !$ || ( $ && $.bridget ) ) {
143            return;
144        }
145        $.bridget = jQueryBridget;
146    }
147
148    updateJQuery( jQuery || window.jQuery );
149
150// -----  ----- //
151
152    return jQueryBridget;
153
154}));
155
156/**
157 * EvEmitter v1.1.0
158 * Lil' event emitter
159 * MIT License
160 */
161
162/* jshint unused: true, undef: true, strict: true */
163
164( function( global, factory ) {
165    // universal module definition
166    /* jshint strict: false */ /* globals define, module, window */
167    if ( typeof define == 'function' && define.amd ) {
168        // AMD - RequireJS
169        define( 'ev-emitter/ev-emitter',factory );
170    } else if ( typeof module == 'object' && module.exports ) {
171        // CommonJS - Browserify, Webpack
172        module.exports = factory();
173    } else {
174        // Browser globals
175        global.EvEmitter = factory();
176    }
177
178}( typeof window != 'undefined' ? window : this, function() {
179
180
181
182    function EvEmitter() {}
183
184    var proto = EvEmitter.prototype;
185
186    proto.on = function( eventName, listener ) {
187        if ( !eventName || !listener ) {
188            return;
189        }
190        // set events hash
191        var events = this._events = this._events || {};
192        // set listeners array
193        var listeners = events[ eventName ] = events[ eventName ] || [];
194        // only add once
195        if ( listeners.indexOf( listener ) == -1 ) {
196            listeners.push( listener );
197        }
198
199        return this;
200    };
201
202    proto.once = function( eventName, listener ) {
203        if ( !eventName || !listener ) {
204            return;
205        }
206        // add event
207        this.on( eventName, listener );
208        // set once flag
209        // set onceEvents hash
210        var onceEvents = this._onceEvents = this._onceEvents || {};
211        // set onceListeners object
212        var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
213        // set flag
214        onceListeners[ listener ] = true;
215
216        return this;
217    };
218
219    proto.off = function( eventName, listener ) {
220        var listeners = this._events && this._events[ eventName ];
221        if ( !listeners || !listeners.length ) {
222            return;
223        }
224        var index = listeners.indexOf( listener );
225        if ( index != -1 ) {
226            listeners.splice( index, 1 );
227        }
228
229        return this;
230    };
231
232    proto.emitEvent = function( eventName, args ) {
233        var listeners = this._events && this._events[ eventName ];
234        if ( !listeners || !listeners.length ) {
235            return;
236        }
237        // copy over to avoid interference if .off() in listener
238        listeners = listeners.slice(0);
239        args = args || [];
240        // once stuff
241        var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
242
243        for ( var i=0; i < listeners.length; i++ ) {
244            var listener = listeners[i]
245            var isOnce = onceListeners && onceListeners[ listener ];
246            if ( isOnce ) {
247                // remove listener
248                // remove before trigger to prevent recursion
249                this.off( eventName, listener );
250                // unset once flag
251                delete onceListeners[ listener ];
252            }
253            // trigger listener
254            listener.apply( this, args );
255        }
256
257        return this;
258    };
259
260    proto.allOff = function() {
261        delete this._events;
262        delete this._onceEvents;
263    };
264
265    return EvEmitter;
266
267}));
268
269/*!
270 * getSize v2.0.3
271 * measure size of elements
272 * MIT license
273 */
274
275/* jshint browser: true, strict: true, undef: true, unused: true */
276/* globals console: false */
277
278( function( window, factory ) {
279    /* jshint strict: false */ /* globals define, module */
280    if ( typeof define == 'function' && define.amd ) {
281        // AMD
282        define( 'get-size/get-size',factory );
283    } else if ( typeof module == 'object' && module.exports ) {
284        // CommonJS
285        module.exports = factory();
286    } else {
287        // browser global
288        window.getSize = factory();
289    }
290
291})( window, function factory() {
292    'use strict';
293
294// -------------------------- helpers -------------------------- //
295
296// get a number from a string, not a percentage
297    function getStyleSize( value ) {
298        var num = parseFloat( value );
299        // not a percent like '100%', and a number
300        var isValid = value.indexOf('%') == -1 && !isNaN( num );
301        return isValid && num;
302    }
303
304    function noop() {}
305
306    var logError = typeof console == 'undefined' ? noop :
307        function( message ) {
308            console.error( message );
309        };
310
311// -------------------------- measurements -------------------------- //
312
313    var measurements = [
314        'paddingLeft',
315        'paddingRight',
316        'paddingTop',
317        'paddingBottom',
318        'marginLeft',
319        'marginRight',
320        'marginTop',
321        'marginBottom',
322        'borderLeftWidth',
323        'borderRightWidth',
324        'borderTopWidth',
325        'borderBottomWidth'
326    ];
327
328    var measurementsLength = measurements.length;
329
330    function getZeroSize() {
331        var size = {
332            width: 0,
333            height: 0,
334            innerWidth: 0,
335            innerHeight: 0,
336            outerWidth: 0,
337            outerHeight: 0
338        };
339        for ( var i=0; i < measurementsLength; i++ ) {
340            var measurement = measurements[i];
341            size[ measurement ] = 0;
342        }
343        return size;
344    }
345
346// -------------------------- getStyle -------------------------- //
347
348    /**
349     * getStyle, get style of element, check for Firefox bug
350     * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
351     */
352    function getStyle( elem ) {
353        var style = getComputedStyle( elem );
354        if ( !style ) {
355            logError( 'Style returned ' + style +
356                '. Are you running this code in a hidden iframe on Firefox? ' +
357                'See https://bit.ly/getsizebug1' );
358        }
359        return style;
360    }
361
362// -------------------------- setup -------------------------- //
363
364    var isSetup = false;
365
366    var isBoxSizeOuter;
367
368    /**
369     * setup
370     * check isBoxSizerOuter
371     * do on first getSize() rather than on page load for Firefox bug
372     */
373    function setup() {
374        // setup once
375        if ( isSetup ) {
376            return;
377        }
378        isSetup = true;
379
380        // -------------------------- box sizing -------------------------- //
381
382        /**
383         * Chrome & Safari measure the outer-width on style.width on border-box elems
384         * IE11 & Firefox<29 measures the inner-width
385         */
386        var div = document.createElement('div');
387        div.style.width = '200px';
388        div.style.padding = '1px 2px 3px 4px';
389        div.style.borderStyle = 'solid';
390        div.style.borderWidth = '1px 2px 3px 4px';
391        div.style.boxSizing = 'border-box';
392
393        var body = document.body || document.documentElement;
394        body.appendChild( div );
395        var style = getStyle( div );
396        // round value for browser zoom. desandro/masonry#928
397        isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
398        getSize.isBoxSizeOuter = isBoxSizeOuter;
399
400        body.removeChild( div );
401    }
402
403// -------------------------- getSize -------------------------- //
404
405    function getSize( elem ) {
406        setup();
407
408        // use querySeletor if elem is string
409        if ( typeof elem == 'string' ) {
410            elem = document.querySelector( elem );
411        }
412
413        // do not proceed on non-objects
414        if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
415            return;
416        }
417
418        var style = getStyle( elem );
419
420        // if hidden, everything is 0
421        if ( style.display == 'none' ) {
422            return getZeroSize();
423        }
424
425        var size = {};
426        size.width = elem.offsetWidth;
427        size.height = elem.offsetHeight;
428
429        var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
430
431        // get all measurements
432        for ( var i=0; i < measurementsLength; i++ ) {
433            var measurement = measurements[i];
434            var value = style[ measurement ];
435            var num = parseFloat( value );
436            // any 'auto', 'medium' value will be 0
437            size[ measurement ] = !isNaN( num ) ? num : 0;
438        }
439
440        var paddingWidth = size.paddingLeft + size.paddingRight;
441        var paddingHeight = size.paddingTop + size.paddingBottom;
442        var marginWidth = size.marginLeft + size.marginRight;
443        var marginHeight = size.marginTop + size.marginBottom;
444        var borderWidth = size.borderLeftWidth + size.borderRightWidth;
445        var borderHeight = size.borderTopWidth + size.borderBottomWidth;
446
447        var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
448
449        // overwrite width and height if we can get it from style
450        var styleWidth = getStyleSize( style.width );
451        if ( styleWidth !== false ) {
452            size.width = styleWidth +
453                // add padding and border unless it's already including it
454                ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
455        }
456
457        var styleHeight = getStyleSize( style.height );
458        if ( styleHeight !== false ) {
459            size.height = styleHeight +
460                // add padding and border unless it's already including it
461                ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
462        }
463
464        size.innerWidth = size.width - ( paddingWidth + borderWidth );
465        size.innerHeight = size.height - ( paddingHeight + borderHeight );
466
467        size.outerWidth = size.width + marginWidth;
468        size.outerHeight = size.height + marginHeight;
469
470        return size;
471    }
472
473    return getSize;
474
475});
476
477/**
478 * matchesSelector v2.0.2
479 * matchesSelector( element, '.selector' )
480 * MIT license
481 */
482
483/*jshint browser: true, strict: true, undef: true, unused: true */
484
485( function( window, factory ) {
486    /*global define: false, module: false */
487    'use strict';
488    // universal module definition
489    if ( typeof define == 'function' && define.amd ) {
490        // AMD
491        define( 'desandro-matches-selector/matches-selector',factory );
492    } else if ( typeof module == 'object' && module.exports ) {
493        // CommonJS
494        module.exports = factory();
495    } else {
496        // browser global
497        window.matchesSelector = factory();
498    }
499
500}( window, function factory() {
501    'use strict';
502
503    var matchesMethod = ( function() {
504        var ElemProto = window.Element.prototype;
505        // check for the standard method name first
506        if ( ElemProto.matches ) {
507            return 'matches';
508        }
509        // check un-prefixed
510        if ( ElemProto.matchesSelector ) {
511            return 'matchesSelector';
512        }
513        // check vendor prefixes
514        var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
515
516        for ( var i=0; i < prefixes.length; i++ ) {
517            var prefix = prefixes[i];
518            var method = prefix + 'MatchesSelector';
519            if ( ElemProto[ method ] ) {
520                return method;
521            }
522        }
523    })();
524
525    return function matchesSelector( elem, selector ) {
526        return elem[ matchesMethod ]( selector );
527    };
528
529}));
530
531/**
532 * Fizzy UI utils v2.0.7
533 * MIT license
534 */
535
536/*jshint browser: true, undef: true, unused: true, strict: true */
537
538( function( window, factory ) {
539    // universal module definition
540    /*jshint strict: false */ /*globals define, module, require */
541
542    if ( typeof define == 'function' && define.amd ) {
543        // AMD
544        define( 'fizzy-ui-utils/utils',[
545            'desandro-matches-selector/matches-selector'
546        ], function( matchesSelector ) {
547            return factory( window, matchesSelector );
548        });
549    } else if ( typeof module == 'object' && module.exports ) {
550        // CommonJS
551        module.exports = factory(
552            window,
553            require('desandro-matches-selector')
554        );
555    } else {
556        // browser global
557        window.fizzyUIUtils = factory(
558            window,
559            window.matchesSelector
560        );
561    }
562
563}( window, function factory( window, matchesSelector ) {
564
565
566
567    var utils = {};
568
569// ----- extend ----- //
570
571// extends objects
572    utils.extend = function( a, b ) {
573        for ( var prop in b ) {
574            a[ prop ] = b[ prop ];
575        }
576        return a;
577    };
578
579// ----- modulo ----- //
580
581    utils.modulo = function( num, div ) {
582        return ( ( num % div ) + div ) % div;
583    };
584
585// ----- makeArray ----- //
586
587    var arraySlice = Array.prototype.slice;
588
589// turn element or nodeList into an array
590    utils.makeArray = function( obj ) {
591        if ( Array.isArray( obj ) ) {
592            // use object if already an array
593            return obj;
594        }
595        // return empty array if undefined or null. #6
596        if ( obj === null || obj === undefined ) {
597            return [];
598        }
599
600        var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
601        if ( isArrayLike ) {
602            // convert nodeList to array
603            return arraySlice.call( obj );
604        }
605
606        // array of single index
607        return [ obj ];
608    };
609
610// ----- removeFrom ----- //
611
612    utils.removeFrom = function( ary, obj ) {
613        var index = ary.indexOf( obj );
614        if ( index != -1 ) {
615            ary.splice( index, 1 );
616        }
617    };
618
619// ----- getParent ----- //
620
621    utils.getParent = function( elem, selector ) {
622        while ( elem.parentNode && elem != document.body ) {
623            elem = elem.parentNode;
624            if ( matchesSelector( elem, selector ) ) {
625                return elem;
626            }
627        }
628    };
629
630// ----- getQueryElement ----- //
631
632// use element as selector string
633    utils.getQueryElement = function( elem ) {
634        if ( typeof elem == 'string' ) {
635            return document.querySelector( elem );
636        }
637        return elem;
638    };
639
640// ----- handleEvent ----- //
641
642// enable .ontype to trigger from .addEventListener( elem, 'type' )
643    utils.handleEvent = function( event ) {
644        var method = 'on' + event.type;
645        if ( this[ method ] ) {
646            this[ method ]( event );
647        }
648    };
649
650// ----- filterFindElements ----- //
651
652    utils.filterFindElements = function( elems, selector ) {
653        // make array of elems
654        elems = utils.makeArray( elems );
655        var ffElems = [];
656
657        elems.forEach( function( elem ) {
658            // check that elem is an actual element
659            if ( !( elem instanceof HTMLElement ) ) {
660                return;
661            }
662            // add elem if no selector
663            if ( !selector ) {
664                ffElems.push( elem );
665                return;
666            }
667            // filter & find items if we have a selector
668            // filter
669            if ( matchesSelector( elem, selector ) ) {
670                ffElems.push( elem );
671            }
672            // find children
673            var childElems = elem.querySelectorAll( selector );
674            // concat childElems to filterFound array
675            for ( var i=0; i < childElems.length; i++ ) {
676                ffElems.push( childElems[i] );
677            }
678        });
679
680        return ffElems;
681    };
682
683// ----- debounceMethod ----- //
684
685    utils.debounceMethod = function( _class, methodName, threshold ) {
686        threshold = threshold || 100;
687        // original method
688        var method = _class.prototype[ methodName ];
689        var timeoutName = methodName + 'Timeout';
690
691        _class.prototype[ methodName ] = function() {
692            var timeout = this[ timeoutName ];
693            clearTimeout( timeout );
694
695            var args = arguments;
696            var _this = this;
697            this[ timeoutName ] = setTimeout( function() {
698                method.apply( _this, args );
699                delete _this[ timeoutName ];
700            }, threshold );
701        };
702    };
703
704// ----- docReady ----- //
705
706    utils.docReady = function( callback ) {
707        var readyState = document.readyState;
708        if ( readyState == 'complete' || readyState == 'interactive' ) {
709            // do async to allow for other scripts to run. metafizzy/flickity#441
710            setTimeout( callback );
711        } else {
712            document.addEventListener( 'DOMContentLoaded', callback );
713        }
714    };
715
716// ----- htmlInit ----- //
717
718// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
719    utils.toDashed = function( str ) {
720        return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
721            return $1 + '-' + $2;
722        }).toLowerCase();
723    };
724
725    var console = window.console;
726    /**
727     * allow user to initialize classes via [data-namespace] or .js-namespace class
728     * htmlInit( Widget, 'widgetName' )
729     * options are parsed from data-namespace-options
730     */
731    utils.htmlInit = function( WidgetClass, namespace ) {
732        utils.docReady( function() {
733            var dashedNamespace = utils.toDashed( namespace );
734            var dataAttr = 'data-' + dashedNamespace;
735            var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
736            var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
737            var elems = utils.makeArray( dataAttrElems )
738                .concat( utils.makeArray( jsDashElems ) );
739            var dataOptionsAttr = dataAttr + '-options';
740            var jQuery = window.jQuery;
741
742            elems.forEach( function( elem ) {
743                var attr = elem.getAttribute( dataAttr ) ||
744                    elem.getAttribute( dataOptionsAttr );
745                var options;
746                try {
747                    options = attr && JSON.parse( attr );
748                } catch ( error ) {
749                    // log error, do not initialize
750                    if ( console ) {
751                        console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
752                            ': ' + error );
753                    }
754                    return;
755                }
756                // initialize
757                var instance = new WidgetClass( elem, options );
758                // make available via $().data('namespace')
759                if ( jQuery ) {
760                    jQuery.data( elem, namespace, instance );
761                }
762            });
763
764        });
765    };
766
767// -----  ----- //
768
769    return utils;
770
771}));
772
773// Flickity.Cell
774( function( window, factory ) {
775    // universal module definition
776    /* jshint strict: false */
777    if ( typeof define == 'function' && define.amd ) {
778        // AMD
779        define( 'flickity/js/cell',[
780            'get-size/get-size'
781        ], function( getSize ) {
782            return factory( window, getSize );
783        });
784    } else if ( typeof module == 'object' && module.exports ) {
785        // CommonJS
786        module.exports = factory(
787            window,
788            require('get-size')
789        );
790    } else {
791        // browser global
792        window.Flickity = window.Flickity || {};
793        window.Flickity.Cell = factory(
794            window,
795            window.getSize
796        );
797    }
798
799}( window, function factory( window, getSize ) {
800
801
802
803    function Cell( elem, parent ) {
804        this.element = elem;
805        this.parent = parent;
806
807        this.create();
808    }
809
810    var proto = Cell.prototype;
811
812    proto.create = function() {
813        this.element.style.position = 'absolute';
814        this.element.setAttribute( 'aria-selected', 'false' );
815        this.x = 0;
816        this.shift = 0;
817    };
818
819    proto.destroy = function() {
820        // reset style
821        this.element.style.position = '';
822        var side = this.parent.originSide;
823        this.element.removeAttribute('aria-selected');
824        this.element.style[ side ] = '';
825    };
826
827    proto.getSize = function() {
828        this.size = getSize( this.element );
829    };
830
831    proto.setPosition = function( x ) {
832        this.x = x;
833        this.updateTarget();
834        this.renderPosition( x );
835    };
836
837// setDefaultTarget v1 method, backwards compatibility, remove in v3
838    proto.updateTarget = proto.setDefaultTarget = function() {
839        var marginProperty = this.parent.originSide == 'left' ? 'marginLeft' : 'marginRight';
840        this.target = this.x + this.size[ marginProperty ] +
841            this.size.width * this.parent.cellAlign;
842    };
843
844    proto.renderPosition = function( x ) {
845        // render position of cell with in slider
846        var side = this.parent.originSide;
847        this.element.style[ side ] = this.parent.getPositionValue( x );
848    };
849
850    /**
851     * @param {Integer} factor - 0, 1, or -1
852     **/
853    proto.wrapShift = function( shift ) {
854        this.shift = shift;
855        this.renderPosition( this.x + this.parent.slideableWidth * shift );
856    };
857
858    proto.remove = function() {
859        this.element.parentNode.removeChild( this.element );
860    };
861
862    return Cell;
863
864}));
865
866// slide
867( function( window, factory ) {
868    // universal module definition
869    /* jshint strict: false */
870    if ( typeof define == 'function' && define.amd ) {
871        // AMD
872        define( 'flickity/js/slide',factory );
873    } else if ( typeof module == 'object' && module.exports ) {
874        // CommonJS
875        module.exports = factory();
876    } else {
877        // browser global
878        window.Flickity = window.Flickity || {};
879        window.Flickity.Slide = factory();
880    }
881
882}( window, function factory() {
883    'use strict';
884
885    function Slide( parent ) {
886        this.parent = parent;
887        this.isOriginLeft = parent.originSide == 'left';
888        this.cells = [];
889        this.outerWidth = 0;
890        this.height = 0;
891    }
892
893    var proto = Slide.prototype;
894
895    proto.addCell = function( cell ) {
896        this.cells.push( cell );
897        this.outerWidth += cell.size.outerWidth;
898        this.height = Math.max( cell.size.outerHeight, this.height );
899        // first cell stuff
900        if ( this.cells.length == 1 ) {
901            this.x = cell.x; // x comes from first cell
902            var beginMargin = this.isOriginLeft ? 'marginLeft' : 'marginRight';
903            this.firstMargin = cell.size[ beginMargin ];
904        }
905    };
906
907    proto.updateTarget = function() {
908        var endMargin = this.isOriginLeft ? 'marginRight' : 'marginLeft';
909        var lastCell = this.getLastCell();
910        var lastMargin = lastCell ? lastCell.size[ endMargin ] : 0;
911        var slideWidth = this.outerWidth - ( this.firstMargin + lastMargin );
912        this.target = this.x + this.firstMargin + slideWidth * this.parent.cellAlign;
913    };
914
915    proto.getLastCell = function() {
916        return this.cells[ this.cells.length - 1 ];
917    };
918
919    proto.select = function() {
920        this.changeSelected( true );
921    };
922
923    proto.unselect = function() {
924        this.changeSelected( false );
925    };
926
927    proto.changeSelected = function( isSelected ) {
928        var classMethod = isSelected ? 'add' : 'remove';
929        this.cells.forEach( function( cell ) {
930            cell.element.classList[ classMethod ]('is-selected');
931            cell.element.setAttribute( 'aria-selected', isSelected.toString() );
932        });
933    };
934
935    proto.getCellElements = function() {
936        return this.cells.map( function( cell ) {
937            return cell.element;
938        });
939    };
940
941    return Slide;
942
943}));
944
945// animate
946( function( window, factory ) {
947    // universal module definition
948    /* jshint strict: false */
949    if ( typeof define == 'function' && define.amd ) {
950        // AMD
951        define( 'flickity/js/animate',[
952            'fizzy-ui-utils/utils'
953        ], function( utils ) {
954            return factory( window, utils );
955        });
956    } else if ( typeof module == 'object' && module.exports ) {
957        // CommonJS
958        module.exports = factory(
959            window,
960            require('fizzy-ui-utils')
961        );
962    } else {
963        // browser global
964        window.Flickity = window.Flickity || {};
965        window.Flickity.animatePrototype = factory(
966            window,
967            window.fizzyUIUtils
968        );
969    }
970
971}( window, function factory( window, utils ) {
972
973
974
975// -------------------------- animate -------------------------- //
976
977    var proto = {};
978
979    proto.startAnimation = function() {
980        if ( this.isAnimating ) {
981            return;
982        }
983
984        this.isAnimating = true;
985        this.restingFrames = 0;
986        this.animate();
987    };
988
989    proto.animate = function() {
990        this.applyDragForce();
991        this.applySelectedAttraction();
992
993        var previousX = this.x;
994
995        this.integratePhysics();
996        this.positionSlider();
997        this.settle( previousX );
998        // animate next frame
999        if ( this.isAnimating ) {
1000            var _this = this;
1001            requestAnimationFrame( function animateFrame() {
1002                _this.animate();
1003            });
1004        }
1005    };
1006
1007    proto.positionSlider = function() {
1008        var x = this.x;
1009        // wrap position around
1010        if ( this.options.wrapAround && this.cells.length > 1 ) {
1011            x = utils.modulo( x, this.slideableWidth );
1012            x = x - this.slideableWidth;
1013            this.shiftWrapCells( x );
1014        }
1015
1016        x = x + this.cursorPosition;
1017        // reverse if right-to-left and using transform
1018        x = this.options.rightToLeft ? -x : x;
1019        var value = this.getPositionValue( x );
1020        // use 3D tranforms for hardware acceleration on iOS
1021        // but use 2D when settled, for better font-rendering
1022        this.slider.style.transform = this.isAnimating ?
1023            'translate3d(' + value + ',0,0)' : 'translateX(' + value + ')';
1024
1025        // scroll event
1026        var firstSlide = this.slides[0];
1027        if ( firstSlide ) {
1028            var positionX = -this.x - firstSlide.target;
1029            var progress = positionX / this.slidesWidth;
1030            this.dispatchEvent( 'scroll', null, [ progress, positionX ] );
1031        }
1032    };
1033
1034    proto.positionSliderAtSelected = function() {
1035        if ( !this.cells.length ) {
1036            return;
1037        }
1038        this.x = -this.selectedSlide.target;
1039        this.velocity = 0; // stop wobble
1040        this.positionSlider();
1041    };
1042
1043    proto.getPositionValue = function( position ) {
1044        if ( this.options.percentPosition ) {
1045            // percent position, round to 2 digits, like 12.34%
1046            return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 )+ '%';
1047        } else {
1048            // pixel positioning
1049            return Math.round( position ) + 'px';
1050        }
1051    };
1052
1053    proto.settle = function( previousX ) {
1054        // keep track of frames where x hasn't moved
1055        if ( !this.isPointerDown && Math.round( this.x * 100 ) == Math.round( previousX * 100 ) ) {
1056            this.restingFrames++;
1057        }
1058        // stop animating if resting for 3 or more frames
1059        if ( this.restingFrames > 2 ) {
1060            this.isAnimating = false;
1061            delete this.isFreeScrolling;
1062            // render position with translateX when settled
1063            this.positionSlider();
1064            this.dispatchEvent( 'settle', null, [ this.selectedIndex ] );
1065        }
1066    };
1067
1068    proto.shiftWrapCells = function( x ) {
1069        // shift before cells
1070        var beforeGap = this.cursorPosition + x;
1071        this._shiftCells( this.beforeShiftCells, beforeGap, -1 );
1072        // shift after cells
1073        var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );
1074        this._shiftCells( this.afterShiftCells, afterGap, 1 );
1075    };
1076
1077    proto._shiftCells = function( cells, gap, shift ) {
1078        for ( var i=0; i < cells.length; i++ ) {
1079            var cell = cells[i];
1080            var cellShift = gap > 0 ? shift : 0;
1081            cell.wrapShift( cellShift );
1082            gap -= cell.size.outerWidth;
1083        }
1084    };
1085
1086    proto._unshiftCells = function( cells ) {
1087        if ( !cells || !cells.length ) {
1088            return;
1089        }
1090        for ( var i=0; i < cells.length; i++ ) {
1091            cells[i].wrapShift( 0 );
1092        }
1093    };
1094
1095// -------------------------- physics -------------------------- //
1096
1097    proto.integratePhysics = function() {
1098        this.x += this.velocity;
1099        this.velocity *= this.getFrictionFactor();
1100    };
1101
1102    proto.applyForce = function( force ) {
1103        this.velocity += force;
1104    };
1105
1106    proto.getFrictionFactor = function() {
1107        return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];
1108    };
1109
1110    proto.getRestingPosition = function() {
1111        // my thanks to Steven Wittens, who simplified this math greatly
1112        return this.x + this.velocity / ( 1 - this.getFrictionFactor() );
1113    };
1114
1115    proto.applyDragForce = function() {
1116        if ( !this.isDraggable || !this.isPointerDown ) {
1117            return;
1118        }
1119        // change the position to drag position by applying force
1120        var dragVelocity = this.dragX - this.x;
1121        var dragForce = dragVelocity - this.velocity;
1122        this.applyForce( dragForce );
1123    };
1124
1125    proto.applySelectedAttraction = function() {
1126        // do not attract if pointer down or no slides
1127        var dragDown = this.isDraggable && this.isPointerDown;
1128        if ( dragDown || this.isFreeScrolling || !this.slides.length ) {
1129            return;
1130        }
1131        var distance = this.selectedSlide.target * -1 - this.x;
1132        var force = distance * this.options.selectedAttraction;
1133        this.applyForce( force );
1134    };
1135
1136    return proto;
1137
1138}));
1139
1140// Flickity main
1141( function( window, factory ) {
1142    // universal module definition
1143    /* jshint strict: false */
1144    if ( typeof define == 'function' && define.amd ) {
1145        // AMD
1146        define( 'flickity/js/flickity',[
1147            'ev-emitter/ev-emitter',
1148            'get-size/get-size',
1149            'fizzy-ui-utils/utils',
1150            './cell',
1151            './slide',
1152            './animate'
1153        ], function( EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) {
1154            return factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype );
1155        });
1156    } else if ( typeof module == 'object' && module.exports ) {
1157        // CommonJS
1158        module.exports = factory(
1159            window,
1160            require('ev-emitter'),
1161            require('get-size'),
1162            require('fizzy-ui-utils'),
1163            require('./cell'),
1164            require('./slide'),
1165            require('./animate')
1166        );
1167    } else {
1168        // browser global
1169        var _Flickity = window.Flickity;
1170
1171        window.Flickity = factory(
1172            window,
1173            window.EvEmitter,
1174            window.getSize,
1175            window.fizzyUIUtils,
1176            _Flickity.Cell,
1177            _Flickity.Slide,
1178            _Flickity.animatePrototype
1179        );
1180    }
1181
1182}( window, function factory( window, EvEmitter, getSize,
1183                             utils, Cell, Slide, animatePrototype ) {
1184
1185
1186
1187// vars
1188    var jQuery = window.jQuery;
1189    var getComputedStyle = window.getComputedStyle;
1190    var console = window.console;
1191
1192    function moveElements( elems, toElem ) {
1193        elems = utils.makeArray( elems );
1194        while ( elems.length ) {
1195            toElem.appendChild( elems.shift() );
1196        }
1197    }
1198
1199// -------------------------- Flickity -------------------------- //
1200
1201// globally unique identifiers
1202    var GUID = 0;
1203// internal store of all Flickity intances
1204    var instances = {};
1205
1206    function Flickity( element, options ) {
1207        var queryElement = utils.getQueryElement( element );
1208        if ( !queryElement ) {
1209            if ( console ) {
1210                console.error( 'Bad element for Flickity: ' + ( queryElement || element ) );
1211            }
1212            return;
1213        }
1214        this.element = queryElement;
1215        // do not initialize twice on same element
1216        if ( this.element.flickityGUID ) {
1217            var instance = instances[ this.element.flickityGUID ];
1218            instance.option( options );
1219            return instance;
1220        }
1221
1222        // add jQuery
1223        if ( jQuery ) {
1224            this.$element = jQuery( this.element );
1225        }
1226        // options
1227        this.options = utils.extend( {}, this.constructor.defaults );
1228        this.option( options );
1229
1230        // kick things off
1231        this._create();
1232    }
1233
1234    Flickity.defaults = {
1235        accessibility: true,
1236        // adaptiveHeight: false,
1237        cellAlign: 'center',
1238        // cellSelector: undefined,
1239        // contain: false,
1240        freeScrollFriction: 0.075, // friction when free-scrolling
1241        friction: 0.28, // friction when selecting
1242        namespaceJQueryEvents: true,
1243        // initialIndex: 0,
1244        percentPosition: true,
1245        resize: true,
1246        selectedAttraction: 0.025,
1247        setGallerySize: true
1248        // watchCSS: false,
1249        // wrapAround: false
1250    };
1251
1252// hash of methods triggered on _create()
1253    Flickity.createMethods = [];
1254
1255    var proto = Flickity.prototype;
1256// inherit EventEmitter
1257    utils.extend( proto, EvEmitter.prototype );
1258
1259    proto._create = function() {
1260        // add id for Flickity.data
1261        var id = this.guid = ++GUID;
1262        this.element.flickityGUID = id; // expando
1263        instances[ id ] = this; // associate via id
1264        // initial properties
1265        this.selectedIndex = 0;
1266        // how many frames slider has been in same position
1267        this.restingFrames = 0;
1268        // initial physics properties
1269        this.x = 0;
1270        this.velocity = 0;
1271        this.originSide = this.options.rightToLeft ? 'right' : 'left';
1272        // create viewport & slider
1273        this.viewport = document.createElement('div');
1274        this.viewport.className = 'flickity-viewport';
1275        this._createSlider();
1276
1277        if ( this.options.resize || this.options.watchCSS ) {
1278            window.addEventListener( 'resize', this );
1279        }
1280
1281        // add listeners from on option
1282        for ( var eventName in this.options.on ) {
1283            var listener = this.options.on[ eventName ];
1284            this.on( eventName, listener );
1285        }
1286
1287        Flickity.createMethods.forEach( function( method ) {
1288            this[ method ]();
1289        }, this );
1290
1291        if ( this.options.watchCSS ) {
1292            this.watchCSS();
1293        } else {
1294            this.activate();
1295        }
1296
1297    };
1298
1299    /**
1300     * set options
1301     * @param {Object} opts
1302     */
1303    proto.option = function( opts ) {
1304        utils.extend( this.options, opts );
1305    };
1306
1307    proto.activate = function() {
1308        if ( this.isActive ) {
1309            return;
1310        }
1311        this.isActive = true;
1312        this.element.classList.add('flickity-enabled');
1313        if ( this.options.rightToLeft ) {
1314            this.element.classList.add('flickity-rtl');
1315        }
1316
1317        this.getSize();
1318        // move initial cell elements so they can be loaded as cells
1319        var cellElems = this._filterFindCellElements( this.element.children );
1320        moveElements( cellElems, this.slider );
1321        this.viewport.appendChild( this.slider );
1322        this.element.appendChild( this.viewport );
1323        // get cells from children
1324        this.reloadCells();
1325
1326        if ( this.options.accessibility ) {
1327            // allow element to focusable
1328            this.element.tabIndex = 0;
1329            // listen for key presses
1330            this.element.addEventListener( 'keydown', this );
1331        }
1332
1333        this.emitEvent('activate');
1334
1335        var index;
1336        var initialIndex = this.options.initialIndex;
1337        if ( this.isInitActivated ) {
1338            index = this.selectedIndex;
1339        } else if ( initialIndex !== undefined ) {
1340            index = this.cells[ initialIndex ] ? initialIndex : 0;
1341        } else {
1342            index = 0;
1343        }
1344        // select instantly
1345        this.select( index, false, true );
1346        // flag for initial activation, for using initialIndex
1347        this.isInitActivated = true;
1348        // ready event. #493
1349        this.dispatchEvent('ready');
1350    };
1351
1352// slider positions the cells
1353    proto._createSlider = function() {
1354        // slider element does all the positioning
1355        var slider = document.createElement('div');
1356        slider.className = 'flickity-slider';
1357        slider.style[ this.originSide ] = 0;
1358        this.slider = slider;
1359    };
1360
1361    proto._filterFindCellElements = function( elems ) {
1362        return utils.filterFindElements( elems, this.options.cellSelector );
1363    };
1364
1365// goes through all children
1366    proto.reloadCells = function() {
1367        // collection of item elements
1368        this.cells = this._makeCells( this.slider.children );
1369        this.positionCells();
1370        this._getWrapShiftCells();
1371        this.setGallerySize();
1372    };
1373
1374    /**
1375     * turn elements into Flickity.Cells
1376     * @param {Array or NodeList or HTMLElement} elems
1377     * @returns {Array} items - collection of new Flickity Cells
1378     */
1379    proto._makeCells = function( elems ) {
1380        var cellElems = this._filterFindCellElements( elems );
1381
1382        // create new Flickity for collection
1383        var cells = cellElems.map( function( cellElem ) {
1384            return new Cell( cellElem, this );
1385        }, this );
1386
1387        return cells;
1388    };
1389
1390    proto.getLastCell = function() {
1391        return this.cells[ this.cells.length - 1 ];
1392    };
1393
1394    proto.getLastSlide = function() {
1395        return this.slides[ this.slides.length - 1 ];
1396    };
1397
1398// positions all cells
1399    proto.positionCells = function() {
1400        // size all cells
1401        this._sizeCells( this.cells );
1402        // position all cells
1403        this._positionCells( 0 );
1404    };
1405
1406    /**
1407     * position certain cells
1408     * @param {Integer} index - which cell to start with
1409     */
1410    proto._positionCells = function( index ) {
1411        index = index || 0;
1412        // also measure maxCellHeight
1413        // start 0 if positioning all cells
1414        this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;
1415        var cellX = 0;
1416        // get cellX
1417        if ( index > 0 ) {
1418            var startCell = this.cells[ index - 1 ];
1419            cellX = startCell.x + startCell.size.outerWidth;
1420        }
1421        var len = this.cells.length;
1422        for ( var i=index; i < len; i++ ) {
1423            var cell = this.cells[i];
1424            cell.setPosition( cellX );
1425            cellX += cell.size.outerWidth;
1426            this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );
1427        }
1428        // keep track of cellX for wrap-around
1429        this.slideableWidth = cellX;
1430        // slides
1431        this.updateSlides();
1432        // contain slides target
1433        this._containSlides();
1434        // update slidesWidth
1435        this.slidesWidth = len ? this.getLastSlide().target - this.slides[0].target : 0;
1436    };
1437
1438    /**
1439     * cell.getSize() on multiple cells
1440     * @param {Array} cells
1441     */
1442    proto._sizeCells = function( cells ) {
1443        cells.forEach( function( cell ) {
1444            cell.getSize();
1445        });
1446    };
1447
1448// --------------------------  -------------------------- //
1449
1450    proto.updateSlides = function() {
1451        this.slides = [];
1452        if ( !this.cells.length ) {
1453            return;
1454        }
1455
1456        var slide = new Slide( this );
1457        this.slides.push( slide );
1458        var isOriginLeft = this.originSide == 'left';
1459        var nextMargin = isOriginLeft ? 'marginRight' : 'marginLeft';
1460
1461        var canCellFit = this._getCanCellFit();
1462
1463        this.cells.forEach( function( cell, i ) {
1464            // just add cell if first cell in slide
1465            if ( !slide.cells.length ) {
1466                slide.addCell( cell );
1467                return;
1468            }
1469
1470            var slideWidth = ( slide.outerWidth - slide.firstMargin ) +
1471                ( cell.size.outerWidth - cell.size[ nextMargin ] );
1472
1473            if ( canCellFit.call( this, i, slideWidth ) ) {
1474                slide.addCell( cell );
1475            } else {
1476                // doesn't fit, new slide
1477                slide.updateTarget();
1478
1479                slide = new Slide( this );
1480                this.slides.push( slide );
1481                slide.addCell( cell );
1482            }
1483        }, this );
1484        // last slide
1485        slide.updateTarget();
1486        // update .selectedSlide
1487        this.updateSelectedSlide();
1488    };
1489
1490    proto._getCanCellFit = function() {
1491        var groupCells = this.options.groupCells;
1492        if ( !groupCells ) {
1493            return function() {
1494                return false;
1495            };
1496        } else if ( typeof groupCells == 'number' ) {
1497            // group by number. 3 -> [0,1,2], [3,4,5], ...
1498            var number = parseInt( groupCells, 10 );
1499            return function( i ) {
1500                return ( i % number ) !== 0;
1501            };
1502        }
1503        // default, group by width of slide
1504        // parse '75%
1505        var percentMatch = typeof groupCells == 'string' &&
1506            groupCells.match(/^(\d+)%$/);
1507        var percent = percentMatch ? parseInt( percentMatch[1], 10 ) / 100 : 1;
1508        return function( i, slideWidth ) {
1509            return slideWidth <= ( this.size.innerWidth + 1 ) * percent;
1510        };
1511    };
1512
1513// alias _init for jQuery plugin .flickity()
1514    proto._init =
1515        proto.reposition = function() {
1516            this.positionCells();
1517            this.positionSliderAtSelected();
1518        };
1519
1520    proto.getSize = function() {
1521        this.size = getSize( this.element );
1522        this.setCellAlign();
1523        this.cursorPosition = this.size.innerWidth * this.cellAlign;
1524    };
1525
1526    var cellAlignShorthands = {
1527        // cell align, then based on origin side
1528        center: {
1529            left: 0.5,
1530            right: 0.5
1531        },
1532        left: {
1533            left: 0,
1534            right: 1
1535        },
1536        right: {
1537            right: 0,
1538            left: 1
1539        }
1540    };
1541
1542    proto.setCellAlign = function() {
1543        var shorthand = cellAlignShorthands[ this.options.cellAlign ];
1544        this.cellAlign = shorthand ? shorthand[ this.originSide ] : this.options.cellAlign;
1545    };
1546
1547    proto.setGallerySize = function() {
1548        if ( this.options.setGallerySize ) {
1549            var height = this.options.adaptiveHeight && this.selectedSlide ?
1550                this.selectedSlide.height : this.maxCellHeight;
1551            this.viewport.style.height = height + 'px';
1552        }
1553    };
1554
1555    proto._getWrapShiftCells = function() {
1556        // only for wrap-around
1557        if ( !this.options.wrapAround ) {
1558            return;
1559        }
1560        // unshift previous cells
1561        this._unshiftCells( this.beforeShiftCells );
1562        this._unshiftCells( this.afterShiftCells );
1563        // get before cells
1564        // initial gap
1565        var gapX = this.cursorPosition;
1566        var cellIndex = this.cells.length - 1;
1567        this.beforeShiftCells = this._getGapCells( gapX, cellIndex, -1 );
1568        // get after cells
1569        // ending gap between last cell and end of gallery viewport
1570        gapX = this.size.innerWidth - this.cursorPosition;
1571        // start cloning at first cell, working forwards
1572        this.afterShiftCells = this._getGapCells( gapX, 0, 1 );
1573    };
1574
1575    proto._getGapCells = function( gapX, cellIndex, increment ) {
1576        // keep adding cells until the cover the initial gap
1577        var cells = [];
1578        while ( gapX > 0 ) {
1579            var cell = this.cells[ cellIndex ];
1580            if ( !cell ) {
1581                break;
1582            }
1583            cells.push( cell );
1584            cellIndex += increment;
1585            gapX -= cell.size.outerWidth;
1586        }
1587        return cells;
1588    };
1589
1590// ----- contain ----- //
1591
1592// contain cell targets so no excess sliding
1593    proto._containSlides = function() {
1594        if ( !this.options.contain || this.options.wrapAround || !this.cells.length ) {
1595            return;
1596        }
1597        var isRightToLeft = this.options.rightToLeft;
1598        var beginMargin = isRightToLeft ? 'marginRight' : 'marginLeft';
1599        var endMargin = isRightToLeft ? 'marginLeft' : 'marginRight';
1600        var contentWidth = this.slideableWidth - this.getLastCell().size[ endMargin ];
1601        // content is less than gallery size
1602        var isContentSmaller = contentWidth < this.size.innerWidth;
1603        // bounds
1604        var beginBound = this.cursorPosition + this.cells[0].size[ beginMargin ];
1605        var endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );
1606        // contain each cell target
1607        this.slides.forEach( function( slide ) {
1608            if ( isContentSmaller ) {
1609                // all cells fit inside gallery
1610                slide.target = contentWidth * this.cellAlign;
1611            } else {
1612                // contain to bounds
1613                slide.target = Math.max( slide.target, beginBound );
1614                slide.target = Math.min( slide.target, endBound );
1615            }
1616        }, this );
1617    };
1618
1619// -----  ----- //
1620
1621    /**
1622     * emits events via eventEmitter and jQuery events
1623     * @param {String} type - name of event
1624     * @param {Event} event - original event
1625     * @param {Array} args - extra arguments
1626     */
1627    proto.dispatchEvent = function( type, event, args ) {
1628        var emitArgs = event ? [ event ].concat( args ) : args;
1629        this.emitEvent( type, emitArgs );
1630
1631        if ( jQuery && this.$element ) {
1632            // default trigger with type if no event
1633            type += this.options.namespaceJQueryEvents ? '.flickity' : '';
1634            var $event = type;
1635            if ( event ) {
1636                // create jQuery event
1637                var jQEvent = jQuery.Event( event );
1638                jQEvent.type = type;
1639                $event = jQEvent;
1640            }
1641            this.$element.trigger( $event, args );
1642        }
1643    };
1644
1645// -------------------------- select -------------------------- //
1646
1647    /**
1648     * @param {Integer} index - index of the slide
1649     * @param {Boolean} isWrap - will wrap-around to last/first if at the end
1650     * @param {Boolean} isInstant - will immediately set position at selected cell
1651     */
1652    proto.select = function( index, isWrap, isInstant ) {
1653        if ( !this.isActive ) {
1654            return;
1655        }
1656        index = parseInt( index, 10 );
1657        this._wrapSelect( index );
1658
1659        if ( this.options.wrapAround || isWrap ) {
1660            index = utils.modulo( index, this.slides.length );
1661        }
1662        // bail if invalid index
1663        if ( !this.slides[ index ] ) {
1664            return;
1665        }
1666        var prevIndex = this.selectedIndex;
1667        this.selectedIndex = index;
1668        this.updateSelectedSlide();
1669        if ( isInstant ) {
1670            this.positionSliderAtSelected();
1671        } else {
1672            this.startAnimation();
1673        }
1674        if ( this.options.adaptiveHeight ) {
1675            this.setGallerySize();
1676        }
1677        // events
1678        this.dispatchEvent( 'select', null, [ index ] );
1679        // change event if new index
1680        if ( index != prevIndex ) {
1681            this.dispatchEvent( 'change', null, [ index ] );
1682        }
1683        // old v1 event name, remove in v3
1684        this.dispatchEvent('cellSelect');
1685    };
1686
1687// wraps position for wrapAround, to move to closest slide. #113
1688    proto._wrapSelect = function( index ) {
1689        var len = this.slides.length;
1690        var isWrapping = this.options.wrapAround && len > 1;
1691        if ( !isWrapping ) {
1692            return index;
1693        }
1694        var wrapIndex = utils.modulo( index, len );
1695        // go to shortest
1696        var delta = Math.abs( wrapIndex - this.selectedIndex );
1697        var backWrapDelta = Math.abs( ( wrapIndex + len ) - this.selectedIndex );
1698        var forewardWrapDelta = Math.abs( ( wrapIndex - len ) - this.selectedIndex );
1699        if ( !this.isDragSelect && backWrapDelta < delta ) {
1700            index += len;
1701        } else if ( !this.isDragSelect && forewardWrapDelta < delta ) {
1702            index -= len;
1703        }
1704        // wrap position so slider is within normal area
1705        if ( index < 0 ) {
1706            this.x -= this.slideableWidth;
1707        } else if ( index >= len ) {
1708            this.x += this.slideableWidth;
1709        }
1710    };
1711
1712    proto.previous = function( isWrap, isInstant ) {
1713        this.select( this.selectedIndex - 1, isWrap, isInstant );
1714    };
1715
1716    proto.next = function( isWrap, isInstant ) {
1717        this.select( this.selectedIndex + 1, isWrap, isInstant );
1718    };
1719
1720    proto.updateSelectedSlide = function() {
1721        var slide = this.slides[ this.selectedIndex ];
1722        // selectedIndex could be outside of slides, if triggered before resize()
1723        if ( !slide ) {
1724            return;
1725        }
1726        // unselect previous selected slide
1727        this.unselectSelectedSlide();
1728        // update new selected slide
1729        this.selectedSlide = slide;
1730        slide.select();
1731        this.selectedCells = slide.cells;
1732        this.selectedElements = slide.getCellElements();
1733        // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility
1734        // Remove in v3?
1735        this.selectedCell = slide.cells[0];
1736        this.selectedElement = this.selectedElements[0];
1737    };
1738
1739    proto.unselectSelectedSlide = function() {
1740        if ( this.selectedSlide ) {
1741            this.selectedSlide.unselect();
1742        }
1743    };
1744
1745    /**
1746     * select slide from number or cell element
1747     * @param {Element or Number} elem
1748     */
1749    proto.selectCell = function( value, isWrap, isInstant ) {
1750        // get cell
1751        var cell = this.queryCell( value );
1752        if ( !cell ) {
1753            return;
1754        }
1755
1756        var index = this.getCellSlideIndex( cell );
1757        this.select( index, isWrap, isInstant );
1758    };
1759
1760    proto.getCellSlideIndex = function( cell ) {
1761        // get index of slides that has cell
1762        for ( var i=0; i < this.slides.length; i++ ) {
1763            var slide = this.slides[i];
1764            var index = slide.cells.indexOf( cell );
1765            if ( index != -1 ) {
1766                return i;
1767            }
1768        }
1769    };
1770
1771// -------------------------- get cells -------------------------- //
1772
1773    /**
1774     * get Flickity.Cell, given an Element
1775     * @param {Element} elem
1776     * @returns {Flickity.Cell} item
1777     */
1778    proto.getCell = function( elem ) {
1779        // loop through cells to get the one that matches
1780        for ( var i=0; i < this.cells.length; i++ ) {
1781            var cell = this.cells[i];
1782            if ( cell.element == elem ) {
1783                return cell;
1784            }
1785        }
1786    };
1787
1788    /**
1789     * get collection of Flickity.Cells, given Elements
1790     * @param {Element, Array, NodeList} elems
1791     * @returns {Array} cells - Flickity.Cells
1792     */
1793    proto.getCells = function( elems ) {
1794        elems = utils.makeArray( elems );
1795        var cells = [];
1796        elems.forEach( function( elem ) {
1797            var cell = this.getCell( elem );
1798            if ( cell ) {
1799                cells.push( cell );
1800            }
1801        }, this );
1802        return cells;
1803    };
1804
1805    /**
1806     * get cell elements
1807     * @returns {Array} cellElems
1808     */
1809    proto.getCellElements = function() {
1810        return this.cells.map( function( cell ) {
1811            return cell.element;
1812        });
1813    };
1814
1815    /**
1816     * get parent cell from an element
1817     * @param {Element} elem
1818     * @returns {Flickit.Cell} cell
1819     */
1820    proto.getParentCell = function( elem ) {
1821        // first check if elem is cell
1822        var cell = this.getCell( elem );
1823        if ( cell ) {
1824            return cell;
1825        }
1826        // try to get parent cell elem
1827        elem = utils.getParent( elem, '.flickity-slider > *' );
1828        return this.getCell( elem );
1829    };
1830
1831    /**
1832     * get cells adjacent to a slide
1833     * @param {Integer} adjCount - number of adjacent slides
1834     * @param {Integer} index - index of slide to start
1835     * @returns {Array} cells - array of Flickity.Cells
1836     */
1837    proto.getAdjacentCellElements = function( adjCount, index ) {
1838        if ( !adjCount ) {
1839            return this.selectedSlide.getCellElements();
1840        }
1841        index = index === undefined ? this.selectedIndex : index;
1842
1843        var len = this.slides.length;
1844        if ( 1 + ( adjCount * 2 ) >= len ) {
1845            return this.getCellElements();
1846        }
1847
1848        var cellElems = [];
1849        for ( var i = index - adjCount; i <= index + adjCount ; i++ ) {
1850            var slideIndex = this.options.wrapAround ? utils.modulo( i, len ) : i;
1851            var slide = this.slides[ slideIndex ];
1852            if ( slide ) {
1853                cellElems = cellElems.concat( slide.getCellElements() );
1854            }
1855        }
1856        return cellElems;
1857    };
1858
1859    /**
1860     * select slide from number or cell element
1861     * @param {Element, Selector String, or Number} selector
1862     */
1863    proto.queryCell = function( selector ) {
1864        if ( typeof selector == 'number' ) {
1865            // use number as index
1866            return this.cells[ selector ];
1867        }
1868        if ( typeof selector == 'string' ) {
1869            // use string as selector, get element
1870            selector = this.element.querySelector( selector );
1871        }
1872        // get cell from element
1873        return this.getCell( selector );
1874    };
1875
1876// -------------------------- events -------------------------- //
1877
1878    proto.uiChange = function() {
1879        this.emitEvent('uiChange');
1880    };
1881
1882    proto.childUIPointerDown = function( event ) {
1883        this.emitEvent( 'childUIPointerDown', [ event ] );
1884    };
1885
1886// ----- resize ----- //
1887
1888    proto.onresize = function() {
1889        this.watchCSS();
1890        this.resize();
1891    };
1892
1893    utils.debounceMethod( Flickity, 'onresize', 150 );
1894
1895    proto.resize = function() {
1896        if ( !this.isActive ) {
1897            return;
1898        }
1899        this.getSize();
1900        // wrap values
1901        if ( this.options.wrapAround ) {
1902            this.x = utils.modulo( this.x, this.slideableWidth );
1903        }
1904        this.positionCells();
1905        this._getWrapShiftCells();
1906        this.setGallerySize();
1907        this.emitEvent('resize');
1908        // update selected index for group slides, instant
1909        // TODO: position can be lost between groups of various numbers
1910        var selectedElement = this.selectedElements && this.selectedElements[0];
1911        this.selectCell( selectedElement, false, true );
1912    };
1913
1914// watches the :after property, activates/deactivates
1915    proto.watchCSS = function() {
1916        var watchOption = this.options.watchCSS;
1917        if ( !watchOption ) {
1918            return;
1919        }
1920
1921        var afterContent = getComputedStyle( this.element, ':after' ).content;
1922        // activate if :after { content: 'flickity' }
1923        if ( afterContent.indexOf('flickity') != -1 ) {
1924            this.activate();
1925        } else {
1926            this.deactivate();
1927        }
1928    };
1929
1930// ----- keydown ----- //
1931
1932// go previous/next if left/right keys pressed
1933    proto.onkeydown = function( event ) {
1934        // only work if element is in focus
1935        var isNotFocused = document.activeElement && document.activeElement != this.element;
1936        if ( !this.options.accessibility ||isNotFocused ) {
1937            return;
1938        }
1939
1940        var handler = Flickity.keyboardHandlers[ event.keyCode ];
1941        if ( handler ) {
1942            handler.call( this );
1943        }
1944    };
1945
1946    Flickity.keyboardHandlers = {
1947        // left arrow
1948        37: function() {
1949            var leftMethod = this.options.rightToLeft ? 'next' : 'previous';
1950            this.uiChange();
1951            this[ leftMethod ]();
1952        },
1953        // right arrow
1954        39: function() {
1955            var rightMethod = this.options.rightToLeft ? 'previous' : 'next';
1956            this.uiChange();
1957            this[ rightMethod ]();
1958        },
1959    };
1960
1961// ----- focus ----- //
1962
1963    proto.focus = function() {
1964        // TODO remove scrollTo once focus options gets more support
1965        // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Browser_compatibility
1966        var prevScrollY = window.pageYOffset;
1967        this.element.focus({ preventScroll: true });
1968        // hack to fix scroll jump after focus, #76
1969        if ( window.pageYOffset != prevScrollY ) {
1970            window.scrollTo( window.pageXOffset, prevScrollY );
1971        }
1972    };
1973
1974// -------------------------- destroy -------------------------- //
1975
1976// deactivate all Flickity functionality, but keep stuff available
1977    proto.deactivate = function() {
1978        if ( !this.isActive ) {
1979            return;
1980        }
1981        this.element.classList.remove('flickity-enabled');
1982        this.element.classList.remove('flickity-rtl');
1983        this.unselectSelectedSlide();
1984        // destroy cells
1985        this.cells.forEach( function( cell ) {
1986            cell.destroy();
1987        });
1988        this.element.removeChild( this.viewport );
1989        // move child elements back into element
1990        moveElements( this.slider.children, this.element );
1991        if ( this.options.accessibility ) {
1992            this.element.removeAttribute('tabIndex');
1993            this.element.removeEventListener( 'keydown', this );
1994        }
1995        // set flags
1996        this.isActive = false;
1997        this.emitEvent('deactivate');
1998    };
1999
2000    proto.destroy = function() {
2001        this.deactivate();
2002        window.removeEventListener( 'resize', this );
2003        this.emitEvent('destroy');
2004        if ( jQuery && this.$element ) {
2005            jQuery.removeData( this.element, 'flickity' );
2006        }
2007        delete this.element.flickityGUID;
2008        delete instances[ this.guid ];
2009    };
2010
2011// -------------------------- prototype -------------------------- //
2012
2013    utils.extend( proto, animatePrototype );
2014
2015// -------------------------- extras -------------------------- //
2016
2017    /**
2018     * get Flickity instance from element
2019     * @param {Element} elem
2020     * @returns {Flickity}
2021     */
2022    Flickity.data = function( elem ) {
2023        elem = utils.getQueryElement( elem );
2024        var id = elem && elem.flickityGUID;
2025        return id && instances[ id ];
2026    };
2027
2028    utils.htmlInit( Flickity, 'flickity' );
2029
2030    if ( jQuery && jQuery.bridget ) {
2031        jQuery.bridget( 'flickity', Flickity );
2032    }
2033
2034// set internal jQuery, for Webpack + jQuery v3, #478
2035    Flickity.setJQuery = function( jq ) {
2036        jQuery = jq;
2037    };
2038
2039    Flickity.Cell = Cell;
2040
2041    return Flickity;
2042
2043}));
2044
2045/*!
2046 * Unipointer v2.3.0
2047 * base class for doing one thing with pointer event
2048 * MIT license
2049 */
2050
2051/*jshint browser: true, undef: true, unused: true, strict: true */
2052
2053( function( window, factory ) {
2054    // universal module definition
2055    /* jshint strict: false */ /*global define, module, require */
2056    if ( typeof define == 'function' && define.amd ) {
2057        // AMD
2058        define( 'unipointer/unipointer',[
2059            'ev-emitter/ev-emitter'
2060        ], function( EvEmitter ) {
2061            return factory( window, EvEmitter );
2062        });
2063    } else if ( typeof module == 'object' && module.exports ) {
2064        // CommonJS
2065        module.exports = factory(
2066            window,
2067            require('ev-emitter')
2068        );
2069    } else {
2070        // browser global
2071        window.Unipointer = factory(
2072            window,
2073            window.EvEmitter
2074        );
2075    }
2076
2077}( window, function factory( window, EvEmitter ) {
2078
2079
2080
2081    function noop() {}
2082
2083    function Unipointer() {}
2084
2085// inherit EvEmitter
2086    var proto = Unipointer.prototype = Object.create( EvEmitter.prototype );
2087
2088    proto.bindStartEvent = function( elem ) {
2089        this._bindStartEvent( elem, true );
2090    };
2091
2092    proto.unbindStartEvent = function( elem ) {
2093        this._bindStartEvent( elem, false );
2094    };
2095
2096    /**
2097     * Add or remove start event
2098     * @param {Boolean} isAdd - remove if falsey
2099     */
2100    proto._bindStartEvent = function( elem, isAdd ) {
2101        // munge isAdd, default to true
2102        isAdd = isAdd === undefined ? true : isAdd;
vendor: 8,429 bytes, lines 2103-2407
2103        var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';
2104
2105        // default to mouse events
2106        var startEvent = 'mousedown';
2107        if ( window.PointerEvent ) {
2108            // Pointer Events
2109            startEvent = 'pointerdown';
2110        } else if ( 'ontouchstart' in window ) {
2111            // Touch Events. iOS Safari
2112            startEvent = 'touchstart';
2113        }
2114        elem[ bindMethod ]( startEvent, this );
2115    };
2116
2117// trigger handler methods for events
2118    proto.handleEvent = function( event ) {
2119        var method = 'on' + event.type;
2120        if ( this[ method ] ) {
2121            this[ method ]( event );
2122        }
2123    };
2124
2125// returns the touch that we're keeping track of
2126    proto.getTouch = function( touches ) {
2127        for ( var i=0; i < touches.length; i++ ) {
2128            var touch = touches[i];
2129            if ( touch.identifier == this.pointerIdentifier ) {
2130                return touch;
2131            }
2132        }
2133    };
2134
2135// ----- start event ----- //
2136
2137    proto.onmousedown = function( event ) {
2138        // dismiss clicks from right or middle buttons
2139        var button = event.button;
2140        if ( button && ( button !== 0 && button !== 1 ) ) {
2141            return;
2142        }
2143        this._pointerDown( event, event );
2144    };
2145
2146    proto.ontouchstart = function( event ) {
2147        this._pointerDown( event, event.changedTouches[0] );
2148    };
2149
2150    proto.onpointerdown = function( event ) {
2151        this._pointerDown( event, event );
2152    };
2153
2154    /**
2155     * pointer start
2156     * @param {Event} event
2157     * @param {Event or Touch} pointer
2158     */
2159    proto._pointerDown = function( event, pointer ) {
2160        // dismiss right click and other pointers
2161        // button = 0 is okay, 1-4 not
2162        if ( event.button || this.isPointerDown ) {
2163            return;
2164        }
2165
2166        this.isPointerDown = true;
2167        // save pointer identifier to match up touch events
2168        this.pointerIdentifier = pointer.pointerId !== undefined ?
2169            // pointerId for pointer events, touch.indentifier for touch events
2170            pointer.pointerId : pointer.identifier;
2171
2172        this.pointerDown( event, pointer );
2173    };
2174
2175    proto.pointerDown = function( event, pointer ) {
2176        this._bindPostStartEvents( event );
2177        this.emitEvent( 'pointerDown', [ event, pointer ] );
2178    };
2179
2180// hash of events to be bound after start event
2181    var postStartEvents = {
2182        mousedown: [ 'mousemove', 'mouseup' ],
2183        touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
2184        pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
2185    };
2186
2187    proto._bindPostStartEvents = function( event ) {
2188        if ( !event ) {
2189            return;
2190        }
2191        // get proper events to match start event
2192        var events = postStartEvents[ event.type ];
2193        // bind events to node
2194        events.forEach( function( eventName ) {
2195            window.addEventListener( eventName, this );
2196        }, this );
2197        // save these arguments
2198        this._boundPointerEvents = events;
2199    };
2200
2201    proto._unbindPostStartEvents = function() {
2202        // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)
2203        if ( !this._boundPointerEvents ) {
2204            return;
2205        }
2206        this._boundPointerEvents.forEach( function( eventName ) {
2207            window.removeEventListener( eventName, this );
2208        }, this );
2209
2210        delete this._boundPointerEvents;
2211    };
2212
2213// ----- move event ----- //
2214
2215    proto.onmousemove = function( event ) {
2216        this._pointerMove( event, event );
2217    };
2218
2219    proto.onpointermove = function( event ) {
2220        if ( event.pointerId == this.pointerIdentifier ) {
2221            this._pointerMove( event, event );
2222        }
2223    };
2224
2225    proto.ontouchmove = function( event ) {
2226        var touch = this.getTouch( event.changedTouches );
2227        if ( touch ) {
2228            this._pointerMove( event, touch );
2229        }
2230    };
2231
2232    /**
2233     * pointer move
2234     * @param {Event} event
2235     * @param {Event or Touch} pointer
2236     * @private
2237     */
2238    proto._pointerMove = function( event, pointer ) {
2239        this.pointerMove( event, pointer );
2240    };
2241
2242// public
2243    proto.pointerMove = function( event, pointer ) {
2244        this.emitEvent( 'pointerMove', [ event, pointer ] );
2245    };
2246
2247// ----- end event ----- //
2248
2249
2250    proto.onmouseup = function( event ) {
2251        this._pointerUp( event, event );
2252    };
2253
2254    proto.onpointerup = function( event ) {
2255        if ( event.pointerId == this.pointerIdentifier ) {
2256            this._pointerUp( event, event );
2257        }
2258    };
2259
2260    proto.ontouchend = function( event ) {
2261        var touch = this.getTouch( event.changedTouches );
2262        if ( touch ) {
2263            this._pointerUp( event, touch );
2264        }
2265    };
2266
2267    /**
2268     * pointer up
2269     * @param {Event} event
2270     * @param {Event or Touch} pointer
2271     * @private
2272     */
2273    proto._pointerUp = function( event, pointer ) {
2274        this._pointerDone();
2275        this.pointerUp( event, pointer );
2276    };
2277
2278// public
2279    proto.pointerUp = function( event, pointer ) {
2280        this.emitEvent( 'pointerUp', [ event, pointer ] );
2281    };
2282
2283// ----- pointer done ----- //
2284
2285// triggered on pointer up & pointer cancel
2286    proto._pointerDone = function() {
2287        this._pointerReset();
2288        this._unbindPostStartEvents();
2289        this.pointerDone();
2290    };
2291
2292    proto._pointerReset = function() {
2293        // reset properties
2294        this.isPointerDown = false;
2295        delete this.pointerIdentifier;
2296    };
2297
2298    proto.pointerDone = noop;
2299
2300// ----- pointer cancel ----- //
2301
2302    proto.onpointercancel = function( event ) {
2303        if ( event.pointerId == this.pointerIdentifier ) {
2304            this._pointerCancel( event, event );
2305        }
2306    };
2307
2308    proto.ontouchcancel = function( event ) {
2309        var touch = this.getTouch( event.changedTouches );
2310        if ( touch ) {
2311            this._pointerCancel( event, touch );
2312        }
2313    };
2314
2315    /**
2316     * pointer cancel
2317     * @param {Event} event
2318     * @param {Event or Touch} pointer
2319     * @private
2320     */
2321    proto._pointerCancel = function( event, pointer ) {
2322        this._pointerDone();
2323        this.pointerCancel( event, pointer );
2324    };
2325
2326// public
2327    proto.pointerCancel = function( event, pointer ) {
2328        this.emitEvent( 'pointerCancel', [ event, pointer ] );
2329    };
2330
2331// -----  ----- //
2332
2333// utility function for getting x/y coords from event
2334    Unipointer.getPointerPoint = function( pointer ) {
2335        return {
2336            x: pointer.pageX,
2337            y: pointer.pageY
2338        };
2339    };
2340
2341// -----  ----- //
2342
2343    return Unipointer;
2344
2345}));
2346
2347/*!
2348 * Unidragger v2.3.0
2349 * Draggable base class
2350 * MIT license
2351 */
2352
2353/*jshint browser: true, unused: true, undef: true, strict: true */
2354
2355( function( window, factory ) {
2356    // universal module definition
2357    /*jshint strict: false */ /*globals define, module, require */
2358
2359    if ( typeof define == 'function' && define.amd ) {
2360        // AMD
2361        define( 'unidragger/unidragger',[
2362            'unipointer/unipointer'
2363        ], function( Unipointer ) {
2364            return factory( window, Unipointer );
2365        });
2366    } else if ( typeof module == 'object' && module.exports ) {
2367        // CommonJS
2368        module.exports = factory(
2369            window,
2370            require('unipointer')
2371        );
2372    } else {
2373        // browser global
2374        window.Unidragger = factory(
2375            window,
2376            window.Unipointer
2377        );
2378    }
2379
2380}( window, function factory( window, Unipointer ) {
2381
2382
2383
2384// -------------------------- Unidragger -------------------------- //
2385
2386    function Unidragger() {}
2387
2388// inherit Unipointer & EvEmitter
2389    var proto = Unidragger.prototype = Object.create( Unipointer.prototype );
2390
2391// ----- bind start ----- //
2392
2393    proto.bindHandles = function() {
2394        this._bindHandles( true );
2395    };
2396
2397    proto.unbindHandles = function() {
2398        this._bindHandles( false );
2399    };
2400
2401    /**
2402     * Add or remove start event
2403     * @param {Boolean} isAdd
2404     */
2405    proto._bindHandles = function( isAdd ) {
2406        // munge isAdd, default to true
2407        isAdd = isAdd === undefined ? true : isAdd;
vendor: 4,306 bytes, lines 2408-2543
2408        // bind each handle
2409        var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';
2410        var touchAction = isAdd ? this._touchActionValue : '';
2411        for ( var i=0; i < this.handles.length; i++ ) {
2412            var handle = this.handles[i];
2413            this._bindStartEvent( handle, isAdd );
2414            handle[ bindMethod ]( 'click', this );
2415            // touch-action: none to override browser touch gestures. metafizzy/flickity#540
2416            if ( window.PointerEvent ) {
2417                handle.style.touchAction = touchAction;
2418            }
2419        }
2420    };
2421
2422// prototype so it can be overwriteable by Flickity
2423    proto._touchActionValue = 'none';
2424
2425// ----- start event ----- //
2426
2427    /**
2428     * pointer start
2429     * @param {Event} event
2430     * @param {Event or Touch} pointer
2431     */
2432    proto.pointerDown = function( event, pointer ) {
2433        var isOkay = this.okayPointerDown( event );
2434        if ( !isOkay ) {
2435            return;
2436        }
2437        // track start event position
2438        this.pointerDownPointer = pointer;
2439
2440        event.preventDefault();
2441        this.pointerDownBlur();
2442        // bind move and end events
2443        this._bindPostStartEvents( event );
2444        this.emitEvent( 'pointerDown', [ event, pointer ] );
2445    };
2446
2447// nodes that have text fields
2448    var cursorNodes = {
2449        TEXTAREA: true,
2450        INPUT: true,
2451        SELECT: true,
2452        OPTION: true,
2453    };
2454
2455// input types that do not have text fields
2456    var clickTypes = {
2457        radio: true,
2458        checkbox: true,
2459        button: true,
2460        submit: true,
2461        image: true,
2462        file: true,
2463    };
2464
2465// dismiss inputs with text fields. flickity#403, flickity#404
2466    proto.okayPointerDown = function( event ) {
2467        var isCursorNode = cursorNodes[ event.target.nodeName ];
2468        var isClickType = clickTypes[ event.target.type ];
2469        var isOkay = !isCursorNode || isClickType;
2470        if ( !isOkay ) {
2471            this._pointerReset();
2472        }
2473        return isOkay;
2474    };
2475
2476// kludge to blur previously focused input
2477    proto.pointerDownBlur = function() {
2478        var focused = document.activeElement;
2479        // do not blur body for IE10, metafizzy/flickity#117
2480        var canBlur = focused && focused.blur && focused != document.body;
2481        if ( canBlur ) {
2482            focused.blur();
2483        }
2484    };
2485
2486// ----- move event ----- //
2487
2488    /**
2489     * drag move
2490     * @param {Event} event
2491     * @param {Event or Touch} pointer
2492     */
2493    proto.pointerMove = function( event, pointer ) {
2494        var moveVector = this._dragPointerMove( event, pointer );
2495        this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );
2496        this._dragMove( event, pointer, moveVector );
2497    };
2498
2499// base pointer move logic
2500    proto._dragPointerMove = function( event, pointer ) {
2501        var moveVector = {
2502            x: pointer.pageX - this.pointerDownPointer.pageX,
2503            y: pointer.pageY - this.pointerDownPointer.pageY
2504        };
2505        // start drag if pointer has moved far enough to start drag
2506        if ( !this.isDragging && this.hasDragStarted( moveVector ) ) {
2507            this._dragStart( event, pointer );
2508        }
2509        return moveVector;
2510    };
2511
2512// condition if pointer has moved far enough to start drag
2513    proto.hasDragStarted = function( moveVector ) {
2514        return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;
2515    };
2516
2517// ----- end event ----- //
2518
2519    /**
2520     * pointer up
2521     * @param {Event} event
2522     * @param {Event or Touch} pointer
2523     */
2524    proto.pointerUp = function( event, pointer ) {
2525        this.emitEvent( 'pointerUp', [ event, pointer ] );
2526        this._dragPointerUp( event, pointer );
2527    };
2528
2529    proto._dragPointerUp = function( event, pointer ) {
2530        if ( this.isDragging ) {
2531            this._dragEnd( event, pointer );
2532        } else {
2533            // pointer didn't move enough for drag to start
2534            this._staticClick( event, pointer );
2535        }
2536    };
2537
2538// -------------------------- drag -------------------------- //
2539
2540// dragStart
2541    proto._dragStart = function( event, pointer ) {
2542        this.isDragging = true;
2543        // prevent clicks
2544        this.isPreventingClicks = true;
2545        this.dragStart( event, pointer );
2546    };
2547
2548    proto.dragStart = function( event, pointer ) {
2549        this.emitEvent( 'dragStart', [ event, pointer ] );
2550    };
2551
2552// dragMove
2553    proto._dragMove = function( event, pointer, moveVector ) {
2554        // do not drag if not dragging yet
2555        if ( !this.isDragging ) {
2556            return;
2557        }
2558
2559        this.dragMove( event, pointer, moveVector );
2560    };
2561
2562    proto.dragMove = function( event, pointer, moveVector ) {
2563        event.preventDefault();
2564        this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );
2565    };
2566
2567// dragEnd
2568    proto._dragEnd = function( event, pointer ) {
2569        // set flags
2570        this.isDragging = false;
2571        // re-enable clicking async
2572        setTimeout( function() {
2573            delete this.isPreventingClicks;
2574        }.bind( this ) );
2575
2576        this.dragEnd( event, pointer );
2577    };
2578
2579    proto.dragEnd = function( event, pointer ) {
2580        this.emitEvent( 'dragEnd', [ event, pointer ] );
2581    };
2582
2583// ----- onclick ----- //
2584
2585// handle all clicks and prevent clicks when dragging
2586    proto.onclick = function( event ) {
vendor: 10,621 bytes, lines 2587-2907
2587        if ( this.isPreventingClicks ) {
2588            event.preventDefault();
2589        }
2590    };
2591
2592// ----- staticClick ----- //
2593
2594// triggered after pointer down & up with no/tiny movement
2595    proto._staticClick = function( event, pointer ) {
2596        // ignore emulated mouse up clicks
2597        if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
2598            return;
2599        }
2600
2601        this.staticClick( event, pointer );
2602
2603        // set flag for emulated clicks 300ms after touchend
2604        if ( event.type != 'mouseup' ) {
2605            this.isIgnoringMouseUp = true;
2606            // reset flag after 300ms
2607            setTimeout( function() {
2608                delete this.isIgnoringMouseUp;
2609            }.bind( this ), 400 );
2610        }
2611    };
2612
2613    proto.staticClick = function( event, pointer ) {
2614        this.emitEvent( 'staticClick', [ event, pointer ] );
2615    };
2616
2617// ----- utils ----- //
2618
2619    Unidragger.getPointerPoint = Unipointer.getPointerPoint;
2620
2621// -----  ----- //
2622
2623    return Unidragger;
2624
2625}));
2626
2627// drag
2628( function( window, factory ) {
2629    // universal module definition
2630    /* jshint strict: false */
2631    if ( typeof define == 'function' && define.amd ) {
2632        // AMD
2633        define( 'flickity/js/drag',[
2634            './flickity',
2635            'unidragger/unidragger',
2636            'fizzy-ui-utils/utils'
2637        ], function( Flickity, Unidragger, utils ) {
2638            return factory( window, Flickity, Unidragger, utils );
2639        });
2640    } else if ( typeof module == 'object' && module.exports ) {
2641        // CommonJS
2642        module.exports = factory(
2643            window,
2644            require('./flickity'),
2645            require('unidragger'),
2646            require('fizzy-ui-utils')
2647        );
2648    } else {
2649        // browser global
2650        window.Flickity = factory(
2651            window,
2652            window.Flickity,
2653            window.Unidragger,
2654            window.fizzyUIUtils
2655        );
2656    }
2657
2658}( window, function factory( window, Flickity, Unidragger, utils ) {
2659
2660
2661
2662// ----- defaults ----- //
2663
2664    utils.extend( Flickity.defaults, {
2665        draggable: '>1',
2666        dragThreshold: 3,
2667    });
2668
2669// ----- create ----- //
2670
2671    Flickity.createMethods.push('_createDrag');
2672
2673// -------------------------- drag prototype -------------------------- //
2674
2675    var proto = Flickity.prototype;
2676    utils.extend( proto, Unidragger.prototype );
2677    proto._touchActionValue = 'pan-y';
2678
2679// --------------------------  -------------------------- //
2680
2681    var isTouch = 'createTouch' in document;
2682    var isTouchmoveScrollCanceled = false;
2683
2684    proto._createDrag = function() {
2685        this.on( 'activate', this.onActivateDrag );
2686        this.on( 'uiChange', this._uiChangeDrag );
2687        this.on( 'childUIPointerDown', this._childUIPointerDownDrag );
2688        this.on( 'deactivate', this.onDeactivateDrag );
2689        this.on( 'cellChange', this.updateDraggable );
2690        // TODO updateDraggable on resize? if groupCells & slides change
2691        // HACK - add seemingly innocuous handler to fix iOS 10 scroll behavior
2692        // #457, RubaXa/Sortable#973
2693        if ( isTouch && !isTouchmoveScrollCanceled ) {
2694            window.addEventListener( 'touchmove', function() {});
2695            isTouchmoveScrollCanceled = true;
2696        }
2697    };
2698
2699    proto.onActivateDrag = function() {
2700        this.handles = [ this.viewport ];
2701        this.bindHandles();
2702        this.updateDraggable();
2703    };
2704
2705    proto.onDeactivateDrag = function() {
2706        this.unbindHandles();
2707        this.element.classList.remove('is-draggable');
2708    };
2709
2710    proto.updateDraggable = function() {
2711        // disable dragging if less than 2 slides. #278
2712        if ( this.options.draggable == '>1' ) {
2713            this.isDraggable = this.slides.length > 1;
2714        } else {
2715            this.isDraggable = this.options.draggable;
2716        }
2717        if ( this.isDraggable ) {
2718            this.element.classList.add('is-draggable');
2719        } else {
2720            this.element.classList.remove('is-draggable');
2721        }
2722    };
2723
2724// backwards compatibility
2725    proto.bindDrag = function() {
2726        this.options.draggable = true;
2727        this.updateDraggable();
2728    };
2729
2730    proto.unbindDrag = function() {
2731        this.options.draggable = false;
2732        this.updateDraggable();
2733    };
2734
2735    proto._uiChangeDrag = function() {
2736        delete this.isFreeScrolling;
2737    };
2738
2739    proto._childUIPointerDownDrag = function( event ) {
2740        // allow focus & preventDefault even when not draggable
2741        // so child UI elements keep focus on carousel. #721
2742        event.preventDefault();
2743        this.pointerDownFocus( event );
2744    };
2745
2746// -------------------------- pointer events -------------------------- //
2747
2748    proto.pointerDown = function( event, pointer ) {
2749        if ( !this.isDraggable ) {
2750            this._pointerDownDefault( event, pointer );
2751            return;
2752        }
2753        var isOkay = this.okayPointerDown( event );
2754        if ( !isOkay ) {
2755            return;
2756        }
2757
2758        this._pointerDownPreventDefault( event );
2759        this.pointerDownFocus( event );
2760        // blur
2761        if ( document.activeElement != this.element ) {
2762            // do not blur if already focused
2763            this.pointerDownBlur();
2764        }
2765
2766        // stop if it was moving
2767        this.dragX = this.x;
2768        this.viewport.classList.add('is-pointer-down');
2769        // track scrolling
2770        this.pointerDownScroll = getScrollPosition();
2771        window.addEventListener( 'scroll', this );
2772
2773        this._pointerDownDefault( event, pointer );
2774    };
2775
2776// default pointerDown logic, used for staticClick
2777    proto._pointerDownDefault = function( event, pointer ) {
2778        // track start event position
2779        this.pointerDownPointer = pointer;
2780        // bind move and end events
2781        this._bindPostStartEvents( event );
2782        this.dispatchEvent( 'pointerDown', event, [ pointer ] );
2783    };
2784
2785    var focusNodes = {
2786        INPUT: true,
2787        TEXTAREA: true,
2788        SELECT: true,
2789    };
2790
2791    proto.pointerDownFocus = function( event ) {
2792        var isFocusNode = focusNodes[ event.target.nodeName ];
2793        if ( !isFocusNode ) {
2794            this.focus();
2795        }
2796    };
2797
2798    proto._pointerDownPreventDefault = function( event ) {
2799        var isTouchStart = event.type == 'touchstart';
2800        var isTouchPointer = event.pointerType == 'touch';
2801        var isFocusNode = focusNodes[ event.target.nodeName ];
2802        if ( !isTouchStart && !isTouchPointer && !isFocusNode ) {
2803            event.preventDefault();
2804        }
2805    };
2806
2807// ----- move ----- //
2808
2809    proto.hasDragStarted = function( moveVector ) {
2810        return Math.abs( moveVector.x ) > this.options.dragThreshold;
2811    };
2812
2813// ----- up ----- //
2814
2815    proto.pointerUp = function( event, pointer ) {
2816        delete this.isTouchScrolling;
2817        this.viewport.classList.remove('is-pointer-down');
2818        this.dispatchEvent( 'pointerUp', event, [ pointer ] );
2819        this._dragPointerUp( event, pointer );
2820    };
2821
2822    proto.pointerDone = function() {
2823        window.removeEventListener( 'scroll', this );
2824        delete this.pointerDownScroll;
2825    };
2826
2827// -------------------------- dragging -------------------------- //
2828
2829    proto.dragStart = function( event, pointer ) {
2830        if ( !this.isDraggable ) {
2831            return;
2832        }
2833        this.dragStartPosition = this.x;
2834        this.startAnimation();
2835        window.removeEventListener( 'scroll', this );
2836        this.dispatchEvent( 'dragStart', event, [ pointer ] );
2837    };
2838
2839    proto.pointerMove = function( event, pointer ) {
2840        var moveVector = this._dragPointerMove( event, pointer );
2841        this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] );
2842        this._dragMove( event, pointer, moveVector );
2843    };
2844
2845    proto.dragMove = function( event, pointer, moveVector ) {
2846        if ( !this.isDraggable ) {
2847            return;
2848        }
2849        event.preventDefault();
2850
2851        this.previousDragX = this.dragX;
2852        // reverse if right-to-left
2853        var direction = this.options.rightToLeft ? -1 : 1;
2854        if ( this.options.wrapAround ) {
2855            // wrap around move. #589
2856            moveVector.x = moveVector.x % this.slideableWidth;
2857        }
2858        var dragX = this.dragStartPosition + moveVector.x * direction;
2859
2860        if ( !this.options.wrapAround && this.slides.length ) {
2861            // slow drag
2862            var originBound = Math.max( -this.slides[0].target, this.dragStartPosition );
2863            dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX;
2864            var endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition );
2865            dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX;
2866        }
2867
2868        this.dragX = dragX;
2869
2870        this.dragMoveTime = new Date();
2871        this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] );
2872    };
2873
2874    proto.dragEnd = function( event, pointer ) {
2875        if ( !this.isDraggable ) {
2876            return;
2877        }
2878        if ( this.options.freeScroll ) {
2879            this.isFreeScrolling = true;
2880        }
2881        // set selectedIndex based on where flick will end up
2882        var index = this.dragEndRestingSelect();
2883
2884        if ( this.options.freeScroll && !this.options.wrapAround ) {
2885            // if free-scroll & not wrap around
2886            // do not free-scroll if going outside of bounding slides
2887            // so bounding slides can attract slider, and keep it in bounds
2888            var restingX = this.getRestingPosition();
2889            this.isFreeScrolling = -restingX > this.slides[0].target &&
2890                -restingX < this.getLastSlide().target;
2891        } else if ( !this.options.freeScroll && index == this.selectedIndex ) {
2892            // boost selection if selected index has not changed
2893            index += this.dragEndBoostSelect();
2894        }
2895        delete this.previousDragX;
2896        // apply selection
2897        // TODO refactor this, selecting here feels weird
2898        // HACK, set flag so dragging stays in correct direction
2899        this.isDragSelect = this.options.wrapAround;
2900        this.select( index );
2901        delete this.isDragSelect;
2902        this.dispatchEvent( 'dragEnd', event, [ pointer ] );
2903    };
2904
2905    proto.dragEndRestingSelect = function() {
2906        var restingX = this.getRestingPosition();
2907        // how far away from selected slide
2908        var distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) );
2909        // get closet resting going up and going down
2910        var positiveResting = this._getClosestResting( restingX, distance, 1 );
2911        var negativeResting = this._getClosestResting( restingX, distance, -1 );
2912        // use closer resting for wrap-around
2913        var index = positiveResting.distance < negativeResting.distance ?
2914            positiveResting.index : negativeResting.index;
2915        return index;
2916    };
2917
2918    /**
2919     * given resting X and distance to selected cell
2920     * get the distance and index of the closest cell
2921     * @param {Number} restingX - estimated post-flick resting position
2922     * @param {Number} distance - distance to selected cell
2923     * @param {Integer} increment - +1 or -1, going up or down
2924     * @returns {Object} - { distance: {Number}, index: {Integer} }
2925     */
2926    proto._getClosestResting = function( restingX, distance, increment ) {
2927        var index = this.selectedIndex;
2928        var minDistance = Infinity;
2929        var condition = this.options.contain && !this.options.wrapAround ?
2930            // if contain, keep going if distance is equal to minDistance
2931            function( d, md ) { return d <= md; } : function( d, md ) { return d < md; };
2932        while ( condition( distance, minDistance ) ) {
2933            // measure distance to next cell
2934            index += increment;
2935            minDistance = distance;
2936            distance = this.getSlideDistance( -restingX, index );
2937            if ( distance === null ) {
2938                break;
2939            }
2940            distance = Math.abs( distance );
2941        }
2942        return {
2943            distance: minDistance,
2944            // selected was previous index
2945            index: index - increment
2946        };
2947    };
2948
2949    /**
2950     * measure distance between x and a slide target
2951     * @param {Number} x
2952     * @param {Integer} index - slide index
2953     */
2954    proto.getSlideDistance = function( x, index ) {
2955        var len = this.slides.length;
2956        // wrap around if at least 2 slides
2957        var isWrapAround = this.options.wrapAround && len > 1;
2958        var slideIndex = isWrapAround ? utils.modulo( index, len ) : index;
2959        var slide = this.slides[ slideIndex ];
2960        if ( !slide ) {
2961            return null;
2962        }
2963        // add distance for wrap-around slides
2964        var wrap = isWrapAround ? this.slideableWidth * Math.floor( index / len ) : 0;
2965        return x - ( slide.target + wrap );
2966    };
2967
2968    proto.dragEndBoostSelect = function() {
2969        // do not boost if no previousDragX or dragMoveTime
2970        if ( this.previousDragX === undefined || !this.dragMoveTime ||
2971            // or if drag was held for 100 ms
2972            new Date() - this.dragMoveTime > 100 ) {
2973            return 0;
2974        }
2975
2976        var distance = this.getSlideDistance( -this.dragX, this.selectedIndex );
2977        var delta = this.previousDragX - this.dragX;
2978        if ( distance > 0 && delta > 0 ) {
2979            // boost to next if moving towards the right, and positive velocity
2980            return 1;
2981        } else if ( distance < 0 && delta < 0 ) {
2982            // boost to previous if moving towards the left, and negative velocity
2983            return -1;
2984        }
2985        return 0;
2986    };
2987
2988// ----- staticClick ----- //
2989
2990    proto.staticClick = function( event, pointer ) {
2991        // get clickedCell, if cell was clicked
2992        var clickedCell = this.getParentCell( event.target );
2993        var cellElem = clickedCell && clickedCell.element;
2994        var cellIndex = clickedCell && this.cells.indexOf( clickedCell );
2995        this.dispatchEvent( 'staticClick', event, [ pointer, cellElem, cellIndex ] );
2996    };
2997
2998// ----- scroll ----- //
2999
3000    proto.onscroll = function() {
3001        var scroll = getScrollPosition();
3002        var scrollMoveX = this.pointerDownScroll.x - scroll.x;
3003        var scrollMoveY = this.pointerDownScroll.y - scroll.y;
3004        // cancel click/tap if scroll is too much
3005        if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) {
3006            this._pointerDone();
3007        }
3008    };
3009
3010// ----- utils ----- //
3011
3012    function getScrollPosition() {
3013        return {
3014            x: window.pageXOffset,
3015            y: window.pageYOffset
3016        };
3017    }
3018
3019// -----  ----- //
3020
3021    return Flickity;
3022
3023}));
3024
3025/*!
3026 * Tap listener v2.0.0
3027 * listens to taps
3028 * MIT license
3029 */
3030
3031/*jshint browser: true, unused: true, undef: true, strict: true */
3032
3033( function( window, factory ) {
3034    // universal module definition
3035    /*jshint strict: false*/ /*globals define, module, require */
3036
3037    if ( typeof define == 'function' && define.amd ) {
3038        // AMD
3039        define( 'tap-listener/tap-listener',[
3040            'unipointer/unipointer'
3041        ], function( Unipointer ) {
3042            return factory( window, Unipointer );
3043        });
3044    } else if ( typeof module == 'object' && module.exports ) {
3045        // CommonJS
3046        module.exports = factory(
3047            window,
3048            require('unipointer')
3049        );
3050    } else {
3051        // browser global
3052        window.TapListener = factory(
3053            window,
3054            window.Unipointer
3055        );
3056    }
3057
3058}( window, function factory( window, Unipointer ) {
3059
3060
3061
3062// --------------------------  TapListener -------------------------- //
3063
3064    function TapListener( elem ) {
3065        this.bindTap( elem );
3066    }
3067
3068// inherit Unipointer & EventEmitter
3069    var proto = TapListener.prototype = Object.create( Unipointer.prototype );
3070
3071    /**
3072     * bind tap event to element
3073     * @param {Element} elem
3074     */
3075    proto.bindTap = function( elem ) {
3076        if ( !elem ) {
3077            return;
3078        }
3079        this.unbindTap();
3080        this.tapElement = elem;
3081        this._bindStartEvent( elem, true );
3082    };
3083
3084    proto.unbindTap = function() {
3085        if ( !this.tapElement ) {
3086            return;
3087        }
3088        this._bindStartEvent( this.tapElement, true );
3089        delete this.tapElement;
3090    };
3091
3092    /**
3093     * pointer up
3094     * @param {Event} event
3095     * @param {Event or Touch} pointer
3096     */
3097    proto.pointerUp = function( event, pointer ) {
3098        // ignore emulated mouse up clicks
3099        if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
3100            return;
3101        }
3102
3103        var pointerPoint = Unipointer.getPointerPoint( pointer );
3104        var boundingRect = this.tapElement.getBoundingClientRect();
3105        var scrollX = window.pageXOffset;
3106        var scrollY = window.pageYOffset;
3107        // calculate if pointer is inside tapElement
3108        var isInside = pointerPoint.x >
3108= boundingRect.left + scrollX &&
3109            pointerPoint.x <= boundingRect.right + scrollX &&
3110            pointerPoint.y >= boundingRect.top + scrollY &&
3111            pointerPoint.y <= boundingRect.bottom + scrollY;
3112        // trigger callback if pointer is inside element
3113        if ( isInside ) {
3114            this.emitEvent( 'tap', [ event, pointer ] );
3115        }
3116
3117        // set flag for emulated clicks 300ms after touchend
3118        if ( event.type != 'mouseup' ) {
3119            this.isIgnoringMouseUp = true;
3120            // reset flag after 300ms
3121            var _this = this;
3122            setTimeout( function() {
3123                delete _this.isIgnoringMouseUp;
3124            }, 400 );
3125        }
3126    };
3127
3128    proto.destroy = function() {
3129        this.pointerDone();
3130        this.unbindTap();
3131    };
3132
3133// -----  ----- //
3134
3135    return TapListener;
3136
3137}));
3138
3139// prev/next buttons
3140( function( window, factory ) {
3141    // universal module definition
3142    /* jshint strict: false */
3143    if ( typeof define == 'function' && define.amd ) {
3144        // AMD
3145        define( 'flickity/js/prev-next-button',[
3146            './flickity',
3147            'tap-listener/tap-listener',
3148            'fizzy-ui-utils/utils'
3149        ], function( Flickity, TapListener, utils ) {
3150            return factory( window, Flickity, TapListener, utils );
3151        });
3152    } else if ( typeof module == 'object' && module.exports ) {
3153        // CommonJS
3154        module.exports = factory(
3155            window,
3156            require('./flickity'),
3157            require('tap-listener'),
3158            require('fizzy-ui-utils')
3159        );
3160    } else {
3161        // browser global
3162        factory(
3163            window,
3164            window.Flickity,
3165            window.TapListener,
3166            window.fizzyUIUtils
3167        );
3168    }
3169
3170}( window, function factory( window, Flickity, TapListener, utils ) {
3171    'use strict';
3172
3173    var svgURI = 'http://www.w3.org/2000/svg';
3174
3175// -------------------------- PrevNextButton -------------------------- //
3176
3177    function PrevNextButton( direction, parent ) {
3178        this.direction = direction;
3179        this.parent = parent;
3180        this._create();
3181    }
3182
3183    PrevNextButton.prototype = Object.create( TapListener.prototype );
3184
3185    PrevNextButton.prototype._create = function() {
3186        // properties
3187        this.isEnabled = true;
3188        this.isPrevious = this.direction == -1;
3189        var leftDirection = this.parent.options.rightToLeft ? 1 : -1;
3190        this.isLeft = this.direction == leftDirection;
3191
3192        var element = this.element = document.createElement('button');
3193        element.className = 'flickity-button flickity-prev-next-button';
3194        element.className += this.isPrevious ? ' previous' : ' next';
3195        // prevent button from submitting form http://stackoverflow.com/a/10836076/182183
3196        element.setAttribute( 'type', 'button' );
3197        // init as disabled
3198        this.disable();
3199
3200        element.setAttribute( 'aria-label', this.isPrevious ? 'Previous' : 'Next' );
3201
3202        // create arrow
3203        var svg = this.createSVG();
3204        element.appendChild( svg );
3205        // events
3206        this.on( 'tap', this.onTap );
3207        this.parent.on( 'select', this.update.bind( this ) );
3208        this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) );
3209    };
3210
3211    PrevNextButton.prototype.activate = function() {
3212        this.bindTap( this.element );
3213        // click events from keyboard
3214        this.element.addEventListener( 'click', this );
3215        // add to DOM
3216        this.parent.element.appendChild( this.element );
3217    };
3218
3219    PrevNextButton.prototype.deactivate = function() {
3220        // remove from DOM
3221        this.parent.element.removeChild( this.element );
3222        // do regular TapListener destroy
3223        TapListener.prototype.destroy.call( this );
3224        // click events from keyboard
3225        this.element.removeEventListener( 'click', this );
3226    };
3227
3228    PrevNextButton.prototype.createSVG = function() {
3229        var svg = document.createElementNS( svgURI, 'svg');
3230        svg.setAttribute( 'class', 'flickity-button-icon' );
3231        svg.setAttribute( 'viewBox', '0 0 100 100' );
3232        var path = document.createElementNS( svgURI, 'path');
3233        var pathMovements = getArrowMovements( this.parent.options.arrowShape );
3234        path.setAttribute( 'd', pathMovements );
3235        path.setAttribute( 'class', 'arrow' );
3236        // rotate arrow
3237        if ( !this.isLeft ) {
3238            path.setAttribute( 'transform', 'translate(100, 100) rotate(180) ' );
3239        }
3240        svg.appendChild( path );
3241        return svg;
3242    };
3243
3244// get SVG path movmement
3245    function getArrowMovements( shape ) {
3246        // use shape as movement if string
3247        if ( typeof shape == 'string' ) {
3248            return shape;
3249        }
3250        // create movement string
3251        return 'M ' + shape.x0 + ',50' +
3252            ' L ' + shape.x1 + ',' + ( shape.y1 + 50 ) +
3253            ' L ' + shape.x2 + ',' + ( shape.y2 + 50 ) +
3254            ' L ' + shape.x3 + ',50 ' +
3255            ' L ' + shape.x2 + ',' + ( 50 - shape.y2 ) +
3256            ' L ' + shape.x1 + ',' + ( 50 - shape.y1 ) +
3257            ' Z';
3258    }
3259
3260    PrevNextButton.prototype.onTap = function() {
3261        if ( !this.isEnabled ) {
3262            return;
3263        }
3264        this.parent.uiChange();
3265        var method = this.isPrevious ? 'previous' : 'next';
3266        this.parent[ method ]();
3267    };
3268
3269    PrevNextButton.prototype.handleEvent = utils.handleEvent;
3270
3271    PrevNextButton.prototype.onclick = function( event ) {
3272        // only allow clicks from keyboard
3273        var focused = document.activeElement;
3274        if ( focused && focused == this.element ) {
3275            this.onTap( event, event );
3276        }
3277    };
3278
3279// -----  ----- //
3280
3281    PrevNextButton.prototype.enable = function() {
3282        if ( this.isEnabled ) {
3283            return;
3284        }
3285        this.element.disabled = false;
3286        this.isEnabled = true;
3287    };
3288
3289    PrevNextButton.prototype.disable = function() {
3290        if ( !this.isEnabled ) {
3291            return;
3292        }
3293        this.element.disabled = true;
3294        this.isEnabled = false;
3295    };
3296
3297    PrevNextButton.prototype.update = function() {
3298        // index of first or last slide, if previous or next
3299        var slides = this.parent.slides;
3300        // enable is wrapAround and at least 2 slides
3301        if ( this.parent.options.wrapAround && slides.length > 1 ) {
3302            this.enable();
3303            return;
3304        }
3305        var lastIndex = slides.length ? slides.length - 1 : 0;
3306        var boundIndex = this.isPrevious ? 0 : lastIndex;
3307        var method = this.parent.selectedIndex == boundIndex ? 'disable' : 'enable';
3308        this[ method ]();
3309    };
3310
3311    PrevNextButton.prototype.destroy = function() {
3312        this.deactivate();
3313    };
3314
3315// -------------------------- Flickity prototype -------------------------- //
3316
3317    utils.extend( Flickity.defaults, {
3318        prevNextButtons: true,
3319        arrowShape: {
3320            x0: 10,
3321            x1: 60, y1: 50,
3322            x2: 70, y2: 40,
3323            x3: 30
3324        }
3325    });
3326
3327    Flickity.createMethods.push('_createPrevNextButtons');
3328    var proto = Flickity.prototype;
3329
3330    proto._createPrevNextButtons = function() {
3331        if ( !this.options.prevNextButtons ) {
3332            return;
3333        }
3334
3335        this.prevButton = new PrevNextButton( -1, this );
3336        this.nextButton = new PrevNextButton( 1, this );
3337
3338        this.on( 'activate', this.activatePrevNextButtons );
3339    };
3340
3341    proto.activatePrevNextButtons = function() {
3342        this.prevButton.activate();
3343        this.nextButton.activate();
3344        this.on( 'deactivate', this.deactivatePrevNextButtons );
3345    };
3346
3347    proto.deactivatePrevNextButtons = function() {
3348        this.prevButton.deactivate();
3349        this.nextButton.deactivate();
3350        this.off( 'deactivate', this.deactivatePrevNextButtons );
3351    };
3352
3353// --------------------------  -------------------------- //
3354
3355    Flickity.PrevNextButton = PrevNextButton;
3356
3357    return Flickity;
3358
3359}));
3360
3361// page dots
3362( function( window, factory ) {
3363    // universal module definition
3364    /* jshint strict: false */
3365    if ( typeof define == 'function' && define.amd ) {
3366        // AMD
3367        define( 'flickity/js/page-dots',[
3368            './flickity',
3369            'tap-listener/tap-listener',
3370            'fizzy-ui-utils/utils'
3371        ], function( Flickity, TapListener, utils ) {
3372            return factory( window, Flickity, TapListener, utils );
3373        });
3374    } else if ( typeof module == 'object' && module.exports ) {
3375        // CommonJS
3376        module.exports = factory(
3377            window,
3378            require('./flickity'),
3379            require('tap-listener'),
3380            require('fizzy-ui-utils')
3381        );
3382    } else {
3383        // browser global
3384        factory(
3385            window,
3386            window.Flickity,
3387            window.TapListener,
3388            window.fizzyUIUtils
3389        );
3390    }
3391
3392}( window, function factory( window, Flickity, TapListener, utils ) {
3393
3394// -------------------------- PageDots -------------------------- //
3395
3396
3397
3398    function PageDots( parent ) {
3399        this.parent = parent;
3400        this._create();
3401    }
3402
3403    PageDots.prototype = new TapListener();
3404
3405    PageDots.prototype._create = function() {
3406        // create holder element
3407        this.holder = document.createElement('ol');
3408        this.holder.className = 'flickity-page-dots';
3409        // create dots, array of elements
3410        this.dots = [];
3411        // events
3412        this.on( 'tap', this.onTap );
3413        this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) );
3414    };
3415
3416    PageDots.prototype.activate = function() {
3417        this.setDots();
3418        this.bindTap( this.holder );
3419        // add to DOM
3420        this.parent.element.appendChild( this.holder );
3421    };
3422
3423    PageDots.prototype.deactivate = function() {
3424        // remove from DOM
3425        this.parent.element.removeChild( this.holder );
3426        TapListener.prototype.destroy.call( this );
3427    };
3428
3429    PageDots.prototype.setDots = function() {
3430        // get difference between number of slides and number of dots
3431        var delta = this.parent.slides.length - this.dots.length;
3432        if ( delta > 0 ) {
3433            this.addDots( delta );
3434        } else if ( delta < 0 ) {
3435            this.removeDots( -delta );
3436        }
3437    };
3438
3439    PageDots.prototype.addDots = function( count ) {
3440        var fragment = document.createDocumentFragment();
3441        var newDots = [];
3442        var length = this.dots.length;
3443        var max = length + count;
3444
3445        for ( var i = length; i < max; i++ ) {
3446            var dot = document.createElement('li');
3447            dot.className = 'dot';
3448            dot.setAttribute( 'aria-label', 'Page dot ' + ( i + 1 ) );
3449            fragment.appendChild( dot );
3450            newDots.push( dot );
3451        }
3452
3453        this.holder.appendChild( fragment );
3454        this.dots = this.dots.concat( newDots );
3455    };
3456
3457    PageDots.prototype.removeDots = function( count ) {
3458        // remove from this.dots collection
3459        var removeDots = this.dots.splice( this.dots.length - count, count );
3460        // remove from DOM
3461        removeDots.forEach( function( dot ) {
3462            this.holder.removeChild( dot );
3463        }, this );
3464    };
3465
3466    PageDots.prototype.updateSelected = function() {
3467        // remove selected class on previous
3468        if ( this.selectedDot ) {
3469            this.selectedDot.className = 'dot';
3470            this.selectedDot.removeAttribute('aria-current');
3471        }
3472        // don't proceed if no dots
3473        if ( !this.dots.length ) {
3474            return;
3475        }
3476        this.selectedDot = this.dots[ this.parent.selectedIndex ];
3477        this.selectedDot.className = 'dot is-selected';
3478        this.selectedDot.setAttribute( 'aria-current', 'step' );
3479    };
3480
3481    PageDots.prototype.onTap = function( event ) {
3482        var target = event.target;
3483        // only care about dot clicks
3484        if ( target.nodeName != 'LI' ) {
3485            return;
3486        }
3487
3488        this.parent.uiChange();
3489        var index = this.dots.indexOf( target );
3490        this.parent.select( index );
3491    };
3492
3493    PageDots.prototype.destroy = function() {
3494        this.deactivate();
3495    };
3496
3497    Flickity.PageDots = PageDots;
3498
3499// -------------------------- Flickity -------------------------- //
3500
3501    utils.extend( Flickity.defaults, {
3502        pageDots: true
3503    });
3504
3505    Flickity.createMethods.push('_createPageDots');
3506
3507    var proto = Flickity.prototype;
3508
3509    proto._createPageDots = function() {
3510        if ( !this.options.pageDots ) {
3511            return;
3512        }
3513        this.pageDots = new PageDots( this );
3514        // events
3515        this.on( 'activate', this.activatePageDots );
3516        this.on( 'select', this.updateSelectedPageDots );
3517        this.on( 'cellChange', this.updatePageDots );
3518        this.on( 'resize', this.updatePageDots );
3519        this.on( 'deactivate', this.deactivatePageDots );
3520    };
3521
3522    proto.activatePageDots = function() {
3523        this.pageDots.activate();
3524    };
3525
3526    proto.updateSelectedPageDots = function() {
3527        this.pageDots.updateSelected();
3528    };
3529
3530    proto.updatePageDots = function() {
3531        this.pageDots.setDots();
3532    };
3533
3534    proto.deactivatePageDots = function() {
3535        this.pageDots.deactivate();
3536    };
3537
3538// -----  ----- //
3539
3540    Flickity.PageDots = PageDots;
3541
3542    return Flickity;
3543
3544}));
3545
3546// player & autoPlay
3547( function( window, factory ) {
3548    // universal module definition
3549    /* jshint strict: false */
3550    if ( typeof define == 'function' && define.amd ) {
3551        // AMD
3552        define( 'flickity/js/player',[
3553            'ev-emitter/ev-emitter',
3554            'fizzy-ui-utils/utils',
3555            './flickity'
3556        ], function( EvEmitter, utils, Flickity ) {
3557            return factory( EvEmitter, utils, Flickity );
3558        });
3559    } else if ( typeof module == 'object' && module.exports ) {
3560        // CommonJS
3561        module.exports = factory(
3562            require('ev-emitter'),
3563            require('fizzy-ui-utils'),
3564            require('./flickity')
3565        );
3566    } else {
3567        // browser global
3568        factory(
3569            window.EvEmitter,
3570            window.fizzyUIUtils,
3571            window.Flickity
3572        );
3573    }
3574
3575}( window, function factory( EvEmitter, utils, Flickity ) {
3576
3577
3578
3579// -------------------------- Player -------------------------- //
3580
3581    function Player( parent ) {
3582        this.parent = parent;
3583        this.state = 'stopped';
3584        // visibility change event handler
3585        this.onVisibilityChange = this.visibilityChange.bind( this );
3586        this.onVisibilityPlay = this.visibilityPlay.bind( this );
3587    }
3588
3589    Player.prototype = Object.create( EvEmitter.prototype );
3590
3591// start play
3592    Player.prototype.play = function() {
3593        if ( this.state == 'playing' ) {
3594            return;
3595        }
3596        // do not play if page is hidden, start playing when page is visible
3597        var isPageHidden = document.hidden;
3598        if ( isPageHidden ) {
3599            document.addEventListener( 'visibilitychange', this.onVisibilityPlay );
3600            return;
3601        }
3602
3603        this.state = 'playing';
3604        // listen to visibility change
3605        document.addEventListener( 'visibilitychange', this.onVisibilityChange );
3606        // start ticking
3607        this.tick();
3608    };
3609
3610    Player.prototype.tick = function() {
3611        // do not tick if not playing
3612        if ( this.state != 'playing' ) {
3613            return;
3614        }
3615
3616        var time = this.parent.options.autoPlay;
3617        // default to 3 seconds
3618        time = typeof time == 'number' ? time : 3000;
3619        var _this = this;
3620        // HACK: reset ticks if stopped and started within interval
3621        this.clear();
3622        this.timeout = setTimeout( function() {
3623            _this.parent.next( true );
3624            _this.tick();
3625        }, time );
3626    };
3627
3628    Player.prototype.stop = function() {
3629        this.state = 'stopped';
3630        this.clear();
3631        // remove visibility change event
3632        document.removeEventListener( 'visibilitychange', this.onVisibilityChange );
3633    };
3634
3635    Player.prototype.clear = function() {
3636        clearTimeout( this.timeout );
3637    };
3638
3639    Player.prototype.pause = function() {
3640        if ( this.state == 'playing' ) {
3641            this.state = 'paused';
3642            this.clear();
3643        }
3644    };
3645
3646    Player.prototype.unpause = function() {
3647        // re-start play if paused
3648        if ( this.state == 'paused' ) {
3649            this.play();
3650        }
3651    };
3652
3653// pause if page visibility is hidden, unpause if visible
3654    Player.prototype.visibilityChange = function() {
3655        var isPageHidden = document.hidden;
3656        this[ isPageHidden ? 'pause' : 'unpause' ]();
3657    };
3658
3659    Player.prototype.visibilityPlay = function() {
3660        this.play();
3661        document.removeEventListener( 'visibilitychange', this.onVisibilityPlay );
3662    };
3663
3664// -------------------------- Flickity -------------------------- //
3665
3666    utils.extend( Flickity.defaults, {
3667        pauseAutoPlayOnHover: true
3668    });
3669
3670    Flickity.createMethods.push('_createPlayer');
3671    var proto = Flickity.prototype;
3672
3673    proto._createPlayer = function() {
3674        this.player = new Player( this );
3675
3676        this.on( 'activate', this.activatePlayer );
3677        this.on( 'uiChange', this.stopPlayer );
3678        this.on( 'pointerDown', this.stopPlayer );
3679        this.on( 'deactivate', this.deactivatePlayer );
3680    };
3681
3682    proto.activatePlayer = function() {
3683        if ( !this.options.autoPlay ) {
3684            return;
3685        }
3686        this.player.play();
3687        this.element.addEventListener( 'mouseenter', this );
3688    };
3689
3690// Player API, don't hate the ... thanks I know where the door is
3691
3692    proto.playPlayer = function() {
3693        this.player.play();
3694    };
3695
3696    proto.stopPlayer = function() {
3697        this.player.stop();
3698    };
3699
3700    proto.pausePlayer = function() {
3701        this.player.pause();
3702    };
3703
3704    proto.unpausePlayer = function() {
3705        this.player.unpause();
3706    };
3707
3708    proto.deactivatePlayer = function() {
3709        this.player.stop();
3710        this.element.removeEventListener( 'mouseenter', this );
3711    };
3712
3713// ----- mouseenter/leave ----- //
3714
3715// pause auto-play on hover
3716    proto.onmouseenter = function() {
3717        if ( !this.options.pauseAutoPlayOnHover ) {
3718            return;
3719        }
3720        this.player.pause();
3721        this.element.addEventListener( 'mouseleave', this );
3722    };
3723
3724// resume auto-play on hover off
3725    proto.onmouseleave = function() {
3726        this.player.unpause();
3727        this.element.removeEventListener( 'mouseleave', this );
3728    };
3729
3730// -----  ----- //
3731
3732    Flickity.Player = Player;
3733
3734    return Flickity;
3735
3736}));
3737
3738// add, remove cell
3739( function( window, factory ) {
3740    // universal module definition
3741    /* jshint strict: false */
3742    if ( typeof define == 'function' && define.amd ) {
3743        // AMD
3744        define( 'flickity/js/add-remove-cell',[
3745            './flickity',
3746            'fizzy-ui-utils/utils'
3747        ], function( Flickity, utils ) {
3748            return factory( window, Flickity, utils );
3749        });
3750    } else if ( typeof module == 'object' && module.exports ) {
3751        // CommonJS
3752        module.exports = factory(
3753            window,
3754            require('./flickity'),
3755            require('fizzy-ui-utils')
3756        );
3757    } else {
3758        // browser global
3759        factory(
3760            window,
3761            window.Flickity,
3762            window.fizzyUIUtils
3763        );
3764    }
3765
3766}( window, function factory( window, Flickity, utils ) {
3767
3768
3769
3770// append cells to a document fragment
3771    function getCellsFragment( cells ) {
3772        var fragment = document.createDocumentFragment();
3773        cells.forEach( function( cell ) {
3774            fragment.appendChild( cell.element );
3775        });
3776        return fragment;
3777    }
3778
3779// -------------------------- add/remove cell prototype -------------------------- //
3780
3781    var proto = Flickity.prototype;
3782
3783    /**
3784     * Insert, prepend, or append cells
3785     * @param {Element, Array, NodeList} elems
3786     * @param {Integer} index
3787     */
3788    proto.insert = function( elems, index ) {
3789        var cells = this._makeCells( elems );
3790        if ( !cells || !cells.length ) {
3791            return;
3792        }
3793        var len = this.cells.length;
3794        // default to append
3795        index = index === undefined ? len : index;
3796        // add cells with document fragment
3797        var fragment = getCellsFragment( cells );
3798        // append to slider
3799        var isAppend = index == len;
3800        if ( isAppend ) {
3801            this.slider.appendChild( fragment );
3802        } else {
3803            var insertCellElement = this.cells[ index ].element;
3804            this.slider.insertBefore( fragment, insertCellElement );
3805        }
3806        // add to this.cells
3807        if ( index === 0 ) {
3808            // prepend, add to start
3809            this.cells = cells.concat( this.cells );
3810        } else if ( isAppend ) {
3811            // append, add to end
3812            this.cells = this.cells.concat( cells );
3813        } else {
3814            // insert in this.cells
3815            var endCells = this.cells.splice( index, len - index );
3816            this.cells = this.cells.concat( cells ).concat( endCells );
3817        }
3818
3819        this._sizeCells( cells );
3820        this.cellChange( index, true );
3821    };
3822
3823    proto.append = function( elems ) {
3824        this.insert( elems, this.cells.length );
3825    };
3826
3827    proto.prepend = function( elems ) {
3828        this.insert( elems, 0 );
3829    };
3830
3831    /**
3832     * Remove cells
3833     * @param {Element, Array, NodeList} elems
3834     */
3835    proto.remove = function( elems ) {
3836        var cells = this.getCells( elems );
3837        if ( !cells || !cells.length ) {
3838            return;
3839        }
3840
3841        var minCellIndex = this.cells.length - 1;
3842        // remove cells from collection & DOM
3843        cells.forEach( function( cell ) {
3844            cell.remove();
3845            var index = this.cells.indexOf( cell );
3846            minCellIndex = Math.min( index, minCellIndex );
3847            utils.removeFrom( this.cells, cell );
3848        }, this );
3849
3850        this.cellChange( minCellIndex, true );
3851    };
3852
3853    /**
3854     * logic to be run after a cell's size changes
3855     * @param {Element} elem - cell's element
3856     */
3857    proto.cellSizeChange = function( elem ) {
3858        var cell = this.getCell( elem );
3859        if ( !cell ) {
3860            return;
3861        }
3862        cell.getSize();
3863
3864        var index = this.cells.indexOf( cell );
3865        this.cellChange( index );
3866    };
3867
3868    /**
3869     * logic any time a cell is changed: added, removed, or size changed
3870     * @param {Integer} changedCellIndex - index of the changed cell, optional
3871     */
3872    proto.cellChange = function( changedCellIndex, isPositioningSlider ) {
3873        var prevSelectedElem = this.selectedElement;
3874        this._positionCells( changedCellIndex );
3875        this._getWrapShiftCells();
3876        this.setGallerySize();
3877        // update selectedIndex
3878        // try to maintain position & select previous selected element
3879        var cell = this.getCell( prevSelectedElem );
3880        if ( cell ) {
3881            this.selectedIndex = this.getCellSlideIndex( cell );
3882        }
3883        this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex );
3884
3885        this.emitEvent( 'cellChange', [ changedCellIndex ] );
3886        // position slider
3887        this.select( this.selectedIndex );
3888        // do not position slider after lazy load
3889        if ( isPositioningSlider ) {
3890            this.positionSliderAtSelected();
3891        }
3892    };
3893
3894// -----  ----- //
3895
3896    return Flickity;
3897
3898}));
3899
3900// lazyload
3901( function( window, factory ) {
3902    // universal module definition
3903    /* jshint strict: false */
3904    if ( typeof define == 'function' && define.amd ) {
3905        // AMD
3906        define( 'flickity/js/lazyload',[
3907            './flickity',
3908            'fizzy-ui-utils/utils'
3909        ], function( Flickity, utils ) {
3910            return factory( window, Flickity, utils );
3911        });
3912    } else if ( typeof module == 'object' && module.exports ) {
3913        // CommonJS
3914        module.exports = factory(
3915            window,
3916            require('./flickity'),
3917            require('fizzy-ui-utils')
3918        );
3919    } else {
3920        // browser global
3921        factory(
3922            window,
3923            window.Flickity,
3924            window.fizzyUIUtils
3925        );
3926    }
3927
3928}( window, function factory( window, Flickity, utils ) {
3929    'use strict';
3930
3931    Flickity.createMethods.push('_createLazyload');
3932    var proto = Flickity.prototype;
3933
3934    proto._createLazyload = function() {
3935        this.on( 'select', this.lazyLoad );
3936    };
3937
3938    proto.lazyLoad = function() {
3939        var lazyLoad = this.options.lazyLoad;
3940        if ( !lazyLoad ) {
3941            return;
3942        }
3943        // get adjacent cells, use lazyLoad option for adjacent count
3944        var adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0;
3945        var cellElems = this.getAdjacentCellElements( adjCount );
3946        // get lazy images in those cells
3947        var lazyImages = [];
3948        cellElems.forEach( function( cellElem ) {
3949            var lazyCellImages = getCellLazyImages( cellElem );
3950            lazyImages = lazyImages.concat( lazyCellImages );
3951        });
3952        // load lazy images
3953        lazyImages.forEach( function( img ) {
3954            new LazyLoader( img, this );
3955        }, this );
3956    };
3957
3958    function getCellLazyImages( cellElem ) {
3959        // check if cell element is lazy image
3960        if ( cellElem.nodeName == 'IMG' ) {
3961            var lazyloadAttr = cellElem.getAttribute('data-flickity-lazyload');
3962            var srcAttr = cellElem.getAttribute('data-flickity-lazyload-src');
3963            var srcsetAttr = cellElem.getAttribute('data-flickity-lazyload-srcset');
3964            if ( lazyloadAttr || srcAttr || srcsetAttr ) {
3965                return [ cellElem ];
3966            }
3967        }
3968        // select lazy images in cell
3969        var lazySelector = 'img[data-flickity-lazyload], ' +
3970            'img[data-flickity-lazyload-src], img[data-flickity-lazyload-srcset]';
3971        var imgs = cellElem.querySelectorAll( lazySelector );
3972        return utils.makeArray( imgs );
3973    }
3974
3975// -------------------------- LazyLoader -------------------------- //
3976
3977    /**
3978     * class to handle loading images
3979     */
3980    function LazyLoader( img, flickity ) {
3981        this.img = img;
3982        this.flickity = flickity;
3983        this.load();
3984    }
3985
3986    LazyLoader.prototype.handleEvent = utils.handleEvent;
3987
3988    LazyLoader.prototype.load = function() {
3989        this.img.addEventListener( 'load', this );
3990        this.img.addEventListener( 'error', this );
3991        // get src & srcset
3992        var src = this.img.getAttribute('data-flickity-lazyload') ||
3993            this.img.getAttribute('data-flickity-lazyload-src');
3994        var srcset = this.img.getAttribute('data-flickity-lazyload-srcset');
3995        // set src & serset
3996        this.img.src = src;
3997        if ( srcset ) {
3998            this.img.setAttribute( 'srcset', srcset );
3999        }
4000        // remove attr
4001        this.img.removeAttribute('data-flickity-lazyload');
4002        this.img.removeAttribute('data-flickity-lazyload-src');
4003        this.img.removeAttribute('data-flickity-lazyload-srcset');
4004    };
4005
4006    LazyLoader.prototype.onload = function( event ) {
4007        this.complete( event, 'flickity-lazyloaded' );
4008    };
4009
4010    LazyLoader.prototype.onerror = function( event ) {
4011        this.complete( event, 'flickity-lazyerror' );
4012    };
4013
4014    LazyLoader.prototype.complete = function( event, className ) {
4015        // unbind events
4016        this.img.removeEventListener( 'load', this );
4017        this.img.removeEventListener( 'error', this );
4018
4019        var cell = this.flickity.getParentCell( this.img );
4020        var cellElem = cell && cell.element;
4021        this.flickity.cellSizeChange( cellElem );
4022
4023        this.img.classList.add( className );
4024        this.flickity.dispatchEvent( 'lazyLoad', event, cellElem );
4025    };
4026
4027// -----  ----- //
4028
4029    Flickity.LazyLoader = LazyLoader;
4030
4031    return Flickity;
4032
4033}));
4034
4035/*!
4036 * Flickity v2.1.2
4037 * Touch, responsive, flickable carousels
4038 *
4039 * Licensed GPLv3 for open source use
4040 * or Flickity Commercial License for commercial use
4041 *
4042 * https://flickity.metafizzy.co
4043 * Copyright 2015-2018 Metafizzy
4044 */
4045
4046( function( window, factory ) {
4047    // universal module definition
4048    /* jshint strict: false */
4049    if ( typeof define == 'function' && define.amd ) {
4050        // AMD
4051        define( 'flickity/js/index',[
4052            './flickity',
4053            './drag',
4054            './prev-next-button',
4055            './page-dots',
4056            './player',
4057            './add-remove-cell',
4058            './lazyload'
4059        ], factory );
4060    } else if ( typeof module == 'object' && module.exports ) {
4061        // CommonJS
4062        module.exports = factory(
4063            require('./flickity'),
4064            require('./drag'),
4065            require('./prev-next-button'),
4066            require('./page-dots'),
4067            require('./player'),
4068            require('./add-remove-cell'),
4069            require('./lazyload')
4070        );
4071    }
4072
4073})( window, function factory( Flickity ) {
4074    /*jshint strict: false*/
4075    return Flickity;
4076});
4077
4078/*!
4079 * Flickity asNavFor v2.0.1
4080 * enable asNavFor for Flickity
4081 */
4082
4083/*jshint browser: true, undef: true, unused: true, strict: true*/
4084
4085( function( window, factory ) {
4086    // universal module definition
4087    /*jshint strict: false */ /*globals define, module, require */
4088    if ( typeof define == 'function' && define.amd ) {
4089        // AMD
4090        define( 'flickity-as-nav-for/as-nav-for',[
4091            'flickity/js/index',
4092            'fizzy-ui-utils/utils'
4093        ], factory );
4094    } else if ( typeof module == 'object' && module.exports ) {
4095        // CommonJS
4096        module.exports = factory(
4097            require('flickity'),
4098            require('fizzy-ui-utils')
4099        );
4100    } else {
4101        // browser global
4102        window.Flickity = factory(
4103            window.Flickity,
4104            window.fizzyUIUtils
4105        );
4106    }
4107
4108}( window, function factory( Flickity, utils ) {
4109
4110
4111
4112// -------------------------- asNavFor prototype -------------------------- //
4113
4114// Flickity.defaults.asNavFor = null;
4115
4116    Flickity.createMethods.push('_createAsNavFor');
4117
4118    var proto = Flickity.prototype;
4119
4120    proto._createAsNavFor = function() {
4121        this.on( 'activate', this.activateAsNavFor );
4122        this.on( 'deactivate', this.deactivateAsNavFor );
4123        this.on( 'destroy', this.destroyAsNavFor );
4124
4125        var asNavForOption = this.options.asNavFor;
4126        if ( !asNavForOption ) {
4127            return;
4128        }
4129        // HACK do async, give time for other flickity to be initalized
4130        var _this = this;
4131        setTimeout( function initNavCompanion() {
4132            _this.setNavCompanion( asNavForOption );
4133        });
4134    };
4135
4136    proto.setNavCompanion = function( elem ) {
4137        elem = utils.getQueryElement( elem );
4138        var companion = Flickity.data( elem );
4139        // stop if no companion or companion is self
4140        if ( !companion || companion == this ) {
4141            return;
4142        }
4143
4144        this.navCompanion = companion;
4145        // companion select
4146        var _this = this;
4147        this.onNavCompanionSelect = function() {
4148            _this.navCompanionSelect();
4149        };
4150        companion.on( 'select', this.onNavCompanionSelect );
4151        // click
4152        this.on( 'staticClick', this.onNavStaticClick );
4153
4154        this.navCompanionSelect( true );
4155    };
4156
4157    proto.navCompanionSelect = function( isInstant ) {
4158        if ( !this.navCompanion ) {
4159            return;
4160        }
4161        // select slide that matches first cell of slide
4162        var selectedCell = this.navCompanion.selectedCells[0];
4163        var firstIndex = this.navCompanion.cells.indexOf( selectedCell );
4164        var lastIndex = firstIndex + this.navCompanion.selectedCells.length - 1;
4165        var selectIndex = Math.floor( lerp( firstIndex, lastIndex,
4166            this.navCompanion.cellAlign ) );
4167        this.selectCell( selectIndex, false, isInstant );
4168        // set nav selected class
4169        this.removeNavSelectedElements();
vendor: 5,586 bytes, lines 4170-4355
4170        // stop if companion has more cells than this one
4171        if ( selectIndex >= this.cells.length ) {
4172            return;
4173        }
4174
4175        var selectedCells = this.cells.slice( firstIndex, lastIndex + 1 );
4176        this.navSelectedElements = selectedCells.map( function( cell ) {
4177            return cell.element;
4178        });
4179        this.changeNavSelectedClass('add');
4180    };
4181
4182    function lerp( a, b, t ) {
4183        return ( b - a ) * t + a;
4184    }
4185
4186    proto.changeNavSelectedClass = function( method ) {
4187        this.navSelectedElements.forEach( function( navElem ) {
4188            navElem.classList[ method ]('is-nav-selected');
4189        });
4190    };
4191
4192    proto.activateAsNavFor = function() {
4193        this.navCompanionSelect( true );
4194    };
4195
4196    proto.removeNavSelectedElements = function() {
4197        if ( !this.navSelectedElements ) {
4198            return;
4199        }
4200        this.changeNavSelectedClass('remove');
4201        delete this.navSelectedElements;
4202    };
4203
4204    proto.onNavStaticClick = function( event, pointer, cellElement, cellIndex ) {
4205        if ( typeof cellIndex == 'number' ) {
4206            this.navCompanion.selectCell( cellIndex );
4207        }
4208    };
4209
4210    proto.deactivateAsNavFor = function() {
4211        this.removeNavSelectedElements();
4212    };
4213
4214    proto.destroyAsNavFor = function() {
4215        if ( !this.navCompanion ) {
4216            return;
4217        }
4218        this.navCompanion.off( 'select', this.onNavCompanionSelect );
4219        this.off( 'staticClick', this.onNavStaticClick );
4220        delete this.navCompanion;
4221    };
4222
4223// -----  ----- //
4224
4225    return Flickity;
4226
4227}));
4228
4229/*!
4230 * imagesLoaded v4.1.4
4231 * JavaScript is all like "You images are done yet or what?"
4232 * MIT License
4233 */
4234
4235( function( window, factory ) { 'use strict';
4236    // universal module definition
4237
4238    /*global define: false, module: false, require: false */
4239
4240    if ( typeof define == 'function' && define.amd ) {
4241        // AMD
4242        define( 'imagesloaded/imagesloaded',[
4243            'ev-emitter/ev-emitter'
4244        ], function( EvEmitter ) {
4245            return factory( window, EvEmitter );
4246        });
4247    } else if ( typeof module == 'object' && module.exports ) {
4248        // CommonJS
4249        module.exports = factory(
4250            window,
4251            require('ev-emitter')
4252        );
4253    } else {
4254        // browser global
4255        window.imagesLoaded = factory(
4256            window,
4257            window.EvEmitter
4258        );
4259    }
4260
4261})( typeof window !== 'undefined' ? window : this,
4262
4263// --------------------------  factory -------------------------- //
4264
4265    function factory( window, EvEmitter ) {
4266
4267
4268
4269        var $ = window.jQuery;
4270        var console = window.console;
4271
4272// -------------------------- helpers -------------------------- //
4273
4274// extend objects
4275        function extend( a, b ) {
4276            for ( var prop in b ) {
4277                a[ prop ] = b[ prop ];
4278            }
4279            return a;
4280        }
4281
4282        var arraySlice = Array.prototype.slice;
4283
4284// turn element or nodeList into an array
4285        function makeArray( obj ) {
4286            if ( Array.isArray( obj ) ) {
4287                // use object if already an array
4288                return obj;
4289            }
4290
4291            var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
4292            if ( isArrayLike ) {
4293                // convert nodeList to array
4294                return arraySlice.call( obj );
4295            }
4296
4297            // array of single index
4298            return [ obj ];
4299        }
4300
4301// -------------------------- imagesLoaded -------------------------- //
4302
4303        /**
4304         * @param {Array, Element, NodeList, String} elem
4305         * @param {Object or Function} options - if function, use as callback
4306         * @param {Function} onAlways - callback function
4307         */
4308        function ImagesLoaded( elem, options, onAlways ) {
4309            // coerce ImagesLoaded() without new, to be new ImagesLoaded()
4310            if ( !( this instanceof ImagesLoaded ) ) {
4311                return new ImagesLoaded( elem, options, onAlways );
4312            }
4313            // use elem as selector string
4314            var queryElem = elem;
4315            if ( typeof elem == 'string' ) {
4316                queryElem = document.querySelectorAll( elem );
4317            }
4318            // bail if bad element
4319            if ( !queryElem ) {
4320                console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) );
4321                return;
4322            }
4323
4324            this.elements = makeArray( queryElem );
4325            this.options = extend( {}, this.options );
4326            // shift arguments if no options set
4327            if ( typeof options == 'function' ) {
4328                onAlways = options;
4329            } else {
4330                extend( this.options, options );
4331            }
4332
4333            if ( onAlways ) {
4334                this.on( 'always', onAlways );
4335            }
4336
4337            this.getImages();
4338
4339            if ( $ ) {
4340                // add jQuery Deferred object
4341                this.jqDeferred = new $.Deferred();
4342            }
4343
4344            // HACK check async to allow time to bind listeners
4345            setTimeout( this.check.bind( this ) );
4346        }
4347
4348        ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
4349
4350        ImagesLoaded.prototype.options = {};
4351
4352        ImagesLoaded.prototype.getImages = function() {
4353            this.images = [];
4354
4355            // filter & find items if we have an item selector
vendor: 4,890 bytes, lines 4356-4491
4356            this.elements.forEach( this.addElementImages, this );
4357        };
4358
4359        /**
4360         * @param {Node} element
4361         */
4362        ImagesLoaded.prototype.addElementImages = function( elem ) {
4363            // filter siblings
4364            if ( elem.nodeName == 'IMG' ) {
4365                this.addImage( elem );
4366            }
4367            // get background image on element
4368            if ( this.options.background === true ) {
4369                this.addElementBackgroundImages( elem );
4370            }
4371
4372            // find children
4373            // no non-element nodes, #143
4374            var nodeType = elem.nodeType;
4375            if ( !nodeType || !elementNodeTypes[ nodeType ] ) {
4376                return;
4377            }
4378            var childImgs = elem.querySelectorAll('img');
4379            // concat childElems to filterFound array
4380            for ( var i=0; i < childImgs.length; i++ ) {
4381                var img = childImgs[i];
4382                this.addImage( img );
4383            }
4384
4385            // get child background images
4386            if ( typeof this.options.background == 'string' ) {
4387                var children = elem.querySelectorAll( this.options.background );
4388                for ( i=0; i < children.length; i++ ) {
4389                    var child = children[i];
4390                    this.addElementBackgroundImages( child );
4391                }
4392            }
4393        };
4394
4395        var elementNodeTypes = {
4396            1: true,
4397            9: true,
4398            11: true
4399        };
4400
4401        ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
4402            var style = getComputedStyle( elem );
4403            if ( !style ) {
4404                // Firefox returns null if in a hidden iframe https://bugzil.la/548397
4405                return;
4406            }
4407            // get url inside url("...")
4408            var reURL = /url\((['"])?(.*?)\1\)/gi;
4409            var matches = reURL.exec( style.backgroundImage );
4410            while ( matches !== null ) {
4411                var url = matches && matches[2];
4412                if ( url ) {
4413                    this.addBackground( url, elem );
4414                }
4415                matches = reURL.exec( style.backgroundImage );
4416            }
4417        };
4418
4419        /**
4420         * @param {Image} img
4421         */
4422        ImagesLoaded.prototype.addImage = function( img ) {
4423            var loadingImage = new LoadingImage( img );
4424            this.images.push( loadingImage );
4425        };
4426
4427        ImagesLoaded.prototype.addBackground = function( url, elem ) {
4428            var background = new Background( url, elem );
4429            this.images.push( background );
4430        };
4431
4432        ImagesLoaded.prototype.check = function() {
4433            var _this = this;
4434            this.progressedCount = 0;
4435            this.hasAnyBroken = false;
4436            // complete if no images
4437            if ( !this.images.length ) {
4438                this.complete();
4439                return;
4440            }
4441
4442            function onProgress( image, elem, message ) {
4443                // HACK - Chrome triggers event before object properties have changed. #83
4444                setTimeout( function() {
4445                    _this.progress( image, elem, message );
4446                });
4447            }
4448
4449            this.images.forEach( function( loadingImage ) {
4450                loadingImage.once( 'progress', onProgress );
4451                loadingImage.check();
4452            });
4453        };
4454
4455        ImagesLoaded.prototype.progress = function( image, elem, message ) {
4456            this.progressedCount++;
4457            this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
4458            // progress event
4459            this.emitEvent( 'progress', [ this, image, elem ] );
4460            if ( this.jqDeferred && this.jqDeferred.notify ) {
4461                this.jqDeferred.notify( this, image );
4462            }
4463            // check if completed
4464            if ( this.progressedCount == this.images.length ) {
4465                this.complete();
4466            }
4467
4468            if ( this.options.debug && console ) {
4469                console.log( 'progress: ' + message, image, elem );
4470            }
4471        };
4472
4473        ImagesLoaded.prototype.complete = function() {
4474            var eventName = this.hasAnyBroken ? 'fail' : 'done';
4475            this.isComplete = true;
4476            this.emitEvent( eventName, [ this ] );
4477            this.emitEvent( 'always', [ this ] );
4478            if ( this.jqDeferred ) {
4479                var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
4480                this.jqDeferred[ jqMethod ]( this );
4481            }
4482        };
4483
4484// --------------------------  -------------------------- //
4485
4486        function LoadingImage( img ) {
4487            this.img = img;
4488        }
4489
4490        LoadingImage.prototype = Object.create( EvEmitter.prototype );
4491
vendor: 4,307 bytes, lines 4492-4605
4492        LoadingImage.prototype.check = function() {
4493            // If complete is true and browser supports natural sizes,
4494            // try to check for image status manually.
4495            var isComplete = this.getIsImageComplete();
4496            if ( isComplete ) {
4497                // report based on naturalWidth
4498                this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
4499                return;
4500            }
4501
4502            // If none of the checks above matched, simulate loading on detached element.
4503            this.proxyImage = new Image();
4504            this.proxyImage.addEventListener( 'load', this );
4505            this.proxyImage.addEventListener( 'error', this );
4506            // bind to image as well for Firefox. #191
4507            this.img.addEventListener( 'load', this );
4508            this.img.addEventListener( 'error', this );
4509            this.proxyImage.src = this.img.src;
4510        };
4511
4512        LoadingImage.prototype.getIsImageComplete = function() {
4513            // check for non-zero, non-undefined naturalWidth
4514            // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
4515            return this.img.complete && this.img.naturalWidth;
4516        };
4517
4518        LoadingImage.prototype.confirm = function( isLoaded, message ) {
4519            this.isLoaded = isLoaded;
4520            this.emitEvent( 'progress', [ this, this.img, message ] );
4521        };
4522
4523// ----- events ----- //
4524
4525// trigger specified handler for event type
4526        LoadingImage.prototype.handleEvent = function( event ) {
4527            var method = 'on' + event.type;
4528            if ( this[ method ] ) {
4529                this[ method ]( event );
4530            }
4531        };
4532
4533        LoadingImage.prototype.onload = function() {
4534            this.confirm( true, 'onload' );
4535            this.unbindEvents();
4536        };
4537
4538        LoadingImage.prototype.onerror = function() {
4539            this.confirm( false, 'onerror' );
4540            this.unbindEvents();
4541        };
4542
4543        LoadingImage.prototype.unbindEvents = function() {
4544            this.proxyImage.removeEventListener( 'load', this );
4545            this.proxyImage.removeEventListener( 'error', this );
4546            this.img.removeEventListener( 'load', this );
4547            this.img.removeEventListener( 'error', this );
4548        };
4549
4550// -------------------------- Background -------------------------- //
4551
4552        function Background( url, element ) {
4553            this.url = url;
4554            this.element = element;
4555            this.img = new Image();
4556        }
4557
4558// inherit LoadingImage prototype
4559        Background.prototype = Object.create( LoadingImage.prototype );
4560
4561        Background.prototype.check = function() {
4562            this.img.addEventListener( 'load', this );
4563            this.img.addEventListener( 'error', this );
4564            this.img.src = this.url;
4565            // check if image is already complete
4566            var isComplete = this.getIsImageComplete();
4567            if ( isComplete ) {
4568                this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
4569                this.unbindEvents();
4570            }
4571        };
4572
4573        Background.prototype.unbindEvents = function() {
4574            this.img.removeEventListener( 'load', this );
4575            this.img.removeEventListener( 'error', this );
4576        };
4577
4578        Background.prototype.confirm = function( isLoaded, message ) {
4579            this.isLoaded = isLoaded;
4580            this.emitEvent( 'progress', [ this, this.element, message ] );
4581        };
4582
4583// -------------------------- jQuery -------------------------- //
4584
4585        ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
4586            jQuery = jQuery || window.jQuery;
4587            if ( !jQuery ) {
4588                return;
4589            }
4590            // set local variable
4591            $ = jQuery;
4592            // $().imagesLoaded()
4593            $.fn.imagesLoaded = function( options, callback ) {
4594                var instance = new ImagesLoaded( this, options, callback );
4595                return instance.jqDeferred.promise( $(this) );
4596            };
4597        };
4598// try making plugin
4599        ImagesLoaded.makeJQueryPlugin();
4600
4601// --------------------------  -------------------------- //
4602
4603        return ImagesLoaded;
4604
4605    });
vendor: 1,856 bytes, lines 4606-4670
4606
4607/*!
4608 * Flickity imagesLoaded v2.0.0
4609 * enables imagesLoaded option for Flickity
4610 */
4611
4612/*jshint browser: true, strict: true, undef: true, unused: true */
4613
4614( function( window, factory ) {
4615    // universal module definition
4616    /*jshint strict: false */ /*globals define, module, require */
4617    if ( typeof define == 'function' && define.amd ) {
4618        // AMD
4619        define( [
4620            'flickity/js/index',
4621            'imagesloaded/imagesloaded'
4622        ], function( Flickity, imagesLoaded ) {
4623            return factory( window, Flickity, imagesLoaded );
4624        });
4625    } else if ( typeof module == 'object' && module.exports ) {
4626        // CommonJS
4627        module.exports = factory(
4628            window,
4629            require('flickity'),
4630            require('imagesloaded')
4631        );
4632    } else {
4633        // browser global
4634        window.Flickity = factory(
4635            window,
4636            window.Flickity,
4637            window.imagesLoaded
4638        );
4639    }
4640
4641}( window, function factory( window, Flickity, imagesLoaded ) {
4642    'use strict';
4643
4644    Flickity.createMethods.push('_createImagesLoaded');
4645
4646    var proto = Flickity.prototype;
4647
4648    proto._createImagesLoaded = function() {
4649        this.on( 'activate', this.imagesLoaded );
4650    };
4651
4652    proto.imagesLoaded = function() {
4653        if ( !this.options.imagesLoaded ) {
4654            return;
4655        }
4656        var _this = this;
4657        function onImagesLoadedProgress( instance, image ) {
4658            var cell = _this.getParentCell( image.img );
4659            _this.cellSizeChange( cell && cell.element );
4660            if ( !_this.options.freeScroll ) {
4661                _this.positionSliderAtSelected();
4662            }
4663        }
4664        imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress );
4665    };
4666
4667    return Flickity;
4668
4669}));
4670

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.