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