PageSourceSearch

https://unclenearest.com/wp-content/themes/unclenearest/lib/js/flickity.pkgd.js?ver=1.0

js unclenearest.com collected 2026-10-03 21:39:06 UTC 119,220 bytes, 4,627 lines download raw bytes

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

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.