1const targets = document.querySelectorAll("[data-animate]"); 2const observer = new IntersectionObserver((entries) => { 3 let delay = 0; 4 for (const entry of entries) { 5 const { isIntersecting, target } = entry; 6 if (target.getAttribute("data-animate") !== "true" && isIntersecting) { 7 setTimeout(() => { 8 target.setAttribute("data-animate", "true"); 9 }, delay); 10 delay += 150; 11 } 12 } 13}); 14for (const target of targets) { 15 observer.observe(target); 16} 17 18const scrolls = document.querySelectorAll(".Footer__back-to-top"); 19for (const scroll of scrolls) { 20 const skip = document.querySelector(".skip-link"); 21 scroll.addEventListener("click", () => { 22 skip?.focus(); 23 document.activeElement?.blur(); 24 window.scroll(0, 0); 25 }); 26} 27 28const subtoggles = document.querySelectorAll(".Subnav__subtoggle"); 29for (const subtoggle of subtoggles) { 30 subtoggle.addEventListener("click", () => { 31 const expanded = subtoggle.getAttribute("aria-expanded") === "true"; 32 subtoggle.setAttribute("aria-expanded", (!expanded).toString()); 33 }); 34} 35 36var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; 37 38function getDefaultExportFromCjs (x) { 39 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; 40} 41 42var js = {exports: {}}; 43 44var core = {exports: {}}; 45 46var evEmitter = {exports: {}}; 47 48/** 49 * EvEmitter v2.1.1 50 * Lil' event emitter 51 * MIT License 52 */ 53 54var hasRequiredEvEmitter; 55 56function requireEvEmitter () { 57 if (hasRequiredEvEmitter) return evEmitter.exports; 58 hasRequiredEvEmitter = 1; 59 (function (module) { 60 ( function( global, factory ) { 61 // universal module definition 62 if ( module.exports ) { 63 // CommonJS - Browserify, Webpack 64 module.exports = factory(); 65 } else { 66 // Browser globals 67 global.EvEmitter = factory(); 68 } 69 70 }( typeof window != 'undefined' ? window : commonjsGlobal, function() { 71 72 function EvEmitter() {} 73 74 let proto = EvEmitter.prototype; 75 76 proto.on = function( eventName, listener ) { 77 if ( !eventName || !listener ) return this; 78 79 // set events hash 80 let events = this._events = this._events || {}; 81 // set listeners array 82 let listeners = events[ eventName ] = events[ eventName ] || []; 83 // only add once 84 if ( !listeners.includes( listener ) ) { 85 listeners.push( listener ); 86 } 87 88 return this; 89 }; 90 91 proto.once = function( eventName, listener ) { 92 if ( !eventName || !listener ) return this; 93 94 // add event 95 this.on( eventName, listener ); 96 // set once flag 97 // set onceEvents hash 98 let onceEvents = this._onceEvents = this._onceEvents || {}; 99 // set onceListeners object 100 let onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 101 // set flag 102 onceListeners[ listener ] = true; 103 104 return this; 105 }; 106 107 proto.off = function( eventName, listener ) { 108 let listeners = this._events && this._events[ eventName ]; 109 if ( !listeners || !listeners.length ) return this; 110 111 let index = listeners.indexOf( listener ); 112 if ( index != -1 ) { 113 listeners.splice( index, 1 ); 114 } 115 116 return this; 117 }; 118 119 proto.emitEvent = function( eventName, args ) { 120 let listeners = this._events && this._events[ eventName ]; 121 if ( !listeners || !listeners.length ) return this; 122 123 // copy over to avoid interference if .off() in listener 124 listeners = listeners.slice( 0 ); 125 args = args || []; 126 // once stuff 127 let onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 128 129 for ( let listener of listeners ) { 130 let isOnce = onceListeners && onceListeners[ listener ]; 131 if ( isOnce ) { 132 // remove listener 133 // remove before trigger to prevent recursion 134 this.off( eventName, listener ); 135 // unset once flag 136 delete onceListeners[ listener ]; 137 } 138 // trigger listener 139 listener.apply( this, args ); 140 } 141 142 return this; 143 }; 144 145 proto.allOff = function() { 146 delete this._events; 147 delete this._onceEvents; 148 return this; 149 }; 150 151 return EvEmitter; 152 153 } ) ); 154 } (evEmitter)); 155 return evEmitter.exports; 156} 157 158var getSize = {exports: {}}; 159 160/*! 161 * Infinite Scroll v2.0.4 162 * measure size of elements 163 * MIT license 164 */ 165 166var hasRequiredGetSize; 167 168function requireGetSize () { 169 if (hasRequiredGetSize) return getSize.exports; 170 hasRequiredGetSize = 1; 171 (function (module) { 172 ( function( window, factory ) { 173 if ( module.exports ) { 174 // CommonJS 175 module.exports = factory(); 176 } else { 177 // browser global 178 window.getSize = factory(); 179 } 180 181 } )( window, function factory() { 182 183 // -------------------------- helpers -------------------------- // 184 185 // get a number from a string, not a percentage 186 function getStyleSize( value ) { 187 let num = parseFloat( value ); 188 // not a percent like '100%', and a number 189 let isValid = value.indexOf('%') == -1 && !isNaN( num ); 190 return isValid && num; 191 } 192 193 // -------------------------- measurements -------------------------- // 194 195 let measurements = [ 196 'paddingLeft', 197 'paddingRight', 198 'paddingTop', 199 'paddingBottom', 200 'marginLeft', 201 'marginRight', 202 'marginTop', 203 'marginBottom', 204 'borderLeftWidth', 205 'borderRightWidth', 206 'borderTopWidth', 207 'borderBottomWidth', 208 ]; 209 210 function getZeroSize() { 211 let size = { 212 width: 0, 213 height: 0, 214 innerWidth: 0, 215 innerHeight: 0, 216 outerWidth: 0, 217 outerHeight: 0, 218 };
vendor: 9,233 bytes, lines 219-568
219 measurements.forEach( ( measurement ) => { 220 size[ measurement ] = 0; 221 } ); 222 return size; 223 } 224 225 // -------------------------- getSize -------------------------- // 226 227 function getSize( elem ) { 228 // use querySeletor if elem is string 229 if ( typeof elem == 'string' ) elem = document.querySelector( elem ); 230 231 // do not proceed on non-objects 232 let isElement = elem && typeof elem == 'object' && elem.nodeType; 233 if ( !isElement ) return; 234 235 let style = getComputedStyle( elem ); 236 237 // if hidden, everything is 0 238 if ( style.display == 'none' ) return getZeroSize(); 239 240 let size = {}; 241 size.width = elem.offsetWidth; 242 size.height = elem.offsetHeight; 243 244 let isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 245 246 // get all measurements 247 measurements.forEach( ( measurement ) => { 248 let value = style[ measurement ]; 249 let num = parseFloat( value ); 250 // any 'auto', 'medium' value will be 0 251 size[ measurement ] = !isNaN( num ) ? num : 0; 252 } ); 253 254 let paddingWidth = size.paddingLeft + size.paddingRight; 255 let paddingHeight = size.paddingTop + size.paddingBottom; 256 let marginWidth = size.marginLeft + size.marginRight; 257 let marginHeight = size.marginTop + size.marginBottom; 258 let borderWidth = size.borderLeftWidth + size.borderRightWidth; 259 let borderHeight = size.borderTopWidth + size.borderBottomWidth; 260 261 // overwrite width and height if we can get it from style 262 let styleWidth = getStyleSize( style.width ); 263 if ( styleWidth !== false ) { 264 size.width = styleWidth + 265 // add padding and border unless it's already including it 266 ( isBorderBox ? 0 : paddingWidth + borderWidth ); 267 } 268 269 let styleHeight = getStyleSize( style.height ); 270 if ( styleHeight !== false ) { 271 size.height = styleHeight + 272 // add padding and border unless it's already including it 273 ( isBorderBox ? 0 : paddingHeight + borderHeight ); 274 } 275 276 size.innerWidth = size.width - ( paddingWidth + borderWidth ); 277 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 278 279 size.outerWidth = size.width + marginWidth; 280 size.outerHeight = size.height + marginHeight; 281 282 return size; 283 } 284 285 return getSize; 286 287 } ); 288 } (getSize)); 289 return getSize.exports; 290} 291 292var utils = {exports: {}}; 293 294/** 295 * Fizzy UI utils v3.0.0 296 * MIT license 297 */ 298 299var hasRequiredUtils; 300 301function requireUtils () { 302 if (hasRequiredUtils) return utils.exports; 303 hasRequiredUtils = 1; 304 (function (module) { 305 ( function( global, factory ) { 306 // universal module definition 307 if ( module.exports ) { 308 // CommonJS 309 module.exports = factory( global ); 310 } else { 311 // browser global 312 global.fizzyUIUtils = factory( global ); 313 } 314 315 }( commonjsGlobal, function factory( global ) { 316 317 let utils = {}; 318 319 // ----- extend ----- // 320 321 // extends objects 322 utils.extend = function( a, b ) { 323 return Object.assign( a, b ); 324 }; 325 326 // ----- modulo ----- // 327 328 utils.modulo = function( num, div ) { 329 return ( ( num % div ) + div ) % div; 330 }; 331 332 // ----- makeArray ----- // 333 334 // turn element or nodeList into an array 335 utils.makeArray = function( obj ) { 336 // use object if already an array 337 if ( Array.isArray( obj ) ) return obj; 338 339 // return empty array if undefined or null. #6 340 if ( obj === null || obj === undefined ) return []; 341 342 let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 343 // convert nodeList to array 344 if ( isArrayLike ) return [ ...obj ]; 345 346 // array of single index 347 return [ obj ]; 348 }; 349 350 // ----- removeFrom ----- // 351 352 utils.removeFrom = function( ary, obj ) { 353 let index = ary.indexOf( obj ); 354 if ( index != -1 ) { 355 ary.splice( index, 1 ); 356 } 357 }; 358 359 // ----- getParent ----- // 360 361 utils.getParent = function( elem, selector ) { 362 while ( elem.parentNode && elem != document.body ) { 363 elem = elem.parentNode; 364 if ( elem.matches( selector ) ) return elem; 365 } 366 }; 367 368 // ----- getQueryElement ----- // 369 370 // use element as selector string 371 utils.getQueryElement = function( elem ) { 372 if ( typeof elem == 'string' ) { 373 return document.querySelector( elem ); 374 } 375 return elem; 376 }; 377 378 // ----- handleEvent ----- // 379 380 // enable .ontype to trigger from .addEventListener( elem, 'type' ) 381 utils.handleEvent = function( event ) { 382 let method = 'on' + event.type; 383 if ( this[ method ] ) { 384 this[ method ]( event ); 385 } 386 }; 387 388 // ----- filterFindElements ----- // 389 390 utils.filterFindElements = function( elems, selector ) { 391 // make array of elems 392 elems = utils.makeArray( elems ); 393 394 return elems 395 // check that elem is an actual element 396 .filter( ( elem ) => elem instanceof HTMLElement ) 397 .reduce( ( ffElems, elem ) => { 398 // add elem if no selector 399 if ( !selector ) { 400 ffElems.push( elem ); 401 return ffElems; 402 } 403 // filter & find items if we have a selector 404 // filter 405 if ( elem.matches( selector ) ) { 406 ffElems.push( elem ); 407 } 408 // find children 409 let childElems = elem.querySelectorAll( selector ); 410 // concat childElems to filterFound array 411 ffElems = ffElems.concat( ...childElems ); 412 return ffElems; 413 }, [] ); 414 }; 415 416 // ----- debounceMethod ----- // 417 418 utils.debounceMethod = function( _class, methodName, threshold ) { 419 threshold = threshold || 100; 420 // original method 421 let method = _class.prototype[ methodName ]; 422 let timeoutName = methodName + 'Timeout'; 423 424 _class.prototype[ methodName ] = function() { 425 clearTimeout( this[ timeoutName ] ); 426 427 let args = arguments; 428 this[ timeoutName ] = setTimeout( () => { 429 method.apply( this, args ); 430 delete this[ timeoutName ]; 431 }, threshold ); 432 }; 433 }; 434 435 // ----- docReady ----- // 436 437 utils.docReady = function( onDocReady ) { 438 let readyState = document.readyState; 439 if ( readyState == 'complete' || readyState == 'interactive' ) { 440 // do async to allow for other scripts to run. metafizzy/flickity#441 441 setTimeout( onDocReady ); 442 } else { 443 document.addEventListener( 'DOMContentLoaded', onDocReady ); 444 } 445 }; 446 447 // ----- htmlInit ----- // 448 449 // http://bit.ly/3oYLusc 450 utils.toDashed = function( str ) { 451 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 452 return $1 + '-' + $2; 453 } ).toLowerCase(); 454 }; 455 456 let console = global.console; 457 458 // allow user to initialize classes via [data-namespace] or .js-namespace class 459 // htmlInit( Widget, 'widgetName' ) 460 // options are parsed from data-namespace-options 461 utils.htmlInit = function( WidgetClass, namespace ) { 462 utils.docReady( function() { 463 let dashedNamespace = utils.toDashed( namespace ); 464 let dataAttr = 'data-' + dashedNamespace; 465 let dataAttrElems = document.querySelectorAll( `[${dataAttr}]` ); 466 let jQuery = global.jQuery; 467 468 [ ...dataAttrElems ].forEach( ( elem ) => { 469 let attr = elem.getAttribute( dataAttr ); 470 let options; 471 try { 472 options = attr && JSON.parse( attr ); 473 } catch ( error ) { 474 // log error, do not initialize 475 if ( console ) { 476 console.error( `Error parsing ${dataAttr} on ${elem.className}: ${error}` ); 477 } 478 return; 479 } 480 // initialize 481 let instance = new WidgetClass( elem, options ); 482 // make available via $().data('namespace') 483 if ( jQuery ) { 484 jQuery.data( elem, namespace, instance ); 485 } 486 } ); 487 488 } ); 489 }; 490 491 // ----- ----- // 492 493 return utils; 494 495 } ) ); 496 } (utils)); 497 return utils.exports; 498} 499 500var cell = {exports: {}}; 501 502var hasRequiredCell; 503 504function requireCell () { 505 if (hasRequiredCell) return cell.exports; 506 hasRequiredCell = 1; 507 (function (module) { 508 // Flickity.Cell 509 ( function( window, factory ) { 510 // universal module definition 511 if ( module.exports ) { 512 // CommonJS 513 module.exports = factory( requireGetSize() ); 514 } else { 515 // browser global 516 window.Flickity = window.Flickity || {}; 517 window.Flickity.Cell = factory( window.getSize ); 518 } 519 520 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( getSize ) { 521 522 const cellClassName = 'flickity-cell'; 523 524 function Cell( elem ) { 525 this.element = elem; 526 this.element.classList.add( cellClassName ); 527 528 this.x = 0; 529 this.unselect(); 530 } 531 532 let proto = Cell.prototype; 533 534 proto.destroy = function() { 535 // reset style 536 this.unselect(); 537 this.element.classList.remove( cellClassName ); 538 this.element.style.transform = ''; 539 this.element.removeAttribute('aria-hidden'); 540 }; 541 542 proto.getSize = function() { 543 this.size = getSize( this.element ); 544 }; 545 546 proto.select = function() { 547 this.element.classList.add('is-selected'); 548 this.element.removeAttribute('aria-hidden'); 549 }; 550 551 proto.unselect = function() { 552 this.element.classList.remove('is-selected'); 553 this.element.setAttribute( 'aria-hidden', 'true' ); 554 }; 555 556 proto.remove = function() { 557 this.element.remove(); 558 }; 559 560 return Cell; 561 562 } ) ); 563 } (cell)); 564 return cell.exports; 565} 566 567var slide = {exports: {}}; 568
569var hasRequiredSlide; 570 571function requireSlide () { 572 if (hasRequiredSlide) return slide.exports; 573 hasRequiredSlide = 1; 574 (function (module) { 575 // slide 576 ( function( window, factory ) { 577 // universal module definition 578 if ( module.exports ) { 579 // CommonJS 580 module.exports = factory(); 581 } else { 582 // browser global 583 window.Flickity = window.Flickity || {}; 584 window.Flickity.Slide = factory(); 585 } 586 587 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory() { 588 589 function Slide( beginMargin, endMargin, cellAlign ) { 590 this.beginMargin = beginMargin; 591 this.endMargin = endMargin; 592 this.cellAlign = cellAlign; 593 this.cells = []; 594 this.outerWidth = 0; 595 this.height = 0; 596 } 597 598 let proto = Slide.prototype; 599 600 proto.addCell = function( cell ) { 601 this.cells.push( cell ); 602 this.outerWidth += cell.size.outerWidth; 603 this.height = Math.max( cell.size.outerHeight, this.height ); 604 // first cell stuff 605 if ( this.cells.length === 1 ) { 606 this.x = cell.x; // x comes from first cell 607 this.firstMargin = cell.size[ this.beginMargin ]; 608 } 609 }; 610 611 proto.updateTarget = function() { 612 let lastCell = this.getLastCell(); 613 let lastMargin = lastCell ? lastCell.size[ this.endMargin ] : 0; 614 let slideWidth = this.outerWidth - ( this.firstMargin + lastMargin ); 615 this.target = this.x + this.firstMargin + slideWidth * this.cellAlign; 616 }; 617 618 proto.getLastCell = function() { 619 return this.cells[ this.cells.length - 1 ]; 620 }; 621 622 proto.select = function() { 623 this.cells.forEach( ( cell ) => cell.select() ); 624 }; 625 626 proto.unselect = function() { 627 this.cells.forEach( ( cell ) => cell.unselect() ); 628 }; 629 630 proto.getCellElements = function() { 631 return this.cells.map( ( cell ) => cell.element ); 632 }; 633 634 return Slide; 635 636 } ) ); 637 } (slide)); 638 return slide.exports; 639} 640 641var animate = {exports: {}}; 642
vendor: 81,217 bytes, lines 643-3368
643var hasRequiredAnimate; 644 645function requireAnimate () { 646 if (hasRequiredAnimate) return animate.exports; 647 hasRequiredAnimate = 1; 648 (function (module) { 649 // animate 650 ( function( window, factory ) { 651 // universal module definition 652 if ( module.exports ) { 653 // CommonJS 654 module.exports = factory( requireUtils() ); 655 } else { 656 // browser global 657 window.Flickity = window.Flickity || {}; 658 window.Flickity.animatePrototype = factory( window.fizzyUIUtils ); 659 } 660 661 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( utils ) { 662 663 // -------------------------- animate -------------------------- // 664 665 let proto = {}; 666 667 proto.startAnimation = function() { 668 if ( this.isAnimating ) return; 669 670 this.isAnimating = true; 671 this.restingFrames = 0; 672 this.animate(); 673 }; 674 675 proto.animate = function() { 676 this.applyDragForce(); 677 this.applySelectedAttraction(); 678 679 let previousX = this.x; 680 681 this.integratePhysics(); 682 this.positionSlider(); 683 this.settle( previousX ); 684 // animate next frame 685 if ( this.isAnimating ) requestAnimationFrame( () => this.animate() ); 686 }; 687 688 proto.positionSlider = function() { 689 let x = this.x; 690 // wrap position around 691 if ( this.isWrapping ) { 692 x = utils.modulo( x, this.slideableWidth ) - this.slideableWidth; 693 this.shiftWrapCells( x ); 694 } 695 696 this.setTranslateX( x, this.isAnimating ); 697 this.dispatchScrollEvent(); 698 }; 699 700 proto.setTranslateX = function( x, is3d ) { 701 x += this.cursorPosition; 702 // reverse if right-to-left and using transform 703 if ( this.options.rightToLeft ) x = -x; 704 let translateX = this.getPositionValue( x ); 705 // use 3D transforms for hardware acceleration on iOS 706 // but use 2D when settled, for better font-rendering 707 this.slider.style.transform = is3d ? 708 `translate3d(${translateX},0,0)` : `translateX(${translateX})`; 709 }; 710 711 proto.dispatchScrollEvent = function() { 712 let firstSlide = this.slides[0]; 713 if ( !firstSlide ) return; 714 715 let positionX = -this.x - firstSlide.target; 716 let progress = positionX / this.slidesWidth; 717 this.dispatchEvent( 'scroll', null, [ progress, positionX ] ); 718 }; 719 720 proto.positionSliderAtSelected = function() { 721 if ( !this.cells.length ) return; 722 723 this.x = -this.selectedSlide.target; 724 this.velocity = 0; // stop wobble 725 this.positionSlider(); 726 }; 727 728 proto.getPositionValue = function( position ) { 729 if ( this.options.percentPosition ) { 730 // percent position, round to 2 digits, like 12.34% 731 return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 ) + '%'; 732 } else { 733 // pixel positioning 734 return Math.round( position ) + 'px'; 735 } 736 }; 737 738 proto.settle = function( previousX ) { 739 // keep track of frames where x hasn't moved 740 let isResting = !this.isPointerDown && 741 Math.round( this.x * 100 ) === Math.round( previousX * 100 ); 742 if ( isResting ) this.restingFrames++; 743 // stop animating if resting for 3 or more frames 744 if ( this.restingFrames > 2 ) { 745 this.isAnimating = false; 746 delete this.isFreeScrolling; 747 // render position with translateX when settled 748 this.positionSlider(); 749 this.dispatchEvent( 'settle', null, [ this.selectedIndex ] ); 750 } 751 }; 752 753 proto.shiftWrapCells = function( x ) { 754 // shift before cells 755 let beforeGap = this.cursorPosition + x; 756 this._shiftCells( this.beforeShiftCells, beforeGap, -1 ); 757 // shift after cells 758 let afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition ); 759 this._shiftCells( this.afterShiftCells, afterGap, 1 ); 760 }; 761 762 proto._shiftCells = function( cells, gap, shift ) { 763 cells.forEach( ( cell ) => { 764 let cellShift = gap > 0 ? shift : 0; 765 this._wrapShiftCell( cell, cellShift ); 766 gap -= cell.size.outerWidth; 767 } ); 768 }; 769 770 proto._unshiftCells = function( cells ) { 771 if ( !cells || !cells.length ) return; 772 773 cells.forEach( ( cell ) => this._wrapShiftCell( cell, 0 ) ); 774 }; 775 776 // @param {Integer} shift - 0, 1, or -1 777 proto._wrapShiftCell = function( cell, shift ) { 778 this._renderCellPosition( cell, cell.x + this.slideableWidth * shift ); 779 }; 780 781 // -------------------------- physics -------------------------- // 782 783 proto.integratePhysics = function() { 784 this.x += this.velocity; 785 this.velocity *= this.getFrictionFactor(); 786 }; 787 788 proto.applyForce = function( force ) { 789 this.velocity += force; 790 }; 791 792 proto.getFrictionFactor = function() { 793 return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ]; 794 }; 795 796 proto.getRestingPosition = function() { 797 // my thanks to Steven Wittens, who simplified this math greatly 798 return this.x + this.velocity / ( 1 - this.getFrictionFactor() ); 799 }; 800 801 proto.applyDragForce = function() { 802 if ( !this.isDraggable || !this.isPointerDown ) return; 803 804 // change the position to drag position by applying force 805 let dragVelocity = this.dragX - this.x; 806 let dragForce = dragVelocity - this.velocity; 807 this.applyForce( dragForce ); 808 }; 809 810 proto.applySelectedAttraction = function() { 811 // do not attract if pointer down or no slides 812 let dragDown = this.isDraggable && this.isPointerDown; 813 if ( dragDown || this.isFreeScrolling || !this.slides.length ) return; 814 815 let distance = this.selectedSlide.target * -1 - this.x; 816 let force = distance * this.options.selectedAttraction; 817 this.applyForce( force ); 818 }; 819 820 return proto; 821 822 } ) ); 823 } (animate)); 824 return animate.exports; 825} 826 827var hasRequiredCore; 828 829function requireCore () { 830 if (hasRequiredCore) return core.exports; 831 hasRequiredCore = 1; 832 (function (module) { 833 // Flickity main 834 /* eslint-disable max-params */ 835 ( function( window, factory ) { 836 // universal module definition 837 if ( module.exports ) { 838 // CommonJS 839 module.exports = factory( 840 window, 841 requireEvEmitter(), 842 requireGetSize(), 843 requireUtils(), 844 requireCell(), 845 requireSlide(), 846 requireAnimate(), 847 ); 848 } else { 849 // browser global 850 let _Flickity = window.Flickity; 851 852 window.Flickity = factory( 853 window, 854 window.EvEmitter, 855 window.getSize, 856 window.fizzyUIUtils, 857 _Flickity.Cell, 858 _Flickity.Slide, 859 _Flickity.animatePrototype, 860 ); 861 } 862 863 }( typeof window != 'undefined' ? window : commonjsGlobal, 864 function factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) { 865 /* eslint-enable max-params */ 866 867 // vars 868 const { getComputedStyle, console } = window; 869 let { jQuery } = window; 870 871 // -------------------------- Flickity -------------------------- // 872 873 // globally unique identifiers 874 let GUID = 0; 875 // internal store of all Flickity intances 876 let instances = {}; 877 878 function Flickity( element, options ) { 879 let queryElement = utils.getQueryElement( element ); 880 if ( !queryElement ) { 881 if ( console ) console.error(`Bad element for Flickity: ${queryElement || element}`); 882 return; 883 } 884 this.element = queryElement; 885 // do not initialize twice on same element 886 if ( this.element.flickityGUID ) { 887 let instance = instances[ this.element.flickityGUID ]; 888 if ( instance ) instance.option( options ); 889 return instance; 890 } 891 892 // add jQuery 893 if ( jQuery ) { 894 this.$element = jQuery( this.element ); 895 } 896 // options 897 this.options = { ...this.constructor.defaults }; 898 this.option( options ); 899 900 // kick things off 901 this._create(); 902 } 903 904 Flickity.defaults = { 905 accessibility: true, 906 // adaptiveHeight: false, 907 cellAlign: 'center', 908 // cellSelector: undefined, 909 // contain: false, 910 freeScrollFriction: 0.075, // friction when free-scrolling 911 friction: 0.28, // friction when selecting 912 namespaceJQueryEvents: true, 913 // initialIndex: 0, 914 percentPosition: true, 915 resize: true, 916 selectedAttraction: 0.025, 917 setGallerySize: true, 918 // watchCSS: false, 919 // wrapAround: false 920 }; 921 922 // hash of methods triggered on _create() 923 Flickity.create = {}; 924 925 let proto = Flickity.prototype; 926 // inherit EventEmitter 927 Object.assign( proto, EvEmitter.prototype ); 928 929 proto._create = function() { 930 let { resize, watchCSS, rightToLeft } = this.options; 931 // add id for Flickity.data 932 let id = this.guid = ++GUID; 933 this.element.flickityGUID = id; // expando 934 instances[ id ] = this; // associate via id 935 // initial properties 936 this.selectedIndex = 0; 937 // how many frames slider has been in same position 938 this.restingFrames = 0; 939 // initial physics properties 940 this.x = 0; 941 this.velocity = 0; 942 this.beginMargin = rightToLeft ? 'marginRight' : 'marginLeft'; 943 this.endMargin = rightToLeft ? 'marginLeft' : 'marginRight'; 944 // create viewport & slider 945 this.viewport = document.createElement('div'); 946 this.viewport.className = 'flickity-viewport'; 947 this._createSlider(); 948 // used for keyboard navigation 949 this.focusableElems = [ this.element ]; 950 951 if ( resize || watchCSS ) { 952 window.addEventListener( 'resize', this ); 953 } 954 955 // add listeners from on option 956 for ( let eventName in this.options.on ) { 957 let listener = this.options.on[ eventName ]; 958 this.on( eventName, listener ); 959 } 960 961 for ( let method in Flickity.create ) { 962 Flickity.create[ method ].call( this ); 963 } 964 965 if ( watchCSS ) { 966 this.watchCSS(); 967 } else { 968 this.activate(); 969 } 970 }; 971 972 /** 973 * set options 974 * @param {Object} opts - options to extend 975 */ 976 proto.option = function( opts ) { 977 Object.assign( this.options, opts ); 978 }; 979 980 proto.activate = function() { 981 if ( this.isActive ) return; 982 983 this.isActive = true; 984 this.element.classList.add('flickity-enabled'); 985 if ( this.options.rightToLeft ) { 986 this.element.classList.add('flickity-rtl'); 987 } 988 989 this.getSize(); 990 // move initial cell elements so they can be loaded as cells 991 let cellElems = this._filterFindCellElements( this.element.children ); 992 this.slider.append( ...cellElems ); 993 this.viewport.append( this.slider ); 994 this.element.append( this.viewport ); 995 // get cells from children 996 this.reloadCells(); 997 998 if ( this.options.accessibility ) { 999 // allow element to focusable 1000 this.element.tabIndex = 0; 1001 // listen for key presses 1002 this.element.addEventListener( 'keydown', this ); 1003 } 1004 1005 this.emitEvent('activate'); 1006 this.selectInitialIndex(); 1007 // flag for initial activation, for using initialIndex 1008 this.isInitActivated = true; 1009 // ready event. #493 1010 this.dispatchEvent('ready'); 1011 }; 1012 1013 // slider positions the cells 1014 proto._createSlider = function() { 1015 // slider element does all the positioning 1016 let slider = document.createElement('div'); 1017 slider.className = 'flickity-slider'; 1018 this.slider = slider; 1019 }; 1020 1021 proto._filterFindCellElements = function( elems ) { 1022 return utils.filterFindElements( elems, this.options.cellSelector ); 1023 }; 1024 1025 // goes through all children 1026 proto.reloadCells = function() { 1027 // collection of item elements 1028 this.cells = this._makeCells( this.slider.children ); 1029 this.positionCells(); 1030 this._updateWrapShiftCells(); 1031 this.setGallerySize(); 1032 }; 1033 1034 /** 1035 * turn elements into Flickity.Cells 1036 * @param {[Array, NodeList, HTMLElement]} elems - elements to make into cells 1037 * @returns {Array} items - collection of new Flickity Cells 1038 */ 1039 proto._makeCells = function( elems ) { 1040 let cellElems = this._filterFindCellElements( elems ); 1041 1042 // create new Cells for collection 1043 return cellElems.map( ( cellElem ) => new Cell( cellElem ) ); 1044 }; 1045 1046 proto.getLastCell = function() { 1047 return this.cells[ this.cells.length - 1 ]; 1048 }; 1049 1050 proto.getLastSlide = function() { 1051 return this.slides[ this.slides.length - 1 ]; 1052 }; 1053 1054 // positions all cells 1055 proto.positionCells = function() { 1056 // size all cells 1057 this._sizeCells( this.cells ); 1058 // position all cells 1059 this._positionCells( 0 ); 1060 }; 1061 1062 /** 1063 * position certain cells 1064 * @param {Integer} index - which cell to start with 1065 */ 1066 proto._positionCells = function( index ) { 1067 index = index || 0; 1068 // also measure maxCellHeight 1069 // start 0 if positioning all cells 1070 this.maxCellHeight = index ? this.maxCellHeight || 0 : 0; 1071 let cellX = 0; 1072 // get cellX 1073 if ( index > 0 ) { 1074 let startCell = this.cells[ index - 1 ]; 1075 cellX = startCell.x + startCell.size.outerWidth; 1076 } 1077 1078 this.cells.slice( index ).forEach( ( cell ) => { 1079 cell.x = cellX; 1080 this._renderCellPosition( cell, cellX ); 1081 cellX += cell.size.outerWidth; 1082 this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight ); 1083 } ); 1084 // keep track of cellX for wrap-around 1085 this.slideableWidth = cellX; 1086 // slides 1087 this.updateSlides(); 1088 // contain slides target 1089 this._containSlides(); 1090 // update slidesWidth 1091 this.slidesWidth = this.cells.length ? 1092 this.getLastSlide().target - this.slides[0].target : 0; 1093 }; 1094 1095 proto._renderCellPosition = function( cell, x ) { 1096 // render position of cell with in slider 1097 let sideOffset = this.options.rightToLeft ? -1 : 1; 1098 let renderX = x * sideOffset; 1099 if ( this.options.percentPosition ) renderX *= this.size.innerWidth / cell.size.width; 1100 let positionValue = this.getPositionValue( renderX ); 1101 cell.element.style.transform = `translateX( ${positionValue} )`; 1102 }; 1103 1104 /** 1105 * cell.getSize() on multiple cells 1106 * @param {Array} cells - cells to size 1107 */ 1108 proto._sizeCells = function( cells ) { 1109 cells.forEach( ( cell ) => cell.getSize() ); 1110 }; 1111 1112 // -------------------------- -------------------------- // 1113 1114 proto.updateSlides = function() { 1115 this.slides = []; 1116 if ( !this.cells.length ) return; 1117 1118 let { beginMargin, endMargin } = this; 1119 let slide = new Slide( beginMargin, endMargin, this.cellAlign ); 1120 this.slides.push( slide ); 1121 1122 let canCellFit = this._getCanCellFit(); 1123 1124 this.cells.forEach( ( cell, i ) => { 1125 // just add cell if first cell in slide 1126 if ( !slide.cells.length ) { 1127 slide.addCell( cell ); 1128 return; 1129 } 1130 1131 let slideWidth = ( slide.outerWidth - slide.firstMargin ) + 1132 ( cell.size.outerWidth - cell.size[ endMargin ] ); 1133 1134 if ( canCellFit( i, slideWidth ) ) { 1135 slide.addCell( cell ); 1136 } else { 1137 // doesn't fit, new slide 1138 slide.updateTarget(); 1139 1140 slide = new Slide( beginMargin, endMargin, this.cellAlign ); 1141 this.slides.push( slide ); 1142 slide.addCell( cell ); 1143 } 1144 } ); 1145 // last slide 1146 slide.updateTarget(); 1147 // update .selectedSlide 1148 this.updateSelectedSlide(); 1149 }; 1150 1151 proto._getCanCellFit = function() { 1152 let { groupCells } = this.options; 1153 if ( !groupCells ) return () => false; 1154 1155 if ( typeof groupCells == 'number' ) { 1156 // group by number. 3 -> [0,1,2], [3,4,5], ... 1157 let number = parseInt( groupCells, 10 ); 1158 return ( i ) => ( i % number ) !== 0; 1159 } 1160 // default, group by width of slide 1161 let percent = 1; 1162 // parse '75% 1163 let percentMatch = typeof groupCells == 'string' && groupCells.match( /^(\d+)%$/ ); 1164 if ( percentMatch ) percent = parseInt( percentMatch[1], 10 ) / 100; 1165 let groupWidth = ( this.size.innerWidth + 1 ) * percent; 1166 return ( i, slideWidth ) => slideWidth <= groupWidth; 1167 }; 1168 1169 // alias _init for jQuery plugin .flickity() 1170 proto._init = 1171 proto.reposition = function() { 1172 this.positionCells(); 1173 this.positionSliderAtSelected(); 1174 }; 1175 1176 proto.getSize = function() { 1177 this.size = getSize( this.element ); 1178 this.setCellAlign(); 1179 this.cursorPosition = this.size.innerWidth * this.cellAlign; 1180 }; 1181 1182 let cellAlignShorthands = { 1183 left: 0, 1184 center: 0.5, 1185 right: 1, 1186 }; 1187 1188 proto.setCellAlign = function() { 1189 let { cellAlign, rightToLeft } = this.options; 1190 let shorthand = cellAlignShorthands[ cellAlign ]; 1191 this.cellAlign = shorthand !== undefined ? shorthand : cellAlign; 1192 if ( rightToLeft ) this.cellAlign = 1 - this.cellAlign; 1193 }; 1194 1195 proto.setGallerySize = function() { 1196 if ( !this.options.setGallerySize ) return; 1197 1198 let height = this.options.adaptiveHeight && this.selectedSlide ? 1199 this.selectedSlide.height : this.maxCellHeight; 1200 this.viewport.style.height = `${height}px`; 1201 }; 1202 1203 proto._updateWrapShiftCells = function() { 1204 // update isWrapping 1205 this.isWrapping = this.getIsWrapping(); 1206 // only for wrap-around 1207 if ( !this.isWrapping ) return; 1208 1209 // unshift previous cells 1210 this._unshiftCells( this.beforeShiftCells ); 1211 this._unshiftCells( this.afterShiftCells ); 1212 // get before cells 1213 // initial gap 1214 let beforeGapX = this.cursorPosition; 1215 let lastIndex = this.cells.length - 1; 1216 this.beforeShiftCells = this._getGapCells( beforeGapX, lastIndex, -1 ); 1217 // get after cells 1218 // ending gap between last cell and end of gallery viewport 1219 let afterGapX = this.size.innerWidth - this.cursorPosition; 1220 // start cloning at first cell, working forwards 1221 this.afterShiftCells = this._getGapCells( afterGapX, 0, 1 ); 1222 }; 1223 1224 proto.getIsWrapping = function() { 1225 let { wrapAround } = this.options; 1226 if ( !wrapAround || this.slides.length < 2 ) return false; 1227 1228 if ( wrapAround !== 'fill' ) return true; 1229 // check that slides can fit 1230 1231 let gapWidth = this.slideableWidth - this.size.innerWidth; 1232 if ( gapWidth > this.size.innerWidth ) return true; // gap * 2x big, all good 1233 // check that content width - shifting cell is bigger than viewport width 1234 for ( let cell of this.cells ) { 1235 if ( cell.size.outerWidth > gapWidth ) return false; 1236 } 1237 return true; 1238 }; 1239 1240 proto._getGapCells = function( gapX, cellIndex, increment ) { 1241 // keep adding cells until the cover the initial gap 1242 let cells = []; 1243 while ( gapX > 0 ) { 1244 let cell = this.cells[ cellIndex ]; 1245 if ( !cell ) break; 1246 1247 cells.push( cell ); 1248 cellIndex += increment; 1249 gapX -= cell.size.outerWidth; 1250 } 1251 return cells; 1252 }; 1253 1254 // ----- contain & wrap ----- // 1255 1256 // contain cell targets so no excess sliding 1257 proto._containSlides = function() { 1258 let isContaining = this.options.contain && !this.isWrapping && 1259 this.cells.length; 1260 if ( !isContaining ) return; 1261 1262 let contentWidth = this.slideableWidth - this.getLastCell().size[ this.endMargin ]; 1263 // content is less than gallery size 1264 let isContentSmaller = contentWidth < this.size.innerWidth; 1265 if ( isContentSmaller ) { 1266 // all cells fit inside gallery 1267 this.slides.forEach( ( slide ) => { 1268 slide.target = contentWidth * this.cellAlign; 1269 } ); 1270 } else { 1271 // contain to bounds 1272 let beginBound = this.cursorPosition + this.cells[0].size[ this.beginMargin ]; 1273 let endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign ); 1274 this.slides.forEach( ( slide ) => { 1275 slide.target = Math.max( slide.target, beginBound ); 1276 slide.target = Math.min( slide.target, endBound ); 1277 } ); 1278 } 1279 }; 1280 1281 // ----- events ----- // 1282 1283 /** 1284 * emits events via eventEmitter and jQuery events 1285 * @param {String} type - name of event 1286 * @param {Event} event - original event 1287 * @param {Array} args - extra arguments 1288 */ 1289 proto.dispatchEvent = function( type, event, args ) { 1290 let emitArgs = event ? [ event ].concat( args ) : args; 1291 this.emitEvent( type, emitArgs ); 1292 1293 if ( jQuery && this.$element ) { 1294 // default trigger with type if no event 1295 type += this.options.namespaceJQueryEvents ? '.flickity' : ''; 1296 let $event = type; 1297 if ( event ) { 1298 // create jQuery event 1299 let jQEvent = new jQuery.Event( event ); 1300 jQEvent.type = type; 1301 $event = jQEvent; 1302 } 1303 this.$element.trigger( $event, args ); 1304 } 1305 }; 1306 1307 const unidraggerEvents = [ 1308 'dragStart', 1309 'dragMove', 1310 'dragEnd', 1311 'pointerDown', 1312 'pointerMove', 1313 'pointerEnd', 1314 'staticClick', 1315 ]; 1316 1317 let _emitEvent = proto.emitEvent; 1318 proto.emitEvent = function( eventName, args ) { 1319 if ( eventName === 'staticClick' ) { 1320 // add cellElem and cellIndex args to staticClick 1321 let clickedCell = this.getParentCell( args[0].target ); 1322 let cellElem = clickedCell && clickedCell.element; 1323 let cellIndex = clickedCell && this.cells.indexOf( clickedCell ); 1324 args = args.concat( cellElem, cellIndex ); 1325 } 1326 // do regular thing 1327 _emitEvent.call( this, eventName, args ); 1328 // duck-punch in jQuery events for Unidragger events 1329 let isUnidraggerEvent = unidraggerEvents.includes( eventName ); 1330 if ( !isUnidraggerEvent || !jQuery || !this.$element ) return; 1331 1332 eventName += this.options.namespaceJQueryEvents ? '.flickity' : ''; 1333 let event = args.shift( 0 ); 1334 let jQEvent = new jQuery.Event( event ); 1335 jQEvent.type = eventName; 1336 this.$element.trigger( jQEvent, args ); 1337 }; 1338 1339 // -------------------------- select -------------------------- // 1340 1341 /** 1342 * @param {Integer} index - index of the slide 1343 * @param {Boolean} isWrap - will wrap-around to last/first if at the end 1344 * @param {Boolean} isInstant - will immediately set position at selected cell 1345 */ 1346 proto.select = function( index, isWrap, isInstant ) { 1347 if ( !this.isActive ) return; 1348 1349 index = parseInt( index, 10 ); 1350 this._wrapSelect( index ); 1351 1352 if ( this.isWrapping || isWrap ) { 1353 index = utils.modulo( index, this.slides.length ); 1354 } 1355 // bail if invalid index 1356 if ( !this.slides[ index ] ) return; 1357 1358 let prevIndex = this.selectedIndex; 1359 this.selectedIndex = index; 1360 this.updateSelectedSlide(); 1361 if ( isInstant ) { 1362 this.positionSliderAtSelected(); 1363 } else { 1364 this.startAnimation(); 1365 } 1366 if ( this.options.adaptiveHeight ) { 1367 this.setGallerySize(); 1368 } 1369 // events 1370 this.dispatchEvent( 'select', null, [ index ] ); 1371 // change event if new index 1372 if ( index !== prevIndex ) { 1373 this.dispatchEvent( 'change', null, [ index ] ); 1374 } 1375 }; 1376 1377 // wraps position for wrapAround, to move to closest slide. #113 1378 proto._wrapSelect = function( index ) { 1379 if ( !this.isWrapping ) return; 1380 1381 const { selectedIndex, slideableWidth, slides: { length } } = this; 1382 // shift index for wrap, do not wrap dragSelect 1383 if ( !this.isDragSelect ) { 1384 let wrapIndex = utils.modulo( index, length ); 1385 // go to shortest 1386 let delta = Math.abs( wrapIndex - selectedIndex ); 1387 let backWrapDelta = Math.abs( ( wrapIndex + length ) - selectedIndex ); 1388 let forewardWrapDelta = Math.abs( ( wrapIndex - length ) - selectedIndex ); 1389 if ( backWrapDelta < delta ) { 1390 index += length; 1391 } else if ( forewardWrapDelta < delta ) { 1392 index -= length; 1393 } 1394 } 1395 1396 // wrap position so slider is within normal area 1397 if ( index < 0 ) { 1398 this.x -= slideableWidth; 1399 } else if ( index >= length ) { 1400 this.x += slideableWidth; 1401 } 1402 }; 1403 1404 proto.previous = function( isWrap, isInstant ) { 1405 this.select( this.selectedIndex - 1, isWrap, isInstant ); 1406 }; 1407 1408 proto.next = function( isWrap, isInstant ) { 1409 this.select( this.selectedIndex + 1, isWrap, isInstant ); 1410 }; 1411 1412 proto.updateSelectedSlide = function() { 1413 let slide = this.slides[ this.selectedIndex ]; 1414 // selectedIndex could be outside of slides, if triggered before resize() 1415 if ( !slide ) return; 1416 1417 // unselect previous selected slide 1418 this.unselectSelectedSlide(); 1419 // update new selected slide 1420 this.selectedSlide = slide; 1421 slide.select(); 1422 this.selectedCells = slide.cells; 1423 this.selectedElements = slide.getCellElements(); 1424 // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility 1425 this.selectedCell = slide.cells[0]; 1426 this.selectedElement = this.selectedElements[0]; 1427 }; 1428 1429 proto.unselectSelectedSlide = function() { 1430 if ( this.selectedSlide ) this.selectedSlide.unselect(); 1431 }; 1432 1433 proto.selectInitialIndex = function() { 1434 let initialIndex = this.options.initialIndex; 1435 // already activated, select previous selectedIndex 1436 if ( this.isInitActivated ) { 1437 this.select( this.selectedIndex, false, true ); 1438 return; 1439 } 1440 // select with selector string 1441 if ( initialIndex && typeof initialIndex == 'string' ) { 1442 let cell = this.queryCell( initialIndex ); 1443 if ( cell ) { 1444 this.selectCell( initialIndex, false, true ); 1445 return; 1446 } 1447 } 1448 1449 let index = 0; 1450 // select with number 1451 if ( initialIndex && this.slides[ initialIndex ] ) { 1452 index = initialIndex; 1453 } 1454 // select instantly 1455 this.select( index, false, true ); 1456 }; 1457 1458 /** 1459 * select slide from number or cell element 1460 * @param {[Element, Number]} value - zero-based index or element to select 1461 * @param {Boolean} isWrap - enables wrapping around for extra index 1462 * @param {Boolean} isInstant - disables slide animation 1463 */ 1464 proto.selectCell = function( value, isWrap, isInstant ) { 1465 // get cell 1466 let cell = this.queryCell( value ); 1467 if ( !cell ) return; 1468 1469 let index = this.getCellSlideIndex( cell ); 1470 this.select( index, isWrap, isInstant ); 1471 }; 1472 1473 proto.getCellSlideIndex = function( cell ) { 1474 // get index of slide that has cell 1475 let cellSlide = this.slides.find( ( slide ) => slide.cells.includes( cell ) ); 1476 return this.slides.indexOf( cellSlide ); 1477 }; 1478 1479 // -------------------------- get cells -------------------------- // 1480 1481 /** 1482 * get Flickity.Cell, given an Element 1483 * @param {Element} elem - matching cell element 1484 * @returns {Flickity.Cell} cell - matching cell 1485 */ 1486 proto.getCell = function( elem ) { 1487 // loop through cells to get the one that matches 1488 for ( let cell of this.cells ) { 1489 if ( cell.element === elem ) return cell; 1490 } 1491 }; 1492 1493 /** 1494 * get collection of Flickity.Cells, given Elements 1495 * @param {[Element, Array, NodeList]} elems - multiple elements 1496 * @returns {Array} cells - Flickity.Cells 1497 */ 1498 proto.getCells = function( elems ) { 1499 elems = utils.makeArray( elems ); 1500 return elems.map( ( elem ) => this.getCell( elem ) ).filter( Boolean ); 1501 }; 1502 1503 /** 1504 * get cell elements 1505 * @returns {Array} cellElems 1506 */ 1507 proto.getCellElements = function() { 1508 return this.cells.map( ( cell ) => cell.element ); 1509 }; 1510 1511 /** 1512 * get parent cell from an element 1513 * @param {Element} elem - child element 1514 * @returns {Flickit.Cell} cell - parent cell 1515 */ 1516 proto.getParentCell = function( elem ) { 1517 // first check if elem is cell 1518 let cell = this.getCell( elem ); 1519 if ( cell ) return cell; 1520 1521 // try to get parent cell elem 1522 let closest = elem.closest('.flickity-slider > *'); 1523 return this.getCell( closest ); 1524 }; 1525 1526 /** 1527 * get cells adjacent to a slide 1528 * @param {Integer} adjCount - number of adjacent slides 1529 * @param {Integer} index - index of slide to start 1530 * @returns {Array} cells - array of Flickity.Cells 1531 */ 1532 proto.getAdjacentCellElements = function( adjCount, index ) { 1533 if ( !adjCount ) return this.selectedSlide.getCellElements(); 1534 1535 index = index === undefined ? this.selectedIndex : index; 1536 1537 let len = this.slides.length; 1538 if ( 1 + ( adjCount * 2 ) >= len ) { 1539 return this.getCellElements(); // get all 1540 } 1541 1542 let cellElems = []; 1543 for ( let i = index - adjCount; i <= index + adjCount; i++ ) { 1544 let slideIndex = this.isWrapping ? utils.modulo( i, len ) : i; 1545 let slide = this.slides[ slideIndex ]; 1546 if ( slide ) { 1547 cellElems = cellElems.concat( slide.getCellElements() ); 1548 } 1549 } 1550 return cellElems; 1551 }; 1552 1553 /** 1554 * select slide from number or cell element 1555 * @param {[Element, String, Number]} selector - element, selector string, or index 1556 * @returns {Flickity.Cell} - matching cell 1557 */ 1558 proto.queryCell = function( selector ) { 1559 if ( typeof selector == 'number' ) { 1560 // use number as index 1561 return this.cells[ selector ]; 1562 } 1563 // do not select invalid selectors from hash: #123, #/. #791 1564 let isSelectorString = typeof selector == 'string' && !selector.match( /^[#.]?[\d/]/ ); 1565 if ( isSelectorString ) { 1566 // use string as selector, get element 1567 selector = this.element.querySelector( selector ); 1568 } 1569 // get cell from element 1570 return this.getCell( selector ); 1571 }; 1572 1573 // -------------------------- events -------------------------- // 1574 1575 proto.uiChange = function() { 1576 this.emitEvent('uiChange'); 1577 }; 1578 1579 // ----- resize ----- // 1580 1581 proto.onresize = function() { 1582 this.watchCSS(); 1583 this.resize(); 1584 }; 1585 1586 utils.debounceMethod( Flickity, 'onresize', 150 ); 1587 1588 proto.resize = function() { 1589 // #1177 disable resize behavior when animating or dragging for iOS 15 1590 if ( !this.isActive || this.isAnimating || this.isDragging ) return; 1591 this.getSize(); 1592 // wrap values 1593 if ( this.isWrapping ) { 1594 this.x = utils.modulo( this.x, this.slideableWidth ); 1595 } 1596 this.positionCells(); 1597 this._updateWrapShiftCells(); 1598 this.setGallerySize(); 1599 this.emitEvent('resize'); 1600 // update selected index for group slides, instant 1601 // TODO: position can be lost between groups of various numbers 1602 let selectedElement = this.selectedElements && this.selectedElements[0]; 1603 this.selectCell( selectedElement, false, true ); 1604 }; 1605 1606 // watches the :after property, activates/deactivates 1607 proto.watchCSS = function() { 1608 if ( !this.options.watchCSS ) return; 1609 1610 let afterContent = getComputedStyle( this.element, ':after' ).content; 1611 // activate if :after { content: 'flickity' } 1612 if ( afterContent.includes('flickity') ) { 1613 this.activate(); 1614 } else { 1615 this.deactivate(); 1616 } 1617 }; 1618 1619 // ----- keydown ----- // 1620 1621 // go previous/next if left/right keys pressed 1622 proto.onkeydown = function( event ) { 1623 let { activeElement } = document; 1624 let handler = Flickity.keyboardHandlers[ event.key ]; 1625 // only work if element is in focus 1626 if ( !this.options.accessibility || !activeElement || !handler ) return; 1627 1628 let isFocused = this.focusableElems.some( ( elem ) => activeElement === elem ); 1629 if ( isFocused ) handler.call( this ); 1630 }; 1631 1632 Flickity.keyboardHandlers = { 1633 ArrowLeft: function() { 1634 this.uiChange(); 1635 let leftMethod = this.options.rightToLeft ? 'next' : 'previous'; 1636 this[ leftMethod ](); 1637 }, 1638 ArrowRight: function() { 1639 this.uiChange(); 1640 let rightMethod = this.options.rightToLeft ? 'previous' : 'next'; 1641 this[ rightMethod ](); 1642 }, 1643 }; 1644 1645 // ----- focus ----- // 1646 1647 proto.focus = function() { 1648 this.element.focus({ preventScroll: true }); 1649 }; 1650 1651 // -------------------------- destroy -------------------------- // 1652 1653 // deactivate all Flickity functionality, but keep stuff available 1654 proto.deactivate = function() { 1655 if ( !this.isActive ) return; 1656 1657 this.element.classList.remove('flickity-enabled'); 1658 this.element.classList.remove('flickity-rtl'); 1659 this.unselectSelectedSlide(); 1660 // destroy cells 1661 this.cells.forEach( ( cell ) => cell.destroy() ); 1662 this.viewport.remove(); 1663 // move child elements back into element 1664 this.element.append( ...this.slider.children ); 1665 if ( this.options.accessibility ) { 1666 this.element.removeAttribute('tabIndex'); 1667 this.element.removeEventListener( 'keydown', this ); 1668 } 1669 // set flags 1670 this.isActive = false; 1671 this.emitEvent('deactivate'); 1672 }; 1673 1674 proto.destroy = function() { 1675 this.deactivate(); 1676 window.removeEventListener( 'resize', this ); 1677 this.allOff(); 1678 this.emitEvent('destroy'); 1679 if ( jQuery && this.$element ) { 1680 jQuery.removeData( this.element, 'flickity' ); 1681 } 1682 delete this.element.flickityGUID; 1683 delete instances[ this.guid ]; 1684 }; 1685 1686 // -------------------------- prototype -------------------------- // 1687 1688 Object.assign( proto, animatePrototype ); 1689 1690 // -------------------------- extras -------------------------- // 1691 1692 /** 1693 * get Flickity instance from element 1694 * @param {[Element, String]} elem - element or selector string 1695 * @returns {Flickity} - Flickity instance 1696 */ 1697 Flickity.data = function( elem ) { 1698 elem = utils.getQueryElement( elem ); 1699 if ( elem ) return instances[ elem.flickityGUID ]; 1700 }; 1701 1702 utils.htmlInit( Flickity, 'flickity' ); 1703 1704 let { jQueryBridget } = window; 1705 if ( jQuery && jQueryBridget ) { 1706 jQueryBridget( 'flickity', Flickity, jQuery ); 1707 } 1708 1709 // set internal jQuery, for Webpack + jQuery v3, #478 1710 Flickity.setJQuery = function( jq ) { 1711 jQuery = jq; 1712 }; 1713 1714 Flickity.Cell = Cell; 1715 Flickity.Slide = Slide; 1716 1717 return Flickity; 1718 1719 } ) ); 1720 } (core)); 1721 return core.exports; 1722} 1723 1724var drag = {exports: {}}; 1725 1726var unidragger = {exports: {}}; 1727 1728/*! 1729 * Unidragger v3.0.1 1730 * Draggable base class 1731 * MIT license 1732 */ 1733 1734var hasRequiredUnidragger; 1735 1736function requireUnidragger () { 1737 if (hasRequiredUnidragger) return unidragger.exports; 1738 hasRequiredUnidragger = 1; 1739 (function (module) { 1740 ( function( window, factory ) { 1741 // universal module definition 1742 if ( module.exports ) { 1743 // CommonJS 1744 module.exports = factory( 1745 window, 1746 requireEvEmitter(), 1747 ); 1748 } else { 1749 // browser global 1750 window.Unidragger = factory( 1751 window, 1752 window.EvEmitter, 1753 ); 1754 } 1755 1756 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( window, EvEmitter ) { 1757 1758 function Unidragger() {} 1759 1760 // inherit EvEmitter 1761 let proto = Unidragger.prototype = Object.create( EvEmitter.prototype ); 1762 1763 // ----- bind start ----- // 1764 1765 // trigger handler methods for events 1766 proto.handleEvent = function( event ) { 1767 let method = 'on' + event.type; 1768 if ( this[ method ] ) { 1769 this[ method ]( event ); 1770 } 1771 }; 1772 1773 let startEvent, activeEvents; 1774 if ( 'ontouchstart' in window ) { 1775 // HACK prefer Touch Events as you can preventDefault on touchstart to 1776 // disable scroll in iOS & mobile Chrome metafizzy/flickity#1177 1777 startEvent = 'touchstart'; 1778 activeEvents = [ 'touchmove', 'touchend', 'touchcancel' ]; 1779 } else if ( window.PointerEvent ) { 1780 // Pointer Events 1781 startEvent = 'pointerdown'; 1782 activeEvents = [ 'pointermove', 'pointerup', 'pointercancel' ]; 1783 } else { 1784 // mouse events 1785 startEvent = 'mousedown'; 1786 activeEvents = [ 'mousemove', 'mouseup' ]; 1787 } 1788 1789 // prototype so it can be overwriteable by Flickity 1790 proto.touchActionValue = 'none'; 1791 1792 proto.bindHandles = function() { 1793 this._bindHandles( 'addEventListener', this.touchActionValue ); 1794 }; 1795 1796 proto.unbindHandles = function() { 1797 this._bindHandles( 'removeEventListener', '' ); 1798 }; 1799 1800 /** 1801 * Add or remove start event 1802 * @param {String} bindMethod - addEventListener or removeEventListener 1803 * @param {String} touchAction - value for touch-action CSS property 1804 */ 1805 proto._bindHandles = function( bindMethod, touchAction ) { 1806 this.handles.forEach( ( handle ) => { 1807 handle[ bindMethod ]( startEvent, this ); 1808 handle[ bindMethod ]( 'click', this ); 1809 // touch-action: none to override browser touch gestures. metafizzy/flickity#540 1810 if ( window.PointerEvent ) handle.style.touchAction = touchAction; 1811 } ); 1812 }; 1813 1814 proto.bindActivePointerEvents = function() { 1815 activeEvents.forEach( ( eventName ) => { 1816 window.addEventListener( eventName, this ); 1817 } ); 1818 }; 1819 1820 proto.unbindActivePointerEvents = function() { 1821 activeEvents.forEach( ( eventName ) => { 1822 window.removeEventListener( eventName, this ); 1823 } ); 1824 }; 1825 1826 // ----- event handler helpers ----- // 1827 1828 // trigger method with matching pointer 1829 proto.withPointer = function( methodName, event ) { 1830 if ( event.pointerId === this.pointerIdentifier ) { 1831 this[ methodName ]( event, event ); 1832 } 1833 }; 1834 1835 // trigger method with matching touch 1836 proto.withTouch = function( methodName, event ) { 1837 let touch; 1838 for ( let changedTouch of event.changedTouches ) { 1839 if ( changedTouch.identifier === this.pointerIdentifier ) { 1840 touch = changedTouch; 1841 } 1842 } 1843 if ( touch ) this[ methodName ]( event, touch ); 1844 }; 1845 1846 // ----- start event ----- // 1847 1848 proto.onmousedown = function( event ) { 1849 this.pointerDown( event, event ); 1850 }; 1851 1852 proto.ontouchstart = function( event ) { 1853 this.pointerDown( event, event.changedTouches[0] ); 1854 }; 1855 1856 proto.onpointerdown = function( event ) { 1857 this.pointerDown( event, event ); 1858 }; 1859 1860 // nodes that have text fields 1861 const cursorNodes = [ 'TEXTAREA', 'INPUT', 'SELECT', 'OPTION' ]; 1862 // input types that do not have text fields 1863 const clickTypes = [ 'radio', 'checkbox', 'button', 'submit', 'image', 'file' ]; 1864 1865 /** 1866 * any time you set `event, pointer` it refers to: 1867 * @param {Event} event 1868 * @param {Event | Touch} pointer 1869 */ 1870 proto.pointerDown = function( event, pointer ) { 1871 // dismiss multi-touch taps, right clicks, and clicks on text fields 1872 let isCursorNode = cursorNodes.includes( event.target.nodeName ); 1873 let isClickType = clickTypes.includes( event.target.type ); 1874 let isOkayElement = !isCursorNode || isClickType; 1875 let isOkay = !this.isPointerDown && !event.button && isOkayElement; 1876 if ( !isOkay ) return; 1877 1878 this.isPointerDown = true; 1879 // save pointer identifier to match up touch events 1880 this.pointerIdentifier = pointer.pointerId !== undefined ? 1881 // pointerId for pointer events, touch.indentifier for touch events 1882 pointer.pointerId : pointer.identifier; 1883 // track position for move 1884 this.pointerDownPointer = { 1885 pageX: pointer.pageX, 1886 pageY: pointer.pageY, 1887 }; 1888 1889 this.bindActivePointerEvents(); 1890 this.emitEvent( 'pointerDown', [ event, pointer ] ); 1891 }; 1892 1893 // ----- move ----- // 1894 1895 proto.onmousemove = function( event ) { 1896 this.pointerMove( event, event ); 1897 }; 1898 1899 proto.onpointermove = function( event ) { 1900 this.withPointer( 'pointerMove', event ); 1901 }; 1902 1903 proto.ontouchmove = function( event ) { 1904 this.withTouch( 'pointerMove', event ); 1905 }; 1906 1907 proto.pointerMove = function( event, pointer ) { 1908 let moveVector = { 1909 x: pointer.pageX - this.pointerDownPointer.pageX, 1910 y: pointer.pageY - this.pointerDownPointer.pageY, 1911 }; 1912 this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] ); 1913 // start drag if pointer has moved far enough to start drag 1914 let isDragStarting = !this.isDragging && this.hasDragStarted( moveVector ); 1915 if ( isDragStarting ) this.dragStart( event, pointer ); 1916 if ( this.isDragging ) this.dragMove( event, pointer, moveVector ); 1917 }; 1918 1919 // condition if pointer has moved far enough to start drag 1920 proto.hasDragStarted = function( moveVector ) { 1921 return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3; 1922 }; 1923 1924 // ----- drag ----- // 1925 1926 proto.dragStart = function( event, pointer ) { 1927 this.isDragging = true; 1928 this.isPreventingClicks = true; // set flag to prevent clicks 1929 this.emitEvent( 'dragStart', [ event, pointer ] ); 1930 }; 1931 1932 proto.dragMove = function( event, pointer, moveVector ) { 1933 this.emitEvent( 'dragMove', [ event, pointer, moveVector ] ); 1934 }; 1935 1936 // ----- end ----- // 1937 1938 proto.onmouseup = function( event ) { 1939 this.pointerUp( event, event ); 1940 }; 1941 1942 proto.onpointerup = function( event ) { 1943 this.withPointer( 'pointerUp', event ); 1944 }; 1945 1946 proto.ontouchend = function( event ) { 1947 this.withTouch( 'pointerUp', event ); 1948 }; 1949 1950 proto.pointerUp = function( event, pointer ) { 1951 this.pointerDone(); 1952 this.emitEvent( 'pointerUp', [ event, pointer ] ); 1953 1954 if ( this.isDragging ) { 1955 this.dragEnd( event, pointer ); 1956 } else { 1957 // pointer didn't move enough for drag to start 1958 this.staticClick( event, pointer ); 1959 } 1960 }; 1961 1962 proto.dragEnd = function( event, pointer ) { 1963 this.isDragging = false; // reset flag 1964 // re-enable clicking async 1965 setTimeout( () => delete this.isPreventingClicks ); 1966 1967 this.emitEvent( 'dragEnd', [ event, pointer ] ); 1968 }; 1969 1970 // triggered on pointer up & pointer cancel 1971 proto.pointerDone = function() { 1972 this.isPointerDown = false; 1973 delete this.pointerIdentifier; 1974 this.unbindActivePointerEvents(); 1975 this.emitEvent('pointerDone'); 1976 }; 1977 1978 // ----- cancel ----- // 1979 1980 proto.onpointercancel = function( event ) { 1981 this.withPointer( 'pointerCancel', event ); 1982 }; 1983 1984 proto.ontouchcancel = function( event ) { 1985 this.withTouch( 'pointerCancel', event ); 1986 }; 1987 1988 proto.pointerCancel = function( event, pointer ) { 1989 this.pointerDone(); 1990 this.emitEvent( 'pointerCancel', [ event, pointer ] ); 1991 }; 1992 1993 // ----- click ----- // 1994 1995 // handle all clicks and prevent clicks when dragging 1996 proto.onclick = function( event ) { 1997 if ( this.isPreventingClicks ) event.preventDefault(); 1998 }; 1999 2000 // triggered after pointer down & up with no/tiny movement 2001 proto.staticClick = function( event, pointer ) { 2002 // ignore emulated mouse up clicks 2003 let isMouseup = event.type === 'mouseup'; 2004 if ( isMouseup && this.isIgnoringMouseUp ) return; 2005 2006 this.emitEvent( 'staticClick', [ event, pointer ] ); 2007 2008 // set flag for emulated clicks 300ms after touchend 2009 if ( isMouseup ) { 2010 this.isIgnoringMouseUp = true; 2011 // reset flag after 400ms 2012 setTimeout( () => { 2013 delete this.isIgnoringMouseUp; 2014 }, 400 ); 2015 } 2016 }; 2017 2018 // ----- ----- // 2019 2020 return Unidragger; 2021 2022 } ) ); 2023 } (unidragger)); 2024 return unidragger.exports; 2025} 2026 2027var hasRequiredDrag; 2028 2029function requireDrag () { 2030 if (hasRequiredDrag) return drag.exports; 2031 hasRequiredDrag = 1; 2032 (function (module) { 2033 // drag 2034 ( function( window, factory ) { 2035 // universal module definition 2036 if ( module.exports ) { 2037 // CommonJS 2038 module.exports = factory( 2039 window, 2040 requireCore(), 2041 requireUnidragger(), 2042 requireUtils(), 2043 ); 2044 } else { 2045 // browser global 2046 window.Flickity = factory( 2047 window, 2048 window.Flickity, 2049 window.Unidragger, 2050 window.fizzyUIUtils, 2051 ); 2052 } 2053 2054 }( typeof window != 'undefined' ? window : commonjsGlobal, 2055 function factory( window, Flickity, Unidragger, utils ) { 2056 2057 // ----- defaults ----- // 2058 2059 Object.assign( Flickity.defaults, { 2060 draggable: '>1', 2061 dragThreshold: 3, 2062 } ); 2063 2064 // -------------------------- drag prototype -------------------------- // 2065 2066 let proto = Flickity.prototype; 2067 Object.assign( proto, Unidragger.prototype ); // inherit Unidragger 2068 proto.touchActionValue = ''; 2069 2070 // -------------------------- -------------------------- // 2071 2072 Flickity.create.drag = function() { 2073 this.on( 'activate', this.onActivateDrag ); 2074 this.on( 'uiChange', this._uiChangeDrag ); 2075 this.on( 'deactivate', this.onDeactivateDrag ); 2076 this.on( 'cellChange', this.updateDraggable ); 2077 this.on( 'pointerDown', this.handlePointerDown ); 2078 this.on( 'pointerUp', this.handlePointerUp ); 2079 this.on( 'pointerDown', this.handlePointerDone ); 2080 this.on( 'dragStart', this.handleDragStart ); 2081 this.on( 'dragMove', this.handleDragMove ); 2082 this.on( 'dragEnd', this.handleDragEnd ); 2083 this.on( 'staticClick', this.handleStaticClick ); 2084 // TODO updateDraggable on resize? if groupCells & slides change 2085 }; 2086 2087 proto.onActivateDrag = function() { 2088 this.handles = [ this.viewport ]; 2089 this.bindHandles(); 2090 this.updateDraggable(); 2091 }; 2092 2093 proto.onDeactivateDrag = function() { 2094 this.unbindHandles(); 2095 this.element.classList.remove('is-draggable'); 2096 }; 2097 2098 proto.updateDraggable = function() { 2099 // disable dragging if less than 2 slides. #278 2100 if ( this.options.draggable === '>1' ) { 2101 this.isDraggable = this.slides.length > 1; 2102 } else { 2103 this.isDraggable = this.options.draggable; 2104 } 2105 this.element.classList.toggle( 'is-draggable', this.isDraggable ); 2106 }; 2107 2108 proto._uiChangeDrag = function() { 2109 delete this.isFreeScrolling; 2110 }; 2111 2112 // -------------------------- pointer events -------------------------- // 2113 2114 proto.handlePointerDown = function( event ) { 2115 if ( !this.isDraggable ) { 2116 // proceed for staticClick 2117 this.bindActivePointerEvents( event ); 2118 return; 2119 } 2120 2121 let isTouchStart = event.type === 'touchstart'; 2122 let isTouchPointer = event.pointerType === 'touch'; 2123 let isFocusNode = event.target.matches('input, textarea, select'); 2124 if ( !isTouchStart && !isTouchPointer && !isFocusNode ) event.preventDefault(); 2125 if ( !isFocusNode ) this.focus(); 2126 // blur 2127 if ( document.activeElement !== this.element ) document.activeElement.blur(); 2128 // stop if it was moving 2129 this.dragX = this.x; 2130 this.viewport.classList.add('is-pointer-down'); 2131 // track scrolling 2132 this.pointerDownScroll = getScrollPosition(); 2133 window.addEventListener( 'scroll', this ); 2134 this.bindActivePointerEvents( event ); 2135 }; 2136 2137 // ----- move ----- // 2138 2139 proto.hasDragStarted = function( moveVector ) { 2140 return Math.abs( moveVector.x ) > this.options.dragThreshold; 2141 }; 2142 2143 // ----- up ----- // 2144 2145 proto.handlePointerUp = function() { 2146 delete this.isTouchScrolling; 2147 this.viewport.classList.remove('is-pointer-down'); 2148 }; 2149 2150 proto.handlePointerDone = function() { 2151 window.removeEventListener( 'scroll', this ); 2152 delete this.pointerDownScroll; 2153 }; 2154 2155 // -------------------------- dragging -------------------------- // 2156 2157 proto.handleDragStart = function() { 2158 if ( !this.isDraggable ) return; 2159 2160 this.dragStartPosition = this.x; 2161 this.startAnimation(); 2162 window.removeEventListener( 'scroll', this ); 2163 }; 2164 2165 proto.handleDragMove = function( event, pointer, moveVector ) { 2166 if ( !this.isDraggable ) return; 2167 2168 event.preventDefault(); 2169 2170 this.previousDragX = this.dragX; 2171 // reverse if right-to-left 2172 let direction = this.options.rightToLeft ? -1 : 1; 2173 // wrap around move. #589 2174 if ( this.isWrapping ) moveVector.x %= this.slideableWidth; 2175 let dragX = this.dragStartPosition + moveVector.x * direction; 2176 2177 if ( !this.isWrapping ) { 2178 // slow drag 2179 let originBound = Math.max( -this.slides[0].target, this.dragStartPosition ); 2180 dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX; 2181 let endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition ); 2182 dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX; 2183 } 2184 2185 this.dragX = dragX; 2186 this.dragMoveTime = new Date(); 2187 }; 2188 2189 proto.handleDragEnd = function() { 2190 if ( !this.isDraggable ) return; 2191 2192 let { freeScroll } = this.options; 2193 if ( freeScroll ) this.isFreeScrolling = true; 2194 // set selectedIndex based on where flick will end up 2195 let index = this.dragEndRestingSelect(); 2196 2197 if ( freeScroll && !this.isWrapping ) { 2198 // if free-scroll & not wrap around 2199 // do not free-scroll if going outside of bounding slides 2200 // so bounding slides can attract slider, and keep it in bounds 2201 let restingX = this.getRestingPosition(); 2202 this.isFreeScrolling = -restingX > this.slides[0].target && 2203 -restingX < this.getLastSlide().target; 2204 } else if ( !freeScroll && index === this.selectedIndex ) { 2205 // boost selection if selected index has not changed 2206 index += this.dragEndBoostSelect(); 2207 } 2208 delete this.previousDragX; 2209 // apply selection 2210 // HACK, set flag so dragging stays in correct direction 2211 this.isDragSelect = this.isWrapping; 2212 this.select( index ); 2213 delete this.isDragSelect; 2214 }; 2215 2216 proto.dragEndRestingSelect = function() { 2217 let restingX = this.getRestingPosition(); 2218 // how far away from selected slide 2219 let distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) ); 2220 // get closet resting going up and going down 2221 let positiveResting = this._getClosestResting( restingX, distance, 1 ); 2222 let negativeResting = this._getClosestResting( restingX, distance, -1 ); 2223 // use closer resting for wrap-around 2224 return positiveResting.distance < negativeResting.distance ? 2225 positiveResting.index : negativeResting.index; 2226 }; 2227 2228 /** 2229 * given resting X and distance to selected cell 2230 * get the distance and index of the closest cell 2231 * @param {Number} restingX - estimated post-flick resting position 2232 * @param {Number} distance - distance to selected cell 2233 * @param {Integer} increment - +1 or -1, going up or down 2234 * @returns {Object} - { distance: {Number}, index: {Integer} } 2235 */ 2236 proto._getClosestResting = function( restingX, distance, increment ) { 2237 let index = this.selectedIndex; 2238 let minDistance = Infinity; 2239 let condition = this.options.contain && !this.isWrapping ? 2240 // if containing, keep going if distance is equal to minDistance 2241 ( dist, minDist ) => dist <= minDist : 2242 ( dist, minDist ) => dist < minDist; 2243 2244 while ( condition( distance, minDistance ) ) { 2245 // measure distance to next cell 2246 index += increment; 2247 minDistance = distance; 2248 distance = this.getSlideDistance( -restingX, index ); 2249 if ( distance === null ) break; 2250 2251 distance = Math.abs( distance ); 2252 } 2253 return { 2254 distance: minDistance, 2255 // selected was previous index 2256 index: index - increment, 2257 }; 2258 }; 2259 2260 /** 2261 * measure distance between x and a slide target 2262 * @param {Number} x - horizontal position 2263 * @param {Integer} index - slide index 2264 * @returns {Number} - slide distance 2265 */ 2266 proto.getSlideDistance = function( x, index ) { 2267 let len = this.slides.length; 2268 // wrap around if at least 2 slides 2269 let isWrapAround = this.options.wrapAround && len > 1; 2270 let slideIndex = isWrapAround ? utils.modulo( index, len ) : index; 2271 let slide = this.slides[ slideIndex ]; 2272 if ( !slide ) return null; 2273 2274 // add distance for wrap-around slides 2275 let wrap = isWrapAround ? this.slideableWidth * Math.floor( index/len ) : 0; 2276 return x - ( slide.target + wrap ); 2277 }; 2278 2279 proto.dragEndBoostSelect = function() { 2280 // do not boost if no previousDragX or dragMoveTime 2281 if ( this.previousDragX === undefined || !this.dragMoveTime || 2282 // or if drag was held for 100 ms 2283 new Date() - this.dragMoveTime > 100 ) { 2284 return 0; 2285 } 2286 2287 let distance = this.getSlideDistance( -this.dragX, this.selectedIndex ); 2288 let delta = this.previousDragX - this.dragX; 2289 if ( distance > 0 && delta > 0 ) { 2290 // boost to next if moving towards the right, and positive velocity 2291 return 1; 2292 } else if ( distance < 0 && delta < 0 ) { 2293 // boost to previous if moving towards the left, and negative velocity 2294 return -1; 2295 } 2296 return 0; 2297 }; 2298 2299 // ----- scroll ----- // 2300 2301 proto.onscroll = function() { 2302 let scroll = getScrollPosition(); 2303 let scrollMoveX = this.pointerDownScroll.x - scroll.x; 2304 let scrollMoveY = this.pointerDownScroll.y - scroll.y; 2305 // cancel click/tap if scroll is too much 2306 if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) { 2307 this.pointerDone(); 2308 } 2309 }; 2310 2311 // ----- utils ----- // 2312 2313 function getScrollPosition() { 2314 return { 2315 x: window.pageXOffset, 2316 y: window.pageYOffset, 2317 }; 2318 } 2319 2320 // ----- ----- // 2321 2322 return Flickity; 2323 2324 } ) ); 2325 } (drag)); 2326 return drag.exports; 2327} 2328 2329var prevNextButton = {exports: {}}; 2330 2331var hasRequiredPrevNextButton; 2332 2333function requirePrevNextButton () { 2334 if (hasRequiredPrevNextButton) return prevNextButton.exports; 2335 hasRequiredPrevNextButton = 1; 2336 (function (module) { 2337 // prev/next buttons 2338 ( function( window, factory ) { 2339 // universal module definition 2340 if ( module.exports ) { 2341 // CommonJS 2342 module.exports = factory( requireCore() ); 2343 } else { 2344 // browser global 2345 factory( window.Flickity ); 2346 } 2347 2348 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( Flickity ) { 2349 2350 const svgURI = 'http://www.w3.org/2000/svg'; 2351 2352 // -------------------------- PrevNextButton -------------------------- // 2353 2354 function PrevNextButton( increment, direction, arrowShape ) { 2355 this.increment = increment; 2356 this.direction = direction; 2357 this.isPrevious = increment === 'previous'; 2358 this.isLeft = direction === 'left'; 2359 this._create( arrowShape ); 2360 } 2361 2362 PrevNextButton.prototype._create = function( arrowShape ) { 2363 // properties 2364 let element = this.element = document.createElement('button'); 2365 element.className = `flickity-button flickity-prev-next-button ${this.increment}`; 2366 let label = this.isPrevious ? 'Previous' : 'Next'; 2367 // prevent button from submitting form https://stackoverflow.com/a/10836076/182183 2368 element.setAttribute( 'type', 'button' ); 2369 element.setAttribute( 'aria-label', label ); 2370 // init as disabled 2371 this.disable(); 2372 // create arrow 2373 let svg = this.createSVG( label, arrowShape ); 2374 element.append( svg ); 2375 }; 2376 2377 PrevNextButton.prototype.createSVG = function( label, arrowShape ) { 2378 let svg = document.createElementNS( svgURI, 'svg' ); 2379 svg.setAttribute( 'class', 'flickity-button-icon' ); 2380 svg.setAttribute( 'viewBox', '0 0 100 100' ); 2381 // add title #1189 2382 let title = document.createElementNS( svgURI, 'title' ); 2383 title.append( label ); 2384 // add path 2385 let path = document.createElementNS( svgURI, 'path' ); 2386 let pathMovements = getArrowMovements( arrowShape ); 2387 path.setAttribute( 'd', pathMovements ); 2388 path.setAttribute( 'class', 'arrow' ); 2389 // rotate arrow 2390 if ( !this.isLeft ) { 2391 path.setAttribute( 'transform', 'translate(100, 100) rotate(180)' ); 2392 } 2393 svg.append( title, path ); 2394 return svg; 2395 }; 2396 2397 // get SVG path movmement 2398 function getArrowMovements( shape ) { 2399 // use shape as movement if string 2400 if ( typeof shape == 'string' ) return shape; 2401 2402 let { x0, x1, x2, x3, y1, y2 } = shape; 2403 2404 // create movement string 2405 return `M ${x0}, 50 2406 L ${x1}, ${y1 + 50} 2407 L ${x2}, ${y2 + 50} 2408 L ${x3}, 50 2409 L ${x2}, ${50 - y2} 2410 L ${x1}, ${50 - y1} 2411 Z`; 2412 } 2413 2414 // ----- ----- // 2415 2416 PrevNextButton.prototype.enable = function() { 2417 this.element.removeAttribute('disabled'); 2418 }; 2419 2420 PrevNextButton.prototype.disable = function() { 2421 this.element.setAttribute( 'disabled', true ); 2422 }; 2423 2424 // -------------------------- Flickity prototype -------------------------- // 2425 2426 Object.assign( Flickity.defaults, { 2427 prevNextButtons: true, 2428 arrowShape: { 2429 x0: 10, 2430 x1: 60, y1: 50, 2431 x2: 70, y2: 40, 2432 x3: 30, 2433 }, 2434 } ); 2435 2436 Flickity.create.prevNextButtons = function() { 2437 if ( !this.options.prevNextButtons ) return; 2438 2439 let { rightToLeft, arrowShape } = this.options; 2440 let prevDirection = rightToLeft ? 'right' : 'left'; 2441 let nextDirection = rightToLeft ? 'left' : 'right'; 2442 this.prevButton = new PrevNextButton( 'previous', prevDirection, arrowShape ); 2443 this.nextButton = new PrevNextButton( 'next', nextDirection, arrowShape ); 2444 this.focusableElems.push( this.prevButton.element ); 2445 this.focusableElems.push( this.nextButton.element ); 2446 2447 this.handlePrevButtonClick = () => { 2448 this.uiChange(); 2449 this.previous(); 2450 }; 2451 2452 this.handleNextButtonClick = () => { 2453 this.uiChange(); 2454 this.next(); 2455 }; 2456 2457 this.on( 'activate', this.activatePrevNextButtons ); 2458 this.on( 'select', this.updatePrevNextButtons ); 2459 }; 2460 2461 let proto = Flickity.prototype; 2462 2463 proto.updatePrevNextButtons = function() { 2464 let lastIndex = this.slides.length ? this.slides.length - 1 : 0; 2465 this.updatePrevNextButton( this.prevButton, 0 ); 2466 this.updatePrevNextButton( this.nextButton, lastIndex ); 2467 }; 2468 2469 proto.updatePrevNextButton = function( button, disabledIndex ) { 2470 // enable is wrapAround and at least 2 slides 2471 if ( this.isWrapping && this.slides.length > 1 ) { 2472 button.enable(); 2473 return; 2474 } 2475 2476 let isEnabled = this.selectedIndex !== disabledIndex; 2477 button[ isEnabled ? 'enable' : 'disable' ](); 2478 // if disabling button that is focused, 2479 // shift focus to element to maintain keyboard accessibility 2480 let isDisabledFocused = !isEnabled && document.activeElement === button.element; 2481 if ( isDisabledFocused ) this.focus(); 2482 }; 2483 2484 proto.activatePrevNextButtons = function() { 2485 this.prevButton.element.addEventListener( 'click', this.handlePrevButtonClick ); 2486 this.nextButton.element.addEventListener( 'click', this.handleNextButtonClick ); 2487 this.element.append( this.prevButton.element, this.nextButton.element ); 2488 this.on( 'deactivate', this.deactivatePrevNextButtons ); 2489 }; 2490 2491 proto.deactivatePrevNextButtons = function() { 2492 this.prevButton.element.remove(); 2493 this.nextButton.element.remove(); 2494 this.prevButton.element.removeEventListener( 'click', this.handlePrevButtonClick ); 2495 this.nextButton.element.removeEventListener( 'click', this.handleNextButtonClick ); 2496 this.off( 'deactivate', this.deactivatePrevNextButtons ); 2497 }; 2498 2499 // -------------------------- -------------------------- // 2500 2501 Flickity.PrevNextButton = PrevNextButton; 2502 2503 return Flickity; 2504 2505 } ) ); 2506 } (prevNextButton)); 2507 return prevNextButton.exports; 2508} 2509 2510var pageDots = {exports: {}}; 2511 2512var hasRequiredPageDots; 2513 2514function requirePageDots () { 2515 if (hasRequiredPageDots) return pageDots.exports; 2516 hasRequiredPageDots = 1; 2517 (function (module) { 2518 // page dots 2519 ( function( window, factory ) { 2520 // universal module definition 2521 if ( module.exports ) { 2522 // CommonJS 2523 module.exports = factory( 2524 requireCore(), 2525 requireUtils(), 2526 ); 2527 } else { 2528 // browser global 2529 factory( 2530 window.Flickity, 2531 window.fizzyUIUtils, 2532 ); 2533 } 2534 2535 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( Flickity, utils ) { 2536 2537 // -------------------------- PageDots -------------------------- // 2538 2539 function PageDots() { 2540 // create holder element 2541 this.holder = document.createElement('div'); 2542 this.holder.className = 'flickity-page-dots'; 2543 // create dots, array of elements 2544 this.dots = []; 2545 } 2546 2547 PageDots.prototype.setDots = function( slidesLength ) { 2548 // get difference between number of slides and number of dots 2549 let delta = slidesLength - this.dots.length; 2550 if ( delta > 0 ) { 2551 this.addDots( delta ); 2552 } else if ( delta < 0 ) { 2553 this.removeDots( -delta ); 2554 } 2555 }; 2556 2557 PageDots.prototype.addDots = function( count ) { 2558 let newDots = new Array( count ).fill() 2559 .map( ( item, i ) => { 2560 let dot = document.createElement('button'); 2561 dot.setAttribute( 'type', 'button' ); 2562 let num = i + 1 + this.dots.length; 2563 dot.className = 'flickity-page-dot'; 2564 dot.textContent = `View slide ${num}`; 2565 return dot; 2566 } ); 2567 2568 this.holder.append( ...newDots ); 2569 this.dots = this.dots.concat( newDots ); 2570 }; 2571 2572 PageDots.prototype.removeDots = function( count ) { 2573 // remove from this.dots collection 2574 let removeDots = this.dots.splice( this.dots.length - count, count ); 2575 // remove from DOM 2576 removeDots.forEach( ( dot ) => dot.remove() ); 2577 }; 2578 2579 PageDots.prototype.updateSelected = function( index ) { 2580 // remove selected class on previous 2581 if ( this.selectedDot ) { 2582 this.selectedDot.classList.remove('is-selected'); 2583 this.selectedDot.removeAttribute('aria-current'); 2584 } 2585 // don't proceed if no dots 2586 if ( !this.dots.length ) return; 2587 2588 this.selectedDot = this.dots[ index ]; 2589 this.selectedDot.classList.add('is-selected'); 2590 this.selectedDot.setAttribute( 'aria-current', 'step' ); 2591 }; 2592 2593 Flickity.PageDots = PageDots; 2594 2595 // -------------------------- Flickity -------------------------- // 2596 2597 Object.assign( Flickity.defaults, { 2598 pageDots: true, 2599 } ); 2600 2601 Flickity.create.pageDots = function() { 2602 if ( !this.options.pageDots ) return; 2603 2604 this.pageDots = new PageDots(); 2605 this.handlePageDotsClick = this.onPageDotsClick.bind( this ); 2606 // events 2607 this.on( 'activate', this.activatePageDots ); 2608 this.on( 'select', this.updateSelectedPageDots ); 2609 this.on( 'cellChange', this.updatePageDots ); 2610 this.on( 'resize', this.updatePageDots ); 2611 this.on( 'deactivate', this.deactivatePageDots ); 2612 }; 2613 2614 let proto = Flickity.prototype; 2615 2616 proto.activatePageDots = function() { 2617 this.pageDots.setDots( this.slides.length ); 2618 this.focusableElems.push( ...this.pageDots.dots ); 2619 this.pageDots.holder.addEventListener( 'click', this.handlePageDotsClick ); 2620 this.element.append( this.pageDots.holder ); 2621 }; 2622 2623 proto.onPageDotsClick = function( event ) { 2624 let index = this.pageDots.dots.indexOf( event.target ); 2625 if ( index === -1 ) return; // only dot clicks 2626 2627 this.uiChange(); 2628 this.select( index ); 2629 }; 2630 2631 proto.updateSelectedPageDots = function() { 2632 this.pageDots.updateSelected( this.selectedIndex ); 2633 }; 2634 2635 proto.updatePageDots = function() { 2636 this.pageDots.dots.forEach( ( dot ) => { 2637 utils.removeFrom( this.focusableElems, dot ); 2638 } ); 2639 this.pageDots.setDots( this.slides.length ); 2640 this.focusableElems.push( ...this.pageDots.dots ); 2641 }; 2642 2643 proto.deactivatePageDots = function() { 2644 this.pageDots.holder.remove(); 2645 this.pageDots.holder.removeEventListener( 'click', this.handlePageDotsClick ); 2646 }; 2647 2648 // ----- ----- // 2649 2650 Flickity.PageDots = PageDots; 2651 2652 return Flickity; 2653 2654 } ) ); 2655 } (pageDots)); 2656 return pageDots.exports; 2657} 2658 2659var player = {exports: {}}; 2660 2661var hasRequiredPlayer; 2662 2663function requirePlayer () { 2664 if (hasRequiredPlayer) return player.exports; 2665 hasRequiredPlayer = 1; 2666 (function (module) { 2667 // player & autoPlay 2668 ( function( window, factory ) { 2669 // universal module definition 2670 if ( module.exports ) { 2671 // CommonJS 2672 module.exports = factory( requireCore() ); 2673 } else { 2674 // browser global 2675 factory( window.Flickity ); 2676 } 2677 2678 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( Flickity ) { 2679 2680 // -------------------------- Player -------------------------- // 2681 2682 function Player( autoPlay, onTick ) { 2683 this.autoPlay = autoPlay; 2684 this.onTick = onTick; 2685 this.state = 'stopped'; 2686 // visibility change event handler 2687 this.onVisibilityChange = this.visibilityChange.bind( this ); 2688 this.onVisibilityPlay = this.visibilityPlay.bind( this ); 2689 } 2690 2691 // start play 2692 Player.prototype.play = function() { 2693 if ( this.state === 'playing' ) return; 2694 2695 // do not play if page is hidden, start playing when page is visible 2696 let isPageHidden = document.hidden; 2697 if ( isPageHidden ) { 2698 document.addEventListener( 'visibilitychange', this.onVisibilityPlay ); 2699 return; 2700 } 2701 2702 this.state = 'playing'; 2703 // listen to visibility change 2704 document.addEventListener( 'visibilitychange', this.onVisibilityChange ); 2705 // start ticking 2706 this.tick(); 2707 }; 2708 2709 Player.prototype.tick = function() { 2710 // do not tick if not playing 2711 if ( this.state !== 'playing' ) return; 2712 2713 // default to 3 seconds 2714 let time = typeof this.autoPlay == 'number' ? this.autoPlay : 3000; 2715 // HACK: reset ticks if stopped and started within interval 2716 this.clear(); 2717 this.timeout = setTimeout( () => { 2718 this.onTick(); 2719 this.tick(); 2720 }, time ); 2721 }; 2722 2723 Player.prototype.stop = function() { 2724 this.state = 'stopped'; 2725 this.clear(); 2726 // remove visibility change event 2727 document.removeEventListener( 'visibilitychange', this.onVisibilityChange ); 2728 }; 2729 2730 Player.prototype.clear = function() { 2731 clearTimeout( this.timeout ); 2732 }; 2733 2734 Player.prototype.pause = function() { 2735 if ( this.state === 'playing' ) { 2736 this.state = 'paused'; 2737 this.clear(); 2738 } 2739 }; 2740 2741 Player.prototype.unpause = function() { 2742 // re-start play if paused 2743 if ( this.state === 'paused' ) this.play(); 2744 }; 2745 2746 // pause if page visibility is hidden, unpause if visible 2747 Player.prototype.visibilityChange = function() { 2748 let isPageHidden = document.hidden; 2749 this[ isPageHidden ? 'pause' : 'unpause' ](); 2750 }; 2751 2752 Player.prototype.visibilityPlay = function() { 2753 this.play(); 2754 document.removeEventListener( 'visibilitychange', this.onVisibilityPlay ); 2755 }; 2756 2757 // -------------------------- Flickity -------------------------- // 2758 2759 Object.assign( Flickity.defaults, { 2760 pauseAutoPlayOnHover: true, 2761 } ); 2762 2763 Flickity.create.player = function() { 2764 this.player = new Player( this.options.autoPlay, () => { 2765 this.next( true ); 2766 } ); 2767 2768 this.on( 'activate', this.activatePlayer ); 2769 this.on( 'uiChange', this.stopPlayer ); 2770 this.on( 'pointerDown', this.stopPlayer ); 2771 this.on( 'deactivate', this.deactivatePlayer ); 2772 }; 2773 2774 let proto = Flickity.prototype; 2775 2776 proto.activatePlayer = function() { 2777 if ( !this.options.autoPlay ) return; 2778 2779 this.player.play(); 2780 this.element.addEventListener( 'mouseenter', this ); 2781 }; 2782 2783 // Player API, don't hate the ... thanks I know where the door is 2784 2785 proto.playPlayer = function() { 2786 this.player.play(); 2787 }; 2788 2789 proto.stopPlayer = function() { 2790 this.player.stop(); 2791 }; 2792 2793 proto.pausePlayer = function() { 2794 this.player.pause(); 2795 }; 2796 2797 proto.unpausePlayer = function() { 2798 this.player.unpause(); 2799 }; 2800 2801 proto.deactivatePlayer = function() { 2802 this.player.stop(); 2803 this.element.removeEventListener( 'mouseenter', this ); 2804 }; 2805 2806 // ----- mouseenter/leave ----- // 2807 2808 // pause auto-play on hover 2809 proto.onmouseenter = function() { 2810 if ( !this.options.pauseAutoPlayOnHover ) return; 2811 2812 this.player.pause(); 2813 this.element.addEventListener( 'mouseleave', this ); 2814 }; 2815 2816 // resume auto-play on hover off 2817 proto.onmouseleave = function() { 2818 this.player.unpause(); 2819 this.element.removeEventListener( 'mouseleave', this ); 2820 }; 2821 2822 // ----- ----- // 2823 2824 Flickity.Player = Player; 2825 2826 return Flickity; 2827 2828 } ) ); 2829 } (player)); 2830 return player.exports; 2831} 2832 2833var addRemoveCell = {exports: {}}; 2834 2835var hasRequiredAddRemoveCell; 2836 2837function requireAddRemoveCell () { 2838 if (hasRequiredAddRemoveCell) return addRemoveCell.exports; 2839 hasRequiredAddRemoveCell = 1; 2840 (function (module) { 2841 // add, remove cell 2842 ( function( window, factory ) { 2843 // universal module definition 2844 if ( module.exports ) { 2845 // CommonJS 2846 module.exports = factory( 2847 requireCore(), 2848 requireUtils(), 2849 ); 2850 } else { 2851 // browser global 2852 factory( 2853 window.Flickity, 2854 window.fizzyUIUtils, 2855 ); 2856 } 2857 2858 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( Flickity, utils ) { 2859 2860 // append cells to a document fragment 2861 function getCellsFragment( cells ) { 2862 let fragment = document.createDocumentFragment(); 2863 cells.forEach( ( cell ) => fragment.appendChild( cell.element ) ); 2864 return fragment; 2865 } 2866 2867 // -------------------------- add/remove cell prototype -------------------------- // 2868 2869 let proto = Flickity.prototype; 2870 2871 /** 2872 * Insert, prepend, or append cells 2873 * @param {[Element, Array, NodeList]} elems - Elements to insert 2874 * @param {Integer} index - Zero-based number to insert 2875 */ 2876 proto.insert = function( elems, index ) { 2877 let cells = this._makeCells( elems ); 2878 if ( !cells || !cells.length ) return; 2879 2880 let len = this.cells.length; 2881 // default to append 2882 index = index === undefined ? len : index; 2883 // add cells with document fragment 2884 let fragment = getCellsFragment( cells ); 2885 // append to slider 2886 let isAppend = index === len; 2887 if ( isAppend ) { 2888 this.slider.appendChild( fragment ); 2889 } else { 2890 let insertCellElement = this.cells[ index ].element; 2891 this.slider.insertBefore( fragment, insertCellElement ); 2892 } 2893 // add to this.cells 2894 if ( index === 0 ) { 2895 // prepend, add to start 2896 this.cells = cells.concat( this.cells ); 2897 } else if ( isAppend ) { 2898 // append, add to end 2899 this.cells = this.cells.concat( cells ); 2900 } else { 2901 // insert in this.cells 2902 let endCells = this.cells.splice( index, len - index ); 2903 this.cells = this.cells.concat( cells ).concat( endCells ); 2904 } 2905 2906 this._sizeCells( cells ); 2907 this.cellChange( index ); 2908 this.positionSliderAtSelected(); 2909 }; 2910 2911 proto.append = function( elems ) { 2912 this.insert( elems, this.cells.length ); 2913 }; 2914 2915 proto.prepend = function( elems ) { 2916 this.insert( elems, 0 ); 2917 }; 2918 2919 /** 2920 * Remove cells 2921 * @param {[Element, Array, NodeList]} elems - ELements to remove 2922 */ 2923 proto.remove = function( elems ) { 2924 let cells = this.getCells( elems ); 2925 if ( !cells || !cells.length ) return; 2926 2927 let minCellIndex = this.cells.length - 1; 2928 // remove cells from collection & DOM 2929 cells.forEach( ( cell ) => { 2930 cell.remove(); 2931 let index = this.cells.indexOf( cell ); 2932 minCellIndex = Math.min( index, minCellIndex ); 2933 utils.removeFrom( this.cells, cell ); 2934 } ); 2935 2936 this.cellChange( minCellIndex ); 2937 this.positionSliderAtSelected(); 2938 }; 2939 2940 /** 2941 * logic to be run after a cell's size changes 2942 * @param {Element} elem - cell's element 2943 */ 2944 proto.cellSizeChange = function( elem ) { 2945 let cell = this.getCell( elem ); 2946 if ( !cell ) return; 2947 2948 cell.getSize(); 2949 2950 let index = this.cells.indexOf( cell ); 2951 this.cellChange( index ); 2952 // do not position slider after lazy load 2953 }; 2954 2955 /** 2956 * logic any time a cell is changed: added, removed, or size changed 2957 * @param {Integer} changedCellIndex - index of the changed cell, optional 2958 */ 2959 proto.cellChange = function( changedCellIndex ) { 2960 let prevSelectedElem = this.selectedElement; 2961 this._positionCells( changedCellIndex ); 2962 this._updateWrapShiftCells(); 2963 this.setGallerySize(); 2964 // update selectedIndex, try to maintain position & select previous selected element 2965 let cell = this.getCell( prevSelectedElem ); 2966 if ( cell ) this.selectedIndex = this.getCellSlideIndex( cell ); 2967 this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex ); 2968 2969 this.emitEvent( 'cellChange', [ changedCellIndex ] ); 2970 // position slider 2971 this.select( this.selectedIndex ); 2972 }; 2973 2974 // ----- ----- // 2975 2976 return Flickity; 2977 2978 } ) ); 2979 } (addRemoveCell)); 2980 return addRemoveCell.exports; 2981} 2982 2983var lazyload = {exports: {}}; 2984 2985var hasRequiredLazyload; 2986 2987function requireLazyload () { 2988 if (hasRequiredLazyload) return lazyload.exports; 2989 hasRequiredLazyload = 1; 2990 (function (module) { 2991 // lazyload 2992 ( function( window, factory ) { 2993 // universal module definition 2994 if ( module.exports ) { 2995 // CommonJS 2996 module.exports = factory( 2997 requireCore(), 2998 requireUtils(), 2999 ); 3000 } else { 3001 // browser global 3002 factory( 3003 window.Flickity, 3004 window.fizzyUIUtils, 3005 ); 3006 } 3007 3008 }( typeof window != 'undefined' ? window : commonjsGlobal, function factory( Flickity, utils ) { 3009 3010 const lazyAttr = 'data-flickity-lazyload'; 3011 const lazySrcAttr = `${lazyAttr}-src`; 3012 const lazySrcsetAttr = `${lazyAttr}-srcset`; 3013 const imgSelector = `img[${lazyAttr}], img[${lazySrcAttr}], ` + 3014 `img[${lazySrcsetAttr}], source[${lazySrcsetAttr}]`; 3015 3016 Flickity.create.lazyLoad = function() { 3017 this.on( 'select', this.lazyLoad ); 3018 3019 this.handleLazyLoadComplete = this.onLazyLoadComplete.bind( this ); 3020 }; 3021 3022 let proto = Flickity.prototype; 3023 3024 proto.lazyLoad = function() { 3025 let { lazyLoad } = this.options; 3026 if ( !lazyLoad ) return; 3027 3028 // get adjacent cells, use lazyLoad option for adjacent count 3029 let adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0; 3030 // lazy load images 3031 this.getAdjacentCellElements( adjCount ) 3032 .map( getCellLazyImages ) 3033 .flat() 3034 .forEach( ( img ) => new LazyLoader( img, this.handleLazyLoadComplete ) ); 3035 }; 3036 3037 function getCellLazyImages( cellElem ) { 3038 // check if cell element is lazy image 3039 if ( cellElem.matches('img') ) { 3040 let cellAttr = cellElem.getAttribute( lazyAttr ); 3041 let cellSrcAttr = cellElem.getAttribute( lazySrcAttr ); 3042 let cellSrcsetAttr = cellElem.getAttribute( lazySrcsetAttr ); 3043 if ( cellAttr || cellSrcAttr || cellSrcsetAttr ) { 3044 return cellElem; 3045 } 3046 } 3047 // select lazy images in cell 3048 return [ ...cellElem.querySelectorAll( imgSelector ) ]; 3049 } 3050 3051 proto.onLazyLoadComplete = function( img, event ) { 3052 let cell = this.getParentCell( img ); 3053 let cellElem = cell && cell.element; 3054 this.cellSizeChange( cellElem ); 3055 3056 this.dispatchEvent( 'lazyLoad', event, cellElem ); 3057 }; 3058 3059 // -------------------------- LazyLoader -------------------------- // 3060 3061 /** 3062 * class to handle loading images 3063 * @param {Image} img - Image element 3064 * @param {Function} onComplete - callback function 3065 */ 3066 function LazyLoader( img, onComplete ) { 3067 this.img = img; 3068 this.onComplete = onComplete; 3069 this.load(); 3070 } 3071 3072 LazyLoader.prototype.handleEvent = utils.handleEvent; 3073 3074 LazyLoader.prototype.load = function() { 3075 this.img.addEventListener( 'load', this ); 3076 this.img.addEventListener( 'error', this ); 3077 // get src & srcset 3078 let src = this.img.getAttribute( lazyAttr ) || 3079 this.img.getAttribute( lazySrcAttr ); 3080 let srcset = this.img.getAttribute( lazySrcsetAttr ); 3081 // set src & serset 3082 this.img.src = src; 3083 if ( srcset ) this.img.setAttribute( 'srcset', srcset ); 3084 // remove attr 3085 this.img.removeAttribute( lazyAttr ); 3086 this.img.removeAttribute( lazySrcAttr ); 3087 this.img.removeAttribute( lazySrcsetAttr ); 3088 }; 3089 3090 LazyLoader.prototype.onload = function( event ) { 3091 this.complete( event, 'flickity-lazyloaded' ); 3092 }; 3093 3094 LazyLoader.prototype.onerror = function( event ) { 3095 this.complete( event, 'flickity-lazyerror' ); 3096 }; 3097 3098 LazyLoader.prototype.complete = function( event, className ) { 3099 // unbind events 3100 this.img.removeEventListener( 'load', this ); 3101 this.img.removeEventListener( 'error', this ); 3102 let mediaElem = this.img.parentNode.matches('picture') ? this.img.parentNode : this.img; 3103 mediaElem.classList.add( className ); 3104 3105 this.onComplete( this.img, event ); 3106 }; 3107 3108 // ----- ----- // 3109 3110 Flickity.LazyLoader = LazyLoader; 3111 3112 return Flickity; 3113 3114 } ) ); 3115 } (lazyload)); 3116 return lazyload.exports; 3117} 3118 3119var imagesloaded$1 = {exports: {}}; 3120 3121var imagesloaded = {exports: {}}; 3122 3123/*! 3124 * imagesLoaded v5.0.0 3125 * JavaScript is all like "You images are done yet or what?" 3126 * MIT License 3127 */ 3128 3129var hasRequiredImagesloaded$1; 3130 3131function requireImagesloaded$1 () { 3132 if (hasRequiredImagesloaded$1) return imagesloaded.exports; 3133 hasRequiredImagesloaded$1 = 1; 3134 (function (module) { 3135 ( function( window, factory ) { 3136 // universal module definition 3137 if ( module.exports ) { 3138 // CommonJS 3139 module.exports = factory( window, requireEvEmitter() ); 3140 } else { 3141 // browser global 3142 window.imagesLoaded = factory( window, window.EvEmitter ); 3143 } 3144 3145 } )( typeof window !== 'undefined' ? window : commonjsGlobal, 3146 function factory( window, EvEmitter ) { 3147 3148 let $ = window.jQuery; 3149 let console = window.console; 3150 3151 // -------------------------- helpers -------------------------- // 3152 3153 // turn element or nodeList into an array 3154 function makeArray( obj ) { 3155 // use object if already an array 3156 if ( Array.isArray( obj ) ) return obj; 3157 3158 let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 3159 // convert nodeList to array 3160 if ( isArrayLike ) return [ ...obj ]; 3161 3162 // array of single index 3163 return [ obj ]; 3164 } 3165 3166 // -------------------------- imagesLoaded -------------------------- // 3167 3168 /** 3169 * @param {[Array, Element, NodeList, String]} elem 3170 * @param {[Object, Function]} options - if function, use as callback 3171 * @param {Function} onAlways - callback function 3172 * @returns {ImagesLoaded} 3173 */ 3174 function ImagesLoaded( elem, options, onAlways ) { 3175 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 3176 if ( !( this instanceof ImagesLoaded ) ) { 3177 return new ImagesLoaded( elem, options, onAlways ); 3178 } 3179 // use elem as selector string 3180 let queryElem = elem; 3181 if ( typeof elem == 'string' ) { 3182 queryElem = document.querySelectorAll( elem ); 3183 } 3184 // bail if bad element 3185 if ( !queryElem ) { 3186 console.error(`Bad element for imagesLoaded ${queryElem || elem}`); 3187 return; 3188 } 3189 3190 this.elements = makeArray( queryElem ); 3191 this.options = {}; 3192 // shift arguments if no options set 3193 if ( typeof options == 'function' ) { 3194 onAlways = options; 3195 } else { 3196 Object.assign( this.options, options ); 3197 } 3198 3199 if ( onAlways ) this.on( 'always', onAlways ); 3200 3201 this.getImages(); 3202 // add jQuery Deferred object 3203 if ( $ ) this.jqDeferred = new $.Deferred(); 3204 3205 // HACK check async to allow time to bind listeners 3206 setTimeout( this.check.bind( this ) ); 3207 } 3208 3209 ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 3210 3211 ImagesLoaded.prototype.getImages = function() { 3212 this.images = []; 3213 3214 // filter & find items if we have an item selector 3215 this.elements.forEach( this.addElementImages, this ); 3216 }; 3217 3218 const elementNodeTypes = [ 1, 9, 11 ]; 3219 3220 /** 3221 * @param {Node} elem 3222 */ 3223 ImagesLoaded.prototype.addElementImages = function( elem ) { 3224 // filter siblings 3225 if ( elem.nodeName === 'IMG' ) { 3226 this.addImage( elem ); 3227 } 3228 // get background image on element 3229 if ( this.options.background === true ) { 3230 this.addElementBackgroundImages( elem ); 3231 } 3232 3233 // find children 3234 // no non-element nodes, #143 3235 let { nodeType } = elem; 3236 if ( !nodeType || !elementNodeTypes.includes( nodeType ) ) return; 3237 3238 let childImgs = elem.querySelectorAll('img'); 3239 // concat childElems to filterFound array 3240 for ( let img of childImgs ) { 3241 this.addImage( img ); 3242 } 3243 3244 // get child background images 3245 if ( typeof this.options.background == 'string' ) { 3246 let children = elem.querySelectorAll( this.options.background ); 3247 for ( let child of children ) { 3248 this.addElementBackgroundImages( child ); 3249 } 3250 } 3251 }; 3252 3253 const reURL = /url\((['"])?(.*?)\1\)/gi; 3254 3255 ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 3256 let style = getComputedStyle( elem ); 3257 // Firefox returns null if in a hidden iframe https://bugzil.la/548397 3258 if ( !style ) return; 3259 3260 // get url inside url("...") 3261 let matches = reURL.exec( style.backgroundImage ); 3262 while ( matches !== null ) { 3263 let url = matches && matches[2]; 3264 if ( url ) { 3265 this.addBackground( url, elem ); 3266 } 3267 matches = reURL.exec( style.backgroundImage ); 3268 } 3269 }; 3270 3271 /** 3272 * @param {Image} img 3273 */ 3274 ImagesLoaded.prototype.addImage = function( img ) { 3275 let loadingImage = new LoadingImage( img ); 3276 this.images.push( loadingImage ); 3277 }; 3278 3279 ImagesLoaded.prototype.addBackground = function( url, elem ) { 3280 let background = new Background( url, elem ); 3281 this.images.push( background ); 3282 }; 3283 3284 ImagesLoaded.prototype.check = function() { 3285 this.progressedCount = 0; 3286 this.hasAnyBroken = false; 3287 // complete if no images 3288 if ( !this.images.length ) { 3289 this.complete(); 3290 return; 3291 } 3292 3293 /* eslint-disable-next-line func-style */ 3294 let onProgress = ( image, elem, message ) => { 3295 // HACK - Chrome triggers event before object properties have changed. #83 3296 setTimeout( () => { 3297 this.progress( image, elem, message ); 3298 } ); 3299 }; 3300 3301 this.images.forEach( function( loadingImage ) { 3302 loadingImage.once( 'progress', onProgress ); 3303 loadingImage.check(); 3304 } ); 3305 }; 3306 3307 ImagesLoaded.prototype.progress = function( image, elem, message ) { 3308 this.progressedCount++; 3309 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 3310 // progress event 3311 this.emitEvent( 'progress', [ this, image, elem ] ); 3312 if ( this.jqDeferred && this.jqDeferred.notify ) { 3313 this.jqDeferred.notify( this, image ); 3314 } 3315 // check if completed 3316 if ( this.progressedCount === this.images.length ) { 3317 this.complete(); 3318 } 3319 3320 if ( this.options.debug && console ) { 3321 console.log( `progress: ${message}`, image, elem ); 3322 } 3323 }; 3324 3325 ImagesLoaded.prototype.complete = function() { 3326 let eventName = this.hasAnyBroken ? 'fail' : 'done'; 3327 this.isComplete = true; 3328 this.emitEvent( eventName, [ this ] ); 3329 this.emitEvent( 'always', [ this ] ); 3330 if ( this.jqDeferred ) { 3331 let jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 3332 this.jqDeferred[ jqMethod ]( this ); 3333 } 3334 }; 3335 3336 // -------------------------- -------------------------- // 3337 3338 function LoadingImage( img ) { 3339 this.img = img; 3340 } 3341 3342 LoadingImage.prototype = Object.create( EvEmitter.prototype ); 3343 3344 LoadingImage.prototype.check = function() { 3345 // If complete is true and browser supports natural sizes, 3346 // try to check for image status manually. 3347 let isComplete = this.getIsImageComplete(); 3348 if ( isComplete ) { 3349 // report based on naturalWidth 3350 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 3351 return; 3352 } 3353 3354 // If none of the checks above matched, simulate loading on detached element. 3355 this.proxyImage = new Image(); 3356 // add crossOrigin attribute. #204 3357 if ( this.img.crossOrigin ) { 3358 this.proxyImage.crossOrigin = this.img.crossOrigin; 3359 } 3360 this.proxyImage.addEventListener( 'load', this ); 3361 this.proxyImage.addEventListener( 'error', this ); 3362 // bind to image as well for Firefox. #191 3363 this.img.addEventListener( 'load', this ); 3364 this.img.addEventListener( 'error', this ); 3365 this.proxyImage.src = this.img.currentSrc || this.img.src; 3366 }; 3367 3368 LoadingImage.prototype.getIsImageComplete = function() {
3369 // check for non-zero, non-undefined naturalWidth 3370 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 3371 return this.img.complete && this.img.naturalWidth; 3372 }; 3373 3374 LoadingImage.prototype.confirm = function( isLoaded, message ) { 3375 this.isLoaded = isLoaded; 3376 let { parentNode } = this.img; 3377 // emit progress with parent <picture> or self <img> 3378 let elem = parentNode.nodeName === 'PICTURE' ? parentNode : this.img; 3379 this.emitEvent( 'progress', [ this, elem, message ] ); 3380 }; 3381 3382 // ----- events ----- // 3383 3384 // trigger specified handler for event type 3385 LoadingImage.prototype.handleEvent = function( event ) { 3386 let method = 'on' + event.type; 3387 if ( this[ method ] ) { 3388 this[ method ]( event ); 3389 } 3390 }; 3391 3392 LoadingImage.prototype.onload = function() { 3393 this.confirm( true, 'onload' ); 3394 this.unbindEvents(); 3395 }; 3396 3397 LoadingImage.prototype.onerror = function() { 3398 this.confirm( false, 'onerror' ); 3399 this.unbindEvents(); 3400 }; 3401 3402 LoadingImage.prototype.unbindEvents = function() { 3403 this.proxyImage.removeEventListener( 'load', this ); 3404 this.proxyImage.removeEventListener( 'error', this ); 3405 this.img.removeEventListener( 'load', this ); 3406 this.img.removeEventListener( 'error', this ); 3407 }; 3408 3409 // -------------------------- Background -------------------------- // 3410 3411 function Background( url, element ) { 3412 this.url = url; 3413 this.element = element; 3414 this.img = new Image(); 3415 } 3416 3417 // inherit LoadingImage prototype 3418 Background.prototype = Object.create( LoadingImage.prototype ); 3419 3420 Background.prototype.check = function() { 3421 this.img.addEventListener( 'load', this ); 3422 this.img.addEventListener( 'error', this ); 3423 this.img.src = this.url; 3424 // check if image is already complete 3425 let isComplete = this.getIsImageComplete(); 3426 if ( isComplete ) { 3427 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 3428 this.unbindEvents(); 3429 } 3430 }; 3431 3432 Background.prototype.unbindEvents = function() { 3433 this.img.removeEventListener( 'load', this ); 3434 this.img.removeEventListener( 'error', this ); 3435 }; 3436 3437 Background.prototype.confirm = function( isLoaded, message ) { 3438 this.isLoaded = isLoaded; 3439 this.emitEvent( 'progress', [ this, this.element, message ] ); 3440 }; 3441 3442 // -------------------------- jQuery -------------------------- // 3443 3444 ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 3445 jQuery = jQuery || window.jQuery; 3446 if ( !jQuery ) return; 3447 3448 // set local variable 3449 $ = jQuery; 3450 // $().imagesLoaded() 3451 $.fn.imagesLoaded = function( options, onAlways ) { 3452 let instance = new ImagesLoaded( this, options, onAlways ); 3453 return instance.jqDeferred.promise( $( this ) ); 3454 }; 3455 }; 3456 // try making plugin 3457 ImagesLoaded.makeJQueryPlugin(); 3458 3459 // -------------------------- -------------------------- // 3460 3461 return ImagesLoaded; 3462 3463 } ); 3464 } (imagesloaded)); 3465 return imagesloaded.exports; 3466} 3467 3468var hasRequiredImagesloaded; 3469 3470function requireImagesloaded () { 3471 if (hasRequiredImagesloaded) return imagesloaded$1.exports; 3472 hasRequiredImagesloaded = 1; 3473 (function (module) { 3474 // imagesloaded 3475 ( function( window, factory ) { 3476 // universal module definition 3477 if ( module.exports ) { 3478 // CommonJS 3479 module.exports = factory( 3480 requireCore(), 3481 requireImagesloaded$1(), 3482 ); 3483 } else { 3484 // browser global 3485 factory( 3486 window.Flickity, 3487 window.imagesLoaded, 3488 ); 3489 } 3490 3491 }( typeof window != 'undefined' ? window : commonjsGlobal, 3492 function factory( Flickity, imagesLoaded ) { 3493 3494 Flickity.create.imagesLoaded = function() { 3495 this.on( 'activate', this.imagesLoaded ); 3496 }; 3497 3498 Flickity.prototype.imagesLoaded = function() { 3499 if ( !this.options.imagesLoaded ) return; 3500 3501 let onImagesLoadedProgress = ( instance, image ) => { 3502 let cell = this.getParentCell( image.img ); 3503 this.cellSizeChange( cell && cell.element ); 3504 if ( !this.options.freeScroll ) this.positionSliderAtSelected(); 3505 }; 3506 imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress ); 3507 }; 3508 3509 return Flickity; 3510 3511 } ) ); 3512 } (imagesloaded$1)); 3513 return imagesloaded$1.exports; 3514} 3515 3516/*! 3517 * Flickity v3.0.0 3518 * Touch, responsive, flickable carousels 3519 * 3520 * Licensed GPLv3 for open source use 3521 * or Flickity Commercial License for commercial use 3522 * 3523 * https://flickity.metafizzy.co 3524 * Copyright 2015-2022 Metafizzy 3525 */ 3526 3527(function (module) { 3528 if ( module.exports ) { 3529 const Flickity = requireCore(); 3530 requireDrag(); 3531 requirePrevNextButton(); 3532 requirePageDots(); 3533 requirePlayer();
3534 requireAddRemoveCell(); 3535 requireLazyload(); 3536 requireImagesloaded(); 3537 3538 module.exports = Flickity; 3539 } 3540} (js)); 3541 3542var jsExports = js.exports; 3543const Flickity = /*@__PURE__*/getDefaultExportFromCjs(jsExports); 3544 3545var slider = document.querySelectorAll(".ImageCarousel"); 3546slider.forEach((element) => { 3547 var carousel = element.querySelector(".slider"); 3548 var flkty = new Flickity(carousel, { 3549 cellSelector: ".ImageCarousel__slide", 3550 pageDots: false, 3551 prevNextButtons: true, 3552 groupCells: true, 3553 wrapAround: true, 3554 selectedAttraction: 0.01, 3555 accessibility: false, 3556 cellAlign: "left" 3557 }); 3558 const slides = carousel.querySelectorAll(".ImageCarousel__slide"); 3559 slides.forEach((slide, index) => { 3560 slide.setAttribute("data-index", index + 1); 3561 }); 3562 var carouselStatus = element.querySelector(".flickity-status"); 3563 function updateStatus() { 3564 var slideNumber = flkty.selectedIndex + 1; 3565 var totalSlides = flkty.slides.length; 3566 var formattedSlideNumber = slideNumber < 10 ? slideNumber : slideNumber; 3567 var formattedTotalSlides = totalSlides < 10 ? totalSlides : totalSlides; 3568 carouselStatus.innerHTML = formattedSlideNumber + "<span>/</span>" + formattedTotalSlides; 3569 } 3570 flkty.resize; 3571 flkty.on("change", function(index) { 3572 var activeSlides = carousel.querySelectorAll(".is-selected"); 3573 const links = carousel.querySelectorAll("a[tabindex]"); 3574 if (links !== null) { 3575 for (const link of links) { 3576 link.setAttribute("tabindex", "-1"); 3577 } 3578 } 3579 for (const selected of activeSlides) { 3580 var activeLink = selected.querySelectorAll("a"); 3581 if (activeLink !== null) { 3582 for (const link of activeLink) { 3583 link.setAttribute("tabindex", "0"); 3584 } 3585 } 3586 } 3587 updateStatus(); 3588 }); 3589 window.addEventListener("load", function() { 3590 flkty.resize; 3591 window.dispatchEvent(new Event("resize")); 3592 var activeSlides = carousel.querySelectorAll(".is-selected"); 3593 const links = carousel.querySelectorAll("a[tabindex]"); 3594 if (links !== null) { 3595 for (const link of links) { 3596 link.setAttribute("tabindex", "-1"); 3597 } 3598 } 3599 for (const selected of activeSlides) { 3600 var activeLink = selected.querySelectorAll("a"); 3601 if (activeLink !== null) { 3602 for (const link of activeLink) { 3603 link.setAttribute("tabindex", "0"); 3604 } 3605 } 3606 } 3607 setTimeout(function() { 3608 carousel.classList.add("loaded"); 3609 }); 3610 }); 3611 window.addEventListener("resize", function() { 3612 if (carousel.classList.contains("flickity-enabled")) { 3613 updateStatus(); 3614 } 3615 carousel.classList.remove("loaded"); 3616 setTimeout(function() { 3617 carousel.classList.add("loaded"); 3618 }, 500); 3619 }); 3620 function updateNavStyles() { 3621 if (slides.length > 0 && carousel) { 3622 const firstSlide = slides[0]; 3623 const image = firstSlide.querySelector("img"); 3624 if (image) { 3625 const imageHeight = image.offsetHeight; 3626 carousel.style.setProperty("--nav", `${imageHeight}px`); 3627 } 3628 } 3629 } 3630 setTimeout(function() { 3631 updateNavStyles(); 3632 }, 500); 3633 window.addEventListener("resize", updateNavStyles); 3634}); 3635 3636const toggles = document.querySelectorAll(".Accordion__toggle"); 3637for (const toggle of toggles) { 3638 toggle.addEventListener("click", () => { 3639 const expanded = toggle.getAttribute("aria-expanded") === "true"; 3640 toggle.setAttribute("aria-expanded", (!expanded).toString()); 3641 }); 3642}
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.