JAVASCRIPT   50

flickity.js

Guest on 12th August 2021 06:54:39 PM

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

Raw Paste


Login or Register to edit or fork this paste. It's free.