PageSourceSearch

https://krymsos.com/wp-content/themes/krymsos/hg-assets/flickity.js

js krymsos.com collected 2026-09-24 19:33:22 UTC 120,717 bytes, 4,673 lines download raw bytes

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

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.