vendor: 37,723 bytes, lines 1-1693
1/*! Magnific Popup - v1.1.0 - 2016-02-20 2* http://dimsemenov.com/plugins/magnific-popup/ 3* Copyright (c) 2016 Dmitry Semenov; */ 4;(function (factory) { 5if (typeof define === 'function' && define.amd) { 6 // AMD. Register as an anonymous module. 7 define(['jquery'], factory); 8 } else if (typeof exports === 'object') { 9 // Node/CommonJS 10 factory(require('jquery')); 11 } else { 12 // Browser globals 13 factory(window.jQuery || window.Zepto); 14 } 15 }(function($) { 16 17/*>>core*/ 18/** 19 * 20 * Magnific Popup Core JS file 21 * 22 */ 23 24 25/** 26 * Private static constants 27 */ 28var CLOSE_EVENT = 'Close', 29 BEFORE_CLOSE_EVENT = 'BeforeClose', 30 AFTER_CLOSE_EVENT = 'AfterClose', 31 BEFORE_APPEND_EVENT = 'BeforeAppend', 32 MARKUP_PARSE_EVENT = 'MarkupParse', 33 OPEN_EVENT = 'Open', 34 CHANGE_EVENT = 'Change', 35 NS = 'mfp', 36 EVENT_NS = '.' + NS, 37 READY_CLASS = 'mfp-ready', 38 REMOVING_CLASS = 'mfp-removing', 39 PREVENT_CLOSE_CLASS = 'mfp-prevent-close'; 40 41 42/** 43 * Private vars 44 */ 45/*jshint -W079 */ 46var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this' 47 MagnificPopup = function(){}, 48 _isJQ = !!(window.jQuery), 49 _prevStatus, 50 _window = $(window), 51 _document, 52 _prevContentType, 53 _wrapClasses, 54 _currPopupType; 55 56 57/** 58 * Private functions 59 */ 60var _mfpOn = function(name, f) { 61 mfp.ev.on(NS + name + EVENT_NS, f); 62 }, 63 _getEl = function(className, appendTo, html, raw) { 64 var el = document.createElement('div'); 65 el.className = 'mfp-'+className; 66 if(html) { 67 el.innerHTML = html; 68 } 69 if(!raw) { 70 el = $(el); 71 if(appendTo) { 72 el.appendTo(appendTo); 73 } 74 } else if(appendTo) { 75 appendTo.appendChild(el); 76 } 77 return el; 78 }, 79 _mfpTrigger = function(e, data) { 80 mfp.ev.triggerHandler(NS + e, data); 81 82 if(mfp.st.callbacks) { 83 // converts "mfpEventName" to "eventName" callback and triggers it if it's present 84 e = e.charAt(0).toLowerCase() + e.slice(1); 85 if(mfp.st.callbacks[e]) { 86 mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]); 87 } 88 } 89 }, 90 _getCloseBtn = function(type) { 91 if(type !== _currPopupType || !mfp.currTemplate.closeBtn) { 92 mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) ); 93 _currPopupType = type; 94 } 95 return mfp.currTemplate.closeBtn; 96 }, 97 // Initialize Magnific Popup only when called at least once 98 _checkInstance = function() { 99 if(!$.magnificPopup.instance) { 100 /*jshint -W020 */ 101 mfp = new MagnificPopup(); 102 mfp.init(); 103 $.magnificPopup.instance = mfp; 104 } 105 }, 106 // CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr 107 supportsTransitions = function() { 108 var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist 109 v = ['ms','O','Moz','Webkit']; // 'v' for vendor 110 111 if( s['transition'] !== undefined ) { 112 return true; 113 } 114 115 while( v.length ) { 116 if( v.pop() + 'Transition' in s ) { 117 return true; 118 } 119 } 120 121 return false; 122 }; 123 124 125 126/** 127 * Public functions 128 */ 129MagnificPopup.prototype = { 130 131 constructor: MagnificPopup, 132 133 /** 134 * Initializes Magnific Popup plugin. 135 * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed 136 */ 137 init: function() { 138 var appVersion = navigator.appVersion; 139 mfp.isLowIE = mfp.isIE8 = document.all && !document.addEventListener; 140 mfp.isAndroid = (/android/gi).test(appVersion); 141 mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion); 142 mfp.supportsTransition = supportsTransitions(); 143 144 // We disable fixed positioned lightbox on devices that don't handle it nicely. 145 // If you know a better way of detecting this - let me know. 146 mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) ); 147 _document = $(document); 148 149 mfp.popupsCache = {}; 150 }, 151 152 /** 153 * Opens popup 154 * @param data [description] 155 */ 156 open: function(data) { 157 158 var i; 159 160 if(data.isObj === false) { 161 // convert jQuery collection to array to avoid conflicts later 162 mfp.items = data.items.toArray(); 163 164 mfp.index = 0; 165 var items = data.items, 166 item; 167 for(i = 0; i < items.length; i++) { 168 item = items[i]; 169 if(item.parsed) { 170 item = item.el[0]; 171 } 172 if(item === data.el[0]) { 173 mfp.index = i; 174 break; 175 } 176 } 177 } else { 178 mfp.items = $.isArray(data.items) ? data.items : [data.items]; 179 mfp.index = data.index || 0; 180 } 181 182 // if popup is already opened - we just update the content 183 if(mfp.isOpen) { 184 mfp.updateItemHTML(); 185 return; 186 } 187 188 mfp.types = []; 189 _wrapClasses = ''; 190 if(data.mainEl && data.mainEl.length) { 191 mfp.ev = data.mainEl.eq(0); 192 } else { 193 mfp.ev = _document; 194 } 195 196 if(data.key) { 197 if(!mfp.popupsCache[data.key]) { 198 mfp.popupsCache[data.key] = {}; 199 } 200 mfp.currTemplate = mfp.popupsCache[data.key]; 201 } else { 202 mfp.currTemplate = {}; 203 } 204 205 206 207 mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data ); 208 mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos; 209 210 if(mfp.st.modal) { 211 mfp.st.closeOnContentClick = false; 212 mfp.st.closeOnBgClick = false; 213 mfp.st.showCloseBtn = false; 214 mfp.st.enableEscapeKey = false; 215 } 216 217 218 // Building markup 219 // main containers are created only once 220 if(!mfp.bgOverlay) { 221 222 // Dark overlay 223 mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() { 224 mfp.close(); 225 }); 226 227 mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) { 228 if(mfp._checkIfClose(e.target)) { 229 mfp.close(); 230 } 231 }); 232 233 mfp.container = _getEl('container', mfp.wrap); 234 } 235 236 mfp.contentContainer = _getEl('content'); 237 if(mfp.st.preloader) { 238 mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading); 239 } 240 241 242 // Initializing modules 243 var modules = $.magnificPopup.modules; 244 for(i = 0; i < modules.length; i++) { 245 var n = modules[i]; 246 n = n.charAt(0).toUpperCase() + n.slice(1); 247 mfp['init'+n].call(mfp); 248 } 249 _mfpTrigger('BeforeOpen'); 250 251 252 if(mfp.st.showCloseBtn) { 253 // Close button 254 if(!mfp.st.closeBtnInside) { 255 mfp.wrap.append( _getCloseBtn() ); 256 } else { 257 _mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) { 258 values.close_replaceWith = _getCloseBtn(item.type); 259 }); 260 _wrapClasses += ' mfp-close-btn-in'; 261 } 262 } 263 264 if(mfp.st.alignTop) { 265 _wrapClasses += ' mfp-align-top'; 266 } 267 268 269 270 if(mfp.fixedContentPos) { 271 mfp.wrap.css({ 272 overflow: mfp.st.overflowY, 273 overflowX: 'hidden', 274 overflowY: mfp.st.overflowY 275 }); 276 } else { 277 mfp.wrap.css({ 278 top: _window.scrollTop(), 279 position: 'absolute' 280 }); 281 } 282 if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) { 283 mfp.bgOverlay.css({ 284 height: _document.height(), 285 position: 'absolute' 286 }); 287 } 288 289 290 291 if(mfp.st.enableEscapeKey) { 292 // Close on ESC key 293 _document.on('keyup' + EVENT_NS, function(e) { 294 if(e.keyCode === 27) { 295 mfp.close(); 296 } 297 }); 298 } 299 300 _window.on('resize' + EVENT_NS, function() { 301 mfp.updateSize(); 302 }); 303 304 305 if(!mfp.st.closeOnContentClick) { 306 _wrapClasses += ' mfp-auto-cursor'; 307 } 308 309 if(_wrapClasses) 310 mfp.wrap.addClass(_wrapClasses); 311 312 313 // this triggers recalculation of layout, so we get it once to not to trigger twice 314 var windowHeight = mfp.wH = _window.height(); 315 316 317 var windowStyles = {}; 318 319 if( mfp.fixedContentPos ) { 320 if(mfp._hasScrollBar(windowHeight)){ 321 var s = mfp._getScrollbarSize(); 322 if(s) { 323 windowStyles.marginRight = s; 324 } 325 } 326 } 327 328 if(mfp.fixedContentPos) { 329 if(!mfp.isIE7) { 330 windowStyles.overflow = 'hidden'; 331 } else { 332 // ie7 double-scroll bug 333 $('body, html').css('overflow', 'hidden'); 334 } 335 } 336 337 338 339 var classesToadd = mfp.st.mainClass; 340 if(mfp.isIE7) { 341 classesToadd += ' mfp-ie7'; 342 } 343 if(classesToadd) { 344 mfp._addClassToMFP( classesToadd ); 345 } 346 347 // add content 348 mfp.updateItemHTML(); 349 350 _mfpTrigger('BuildControls'); 351 352 // remove scrollbar, add margin e.t.c 353 $('html').css(windowStyles); 354 355 // add everything to DOM 356 mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || $(document.body) ); 357 358 // Save last focused element 359 mfp._lastFocusedEl = document.activeElement; 360 361 // Wait for next cycle to allow CSS transition 362 setTimeout(function() { 363 364 if(mfp.content) { 365 mfp._addClassToMFP(READY_CLASS); 366 mfp._setFocus(); 367 } else { 368 // if content is not defined (not loaded e.t.c) we add class only for BG 369 mfp.bgOverlay.addClass(READY_CLASS); 370 } 371 372 // Trap the focus in popup 373 _document.on('focusin' + EVENT_NS, mfp._onFocusIn); 374 375 }, 16); 376 377 mfp.isOpen = true; 378 mfp.updateSize(windowHeight); 379 _mfpTrigger(OPEN_EVENT); 380 381 return data; 382 }, 383 384 /** 385 * Closes the popup 386 */ 387 close: function() { 388 if(!mfp.isOpen) return; 389 _mfpTrigger(BEFORE_CLOSE_EVENT); 390 391 mfp.isOpen = false; 392 // for CSS3 animation 393 if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition ) { 394 mfp._addClassToMFP(REMOVING_CLASS); 395 setTimeout(function() { 396 mfp._close(); 397 }, mfp.st.removalDelay); 398 } else { 399 mfp._close(); 400 } 401 }, 402 403 /** 404 * Helper for close() function 405 */ 406 _close: function() { 407 _mfpTrigger(CLOSE_EVENT); 408 409 var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' '; 410 411 mfp.bgOverlay.detach(); 412 mfp.wrap.detach(); 413 mfp.container.empty(); 414 415 if(mfp.st.mainClass) { 416 classesToRemove += mfp.st.mainClass + ' '; 417 } 418 419 mfp._removeClassFromMFP(classesToRemove); 420 421 if(mfp.fixedContentPos) { 422 var windowStyles = {marginRight: ''}; 423 if(mfp.isIE7) { 424 $('body, html').css('overflow', ''); 425 } else { 426 windowStyles.overflow = ''; 427 } 428 $('html').css(windowStyles); 429 } 430 431 _document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS); 432 mfp.ev.off(EVENT_NS); 433 434 // clean up DOM elements that aren't removed 435 mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style'); 436 mfp.bgOverlay.attr('class', 'mfp-bg'); 437 mfp.container.attr('class', 'mfp-container'); 438 439 // remove close button from target element 440 if(mfp.st.showCloseBtn && 441 (!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) { 442 if(mfp.currTemplate.closeBtn) 443 mfp.currTemplate.closeBtn.detach(); 444 } 445 446 447 if(mfp.st.autoFocusLast && mfp._lastFocusedEl) { 448 $(mfp._lastFocusedEl).focus(); // put tab focus back 449 } 450 mfp.currItem = null; 451 mfp.content = null; 452 mfp.currTemplate = null; 453 mfp.prevHeight = 0; 454 455 _mfpTrigger(AFTER_CLOSE_EVENT); 456 }, 457 458 updateSize: function(winHeight) { 459 460 if(mfp.isIOS) { 461 // fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2 462 var zoomLevel = document.documentElement.clientWidth / window.innerWidth; 463 var height = window.innerHeight * zoomLevel; 464 mfp.wrap.css('height', height); 465 mfp.wH = height; 466 } else { 467 mfp.wH = winHeight || _window.height(); 468 } 469 // Fixes #84: popup incorrectly positioned with position:relative on body 470 if(!mfp.fixedContentPos) { 471 mfp.wrap.css('height', mfp.wH); 472 } 473 474 _mfpTrigger('Resize'); 475 476 }, 477 478 /** 479 * Set content of popup based on current index 480 */ 481 updateItemHTML: function() { 482 var item = mfp.items[mfp.index]; 483 484 // Detach and perform modifications 485 mfp.contentContainer.detach(); 486 487 if(mfp.content) 488 mfp.content.detach(); 489 490 if(!item.parsed) { 491 item = mfp.parseEl( mfp.index ); 492 } 493 494 var type = item.type; 495 496 _mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]); 497 // BeforeChange event works like so: 498 // _mfpOn('BeforeChange', function(e, prevType, newType) { }); 499 500 mfp.currItem = item; 501 502 if(!mfp.currTemplate[type]) { 503 var markup = mfp.st[type] ? mfp.st[type].markup : false; 504 505 // allows to modify markup 506 _mfpTrigger('FirstMarkupParse', markup); 507 508 if(markup) { 509 mfp.currTemplate[type] = $(markup); 510 } else { 511 // if there is no markup found we just define that template is parsed 512 mfp.currTemplate[type] = true; 513 } 514 } 515 516 if(_prevContentType && _prevContentType !== item.type) { 517 mfp.container.removeClass('mfp-'+_prevContentType+'-holder'); 518 } 519 520 var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]); 521 mfp.appendContent(newContent, type); 522 523 item.preloaded = true; 524 525 _mfpTrigger(CHANGE_EVENT, item); 526 _prevContentType = item.type; 527 528 // Append container back after its content changed 529 mfp.container.prepend(mfp.contentContainer); 530 531 _mfpTrigger('AfterChange'); 532 }, 533 534 535 /** 536 * Set HTML content of popup 537 */ 538 appendContent: function(newContent, type) { 539 mfp.content = newContent; 540 541 if(newContent) { 542 if(mfp.st.showCloseBtn && mfp.st.closeBtnInside && 543 mfp.currTemplate[type] === true) { 544 // if there is no markup, we just append close button element inside 545 if(!mfp.content.find('.mfp-close').length) { 546 mfp.content.append(_getCloseBtn()); 547 } 548 } else { 549 mfp.content = newContent; 550 } 551 } else { 552 mfp.content = ''; 553 } 554 555 _mfpTrigger(BEFORE_APPEND_EVENT); 556 mfp.container.addClass('mfp-'+type+'-holder'); 557 558 mfp.contentContainer.append(mfp.content); 559 }, 560 561 562 /** 563 * Creates Magnific Popup data object based on given data 564 * @param {int} index Index of item to parse 565 */ 566 parseEl: function(index) { 567 var item = mfp.items[index], 568 type; 569 570 if(item.tagName) { 571 item = { el: $(item) }; 572 } else { 573 type = item.type; 574 item = { data: item, src: item.src }; 575 } 576 577 if(item.el) { 578 var types = mfp.types; 579 580 // check for 'mfp-TYPE' class 581 for(var i = 0; i < types.length; i++) { 582 if( item.el.hasClass('mfp-'+types[i]) ) { 583 type = types[i]; 584 break; 585 } 586 } 587 588 item.src = item.el.attr('data-mfp-src'); 589 if(!item.src) { 590 item.src = item.el.attr('href'); 591 } 592 } 593 594 item.type = type || mfp.st.type || 'inline'; 595 item.index = index; 596 item.parsed = true; 597 mfp.items[index] = item; 598 _mfpTrigger('ElementParse', item); 599 600 return mfp.items[index]; 601 }, 602 603 604 /** 605 * Initializes single popup or a group of popups 606 */ 607 addGroup: function(el, options) { 608 var eHandler = function(e) { 609 e.mfpEl = this; 610 mfp._openClick(e, el, options); 611 }; 612 613 if(!options) { 614 options = {}; 615 } 616 617 var eName = 'click.magnificPopup'; 618 options.mainEl = el; 619 620 if(options.items) { 621 options.isObj = true; 622 el.off(eName).on(eName, eHandler); 623 } else { 624 options.isObj = false; 625 if(options.delegate) { 626 el.off(eName).on(eName, options.delegate , eHandler); 627 } else { 628 options.items = el; 629 el.off(eName).on(eName, eHandler); 630 } 631 } 632 }, 633 _openClick: function(e, el, options) { 634 var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick; 635 636 637 if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey ) ) { 638 return; 639 } 640 641 var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn; 642 643 if(disableOn) { 644 if($.isFunction(disableOn)) { 645 if( !disableOn.call(mfp) ) { 646 return true; 647 } 648 } else { // else it's number 649 if( _window.width() < disableOn ) { 650 return true; 651 } 652 } 653 } 654 655 if(e.type) { 656 e.preventDefault(); 657 658 // This will prevent popup from closing if element is inside and popup is already opened 659 if(mfp.isOpen) { 660 e.stopPropagation(); 661 } 662 } 663 664 options.el = $(e.mfpEl); 665 if(options.delegate) { 666 options.items = el.find(options.delegate); 667 } 668 mfp.open(options); 669 }, 670 671 672 /** 673 * Updates text on preloader 674 */ 675 updateStatus: function(status, text) { 676 677 if(mfp.preloader) { 678 if(_prevStatus !== status) { 679 mfp.container.removeClass('mfp-s-'+_prevStatus); 680 } 681 682 if(!text && status === 'loading') { 683 text = mfp.st.tLoading; 684 } 685 686 var data = { 687 status: status, 688 text: text 689 }; 690 // allows to modify status 691 _mfpTrigger('UpdateStatus', data); 692 693 status = data.status; 694 text = data.text; 695 696 mfp.preloader.html(text); 697 698 mfp.preloader.find('a').on('click', function(e) { 699 e.stopImmediatePropagation(); 700 }); 701 702 mfp.container.addClass('mfp-s-'+status); 703 _prevStatus = status; 704 } 705 }, 706 707 708 /* 709 "Private" helpers that aren't private at all 710 */ 711 // Check to close popup or not 712 // "target" is an element that was clicked 713 _checkIfClose: function(target) { 714 715 if($(target).hasClass(PREVENT_CLOSE_CLASS)) { 716 return; 717 } 718 719 var closeOnContent = mfp.st.closeOnContentClick; 720 var closeOnBg = mfp.st.closeOnBgClick; 721 722 if(closeOnContent && closeOnBg) { 723 return true; 724 } else { 725 726 // We close the popup if click is on close button or on preloader. Or if there is no content. 727 if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) { 728 return true; 729 } 730 731 // if click is outside the content 732 if( (target !== mfp.content[0] && !$.contains(mfp.content[0], target)) ) { 733 if(closeOnBg) { 734 // last check, if the clicked element is in DOM, (in case it's removed onclick) 735 if( $.contains(document, target) ) { 736 return true; 737 } 738 } 739 } else if(closeOnContent) { 740 return true; 741 } 742 743 } 744 return false; 745 }, 746 _addClassToMFP: function(cName) { 747 mfp.bgOverlay.addClass(cName); 748 mfp.wrap.addClass(cName); 749 }, 750 _removeClassFromMFP: function(cName) { 751 this.bgOverlay.removeClass(cName); 752 mfp.wrap.removeClass(cName); 753 }, 754 _hasScrollBar: function(winHeight) { 755 return ( (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) ); 756 }, 757 _setFocus: function() { 758 (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus(); 759 }, 760 _onFocusIn: function(e) { 761 if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) { 762 mfp._setFocus(); 763 return false; 764 } 765 }, 766 _parseMarkup: function(template, values, item) { 767 var arr; 768 if(item.data) { 769 values = $.extend(item.data, values); 770 } 771 _mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] ); 772 773 $.each(values, function(key, value) { 774 if(value === undefined || value === false) { 775 return true; 776 } 777 arr = key.split('_'); 778 if(arr.length > 1) { 779 var el = template.find(EVENT_NS + '-'+arr[0]); 780 781 if(el.length > 0) { 782 var attr = arr[1]; 783 if(attr === 'replaceWith') { 784 if(el[0] !== value[0]) { 785 el.replaceWith(value); 786 } 787 } else if(attr === 'img') { 788 if(el.is('img')) { 789 el.attr('src', value); 790 } else { 791 el.replaceWith( $('<img>').attr('src', value).attr('class', el.attr('class')) ); 792 } 793 } else { 794 el.attr(arr[1], value); 795 } 796 } 797 798 } else { 799 template.find(EVENT_NS + '-'+key).html(value); 800 } 801 }); 802 }, 803 804 _getScrollbarSize: function() { 805 // thx David 806 if(mfp.scrollbarSize === undefined) { 807 var scrollDiv = document.createElement("div"); 808 scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; 809 document.body.appendChild(scrollDiv); 810 mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth; 811 document.body.removeChild(scrollDiv); 812 } 813 return mfp.scrollbarSize; 814 } 815 816}; /* MagnificPopup core prototype end */ 817 818 819 820 821/** 822 * Public static functions 823 */ 824$.magnificPopup = { 825 instance: null, 826 proto: MagnificPopup.prototype, 827 modules: [], 828 829 open: function(options, index) { 830 _checkInstance(); 831 832 if(!options) { 833 options = {}; 834 } else { 835 options = $.extend(true, {}, options); 836 } 837 838 options.isObj = true; 839 options.index = index || 0; 840 return this.instance.open(options); 841 }, 842 843 close: function() { 844 return $.magnificPopup.instance && $.magnificPopup.instance.close(); 845 }, 846 847 registerModule: function(name, module) { 848 if(module.options) { 849 $.magnificPopup.defaults[name] = module.options; 850 } 851 $.extend(this.proto, module.proto); 852 this.modules.push(name); 853 }, 854 855 defaults: { 856 857 // Info about options is in docs: 858 // http://dimsemenov.com/plugins/magnific-popup/documentation.html#options 859 860 disableOn: 0, 861 862 key: null, 863 864 midClick: false, 865 866 mainClass: '', 867 868 preloader: true, 869 870 focus: '', // CSS selector of input to focus after popup is opened 871 872 closeOnContentClick: false, 873 874 closeOnBgClick: true, 875 876 closeBtnInside: true, 877 878 showCloseBtn: true, 879 880 enableEscapeKey: true, 881 882 modal: false, 883 884 alignTop: false, 885 886 removalDelay: 0, 887 888 prependTo: null, 889 890 fixedContentPos: 'auto', 891 892 fixedBgPos: 'auto', 893 894 overflowY: 'auto', 895 896 closeMarkup: '<button title="%title%" type="button" class="mfp-close">×</button>', 897 898 tClose: 'Close (Esc)', 899 900 tLoading: 'Loading...', 901 902 autoFocusLast: true 903 904 } 905}; 906 907 908 909$.fn.magnificPopup = function(options) { 910 _checkInstance(); 911 912 var jqEl = $(this); 913 914 // We call some API method of first param is a string 915 if (typeof options === "string" ) { 916 917 if(options === 'open') { 918 var items, 919 itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup, 920 index = parseInt(arguments[1], 10) || 0; 921 922 if(itemOpts.items) { 923 items = itemOpts.items[index]; 924 } else { 925 items = jqEl; 926 if(itemOpts.delegate) { 927 items = items.find(itemOpts.delegate); 928 } 929 items = items.eq( index ); 930 } 931 mfp._openClick({mfpEl:items}, jqEl, itemOpts); 932 } else { 933 if(mfp.isOpen) 934 mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1)); 935 } 936 937 } else { 938 // clone options obj 939 options = $.extend(true, {}, options); 940 941 /* 942 * As Zepto doesn't support .data() method for objects 943 * and it works only in normal browsers 944 * we assign "options" object directly to the DOM element. FTW! 945 */ 946 if(_isJQ) { 947 jqEl.data('magnificPopup', options); 948 } else { 949 jqEl[0].magnificPopup = options; 950 } 951 952 mfp.addGroup(jqEl, options); 953 954 } 955 return jqEl; 956}; 957 958/*>>core*/ 959 960/*>>inline*/ 961 962var INLINE_NS = 'inline', 963 _hiddenClass, 964 _inlinePlaceholder, 965 _lastInlineElement, 966 _putInlineElementsBack = function() { 967 if(_lastInlineElement) { 968 _inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach(); 969 _lastInlineElement = null; 970 } 971 }; 972 973$.magnificPopup.registerModule(INLINE_NS, { 974 options: { 975 hiddenClass: 'hide', // will be appended with `mfp-` prefix 976 markup: '', 977 tNotFound: 'Content not found' 978 }, 979 proto: { 980 981 initInline: function() { 982 mfp.types.push(INLINE_NS); 983 984 _mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() { 985 _putInlineElementsBack(); 986 }); 987 }, 988 989 getInline: function(item, template) { 990 991 _putInlineElementsBack(); 992 993 if(item.src) { 994 var inlineSt = mfp.st.inline, 995 el = $(item.src); 996 997 if(el.length) { 998 999 // If target element has parent - we replace it with placeholder and put it back after popup is closed 1000 var parent = el[0].parentNode; 1001 if(parent && parent.tagName) { 1002 if(!_inlinePlaceholder) { 1003 _hiddenClass = inlineSt.hiddenClass; 1004 _inlinePlaceholder = _getEl(_hiddenClass); 1005 _hiddenClass = 'mfp-'+_hiddenClass; 1006 } 1007 // replace target inline element with placeholder 1008 _lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass); 1009 } 1010 1011 mfp.updateStatus('ready'); 1012 } else { 1013 mfp.updateStatus('error', inlineSt.tNotFound); 1014 el = $('<div>'); 1015 } 1016 1017 item.inlineElement = el; 1018 return el; 1019 } 1020 1021 mfp.updateStatus('ready'); 1022 mfp._parseMarkup(template, {}, item); 1023 return template; 1024 } 1025 } 1026}); 1027 1028/*>>inline*/ 1029 1030/*>>ajax*/ 1031var AJAX_NS = 'ajax', 1032 _ajaxCur, 1033 _removeAjaxCursor = function() { 1034 if(_ajaxCur) { 1035 $(document.body).removeClass(_ajaxCur); 1036 } 1037 }, 1038 _destroyAjaxRequest = function() { 1039 _removeAjaxCursor(); 1040 if(mfp.req) { 1041 mfp.req.abort(); 1042 } 1043 }; 1044 1045$.magnificPopup.registerModule(AJAX_NS, { 1046 1047 options: { 1048 settings: null, 1049 cursor: 'mfp-ajax-cur', 1050 tError: '<a href="%url%">The content</a> could not be loaded.' 1051 }, 1052 1053 proto: { 1054 initAjax: function() { 1055 mfp.types.push(AJAX_NS); 1056 _ajaxCur = mfp.st.ajax.cursor; 1057 1058 _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest); 1059 _mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest); 1060 }, 1061 getAjax: function(item) { 1062 1063 if(_ajaxCur) { 1064 $(document.body).addClass(_ajaxCur); 1065 } 1066 1067 mfp.updateStatus('loading'); 1068 1069 var opts = $.extend({ 1070 url: item.src, 1071 success: function(data, textStatus, jqXHR) { 1072 var temp = { 1073 data:data, 1074 xhr:jqXHR 1075 }; 1076 1077 _mfpTrigger('ParseAjax', temp); 1078 1079 mfp.appendContent( $(temp.data), AJAX_NS ); 1080 1081 item.finished = true; 1082 1083 _removeAjaxCursor(); 1084 1085 mfp._setFocus(); 1086 1087 setTimeout(function() { 1088 mfp.wrap.addClass(READY_CLASS); 1089 }, 16); 1090 1091 mfp.updateStatus('ready'); 1092 1093 _mfpTrigger('AjaxContentAdded'); 1094 }, 1095 error: function() { 1096 _removeAjaxCursor(); 1097 item.finished = item.loadError = true; 1098 mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src)); 1099 } 1100 }, mfp.st.ajax.settings); 1101 1102 mfp.req = $.ajax(opts); 1103 1104 return ''; 1105 } 1106 } 1107}); 1108 1109/*>>ajax*/ 1110 1111/*>>image*/ 1112var _imgInterval, 1113 _getTitle = function(item) { 1114 if(item.data && item.data.title !== undefined) 1115 return item.data.title; 1116 1117 var src = mfp.st.image.titleSrc; 1118 1119 if(src) { 1120 if($.isFunction(src)) { 1121 return src.call(mfp, item); 1122 } else if(item.el) { 1123 return item.el.attr(src) || ''; 1124 } 1125 } 1126 return ''; 1127 }; 1128 1129$.magnificPopup.registerModule('image', { 1130 1131 options: { 1132 markup: '<div class="mfp-figure">'+ 1133 '<div class="mfp-close"></div>'+ 1134 '<figure>'+ 1135 '<div class="mfp-img"></div>'+ 1136 '<figcaption>'+ 1137 '<div class="mfp-bottom-bar">'+ 1138 '<div class="mfp-title"></div>'+ 1139 '<div class="mfp-counter"></div>'+ 1140 '</div>'+ 1141 '</figcaption>'+ 1142 '</figure>'+ 1143 '</div>', 1144 cursor: 'mfp-zoom-out-cur', 1145 titleSrc: 'title', 1146 verticalFit: true, 1147 tError: '<a href="%url%">The image</a> could not be loaded.' 1148 }, 1149 1150 proto: { 1151 initImage: function() { 1152 var imgSt = mfp.st.image, 1153 ns = '.image'; 1154 1155 mfp.types.push('image'); 1156 1157 _mfpOn(OPEN_EVENT+ns, function() { 1158 if(mfp.currItem.type === 'image' && imgSt.cursor) { 1159 $(document.body).addClass(imgSt.cursor); 1160 } 1161 }); 1162 1163 _mfpOn(CLOSE_EVENT+ns, function() { 1164 if(imgSt.cursor) { 1165 $(document.body).removeClass(imgSt.cursor); 1166 } 1167 _window.off('resize' + EVENT_NS); 1168 }); 1169 1170 _mfpOn('Resize'+ns, mfp.resizeImage); 1171 if(mfp.isLowIE) { 1172 _mfpOn('AfterChange', mfp.resizeImage); 1173 } 1174 }, 1175 resizeImage: function() { 1176 var item = mfp.currItem; 1177 if(!item || !item.img) return; 1178 1179 if(mfp.st.image.verticalFit) { 1180 var decr = 0; 1181 // fix box-sizing in ie7/8 1182 if(mfp.isLowIE) { 1183 decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10); 1184 } 1185 item.img.css('max-height', mfp.wH-decr); 1186 } 1187 }, 1188 _onImageHasSize: function(item) { 1189 if(item.img) { 1190 1191 item.hasSize = true; 1192 1193 if(_imgInterval) { 1194 clearInterval(_imgInterval); 1195 } 1196 1197 item.isCheckingImgSize = false; 1198 1199 _mfpTrigger('ImageHasSize', item); 1200 1201 if(item.imgHidden) { 1202 if(mfp.content) 1203 mfp.content.removeClass('mfp-loading'); 1204 1205 item.imgHidden = false; 1206 } 1207 1208 } 1209 }, 1210 1211 /** 1212 * Function that loops until the image has size to display elements that rely on it asap 1213 */ 1214 findImageSize: function(item) { 1215 1216 var counter = 0, 1217 img = item.img[0], 1218 mfpSetInterval = function(delay) { 1219 1220 if(_imgInterval) { 1221 clearInterval(_imgInterval); 1222 } 1223 // decelerating interval that checks for size of an image 1224 _imgInterval = setInterval(function() { 1225 if(img.naturalWidth > 0) { 1226 mfp._onImageHasSize(item); 1227 return; 1228 } 1229 1230 if(counter > 200) { 1231 clearInterval(_imgInterval); 1232 } 1233 1234 counter++; 1235 if(counter === 3) { 1236 mfpSetInterval(10); 1237 } else if(counter === 40) { 1238 mfpSetInterval(50); 1239 } else if(counter === 100) { 1240 mfpSetInterval(500); 1241 } 1242 }, delay); 1243 }; 1244 1245 mfpSetInterval(1); 1246 }, 1247 1248 getImage: function(item, template) { 1249 1250 var guard = 0, 1251 1252 // image load complete handler 1253 onLoadComplete = function() { 1254 if(item) { 1255 if (item.img[0].complete) { 1256 item.img.off('.mfploader'); 1257 1258 if(item === mfp.currItem){ 1259 mfp._onImageHasSize(item); 1260 1261 mfp.updateStatus('ready'); 1262 } 1263 1264 item.hasSize = true; 1265 item.loaded = true; 1266 1267 _mfpTrigger('ImageLoadComplete'); 1268 1269 } 1270 else { 1271 // if image complete check fails 200 times (20 sec), we assume that there was an error. 1272 guard++; 1273 if(guard < 200) { 1274 setTimeout(onLoadComplete,100); 1275 } else { 1276 onLoadError(); 1277 } 1278 } 1279 } 1280 }, 1281 1282 // image error handler 1283 onLoadError = function() { 1284 if(item) { 1285 item.img.off('.mfploader'); 1286 if(item === mfp.currItem){ 1287 mfp._onImageHasSize(item); 1288 mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) ); 1289 } 1290 1291 item.hasSize = true; 1292 item.loaded = true; 1293 item.loadError = true; 1294 } 1295 }, 1296 imgSt = mfp.st.image; 1297 1298 1299 var el = template.find('.mfp-img'); 1300 if(el.length) { 1301 var img = document.createElement('img'); 1302 img.className = 'mfp-img'; 1303 if(item.el && item.el.find('img').length) { 1304 img.alt = item.el.find('img').attr('alt'); 1305 } 1306 item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError); 1307 img.src = item.src; 1308 1309 // without clone() "error" event is not firing when IMG is replaced by new IMG 1310 // TODO: find a way to avoid such cloning 1311 if(el.is('img')) { 1312 item.img = item.img.clone(); 1313 } 1314 1315 img = item.img[0]; 1316 if(img.naturalWidth > 0) { 1317 item.hasSize = true; 1318 } else if(!img.width) { 1319 item.hasSize = false; 1320 } 1321 } 1322 1323 mfp._parseMarkup(template, { 1324 title: _getTitle(item), 1325 img_replaceWith: item.img 1326 }, item); 1327 1328 mfp.resizeImage(); 1329 1330 if(item.hasSize) { 1331 if(_imgInterval) clearInterval(_imgInterval); 1332 1333 if(item.loadError) { 1334 template.addClass('mfp-loading'); 1335 mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) ); 1336 } else { 1337 template.removeClass('mfp-loading'); 1338 mfp.updateStatus('ready'); 1339 } 1340 return template; 1341 } 1342 1343 mfp.updateStatus('loading'); 1344 item.loading = true; 1345 1346 if(!item.hasSize) { 1347 item.imgHidden = true; 1348 template.addClass('mfp-loading'); 1349 mfp.findImageSize(item); 1350 } 1351 1352 return template; 1353 } 1354 } 1355}); 1356 1357/*>>image*/ 1358 1359/*>>zoom*/ 1360var hasMozTransform, 1361 getHasMozTransform = function() { 1362 if(hasMozTransform === undefined) { 1363 hasMozTransform = document.createElement('p').style.MozTransform !== undefined; 1364 } 1365 return hasMozTransform; 1366 }; 1367 1368$.magnificPopup.registerModule('zoom', { 1369 1370 options: { 1371 enabled: false, 1372 easing: 'ease-in-out', 1373 duration: 300, 1374 opener: function(element) { 1375 return element.is('img') ? element : element.find('img'); 1376 } 1377 }, 1378 1379 proto: { 1380 1381 initZoom: function() { 1382 var zoomSt = mfp.st.zoom, 1383 ns = '.zoom', 1384 image; 1385 1386 if(!zoomSt.enabled || !mfp.supportsTransition) { 1387 return; 1388 } 1389 1390 var duration = zoomSt.duration, 1391 getElToAnimate = function(image) { 1392 var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'), 1393 transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing, 1394 cssObj = { 1395 position: 'fixed', 1396 zIndex: 9999, 1397 left: 0, 1398 top: 0, 1399 '-webkit-backface-visibility': 'hidden' 1400 }, 1401 t = 'transition'; 1402 1403 cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition; 1404 1405 newImg.css(cssObj); 1406 return newImg; 1407 }, 1408 showMainContent = function() { 1409 mfp.content.css('visibility', 'visible'); 1410 }, 1411 openTimeout, 1412 animatedImg; 1413 1414 _mfpOn('BuildControls'+ns, function() { 1415 if(mfp._allowZoom()) { 1416 1417 clearTimeout(openTimeout); 1418 mfp.content.css('visibility', 'hidden'); 1419 1420 // Basically, all code below does is clones existing image, puts in on top of the current one and animated it 1421 1422 image = mfp._getItemToZoom(); 1423 1424 if(!image) { 1425 showMainContent(); 1426 return; 1427 } 1428 1429 animatedImg = getElToAnimate(image); 1430 1431 animatedImg.css( mfp._getOffset() ); 1432 1433 mfp.wrap.append(animatedImg); 1434 1435 openTimeout = setTimeout(function() { 1436 animatedImg.css( mfp._getOffset( true ) ); 1437 openTimeout = setTimeout(function() { 1438 1439 showMainContent(); 1440 1441 setTimeout(function() { 1442 animatedImg.remove(); 1443 image = animatedImg = null; 1444 _mfpTrigger('ZoomAnimationEnded'); 1445 }, 16); // avoid blink when switching images 1446 1447 }, duration); // this timeout equals animation duration 1448 1449 }, 16); // by adding this timeout we avoid short glitch at the beginning of animation 1450 1451 1452 // Lots of timeouts... 1453 } 1454 }); 1455 _mfpOn(BEFORE_CLOSE_EVENT+ns, function() { 1456 if(mfp._allowZoom()) { 1457 1458 clearTimeout(openTimeout); 1459 1460 mfp.st.removalDelay = duration; 1461 1462 if(!image) { 1463 image = mfp._getItemToZoom(); 1464 if(!image) { 1465 return; 1466 } 1467 animatedImg = getElToAnimate(image); 1468 } 1469 1470 animatedImg.css( mfp._getOffset(true) ); 1471 mfp.wrap.append(animatedImg); 1472 mfp.content.css('visibility', 'hidden'); 1473 1474 setTimeout(function() { 1475 animatedImg.css( mfp._getOffset() ); 1476 }, 16); 1477 } 1478 1479 }); 1480 1481 _mfpOn(CLOSE_EVENT+ns, function() { 1482 if(mfp._allowZoom()) { 1483 showMainContent(); 1484 if(animatedImg) { 1485 animatedImg.remove(); 1486 } 1487 image = null; 1488 } 1489 }); 1490 }, 1491 1492 _allowZoom: function() { 1493 return mfp.currItem.type === 'image'; 1494 }, 1495 1496 _getItemToZoom: function() { 1497 if(mfp.currItem.hasSize) { 1498 return mfp.currItem.img; 1499 } else { 1500 return false; 1501 } 1502 }, 1503 1504 // Get element postion relative to viewport 1505 _getOffset: function(isLarge) { 1506 var el; 1507 if(isLarge) { 1508 el = mfp.currItem.img; 1509 } else { 1510 el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem); 1511 } 1512 1513 var offset = el.offset(); 1514 var paddingTop = parseInt(el.css('padding-top'),10); 1515 var paddingBottom = parseInt(el.css('padding-bottom'),10); 1516 offset.top -= ( $(window).scrollTop() - paddingTop ); 1517 1518 1519 /* 1520 1521 Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa. 1522 1523 */ 1524 var obj = { 1525 width: el.width(), 1526 // fix Zepto height+padding issue 1527 height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop 1528 }; 1529 1530 // I hate to do this, but there is no another option 1531 if( getHasMozTransform() ) { 1532 obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)'; 1533 } else { 1534 obj.left = offset.left; 1535 obj.top = offset.top; 1536 } 1537 return obj; 1538 } 1539 1540 } 1541}); 1542 1543 1544 1545/*>>zoom*/ 1546 1547/*>>iframe*/ 1548 1549var IFRAME_NS = 'iframe', 1550 _emptyPage = '//about:blank', 1551 1552 _fixIframeBugs = function(isShowing) { 1553 if(mfp.currTemplate[IFRAME_NS]) { 1554 var el = mfp.currTemplate[IFRAME_NS].find('iframe'); 1555 if(el.length) { 1556 // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug 1557 if(!isShowing) { 1558 el[0].src = _emptyPage; 1559 } 1560 1561 // IE8 black screen bug fix 1562 if(mfp.isIE8) { 1563 el.css('display', isShowing ? 'block' : 'none'); 1564 } 1565 } 1566 } 1567 }; 1568 1569$.magnificPopup.registerModule(IFRAME_NS, { 1570 1571 options: { 1572 markup: '<div class="mfp-iframe-scaler">'+ 1573 '<div class="mfp-close"></div>'+ 1574 '<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+ 1575 '</div>', 1576 1577 srcAction: 'iframe_src', 1578 1579 // we don't care and support only one default type of URL by default 1580 patterns: { 1581 youtube: { 1582 index: 'youtube.com', 1583 id: 'v=', 1584 src: '//www.youtube.com/embed/%id%?autoplay=1' 1585 }, 1586 vimeo: { 1587 index: 'vimeo.com/', 1588 id: '/', 1589 src: '//player.vimeo.com/video/%id%?autoplay=1' 1590 }, 1591 gmaps: { 1592 index: '//maps.google.', 1593 src: '%id%&output=embed' 1594 } 1595 } 1596 }, 1597 1598 proto: { 1599 initIframe: function() { 1600 mfp.types.push(IFRAME_NS); 1601 1602 _mfpOn('BeforeChange', function(e, prevType, newType) { 1603 if(prevType !== newType) { 1604 if(prevType === IFRAME_NS) { 1605 _fixIframeBugs(); // iframe if removed 1606 } else if(newType === IFRAME_NS) { 1607 _fixIframeBugs(true); // iframe is showing 1608 } 1609 }// else { 1610 // iframe source is switched, don't do anything 1611 //} 1612 }); 1613 1614 _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() { 1615 _fixIframeBugs(); 1616 }); 1617 }, 1618 1619 getIframe: function(item, template) { 1620 var embedSrc = item.src; 1621 var iframeSt = mfp.st.iframe; 1622 1623 $.each(iframeSt.patterns, function() { 1624 if(embedSrc.indexOf( this.index ) > -1) { 1625 if(this.id) { 1626 if(typeof this.id === 'string') { 1627 embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length); 1628 } else { 1629 embedSrc = this.id.call( this, embedSrc ); 1630 } 1631 } 1632 embedSrc = this.src.replace('%id%', embedSrc ); 1633 return false; // break; 1634 } 1635 }); 1636 1637 var dataObj = {}; 1638 if(iframeSt.srcAction) { 1639 dataObj[iframeSt.srcAction] = embedSrc; 1640 } 1641 mfp._parseMarkup(template, dataObj, item); 1642 1643 mfp.updateStatus('ready'); 1644 1645 return template; 1646 } 1647 } 1648}); 1649 1650 1651 1652/*>>iframe*/ 1653 1654/*>>gallery*/ 1655/** 1656 * Get looped index depending on number of slides 1657 */ 1658var _getLoopedId = function(index) { 1659 var numSlides = mfp.items.length; 1660 if(index > numSlides - 1) { 1661 return index - numSlides; 1662 } else if(index < 0) { 1663 return numSlides + index; 1664 } 1665 return index; 1666 }, 1667 _replaceCurrTotal = function(text, curr, total) { 1668 return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total); 1669 }; 1670 1671$.magnificPopup.registerModule('gallery', { 1672 1673 options: { 1674 enabled: false, 1675 arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>', 1676 preload: [0,2], 1677 navigateByImgClick: true, 1678 arrows: true, 1679 1680 tPrev: 'Previous (Left arrow key)', 1681 tNext: 'Next (Right arrow key)', 1682 tCounter: '%curr% of %total%' 1683 }, 1684 1685 proto: { 1686 initGallery: function() { 1687 1688 var gSt = mfp.st.gallery, 1689 ns = '.mfp-gallery'; 1690 1691 mfp.direction = true; // true - next, false - prev 1692 1693 if(!gSt || !gSt.enabled ) return false;
1694 1695 _wrapClasses += ' mfp-gallery'; 1696 1697 _mfpOn(OPEN_EVENT+ns, function() { 1698 1699 if(gSt.navigateByImgClick) { 1700 mfp.wrap.on('click'+ns, '.mfp-img', function() { 1701 if(mfp.items.length > 1) { 1702 mfp.next(); 1703 return false; 1704 } 1705 }); 1706 } 1707 1708 _document.on('keydown'+ns, function(e) { 1709 if (e.keyCode === 37) { 1710 mfp.prev(); 1711 } else if (e.keyCode === 39) { 1712 mfp.next(); 1713 } 1714 }); 1715 }); 1716 1717 _mfpOn('UpdateStatus'+ns, function(e, data) { 1718 if(data.text) { 1719 data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length); 1720 } 1721 }); 1722 1723 _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) { 1724 var l = mfp.items.length; 1725 values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : ''; 1726 }); 1727 1728 _mfpOn('BuildControls' + ns, function() { 1729 if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) { 1730 var markup = gSt.arrowMarkup, 1731 arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS), 1732 arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS); 1733 1734 arrowLeft.click(function() { 1735 mfp.prev(); 1736 }); 1737 arrowRight.click(function() { 1738 mfp.next(); 1739 }); 1740 1741 mfp.container.append(arrowLeft.add(arrowRight)); 1742 } 1743 }); 1744 1745 _mfpOn(CHANGE_EVENT+ns, function() { 1746 if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout); 1747 1748 mfp._preloadTimeout = setTimeout(function() { 1749 mfp.preloadNearbyImages(); 1750 mfp._preloadTimeout = null; 1751 }, 16); 1752 }); 1753 1754 1755 _mfpOn(CLOSE_EVENT+ns, function() { 1756 _document.off(ns); 1757 mfp.wrap.off('click'+ns); 1758 mfp.arrowRight = mfp.arrowLeft = null; 1759 }); 1760 1761 }, 1762 next: function() { 1763 mfp.direction = true; 1764 mfp.index = _getLoopedId(mfp.index + 1); 1765 mfp.updateItemHTML(); 1766 }, 1767 prev: function() { 1768 mfp.direction = false; 1769 mfp.index = _getLoopedId(mfp.index - 1); 1770 mfp.updateItemHTML(); 1771 }, 1772 goTo: function(newIndex) { 1773 mfp.direction = (newIndex >= mfp.index); 1774 mfp.index = newIndex; 1775 mfp.updateItemHTML(); 1776 }, 1777 preloadNearbyImages: function() { 1778 var p = mfp.st.gallery.preload, 1779 preloadBefore = Math.min(p[0], mfp.items.length), 1780 preloadAfter = Math.min(p[1], mfp.items.length), 1781 i; 1782 1783 for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) { 1784 mfp._preloadItem(mfp.index+i); 1785 } 1786 for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) { 1787 mfp._preloadItem(mfp.index-i); 1788 } 1789 }, 1790 _preloadItem: function(index) { 1791 index = _getLoopedId(index); 1792 1793 if(mfp.items[index].preloaded) { 1794 return; 1795 } 1796 1797 var item = mfp.items[index]; 1798 if(!item.parsed) { 1799 item = mfp.parseEl( index ); 1800 } 1801 1802 _mfpTrigger('LazyLoad', item); 1803 1804 if(item.type === 'image') { 1805 item.img = $('<img class="mfp-img" />').on('load.mfploader', function() { 1806 item.hasSize = true; 1807 }).on('error.mfploader', function() { 1808 item.hasSize = true; 1809 item.loadError = true; 1810 _mfpTrigger('LazyLoadError', item); 1811 }).attr('src', item.src); 1812 } 1813 1814 1815 item.preloaded = true; 1816 } 1817 } 1818}); 1819 1820/*>>gallery*/ 1821 1822/*>>retina*/ 1823 1824var RETINA_NS = 'retina'; 1825 1826$.magnificPopup.registerModule(RETINA_NS, { 1827 options: { 1828 replaceSrc: function(item) { 1829 return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; }); 1830 }, 1831 ratio: 1 // Function or number. Set to 1 to disable. 1832 }, 1833 proto: { 1834 initRetina: function() { 1835 if(window.devicePixelRatio > 1) { 1836 1837 var st = mfp.st.retina, 1838 ratio = st.ratio; 1839 1840 ratio = !isNaN(ratio) ? ratio : ratio(); 1841 1842 if(ratio > 1) { 1843 _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) { 1844 item.img.css({ 1845 'max-width': item.img[0].naturalWidth / ratio, 1846 'width': '100%' 1847 }); 1848 }); 1849 _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) { 1850 item.src = st.replaceSrc(item, ratio); 1851 }); 1852 } 1853 } 1854 1855 } 1856 } 1857}); 1858 1859/*>>retina*/ 1860 _checkInstance(); })); 1861// MagnificPopup 1862// ------------------------------------------------------------- 1863jQuery(document).ready(function ($) { 1864 $('.video-popup').magnificPopup({ 1865 type: 'iframe', 1866 }); 1867 1868 $('.iframe-popup a').magnificPopup({ 1869 type: 'iframe', 1870 }); 1871 1872 $('.photo-popup').magnificPopup({ 1873 type: 'image', 1874 }); 1875 1876 $('.youtube-video').magnificPopup({ 1877 type: 'iframe', 1878 iframe: { 1879 patterns: { 1880 youtube: { 1881 index: 'youtube.com/', 1882 id: 'v=', 1883 src: '//www.youtube.com/embed/%id%?rel=0&autoplay=1', 1884 }, 1885 }, 1886 }, 1887 }); 1888}); 1889
vendor: 12,075 bytes, lines 1890-2330
1890/*! 1891 * imagesLoaded PACKAGED v5.0.0 1892 * JavaScript is all like "You images are done yet or what?" 1893 * MIT License 1894 */ 1895 1896/** 1897 * EvEmitter v2.1.1 1898 * Lil' event emitter 1899 * MIT License 1900 */ 1901 1902( function( global, factory ) { 1903 // universal module definition 1904 if ( typeof module == 'object' && module.exports ) { 1905 // CommonJS - Browserify, Webpack 1906 module.exports = factory(); 1907 } else { 1908 // Browser globals 1909 global.EvEmitter = factory(); 1910 } 1911 1912}( typeof window != 'undefined' ? window : this, function() { 1913 1914function EvEmitter() {} 1915 1916let proto = EvEmitter.prototype; 1917 1918proto.on = function( eventName, listener ) { 1919 if ( !eventName || !listener ) return this; 1920 1921 // set events hash 1922 let events = this._events = this._events || {}; 1923 // set listeners array 1924 let listeners = events[ eventName ] = events[ eventName ] || []; 1925 // only add once 1926 if ( !listeners.includes( listener ) ) { 1927 listeners.push( listener ); 1928 } 1929 1930 return this; 1931}; 1932 1933proto.once = function( eventName, listener ) { 1934 if ( !eventName || !listener ) return this; 1935 1936 // add event 1937 this.on( eventName, listener ); 1938 // set once flag 1939 // set onceEvents hash 1940 let onceEvents = this._onceEvents = this._onceEvents || {}; 1941 // set onceListeners object 1942 let onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 1943 // set flag 1944 onceListeners[ listener ] = true; 1945 1946 return this; 1947}; 1948 1949proto.off = function( eventName, listener ) { 1950 let listeners = this._events && this._events[ eventName ]; 1951 if ( !listeners || !listeners.length ) return this; 1952 1953 let index = listeners.indexOf( listener ); 1954 if ( index != -1 ) { 1955 listeners.splice( index, 1 ); 1956 } 1957 1958 return this; 1959}; 1960 1961proto.emitEvent = function( eventName, args ) { 1962 let listeners = this._events && this._events[ eventName ]; 1963 if ( !listeners || !listeners.length ) return this; 1964 1965 // copy over to avoid interference if .off() in listener 1966 listeners = listeners.slice( 0 ); 1967 args = args || []; 1968 // once stuff 1969 let onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 1970 1971 for ( let listener of listeners ) { 1972 let isOnce = onceListeners && onceListeners[ listener ]; 1973 if ( isOnce ) { 1974 // remove listener 1975 // remove before trigger to prevent recursion 1976 this.off( eventName, listener ); 1977 // unset once flag 1978 delete onceListeners[ listener ]; 1979 } 1980 // trigger listener 1981 listener.apply( this, args ); 1982 } 1983 1984 return this; 1985}; 1986 1987proto.allOff = function() { 1988 delete this._events; 1989 delete this._onceEvents; 1990 return this; 1991}; 1992 1993return EvEmitter; 1994 1995} ) ); 1996/*! 1997 * imagesLoaded v5.0.0 1998 * JavaScript is all like "You images are done yet or what?" 1999 * MIT License 2000 */ 2001 2002( function( window, factory ) { 2003 // universal module definition 2004 if ( typeof module == 'object' && module.exports ) { 2005 // CommonJS 2006 module.exports = factory( window, require('ev-emitter') ); 2007 } else { 2008 // browser global 2009 window.imagesLoaded = factory( window, window.EvEmitter ); 2010 } 2011 2012} )( typeof window !== 'undefined' ? window : this, 2013 function factory( window, EvEmitter ) { 2014 2015let $ = window.jQuery; 2016let console = window.console; 2017 2018// -------------------------- helpers -------------------------- // 2019 2020// turn element or nodeList into an array 2021function makeArray( obj ) { 2022 // use object if already an array 2023 if ( Array.isArray( obj ) ) return obj; 2024 2025 let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 2026 // convert nodeList to array 2027 if ( isArrayLike ) return [ ...obj ]; 2028 2029 // array of single index 2030 return [ obj ]; 2031} 2032 2033// -------------------------- imagesLoaded -------------------------- // 2034 2035/** 2036 * @param {[Array, Element, NodeList, String]} elem 2037 * @param {[Object, Function]} options - if function, use as callback 2038 * @param {Function} onAlways - callback function 2039 * @returns {ImagesLoaded} 2040 */ 2041function ImagesLoaded( elem, options, onAlways ) { 2042 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 2043 if ( !( this instanceof ImagesLoaded ) ) { 2044 return new ImagesLoaded( elem, options, onAlways ); 2045 } 2046 // use elem as selector string 2047 let queryElem = elem; 2048 if ( typeof elem == 'string' ) { 2049 queryElem = document.querySelectorAll( elem ); 2050 } 2051 // bail if bad element 2052 if ( !queryElem ) { 2053 console.error(`Bad element for imagesLoaded ${queryElem || elem}`); 2054 return; 2055 } 2056 2057 this.elements = makeArray( queryElem ); 2058 this.options = {}; 2059 // shift arguments if no options set 2060 if ( typeof options == 'function' ) { 2061 onAlways = options; 2062 } else { 2063 Object.assign( this.options, options ); 2064 } 2065 2066 if ( onAlways ) this.on( 'always', onAlways ); 2067 2068 this.getImages(); 2069 // add jQuery Deferred object 2070 if ( $ ) this.jqDeferred = new $.Deferred(); 2071 2072 // HACK check async to allow time to bind listeners 2073 setTimeout( this.check.bind( this ) ); 2074} 2075 2076ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 2077 2078ImagesLoaded.prototype.getImages = function() { 2079 this.images = []; 2080 2081 // filter & find items if we have an item selector 2082 this.elements.forEach( this.addElementImages, this ); 2083}; 2084 2085const elementNodeTypes = [ 1, 9, 11 ]; 2086 2087/** 2088 * @param {Node} elem 2089 */ 2090ImagesLoaded.prototype.addElementImages = function( elem ) { 2091 // filter siblings 2092 if ( elem.nodeName === 'IMG' ) { 2093 this.addImage( elem ); 2094 } 2095 // get background image on element 2096 if ( this.options.background === true ) { 2097 this.addElementBackgroundImages( elem ); 2098 } 2099 2100 // find children 2101 // no non-element nodes, #143 2102 let { nodeType } = elem; 2103 if ( !nodeType || !elementNodeTypes.includes( nodeType ) ) return; 2104 2105 let childImgs = elem.querySelectorAll('img'); 2106 // concat childElems to filterFound array 2107 for ( let img of childImgs ) { 2108 this.addImage( img ); 2109 } 2110 2111 // get child background images 2112 if ( typeof this.options.background == 'string' ) { 2113 let children = elem.querySelectorAll( this.options.background ); 2114 for ( let child of children ) { 2115 this.addElementBackgroundImages( child ); 2116 } 2117 } 2118}; 2119 2120const reURL = /url\((['"])?(.*?)\1\)/gi; 2121 2122ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 2123 let style = getComputedStyle( elem ); 2124 // Firefox returns null if in a hidden iframe https://bugzil.la/548397 2125 if ( !style ) return; 2126 2127 // get url inside url("...") 2128 let matches = reURL.exec( style.backgroundImage ); 2129 while ( matches !== null ) { 2130 let url = matches && matches[2]; 2131 if ( url ) { 2132 this.addBackground( url, elem ); 2133 } 2134 matches = reURL.exec( style.backgroundImage ); 2135 } 2136}; 2137 2138/** 2139 * @param {Image} img 2140 */ 2141ImagesLoaded.prototype.addImage = function( img ) { 2142 let loadingImage = new LoadingImage( img ); 2143 this.images.push( loadingImage ); 2144}; 2145 2146ImagesLoaded.prototype.addBackground = function( url, elem ) { 2147 let background = new Background( url, elem ); 2148 this.images.push( background ); 2149}; 2150 2151ImagesLoaded.prototype.check = function() { 2152 this.progressedCount = 0; 2153 this.hasAnyBroken = false; 2154 // complete if no images 2155 if ( !this.images.length ) { 2156 this.complete(); 2157 return; 2158 } 2159 2160 /* eslint-disable-next-line func-style */ 2161 let onProgress = ( image, elem, message ) => { 2162 // HACK - Chrome triggers event before object properties have changed. #83 2163 setTimeout( () => { 2164 this.progress( image, elem, message ); 2165 } ); 2166 }; 2167 2168 this.images.forEach( function( loadingImage ) { 2169 loadingImage.once( 'progress', onProgress ); 2170 loadingImage.check(); 2171 } ); 2172}; 2173 2174ImagesLoaded.prototype.progress = function( image, elem, message ) { 2175 this.progressedCount++; 2176 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 2177 // progress event 2178 this.emitEvent( 'progress', [ this, image, elem ] ); 2179 if ( this.jqDeferred && this.jqDeferred.notify ) { 2180 this.jqDeferred.notify( this, image ); 2181 } 2182 // check if completed 2183 if ( this.progressedCount === this.images.length ) { 2184 this.complete(); 2185 } 2186 2187 if ( this.options.debug && console ) { 2188 console.log( `progress: ${message}`, image, elem ); 2189 } 2190}; 2191 2192ImagesLoaded.prototype.complete = function() { 2193 let eventName = this.hasAnyBroken ? 'fail' : 'done'; 2194 this.isComplete = true; 2195 this.emitEvent( eventName, [ this ] ); 2196 this.emitEvent( 'always', [ this ] ); 2197 if ( this.jqDeferred ) { 2198 let jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 2199 this.jqDeferred[ jqMethod ]( this ); 2200 } 2201}; 2202 2203// -------------------------- -------------------------- // 2204 2205function LoadingImage( img ) { 2206 this.img = img; 2207} 2208 2209LoadingImage.prototype = Object.create( EvEmitter.prototype ); 2210 2211LoadingImage.prototype.check = function() { 2212 // If complete is true and browser supports natural sizes, 2213 // try to check for image status manually. 2214 let isComplete = this.getIsImageComplete(); 2215 if ( isComplete ) { 2216 // report based on naturalWidth 2217 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 2218 return; 2219 } 2220 2221 // If none of the checks above matched, simulate loading on detached element. 2222 this.proxyImage = new Image(); 2223 // add crossOrigin attribute. #204 2224 if ( this.img.crossOrigin ) { 2225 this.proxyImage.crossOrigin = this.img.crossOrigin; 2226 } 2227 this.proxyImage.addEventListener( 'load', this ); 2228 this.proxyImage.addEventListener( 'error', this ); 2229 // bind to image as well for Firefox. #191 2230 this.img.addEventListener( 'load', this ); 2231 this.img.addEventListener( 'error', this ); 2232 this.proxyImage.src = this.img.currentSrc || this.img.src; 2233}; 2234 2235LoadingImage.prototype.getIsImageComplete = function() { 2236 // check for non-zero, non-undefined naturalWidth 2237 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 2238 return this.img.complete && this.img.naturalWidth; 2239}; 2240 2241LoadingImage.prototype.confirm = function( isLoaded, message ) { 2242 this.isLoaded = isLoaded; 2243 let { parentNode } = this.img; 2244 // emit progress with parent <picture> or self <img> 2245 let elem = parentNode.nodeName === 'PICTURE' ? parentNode : this.img; 2246 this.emitEvent( 'progress', [ this, elem, message ] ); 2247}; 2248 2249// ----- events ----- // 2250 2251// trigger specified handler for event type 2252LoadingImage.prototype.handleEvent = function( event ) { 2253 let method = 'on' + event.type; 2254 if ( this[ method ] ) { 2255 this[ method ]( event ); 2256 } 2257}; 2258 2259LoadingImage.prototype.onload = function() { 2260 this.confirm( true, 'onload' ); 2261 this.unbindEvents(); 2262}; 2263 2264LoadingImage.prototype.onerror = function() { 2265 this.confirm( false, 'onerror' ); 2266 this.unbindEvents(); 2267}; 2268 2269LoadingImage.prototype.unbindEvents = function() { 2270 this.proxyImage.removeEventListener( 'load', this ); 2271 this.proxyImage.removeEventListener( 'error', this ); 2272 this.img.removeEventListener( 'load', this ); 2273 this.img.removeEventListener( 'error', this ); 2274}; 2275 2276// -------------------------- Background -------------------------- // 2277 2278function Background( url, element ) { 2279 this.url = url; 2280 this.element = element; 2281 this.img = new Image(); 2282} 2283 2284// inherit LoadingImage prototype 2285Background.prototype = Object.create( LoadingImage.prototype ); 2286 2287Background.prototype.check = function() { 2288 this.img.addEventListener( 'load', this ); 2289 this.img.addEventListener( 'error', this ); 2290 this.img.src = this.url; 2291 // check if image is already complete 2292 let isComplete = this.getIsImageComplete(); 2293 if ( isComplete ) { 2294 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 2295 this.unbindEvents(); 2296 } 2297}; 2298 2299Background.prototype.unbindEvents = function() { 2300 this.img.removeEventListener( 'load', this ); 2301 this.img.removeEventListener( 'error', this ); 2302}; 2303 2304Background.prototype.confirm = function( isLoaded, message ) { 2305 this.isLoaded = isLoaded; 2306 this.emitEvent( 'progress', [ this, this.element, message ] ); 2307}; 2308 2309// -------------------------- jQuery -------------------------- // 2310 2311ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 2312 jQuery = jQuery || window.jQuery; 2313 if ( !jQuery ) return; 2314 2315 // set local variable 2316 $ = jQuery; 2317 // $().imagesLoaded() 2318 $.fn.imagesLoaded = function( options, onAlways ) { 2319 let instance = new ImagesLoaded( this, options, onAlways ); 2320 return instance.jqDeferred.promise( $( this ) ); 2321 }; 2322}; 2323// try making plugin 2324ImagesLoaded.makeJQueryPlugin(); 2325 2326// -------------------------- -------------------------- // 2327 2328return ImagesLoaded; 2329 2330} );
2331 2332// ImagesLoaded 2333// ------------------------------------------------------------ 2334
vendor: 95,083 bytes, lines 2335-5741
2335/*! 2336 * Flickity PACKAGED v3.0.0 2337 * Touch, responsive, flickable carousels 2338 * 2339 * Licensed GPLv3 for open source use 2340 * or Flickity Commercial License for commercial use 2341 * 2342 * https://flickity.metafizzy.co 2343 * Copyright 2015-2022 Metafizzy 2344 */ 2345 2346/** 2347 * Bridget makes jQuery widgets 2348 * v3.0.1 2349 * MIT license 2350 */ 2351 2352( function( window, factory ) { 2353 // module definition 2354 if ( typeof module == 'object' && module.exports ) { 2355 // CommonJS 2356 module.exports = factory( 2357 window, 2358 require('jquery'), 2359 ); 2360 } else { 2361 // browser global 2362 window.jQueryBridget = factory( 2363 window, 2364 window.jQuery, 2365 ); 2366 } 2367 2368}( window, function factory( window, jQuery ) { 2369 2370// ----- utils ----- // 2371 2372// helper function for logging errors 2373// $.error breaks jQuery chaining 2374let console = window.console; 2375let logError = typeof console == 'undefined' ? function() {} : 2376 function( message ) { 2377 console.error( message ); 2378 }; 2379 2380// ----- jQueryBridget ----- // 2381 2382function jQueryBridget( namespace, PluginClass, $ ) { 2383 $ = $ || jQuery || window.jQuery; 2384 if ( !$ ) { 2385 return; 2386 } 2387 2388 // add option method -> $().plugin('option', {...}) 2389 if ( !PluginClass.prototype.option ) { 2390 // option setter 2391 PluginClass.prototype.option = function( opts ) { 2392 if ( !opts ) return; 2393 2394 this.options = Object.assign( this.options || {}, opts ); 2395 }; 2396 } 2397 2398 // make jQuery plugin 2399 $.fn[ namespace ] = function( arg0, ...args ) { 2400 if ( typeof arg0 == 'string' ) { 2401 // method call $().plugin( 'methodName', { options } ) 2402 return methodCall( this, arg0, args ); 2403 } 2404 // just $().plugin({ options }) 2405 plainCall( this, arg0 ); 2406 return this; 2407 }; 2408 2409 // $().plugin('methodName') 2410 function methodCall( $elems, methodName, args ) { 2411 let returnValue; 2412 let pluginMethodStr = `$().${namespace}("${methodName}")`; 2413 2414 $elems.each( function( i, elem ) { 2415 // get instance 2416 let instance = $.data( elem, namespace ); 2417 if ( !instance ) { 2418 logError( `${namespace} not initialized.` + 2419 ` Cannot call method ${pluginMethodStr}` ); 2420 return; 2421 } 2422 2423 let method = instance[ methodName ]; 2424 if ( !method || methodName.charAt( 0 ) == '_' ) { 2425 logError(`${pluginMethodStr} is not a valid method`); 2426 return; 2427 } 2428 2429 // apply method, get return value 2430 let value = method.apply( instance, args ); 2431 // set return value if value is returned, use only first value 2432 returnValue = returnValue === undefined ? value : returnValue; 2433 } ); 2434 2435 return returnValue !== undefined ? returnValue : $elems; 2436 } 2437 2438 function plainCall( $elems, options ) { 2439 $elems.each( function( i, elem ) { 2440 let instance = $.data( elem, namespace ); 2441 if ( instance ) { 2442 // set options & init 2443 instance.option( options ); 2444 instance._init(); 2445 } else { 2446 // initialize new instance 2447 instance = new PluginClass( elem, options ); 2448 $.data( elem, namespace, instance ); 2449 } 2450 } ); 2451 } 2452 2453} 2454 2455// ----- ----- // 2456 2457return jQueryBridget; 2458 2459} ) ); 2460/** 2461 * EvEmitter v2.1.1 2462 * Lil' event emitter 2463 * MIT License 2464 */ 2465 2466( function( global, factory ) { 2467 // universal module definition 2468 if ( typeof module == 'object' && module.exports ) { 2469 // CommonJS - Browserify, Webpack 2470 module.exports = factory(); 2471 } else { 2472 // Browser globals 2473 global.EvEmitter = factory(); 2474 } 2475 2476}( typeof window != 'undefined' ? window : this, function() { 2477 2478function EvEmitter() {} 2479 2480let proto = EvEmitter.prototype; 2481 2482proto.on = function( eventName, listener ) { 2483 if ( !eventName || !listener ) return this; 2484 2485 // set events hash 2486 let events = this._events = this._events || {}; 2487 // set listeners array 2488 let listeners = events[ eventName ] = events[ eventName ] || []; 2489 // only add once 2490 if ( !listeners.includes( listener ) ) { 2491 listeners.push( listener ); 2492 } 2493 2494 return this; 2495}; 2496 2497proto.once = function( eventName, listener ) { 2498 if ( !eventName || !listener ) return this; 2499 2500 // add event 2501 this.on( eventName, listener ); 2502 // set once flag 2503 // set onceEvents hash 2504 let onceEvents = this._onceEvents = this._onceEvents || {}; 2505 // set onceListeners object 2506 let onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 2507 // set flag 2508 onceListeners[ listener ] = true; 2509 2510 return this; 2511}; 2512 2513proto.off = function( eventName, listener ) { 2514 let listeners = this._events && this._events[ eventName ]; 2515 if ( !listeners || !listeners.length ) return this; 2516 2517 let index = listeners.indexOf( listener ); 2518 if ( index != -1 ) { 2519 listeners.splice( index, 1 ); 2520 } 2521 2522 return this; 2523}; 2524 2525proto.emitEvent = function( eventName, args ) { 2526 let listeners = this._events && this._events[ eventName ]; 2527 if ( !listeners || !listeners.length ) return this; 2528 2529 // copy over to avoid interference if .off() in listener 2530 listeners = listeners.slice( 0 ); 2531 args = args || []; 2532 // once stuff 2533 let onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 2534 2535 for ( let listener of listeners ) { 2536 let isOnce = onceListeners && onceListeners[ listener ]; 2537 if ( isOnce ) { 2538 // remove listener 2539 // remove before trigger to prevent recursion 2540 this.off( eventName, listener ); 2541 // unset once flag 2542 delete onceListeners[ listener ]; 2543 } 2544 // trigger listener 2545 listener.apply( this, args ); 2546 } 2547 2548 return this; 2549}; 2550 2551proto.allOff = function() { 2552 delete this._events; 2553 delete this._onceEvents; 2554 return this; 2555}; 2556 2557return EvEmitter; 2558 2559} ) ); 2560/*! 2561 * Infinite Scroll v2.0.4 2562 * measure size of elements 2563 * MIT license 2564 */ 2565 2566( function( window, factory ) { 2567 if ( typeof module == 'object' && module.exports ) { 2568 // CommonJS 2569 module.exports = factory(); 2570 } else { 2571 // browser global 2572 window.getSize = factory(); 2573 } 2574 2575} )( window, function factory() { 2576 2577// -------------------------- helpers -------------------------- // 2578 2579// get a number from a string, not a percentage 2580function getStyleSize( value ) { 2581 let num = parseFloat( value ); 2582 // not a percent like '100%', and a number 2583 let isValid = value.indexOf('%') == -1 && !isNaN( num ); 2584 return isValid && num; 2585} 2586 2587// -------------------------- measurements -------------------------- // 2588 2589let measurements = [ 2590 'paddingLeft', 2591 'paddingRight', 2592 'paddingTop', 2593 'paddingBottom', 2594 'marginLeft', 2595 'marginRight', 2596 'marginTop', 2597 'marginBottom', 2598 'borderLeftWidth', 2599 'borderRightWidth', 2600 'borderTopWidth', 2601 'borderBottomWidth', 2602]; 2603 2604let measurementsLength = measurements.length; 2605 2606function getZeroSize() { 2607 let size = { 2608 width: 0, 2609 height: 0, 2610 innerWidth: 0, 2611 innerHeight: 0, 2612 outerWidth: 0, 2613 outerHeight: 0, 2614 }; 2615 measurements.forEach( ( measurement ) => { 2616 size[ measurement ] = 0; 2617 } ); 2618 return size; 2619} 2620 2621// -------------------------- getSize -------------------------- // 2622 2623function getSize( elem ) { 2624 // use querySeletor if elem is string 2625 if ( typeof elem == 'string' ) elem = document.querySelector( elem ); 2626 2627 // do not proceed on non-objects 2628 let isElement = elem && typeof elem == 'object' && elem.nodeType; 2629 if ( !isElement ) return; 2630 2631 let style = getComputedStyle( elem ); 2632 2633 // if hidden, everything is 0 2634 if ( style.display == 'none' ) return getZeroSize(); 2635 2636 let size = {}; 2637 size.width = elem.offsetWidth; 2638 size.height = elem.offsetHeight; 2639 2640 let isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 2641 2642 // get all measurements 2643 measurements.forEach( ( measurement ) => { 2644 let value = style[ measurement ]; 2645 let num = parseFloat( value ); 2646 // any 'auto', 'medium' value will be 0 2647 size[ measurement ] = !isNaN( num ) ? num : 0; 2648 } ); 2649 2650 let paddingWidth = size.paddingLeft + size.paddingRight; 2651 let paddingHeight = size.paddingTop + size.paddingBottom; 2652 let marginWidth = size.marginLeft + size.marginRight; 2653 let marginHeight = size.marginTop + size.marginBottom; 2654 let borderWidth = size.borderLeftWidth + size.borderRightWidth; 2655 let borderHeight = size.borderTopWidth + size.borderBottomWidth; 2656 2657 // overwrite width and height if we can get it from style 2658 let styleWidth = getStyleSize( style.width ); 2659 if ( styleWidth !== false ) { 2660 size.width = styleWidth + 2661 // add padding and border unless it's already including it 2662 ( isBorderBox ? 0 : paddingWidth + borderWidth ); 2663 } 2664 2665 let styleHeight = getStyleSize( style.height ); 2666 if ( styleHeight !== false ) { 2667 size.height = styleHeight + 2668 // add padding and border unless it's already including it 2669 ( isBorderBox ? 0 : paddingHeight + borderHeight ); 2670 } 2671 2672 size.innerWidth = size.width - ( paddingWidth + borderWidth ); 2673 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 2674 2675 size.outerWidth = size.width + marginWidth; 2676 size.outerHeight = size.height + marginHeight; 2677 2678 return size; 2679} 2680 2681return getSize; 2682 2683} ); 2684/** 2685 * Fizzy UI utils v3.0.0 2686 * MIT license 2687 */ 2688 2689( function( global, factory ) { 2690 // universal module definition 2691 if ( typeof module == 'object' && module.exports ) { 2692 // CommonJS 2693 module.exports = factory( global ); 2694 } else { 2695 // browser global 2696 global.fizzyUIUtils = factory( global ); 2697 } 2698 2699}( this, function factory( global ) { 2700 2701let utils = {}; 2702 2703// ----- extend ----- // 2704 2705// extends objects 2706utils.extend = function( a, b ) { 2707 return Object.assign( a, b ); 2708}; 2709 2710// ----- modulo ----- // 2711 2712utils.modulo = function( num, div ) { 2713 return ( ( num % div ) + div ) % div; 2714}; 2715 2716// ----- makeArray ----- // 2717 2718// turn element or nodeList into an array 2719utils.makeArray = function( obj ) { 2720 // use object if already an array 2721 if ( Array.isArray( obj ) ) return obj; 2722 2723 // return empty array if undefined or null. #6 2724 if ( obj === null || obj === undefined ) return []; 2725 2726 let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 2727 // convert nodeList to array 2728 if ( isArrayLike ) return [ ...obj ]; 2729 2730 // array of single index 2731 return [ obj ]; 2732}; 2733 2734// ----- removeFrom ----- // 2735 2736utils.removeFrom = function( ary, obj ) { 2737 let index = ary.indexOf( obj ); 2738 if ( index != -1 ) { 2739 ary.splice( index, 1 ); 2740 } 2741}; 2742 2743// ----- getParent ----- // 2744 2745utils.getParent = function( elem, selector ) { 2746 while ( elem.parentNode && elem != document.body ) { 2747 elem = elem.parentNode; 2748 if ( elem.matches( selector ) ) return elem; 2749 } 2750}; 2751 2752// ----- getQueryElement ----- // 2753 2754// use element as selector string 2755utils.getQueryElement = function( elem ) { 2756 if ( typeof elem == 'string' ) { 2757 return document.querySelector( elem ); 2758 } 2759 return elem; 2760}; 2761 2762// ----- handleEvent ----- // 2763 2764// enable .ontype to trigger from .addEventListener( elem, 'type' ) 2765utils.handleEvent = function( event ) { 2766 let method = 'on' + event.type; 2767 if ( this[ method ] ) { 2768 this[ method ]( event ); 2769 } 2770}; 2771 2772// ----- filterFindElements ----- // 2773 2774utils.filterFindElements = function( elems, selector ) { 2775 // make array of elems 2776 elems = utils.makeArray( elems ); 2777 2778 return elems 2779 // check that elem is an actual element 2780 .filter( ( elem ) => elem instanceof HTMLElement ) 2781 .reduce( ( ffElems, elem ) => { 2782 // add elem if no selector 2783 if ( !selector ) { 2784 ffElems.push( elem ); 2785 return ffElems; 2786 } 2787 // filter & find items if we have a selector 2788 // filter 2789 if ( elem.matches( selector ) ) { 2790 ffElems.push( elem ); 2791 } 2792 // find children 2793 let childElems = elem.querySelectorAll( selector ); 2794 // concat childElems to filterFound array 2795 ffElems = ffElems.concat( ...childElems ); 2796 return ffElems; 2797 }, [] ); 2798}; 2799 2800// ----- debounceMethod ----- // 2801 2802utils.debounceMethod = function( _class, methodName, threshold ) { 2803 threshold = threshold || 100; 2804 // original method 2805 let method = _class.prototype[ methodName ]; 2806 let timeoutName = methodName + 'Timeout'; 2807 2808 _class.prototype[ methodName ] = function() { 2809 clearTimeout( this[ timeoutName ] ); 2810 2811 let args = arguments; 2812 this[ timeoutName ] = setTimeout( () => { 2813 method.apply( this, args ); 2814 delete this[ timeoutName ]; 2815 }, threshold ); 2816 }; 2817}; 2818 2819// ----- docReady ----- // 2820 2821utils.docReady = function( onDocReady ) { 2822 let readyState = document.readyState; 2823 if ( readyState == 'complete' || readyState == 'interactive' ) { 2824 // do async to allow for other scripts to run. metafizzy/flickity#441 2825 setTimeout( onDocReady ); 2826 } else { 2827 document.addEventListener( 'DOMContentLoaded', onDocReady ); 2828 } 2829}; 2830 2831// ----- htmlInit ----- // 2832 2833// http://bit.ly/3oYLusc 2834utils.toDashed = function( str ) { 2835 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 2836 return $1 + '-' + $2; 2837 } ).toLowerCase(); 2838}; 2839 2840let console = global.console; 2841 2842// allow user to initialize classes via [data-namespace] or .js-namespace class 2843// htmlInit( Widget, 'widgetName' ) 2844// options are parsed from data-namespace-options 2845utils.htmlInit = function( WidgetClass, namespace ) { 2846 utils.docReady( function() { 2847 let dashedNamespace = utils.toDashed( namespace ); 2848 let dataAttr = 'data-' + dashedNamespace; 2849 let dataAttrElems = document.querySelectorAll( `[${dataAttr}]` ); 2850 let jQuery = global.jQuery; 2851 2852 [ ...dataAttrElems ].forEach( ( elem ) => { 2853 let attr = elem.getAttribute( dataAttr ); 2854 let options; 2855 try { 2856 options = attr && JSON.parse( attr ); 2857 } catch ( error ) { 2858 // log error, do not initialize 2859 if ( console ) { 2860 console.error( `Error parsing ${dataAttr} on ${elem.className}: ${error}` ); 2861 } 2862 return; 2863 } 2864 // initialize 2865 let instance = new WidgetClass( elem, options ); 2866 // make available via $().data('namespace') 2867 if ( jQuery ) { 2868 jQuery.data( elem, namespace, instance ); 2869 } 2870 } ); 2871 2872 } ); 2873}; 2874 2875// ----- ----- // 2876 2877return utils; 2878 2879} ) ); 2880/*! 2881 * Unidragger v3.0.0 2882 * Draggable base class 2883 * MIT license 2884 */ 2885 2886( function( window, factory ) { 2887 // universal module definition 2888 if ( typeof module == 'object' && module.exports ) { 2889 // CommonJS 2890 module.exports = factory( 2891 window, 2892 require('ev-emitter'), 2893 ); 2894 } else { 2895 // browser global 2896 window.Unidragger = factory( 2897 window, 2898 window.EvEmitter, 2899 ); 2900 } 2901 2902}( typeof window != 'undefined' ? window : this, function factory( window, EvEmitter ) { 2903 2904function Unidragger() {} 2905 2906// inherit EvEmitter 2907let proto = Unidragger.prototype = Object.create( EvEmitter.prototype ); 2908 2909// ----- bind start ----- // 2910 2911// trigger handler methods for events 2912proto.handleEvent = function( event ) { 2913 let method = 'on' + event.type; 2914 if ( this[ method ] ) { 2915 this[ method ]( event ); 2916 } 2917}; 2918 2919let startEvent, activeEvents; 2920if ( 'ontouchstart' in window ) { 2921 // HACK prefer Touch Events as you can preventDefault on touchstart to 2922 // disable scroll in iOS & mobile Chrome metafizzy/flickity#1177 2923 startEvent = 'touchstart'; 2924 activeEvents = [ 'touchmove', 'touchend', 'touchcancel' ]; 2925} else if ( window.PointerEvent ) { 2926 // Pointer Events 2927 startEvent = 'pointerdown'; 2928 activeEvents = [ 'pointermove', 'pointerup', 'pointercancel' ]; 2929} else { 2930 // mouse events 2931 startEvent = 'mousedown'; 2932 activeEvents = [ 'mousemove', 'mouseup' ]; 2933} 2934 2935// prototype so it can be overwriteable by Flickity 2936proto.touchActionValue = 'none'; 2937 2938proto.bindHandles = function() { 2939 this._bindHandles( 'addEventListener', this.touchActionValue ); 2940}; 2941 2942proto.unbindHandles = function() { 2943 this._bindHandles( 'removeEventListener', '' ); 2944}; 2945 2946/** 2947 * Add or remove start event 2948 * @param {String} bindMethod - addEventListener or removeEventListener 2949 * @param {String} touchAction - value for touch-action CSS property 2950 */ 2951proto._bindHandles = function( bindMethod, touchAction ) { 2952 this.handles.forEach( ( handle ) => { 2953 handle[ bindMethod ]( startEvent, this ); 2954 handle[ bindMethod ]( 'click', this ); 2955 // touch-action: none to override browser touch gestures. metafizzy/flickity#540 2956 if ( window.PointerEvent ) handle.style.touchAction = touchAction; 2957 } ); 2958}; 2959 2960proto.bindActivePointerEvents = function() { 2961 activeEvents.forEach( ( eventName ) => { 2962 window.addEventListener( eventName, this ); 2963 } ); 2964}; 2965 2966proto.unbindActivePointerEvents = function() { 2967 activeEvents.forEach( ( eventName ) => { 2968 window.removeEventListener( eventName, this ); 2969 } ); 2970}; 2971 2972// ----- event handler helpers ----- // 2973 2974// trigger method with matching pointer 2975proto.withPointer = function( methodName, event ) { 2976 if ( event.pointerId == this.pointerIdentifier ) { 2977 this[ methodName ]( event, event ); 2978 } 2979}; 2980 2981// trigger method with matching touch 2982proto.withTouch = function( methodName, event ) { 2983 let touch; 2984 for ( let changedTouch of event.changedTouches ) { 2985 if ( changedTouch.identifier == this.pointerIdentifier ) { 2986 touch = changedTouch; 2987 } 2988 } 2989 if ( touch ) this[ methodName ]( event, touch ); 2990}; 2991 2992// ----- start event ----- // 2993 2994proto.onmousedown = function( event ) { 2995 this.pointerDown( event, event ); 2996}; 2997 2998proto.ontouchstart = function( event ) { 2999 this.pointerDown( event, event.changedTouches[0] ); 3000}; 3001 3002proto.onpointerdown = function( event ) { 3003 this.pointerDown( event, event ); 3004}; 3005 3006// nodes that have text fields 3007const cursorNodes = [ 'TEXTAREA', 'INPUT', 'SELECT', 'OPTION' ]; 3008// input types that do not have text fields 3009const clickTypes = [ 'radio', 'checkbox', 'button', 'submit', 'image', 'file' ]; 3010 3011/** 3012 * any time you set `event, pointer` it refers to: 3013 * @param {Event} event 3014 * @param {Event | Touch} pointer 3015 */ 3016proto.pointerDown = function( event, pointer ) { 3017 // dismiss multi-touch taps, right clicks, and clicks on text fields 3018 let isCursorNode = cursorNodes.includes( event.target.nodeName ); 3019 let isClickType = clickTypes.includes( event.target.type ); 3020 let isOkayElement = !isCursorNode || isClickType; 3021 let isOkay = !this.isPointerDown && !event.button && isOkayElement; 3022 if ( !isOkay ) return; 3023 3024 this.isPointerDown = true; 3025 // save pointer identifier to match up touch events 3026 this.pointerIdentifier = pointer.pointerId !== undefined ? 3027 // pointerId for pointer events, touch.indentifier for touch events 3028 pointer.pointerId : pointer.identifier; 3029 // track position for move 3030 this.pointerDownPointer = { 3031 pageX: pointer.pageX, 3032 pageY: pointer.pageY, 3033 }; 3034 3035 this.bindActivePointerEvents(); 3036 this.emitEvent( 'pointerDown', [ event, pointer ] ); 3037}; 3038 3039// ----- move ----- // 3040 3041proto.onmousemove = function( event ) { 3042 this.pointerMove( event, event ); 3043}; 3044 3045proto.onpointermove = function( event ) { 3046 this.withPointer( 'pointerMove', event ); 3047}; 3048 3049proto.ontouchmove = function( event ) { 3050 this.withTouch( 'pointerMove', event ); 3051}; 3052 3053proto.pointerMove = function( event, pointer ) { 3054 let moveVector = { 3055 x: pointer.pageX - this.pointerDownPointer.pageX, 3056 y: pointer.pageY - this.pointerDownPointer.pageY, 3057 }; 3058 this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] ); 3059 // start drag if pointer has moved far enough to start drag 3060 let isDragStarting = !this.isDragging && this.hasDragStarted( moveVector ); 3061 if ( isDragStarting ) this.dragStart( event, pointer ); 3062 if ( this.isDragging ) this.dragMove( event, pointer, moveVector ); 3063}; 3064 3065// condition if pointer has moved far enough to start drag 3066proto.hasDragStarted = function( moveVector ) { 3067 return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3; 3068}; 3069 3070// ----- drag ----- // 3071 3072proto.dragStart = function( event, pointer ) { 3073 this.isDragging = true; 3074 this.isPreventingClicks = true; // set flag to prevent clicks 3075 this.emitEvent( 'dragStart', [ event, pointer ] ); 3076}; 3077 3078proto.dragMove = function( event, pointer, moveVector ) { 3079 this.emitEvent( 'dragMove', [ event, pointer, moveVector ] ); 3080}; 3081 3082// ----- end ----- // 3083 3084proto.onmouseup = function( event ) { 3085 this.pointerUp( event, event ); 3086}; 3087 3088proto.onpointerup = function( event ) { 3089 this.withPointer( 'pointerUp', event ); 3090}; 3091 3092proto.ontouchend = function( event ) { 3093 this.withTouch( 'pointerUp', event ); 3094}; 3095 3096proto.pointerUp = function( event, pointer ) { 3097 this.pointerDone(); 3098 this.emitEvent( 'pointerUp', [ event, pointer ] ); 3099 3100 if ( this.isDragging ) { 3101 this.dragEnd( event, pointer ); 3102 } else { 3103 // pointer didn't move enough for drag to start 3104 this.staticClick( event, pointer ); 3105 } 3106}; 3107 3108proto.dragEnd = function( event, pointer ) { 3109 this.isDragging = false; // reset flag 3110 // re-enable clicking async 3111 setTimeout( () => delete this.isPreventingClicks ); 3112 3113 this.emitEvent( 'dragEnd', [ event, pointer ] ); 3114}; 3115 3116// triggered on pointer up & pointer cancel 3117proto.pointerDone = function() { 3118 this.isPointerDown = false; 3119 delete this.pointerIdentifier; 3120 this.unbindActivePointerEvents(); 3121 this.emitEvent('pointerDone'); 3122}; 3123 3124// ----- cancel ----- // 3125 3126proto.onpointercancel = function( event ) { 3127 this.withPointer( 'pointerCancel', event ); 3128}; 3129 3130proto.ontouchcancel = function( event ) { 3131 this.withTouch( 'pointerCancel', event ); 3132}; 3133 3134proto.pointerCancel = function( event, pointer ) { 3135 this.pointerDone(); 3136 this.emitEvent( 'pointerCancel', [ event, pointer ] ); 3137}; 3138 3139// ----- click ----- // 3140 3141// handle all clicks and prevent clicks when dragging 3142proto.onclick = function( event ) { 3143 if ( this.isPreventingClicks ) event.preventDefault(); 3144}; 3145 3146// triggered after pointer down & up with no/tiny movement 3147proto.staticClick = function( event, pointer ) { 3148 // ignore emulated mouse up clicks 3149 let isMouseup = event.type == 'mouseup'; 3150 if ( isMouseup && this.isIgnoringMouseUp ) return; 3151 3152 this.emitEvent( 'staticClick', [ event, pointer ] ); 3153 3154 // set flag for emulated clicks 300ms after touchend 3155 if ( isMouseup ) { 3156 this.isIgnoringMouseUp = true; 3157 // reset flag after 400ms 3158 setTimeout( () => { 3159 delete this.isIgnoringMouseUp; 3160 }, 400 ); 3161 } 3162}; 3163 3164// ----- ----- // 3165 3166return Unidragger; 3167 3168} ) ); 3169/*! 3170 * imagesLoaded v5.0.0 3171 * JavaScript is all like "You images are done yet or what?" 3172 * MIT License 3173 */ 3174 3175( function( window, factory ) { 3176 // universal module definition 3177 if ( typeof module == 'object' && module.exports ) { 3178 // CommonJS 3179 module.exports = factory( window, require('ev-emitter') ); 3180 } else { 3181 // browser global 3182 window.imagesLoaded = factory( window, window.EvEmitter ); 3183 } 3184 3185} )( typeof window !== 'undefined' ? window : this, 3186 function factory( window, EvEmitter ) { 3187 3188let $ = window.jQuery; 3189let console = window.console; 3190 3191// -------------------------- helpers -------------------------- // 3192 3193// turn element or nodeList into an array 3194function makeArray( obj ) { 3195 // use object if already an array 3196 if ( Array.isArray( obj ) ) return obj; 3197 3198 let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 3199 // convert nodeList to array 3200 if ( isArrayLike ) return [ ...obj ]; 3201 3202 // array of single index 3203 return [ obj ]; 3204} 3205 3206// -------------------------- imagesLoaded -------------------------- // 3207 3208/** 3209 * @param {[Array, Element, NodeList, String]} elem 3210 * @param {[Object, Function]} options - if function, use as callback 3211 * @param {Function} onAlways - callback function 3212 * @returns {ImagesLoaded} 3213 */ 3214function ImagesLoaded( elem, options, onAlways ) { 3215 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 3216 if ( !( this instanceof ImagesLoaded ) ) { 3217 return new ImagesLoaded( elem, options, onAlways ); 3218 } 3219 // use elem as selector string 3220 let queryElem = elem; 3221 if ( typeof elem == 'string' ) { 3222 queryElem = document.querySelectorAll( elem ); 3223 } 3224 // bail if bad element 3225 if ( !queryElem ) { 3226 console.error(`Bad element for imagesLoaded ${queryElem || elem}`); 3227 return; 3228 } 3229 3230 this.elements = makeArray( queryElem ); 3231 this.options = {}; 3232 // shift arguments if no options set 3233 if ( typeof options == 'function' ) { 3234 onAlways = options; 3235 } else { 3236 Object.assign( this.options, options ); 3237 } 3238 3239 if ( onAlways ) this.on( 'always', onAlways ); 3240 3241 this.getImages(); 3242 // add jQuery Deferred object 3243 if ( $ ) this.jqDeferred = new $.Deferred(); 3244 3245 // HACK check async to allow time to bind listeners 3246 setTimeout( this.check.bind( this ) ); 3247} 3248 3249ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 3250 3251ImagesLoaded.prototype.getImages = function() { 3252 this.images = []; 3253 3254 // filter & find items if we have an item selector 3255 this.elements.forEach( this.addElementImages, this ); 3256}; 3257 3258const elementNodeTypes = [ 1, 9, 11 ]; 3259 3260/** 3261 * @param {Node} elem 3262 */ 3263ImagesLoaded.prototype.addElementImages = function( elem ) { 3264 // filter siblings 3265 if ( elem.nodeName === 'IMG' ) { 3266 this.addImage( elem ); 3267 } 3268 // get background image on element 3269 if ( this.options.background === true ) { 3270 this.addElementBackgroundImages( elem ); 3271 } 3272 3273 // find children 3274 // no non-element nodes, #143 3275 let { nodeType } = elem; 3276 if ( !nodeType || !elementNodeTypes.includes( nodeType ) ) return; 3277 3278 let childImgs = elem.querySelectorAll('img'); 3279 // concat childElems to filterFound array 3280 for ( let img of childImgs ) { 3281 this.addImage( img ); 3282 } 3283 3284 // get child background images 3285 if ( typeof this.options.background == 'string' ) { 3286 let children = elem.querySelectorAll( this.options.background ); 3287 for ( let child of children ) { 3288 this.addElementBackgroundImages( child ); 3289 } 3290 } 3291}; 3292 3293const reURL = /url\((['"])?(.*?)\1\)/gi; 3294 3295ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 3296 let style = getComputedStyle( elem ); 3297 // Firefox returns null if in a hidden iframe https://bugzil.la/548397 3298 if ( !style ) return; 3299 3300 // get url inside url("...") 3301 let matches = reURL.exec( style.backgroundImage ); 3302 while ( matches !== null ) { 3303 let url = matches && matches[2]; 3304 if ( url ) { 3305 this.addBackground( url, elem ); 3306 } 3307 matches = reURL.exec( style.backgroundImage ); 3308 } 3309}; 3310 3311/** 3312 * @param {Image} img 3313 */ 3314ImagesLoaded.prototype.addImage = function( img ) { 3315 let loadingImage = new LoadingImage( img ); 3316 this.images.push( loadingImage ); 3317}; 3318 3319ImagesLoaded.prototype.addBackground = function( url, elem ) { 3320 let background = new Background( url, elem ); 3321 this.images.push( background ); 3322}; 3323 3324ImagesLoaded.prototype.check = function() { 3325 this.progressedCount = 0; 3326 this.hasAnyBroken = false; 3327 // complete if no images 3328 if ( !this.images.length ) { 3329 this.complete(); 3330 return; 3331 } 3332 3333 /* eslint-disable-next-line func-style */ 3334 let onProgress = ( image, elem, message ) => { 3335 // HACK - Chrome triggers event before object properties have changed. #83 3336 setTimeout( () => { 3337 this.progress( image, elem, message ); 3338 } ); 3339 }; 3340 3341 this.images.forEach( function( loadingImage ) { 3342 loadingImage.once( 'progress', onProgress ); 3343 loadingImage.check(); 3344 } ); 3345}; 3346 3347ImagesLoaded.prototype.progress = function( image, elem, message ) { 3348 this.progressedCount++; 3349 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 3350 // progress event 3351 this.emitEvent( 'progress', [ this, image, elem ] ); 3352 if ( this.jqDeferred && this.jqDeferred.notify ) { 3353 this.jqDeferred.notify( this, image ); 3354 } 3355 // check if completed 3356 if ( this.progressedCount === this.images.length ) { 3357 this.complete(); 3358 } 3359 3360 if ( this.options.debug && console ) { 3361 console.log( `progress: ${message}`, image, elem ); 3362 } 3363}; 3364 3365ImagesLoaded.prototype.complete = function() { 3366 let eventName = this.hasAnyBroken ? 'fail' : 'done'; 3367 this.isComplete = true; 3368 this.emitEvent( eventName, [ this ] ); 3369 this.emitEvent( 'always', [ this ] ); 3370 if ( this.jqDeferred ) { 3371 let jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 3372 this.jqDeferred[ jqMethod ]( this ); 3373 } 3374}; 3375 3376// -------------------------- -------------------------- // 3377 3378function LoadingImage( img ) { 3379 this.img = img; 3380} 3381 3382LoadingImage.prototype = Object.create( EvEmitter.prototype ); 3383 3384LoadingImage.prototype.check = function() { 3385 // If complete is true and browser supports natural sizes, 3386 // try to check for image status manually. 3387 let isComplete = this.getIsImageComplete(); 3388 if ( isComplete ) { 3389 // report based on naturalWidth 3390 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 3391 return; 3392 } 3393 3394 // If none of the checks above matched, simulate loading on detached element. 3395 this.proxyImage = new Image(); 3396 // add crossOrigin attribute. #204 3397 if ( this.img.crossOrigin ) { 3398 this.proxyImage.crossOrigin = this.img.crossOrigin; 3399 } 3400 this.proxyImage.addEventListener( 'load', this ); 3401 this.proxyImage.addEventListener( 'error', this ); 3402 // bind to image as well for Firefox. #191 3403 this.img.addEventListener( 'load', this ); 3404 this.img.addEventListener( 'error', this ); 3405 this.proxyImage.src = this.img.currentSrc || this.img.src; 3406}; 3407 3408LoadingImage.prototype.getIsImageComplete = function() { 3409 // check for non-zero, non-undefined naturalWidth 3410 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 3411 return this.img.complete && this.img.naturalWidth; 3412}; 3413 3414LoadingImage.prototype.confirm = function( isLoaded, message ) { 3415 this.isLoaded = isLoaded; 3416 let { parentNode } = this.img; 3417 // emit progress with parent <picture> or self <img> 3418 let elem = parentNode.nodeName === 'PICTURE' ? parentNode : this.img; 3419 this.emitEvent( 'progress', [ this, elem, message ] ); 3420}; 3421 3422// ----- events ----- // 3423 3424// trigger specified handler for event type 3425LoadingImage.prototype.handleEvent = function( event ) { 3426 let method = 'on' + event.type; 3427 if ( this[ method ] ) { 3428 this[ method ]( event ); 3429 } 3430}; 3431 3432LoadingImage.prototype.onload = function() { 3433 this.confirm( true, 'onload' ); 3434 this.unbindEvents(); 3435}; 3436 3437LoadingImage.prototype.onerror = function() { 3438 this.confirm( false, 'onerror' ); 3439 this.unbindEvents(); 3440}; 3441 3442LoadingImage.prototype.unbindEvents = function() { 3443 this.proxyImage.removeEventListener( 'load', this ); 3444 this.proxyImage.removeEventListener( 'error', this ); 3445 this.img.removeEventListener( 'load', this ); 3446 this.img.removeEventListener( 'error', this ); 3447}; 3448 3449// -------------------------- Background -------------------------- // 3450 3451function Background( url, element ) { 3452 this.url = url; 3453 this.element = element; 3454 this.img = new Image(); 3455} 3456 3457// inherit LoadingImage prototype 3458Background.prototype = Object.create( LoadingImage.prototype ); 3459 3460Background.prototype.check = function() { 3461 this.img.addEventListener( 'load', this ); 3462 this.img.addEventListener( 'error', this ); 3463 this.img.src = this.url; 3464 // check if image is already complete 3465 let isComplete = this.getIsImageComplete(); 3466 if ( isComplete ) { 3467 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 3468 this.unbindEvents(); 3469 } 3470}; 3471 3472Background.prototype.unbindEvents = function() { 3473 this.img.removeEventListener( 'load', this ); 3474 this.img.removeEventListener( 'error', this ); 3475}; 3476 3477Background.prototype.confirm = function( isLoaded, message ) { 3478 this.isLoaded = isLoaded; 3479 this.emitEvent( 'progress', [ this, this.element, message ] ); 3480}; 3481 3482// -------------------------- jQuery -------------------------- // 3483 3484ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 3485 jQuery = jQuery || window.jQuery; 3486 if ( !jQuery ) return; 3487 3488 // set local variable 3489 $ = jQuery; 3490 // $().imagesLoaded() 3491 $.fn.imagesLoaded = function( options, onAlways ) { 3492 let instance = new ImagesLoaded( this, options, onAlways ); 3493 return instance.jqDeferred.promise( $( this ) ); 3494 }; 3495}; 3496// try making plugin 3497ImagesLoaded.makeJQueryPlugin(); 3498 3499// -------------------------- -------------------------- // 3500 3501return ImagesLoaded; 3502 3503} ); 3504// Flickity.Cell 3505( function( window, factory ) { 3506 // universal module definition 3507 if ( typeof module == 'object' && module.exports ) { 3508 // CommonJS 3509 module.exports = factory( require('get-size') ); 3510 } else { 3511 // browser global 3512 window.Flickity = window.Flickity || {}; 3513 window.Flickity.Cell = factory( window.getSize ); 3514 } 3515 3516}( typeof window != 'undefined' ? window : this, function factory( getSize ) { 3517 3518const cellClassName = 'flickity-cell'; 3519 3520function Cell( elem ) { 3521 this.element = elem; 3522 this.element.classList.add( cellClassName ); 3523 3524 this.x = 0; 3525 this.unselect(); 3526} 3527 3528let proto = Cell.prototype; 3529 3530proto.destroy = function() { 3531 // reset style 3532 this.unselect(); 3533 this.element.classList.remove( cellClassName ); 3534 this.element.style.transform = ''; 3535 this.element.removeAttribute('aria-hidden'); 3536}; 3537 3538proto.getSize = function() { 3539 this.size = getSize( this.element ); 3540}; 3541 3542proto.select = function() { 3543 this.element.classList.add('is-selected'); 3544 this.element.removeAttribute('aria-hidden'); 3545}; 3546 3547proto.unselect = function() { 3548 this.element.classList.remove('is-selected'); 3549 this.element.setAttribute( 'aria-hidden', 'true' ); 3550}; 3551 3552proto.remove = function() { 3553 this.element.remove(); 3554}; 3555 3556return Cell; 3557 3558} ) ); 3559// slide 3560( function( window, factory ) { 3561 // universal module definition 3562 if ( typeof module == 'object' && module.exports ) { 3563 // CommonJS 3564 module.exports = factory(); 3565 } else { 3566 // browser global 3567 window.Flickity = window.Flickity || {}; 3568 window.Flickity.Slide = factory(); 3569 } 3570 3571}( typeof window != 'undefined' ? window : this, function factory() { 3572 3573function Slide( beginMargin, endMargin, cellAlign ) { 3574 this.beginMargin = beginMargin; 3575 this.endMargin = endMargin; 3576 this.cellAlign = cellAlign; 3577 this.cells = []; 3578 this.outerWidth = 0; 3579 this.height = 0; 3580} 3581 3582let proto = Slide.prototype; 3583 3584proto.addCell = function( cell ) { 3585 this.cells.push( cell ); 3586 this.outerWidth += cell.size.outerWidth; 3587 this.height = Math.max( cell.size.outerHeight, this.height ); 3588 // first cell stuff 3589 if ( this.cells.length === 1 ) { 3590 this.x = cell.x; // x comes from first cell 3591 this.firstMargin = cell.size[ this.beginMargin ]; 3592 } 3593}; 3594 3595proto.updateTarget = function() { 3596 let lastCell = this.getLastCell(); 3597 let lastMargin = lastCell ? lastCell.size[ this.endMargin ] : 0; 3598 let slideWidth = this.outerWidth - ( this.firstMargin + lastMargin ); 3599 this.target = this.x + this.firstMargin + slideWidth * this.cellAlign; 3600}; 3601 3602proto.getLastCell = function() { 3603 return this.cells[ this.cells.length - 1 ]; 3604}; 3605 3606proto.select = function() { 3607 this.cells.forEach( ( cell ) => cell.select() ); 3608}; 3609 3610proto.unselect = function() { 3611 this.cells.forEach( ( cell ) => cell.unselect() ); 3612}; 3613 3614proto.getCellElements = function() { 3615 return this.cells.map( ( cell ) => cell.element ); 3616}; 3617 3618return Slide; 3619 3620} ) ); 3621// animate 3622( function( window, factory ) { 3623 // universal module definition 3624 if ( typeof module == 'object' && module.exports ) { 3625 // CommonJS 3626 module.exports = factory( require('fizzy-ui-utils') ); 3627 } else { 3628 // browser global 3629 window.Flickity = window.Flickity || {}; 3630 window.Flickity.animatePrototype = factory( window.fizzyUIUtils ); 3631 } 3632 3633}( typeof window != 'undefined' ? window : this, function factory( utils ) { 3634 3635// -------------------------- animate -------------------------- // 3636 3637let proto = {}; 3638 3639proto.startAnimation = function() { 3640 if ( this.isAnimating ) return; 3641 3642 this.isAnimating = true; 3643 this.restingFrames = 0; 3644 this.animate(); 3645}; 3646 3647proto.animate = function() { 3648 this.applyDragForce(); 3649 this.applySelectedAttraction(); 3650 3651 let previousX = this.x; 3652 3653 this.integratePhysics(); 3654 this.positionSlider(); 3655 this.settle( previousX ); 3656 // animate next frame 3657 if ( this.isAnimating ) requestAnimationFrame( () => this.animate() ); 3658}; 3659 3660proto.positionSlider = function() { 3661 let x = this.x; 3662 // wrap position around 3663 if ( this.isWrapping ) { 3664 x = utils.modulo( x, this.slideableWidth ) - this.slideableWidth; 3665 this.shiftWrapCells( x ); 3666 } 3667 3668 this.setTranslateX( x, this.isAnimating ); 3669 this.dispatchScrollEvent(); 3670}; 3671 3672proto.setTranslateX = function( x, is3d ) { 3673 x += this.cursorPosition; 3674 // reverse if right-to-left and using transform 3675 if ( this.options.rightToLeft ) x = -x; 3676 let translateX = this.getPositionValue( x ); 3677 // use 3D transforms for hardware acceleration on iOS 3678 // but use 2D when settled, for better font-rendering 3679 this.slider.style.transform = is3d ? 3680 `translate3d(${translateX},0,0)` : `translateX(${translateX})`; 3681}; 3682 3683proto.dispatchScrollEvent = function() { 3684 let firstSlide = this.slides[0]; 3685 if ( !firstSlide ) return; 3686 3687 let positionX = -this.x - firstSlide.target; 3688 let progress = positionX / this.slidesWidth; 3689 this.dispatchEvent( 'scroll', null, [ progress, positionX ] ); 3690}; 3691 3692proto.positionSliderAtSelected = function() { 3693 if ( !this.cells.length ) return; 3694 3695 this.x = -this.selectedSlide.target; 3696 this.velocity = 0; // stop wobble 3697 this.positionSlider(); 3698}; 3699 3700proto.getPositionValue = function( position ) { 3701 if ( this.options.percentPosition ) { 3702 // percent position, round to 2 digits, like 12.34% 3703 return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 ) + '%'; 3704 } else { 3705 // pixel positioning 3706 return Math.round( position ) + 'px'; 3707 } 3708}; 3709 3710proto.settle = function( previousX ) { 3711 // keep track of frames where x hasn't moved 3712 let isResting = !this.isPointerDown && 3713 Math.round( this.x * 100 ) === Math.round( previousX * 100 ); 3714 if ( isResting ) this.restingFrames++; 3715 // stop animating if resting for 3 or more frames 3716 if ( this.restingFrames > 2 ) { 3717 this.isAnimating = false; 3718 delete this.isFreeScrolling; 3719 // render position with translateX when settled 3720 this.positionSlider(); 3721 this.dispatchEvent( 'settle', null, [ this.selectedIndex ] ); 3722 } 3723}; 3724 3725proto.shiftWrapCells = function( x ) { 3726 // shift before cells 3727 let beforeGap = this.cursorPosition + x; 3728 this._shiftCells( this.beforeShiftCells, beforeGap, -1 ); 3729 // shift after cells 3730 let afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition ); 3731 this._shiftCells( this.afterShiftCells, afterGap, 1 ); 3732}; 3733 3734proto._shiftCells = function( cells, gap, shift ) { 3735 cells.forEach( ( cell ) => { 3736 let cellShift = gap > 0 ? shift : 0; 3737 this._wrapShiftCell( cell, cellShift ); 3738 gap -= cell.size.outerWidth; 3739 } ); 3740}; 3741 3742proto._unshiftCells = function( cells ) { 3743 if ( !cells || !cells.length ) return; 3744 3745 cells.forEach( ( cell ) => this._wrapShiftCell( cell, 0 ) ); 3746}; 3747 3748// @param {Integer} shift - 0, 1, or -1 3749proto._wrapShiftCell = function( cell, shift ) { 3750 this._renderCellPosition( cell, cell.x + this.slideableWidth * shift ); 3751}; 3752 3753// -------------------------- physics -------------------------- // 3754 3755proto.integratePhysics = function() { 3756 this.x += this.velocity; 3757 this.velocity *= this.getFrictionFactor(); 3758}; 3759 3760proto.applyForce = function( force ) { 3761 this.velocity += force; 3762}; 3763 3764proto.getFrictionFactor = function() { 3765 return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ]; 3766}; 3767 3768proto.getRestingPosition = function() { 3769 // my thanks to Steven Wittens, who simplified this math greatly 3770 return this.x + this.velocity / ( 1 - this.getFrictionFactor() ); 3771}; 3772 3773proto.applyDragForce = function() { 3774 if ( !this.isDraggable || !this.isPointerDown ) return; 3775 3776 // change the position to drag position by applying force 3777 let dragVelocity = this.dragX - this.x; 3778 let dragForce = dragVelocity - this.velocity; 3779 this.applyForce( dragForce ); 3780}; 3781 3782proto.applySelectedAttraction = function() { 3783 // do not attract if pointer down or no slides 3784 let dragDown = this.isDraggable && this.isPointerDown; 3785 if ( dragDown || this.isFreeScrolling || !this.slides.length ) return; 3786 3787 let distance = this.selectedSlide.target * -1 - this.x; 3788 let force = distance * this.options.selectedAttraction; 3789 this.applyForce( force ); 3790}; 3791 3792return proto; 3793 3794} ) ); 3795// Flickity main 3796/* eslint-disable max-params */ 3797( function( window, factory ) { 3798 // universal module definition 3799 if ( typeof module == 'object' && module.exports ) { 3800 // CommonJS 3801 module.exports = factory( 3802 window, 3803 require('ev-emitter'), 3804 require('get-size'), 3805 require('fizzy-ui-utils'), 3806 require('./cell'), 3807 require('./slide'), 3808 require('./animate'), 3809 ); 3810 } else { 3811 // browser global 3812 let _Flickity = window.Flickity; 3813 3814 window.Flickity = factory( 3815 window, 3816 window.EvEmitter, 3817 window.getSize, 3818 window.fizzyUIUtils, 3819 _Flickity.Cell, 3820 _Flickity.Slide, 3821 _Flickity.animatePrototype, 3822 ); 3823 } 3824 3825}( typeof window != 'undefined' ? window : this, 3826 function factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) { 3827/* eslint-enable max-params */ 3828 3829// vars 3830const { getComputedStyle, console } = window; 3831let { jQuery } = window; 3832 3833// -------------------------- Flickity -------------------------- // 3834 3835// globally unique identifiers 3836let GUID = 0; 3837// internal store of all Flickity intances 3838let instances = {}; 3839 3840function Flickity( element, options ) { 3841 let queryElement = utils.getQueryElement( element ); 3842 if ( !queryElement ) { 3843 if ( console ) console.error(`Bad element for Flickity: ${queryElement || element}`); 3844 return; 3845 } 3846 this.element = queryElement; 3847 // do not initialize twice on same element 3848 if ( this.element.flickityGUID ) { 3849 let instance = instances[ this.element.flickityGUID ]; 3850 if ( instance ) instance.option( options ); 3851 return instance; 3852 } 3853 3854 // add jQuery 3855 if ( jQuery ) { 3856 this.$element = jQuery( this.element ); 3857 } 3858 // options 3859 this.options = { ...this.constructor.defaults }; 3860 this.option( options ); 3861 3862 // kick things off 3863 this._create(); 3864} 3865 3866Flickity.defaults = { 3867 accessibility: true, 3868 // adaptiveHeight: false, 3869 cellAlign: 'center', 3870 // cellSelector: undefined, 3871 // contain: false, 3872 freeScrollFriction: 0.075, // friction when free-scrolling 3873 friction: 0.28, // friction when selecting 3874 namespaceJQueryEvents: true, 3875 // initialIndex: 0, 3876 percentPosition: true, 3877 resize: true, 3878 selectedAttraction: 0.025, 3879 setGallerySize: true, 3880 // watchCSS: false, 3881 // wrapAround: false 3882}; 3883 3884// hash of methods triggered on _create() 3885Flickity.create = {}; 3886 3887let proto = Flickity.prototype; 3888// inherit EventEmitter 3889Object.assign( proto, EvEmitter.prototype ); 3890 3891proto._create = function() { 3892 let { resize, watchCSS, rightToLeft } = this.options; 3893 // add id for Flickity.data 3894 let id = this.guid = ++GUID; 3895 this.element.flickityGUID = id; // expando 3896 instances[ id ] = this; // associate via id 3897 // initial properties 3898 this.selectedIndex = 0; 3899 // how many frames slider has been in same position 3900 this.restingFrames = 0; 3901 // initial physics properties 3902 this.x = 0; 3903 this.velocity = 0; 3904 this.beginMargin = rightToLeft ? 'marginRight' : 'marginLeft'; 3905 this.endMargin = rightToLeft ? 'marginLeft' : 'marginRight'; 3906 // create viewport & slider 3907 this.viewport = document.createElement('div'); 3908 this.viewport.className = 'flickity-viewport'; 3909 this._createSlider(); 3910 // used for keyboard navigation 3911 this.focusableElems = [ this.element ]; 3912 3913 if ( resize || watchCSS ) { 3914 window.addEventListener( 'resize', this ); 3915 } 3916 3917 // add listeners from on option 3918 for ( let eventName in this.options.on ) { 3919 let listener = this.options.on[ eventName ]; 3920 this.on( eventName, listener ); 3921 } 3922 3923 for ( let method in Flickity.create ) { 3924 Flickity.create[ method ].call( this ); 3925 } 3926 3927 if ( watchCSS ) { 3928 this.watchCSS(); 3929 } else { 3930 this.activate(); 3931 } 3932}; 3933 3934/** 3935 * set options 3936 * @param {Object} opts - options to extend 3937 */ 3938proto.option = function( opts ) { 3939 Object.assign( this.options, opts ); 3940}; 3941 3942proto.activate = function() { 3943 if ( this.isActive ) return; 3944 3945 this.isActive = true; 3946 this.element.classList.add('flickity-enabled'); 3947 if ( this.options.rightToLeft ) { 3948 this.element.classList.add('flickity-rtl'); 3949 } 3950 3951 this.getSize(); 3952 // move initial cell elements so they can be loaded as cells 3953 let cellElems = this._filterFindCellElements( this.element.children ); 3954 this.slider.append( ...cellElems ); 3955 this.viewport.append( this.slider ); 3956 this.element.append( this.viewport ); 3957 // get cells from children 3958 this.reloadCells(); 3959 3960 if ( this.options.accessibility ) { 3961 // allow element to focusable 3962 this.element.tabIndex = 0; 3963 // listen for key presses 3964 this.element.addEventListener( 'keydown', this ); 3965 } 3966 3967 this.emitEvent('activate'); 3968 this.selectInitialIndex(); 3969 // flag for initial activation, for using initialIndex 3970 this.isInitActivated = true; 3971 // ready event. #493 3972 this.dispatchEvent('ready'); 3973}; 3974 3975// slider positions the cells 3976proto._createSlider = function() { 3977 // slider element does all the positioning 3978 let slider = document.createElement('div'); 3979 slider.className = 'flickity-slider'; 3980 this.slider = slider; 3981}; 3982 3983proto._filterFindCellElements = function( elems ) { 3984 return utils.filterFindElements( elems, this.options.cellSelector ); 3985}; 3986 3987// goes through all children 3988proto.reloadCells = function() { 3989 // collection of item elements 3990 this.cells = this._makeCells( this.slider.children ); 3991 this.positionCells(); 3992 this._updateWrapShiftCells(); 3993 this.setGallerySize(); 3994}; 3995 3996/** 3997 * turn elements into Flickity.Cells 3998 * @param {[Array, NodeList, HTMLElement]} elems - elements to make into cells 3999 * @returns {Array} items - collection of new Flickity Cells 4000 */ 4001proto._makeCells = function( elems ) { 4002 let cellElems = this._filterFindCellElements( elems ); 4003 4004 // create new Cells for collection 4005 return cellElems.map( ( cellElem ) => new Cell( cellElem ) ); 4006}; 4007 4008proto.getLastCell = function() { 4009 return this.cells[ this.cells.length - 1 ]; 4010}; 4011 4012proto.getLastSlide = function() { 4013 return this.slides[ this.slides.length - 1 ]; 4014}; 4015 4016// positions all cells 4017proto.positionCells = function() { 4018 // size all cells 4019 this._sizeCells( this.cells ); 4020 // position all cells 4021 this._positionCells( 0 ); 4022}; 4023 4024/** 4025 * position certain cells 4026 * @param {Integer} index - which cell to start with 4027 */ 4028proto._positionCells = function( index ) { 4029 index = index || 0; 4030 // also measure maxCellHeight 4031 // start 0 if positioning all cells 4032 this.maxCellHeight = index ? this.maxCellHeight || 0 : 0; 4033 let cellX = 0; 4034 // get cellX 4035 if ( index > 0 ) { 4036 let startCell = this.cells[ index - 1 ]; 4037 cellX = startCell.x + startCell.size.outerWidth; 4038 } 4039 4040 this.cells.slice( index ).forEach( ( cell ) => { 4041 cell.x = cellX; 4042 this._renderCellPosition( cell, cellX ); 4043 cellX += cell.size.outerWidth; 4044 this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight ); 4045 } ); 4046 // keep track of cellX for wrap-around 4047 this.slideableWidth = cellX; 4048 // slides 4049 this.updateSlides(); 4050 // contain slides target 4051 this._containSlides(); 4052 // update slidesWidth 4053 this.slidesWidth = this.cells.length ? 4054 this.getLastSlide().target - this.slides[0].target : 0; 4055}; 4056 4057proto._renderCellPosition = function( cell, x ) { 4058 // render position of cell with in slider 4059 let sideOffset = this.options.rightToLeft ? -1 : 1; 4060 let renderX = x * sideOffset; 4061 if ( this.options.percentPosition ) renderX *= this.size.innerWidth / cell.size.width; 4062 let positionValue = this.getPositionValue( renderX ); 4063 cell.element.style.transform = `translateX( ${positionValue} )`; 4064}; 4065 4066/** 4067 * cell.getSize() on multiple cells 4068 * @param {Array} cells - cells to size 4069 */ 4070proto._sizeCells = function( cells ) { 4071 cells.forEach( ( cell ) => cell.getSize() ); 4072}; 4073 4074// -------------------------- -------------------------- // 4075 4076proto.updateSlides = function() { 4077 this.slides = []; 4078 if ( !this.cells.length ) return; 4079 4080 let { beginMargin, endMargin } = this; 4081 let slide = new Slide( beginMargin, endMargin, this.cellAlign ); 4082 this.slides.push( slide ); 4083 4084 let canCellFit = this._getCanCellFit(); 4085 4086 this.cells.forEach( ( cell, i ) => { 4087 // just add cell if first cell in slide 4088 if ( !slide.cells.length ) { 4089 slide.addCell( cell ); 4090 return; 4091 } 4092 4093 let slideWidth = ( slide.outerWidth - slide.firstMargin ) + 4094 ( cell.size.outerWidth - cell.size[ endMargin ] ); 4095 4096 if ( canCellFit( i, slideWidth ) ) { 4097 slide.addCell( cell ); 4098 } else { 4099 // doesn't fit, new slide 4100 slide.updateTarget(); 4101 4102 slide = new Slide( beginMargin, endMargin, this.cellAlign ); 4103 this.slides.push( slide ); 4104 slide.addCell( cell ); 4105 } 4106 } ); 4107 // last slide 4108 slide.updateTarget(); 4109 // update .selectedSlide 4110 this.updateSelectedSlide(); 4111}; 4112 4113proto._getCanCellFit = function() { 4114 let { groupCells } = this.options; 4115 if ( !groupCells ) return () => false; 4116 4117 if ( typeof groupCells == 'number' ) { 4118 // group by number. 3 -> [0,1,2], [3,4,5], ... 4119 let number = parseInt( groupCells, 10 ); 4120 return ( i ) => ( i % number ) !== 0; 4121 } 4122 // default, group by width of slide 4123 let percent = 1; 4124 // parse '75% 4125 let percentMatch = typeof groupCells == 'string' && groupCells.match( /^(\d+)%$/ ); 4126 if ( percentMatch ) percent = parseInt( percentMatch[1], 10 ) / 100; 4127 let groupWidth = ( this.size.innerWidth + 1 ) * percent; 4128 return ( i, slideWidth ) => slideWidth <= groupWidth; 4129}; 4130 4131// alias _init for jQuery plugin .flickity() 4132proto._init = 4133proto.reposition = function() { 4134 this.positionCells(); 4135 this.positionSliderAtSelected(); 4136}; 4137 4138proto.getSize = function() { 4139 this.size = getSize( this.element ); 4140 this.setCellAlign(); 4141 this.cursorPosition = this.size.innerWidth * this.cellAlign; 4142}; 4143 4144let cellAlignShorthands = { 4145 left: 0, 4146 center: 0.5, 4147 right: 1, 4148}; 4149 4150proto.setCellAlign = function() { 4151 let { cellAlign, rightToLeft } = this.options; 4152 let shorthand = cellAlignShorthands[ cellAlign ]; 4153 this.cellAlign = shorthand !== undefined ? shorthand : cellAlign; 4154 if ( rightToLeft ) this.cellAlign = 1 - this.cellAlign; 4155}; 4156 4157proto.setGallerySize = function() { 4158 if ( !this.options.setGallerySize ) return; 4159 4160 let height = this.options.adaptiveHeight && this.selectedSlide ? 4161 this.selectedSlide.height : this.maxCellHeight; 4162 this.viewport.style.height = `${height}px`; 4163}; 4164 4165proto._updateWrapShiftCells = function() { 4166 // update isWrapping 4167 this.isWrapping = this.getIsWrapping(); 4168 // only for wrap-around 4169 if ( !this.isWrapping ) return; 4170 4171 // unshift previous cells 4172 this._unshiftCells( this.beforeShiftCells ); 4173 this._unshiftCells( this.afterShiftCells ); 4174 // get before cells 4175 // initial gap 4176 let beforeGapX = this.cursorPosition; 4177 let lastIndex = this.cells.length - 1; 4178 this.beforeShiftCells = this._getGapCells( beforeGapX, lastIndex, -1 ); 4179 // get after cells 4180 // ending gap between last cell and end of gallery viewport 4181 let afterGapX = this.size.innerWidth - this.cursorPosition; 4182 // start cloning at first cell, working forwards 4183 this.afterShiftCells = this._getGapCells( afterGapX, 0, 1 ); 4184}; 4185 4186proto.getIsWrapping = function() { 4187 let { wrapAround } = this.options; 4188 if ( !wrapAround || this.slides.length < 2 ) return false; 4189 4190 if ( wrapAround !== 'fill' ) return true; 4191 // check that slides can fit 4192 4193 let gapWidth = this.slideableWidth - this.size.innerWidth; 4194 if ( gapWidth > this.size.innerWidth ) return true; // gap * 2x big, all good 4195 // check that content width - shifting cell is bigger than viewport width 4196 for ( let cell of this.cells ) { 4197 if ( cell.size.outerWidth > gapWidth ) return false; 4198 } 4199 return true; 4200}; 4201 4202proto._getGapCells = function( gapX, cellIndex, increment ) { 4203 // keep adding cells until the cover the initial gap 4204 let cells = []; 4205 while ( gapX > 0 ) { 4206 let cell = this.cells[ cellIndex ]; 4207 if ( !cell ) break; 4208 4209 cells.push( cell ); 4210 cellIndex += increment; 4211 gapX -= cell.size.outerWidth; 4212 } 4213 return cells; 4214}; 4215 4216// ----- contain & wrap ----- // 4217 4218// contain cell targets so no excess sliding 4219proto._containSlides = function() { 4220 let isContaining = this.options.contain && !this.isWrapping && 4221 this.cells.length; 4222 if ( !isContaining ) return; 4223 4224 let contentWidth = this.slideableWidth - this.getLastCell().size[ this.endMargin ]; 4225 // content is less than gallery size 4226 let isContentSmaller = contentWidth < this.size.innerWidth; 4227 if ( isContentSmaller ) { 4228 // all cells fit inside gallery 4229 this.slides.forEach( ( slide ) => { 4230 slide.target = contentWidth * this.cellAlign; 4231 } ); 4232 } else { 4233 // contain to bounds 4234 let beginBound = this.cursorPosition + this.cells[0].size[ this.beginMargin ]; 4235 let endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign ); 4236 this.slides.forEach( ( slide ) => { 4237 slide.target = Math.max( slide.target, beginBound ); 4238 slide.target = Math.min( slide.target, endBound ); 4239 } ); 4240 } 4241}; 4242 4243// ----- events ----- // 4244 4245/** 4246 * emits events via eventEmitter and jQuery events 4247 * @param {String} type - name of event 4248 * @param {Event} event - original event 4249 * @param {Array} args - extra arguments 4250 */ 4251proto.dispatchEvent = function( type, event, args ) { 4252 let emitArgs = event ? [ event ].concat( args ) : args; 4253 this.emitEvent( type, emitArgs ); 4254 4255 if ( jQuery && this.$element ) { 4256 // default trigger with type if no event 4257 type += this.options.namespaceJQueryEvents ? '.flickity' : ''; 4258 let $event = type; 4259 if ( event ) { 4260 // create jQuery event 4261 let jQEvent = new jQuery.Event( event ); 4262 jQEvent.type = type; 4263 $event = jQEvent; 4264 } 4265 this.$element.trigger( $event, args ); 4266 } 4267}; 4268 4269const unidraggerEvents = [ 4270 'dragStart', 4271 'dragMove', 4272 'dragEnd', 4273 'pointerDown', 4274 'pointerMove', 4275 'pointerEnd', 4276 'staticClick', 4277]; 4278 4279let _emitEvent = proto.emitEvent; 4280proto.emitEvent = function( eventName, args ) { 4281 if ( eventName === 'staticClick' ) { 4282 // add cellElem and cellIndex args to staticClick 4283 let clickedCell = this.getParentCell( args[0].target ); 4284 let cellElem = clickedCell && clickedCell.element; 4285 let cellIndex = clickedCell && this.cells.indexOf( clickedCell ); 4286 args = args.concat( cellElem, cellIndex ); 4287 } 4288 // do regular thing 4289 _emitEvent.call( this, eventName, args ); 4290 // duck-punch in jQuery events for Unidragger events 4291 let isUnidraggerEvent = unidraggerEvents.includes( eventName ); 4292 if ( !isUnidraggerEvent || !jQuery || !this.$element ) return; 4293 4294 eventName += this.options.namespaceJQueryEvents ? '.flickity' : ''; 4295 let event = args.shift( 0 ); 4296 let jQEvent = new jQuery.Event( event ); 4297 jQEvent.type = eventName; 4298 this.$element.trigger( jQEvent, args ); 4299}; 4300 4301// -------------------------- select -------------------------- // 4302 4303/** 4304 * @param {Integer} index - index of the slide 4305 * @param {Boolean} isWrap - will wrap-around to last/first if at the end 4306 * @param {Boolean} isInstant - will immediately set position at selected cell 4307 */ 4308proto.select = function( index, isWrap, isInstant ) { 4309 if ( !this.isActive ) return; 4310 4311 index = parseInt( index, 10 ); 4312 this._wrapSelect( index ); 4313 4314 if ( this.isWrapping || isWrap ) { 4315 index = utils.modulo( index, this.slides.length ); 4316 } 4317 // bail if invalid index 4318 if ( !this.slides[ index ] ) return; 4319 4320 let prevIndex = this.selectedIndex; 4321 this.selectedIndex = index; 4322 this.updateSelectedSlide(); 4323 if ( isInstant ) { 4324 this.positionSliderAtSelected(); 4325 } else { 4326 this.startAnimation(); 4327 } 4328 if ( this.options.adaptiveHeight ) { 4329 this.setGallerySize(); 4330 } 4331 // events 4332 this.dispatchEvent( 'select', null, [ index ] ); 4333 // change event if new index 4334 if ( index !== prevIndex ) { 4335 this.dispatchEvent( 'change', null, [ index ] ); 4336 } 4337}; 4338 4339// wraps position for wrapAround, to move to closest slide. #113 4340proto._wrapSelect = function( index ) { 4341 if ( !this.isWrapping ) return; 4342 4343 const { selectedIndex, slideableWidth, slides: { length } } = this; 4344 // shift index for wrap, do not wrap dragSelect 4345 if ( !this.isDragSelect ) { 4346 let wrapIndex = utils.modulo( index, length ); 4347 // go to shortest 4348 let delta = Math.abs( wrapIndex - selectedIndex ); 4349 let backWrapDelta = Math.abs( ( wrapIndex + length ) - selectedIndex ); 4350 let forewardWrapDelta = Math.abs( ( wrapIndex - length ) - selectedIndex ); 4351 if ( backWrapDelta < delta ) { 4352 index += length; 4353 } else if ( forewardWrapDelta < delta ) { 4354 index -= length; 4355 } 4356 } 4357 4358 // wrap position so slider is within normal area 4359 if ( index < 0 ) { 4360 this.x -= slideableWidth; 4361 } else if ( index >= length ) { 4362 this.x += slideableWidth; 4363 } 4364}; 4365 4366proto.previous = function( isWrap, isInstant ) { 4367 this.select( this.selectedIndex - 1, isWrap, isInstant ); 4368}; 4369 4370proto.next = function( isWrap, isInstant ) { 4371 this.select( this.selectedIndex + 1, isWrap, isInstant ); 4372}; 4373 4374proto.updateSelectedSlide = function() { 4375 let slide = this.slides[ this.selectedIndex ]; 4376 // selectedIndex could be outside of slides, if triggered before resize() 4377 if ( !slide ) return; 4378 4379 // unselect previous selected slide 4380 this.unselectSelectedSlide(); 4381 // update new selected slide 4382 this.selectedSlide = slide; 4383 slide.select(); 4384 this.selectedCells = slide.cells; 4385 this.selectedElements = slide.getCellElements(); 4386 // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility 4387 this.selectedCell = slide.cells[0]; 4388 this.selectedElement = this.selectedElements[0]; 4389}; 4390 4391proto.unselectSelectedSlide = function() { 4392 if ( this.selectedSlide ) this.selectedSlide.unselect(); 4393}; 4394 4395proto.selectInitialIndex = function() { 4396 let initialIndex = this.options.initialIndex; 4397 // already activated, select previous selectedIndex 4398 if ( this.isInitActivated ) { 4399 this.select( this.selectedIndex, false, true ); 4400 return; 4401 } 4402 // select with selector string 4403 if ( initialIndex && typeof initialIndex == 'string' ) { 4404 let cell = this.queryCell( initialIndex ); 4405 if ( cell ) { 4406 this.selectCell( initialIndex, false, true ); 4407 return; 4408 } 4409 } 4410 4411 let index = 0; 4412 // select with number 4413 if ( initialIndex && this.slides[ initialIndex ] ) { 4414 index = initialIndex; 4415 } 4416 // select instantly 4417 this.select( index, false, true ); 4418}; 4419 4420/** 4421 * select slide from number or cell element 4422 * @param {[Element, Number]} value - zero-based index or element to select 4423 * @param {Boolean} isWrap - enables wrapping around for extra index 4424 * @param {Boolean} isInstant - disables slide animation 4425 */ 4426proto.selectCell = function( value, isWrap, isInstant ) { 4427 // get cell 4428 let cell = this.queryCell( value ); 4429 if ( !cell ) return; 4430 4431 let index = this.getCellSlideIndex( cell ); 4432 this.select( index, isWrap, isInstant ); 4433}; 4434 4435proto.getCellSlideIndex = function( cell ) { 4436 // get index of slide that has cell 4437 let cellSlide = this.slides.find( ( slide ) => slide.cells.includes( cell ) ); 4438 return this.slides.indexOf( cellSlide ); 4439}; 4440 4441// -------------------------- get cells -------------------------- // 4442 4443/** 4444 * get Flickity.Cell, given an Element 4445 * @param {Element} elem - matching cell element 4446 * @returns {Flickity.Cell} cell - matching cell 4447 */ 4448proto.getCell = function( elem ) { 4449 // loop through cells to get the one that matches 4450 for ( let cell of this.cells ) { 4451 if ( cell.element === elem ) return cell; 4452 } 4453}; 4454 4455/** 4456 * get collection of Flickity.Cells, given Elements 4457 * @param {[Element, Array, NodeList]} elems - multiple elements 4458 * @returns {Array} cells - Flickity.Cells 4459 */ 4460proto.getCells = function( elems ) { 4461 elems = utils.makeArray( elems ); 4462 return elems.map( ( elem ) => this.getCell( elem ) ).filter( Boolean ); 4463}; 4464 4465/** 4466 * get cell elements 4467 * @returns {Array} cellElems 4468 */ 4469proto.getCellElements = function() { 4470 return this.cells.map( ( cell ) => cell.element ); 4471}; 4472 4473/** 4474 * get parent cell from an element 4475 * @param {Element} elem - child element 4476 * @returns {Flickit.Cell} cell - parent cell 4477 */ 4478proto.getParentCell = function( elem ) { 4479 // first check if elem is cell 4480 let cell = this.getCell( elem ); 4481 if ( cell ) return cell; 4482 4483 // try to get parent cell elem 4484 let closest = elem.closest('.flickity-slider > *'); 4485 return this.getCell( closest ); 4486}; 4487 4488/** 4489 * get cells adjacent to a slide 4490 * @param {Integer} adjCount - number of adjacent slides 4491 * @param {Integer} index - index of slide to start 4492 * @returns {Array} cells - array of Flickity.Cells 4493 */ 4494proto.getAdjacentCellElements = function( adjCount, index ) { 4495 if ( !adjCount ) return this.selectedSlide.getCellElements(); 4496 4497 index = index === undefined ? this.selectedIndex : index; 4498 4499 let len = this.slides.length; 4500 if ( 1 + ( adjCount * 2 ) >= len ) { 4501 return this.getCellElements(); // get all 4502 } 4503 4504 let cellElems = []; 4505 for ( let i = index - adjCount; i <= index + adjCount; i++ ) { 4506 let slideIndex = this.isWrapping ? utils.modulo( i, len ) : i; 4507 let slide = this.slides[ slideIndex ]; 4508 if ( slide ) { 4509 cellElems = cellElems.concat( slide.getCellElements() ); 4510 } 4511 } 4512 return cellElems; 4513}; 4514 4515/** 4516 * select slide from number or cell element 4517 * @param {[Element, String, Number]} selector - element, selector string, or index 4518 * @returns {Flickity.Cell} - matching cell 4519 */ 4520proto.queryCell = function( selector ) { 4521 if ( typeof selector == 'number' ) { 4522 // use number as index 4523 return this.cells[ selector ]; 4524 } 4525 // do not select invalid selectors from hash: #123, #/. #791 4526 let isSelectorString = typeof selector == 'string' && !selector.match( /^[#.]?[\d/]/ ); 4527 if ( isSelectorString ) { 4528 // use string as selector, get element 4529 selector = this.element.querySelector( selector ); 4530 } 4531 // get cell from element 4532 return this.getCell( selector ); 4533}; 4534 4535// -------------------------- events -------------------------- // 4536 4537proto.uiChange = function() { 4538 this.emitEvent('uiChange'); 4539}; 4540 4541// ----- resize ----- // 4542 4543proto.onresize = function() { 4544 this.watchCSS(); 4545 this.resize(); 4546}; 4547 4548utils.debounceMethod( Flickity, 'onresize', 150 ); 4549 4550proto.resize = function() { 4551 // #1177 disable resize behavior when animating or dragging for iOS 15 4552 if ( !this.isActive || this.isAnimating || this.isDragging ) return; 4553 this.getSize(); 4554 // wrap values 4555 if ( this.isWrapping ) { 4556 this.x = utils.modulo( this.x, this.slideableWidth ); 4557 } 4558 this.positionCells(); 4559 this._updateWrapShiftCells(); 4560 this.setGallerySize(); 4561 this.emitEvent('resize'); 4562 // update selected index for group slides, instant 4563 // TODO: position can be lost between groups of various numbers 4564 let selectedElement = this.selectedElements && this.selectedElements[0]; 4565 this.selectCell( selectedElement, false, true ); 4566}; 4567 4568// watches the :after property, activates/deactivates 4569proto.watchCSS = function() { 4570 if ( !this.options.watchCSS ) return; 4571 4572 let afterContent = getComputedStyle( this.element, ':after' ).content; 4573 // activate if :after { content: 'flickity' } 4574 if ( afterContent.includes('flickity') ) { 4575 this.activate(); 4576 } else { 4577 this.deactivate(); 4578 } 4579}; 4580 4581// ----- keydown ----- // 4582 4583// go previous/next if left/right keys pressed 4584proto.onkeydown = function( event ) { 4585 let { activeElement } = document; 4586 let handler = Flickity.keyboardHandlers[ event.key ]; 4587 // only work if element is in focus 4588 if ( !this.options.accessibility || !activeElement || !handler ) return; 4589 4590 let isFocused = this.focusableElems.some( ( elem ) => activeElement === elem ); 4591 if ( isFocused ) handler.call( this ); 4592}; 4593 4594Flickity.keyboardHandlers = { 4595 ArrowLeft: function() { 4596 this.uiChange(); 4597 let leftMethod = this.options.rightToLeft ? 'next' : 'previous'; 4598 this[ leftMethod ](); 4599 }, 4600 ArrowRight: function() { 4601 this.uiChange(); 4602 let rightMethod = this.options.rightToLeft ? 'previous' : 'next'; 4603 this[ rightMethod ](); 4604 }, 4605}; 4606 4607// ----- focus ----- // 4608 4609proto.focus = function() { 4610 this.element.focus({ preventScroll: true }); 4611}; 4612 4613// -------------------------- destroy -------------------------- // 4614 4615// deactivate all Flickity functionality, but keep stuff available 4616proto.deactivate = function() { 4617 if ( !this.isActive ) return; 4618 4619 this.element.classList.remove('flickity-enabled'); 4620 this.element.classList.remove('flickity-rtl'); 4621 this.unselectSelectedSlide(); 4622 // destroy cells 4623 this.cells.forEach( ( cell ) => cell.destroy() ); 4624 this.viewport.remove(); 4625 // move child elements back into element 4626 this.element.append( ...this.slider.children ); 4627 if ( this.options.accessibility ) { 4628 this.element.removeAttribute('tabIndex'); 4629 this.element.removeEventListener( 'keydown', this ); 4630 } 4631 // set flags 4632 this.isActive = false; 4633 this.emitEvent('deactivate'); 4634}; 4635 4636proto.destroy = function() { 4637 this.deactivate(); 4638 window.removeEventListener( 'resize', this ); 4639 this.allOff(); 4640 this.emitEvent('destroy'); 4641 if ( jQuery && this.$element ) { 4642 jQuery.removeData( this.element, 'flickity' ); 4643 } 4644 delete this.element.flickityGUID; 4645 delete instances[ this.guid ]; 4646}; 4647 4648// -------------------------- prototype -------------------------- // 4649 4650Object.assign( proto, animatePrototype ); 4651 4652// -------------------------- extras -------------------------- // 4653 4654/** 4655 * get Flickity instance from element 4656 * @param {[Element, String]} elem - element or selector string 4657 * @returns {Flickity} - Flickity instance 4658 */ 4659Flickity.data = function( elem ) { 4660 elem = utils.getQueryElement( elem ); 4661 if ( elem ) return instances[ elem.flickityGUID ]; 4662}; 4663 4664utils.htmlInit( Flickity, 'flickity' ); 4665 4666let { jQueryBridget } = window; 4667if ( jQuery && jQueryBridget ) { 4668 jQueryBridget( 'flickity', Flickity, jQuery ); 4669} 4670 4671// set internal jQuery, for Webpack + jQuery v3, #478 4672Flickity.setJQuery = function( jq ) { 4673 jQuery = jq; 4674}; 4675 4676Flickity.Cell = Cell; 4677Flickity.Slide = Slide; 4678 4679return Flickity; 4680 4681} ) ); 4682// drag 4683( function( window, factory ) { 4684 // universal module definition 4685 if ( typeof module == 'object' && module.exports ) { 4686 // CommonJS 4687 module.exports = factory( 4688 window, 4689 require('./core'), 4690 require('unidragger'), 4691 require('fizzy-ui-utils'), 4692 ); 4693 } else { 4694 // browser global 4695 window.Flickity = factory( 4696 window, 4697 window.Flickity, 4698 window.Unidragger, 4699 window.fizzyUIUtils, 4700 ); 4701 } 4702 4703}( typeof window != 'undefined' ? window : this, 4704 function factory( window, Flickity, Unidragger, utils ) { 4705 4706// ----- defaults ----- // 4707 4708Object.assign( Flickity.defaults, { 4709 draggable: '>1', 4710 dragThreshold: 3, 4711} ); 4712 4713// -------------------------- drag prototype -------------------------- // 4714 4715let proto = Flickity.prototype; 4716Object.assign( proto, Unidragger.prototype ); // inherit Unidragger 4717proto.touchActionValue = ''; 4718 4719// -------------------------- -------------------------- // 4720 4721Flickity.create.drag = function() { 4722 this.on( 'activate', this.onActivateDrag ); 4723 this.on( 'uiChange', this._uiChangeDrag ); 4724 this.on( 'deactivate', this.onDeactivateDrag ); 4725 this.on( 'cellChange', this.updateDraggable ); 4726 this.on( 'pointerDown', this.handlePointerDown ); 4727 this.on( 'pointerUp', this.handlePointerUp ); 4728 this.on( 'pointerDown', this.handlePointerDone ); 4729 this.on( 'dragStart', this.handleDragStart ); 4730 this.on( 'dragMove', this.handleDragMove ); 4731 this.on( 'dragEnd', this.handleDragEnd ); 4732 this.on( 'staticClick', this.handleStaticClick ); 4733 // TODO updateDraggable on resize? if groupCells & slides change 4734}; 4735 4736proto.onActivateDrag = function() { 4737 this.handles = [ this.viewport ]; 4738 this.bindHandles(); 4739 this.updateDraggable(); 4740}; 4741 4742proto.onDeactivateDrag = function() { 4743 this.unbindHandles(); 4744 this.element.classList.remove('is-draggable'); 4745}; 4746 4747proto.updateDraggable = function() { 4748 // disable dragging if less than 2 slides. #278 4749 if ( this.options.draggable === '>1' ) { 4750 this.isDraggable = this.slides.length > 1; 4751 } else { 4752 this.isDraggable = this.options.draggable; 4753 } 4754 this.element.classList.toggle( 'is-draggable', this.isDraggable ); 4755}; 4756 4757proto._uiChangeDrag = function() { 4758 delete this.isFreeScrolling; 4759}; 4760 4761// -------------------------- pointer events -------------------------- // 4762 4763proto.handlePointerDown = function( event ) { 4764 if ( !this.isDraggable ) { 4765 // proceed for staticClick 4766 this.bindActivePointerEvents( event ); 4767 return; 4768 } 4769 4770 let isTouchStart = event.type === 'touchstart'; 4771 let isTouchPointer = event.pointerType === 'touch'; 4772 let isFocusNode = event.target.matches('input, textarea, select'); 4773 if ( !isTouchStart && !isTouchPointer && !isFocusNode ) event.preventDefault(); 4774 if ( !isFocusNode ) this.focus(); 4775 // blur 4776 if ( document.activeElement !== this.element ) document.activeElement.blur(); 4777 // stop if it was moving 4778 this.dragX = this.x; 4779 this.viewport.classList.add('is-pointer-down'); 4780 // track scrolling 4781 this.pointerDownScroll = getScrollPosition(); 4782 window.addEventListener( 'scroll', this ); 4783 this.bindActivePointerEvents( event ); 4784}; 4785 4786// ----- move ----- // 4787 4788proto.hasDragStarted = function( moveVector ) { 4789 return Math.abs( moveVector.x ) > this.options.dragThreshold; 4790}; 4791 4792// ----- up ----- // 4793 4794proto.handlePointerUp = function() { 4795 delete this.isTouchScrolling; 4796 this.viewport.classList.remove('is-pointer-down'); 4797}; 4798 4799proto.handlePointerDone = function() { 4800 window.removeEventListener( 'scroll', this ); 4801 delete this.pointerDownScroll; 4802}; 4803 4804// -------------------------- dragging -------------------------- // 4805 4806proto.handleDragStart = function() { 4807 if ( !this.isDraggable ) return; 4808 4809 this.dragStartPosition = this.x; 4810 this.startAnimation(); 4811 window.removeEventListener( 'scroll', this ); 4812}; 4813 4814proto.handleDragMove = function( event, pointer, moveVector ) { 4815 if ( !this.isDraggable ) return; 4816 4817 event.preventDefault(); 4818 4819 this.previousDragX = this.dragX; 4820 // reverse if right-to-left 4821 let direction = this.options.rightToLeft ? -1 : 1; 4822 // wrap around move. #589 4823 if ( this.isWrapping ) moveVector.x %= this.slideableWidth; 4824 let dragX = this.dragStartPosition + moveVector.x * direction; 4825 4826 if ( !this.isWrapping ) { 4827 // slow drag 4828 let originBound = Math.max( -this.slides[0].target, this.dragStartPosition ); 4829 dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX; 4830 let endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition ); 4831 dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX; 4832 } 4833 4834 this.dragX = dragX; 4835 this.dragMoveTime = new Date(); 4836}; 4837 4838proto.handleDragEnd = function() { 4839 if ( !this.isDraggable ) return; 4840 4841 let { freeScroll } = this.options; 4842 if ( freeScroll ) this.isFreeScrolling = true; 4843 // set selectedIndex based on where flick will end up 4844 let index = this.dragEndRestingSelect(); 4845 4846 if ( freeScroll && !this.isWrapping ) { 4847 // if free-scroll & not wrap around 4848 // do not free-scroll if going outside of bounding slides 4849 // so bounding slides can attract slider, and keep it in bounds 4850 let restingX = this.getRestingPosition(); 4851 this.isFreeScrolling = -restingX > this.slides[0].target && 4852 -restingX < this.getLastSlide().target; 4853 } else if ( !freeScroll && index === this.selectedIndex ) { 4854 // boost selection if selected index has not changed 4855 index += this.dragEndBoostSelect(); 4856 } 4857 delete this.previousDragX; 4858 // apply selection 4859 // HACK, set flag so dragging stays in correct direction 4860 this.isDragSelect = this.isWrapping; 4861 this.select( index ); 4862 delete this.isDragSelect; 4863}; 4864 4865proto.dragEndRestingSelect = function() { 4866 let restingX = this.getRestingPosition(); 4867 // how far away from selected slide 4868 let distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) ); 4869 // get closet resting going up and going down 4870 let positiveResting = this._getClosestResting( restingX, distance, 1 ); 4871 let negativeResting = this._getClosestResting( restingX, distance, -1 ); 4872 // use closer resting for wrap-around 4873 return positiveResting.distance < negativeResting.distance ? 4874 positiveResting.index : negativeResting.index; 4875}; 4876 4877/** 4878 * given resting X and distance to selected cell 4879 * get the distance and index of the closest cell 4880 * @param {Number} restingX - estimated post-flick resting position 4881 * @param {Number} distance - distance to selected cell 4882 * @param {Integer} increment - +1 or -1, going up or down 4883 * @returns {Object} - { distance: {Number}, index: {Integer} } 4884 */ 4885proto._getClosestResting = function( restingX, distance, increment ) { 4886 let index = this.selectedIndex; 4887 let minDistance = Infinity; 4888 let condition = this.options.contain && !this.isWrapping ? 4889 // if containing, keep going if distance is equal to minDistance 4890 ( dist, minDist ) => dist <= minDist : 4891 ( dist, minDist ) => dist < minDist; 4892 4893 while ( condition( distance, minDistance ) ) { 4894 // measure distance to next cell 4895 index += increment; 4896 minDistance = distance; 4897 distance = this.getSlideDistance( -restingX, index ); 4898 if ( distance === null ) break; 4899 4900 distance = Math.abs( distance ); 4901 } 4902 return { 4903 distance: minDistance, 4904 // selected was previous index 4905 index: index - increment, 4906 }; 4907}; 4908 4909/** 4910 * measure distance between x and a slide target 4911 * @param {Number} x - horizontal position 4912 * @param {Integer} index - slide index 4913 * @returns {Number} - slide distance 4914 */ 4915proto.getSlideDistance = function( x, index ) { 4916 let len = this.slides.length; 4917 // wrap around if at least 2 slides 4918 let isWrapAround = this.options.wrapAround && len > 1; 4919 let slideIndex = isWrapAround ? utils.modulo( index, len ) : index; 4920 let slide = this.slides[ slideIndex ]; 4921 if ( !slide ) return null; 4922 4923 // add distance for wrap-around slides 4924 let wrap = isWrapAround ? this.slideableWidth * Math.floor( index/len ) : 0; 4925 return x - ( slide.target + wrap ); 4926}; 4927 4928proto.dragEndBoostSelect = function() { 4929 // do not boost if no previousDragX or dragMoveTime 4930 if ( this.previousDragX === undefined || !this.dragMoveTime || 4931 // or if drag was held for 100 ms 4932 new Date() - this.dragMoveTime > 100 ) { 4933 return 0; 4934 } 4935 4936 let distance = this.getSlideDistance( -this.dragX, this.selectedIndex ); 4937 let delta = this.previousDragX - this.dragX; 4938 if ( distance > 0 && delta > 0 ) { 4939 // boost to next if moving towards the right, and positive velocity 4940 return 1; 4941 } else if ( distance < 0 && delta < 0 ) { 4942 // boost to previous if moving towards the left, and negative velocity 4943 return -1; 4944 } 4945 return 0; 4946}; 4947 4948// ----- scroll ----- // 4949 4950proto.onscroll = function() { 4951 let scroll = getScrollPosition(); 4952 let scrollMoveX = this.pointerDownScroll.x - scroll.x; 4953 let scrollMoveY = this.pointerDownScroll.y - scroll.y; 4954 // cancel click/tap if scroll is too much 4955 if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) { 4956 this.pointerDone(); 4957 } 4958}; 4959 4960// ----- utils ----- // 4961 4962function getScrollPosition() { 4963 return { 4964 x: window.pageXOffset, 4965 y: window.pageYOffset, 4966 }; 4967} 4968 4969// ----- ----- // 4970 4971return Flickity; 4972 4973} ) ); 4974// prev/next buttons 4975( function( window, factory ) { 4976 // universal module definition 4977 if ( typeof module == 'object' && module.exports ) { 4978 // CommonJS 4979 module.exports = factory( require('./core') ); 4980 } else { 4981 // browser global 4982 factory( window.Flickity ); 4983 } 4984 4985}( typeof window != 'undefined' ? window : this, function factory( Flickity ) { 4986 4987const svgURI = 'http://www.w3.org/2000/svg'; 4988 4989// -------------------------- PrevNextButton -------------------------- // 4990 4991function PrevNextButton( increment, direction, arrowShape ) { 4992 this.increment = increment; 4993 this.direction = direction; 4994 this.isPrevious = increment === 'previous'; 4995 this.isLeft = direction === 'left'; 4996 this._create( arrowShape ); 4997} 4998 4999PrevNextButton.prototype._create = function( arrowShape ) { 5000 // properties 5001 let element = this.element = document.createElement('button'); 5002 element.className = `flickity-button flickity-prev-next-button ${this.increment}`; 5003 let label = this.isPrevious ? 'Previous' : 'Next'; 5004 // prevent button from submitting form https://stackoverflow.com/a/10836076/182183 5005 element.setAttribute( 'type', 'button' ); 5006 element.setAttribute( 'aria-label', label ); 5007 // init as disabled 5008 this.disable(); 5009 // create arrow 5010 let svg = this.createSVG( label, arrowShape ); 5011 element.append( svg ); 5012}; 5013 5014PrevNextButton.prototype.createSVG = function( label, arrowShape ) { 5015 let svg = document.createElementNS( svgURI, 'svg' ); 5016 svg.setAttribute( 'class', 'flickity-button-icon' ); 5017 svg.setAttribute( 'viewBox', '0 0 100 100' ); 5018 // add title #1189 5019 let title = document.createElementNS( svgURI, 'title' ); 5020 title.append( label ); 5021 // add path 5022 let path = document.createElementNS( svgURI, 'path' ); 5023 let pathMovements = getArrowMovements( arrowShape ); 5024 path.setAttribute( 'd', pathMovements ); 5025 path.setAttribute( 'class', 'arrow' ); 5026 // rotate arrow 5027 if ( !this.isLeft ) { 5028 path.setAttribute( 'transform', 'translate(100, 100) rotate(180)' ); 5029 } 5030 svg.append( title, path ); 5031 return svg; 5032}; 5033 5034// get SVG path movmement 5035function getArrowMovements( shape ) { 5036 // use shape as movement if string 5037 if ( typeof shape == 'string' ) return shape; 5038 5039 let { x0, x1, x2, x3, y1, y2 } = shape; 5040 5041 // create movement string 5042 return `M ${x0}, 50 5043 L ${x1}, ${y1 + 50} 5044 L ${x2}, ${y2 + 50} 5045 L ${x3}, 50 5046 L ${x2}, ${50 - y2} 5047 L ${x1}, ${50 - y1} 5048 Z`; 5049} 5050 5051// ----- ----- // 5052 5053PrevNextButton.prototype.enable = function() { 5054 this.element.removeAttribute('disabled'); 5055}; 5056 5057PrevNextButton.prototype.disable = function() { 5058 this.element.setAttribute( 'disabled', true ); 5059}; 5060 5061// -------------------------- Flickity prototype -------------------------- // 5062 5063Object.assign( Flickity.defaults, { 5064 prevNextButtons: true, 5065 arrowShape: { 5066 x0: 10, 5067 x1: 60, y1: 50, 5068 x2: 70, y2: 40, 5069 x3: 30, 5070 }, 5071} ); 5072 5073Flickity.create.prevNextButtons = function() { 5074 if ( !this.options.prevNextButtons ) return; 5075 5076 let { rightToLeft, arrowShape } = this.options; 5077 let prevDirection = rightToLeft ? 'right' : 'left'; 5078 let nextDirection = rightToLeft ? 'left' : 'right'; 5079 this.prevButton = new PrevNextButton( 'previous', prevDirection, arrowShape ); 5080 this.nextButton = new PrevNextButton( 'next', nextDirection, arrowShape ); 5081 this.focusableElems.push( this.prevButton.element ); 5082 this.focusableElems.push( this.nextButton.element ); 5083 5084 this.handlePrevButtonClick = () => { 5085 this.uiChange(); 5086 this.previous(); 5087 }; 5088 5089 this.handleNextButtonClick = () => { 5090 this.uiChange(); 5091 this.next(); 5092 }; 5093 5094 this.on( 'activate', this.activatePrevNextButtons ); 5095 this.on( 'select', this.updatePrevNextButtons ); 5096}; 5097 5098let proto = Flickity.prototype; 5099 5100proto.updatePrevNextButtons = function() { 5101 let lastIndex = this.slides.length ? this.slides.length - 1 : 0; 5102 this.updatePrevNextButton( this.prevButton, 0 ); 5103 this.updatePrevNextButton( this.nextButton, lastIndex ); 5104}; 5105 5106proto.updatePrevNextButton = function( button, disabledIndex ) { 5107 // enable is wrapAround and at least 2 slides 5108 if ( this.isWrapping && this.slides.length > 1 ) { 5109 button.enable(); 5110 return; 5111 } 5112 5113 let isEnabled = this.selectedIndex !== disabledIndex; 5114 button[ isEnabled ? 'enable' : 'disable' ](); 5115 // if disabling button that is focused, 5116 // shift focus to element to maintain keyboard accessibility 5117 let isDisabledFocused = !isEnabled && document.activeElement === button.element; 5118 if ( isDisabledFocused ) this.focus(); 5119}; 5120 5121proto.activatePrevNextButtons = function() { 5122 this.prevButton.element.addEventListener( 'click', this.handlePrevButtonClick ); 5123 this.nextButton.element.addEventListener( 'click', this.handleNextButtonClick ); 5124 this.element.append( this.prevButton.element, this.nextButton.element ); 5125 this.on( 'deactivate', this.deactivatePrevNextButtons ); 5126}; 5127 5128proto.deactivatePrevNextButtons = function() { 5129 this.prevButton.element.remove(); 5130 this.nextButton.element.remove(); 5131 this.prevButton.element.removeEventListener( 'click', this.handlePrevButtonClick ); 5132 this.nextButton.element.removeEventListener( 'click', this.handleNextButtonClick ); 5133 this.off( 'deactivate', this.deactivatePrevNextButtons ); 5134}; 5135 5136// -------------------------- -------------------------- // 5137 5138Flickity.PrevNextButton = PrevNextButton; 5139 5140return Flickity; 5141 5142} ) ); 5143// page dots 5144( function( window, factory ) { 5145 // universal module definition 5146 if ( typeof module == 'object' && module.exports ) { 5147 // CommonJS 5148 module.exports = factory( 5149 require('./core'), 5150 require('fizzy-ui-utils'), 5151 ); 5152 } else { 5153 // browser global 5154 factory( 5155 window.Flickity, 5156 window.fizzyUIUtils, 5157 ); 5158 } 5159 5160}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) { 5161 5162// -------------------------- PageDots -------------------------- // 5163 5164function PageDots() { 5165 // create holder element 5166 this.holder = document.createElement('div'); 5167 this.holder.className = 'flickity-page-dots'; 5168 // create dots, array of elements 5169 this.dots = []; 5170} 5171 5172PageDots.prototype.setDots = function( slidesLength ) { 5173 // get difference between number of slides and number of dots 5174 let delta = slidesLength - this.dots.length; 5175 if ( delta > 0 ) { 5176 this.addDots( delta ); 5177 } else if ( delta < 0 ) { 5178 this.removeDots( -delta ); 5179 } 5180}; 5181 5182PageDots.prototype.addDots = function( count ) { 5183 let newDots = new Array( count ).fill() 5184 .map( ( item, i ) => { 5185 let dot = document.createElement('button'); 5186 dot.setAttribute( 'type', 'button' ); 5187 let num = i + 1 + this.dots.length; 5188 dot.className = 'flickity-page-dot'; 5189 dot.textContent = `View slide ${num}`; 5190 return dot; 5191 } ); 5192 5193 this.holder.append( ...newDots ); 5194 this.dots = this.dots.concat( newDots ); 5195}; 5196 5197PageDots.prototype.removeDots = function( count ) { 5198 // remove from this.dots collection 5199 let removeDots = this.dots.splice( this.dots.length - count, count ); 5200 // remove from DOM 5201 removeDots.forEach( ( dot ) => dot.remove() ); 5202}; 5203 5204PageDots.prototype.updateSelected = function( index ) { 5205 // remove selected class on previous 5206 if ( this.selectedDot ) { 5207 this.selectedDot.classList.remove('is-selected'); 5208 this.selectedDot.removeAttribute('aria-current'); 5209 } 5210 // don't proceed if no dots 5211 if ( !this.dots.length ) return; 5212 5213 this.selectedDot = this.dots[ index ]; 5214 this.selectedDot.classList.add('is-selected'); 5215 this.selectedDot.setAttribute( 'aria-current', 'step' ); 5216}; 5217 5218Flickity.PageDots = PageDots; 5219 5220// -------------------------- Flickity -------------------------- // 5221 5222Object.assign( Flickity.defaults, { 5223 pageDots: true, 5224} ); 5225 5226Flickity.create.pageDots = function() { 5227 if ( !this.options.pageDots ) return; 5228 5229 this.pageDots = new PageDots(); 5230 this.handlePageDotsClick = this.onPageDotsClick.bind( this ); 5231 // events 5232 this.on( 'activate', this.activatePageDots ); 5233 this.on( 'select', this.updateSelectedPageDots ); 5234 this.on( 'cellChange', this.updatePageDots ); 5235 this.on( 'resize', this.updatePageDots ); 5236 this.on( 'deactivate', this.deactivatePageDots ); 5237}; 5238 5239let proto = Flickity.prototype; 5240 5241proto.activatePageDots = function() { 5242 this.pageDots.setDots( this.slides.length ); 5243 this.focusableElems.push( ...this.pageDots.dots ); 5244 this.pageDots.holder.addEventListener( 'click', this.handlePageDotsClick ); 5245 this.element.append( this.pageDots.holder ); 5246}; 5247 5248proto.onPageDotsClick = function( event ) { 5249 let index = this.pageDots.dots.indexOf( event.target ); 5250 if ( index === -1 ) return; // only dot clicks 5251 5252 this.uiChange(); 5253 this.select( index ); 5254}; 5255 5256proto.updateSelectedPageDots = function() { 5257 this.pageDots.updateSelected( this.selectedIndex ); 5258}; 5259 5260proto.updatePageDots = function() { 5261 this.pageDots.dots.forEach( ( dot ) => { 5262 utils.removeFrom( this.focusableElems, dot ); 5263 } ); 5264 this.pageDots.setDots( this.slides.length ); 5265 this.focusableElems.push( ...this.pageDots.dots ); 5266}; 5267 5268proto.deactivatePageDots = function() { 5269 this.pageDots.holder.remove(); 5270 this.pageDots.holder.removeEventListener( 'click', this.handlePageDotsClick ); 5271}; 5272 5273// ----- ----- // 5274 5275Flickity.PageDots = PageDots; 5276 5277return Flickity; 5278 5279} ) ); 5280// player & autoPlay 5281( function( window, factory ) { 5282 // universal module definition 5283 if ( typeof module == 'object' && module.exports ) { 5284 // CommonJS 5285 module.exports = factory( require('./core') ); 5286 } else { 5287 // browser global 5288 factory( window.Flickity ); 5289 } 5290 5291}( typeof window != 'undefined' ? window : this, function factory( Flickity ) { 5292 5293// -------------------------- Player -------------------------- // 5294 5295function Player( autoPlay, onTick ) { 5296 this.autoPlay = autoPlay; 5297 this.onTick = onTick; 5298 this.state = 'stopped'; 5299 // visibility change event handler 5300 this.onVisibilityChange = this.visibilityChange.bind( this ); 5301 this.onVisibilityPlay = this.visibilityPlay.bind( this ); 5302} 5303 5304// start play 5305Player.prototype.play = function() { 5306 if ( this.state === 'playing' ) return; 5307 5308 // do not play if page is hidden, start playing when page is visible 5309 let isPageHidden = document.hidden; 5310 if ( isPageHidden ) { 5311 document.addEventListener( 'visibilitychange', this.onVisibilityPlay ); 5312 return; 5313 } 5314 5315 this.state = 'playing'; 5316 // listen to visibility change 5317 document.addEventListener( 'visibilitychange', this.onVisibilityChange ); 5318 // start ticking 5319 this.tick(); 5320}; 5321 5322Player.prototype.tick = function() { 5323 // do not tick if not playing 5324 if ( this.state !== 'playing' ) return; 5325 5326 // default to 3 seconds 5327 let time = typeof this.autoPlay == 'number' ? this.autoPlay : 3000; 5328 // HACK: reset ticks if stopped and started within interval 5329 this.clear(); 5330 this.timeout = setTimeout( () => { 5331 this.onTick(); 5332 this.tick(); 5333 }, time ); 5334}; 5335 5336Player.prototype.stop = function() { 5337 this.state = 'stopped'; 5338 this.clear(); 5339 // remove visibility change event 5340 document.removeEventListener( 'visibilitychange', this.onVisibilityChange ); 5341}; 5342 5343Player.prototype.clear = function() { 5344 clearTimeout( this.timeout ); 5345}; 5346 5347Player.prototype.pause = function() { 5348 if ( this.state === 'playing' ) { 5349 this.state = 'paused'; 5350 this.clear(); 5351 } 5352}; 5353 5354Player.prototype.unpause = function() { 5355 // re-start play if paused 5356 if ( this.state === 'paused' ) this.play(); 5357}; 5358 5359// pause if page visibility is hidden, unpause if visible 5360Player.prototype.visibilityChange = function() { 5361 let isPageHidden = document.hidden; 5362 this[ isPageHidden ? 'pause' : 'unpause' ](); 5363}; 5364 5365Player.prototype.visibilityPlay = function() { 5366 this.play(); 5367 document.removeEventListener( 'visibilitychange', this.onVisibilityPlay ); 5368}; 5369 5370// -------------------------- Flickity -------------------------- // 5371 5372Object.assign( Flickity.defaults, { 5373 pauseAutoPlayOnHover: true, 5374} ); 5375 5376Flickity.create.player = function() { 5377 this.player = new Player( this.options.autoPlay, () => { 5378 this.next( true ); 5379 } ); 5380 5381 this.on( 'activate', this.activatePlayer ); 5382 this.on( 'uiChange', this.stopPlayer ); 5383 this.on( 'pointerDown', this.stopPlayer ); 5384 this.on( 'deactivate', this.deactivatePlayer ); 5385}; 5386 5387let proto = Flickity.prototype; 5388 5389proto.activatePlayer = function() { 5390 if ( !this.options.autoPlay ) return; 5391 5392 this.player.play(); 5393 this.element.addEventListener( 'mouseenter', this ); 5394}; 5395 5396// Player API, don't hate the ... thanks I know where the door is 5397 5398proto.playPlayer = function() { 5399 this.player.play(); 5400}; 5401 5402proto.stopPlayer = function() { 5403 this.player.stop(); 5404}; 5405 5406proto.pausePlayer = function() { 5407 this.player.pause(); 5408}; 5409 5410proto.unpausePlayer = function() { 5411 this.player.unpause(); 5412}; 5413 5414proto.deactivatePlayer = function() { 5415 this.player.stop(); 5416 this.element.removeEventListener( 'mouseenter', this ); 5417}; 5418 5419// ----- mouseenter/leave ----- // 5420 5421// pause auto-play on hover 5422proto.onmouseenter = function() { 5423 if ( !this.options.pauseAutoPlayOnHover ) return; 5424 5425 this.player.pause(); 5426 this.element.addEventListener( 'mouseleave', this ); 5427}; 5428 5429// resume auto-play on hover off 5430proto.onmouseleave = function() { 5431 this.player.unpause(); 5432 this.element.removeEventListener( 'mouseleave', this ); 5433}; 5434 5435// ----- ----- // 5436 5437Flickity.Player = Player; 5438 5439return Flickity; 5440 5441} ) ); 5442// add, remove cell 5443( function( window, factory ) { 5444 // universal module definition 5445 if ( typeof module == 'object' && module.exports ) { 5446 // CommonJS 5447 module.exports = factory( 5448 require('./core'), 5449 require('fizzy-ui-utils'), 5450 ); 5451 } else { 5452 // browser global 5453 factory( 5454 window.Flickity, 5455 window.fizzyUIUtils, 5456 ); 5457 } 5458 5459}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) { 5460 5461// append cells to a document fragment 5462function getCellsFragment( cells ) { 5463 let fragment = document.createDocumentFragment(); 5464 cells.forEach( ( cell ) => fragment.appendChild( cell.element ) ); 5465 return fragment; 5466} 5467 5468// -------------------------- add/remove cell prototype -------------------------- // 5469 5470let proto = Flickity.prototype; 5471 5472/** 5473 * Insert, prepend, or append cells 5474 * @param {[Element, Array, NodeList]} elems - Elements to insert 5475 * @param {Integer} index - Zero-based number to insert 5476 */ 5477proto.insert = function( elems, index ) { 5478 let cells = this._makeCells( elems ); 5479 if ( !cells || !cells.length ) return; 5480 5481 let len = this.cells.length; 5482 // default to append 5483 index = index === undefined ? len : index; 5484 // add cells with document fragment 5485 let fragment = getCellsFragment( cells ); 5486 // append to slider 5487 let isAppend = index === len; 5488 if ( isAppend ) { 5489 this.slider.appendChild( fragment ); 5490 } else { 5491 let insertCellElement = this.cells[ index ].element; 5492 this.slider.insertBefore( fragment, insertCellElement ); 5493 } 5494 // add to this.cells 5495 if ( index === 0 ) { 5496 // prepend, add to start 5497 this.cells = cells.concat( this.cells ); 5498 } else if ( isAppend ) { 5499 // append, add to end 5500 this.cells = this.cells.concat( cells ); 5501 } else { 5502 // insert in this.cells 5503 let endCells = this.cells.splice( index, len - index ); 5504 this.cells = this.cells.concat( cells ).concat( endCells ); 5505 } 5506 5507 this._sizeCells( cells ); 5508 this.cellChange( index ); 5509 this.positionSliderAtSelected(); 5510}; 5511 5512proto.append = function( elems ) { 5513 this.insert( elems, this.cells.length ); 5514}; 5515 5516proto.prepend = function( elems ) { 5517 this.insert( elems, 0 ); 5518}; 5519 5520/** 5521 * Remove cells 5522 * @param {[Element, Array, NodeList]} elems - ELements to remove 5523 */ 5524proto.remove = function( elems ) { 5525 let cells = this.getCells( elems ); 5526 if ( !cells || !cells.length ) return; 5527 5528 let minCellIndex = this.cells.length - 1; 5529 // remove cells from collection & DOM 5530 cells.forEach( ( cell ) => { 5531 cell.remove(); 5532 let index = this.cells.indexOf( cell ); 5533 minCellIndex = Math.min( index, minCellIndex ); 5534 utils.removeFrom( this.cells, cell ); 5535 } ); 5536 5537 this.cellChange( minCellIndex ); 5538 this.positionSliderAtSelected(); 5539}; 5540 5541/** 5542 * logic to be run after a cell's size changes 5543 * @param {Element} elem - cell's element 5544 */ 5545proto.cellSizeChange = function( elem ) { 5546 let cell = this.getCell( elem ); 5547 if ( !cell ) return; 5548 5549 cell.getSize(); 5550 5551 let index = this.cells.indexOf( cell ); 5552 this.cellChange( index ); 5553 // do not position slider after lazy load 5554}; 5555 5556/** 5557 * logic any time a cell is changed: added, removed, or size changed 5558 * @param {Integer} changedCellIndex - index of the changed cell, optional 5559 */ 5560proto.cellChange = function( changedCellIndex ) { 5561 let prevSelectedElem = this.selectedElement; 5562 this._positionCells( changedCellIndex ); 5563 this._updateWrapShiftCells(); 5564 this.setGallerySize(); 5565 // update selectedIndex, try to maintain position & select previous selected element 5566 let cell = this.getCell( prevSelectedElem ); 5567 if ( cell ) this.selectedIndex = this.getCellSlideIndex( cell ); 5568 this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex ); 5569 5570 this.emitEvent( 'cellChange', [ changedCellIndex ] ); 5571 // position slider 5572 this.select( this.selectedIndex ); 5573}; 5574 5575// ----- ----- // 5576 5577return Flickity; 5578 5579} ) ); 5580// lazyload 5581( function( window, factory ) { 5582 // universal module definition 5583 if ( typeof module == 'object' && module.exports ) { 5584 // CommonJS 5585 module.exports = factory( 5586 require('./core'), 5587 require('fizzy-ui-utils'), 5588 ); 5589 } else { 5590 // browser global 5591 factory( 5592 window.Flickity, 5593 window.fizzyUIUtils, 5594 ); 5595 } 5596 5597}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) { 5598 5599const lazyAttr = 'data-flickity-lazyload'; 5600const lazySrcAttr = `${lazyAttr}-src`; 5601const lazySrcsetAttr = `${lazyAttr}-srcset`; 5602const imgSelector = `img[${lazyAttr}], img[${lazySrcAttr}], ` + 5603 `img[${lazySrcsetAttr}], source[${lazySrcsetAttr}]`; 5604 5605Flickity.create.lazyLoad = function() { 5606 this.on( 'select', this.lazyLoad ); 5607 5608 this.handleLazyLoadComplete = this.onLazyLoadComplete.bind( this ); 5609}; 5610 5611let proto = Flickity.prototype; 5612 5613proto.lazyLoad = function() { 5614 let { lazyLoad } = this.options; 5615 if ( !lazyLoad ) return; 5616 5617 // get adjacent cells, use lazyLoad option for adjacent count 5618 let adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0; 5619 // lazy load images 5620 this.getAdjacentCellElements( adjCount ) 5621 .map( getCellLazyImages ) 5622 .flat() 5623 .forEach( ( img ) => new LazyLoader( img, this.handleLazyLoadComplete ) ); 5624}; 5625 5626function getCellLazyImages( cellElem ) { 5627 // check if cell element is lazy image 5628 if ( cellElem.matches('img') ) { 5629 let cellAttr = cellElem.getAttribute( lazyAttr ); 5630 let cellSrcAttr = cellElem.getAttribute( lazySrcAttr ); 5631 let cellSrcsetAttr = cellElem.getAttribute( lazySrcsetAttr ); 5632 if ( cellAttr || cellSrcAttr || cellSrcsetAttr ) { 5633 return cellElem; 5634 } 5635 } 5636 // select lazy images in cell 5637 return [ ...cellElem.querySelectorAll( imgSelector ) ]; 5638} 5639 5640proto.onLazyLoadComplete = function( img, event ) { 5641 let cell = this.getParentCell( img ); 5642 let cellElem = cell && cell.element; 5643 this.cellSizeChange( cellElem ); 5644 5645 this.dispatchEvent( 'lazyLoad', event, cellElem ); 5646}; 5647 5648// -------------------------- LazyLoader -------------------------- // 5649 5650/** 5651 * class to handle loading images 5652 * @param {Image} img - Image element 5653 * @param {Function} onComplete - callback function 5654 */ 5655function LazyLoader( img, onComplete ) { 5656 this.img = img; 5657 this.onComplete = onComplete; 5658 this.load(); 5659} 5660 5661LazyLoader.prototype.handleEvent = utils.handleEvent; 5662 5663LazyLoader.prototype.load = function() { 5664 this.img.addEventListener( 'load', this ); 5665 this.img.addEventListener( 'error', this ); 5666 // get src & srcset 5667 let src = this.img.getAttribute( lazyAttr ) || 5668 this.img.getAttribute( lazySrcAttr ); 5669 let srcset = this.img.getAttribute( lazySrcsetAttr ); 5670 // set src & serset 5671 this.img.src = src; 5672 if ( srcset ) this.img.setAttribute( 'srcset', srcset ); 5673 // remove attr 5674 this.img.removeAttribute( lazyAttr ); 5675 this.img.removeAttribute( lazySrcAttr ); 5676 this.img.removeAttribute( lazySrcsetAttr ); 5677}; 5678 5679LazyLoader.prototype.onload = function( event ) { 5680 this.complete( event, 'flickity-lazyloaded' ); 5681}; 5682 5683LazyLoader.prototype.onerror = function( event ) { 5684 this.complete( event, 'flickity-lazyerror' ); 5685}; 5686 5687LazyLoader.prototype.complete = function( event, className ) { 5688 // unbind events 5689 this.img.removeEventListener( 'load', this ); 5690 this.img.removeEventListener( 'error', this ); 5691 let mediaElem = this.img.parentNode.matches('picture') ? this.img.parentNode : this.img; 5692 mediaElem.classList.add( className ); 5693 5694 this.onComplete( this.img, event ); 5695}; 5696 5697// ----- ----- // 5698 5699Flickity.LazyLoader = LazyLoader; 5700 5701return Flickity; 5702 5703} ) ); 5704// imagesloaded 5705( function( window, factory ) { 5706 // universal module definition 5707 if ( typeof module == 'object' && module.exports ) { 5708 // CommonJS 5709 module.exports = factory( 5710 require('./core'), 5711 require('imagesloaded'), 5712 ); 5713 } else { 5714 // browser global 5715 factory( 5716 window.Flickity, 5717 window.imagesLoaded, 5718 ); 5719 } 5720 5721}( typeof window != 'undefined' ? window : this, 5722 function factory( Flickity, imagesLoaded ) { 5723 5724Flickity.create.imagesLoaded = function() { 5725 this.on( 'activate', this.imagesLoaded ); 5726}; 5727 5728Flickity.prototype.imagesLoaded = function() { 5729 if ( !this.options.imagesLoaded ) return; 5730 5731 let onImagesLoadedProgress = ( instance, image ) => { 5732 let cell = this.getParentCell( image.img ); 5733 this.cellSizeChange( cell && cell.element ); 5734 if ( !this.options.freeScroll ) this.positionSliderAtSelected(); 5735 }; 5736 imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress ); 5737}; 5738 5739return Flickity; 5740 5741} ) );
5742 5743// Flickity 5744// ------------------------------------------------------------- 5745 5746// Homepage - testimonial-gallery 5747// ------------------------------------------------------------- 5748// jQuery(document).ready(function($){ 5749// $('.home .tribe-events-day-time-slot').flickity({ 5750// wrapAround: true, 5751// contain: true, 5752// autoPlay: 5500, 5753// prevNextButtons: false, 5754// pageDots: true, 5755// imagesLoaded: true, 5756// cellAlign: 'left' 5757// }); 5758// }); 5759 5760// ------------------------------------------------------------- 5761// ------------------------------------------------------------- 5762// ------------------------------------------------------------- 5763// Have you seen a IE mobile device? There is issues that this mmenu has with IE 5764// ------------------------------------------------------------- 5765// ------------------------------------------------------------- 5766// ------------------------------------------------------------- 5767// if (document.documentElement.clientWidth < 769) {
vendor: 37,528 bytes, lines 5768-5769
5768/*! For license information please see mmenu.js.LICENSE.txt */ 5769(()=>{"use strict";const e={hooks:{},navbar:{add:!0,title:"Menu",titleLink:"parent"},slidingSubmenus:!0},t={classNames:{divider:"Divider",nolistview:"NoListview",nopanel:"NoPanel",panel:"Panel",selected:"Selected",vertical:"Vertical"},language:null,panelNodetype:["ul","ol","div"],screenReader:{closeSubmenu:"Close submenu",openSubmenu:"Open submenu",toggleSubmenu:"Toggle submenu"}},n=(e,t)=>{"object"!=s(e)&&(e={}),"object"!=s(t)&&(t={});for(let i in t)t.hasOwnProperty(i)&&(void 0===e[i]?e[i]=t[i]:"object"==s(e[i])&&n(e[i],t[i]));return e},s=e=>({}.toString.call(e).match(/\s([a-zA-Z]+)/)[1].toLowerCase()),i=()=>"mm-"+a++;let a=0;const o=e=>"mm-clone-"==e.slice(0,9)?e:`mm-clone-${e}`,r=e=>"mm-clone-"==e.slice(0,9)?e.slice(9):e,l={},m=(e,t)=>{void 0===l[t]&&(l[t]={}),n(l[t],e)},c=e=>{const t=e.split("."),n=document.createElement(t.shift());return n.classList.add(...t),n},d=(e,t)=>t.length?[].slice.call(e.querySelectorAll(t)):[],h=(e,t)=>{const n=Array.prototype.slice.call(e.children);return t?n.filter((e=>e.matches(t))):n},p=(e,t)=>{let n=[],s=e.parentElement;for(;s;)n.push(s),s=s.parentElement;return t?n.filter((e=>e.matches(t))):n},u=e=>e.filter((e=>!e.matches(".mm-hidden"))),f=e=>{let t=[];return u(e).forEach((e=>{t.push(...h(e,"a.mm-listitem__text"))})),t.filter((e=>!e.matches(".mm-btn--next")))},b=(e,t,n)=>{e.matches("."+t)&&e.classList.add(n)};let v={};const g=(e,t,n)=>{"number"==typeof e&&(e="(min-width: "+e+"px)"),v[e]=v[e]||[],v[e].push({yes:t,no:n})},L=(e,t)=>{var n=t.matches?"yes":"no";for(let t=0;t<v[e].length;t++)v[e][t][n]()};var _,E,w,P=function(e,t,n){if(!t.has(e))throw new TypeError("attempted to set private field on non-instance");return t.set(e,n),n},y=function(e,t){if(!t.has(e))throw new TypeError("attempted to get private field on non-instance");return t.get(e)};m({"Close submenu":"Untermenü schlieÃen",Menu:"Menü","Open submenu":"Untermenü öffnen","Toggle submenu":"Untermenü wechseln"},"de"),m({"Close submenu":"Ø¨Ø³ØªÙ Ø²ÛØ±Ù ÙÙ",Menu:"Ù ÙÙ","Open submenu":"Ø¨Ø§Ø²Ú©Ø±Ø¯Ù Ø²ÛØ±Ù ÙÙ","Toggle submenu":"سÙÛÛÚ Ø²ÛØ±Ù ÙÙ"},"fa"),m({"Close submenu":"Submenu sluiten",Menu:"Menu","Open submenu":"Submenu openen","Toggle submenu":"Submenu wisselen"},"nl"),m({"Close submenu":"Fechar submenu",Menu:"Menu","Open submenu":"Abrir submenu","Toggle submenu":"Alternar submenu"},"pt_br"),m({"Close submenu":"ÐакÑÑÑÑ Ð¿Ð¾Ð´Ð¼ÐµÐ½Ñ",Menu:"ÐенÑ","Open submenu":"ÐÑкÑÑÑÑ Ð¿Ð¾Ð´Ð¼ÐµÐ½Ñ","Toggle submenu":"ÐеÑеклÑÑиÑÑ Ð¿Ð¾Ð´Ð¼ÐµÐ½Ñ"},"ru"),m({"Close submenu":"ZatvoriÅ¥ submenu",Menu:"Menu","Open submenu":"OtvoriÅ¥ submenu","Toggle submenu":"Prepnúť submenu"},"sk"),m({"Close submenu":"ÐакÑиÑи пÑдменÑ",Menu:"ÐенÑ","Open submenu":"ÐÑдкÑиÑи пÑдменÑ","Toggle submenu":"ÐеÑемкнÑÑи пÑдменÑ"},"uk");class S{constructor(s,i,a){return _.set(this,void 0),E.set(this,void 0),w.set(this,void 0),this.opts=n(i,e),this.conf=n(a,t),this._api=["i18n","bind","openPanel","closePanel","setSelected"],this.node={},this.hook={},this.node.menu="string"==typeof s?document.querySelector(s):s,"function"==typeof this._deprecatedWarnings&&this._deprecatedWarnings(),this.trigger("init:before"),this._initObservers(),this._initAddons(),this._initHooks(),this._initAPI(),this._initMenu(),this._initPanels(),this._initOpened(),(()=>{for(let e in v){let t=window.matchMedia(e);L(e,t),t.onchange=n=>{L(e,t)}}})(),this.trigger("init:after"),this}openPanel(e,t=!0,n=!0){if(!e)return;e=e.closest(".mm-panel"),this.trigger("openPanel:before",[e,{animation:t,setfocus:n}]);const s=e.closest(".mm-listitem--vertical");if(s){s.classList.add("mm-listitem--opened");const e=s.closest(".mm-panel");this.openPanel(e)}else{const n=h(this.node.pnls,".mm-panel--opened")[0];e.matches(".mm-panel--parent")&&n&&n.classList.add("mm-panel--highest");const s=["mm-panel--opened","mm-panel--parent"],i=[];t?s.push("mm-panel--noanimation"):i.push("mm-panel--noanimation"),h(this.node.pnls,".mm-panel").forEach((t=>{t.classList.add(...i),t.classList.remove(...s),t!==n&&t.classList.remove("mm-panel--highest"),t===e?t.removeAttribute("inert"):t.setAttribute("inert","true")})),e.classList.add("mm-panel--opened");let a=d(this.node.pnls,`#${e.dataset.mmParent}`)[0];for(;a;)a=a.closest(".mm-panel"),a.classList.add("mm-panel--parent"),a=d(this.node.pnls,`#${a.dataset.mmParent}`)[0]}this.trigger("openPanel:after",[e,{animation:t,setfocus:n}])}closePanel(e,t=!0,n=!0){if(e&&(e.matches(".mm-panel--opened")||e.parentElement.matches(".mm-listitem--opened"))){if(this.trigger("closePanel:before",[e]),e.parentElement.matches(".mm-listitem--vertical"))e.parentElement.classList.remove("mm-listitem--opened");else if(e.dataset.mmParent){const s=d(this.node.pnls,`#${e.dataset.mmParent}`)[0];this.openPanel(s,t,n)}else{const s=h(this.node.pnls,".mm-panel--parent").pop();if(s&&s!==e)this.openPanel(s,t,n);else{const s=h(this.node.pnls,".mm-panel")[0];s&&s!==e&&this.openPanel(s,t,n)}}this.trigger("closePanel:after",[e])}}togglePanel(e){let t="openPanel";(e.parentElement.matches(".mm-listitem--opened")||e.matches(".mm-panel--opened"))&&(t="closePanel"),this[t](e)}setSelected(e){this.trigger("setSelected:before",[e]),d(this.node.menu,".mm-listitem--selected").forEach((e=>{e.classList.remove("mm-listitem--selected")})),e.classList.add("mm-listitem--selected"),this.trigger("setSelected:after",[e])}bind(e,t){this.hook[e]=this.hook[e]||[],this.hook[e].push(t)}trigger(e,t){if(this.hook[e])for(var n=0,s=this.hook[e].length;n<s;n++)this.hook[e][n].apply(this,t)}_initObservers(){P(this,_,new MutationObserver((e=>{e.forEach((e=>{e.addedNodes.forEach((e=>{e.matches(this.conf.panelNodetype.join(", "))&&this._initListview(e)}))}))}))),P(this,E,new MutationObserver((e=>{e.forEach((e=>{e.addedNodes.forEach((e=>{this._initListitem(e)}))}))}))),P(this,w,new MutationObserver((e=>{e.forEach((e=>{e.addedNodes.forEach((e=>{(null==e?void 0:e.matches(this.conf.panelNodetype.join(", ")))&&this._initSubPanel(e)}))}))})))}_initAPI(){const e=this;this.API={},this._api.forEach((t=>{this.API[t]=function(){return e[t].apply(e,arguments)}})),this.node.menu.mmApi=this.API}_initHooks(){for(let e in this.opts.hooks)this.bind(e,this.opts.hooks[e])}_initAddons(){this.trigger("initAddons:before");for(let e in S.addons)S.addons[e].call(this);this.trigger("initAddons:after")}_initMenu(){this.trigger("initMenu:before"),this.node.wrpr=this.node.wrpr||this.node.menu.parentElement,this.node.wrpr.classList.add("mm-wrapper"),this.node.menu.classList.add("mm-menu"),this.node.menu.id=this.node.menu.id||i(),this.node.menu.setAttribute("aria-label",this.i18n(this.opts.navbar.title||"Menu")),this.node.menu.setAttribute("aria-modal","true"),this.node.menu.setAttribute("role","dialog");const e=h(this.node.menu).filter((e=>e.matches(this.conf.panelNodetype.join(", "))));this.node.pnls=c("div.mm-panels"),this.node.menu.append(this.node.pnls),e.forEach((e=>{this._initPanel(e)})),this.trigger("initMenu:after")}_initPanels(){this.trigger("initPanels:before"),this.node.menu.addEventListener("click",(e=>{var t,n;const s=(null===(n=null===(t=e.target)||void 0===t?void 0:t.closest("a[href]"))||void 0===n?void 0:n.getAttribute("href"))||"";if("#"===s.slice(0,1))try{const t=d(this.node.menu,s)[0];t&&(e.preventDefault(),this.togglePanel(t))}catch(e){}}),{capture:!0}),this.trigger("initPanels:after")}_initPanel(e){var t;if(!e.matches(".mm-panel")&&(b(e,this.conf.classNames.panel,"mm-panel"),b(e,this.conf.classNames.nopanel,"mm-nopanel"),!e.matches(".mm-nopanel"))){if(this.trigger("initPanel:before",[e]),e.id=e.id||i(),e.matches("ul, ol")){const t=c("div");t.id=e.id,e.removeAttribute("id"),[].slice.call(e.classList).filter((e=>"mm-"===e.slice(0,3))).forEach((n=>{t.classList.add(n),e.classList.remove(n)})),Object.keys(e.dataset).filter((e=>"mm"===e.slice(0,2))).forEach((n=>{t.dataset[n]=e.dataset[n],delete e.dataset[n]})),e.before(t),t.append(e),e=t}return e.classList.add("mm-panel"),(null===(t=e.parentElement)||void 0===t?void 0:t.matches(".mm-listitem--vertical"))||this.node.pnls.append(e),this._initNavbar(e),h(e,"ul, ol").forEach((e=>{this._initListview(e)})),y(this,_).observe(e,{childList:!0}),this.trigger("initPanel:after",[e]),e}}_initNavbar(e){if(h(e,".mm-navbar").length)return;let t=null,n=null;if(e.dataset.mmParent)for(t=d(this.node.pnls,`#${e.dataset.mmParent}`)[0],n=t.closest(".mm-panel");n.closest(".mm-listitem--vertical");)n=n.parentElement.closest(".mm-panel");if(null==t?void 0:t.matches(".mm-listitem--vertical"))return;this.trigger("initNavbar:before",[e]);const s=c("div.mm-navbar");if(this.opts.navbar.add||s.classList.add("mm-hidden"),n){const e=c("a.mm-btn.mm-btn--prev.mm-navbar__btn");e.href=`#${n.id}`,e.setAttribute("aria-label",this.i18n(this.conf.screenReader.closeSubmenu)),s.append(e)}let i=null;t?i=h(t,".mm-listitem__text")[0]:n&&(i=d(n,'a[href="#'+e.id+'"]')[0]);const a=c("a.mm-navbar__title");switch(a.tabIndex=-1,a.setAttribute("aria-hidden","true"),this.opts.navbar.titleLink){case"anchor":i&&(a.href=i.getAttribute("href"));break;case"parent":n&&(a.href=`#${n.id}`)}const o=c("span");var r;o.innerHTML=e.dataset.mmTitle||((r=i)?[].slice.call(r.childNodes).filter((e=>e.nodeType===Node.TEXT_NODE)).map((e=>e.nodeValue.trim())).join(" "):"")||this.i18n(this.opts.navbar.title||"Menu"),e.prepend(s),s.append(a),a.append(o),this.trigger("initNavbar:after",[e])}_initListview(e){["htmlulistelement","htmlolistelement"].includes(s(e))&&(e.matches(".mm-listview")||(b(e,this.conf.classNames.nolistview,"mm-nolistview"),e.matches(".mm-nolistview")||(this.trigger("initListview:before",[e]),e.classList.add("mm-listview"),h(e).forEach((e=>{this._initListitem(e)})),y(this,E).observe(e,{childList:!0}),this.trigger("initListview:after",[e]))))}_initListitem(e){["htmllielement"].includes(s(e))&&(e.matches(".mm-listitem")||(b(e,this.conf.classNames.divider,"mm-divider"),e.matches(".mm-divider")||(this.trigger("initListitem:before",[e]),e.classList.add("mm-listitem"),b(e,this.conf.classNames.selected,"mm-listitem--selected"),h(e,"a, span").forEach((e=>{e.classList.add("mm-listitem__text")})),h(e,this.conf.panelNodetype.join(", ")).forEach((e=>{this._initSubPanel(e)})),y(this,w).observe(e,{childList:!0}),this.trigger("initListitem:after",[e]))))}_initSubPanel(e){if(e.matches(".mm-panel"))return;const t=e.parentElement;(e.matches("."+this.conf.classNames.vertical)||!this.opts.slidingSubmenus)&&t.classList.add("mm-listitem--vertical"),t.id=t.id||i(),e.id=e.id||i(),t.dataset.mmChild=e.id,e.dataset.mmParent=t.id;let n=h(t,".mm-btn")[0];n||(n=c("a.mm-btn.mm-btn--next.mm-listitem__btn"),h(t,"a, span").forEach((e=>{e.matches("span")?(n.classList.add("mm-listitem__text"),n.innerHTML=e.innerHTML,t.insertBefore(n,e.nextElementSibling),e.remove()):t.insertBefore(n,e.nextElementSibling)})),n.setAttribute("aria-label",this.i18n(this.conf.screenReader[t.matches(".mm-listitem--vertical")?"toggleSubmenu":"openSubmenu"]))),n.href=`#${e.id}`,this._initPanel(e)}_initOpened(){this.trigger("initOpened:before");const e=d(this.node.pnls,".mm-listitem--selected").pop();let t=h(this.node.pnls,".mm-panel")[0];e&&(this.setSelected(e),t=e.closest(".mm-panel")),this.openPanel(t,!1,!1),this.trigger("initOpened:after")}i18n(e){return((e,t)=>"string"==typeof t&&void 0!==l[t]&&l[t][e]||e)(e,this.conf.language)}static i18n(e={},t=""){if(!e||!t)return l;m(e,t)}}_=new WeakMap,E=new WeakMap,w=new WeakMap,S.addons={},S.node={},S.vars={};const M={use:!0,position:"left"},k={clone:!1,menu:{insertMethod:"append",insertSelector:"body"},page:{nodetype:"div",selector:null,noSelector:[]},screenReader:{closeMenu:"Close menu",openMenu:"Open menu"}},T=["left","left-front","right","right-front","top","bottom"];S.prototype.open=function(){this.node.menu.matches(".mm-menu--opened")||(this.trigger("open:before"),this.node.wrpr.classList.add("mm-wrapper--opened",`mm-wrapper--position-${this.opts.offCanvas.position}`),this.node.menu.classList.add("mm-menu--opened"),this.node.menu.removeAttribute("inert"),S.node.blck.removeAttribute("inert"),S.node.page.setAttribute("inert","true"),this.node.open=document.activeElement,this.trigger("open:after"))},S.prototype.close=function(){var e;this.node.menu.matches(".mm-menu--opened")&&(this.trigger("close:before"),this.node.wrpr.classList.remove("mm-wrapper--opened",`mm-wrapper--position-${this.opts.offCanvas.position}`),this.node.menu.classList.remove("mm-menu--opened"),this.node.menu.setAttribute("inert","true"),S.node.blck.setAttribute("inert","true"),S.node.page.removeAttribute("inert"),null===(e=this.node.open||document.querySelector(`[href="#${this.node.menu.id}"]`)||null)||void 0===e||e.focus(),document.body.scrollLeft=0,document.documentElement.scrollLeft=0,this.trigger("close:after"))},S.prototype.setPage=function(e){const t=this.conf.offCanvas;if(!e){let n="string"==typeof t.page.selector?d(document.body,t.page.selector):h(document.body,t.page.nodetype);if(n=n.filter((e=>!e.matches(".mm-menu, .mm-wrapper__blocker"))),t.page.noSelector.length&&(n=n.filter((e=>!e.matches(t.page.noSelector.join(", "))))),n.length>1){let e=c("div");n[0].before(e),n.forEach((t=>{e.append(t)})),n=[e]}e=n[0]}this.trigger("setPage:before",[e]),e.classList.add("mm-page","mm-slideout"),e.id=e.id||i(),S.node.blck.setAttribute("href",`#${e.id}`),S.node.page=e,this.trigger("setPage:after",[e])};const x={fix:!0},A="ontouchstart"in window||!!navigator.msMaxTouchPoints||!1,C=["light","dark","white","black","light-contrast","dark-contrast","white-contrast","black-contrast"];S.prototype.theme=function(e=null){const t=this.opts.theme;if(!e)return t;C.includes(e)&&(this.node.menu.classList.remove(`mm-menu--theme-${t}`),this.node.menu.classList.add(`mm-menu--theme-${e}`),this.opts.theme=e)};const N={close:!1,open:!1},$={add:!1},O={use:!1,top:[],bottom:[],position:"left",type:"default"},H={add:!1,blockPanel:!0,visible:3},q={breadcrumbs:{separator:"/",removeFirst:!1}};function I(){this.opts.navbars=this.opts.navbars||[],this.conf.navbars=this.conf.navbars||{},n(this.conf.navbars,q);let e=this.opts.navbars;if(void 0!==e&&(e instanceof Array||(e=[e]),e.length)){var t={};e.forEach((e=>{if(!(e=function(e){return"boolean"==typeof e&&e&&(e={}),"object"!=typeof e&&(e={}),void 0===e.content&&(e.content=["prev","title"]),e.content instanceof Array||(e.content=[e.content]),void 0===e.use&&(e.use=!0),e}(e)).use)return;const n=c("div.mm-navbar");let{position:s}=e;"bottom"!==s&&(s="top"),t[s]||(t[s]=c("div.mm-navbars.mm-navbars--"+s)),t[s].append(n);for(let t=0,s=e.content.length;t<s;t++){const s=e.content[t];if("string"==typeof s){const e=I.navbarContents[s];if("function"==typeof e)e.call(this,n);else{let e=c("span");e.innerHTML=s;const t=h(e);1==t.length&&(e=t[0]),n.append(e)}}else n.append(s)}if("string"==typeof e.type){const t=I.navbarTypes[e.type];"function"==typeof t&&t.call(this,n)}let i=()=>{n.classList.remove("mm-hidden")};"boolean"==typeof e.use?this.bind("initMenu:after",i):g(e.use,i,(()=>{n.classList.add("mm-hidden")}))})),this.bind("initMenu:after",(()=>{for(let e in t)this.node.pnls["bottom"==e?"after":"before"](t[e])}))}}I.navbarContents={breadcrumbs:function(e){var t=c("div.mm-navbar__breadcrumbs");e.append(t),this.bind("initNavbar:after",(e=>{if(!e.querySelector(".mm-navbar__breadcrumbs")){h(e,".mm-navbar")[0].classList.add("mm-hidden");for(var t=[],n=c("span.mm-navbar__breadcrumbs"),s=e,i=!0;s;){if(!(s=s.closest(".mm-panel")).parentElement.matches(".mm-listitem--vertical")){let e=d(s,".mm-navbar__title span")[0];if(e){let n=e.textContent;n.length&&t.unshift(i?`<span>${n}</span>`:`<a \n href="#${s.id}" \n title="${this.i18n(this.conf.screenReader.openSubmenu)}"\n >${n}</a>`)}i=!1}s=d(this.node.pnls,`#${s.dataset.mmParent}`)[0]}this.conf.navbars.breadcrumbs.removeFirst&&t.shift(),n.innerHTML=t.join('<span class="mm-separator">'+this.conf.navbars.breadcrumbs.separator+"</span>"),h(e,".mm-navbar")[0].append(n)}})),this.bind("openPanel:before",(e=>{var n=e.querySelector(".mm-navbar__breadcrumbs");t.innerHTML=n?n.innerHTML:""}))},close:function(e){const t=c("a.mm-btn.mm-btn--close.mm-navbar__btn");t.setAttribute("aria-label",this.i18n(this.conf.offCanvas.screenReader.closeMenu)),e.append(t),this.bind("setPage:after",(e=>{t.href=`#${e.id}`}))},prev:function(e){let t=c("a.mm-btn.mm-hidden");e.append(t),this.bind("initNavbar:after",(e=>{h(e,".mm-navbar")[0].classList.add("mm-hidden")})),this.bind("openPanel:before",(e=>{if(e.parentElement.matches(".mm-listitem--vertical"))return;t.classList.add("mm-hidden");const n=e.querySelector(".mm-navbar__btn.mm-btn--prev");if(n){const e=n.cloneNode(!0);t.after(e),t.remove(),t=e}}))},searchfield:function(e){let t=c("div.mm-navbar__searchfield");t.id=i(),e.append(t),this.opts.searchfield=this.opts.searchfield||{},this.opts.searchfield.add=!0,this.opts.searchfield.addTo=`#${t.id}`},title:function(e){let t=c("a.mm-navbar__title");e.append(t),this.bind("openPanel:before",(e=>{if(e.parentElement.matches(".mm-listitem--vertical"))return;const n=e.querySelector(".mm-navbar__title");if(n){const e=n.cloneNode(!0);t.after(e),t.remove(),t=e}}))}},I.navbarTypes={tabs:function(e){function t(n){const s=h(e,`.mm-navbar__tab[href="#${n.id}"]`)[0];if(s)s.classList.add("mm-navbar__tab--selected"),s.ariaExpanded="true";else{const e=d(this.node.pnls,`#${n.dataset.mmParent}`)[0];e&&t.call(this,e.closest(".mm-panel"))}}e.classList.add("mm-navbar--tabs"),e.closest(".mm-navbars").classList.add("mm-navbars--has-tabs"),h(e,"a").forEach((e=>{e.classList.add("mm-navbar__tab")})),this.bind("openPanel:before",(n=>{h(e,"a").forEach((e=>{e.classList.remove("mm-navbar__tab--selected"),e.ariaExpanded="false"})),t.call(this,n)})),this.bind("initPanels:after",(()=>{e.addEventListener("click",(e=>{var t,n,s;const i=null===(n=null===(t=e.target)||void 0===t?void 0:t.closest(".mm-navbar__tab"))||void 0===n?void 0:n.getAttribute("href");try{null===(s=d(this.node.pnls,`${i}.mm-panel`)[0])||void 0===s||s.classList.add("mm-panel--noanimation")}catch(e){}}),{capture:!0})}))}};const j={scroll:!1,update:!1},B={scrollOffset:0,updateOffset:50},R={add:!1,addTo:"panels",noResults:"No results found.",placeholder:"Search",search:!0,searchIn:"panels",splash:"",title:"Search"},D={cancel:!0,clear:!0,form:{},input:{},panel:{},submit:!1};m({cancel:"abbrechen","Cancel searching":"Suche abbrechen","Clear searchfield":"Suchfeld löschen","No results found.":"Keine Ergebnisse gefunden.",Search:"Suche"},"de"),m({cancel:"Ø§ÙØµØ±Ø§Ù","Cancel searching":"ÙØºÙ جستجÙ","Clear searchfield":"پاک کرد٠ÙÛÙØ¯ جستجÙ","No results found.":"ÙØªÛجÙâØ§Û ÛØ§Ùت ÙØ´Ø¯.",Search:"جستجÙ"},"fa"),m({cancel:"annuleren","Cancel searching":"Zoeken annuleren","Clear searchfield":"Zoekveld leeg maken","No results found.":"Geen resultaten gevonden.",Search:"Zoeken"},"nl"),m({cancel:"cancelar","Cancel searching":"Cancelar pesquisa","Clear searchfield":"Limpar campo de pesquisa","No results found.":"Nenhum resultado encontrado.",Search:"Buscar"},"pt_br"),m({cancel:"оÑмениÑÑ","Cancel searching":"ÐÑмениÑÑ Ð¿Ð¾Ð¸Ñк","Clear searchfield":"ÐÑиÑÑиÑÑ Ð¿Ð¾Ð»Ðµ поиÑка","No results found.":"ÐиÑего не найдено.",Search:"ÐайÑи"},"ru"),m({cancel:"zruÅ¡iÅ¥","Cancel searching":"ZruÅ¡iÅ¥ vyhľadávanie","Clear searchfield":"VymazaÅ¥ pole vyhľadávania","No results found.":"Neboli nájdené žiadne výsledky.",Search:"Vyhľadávanie"},"sk"),m({cancel:"ÑкаÑÑваÑи","Cancel searching":"СкаÑÑваÑи поÑÑк","Clear searchfield":"ÐÑиÑÑиÑи поле поÑÑкÑ","No results found.":"ÐÑÑого не знайдено.",Search:"ÐоÑÑк"},"uk");const F=function(){const e=this.opts.searchfield,t=this.conf.searchfield;let n=h(this.node.pnls,".mm-panel--search")[0];return n||(n=c("div.mm-panel--search"),K(n,t.panel),e.title.length&&(n.dataset.mmTitle=this.i18n(e.title)),n.append(c("ul")),this._initPanel(n),n)},Z=function(e){const t=this.opts.searchfield;if(e.matches(t.addTo)){const t=e.matches(".mm-panel--search");if(!d(e,".mm-searchfield").length){const n=W.call(this,t);t&&n.classList.add("mm-searchfield--cancelable"),e.prepend(n),z.call(this,n)}}if(t.splash.length&&e.matches(".mm-panel--search")&&!d(e,".mm-panel__splash").length){const n=c("div.mm-panel__splash");n.innerHTML=t.splash,e.append(n)}if(t.noResults.length&&!d(e,".mm-panel__noresults").length){const n=c("div.mm-panel__noresults");n.innerHTML=this.i18n(t.noResults),e.append(n)}},W=function(e=!1){const t=this.opts.searchfield,n=this.conf.searchfield,s=c("form.mm-searchfield");K(s,n.form);const i=c("div.mm-searchfield__input");s.append(i);const a=c("input");if(i.append(a),a.type="text",a.autocomplete="off",a.placeholder=this.i18n(t.placeholder),a.setAttribute("aria-label",this.i18n(t.placeholder)),K(a,n.input),n.submit){const e=c("button.mm-btnreset.mm-btn.mm-btn--next.mm-searchfield__btn");e.type="submit",i.append(e)}else if(n.clear){const e=c("button.mm-btnreset.mm-btn.mm-btn--close.mm-searchfield__btn");e.type="reset",e.setAttribute("aria-label",this.i18n("Clear searchfield")),i.append(e),s.addEventListener("reset",(()=>{window.requestAnimationFrame((()=>{a.dispatchEvent(new Event("input"))}))}))}if(n.cancel&&e){const e=c("a.mm-searchfield__cancel");e.href="#",e.setAttribute("aria-label",this.i18n("Cancel searching")),e.textContent=this.i18n("cancel"),s.append(e),e.addEventListener("click",(e=>{e.preventDefault(),this.closePanel(h(this.node.pnls,".mm-panel--search")[0],!1)}))}return s},z=function(e){const t=this.opts.searchfield,n=e.closest(".mm-panel")||d(this.node.pnls,".mm-panel--search")[0],s=d(e,"input")[0];let i=n.matches(".mm-panel--search")?h(this.node.pnls,t.searchIn):[n];i=i.filter((e=>!e.matches(".mm-panel--search")));const a=()=>{const a=s.value.toLowerCase().trim();if(a.length?e.classList.add("mm-searchfield--searching"):e.classList.remove("mm-searchfield--searching"),!t.search)return;const o=[];if(i.forEach((e=>{e.scrollTop=0,o.push(...d(e,".mm-listitem"))})),a.length){this.trigger("search:before"),n.classList.add("mm-panel--searching"),o.forEach((e=>{const t=h(e,".mm-listitem__text")[0];var n;(!t||(n=t,[].slice.call(n.childNodes).filter((e=>!e.ariaHidden)).map((e=>e.textContent)).join(" ")).toLowerCase().indexOf(a)>-1)&&(e.dataset.mmSearchresult=a)}));let e=0;e=n.matches(".mm-panel--search")?V(n,a,i):Y(a,i),n.classList[0==e?"add":"remove"]("mm-panel--noresults"),this.trigger("search:after")}else this.trigger("clear:before"),n.classList.remove("mm-panel--searching","mm-panel--noresults"),n.matches(".mm-panel--search")?(U(n),t.splash||this.closePanel(n,!1,!1)):G(i),this.trigger("clear:after")};s.addEventListener("input",a),a()},V=(e,t,n)=>{const s=d(e,".mm-listview")[0];s.innerHTML="";let i=0;return n.forEach((e=>{const n=d(e,`[data-mm-searchresult="${t}"]`);if(i+=n.length,n.length){const t=d(e,".mm-navbar__title")[0];if(t){const e=c("li.mm-divider");e.innerHTML=t.innerHTML,s.append(e)}n.forEach((e=>{const t=e.cloneNode(!0);s.append(t)}))}})),d(s,".mm-panel").forEach((e=>{e.remove()})),["id","data-mm-parent","data-mm-child"].forEach((e=>{d(s,`[${e}]`).forEach((t=>{t.removeAttribute(e)}))})),d(s,".mm-listitem--opened").forEach((e=>{e.classList.remove("mm-listitem--opened")})),i},U=e=>{d(e,".mm-listview")[0].innerHTML=""},Y=(e,t)=>{let n=0;return t.forEach((t=>{const s=d(t,`[data-mm-searchresult="${e}"]`);n+=s.length,s.length&&s.forEach((t=>{const n=((e,t)=>{let n=[],s=e.previousElementSibling;for(;s;)t&&!s.matches(t)||n.push(s),s=s.previousElementSibling;return n})(t,".mm-divider")[0];n&&(n.dataset.mmSearchresult=e)})),d(t,".mm-listitem, .mm-divider").forEach((t=>{t.classList.add("mm-hidden"),t.dataset.mmSearchresult===e&&[t,...p(t,".mm-listitem")].forEach((e=>{e.classList.remove("mm-hidden")}))}))})),n},G=e=>{e.forEach((e=>{d(e,".mm-listitem, .mm-divider").forEach((e=>{e.classList.remove("mm-hidden")}))}))},K=(e,t)=>{t&&Object.keys(t).forEach((n=>{e[n]=t[n]}))},X={add:!1,addTo:"panels"},J={current:!0,hover:!1,parent:!1},Q={collapsed:{use:!1},expanded:{use:!1,initial:"open"}};S.addons={offcanvas:function(){this.opts.offCanvas=this.opts.offCanvas||{},this.conf.offCanvas=this.conf.offCanvas||{};const e=n(this.opts.offCanvas,M),t=n(this.conf.offCanvas,k);e.use&&(T.includes(e.position)||(e.position=T[0]),this._api.push("open","close","setPage","position"),t.clone&&(this.node.menu=this.node.menu.cloneNode(!0),this.node.menu.id&&(this.node.menu.id=o(this.node.menu.id)),d(this.node.menu,"[id]").forEach((e=>{e.id=o(e.id)}))),this.bind("initMenu:before",(()=>{this.node.wrpr=document.querySelector(t.menu.insertSelector),this.node.wrpr[t.menu.insertMethod](this.node.menu)})),S.node.blck||this.bind("initMenu:before",(()=>{const e=c("a.mm-wrapper__blocker.mm-blocker.mm-slideout");e.id=i(),e.setAttribute("aria-label",this.i18n(t.screenReader.closeMenu)),e.setAttribute("inert","true"),document.querySelector(t.menu.insertSelector).append(e),S.node.blck=e})),this.bind("initMenu:after",(()=>{this.setPage(S.node.page),this.node.menu.classList.add("mm-menu--offcanvas"),this.node.menu.setAttribute("inert","true"),T.includes(e.position)&&(this.node.wrpr.classList.add(`mm-wrapper--position-${e.position}`),this.node.menu.classList.add(`mm-menu--position-${e.position}`));let t=window.location.hash;if(t){let e=r(this.node.menu.id);e&&e==t.slice(1)&&setTimeout((()=>{this.open()}),1e3)}})),document.addEventListener("click",(e=>{var t;switch(null===(t=e.target.closest("a"))||void 0===t?void 0:t.getAttribute("href")){case`#${r(this.node.menu.id)}`:e.preventDefault(),this.open();break;case`#${r(S.node.page.id)}`:e.preventDefault(),this.close()}})),document.addEventListener("keyup",(e=>{"Escape"==e.key&&this.close()})))},scrollBugFix:function(){if(!A||!this.opts.offCanvas.use)return;if(this.opts.scrollBugFix=this.opts.scrollBugFix||{},!n(this.opts.scrollBugFix,x).fix)return;const e=(e=>{let t="",n=null;return e.addEventListener("touchstart",(e=>{1===e.touches.length&&(t="",n=e.touches[0].pageY)})),e.addEventListener("touchend",(e=>{0===e.touches.length&&(t="",n=null)})),e.addEventListener("touchmove",(e=>{if(t="",n&&1===e.touches.length){const s=e.changedTouches[0].pageY;s>n?t="down":s<n&&(t="up"),n=s}})),{get:()=>t}})(this.node.menu);this.node.menu.addEventListener("scroll",(e=>{e.preventDefault(),e.stopPropagation()}),{passive:!1}),this.node.menu.addEventListener("touchmove",(t=>{let n=t.target.closest(".mm-panel, .mm-iconbar__top, .mm-iconbar__bottom");n&&n.closest(".mm-listitem--vertical")&&(n=p(n,".mm-panel").pop()),n?(n.scrollHeight===n.offsetHeight||0==n.scrollTop&&"down"==e.get()||n.scrollHeight==n.scrollTop+n.offsetHeight&&"up"==e.get())&&t.stopPropagation():t.stopPropagation()}),{passive:!1}),this.bind("open:after",(()=>{var e=h(this.node.pnls,".mm-panel--opened")[0];e&&(e.scrollTop=0)})),window.addEventListener("orientationchange",(e=>{var t=h(this.node.pnls,".mm-panel--opened")[0];t&&(t.scrollTop=0,t.style["-webkit-overflow-scrolling"]="auto",t.style["-webkit-overflow-scrolling"]="touch")}))},theme:function(){this.opts.theme=this.opts.theme||"light";const e=this.opts.theme;C.includes(e)||(this.opts.theme=C[0]),this._api.push("theme"),this.bind("initMenu:after",(()=>{this.theme(this.opts.theme)}))},backButton:function(){if(this.opts.backButton=this.opts.backButton||{},!this.opts.offCanvas.use)return;const e=n(this.opts.backButton,N),t=`#${this.node.menu.id}`;if(e.close){let e=[];const n=()=>{e=[t],h(this.node.pnls,".mm-panel--opened, .mm-panel--parent").forEach((t=>{e.push("#"+t.id)}))};this.bind("open:after",(()=>{history.pushState(null,"",location.pathname+location.search+t)})),this.bind("open:after",n),this.bind("openPanel:after",n),this.bind("close:after",(()=>{e=[],history.back(),history.pushState(null,"",location.pathname+location.search)})),window.addEventListener("popstate",(()=>{if(this.node.menu.matches(".mm-menu--opened")&&e.length){e=e.slice(0,-1);const n=e[e.length-1];n==t?this.close():(this.openPanel(this.node.menu.querySelector(n)),history.pushState(null,"",location.pathname+location.search+t))}}))}e.open&&window.addEventListener("popstate",(e=>{this.node.menu.matches(".mm-menu--opened")||location.hash!=t||this.open()}))},counters:function(){if(this.opts.counters=this.opts.counters||{},!n(this.opts.counters,$).add)return;const e=e=>{const t=this.node.pnls.querySelector(`#${e.dataset.mmParent}`);if(!t)return;const n=t.querySelector(".mm-counter");if(!n)return;const s=[];h(e,".mm-listview").forEach((e=>{s.push(...h(e,".mm-listitem"))})),n.innerHTML=u(s).length.toString()},t=new MutationObserver((t=>{t.forEach((t=>{"class"==t.attributeName&&e(t.target.closest(".mm-panel"))}))}));this.bind("initListview:after",(t=>{const n=t.closest(".mm-panel"),s=this.node.pnls.querySelector(`#${n.dataset.mmParent}`);if(!s)return;const i=h(s,".mm-btn")[0];if(i){if(!h(i,".mm-counter").length){const e=c("span.mm-counter");e.setAttribute("aria-hidden","true"),i.prepend(e)}e(n)}})),this.bind("initListitem:after",(e=>{const n=e.closest(".mm-panel");n&&this.node.pnls.querySelector(`#${n.dataset.mmParent}`)&&t.observe(e,{attributes:!0})}))},iconbar:function(){this.opts.iconbar=this.opts.iconbar||{};const e=n(this.opts.iconbar,O);if(!e.use)return;let t;if(["top","bottom"].forEach(((n,i)=>{let a=e[n];"array"!=s(a)&&(a=[a]);const o=c("div.mm-iconbar__"+n);for(let e=0,t=a.length;e<t;e++)"string"==typeof a[e]?o.innerHTML+=a[e]:o.append(a[e]);o.children.length&&(t||(t=c("div.mm-iconbar")),t.append(o))})),t){this.bind("initMenu:after",(()=>{this.node.menu.prepend(t)}));let n="mm-menu--iconbar-"+e.position,s=()=>{this.node.menu.classList.add(n)},i=()=>{this.node.menu.classList.remove(n)};if("boolean"==typeof e.use?this.bind("initMenu:after",s):g(e.use,s,i),"tabs"==e.type){t.classList.add("mm-iconbar--tabs"),t.addEventListener("click",(e=>{const t=e.target.closest(".mm-iconbar__tab");if(t)if(t.matches(".mm-iconbar__tab--selected"))e.stopImmediatePropagation();else try{const n=d(this.node.menu,`${t.getAttribute("href")}.mm-panel`)[0];n&&(e.preventDefault(),e.stopImmediatePropagation(),this.openPanel(n,!1))}catch(e){}}));const e=n=>{d(t,"a").forEach((e=>{e.classList.remove("mm-iconbar__tab--selected")}));const s=d(t,'[href="#'+n.id+'"]')[0];if(s)s.classList.add("mm-iconbar__tab--selected");else{const t=d(this.node.pnls,`#${n.dataset.mmParent}`)[0];t&&e(t.closest(".mm-panel"))}};this.bind("openPanel:before",e)}}},iconPanels:function(){this.opts.iconPanels=this.opts.iconPanels||{};const e=n(this.opts.iconPanels,H);let t=!1;if("first"==e.visible&&(t=!0,e.visible=1),e.visible=Math.min(3,Math.max(1,e.visible)),e.visible++,e.add){this.bind("initMenu:after",(()=>{this.node.menu.classList.add("mm-menu--iconpanel")}));const n=["mm-panel--iconpanel-0","mm-panel--iconpanel-1","mm-panel--iconpanel-2","mm-panel--iconpanel-3"];t?this.bind("initMenu:after",(()=>{var e;null===(e=h(this.node.pnls,".mm-panel")[0])||void 0===e||e.classList.add("mm-panel--iconpanel-first")})):this.bind("openPanel:after",(t=>{if(t.closest(".mm-listitem--vertical"))return;let s=h(this.node.pnls,".mm-panel");s=s.filter((e=>e.matches(".mm-panel--parent"))),s.push(t),s=s.slice(-e.visible),s.forEach(((e,t)=>{e.classList.remove("mm-panel--iconpanel-first",...n),e.classList.add(`mm-panel--iconpanel-${t}`)}))}))}},navbars:I,pageScroll:function(){this.opts.pageScroll=this.opts.pageScroll||{},this.conf.pageScroll=this.conf.pageScroll||{};const e=n(this.opts.pageScroll,j),t=n(this.conf.pageScroll,B);var s;function i(){s&&window.scrollTo({top:s.getBoundingClientRect().top+document.scrollingElement.scrollTop-t.scrollOffset,behavior:"smooth"}),s=null}function a(e){try{if("#"==e.slice(0,1))return d(S.node.page,e)[0]}catch(e){}return null}if(this.opts.offCanvas.use&&e.scroll&&(this.bind("close:after",(()=>{i()})),this.node.menu.addEventListener("click",(e=>{var t,n;const o=(null===(n=null===(t=e.target)||void 0===t?void 0:t.closest("a[href]"))||void 0===n?void 0:n.getAttribute("href"))||"";(s=a(o))&&(e.preventDefault(),this.node.menu.matches(".mm-menu--sidebar-expanded")&&this.node.wrpr.matches(".mm-wrapper--sidebar-expanded")?i():this.close())}))),e.update){let e=[];this.bind("initListview:after",(t=>{const n=h(t,".mm-listitem");f(n).forEach((t=>{const n=a(t.getAttribute("href"));n&&e.unshift(n)}))}));let n=-1;window.addEventListener("scroll",(s=>{const i=window.scrollY;for(var a=0;a<e.length;a++)if(e[a].offsetTop<i+t.updateOffset){if(n!==a){n=a;let t=h(this.node.pnls,".mm-panel--opened")[0],s=d(t,".mm-listitem"),i=f(s);i=i.filter((t=>t.matches('[href="#'+e[a].id+'"]'))),i.length&&this.setSelected(i[0].parentElement)}break}}),{passive:!0})}},searchfield:function(){this.opts.searchfield=this.opts.searchfield||{},this.conf.searchfield=this.conf.searchfield||{};const e=n(this.opts.searchfield,R);if(n(this.conf.searchfield,D),e.add){switch(e.addTo){case"panels":e.addTo=".mm-panel";break;case"searchpanel":e.addTo=".mm-panel--search"}"panels"===e.searchIn&&(e.searchIn=".mm-panel"),this.bind("initPanel:after",(t=>{t.matches(e.addTo)&&!t.closest(".mm-listitem--vertical")&&Z.call(this,t)})),this.bind("initMenu:after",(()=>{const t=F.call(this);Z.call(this,t),d(this.node.menu,e.addTo).forEach((n=>{if(!n.matches(".mm-panel")){const s=W.call(this,!0);n.append(s);const i=d(s,"input")[0];e.splash.length?(i.addEventListener("focusin",(()=>{this.openPanel(t,!1,!1)})),this.bind("openPanel:after",(e=>{e.matches(".mm-panel--search")?s.classList.add("mm-searchfield--cancelable"):s.classList.remove("mm-searchfield--cancelable")}))):(this.bind("search:after",(()=>{this.openPanel(t,!1,!1)})),i.addEventListener("focusout",(()=>{i.value.length||this.closePanel(t,!1)}))),z.call(this,s)}}))})),this.bind("close:before",(()=>{d(this.node.menu,".mm-searchfield input").forEach((e=>{e.blur()}))}))}},sectionIndexer:function(){this.opts.sectionIndexer=this.opts.sectionIndexer||{},n(this.opts.sectionIndexer,X).add&&this.bind("initPanels:after",(()=>{if(!this.node.indx){let e="";"abcdefghijklmnopqrstuvwxyz".split("").forEach((t=>{e+='<a href="#">'+t+"</a>"}));let t=c("div.mm-sectionindexer");t.innerHTML=e,this.node.pnls.prepend(t),this.node.indx=t,this.node.indx.addEventListener("click",(e=>{e.target.matches("a")&&e.preventDefault()}));let n=e=>{if(!e.target.matches("a"))return;const t=e.target.textContent,n=h(this.node.pnls,".mm-panel--opened")[0];let s=-1,i=n.scrollTop;n.scrollTop=0,d(n,".mm-divider").filter((e=>!e.matches(".mm-hidden"))).forEach((e=>{s<0&&t==e.textContent.trim().slice(0,1).toLowerCase()&&(s=e.offsetTop)})),n.scrollTop=s>-1?s:i};A?(this.node.indx.addEventListener("touchstart",n),this.node.indx.addEventListener("touchmove",n)):this.node.indx.addEventListener("mouseover",n)}this.bind("openPanel:before",(e=>{const t=d(e,".mm-divider").filter((e=>!e.matches(".mm-hidden"))).length;this.node.indx.classList[t?"add":"remove"]("mm-sectionindexer--active")}))}))},setSelected:function(){this.opts.setSelected=this.opts.setSelected||{};const e=n(this.opts.setSelected,J);if("detect"==e.current){const e=t=>{t=t.split("?")[0].split("#")[0];const n=this.node.menu.querySelector('a[href="'+t+'"], a[href="'+t+'/"]');if(n)this.setSelected(n.parentElement);else{const n=t.split("/").slice(0,-1);n.length&&e(n.join("/"))}};this.bind("initMenu:after",(()=>{e.call(this,window.location.href)}))}else e.current||this.bind("initListview:after",(e=>{h(e,".mm-listitem--selected").forEach((e=>{e.classList.remove("mm-listitem--selected")}))}));e.hover&&this.bind("initMenu:after",(()=>{this.node.menu.classList.add("mm-menu--selected-hover")})),e.parent&&(this.bind("openPanel:after",(e=>{d(this.node.pnls,".mm-listitem--selected-parent").forEach((e=>{e.classList.remove("mm-listitem--selected-parent")}));let t=e;for(;t;){let e=d(this.node.pnls,`#${t.dataset.mmParent}`)[0];t=null==e?void 0:e.closest(".mm-panel"),e&&!e.matches(".mm-listitem--vertical")&&e.classList.add("mm-listitem--selected-parent")}})),this.bind("initMenu:after",(()=>{this.node.menu.classList.add("mm-menu--selected-parent")})))},sidebar:function(){if(!this.opts.offCanvas.use)return;this.opts.sidebar=this.opts.sidebar||{};const e=n(this.opts.sidebar,Q);if(e.collapsed.use){this.bind("initMenu:after",(()=>{this.node.menu.classList.add("mm-menu--sidebar-collapsed")}));let t=()=>{this.node.wrpr.classList.add("mm-wrapper--sidebar-collapsed")},n=()=>{this.node.wrpr.classList.remove("mm-wrapper--sidebar-collapsed")};"boolean"==typeof e.collapsed.use?this.bind("initMenu:after",t):g(e.collapsed.use,t,n)}if(e.expanded.use){this.bind("initMenu:after",(()=>{this.node.menu.classList.add("mm-menu--sidebar-expanded")}));let t=!1,n=()=>{t=!0,this.node.wrpr.classList.add("mm-wrapper--sidebar-expanded"),this.node.menu.removeAttribute("aria-modal"),this.open(),S.node.page.removeAttribute("inert")},s=()=>{t=!1,this.node.wrpr.classList.remove("mm-wrapper--sidebar-expanded"),this.node.menu.setAttribute("aria-modal","true"),this.close()};"boolean"==typeof e.expanded.use?this.bind("initMenu:after",n):g(e.expanded.use,n,s),this.bind("close:after",(()=>{t&&window.sessionStorage.setItem("mmenuExpandedState","closed")})),this.bind("open:after",(()=>{t&&(window.sessionStorage.setItem("mmenuExpandedState","open"),S.node.page.removeAttribute("inert"))}));let i=e.expanded.initial;const a=window.sessionStorage.getItem("mmenuExpandedState");switch(a){case"open":case"closed":i=a}"closed"===i&&this.bind("init:after",(()=>{this.close()}))}}},window&&(window.Mmenu=S)})();
5769 5770// MMENU 5771// ------------------------------------------------------------- 5772jQuery(document).ready(function ($) { 5773 new Mmenu('#sidebar', { 5774 offCanvas: { 5775 position: 'left', 5776 }, 5777 theme: 'light', 5778 }); 5779}); 5780// } 5781 5782// Sticky Header 5783// ------------------------------------------------------------- 5784jQuery(document).ready(function ($) { 5785 if ($('body.page-id-2 .sticky-header').length >= 1) { 5786 $(window).scroll(function () { 5787 var header = $(document).scrollTop(); 5788 var headerHeight = $('.site-header').height(); 5789 if (header > headerHeight) { 5790 $('.site-header').height(headerHeight); 5791 $('.sticky-header').addClass('sticky'); 5792 $('.sticky-header').fadeIn(); 5793 } else { 5794 $('.site-header').css('height', 'auto'); 5795 $('.sticky-header').removeClass('sticky'); 5796 } 5797 }); 5798 } else { 5799 $('.sticky-header').addClass('sticky'); 5800 } 5801}); 5802 5803// https://tympanus.net/codrops/2013/03/19/thumbnail-grid-with-expanding-preview/ 5804jQuery(document).ready(function ($) { 5805 // Get Viewport Dimensions -- NEW 5806 // ------------------------------------------------------------- 5807 function updateViewportDimensions() { 5808 var viewportwidth; 5809 var viewportheight; 5810 // the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight 5811 if (typeof window.innerWidth != 'undefined') { 5812 (viewportwidth = window.innerWidth), (viewportheight = window.innerHeight); 5813 } 5814 // IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document) 5815 else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) { 5816 (viewportwidth = document.documentElement.clientWidth), (viewportheight = document.documentElement.clientHeight); 5817 } 5818 // older versions of IE 5819 else { 5820 (viewportwidth = document.getElementsByTagName('body')[0].clientWidth), (viewportheight = document.getElementsByTagName('body')[0].clientHeight); 5821 } 5822 return { 5823 width: viewportwidth, 5824 height: viewportheight, 5825 }; 5826 } 5827 var viewport = updateViewportDimensions(); 5828 5829 // Throttle Resize-triggered Events 5830 // source: http://stackoverflow.com/questions/2854407/javascript-jquery-window-resize-how-to-fire-after-the-resize-is-completed 5831 // ------------------------------------------------------------- 5832 var waitForFinalEvent = (function () { 5833 var timers = {}; 5834 return function (callback, ms, uniqueId) { 5835 if (!uniqueId) { 5836 uniqueId = "Don't call this twice without a uniqueId"; 5837 } 5838 if (timers[uniqueId]) { 5839 clearTimeout(timers[uniqueId]); 5840 } 5841 timers[uniqueId] = setTimeout(callback, ms); 5842 }; 5843 })(); 5844 var timeToWaitForLast = 100; 5845 5846 gallerfy(); 5847 var curPicPos = 0; 5848 5849 $('.comogallery article > .gallery-header > a').click(function () { 5850 var galleryheaderHeight = $('.comogallery .gallery-header').height(); 5851 var gallerycontentMarginTop = parseInt($('.comogallery .gallery-content').css('margin-top')); 5852 var gallerycontentHeight = -1; 5853 5854 $('.comogallery .gallery-content').each(function () { 5855 gallerycontentHeight = gallerycontentHeight > $(this).height() ? gallerycontentHeight : $(this).height(); 5856 }); 5857 5858 var resultitemHeight = galleryheaderHeight + gallerycontentHeight + gallerycontentMarginTop; 5859 $('.comogallery article').removeClass('open').css('height', 'auto'); 5860 $(this).parent().parent().addClass('open').css('height', resultitemHeight); 5861 $('.comogallery article .gallery-content').css('height', gallerycontentHeight); 5862 curPicPos = $(this).parent().attr('data-pos'); 5863 $(window).scrollTop(curPicPos); 5864 e.preventDefault(); 5865 }); 5866 5867 $(window).resize(function () { 5868 var galleryheaderHeight = $('.comogallery .gallery-header').height(); 5869 var gallerycontentMarginTop = parseInt($('.comogallery .gallery-content').css('margin-top')); 5870 var gallerycontentHeight = -1; 5871 5872 $('.comogallery .gallery-content').each(function () { 5873 gallerycontentHeight = gallerycontentHeight > $(this).height() ? gallerycontentHeight : $(this).height(); 5874 }); 5875 5876 var resultitemHeight = galleryheaderHeight + gallerycontentHeight + gallerycontentMarginTop; 5877 viewport = updateViewportDimensions(); 5878 $('.comogallery article.open').css('height', resultitemHeight); 5879 $('.comogallery article .gallery-content').css('height', gallerycontentHeight); 5880 }); 5881 5882 $('.comogallery article') 5883 .find('.detailNext') 5884 .click(function () { 5885 var galleryheaderHeight = $('.comogallery .gallery-header').height(); 5886 var gallerycontentMarginTop = parseInt($('.comogallery .gallery-content').css('margin-top')); 5887 var gallerycontentHeight = -1; 5888 5889 $('.comogallery .gallery-content').each(function () { 5890 gallerycontentHeight = gallerycontentHeight > $(this).height() ? gallerycontentHeight : $(this).height(); 5891 }); 5892 5893 var resultitemHeight = galleryheaderHeight + gallerycontentHeight + gallerycontentMarginTop; 5894 $(this).parent().parent().parent().parent().next().css('height', resultitemHeight).addClass('open').prev().removeClass('open').css('height', 'auto'); 5895 curPicPos = $(this).parent().parent().parent().parent().next().find('.gallery-header').attr('data-pos'); 5896 $(window).scrollTop(curPicPos); 5897 return false;
5898 }); 5899 5900 $('.comogallery article') 5901 .find('.detailPrev') 5902 .click(function () { 5903 var galleryheaderHeight = $('.comogallery .gallery-header').height(); 5904 var gallerycontentMarginTop = parseInt($('.comogallery .gallery-content').css('margin-top')); 5905 var gallerycontentHeight = -1; 5906 5907 $('.comogallery .gallery-content').each(function () { 5908 gallerycontentHeight = gallerycontentHeight > $(this).height() ? gallerycontentHeight : $(this).height(); 5909 }); 5910 5911 var resultitemHeight = galleryheaderHeight + gallerycontentHeight + gallerycontentMarginTop; 5912 $(this).parent().parent().parent().parent().prev().css('height', resultitemHeight).addClass('open').next().removeClass('open').css('height', 'auto'); 5913 curPicPos = $(this).parent().parent().parent().parent().prev().find('.gallery-header').attr('data-pos'); 5914 $(window).scrollTop(curPicPos); 5915 return false; 5916 }); 5917 5918 $('.comogallery article') 5919 .find('.detailClose') 5920 .click(function () { 5921 $('.comogallery article').removeClass('open').css('height', 'auto'); 5922 return false; 5923 }); 5924 5925 function gallerfy() { 5926 $('.comogallery .gallery-header').each(function () { 5927 $(this).attr('data-pos', parseInt($(this).offset().top) - 65); 5928 }); 5929 } 5930}); 5931 5932// Homepage - get day 5933// ------------------------------------------------------------- 5934jQuery(document).ready(function ($) { 5935 var today = moment().format('ddd'); 5936 5937 if ($('body.page-id-2 .bp-contact-card').length >= 1) { 5938 $('.bp-opening-hours').addClass(today); 5939 } 5940});
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.