PageSourceSearch

https://unescochair-cbrsr.org/fronend/js/flickity.pkgd.js

js unescochair-cbrsr.org collected 2026-10-03 21:37:39 UTC 103,803 bytes, 3,802 lines download raw bytes

1/*!
2 * Flickity PACKAGED v0.1.0
3 * Touch, responsive, flickable galleries
4 * http://flickity.metafizzy.co
5 * Copyright 2015 Metafizzy
6 */
7
8/**
9 * Bridget makes jQuery widgets
10 * v1.1.0
11 * MIT license
12 */
13
14( function( window ) {
15
16
17
18// -------------------------- utils -------------------------- //
19
20var slice = Array.prototype.slice;
21
22function noop() {}
23
24// -------------------------- definition -------------------------- //
25
26function defineBridget( $ ) {
27
28// bail if no jQuery
29if ( !$ ) {
30  return;
31}
32
33// -------------------------- addOptionMethod -------------------------- //
34
35/**
36 * adds option method -> $().plugin('option', {...})
37 * @param {Function} PluginClass - constructor class
38 */
39function addOptionMethod( PluginClass ) {
40  // don't overwrite original option method
41  if ( PluginClass.prototype.option ) {
42    return;
43  }
44
45  // option setter
46  PluginClass.prototype.option = function( opts ) {
47    // bail out if not an object
48    if ( !$.isPlainObject( opts ) ){
49      return;
50    }
51    this.options = $.extend( true, this.options, opts );
52  };
53}
54
55// -------------------------- plugin bridge -------------------------- //
56
57// helper function for logging errors
58// $.error breaks jQuery chaining
59var logError = typeof console === 'undefined' ? noop :
60  function( message ) {
61    console.error( message );
62  };
63
64/**
65 * jQuery plugin bridge, access methods like $elem.plugin('method')
66 * @param {String} namespace - plugin name
67 * @param {Function} PluginClass - constructor class
68 */
69function bridge( namespace, PluginClass ) {
70  // add to jQuery fn namespace
71  $.fn[ namespace ] = function( options ) {
72    if ( typeof options === 'string' ) {
73      // call plugin method when first argument is a string
74      // get arguments for method
75      var args = slice.call( arguments, 1 );
76
77      for ( var i=0, len = this.length; i < len; i++ ) {
78        var elem = this[i];
79        var instance = $.data( elem, namespace );
80        if ( !instance ) {
81          logError( "cannot call methods on " + namespace + " prior to initialization; " +
82            "attempted to call '" + options + "'" );
83          continue;
84        }
85        if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
86          logError( "no such method '" + options + "' for " + namespace + " instance" );
87          continue;
88        }
89
90        // trigger method with arguments
91        var returnValue = instance[ options ].apply( instance, args );
92
93        // break look and return first value if provided
94        if ( returnValue !== undefined ) {
95          return returnValue;
96        }
97      }
98      // return this if no return value
99      return this;
100    } else {
101      return this.each( function() {
102        var instance = $.data( this, namespace );
103        if ( instance ) {
104          // apply options & init
105          instance.option( options );
106          instance._init();
107        } else {
108          // initialize new instance
109          instance = new PluginClass( this, options );
110          $.data( this, namespace, instance );
111        }
112      });
113    }
114  };
115
116}
117
118// -------------------------- bridget -------------------------- //
119
120/**
121 * converts a Prototypical class into a proper jQuery plugin
122 *   the class must have a ._init method
123 * @param {String} namespace - plugin name, used in $().pluginName
124 * @param {Function} PluginClass - constructor class
125 */
126$.bridget = function( namespace, PluginClass ) {
127  addOptionMethod( PluginClass );
128  bridge( namespace, PluginClass );
129};
130
131return $.bridget;
132
133}
134
135// transport
136if ( typeof define === 'function' && define.amd ) {
137  // AMD
138  define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
139} else if ( typeof exports === 'object' ) {
140  defineBridget( require('jquery') );
141} else {
142  // get jquery from browser global
143  defineBridget( window.jQuery );
144}
145
146})( window );
147
148/*!
149 * classie v1.0.1
150 * class helper functions
151 * from bonzo https://github.com/ded/bonzo
152 * MIT license
153 * 
154 * classie.has( elem, 'my-class' ) -> true/false
155 * classie.add( elem, 'my-new-class' )
156 * classie.remove( elem, 'my-unwanted-class' )
157 * classie.toggle( elem, 'my-class' )
158 */
159
160/*jshint browser: true, strict: true, undef: true, unused: true */
161/*global define: false, module: false */
162
163( function( window ) {
164
165
166
167// class helper functions from bonzo https://github.com/ded/bonzo
168
169function classReg( className ) {
170  return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
171}
172
173// classList support for class management
174// altho to be fair, the api sucks because it won't accept multiple classes at once
175var hasClass, addClass, removeClass;
176
177if ( 'classList' in document.documentElement ) {
178  hasClass = function( elem, c ) {
179    return elem.classList.contains( c );
180  };
181  addClass = function( elem, c ) {
182    elem.classList.add( c );
183  };
184  removeClass = function( elem, c ) {
185    elem.classList.remove( c );
186  };
187}
188else {
189  hasClass = function( elem, c ) {
190    return classReg( c ).test( elem.className );
191  };
192  addClass = function( elem, c ) {
193    if ( !hasClass( elem, c ) ) {
194      elem.className = elem.className + ' ' + c;
195    }
196  };
197  removeClass = function( elem, c ) {
198    elem.className = elem.className.replace( classReg( c ), ' ' );
199  };
200}
201
202function toggleClass( elem, c ) {
203  var fn = hasClass( elem, c ) ? removeClass : addClass;
204  fn( elem, c );
205}
206
207var classie = {
208  // full names
209  hasClass: hasClass,
210  addClass: addClass,
211  removeClass: removeClass,
212  toggleClass: toggleClass,
213  // short names
214  has: hasClass,
215  add: addClass,
216  remove: removeClass,
217  toggle: toggleClass
218};
219
220// transport
221if ( typeof define === 'function' && define.amd ) {
222  // AMD
223  define( 'classie/classie',classie );
224} else if ( typeof exports === 'object' ) {
225  // CommonJS
226  module.exports = classie;
227} else {
228  // browser global
229  window.classie = classie;
230}
231
232})( window );
233
234/*!
235 * EventEmitter v4.2.11 - git.io/ee
236 * Unlicense - http://unlicense.org/
237 * Oliver Caldwell - http://oli.me.uk/
238 * @preserve
239 */
240
241;(function () {
242    
243
244    /**
245     * Class for managing events.
246     * Can be extended to provide event functionality in other classes.
247     *
248     * @class EventEmitter Manages event registering and emitting.
249     */
250    function EventEmitter() {}
251
252    // Shortcuts to improve speed and size
253    var proto = EventEmitter.prototype;
254    var exports = this;
255    var originalGlobalValue = exports.EventEmitter;
256
257    /**
258     * Finds the index of the listener for the event in its storage array.
259     *
260     * @param {Function[]} listeners Array of listeners to search through.
261     * @param {Function} listener Method to look for.
262     * @return {Number} Index of the specified listener, -1 if not found
263     * @api private
264     */
265    function indexOfListener(listeners, listener) {
266        var i = listeners.length;
267        while (i--) {
268            if (listeners[i].listener === listener) {
269                return i;
270            }
271        }
272
273        return -1;
274    }
275
276    /**
277     * Alias a method while keeping the context correct, to allow for over
vendor: 16,384 bytes, lines 277-680
277writing of target method.
278     *
279     * @param {String} name The name of the target method.
280     * @return {Function} The aliased method
281     * @api private
282     */
283    function alias(name) {
284        return function aliasClosure() {
285            return this[name].apply(this, arguments);
286        };
287    }
288
289    /**
290     * Returns the listener array for the specified event.
291     * Will initialise the event object and listener arrays if required.
292     * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
293     * Each property in the object response is an array of listener functions.
294     *
295     * @param {String|RegExp} evt Name of the event to return the listeners from.
296     * @return {Function[]|Object} All listener functions for the event.
297     */
298    proto.getListeners = function getListeners(evt) {
299        var events = this._getEvents();
300        var response;
301        var key;
302
303        // Return a concatenated array of all matching events if
304        // the selector is a regular expression.
305        if (evt instanceof RegExp) {
306            response = {};
307            for (key in events) {
308                if (events.hasOwnProperty(key) && evt.test(key)) {
309                    response[key] = events[key];
310                }
311            }
312        }
313        else {
314            response = events[evt] || (events[evt] = []);
315        }
316
317        return response;
318    };
319
320    /**
321     * Takes a list of listener objects and flattens it into a list of listener functions.
322     *
323     * @param {Object[]} listeners Raw listener objects.
324     * @return {Function[]} Just the listener functions.
325     */
326    proto.flattenListeners = function flattenListeners(listeners) {
327        var flatListeners = [];
328        var i;
329
330        for (i = 0; i < listeners.length; i += 1) {
331            flatListeners.push(listeners[i].listener);
332        }
333
334        return flatListeners;
335    };
336
337    /**
338     * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
339     *
340     * @param {String|RegExp} evt Name of the event to return the listeners from.
341     * @return {Object} All listener functions for an event in an object.
342     */
343    proto.getListenersAsObject = function getListenersAsObject(evt) {
344        var listeners = this.getListeners(evt);
345        var response;
346
347        if (listeners instanceof Array) {
348            response = {};
349            response[evt] = listeners;
350        }
351
352        return response || listeners;
353    };
354
355    /**
356     * Adds a listener function to the specified event.
357     * The listener will not be added if it is a duplicate.
358     * If the listener returns true then it will be removed after it is called.
359     * If you pass a regular expression as the event name then the listener will be added to all events that match it.
360     *
361     * @param {String|RegExp} evt Name of the event to attach the listener to.
362     * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
363     * @return {Object} Current instance of EventEmitter for chaining.
364     */
365    proto.addListener = function addListener(evt, listener) {
366        var listeners = this.getListenersAsObject(evt);
367        var listenerIsWrapped = typeof listener === 'object';
368        var key;
369
370        for (key in listeners) {
371            if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
372                listeners[key].push(listenerIsWrapped ? listener : {
373                    listener: listener,
374                    once: false
375                });
376            }
377        }
378
379        return this;
380    };
381
382    /**
383     * Alias of addListener
384     */
385    proto.on = alias('addListener');
386
387    /**
388     * Semi-alias of addListener. It will add a listener that will be
389     * automatically removed after its first execution.
390     *
391     * @param {String|RegExp} evt Name of the event to attach the listener to.
392     * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
393     * @return {Object} Current instance of EventEmitter for chaining.
394     */
395    proto.addOnceListener = function addOnceListener(evt, listener) {
396        return this.addListener(evt, {
397            listener: listener,
398            once: true
399        });
400    };
401
402    /**
403     * Alias of addOnceListener.
404     */
405    proto.once = alias('addOnceListener');
406
407    /**
408     * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
409     * You need to tell it what event names should be matched by a regex.
410     *
411     * @param {String} evt Name of the event to create.
412     * @return {Object} Current instance of EventEmitter for chaining.
413     */
414    proto.defineEvent = function defineEvent(evt) {
415        this.getListeners(evt);
416        return this;
417    };
418
419    /**
420     * Uses defineEvent to define multiple events.
421     *
422     * @param {String[]} evts An array of event names to define.
423     * @return {Object} Current instance of EventEmitter for chaining.
424     */
425    proto.defineEvents = function defineEvents(evts) {
426        for (var i = 0; i < evts.length; i += 1) {
427            this.defineEvent(evts[i]);
428        }
429        return this;
430    };
431
432    /**
433     * Removes a listener function from the specified event.
434     * When passed a regular expression as the event name, it will remove the listener from all events that match it.
435     *
436     * @param {String|RegExp} evt Name of the event to remove the listener from.
437     * @param {Function} listener Method to remove from the event.
438     * @return {Object} Current instance of EventEmitter for chaining.
439     */
440    proto.removeListener = function removeListener(evt, listener) {
441        var listeners = this.getListenersAsObject(evt);
442        var index;
443        var key;
444
445        for (key in listeners) {
446            if (listeners.hasOwnProperty(key)) {
447                index = indexOfListener(listeners[key], listener);
448
449                if (index !== -1) {
450                    listeners[key].splice(index, 1);
451                }
452            }
453        }
454
455        return this;
456    };
457
458    /**
459     * Alias of removeListener
460     */
461    proto.off = alias('removeListener');
462
463    /**
464     * Adds listeners in bulk using the manipulateListeners method.
465     * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
466     * You can also pass it a regular expression to add the array of listeners to all events that match it.
467     * Yeah, this function does quite a bit. That's probably a bad thing.
468     *
469     * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
470     * @param {Function[]} [listeners] An optional array of listener functions to add.
471     * @return {Object} Current instance of EventEmitter for chaining.
472     */
473    proto.addListeners = function addListeners(evt, listeners) {
474        // Pass through to manipulateListeners
475        return this.manipulateListeners(false, evt, listeners);
476    };
477
478    /**
479     * Removes listeners in bulk using the manipulateListeners method.
480     * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
481     * You can also pass it an event name and an array of listeners to be removed.
482     * You can also pass it a regular expression to remove the listeners from all events that match it.
483     *
484     * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
485     * @param {Function[]} [listeners] An optional array of listener functions to remove.
486     * @return {Object} Current instance of EventEmitter for chaining.
487     */
488    proto.removeListeners = function removeListeners(evt, listeners) {
489        // Pass through to manipulateListeners
490        return this.manipulateListeners(true, evt, listeners);
491    };
492
493    /**
494     * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
495     * The first argument will determine if the listeners are removed (true) or added (false).
496     * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
497     * You can also pass it an event name and an array of listeners to be added/removed.
498     * You can also pass it a regular expression to manipulate the listeners of all events that match it.
499     *
500     * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
501     * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
502     * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
503     * @return {Object} Current instance of EventEmitter for chaining.
504     */
505    proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
506        var i;
507        var value;
508        var single = remove ? this.removeListener : this.addListener;
509        var multiple = remove ? this.removeListeners : this.addListeners;
510
511        // If evt is an object then pass each of its properties to this method
512        if (typeof evt === 'object' && !(evt instanceof RegExp)) {
513            for (i in evt) {
514                if (evt.hasOwnProperty(i) && (value = evt[i])) {
515                    // Pass the single listener straight through to the singular method
516                    if (typeof value === 'function') {
517                        single.call(this, i, value);
518                    }
519                    else {
520                        // Otherwise pass back to the multiple function
521                        multiple.call(this, i, value);
522                    }
523                }
524            }
525        }
526        else {
527            // So evt must be a string
528            // And listeners must be an array of listeners
529            // Loop over it and pass each one to the multiple method
530            i = listeners.length;
531            while (i--) {
532                single.call(this, evt, listeners[i]);
533            }
534        }
535
536        return this;
537    };
538
539    /**
540     * Removes all listeners from a specified event.
541     * If you do not specify an event then all listeners will be removed.
542     * That means every event will be emptied.
543     * You can also pass a regex to remove all events that match it.
544     *
545     * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
546     * @return {Object} Current instance of EventEmitter for chaining.
547     */
548    proto.removeEvent = function removeEvent(evt) {
549        var type = typeof evt;
550        var events = this._getEvents();
551        var key;
552
553        // Remove different things depending on the state of evt
554        if (type === 'string') {
555            // Remove all listeners for the specified event
556            delete events[evt];
557        }
558        else if (evt instanceof RegExp) {
559            // Remove all events matching the regex.
560            for (key in events) {
561                if (events.hasOwnProperty(key) && evt.test(key)) {
562                    delete events[key];
563                }
564            }
565        }
566        else {
567            // Remove all listeners in all events
568            delete this._events;
569        }
570
571        return this;
572    };
573
574    /**
575     * Alias of removeEvent.
576     *
577     * Added to mirror the node API.
578     */
579    proto.removeAllListeners = alias('removeEvent');
580
581    /**
582     * Emits an event of your choice.
583     * When emitted, every listener attached to that event will be executed.
584     * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
585     * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
586     * So they will not arrive within the array on the other side, they will be separate.
587     * You can also pass a regular expression to emit to all events that match it.
588     *
589     * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
590     * @param {Array} [args] Optional array of arguments to be passed to each listener.
591     * @return {Object} Current instance of EventEmitter for chaining.
592     */
593    proto.emitEvent = function emitEvent(evt, args) {
594        var listeners = this.getListenersAsObject(evt);
595        var listener;
596        var i;
597        var key;
598        var response;
599
600        for (key in listeners) {
601            if (listeners.hasOwnProperty(key)) {
602                i = listeners[key].length;
603
604                while (i--) {
605                    // If the listener returns true then it shall be removed from the event
606                    // The function is executed either with a basic call or an apply if there is an args array
607                    listener = listeners[key][i];
608
609                    if (listener.once === true) {
610                        this.removeListener(evt, listener.listener);
611                    }
612
613                    response = listener.listener.apply(this, args || []);
614
615                    if (response === this._getOnceReturnValue()) {
616                        this.removeListener(evt, listener.listener);
617                    }
618                }
619            }
620        }
621
622        return this;
623    };
624
625    /**
626     * Alias of emitEvent
627     */
628    proto.trigger = alias('emitEvent');
629
630    /**
631     * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
632     * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
633     *
634     * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
635     * @param {...*} Optional additional arguments to be passed to each listener.
636     * @return {Object} Current instance of EventEmitter for chaining.
637     */
638    proto.emit = function emit(evt) {
639        var args = Array.prototype.slice.call(arguments, 1);
640        return this.emitEvent(evt, args);
641    };
642
643    /**
644     * Sets the current value to check against when executing listeners. If a
645     * listeners return value matches the one set here then it will be removed
646     * after execution. This value defaults to true.
647     *
648     * @param {*} value The new value to check for when executing listeners.
649     * @return {Object} Current instance of EventEmitter for chaining.
650     */
651    proto.setOnceReturnValue = function setOnceReturnValue(value) {
652        this._onceReturnValue = value;
653        return this;
654    };
655
656    /**
657     * Fetches the current value to check against when executing listeners. If
658     * the listeners return value matches this one then it should be removed
659     * automatically. It will return true by default.
660     *
661     * @return {*|Boolean} The current value to check for or the default, true.
662     * @api private
663     */
664    proto._getOnceReturnValue = function _getOnceReturnValue() {
665        if (this.hasOwnProperty('_onceReturnValue')) {
666            return this._onceReturnValue;
667        }
668        else {
669            return true;
670        }
671    };
672
673    /**
674     * Fetches the events object and creates one if required.
675     *
676     * @return {Object} The events storage object.
677     * @api private
678     */
679    proto._getEvents = function _getEvents() {
680        return this._events || (this
680._events = {});
681    };
682
683    /**
684     * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
685     *
686     * @return {Function} Non conflicting EventEmitter class.
687     */
688    EventEmitter.noConflict = function noConflict() {
689        exports.EventEmitter = originalGlobalValue;
690        return EventEmitter;
691    };
692
693    // Expose the class either via AMD, CommonJS or the global object
694    if (typeof define === 'function' && define.amd) {
695        define('eventEmitter/EventEmitter',[],function () {
696            return EventEmitter;
697        });
698    }
699    else if (typeof module === 'object' && module.exports){
700        module.exports = EventEmitter;
701    }
702    else {
703        exports.EventEmitter = EventEmitter;
704    }
705}.call(this));
706
707/*!
708 * eventie v1.0.5
709 * event binding helper
710 *   eventie.bind( elem, 'click', myFn )
711 *   eventie.unbind( elem, 'click', myFn )
712 * MIT license
713 */
714
715/*jshint browser: true, undef: true, unused: true */
716/*global define: false, module: false */
717
718( function( window ) {
719
720
721
722var docElem = document.documentElement;
723
724var bind = function() {};
725
726function getIEEvent( obj ) {
727  var event = window.event;
728  // add event.target
729  event.target = event.target || event.srcElement || obj;
730  return event;
731}
732
733if ( docElem.addEventListener ) {
734  bind = function( obj, type, fn ) {
735    obj.addEventListener( type, fn, false );
736  };
737} else if ( docElem.attachEvent ) {
738  bind = function( obj, type, fn ) {
739    obj[ type + fn ] = fn.handleEvent ?
740      function() {
741        var event = getIEEvent( obj );
742        fn.handleEvent.call( fn, event );
743      } :
744      function() {
745        var event = getIEEvent( obj );
746        fn.call( obj, event );
747      };
748    obj.attachEvent( "on" + type, obj[ type + fn ] );
749  };
750}
751
752var unbind = function() {};
753
754if ( docElem.removeEventListener ) {
755  unbind = function( obj, type, fn ) {
756    obj.removeEventListener( type, fn, false );
757  };
758} else if ( docElem.detachEvent ) {
759  unbind = function( obj, type, fn ) {
760    obj.detachEvent( "on" + type, obj[ type + fn ] );
761    try {
762      delete obj[ type + fn ];
763    } catch ( err ) {
764      // can't delete window object properties
765      obj[ type + fn ] = undefined;
766    }
767  };
768}
769
770var eventie = {
771  bind: bind,
772  unbind: unbind
773};
774
775// ----- module definition ----- //
776
777if ( typeof define === 'function' && define.amd ) {
778  // AMD
779  define( 'eventie/eventie',eventie );
780} else if ( typeof exports === 'object' ) {
781  // CommonJS
782  module.exports = eventie;
783} else {
784  // browser global
785  window.eventie = eventie;
786}
787
788})( this );
789
790/*!
791 * getStyleProperty v1.0.4
792 * original by kangax
793 * http://perfectionkills.com/feature-testing-css-properties/
794 * MIT license
795 */
796
797/*jshint browser: true, strict: true, undef: true */
798/*global define: false, exports: false, module: false */
799
800( function( window ) {
801
802
803
804var prefixes = 'Webkit Moz ms Ms O'.split(' ');
805var docElemStyle = document.documentElement.style;
806
807function getStyleProperty( propName ) {
808  if ( !propName ) {
809    return;
810  }
811
812  // test standard property first
813  if ( typeof docElemStyle[ propName ] === 'string' ) {
814    return propName;
815  }
816
817  // capitalize
818  propName = propName.charAt(0).toUpperCase() + propName.slice(1);
819
820  // test vendor specific properties
821  var prefixed;
822  for ( var i=0, len = prefixes.length; i < len; i++ ) {
823    prefixed = prefixes[i] + propName;
824    if ( typeof docElemStyle[ prefixed ] === 'string' ) {
825      return prefixed;
826    }
827  }
828}
829
830// transport
831if ( typeof define === 'function' && define.amd ) {
832  // AMD
833  define( 'get-style-property/get-style-property',[],function() {
834    return getStyleProperty;
835  });
836} else if ( typeof exports === 'object' ) {
837  // CommonJS for Component
838  module.exports = getStyleProperty;
839} else {
840  // browser global
841  window.getStyleProperty = getStyleProperty;
842}
843
844})( window );
845
846/*!
847 * getSize v1.2.2
848 * measure size of elements
849 * MIT license
850 */
851
852/*jshint browser: true, strict: true, undef: true, unused: true */
853/*global define: false, exports: false, require: false, module: false, console: false */
854
855( function( window, undefined ) {
856
857
858
859// -------------------------- helpers -------------------------- //
860
861// get a number from a string, not a percentage
862function getStyleSize( value ) {
863  var num = parseFloat( value );
864  // not a percent like '100%', and a number
865  var isValid = value.indexOf('%') === -1 && !isNaN( num );
866  return isValid && num;
867}
868
869function noop() {}
870
871var logError = typeof console === 'undefined' ? noop :
872  function( message ) {
873    console.error( message );
874  };
875
876// -------------------------- measurements -------------------------- //
877
878var measurements = [
879  'paddingLeft',
880  'paddingRight',
881  'paddingTop',
882  'paddingBottom',
883  'marginLeft',
884  'marginRight',
885  'marginTop',
886  'marginBottom',
887  'borderLeftWidth',
888  'borderRightWidth',
889  'borderTopWidth',
890  'borderBottomWidth'
891];
892
893function getZeroSize() {
894  var size = {
895    width: 0,
896    height: 0,
897    innerWidth: 0,
898    innerHeight: 0,
899    outerWidth: 0,
900    outerHeight: 0
901  };
902  for ( var i=0, len = measurements.length; i < len; i++ ) {
903    var measurement = measurements[i];
904    size[ measurement ] = 0;
905  }
906  return size;
907}
908
909
910
911function defineGetSize( getStyleProperty ) {
912
913// -------------------------- setup -------------------------- //
914
915var isSetup = false;
916
917var getStyle, boxSizingProp, isBoxSizeOuter;
918
919/**
920 * setup vars and functions
921 * do it on initial getSize(), rather than on script load
922 * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
923 */
924function setup() {
925  // setup once
926  if ( isSetup ) {
927    return;
928  }
929  isSetup = true;
930
931  var getComputedStyle = window.getComputedStyle;
932  getStyle = ( function() {
933    var getStyleFn = getComputedStyle ?
934      function( elem ) {
935        return getComputedStyle( elem, null );
936      } :
937      function( elem ) {
938        return elem.currentStyle;
939      };
940
941      return function getStyle( elem ) {
942        var style = getStyleFn( elem );
943        if ( !style ) {
944          logError( 'Style returned ' + style +
945            '. Are you running this code in a hidden iframe on Firefox? ' +
946            'See http://bit.ly/getsizebug1' );
947        }
948        return style;
949      };
950  })();
951
952  // -------------------------- box sizing -------------------------- //
953
954  boxSizingProp = getStyleProperty('boxSizing');
955
956  /**
957   * WebKit measures the outer-width on style.width on border-box elems
958   * IE & Firefox measures the inner-width
959   */
960  if ( boxSizingProp ) {
961    var div = document.createElement('div');
962    div.style.width = '200px';
963    div.style.padding = '1px 2px 3px 4px';
964    div.style.borderStyle = 'solid';
965    div.style.borderWidth = '1px 2px 3px 4px';
966    div.style[ boxSizingProp ] = 'border-box';
967
968    var body = document.body || document.documentElement;
969    body.appendChild( div );
970    var style = getStyle( div );
971
972    isBoxSizeOuter = getStyleSize( style.width ) === 200;
973    body.removeChild( div );
974  }
975
976}
977
978// -------------------------- getSize -------------------------- //
979
980function getSize( elem ) {
981  setup();
982
983  // use querySeletor if elem is string
984  if ( typeof elem === 'string' ) {
985    elem = document.querySelector( elem );
986  }
987
988  // do not proceed on non-objects
989  if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
990    return;
991  }
992
993  var style = getStyle( elem );
994
995  // if hidden, everything is 0
996  if ( style.display === 'none' ) {
997    return getZeroSize();
998  }
999
1000  var size = {};
1001  size.width = elem.offsetWidth;
1002  size.height = elem.offsetHeight;
1003
1004  var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
1005    style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
1006
1007  // get all measurements
1008  for ( var i=0, len = measurements.length; i < len; i++ ) {
1009    var measurement = measurements[i];
1010    var value = style[ measurement ];
1011    value = mungeNonPixel( elem, value );
1012    var num = parseFloat( value );
1013    // any 'auto', 'medium' value will be 0
1014    size[ measurement ] = !isNaN( num ) ? num : 0;
1015  }
1016
1017  var paddingWidth = size.paddingLeft + size.paddingRight;
1018  var paddingHeight = size.paddingTop + size.paddingBottom;
1019  var marginWidth = size.marginLeft + size.marginRight;
1020  var marginHeight = size.marginTop + size.marginBottom;
1021  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
1022  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
1023
1024  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
1025
1026  // overwrite width and height if we can get it from style
1027  var styleWidth = getStyleSize( style.width );
1028  if ( styleWidth !== false ) {
1029    size.width = styleWidth +
1030      // add padding and border unless it's already including it
1031      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
1032  }
1033
1034  var styleHeight = getStyleSize( style.height );
1035  if ( styleHeight !== false ) {
1036    size.height = styleHeight +
1037      // add padding and border unless it's already including it
1038      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
1039  }
1040
1041  size.innerWidth = size.width - ( paddingWidth + borderWidth );
1042  size.innerHeight = size.height - ( paddingHeight + borderHeight );
1043
1044  size.outerWidth = size.width + marginWidth;
1045  size.outerHeight = size.height + marginHeight;
1046
1047  return size;
1048}
1049
1050// IE8 returns percent values, not pixels
1051// taken from jQuery's curCSS
1052function mungeNonPixel( elem, value ) {
1053  // IE8 and has percent value
1054  if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
1055    return value;
1056  }
1057  var style = elem.style;
1058  // Remember the original values
1059  var left = style.left;
1060  var rs = elem.runtimeStyle;
1061  var rsLeft = rs && rs.left;
1062
1063  // Put in the new values to get a computed value out
1064  if ( rsLeft ) {
1065    rs.left = elem.currentStyle.left;
1066  }
1067  style.left = value;
1068  value = style.pixelLeft;
1069
1070  // Revert the changed values
1071  style.left = left;
1072  if ( rsLeft ) {
1073    rs.left = rsLeft;
1074  }
1075
1076  return value;
1077}
1078
1079return getSize;
1080
1081}
1082
1083// transport
1084if ( typeof define === 'function' && define.amd ) {
1085  // AMD for RequireJS
1086  define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
1087} else if ( typeof exports === 'object' ) {
1088  // CommonJS for Component
1089  module.exports = defineGetSize( require('desandro-get-style-property') );
1090} else {
1091  // browser global
1092  window.getSize = defineGetSize( window.getStyleProperty );
1093}
1094
1095})( window );
1096
1097/*!
1098 * docReady v1.0.4
1099 * Cross browser DOMContentLoaded event emitter
1100 * MIT license
1101 */
1102
1103/*jshint browser: true, strict: true, undef: true, unused: true*/
1104/*global define: false, require: false, module: false */
1105
1106( function( window ) {
1107
1108
1109
1110var document = window.document;
1111// collection of functions to be triggered on ready
1112var queue = [];
1113
1114function docReady( fn ) {
1115  // throw out non-functions
1116  if ( typeof fn !== 'function' ) {
1117    return;
1118  }
1119
1120  if ( docReady.isReady ) {
1121    // ready now, hit it
1122    fn();
1123  } else {
1124    // queue function when ready
1125    queue.push( fn );
1126  }
1127}
1128
1129docReady.isReady = false;
1130
1131// triggered on various doc ready events
1132function onReady( event ) {
1133  // bail if already triggered or IE8 document is not ready just yet
1134  var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
1135  if ( docReady.isReady || isIE8NotReady ) {
1136    return;
1137  }
1138
1139  trigger();
1140}
1141
1142function trigger() {
1143  docReady.isReady = true;
1144  // process queue
1145  for ( var i=0, len = queue.length; i < len; i++ ) {
1146    var fn = queue[i];
1147    fn();
1148  }
1149}
1150
1151function defineDocReady( eventie ) {
1152  // trigger ready if page is ready
1153  if ( document.readyState === 'complete' ) {
1154    trigger();
1155  } else {
1156    // listen for events
1157    eventie.bind( document, 'DOMContentLoaded', onReady );
1158    eventie.bind( document, 'readystatechange', onReady );
1159    eventie.bind( window, 'load', onReady );
1160  }
1161
1162  return docReady;
1163}
1164
1165// transport
1166if ( typeof define === 'function' && define.amd ) {
1167  // AMD
1168  define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
1169} else if ( typeof exports === 'object' ) {
1170  module.exports = defineDocReady( require('eventie') );
1171} else {
1172  // browser global
1173  window.docReady = defineDocReady( window.eventie );
1174}
1175
1176})( window );
1177
1178/**
1179 * matchesSelector v1.0.2
1180 * matchesSelector( element, '.selector' )
1181 * MIT license
1182 */
1183
1184/*jshint browser: true, strict: true, undef: true, unused: true */
1185/*global define: false, module: false */
1186
1187( function( ElemProto ) {
1188
1189  
1190
1191  var matchesMethod = ( function() {
1192    // check un-prefixed
1193    if ( ElemProto.matchesSelector ) {
1194      return 'matchesSelector';
1195    }
1196    // check vendor prefixes
1197    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1198
1199    for ( var i=0, len = prefixes.length; i < len; i++ ) {
1200      var prefix = prefixes[i];
1201      var method = prefix + 'MatchesSelector';
1202      if ( ElemProto[ method ] ) {
1203        return method;
1204      }
1205    }
1206  })();
1207
1208  // ----- match ----- //
1209
1210  function match( elem, selector ) {
1211    return elem[ matchesMethod ]( selector );
1212  }
1213
1214  // ----- appendToFragment ----- //
1215
1216  function checkParent( elem ) {
1217    // not needed if already has parent
1218    if ( elem.parentNode ) {
1219      return;
1220    }
1221    var fragment = document.createDocumentFragment();
1222    fragment.appendChild( elem );
1223  }
1224
1225  // ----- query ----- //
1226
1227  // fall back to using QSA
1228  // thx @jonathantneal https://gist.github.com/3062955
1229  function query( elem, selector ) {
1230    // append to fragment if no parent
1231    checkParent( elem );
1232
1233    // match elem with all selected elems of parent
1234    var elems = elem.parentNode.querySelectorAll( selector );
1235    for ( var i=0, len = elems.length; i < len; i++ ) {
1236      // return true if match
1237      if ( elems[i] === elem ) {
1238        return true;
1239      }
1240    }
1241    // otherwise return false
1242    return false;
1243  }
1244
1245  // ----- matchChild ----- //
1246
1247  function matchChild( elem, selector ) {
1248    checkParent( elem );
1249    return match( elem, selector );
1250  }
1251
1252  // ----- matchesSelector ----- //
1253
1254  var matchesSelector;
1255
1256  if ( matchesMethod ) {
1257    // IE9 supports matchesSelector, but doesn't work on orphaned elems
1258    // check for that
1259    var div = document.createElement('div');
1260    var supportsOrphans = match( div, 'div' );
1261    matchesSelector = supportsOrphans ? match : matchChild;
1262  } else {
1263    matchesSelector = query;
1264  }
1265
1266  // transport
1267  if ( typeof define === 'function' && define.amd ) {
1268    // AMD
1269    define( 'matches-selector/matches-selector',[],function() {
1270      return matchesSelector;
1271    });
1272  } else if ( typeof exports === 'object' ) {
1273    module.exports = matchesSelector;
1274  }
1275  else {
1276    // browser global
1277    window.matchesSelector = matchesSelector;
1278  }
1279
1280})( Element.prototype );
1281
1282/**
1283 * utils
1284 */
1285
1286( function( window, factory ) {
1287  
1288  // universal module definition
1289
1290  if ( typeof define == 'function' && define.amd ) {
1291    // AMD
1292    define( 'flickity/js/utils',[
1293      'doc-ready/doc-ready',
1294      'matches-selector/matches-selector'
1295    ], function( docReady, matchesSelector ) {
1296      return factory( window, docReady, matchesSelector );
1297    });
1298  } else if ( typeof exports == 'object' ) {
1299    // CommonJS
1300    module.exports = factory(
1301      window,
1302      require('doc-ready'),
1303      require('desandro-matches-selector')
1304    );
1305  } else {
1306    // browser global
1307    window.utils = factory(
1308      window,
1309      window.docReady,
1310      window.matchesSelector
1311    );
1312  }
1313
1314}( window, function factory( window, docReady, matchesSelector ) {
1315
1316
1317
1318var U = {};
1319
1320// ----- extend ----- //
1321
1322// extends objects
1323U.extend = function( a, b ) {
1324  for ( var prop in b ) {
1325    a[ prop ] = b[ prop ];
1326  }
1327  return a;
1328};
1329
1330// ----- modulo ----- //
1331
1332U.modulo = function( num, div ) {
1333  return ( ( num % div ) + div ) % div;
1334};
1335
1336// ----- isArray ----- //
1337  
1338var objToString = Object.prototype.toString;
1339U.isArray = function( obj ) {
1340  return objToString.call( obj ) == '[object Array]';
1341};
1342
1343// ----- makeArray ----- //
1344
1345// turn element or nodeList into an array
1346U.makeArray = function( obj ) {
1347  var ary = [];
1348  if ( U.isArray( obj ) ) {
1349    // use object if already an array
1350    ary = obj;
1351  } else if ( obj && typeof obj.length == 'number' ) {
1352    // convert nodeList to array
1353    for ( var i=0, len = obj.length; i < len; i++ ) {
1354      ary.push( obj[i] );
1355    }
1356  } else {
1357    // array of single index
1358    ary.push( obj );
1359  }
1360  return ary;
1361};
1362
1363// ----- indexOf ----- //
1364
1365// index of helper cause IE8
1366U.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1367    return ary.indexOf( obj );
1368  } : function( ary, obj ) {
1369    for ( var i=0, len = ary.length; i < len; i++ ) {
1370      if ( ary[i] === obj ) {
1371        return i;
1372      }
1373    }
1374    return -1;
1375  };
1376
1377// ----- removeFrom ----- //
1378
1379U.removeFrom = function( obj, ary ) {
1380  var index = U.indexOf( ary, obj );
1381  if ( index != -1 ) {
1382    ary.splice( index, 1 );
1383  }
1384};
1385
1386// ----- isElement ----- //
1387
1388// http://stackoverflow.com/a/384380/182183
1389U.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
1390  function isElementDOM2( obj ) {
1391    return obj instanceof HTMLElement;
1392  } :
1393  function isElementQuirky( obj ) {
1394    return obj && typeof obj == 'object' &&
1395      obj.nodeType == 1 && typeof obj.nodeName == 'string';
1396  };
1397
1398// ----- setText ----- //
1399
1400U.setText = ( function() {
1401  var setTextProperty;
1402  function setText( elem, text ) {
1403    // only check setTextProperty once
1404    setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
1405    elem[ setTextProperty ] = text;
1406  }
1407  return setText;
1408})();
1409
1410// ----- getParent ----- //
1411
1412U.getParent = function( elem, selector ) {
1413  while ( elem != document.body ) {
1414    elem = elem.parentNode;
1415    if ( matchesSelector( elem, selector ) ) {
1416      return elem;
1417    }
1418  }
1419};
1420
1421// ----- getQueryElement ----- //
1422
1423// use element as selector string
1424U.getQueryElement = function( elem ) {
1425  if ( typeof elem == 'string' ) {
1426    return document.querySelector( elem );
1427  }
1428  return elem;
1429};
1430
1431// ----- filterFindElements ----- //
1432
1433U.filterFindElements = function( elems, selector ) {
1434  // make array of elems
1435  elems = U.makeArray( elems );
1436  var ffElems = [];
1437
1438  for ( var i=0, len = elems.length; i < len; i++ ) {
1439    var elem = elems[i];
1440    // check that elem is an actual element
1441    if ( !U.isElement( elem ) ) {
1442      continue;
1443    }
1444    // filter & find items if we have a selector
1445    if ( selector ) {
1446      // filter siblings
1447      if ( matchesSelector( elem, selector ) ) {
1448        ffElems.push( elem );
1449      }
1450      // find children
1451      var childElems = elem.querySelectorAll( selector );
1452      // concat childElems to filterFound array
1453      for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
1454        ffElems.push( childElems[j] );
1455      }
1456    } else {
1457      ffElems.push( elem );
1458    }
1459  }
1460
1461  return ffElems;
1462};
1463
1464// ----- debounceMethod ----- //
1465
1466U.debounceMethod = function( _class, methodName, threshold ) {
1467  // original method
1468  var method = _class.prototype[ methodName ];
1469  var timeoutName = methodName + 'Timeout';
1470
1471  _class.prototype[ methodName ] = function() {
1472    var timeout = this[ timeoutName ];
1473    if ( timeout ) {
1474      clearTimeout( timeout );
1475    }
1476    var args = arguments;
1477
1478    var _this = this;
1479    this[ timeoutName ] = setTimeout( function() {
1480      method.apply( _this, args );
1481      delete _this[ timeoutName ];
1482    }, threshold || 100 );
1483  };
1484};
1485
1486// ----- htmlInit ----- //
1487
1488var jQuery = window.jQuery;
1489
1490// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1491function toDashed( str ) {
1492  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1493    return $1 + '-' + $2;
1494  }).toLowerCase();
1495}
1496
1497
1498/**
1499 * allow user to initialize classes via .js-namespace class
1500 * htmlInit( Widget, 'widgetName' )
1501 * options are parsed from data-namespace-option attribute
1502 */
1503U.htmlInit = function( WidgetClass, namespace ) {
1504  docReady( function() {
1505    var dashedNamespace = toDashed( namespace );
1506    var elems = document.querySelectorAll( '.js-' + dashedNamespace );
1507    var dataAttr = 'data-' + dashedNamespace + '-options';
1508
1509    for ( var i=0, len = elems.length; i < len; i++ ) {
1510      var elem = elems[i];
1511      var attr = elem.getAttribute( dataAttr );
1512      var options;
1513      try {
1514        options = attr && JSON.parse( attr );
1515      } catch ( error ) {
1516        // log error, do not initialize
1517        if ( console ) {
1518          console.error( 'Error parsing ' + dataAttr + ' on ' +
1519            elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
1520            error );
1521        }
1522        continue;
1523      }
1524      // initialize
1525      var instance = new WidgetClass( elem, options );
1526      // make available via $().data('layoutname')
1527      if ( jQuery ) {
1528        jQuery.data( elem, namespace, instance );
1529      }
1530    }
1531  });
1532};
1533
1534// -----  ----- //
1535
1536return U;
1537
1538}));
1539
1540( function( window, factory ) {
1541  
1542  // universal module definition
1543
1544  if ( typeof define == 'function' && define.amd ) {
1545    // AMD
1546    define( 'flickity/js/cell',[
1547      'get-size/get-size'
1548    ], function( getSize ) {
1549      return factory( window, getSize );
1550    });
1551  } else if ( typeof exports == 'object' ) {
1552    // CommonJS
1553    module.exports = factory(
1554      window,
1555      require('get-size')
1556    );
1557  } else {
1558    // browser global
1559    window.Flickity = window.Flickity || {};
1560    window.Flickity.Cell = factory(
1561      window,
1562      window.getSize
1563    );
1564  }
1565
1566}( window, function factory( window, getSize ) {
1567
1568
1569
1570function Cell( elem, parent ) {
1571  this.element = elem;
1572  this.parent = parent;
1573
1574  this.create();
1575}
1576
1577Cell.prototype.create = function() {
1578  this.element.style.position = 'absolute';
1579  this.x = 0;
1580  this.shift = 0;
1581};
1582
1583Cell.prototype.destroy = function() {
1584  // reset style
1585  this.element.style.position = '';
1586  var side = this.parent.originSide;
1587  this.element.style[ side ] = '';
1588};
1589
1590Cell.prototype.getSize = function() {
1591  this.size = getSize( this.element );
1592};
1593
1594Cell.prototype.setPosition = function( x ) {
1595  this.x = x;
1596  this.setDefaultTarget();
1597  this.renderPosition( x );
1598};
1599
1600Cell.prototype.setDefaultTarget = function() {
1601  var marginProperty = this.parent.originSide == 'left' ? 'marginLeft' : 'marginRight';
1602  this.target = this.x + this.size[ marginProperty ] +
1603    this.size.width * this.parent.cellAlign;
1604};
1605
1606Cell.prototype.renderPosition = function( x ) {
1607  // render position of cell with in slider
1608  var side = this.parent.originSide;
1609  this.element.style[ side ] = this.parent.getPositionValue( x );
1610};
1611
1612/**
1613 * @param {Integer} factor - 0, 1, or -1
1614**/
1615Cell.prototype.wrapShift = function( shift ) {
1616  this.shift = shift;
1617  this.renderPosition( this.x + this.parent.slideableWidth * shift );
1618};
1619
1620Cell.prototype.remove = function() {
1621  this.element.parentNode.removeChild( this.element );
1622};
1623
1624return Cell;
1625
1626}));
1627
1628// -------------------------- prev/next button -------------------------- //
1629
1630( function( window, factory ) {
1631  
1632  // universal module definition
1633
1634  if ( typeof define == 'function' && define.amd ) {
1635    // AMD
1636    define( 'flickity/js/prev-next-button',[
1637      './utils'
1638    ], function( utils ) {
1639      return factory( window, utils );
1640    });
1641  } else if ( typeof exports == 'object' ) {
1642    // CommonJS
1643    module.exports = factory(
1644      window,
1645      require('./utils')
1646    );
1647  } else {
1648    // browser global
1649    window.Flickity = window.Flickity || {};
1650    window.Flickity.PrevNextButton = factory(
1651      window,
1652      window.utils
1653    );
1654  }
1655
1656}( window, function factory( window, utils ) {
1657
1658
1659
1660var svgURI = 'http://www.w3.org/2000/svg';
1661
1662// -------------------------- inline SVG support -------------------------- //
1663
1664// only check on demand, not on script load
1665var supportsInlineSVG = ( function() {
1666  var supports;
1667  function checkSupport() {
1668    if ( supports !== undefined ) {
1669      return supports;
1670    }
1671    var div = document.createElement('div');
1672    div.innerHTML = '<svg/>';
1673    supports = ( div.firstChild && div.firstChild.namespaceURI ) == svgURI;
1674    return supports;
1675  }
1676  return checkSupport;
1677})();
1678
1679function PrevNextButton( direction, parent ) {
1680  this.direction = direction;
1681  this.parent = parent;
1682  this._create();
1683}
1684
1685PrevNextButton.prototype._create = function() {
1686  // properties
1687  this.isEnabled = true;
1688  this.isPrevious = this.direction == -1;
1689  var leftDirection = this.parent.options.rightToLeft ? 1 : -1;
1690  this.isLeft = this.direction == leftDirection;
1691
1692  this.element = document.createElement('button');
1693  this.element.className = 'flickity-prev-next-button';
1694  this.element.className += this.isPrevious ? ' previous' : ' next';
1695  // create arrow
1696  if ( supportsInlineSVG() ) {
1697    var svg = this.createSVG();
1698    this.element.appendChild( svg );
1699  } else {
1700    // SVG not supported, set button text
1701    this.setArrowText();
1702    this.element.className += ' no-svg';
1703  }
1704
1705  // update on select
1706  var _this = this;
1707  this.onselect = function() {
1708    _this.update();
1709  };
1710  this.parent.on( 'select', this.onselect );
1711
1712  // listen to click event
1713  this.element.onclick = function() {
1714    _this.onclick();
1715  };
1716
1717};
1718
1719PrevNextButton.prototype.activate = function() {
1720  // add to DOM
1721  this.parent.element.appendChild( this.element );
1722};
1723
1724PrevNextButton.prototype.deactivate = function() {
1725  // remove from DOM
1726  this.parent.element.removeChild( this.element );
1727};
1728
1729PrevNextButton.prototype.createSVG = function() {
1730  var svg = document.createElementNS( svgURI, 'svg');
1731  svg.setAttribute( 'viewBox', '0 0 100 100' );
1732  var path = document.createElementNS( svgURI, 'path');
1733  path.setAttribute( 'd', 'M 50,0 L 60,10 L 20,50 L 60,90 L 50,100 L 0,50 Z' );
1734  path.setAttribute( 'class', 'arrow' );
1735  // adjust arrow
1736  var arrowTransform = this.isLeft ? 'translate(15,0)' :
1737    'translate(85,100) rotate(180)';
1738  path.setAttribute( 'transform', arrowTransform );
1739  svg.appendChild( path );
1740  return svg;
1741};
1742
1743PrevNextButton.prototype.setArrowText = function() {
1744  var parentOptions = this.parent.options;
1745  var arrowText = this.isLeft ? parentOptions.leftArrowText : parentOptions.rightArrowText;
1746  utils.setText( this.element, arrowText );
1747};
1748
1749PrevNextButton.prototype.onclick = function() {
1750  if ( !this.isEnabled ) {
1751    return;
1752  }
1753  this.parent.uiChange();
1754  var method = this.isPrevious ? 'previous' : 'next';
1755  this.parent[ method ]();
1756};
1757
1758PrevNextButton.prototype.enable = function() {
1759  if ( this.isEnabled ) {
1760    return;
1761  }
1762  this.element.disabled = false;
1763  this.isEnabled = true;
1764};
1765
1766PrevNextButton.prototype.disable = function() {
1767  if ( !this.isEnabled ) {
1768    return;
1769  }
1770  this.element.disabled = true;
1771  this.isEnabled = false;
1772};
1773
1774PrevNextButton.prototype.update = function() {
1775  if ( this.parent.options.wrapAround ) {
1776    this.enable();
1777    return;
1778  }
1779  // index of first or last cell, if previous or next
1780  var boundIndex = this.isPrevious ? 0 : this.parent.cells.length - 1;
1781  var method = this.parent.selectedIndex == boundIndex ? 'disable' : 'enable';
1782  this[ method ]();
1783};
1784
1785return PrevNextButton;
1786
1787}));
1788
1789( function( window, factory ) {
1790  
1791  // universal module definition
1792
1793  if ( typeof define == 'function' && define.amd ) {
1794    // AMD
1795    define( 'flickity/js/page-dots',[
1796      'eventie/eventie',
1797      './utils'
1798    ], function( eventie, utils ) {
1799      return factory( window, eventie, utils );
1800    });
1801  } else if ( typeof exports == 'object' ) {
1802    // CommonJS
1803    module.exports = factory(
1804      window,
1805      require('eventie'),
1806      require('./utils')
1807    );
1808  } else {
1809    // browser global
1810    window.Flickity = window.Flickity || {};
1811    window.Flickity.PageDots = factory(
1812      window,
1813      window.eventie,
1814      window.utils
1815    );
1816  }
1817
1818}( window, function factory( window, eventie, U ) {
1819
1820// -------------------------- PageDots -------------------------- //
1821
1822
1823
1824function PageDots( parent ) {
1825  this.parent = parent;
1826  this._create();
1827}
1828
1829PageDots.prototype._create = function() {
1830  // create holder element
1831  this.holder = document.createElement('ol');
1832  this.holder.className = 'flickity-page-dots';
1833  // create dots, array of elements
1834  this.dots = [];
1835  // update on select
1836  var _this = this;
1837  this.onselect = function() {
1838    _this.updateSelected();
1839  };
1840  this.parent.on( 'select', this.onselect );
1841
1842  eventie.bind( this.holder, 'click', this );
1843};
1844
1845PageDots.prototype.activate = function() {
1846  this.setDots();
1847  this.updateSelected();
1848  // add to DOM
1849  this.parent.element.appendChild( this.holder );
1850};
1851
1852PageDots.prototype.deactivate = function() {
1853  // remove from DOM
1854  this.parent.element.removeChild( this.holder );
1855};
1856
1857PageDots.prototype.setDots = function() {
1858  // get difference between number of cells and number of dots
1859  var delta = this.parent.cells.length - this.dots.length;
1860  if ( delta > 0 ) {
1861    this.addDots( delta );
1862  } else if ( delta < 0 ) {
1863    this.removeDots( -delta );
1864  }
1865};
1866
1867PageDots.prototype.addDots = function( count ) {
1868  var fragment = document.createDocumentFragment();
1869  var newDots = [];
1870  while ( count ) {
1871    var dot = document.createElement('li');
1872    dot.className = 'dot';
1873    fragment.appendChild( dot );
1874    newDots.push( dot );
1875    count--;
1876  }
1877  this.holder.appendChild( fragment );
1878  this.dots = this.dots.concat( newDots );
1879};
1880
1881PageDots.prototype.removeDots = function( count ) {
1882  // remove from this.dots collection
1883  var removeDots = this.dots.splice( this.dots.length - count, count );
1884  // remove from DOM
1885  for ( var i=0, len = removeDots.length; i < len; i++ ) {
1886    var dot = removeDots[i];
1887    this.holder.removeChild( dot );
1888  }
1889};
1890
1891PageDots.prototype.updateSelected = function() {
1892  // remove selected class on previous
1893  if ( this.selectedDot ) {
1894    this.selectedDot.className = 'dot';
1895  }
1896
1897  this.selectedDot = this.dots[ this.parent.selectedIndex ];
1898  this.selectedDot.className = 'dot is-selected';
1899};
1900
1901// trigger handler methods for events
1902PageDots.prototype.handleEvent = function( event ) {
1903  var method = 'on' + event.type;
1904  if ( this[ method ] ) {
1905    this[ method ]( event );
1906  }
1907};
1908
1909PageDots.prototype.onclick = function( event ) {
1910  var target = event.target;
1911  // only care about dot clicks
1912  if ( target.nodeName != 'LI' ) {
1913    return;
1914  }
1915
1916  this.parent.uiChange();
1917  var index = U.indexOf( this.dots, target );
1918  this.parent.select( index );
1919};
1920
1921return PageDots;
1922
1923}));
1924
1925( function( window, factory ) {
1926  
1927  // universal module definition
1928
1929  if ( typeof define == 'function' && define.amd ) {
1930    // AMD
1931    define( 'flickity/js/player',[],function() {
1932      return factory();
1933    });
1934  } else if ( typeof exports == 'object' ) {
1935    // CommonJS
1936    module.exports = factory();
1937  } else {
1938    // browser global
1939    window.Flickity = window.Flickity || {};
1940    window.Flickity.Player = factory();
1941  }
1942
1943}( window, function factory() {
1944
1945
1946
1947function Player( parent ) {
1948  this.isPlaying = false;
1949  this.parent = parent;
1950}
1951
1952// start play
1953Player.prototype.play = function() {
1954  this.isPlaying = true;
1955  // playing kills pauses
1956  delete this.isPaused;
1957  // start ticking
1958  this.tick();
1959};
1960
1961Player.prototype.tick = function() {
1962  // do not tick if paused or not playing
1963  if ( !this.isPlaying || this.isPaused ) {
1964    return;
1965  }
1966  var time = this.parent.options.autoPlay;
1967  // default to 3 seconds
1968  time = typeof time == 'number' ? time : 3000;
1969  var _this = this;
1970  this.timeout = setTimeout( function() {
1971    _this.parent.next( true );
1972    _this.tick();
1973  }, time );
1974};
1975
1976Player.prototype.stop = function() {
1977  this.isPlaying = false;
1978  // stopping kills pauses
1979  delete this.isPaused;
1980  this.clear();
1981};
1982
1983Player.prototype.clear = function() {
1984  clearTimeout( this.timeout );
1985};
1986
1987Player.prototype.pause = function() {
1988  if ( this.isPlaying ) {
1989    this.isPaused = true;
1990    this.clear();
1991  }
1992};
1993
1994Player.prototype.unpause = function() {
1995  // re-start play if in unpaused state
1996  if ( this.isPaused ) {
1997    this.play();
1998  }
1999};
2000
2001return Player;
2002
2003}));
2004
2005( function( window, factory ) {
2006  
2007  // universal module definition
2008
2009  if ( typeof define == 'function' && define.amd ) {
2010    // AMD
2011    define( 'flickity/js/unipointer',[
2012      'eventie/eventie'
2013    ], function( eventie ) {
2014      return factory( window, eventie );
2015    });
2016  } else if ( typeof exports == 'object' ) {
2017    // CommonJS
2018    module.exports = factory(
2019      window,
2020      require('eventie')
2021    );
2022  } else {
2023    // browser global
2024    window.Unipointer = factory(
2025      window,
2026      window.eventie
2027    );
2028  }
2029
2030}( window, function factory( window, eventie ) {
2031
2032
2033
2034// -----  ----- //
2035
2036function noop() {}
2037
2038// -------------------------- Unipointer -------------------------- //
2039
2040function Unipointer() {}
2041
2042// trigger handler methods for events
2043Unipointer.prototype.handleEvent = function( event ) {
2044  var method = 'on' + event.type;
2045  if ( this[ method ] ) {
2046    this[ method ]( event );
2047  }
2048};
2049
2050// returns the touch that we're keeping track of
2051Unipointer.prototype.getTouch = function( touches ) {
2052  for ( var i=0, len = touches.length; i < len; i++ ) {
2053    var touch = touches[i];
2054    if ( touch.identifier == this.pointerIdentifier ) {
2055      return touch;
2056    }
2057  }
2058};
2059
2060// ----- bind start ----- //
2061
2062// works as unbinder, as you can .bindHandles( false ) to unbind
2063
2064/**
2065 * @param {Boolean} isBind - will unbind if falsey
2066 */
2067Unipointer.prototype.bindHandles = function( isBind ) {
2068  var binder;
2069  if ( window.navigator.pointerEnabled ) {
2070    binder = this.bindPointer;
2071  } else if ( window.navigator.msPointerEnabled ) {
2072    binder = this.bindMSPointer;
2073  } else {
2074    binder = this.bindMouseTouch;
2075  }
2076  // munge isBind, default to true
2077  isBind = isBind === undefined ? true : !!isBind;
2078  for ( var i=0, len = this.handles.length; i < len; i++ ) {
2079    var handle = this.handles[i];
2080    binder.call( this, handle, isBind );
2081  }
2082};
2083
2084Unipointer.prototype.bindPointer = function( handle, isBind ) {
2085  // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca
2086  var bindMethod = isBind ? 'bind' : 'unbind';
2087  eventie[ bindMethod ]( handle, 'pointerdown', this );
2088  // disable scrolling on the element
2089  handle.style.touchAction = isBind ? 'none' : '';
2090};
2091
2092Unipointer.prototype.bindMSPointer = function( handle, isBind ) {
2093  // IE10 Pointer Events
2094  var bindMethod = isBind ? 'bind' : 'unbind';
2095  eventie[ bindMethod ]( handle, 'MSPointerDown', this );
2096  // disable scrolling on the element
2097  handle.style.msTouchAction = isBind ? 'none' : '';
2098};
2099
2100Unipointer.prototype.bindMouseTouch = function( handle, isBind ) {
2101  // listen for both, for devices like Chrome Pixel
2102  //   which has touch and mouse events
2103  var bindMethod = isBind ? 'bind' : 'unbind';
2104  eventie[ bindMethod ]( handle, 'mousedown', this );
2105  eventie[ bindMethod ]( handle, 'touchstart', this );
2106  // TODO re-enable img.ondragstart when unbinding
2107  if ( isBind ) {
2108    disableImgOndragstart( handle );
2109  }
2110};
2111
2112// remove default dragging interaction on all images in IE8
2113// IE8 does its own drag thing on images, which messes stuff up
2114
2115function noDragStart() {
2116  return false;
2117}
2118
2119// TODO replace this with a IE8 test
2120var isIE8 = 'attachEvent' in document.documentElement;
2121
2122// IE8 only
2123var disableImgOndragstart = !isIE8 ? noop : function( handle ) {
2124
2125  if ( handle.nodeName == 'IMG' ) {
2126    handle.ondragstart = noDragStart;
2127  }
2128
2129  var images = handle.querySelectorAll('img');
2130  for ( var i=0, len = images.length; i < len; i++ ) {
2131    var img = images[i];
2132    img.ondragstart = noDragStart;
2133  }
2134};
2135
2136// ----- start event ----- //
2137
2138Unipointer.prototype.onmousedown = function( event ) {
2139  // dismiss clicks from right or middle buttons
2140  var button = event.button;
2141  if ( button && ( button !== 0 && button !== 1 ) ) {
2142    return;
2143  }
2144  this._pointerDown( event, event );
2145};
2146
2147Unipointer.prototype.ontouchstart = function( event ) {
2148  this._pointerDown( event, event.changedTouches[0] );
2149};
2150
2151Unipointer.prototype.onMSPointerDown =
2152Unipointer.prototype.onpointerdown = function( event ) {
2153  this._pointerDown( event, event );
2154};
2155
2156// hash of events to be bound after start event
2157var postStartEvents = {
2158  mousedown: [ 'mousemove', 'mouseup' ],
2159  touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
2160  pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
2161  MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ]
2162};
2163
2164/**
2165 * pointer start
2166 * @param {Event} event
2167 * @param {Event or Touch} pointer
2168 */
2169Unipointer.prototype._pointerDown = function( event, pointer ) {
2170  // dismiss other pointers
2171  if ( this.isPointerDown ) {
2172    return;
2173  }
2174
2175  this.isPointerDown = true;
2176
2177  // save pointer identifier to match up touch events
2178  this.pointerIdentifier = pointer.pointerId !== undefined ?
2179    // pointerId for pointer events, touch.indentifier for touch events
2180    pointer.pointerId : pointer.identifier;
2181
2182  // bind move and end events
2183  this._bindPostStartEvents({
2184    // get proper events to match start event
2185    events: postStartEvents[ event.type ],
2186    // IE8 needs to be bound to document
2187    node: event.preventDefault ? window : document
2188  });
2189
2190  this.pointerDown( event, pointer );
2191  this.emitEvent( 'pointerDown', [ this, event, pointer ] );
2192};
2193
2194Unipointer.prototype.pointerDown = noop;
2195
2196// ----- bind/unbind ----- //
2197
2198Unipointer.prototype._bindPostStartEvents = function( args ) {
2199  for ( var i=0, len = args.events.length; i < len; i++ ) {
2200    var event = args.events[i];
2201    eventie.bind( args.node, event, this );
2202  }
2203  // save these arguments
2204  this._boundPointerEvents = args;
2205};
2206
2207Unipointer.prototype._unbindPostStartEvents = function() {
2208  var args = this._boundPointerEvents;
2209  // IE8 can trigger dragEnd twice, check for _boundEvents
2210  if ( !args || !args.events ) {
2211    return;
2212  }
2213
2214  for ( var i=0, len = args.events.length; i < len; i++ ) {
2215    var event = args.events[i];
2216    eventie.unbind( args.node, event, this );
2217  }
2218  delete this._boundPointerEvents;
2219};
2220
2221// ----- move event ----- //
2222
2223Unipointer.prototype.onmousemove = function( event ) {
2224  this._pointerMove( event, event );
2225};
2226
2227Unipointer.prototype.onMSPointerMove =
2228Unipointer.prototype.onpointermove = function( event ) {
2229  if ( event.pointerId == this.pointerIdentifier ) {
2230    this._pointerMove( event, event );
2231  }
2232};
2233
2234Unipointer.prototype.ontouchmove = function( event ) {
2235  var touch = this.getTouch( event.changedTouches );
2236  if ( touch ) {
2237    this._pointerMove( event, touch );
2238  }
2239};
2240
2241/**
2242 * drag move
2243 * @param {Event} event
2244 * @param {Event or Touch} pointer
2245 */
2246Unipointer.prototype._pointerMove = function( event, pointer ) {
2247  this.pointerMove( event, pointer );
2248  this.emitEvent( 'pointerMove', [ this, event, pointer ] );
2249};
2250
2251Unipointer.prototype.pointerMove = noop;
2252
2253// ----- end event ----- //
2254
2255Unipointer.prototype.onmouseup = function( event ) {
2256  this._pointerUp( event, event );
2257};
2258
2259Unipointer.prototype.onMSPointerUp =
2260Unipointer.prototype.onpointerup = function( event ) {
2261  if ( event.pointerId == this.pointerIdentifier ) {
2262    this._pointerUp( event, event );
2263  }
2264};
2265
2266Unipointer.prototype.ontouchend = function( event ) {
2267  var touch = this.getTouch( event.changedTouches );
2268  if ( touch ) {
2269    this._pointerUp( event, touch );
2270  }
2271};
2272
2273/**
2274 * drag end
2275 * @param {Event} event
2276 * @param {Event or Touch} pointer
2277 */
2278Unipointer.prototype._pointerUp = function( event, pointer ) {
2279  this.isPointerDown = false;
2280
2281  delete this.pointerIdentifier;
2282
2283  // remove events
2284  this._unbindPostStartEvents();
2285
2286  this.pointerUp( event, pointer );
2287  this.emitEvent( 'pointerUp', [ this, event, pointer ] );
2288};
2289
2290Unipointer.prototype.pointerUp = noop;
2291
2292// ----- cancel event ----- //
2293
2294// coerce to end event
2295
2296Unipointer.prototype.onMSPointerCancel =
2297Unipointer.prototype.onpointercancel = function( event ) {
2298  if ( event.pointerId == this.pointerIdentifier ) {
2299    this._pointerUp( event, event );
2300  }
2301};
2302
2303Unipointer.prototype.ontouchcancel = function( event ) {
2304  var touch = this.getTouch( event.changedTouches );
2305  this._pointerUp( event, touch );
2306};
2307
2308// -----  ----- //
2309
2310Unipointer.getPointerPoint = function( pointer ) {
2311  return {
2312    x: pointer.pageX !== undefined ? pointer.pageX : pointer.clientX,
2313    y: pointer.pageY !== undefined ? pointer.pageY : pointer.clientY
2314  };
2315};
2316
2317// fix for IE8
2318Unipointer.setPointerPoint = function( point, pointer ) {
2319  point.x = pointer.pageX !== undefined ? pointer.pageX : pointer.clientX;
2320  point.y = pointer.pageY !== undefined ? pointer.pageY : pointer.clientY;
2321};
2322
2323// -----  ----- //
2324
2325return Unipointer;
2326
2327}));
2328
2329( function( window, factory ) {
2330  
2331  // universal module definition
2332
2333  if ( typeof define == 'function' && define.amd ) {
2334    // AMD
2335    define( 'flickity/js/drag',[
2336      './unipointer',
2337      'classie/classie',
2338      'eventie/eventie',
2339      './utils'
2340    ], function( Unipointer, eventie, utils ) {
2341      return factory( window, Unipointer, eventie, utils );
2342    });
2343  } else if ( typeof exports == 'object' ) {
2344    // CommonJS
2345    module.exports = factory(
2346      window,
2347      require('./unipointer'),
2348      require('desandro-classie'),
2349      require('eventie'),
2350      require('./utils')
2351    );
2352  } else {
2353    // browser global
2354    window.Flickity = window.Flickity || {};
2355    window.Flickity.dragPrototype = factory(
2356      window,
2357      window.Unipointer,
2358      window.classie,
2359      window.eventie,
2360      window.utils
2361    );
2362  }
2363
2364}( window, function factory( window, Unipointer, classie, eventie, U ) {
2365
2366
2367
2368// handle IE8 prevent default
2369function preventDefaultEvent( event ) {
2370  if ( event.preventDefault ) {
2371    event.preventDefault();
2372  } else {
2373    event.returnValue = false;
2374  }
2375}
2376
2377// -------------------------- drag prototype -------------------------- //
2378
2379var proto = {};
2380U.extend( proto, Unipointer.prototype );
2381
2382// --------------------------  -------------------------- //
2383
2384proto.bindDrag = function() {
2385  if ( !this.options.draggable ) {
2386    return;
2387  }
2388  this.handles = [ this.viewport ];
2389  this.bindHandles();
2390  // bind click handler
2391  eventie.bind( this.viewport, 'click', this );
2392};
2393
2394proto.unbindDrag = function() {
2395  if ( !this.options.draggable ) {
2396    return;
2397  }
2398  this.bindHandles( false );
2399  // unbind click handler
2400  eventie.unbind( this.viewport, 'click', this );
2401};
2402
2403// -------------------------- pointer events -------------------------- //
2404
2405var allowTouchstartNodes = {
2406  INPUT: true,
2407  A: true,
2408  BUTTON: true
2409};
2410
2411proto.pointerDown = function( event, pointer ) {
2412  var targetNodeName = event.target.nodeName;
2413  // HACK iOS, allow clicks on buttons, inputs, and links
2414  var isTouchstart = event.type == 'touchstart';
2415  var isTouchstartNode = allowTouchstartNodes[ targetNodeName ];
2416  if ( !isTouchstart || ( isTouchstart && !isTouchstartNode ) ) {
2417    preventDefaultEvent( event );
2418  }
2419  // kludge to blur focused inputs in dragger
2420  var focused = document.activeElement;
2421  if ( focused && focused.blur && focused != this.element ) {
2422    focused.blur();
2423  }
2424  // focus element, if its not an input
2425  if ( this.options.accessibility && targetNodeName != 'INPUT' ) {
2426    this.element.focus();
2427  }
2428  // stop if it was moving
2429  this.velocity = 0;
2430  // track to see when dragging starts
2431  this.pointerDownPoint = Unipointer.getPointerPoint( pointer );
2432  // stop auto play
2433  this.player.stop();
2434  classie.add( this.viewport, 'is-pointer-down' );
2435};
2436
2437proto.pointerMove = function( event, pointer ) {
2438  var movePoint = Unipointer.getPointerPoint( pointer );
2439  var dragMove = movePoint.x - this.pointerDownPoint.x;
2440  // start drag
2441  if ( !this.isDragging && Math.abs( dragMove ) > 3 ) {
2442    this.dragStart( event, pointer );
2443  }
2444
2445  this.dragMove( movePoint, event, pointer );
2446};
2447
2448proto.pointerUp = function( event, pointer ) {
2449  if ( this.isDragging ) {
2450    this.dragEnd( event, pointer );
2451  } else {
2452    // pointer didn't move enough for drag to start
2453    this.staticClick( event, pointer );
2454  }
2455  classie.remove( this.viewport, 'is-pointer-down' );
2456};
2457
2458// -------------------------- dragging -------------------------- //
2459
2460proto.dragStart = function( event, pointer ) {
2461  this.isDragging = true;
2462  this.dragStartPoint = Unipointer.getPointerPoint( pointer );
2463  this.dragStartPosition = this.x;
2464  this.startAnimation();
2465  // prevent clicks
2466  this.isPreventingClicks = true;
2467  this.dispatchEvent( 'dragStart', event, [ pointer ] );
2468};
2469
2470proto.dragMove = function( movePoint, event, pointer ) {
2471  // do not drag if not dragging yet
2472  if ( !this.isDragging ) {
2473    return;
2474  }
2475
2476  this.previousDragX = this.x;
2477
2478  var movedX = movePoint.x - this.dragStartPoint.x;
2479  // reverse if right-to-left
2480  var direction = this.options.rightToLeft ? -1 : 1;
2481  this.x = this.dragStartPosition + movedX * direction;
2482
2483  if ( !this.options.wrapAround && this.cells.length ) {
2484    // slow drag
2485    var originBound = Math.max( -this.cells[0].target, this.dragStartPosition);
2486    this.x = this.x > originBound ? ( this.x - originBound ) * 0.5 + originBound : this.x;
2487    var endBound = Math.min( -this.getLastCell().target, this.dragStartPosition );
2488    this.x = this.x < endBound ? ( this.x - endBound ) * 0.5 + endBound : this.x;
2489  }
2490
2491  this.previousDragMoveTime = this.dragMoveTime;
2492  this.dragMoveTime = new Date();
2493  this.dispatchEvent( 'dragMove', event, [ pointer ] );
2494};
2495
2496proto.dragEnd = function( event, pointer ) {
2497  this.dragEndFlick();
2498  if ( this.options.freeScroll ) {
2499    this.isFreeScrolling = true;
2500  }
2501  // set selectedIndex based on where flick will end up
2502  var index = this.dragEndRestingSelect();
2503
2504  if ( this.options.freeScroll && !this.options.wrapAround ) {
2505    // if free-scroll & not wrap around
2506    // do not free-scroll if going outside of bounding cells
2507    // so bounding cells can attract slider, and keep it in bounds
2508    var restingX = this.getRestingPosition();
2509    this.isFreeScrolling = -restingX > this.cells[0].target &&
2510      -restingX < this.getLastCell().target;
2511  } else if ( !this.options.freeScroll && index == this.selectedIndex ) {
2512    // boost selection if selected index has not changed
2513    index += this.dragEndBoostSelect();
2514  }
2515  // apply selection
2516  // TODO refactor this, selecting here feels weird
2517  this.select( index );
2518  // set flags
2519  this.isDragging = false;
2520  // re-enable clicking async
2521  var _this = this;
2522  setTimeout( function() {
2523    delete _this.isPreventingClicks;
2524  });
2525
2526  this.dispatchEvent( 'dragEnd', event, [ pointer ] );
2527};
2528
2529// apply velocity after dragging
2530proto.dragEndFlick = function() {
2531  if ( !isFinite( this.previousDragX ) ) {
2532    return;
2533  }
2534  // set slider velocity
2535  var timeDelta = this.dragMoveTime - this.previousDragMoveTime;
2536  // 60 frames per second, ideally
2537  // TODO, velocity should be in pixels per millisecond
2538  // currently in pixels per frame
2539  timeDelta /= 1000 / 60;
2540  var xDelta = this.x - this.previousDragX;
2541  this.velocity = xDelta / timeDelta;
2542  // reset
2543  delete this.previousDragX;
2544};
2545
2546proto.dragEndRestingSelect = function() {
2547  var restingX = this.getRestingPosition();
2548  // how far away from selected cell
2549  var distance = Math.abs( this.getCellDistance( -restingX, this.selectedIndex ) );
2550  // get closet resting going up and going down
2551  var positiveResting = this._getClosestResting( restingX, distance, 1 );
2552  var negativeResting = this._getClosestResting( restingX, distance, -1 );
2553  // use closer resting for wrap-around
2554  var index = positiveResting.distance < negativeResting.distance ?
2555    positiveResting.index : negativeResting.index;
2556  return index;
2557};
2558
2559/**
2560 * given resting X and distance to selected cell
2561 * get the distance and index of the closest cell
2562 * @param {Number} restingX - estimated post-flick resting position
2563 * @param {Number} distance - distance to selected cell
2564 * @param {Integer} increment - +1 or -1, going up or down
2565 * @returns {Object} - { distance: {Number}, index: {Integer} }
2566 */
2567proto._getClosestResting = function( restingX, distance, increment ) {
2568  var index = this.selectedIndex;
2569  var minDistance = Infinity;
2570  var condition = this.options.contain && !this.options.wrapAround ?
2571    // if fit-content, keep going if distance is equal to minDistance
2572    function( d, md ) { return d <= md; } : function( d, md ) { return d < md; };
2573  while ( condition( distance, minDistance ) ) {
2574    // measure distance to next cell
2575    index += increment;
2576    minDistance = distance;
2577    distance = this.getCellDistance( -restingX, index );
2578    if ( distance === null ) {
2579      break;
2580    }
2581    distance = Math.abs( distance );
2582  }
2583  return {
2584    distance: minDistance,
2585    // selected was previous index
2586    index: index - increment
2587  };
2588};
2589
2590/**
2591 * measure distance between x and a cell target
2592 * @param {Number} x
2593 * @param {Integer} index - cell index
2594 */
2595proto.getCellDistance = function( x, index ) {
2596  var len = this.cells.length;
2597  var cellIndex = this.options.wrapAround ? U.modulo( index, len ) : index;
2598  var cell = this.cells[ cellIndex ];
2599  if ( !cell ) {
2600    return null;
2601  }
2602  // add distance for wrap-around cells
2603  var wrap = this.options.wrapAround ? this.slideableWidth * Math.floor( index / len ) : 0;
2604  return x - ( cell.target + wrap );
2605};
2606
2607proto.dragEndBoostSelect = function() {
2608  var distance = this.getCellDistance( -this.x, this.selectedIndex );
2609  if ( distance > 0 && this.velocity < -1 ) {
2610    // if moving towards the right, and positive velocity, and the next attractor
2611    return 1;
2612  } else if ( distance < 0 && this.velocity > 1 ) {
2613    // if moving towards the left, and negative velocity, and previous attractor
2614    return -1;
2615  }
2616  return 0;
2617};
2618
2619// ----- onclick ----- //
2620
2621// handle all clicks and prevent clicks when dragging
2622proto.onclick = function( event ) {
2623  if ( this.isPreventingClicks ) {
2624    preventDefaultEvent( event );
2625  }
2626};
2627
2628// ----- staticClick ----- //
2629
2630// triggered after pointer down & up with no/tiny movement
2631proto.staticClick = function( event, pointer ) {
2632  // allow click in text input
2633  if ( event.target.nodeName == 'INPUT' && event.target.type == 'text' ) {
2634    event.target.focus();
2635  }
2636  this.dispatchEvent( 'staticClick', event, [ pointer ] );
2637};
2638
2639// -----  ----- //
2640
2641return proto;
2642
2643}));
2644
2645( function( window, factory ) {
2646  
2647  // universal module definition
2648
2649  if ( typeof define == 'function' && define.amd ) {
2650    // AMD
2651    define( 'flickity/js/animate',[
2652      'get-style-property/get-style-property',
2653      './utils'
2654    ], function( getStyleProperty, utils ) {
2655      return factory( window, getStyleProperty, utils );
2656    });
2657  } else if ( typeof exports == 'object' ) {
2658    // CommonJS
2659    module.exports = factory(
2660      window,
2661      require('desandro-get-style-property'),
2662      require('./utils')
2663    );
2664  } else {
2665    // browser global
2666    window.Flickity = window.Flickity || {};
2667    window.Flickity.animatePrototype = factory(
2668      window,
2669      window.getStyleProperty,
2670      window.utils
2671    );
2672  }
2673
2674}( window, function factory( window, getStyleProperty, U ) {
2675
2676
2677
2678// -------------------------- requestAnimationFrame -------------------------- //
2679
2680// https://gist.github.com/1866474
2681
2682var lastTime = 0;
2683var prefixes = 'webkit moz ms o'.split(' ');
2684// get unprefixed rAF and cAF, if present
2685var requestAnimationFrame = window.requestAnimationFrame;
2686var cancelAnimationFrame = window.cancelAnimationFrame;
2687// loop through vendor prefixes and get prefixed rAF and cAF
2688var prefix;
2689for( var i = 0; i < prefixes.length; i++ ) {
2690  if ( requestAnimationFrame && cancelAnimationFrame ) {
2691    break;
2692  }
2693  prefix = prefixes[i];
2694  requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];
2695  cancelAnimationFrame  = cancelAnimationFrame  || window[ prefix + 'CancelAnimationFrame' ] ||
2696                            window[ prefix + 'CancelRequestAnimationFrame' ];
2697}
2698
2699// fallback to setTimeout and clearTimeout if either request/cancel is not supported
2700if ( !requestAnimationFrame || !cancelAnimationFrame )  {
2701  requestAnimationFrame = function( callback ) {
2702    var currTime = new Date().getTime();
2703    var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
2704    var id = window.setTimeout( function() {
2705      callback( currTime + timeToCall );
2706    }, timeToCall );
2707    lastTime = currTime + timeToCall;
2708    return id;
2709  };
2710
2711  cancelAnimationFrame = function( id ) {
2712    window.clearTimeout( id );
2713  };
2714}
2715
2716// -------------------------- animate -------------------------- //
2717
2718var proto = {};
2719
2720proto.startAnimation = function() {
2721  if ( this.isAnimating ) {
2722    return;
2723  }
2724
2725  this.isAnimating = true;
2726  this.restingFrames = 0;
2727  this.animate();
2728};
2729
2730proto.animate = function() {
2731  this.applySelectedAttraction();
2732
2733  var previousX = this.x;
2734
2735  this.updatePhysics();
2736  this.positionSlider();
2737  this.settle( previousX );
2738  // animate next frame
2739  if ( this.isAnimating ) {
2740    var _this = this;
2741    requestAnimationFrame( function animateFrame() {
2742      _this.animate();
2743    });
2744  }
2745
2746  /** /
2747  // log animation frame rate
2748  var now = new Date();
2749  if ( this.then ) {
2750    console.log( ~~( 1000 / (now-this.then)) + 'fps' )
2751  }
2752  this.then = now;
2753  /**/
2754};
2755
2756
2757var transformProperty = getStyleProperty('transform');
2758var is3d = !!getStyleProperty('perspective');
2759
2760proto.positionSlider = function() {
2761  var x = this.x;
2762  // wrap position around
2763  if ( this.options.wrapAround ) {
2764    x = U.modulo( x, this.slideableWidth );
2765    x = x - this.slideableWidth;
2766    this.shiftWrapCells( x );
2767  }
2768
2769  x = x + this.cursorPosition;
2770
2771  // reverse if right-to-left and using transform
2772  x = this.options.rightToLeft && transformProperty ? -x : x;
2773
2774  var value = this.getPositionValue( x );
2775
2776  if ( transformProperty ) {
2777    // use 3D tranforms for hardware acceleration on iOS
2778    // but use 2D when settled, for better font-rendering
2779    this.slider.style[ transformProperty ] = is3d && this.isAnimating ?
2780      'translate3d(' + value + ',0,0)' : 'translateX(' + value + ')';
2781  } else {
2782    this.slider.style[ this.originSide ] = value;
2783  }
2784};
2785
2786proto.positionSliderAtSelected = function() {
2787  var selectedCell = this.cells[ this.selectedIndex ];
2788  this.x = -selectedCell.target;
2789  this.positionSlider();
2790};
2791
2792proto.getPositionValue = function( position ) {
2793  if ( this.options.percentPosition ) {
2794    // percent position, round to 2 digits, like 12.34%
2795    return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 )+ '%';
2796  } else {
2797    // pixel positioning
2798    return Math.round( position ) + 'px';
2799  }
2800};
2801
2802proto.settle = function( previousX ) {
2803  // keep track of frames where x hasn't moved
2804  if ( !this.isPointerDown && Math.round( this.x * 100 ) == Math.round( previousX * 100 ) ) {
2805    this.restingFrames++;
2806  }
2807  // stop animating if resting for 3 or more frames
2808  if ( this.restingFrames > 2 ) {
2809    this.isAnimating = false;
2810    delete this.isFreeScrolling;
2811    // render position with translateX when settled
2812    if ( is3d ) {
2813      this.positionSlider();
2814    }
2815    this.dispatchEvent('settle');
2816  }
2817};
2818
2819proto.shiftWrapCells = function( x ) {
2820  // shift before cells
2821  var beforeGap = this.cursorPosition + x;
2822  this._shiftCells( this.beforeShiftCells, beforeGap, -1 );
2823  // shift after cells
2824  var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );
2825  this._shiftCells( this.afterShiftCells, afterGap, 1 );
2826};
2827
2828proto._shiftCells = function( cells, gap, shift ) {
2829  for ( var i=0, len = cells.length; i < len; i++ ) {
2830    var cell = cells[i];
2831    var cellShift = gap > 0 ? shift : 0;
2832    cell.wrapShift( cellShift );
2833    gap -= cell.size.outerWidth;
2834  }
2835};
2836
2837proto._unshiftCells = function( cells ) {
2838  if ( !cells || !cells.length ) {
2839    return;
2840  }
2841  for ( var i=0, len = cells.length; i < len; i++ ) {
2842    cells[i].wrapShift( 0 );
2843  }
2844};
2845
2846// -------------------------- physics -------------------------- //
2847
2848proto.updatePhysics = function() {
2849  this.velocity += this.accel;
2850  this.x += this.velocity;
2851  this.velocity *= this.getFrictionFactor();
2852  // reset acceleration
2853  this.accel = 0;
2854};
2855
2856proto.applyForce = function( force ) {
2857  this.accel += force;
2858};
2859
2860proto.getFrictionFactor = function() {
2861  return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];
2862};
2863
2864
2865proto.getRestingPosition = function() {
2866  // my thanks to Steven Wittens, who simplified this math greatly
2867  return this.x + this.velocity / ( 1 - this.getFrictionFactor() );
2868};
2869
2870
2871proto.applySelectedAttraction = function() {
2872  // do not attract if pointer down or no cells
2873  if ( this.isPointerDown || this.isFreeScrolling || !this.cells.length ) {
2874    return;
2875  }
2876  var cell = this.cells[ this.selectedIndex ];
2877  var wrap = this.options.wrapAround ?
2878    this.slideableWidth * Math.floor( this.selectedIndex / this.cells.length ) : 0;
2879  var distance = ( cell.target + wrap ) * -1 - this.x;
2880  var force = distance * this.options.selectedAttraction;
2881  this.applyForce( force );
2882};
2883
2884return proto;
2885
2886}));
2887
2888( function( window, factory ) {
2889  
2890  // universal module definition
2891
2892  if ( typeof define == 'function' && define.amd ) {
2893    // AMD
2894    define( 'flickity/js/cell-change',[
2895      './utils'
2896    ], function( utils ) {
2897      return factory( window, utils );
2898    });
2899  } else if ( typeof exports == 'object' ) {
2900    // CommonJS
2901    module.exports = factory(
2902      window,
2903      require('./utils')
2904    );
2905  } else {
2906    // browser global
2907    window.Flickity = window.Flickity || {};
2908    window.Flickity.cellChangePrototype = factory(
2909      window,
2910      window.utils
2911    );
2912  }
2913
2914})( window, function factory( window, U ) {
2915
2916
2917
2918// append cells to a document fragment
2919function getCellsFragment( cells ) {
2920  var fragment = document.createDocumentFragment();
2921  for ( var i=0, len = cells.length; i < len; i++ ) {
2922    var cell = cells[i];
2923    fragment.appendChild( cell.element );
2924  }
2925  return fragment;
2926}
2927
2928// -------------------------- cell change prototype -------------------------- //
2929
2930var proto = {};
2931
2932/**
2933 * Insert, prepend, or append cells
2934 * @param {Element, Array, NodeList} elems
2935 * @param {Integer} index
2936 */
2937proto.insert = function( elems, index ) {
2938  var cells = this._makeCells( elems );
2939  if ( !cells || !cells.length ) {
2940    return;
2941  }
2942  var len = this.cells.length;
2943  // default to append
2944  index = index === undefined ? len : index;
2945  // add cells with document fragment
2946  var fragment = getCellsFragment( cells );
2947  // append to slider
2948  var isAppend = index == len;
2949  if ( isAppend ) {
2950    this.slider.appendChild( fragment );
2951  } else {
2952    var insertCellElement = this.cells[ index ].element;
2953    this.slider.insertBefore( fragment, insertCellElement );
2954  }
2955  // add to this.cells
2956  if ( index === 0 ) {
2957    // prepend, add to start
2958    this.cells = cells.concat( this.cells );
2959  } else if ( isAppend ) {
2960    // append, add to end
2961    this.cells = this.cells.concat( cells );
2962  } else {
2963    // insert in this.cells
2964    var endCells = this.cells.splice( index, len - index );
2965    this.cells = this.cells.concat( cells ).concat( endCells );
2966  }
2967
2968  this._sizeCells( cells );
2969  this._cellAddedRemoved( index );
2970};
2971
2972proto.append = function( elems ) {
2973  this.insert( elems, this.cells.length );
2974};
2975
2976proto.prepend = function( elems ) {
2977  this.insert( elems, 0 );
2978};
2979
2980/**
2981 * Remove cells
2982 * @param {Element, Array, NodeList} elems
2983 */
2984proto.remove = function( elems ) {
2985  var cells = this.getCells( elems );
2986  for ( var i=0, len = cells.length; i < len; i++ ) {
2987    var cell = cells[i];
2988    cell.remove();
2989    // remove item from collection
2990    U.removeFrom( cell, this.cells );
2991  }
2992
2993  if ( cells.length ) {
2994    // update stuff
2995    this._cellAddedRemoved( 0 );
2996  }
2997};
2998
2999// updates when cells are added or removed
3000proto._cellAddedRemoved = function( index ) {
3001  // update page dots
3002  if ( this.pageDots ) {
3003    this.pageDots.setDots();
3004  }
3005  // TODO cell is removed before the selected cell, adjust selectedIndex by -1
3006  this.selectedIndex = Math.max( 0, Math.min( this.cells.length - 1, this.selectedIndex ) );
3007
3008  this.cellChange( index );
3009};
3010
3011/**
3012 * logic to be run after a cell's size changes
3013 * @param {Element} elem - cell's element
3014 */
3015proto.cellSizeChange = function( elem ) {
3016  var cell = this.getCell( elem );
3017  if ( !cell ) {
3018    return;
3019  }
3020  cell.getSize();
3021
3022  var index = U.indexOf( this.cells, cell );
3023  this.cellChange( index );
3024};
3025
3026/**
3027 * logic any time a cell is changed: added, removed, or size changed
3028 * @param {Integer} index - index of the changed cell, optional
3029 */
3030proto.cellChange = function( index ) {
3031  // TODO maybe always size all cells unless isSkippingSizing
3032  // size all cells if necessary
3033  // if ( !isSkippingSizing ) {
3034  //   this._sizeCells( this.cells );
3035  // }
3036
3037  index = index || 0;
3038
3039  this._positionCells( index );
3040  this._getWrapShiftCells();
3041  this.setContainerSize();
3042  // position slider
3043  if ( this.options.freeScroll ) {
3044    this.positionSlider();
3045  } else {
3046    this.select( this.selectedIndex );
3047  }
3048};
3049
3050// -----  ----- //
3051
3052return proto;
3053
3054});
3055
3056/*!
3057 * Flickity v0.1.0
3058 * Touch, responsive, flickable galleries
3059 * http://flickity.metafizzy.co
3060 * Copyright 2015 Metafizzy
3061 */
3062
3063( function( window, factory ) {
3064  
3065  // universal module definition
3066
3067  if ( typeof define == 'function' && define.amd ) {
3068    // AMD
3069    define( [
3070      'classie/classie',
3071      'eventEmitter/EventEmitter',
3072      'eventie/eventie',
3073      'get-size/get-size',
3074      'flickity/js/utils',
3075      'flickity/js/cell',
3076      'flickity/js/prev-next-button',
3077      'flickity/js/page-dots',
3078      'flickity/js/player',
3079      'flickity/js/drag',
3080      'flickity/js/animate',
3081      'flickity/js/cell-change'
3082    ], function( classie, EventEmitter, eventie, getSize, U, Cell, PrevNextButton, PageDots, Player, dragPrototype, animatePrototype, cellChangePrototype ) {
3083      return factory( window, classie, EventEmitter, eventie, getSize, U, Cell, PrevNextButton, PageDots, Player, dragPrototype, animatePrototype, cellChangePrototype );
3084    });
3085  } else if ( typeof exports == 'object' ) {
3086    // CommonJS
3087    module.exports = factory(
3088      window,
3089      require('desandro-classie'),
3090      require('wolfy87-eventemitter'),
3091      require('eventie'),
3092      require('get-size'),
3093      require('./utils'),
3094      require('./cell'),
3095      require('./prev-next-button'),
3096      require('./page-dots'),
3097      require('./player'),
3098      require('./drag'),
3099      require('./animate'),
3100      require('./cell-change')
3101    );
3102  } else {
3103    // browser global
3104    var _Flickity = window.Flickity;
3105
3106    window.Flickity = factory(
3107      window,
3108      window.classie,
3109      window.EventEmitter,
3110      window.eventie,
3111      window.getSize,
3112      window.utils,
3113      _Flickity.Cell,
3114      _Flickity.PrevNextButton,
3115      _Flickity.PageDots,
3116      _Flickity.Player,
3117      _Flickity.dragPrototype,
3118      _Flickity.animatePrototype,
3119      _Flickity.cellChangePrototype
3120    );
3121  }
3122
3123}( window, function factory( window, classie, EventEmitter, eventie, getSize,
3124  U, Cell, PrevNextButton, PageDots, Player, dragPrototype, animatePrototype,
3125  cellChangePrototype ) {
3126
3127
3128
3129// vars
3130var jQuery = window.jQuery;
3131var getComputedStyle = window.getComputedStyle;
3132var console = window.console;
3133var imagesLoaded = window.imagesLoaded;
3134
3135function moveChildren( fromElem, toElem ) {
3136  while ( fromElem.children.length ) {
3137    toElem.appendChild( fromElem.children[0] );
3138  }
3139}
3140
3141// -------------------------- Flickity -------------------------- //
3142
3143// globally unique identifiers
3144var GUID = 0;
3145// internal store of all Flickity intances
3146var instances = {};
3147
3148function Flickity( element, options ) {
3149  var queryElement = U.getQueryElement( element );
3150  if ( !queryElement ) {
3151    if ( console ) {
3152      console.error( 'Bad element for Flickity: ' + ( queryElement || element ) );
3153    }
3154    return;
3155  }
3156  this.element = queryElement;
3157  // add jQuery
3158  if ( jQuery ) {
3159    this.$element = jQuery( this.element );
3160  }
3161  // options
3162  this.options = U.extend( {}, this.constructor.defaults );
3163  this.option( options );
3164
3165  // kick things off
3166  this._create();
3167}
3168
3169Flickity.defaults = {
3170  accessibility: true,
3171  // autoPlay: undefined,
3172  freeScrollFriction: 0.075, // friction when free-scrolling
3173  friction: 0.28, // friction when selecting
3174  cellAlign: 'center',
3175  // cellSelector: undefined,
3176  // contain: false,
3177  draggable: true,
3178  // initialIndex: 0,
3179  // imagesLoaded: false,
3180  percentPosition: true,
3181  pageDots: true,
3182  prevNextButtons: true,
3183  resizeBound: true,
3184  // watcCSS: false,
3185  // wrapAround: false,
3186  selectedAttraction: 0.025,
3187  leftArrowText: '←', // text for prev/next button when no SVG support
3188  rightArrowText: '→'
3189};
3190
3191// inherit EventEmitter
3192U.extend( Flickity.prototype, EventEmitter.prototype );
3193
3194Flickity.prototype._create = function() {
3195  // add id for Flickity.data
3196  var id = this.guid = ++GUID;
3197  this.element.flickityGUID = id; // expando
3198  instances[ id ] = this; // associate via id
3199  // initial properties
3200  this.selectedIndex = this.options.initialIndex || 0;
3201  // how many frames slider has been in same position
3202  this.restingFrames = 0;
3203  // initial physics properties
3204  this.x = 0;
3205  this.velocity = 0;
3206  this.accel = 0;
3207  this.originSide = this.options.rightToLeft ? 'right' : 'left';
3208  // create viewport & slider
3209  this.viewport = document.createElement('div');
3210  this.viewport.className = 'flickity-viewport';
3211  this._createSlider();
3212  // create prev/next buttons, page dots, and player
3213  if ( this.options.prevNextButtons ) {
3214    this.prevButton = new PrevNextButton( -1, this );
3215    this.nextButton = new PrevNextButton( 1, this );
3216  }
3217  if ( this.options.pageDots ) {
3218    this.pageDots = new PageDots( this );
3219  }
3220  this.player = new Player( this );
3221
3222  if ( this.options.resizeBound || this.options.watchCSS ) {
3223    eventie.bind( window, 'resize', this );
3224  }
3225
3226  if ( this.options.watchCSS ) {
3227    this.watchCSS();
3228  } else {
3229    this.activate();
3230  }
3231
3232};
3233
3234/**
3235 * set options
3236 * @param {Object} opts
3237 */
3238Flickity.prototype.option = function( opts ) {
3239  U.extend( this.options, opts );
3240};
3241
3242Flickity.prototype.activate = function() {
3243  if ( this.isActive ) {
3244    return;
3245  }
3246  this.isActive = true;
3247  classie.add( this.element, 'flickity-enabled' );
3248  // move children to slider
3249  moveChildren( this.element, this.slider );
3250  this.viewport.appendChild( this.slider );
3251  this.element.appendChild( this.viewport );
3252
3253  this.getSize();
3254  // get cells from children
3255  this.reloadCells();
3256  this.setContainerSize();
3257  // activate prev/next buttons, page dots
3258  if ( this.prevButton ) {
3259    this.prevButton.activate();
3260  }
3261  if ( this.nextButton ) {
3262    this.nextButton.activate();
3263  }
3264  if ( this.pageDots ) {
3265    this.pageDots.activate();
3266  }
3267  // player
3268  if ( this.options.autoPlay ) {
3269    this.player.play();
3270    // add hover listeners
3271    eventie.bind( this.element, 'mouseenter', this );
3272    // TODO add event for pointer enter
3273  }
3274
3275  this.positionSliderAtSelected();
3276  this.select( this.selectedIndex );
3277
3278  this.imagesLoaded();
3279
3280  // events
3281  this.bindDrag();
3282
3283  if ( this.options.accessibility ) {
3284    // allow element to focusable
3285    this.element.tabIndex = 0;
3286    // listen for key presses
3287    eventie.bind( this.element, 'keydown', this );
3288  }
3289};
3290
3291// slider positions the cells
3292Flickity.prototype._createSlider = function() {
3293  // slider element does all the positioning
3294  var slider = document.createElement('div');
3295  slider.className = 'flickity-slider';
3296  slider.style[ this.originSide ] = 0;
3297  this.slider = slider;
3298};
3299
3300// goes through all children
3301Flickity.prototype.reloadCells = function() {
3302  // collection of item elements
3303  this.cells = this._makeCells( this.slider.children );
3304  this.positionCells( this.cells );
3305  this._getWrapShiftCells();
3306  this.setContainerSize();
3307};
3308
3309/**
3310 * turn elements into Flickity.Cells
3311 * @param {Array or NodeList or HTMLElement} elems
3312 * @returns {Array} items - collection of new Flickity Cells
3313 */
3314Flickity.prototype._makeCells = function( elems ) {
3315  var cellElems = U.filterFindElements( elems, this.options.cellSelector );
3316
3317  // create new Flickity for collection
3318  var cells = [];
3319  for ( var i=0, len = cellElems.length; i < len; i++ ) {
3320    var elem = cellElems[i];
3321    var cell = new Cell( elem, this );
3322    cells.push( cell );
3323  }
3324
3325  return cells;
3326};
3327
3328Flickity.prototype.getLastCell = function() {
3329  return this.cells[ this.cells.length - 1 ];
3330};
3331
3332// positions all cells
3333Flickity.prototype.positionCells = function() {
3334  // size all cells
3335  this._sizeCells( this.cells );
3336  // position all cells
3337  this._positionCells( 0 );
3338};
3339
3340/**
3341 * position certain cells
3342 * @param {Integer} index - which cell to start with
3343 */
3344Flickity.prototype._positionCells = function( index ) {
3345  // also measure maxCellHeight
3346  // start 0 if positioning all cells
3347  this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;
3348  var cellX = 0;
3349  // get cellX
3350  if ( index > 0 ) {
3351    var startCell = this.cells[ index - 1 ];
3352    cellX = startCell.x + startCell.size.outerWidth;
3353  }
3354  var cell;
3355  for ( var len = this.cells.length, i=index; i < len; i++ ) {
3356    cell = this.cells[i];
3357    cell.setPosition( cellX );
3358    cellX += cell.size.outerWidth;
3359    this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );
3360  }
3361  // keep track of cellX for wrap-around
3362  this.slideableWidth = cellX;
3363  // contain cell target
3364  this._containCells();
3365};
3366
3367/**
3368 * cell.getSize() on multiple cells
3369 * @param {Array} cells
3370 */
3371Flickity.prototype._sizeCells = function( cells ) {
3372  for ( var i=0, len = cells.length; i < len; i++ ) {
3373    var cell = cells[i];
3374    cell.getSize();
3375  }
3376};
3377
3378Flickity.prototype.getSize = function() {
3379  this.size = getSize( this.element );
3380  this.setCellAlign();
3381  this.cursorPosition = this.size.innerWidth * this.cellAlign;
3382};
3383
3384var cellAlignShorthands = {
3385  // cell align, then based on origin side
3386  center: {
3387    left: 0.5,
3388    right: 0.5
3389  },
3390  left: {
3391    left: 0,
3392    right: 1
3393  },
3394  right: {
3395    right: 0,
3396    left: 1
3397  }
3398};
3399
3400Flickity.prototype.setCellAlign = function() {
3401  var shorthand = cellAlignShorthands[ this.options.cellAlign ];
3402  this.cellAlign = shorthand ? shorthand[ this.originSide ] : this.options.cellAlign;
3403};
3404
3405Flickity.prototype.setContainerSize = function() {
3406  this.viewport.style.height = this.maxCellHeight + 'px';
3407};
3408
3409Flickity.prototype._getWrapShiftCells = function() {
3410  // only for wrap-around
3411  if ( !this.options.wrapAround ) {
3412    return;
3413  }
3414  // unshift previous cells
3415  this._unshiftCells( this.beforeShiftCells );
3416  this._unshiftCells( this.afterShiftCells );
3417  // get before cells
3418  // initial gap
3419  var gapX = this.cursorPosition;
3420  var cellIndex = this.cells.length - 1;
3421  this.beforeShiftCells = this._getGapCells( gapX, cellIndex, -1 );
3422  // get after cells
3423  // ending gap between last cell and end of gallery viewport
3424  gapX = this.size.innerWidth - this.cursorPosition;
3425  // start cloning at first cell, working forwards
3426  this.afterShiftCells = this._getGapCells( gapX, 0, 1 );
3427};
3428
3429Flickity.prototype._getGapCells = function( gapX, cellIndex, increment ) {
3430  // keep adding cells until the cover the initial gap
3431  var cells = [];
3432  while ( gapX > 0 ) {
3433    var cell = this.cells[ cellIndex ];
3434    if ( !cell ) {
3435      break;
3436    }
3437    cells.push( cell );
3438    cellIndex += increment;
3439    gapX -= cell.size.outerWidth;
3440  }
3441  return cells;
3442};
3443
3444// ----- contain ----- //
3445
3446// contain cell targets so no excess sliding
3447Flickity.prototype._containCells = function() {
3448  if ( !this.options.contain || this.options.wrapAround ) {
3449    return;
3450  }
3451  // end limit
3452  var lastCell = this.getLastCell();
3453  var endMargin = this.options.rightToLeft ? 'marginLeft' : 'marginRight';
3454  var contentWidth = this.slideableWidth - lastCell.size[ endMargin ];
3455  var endLimit = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );
3456  // contain each cell target
3457  for ( var i=0, len = this.cells.length; i < len; i++ ) {
3458    var cell = this.cells[i];
3459    // reset default target
3460    cell.setDefaultTarget();
3461    cell.target = Math.max( cell.target, this.cursorPosition );
3462    cell.target = Math.min( cell.target, endLimit );
3463  }
3464};
3465
3466// -----  ----- //
3467
3468/**
3469 * emits events via eventEmitter and jQuery events
3470 * @param {String} type - name of event
3471 * @param {Event} event - original event
3472 * @param {Array} args - extra arguments
3473 */
3474Flickity.prototype.dispatchEvent = function( type, event, args ) {
3475  var emitArgs = [ event ].concat( args );
3476  this.emitEvent( type, emitArgs );
3477
3478  if ( jQuery && this.$element ) {
3479    if ( event ) {
3480      // create jQuery event
3481      var $event = jQuery.Event( event );
3482      $event.type = type;
3483      this.$element.trigger( $event, args );
3484    } else {
3485      // just trigger with type if no event available
3486      this.$element.trigger( type, args );
3487    }
3488  }
3489};
3490
3491// -------------------------- select -------------------------- //
3492
3493/**
3494 * @param {Integer} index - index of the cell
3495 * @param {Boolean} isWrap - will wrap-around to last/first if at the end
3496 */
3497Flickity.prototype.select = function( index, isWrap ) {
3498  if ( !this.isActive ) {
3499    return;
3500  }
3501  // wrap position so slider is within normal area
3502  if ( this.options.wrapAround ) {
3503    if ( index < 0 ) {
3504      this.x -= this.slideableWidth;
3505    } else if ( index >= this.cells.length ) {
3506      this.x += this.slideableWidth;
3507    }
3508  }
3509
3510  if ( this.options.wrapAround || isWrap ) {
3511    index = U.modulo( index, this.cells.length );
3512  }
3513
3514  if ( this.cells[ index ] ) {
3515    this.selectedIndex = index;
3516    this.setSelectedCell();
3517    this.startAnimation();
3518    this.dispatchEvent('select');
3519  }
3520};
3521
3522Flickity.prototype.previous = function( isWrap ) {
3523  this.select( this.selectedIndex - 1, isWrap );
3524};
3525
3526Flickity.prototype.next = function( isWrap ) {
3527  this.select( this.selectedIndex + 1, isWrap );
3528};
3529
3530Flickity.prototype.updatePrevNextButtons = function() {
3531  if ( this.prevButton ) {
3532    this.prevButton.update();
3533  }
3534  if ( this.nextButton ) {
3535    this.nextButton.update();
3536  }
3537};
3538
3539Flickity.prototype.setSelectedCell = function() {
3540  this._removeSelectedCellClass();
3541  this.selectedCell = this.cells[ this.selectedIndex ];
3542  classie.add( this.selectedCell.element, 'is-selected' );
3543};
3544
3545Flickity.prototype._removeSelectedCellClass = function() {
3546  if ( this.selectedCell ) {
3547    classie.remove( this.selectedCell.element, 'is-selected' );
3548  }
3549};
3550
3551// on button clicks and ui changes
3552// stop player and stop free scrolling
3553Flickity.prototype.uiChange = function() {
3554  this.player.stop();
3555  delete this.isFreeScrolling;
3556};
3557
3558// -------------------------- images -------------------------- //
3559
3560// TODO move out this repo to avoid problems with imagesLoaded dependency
3561Flickity.prototype.imagesLoaded = function() {
3562  if ( !this.options.imagesLoaded || !imagesLoaded ) {
3563    return;
3564  }
3565  var _this = this;
3566  function onImagesLoadedProgress( instance, image ) {
3567    // check if image is a cell
3568    var cell = _this.getCell( image.img );
3569    // otherwise get its parents
3570    var cellElem = cell.element || U.getParent( image.img, '.flickity-slider > *' );
3571    _this.cellSizeChange( cellElem );
3572  }
3573  imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress );
3574};
3575
3576// -------------------------- get cells -------------------------- //
3577
3578/**
3579 * get Flickity.Cell, given an Element
3580 * @param {Element} elem
3581 * @returns {Flickity.Cell} item
3582 */
3583Flickity.prototype.getCell = function( elem ) {
3584  // loop through cells to get the one that matches
3585  for ( var i=0, len = this.cells.length; i < len; i++ ) {
3586    var cell = this.cells[i];
3587    if ( cell.element == elem ) {
3588      return cell;
3589    }
3590  }
3591};
3592
3593/**
3594 * get collection of Flickity.Cells, given Elements
3595 * @param {Element, Array, NodeList} elems
3596 * @returns {Array} cells - Flickity.Cells
3597 */
3598Flickity.prototype.getCells = function( elems ) {
3599  elems = U.makeArray( elems );
3600  var cells = [];
3601  for ( var i=0, len = elems.length; i < len; i++ ) {
3602    var elem = elems[i];
3603    var cell = this.getCell( elem );
3604    if ( cell ) {
3605      cells.push( cell );
3606    }
3607  }
3608  return cells;
3609};
3610
3611// -------------------------- events -------------------------- //
3612
3613// ----- resize ----- //
3614
3615Flickity.prototype.onresize = function() {
3616  this.watchCSS();
3617  this.resize();
3618};
3619
3620U.debounceMethod( Flickity, 'onresize', 150 );
3621
3622Flickity.prototype.resize = function() {
3623  if ( !this.isActive ) {
3624    return;
3625  }
3626  this.getSize();
3627  // wrap values
3628  if ( this.options.wrapAround ) {
3629    this.x = U.modulo( this.x, this.slideableWidth );
3630  }
3631  this.positionCells();
3632  this._getWrapShiftCells();
3633  this.setContainerSize();
3634  this.positionSliderAtSelected();
3635};
3636
3637var supportsConditionalCSS = Flickity.supportsConditionalCSS = ( function() {
3638  var supports;
3639  return function checkSupport() {
3640    if ( supports !== undefined ) {
3641      return supports;
3642    }
3643    if ( !getComputedStyle ) {
3644      supports = false;
3645      return;
3646    }
3647    // style body's :after and check that
3648    var style = document.createElement('style');
3649    var cssText = document.createTextNode('body:after { content: "foo"; display: none; }');
3650    style.appendChild( cssText );
3651    document.head.appendChild( style );
3652    var afterContent = getComputedStyle( document.body, ':after' ).content;
3653    // check if able to get :after content
3654    supports = afterContent.indexOf('foo') != -1;
3655    document.head.removeChild( style );
3656    return supports;
3657  };
3658})();
3659
3660// watches the :after property, activates/deactivates
3661Flickity.prototype.watchCSS = function() {
3662  var watchOption = this.options.watchCSS;
3663  if ( !watchOption ) {
3664    return;
3665  }
3666  var supports = supportsConditionalCSS();
3667  if ( !supports ) {
3668    // activate if watch option is fallbackOn
3669    var method = watchOption == 'fallbackOn' ? 'activate' : 'deactivate';
3670    this[ method ]();
3671    return;
3672  }
3673
3674  var afterContent = getComputedStyle( this.element, ':after' ).content;
3675  // activate if :after { content: 'flickity' }
3676  if ( afterContent.indexOf('flickity') != -1 ) {
3677    this.activate();
3678  } else {
3679    this.deactivate();
3680  }
3681};
3682
3683// ----- keydown ----- //
3684
3685// go previous/next if left/right keys pressed
3686Flickity.prototype.onkeydown = function( event ) {
3687  // only work if element is in focus
3688  if ( !this.options.accessibility ||
3689    ( document.activeElement && document.activeElement != this.element ) ) {
3690    return;
3691  }
3692
3693  if ( event.keyCode == 37 ) {
3694    // go left
3695    var leftMethod = this.options.rightToLeft ? 'next' : 'previous';
3696    this.uiChange();
3697    this[ leftMethod ]();
3698  } else if ( event.keyCode == 39 ) {
3699    // go right
3700    var rightMethod = this.options.rightToLeft ? 'previous' : 'next';
3701    this.uiChange();
3702    this[ rightMethod ]();
3703  }
3704};
3705
3706// ----- mouseenter/leave ----- //
3707
3708// pause auto-play on hover
3709Flickity.prototype.onmouseenter = function() {
3710  this.player.pause();
3711  eventie.bind( this.element, 'mouseleave', this );
3712};
3713
3714// resume auto-play on hover off
3715Flickity.prototype.onmouseleave = function() {
3716  this.player.unpause();
3717  eventie.unbind( this.element, 'mouseleave', this );
3718};
3719
3720// -------------------------- destroy -------------------------- //
3721
3722// deactivate all Flickity functionality, but keep stuff available
3723Flickity.prototype.deactivate = function() {
3724  if ( !this.isActive ) {
3725    return;
3726  }
3727  classie.remove( this.element, 'flickity-enabled' );
3728  // destroy cells
3729  for ( var i=0, len = this.cells.length; i < len; i++ ) {
3730    var cell = this.cells[i];
3731    cell.destroy();
3732  }
3733  this._removeSelectedCellClass();
3734  this.element.removeChild( this.viewport );
3735  // move child elements back into element
3736  moveChildren( this.slider, this.element );
3737  // deactivate prev/next buttons, page dots; stop player
3738  if ( this.prevButton ) {
3739    this.prevButton.deactivate();
3740  }
3741  if ( this.nextButton ) {
3742    this.nextButton.deactivate();
3743  }
3744  if ( this.pageDots ) {
3745    this.pageDots.deactivate();
3746  }
3747  this.player.stop();
3748  // unbind events
3749  this.unbindDrag();
3750  if ( this.options.accessibility ) {
3751    this.element.removeAttribute('tabIndex');
3752    eventie.unbind( this.element, 'keydown', this );
3753  }
3754  // set flags
3755  this.isActive = false;
3756  this.isAnimating = false;
3757};
3758
3759Flickity.prototype.destroy = function() {
3760  this.deactivate();
3761  if ( this.options.resizeBound || this.options.watch ) {
3762    eventie.unbind( window, 'resize', this );
3763  }
3764  delete this.element.flickityGUID;
3765  delete instances[ this.guid ];
3766};
3767
3768// -------------------------- prototype -------------------------- //
3769
3770U.extend( Flickity.prototype, dragPrototype );
3771U.extend( Flickity.prototype, animatePrototype );
3772U.extend( Flickity.prototype, cellChangePrototype );
3773
3774// -------------------------- extras -------------------------- //
3775
3776/**
3777 * get Flickity instance from element
3778 * @param {Element} elem
3779 * @returns {Flickity}
3780 */
3781Flickity.data = function( elem ) {
3782  elem = U.getQueryElement( elem );
3783  var id = elem && elem.flickityGUID;
3784  return id && instances[ id ];
3785};
3786
3787U.htmlInit( Flickity, 'flickity' );
3788
3789if ( jQuery && jQuery.bridget ) {
3790  jQuery.bridget( 'flickity', Flickity );
3791}
3792
3793// make classes accessible
3794Flickity.Cell = Cell;
3795Flickity.PrevNextButton = PrevNextButton;
3796Flickity.PageDots = PageDots;
3797Flickity.Player = Player;
3798
3799return Flickity;
3800
3801}));
3802

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.