|
@@ -0,0 +1,4586 @@
|
|
|
+/*!
|
|
|
+ * Flickity PACKAGED v2.2.1
|
|
|
+ * Touch, responsive, flickable carousels
|
|
|
+ *
|
|
|
+ * Licensed GPLv3 for open source use
|
|
|
+ * or Flickity Commercial License for commercial use
|
|
|
+ *
|
|
|
+ * https://flickity.metafizzy.co
|
|
|
+ * Copyright 2015-2019 Metafizzy
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * Bridget makes jQuery widgets
|
|
|
+ * v2.0.1
|
|
|
+ * MIT license
|
|
|
+ */
|
|
|
+
|
|
|
+/* jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /*jshint strict: false */ /* globals define, module, require */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
|
|
|
+ return factory( window, jQuery );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('jquery')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.jQueryBridget = factory(
|
|
|
+ window,
|
|
|
+ window.jQuery
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, jQuery ) {
|
|
|
+'use strict';
|
|
|
+
|
|
|
+// ----- utils ----- //
|
|
|
+
|
|
|
+var arraySlice = Array.prototype.slice;
|
|
|
+
|
|
|
+// helper function for logging errors
|
|
|
+// $.error breaks jQuery chaining
|
|
|
+var console = window.console;
|
|
|
+var logError = typeof console == 'undefined' ? function() {} :
|
|
|
+ function( message ) {
|
|
|
+ console.error( message );
|
|
|
+ };
|
|
|
+
|
|
|
+// ----- jQueryBridget ----- //
|
|
|
+
|
|
|
+function jQueryBridget( namespace, PluginClass, $ ) {
|
|
|
+ $ = $ || jQuery || window.jQuery;
|
|
|
+ if ( !$ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // add option method -> $().plugin('option', {...})
|
|
|
+ if ( !PluginClass.prototype.option ) {
|
|
|
+ // option setter
|
|
|
+ PluginClass.prototype.option = function( opts ) {
|
|
|
+ // bail out if not an object
|
|
|
+ if ( !$.isPlainObject( opts ) ){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.options = $.extend( true, this.options, opts );
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // make jQuery plugin
|
|
|
+ $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
|
|
|
+ if ( typeof arg0 == 'string' ) {
|
|
|
+ // method call $().plugin( 'methodName', { options } )
|
|
|
+ // shift arguments by 1
|
|
|
+ var args = arraySlice.call( arguments, 1 );
|
|
|
+ return methodCall( this, arg0, args );
|
|
|
+ }
|
|
|
+ // just $().plugin({ options })
|
|
|
+ plainCall( this, arg0 );
|
|
|
+ return this;
|
|
|
+ };
|
|
|
+
|
|
|
+ // $().plugin('methodName')
|
|
|
+ function methodCall( $elems, methodName, args ) {
|
|
|
+ var returnValue;
|
|
|
+ var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
|
|
|
+
|
|
|
+ $elems.each( function( i, elem ) {
|
|
|
+ // get instance
|
|
|
+ var instance = $.data( elem, namespace );
|
|
|
+ if ( !instance ) {
|
|
|
+ logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
|
|
|
+ pluginMethodStr );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var method = instance[ methodName ];
|
|
|
+ if ( !method || methodName.charAt(0) == '_' ) {
|
|
|
+ logError( pluginMethodStr + ' is not a valid method' );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // apply method, get return value
|
|
|
+ var value = method.apply( instance, args );
|
|
|
+ // set return value if value is returned, use only first value
|
|
|
+ returnValue = returnValue === undefined ? value : returnValue;
|
|
|
+ });
|
|
|
+
|
|
|
+ return returnValue !== undefined ? returnValue : $elems;
|
|
|
+ }
|
|
|
+
|
|
|
+ function plainCall( $elems, options ) {
|
|
|
+ $elems.each( function( i, elem ) {
|
|
|
+ var instance = $.data( elem, namespace );
|
|
|
+ if ( instance ) {
|
|
|
+ // set options & init
|
|
|
+ instance.option( options );
|
|
|
+ instance._init();
|
|
|
+ } else {
|
|
|
+ // initialize new instance
|
|
|
+ instance = new PluginClass( elem, options );
|
|
|
+ $.data( elem, namespace, instance );
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ updateJQuery( $ );
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// ----- updateJQuery ----- //
|
|
|
+
|
|
|
+// set $.bridget for v1 backwards compatibility
|
|
|
+function updateJQuery( $ ) {
|
|
|
+ if ( !$ || ( $ && $.bridget ) ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $.bridget = jQueryBridget;
|
|
|
+}
|
|
|
+
|
|
|
+updateJQuery( jQuery || window.jQuery );
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return jQueryBridget;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/**
|
|
|
+ * EvEmitter v1.1.0
|
|
|
+ * Lil' event emitter
|
|
|
+ * MIT License
|
|
|
+ */
|
|
|
+
|
|
|
+/* jshint unused: true, undef: true, strict: true */
|
|
|
+
|
|
|
+( function( global, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */ /* globals define, module, window */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD - RequireJS
|
|
|
+ define( 'ev-emitter/ev-emitter',factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS - Browserify, Webpack
|
|
|
+ module.exports = factory();
|
|
|
+ } else {
|
|
|
+ // Browser globals
|
|
|
+ global.EvEmitter = factory();
|
|
|
+ }
|
|
|
+
|
|
|
+}( typeof window != 'undefined' ? window : this, function() {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+function EvEmitter() {}
|
|
|
+
|
|
|
+var proto = EvEmitter.prototype;
|
|
|
+
|
|
|
+proto.on = function( eventName, listener ) {
|
|
|
+ if ( !eventName || !listener ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // set events hash
|
|
|
+ var events = this._events = this._events || {};
|
|
|
+ // set listeners array
|
|
|
+ var listeners = events[ eventName ] = events[ eventName ] || [];
|
|
|
+ // only add once
|
|
|
+ if ( listeners.indexOf( listener ) == -1 ) {
|
|
|
+ listeners.push( listener );
|
|
|
+ }
|
|
|
+
|
|
|
+ return this;
|
|
|
+};
|
|
|
+
|
|
|
+proto.once = function( eventName, listener ) {
|
|
|
+ if ( !eventName || !listener ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // add event
|
|
|
+ this.on( eventName, listener );
|
|
|
+ // set once flag
|
|
|
+ // set onceEvents hash
|
|
|
+ var onceEvents = this._onceEvents = this._onceEvents || {};
|
|
|
+ // set onceListeners object
|
|
|
+ var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
|
|
|
+ // set flag
|
|
|
+ onceListeners[ listener ] = true;
|
|
|
+
|
|
|
+ return this;
|
|
|
+};
|
|
|
+
|
|
|
+proto.off = function( eventName, listener ) {
|
|
|
+ var listeners = this._events && this._events[ eventName ];
|
|
|
+ if ( !listeners || !listeners.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var index = listeners.indexOf( listener );
|
|
|
+ if ( index != -1 ) {
|
|
|
+ listeners.splice( index, 1 );
|
|
|
+ }
|
|
|
+
|
|
|
+ return this;
|
|
|
+};
|
|
|
+
|
|
|
+proto.emitEvent = function( eventName, args ) {
|
|
|
+ var listeners = this._events && this._events[ eventName ];
|
|
|
+ if ( !listeners || !listeners.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // copy over to avoid interference if .off() in listener
|
|
|
+ listeners = listeners.slice(0);
|
|
|
+ args = args || [];
|
|
|
+ // once stuff
|
|
|
+ var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
|
|
|
+
|
|
|
+ for ( var i=0; i < listeners.length; i++ ) {
|
|
|
+ var listener = listeners[i]
|
|
|
+ var isOnce = onceListeners && onceListeners[ listener ];
|
|
|
+ if ( isOnce ) {
|
|
|
+ // remove listener
|
|
|
+ // remove before trigger to prevent recursion
|
|
|
+ this.off( eventName, listener );
|
|
|
+ // unset once flag
|
|
|
+ delete onceListeners[ listener ];
|
|
|
+ }
|
|
|
+ // trigger listener
|
|
|
+ listener.apply( this, args );
|
|
|
+ }
|
|
|
+
|
|
|
+ return this;
|
|
|
+};
|
|
|
+
|
|
|
+proto.allOff = function() {
|
|
|
+ delete this._events;
|
|
|
+ delete this._onceEvents;
|
|
|
+};
|
|
|
+
|
|
|
+return EvEmitter;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/*!
|
|
|
+ * getSize v2.0.3
|
|
|
+ * measure size of elements
|
|
|
+ * MIT license
|
|
|
+ */
|
|
|
+
|
|
|
+/* jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
+/* globals console: false */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ /* jshint strict: false */ /* globals define, module */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'get-size/get-size',factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory();
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.getSize = factory();
|
|
|
+ }
|
|
|
+
|
|
|
+})( window, function factory() {
|
|
|
+'use strict';
|
|
|
+
|
|
|
+// -------------------------- helpers -------------------------- //
|
|
|
+
|
|
|
+// get a number from a string, not a percentage
|
|
|
+function getStyleSize( value ) {
|
|
|
+ var num = parseFloat( value );
|
|
|
+ // not a percent like '100%', and a number
|
|
|
+ var isValid = value.indexOf('%') == -1 && !isNaN( num );
|
|
|
+ return isValid && num;
|
|
|
+}
|
|
|
+
|
|
|
+function noop() {}
|
|
|
+
|
|
|
+var logError = typeof console == 'undefined' ? noop :
|
|
|
+ function( message ) {
|
|
|
+ console.error( message );
|
|
|
+ };
|
|
|
+
|
|
|
+// -------------------------- measurements -------------------------- //
|
|
|
+
|
|
|
+var measurements = [
|
|
|
+ 'paddingLeft',
|
|
|
+ 'paddingRight',
|
|
|
+ 'paddingTop',
|
|
|
+ 'paddingBottom',
|
|
|
+ 'marginLeft',
|
|
|
+ 'marginRight',
|
|
|
+ 'marginTop',
|
|
|
+ 'marginBottom',
|
|
|
+ 'borderLeftWidth',
|
|
|
+ 'borderRightWidth',
|
|
|
+ 'borderTopWidth',
|
|
|
+ 'borderBottomWidth'
|
|
|
+];
|
|
|
+
|
|
|
+var measurementsLength = measurements.length;
|
|
|
+
|
|
|
+function getZeroSize() {
|
|
|
+ var size = {
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ innerWidth: 0,
|
|
|
+ innerHeight: 0,
|
|
|
+ outerWidth: 0,
|
|
|
+ outerHeight: 0
|
|
|
+ };
|
|
|
+ for ( var i=0; i < measurementsLength; i++ ) {
|
|
|
+ var measurement = measurements[i];
|
|
|
+ size[ measurement ] = 0;
|
|
|
+ }
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- getStyle -------------------------- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * getStyle, get style of element, check for Firefox bug
|
|
|
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
|
|
|
+ */
|
|
|
+function getStyle( elem ) {
|
|
|
+ var style = getComputedStyle( elem );
|
|
|
+ if ( !style ) {
|
|
|
+ logError( 'Style returned ' + style +
|
|
|
+ '. Are you running this code in a hidden iframe on Firefox? ' +
|
|
|
+ 'See https://bit.ly/getsizebug1' );
|
|
|
+ }
|
|
|
+ return style;
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- setup -------------------------- //
|
|
|
+
|
|
|
+var isSetup = false;
|
|
|
+
|
|
|
+var isBoxSizeOuter;
|
|
|
+
|
|
|
+/**
|
|
|
+ * setup
|
|
|
+ * check isBoxSizerOuter
|
|
|
+ * do on first getSize() rather than on page load for Firefox bug
|
|
|
+ */
|
|
|
+function setup() {
|
|
|
+ // setup once
|
|
|
+ if ( isSetup ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ isSetup = true;
|
|
|
+
|
|
|
+ // -------------------------- box sizing -------------------------- //
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Chrome & Safari measure the outer-width on style.width on border-box elems
|
|
|
+ * IE11 & Firefox<29 measures the inner-width
|
|
|
+ */
|
|
|
+ var div = document.createElement('div');
|
|
|
+ div.style.width = '200px';
|
|
|
+ div.style.padding = '1px 2px 3px 4px';
|
|
|
+ div.style.borderStyle = 'solid';
|
|
|
+ div.style.borderWidth = '1px 2px 3px 4px';
|
|
|
+ div.style.boxSizing = 'border-box';
|
|
|
+
|
|
|
+ var body = document.body || document.documentElement;
|
|
|
+ body.appendChild( div );
|
|
|
+ var style = getStyle( div );
|
|
|
+ // round value for browser zoom. desandro/masonry#928
|
|
|
+ isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
|
|
|
+ getSize.isBoxSizeOuter = isBoxSizeOuter;
|
|
|
+
|
|
|
+ body.removeChild( div );
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- getSize -------------------------- //
|
|
|
+
|
|
|
+function getSize( elem ) {
|
|
|
+ setup();
|
|
|
+
|
|
|
+ // use querySeletor if elem is string
|
|
|
+ if ( typeof elem == 'string' ) {
|
|
|
+ elem = document.querySelector( elem );
|
|
|
+ }
|
|
|
+
|
|
|
+ // do not proceed on non-objects
|
|
|
+ if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var style = getStyle( elem );
|
|
|
+
|
|
|
+ // if hidden, everything is 0
|
|
|
+ if ( style.display == 'none' ) {
|
|
|
+ return getZeroSize();
|
|
|
+ }
|
|
|
+
|
|
|
+ var size = {};
|
|
|
+ size.width = elem.offsetWidth;
|
|
|
+ size.height = elem.offsetHeight;
|
|
|
+
|
|
|
+ var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
|
|
|
+
|
|
|
+ // get all measurements
|
|
|
+ for ( var i=0; i < measurementsLength; i++ ) {
|
|
|
+ var measurement = measurements[i];
|
|
|
+ var value = style[ measurement ];
|
|
|
+ var num = parseFloat( value );
|
|
|
+ // any 'auto', 'medium' value will be 0
|
|
|
+ size[ measurement ] = !isNaN( num ) ? num : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ var paddingWidth = size.paddingLeft + size.paddingRight;
|
|
|
+ var paddingHeight = size.paddingTop + size.paddingBottom;
|
|
|
+ var marginWidth = size.marginLeft + size.marginRight;
|
|
|
+ var marginHeight = size.marginTop + size.marginBottom;
|
|
|
+ var borderWidth = size.borderLeftWidth + size.borderRightWidth;
|
|
|
+ var borderHeight = size.borderTopWidth + size.borderBottomWidth;
|
|
|
+
|
|
|
+ var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
|
|
|
+
|
|
|
+ // overwrite width and height if we can get it from style
|
|
|
+ var styleWidth = getStyleSize( style.width );
|
|
|
+ if ( styleWidth !== false ) {
|
|
|
+ size.width = styleWidth +
|
|
|
+ // add padding and border unless it's already including it
|
|
|
+ ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
|
|
|
+ }
|
|
|
+
|
|
|
+ var styleHeight = getStyleSize( style.height );
|
|
|
+ if ( styleHeight !== false ) {
|
|
|
+ size.height = styleHeight +
|
|
|
+ // add padding and border unless it's already including it
|
|
|
+ ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
|
|
|
+ }
|
|
|
+
|
|
|
+ size.innerWidth = size.width - ( paddingWidth + borderWidth );
|
|
|
+ size.innerHeight = size.height - ( paddingHeight + borderHeight );
|
|
|
+
|
|
|
+ size.outerWidth = size.width + marginWidth;
|
|
|
+ size.outerHeight = size.height + marginHeight;
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+return getSize;
|
|
|
+
|
|
|
+});
|
|
|
+
|
|
|
+/**
|
|
|
+ * matchesSelector v2.0.2
|
|
|
+ * matchesSelector( element, '.selector' )
|
|
|
+ * MIT license
|
|
|
+ */
|
|
|
+
|
|
|
+/*jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ /*global define: false, module: false */
|
|
|
+ 'use strict';
|
|
|
+ // universal module definition
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'desandro-matches-selector/matches-selector',factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory();
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.matchesSelector = factory();
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory() {
|
|
|
+ 'use strict';
|
|
|
+
|
|
|
+ var matchesMethod = ( function() {
|
|
|
+ var ElemProto = window.Element.prototype;
|
|
|
+ // check for the standard method name first
|
|
|
+ if ( ElemProto.matches ) {
|
|
|
+ return 'matches';
|
|
|
+ }
|
|
|
+ // check un-prefixed
|
|
|
+ if ( ElemProto.matchesSelector ) {
|
|
|
+ return 'matchesSelector';
|
|
|
+ }
|
|
|
+ // check vendor prefixes
|
|
|
+ var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
|
|
|
+
|
|
|
+ for ( var i=0; i < prefixes.length; i++ ) {
|
|
|
+ var prefix = prefixes[i];
|
|
|
+ var method = prefix + 'MatchesSelector';
|
|
|
+ if ( ElemProto[ method ] ) {
|
|
|
+ return method;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })();
|
|
|
+
|
|
|
+ return function matchesSelector( elem, selector ) {
|
|
|
+ return elem[ matchesMethod ]( selector );
|
|
|
+ };
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/**
|
|
|
+ * Fizzy UI utils v2.0.7
|
|
|
+ * MIT license
|
|
|
+ */
|
|
|
+
|
|
|
+/*jshint browser: true, undef: true, unused: true, strict: true */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /*jshint strict: false */ /*globals define, module, require */
|
|
|
+
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'fizzy-ui-utils/utils',[
|
|
|
+ 'desandro-matches-selector/matches-selector'
|
|
|
+ ], function( matchesSelector ) {
|
|
|
+ return factory( window, matchesSelector );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('desandro-matches-selector')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.fizzyUIUtils = factory(
|
|
|
+ window,
|
|
|
+ window.matchesSelector
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, matchesSelector ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+var utils = {};
|
|
|
+
|
|
|
+// ----- extend ----- //
|
|
|
+
|
|
|
+// extends objects
|
|
|
+utils.extend = function( a, b ) {
|
|
|
+ for ( var prop in b ) {
|
|
|
+ a[ prop ] = b[ prop ];
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- modulo ----- //
|
|
|
+
|
|
|
+utils.modulo = function( num, div ) {
|
|
|
+ return ( ( num % div ) + div ) % div;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- makeArray ----- //
|
|
|
+
|
|
|
+var arraySlice = Array.prototype.slice;
|
|
|
+
|
|
|
+// turn element or nodeList into an array
|
|
|
+utils.makeArray = function( obj ) {
|
|
|
+ if ( Array.isArray( obj ) ) {
|
|
|
+ // use object if already an array
|
|
|
+ return obj;
|
|
|
+ }
|
|
|
+ // return empty array if undefined or null. #6
|
|
|
+ if ( obj === null || obj === undefined ) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
|
|
|
+ if ( isArrayLike ) {
|
|
|
+ // convert nodeList to array
|
|
|
+ return arraySlice.call( obj );
|
|
|
+ }
|
|
|
+
|
|
|
+ // array of single index
|
|
|
+ return [ obj ];
|
|
|
+};
|
|
|
+
|
|
|
+// ----- removeFrom ----- //
|
|
|
+
|
|
|
+utils.removeFrom = function( ary, obj ) {
|
|
|
+ var index = ary.indexOf( obj );
|
|
|
+ if ( index != -1 ) {
|
|
|
+ ary.splice( index, 1 );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- getParent ----- //
|
|
|
+
|
|
|
+utils.getParent = function( elem, selector ) {
|
|
|
+ while ( elem.parentNode && elem != document.body ) {
|
|
|
+ elem = elem.parentNode;
|
|
|
+ if ( matchesSelector( elem, selector ) ) {
|
|
|
+ return elem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- getQueryElement ----- //
|
|
|
+
|
|
|
+// use element as selector string
|
|
|
+utils.getQueryElement = function( elem ) {
|
|
|
+ if ( typeof elem == 'string' ) {
|
|
|
+ return document.querySelector( elem );
|
|
|
+ }
|
|
|
+ return elem;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- handleEvent ----- //
|
|
|
+
|
|
|
+// enable .ontype to trigger from .addEventListener( elem, 'type' )
|
|
|
+utils.handleEvent = function( event ) {
|
|
|
+ var method = 'on' + event.type;
|
|
|
+ if ( this[ method ] ) {
|
|
|
+ this[ method ]( event );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- filterFindElements ----- //
|
|
|
+
|
|
|
+utils.filterFindElements = function( elems, selector ) {
|
|
|
+ // make array of elems
|
|
|
+ elems = utils.makeArray( elems );
|
|
|
+ var ffElems = [];
|
|
|
+
|
|
|
+ elems.forEach( function( elem ) {
|
|
|
+ // check that elem is an actual element
|
|
|
+ if ( !( elem instanceof HTMLElement ) ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // add elem if no selector
|
|
|
+ if ( !selector ) {
|
|
|
+ ffElems.push( elem );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // filter & find items if we have a selector
|
|
|
+ // filter
|
|
|
+ if ( matchesSelector( elem, selector ) ) {
|
|
|
+ ffElems.push( elem );
|
|
|
+ }
|
|
|
+ // find children
|
|
|
+ var childElems = elem.querySelectorAll( selector );
|
|
|
+ // concat childElems to filterFound array
|
|
|
+ for ( var i=0; i < childElems.length; i++ ) {
|
|
|
+ ffElems.push( childElems[i] );
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return ffElems;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- debounceMethod ----- //
|
|
|
+
|
|
|
+utils.debounceMethod = function( _class, methodName, threshold ) {
|
|
|
+ threshold = threshold || 100;
|
|
|
+ // original method
|
|
|
+ var method = _class.prototype[ methodName ];
|
|
|
+ var timeoutName = methodName + 'Timeout';
|
|
|
+
|
|
|
+ _class.prototype[ methodName ] = function() {
|
|
|
+ var timeout = this[ timeoutName ];
|
|
|
+ clearTimeout( timeout );
|
|
|
+
|
|
|
+ var args = arguments;
|
|
|
+ var _this = this;
|
|
|
+ this[ timeoutName ] = setTimeout( function() {
|
|
|
+ method.apply( _this, args );
|
|
|
+ delete _this[ timeoutName ];
|
|
|
+ }, threshold );
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// ----- docReady ----- //
|
|
|
+
|
|
|
+utils.docReady = function( callback ) {
|
|
|
+ var readyState = document.readyState;
|
|
|
+ if ( readyState == 'complete' || readyState == 'interactive' ) {
|
|
|
+ // do async to allow for other scripts to run. metafizzy/flickity#441
|
|
|
+ setTimeout( callback );
|
|
|
+ } else {
|
|
|
+ document.addEventListener( 'DOMContentLoaded', callback );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- htmlInit ----- //
|
|
|
+
|
|
|
+// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
|
|
|
+utils.toDashed = function( str ) {
|
|
|
+ return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
|
|
|
+ return $1 + '-' + $2;
|
|
|
+ }).toLowerCase();
|
|
|
+};
|
|
|
+
|
|
|
+var console = window.console;
|
|
|
+/**
|
|
|
+ * allow user to initialize classes via [data-namespace] or .js-namespace class
|
|
|
+ * htmlInit( Widget, 'widgetName' )
|
|
|
+ * options are parsed from data-namespace-options
|
|
|
+ */
|
|
|
+utils.htmlInit = function( WidgetClass, namespace ) {
|
|
|
+ utils.docReady( function() {
|
|
|
+ var dashedNamespace = utils.toDashed( namespace );
|
|
|
+ var dataAttr = 'data-' + dashedNamespace;
|
|
|
+ var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
|
|
|
+ var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
|
|
|
+ var elems = utils.makeArray( dataAttrElems )
|
|
|
+ .concat( utils.makeArray( jsDashElems ) );
|
|
|
+ var dataOptionsAttr = dataAttr + '-options';
|
|
|
+ var jQuery = window.jQuery;
|
|
|
+
|
|
|
+ elems.forEach( function( elem ) {
|
|
|
+ var attr = elem.getAttribute( dataAttr ) ||
|
|
|
+ elem.getAttribute( dataOptionsAttr );
|
|
|
+ var options;
|
|
|
+ try {
|
|
|
+ options = attr && JSON.parse( attr );
|
|
|
+ } catch ( error ) {
|
|
|
+ // log error, do not initialize
|
|
|
+ if ( console ) {
|
|
|
+ console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
|
|
|
+ ': ' + error );
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // initialize
|
|
|
+ var instance = new WidgetClass( elem, options );
|
|
|
+ // make available via $().data('namespace')
|
|
|
+ if ( jQuery ) {
|
|
|
+ jQuery.data( elem, namespace, instance );
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return utils;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// Flickity.Cell
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/cell',[
|
|
|
+ 'get-size/get-size'
|
|
|
+ ], function( getSize ) {
|
|
|
+ return factory( window, getSize );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('get-size')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Flickity = window.Flickity || {};
|
|
|
+ window.Flickity.Cell = factory(
|
|
|
+ window,
|
|
|
+ window.getSize
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, getSize ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+function Cell( elem, parent ) {
|
|
|
+ this.element = elem;
|
|
|
+ this.parent = parent;
|
|
|
+
|
|
|
+ this.create();
|
|
|
+}
|
|
|
+
|
|
|
+var proto = Cell.prototype;
|
|
|
+
|
|
|
+proto.create = function() {
|
|
|
+ this.element.style.position = 'absolute';
|
|
|
+ this.element.setAttribute( 'aria-hidden', 'true' );
|
|
|
+ this.x = 0;
|
|
|
+ this.shift = 0;
|
|
|
+};
|
|
|
+
|
|
|
+proto.destroy = function() {
|
|
|
+ // reset style
|
|
|
+ this.unselect();
|
|
|
+ this.element.style.position = '';
|
|
|
+ var side = this.parent.originSide;
|
|
|
+ this.element.style[ side ] = '';
|
|
|
+};
|
|
|
+
|
|
|
+proto.getSize = function() {
|
|
|
+ this.size = getSize( this.element );
|
|
|
+};
|
|
|
+
|
|
|
+proto.setPosition = function( x ) {
|
|
|
+ this.x = x;
|
|
|
+ this.updateTarget();
|
|
|
+ this.renderPosition( x );
|
|
|
+};
|
|
|
+
|
|
|
+// setDefaultTarget v1 method, backwards compatibility, remove in v3
|
|
|
+proto.updateTarget = proto.setDefaultTarget = function() {
|
|
|
+ var marginProperty = this.parent.originSide == 'left' ? 'marginLeft' : 'marginRight';
|
|
|
+ this.target = this.x + this.size[ marginProperty ] +
|
|
|
+ this.size.width * this.parent.cellAlign;
|
|
|
+};
|
|
|
+
|
|
|
+proto.renderPosition = function( x ) {
|
|
|
+ // render position of cell with in slider
|
|
|
+ var side = this.parent.originSide;
|
|
|
+ this.element.style[ side ] = this.parent.getPositionValue( x );
|
|
|
+};
|
|
|
+
|
|
|
+proto.select = function() {
|
|
|
+ this.element.classList.add('is-selected');
|
|
|
+ this.element.removeAttribute('aria-hidden');
|
|
|
+};
|
|
|
+
|
|
|
+proto.unselect = function() {
|
|
|
+ this.element.classList.remove('is-selected');
|
|
|
+ this.element.setAttribute( 'aria-hidden', 'true' );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {Integer} factor - 0, 1, or -1
|
|
|
+**/
|
|
|
+proto.wrapShift = function( shift ) {
|
|
|
+ this.shift = shift;
|
|
|
+ this.renderPosition( this.x + this.parent.slideableWidth * shift );
|
|
|
+};
|
|
|
+
|
|
|
+proto.remove = function() {
|
|
|
+ this.element.parentNode.removeChild( this.element );
|
|
|
+};
|
|
|
+
|
|
|
+return Cell;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// slide
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/slide',factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory();
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Flickity = window.Flickity || {};
|
|
|
+ window.Flickity.Slide = factory();
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory() {
|
|
|
+'use strict';
|
|
|
+
|
|
|
+function Slide( parent ) {
|
|
|
+ this.parent = parent;
|
|
|
+ this.isOriginLeft = parent.originSide == 'left';
|
|
|
+ this.cells = [];
|
|
|
+ this.outerWidth = 0;
|
|
|
+ this.height = 0;
|
|
|
+}
|
|
|
+
|
|
|
+var proto = Slide.prototype;
|
|
|
+
|
|
|
+proto.addCell = function( cell ) {
|
|
|
+ this.cells.push( cell );
|
|
|
+ this.outerWidth += cell.size.outerWidth;
|
|
|
+ this.height = Math.max( cell.size.outerHeight, this.height );
|
|
|
+ // first cell stuff
|
|
|
+ if ( this.cells.length == 1 ) {
|
|
|
+ this.x = cell.x; // x comes from first cell
|
|
|
+ var beginMargin = this.isOriginLeft ? 'marginLeft' : 'marginRight';
|
|
|
+ this.firstMargin = cell.size[ beginMargin ];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.updateTarget = function() {
|
|
|
+ var endMargin = this.isOriginLeft ? 'marginRight' : 'marginLeft';
|
|
|
+ var lastCell = this.getLastCell();
|
|
|
+ var lastMargin = lastCell ? lastCell.size[ endMargin ] : 0;
|
|
|
+ var slideWidth = this.outerWidth - ( this.firstMargin + lastMargin );
|
|
|
+ this.target = this.x + this.firstMargin + slideWidth * this.parent.cellAlign;
|
|
|
+};
|
|
|
+
|
|
|
+proto.getLastCell = function() {
|
|
|
+ return this.cells[ this.cells.length - 1 ];
|
|
|
+};
|
|
|
+
|
|
|
+proto.select = function() {
|
|
|
+ this.cells.forEach( function( cell ) {
|
|
|
+ cell.select();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+proto.unselect = function() {
|
|
|
+ this.cells.forEach( function( cell ) {
|
|
|
+ cell.unselect();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+proto.getCellElements = function() {
|
|
|
+ return this.cells.map( function( cell ) {
|
|
|
+ return cell.element;
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+return Slide;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// animate
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/animate',[
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], function( utils ) {
|
|
|
+ return factory( window, utils );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Flickity = window.Flickity || {};
|
|
|
+ window.Flickity.animatePrototype = factory(
|
|
|
+ window,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, utils ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// -------------------------- animate -------------------------- //
|
|
|
+
|
|
|
+var proto = {};
|
|
|
+
|
|
|
+proto.startAnimation = function() {
|
|
|
+ if ( this.isAnimating ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.isAnimating = true;
|
|
|
+ this.restingFrames = 0;
|
|
|
+ this.animate();
|
|
|
+};
|
|
|
+
|
|
|
+proto.animate = function() {
|
|
|
+ this.applyDragForce();
|
|
|
+ this.applySelectedAttraction();
|
|
|
+
|
|
|
+ var previousX = this.x;
|
|
|
+
|
|
|
+ this.integratePhysics();
|
|
|
+ this.positionSlider();
|
|
|
+ this.settle( previousX );
|
|
|
+ // animate next frame
|
|
|
+ if ( this.isAnimating ) {
|
|
|
+ var _this = this;
|
|
|
+ requestAnimationFrame( function animateFrame() {
|
|
|
+ _this.animate();
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.positionSlider = function() {
|
|
|
+ var x = this.x;
|
|
|
+ // wrap position around
|
|
|
+ if ( this.options.wrapAround && this.cells.length > 1 ) {
|
|
|
+ x = utils.modulo( x, this.slideableWidth );
|
|
|
+ x = x - this.slideableWidth;
|
|
|
+ this.shiftWrapCells( x );
|
|
|
+ }
|
|
|
+
|
|
|
+ this.setTranslateX( x, this.isAnimating );
|
|
|
+ this.dispatchScrollEvent();
|
|
|
+};
|
|
|
+
|
|
|
+proto.setTranslateX = function( x, is3d ) {
|
|
|
+ x += this.cursorPosition;
|
|
|
+ // reverse if right-to-left and using transform
|
|
|
+ x = this.options.rightToLeft ? -x : x;
|
|
|
+ var translateX = this.getPositionValue( x );
|
|
|
+ // use 3D tranforms for hardware acceleration on iOS
|
|
|
+ // but use 2D when settled, for better font-rendering
|
|
|
+ this.slider.style.transform = is3d ?
|
|
|
+ 'translate3d(' + translateX + ',0,0)' : 'translateX(' + translateX + ')';
|
|
|
+};
|
|
|
+
|
|
|
+proto.dispatchScrollEvent = function() {
|
|
|
+ var firstSlide = this.slides[0];
|
|
|
+ if ( !firstSlide ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var positionX = -this.x - firstSlide.target;
|
|
|
+ var progress = positionX / this.slidesWidth;
|
|
|
+ this.dispatchEvent( 'scroll', null, [ progress, positionX ] );
|
|
|
+};
|
|
|
+
|
|
|
+proto.positionSliderAtSelected = function() {
|
|
|
+ if ( !this.cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.x = -this.selectedSlide.target;
|
|
|
+ this.velocity = 0; // stop wobble
|
|
|
+ this.positionSlider();
|
|
|
+};
|
|
|
+
|
|
|
+proto.getPositionValue = function( position ) {
|
|
|
+ if ( this.options.percentPosition ) {
|
|
|
+ // percent position, round to 2 digits, like 12.34%
|
|
|
+ return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 )+ '%';
|
|
|
+ } else {
|
|
|
+ // pixel positioning
|
|
|
+ return Math.round( position ) + 'px';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.settle = function( previousX ) {
|
|
|
+ // keep track of frames where x hasn't moved
|
|
|
+ if ( !this.isPointerDown && Math.round( this.x * 100 ) == Math.round( previousX * 100 ) ) {
|
|
|
+ this.restingFrames++;
|
|
|
+ }
|
|
|
+ // stop animating if resting for 3 or more frames
|
|
|
+ if ( this.restingFrames > 2 ) {
|
|
|
+ this.isAnimating = false;
|
|
|
+ delete this.isFreeScrolling;
|
|
|
+ // render position with translateX when settled
|
|
|
+ this.positionSlider();
|
|
|
+ this.dispatchEvent( 'settle', null, [ this.selectedIndex ] );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.shiftWrapCells = function( x ) {
|
|
|
+ // shift before cells
|
|
|
+ var beforeGap = this.cursorPosition + x;
|
|
|
+ this._shiftCells( this.beforeShiftCells, beforeGap, -1 );
|
|
|
+ // shift after cells
|
|
|
+ var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );
|
|
|
+ this._shiftCells( this.afterShiftCells, afterGap, 1 );
|
|
|
+};
|
|
|
+
|
|
|
+proto._shiftCells = function( cells, gap, shift ) {
|
|
|
+ for ( var i=0; i < cells.length; i++ ) {
|
|
|
+ var cell = cells[i];
|
|
|
+ var cellShift = gap > 0 ? shift : 0;
|
|
|
+ cell.wrapShift( cellShift );
|
|
|
+ gap -= cell.size.outerWidth;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto._unshiftCells = function( cells ) {
|
|
|
+ if ( !cells || !cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for ( var i=0; i < cells.length; i++ ) {
|
|
|
+ cells[i].wrapShift( 0 );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- physics -------------------------- //
|
|
|
+
|
|
|
+proto.integratePhysics = function() {
|
|
|
+ this.x += this.velocity;
|
|
|
+ this.velocity *= this.getFrictionFactor();
|
|
|
+};
|
|
|
+
|
|
|
+proto.applyForce = function( force ) {
|
|
|
+ this.velocity += force;
|
|
|
+};
|
|
|
+
|
|
|
+proto.getFrictionFactor = function() {
|
|
|
+ return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];
|
|
|
+};
|
|
|
+
|
|
|
+proto.getRestingPosition = function() {
|
|
|
+ // my thanks to Steven Wittens, who simplified this math greatly
|
|
|
+ return this.x + this.velocity / ( 1 - this.getFrictionFactor() );
|
|
|
+};
|
|
|
+
|
|
|
+proto.applyDragForce = function() {
|
|
|
+ if ( !this.isDraggable || !this.isPointerDown ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // change the position to drag position by applying force
|
|
|
+ var dragVelocity = this.dragX - this.x;
|
|
|
+ var dragForce = dragVelocity - this.velocity;
|
|
|
+ this.applyForce( dragForce );
|
|
|
+};
|
|
|
+
|
|
|
+proto.applySelectedAttraction = function() {
|
|
|
+ // do not attract if pointer down or no slides
|
|
|
+ var dragDown = this.isDraggable && this.isPointerDown;
|
|
|
+ if ( dragDown || this.isFreeScrolling || !this.slides.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var distance = this.selectedSlide.target * -1 - this.x;
|
|
|
+ var force = distance * this.options.selectedAttraction;
|
|
|
+ this.applyForce( force );
|
|
|
+};
|
|
|
+
|
|
|
+return proto;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// Flickity main
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/flickity',[
|
|
|
+ 'ev-emitter/ev-emitter',
|
|
|
+ 'get-size/get-size',
|
|
|
+ 'fizzy-ui-utils/utils',
|
|
|
+ './cell',
|
|
|
+ './slide',
|
|
|
+ './animate'
|
|
|
+ ], function( EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) {
|
|
|
+ return factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('ev-emitter'),
|
|
|
+ require('get-size'),
|
|
|
+ require('fizzy-ui-utils'),
|
|
|
+ require('./cell'),
|
|
|
+ require('./slide'),
|
|
|
+ require('./animate')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ var _Flickity = window.Flickity;
|
|
|
+
|
|
|
+ window.Flickity = factory(
|
|
|
+ window,
|
|
|
+ window.EvEmitter,
|
|
|
+ window.getSize,
|
|
|
+ window.fizzyUIUtils,
|
|
|
+ _Flickity.Cell,
|
|
|
+ _Flickity.Slide,
|
|
|
+ _Flickity.animatePrototype
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, EvEmitter, getSize,
|
|
|
+ utils, Cell, Slide, animatePrototype ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// vars
|
|
|
+var jQuery = window.jQuery;
|
|
|
+var getComputedStyle = window.getComputedStyle;
|
|
|
+var console = window.console;
|
|
|
+
|
|
|
+function moveElements( elems, toElem ) {
|
|
|
+ elems = utils.makeArray( elems );
|
|
|
+ while ( elems.length ) {
|
|
|
+ toElem.appendChild( elems.shift() );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- Flickity -------------------------- //
|
|
|
+
|
|
|
+// globally unique identifiers
|
|
|
+var GUID = 0;
|
|
|
+// internal store of all Flickity intances
|
|
|
+var instances = {};
|
|
|
+
|
|
|
+function Flickity( element, options ) {
|
|
|
+ var queryElement = utils.getQueryElement( element );
|
|
|
+ if ( !queryElement ) {
|
|
|
+ if ( console ) {
|
|
|
+ console.error( 'Bad element for Flickity: ' + ( queryElement || element ) );
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.element = queryElement;
|
|
|
+ // do not initialize twice on same element
|
|
|
+ if ( this.element.flickityGUID ) {
|
|
|
+ var instance = instances[ this.element.flickityGUID ];
|
|
|
+ instance.option( options );
|
|
|
+ return instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ // add jQuery
|
|
|
+ if ( jQuery ) {
|
|
|
+ this.$element = jQuery( this.element );
|
|
|
+ }
|
|
|
+ // options
|
|
|
+ this.options = utils.extend( {}, this.constructor.defaults );
|
|
|
+ this.option( options );
|
|
|
+
|
|
|
+ // kick things off
|
|
|
+ this._create();
|
|
|
+}
|
|
|
+
|
|
|
+Flickity.defaults = {
|
|
|
+ accessibility: true,
|
|
|
+ // adaptiveHeight: false,
|
|
|
+ cellAlign: 'center',
|
|
|
+ // cellSelector: undefined,
|
|
|
+ // contain: false,
|
|
|
+ freeScrollFriction: 0.075, // friction when free-scrolling
|
|
|
+ friction: 0.28, // friction when selecting
|
|
|
+ namespaceJQueryEvents: true,
|
|
|
+ // initialIndex: 0,
|
|
|
+ percentPosition: true,
|
|
|
+ resize: true,
|
|
|
+ selectedAttraction: 0.025,
|
|
|
+ setGallerySize: true
|
|
|
+ // watchCSS: false,
|
|
|
+ // wrapAround: false
|
|
|
+};
|
|
|
+
|
|
|
+// hash of methods triggered on _create()
|
|
|
+Flickity.createMethods = [];
|
|
|
+
|
|
|
+var proto = Flickity.prototype;
|
|
|
+// inherit EventEmitter
|
|
|
+utils.extend( proto, EvEmitter.prototype );
|
|
|
+
|
|
|
+proto._create = function() {
|
|
|
+ // add id for Flickity.data
|
|
|
+ var id = this.guid = ++GUID;
|
|
|
+ this.element.flickityGUID = id; // expando
|
|
|
+ instances[ id ] = this; // associate via id
|
|
|
+ // initial properties
|
|
|
+ this.selectedIndex = 0;
|
|
|
+ // how many frames slider has been in same position
|
|
|
+ this.restingFrames = 0;
|
|
|
+ // initial physics properties
|
|
|
+ this.x = 0;
|
|
|
+ this.velocity = 0;
|
|
|
+ this.originSide = this.options.rightToLeft ? 'right' : 'left';
|
|
|
+ // create viewport & slider
|
|
|
+ this.viewport = document.createElement('div');
|
|
|
+ this.viewport.className = 'flickity-viewport';
|
|
|
+ this._createSlider();
|
|
|
+
|
|
|
+ if ( this.options.resize || this.options.watchCSS ) {
|
|
|
+ window.addEventListener( 'resize', this );
|
|
|
+ }
|
|
|
+
|
|
|
+ // add listeners from on option
|
|
|
+ for ( var eventName in this.options.on ) {
|
|
|
+ var listener = this.options.on[ eventName ];
|
|
|
+ this.on( eventName, listener );
|
|
|
+ }
|
|
|
+
|
|
|
+ Flickity.createMethods.forEach( function( method ) {
|
|
|
+ this[ method ]();
|
|
|
+ }, this );
|
|
|
+
|
|
|
+ if ( this.options.watchCSS ) {
|
|
|
+ this.watchCSS();
|
|
|
+ } else {
|
|
|
+ this.activate();
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * set options
|
|
|
+ * @param {Object} opts
|
|
|
+ */
|
|
|
+proto.option = function( opts ) {
|
|
|
+ utils.extend( this.options, opts );
|
|
|
+};
|
|
|
+
|
|
|
+proto.activate = function() {
|
|
|
+ if ( this.isActive ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.isActive = true;
|
|
|
+ this.element.classList.add('flickity-enabled');
|
|
|
+ if ( this.options.rightToLeft ) {
|
|
|
+ this.element.classList.add('flickity-rtl');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.getSize();
|
|
|
+ // move initial cell elements so they can be loaded as cells
|
|
|
+ var cellElems = this._filterFindCellElements( this.element.children );
|
|
|
+ moveElements( cellElems, this.slider );
|
|
|
+ this.viewport.appendChild( this.slider );
|
|
|
+ this.element.appendChild( this.viewport );
|
|
|
+ // get cells from children
|
|
|
+ this.reloadCells();
|
|
|
+
|
|
|
+ if ( this.options.accessibility ) {
|
|
|
+ // allow element to focusable
|
|
|
+ this.element.tabIndex = 0;
|
|
|
+ // listen for key presses
|
|
|
+ this.element.addEventListener( 'keydown', this );
|
|
|
+ }
|
|
|
+
|
|
|
+ this.emitEvent('activate');
|
|
|
+ this.selectInitialIndex();
|
|
|
+ // flag for initial activation, for using initialIndex
|
|
|
+ this.isInitActivated = true;
|
|
|
+ // ready event. #493
|
|
|
+ this.dispatchEvent('ready');
|
|
|
+};
|
|
|
+
|
|
|
+// slider positions the cells
|
|
|
+proto._createSlider = function() {
|
|
|
+ // slider element does all the positioning
|
|
|
+ var slider = document.createElement('div');
|
|
|
+ slider.className = 'flickity-slider';
|
|
|
+ slider.style[ this.originSide ] = 0;
|
|
|
+ this.slider = slider;
|
|
|
+};
|
|
|
+
|
|
|
+proto._filterFindCellElements = function( elems ) {
|
|
|
+ return utils.filterFindElements( elems, this.options.cellSelector );
|
|
|
+};
|
|
|
+
|
|
|
+// goes through all children
|
|
|
+proto.reloadCells = function() {
|
|
|
+ // collection of item elements
|
|
|
+ this.cells = this._makeCells( this.slider.children );
|
|
|
+ this.positionCells();
|
|
|
+ this._getWrapShiftCells();
|
|
|
+ this.setGallerySize();
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * turn elements into Flickity.Cells
|
|
|
+ * @param {Array or NodeList or HTMLElement} elems
|
|
|
+ * @returns {Array} items - collection of new Flickity Cells
|
|
|
+ */
|
|
|
+proto._makeCells = function( elems ) {
|
|
|
+ var cellElems = this._filterFindCellElements( elems );
|
|
|
+
|
|
|
+ // create new Flickity for collection
|
|
|
+ var cells = cellElems.map( function( cellElem ) {
|
|
|
+ return new Cell( cellElem, this );
|
|
|
+ }, this );
|
|
|
+
|
|
|
+ return cells;
|
|
|
+};
|
|
|
+
|
|
|
+proto.getLastCell = function() {
|
|
|
+ return this.cells[ this.cells.length - 1 ];
|
|
|
+};
|
|
|
+
|
|
|
+proto.getLastSlide = function() {
|
|
|
+ return this.slides[ this.slides.length - 1 ];
|
|
|
+};
|
|
|
+
|
|
|
+// positions all cells
|
|
|
+proto.positionCells = function() {
|
|
|
+ // size all cells
|
|
|
+ this._sizeCells( this.cells );
|
|
|
+ // position all cells
|
|
|
+ this._positionCells( 0 );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * position certain cells
|
|
|
+ * @param {Integer} index - which cell to start with
|
|
|
+ */
|
|
|
+proto._positionCells = function( index ) {
|
|
|
+ index = index || 0;
|
|
|
+ // also measure maxCellHeight
|
|
|
+ // start 0 if positioning all cells
|
|
|
+ this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;
|
|
|
+ var cellX = 0;
|
|
|
+ // get cellX
|
|
|
+ if ( index > 0 ) {
|
|
|
+ var startCell = this.cells[ index - 1 ];
|
|
|
+ cellX = startCell.x + startCell.size.outerWidth;
|
|
|
+ }
|
|
|
+ var len = this.cells.length;
|
|
|
+ for ( var i=index; i < len; i++ ) {
|
|
|
+ var cell = this.cells[i];
|
|
|
+ cell.setPosition( cellX );
|
|
|
+ cellX += cell.size.outerWidth;
|
|
|
+ this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );
|
|
|
+ }
|
|
|
+ // keep track of cellX for wrap-around
|
|
|
+ this.slideableWidth = cellX;
|
|
|
+ // slides
|
|
|
+ this.updateSlides();
|
|
|
+ // contain slides target
|
|
|
+ this._containSlides();
|
|
|
+ // update slidesWidth
|
|
|
+ this.slidesWidth = len ? this.getLastSlide().target - this.slides[0].target : 0;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * cell.getSize() on multiple cells
|
|
|
+ * @param {Array} cells
|
|
|
+ */
|
|
|
+proto._sizeCells = function( cells ) {
|
|
|
+ cells.forEach( function( cell ) {
|
|
|
+ cell.getSize();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- -------------------------- //
|
|
|
+
|
|
|
+proto.updateSlides = function() {
|
|
|
+ this.slides = [];
|
|
|
+ if ( !this.cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var slide = new Slide( this );
|
|
|
+ this.slides.push( slide );
|
|
|
+ var isOriginLeft = this.originSide == 'left';
|
|
|
+ var nextMargin = isOriginLeft ? 'marginRight' : 'marginLeft';
|
|
|
+
|
|
|
+ var canCellFit = this._getCanCellFit();
|
|
|
+
|
|
|
+ this.cells.forEach( function( cell, i ) {
|
|
|
+ // just add cell if first cell in slide
|
|
|
+ if ( !slide.cells.length ) {
|
|
|
+ slide.addCell( cell );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var slideWidth = ( slide.outerWidth - slide.firstMargin ) +
|
|
|
+ ( cell.size.outerWidth - cell.size[ nextMargin ] );
|
|
|
+
|
|
|
+ if ( canCellFit.call( this, i, slideWidth ) ) {
|
|
|
+ slide.addCell( cell );
|
|
|
+ } else {
|
|
|
+ // doesn't fit, new slide
|
|
|
+ slide.updateTarget();
|
|
|
+
|
|
|
+ slide = new Slide( this );
|
|
|
+ this.slides.push( slide );
|
|
|
+ slide.addCell( cell );
|
|
|
+ }
|
|
|
+ }, this );
|
|
|
+ // last slide
|
|
|
+ slide.updateTarget();
|
|
|
+ // update .selectedSlide
|
|
|
+ this.updateSelectedSlide();
|
|
|
+};
|
|
|
+
|
|
|
+proto._getCanCellFit = function() {
|
|
|
+ var groupCells = this.options.groupCells;
|
|
|
+ if ( !groupCells ) {
|
|
|
+ return function() {
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ } else if ( typeof groupCells == 'number' ) {
|
|
|
+ // group by number. 3 -> [0,1,2], [3,4,5], ...
|
|
|
+ var number = parseInt( groupCells, 10 );
|
|
|
+ return function( i ) {
|
|
|
+ return ( i % number ) !== 0;
|
|
|
+ };
|
|
|
+ }
|
|
|
+ // default, group by width of slide
|
|
|
+ // parse '75%
|
|
|
+ var percentMatch = typeof groupCells == 'string' &&
|
|
|
+ groupCells.match(/^(\d+)%$/);
|
|
|
+ var percent = percentMatch ? parseInt( percentMatch[1], 10 ) / 100 : 1;
|
|
|
+ return function( i, slideWidth ) {
|
|
|
+ return slideWidth <= ( this.size.innerWidth + 1 ) * percent;
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// alias _init for jQuery plugin .flickity()
|
|
|
+proto._init =
|
|
|
+proto.reposition = function() {
|
|
|
+ this.positionCells();
|
|
|
+ this.positionSliderAtSelected();
|
|
|
+};
|
|
|
+
|
|
|
+proto.getSize = function() {
|
|
|
+ this.size = getSize( this.element );
|
|
|
+ this.setCellAlign();
|
|
|
+ this.cursorPosition = this.size.innerWidth * this.cellAlign;
|
|
|
+};
|
|
|
+
|
|
|
+var cellAlignShorthands = {
|
|
|
+ // cell align, then based on origin side
|
|
|
+ center: {
|
|
|
+ left: 0.5,
|
|
|
+ right: 0.5
|
|
|
+ },
|
|
|
+ left: {
|
|
|
+ left: 0,
|
|
|
+ right: 1
|
|
|
+ },
|
|
|
+ right: {
|
|
|
+ right: 0,
|
|
|
+ left: 1
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.setCellAlign = function() {
|
|
|
+ var shorthand = cellAlignShorthands[ this.options.cellAlign ];
|
|
|
+ this.cellAlign = shorthand ? shorthand[ this.originSide ] : this.options.cellAlign;
|
|
|
+};
|
|
|
+
|
|
|
+proto.setGallerySize = function() {
|
|
|
+ if ( this.options.setGallerySize ) {
|
|
|
+ var height = this.options.adaptiveHeight && this.selectedSlide ?
|
|
|
+ this.selectedSlide.height : this.maxCellHeight;
|
|
|
+ this.viewport.style.height = height + 'px';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto._getWrapShiftCells = function() {
|
|
|
+ // only for wrap-around
|
|
|
+ if ( !this.options.wrapAround ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // unshift previous cells
|
|
|
+ this._unshiftCells( this.beforeShiftCells );
|
|
|
+ this._unshiftCells( this.afterShiftCells );
|
|
|
+ // get before cells
|
|
|
+ // initial gap
|
|
|
+ var gapX = this.cursorPosition;
|
|
|
+ var cellIndex = this.cells.length - 1;
|
|
|
+ this.beforeShiftCells = this._getGapCells( gapX, cellIndex, -1 );
|
|
|
+ // get after cells
|
|
|
+ // ending gap between last cell and end of gallery viewport
|
|
|
+ gapX = this.size.innerWidth - this.cursorPosition;
|
|
|
+ // start cloning at first cell, working forwards
|
|
|
+ this.afterShiftCells = this._getGapCells( gapX, 0, 1 );
|
|
|
+};
|
|
|
+
|
|
|
+proto._getGapCells = function( gapX, cellIndex, increment ) {
|
|
|
+ // keep adding cells until the cover the initial gap
|
|
|
+ var cells = [];
|
|
|
+ while ( gapX > 0 ) {
|
|
|
+ var cell = this.cells[ cellIndex ];
|
|
|
+ if ( !cell ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ cells.push( cell );
|
|
|
+ cellIndex += increment;
|
|
|
+ gapX -= cell.size.outerWidth;
|
|
|
+ }
|
|
|
+ return cells;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- contain ----- //
|
|
|
+
|
|
|
+// contain cell targets so no excess sliding
|
|
|
+proto._containSlides = function() {
|
|
|
+ if ( !this.options.contain || this.options.wrapAround || !this.cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var isRightToLeft = this.options.rightToLeft;
|
|
|
+ var beginMargin = isRightToLeft ? 'marginRight' : 'marginLeft';
|
|
|
+ var endMargin = isRightToLeft ? 'marginLeft' : 'marginRight';
|
|
|
+ var contentWidth = this.slideableWidth - this.getLastCell().size[ endMargin ];
|
|
|
+ // content is less than gallery size
|
|
|
+ var isContentSmaller = contentWidth < this.size.innerWidth;
|
|
|
+ // bounds
|
|
|
+ var beginBound = this.cursorPosition + this.cells[0].size[ beginMargin ];
|
|
|
+ var endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );
|
|
|
+ // contain each cell target
|
|
|
+ this.slides.forEach( function( slide ) {
|
|
|
+ if ( isContentSmaller ) {
|
|
|
+ // all cells fit inside gallery
|
|
|
+ slide.target = contentWidth * this.cellAlign;
|
|
|
+ } else {
|
|
|
+ // contain to bounds
|
|
|
+ slide.target = Math.max( slide.target, beginBound );
|
|
|
+ slide.target = Math.min( slide.target, endBound );
|
|
|
+ }
|
|
|
+ }, this );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * emits events via eventEmitter and jQuery events
|
|
|
+ * @param {String} type - name of event
|
|
|
+ * @param {Event} event - original event
|
|
|
+ * @param {Array} args - extra arguments
|
|
|
+ */
|
|
|
+proto.dispatchEvent = function( type, event, args ) {
|
|
|
+ var emitArgs = event ? [ event ].concat( args ) : args;
|
|
|
+ this.emitEvent( type, emitArgs );
|
|
|
+
|
|
|
+ if ( jQuery && this.$element ) {
|
|
|
+ // default trigger with type if no event
|
|
|
+ type += this.options.namespaceJQueryEvents ? '.flickity' : '';
|
|
|
+ var $event = type;
|
|
|
+ if ( event ) {
|
|
|
+ // create jQuery event
|
|
|
+ var jQEvent = jQuery.Event( event );
|
|
|
+ jQEvent.type = type;
|
|
|
+ $event = jQEvent;
|
|
|
+ }
|
|
|
+ this.$element.trigger( $event, args );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- select -------------------------- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {Integer} index - index of the slide
|
|
|
+ * @param {Boolean} isWrap - will wrap-around to last/first if at the end
|
|
|
+ * @param {Boolean} isInstant - will immediately set position at selected cell
|
|
|
+ */
|
|
|
+proto.select = function( index, isWrap, isInstant ) {
|
|
|
+ if ( !this.isActive ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ index = parseInt( index, 10 );
|
|
|
+ this._wrapSelect( index );
|
|
|
+
|
|
|
+ if ( this.options.wrapAround || isWrap ) {
|
|
|
+ index = utils.modulo( index, this.slides.length );
|
|
|
+ }
|
|
|
+ // bail if invalid index
|
|
|
+ if ( !this.slides[ index ] ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var prevIndex = this.selectedIndex;
|
|
|
+ this.selectedIndex = index;
|
|
|
+ this.updateSelectedSlide();
|
|
|
+ if ( isInstant ) {
|
|
|
+ this.positionSliderAtSelected();
|
|
|
+ } else {
|
|
|
+ this.startAnimation();
|
|
|
+ }
|
|
|
+ if ( this.options.adaptiveHeight ) {
|
|
|
+ this.setGallerySize();
|
|
|
+ }
|
|
|
+ // events
|
|
|
+ this.dispatchEvent( 'select', null, [ index ] );
|
|
|
+ // change event if new index
|
|
|
+ if ( index != prevIndex ) {
|
|
|
+ this.dispatchEvent( 'change', null, [ index ] );
|
|
|
+ }
|
|
|
+ // old v1 event name, remove in v3
|
|
|
+ this.dispatchEvent('cellSelect');
|
|
|
+};
|
|
|
+
|
|
|
+// wraps position for wrapAround, to move to closest slide. #113
|
|
|
+proto._wrapSelect = function( index ) {
|
|
|
+ var len = this.slides.length;
|
|
|
+ var isWrapping = this.options.wrapAround && len > 1;
|
|
|
+ if ( !isWrapping ) {
|
|
|
+ return index;
|
|
|
+ }
|
|
|
+ var wrapIndex = utils.modulo( index, len );
|
|
|
+ // go to shortest
|
|
|
+ var delta = Math.abs( wrapIndex - this.selectedIndex );
|
|
|
+ var backWrapDelta = Math.abs( ( wrapIndex + len ) - this.selectedIndex );
|
|
|
+ var forewardWrapDelta = Math.abs( ( wrapIndex - len ) - this.selectedIndex );
|
|
|
+ if ( !this.isDragSelect && backWrapDelta < delta ) {
|
|
|
+ index += len;
|
|
|
+ } else if ( !this.isDragSelect && forewardWrapDelta < delta ) {
|
|
|
+ index -= len;
|
|
|
+ }
|
|
|
+ // wrap position so slider is within normal area
|
|
|
+ if ( index < 0 ) {
|
|
|
+ this.x -= this.slideableWidth;
|
|
|
+ } else if ( index >= len ) {
|
|
|
+ this.x += this.slideableWidth;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.previous = function( isWrap, isInstant ) {
|
|
|
+ this.select( this.selectedIndex - 1, isWrap, isInstant );
|
|
|
+};
|
|
|
+
|
|
|
+proto.next = function( isWrap, isInstant ) {
|
|
|
+ this.select( this.selectedIndex + 1, isWrap, isInstant );
|
|
|
+};
|
|
|
+
|
|
|
+proto.updateSelectedSlide = function() {
|
|
|
+ var slide = this.slides[ this.selectedIndex ];
|
|
|
+ // selectedIndex could be outside of slides, if triggered before resize()
|
|
|
+ if ( !slide ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // unselect previous selected slide
|
|
|
+ this.unselectSelectedSlide();
|
|
|
+ // update new selected slide
|
|
|
+ this.selectedSlide = slide;
|
|
|
+ slide.select();
|
|
|
+ this.selectedCells = slide.cells;
|
|
|
+ this.selectedElements = slide.getCellElements();
|
|
|
+ // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility
|
|
|
+ // Remove in v3?
|
|
|
+ this.selectedCell = slide.cells[0];
|
|
|
+ this.selectedElement = this.selectedElements[0];
|
|
|
+};
|
|
|
+
|
|
|
+proto.unselectSelectedSlide = function() {
|
|
|
+ if ( this.selectedSlide ) {
|
|
|
+ this.selectedSlide.unselect();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.selectInitialIndex = function() {
|
|
|
+ var initialIndex = this.options.initialIndex;
|
|
|
+ // already activated, select previous selectedIndex
|
|
|
+ if ( this.isInitActivated ) {
|
|
|
+ this.select( this.selectedIndex, false, true );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // select with selector string
|
|
|
+ if ( initialIndex && typeof initialIndex == 'string' ) {
|
|
|
+ var cell = this.queryCell( initialIndex );
|
|
|
+ if ( cell ) {
|
|
|
+ this.selectCell( initialIndex, false, true );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var index = 0;
|
|
|
+ // select with number
|
|
|
+ if ( initialIndex && this.slides[ initialIndex ] ) {
|
|
|
+ index = initialIndex;
|
|
|
+ }
|
|
|
+ // select instantly
|
|
|
+ this.select( index, false, true );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * select slide from number or cell element
|
|
|
+ * @param {Element or Number} elem
|
|
|
+ */
|
|
|
+proto.selectCell = function( value, isWrap, isInstant ) {
|
|
|
+ // get cell
|
|
|
+ var cell = this.queryCell( value );
|
|
|
+ if ( !cell ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var index = this.getCellSlideIndex( cell );
|
|
|
+ this.select( index, isWrap, isInstant );
|
|
|
+};
|
|
|
+
|
|
|
+proto.getCellSlideIndex = function( cell ) {
|
|
|
+ // get index of slides that has cell
|
|
|
+ for ( var i=0; i < this.slides.length; i++ ) {
|
|
|
+ var slide = this.slides[i];
|
|
|
+ var index = slide.cells.indexOf( cell );
|
|
|
+ if ( index != -1 ) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- get cells -------------------------- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * get Flickity.Cell, given an Element
|
|
|
+ * @param {Element} elem
|
|
|
+ * @returns {Flickity.Cell} item
|
|
|
+ */
|
|
|
+proto.getCell = function( elem ) {
|
|
|
+ // loop through cells to get the one that matches
|
|
|
+ for ( var i=0; i < this.cells.length; i++ ) {
|
|
|
+ var cell = this.cells[i];
|
|
|
+ if ( cell.element == elem ) {
|
|
|
+ return cell;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * get collection of Flickity.Cells, given Elements
|
|
|
+ * @param {Element, Array, NodeList} elems
|
|
|
+ * @returns {Array} cells - Flickity.Cells
|
|
|
+ */
|
|
|
+proto.getCells = function( elems ) {
|
|
|
+ elems = utils.makeArray( elems );
|
|
|
+ var cells = [];
|
|
|
+ elems.forEach( function( elem ) {
|
|
|
+ var cell = this.getCell( elem );
|
|
|
+ if ( cell ) {
|
|
|
+ cells.push( cell );
|
|
|
+ }
|
|
|
+ }, this );
|
|
|
+ return cells;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * get cell elements
|
|
|
+ * @returns {Array} cellElems
|
|
|
+ */
|
|
|
+proto.getCellElements = function() {
|
|
|
+ return this.cells.map( function( cell ) {
|
|
|
+ return cell.element;
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * get parent cell from an element
|
|
|
+ * @param {Element} elem
|
|
|
+ * @returns {Flickit.Cell} cell
|
|
|
+ */
|
|
|
+proto.getParentCell = function( elem ) {
|
|
|
+ // first check if elem is cell
|
|
|
+ var cell = this.getCell( elem );
|
|
|
+ if ( cell ) {
|
|
|
+ return cell;
|
|
|
+ }
|
|
|
+ // try to get parent cell elem
|
|
|
+ elem = utils.getParent( elem, '.flickity-slider > *' );
|
|
|
+ return this.getCell( elem );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * get cells adjacent to a slide
|
|
|
+ * @param {Integer} adjCount - number of adjacent slides
|
|
|
+ * @param {Integer} index - index of slide to start
|
|
|
+ * @returns {Array} cells - array of Flickity.Cells
|
|
|
+ */
|
|
|
+proto.getAdjacentCellElements = function( adjCount, index ) {
|
|
|
+ if ( !adjCount ) {
|
|
|
+ return this.selectedSlide.getCellElements();
|
|
|
+ }
|
|
|
+ index = index === undefined ? this.selectedIndex : index;
|
|
|
+
|
|
|
+ var len = this.slides.length;
|
|
|
+ if ( 1 + ( adjCount * 2 ) >= len ) {
|
|
|
+ return this.getCellElements();
|
|
|
+ }
|
|
|
+
|
|
|
+ var cellElems = [];
|
|
|
+ for ( var i = index - adjCount; i <= index + adjCount ; i++ ) {
|
|
|
+ var slideIndex = this.options.wrapAround ? utils.modulo( i, len ) : i;
|
|
|
+ var slide = this.slides[ slideIndex ];
|
|
|
+ if ( slide ) {
|
|
|
+ cellElems = cellElems.concat( slide.getCellElements() );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return cellElems;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * select slide from number or cell element
|
|
|
+ * @param {Element, Selector String, or Number} selector
|
|
|
+ */
|
|
|
+proto.queryCell = function( selector ) {
|
|
|
+ if ( typeof selector == 'number' ) {
|
|
|
+ // use number as index
|
|
|
+ return this.cells[ selector ];
|
|
|
+ }
|
|
|
+ if ( typeof selector == 'string' ) {
|
|
|
+ // do not select invalid selectors from hash: #123, #/. #791
|
|
|
+ if ( selector.match(/^[#\.]?[\d\/]/) ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // use string as selector, get element
|
|
|
+ selector = this.element.querySelector( selector );
|
|
|
+ }
|
|
|
+ // get cell from element
|
|
|
+ return this.getCell( selector );
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- events -------------------------- //
|
|
|
+
|
|
|
+proto.uiChange = function() {
|
|
|
+ this.emitEvent('uiChange');
|
|
|
+};
|
|
|
+
|
|
|
+// keep focus on element when child UI elements are clicked
|
|
|
+proto.childUIPointerDown = function( event ) {
|
|
|
+ // HACK iOS does not allow touch events to bubble up?!
|
|
|
+ if ( event.type != 'touchstart' ) {
|
|
|
+ event.preventDefault();
|
|
|
+ }
|
|
|
+ this.focus();
|
|
|
+};
|
|
|
+
|
|
|
+// ----- resize ----- //
|
|
|
+
|
|
|
+proto.onresize = function() {
|
|
|
+ this.watchCSS();
|
|
|
+ this.resize();
|
|
|
+};
|
|
|
+
|
|
|
+utils.debounceMethod( Flickity, 'onresize', 150 );
|
|
|
+
|
|
|
+proto.resize = function() {
|
|
|
+ if ( !this.isActive ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.getSize();
|
|
|
+ // wrap values
|
|
|
+ if ( this.options.wrapAround ) {
|
|
|
+ this.x = utils.modulo( this.x, this.slideableWidth );
|
|
|
+ }
|
|
|
+ this.positionCells();
|
|
|
+ this._getWrapShiftCells();
|
|
|
+ this.setGallerySize();
|
|
|
+ this.emitEvent('resize');
|
|
|
+ // update selected index for group slides, instant
|
|
|
+ // TODO: position can be lost between groups of various numbers
|
|
|
+ var selectedElement = this.selectedElements && this.selectedElements[0];
|
|
|
+ this.selectCell( selectedElement, false, true );
|
|
|
+};
|
|
|
+
|
|
|
+// watches the :after property, activates/deactivates
|
|
|
+proto.watchCSS = function() {
|
|
|
+ var watchOption = this.options.watchCSS;
|
|
|
+ if ( !watchOption ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var afterContent = getComputedStyle( this.element, ':after' ).content;
|
|
|
+ // activate if :after { content: 'flickity' }
|
|
|
+ if ( afterContent.indexOf('flickity') != -1 ) {
|
|
|
+ this.activate();
|
|
|
+ } else {
|
|
|
+ this.deactivate();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- keydown ----- //
|
|
|
+
|
|
|
+// go previous/next if left/right keys pressed
|
|
|
+proto.onkeydown = function( event ) {
|
|
|
+ // only work if element is in focus
|
|
|
+ var isNotFocused = document.activeElement && document.activeElement != this.element;
|
|
|
+ if ( !this.options.accessibility ||isNotFocused ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var handler = Flickity.keyboardHandlers[ event.keyCode ];
|
|
|
+ if ( handler ) {
|
|
|
+ handler.call( this );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Flickity.keyboardHandlers = {
|
|
|
+ // left arrow
|
|
|
+ 37: function() {
|
|
|
+ var leftMethod = this.options.rightToLeft ? 'next' : 'previous';
|
|
|
+ this.uiChange();
|
|
|
+ this[ leftMethod ]();
|
|
|
+ },
|
|
|
+ // right arrow
|
|
|
+ 39: function() {
|
|
|
+ var rightMethod = this.options.rightToLeft ? 'previous' : 'next';
|
|
|
+ this.uiChange();
|
|
|
+ this[ rightMethod ]();
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+// ----- focus ----- //
|
|
|
+
|
|
|
+proto.focus = function() {
|
|
|
+ // TODO remove scrollTo once focus options gets more support
|
|
|
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Browser_compatibility
|
|
|
+ var prevScrollY = window.pageYOffset;
|
|
|
+ this.element.focus({ preventScroll: true });
|
|
|
+ // hack to fix scroll jump after focus, #76
|
|
|
+ if ( window.pageYOffset != prevScrollY ) {
|
|
|
+ window.scrollTo( window.pageXOffset, prevScrollY );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- destroy -------------------------- //
|
|
|
+
|
|
|
+// deactivate all Flickity functionality, but keep stuff available
|
|
|
+proto.deactivate = function() {
|
|
|
+ if ( !this.isActive ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.element.classList.remove('flickity-enabled');
|
|
|
+ this.element.classList.remove('flickity-rtl');
|
|
|
+ this.unselectSelectedSlide();
|
|
|
+ // destroy cells
|
|
|
+ this.cells.forEach( function( cell ) {
|
|
|
+ cell.destroy();
|
|
|
+ });
|
|
|
+ this.element.removeChild( this.viewport );
|
|
|
+ // move child elements back into element
|
|
|
+ moveElements( this.slider.children, this.element );
|
|
|
+ if ( this.options.accessibility ) {
|
|
|
+ this.element.removeAttribute('tabIndex');
|
|
|
+ this.element.removeEventListener( 'keydown', this );
|
|
|
+ }
|
|
|
+ // set flags
|
|
|
+ this.isActive = false;
|
|
|
+ this.emitEvent('deactivate');
|
|
|
+};
|
|
|
+
|
|
|
+proto.destroy = function() {
|
|
|
+ this.deactivate();
|
|
|
+ window.removeEventListener( 'resize', this );
|
|
|
+ this.allOff();
|
|
|
+ this.emitEvent('destroy');
|
|
|
+ if ( jQuery && this.$element ) {
|
|
|
+ jQuery.removeData( this.element, 'flickity' );
|
|
|
+ }
|
|
|
+ delete this.element.flickityGUID;
|
|
|
+ delete instances[ this.guid ];
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- prototype -------------------------- //
|
|
|
+
|
|
|
+utils.extend( proto, animatePrototype );
|
|
|
+
|
|
|
+// -------------------------- extras -------------------------- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * get Flickity instance from element
|
|
|
+ * @param {Element} elem
|
|
|
+ * @returns {Flickity}
|
|
|
+ */
|
|
|
+Flickity.data = function( elem ) {
|
|
|
+ elem = utils.getQueryElement( elem );
|
|
|
+ var id = elem && elem.flickityGUID;
|
|
|
+ return id && instances[ id ];
|
|
|
+};
|
|
|
+
|
|
|
+utils.htmlInit( Flickity, 'flickity' );
|
|
|
+
|
|
|
+if ( jQuery && jQuery.bridget ) {
|
|
|
+ jQuery.bridget( 'flickity', Flickity );
|
|
|
+}
|
|
|
+
|
|
|
+// set internal jQuery, for Webpack + jQuery v3, #478
|
|
|
+Flickity.setJQuery = function( jq ) {
|
|
|
+ jQuery = jq;
|
|
|
+};
|
|
|
+
|
|
|
+Flickity.Cell = Cell;
|
|
|
+Flickity.Slide = Slide;
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/*!
|
|
|
+ * Unipointer v2.3.0
|
|
|
+ * base class for doing one thing with pointer event
|
|
|
+ * MIT license
|
|
|
+ */
|
|
|
+
|
|
|
+/*jshint browser: true, undef: true, unused: true, strict: true */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */ /*global define, module, require */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'unipointer/unipointer',[
|
|
|
+ 'ev-emitter/ev-emitter'
|
|
|
+ ], function( EvEmitter ) {
|
|
|
+ return factory( window, EvEmitter );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('ev-emitter')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Unipointer = factory(
|
|
|
+ window,
|
|
|
+ window.EvEmitter
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, EvEmitter ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+function noop() {}
|
|
|
+
|
|
|
+function Unipointer() {}
|
|
|
+
|
|
|
+// inherit EvEmitter
|
|
|
+var proto = Unipointer.prototype = Object.create( EvEmitter.prototype );
|
|
|
+
|
|
|
+proto.bindStartEvent = function( elem ) {
|
|
|
+ this._bindStartEvent( elem, true );
|
|
|
+};
|
|
|
+
|
|
|
+proto.unbindStartEvent = function( elem ) {
|
|
|
+ this._bindStartEvent( elem, false );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add or remove start event
|
|
|
+ * @param {Boolean} isAdd - remove if falsey
|
|
|
+ */
|
|
|
+proto._bindStartEvent = function( elem, isAdd ) {
|
|
|
+ // munge isAdd, default to true
|
|
|
+ isAdd = isAdd === undefined ? true : isAdd;
|
|
|
+ var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';
|
|
|
+
|
|
|
+ // default to mouse events
|
|
|
+ var startEvent = 'mousedown';
|
|
|
+ if ( window.PointerEvent ) {
|
|
|
+ // Pointer Events
|
|
|
+ startEvent = 'pointerdown';
|
|
|
+ } else if ( 'ontouchstart' in window ) {
|
|
|
+ // Touch Events. iOS Safari
|
|
|
+ startEvent = 'touchstart';
|
|
|
+ }
|
|
|
+ elem[ bindMethod ]( startEvent, this );
|
|
|
+};
|
|
|
+
|
|
|
+// trigger handler methods for events
|
|
|
+proto.handleEvent = function( event ) {
|
|
|
+ var method = 'on' + event.type;
|
|
|
+ if ( this[ method ] ) {
|
|
|
+ this[ method ]( event );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// returns the touch that we're keeping track of
|
|
|
+proto.getTouch = function( touches ) {
|
|
|
+ for ( var i=0; i < touches.length; i++ ) {
|
|
|
+ var touch = touches[i];
|
|
|
+ if ( touch.identifier == this.pointerIdentifier ) {
|
|
|
+ return touch;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- start event ----- //
|
|
|
+
|
|
|
+proto.onmousedown = function( event ) {
|
|
|
+ // dismiss clicks from right or middle buttons
|
|
|
+ var button = event.button;
|
|
|
+ if ( button && ( button !== 0 && button !== 1 ) ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._pointerDown( event, event );
|
|
|
+};
|
|
|
+
|
|
|
+proto.ontouchstart = function( event ) {
|
|
|
+ this._pointerDown( event, event.changedTouches[0] );
|
|
|
+};
|
|
|
+
|
|
|
+proto.onpointerdown = function( event ) {
|
|
|
+ this._pointerDown( event, event );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * pointer start
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ */
|
|
|
+proto._pointerDown = function( event, pointer ) {
|
|
|
+ // dismiss right click and other pointers
|
|
|
+ // button = 0 is okay, 1-4 not
|
|
|
+ if ( event.button || this.isPointerDown ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.isPointerDown = true;
|
|
|
+ // save pointer identifier to match up touch events
|
|
|
+ this.pointerIdentifier = pointer.pointerId !== undefined ?
|
|
|
+ // pointerId for pointer events, touch.indentifier for touch events
|
|
|
+ pointer.pointerId : pointer.identifier;
|
|
|
+
|
|
|
+ this.pointerDown( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+proto.pointerDown = function( event, pointer ) {
|
|
|
+ this._bindPostStartEvents( event );
|
|
|
+ this.emitEvent( 'pointerDown', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// hash of events to be bound after start event
|
|
|
+var postStartEvents = {
|
|
|
+ mousedown: [ 'mousemove', 'mouseup' ],
|
|
|
+ touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
|
|
|
+ pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
|
|
|
+};
|
|
|
+
|
|
|
+proto._bindPostStartEvents = function( event ) {
|
|
|
+ if ( !event ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // get proper events to match start event
|
|
|
+ var events = postStartEvents[ event.type ];
|
|
|
+ // bind events to node
|
|
|
+ events.forEach( function( eventName ) {
|
|
|
+ window.addEventListener( eventName, this );
|
|
|
+ }, this );
|
|
|
+ // save these arguments
|
|
|
+ this._boundPointerEvents = events;
|
|
|
+};
|
|
|
+
|
|
|
+proto._unbindPostStartEvents = function() {
|
|
|
+ // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)
|
|
|
+ if ( !this._boundPointerEvents ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._boundPointerEvents.forEach( function( eventName ) {
|
|
|
+ window.removeEventListener( eventName, this );
|
|
|
+ }, this );
|
|
|
+
|
|
|
+ delete this._boundPointerEvents;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- move event ----- //
|
|
|
+
|
|
|
+proto.onmousemove = function( event ) {
|
|
|
+ this._pointerMove( event, event );
|
|
|
+};
|
|
|
+
|
|
|
+proto.onpointermove = function( event ) {
|
|
|
+ if ( event.pointerId == this.pointerIdentifier ) {
|
|
|
+ this._pointerMove( event, event );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.ontouchmove = function( event ) {
|
|
|
+ var touch = this.getTouch( event.changedTouches );
|
|
|
+ if ( touch ) {
|
|
|
+ this._pointerMove( event, touch );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * pointer move
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+proto._pointerMove = function( event, pointer ) {
|
|
|
+ this.pointerMove( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+// public
|
|
|
+proto.pointerMove = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'pointerMove', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- end event ----- //
|
|
|
+
|
|
|
+
|
|
|
+proto.onmouseup = function( event ) {
|
|
|
+ this._pointerUp( event, event );
|
|
|
+};
|
|
|
+
|
|
|
+proto.onpointerup = function( event ) {
|
|
|
+ if ( event.pointerId == this.pointerIdentifier ) {
|
|
|
+ this._pointerUp( event, event );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.ontouchend = function( event ) {
|
|
|
+ var touch = this.getTouch( event.changedTouches );
|
|
|
+ if ( touch ) {
|
|
|
+ this._pointerUp( event, touch );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * pointer up
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+proto._pointerUp = function( event, pointer ) {
|
|
|
+ this._pointerDone();
|
|
|
+ this.pointerUp( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+// public
|
|
|
+proto.pointerUp = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'pointerUp', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- pointer done ----- //
|
|
|
+
|
|
|
+// triggered on pointer up & pointer cancel
|
|
|
+proto._pointerDone = function() {
|
|
|
+ this._pointerReset();
|
|
|
+ this._unbindPostStartEvents();
|
|
|
+ this.pointerDone();
|
|
|
+};
|
|
|
+
|
|
|
+proto._pointerReset = function() {
|
|
|
+ // reset properties
|
|
|
+ this.isPointerDown = false;
|
|
|
+ delete this.pointerIdentifier;
|
|
|
+};
|
|
|
+
|
|
|
+proto.pointerDone = noop;
|
|
|
+
|
|
|
+// ----- pointer cancel ----- //
|
|
|
+
|
|
|
+proto.onpointercancel = function( event ) {
|
|
|
+ if ( event.pointerId == this.pointerIdentifier ) {
|
|
|
+ this._pointerCancel( event, event );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.ontouchcancel = function( event ) {
|
|
|
+ var touch = this.getTouch( event.changedTouches );
|
|
|
+ if ( touch ) {
|
|
|
+ this._pointerCancel( event, touch );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * pointer cancel
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+proto._pointerCancel = function( event, pointer ) {
|
|
|
+ this._pointerDone();
|
|
|
+ this.pointerCancel( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+// public
|
|
|
+proto.pointerCancel = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'pointerCancel', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+// utility function for getting x/y coords from event
|
|
|
+Unipointer.getPointerPoint = function( pointer ) {
|
|
|
+ return {
|
|
|
+ x: pointer.pageX,
|
|
|
+ y: pointer.pageY
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return Unipointer;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/*!
|
|
|
+ * Unidragger v2.3.0
|
|
|
+ * Draggable base class
|
|
|
+ * MIT license
|
|
|
+ */
|
|
|
+
|
|
|
+/*jshint browser: true, unused: true, undef: true, strict: true */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /*jshint strict: false */ /*globals define, module, require */
|
|
|
+
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'unidragger/unidragger',[
|
|
|
+ 'unipointer/unipointer'
|
|
|
+ ], function( Unipointer ) {
|
|
|
+ return factory( window, Unipointer );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('unipointer')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Unidragger = factory(
|
|
|
+ window,
|
|
|
+ window.Unipointer
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Unipointer ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// -------------------------- Unidragger -------------------------- //
|
|
|
+
|
|
|
+function Unidragger() {}
|
|
|
+
|
|
|
+// inherit Unipointer & EvEmitter
|
|
|
+var proto = Unidragger.prototype = Object.create( Unipointer.prototype );
|
|
|
+
|
|
|
+// ----- bind start ----- //
|
|
|
+
|
|
|
+proto.bindHandles = function() {
|
|
|
+ this._bindHandles( true );
|
|
|
+};
|
|
|
+
|
|
|
+proto.unbindHandles = function() {
|
|
|
+ this._bindHandles( false );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add or remove start event
|
|
|
+ * @param {Boolean} isAdd
|
|
|
+ */
|
|
|
+proto._bindHandles = function( isAdd ) {
|
|
|
+ // munge isAdd, default to true
|
|
|
+ isAdd = isAdd === undefined ? true : isAdd;
|
|
|
+ // bind each handle
|
|
|
+ var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';
|
|
|
+ var touchAction = isAdd ? this._touchActionValue : '';
|
|
|
+ for ( var i=0; i < this.handles.length; i++ ) {
|
|
|
+ var handle = this.handles[i];
|
|
|
+ this._bindStartEvent( handle, isAdd );
|
|
|
+ handle[ bindMethod ]( 'click', this );
|
|
|
+ // touch-action: none to override browser touch gestures. metafizzy/flickity#540
|
|
|
+ if ( window.PointerEvent ) {
|
|
|
+ handle.style.touchAction = touchAction;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// prototype so it can be overwriteable by Flickity
|
|
|
+proto._touchActionValue = 'none';
|
|
|
+
|
|
|
+// ----- start event ----- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * pointer start
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ */
|
|
|
+proto.pointerDown = function( event, pointer ) {
|
|
|
+ var isOkay = this.okayPointerDown( event );
|
|
|
+ if ( !isOkay ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // track start event position
|
|
|
+ this.pointerDownPointer = pointer;
|
|
|
+
|
|
|
+ event.preventDefault();
|
|
|
+ this.pointerDownBlur();
|
|
|
+ // bind move and end events
|
|
|
+ this._bindPostStartEvents( event );
|
|
|
+ this.emitEvent( 'pointerDown', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// nodes that have text fields
|
|
|
+var cursorNodes = {
|
|
|
+ TEXTAREA: true,
|
|
|
+ INPUT: true,
|
|
|
+ SELECT: true,
|
|
|
+ OPTION: true,
|
|
|
+};
|
|
|
+
|
|
|
+// input types that do not have text fields
|
|
|
+var clickTypes = {
|
|
|
+ radio: true,
|
|
|
+ checkbox: true,
|
|
|
+ button: true,
|
|
|
+ submit: true,
|
|
|
+ image: true,
|
|
|
+ file: true,
|
|
|
+};
|
|
|
+
|
|
|
+// dismiss inputs with text fields. flickity#403, flickity#404
|
|
|
+proto.okayPointerDown = function( event ) {
|
|
|
+ var isCursorNode = cursorNodes[ event.target.nodeName ];
|
|
|
+ var isClickType = clickTypes[ event.target.type ];
|
|
|
+ var isOkay = !isCursorNode || isClickType;
|
|
|
+ if ( !isOkay ) {
|
|
|
+ this._pointerReset();
|
|
|
+ }
|
|
|
+ return isOkay;
|
|
|
+};
|
|
|
+
|
|
|
+// kludge to blur previously focused input
|
|
|
+proto.pointerDownBlur = function() {
|
|
|
+ var focused = document.activeElement;
|
|
|
+ // do not blur body for IE10, metafizzy/flickity#117
|
|
|
+ var canBlur = focused && focused.blur && focused != document.body;
|
|
|
+ if ( canBlur ) {
|
|
|
+ focused.blur();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- move event ----- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * drag move
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ */
|
|
|
+proto.pointerMove = function( event, pointer ) {
|
|
|
+ var moveVector = this._dragPointerMove( event, pointer );
|
|
|
+ this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );
|
|
|
+ this._dragMove( event, pointer, moveVector );
|
|
|
+};
|
|
|
+
|
|
|
+// base pointer move logic
|
|
|
+proto._dragPointerMove = function( event, pointer ) {
|
|
|
+ var moveVector = {
|
|
|
+ x: pointer.pageX - this.pointerDownPointer.pageX,
|
|
|
+ y: pointer.pageY - this.pointerDownPointer.pageY
|
|
|
+ };
|
|
|
+ // start drag if pointer has moved far enough to start drag
|
|
|
+ if ( !this.isDragging && this.hasDragStarted( moveVector ) ) {
|
|
|
+ this._dragStart( event, pointer );
|
|
|
+ }
|
|
|
+ return moveVector;
|
|
|
+};
|
|
|
+
|
|
|
+// condition if pointer has moved far enough to start drag
|
|
|
+proto.hasDragStarted = function( moveVector ) {
|
|
|
+ return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- end event ----- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * pointer up
|
|
|
+ * @param {Event} event
|
|
|
+ * @param {Event or Touch} pointer
|
|
|
+ */
|
|
|
+proto.pointerUp = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'pointerUp', [ event, pointer ] );
|
|
|
+ this._dragPointerUp( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+proto._dragPointerUp = function( event, pointer ) {
|
|
|
+ if ( this.isDragging ) {
|
|
|
+ this._dragEnd( event, pointer );
|
|
|
+ } else {
|
|
|
+ // pointer didn't move enough for drag to start
|
|
|
+ this._staticClick( event, pointer );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- drag -------------------------- //
|
|
|
+
|
|
|
+// dragStart
|
|
|
+proto._dragStart = function( event, pointer ) {
|
|
|
+ this.isDragging = true;
|
|
|
+ // prevent clicks
|
|
|
+ this.isPreventingClicks = true;
|
|
|
+ this.dragStart( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragStart = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'dragStart', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// dragMove
|
|
|
+proto._dragMove = function( event, pointer, moveVector ) {
|
|
|
+ // do not drag if not dragging yet
|
|
|
+ if ( !this.isDragging ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.dragMove( event, pointer, moveVector );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragMove = function( event, pointer, moveVector ) {
|
|
|
+ event.preventDefault();
|
|
|
+ this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );
|
|
|
+};
|
|
|
+
|
|
|
+// dragEnd
|
|
|
+proto._dragEnd = function( event, pointer ) {
|
|
|
+ // set flags
|
|
|
+ this.isDragging = false;
|
|
|
+ // re-enable clicking async
|
|
|
+ setTimeout( function() {
|
|
|
+ delete this.isPreventingClicks;
|
|
|
+ }.bind( this ) );
|
|
|
+
|
|
|
+ this.dragEnd( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragEnd = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'dragEnd', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- onclick ----- //
|
|
|
+
|
|
|
+// handle all clicks and prevent clicks when dragging
|
|
|
+proto.onclick = function( event ) {
|
|
|
+ if ( this.isPreventingClicks ) {
|
|
|
+ event.preventDefault();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- staticClick ----- //
|
|
|
+
|
|
|
+// triggered after pointer down & up with no/tiny movement
|
|
|
+proto._staticClick = function( event, pointer ) {
|
|
|
+ // ignore emulated mouse up clicks
|
|
|
+ if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.staticClick( event, pointer );
|
|
|
+
|
|
|
+ // set flag for emulated clicks 300ms after touchend
|
|
|
+ if ( event.type != 'mouseup' ) {
|
|
|
+ this.isIgnoringMouseUp = true;
|
|
|
+ // reset flag after 300ms
|
|
|
+ setTimeout( function() {
|
|
|
+ delete this.isIgnoringMouseUp;
|
|
|
+ }.bind( this ), 400 );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.staticClick = function( event, pointer ) {
|
|
|
+ this.emitEvent( 'staticClick', [ event, pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- utils ----- //
|
|
|
+
|
|
|
+Unidragger.getPointerPoint = Unipointer.getPointerPoint;
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return Unidragger;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// drag
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/drag',[
|
|
|
+ './flickity',
|
|
|
+ 'unidragger/unidragger',
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], function( Flickity, Unidragger, utils ) {
|
|
|
+ return factory( window, Flickity, Unidragger, utils );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('./flickity'),
|
|
|
+ require('unidragger'),
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Flickity = factory(
|
|
|
+ window,
|
|
|
+ window.Flickity,
|
|
|
+ window.Unidragger,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Flickity, Unidragger, utils ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// ----- defaults ----- //
|
|
|
+
|
|
|
+utils.extend( Flickity.defaults, {
|
|
|
+ draggable: '>1',
|
|
|
+ dragThreshold: 3,
|
|
|
+});
|
|
|
+
|
|
|
+// ----- create ----- //
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createDrag');
|
|
|
+
|
|
|
+// -------------------------- drag prototype -------------------------- //
|
|
|
+
|
|
|
+var proto = Flickity.prototype;
|
|
|
+utils.extend( proto, Unidragger.prototype );
|
|
|
+proto._touchActionValue = 'pan-y';
|
|
|
+
|
|
|
+// -------------------------- -------------------------- //
|
|
|
+
|
|
|
+var isTouch = 'createTouch' in document;
|
|
|
+var isTouchmoveScrollCanceled = false;
|
|
|
+
|
|
|
+proto._createDrag = function() {
|
|
|
+ this.on( 'activate', this.onActivateDrag );
|
|
|
+ this.on( 'uiChange', this._uiChangeDrag );
|
|
|
+ this.on( 'deactivate', this.onDeactivateDrag );
|
|
|
+ this.on( 'cellChange', this.updateDraggable );
|
|
|
+ // TODO updateDraggable on resize? if groupCells & slides change
|
|
|
+ // HACK - add seemingly innocuous handler to fix iOS 10 scroll behavior
|
|
|
+ // #457, RubaXa/Sortable#973
|
|
|
+ if ( isTouch && !isTouchmoveScrollCanceled ) {
|
|
|
+ window.addEventListener( 'touchmove', function() {});
|
|
|
+ isTouchmoveScrollCanceled = true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.onActivateDrag = function() {
|
|
|
+ this.handles = [ this.viewport ];
|
|
|
+ this.bindHandles();
|
|
|
+ this.updateDraggable();
|
|
|
+};
|
|
|
+
|
|
|
+proto.onDeactivateDrag = function() {
|
|
|
+ this.unbindHandles();
|
|
|
+ this.element.classList.remove('is-draggable');
|
|
|
+};
|
|
|
+
|
|
|
+proto.updateDraggable = function() {
|
|
|
+ // disable dragging if less than 2 slides. #278
|
|
|
+ if ( this.options.draggable == '>1' ) {
|
|
|
+ this.isDraggable = this.slides.length > 1;
|
|
|
+ } else {
|
|
|
+ this.isDraggable = this.options.draggable;
|
|
|
+ }
|
|
|
+ if ( this.isDraggable ) {
|
|
|
+ this.element.classList.add('is-draggable');
|
|
|
+ } else {
|
|
|
+ this.element.classList.remove('is-draggable');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// backwards compatibility
|
|
|
+proto.bindDrag = function() {
|
|
|
+ this.options.draggable = true;
|
|
|
+ this.updateDraggable();
|
|
|
+};
|
|
|
+
|
|
|
+proto.unbindDrag = function() {
|
|
|
+ this.options.draggable = false;
|
|
|
+ this.updateDraggable();
|
|
|
+};
|
|
|
+
|
|
|
+proto._uiChangeDrag = function() {
|
|
|
+ delete this.isFreeScrolling;
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- pointer events -------------------------- //
|
|
|
+
|
|
|
+proto.pointerDown = function( event, pointer ) {
|
|
|
+ if ( !this.isDraggable ) {
|
|
|
+ this._pointerDownDefault( event, pointer );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var isOkay = this.okayPointerDown( event );
|
|
|
+ if ( !isOkay ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._pointerDownPreventDefault( event );
|
|
|
+ this.pointerDownFocus( event );
|
|
|
+ // blur
|
|
|
+ if ( document.activeElement != this.element ) {
|
|
|
+ // do not blur if already focused
|
|
|
+ this.pointerDownBlur();
|
|
|
+ }
|
|
|
+
|
|
|
+ // stop if it was moving
|
|
|
+ this.dragX = this.x;
|
|
|
+ this.viewport.classList.add('is-pointer-down');
|
|
|
+ // track scrolling
|
|
|
+ this.pointerDownScroll = getScrollPosition();
|
|
|
+ window.addEventListener( 'scroll', this );
|
|
|
+
|
|
|
+ this._pointerDownDefault( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+// default pointerDown logic, used for staticClick
|
|
|
+proto._pointerDownDefault = function( event, pointer ) {
|
|
|
+ // track start event position
|
|
|
+ // Safari 9 overrides pageX and pageY. These values needs to be copied. #779
|
|
|
+ this.pointerDownPointer = {
|
|
|
+ pageX: pointer.pageX,
|
|
|
+ pageY: pointer.pageY,
|
|
|
+ };
|
|
|
+ // bind move and end events
|
|
|
+ this._bindPostStartEvents( event );
|
|
|
+ this.dispatchEvent( 'pointerDown', event, [ pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+var focusNodes = {
|
|
|
+ INPUT: true,
|
|
|
+ TEXTAREA: true,
|
|
|
+ SELECT: true,
|
|
|
+};
|
|
|
+
|
|
|
+proto.pointerDownFocus = function( event ) {
|
|
|
+ var isFocusNode = focusNodes[ event.target.nodeName ];
|
|
|
+ if ( !isFocusNode ) {
|
|
|
+ this.focus();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto._pointerDownPreventDefault = function( event ) {
|
|
|
+ var isTouchStart = event.type == 'touchstart';
|
|
|
+ var isTouchPointer = event.pointerType == 'touch';
|
|
|
+ var isFocusNode = focusNodes[ event.target.nodeName ];
|
|
|
+ if ( !isTouchStart && !isTouchPointer && !isFocusNode ) {
|
|
|
+ event.preventDefault();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- move ----- //
|
|
|
+
|
|
|
+proto.hasDragStarted = function( moveVector ) {
|
|
|
+ return Math.abs( moveVector.x ) > this.options.dragThreshold;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- up ----- //
|
|
|
+
|
|
|
+proto.pointerUp = function( event, pointer ) {
|
|
|
+ delete this.isTouchScrolling;
|
|
|
+ this.viewport.classList.remove('is-pointer-down');
|
|
|
+ this.dispatchEvent( 'pointerUp', event, [ pointer ] );
|
|
|
+ this._dragPointerUp( event, pointer );
|
|
|
+};
|
|
|
+
|
|
|
+proto.pointerDone = function() {
|
|
|
+ window.removeEventListener( 'scroll', this );
|
|
|
+ delete this.pointerDownScroll;
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- dragging -------------------------- //
|
|
|
+
|
|
|
+proto.dragStart = function( event, pointer ) {
|
|
|
+ if ( !this.isDraggable ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.dragStartPosition = this.x;
|
|
|
+ this.startAnimation();
|
|
|
+ window.removeEventListener( 'scroll', this );
|
|
|
+ this.dispatchEvent( 'dragStart', event, [ pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+proto.pointerMove = function( event, pointer ) {
|
|
|
+ var moveVector = this._dragPointerMove( event, pointer );
|
|
|
+ this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] );
|
|
|
+ this._dragMove( event, pointer, moveVector );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragMove = function( event, pointer, moveVector ) {
|
|
|
+ if ( !this.isDraggable ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ this.previousDragX = this.dragX;
|
|
|
+ // reverse if right-to-left
|
|
|
+ var direction = this.options.rightToLeft ? -1 : 1;
|
|
|
+ if ( this.options.wrapAround ) {
|
|
|
+ // wrap around move. #589
|
|
|
+ moveVector.x = moveVector.x % this.slideableWidth;
|
|
|
+ }
|
|
|
+ var dragX = this.dragStartPosition + moveVector.x * direction;
|
|
|
+
|
|
|
+ if ( !this.options.wrapAround && this.slides.length ) {
|
|
|
+ // slow drag
|
|
|
+ var originBound = Math.max( -this.slides[0].target, this.dragStartPosition );
|
|
|
+ dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX;
|
|
|
+ var endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition );
|
|
|
+ dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.dragX = dragX;
|
|
|
+
|
|
|
+ this.dragMoveTime = new Date();
|
|
|
+ this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragEnd = function( event, pointer ) {
|
|
|
+ if ( !this.isDraggable ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if ( this.options.freeScroll ) {
|
|
|
+ this.isFreeScrolling = true;
|
|
|
+ }
|
|
|
+ // set selectedIndex based on where flick will end up
|
|
|
+ var index = this.dragEndRestingSelect();
|
|
|
+
|
|
|
+ if ( this.options.freeScroll && !this.options.wrapAround ) {
|
|
|
+ // if free-scroll & not wrap around
|
|
|
+ // do not free-scroll if going outside of bounding slides
|
|
|
+ // so bounding slides can attract slider, and keep it in bounds
|
|
|
+ var restingX = this.getRestingPosition();
|
|
|
+ this.isFreeScrolling = -restingX > this.slides[0].target &&
|
|
|
+ -restingX < this.getLastSlide().target;
|
|
|
+ } else if ( !this.options.freeScroll && index == this.selectedIndex ) {
|
|
|
+ // boost selection if selected index has not changed
|
|
|
+ index += this.dragEndBoostSelect();
|
|
|
+ }
|
|
|
+ delete this.previousDragX;
|
|
|
+ // apply selection
|
|
|
+ // TODO refactor this, selecting here feels weird
|
|
|
+ // HACK, set flag so dragging stays in correct direction
|
|
|
+ this.isDragSelect = this.options.wrapAround;
|
|
|
+ this.select( index );
|
|
|
+ delete this.isDragSelect;
|
|
|
+ this.dispatchEvent( 'dragEnd', event, [ pointer ] );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragEndRestingSelect = function() {
|
|
|
+ var restingX = this.getRestingPosition();
|
|
|
+ // how far away from selected slide
|
|
|
+ var distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) );
|
|
|
+ // get closet resting going up and going down
|
|
|
+ var positiveResting = this._getClosestResting( restingX, distance, 1 );
|
|
|
+ var negativeResting = this._getClosestResting( restingX, distance, -1 );
|
|
|
+ // use closer resting for wrap-around
|
|
|
+ var index = positiveResting.distance < negativeResting.distance ?
|
|
|
+ positiveResting.index : negativeResting.index;
|
|
|
+ return index;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * given resting X and distance to selected cell
|
|
|
+ * get the distance and index of the closest cell
|
|
|
+ * @param {Number} restingX - estimated post-flick resting position
|
|
|
+ * @param {Number} distance - distance to selected cell
|
|
|
+ * @param {Integer} increment - +1 or -1, going up or down
|
|
|
+ * @returns {Object} - { distance: {Number}, index: {Integer} }
|
|
|
+ */
|
|
|
+proto._getClosestResting = function( restingX, distance, increment ) {
|
|
|
+ var index = this.selectedIndex;
|
|
|
+ var minDistance = Infinity;
|
|
|
+ var condition = this.options.contain && !this.options.wrapAround ?
|
|
|
+ // if contain, keep going if distance is equal to minDistance
|
|
|
+ function( d, md ) { return d <= md; } : function( d, md ) { return d < md; };
|
|
|
+ while ( condition( distance, minDistance ) ) {
|
|
|
+ // measure distance to next cell
|
|
|
+ index += increment;
|
|
|
+ minDistance = distance;
|
|
|
+ distance = this.getSlideDistance( -restingX, index );
|
|
|
+ if ( distance === null ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ distance = Math.abs( distance );
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ distance: minDistance,
|
|
|
+ // selected was previous index
|
|
|
+ index: index - increment
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * measure distance between x and a slide target
|
|
|
+ * @param {Number} x
|
|
|
+ * @param {Integer} index - slide index
|
|
|
+ */
|
|
|
+proto.getSlideDistance = function( x, index ) {
|
|
|
+ var len = this.slides.length;
|
|
|
+ // wrap around if at least 2 slides
|
|
|
+ var isWrapAround = this.options.wrapAround && len > 1;
|
|
|
+ var slideIndex = isWrapAround ? utils.modulo( index, len ) : index;
|
|
|
+ var slide = this.slides[ slideIndex ];
|
|
|
+ if ( !slide ) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // add distance for wrap-around slides
|
|
|
+ var wrap = isWrapAround ? this.slideableWidth * Math.floor( index / len ) : 0;
|
|
|
+ return x - ( slide.target + wrap );
|
|
|
+};
|
|
|
+
|
|
|
+proto.dragEndBoostSelect = function() {
|
|
|
+ // do not boost if no previousDragX or dragMoveTime
|
|
|
+ if ( this.previousDragX === undefined || !this.dragMoveTime ||
|
|
|
+ // or if drag was held for 100 ms
|
|
|
+ new Date() - this.dragMoveTime > 100 ) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ var distance = this.getSlideDistance( -this.dragX, this.selectedIndex );
|
|
|
+ var delta = this.previousDragX - this.dragX;
|
|
|
+ if ( distance > 0 && delta > 0 ) {
|
|
|
+ // boost to next if moving towards the right, and positive velocity
|
|
|
+ return 1;
|
|
|
+ } else if ( distance < 0 && delta < 0 ) {
|
|
|
+ // boost to previous if moving towards the left, and negative velocity
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- staticClick ----- //
|
|
|
+
|
|
|
+proto.staticClick = function( event, pointer ) {
|
|
|
+ // get clickedCell, if cell was clicked
|
|
|
+ var clickedCell = this.getParentCell( event.target );
|
|
|
+ var cellElem = clickedCell && clickedCell.element;
|
|
|
+ var cellIndex = clickedCell && this.cells.indexOf( clickedCell );
|
|
|
+ this.dispatchEvent( 'staticClick', event, [ pointer, cellElem, cellIndex ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- scroll ----- //
|
|
|
+
|
|
|
+proto.onscroll = function() {
|
|
|
+ var scroll = getScrollPosition();
|
|
|
+ var scrollMoveX = this.pointerDownScroll.x - scroll.x;
|
|
|
+ var scrollMoveY = this.pointerDownScroll.y - scroll.y;
|
|
|
+ // cancel click/tap if scroll is too much
|
|
|
+ if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) {
|
|
|
+ this._pointerDone();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- utils ----- //
|
|
|
+
|
|
|
+function getScrollPosition() {
|
|
|
+ return {
|
|
|
+ x: window.pageXOffset,
|
|
|
+ y: window.pageYOffset
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// prev/next buttons
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/prev-next-button',[
|
|
|
+ './flickity',
|
|
|
+ 'unipointer/unipointer',
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], function( Flickity, Unipointer, utils ) {
|
|
|
+ return factory( window, Flickity, Unipointer, utils );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('./flickity'),
|
|
|
+ require('unipointer'),
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ factory(
|
|
|
+ window,
|
|
|
+ window.Flickity,
|
|
|
+ window.Unipointer,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Flickity, Unipointer, utils ) {
|
|
|
+'use strict';
|
|
|
+
|
|
|
+var svgURI = 'http://www.w3.org/2000/svg';
|
|
|
+
|
|
|
+// -------------------------- PrevNextButton -------------------------- //
|
|
|
+
|
|
|
+function PrevNextButton( direction, parent ) {
|
|
|
+ this.direction = direction;
|
|
|
+ this.parent = parent;
|
|
|
+ this._create();
|
|
|
+}
|
|
|
+
|
|
|
+PrevNextButton.prototype = Object.create( Unipointer.prototype );
|
|
|
+
|
|
|
+PrevNextButton.prototype._create = function() {
|
|
|
+ // properties
|
|
|
+ this.isEnabled = true;
|
|
|
+ this.isPrevious = this.direction == -1;
|
|
|
+ var leftDirection = this.parent.options.rightToLeft ? 1 : -1;
|
|
|
+ this.isLeft = this.direction == leftDirection;
|
|
|
+
|
|
|
+ var element = this.element = document.createElement('button');
|
|
|
+ element.className = 'flickity-button flickity-prev-next-button';
|
|
|
+ element.className += this.isPrevious ? ' previous' : ' next';
|
|
|
+ // prevent button from submitting form http://stackoverflow.com/a/10836076/182183
|
|
|
+ element.setAttribute( 'type', 'button' );
|
|
|
+ // init as disabled
|
|
|
+ this.disable();
|
|
|
+
|
|
|
+ element.setAttribute( 'aria-label', this.isPrevious ? 'Previous' : 'Next' );
|
|
|
+
|
|
|
+ // create arrow
|
|
|
+ var svg = this.createSVG();
|
|
|
+ element.appendChild( svg );
|
|
|
+ // events
|
|
|
+ this.parent.on( 'select', this.update.bind( this ) );
|
|
|
+ this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) );
|
|
|
+};
|
|
|
+
|
|
|
+PrevNextButton.prototype.activate = function() {
|
|
|
+ this.bindStartEvent( this.element );
|
|
|
+ this.element.addEventListener( 'click', this );
|
|
|
+ // add to DOM
|
|
|
+ this.parent.element.appendChild( this.element );
|
|
|
+};
|
|
|
+
|
|
|
+PrevNextButton.prototype.deactivate = function() {
|
|
|
+ // remove from DOM
|
|
|
+ this.parent.element.removeChild( this.element );
|
|
|
+ // click events
|
|
|
+ this.unbindStartEvent( this.element );
|
|
|
+ this.element.removeEventListener( 'click', this );
|
|
|
+};
|
|
|
+
|
|
|
+PrevNextButton.prototype.createSVG = function() {
|
|
|
+ var svg = document.createElementNS( svgURI, 'svg');
|
|
|
+ svg.setAttribute( 'class', 'flickity-button-icon' );
|
|
|
+ svg.setAttribute( 'viewBox', '0 0 100 100' );
|
|
|
+ var path = document.createElementNS( svgURI, 'path');
|
|
|
+ var pathMovements = getArrowMovements( this.parent.options.arrowShape );
|
|
|
+ path.setAttribute( 'd', pathMovements );
|
|
|
+ path.setAttribute( 'class', 'arrow' );
|
|
|
+ // rotate arrow
|
|
|
+ if ( !this.isLeft ) {
|
|
|
+ path.setAttribute( 'transform', 'translate(100, 100) rotate(180) ' );
|
|
|
+ }
|
|
|
+ svg.appendChild( path );
|
|
|
+ return svg;
|
|
|
+};
|
|
|
+
|
|
|
+// get SVG path movmement
|
|
|
+function getArrowMovements( shape ) {
|
|
|
+ // use shape as movement if string
|
|
|
+ if ( typeof shape == 'string' ) {
|
|
|
+ return shape;
|
|
|
+ }
|
|
|
+ // create movement string
|
|
|
+ return 'M ' + shape.x0 + ',50' +
|
|
|
+ ' L ' + shape.x1 + ',' + ( shape.y1 + 50 ) +
|
|
|
+ ' L ' + shape.x2 + ',' + ( shape.y2 + 50 ) +
|
|
|
+ ' L ' + shape.x3 + ',50 ' +
|
|
|
+ ' L ' + shape.x2 + ',' + ( 50 - shape.y2 ) +
|
|
|
+ ' L ' + shape.x1 + ',' + ( 50 - shape.y1 ) +
|
|
|
+ ' Z';
|
|
|
+}
|
|
|
+
|
|
|
+PrevNextButton.prototype.handleEvent = utils.handleEvent;
|
|
|
+
|
|
|
+PrevNextButton.prototype.onclick = function() {
|
|
|
+ if ( !this.isEnabled ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.parent.uiChange();
|
|
|
+ var method = this.isPrevious ? 'previous' : 'next';
|
|
|
+ this.parent[ method ]();
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+PrevNextButton.prototype.enable = function() {
|
|
|
+ if ( this.isEnabled ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.element.disabled = false;
|
|
|
+ this.isEnabled = true;
|
|
|
+};
|
|
|
+
|
|
|
+PrevNextButton.prototype.disable = function() {
|
|
|
+ if ( !this.isEnabled ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.element.disabled = true;
|
|
|
+ this.isEnabled = false;
|
|
|
+};
|
|
|
+
|
|
|
+PrevNextButton.prototype.update = function() {
|
|
|
+ // index of first or last slide, if previous or next
|
|
|
+ var slides = this.parent.slides;
|
|
|
+ // enable is wrapAround and at least 2 slides
|
|
|
+ if ( this.parent.options.wrapAround && slides.length > 1 ) {
|
|
|
+ this.enable();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var lastIndex = slides.length ? slides.length - 1 : 0;
|
|
|
+ var boundIndex = this.isPrevious ? 0 : lastIndex;
|
|
|
+ var method = this.parent.selectedIndex == boundIndex ? 'disable' : 'enable';
|
|
|
+ this[ method ]();
|
|
|
+};
|
|
|
+
|
|
|
+PrevNextButton.prototype.destroy = function() {
|
|
|
+ this.deactivate();
|
|
|
+ this.allOff();
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- Flickity prototype -------------------------- //
|
|
|
+
|
|
|
+utils.extend( Flickity.defaults, {
|
|
|
+ prevNextButtons: true,
|
|
|
+ arrowShape: {
|
|
|
+ x0: 10,
|
|
|
+ x1: 60, y1: 50,
|
|
|
+ x2: 70, y2: 40,
|
|
|
+ x3: 30
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createPrevNextButtons');
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+proto._createPrevNextButtons = function() {
|
|
|
+ if ( !this.options.prevNextButtons ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.prevButton = new PrevNextButton( -1, this );
|
|
|
+ this.nextButton = new PrevNextButton( 1, this );
|
|
|
+
|
|
|
+ this.on( 'activate', this.activatePrevNextButtons );
|
|
|
+};
|
|
|
+
|
|
|
+proto.activatePrevNextButtons = function() {
|
|
|
+ this.prevButton.activate();
|
|
|
+ this.nextButton.activate();
|
|
|
+ this.on( 'deactivate', this.deactivatePrevNextButtons );
|
|
|
+};
|
|
|
+
|
|
|
+proto.deactivatePrevNextButtons = function() {
|
|
|
+ this.prevButton.deactivate();
|
|
|
+ this.nextButton.deactivate();
|
|
|
+ this.off( 'deactivate', this.deactivatePrevNextButtons );
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- -------------------------- //
|
|
|
+
|
|
|
+Flickity.PrevNextButton = PrevNextButton;
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// page dots
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/page-dots',[
|
|
|
+ './flickity',
|
|
|
+ 'unipointer/unipointer',
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], function( Flickity, Unipointer, utils ) {
|
|
|
+ return factory( window, Flickity, Unipointer, utils );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('./flickity'),
|
|
|
+ require('unipointer'),
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ factory(
|
|
|
+ window,
|
|
|
+ window.Flickity,
|
|
|
+ window.Unipointer,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Flickity, Unipointer, utils ) {
|
|
|
+
|
|
|
+// -------------------------- PageDots -------------------------- //
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+function PageDots( parent ) {
|
|
|
+ this.parent = parent;
|
|
|
+ this._create();
|
|
|
+}
|
|
|
+
|
|
|
+PageDots.prototype = Object.create( Unipointer.prototype );
|
|
|
+
|
|
|
+PageDots.prototype._create = function() {
|
|
|
+ // create holder element
|
|
|
+ this.holder = document.createElement('ol');
|
|
|
+ this.holder.className = 'flickity-page-dots';
|
|
|
+ // create dots, array of elements
|
|
|
+ this.dots = [];
|
|
|
+ // events
|
|
|
+ this.handleClick = this.onClick.bind( this );
|
|
|
+ this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.activate = function() {
|
|
|
+ this.setDots();
|
|
|
+ this.holder.addEventListener( 'click', this.handleClick );
|
|
|
+ this.bindStartEvent( this.holder );
|
|
|
+ // add to DOM
|
|
|
+ this.parent.element.appendChild( this.holder );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.deactivate = function() {
|
|
|
+ this.holder.removeEventListener( 'click', this.handleClick );
|
|
|
+ this.unbindStartEvent( this.holder );
|
|
|
+ // remove from DOM
|
|
|
+ this.parent.element.removeChild( this.holder );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.setDots = function() {
|
|
|
+ // get difference between number of slides and number of dots
|
|
|
+ var delta = this.parent.slides.length - this.dots.length;
|
|
|
+ if ( delta > 0 ) {
|
|
|
+ this.addDots( delta );
|
|
|
+ } else if ( delta < 0 ) {
|
|
|
+ this.removeDots( -delta );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.addDots = function( count ) {
|
|
|
+ var fragment = document.createDocumentFragment();
|
|
|
+ var newDots = [];
|
|
|
+ var length = this.dots.length;
|
|
|
+ var max = length + count;
|
|
|
+
|
|
|
+ for ( var i = length; i < max; i++ ) {
|
|
|
+ var dot = document.createElement('li');
|
|
|
+ dot.className = 'dot';
|
|
|
+ dot.setAttribute( 'aria-label', 'Page dot ' + ( i + 1 ) );
|
|
|
+ fragment.appendChild( dot );
|
|
|
+ newDots.push( dot );
|
|
|
+ }
|
|
|
+
|
|
|
+ this.holder.appendChild( fragment );
|
|
|
+ this.dots = this.dots.concat( newDots );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.removeDots = function( count ) {
|
|
|
+ // remove from this.dots collection
|
|
|
+ var removeDots = this.dots.splice( this.dots.length - count, count );
|
|
|
+ // remove from DOM
|
|
|
+ removeDots.forEach( function( dot ) {
|
|
|
+ this.holder.removeChild( dot );
|
|
|
+ }, this );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.updateSelected = function() {
|
|
|
+ // remove selected class on previous
|
|
|
+ if ( this.selectedDot ) {
|
|
|
+ this.selectedDot.className = 'dot';
|
|
|
+ this.selectedDot.removeAttribute('aria-current');
|
|
|
+ }
|
|
|
+ // don't proceed if no dots
|
|
|
+ if ( !this.dots.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.selectedDot = this.dots[ this.parent.selectedIndex ];
|
|
|
+ this.selectedDot.className = 'dot is-selected';
|
|
|
+ this.selectedDot.setAttribute( 'aria-current', 'step' );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.onTap = // old method name, backwards-compatible
|
|
|
+PageDots.prototype.onClick = function( event ) {
|
|
|
+ var target = event.target;
|
|
|
+ // only care about dot clicks
|
|
|
+ if ( target.nodeName != 'LI' ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.parent.uiChange();
|
|
|
+ var index = this.dots.indexOf( target );
|
|
|
+ this.parent.select( index );
|
|
|
+};
|
|
|
+
|
|
|
+PageDots.prototype.destroy = function() {
|
|
|
+ this.deactivate();
|
|
|
+ this.allOff();
|
|
|
+};
|
|
|
+
|
|
|
+Flickity.PageDots = PageDots;
|
|
|
+
|
|
|
+// -------------------------- Flickity -------------------------- //
|
|
|
+
|
|
|
+utils.extend( Flickity.defaults, {
|
|
|
+ pageDots: true
|
|
|
+});
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createPageDots');
|
|
|
+
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+proto._createPageDots = function() {
|
|
|
+ if ( !this.options.pageDots ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.pageDots = new PageDots( this );
|
|
|
+ // events
|
|
|
+ this.on( 'activate', this.activatePageDots );
|
|
|
+ this.on( 'select', this.updateSelectedPageDots );
|
|
|
+ this.on( 'cellChange', this.updatePageDots );
|
|
|
+ this.on( 'resize', this.updatePageDots );
|
|
|
+ this.on( 'deactivate', this.deactivatePageDots );
|
|
|
+};
|
|
|
+
|
|
|
+proto.activatePageDots = function() {
|
|
|
+ this.pageDots.activate();
|
|
|
+};
|
|
|
+
|
|
|
+proto.updateSelectedPageDots = function() {
|
|
|
+ this.pageDots.updateSelected();
|
|
|
+};
|
|
|
+
|
|
|
+proto.updatePageDots = function() {
|
|
|
+ this.pageDots.setDots();
|
|
|
+};
|
|
|
+
|
|
|
+proto.deactivatePageDots = function() {
|
|
|
+ this.pageDots.deactivate();
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+Flickity.PageDots = PageDots;
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// player & autoPlay
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/player',[
|
|
|
+ 'ev-emitter/ev-emitter',
|
|
|
+ 'fizzy-ui-utils/utils',
|
|
|
+ './flickity'
|
|
|
+ ], function( EvEmitter, utils, Flickity ) {
|
|
|
+ return factory( EvEmitter, utils, Flickity );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ require('ev-emitter'),
|
|
|
+ require('fizzy-ui-utils'),
|
|
|
+ require('./flickity')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ factory(
|
|
|
+ window.EvEmitter,
|
|
|
+ window.fizzyUIUtils,
|
|
|
+ window.Flickity
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( EvEmitter, utils, Flickity ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// -------------------------- Player -------------------------- //
|
|
|
+
|
|
|
+function Player( parent ) {
|
|
|
+ this.parent = parent;
|
|
|
+ this.state = 'stopped';
|
|
|
+ // visibility change event handler
|
|
|
+ this.onVisibilityChange = this.visibilityChange.bind( this );
|
|
|
+ this.onVisibilityPlay = this.visibilityPlay.bind( this );
|
|
|
+}
|
|
|
+
|
|
|
+Player.prototype = Object.create( EvEmitter.prototype );
|
|
|
+
|
|
|
+// start play
|
|
|
+Player.prototype.play = function() {
|
|
|
+ if ( this.state == 'playing' ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // do not play if page is hidden, start playing when page is visible
|
|
|
+ var isPageHidden = document.hidden;
|
|
|
+ if ( isPageHidden ) {
|
|
|
+ document.addEventListener( 'visibilitychange', this.onVisibilityPlay );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.state = 'playing';
|
|
|
+ // listen to visibility change
|
|
|
+ document.addEventListener( 'visibilitychange', this.onVisibilityChange );
|
|
|
+ // start ticking
|
|
|
+ this.tick();
|
|
|
+};
|
|
|
+
|
|
|
+Player.prototype.tick = function() {
|
|
|
+ // do not tick if not playing
|
|
|
+ if ( this.state != 'playing' ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var time = this.parent.options.autoPlay;
|
|
|
+ // default to 3 seconds
|
|
|
+ time = typeof time == 'number' ? time : 3000;
|
|
|
+ var _this = this;
|
|
|
+ // HACK: reset ticks if stopped and started within interval
|
|
|
+ this.clear();
|
|
|
+ this.timeout = setTimeout( function() {
|
|
|
+ _this.parent.next( true );
|
|
|
+ _this.tick();
|
|
|
+ }, time );
|
|
|
+};
|
|
|
+
|
|
|
+Player.prototype.stop = function() {
|
|
|
+ this.state = 'stopped';
|
|
|
+ this.clear();
|
|
|
+ // remove visibility change event
|
|
|
+ document.removeEventListener( 'visibilitychange', this.onVisibilityChange );
|
|
|
+};
|
|
|
+
|
|
|
+Player.prototype.clear = function() {
|
|
|
+ clearTimeout( this.timeout );
|
|
|
+};
|
|
|
+
|
|
|
+Player.prototype.pause = function() {
|
|
|
+ if ( this.state == 'playing' ) {
|
|
|
+ this.state = 'paused';
|
|
|
+ this.clear();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Player.prototype.unpause = function() {
|
|
|
+ // re-start play if paused
|
|
|
+ if ( this.state == 'paused' ) {
|
|
|
+ this.play();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// pause if page visibility is hidden, unpause if visible
|
|
|
+Player.prototype.visibilityChange = function() {
|
|
|
+ var isPageHidden = document.hidden;
|
|
|
+ this[ isPageHidden ? 'pause' : 'unpause' ]();
|
|
|
+};
|
|
|
+
|
|
|
+Player.prototype.visibilityPlay = function() {
|
|
|
+ this.play();
|
|
|
+ document.removeEventListener( 'visibilitychange', this.onVisibilityPlay );
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- Flickity -------------------------- //
|
|
|
+
|
|
|
+utils.extend( Flickity.defaults, {
|
|
|
+ pauseAutoPlayOnHover: true
|
|
|
+});
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createPlayer');
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+proto._createPlayer = function() {
|
|
|
+ this.player = new Player( this );
|
|
|
+
|
|
|
+ this.on( 'activate', this.activatePlayer );
|
|
|
+ this.on( 'uiChange', this.stopPlayer );
|
|
|
+ this.on( 'pointerDown', this.stopPlayer );
|
|
|
+ this.on( 'deactivate', this.deactivatePlayer );
|
|
|
+};
|
|
|
+
|
|
|
+proto.activatePlayer = function() {
|
|
|
+ if ( !this.options.autoPlay ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.player.play();
|
|
|
+ this.element.addEventListener( 'mouseenter', this );
|
|
|
+};
|
|
|
+
|
|
|
+// Player API, don't hate the ... thanks I know where the door is
|
|
|
+
|
|
|
+proto.playPlayer = function() {
|
|
|
+ this.player.play();
|
|
|
+};
|
|
|
+
|
|
|
+proto.stopPlayer = function() {
|
|
|
+ this.player.stop();
|
|
|
+};
|
|
|
+
|
|
|
+proto.pausePlayer = function() {
|
|
|
+ this.player.pause();
|
|
|
+};
|
|
|
+
|
|
|
+proto.unpausePlayer = function() {
|
|
|
+ this.player.unpause();
|
|
|
+};
|
|
|
+
|
|
|
+proto.deactivatePlayer = function() {
|
|
|
+ this.player.stop();
|
|
|
+ this.element.removeEventListener( 'mouseenter', this );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- mouseenter/leave ----- //
|
|
|
+
|
|
|
+// pause auto-play on hover
|
|
|
+proto.onmouseenter = function() {
|
|
|
+ if ( !this.options.pauseAutoPlayOnHover ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.player.pause();
|
|
|
+ this.element.addEventListener( 'mouseleave', this );
|
|
|
+};
|
|
|
+
|
|
|
+// resume auto-play on hover off
|
|
|
+proto.onmouseleave = function() {
|
|
|
+ this.player.unpause();
|
|
|
+ this.element.removeEventListener( 'mouseleave', this );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+Flickity.Player = Player;
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// add, remove cell
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/add-remove-cell',[
|
|
|
+ './flickity',
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], function( Flickity, utils ) {
|
|
|
+ return factory( window, Flickity, utils );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('./flickity'),
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ factory(
|
|
|
+ window,
|
|
|
+ window.Flickity,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Flickity, utils ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// append cells to a document fragment
|
|
|
+function getCellsFragment( cells ) {
|
|
|
+ var fragment = document.createDocumentFragment();
|
|
|
+ cells.forEach( function( cell ) {
|
|
|
+ fragment.appendChild( cell.element );
|
|
|
+ });
|
|
|
+ return fragment;
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- add/remove cell prototype -------------------------- //
|
|
|
+
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Insert, prepend, or append cells
|
|
|
+ * @param {Element, Array, NodeList} elems
|
|
|
+ * @param {Integer} index
|
|
|
+ */
|
|
|
+proto.insert = function( elems, index ) {
|
|
|
+ var cells = this._makeCells( elems );
|
|
|
+ if ( !cells || !cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var len = this.cells.length;
|
|
|
+ // default to append
|
|
|
+ index = index === undefined ? len : index;
|
|
|
+ // add cells with document fragment
|
|
|
+ var fragment = getCellsFragment( cells );
|
|
|
+ // append to slider
|
|
|
+ var isAppend = index == len;
|
|
|
+ if ( isAppend ) {
|
|
|
+ this.slider.appendChild( fragment );
|
|
|
+ } else {
|
|
|
+ var insertCellElement = this.cells[ index ].element;
|
|
|
+ this.slider.insertBefore( fragment, insertCellElement );
|
|
|
+ }
|
|
|
+ // add to this.cells
|
|
|
+ if ( index === 0 ) {
|
|
|
+ // prepend, add to start
|
|
|
+ this.cells = cells.concat( this.cells );
|
|
|
+ } else if ( isAppend ) {
|
|
|
+ // append, add to end
|
|
|
+ this.cells = this.cells.concat( cells );
|
|
|
+ } else {
|
|
|
+ // insert in this.cells
|
|
|
+ var endCells = this.cells.splice( index, len - index );
|
|
|
+ this.cells = this.cells.concat( cells ).concat( endCells );
|
|
|
+ }
|
|
|
+
|
|
|
+ this._sizeCells( cells );
|
|
|
+ this.cellChange( index, true );
|
|
|
+};
|
|
|
+
|
|
|
+proto.append = function( elems ) {
|
|
|
+ this.insert( elems, this.cells.length );
|
|
|
+};
|
|
|
+
|
|
|
+proto.prepend = function( elems ) {
|
|
|
+ this.insert( elems, 0 );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Remove cells
|
|
|
+ * @param {Element, Array, NodeList} elems
|
|
|
+ */
|
|
|
+proto.remove = function( elems ) {
|
|
|
+ var cells = this.getCells( elems );
|
|
|
+ if ( !cells || !cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var minCellIndex = this.cells.length - 1;
|
|
|
+ // remove cells from collection & DOM
|
|
|
+ cells.forEach( function( cell ) {
|
|
|
+ cell.remove();
|
|
|
+ var index = this.cells.indexOf( cell );
|
|
|
+ minCellIndex = Math.min( index, minCellIndex );
|
|
|
+ utils.removeFrom( this.cells, cell );
|
|
|
+ }, this );
|
|
|
+
|
|
|
+ this.cellChange( minCellIndex, true );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * logic to be run after a cell's size changes
|
|
|
+ * @param {Element} elem - cell's element
|
|
|
+ */
|
|
|
+proto.cellSizeChange = function( elem ) {
|
|
|
+ var cell = this.getCell( elem );
|
|
|
+ if ( !cell ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ cell.getSize();
|
|
|
+
|
|
|
+ var index = this.cells.indexOf( cell );
|
|
|
+ this.cellChange( index );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * logic any time a cell is changed: added, removed, or size changed
|
|
|
+ * @param {Integer} changedCellIndex - index of the changed cell, optional
|
|
|
+ */
|
|
|
+proto.cellChange = function( changedCellIndex, isPositioningSlider ) {
|
|
|
+ var prevSelectedElem = this.selectedElement;
|
|
|
+ this._positionCells( changedCellIndex );
|
|
|
+ this._getWrapShiftCells();
|
|
|
+ this.setGallerySize();
|
|
|
+ // update selectedIndex
|
|
|
+ // try to maintain position & select previous selected element
|
|
|
+ var cell = this.getCell( prevSelectedElem );
|
|
|
+ if ( cell ) {
|
|
|
+ this.selectedIndex = this.getCellSlideIndex( cell );
|
|
|
+ }
|
|
|
+ this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex );
|
|
|
+
|
|
|
+ this.emitEvent( 'cellChange', [ changedCellIndex ] );
|
|
|
+ // position slider
|
|
|
+ this.select( this.selectedIndex );
|
|
|
+ // do not position slider after lazy load
|
|
|
+ if ( isPositioningSlider ) {
|
|
|
+ this.positionSliderAtSelected();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+// lazyload
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/lazyload',[
|
|
|
+ './flickity',
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], function( Flickity, utils ) {
|
|
|
+ return factory( window, Flickity, utils );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('./flickity'),
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ factory(
|
|
|
+ window,
|
|
|
+ window.Flickity,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Flickity, utils ) {
|
|
|
+'use strict';
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createLazyload');
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+proto._createLazyload = function() {
|
|
|
+ this.on( 'select', this.lazyLoad );
|
|
|
+};
|
|
|
+
|
|
|
+proto.lazyLoad = function() {
|
|
|
+ var lazyLoad = this.options.lazyLoad;
|
|
|
+ if ( !lazyLoad ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // get adjacent cells, use lazyLoad option for adjacent count
|
|
|
+ var adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0;
|
|
|
+ var cellElems = this.getAdjacentCellElements( adjCount );
|
|
|
+ // get lazy images in those cells
|
|
|
+ var lazyImages = [];
|
|
|
+ cellElems.forEach( function( cellElem ) {
|
|
|
+ var lazyCellImages = getCellLazyImages( cellElem );
|
|
|
+ lazyImages = lazyImages.concat( lazyCellImages );
|
|
|
+ });
|
|
|
+ // load lazy images
|
|
|
+ lazyImages.forEach( function( img ) {
|
|
|
+ new LazyLoader( img, this );
|
|
|
+ }, this );
|
|
|
+};
|
|
|
+
|
|
|
+function getCellLazyImages( cellElem ) {
|
|
|
+ // check if cell element is lazy image
|
|
|
+ if ( cellElem.nodeName == 'IMG' ) {
|
|
|
+ var lazyloadAttr = cellElem.getAttribute('data-flickity-lazyload');
|
|
|
+ var srcAttr = cellElem.getAttribute('data-flickity-lazyload-src');
|
|
|
+ var srcsetAttr = cellElem.getAttribute('data-flickity-lazyload-srcset');
|
|
|
+ if ( lazyloadAttr || srcAttr || srcsetAttr ) {
|
|
|
+ return [ cellElem ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // select lazy images in cell
|
|
|
+ var lazySelector = 'img[data-flickity-lazyload], ' +
|
|
|
+ 'img[data-flickity-lazyload-src], img[data-flickity-lazyload-srcset]';
|
|
|
+ var imgs = cellElem.querySelectorAll( lazySelector );
|
|
|
+ return utils.makeArray( imgs );
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- LazyLoader -------------------------- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * class to handle loading images
|
|
|
+ */
|
|
|
+function LazyLoader( img, flickity ) {
|
|
|
+ this.img = img;
|
|
|
+ this.flickity = flickity;
|
|
|
+ this.load();
|
|
|
+}
|
|
|
+
|
|
|
+LazyLoader.prototype.handleEvent = utils.handleEvent;
|
|
|
+
|
|
|
+LazyLoader.prototype.load = function() {
|
|
|
+ this.img.addEventListener( 'load', this );
|
|
|
+ this.img.addEventListener( 'error', this );
|
|
|
+ // get src & srcset
|
|
|
+ var src = this.img.getAttribute('data-flickity-lazyload') ||
|
|
|
+ this.img.getAttribute('data-flickity-lazyload-src');
|
|
|
+ var srcset = this.img.getAttribute('data-flickity-lazyload-srcset');
|
|
|
+ // set src & serset
|
|
|
+ this.img.src = src;
|
|
|
+ if ( srcset ) {
|
|
|
+ this.img.setAttribute( 'srcset', srcset );
|
|
|
+ }
|
|
|
+ // remove attr
|
|
|
+ this.img.removeAttribute('data-flickity-lazyload');
|
|
|
+ this.img.removeAttribute('data-flickity-lazyload-src');
|
|
|
+ this.img.removeAttribute('data-flickity-lazyload-srcset');
|
|
|
+};
|
|
|
+
|
|
|
+LazyLoader.prototype.onload = function( event ) {
|
|
|
+ this.complete( event, 'flickity-lazyloaded' );
|
|
|
+};
|
|
|
+
|
|
|
+LazyLoader.prototype.onerror = function( event ) {
|
|
|
+ this.complete( event, 'flickity-lazyerror' );
|
|
|
+};
|
|
|
+
|
|
|
+LazyLoader.prototype.complete = function( event, className ) {
|
|
|
+ // unbind events
|
|
|
+ this.img.removeEventListener( 'load', this );
|
|
|
+ this.img.removeEventListener( 'error', this );
|
|
|
+
|
|
|
+ var cell = this.flickity.getParentCell( this.img );
|
|
|
+ var cellElem = cell && cell.element;
|
|
|
+ this.flickity.cellSizeChange( cellElem );
|
|
|
+
|
|
|
+ this.img.classList.add( className );
|
|
|
+ this.flickity.dispatchEvent( 'lazyLoad', event, cellElem );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+Flickity.LazyLoader = LazyLoader;
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/*!
|
|
|
+ * Flickity v2.2.1
|
|
|
+ * Touch, responsive, flickable carousels
|
|
|
+ *
|
|
|
+ * Licensed GPLv3 for open source use
|
|
|
+ * or Flickity Commercial License for commercial use
|
|
|
+ *
|
|
|
+ * https://flickity.metafizzy.co
|
|
|
+ * Copyright 2015-2019 Metafizzy
|
|
|
+ */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity/js/index',[
|
|
|
+ './flickity',
|
|
|
+ './drag',
|
|
|
+ './prev-next-button',
|
|
|
+ './page-dots',
|
|
|
+ './player',
|
|
|
+ './add-remove-cell',
|
|
|
+ './lazyload'
|
|
|
+ ], factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ require('./flickity'),
|
|
|
+ require('./drag'),
|
|
|
+ require('./prev-next-button'),
|
|
|
+ require('./page-dots'),
|
|
|
+ require('./player'),
|
|
|
+ require('./add-remove-cell'),
|
|
|
+ require('./lazyload')
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+})( window, function factory( Flickity ) {
|
|
|
+ /*jshint strict: false*/
|
|
|
+ return Flickity;
|
|
|
+});
|
|
|
+
|
|
|
+/*!
|
|
|
+ * Flickity asNavFor v2.0.2
|
|
|
+ * enable asNavFor for Flickity
|
|
|
+ */
|
|
|
+
|
|
|
+/*jshint browser: true, undef: true, unused: true, strict: true*/
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /*jshint strict: false */ /*globals define, module, require */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'flickity-as-nav-for/as-nav-for',[
|
|
|
+ 'flickity/js/index',
|
|
|
+ 'fizzy-ui-utils/utils'
|
|
|
+ ], factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ require('flickity'),
|
|
|
+ require('fizzy-ui-utils')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Flickity = factory(
|
|
|
+ window.Flickity,
|
|
|
+ window.fizzyUIUtils
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( Flickity, utils ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// -------------------------- asNavFor prototype -------------------------- //
|
|
|
+
|
|
|
+// Flickity.defaults.asNavFor = null;
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createAsNavFor');
|
|
|
+
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+proto._createAsNavFor = function() {
|
|
|
+ this.on( 'activate', this.activateAsNavFor );
|
|
|
+ this.on( 'deactivate', this.deactivateAsNavFor );
|
|
|
+ this.on( 'destroy', this.destroyAsNavFor );
|
|
|
+
|
|
|
+ var asNavForOption = this.options.asNavFor;
|
|
|
+ if ( !asNavForOption ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // HACK do async, give time for other flickity to be initalized
|
|
|
+ var _this = this;
|
|
|
+ setTimeout( function initNavCompanion() {
|
|
|
+ _this.setNavCompanion( asNavForOption );
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+proto.setNavCompanion = function( elem ) {
|
|
|
+ elem = utils.getQueryElement( elem );
|
|
|
+ var companion = Flickity.data( elem );
|
|
|
+ // stop if no companion or companion is self
|
|
|
+ if ( !companion || companion == this ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.navCompanion = companion;
|
|
|
+ // companion select
|
|
|
+ var _this = this;
|
|
|
+ this.onNavCompanionSelect = function() {
|
|
|
+ _this.navCompanionSelect();
|
|
|
+ };
|
|
|
+ companion.on( 'select', this.onNavCompanionSelect );
|
|
|
+ // click
|
|
|
+ this.on( 'staticClick', this.onNavStaticClick );
|
|
|
+
|
|
|
+ this.navCompanionSelect( true );
|
|
|
+};
|
|
|
+
|
|
|
+proto.navCompanionSelect = function( isInstant ) {
|
|
|
+ // wait for companion & selectedCells first. #8
|
|
|
+ var companionCells = this.navCompanion && this.navCompanion.selectedCells;
|
|
|
+ if ( !companionCells ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // select slide that matches first cell of slide
|
|
|
+ var selectedCell = companionCells[0];
|
|
|
+ var firstIndex = this.navCompanion.cells.indexOf( selectedCell );
|
|
|
+ var lastIndex = firstIndex + companionCells.length - 1;
|
|
|
+ var selectIndex = Math.floor( lerp( firstIndex, lastIndex,
|
|
|
+ this.navCompanion.cellAlign ) );
|
|
|
+ this.selectCell( selectIndex, false, isInstant );
|
|
|
+ // set nav selected class
|
|
|
+ this.removeNavSelectedElements();
|
|
|
+ // stop if companion has more cells than this one
|
|
|
+ if ( selectIndex >= this.cells.length ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var selectedCells = this.cells.slice( firstIndex, lastIndex + 1 );
|
|
|
+ this.navSelectedElements = selectedCells.map( function( cell ) {
|
|
|
+ return cell.element;
|
|
|
+ });
|
|
|
+ this.changeNavSelectedClass('add');
|
|
|
+};
|
|
|
+
|
|
|
+function lerp( a, b, t ) {
|
|
|
+ return ( b - a ) * t + a;
|
|
|
+}
|
|
|
+
|
|
|
+proto.changeNavSelectedClass = function( method ) {
|
|
|
+ this.navSelectedElements.forEach( function( navElem ) {
|
|
|
+ navElem.classList[ method ]('is-nav-selected');
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+proto.activateAsNavFor = function() {
|
|
|
+ this.navCompanionSelect( true );
|
|
|
+};
|
|
|
+
|
|
|
+proto.removeNavSelectedElements = function() {
|
|
|
+ if ( !this.navSelectedElements ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.changeNavSelectedClass('remove');
|
|
|
+ delete this.navSelectedElements;
|
|
|
+};
|
|
|
+
|
|
|
+proto.onNavStaticClick = function( event, pointer, cellElement, cellIndex ) {
|
|
|
+ if ( typeof cellIndex == 'number' ) {
|
|
|
+ this.navCompanion.selectCell( cellIndex );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+proto.deactivateAsNavFor = function() {
|
|
|
+ this.removeNavSelectedElements();
|
|
|
+};
|
|
|
+
|
|
|
+proto.destroyAsNavFor = function() {
|
|
|
+ if ( !this.navCompanion ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.navCompanion.off( 'select', this.onNavCompanionSelect );
|
|
|
+ this.off( 'staticClick', this.onNavStaticClick );
|
|
|
+ delete this.navCompanion;
|
|
|
+};
|
|
|
+
|
|
|
+// ----- ----- //
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|
|
|
+/*!
|
|
|
+ * imagesLoaded v4.1.4
|
|
|
+ * JavaScript is all like "You images are done yet or what?"
|
|
|
+ * MIT License
|
|
|
+ */
|
|
|
+
|
|
|
+( function( window, factory ) { 'use strict';
|
|
|
+ // universal module definition
|
|
|
+
|
|
|
+ /*global define: false, module: false, require: false */
|
|
|
+
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( 'imagesloaded/imagesloaded',[
|
|
|
+ 'ev-emitter/ev-emitter'
|
|
|
+ ], function( EvEmitter ) {
|
|
|
+ return factory( window, EvEmitter );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('ev-emitter')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.imagesLoaded = factory(
|
|
|
+ window,
|
|
|
+ window.EvEmitter
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+})( typeof window !== 'undefined' ? window : this,
|
|
|
+
|
|
|
+// -------------------------- factory -------------------------- //
|
|
|
+
|
|
|
+function factory( window, EvEmitter ) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+var $ = window.jQuery;
|
|
|
+var console = window.console;
|
|
|
+
|
|
|
+// -------------------------- helpers -------------------------- //
|
|
|
+
|
|
|
+// extend objects
|
|
|
+function extend( a, b ) {
|
|
|
+ for ( var prop in b ) {
|
|
|
+ a[ prop ] = b[ prop ];
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+}
|
|
|
+
|
|
|
+var arraySlice = Array.prototype.slice;
|
|
|
+
|
|
|
+// turn element or nodeList into an array
|
|
|
+function makeArray( obj ) {
|
|
|
+ if ( Array.isArray( obj ) ) {
|
|
|
+ // use object if already an array
|
|
|
+ return obj;
|
|
|
+ }
|
|
|
+
|
|
|
+ var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
|
|
|
+ if ( isArrayLike ) {
|
|
|
+ // convert nodeList to array
|
|
|
+ return arraySlice.call( obj );
|
|
|
+ }
|
|
|
+
|
|
|
+ // array of single index
|
|
|
+ return [ obj ];
|
|
|
+}
|
|
|
+
|
|
|
+// -------------------------- imagesLoaded -------------------------- //
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {Array, Element, NodeList, String} elem
|
|
|
+ * @param {Object or Function} options - if function, use as callback
|
|
|
+ * @param {Function} onAlways - callback function
|
|
|
+ */
|
|
|
+function ImagesLoaded( elem, options, onAlways ) {
|
|
|
+ // coerce ImagesLoaded() without new, to be new ImagesLoaded()
|
|
|
+ if ( !( this instanceof ImagesLoaded ) ) {
|
|
|
+ return new ImagesLoaded( elem, options, onAlways );
|
|
|
+ }
|
|
|
+ // use elem as selector string
|
|
|
+ var queryElem = elem;
|
|
|
+ if ( typeof elem == 'string' ) {
|
|
|
+ queryElem = document.querySelectorAll( elem );
|
|
|
+ }
|
|
|
+ // bail if bad element
|
|
|
+ if ( !queryElem ) {
|
|
|
+ console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.elements = makeArray( queryElem );
|
|
|
+ this.options = extend( {}, this.options );
|
|
|
+ // shift arguments if no options set
|
|
|
+ if ( typeof options == 'function' ) {
|
|
|
+ onAlways = options;
|
|
|
+ } else {
|
|
|
+ extend( this.options, options );
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( onAlways ) {
|
|
|
+ this.on( 'always', onAlways );
|
|
|
+ }
|
|
|
+
|
|
|
+ this.getImages();
|
|
|
+
|
|
|
+ if ( $ ) {
|
|
|
+ // add jQuery Deferred object
|
|
|
+ this.jqDeferred = new $.Deferred();
|
|
|
+ }
|
|
|
+
|
|
|
+ // HACK check async to allow time to bind listeners
|
|
|
+ setTimeout( this.check.bind( this ) );
|
|
|
+}
|
|
|
+
|
|
|
+ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
|
|
|
+
|
|
|
+ImagesLoaded.prototype.options = {};
|
|
|
+
|
|
|
+ImagesLoaded.prototype.getImages = function() {
|
|
|
+ this.images = [];
|
|
|
+
|
|
|
+ // filter & find items if we have an item selector
|
|
|
+ this.elements.forEach( this.addElementImages, this );
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {Node} element
|
|
|
+ */
|
|
|
+ImagesLoaded.prototype.addElementImages = function( elem ) {
|
|
|
+ // filter siblings
|
|
|
+ if ( elem.nodeName == 'IMG' ) {
|
|
|
+ this.addImage( elem );
|
|
|
+ }
|
|
|
+ // get background image on element
|
|
|
+ if ( this.options.background === true ) {
|
|
|
+ this.addElementBackgroundImages( elem );
|
|
|
+ }
|
|
|
+
|
|
|
+ // find children
|
|
|
+ // no non-element nodes, #143
|
|
|
+ var nodeType = elem.nodeType;
|
|
|
+ if ( !nodeType || !elementNodeTypes[ nodeType ] ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var childImgs = elem.querySelectorAll('img');
|
|
|
+ // concat childElems to filterFound array
|
|
|
+ for ( var i=0; i < childImgs.length; i++ ) {
|
|
|
+ var img = childImgs[i];
|
|
|
+ this.addImage( img );
|
|
|
+ }
|
|
|
+
|
|
|
+ // get child background images
|
|
|
+ if ( typeof this.options.background == 'string' ) {
|
|
|
+ var children = elem.querySelectorAll( this.options.background );
|
|
|
+ for ( i=0; i < children.length; i++ ) {
|
|
|
+ var child = children[i];
|
|
|
+ this.addElementBackgroundImages( child );
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+var elementNodeTypes = {
|
|
|
+ 1: true,
|
|
|
+ 9: true,
|
|
|
+ 11: true
|
|
|
+};
|
|
|
+
|
|
|
+ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
|
|
|
+ var style = getComputedStyle( elem );
|
|
|
+ if ( !style ) {
|
|
|
+ // Firefox returns null if in a hidden iframe https://bugzil.la/548397
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // get url inside url("...")
|
|
|
+ var reURL = /url\((['"])?(.*?)\1\)/gi;
|
|
|
+ var matches = reURL.exec( style.backgroundImage );
|
|
|
+ while ( matches !== null ) {
|
|
|
+ var url = matches && matches[2];
|
|
|
+ if ( url ) {
|
|
|
+ this.addBackground( url, elem );
|
|
|
+ }
|
|
|
+ matches = reURL.exec( style.backgroundImage );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {Image} img
|
|
|
+ */
|
|
|
+ImagesLoaded.prototype.addImage = function( img ) {
|
|
|
+ var loadingImage = new LoadingImage( img );
|
|
|
+ this.images.push( loadingImage );
|
|
|
+};
|
|
|
+
|
|
|
+ImagesLoaded.prototype.addBackground = function( url, elem ) {
|
|
|
+ var background = new Background( url, elem );
|
|
|
+ this.images.push( background );
|
|
|
+};
|
|
|
+
|
|
|
+ImagesLoaded.prototype.check = function() {
|
|
|
+ var _this = this;
|
|
|
+ this.progressedCount = 0;
|
|
|
+ this.hasAnyBroken = false;
|
|
|
+ // complete if no images
|
|
|
+ if ( !this.images.length ) {
|
|
|
+ this.complete();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ function onProgress( image, elem, message ) {
|
|
|
+ // HACK - Chrome triggers event before object properties have changed. #83
|
|
|
+ setTimeout( function() {
|
|
|
+ _this.progress( image, elem, message );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ this.images.forEach( function( loadingImage ) {
|
|
|
+ loadingImage.once( 'progress', onProgress );
|
|
|
+ loadingImage.check();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+ImagesLoaded.prototype.progress = function( image, elem, message ) {
|
|
|
+ this.progressedCount++;
|
|
|
+ this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
|
|
|
+ // progress event
|
|
|
+ this.emitEvent( 'progress', [ this, image, elem ] );
|
|
|
+ if ( this.jqDeferred && this.jqDeferred.notify ) {
|
|
|
+ this.jqDeferred.notify( this, image );
|
|
|
+ }
|
|
|
+ // check if completed
|
|
|
+ if ( this.progressedCount == this.images.length ) {
|
|
|
+ this.complete();
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( this.options.debug && console ) {
|
|
|
+ console.log( 'progress: ' + message, image, elem );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+ImagesLoaded.prototype.complete = function() {
|
|
|
+ var eventName = this.hasAnyBroken ? 'fail' : 'done';
|
|
|
+ this.isComplete = true;
|
|
|
+ this.emitEvent( eventName, [ this ] );
|
|
|
+ this.emitEvent( 'always', [ this ] );
|
|
|
+ if ( this.jqDeferred ) {
|
|
|
+ var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
|
|
|
+ this.jqDeferred[ jqMethod ]( this );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- -------------------------- //
|
|
|
+
|
|
|
+function LoadingImage( img ) {
|
|
|
+ this.img = img;
|
|
|
+}
|
|
|
+
|
|
|
+LoadingImage.prototype = Object.create( EvEmitter.prototype );
|
|
|
+
|
|
|
+LoadingImage.prototype.check = function() {
|
|
|
+ // If complete is true and browser supports natural sizes,
|
|
|
+ // try to check for image status manually.
|
|
|
+ var isComplete = this.getIsImageComplete();
|
|
|
+ if ( isComplete ) {
|
|
|
+ // report based on naturalWidth
|
|
|
+ this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If none of the checks above matched, simulate loading on detached element.
|
|
|
+ this.proxyImage = new Image();
|
|
|
+ this.proxyImage.addEventListener( 'load', this );
|
|
|
+ this.proxyImage.addEventListener( 'error', this );
|
|
|
+ // bind to image as well for Firefox. #191
|
|
|
+ this.img.addEventListener( 'load', this );
|
|
|
+ this.img.addEventListener( 'error', this );
|
|
|
+ this.proxyImage.src = this.img.src;
|
|
|
+};
|
|
|
+
|
|
|
+LoadingImage.prototype.getIsImageComplete = function() {
|
|
|
+ // check for non-zero, non-undefined naturalWidth
|
|
|
+ // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
|
|
|
+ return this.img.complete && this.img.naturalWidth;
|
|
|
+};
|
|
|
+
|
|
|
+LoadingImage.prototype.confirm = function( isLoaded, message ) {
|
|
|
+ this.isLoaded = isLoaded;
|
|
|
+ this.emitEvent( 'progress', [ this, this.img, message ] );
|
|
|
+};
|
|
|
+
|
|
|
+// ----- events ----- //
|
|
|
+
|
|
|
+// trigger specified handler for event type
|
|
|
+LoadingImage.prototype.handleEvent = function( event ) {
|
|
|
+ var method = 'on' + event.type;
|
|
|
+ if ( this[ method ] ) {
|
|
|
+ this[ method ]( event );
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+LoadingImage.prototype.onload = function() {
|
|
|
+ this.confirm( true, 'onload' );
|
|
|
+ this.unbindEvents();
|
|
|
+};
|
|
|
+
|
|
|
+LoadingImage.prototype.onerror = function() {
|
|
|
+ this.confirm( false, 'onerror' );
|
|
|
+ this.unbindEvents();
|
|
|
+};
|
|
|
+
|
|
|
+LoadingImage.prototype.unbindEvents = function() {
|
|
|
+ this.proxyImage.removeEventListener( 'load', this );
|
|
|
+ this.proxyImage.removeEventListener( 'error', this );
|
|
|
+ this.img.removeEventListener( 'load', this );
|
|
|
+ this.img.removeEventListener( 'error', this );
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- Background -------------------------- //
|
|
|
+
|
|
|
+function Background( url, element ) {
|
|
|
+ this.url = url;
|
|
|
+ this.element = element;
|
|
|
+ this.img = new Image();
|
|
|
+}
|
|
|
+
|
|
|
+// inherit LoadingImage prototype
|
|
|
+Background.prototype = Object.create( LoadingImage.prototype );
|
|
|
+
|
|
|
+Background.prototype.check = function() {
|
|
|
+ this.img.addEventListener( 'load', this );
|
|
|
+ this.img.addEventListener( 'error', this );
|
|
|
+ this.img.src = this.url;
|
|
|
+ // check if image is already complete
|
|
|
+ var isComplete = this.getIsImageComplete();
|
|
|
+ if ( isComplete ) {
|
|
|
+ this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
|
|
|
+ this.unbindEvents();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Background.prototype.unbindEvents = function() {
|
|
|
+ this.img.removeEventListener( 'load', this );
|
|
|
+ this.img.removeEventListener( 'error', this );
|
|
|
+};
|
|
|
+
|
|
|
+Background.prototype.confirm = function( isLoaded, message ) {
|
|
|
+ this.isLoaded = isLoaded;
|
|
|
+ this.emitEvent( 'progress', [ this, this.element, message ] );
|
|
|
+};
|
|
|
+
|
|
|
+// -------------------------- jQuery -------------------------- //
|
|
|
+
|
|
|
+ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
|
|
|
+ jQuery = jQuery || window.jQuery;
|
|
|
+ if ( !jQuery ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // set local variable
|
|
|
+ $ = jQuery;
|
|
|
+ // $().imagesLoaded()
|
|
|
+ $.fn.imagesLoaded = function( options, callback ) {
|
|
|
+ var instance = new ImagesLoaded( this, options, callback );
|
|
|
+ return instance.jqDeferred.promise( $(this) );
|
|
|
+ };
|
|
|
+};
|
|
|
+// try making plugin
|
|
|
+ImagesLoaded.makeJQueryPlugin();
|
|
|
+
|
|
|
+// -------------------------- -------------------------- //
|
|
|
+
|
|
|
+return ImagesLoaded;
|
|
|
+
|
|
|
+});
|
|
|
+
|
|
|
+/*!
|
|
|
+ * Flickity imagesLoaded v2.0.0
|
|
|
+ * enables imagesLoaded option for Flickity
|
|
|
+ */
|
|
|
+
|
|
|
+/*jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /*jshint strict: false */ /*globals define, module, require */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( [
|
|
|
+ 'flickity/js/index',
|
|
|
+ 'imagesloaded/imagesloaded'
|
|
|
+ ], function( Flickity, imagesLoaded ) {
|
|
|
+ return factory( window, Flickity, imagesLoaded );
|
|
|
+ });
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ window,
|
|
|
+ require('flickity'),
|
|
|
+ require('imagesloaded')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Flickity = factory(
|
|
|
+ window,
|
|
|
+ window.Flickity,
|
|
|
+ window.imagesLoaded
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( window, Flickity, imagesLoaded ) {
|
|
|
+'use strict';
|
|
|
+
|
|
|
+Flickity.createMethods.push('_createImagesLoaded');
|
|
|
+
|
|
|
+var proto = Flickity.prototype;
|
|
|
+
|
|
|
+proto._createImagesLoaded = function() {
|
|
|
+ this.on( 'activate', this.imagesLoaded );
|
|
|
+};
|
|
|
+
|
|
|
+proto.imagesLoaded = function() {
|
|
|
+ if ( !this.options.imagesLoaded ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var _this = this;
|
|
|
+ function onImagesLoadedProgress( instance, image ) {
|
|
|
+ var cell = _this.getParentCell( image.img );
|
|
|
+ _this.cellSizeChange( cell && cell.element );
|
|
|
+ if ( !_this.options.freeScroll ) {
|
|
|
+ _this.positionSliderAtSelected();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress );
|
|
|
+};
|
|
|
+
|
|
|
+return Flickity;
|
|
|
+
|
|
|
+}));
|
|
|
+
|