/*! * flickity packaged v2.2.2 * touch, responsive, flickable carousels * * licensed gplv3 for open source use * or flickity commercial license for commercial use * * https://flickity.metafizzy.co * copyright 2015-2021 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 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 ] = ''; this.element.removeattribute('aria-hidden'); }; 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} shift - 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 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 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 -= 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 transforms 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 var isresting = !this.ispointerdown && math.round( this.x * 100 ) == math.round( previousx * 100 ); if ( isresting ) { 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 /* eslint-disable max-params */ ( function( window, factory ) { // universal module definition 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 ) { /* eslint-enable max-params */ // 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 ]; if ( instance ) 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 - options to extend */ 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, nodelist, htmlelement]} elems - elements to make into cells * @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 - cells to size */ 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 ) { /* eslint-disable-next-line no-invalid-this */ 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 = new 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, number]} value - zero-based index or element to select * @param {boolean} iswrap - enables wrapping around for extra index * @param {boolean} isinstant - disables slide animation */ 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 - matching cell element * @returns {flickity.cell} cell - matching cell */ 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 - multiple elements * @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 - child element * @returns {flickit.cell} cell - parent 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, string, number]} selector - element, selector string, or index * @returns {flickity.cell} - matching cell */ 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, string]} elem - element or selector string * @returns {flickity} - flickity instance */ 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.1 * 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 // safari 9 overrides pagex and pagey. these values needs to be copied. flickity#842 this.pointerdownpointer = { pagex: pointer.pagex, pagey: pointer.pagey, }; 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 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 %= 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( dist, mindist ) { return dist <= mindist; } : function( dist, mindist ) { return dist < mindist; }; 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 - horizontal position * @param {integer} index - slide index * @returns {number} - slide distance */ 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 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 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 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 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 - elements to insert * @param {integer} index - zero-based number to insert */ 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 - elements to remove */ 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 * @param {boolean} ispositioningslider - positions slider after selection */ 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 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 * @param {image} img - image element * @param {flickity} flickity - flickity instance */ 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.2 * touch, responsive, flickable carousels * * licensed gplv3 for open source use * or flickity commercial license for commercial use * * https://flickity.metafizzy.co * copyright 2015-2021 metafizzy */ ( function( window, factory ) { // universal module definition 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 ) { 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; }));