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