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