vendor: 162,356 bytes, lines 1-5689
1// ================================================== 2// fancyBox v3.5.7 3// 4// Licensed GPLv3 for open source use 5// or fancyBox Commercial License for commercial use 6// 7// http://fancyapps.com/fancybox/ 8// Copyright 2019 fancyApps 9// 10// ================================================== 11(function (window, document, $, undefined) { 12 "use strict"; 13 14 window.console = window.console || { 15 info: function (stuff) {} 16 }; 17 18 // If there's no jQuery, fancyBox can't work 19 // ========================================= 20 21 if (!$) { 22 return; 23 } 24 25 // Check if fancyBox is already initialized 26 // ======================================== 27 28 if ($.fn.fancybox) { 29 console.info("fancyBox already initialized"); 30 31 return; 32 } 33 34 // Private default settings 35 // ======================== 36 37 var defaults = { 38 // Close existing modals 39 // Set this to false if you do not need to stack multiple instances 40 closeExisting: false, 41 42 // Enable infinite gallery navigation 43 loop: false, 44 45 // Horizontal space between slides 46 gutter: 50, 47 48 // Enable keyboard navigation 49 keyboard: true, 50 51 // Should allow caption to overlap the content 52 preventCaptionOverlap: true, 53 54 // Should display navigation arrows at the screen edges 55 arrows: true, 56 57 // Should display counter at the top left corner 58 infobar: true, 59 60 // Should display close button (using `btnTpl.smallBtn` template) over the content 61 // Can be true, false, "auto" 62 // If "auto" - will be automatically enabled for "html", "inline" or "ajax" items 63 smallBtn: "auto", 64 65 // Should display toolbar (buttons at the top) 66 // Can be true, false, "auto" 67 // If "auto" - will be automatically hidden if "smallBtn" is enabled 68 toolbar: "auto", 69 70 // What buttons should appear in the top right corner. 71 // Buttons will be created using templates from `btnTpl` option 72 // and they will be placed into toolbar (class="fancybox-toolbar"` element) 73 buttons: [ 74 "zoom", 75 //"share", 76 "slideShow", 77 //"fullScreen", 78 //"download", 79 "thumbs", 80 "close" 81 ], 82 83 // Detect "idle" time in seconds 84 idleTime: 3, 85 86 // Disable right-click and use simple image protection for images 87 protect: false, 88 89 // Shortcut to make content "modal" - disable keyboard navigtion, hide buttons, etc 90 modal: false, 91 92 image: { 93 // Wait for images to load before displaying 94 // true - wait for image to load and then display; 95 // false - display thumbnail and load the full-sized image over top, 96 // requires predefined image dimensions (`data-width` and `data-height` attributes) 97 preload: false 98 }, 99 100 ajax: { 101 // Object containing settings for ajax request 102 settings: { 103 // This helps to indicate that request comes from the modal 104 // Feel free to change naming 105 data: { 106 fancybox: true 107 } 108 } 109 }, 110 111 iframe: { 112 // Iframe template 113 tpl: '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen="allowfullscreen" allow="autoplay; fullscreen" src=""></iframe>', 114 115 // Preload iframe before displaying it 116 // This allows to calculate iframe content width and height 117 // (note: Due to "Same Origin Policy", you can't get cross domain data). 118 preload: true, 119 120 // Custom CSS styling for iframe wrapping element 121 // You can use this to set custom iframe dimensions 122 css: {}, 123 124 // Iframe tag attributes 125 attr: { 126 scrolling: "auto" 127 } 128 }, 129 130 // For HTML5 video only 131 video: { 132 tpl: '<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}">' + 133 '<source src="{{src}}" type="{{format}}" />' + 134 'Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!' + 135 "</video>", 136 format: "", // custom video format 137 autoStart: true 138 }, 139 140 // Default content type if cannot be detected automatically 141 defaultType: "image", 142 143 // Open/close animation type 144 // Possible values: 145 // false - disable 146 // "zoom" - zoom images from/to thumbnail 147 // "fade" 148 // "zoom-in-out" 149 // 150 animationEffect: "zoom", 151 152 // Duration in ms for open/close animation 153 animationDuration: 366, 154 155 // Should image change opacity while zooming 156 // If opacity is "auto", then opacity will be changed if image and thumbnail have different aspect ratios 157 zoomOpacity: "auto", 158 159 // Transition effect between slides 160 // 161 // Possible values: 162 // false - disable 163 // "fade' 164 // "slide' 165 // "circular' 166 // "tube' 167 // "zoom-in-out' 168 // "rotate' 169 // 170 transitionEffect: "fade", 171 172 // Duration in ms for transition animation 173 transitionDuration: 366, 174 175 // Custom CSS class for slide element 176 slideClass: "", 177 178 // Custom CSS class for layout 179 baseClass: "", 180 181 // Base template for layout 182 baseTpl: '<div class="fancybox-container" role="dialog" tabindex="-1">' + 183 '<div class="fancybox-bg"></div>' + 184 '<div class="fancybox-inner">' + 185 '<div class="fancybox-infobar"><span data-fancybox-index></span> / <span data-fancybox-count></span></div>' + 186 '<div class="fancybox-toolbar">{{buttons}}</div>' + 187 '<div class="fancybox-navigation">{{arrows}}</div>' + 188 '<div class="fancybox-stage"></div>' + 189 '<div class="fancybox-caption"><div class="fancybox-caption__body"></div></div>' + 190 "</div>" + 191 "</div>", 192 193 // Loading indicator template 194 spinnerTpl: '<div class="fancybox-loading"></div>', 195 196 // Error message template 197 errorTpl: '<div class="fancybox-error"><p>{{ERROR}}</p></div>', 198 199 btnTpl: { 200 download: '<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;">' + 201 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.62 17.09V19H5.38v-1.91zm-2.97-6.96L17 11.45l-5 4.87-5-4.87 1.36-1.32 2.68 2.64V5h1.92v7.77z"/></svg>' + 202 "</a>", 203 204 zoom: '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' + 205 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.7 17.3l-3-3a5.9 5.9 0 0 0-.6-7.6 5.9 5.9 0 0 0-8.4 0 5.9 5.9 0 0 0 0 8.4 5.9 5.9 0 0 0 7.7.7l3 3a1 1 0 0 0 1.3 0c.4-.5.4-1 0-1.5zM8.1 13.8a4 4 0 0 1 0-5.7 4 4 0 0 1 5.7 0 4 4 0 0 1 0 5.7 4 4 0 0 1-5.7 0z"/></svg>' + 206 "</button>", 207 208 close: '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' + 209 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 10.6L6.6 5.2 5.2 6.6l5.4 5.4-5.4 5.4 1.4 1.4 5.4-5.4 5.4 5.4 1.4-1.4-5.4-5.4 5.4-5.4-1.4-1.4-5.4 5.4z"/></svg>' + 210 "</button>", 211 212 // Arrows 213 arrowLeft: '<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' + 214 '<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.28 15.7l-1.34 1.37L5 12l4.94-5.07 1.34 1.38-2.68 2.72H19v1.94H8.6z"/></svg></div>' + 215 "</button>", 216 217 arrowRight: '<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' + 218 '<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.4 12.97l-2.68 2.72 1.34 1.38L19 12l-4.94-5.07-1.34 1.38 2.68 2.72H5v1.94z"/></svg></div>' + 219 "</button>", 220 221 // This small close button will be appended to your html/inline/ajax content by default, 222 // if "smallBtn" option is not set to false 223 smallBtn: '<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}">' + 224 '<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 24 24"><path d="M13 12l5-5-1-1-5 5-5-5-1 1 5 5-5 5 1 1 5-5 5 5 1-1z"/></svg>' + 225 "</button>" 226 }, 227 228 // Container is injected into this element 229 parentEl: "body", 230 231 // Hide browser vertical scrollbars; use at your own risk 232 hideScrollbar: true, 233 234 // Focus handling 235 // ============== 236 237 // Try to focus on the first focusable element after opening 238 autoFocus: true, 239 240 // Put focus back to active element after closing 241 backFocus: true, 242 243 // Do not let user to focus on element outside modal content 244 trapFocus: true, 245 246 // Module specific options 247 // ======================= 248 249 fullScreen: { 250 autoStart: false 251 }, 252 253 // Set `touch: false` to disable panning/swiping 254 touch: { 255 vertical: true, // Allow to drag content vertically 256 momentum: true // Continue movement after releasing mouse/touch when panning 257 }, 258 259 // Hash value when initializing manually, 260 // set `false` to disable hash change 261 hash: null, 262 263 // Customize or add new media types 264 // Example: 265 /* 266 media : { 267 youtube : { 268 params : { 269 autoplay : 0 270 } 271 } 272 } 273 */ 274 media: {}, 275 276 slideShow: { 277 autoStart: false, 278 speed: 3000 279 }, 280 281 thumbs: { 282 autoStart: false, // Display thumbnails on opening 283 hideOnClose: true, // Hide thumbnail grid when closing animation starts 284 parentEl: ".fancybox-container", // Container is injected into this element 285 axis: "y" // Vertical (y) or horizontal (x) scrolling 286 }, 287 288 // Use mousewheel to navigate gallery 289 // If 'auto' - enabled for images only 290 wheel: "auto", 291 292 // Callbacks 293 //========== 294 295 // See Documentation/API/Events for more information 296 // Example: 297 /* 298 afterShow: function( instance, current ) { 299 console.info( 'Clicked element:' ); 300 console.info( current.opts.$orig ); 301 } 302 */ 303 304 onInit: $.noop, // When instance has been initialized 305 306 beforeLoad: $.noop, // Before the content of a slide is being loaded 307 afterLoad: $.noop, // When the content of a slide is done loading 308 309 beforeShow: $.noop, // Before open animation starts 310 afterShow: $.noop, // When content is done loading and animating 311 312 beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close. 313 afterClose: $.noop, // After instance has been closed 314 315 onActivate: $.noop, // When instance is brought to front 316 onDeactivate: $.noop, // When other instance has been activated 317 318 // Interaction 319 // =========== 320 321 // Use options below to customize taken action when user clicks or double clicks on the fancyBox area, 322 // each option can be string or method that returns value. 323 // 324 // Possible values: 325 // "close" - close instance 326 // "next" - move to next gallery item 327 // "nextOrClose" - move to next gallery item or close if gallery has only one item 328 // "toggleControls" - show/hide controls 329 // "zoom" - zoom image (if loaded) 330 // false - do nothing 331 332 // Clicked on the content 333 clickContent: function (current, event) { 334 return current.type === "image" ? "zoom" : false; 335 }, 336 337 // Clicked on the slide 338 clickSlide: "close", 339 340 // Clicked on the background (backdrop) element; 341 // if you have not changed the layout, then most likely you need to use `clickSlide` option 342 clickOutside: "close", 343 344 // Same as previous two, but for double click 345 dblclickContent: false, 346 dblclickSlide: false, 347 dblclickOutside: false, 348 349 // Custom options when mobile device is detected 350 // ============================================= 351 352 mobile: { 353 preventCaptionOverlap: false, 354 idleTime: false, 355 clickContent: function (current, event) { 356 return current.type === "image" ? "toggleControls" : false; 357 }, 358 clickSlide: function (current, event) { 359 return current.type === "image" ? "toggleControls" : "close"; 360 }, 361 dblclickContent: function (current, event) { 362 return current.type === "image" ? "zoom" : false; 363 }, 364 dblclickSlide: function (current, event) { 365 return current.type === "image" ? "zoom" : false; 366 } 367 }, 368 369 // Internationalization 370 // ==================== 371 372 lang: "en", 373 i18n: { 374 en: { 375 CLOSE: "Close", 376 NEXT: "Next", 377 PREV: "Previous", 378 ERROR: "The requested content cannot be loaded. <br/> Please try again later.", 379 PLAY_START: "Start slideshow", 380 PLAY_STOP: "Pause slideshow", 381 FULL_SCREEN: "Full screen", 382 THUMBS: "Thumbnails", 383 DOWNLOAD: "Download", 384 SHARE: "Share", 385 ZOOM: "Zoom" 386 }, 387 de: { 388 CLOSE: "Schließen", 389 NEXT: "Weiter", 390 PREV: "Zurück", 391 ERROR: "Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.", 392 PLAY_START: "Diaschau starten", 393 PLAY_STOP: "Diaschau beenden", 394 FULL_SCREEN: "Vollbild", 395 THUMBS: "Vorschaubilder", 396 DOWNLOAD: "Herunterladen", 397 SHARE: "Teilen", 398 ZOOM: "Vergrößern" 399 } 400 } 401 }; 402 403 // Few useful variables and methods 404 // ================================ 405 406 var $W = $(window); 407 var $D = $(document); 408 409 var called = 0; 410 411 // Check if an object is a jQuery object and not a native JavaScript object 412 // ======================================================================== 413 var isQuery = function (obj) { 414 return obj && obj.hasOwnProperty && obj instanceof $; 415 }; 416 417 // Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame" 418 // =============================================================================== 419 var requestAFrame = (function () { 420 return ( 421 window.requestAnimationFrame || 422 window.webkitRequestAnimationFrame || 423 window.mozRequestAnimationFrame || 424 window.oRequestAnimationFrame || 425 // if all else fails, use setTimeout 426 function (callback) { 427 return window.setTimeout(callback, 1000 / 60); 428 } 429 ); 430 })(); 431 432 var cancelAFrame = (function () { 433 return ( 434 window.cancelAnimationFrame || 435 window.webkitCancelAnimationFrame || 436 window.mozCancelAnimationFrame || 437 window.oCancelAnimationFrame || 438 function (id) { 439 window.clearTimeout(id); 440 } 441 ); 442 })(); 443 444 // Detect the supported transition-end event property name 445 // ======================================================= 446 var transitionEnd = (function () { 447 var el = document.createElement("fakeelement"), 448 t; 449 450 var transitions = { 451 transition: "transitionend", 452 OTransition: "oTransitionEnd", 453 MozTransition: "transitionend", 454 WebkitTransition: "webkitTransitionEnd" 455 }; 456 457 for (t in transitions) { 458 if (el.style[t] !== undefined) { 459 return transitions[t]; 460 } 461 } 462 463 return "transitionend"; 464 })(); 465 466 // Force redraw on an element. 467 // This helps in cases where the browser doesn't redraw an updated element properly 468 // ================================================================================ 469 var forceRedraw = function ($el) { 470 return $el && $el.length && $el[0].offsetHeight; 471 }; 472 473 // Exclude array (`buttons`) options from deep merging 474 // =================================================== 475 var mergeOpts = function (opts1, opts2) { 476 var rez = $.extend(true, {}, opts1, opts2); 477 478 $.each(opts2, function (key, value) { 479 if ($.isArray(value)) { 480 rez[key] = value; 481 } 482 }); 483 484 return rez; 485 }; 486 487 // How much of an element is visible in viewport 488 // ============================================= 489 490 var inViewport = function (elem) { 491 var elemCenter, rez; 492 493 if (!elem || elem.ownerDocument !== document) { 494 return false; 495 } 496 497 $(".fancybox-container").css("pointer-events", "none"); 498 499 elemCenter = { 500 x: elem.getBoundingClientRect().left + elem.offsetWidth / 2, 501 y: elem.getBoundingClientRect().top + elem.offsetHeight / 2 502 }; 503 504 rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem; 505 506 $(".fancybox-container").css("pointer-events", ""); 507 508 return rez; 509 }; 510 511 // Class definition 512 // ================ 513 514 var FancyBox = function (content, opts, index) { 515 var self = this; 516 517 self.opts = mergeOpts({ 518 index: index 519 }, $.fancybox.defaults); 520 521 if ($.isPlainObject(opts)) { 522 self.opts = mergeOpts(self.opts, opts); 523 } 524 525 if ($.fancybox.isMobile) { 526 self.opts = mergeOpts(self.opts, self.opts.mobile); 527 } 528 529 self.id = self.opts.id || ++called; 530 531 self.currIndex = parseInt(self.opts.index, 10) || 0; 532 self.prevIndex = null; 533 534 self.prevPos = null; 535 self.currPos = 0; 536 537 self.firstRun = true; 538 539 // All group items 540 self.group = []; 541 542 // Existing slides (for current, next and previous gallery items) 543 self.slides = {}; 544 545 // Create group elements 546 self.addContent(content); 547 548 if (!self.group.length) { 549 return; 550 } 551 552 self.init(); 553 }; 554 555 $.extend(FancyBox.prototype, { 556 // Create DOM structure 557 // ==================== 558 559 init: function () { 560 var self = this, 561 firstItem = self.group[self.currIndex], 562 firstItemOpts = firstItem.opts, 563 $container, 564 buttonStr; 565 566 if (firstItemOpts.closeExisting) { 567 $.fancybox.close(true); 568 } 569 570 // Hide scrollbars 571 // =============== 572 573 $("body").addClass("fancybox-active"); 574 575 if ( 576 !$.fancybox.getInstance() && 577 firstItemOpts.hideScrollbar !== false && 578 !$.fancybox.isMobile && 579 document.body.scrollHeight > window.innerHeight 580 ) { 581 $("head").append( 582 '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:' + 583 (window.innerWidth - document.documentElement.clientWidth) + 584 "px;}</style>" 585 ); 586 587 $("body").addClass("compensate-for-scrollbar"); 588 } 589 590 // Build html markup and set references 591 // ==================================== 592 593 // Build html code for buttons and insert into main template 594 buttonStr = ""; 595 596 $.each(firstItemOpts.buttons, function (index, value) { 597 buttonStr += firstItemOpts.btnTpl[value] || ""; 598 }); 599 600 // Create markup from base template, it will be initially hidden to 601 // avoid unnecessary work like painting while initializing is not complete 602 $container = $( 603 self.translate( 604 self, 605 firstItemOpts.baseTpl 606 .replace("{{buttons}}", buttonStr) 607 .replace("{{arrows}}", firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight) 608 ) 609 ) 610 .attr("id", "fancybox-container-" + self.id) 611 .addClass(firstItemOpts.baseClass) 612 .data("FancyBox", self) 613 .appendTo(firstItemOpts.parentEl); 614 615 // Create object holding references to jQuery wrapped nodes 616 self.$refs = { 617 container: $container 618 }; 619 620 ["bg", "inner", "infobar", "toolbar", "stage", "caption", "navigation"].forEach(function (item) { 621 self.$refs[item] = $container.find(".fancybox-" + item); 622 }); 623 624 self.trigger("onInit"); 625 626 // Enable events, deactive previous instances 627 self.activate(); 628 629 // Build slides, load and reveal content 630 self.jumpTo(self.currIndex); 631 }, 632 633 // Simple i18n support - replaces object keys found in template 634 // with corresponding values 635 // ============================================================ 636 637 translate: function (obj, str) { 638 var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en; 639 640 return str.replace(/\{\{(\w+)\}\}/g, function (match, n) { 641 return arr[n] === undefined ? match : arr[n]; 642 }); 643 }, 644 645 // Populate current group with fresh content 646 // Check if each object has valid type and content 647 // =============================================== 648 649 addContent: function (content) { 650 var self = this, 651 items = $.makeArray(content), 652 thumbs; 653 654 $.each(items, function (i, item) { 655 var obj = {}, 656 opts = {}, 657 $item, 658 type, 659 found, 660 src, 661 srcParts; 662 663 // Step 1 - Make sure we have an object 664 // ==================================== 665 666 if ($.isPlainObject(item)) { 667 // We probably have manual usage here, something like 668 // $.fancybox.open( [ { src : "image.jpg", type : "image" } ] ) 669 670 obj = item; 671 opts = item.opts || item; 672 } else if ($.type(item) === "object" && $(item).length) { 673 // Here we probably have jQuery collection returned by some selector 674 $item = $(item); 675 676 // Support attributes like `data-options='{"touch" : false}'` and `data-touch='false'` 677 opts = $item.data() || {}; 678 opts = $.extend(true, {}, opts, opts.options); 679 680 // Here we store clicked element 681 opts.$orig = $item; 682 683 obj.src = self.opts.src || opts.src || $item.attr("href"); 684 685 // Assume that simple syntax is used, for example: 686 // `$.fancybox.open( $("#test"), {} );` 687 if (!obj.type && !obj.src) { 688 obj.type = "inline"; 689 obj.src = item; 690 } 691 } else { 692 // Assume we have a simple html code, for example: 693 // $.fancybox.open( '<div><h1>Hi!</h1></div>' ); 694 obj = { 695 type: "html", 696 src: item + "" 697 }; 698 } 699 700 // Each gallery object has full collection of options 701 obj.opts = $.extend(true, {}, self.opts, opts); 702 703 // Do not merge buttons array 704 if ($.isArray(opts.buttons)) { 705 obj.opts.buttons = opts.buttons; 706 } 707 708 if ($.fancybox.isMobile && obj.opts.mobile) { 709 obj.opts = mergeOpts(obj.opts, obj.opts.mobile); 710 } 711 712 // Step 2 - Make sure we have content type, if not - try to guess 713 // ============================================================== 714 715 type = obj.type || obj.opts.type; 716 src = obj.src || ""; 717 718 if (!type && src) { 719 if ((found = src.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))) { 720 type = "video"; 721 722 if (!obj.opts.video.format) { 723 obj.opts.video.format = "video/" + (found[1] === "ogv" ? "ogg" : found[1]); 724 } 725 } else if (src.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)) { 726 type = "image"; 727 } else if (src.match(/\.(pdf)((\?|#).*)?$/i)) { 728 type = "iframe"; 729 obj = $.extend(true, obj, { 730 contentType: "pdf", 731 opts: { 732 iframe: { 733 preload: false 734 } 735 } 736 }); 737 } else if (src.charAt(0) === "#") { 738 type = "inline"; 739 } 740 } 741 742 if (type) { 743 obj.type = type; 744 } else { 745 self.trigger("objectNeedsType", obj); 746 } 747 748 if (!obj.contentType) { 749 obj.contentType = $.inArray(obj.type, ["html", "inline", "ajax"]) > -1 ? "html" : obj.type; 750 } 751 752 // Step 3 - Some adjustments 753 // ========================= 754 755 obj.index = self.group.length; 756 757 if (obj.opts.smallBtn == "auto") { 758 obj.opts.smallBtn = $.inArray(obj.type, ["html", "inline", "ajax"]) > -1; 759 } 760 761 if (obj.opts.toolbar === "auto") { 762 obj.opts.toolbar = !obj.opts.smallBtn; 763 } 764 765 // Find thumbnail image, check if exists and if is in the viewport 766 obj.$thumb = obj.opts.$thumb || null; 767 768 if (obj.opts.$trigger && obj.index === self.opts.index) { 769 obj.$thumb = obj.opts.$trigger.find("img:first"); 770 771 if (obj.$thumb.length) { 772 obj.opts.$orig = obj.opts.$trigger; 773 } 774 } 775 776 if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) { 777 obj.$thumb = obj.opts.$orig.find("img:first"); 778 } 779 780 if (obj.$thumb && !obj.$thumb.length) { 781 obj.$thumb = null; 782 } 783 784 obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null); 785 786 // "caption" is a "special" option, it can be used to customize caption per gallery item 787 if ($.type(obj.opts.caption) === "function") { 788 obj.opts.caption = obj.opts.caption.apply(item, [self, obj]); 789 } 790 791 if ($.type(self.opts.caption) === "function") { 792 obj.opts.caption = self.opts.caption.apply(item, [self, obj]); 793 } 794 795 // Make sure we have caption as a string or jQuery object 796 if (!(obj.opts.caption instanceof $)) { 797 obj.opts.caption = obj.opts.caption === undefined ? "" : obj.opts.caption + ""; 798 } 799 800 // Check if url contains "filter" used to filter the content 801 // Example: "ajax.html #something" 802 if (obj.type === "ajax") { 803 srcParts = src.split(/\s+/, 2); 804 805 if (srcParts.length > 1) { 806 obj.src = srcParts.shift(); 807 808 obj.opts.filter = srcParts.shift(); 809 } 810 } 811 812 // Hide all buttons and disable interactivity for modal items 813 if (obj.opts.modal) { 814 obj.opts = $.extend(true, obj.opts, { 815 trapFocus: true, 816 // Remove buttons 817 infobar: 0, 818 toolbar: 0, 819 820 smallBtn: 0, 821 822 // Disable keyboard navigation 823 keyboard: 0, 824 825 // Disable some modules 826 slideShow: 0, 827 fullScreen: 0, 828 thumbs: 0, 829 touch: 0, 830 831 // Disable click event handlers 832 clickContent: false, 833 clickSlide: false, 834 clickOutside: false, 835 dblclickContent: false, 836 dblclickSlide: false, 837 dblclickOutside: false 838 }); 839 } 840 841 // Step 4 - Add processed object to group 842 // ====================================== 843 844 self.group.push(obj); 845 }); 846 847 // Update controls if gallery is already opened 848 if (Object.keys(self.slides).length) { 849 self.updateControls(); 850 851 // Update thumbnails, if needed 852 thumbs = self.Thumbs; 853 854 if (thumbs && thumbs.isActive) { 855 thumbs.create(); 856 857 thumbs.focus(); 858 } 859 } 860 }, 861 862 // Attach an event handler functions for: 863 // - navigation buttons 864 // - browser scrolling, resizing; 865 // - focusing 866 // - keyboard 867 // - detecting inactivity 868 // ====================================== 869 870 addEvents: function () { 871 var self = this; 872 873 self.removeEvents(); 874 875 // Make navigation elements clickable 876 // ================================== 877 878 self.$refs.container 879 .on("click.fb-close", "[data-fancybox-close]", function (e) { 880 e.stopPropagation(); 881 e.preventDefault(); 882 883 self.close(e); 884 }) 885 .on("touchstart.fb-prev click.fb-prev", "[data-fancybox-prev]", function (e) { 886 e.stopPropagation(); 887 e.preventDefault(); 888 889 self.previous(); 890 }) 891 .on("touchstart.fb-next click.fb-next", "[data-fancybox-next]", function (e) { 892 e.stopPropagation(); 893 e.preventDefault(); 894 895 self.next(); 896 }) 897 .on("click.fb", "[data-fancybox-zoom]", function (e) { 898 // Click handler for zoom button 899 self[self.isScaledDown() ? "scaleToActual" : "scaleToFit"](); 900 }); 901 902 // Handle page scrolling and browser resizing 903 // ========================================== 904 905 $W.on("orientationchange.fb resize.fb", function (e) { 906 if (e && e.originalEvent && e.originalEvent.type === "resize") { 907 if (self.requestId) { 908 cancelAFrame(self.requestId); 909 } 910 911 self.requestId = requestAFrame(function () { 912 self.update(e); 913 }); 914 } else { 915 if (self.current && self.current.type === "iframe") { 916 self.$refs.stage.hide(); 917 } 918 919 setTimeout( 920 function () { 921 self.$refs.stage.show(); 922 923 self.update(e); 924 }, 925 $.fancybox.isMobile ? 600 : 250 926 ); 927 } 928 }); 929 930 $D.on("keydown.fb", function (e) { 931 var instance = $.fancybox ? $.fancybox.getInstance() : null, 932 current = instance.current, 933 keycode = e.keyCode || e.which; 934 935 // Trap keyboard focus inside of the modal 936 // ======================================= 937 938 if (keycode == 9) { 939 if (current.opts.trapFocus) { 940 self.focus(e); 941 } 942 943 return; 944 } 945 946 // Enable keyboard navigation 947 // ========================== 948 949 if (!current.opts.keyboard || e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is("input,textarea,video,audio,select")) { 950 return; 951 } 952 953 // Backspace and Esc keys 954 if (keycode === 8 || keycode === 27) { 955 e.preventDefault(); 956 957 self.close(e); 958 959 return; 960 } 961 962 // Left arrow and Up arrow 963 if (keycode === 37 || keycode === 38) { 964 e.preventDefault(); 965 966 self.previous(); 967 968 return; 969 } 970 971 // Righ arrow and Down arrow 972 if (keycode === 39 || keycode === 40) { 973 e.preventDefault(); 974 975 self.next(); 976 977 return; 978 } 979 980 self.trigger("afterKeydown", e, keycode); 981 }); 982 983 // Hide controls after some inactivity period 984 if (self.group[self.currIndex].opts.idleTime) { 985 self.idleSecondsCounter = 0; 986 987 $D.on( 988 "mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle", 989 function (e) { 990 self.idleSecondsCounter = 0; 991 992 if (self.isIdle) { 993 self.showControls(); 994 } 995 996 self.isIdle = false; 997 } 998 ); 999 1000 self.idleInterval = window.setInterval(function () { 1001 self.idleSecondsCounter++; 1002 1003 if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) { 1004 self.isIdle = true; 1005 self.idleSecondsCounter = 0; 1006 1007 self.hideControls(); 1008 } 1009 }, 1000); 1010 } 1011 }, 1012 1013 // Remove events added by the core 1014 // =============================== 1015 1016 removeEvents: function () { 1017 var self = this; 1018 1019 $W.off("orientationchange.fb resize.fb"); 1020 $D.off("keydown.fb .fb-idle"); 1021 1022 this.$refs.container.off(".fb-close .fb-prev .fb-next"); 1023 1024 if (self.idleInterval) { 1025 window.clearInterval(self.idleInterval); 1026 1027 self.idleInterval = null; 1028 } 1029 }, 1030 1031 // Change to previous gallery item 1032 // =============================== 1033 1034 previous: function (duration) { 1035 return this.jumpTo(this.currPos - 1, duration); 1036 }, 1037 1038 // Change to next gallery item 1039 // =========================== 1040 1041 next: function (duration) { 1042 return this.jumpTo(this.currPos + 1, duration); 1043 }, 1044 1045 // Switch to selected gallery item 1046 // =============================== 1047 1048 jumpTo: function (pos, duration) { 1049 var self = this, 1050 groupLen = self.group.length, 1051 firstRun, 1052 isMoved, 1053 loop, 1054 current, 1055 previous, 1056 slidePos, 1057 stagePos, 1058 prop, 1059 diff; 1060 1061 if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) { 1062 return; 1063 } 1064 1065 // Should loop? 1066 pos = parseInt(pos, 10); 1067 loop = self.current ? self.current.opts.loop : self.opts.loop; 1068 1069 if (!loop && (pos < 0 || pos >= groupLen)) { 1070 return false; 1071 } 1072 1073 // Check if opening for the first time; this helps to speed things up 1074 firstRun = self.firstRun = !Object.keys(self.slides).length; 1075 1076 // Create slides 1077 previous = self.current; 1078 1079 self.prevIndex = self.currIndex; 1080 self.prevPos = self.currPos; 1081 1082 current = self.createSlide(pos); 1083 1084 if (groupLen > 1) { 1085 if (loop || current.index < groupLen - 1) { 1086 self.createSlide(pos + 1); 1087 } 1088 1089 if (loop || current.index > 0) { 1090 self.createSlide(pos - 1); 1091 } 1092 } 1093 1094 self.current = current; 1095 self.currIndex = current.index; 1096 self.currPos = current.pos; 1097 1098 self.trigger("beforeShow", firstRun); 1099 1100 self.updateControls(); 1101 1102 // Validate duration length 1103 current.forcedDuration = undefined; 1104 1105 if ($.isNumeric(duration)) { 1106 current.forcedDuration = duration; 1107 } else { 1108 duration = current.opts[firstRun ? "animationDuration" : "transitionDuration"]; 1109 } 1110 1111 duration = parseInt(duration, 10); 1112 1113 // Check if user has swiped the slides or if still animating 1114 isMoved = self.isMoved(current); 1115 1116 // Make sure current slide is visible 1117 current.$slide.addClass("fancybox-slide--current"); 1118 1119 // Fresh start - reveal container, current slide and start loading content 1120 if (firstRun) { 1121 if (current.opts.animationEffect && duration) { 1122 self.$refs.container.css("transition-duration", duration + "ms"); 1123 } 1124 1125 self.$refs.container.addClass("fancybox-is-open").trigger("focus"); 1126 1127 // Attempt to load content into slide 1128 // This will later call `afterLoad` -> `revealContent` 1129 self.loadSlide(current); 1130 1131 self.preload("image"); 1132 1133 return; 1134 } 1135 1136 // Get actual slide/stage positions (before cleaning up) 1137 slidePos = $.fancybox.getTranslate(previous.$slide); 1138 stagePos = $.fancybox.getTranslate(self.$refs.stage); 1139 1140 // Clean up all slides 1141 $.each(self.slides, function (index, slide) { 1142 $.fancybox.stop(slide.$slide, true); 1143 }); 1144 1145 if (previous.pos !== current.pos) { 1146 previous.isComplete = false; 1147 } 1148 1149 previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current"); 1150 1151 // If slides are out of place, then animate them to correct position 1152 if (isMoved) { 1153 // Calculate horizontal swipe distance 1154 diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter); 1155 1156 $.each(self.slides, function (index, slide) { 1157 slide.$slide.removeClass("fancybox-animated").removeClass(function (index, className) { 1158 return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" "); 1159 }); 1160 1161 // Make sure that each slide is in equal distance 1162 // This is mostly needed for freshly added slides, because they are not yet positioned 1163 var leftPos = slide.pos * slidePos.width + slide.pos * slide.opts.gutter; 1164 1165 $.fancybox.setTranslate(slide.$slide, { 1166 top: 0, 1167 left: leftPos - stagePos.left + diff 1168 }); 1169 1170 if (slide.pos !== current.pos) { 1171 slide.$slide.addClass("fancybox-slide--" + (slide.pos > current.pos ? "next" : "previous")); 1172 } 1173 1174 // Redraw to make sure that transition will start 1175 forceRedraw(slide.$slide); 1176 1177 // Animate the slide 1178 $.fancybox.animate( 1179 slide.$slide, { 1180 top: 0, 1181 left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter 1182 }, 1183 duration, 1184 function () { 1185 slide.$slide 1186 .css({ 1187 transform: "", 1188 opacity: "" 1189 }) 1190 .removeClass("fancybox-slide--next fancybox-slide--previous"); 1191 1192 if (slide.pos === self.currPos) { 1193 self.complete(); 1194 } 1195 } 1196 ); 1197 }); 1198 } else if (duration && current.opts.transitionEffect) { 1199 // Set transition effect for previously active slide 1200 prop = "fancybox-animated fancybox-fx-" + current.opts.transitionEffect; 1201 1202 previous.$slide.addClass("fancybox-slide--" + (previous.pos > current.pos ? "next" : "previous")); 1203 1204 $.fancybox.animate( 1205 previous.$slide, 1206 prop, 1207 duration, 1208 function () { 1209 previous.$slide.removeClass(prop).removeClass("fancybox-slide--next fancybox-slide--previous"); 1210 }, 1211 false 1212 ); 1213 } 1214 1215 if (current.isLoaded) { 1216 self.revealContent(current); 1217 } else { 1218 self.loadSlide(current); 1219 } 1220 1221 self.preload("image"); 1222 }, 1223 1224 // Create new "slide" element 1225 // These are gallery items that are actually added to DOM 1226 // ======================================================= 1227 1228 createSlide: function (pos) { 1229 var self = this, 1230 $slide, 1231 index; 1232 1233 index = pos % self.group.length; 1234 index = index < 0 ? self.group.length + index : index; 1235 1236 if (!self.slides[pos] && self.group[index]) { 1237 $slide = $('<div class="fancybox-slide"></div>').appendTo(self.$refs.stage); 1238 1239 self.slides[pos] = $.extend(true, {}, self.group[index], { 1240 pos: pos, 1241 $slide: $slide, 1242 isLoaded: false 1243 }); 1244 1245 self.updateSlide(self.slides[pos]); 1246 } 1247 1248 return self.slides[pos]; 1249 }, 1250 1251 // Scale image to the actual size of the image; 1252 // x and y values should be relative to the slide 1253 // ============================================== 1254 1255 scaleToActual: function (x, y, duration) { 1256 var self = this, 1257 current = self.current, 1258 $content = current.$content, 1259 canvasWidth = $.fancybox.getTranslate(current.$slide).width, 1260 canvasHeight = $.fancybox.getTranslate(current.$slide).height, 1261 newImgWidth = current.width, 1262 newImgHeight = current.height, 1263 imgPos, 1264 posX, 1265 posY, 1266 scaleX, 1267 scaleY; 1268 1269 if (self.isAnimating || self.isMoved() || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) { 1270 return; 1271 } 1272 1273 self.isAnimating = true; 1274 1275 $.fancybox.stop($content); 1276 1277 x = x === undefined ? canvasWidth * 0.5 : x; 1278 y = y === undefined ? canvasHeight * 0.5 : y; 1279 1280 imgPos = $.fancybox.getTranslate($content); 1281 1282 imgPos.top -= $.fancybox.getTranslate(current.$slide).top; 1283 imgPos.left -= $.fancybox.getTranslate(current.$slide).left; 1284 1285 scaleX = newImgWidth / imgPos.width; 1286 scaleY = newImgHeight / imgPos.height; 1287 1288 // Get center position for original image 1289 posX = canvasWidth * 0.5 - newImgWidth * 0.5; 1290 posY = canvasHeight * 0.5 - newImgHeight * 0.5; 1291 1292 // Make sure image does not move away from edges 1293 if (newImgWidth > canvasWidth) { 1294 posX = imgPos.left * scaleX - (x * scaleX - x); 1295 1296 if (posX > 0) { 1297 posX = 0; 1298 } 1299 1300 if (posX < canvasWidth - newImgWidth) { 1301 posX = canvasWidth - newImgWidth; 1302 } 1303 } 1304 1305 if (newImgHeight > canvasHeight) { 1306 posY = imgPos.top * scaleY - (y * scaleY - y); 1307 1308 if (posY > 0) { 1309 posY = 0; 1310 } 1311 1312 if (posY < canvasHeight - newImgHeight) { 1313 posY = canvasHeight - newImgHeight; 1314 } 1315 } 1316 1317 self.updateCursor(newImgWidth, newImgHeight); 1318 1319 $.fancybox.animate( 1320 $content, { 1321 top: posY, 1322 left: posX, 1323 scaleX: scaleX, 1324 scaleY: scaleY 1325 }, 1326 duration || 366, 1327 function () { 1328 self.isAnimating = false; 1329 } 1330 ); 1331 1332 // Stop slideshow 1333 if (self.SlideShow && self.SlideShow.isActive) { 1334 self.SlideShow.stop(); 1335 } 1336 }, 1337 1338 // Scale image to fit inside parent element 1339 // ======================================== 1340 1341 scaleToFit: function (duration) { 1342 var self = this, 1343 current = self.current, 1344 $content = current.$content, 1345 end; 1346 1347 if (self.isAnimating || self.isMoved() || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) { 1348 return; 1349 } 1350 1351 self.isAnimating = true; 1352 1353 $.fancybox.stop($content); 1354 1355 end = self.getFitPos(current); 1356 1357 self.updateCursor(end.width, end.height); 1358 1359 $.fancybox.animate( 1360 $content, { 1361 top: end.top, 1362 left: end.left, 1363 scaleX: end.width / $content.width(), 1364 scaleY: end.height / $content.height() 1365 }, 1366 duration || 366, 1367 function () { 1368 self.isAnimating = false; 1369 } 1370 ); 1371 }, 1372 1373 // Calculate image size to fit inside viewport 1374 // =========================================== 1375 1376 getFitPos: function (slide) { 1377 var self = this, 1378 $content = slide.$content, 1379 $slide = slide.$slide, 1380 width = slide.width || slide.opts.width, 1381 height = slide.height || slide.opts.height, 1382 maxWidth, 1383 maxHeight, 1384 minRatio, 1385 aspectRatio, 1386 rez = {}; 1387 1388 if (!slide.isLoaded || !$content || !$content.length) { 1389 return false; 1390 } 1391 1392 maxWidth = $.fancybox.getTranslate(self.$refs.stage).width; 1393 maxHeight = $.fancybox.getTranslate(self.$refs.stage).height; 1394 1395 maxWidth -= 1396 parseFloat($slide.css("paddingLeft")) + 1397 parseFloat($slide.css("paddingRight")) + 1398 parseFloat($content.css("marginLeft")) + 1399 parseFloat($content.css("marginRight")); 1400 1401 maxHeight -= 1402 parseFloat($slide.css("paddingTop")) + 1403 parseFloat($slide.css("paddingBottom")) + 1404 parseFloat($content.css("marginTop")) + 1405 parseFloat($content.css("marginBottom")); 1406 1407 if (!width || !height) { 1408 width = maxWidth; 1409 height = maxHeight; 1410 } 1411 1412 minRatio = Math.min(1, maxWidth / width, maxHeight / height); 1413 1414 width = minRatio * width; 1415 height = minRatio * height; 1416 1417 // Adjust width/height to precisely fit into container 1418 if (width > maxWidth - 0.5) { 1419 width = maxWidth; 1420 } 1421 1422 if (height > maxHeight - 0.5) { 1423 height = maxHeight; 1424 } 1425 1426 if (slide.type === "image") { 1427 rez.top = Math.floor((maxHeight - height) * 0.5) + parseFloat($slide.css("paddingTop")); 1428 rez.left = Math.floor((maxWidth - width) * 0.5) + parseFloat($slide.css("paddingLeft")); 1429 } else if (slide.contentType === "video") { 1430 // Force aspect ratio for the video 1431 // "I say the whole world must learn of our peaceful ways⦠by force!" 1432 aspectRatio = slide.opts.width && slide.opts.height ? width / height : slide.opts.ratio || 16 / 9; 1433 1434 if (height > width / aspectRatio) { 1435 height = width / aspectRatio; 1436 } else if (width > height * aspectRatio) { 1437 width = height * aspectRatio; 1438 } 1439 } 1440 1441 rez.width = width; 1442 rez.height = height; 1443 1444 return rez; 1445 }, 1446 1447 // Update content size and position for all slides 1448 // ============================================== 1449 1450 update: function (e) { 1451 var self = this; 1452 1453 $.each(self.slides, function (key, slide) { 1454 self.updateSlide(slide, e); 1455 }); 1456 }, 1457 1458 // Update slide content position and size 1459 // ====================================== 1460 1461 updateSlide: function (slide, e) { 1462 var self = this, 1463 $content = slide && slide.$content, 1464 width = slide.width || slide.opts.width, 1465 height = slide.height || slide.opts.height, 1466 $slide = slide.$slide; 1467 1468 // First, prevent caption overlap, if needed 1469 self.adjustCaption(slide); 1470 1471 // Then resize content to fit inside the slide 1472 if ($content && (width || height || slide.contentType === "video") && !slide.hasError) { 1473 $.fancybox.stop($content); 1474 1475 $.fancybox.setTranslate($content, self.getFitPos(slide)); 1476 1477 if (slide.pos === self.currPos) { 1478 self.isAnimating = false; 1479 1480 self.updateCursor(); 1481 } 1482 } 1483 1484 // Then some adjustments 1485 self.adjustLayout(slide); 1486 1487 if ($slide.length) { 1488 $slide.trigger("refresh"); 1489 1490 if (slide.pos === self.currPos) { 1491 self.$refs.toolbar 1492 .add(self.$refs.navigation.find(".fancybox-button--arrow_right")) 1493 .toggleClass("compensate-for-scrollbar", $slide.get(0).scrollHeight > $slide.get(0).clientHeight); 1494 } 1495 } 1496 1497 self.trigger("onUpdate", slide, e); 1498 }, 1499 1500 // Horizontally center slide 1501 // ========================= 1502 1503 centerSlide: function (duration) { 1504 var self = this, 1505 current = self.current, 1506 $slide = current.$slide; 1507 1508 if (self.isClosing || !current) { 1509 return; 1510 } 1511 1512 $slide.siblings().css({ 1513 transform: "", 1514 opacity: "" 1515 }); 1516 1517 $slide 1518 .parent() 1519 .children() 1520 .removeClass("fancybox-slide--previous fancybox-slide--next"); 1521 1522 $.fancybox.animate( 1523 $slide, { 1524 top: 0, 1525 left: 0, 1526 opacity: 1 1527 }, 1528 duration === undefined ? 0 : duration, 1529 function () { 1530 // Clean up 1531 $slide.css({ 1532 transform: "", 1533 opacity: "" 1534 }); 1535 1536 if (!current.isComplete) { 1537 self.complete(); 1538 } 1539 }, 1540 false 1541 ); 1542 }, 1543 1544 // Check if current slide is moved (swiped) 1545 // ======================================== 1546 1547 isMoved: function (slide) { 1548 var current = slide || this.current, 1549 slidePos, 1550 stagePos; 1551 1552 if (!current) { 1553 return false; 1554 } 1555 1556 stagePos = $.fancybox.getTranslate(this.$refs.stage); 1557 slidePos = $.fancybox.getTranslate(current.$slide); 1558 1559 return ( 1560 !current.$slide.hasClass("fancybox-animated") && 1561 (Math.abs(slidePos.top - stagePos.top) > 0.5 || Math.abs(slidePos.left - stagePos.left) > 0.5) 1562 ); 1563 }, 1564 1565 // Update cursor style depending if content can be zoomed 1566 // ====================================================== 1567 1568 updateCursor: function (nextWidth, nextHeight) { 1569 var self = this, 1570 current = self.current, 1571 $container = self.$refs.container, 1572 canPan, 1573 isZoomable; 1574 1575 if (!current || self.isClosing || !self.Guestures) { 1576 return; 1577 } 1578 1579 $container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"); 1580 1581 canPan = self.canPan(nextWidth, nextHeight); 1582 1583 isZoomable = canPan ? true : self.isZoomable(); 1584 1585 $container.toggleClass("fancybox-is-zoomable", isZoomable); 1586 1587 $("[data-fancybox-zoom]").prop("disabled", !isZoomable); 1588 1589 if (canPan) { 1590 $container.addClass("fancybox-can-pan"); 1591 } else if ( 1592 isZoomable && 1593 (current.opts.clickContent === "zoom" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) == "zoom")) 1594 ) { 1595 $container.addClass("fancybox-can-zoomIn"); 1596 } else if (current.opts.touch && (current.opts.touch.vertical || self.group.length > 1) && current.contentType !== "video") { 1597 $container.addClass("fancybox-can-swipe"); 1598 } 1599 }, 1600 1601 // Check if current slide is zoomable 1602 // ================================== 1603 1604 isZoomable: function () { 1605 var self = this, 1606 current = self.current, 1607 fitPos; 1608 1609 // Assume that slide is zoomable if: 1610 // - image is still loading 1611 // - actual size of the image is smaller than available area 1612 if (current && !self.isClosing && current.type === "image" && !current.hasError) { 1613 if (!current.isLoaded) { 1614 return true; 1615 } 1616 1617 fitPos = self.getFitPos(current); 1618 1619 if (fitPos && (current.width > fitPos.width || current.height > fitPos.height)) { 1620 return true; 1621 } 1622 } 1623 1624 return false; 1625 }, 1626 1627 // Check if current image dimensions are smaller than actual 1628 // ========================================================= 1629 1630 isScaledDown: function (nextWidth, nextHeight) { 1631 var self = this, 1632 rez = false, 1633 current = self.current, 1634 $content = current.$content; 1635 1636 if (nextWidth !== undefined && nextHeight !== undefined) { 1637 rez = nextWidth < current.width && nextHeight < current.height; 1638 } else if ($content) { 1639 rez = $.fancybox.getTranslate($content); 1640 rez = rez.width < current.width && rez.height < current.height; 1641 } 1642 1643 return rez; 1644 }, 1645 1646 // Check if image dimensions exceed parent element 1647 // =============================================== 1648 1649 canPan: function (nextWidth, nextHeight) { 1650 var self = this, 1651 current = self.current, 1652 pos = null, 1653 rez = false; 1654 1655 if (current.type === "image" && (current.isComplete || (nextWidth && nextHeight)) && !current.hasError) { 1656 rez = self.getFitPos(current); 1657 1658 if (nextWidth !== undefined && nextHeight !== undefined) { 1659 pos = { 1660 width: nextWidth, 1661 height: nextHeight 1662 }; 1663 } else if (current.isComplete) { 1664 pos = $.fancybox.getTranslate(current.$content); 1665 } 1666 1667 if (pos && rez) { 1668 rez = Math.abs(pos.width - rez.width) > 1.5 || Math.abs(pos.height - rez.height) > 1.5; 1669 } 1670 } 1671 1672 return rez; 1673 }, 1674 1675 // Load content into the slide 1676 // =========================== 1677 1678 loadSlide: function (slide) { 1679 var self = this, 1680 type, 1681 $slide, 1682 ajaxLoad; 1683 1684 if (slide.isLoading || slide.isLoaded) { 1685 return; 1686 } 1687 1688 slide.isLoading = true; 1689 1690 if (self.trigger("beforeLoad", slide) === false) { 1691 slide.isLoading = false; 1692 1693 return false; 1694 } 1695 1696 type = slide.type; 1697 $slide = slide.$slide; 1698 1699 $slide 1700 .off("refresh") 1701 .trigger("onReset") 1702 .addClass(slide.opts.slideClass); 1703 1704 // Create content depending on the type 1705 switch (type) { 1706 case "image": 1707 self.setImage(slide); 1708 1709 break; 1710 1711 case "iframe": 1712 self.setIframe(slide); 1713 1714 break; 1715 1716 case "html": 1717 self.setContent(slide, slide.src || slide.content); 1718 1719 break; 1720 1721 case "video": 1722 self.setContent( 1723 slide, 1724 slide.opts.video.tpl 1725 .replace(/\{\{src\}\}/gi, slide.src) 1726 .replace("{{format}}", slide.opts.videoFormat || slide.opts.video.format || "") 1727 .replace("{{poster}}", slide.thumb || "") 1728 ); 1729 1730 break; 1731 1732 case "inline": 1733 if ($(slide.src).length) { 1734 self.setContent(slide, $(slide.src)); 1735 } else { 1736 self.setError(slide); 1737 } 1738 1739 break; 1740 1741 case "ajax": 1742 self.showLoading(slide); 1743 1744 ajaxLoad = $.ajax( 1745 $.extend({}, slide.opts.ajax.settings, { 1746 url: slide.src, 1747 success: function (data, textStatus) { 1748 if (textStatus === "success") { 1749 self.setContent(slide, data); 1750 } 1751 }, 1752 error: function (jqXHR, textStatus) { 1753 if (jqXHR && textStatus !== "abort") { 1754 self.setError(slide); 1755 } 1756 } 1757 }) 1758 ); 1759 1760 $slide.one("onReset", function () { 1761 ajaxLoad.abort(); 1762 }); 1763 1764 break; 1765 1766 default: 1767 self.setError(slide); 1768 1769 break; 1770 } 1771 1772 return true; 1773 }, 1774 1775 // Use thumbnail image, if possible 1776 // ================================ 1777 1778 setImage: function (slide) { 1779 var self = this, 1780 ghost; 1781 1782 // Check if need to show loading icon 1783 setTimeout(function () { 1784 var $img = slide.$image; 1785 1786 if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) { 1787 self.showLoading(slide); 1788 } 1789 }, 50); 1790 1791 //Check if image has srcset 1792 self.checkSrcset(slide); 1793 1794 // This will be wrapper containing both ghost and actual image 1795 slide.$content = $('<div class="fancybox-content"></div>') 1796 .addClass("fancybox-is-hidden") 1797 .appendTo(slide.$slide.addClass("fancybox-slide--image")); 1798 1799 // If we have a thumbnail, we can display it while actual image is loading 1800 // Users will not stare at black screen and actual image will appear gradually 1801 if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && slide.thumb) { 1802 slide.width = slide.opts.width; 1803 slide.height = slide.opts.height; 1804 1805 ghost = document.createElement("img"); 1806 1807 ghost.onerror = function () { 1808 $(this).remove(); 1809 1810 slide.$ghost = null; 1811 }; 1812 1813 ghost.onload = function () { 1814 self.afterLoad(slide); 1815 }; 1816 1817 slide.$ghost = $(ghost) 1818 .addClass("fancybox-image") 1819 .appendTo(slide.$content) 1820 .attr("src", slide.thumb); 1821 } 1822 1823 // Start loading actual image 1824 self.setBigImage(slide); 1825 }, 1826 1827 // Check if image has srcset and get the source 1828 // ============================================ 1829 checkSrcset: function (slide) { 1830 var srcset = slide.opts.srcset || slide.opts.image.srcset, 1831 found, 1832 temp, 1833 pxRatio, 1834 windowWidth; 1835 1836 // If we have "srcset", then we need to find first matching "src" value. 1837 // This is necessary, because when you set an src attribute, the browser will preload the image 1838 // before any javascript or even CSS is applied. 1839 if (srcset) { 1840 pxRatio = window.devicePixelRatio || 1; 1841 windowWidth = window.innerWidth * pxRatio; 1842 1843 temp = srcset.split(",").map(function (el) { 1844 var ret = {}; 1845 1846 el.trim() 1847 .split(/\s+/) 1848 .forEach(function (el, i) { 1849 var value = parseInt(el.substring(0, el.length - 1), 10); 1850 1851 if (i === 0) { 1852 return (ret.url = el); 1853 } 1854 1855 if (value) { 1856 ret.value = value; 1857 ret.postfix = el[el.length - 1]; 1858 } 1859 }); 1860 1861 return ret; 1862 }); 1863 1864 // Sort by value 1865 temp.sort(function (a, b) { 1866 return a.value - b.value; 1867 }); 1868 1869 // Ok, now we have an array of all srcset values 1870 for (var j = 0; j < temp.length; j++) { 1871 var el = temp[j]; 1872 1873 if ((el.postfix === "w" && el.value >= windowWidth) || (el.postfix === "x" && el.value >= pxRatio)) { 1874 found = el; 1875 break; 1876 } 1877 } 1878 1879 // If not found, take the last one 1880 if (!found && temp.length) { 1881 found = temp[temp.length - 1]; 1882 } 1883 1884 if (found) { 1885 slide.src = found.url; 1886 1887 // If we have default width/height values, we can calculate height for matching source 1888 if (slide.width && slide.height && found.postfix == "w") { 1889 slide.height = (slide.width / slide.height) * found.value; 1890 slide.width = found.value; 1891 } 1892 1893 slide.opts.srcset = srcset; 1894 } 1895 } 1896 }, 1897 1898 // Create full-size image 1899 // ====================== 1900 1901 setBigImage: function (slide) { 1902 var self = this, 1903 img = document.createElement("img"), 1904 $img = $(img); 1905 1906 slide.$image = $img 1907 .one("error", function () { 1908 self.setError(slide); 1909 }) 1910 .one("load", function () { 1911 var sizes; 1912 1913 if (!slide.$ghost) { 1914 self.resolveImageSlideSize(slide, this.naturalWidth, this.naturalHeight); 1915 1916 self.afterLoad(slide); 1917 } 1918 1919 if (self.isClosing) { 1920 return; 1921 } 1922 1923 if (slide.opts.srcset) { 1924 sizes = slide.opts.sizes; 1925 1926 if (!sizes || sizes === "auto") { 1927 sizes = 1928 (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? "100" : Math.round((slide.width / slide.height) * 100)) + 1929 "vw"; 1930 } 1931 1932 $img.attr("sizes", sizes).attr("srcset", slide.opts.srcset); 1933 } 1934 1935 // Hide temporary image after some delay 1936 if (slide.$ghost) { 1937 setTimeout(function () { 1938 if (slide.$ghost && !self.isClosing) { 1939 slide.$ghost.hide(); 1940 } 1941 }, Math.min(300, Math.max(1000, slide.height / 1600))); 1942 } 1943 1944 self.hideLoading(slide); 1945 }) 1946 .addClass("fancybox-image") 1947 .attr("src", slide.src) 1948 .appendTo(slide.$content); 1949 1950 if ((img.complete || img.readyState == "complete") && $img.naturalWidth && $img.naturalHeight) { 1951 $img.trigger("load"); 1952 } else if (img.error) { 1953 $img.trigger("error"); 1954 } 1955 }, 1956 1957 // Computes the slide size from image size and maxWidth/maxHeight 1958 // ============================================================== 1959 1960 resolveImageSlideSize: function (slide, imgWidth, imgHeight) { 1961 var maxWidth = parseInt(slide.opts.width, 10), 1962 maxHeight = parseInt(slide.opts.height, 10); 1963 1964 // Sets the default values from the image 1965 slide.width = imgWidth; 1966 slide.height = imgHeight; 1967 1968 if (maxWidth > 0) { 1969 slide.width = maxWidth; 1970 slide.height = Math.floor((maxWidth * imgHeight) / imgWidth); 1971 } 1972 1973 if (maxHeight > 0) { 1974 slide.width = Math.floor((maxHeight * imgWidth) / imgHeight); 1975 slide.height = maxHeight; 1976 } 1977 }, 1978 1979 // Create iframe wrapper, iframe and bindings 1980 // ========================================== 1981 1982 setIframe: function (slide) { 1983 var self = this, 1984 opts = slide.opts.iframe, 1985 $slide = slide.$slide, 1986 $iframe; 1987 1988 slide.$content = $('<div class="fancybox-content' + (opts.preload ? " fancybox-is-hidden" : "") + '"></div>') 1989 .css(opts.css) 1990 .appendTo($slide); 1991 1992 $slide.addClass("fancybox-slide--" + slide.contentType); 1993 1994 slide.$iframe = $iframe = $(opts.tpl.replace(/\{rnd\}/g, new Date().getTime())) 1995 .attr(opts.attr) 1996 .appendTo(slide.$content); 1997 1998 if (opts.preload) { 1999 self.showLoading(slide); 2000 2001 // Unfortunately, it is not always possible to determine if iframe is successfully loaded 2002 // (due to browser security policy) 2003 2004 $iframe.on("load.fb error.fb", function (e) { 2005 this.isReady = 1; 2006 2007 slide.$slide.trigger("refresh"); 2008 2009 self.afterLoad(slide); 2010 }); 2011 2012 // Recalculate iframe content size 2013 // =============================== 2014 2015 $slide.on("refresh.fb", function () { 2016 var $content = slide.$content, 2017 frameWidth = opts.css.width, 2018 frameHeight = opts.css.height, 2019 $contents, 2020 $body; 2021 2022 if ($iframe[0].isReady !== 1) { 2023 return; 2024 } 2025 2026 try { 2027 $contents = $iframe.contents(); 2028 $body = $contents.find("body"); 2029 } catch (ignore) {} 2030 2031 // Calculate content dimensions, if it is accessible 2032 if ($body && $body.length && $body.children().length) { 2033 // Avoid scrolling to top (if multiple instances) 2034 $slide.css("overflow", "visible"); 2035 2036 $content.css({ 2037 width: "100%", 2038 "max-width": "100%", 2039 height: "9999px" 2040 }); 2041 2042 if (frameWidth === undefined) { 2043 frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true))); 2044 } 2045 2046 $content.css("width", frameWidth ? frameWidth : "").css("max-width", ""); 2047 2048 if (frameHeight === undefined) { 2049 frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true))); 2050 } 2051 2052 $content.css("height", frameHeight ? frameHeight : ""); 2053 2054 $slide.css("overflow", "auto"); 2055 } 2056 2057 $content.removeClass("fancybox-is-hidden"); 2058 }); 2059 } else { 2060 self.afterLoad(slide); 2061 } 2062 2063 $iframe.attr("src", slide.src); 2064 2065 // Remove iframe if closing or changing gallery item 2066 $slide.one("onReset", function () { 2067 // This helps IE not to throw errors when closing 2068 try { 2069 $(this) 2070 .find("iframe") 2071 .hide() 2072 .unbind() 2073 .attr("src", "//about:blank"); 2074 } catch (ignore) {} 2075 2076 $(this) 2077 .off("refresh.fb") 2078 .empty(); 2079 2080 slide.isLoaded = false; 2081 slide.isRevealed = false; 2082 }); 2083 }, 2084 2085 // Wrap and append content to the slide 2086 // ====================================== 2087 2088 setContent: function (slide, content) { 2089 var self = this; 2090 2091 if (self.isClosing) { 2092 return; 2093 } 2094 2095 self.hideLoading(slide); 2096 2097 if (slide.$content) { 2098 $.fancybox.stop(slide.$content); 2099 } 2100 2101 slide.$slide.empty(); 2102 2103 // If content is a jQuery object, then it will be moved to the slide. 2104 // The placeholder is created so we will know where to put it back. 2105 if (isQuery(content) && content.parent().length) { 2106 // Make sure content is not already moved to fancyBox 2107 if (content.hasClass("fancybox-content") || content.parent().hasClass("fancybox-content")) { 2108 content.parents(".fancybox-slide").trigger("onReset"); 2109 } 2110 2111 // Create temporary element marking original place of the content 2112 slide.$placeholder = $("<div>") 2113 .hide() 2114 .insertAfter(content); 2115 2116 // Make sure content is visible 2117 content.css("display", "inline-block"); 2118 } else if (!slide.hasError) { 2119 // If content is just a plain text, try to convert it to html 2120 if ($.type(content) === "string") { 2121 content = $("<div>") 2122 .append($.trim(content)) 2123 .contents(); 2124 } 2125 2126 // If "filter" option is provided, then filter content 2127 if (slide.opts.filter) { 2128 content = $("<div>") 2129 .html(content) 2130 .find(slide.opts.filter); 2131 } 2132 } 2133 2134 slide.$slide.one("onReset", function () { 2135 // Pause all html5 video/audio 2136 $(this) 2137 .find("video,audio") 2138 .trigger("pause"); 2139 2140 // Put content back 2141 if (slide.$placeholder) { 2142 slide.$placeholder.after(content.removeClass("fancybox-content").hide()).remove(); 2143 2144 slide.$placeholder = null; 2145 } 2146 2147 // Remove custom close button 2148 if (slide.$smallBtn) { 2149 slide.$smallBtn.remove(); 2150 2151 slide.$smallBtn = null; 2152 } 2153 2154 // Remove content and mark slide as not loaded 2155 if (!slide.hasError) { 2156 $(this).empty(); 2157 2158 slide.isLoaded = false; 2159 slide.isRevealed = false; 2160 } 2161 }); 2162 2163 $(content).appendTo(slide.$slide); 2164 2165 if ($(content).is("video,audio")) { 2166 $(content).addClass("fancybox-video"); 2167 2168 $(content).wrap("<div></div>"); 2169 2170 slide.contentType = "video"; 2171 2172 slide.opts.width = slide.opts.width || $(content).attr("width"); 2173 slide.opts.height = slide.opts.height || $(content).attr("height"); 2174 } 2175 2176 slide.$content = slide.$slide 2177 .children() 2178 .filter("div,form,main,video,audio,article,.fancybox-content") 2179 .first(); 2180 2181 slide.$content.siblings().hide(); 2182 2183 // Re-check if there is a valid content 2184 // (in some cases, ajax response can contain various elements or plain text) 2185 if (!slide.$content.length) { 2186 slide.$content = slide.$slide 2187 .wrapInner("<div></div>") 2188 .children() 2189 .first(); 2190 } 2191 2192 slide.$content.addClass("fancybox-content"); 2193 2194 slide.$slide.addClass("fancybox-slide--" + slide.contentType); 2195 2196 self.afterLoad(slide); 2197 }, 2198 2199 // Display error message 2200 // ===================== 2201 2202 setError: function (slide) { 2203 slide.hasError = true; 2204 2205 slide.$slide 2206 .trigger("onReset") 2207 .removeClass("fancybox-slide--" + slide.contentType) 2208 .addClass("fancybox-slide--error"); 2209 2210 slide.contentType = "html"; 2211 2212 this.setContent(slide, this.translate(slide, slide.opts.errorTpl)); 2213 2214 if (slide.pos === this.currPos) { 2215 this.isAnimating = false; 2216 } 2217 }, 2218 2219 // Show loading icon inside the slide 2220 // ================================== 2221 2222 showLoading: function (slide) { 2223 var self = this; 2224 2225 slide = slide || self.current; 2226 2227 if (slide && !slide.$spinner) { 2228 slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)) 2229 .appendTo(slide.$slide) 2230 .hide() 2231 .fadeIn("fast"); 2232 } 2233 }, 2234 2235 // Remove loading icon from the slide 2236 // ================================== 2237 2238 hideLoading: function (slide) { 2239 var self = this; 2240 2241 slide = slide || self.current; 2242 2243 if (slide && slide.$spinner) { 2244 slide.$spinner.stop().remove(); 2245 2246 delete slide.$spinner; 2247 } 2248 }, 2249 2250 // Adjustments after slide content has been loaded 2251 // =============================================== 2252 2253 afterLoad: function (slide) { 2254 var self = this; 2255 2256 if (self.isClosing) { 2257 return; 2258 } 2259 2260 slide.isLoading = false; 2261 slide.isLoaded = true; 2262 2263 self.trigger("afterLoad", slide); 2264 2265 self.hideLoading(slide); 2266 2267 // Add small close button 2268 if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) { 2269 slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).appendTo(slide.$content); 2270 } 2271 2272 // Disable right click 2273 if (slide.opts.protect && slide.$content && !slide.hasError) { 2274 slide.$content.on("contextmenu.fb", function (e) { 2275 if (e.button == 2) { 2276 e.preventDefault(); 2277 } 2278 2279 return true; 2280 }); 2281 2282 // Add fake element on top of the image 2283 // This makes a bit harder for user to select image 2284 if (slide.type === "image") { 2285 $('<div class="fancybox-spaceball"></div>').appendTo(slide.$content); 2286 } 2287 } 2288 2289 self.adjustCaption(slide); 2290 2291 self.adjustLayout(slide); 2292 2293 if (slide.pos === self.currPos) { 2294 self.updateCursor(); 2295 } 2296 2297 self.revealContent(slide); 2298 }, 2299 2300 // Prevent caption overlap, 2301 // fix css inconsistency across browsers 2302 // ===================================== 2303 2304 adjustCaption: function (slide) { 2305 var self = this, 2306 current = slide || self.current, 2307 caption = current.opts.caption, 2308 preventOverlap = current.opts.preventCaptionOverlap, 2309 $caption = self.$refs.caption, 2310 $clone, 2311 captionH = false; 2312 2313 $caption.toggleClass("fancybox-caption--separate", preventOverlap); 2314 2315 if (preventOverlap && caption && caption.length) { 2316 if (current.pos !== self.currPos) { 2317 $clone = $caption.clone().appendTo($caption.parent()); 2318 2319 $clone 2320 .children() 2321 .eq(0) 2322 .empty() 2323 .html(caption); 2324 2325 captionH = $clone.outerHeight(true); 2326 2327 $clone.empty().remove(); 2328 } else if (self.$caption) { 2329 captionH = self.$caption.outerHeight(true); 2330 } 2331 2332 current.$slide.css("padding-bottom", captionH || ""); 2333 } 2334 }, 2335 2336 // Simple hack to fix inconsistency across browsers, described here (affects Edge, too): 2337 // https://bugzilla.mozilla.org/show_bug.cgi?id=748518 2338 // ==================================================================================== 2339 2340 adjustLayout: function (slide) { 2341 var self = this, 2342 current = slide || self.current, 2343 scrollHeight, 2344 marginBottom, 2345 inlinePadding, 2346 actualPadding; 2347 2348 if (current.isLoaded && current.opts.disableLayoutFix !== true) { 2349 current.$content.css("margin-bottom", ""); 2350 2351 // If we would always set margin-bottom for the content, 2352 // then it would potentially break vertical align 2353 if (current.$content.outerHeight() > current.$slide.height() + 0.5) { 2354 inlinePadding = current.$slide[0].style["padding-bottom"]; 2355 actualPadding = current.$slide.css("padding-bottom"); 2356 2357 if (parseFloat(actualPadding) > 0) { 2358 scrollHeight = current.$slide[0].scrollHeight; 2359 2360 current.$slide.css("padding-bottom", 0); 2361 2362 if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) { 2363 marginBottom = actualPadding; 2364 } 2365 2366 current.$slide.css("padding-bottom", inlinePadding); 2367 } 2368 } 2369 2370 current.$content.css("margin-bottom", marginBottom); 2371 } 2372 }, 2373 2374 // Make content visible 2375 // This method is called right after content has been loaded or 2376 // user navigates gallery and transition should start 2377 // ============================================================ 2378 2379 revealContent: function (slide) { 2380 var self = this, 2381 $slide = slide.$slide, 2382 end = false, 2383 start = false, 2384 isMoved = self.isMoved(slide), 2385 isRevealed = slide.isRevealed, 2386 effect, 2387 effectClassName, 2388 duration, 2389 opacity; 2390 2391 slide.isRevealed = true; 2392 2393 effect = slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"]; 2394 duration = slide.opts[self.firstRun ? "animationDuration" : "transitionDuration"]; 2395 2396 duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10); 2397 2398 if (isMoved || slide.pos !== self.currPos || !duration) { 2399 effect = false; 2400 } 2401 2402 // Check if can zoom 2403 if (effect === "zoom") { 2404 if (slide.pos === self.currPos && duration && slide.type === "image" && !slide.hasError && (start = self.getThumbPos(slide))) { 2405 end = self.getFitPos(slide); 2406 } else { 2407 effect = "fade"; 2408 } 2409 } 2410 2411 // Zoom animation 2412 // ============== 2413 if (effect === "zoom") { 2414 self.isAnimating = true; 2415 2416 end.scaleX = end.width / start.width; 2417 end.scaleY = end.height / start.height; 2418 2419 // Check if we need to animate opacity 2420 opacity = slide.opts.zoomOpacity; 2421 2422 if (opacity == "auto") { 2423 opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1; 2424 } 2425 2426 if (opacity) { 2427 start.opacity = 0.1; 2428 end.opacity = 1; 2429 } 2430 2431 // Draw image at start position 2432 $.fancybox.setTranslate(slide.$content.removeClass("fancybox-is-hidden"), start); 2433 2434 forceRedraw(slide.$content); 2435 2436 // Start animation 2437 $.fancybox.animate(slide.$content, end, duration, function () { 2438 self.isAnimating = false; 2439 2440 self.complete(); 2441 }); 2442 2443 return; 2444 } 2445 2446 self.updateSlide(slide); 2447 2448 // Simply show content if no effect 2449 // ================================ 2450 if (!effect) { 2451 slide.$content.removeClass("fancybox-is-hidden"); 2452 2453 if (!isRevealed && isMoved && slide.type === "image" && !slide.hasError) { 2454 slide.$content.hide().fadeIn("fast"); 2455 } 2456 2457 if (slide.pos === self.currPos) { 2458 self.complete(); 2459 } 2460 2461 return; 2462 } 2463 2464 // Prepare for CSS transiton 2465 // ========================= 2466 $.fancybox.stop($slide); 2467 2468 //effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect; 2469 effectClassName = "fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-animated fancybox-fx-" + effect; 2470 2471 $slide.addClass(effectClassName).removeClass("fancybox-slide--current"); //.addClass(effectClassName); 2472 2473 slide.$content.removeClass("fancybox-is-hidden"); 2474 2475 // Force reflow 2476 forceRedraw($slide); 2477 2478 if (slide.type !== "image") { 2479 slide.$content.hide().show(0); 2480 } 2481 2482 $.fancybox.animate( 2483 $slide, 2484 "fancybox-slide--current", 2485 duration, 2486 function () { 2487 $slide.removeClass(effectClassName).css({ 2488 transform: "", 2489 opacity: "" 2490 }); 2491 2492 if (slide.pos === self.currPos) { 2493 self.complete(); 2494 } 2495 }, 2496 true 2497 ); 2498 }, 2499 2500 // Check if we can and have to zoom from thumbnail 2501 //================================================ 2502 2503 getThumbPos: function (slide) { 2504 var rez = false, 2505 $thumb = slide.$thumb, 2506 thumbPos, 2507 btw, 2508 brw, 2509 bbw, 2510 blw; 2511 2512 if (!$thumb || !inViewport($thumb[0])) { 2513 return false; 2514 } 2515 2516 thumbPos = $.fancybox.getTranslate($thumb); 2517 2518 btw = parseFloat($thumb.css("border-top-width") || 0); 2519 brw = parseFloat($thumb.css("border-right-width") || 0); 2520 bbw = parseFloat($thumb.css("border-bottom-width") || 0); 2521 blw = parseFloat($thumb.css("border-left-width") || 0); 2522 2523 rez = { 2524 top: thumbPos.top + btw, 2525 left: thumbPos.left + blw, 2526 width: thumbPos.width - brw - blw, 2527 height: thumbPos.height - btw - bbw, 2528 scaleX: 1, 2529 scaleY: 1 2530 }; 2531 2532 return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false; 2533 }, 2534 2535 // Final adjustments after current gallery item is moved to position 2536 // and it`s content is loaded 2537 // ================================================================== 2538 2539 complete: function () { 2540 var self = this, 2541 current = self.current, 2542 slides = {}, 2543 $el; 2544 2545 if (self.isMoved() || !current.isLoaded) { 2546 return; 2547 } 2548 2549 if (!current.isComplete) { 2550 current.isComplete = true; 2551 2552 current.$slide.siblings().trigger("onReset"); 2553 2554 self.preload("inline"); 2555 2556 // Trigger any CSS transiton inside the slide 2557 forceRedraw(current.$slide); 2558 2559 current.$slide.addClass("fancybox-slide--complete"); 2560 2561 // Remove unnecessary slides 2562 $.each(self.slides, function (key, slide) { 2563 if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) { 2564 slides[slide.pos] = slide; 2565 } else if (slide) { 2566 $.fancybox.stop(slide.$slide); 2567 2568 slide.$slide.off().remove(); 2569 } 2570 }); 2571 2572 self.slides = slides; 2573 } 2574 2575 self.isAnimating = false; 2576 2577 self.updateCursor(); 2578 2579 self.trigger("afterShow"); 2580 2581 // Autoplay first html5 video/audio 2582 if (!!current.opts.video.autoStart) { 2583 current.$slide 2584 .find("video,audio") 2585 .filter(":visible:first") 2586 .trigger("play") 2587 .one("ended", function () { 2588 if (Document.exitFullscreen) { 2589 Document.exitFullscreen(); 2590 } else if (this.webkitExitFullscreen) { 2591 this.webkitExitFullscreen(); 2592 } 2593 2594 self.next(); 2595 }); 2596 } 2597 2598 // Try to focus on the first focusable element 2599 if (current.opts.autoFocus && current.contentType === "html") { 2600 // Look for the first input with autofocus attribute 2601 $el = current.$content.find("input[autofocus]:enabled:visible:first"); 2602 2603 if ($el.length) { 2604 $el.trigger("focus"); 2605 } else { 2606 self.focus(null, true); 2607 } 2608 } 2609 2610 // Avoid jumping 2611 current.$slide.scrollTop(0).scrollLeft(0); 2612 }, 2613 2614 // Preload next and previous slides 2615 // ================================ 2616 2617 preload: function (type) { 2618 var self = this, 2619 prev, 2620 next; 2621 2622 if (self.group.length < 2) { 2623 return; 2624 } 2625 2626 next = self.slides[self.currPos + 1]; 2627 prev = self.slides[self.currPos - 1]; 2628 2629 if (prev && prev.type === type) { 2630 self.loadSlide(prev); 2631 } 2632 2633 if (next && next.type === type) { 2634 self.loadSlide(next); 2635 } 2636 }, 2637 2638 // Try to find and focus on the first focusable element 2639 // ==================================================== 2640 2641 focus: function (e, firstRun) { 2642 var self = this, 2643 focusableStr = [ 2644 "a[href]", 2645 "area[href]", 2646 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 2647 "select:not([disabled]):not([aria-hidden])", 2648 "textarea:not([disabled]):not([aria-hidden])", 2649 "button:not([disabled]):not([aria-hidden])", 2650 "iframe", 2651 "object", 2652 "embed", 2653 "video", 2654 "audio", 2655 "[contenteditable]", 2656 '[tabindex]:not([tabindex^="-"])' 2657 ].join(","), 2658 focusableItems, 2659 focusedItemIndex; 2660 2661 if (self.isClosing) { 2662 return; 2663 } 2664 2665 if (e || !self.current || !self.current.isComplete) { 2666 // Focus on any element inside fancybox 2667 focusableItems = self.$refs.container.find("*:visible"); 2668 } else { 2669 // Focus inside current slide 2670 focusableItems = self.current.$slide.find("*:visible" + (firstRun ? ":not(.fancybox-close-small)" : "")); 2671 } 2672 2673 focusableItems = focusableItems.filter(focusableStr).filter(function () { 2674 return $(this).css("visibility") !== "hidden" && !$(this).hasClass("disabled"); 2675 }); 2676 2677 if (focusableItems.length) { 2678 focusedItemIndex = focusableItems.index(document.activeElement); 2679 2680 if (e && e.shiftKey) { 2681 // Back tab 2682 if (focusedItemIndex < 0 || focusedItemIndex == 0) { 2683 e.preventDefault(); 2684 2685 focusableItems.eq(focusableItems.length - 1).trigger("focus"); 2686 } 2687 } else { 2688 // Outside or Forward tab 2689 if (focusedItemIndex < 0 || focusedItemIndex == focusableItems.length - 1) { 2690 if (e) { 2691 e.preventDefault(); 2692 } 2693 2694 focusableItems.eq(0).trigger("focus"); 2695 } 2696 } 2697 } else { 2698 self.$refs.container.trigger("focus"); 2699 } 2700 }, 2701 2702 // Activates current instance - brings container to the front and enables keyboard, 2703 // notifies other instances about deactivating 2704 // ================================================================================= 2705 2706 activate: function () { 2707 var self = this; 2708 2709 // Deactivate all instances 2710 $(".fancybox-container").each(function () { 2711 var instance = $(this).data("FancyBox"); 2712 2713 // Skip self and closing instances 2714 if (instance && instance.id !== self.id && !instance.isClosing) { 2715 instance.trigger("onDeactivate"); 2716 2717 instance.removeEvents(); 2718 2719 instance.isVisible = false; 2720 } 2721 }); 2722 2723 self.isVisible = true; 2724 2725 if (self.current || self.isIdle) { 2726 self.update(); 2727 2728 self.updateControls(); 2729 } 2730 2731 self.trigger("onActivate"); 2732 2733 self.addEvents(); 2734 }, 2735 2736 // Start closing procedure 2737 // This will start "zoom-out" animation if needed and clean everything up afterwards 2738 // ================================================================================= 2739 2740 close: function (e, d) { 2741 var self = this, 2742 current = self.current, 2743 effect, 2744 duration, 2745 $content, 2746 domRect, 2747 opacity, 2748 start, 2749 end; 2750 2751 var done = function () { 2752 self.cleanUp(e); 2753 }; 2754 2755 if (self.isClosing) { 2756 return false; 2757 } 2758 2759 self.isClosing = true; 2760 2761 // If beforeClose callback prevents closing, make sure content is centered 2762 if (self.trigger("beforeClose", e) === false) { 2763 self.isClosing = false; 2764 2765 requestAFrame(function () { 2766 self.update(); 2767 }); 2768 2769 return false; 2770 } 2771 2772 // Remove all events 2773 // If there are multiple instances, they will be set again by "activate" method 2774 self.removeEvents(); 2775 2776 $content = current.$content; 2777 effect = current.opts.animationEffect; 2778 duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0; 2779 2780 current.$slide.removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated"); 2781 2782 if (e !== true) { 2783 $.fancybox.stop(current.$slide); 2784 } else { 2785 effect = false; 2786 } 2787 2788 // Remove other slides 2789 current.$slide 2790 .siblings() 2791 .trigger("onReset") 2792 .remove(); 2793 2794 // Trigger animations 2795 if (duration) { 2796 self.$refs.container 2797 .removeClass("fancybox-is-open") 2798 .addClass("fancybox-is-closing") 2799 .css("transition-duration", duration + "ms"); 2800 } 2801 2802 // Clean up 2803 self.hideLoading(current); 2804 2805 self.hideControls(true); 2806 2807 self.updateCursor(); 2808 2809 // Check if possible to zoom-out 2810 if ( 2811 effect === "zoom" && 2812 !($content && duration && current.type === "image" && !self.isMoved() && !current.hasError && (end = self.getThumbPos(current))) 2813 ) { 2814 effect = "fade"; 2815 } 2816 2817 if (effect === "zoom") { 2818 $.fancybox.stop($content); 2819 2820 domRect = $.fancybox.getTranslate($content); 2821 2822 start = { 2823 top: domRect.top, 2824 left: domRect.left, 2825 scaleX: domRect.width / end.width, 2826 scaleY: domRect.height / end.height, 2827 width: end.width, 2828 height: end.height 2829 }; 2830 2831 // Check if we need to animate opacity 2832 opacity = current.opts.zoomOpacity; 2833 2834 if (opacity == "auto") { 2835 opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1; 2836 } 2837 2838 if (opacity) { 2839 end.opacity = 0; 2840 } 2841 2842 $.fancybox.setTranslate($content, start); 2843 2844 forceRedraw($content); 2845 2846 $.fancybox.animate($content, end, duration, done); 2847 2848 return true; 2849 } 2850 2851 if (effect && duration) { 2852 $.fancybox.animate( 2853 current.$slide.addClass("fancybox-slide--previous").removeClass("fancybox-slide--current"), 2854 "fancybox-animated fancybox-fx-" + effect, 2855 duration, 2856 done 2857 ); 2858 } else { 2859 // If skip animation 2860 if (e === true) { 2861 setTimeout(done, duration); 2862 } else { 2863 done(); 2864 } 2865 } 2866 2867 return true; 2868 }, 2869 2870 // Final adjustments after removing the instance 2871 // ============================================= 2872 2873 cleanUp: function (e) { 2874 var self = this, 2875 instance, 2876 $focus = self.current.opts.$orig, 2877 x, 2878 y; 2879 2880 self.current.$slide.trigger("onReset"); 2881 2882 self.$refs.container.empty().remove(); 2883 2884 self.trigger("afterClose", e); 2885 2886 // Place back focus 2887 if (!!self.current.opts.backFocus) { 2888 if (!$focus || !$focus.length || !$focus.is(":visible")) { 2889 $focus = self.$trigger; 2890 } 2891 2892 if ($focus && $focus.length) { 2893 x = window.scrollX; 2894 y = window.scrollY; 2895 2896 $focus.trigger("focus"); 2897 2898 $("html, body") 2899 .scrollTop(y) 2900 .scrollLeft(x); 2901 } 2902 } 2903 2904 self.current = null; 2905 2906 // Check if there are other instances 2907 instance = $.fancybox.getInstance(); 2908 2909 if (instance) { 2910 instance.activate(); 2911 } else { 2912 $("body").removeClass("fancybox-active compensate-for-scrollbar"); 2913 2914 $("#fancybox-style-noscroll").remove(); 2915 } 2916 }, 2917 2918 // Call callback and trigger an event 2919 // ================================== 2920 2921 trigger: function (name, slide) { 2922 var args = Array.prototype.slice.call(arguments, 1), 2923 self = this, 2924 obj = slide && slide.opts ? slide : self.current, 2925 rez; 2926 2927 if (obj) { 2928 args.unshift(obj); 2929 } else { 2930 obj = self; 2931 } 2932 2933 args.unshift(self); 2934 2935 if ($.isFunction(obj.opts[name])) { 2936 rez = obj.opts[name].apply(obj, args); 2937 } 2938 2939 if (rez === false) { 2940 return rez; 2941 } 2942 2943 if (name === "afterClose" || !self.$refs) { 2944 $D.trigger(name + ".fb", args); 2945 } else { 2946 self.$refs.container.trigger(name + ".fb", args); 2947 } 2948 }, 2949 2950 // Update infobar values, navigation button states and reveal caption 2951 // ================================================================== 2952 2953 updateControls: function () { 2954 var self = this, 2955 current = self.current, 2956 index = current.index, 2957 $container = self.$refs.container, 2958 $caption = self.$refs.caption, 2959 caption = current.opts.caption; 2960 2961 // Recalculate content dimensions 2962 current.$slide.trigger("refresh"); 2963 2964 // Set caption 2965 if (caption && caption.length) { 2966 self.$caption = $caption; 2967 2968 $caption 2969 .children() 2970 .eq(0) 2971 .html(caption); 2972 } else { 2973 self.$caption = null; 2974 } 2975 2976 if (!self.hasHiddenControls && !self.isIdle) { 2977 self.showControls(); 2978 } 2979 2980 // Update info and navigation elements 2981 $container.find("[data-fancybox-count]").html(self.group.length); 2982 $container.find("[data-fancybox-index]").html(index + 1); 2983 2984 $container.find("[data-fancybox-prev]").prop("disabled", !current.opts.loop && index <= 0); 2985 $container.find("[data-fancybox-next]").prop("disabled", !current.opts.loop && index >= self.group.length - 1); 2986 2987 if (current.type === "image") { 2988 // Re-enable buttons; update download button source 2989 $container 2990 .find("[data-fancybox-zoom]") 2991 .show() 2992 .end() 2993 .find("[data-fancybox-download]") 2994 .attr("href", current.opts.image.src || current.src) 2995 .show(); 2996 } else if (current.opts.toolbar) { 2997 $container.find("[data-fancybox-download],[data-fancybox-zoom]").hide(); 2998 } 2999 3000 // Make sure focus is not on disabled button/element 3001 if ($(document.activeElement).is(":hidden,[disabled]")) { 3002 self.$refs.container.trigger("focus"); 3003 } 3004 }, 3005 3006 // Hide toolbar and caption 3007 // ======================== 3008 3009 hideControls: function (andCaption) { 3010 var self = this, 3011 arr = ["infobar", "toolbar", "nav"]; 3012 3013 if (andCaption || !self.current.opts.preventCaptionOverlap) { 3014 arr.push("caption"); 3015 } 3016 3017 this.$refs.container.removeClass( 3018 arr 3019 .map(function (i) { 3020 return "fancybox-show-" + i; 3021 }) 3022 .join(" ") 3023 ); 3024 3025 this.hasHiddenControls = true; 3026 }, 3027 3028 showControls: function () { 3029 var self = this, 3030 opts = self.current ? self.current.opts : self.opts, 3031 $container = self.$refs.container; 3032 3033 self.hasHiddenControls = false; 3034 self.idleSecondsCounter = 0; 3035 3036 $container 3037 .toggleClass("fancybox-show-toolbar", !!(opts.toolbar && opts.buttons)) 3038 .toggleClass("fancybox-show-infobar", !!(opts.infobar && self.group.length > 1)) 3039 .toggleClass("fancybox-show-caption", !!self.$caption) 3040 .toggleClass("fancybox-show-nav", !!(opts.arrows && self.group.length > 1)) 3041 .toggleClass("fancybox-is-modal", !!opts.modal); 3042 }, 3043 3044 // Toggle toolbar and caption 3045 // ========================== 3046 3047 toggleControls: function () { 3048 if (this.hasHiddenControls) { 3049 this.showControls(); 3050 } else { 3051 this.hideControls(); 3052 } 3053 } 3054 }); 3055 3056 $.fancybox = { 3057 version: "3.5.7", 3058 defaults: defaults, 3059 3060 // Get current instance and execute a command. 3061 // 3062 // Examples of usage: 3063 // 3064 // $instance = $.fancybox.getInstance(); 3065 // $.fancybox.getInstance().jumpTo( 1 ); 3066 // $.fancybox.getInstance( 'jumpTo', 1 ); 3067 // $.fancybox.getInstance( function() { 3068 // console.info( this.currIndex ); 3069 // }); 3070 // ====================================================== 3071 3072 getInstance: function (command) { 3073 var instance = $('.fancybox-container:not(".fancybox-is-closing"):last').data("FancyBox"), 3074 args = Array.prototype.slice.call(arguments, 1); 3075 3076 if (instance instanceof FancyBox) { 3077 if ($.type(command) === "string") { 3078 instance[command].apply(instance, args); 3079 } else if ($.type(command) === "function") { 3080 command.apply(instance, args); 3081 } 3082 3083 return instance; 3084 } 3085 3086 return false; 3087 }, 3088 3089 // Create new instance 3090 // =================== 3091 3092 open: function (items, opts, index) { 3093 return new FancyBox(items, opts, index); 3094 }, 3095 3096 // Close current or all instances 3097 // ============================== 3098 3099 close: function (all) { 3100 var instance = this.getInstance(); 3101 3102 if (instance) { 3103 instance.close(); 3104 3105 // Try to find and close next instance 3106 if (all === true) { 3107 this.close(all); 3108 } 3109 } 3110 }, 3111 3112 // Close all instances and unbind all events 3113 // ========================================= 3114 3115 destroy: function () { 3116 this.close(true); 3117 3118 $D.add("body").off("click.fb-start", "**"); 3119 }, 3120 3121 // Try to detect mobile devices 3122 // ============================ 3123 3124 isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), 3125 3126 // Detect if 'translate3d' support is available 3127 // ============================================ 3128 3129 use3d: (function () { 3130 var div = document.createElement("div"); 3131 3132 return ( 3133 window.getComputedStyle && 3134 window.getComputedStyle(div) && 3135 window.getComputedStyle(div).getPropertyValue("transform") && 3136 !(document.documentMode && document.documentMode < 11) 3137 ); 3138 })(), 3139 3140 // Helper function to get current visual state of an element 3141 // returns array[ top, left, horizontal-scale, vertical-scale, opacity ] 3142 // ===================================================================== 3143 3144 getTranslate: function ($el) { 3145 var domRect; 3146 3147 if (!$el || !$el.length) { 3148 return false; 3149 } 3150 3151 domRect = $el[0].getBoundingClientRect(); 3152 3153 return { 3154 top: domRect.top || 0, 3155 left: domRect.left || 0, 3156 width: domRect.width, 3157 height: domRect.height, 3158 opacity: parseFloat($el.css("opacity")) 3159 }; 3160 }, 3161 3162 // Shortcut for setting "translate3d" properties for element 3163 // Can set be used to set opacity, too 3164 // ======================================================== 3165 3166 setTranslate: function ($el, props) { 3167 var str = "", 3168 css = {}; 3169 3170 if (!$el || !props) { 3171 return; 3172 } 3173 3174 if (props.left !== undefined || props.top !== undefined) { 3175 str = 3176 (props.left === undefined ? $el.position().left : props.left) + 3177 "px, " + 3178 (props.top === undefined ? $el.position().top : props.top) + 3179 "px"; 3180 3181 if (this.use3d) { 3182 str = "translate3d(" + str + ", 0px)"; 3183 } else { 3184 str = "translate(" + str + ")"; 3185 } 3186 } 3187 3188 if (props.scaleX !== undefined && props.scaleY !== undefined) { 3189 str += " scale(" + props.scaleX + ", " + props.scaleY + ")"; 3190 } else if (props.scaleX !== undefined) { 3191 str += " scaleX(" + props.scaleX + ")"; 3192 } 3193 3194 if (str.length) { 3195 css.transform = str; 3196 } 3197 3198 if (props.opacity !== undefined) { 3199 css.opacity = props.opacity; 3200 } 3201 3202 if (props.width !== undefined) { 3203 css.width = props.width; 3204 } 3205 3206 if (props.height !== undefined) { 3207 css.height = props.height; 3208 } 3209 3210 return $el.css(css); 3211 }, 3212 3213 // Simple CSS transition handler 3214 // ============================= 3215 3216 animate: function ($el, to, duration, callback, leaveAnimationName) { 3217 var self = this, 3218 from; 3219 3220 if ($.isFunction(duration)) { 3221 callback = duration; 3222 duration = null; 3223 } 3224 3225 self.stop($el); 3226 3227 from = self.getTranslate($el); 3228 3229 $el.on(transitionEnd, function (e) { 3230 // Skip events from child elements and z-index change 3231 if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName == "z-index")) { 3232 return; 3233 } 3234 3235 self.stop($el); 3236 3237 if ($.isNumeric(duration)) { 3238 $el.css("transition-duration", ""); 3239 } 3240 3241 if ($.isPlainObject(to)) { 3242 if (to.scaleX !== undefined && to.scaleY !== undefined) { 3243 self.setTranslate($el, { 3244 top: to.top, 3245 left: to.left, 3246 width: from.width * to.scaleX, 3247 height: from.height * to.scaleY, 3248 scaleX: 1, 3249 scaleY: 1 3250 }); 3251 } 3252 } else if (leaveAnimationName !== true) { 3253 $el.removeClass(to); 3254 } 3255 3256 if ($.isFunction(callback)) { 3257 callback(e); 3258 } 3259 }); 3260 3261 if ($.isNumeric(duration)) { 3262 $el.css("transition-duration", duration + "ms"); 3263 } 3264 3265 // Start animation by changing CSS properties or class name 3266 if ($.isPlainObject(to)) { 3267 if (to.scaleX !== undefined && to.scaleY !== undefined) { 3268 delete to.width; 3269 delete to.height; 3270 3271 if ($el.parent().hasClass("fancybox-slide--image")) { 3272 $el.parent().addClass("fancybox-is-scaling"); 3273 } 3274 } 3275 3276 $.fancybox.setTranslate($el, to); 3277 } else { 3278 $el.addClass(to); 3279 } 3280 3281 // Make sure that `transitionend` callback gets fired 3282 $el.data( 3283 "timer", 3284 setTimeout(function () { 3285 $el.trigger(transitionEnd); 3286 }, duration + 33) 3287 ); 3288 }, 3289 3290 stop: function ($el, callCallback) { 3291 if ($el && $el.length) { 3292 clearTimeout($el.data("timer")); 3293 3294 if (callCallback) { 3295 $el.trigger(transitionEnd); 3296 } 3297 3298 $el.off(transitionEnd).css("transition-duration", ""); 3299 3300 $el.parent().removeClass("fancybox-is-scaling"); 3301 } 3302 } 3303 }; 3304 3305 // Default click handler for "fancyboxed" links 3306 // ============================================ 3307 3308 function _run(e, opts) { 3309 var items = [], 3310 index = 0, 3311 $target, 3312 value, 3313 instance; 3314 3315 // Avoid opening multiple times 3316 if (e && e.isDefaultPrevented()) { 3317 return; 3318 } 3319 3320 e.preventDefault(); 3321 3322 opts = opts || {}; 3323 3324 if (e && e.data) { 3325 opts = mergeOpts(e.data.options, opts); 3326 } 3327 3328 $target = opts.$target || $(e.currentTarget).trigger("blur"); 3329 instance = $.fancybox.getInstance(); 3330 3331 if (instance && instance.$trigger && instance.$trigger.is($target)) { 3332 return; 3333 } 3334 3335 if (opts.selector) { 3336 items = $(opts.selector); 3337 } else { 3338 // Get all related items and find index for clicked one 3339 value = $target.attr("data-fancybox") || ""; 3340 3341 if (value) { 3342 items = e.data ? e.data.items : []; 3343 items = items.length ? items.filter('[data-fancybox="' + value + '"]') : $('[data-fancybox="' + value + '"]'); 3344 } else { 3345 items = [$target]; 3346 } 3347 } 3348 3349 index = $(items).index($target); 3350 3351 // Sometimes current item can not be found 3352 if (index < 0) { 3353 index = 0; 3354 } 3355 3356 instance = $.fancybox.open(items, opts, index); 3357 3358 // Save last active element 3359 instance.$trigger = $target; 3360 } 3361 3362 // Create a jQuery plugin 3363 // ====================== 3364 3365 $.fn.fancybox = function (options) { 3366 var selector; 3367 3368 options = options || {}; 3369 selector = options.selector || false; 3370 3371 if (selector) { 3372 // Use body element instead of document so it executes first 3373 $("body") 3374 .off("click.fb-start", selector) 3375 .on("click.fb-start", selector, { 3376 options: options 3377 }, _run); 3378 } else { 3379 this.off("click.fb-start").on( 3380 "click.fb-start", { 3381 items: this, 3382 options: options 3383 }, 3384 _run 3385 ); 3386 } 3387 3388 return this; 3389 }; 3390 3391 // Self initializing plugin for all elements having `data-fancybox` attribute 3392 // ========================================================================== 3393 3394 $D.on("click.fb-start", "[data-fancybox]", _run); 3395 3396 // Enable "trigger elements" 3397 // ========================= 3398 3399 $D.on("click.fb-start", "[data-fancybox-trigger]", function (e) { 3400 $('[data-fancybox="' + $(this).attr("data-fancybox-trigger") + '"]') 3401 .eq($(this).attr("data-fancybox-index") || 0) 3402 .trigger("click.fb-start", { 3403 $trigger: $(this) 3404 }); 3405 }); 3406 3407 // Track focus event for better accessibility styling 3408 // ================================================== 3409 (function () { 3410 var buttonStr = ".fancybox-button", 3411 focusStr = "fancybox-focus", 3412 $pressed = null; 3413 3414 $D.on("mousedown mouseup focus blur", buttonStr, function (e) { 3415 switch (e.type) { 3416 case "mousedown": 3417 $pressed = $(this); 3418 break; 3419 case "mouseup": 3420 $pressed = null; 3421 break; 3422 case "focusin": 3423 $(buttonStr).removeClass(focusStr); 3424 3425 if (!$(this).is($pressed) && !$(this).is("[disabled]")) { 3426 $(this).addClass(focusStr); 3427 } 3428 break; 3429 case "focusout": 3430 $(buttonStr).removeClass(focusStr); 3431 break; 3432 } 3433 }); 3434 })(); 3435})(window, document, jQuery); 3436// ========================================================================== 3437// 3438// Media 3439// Adds additional media type support 3440// 3441// ========================================================================== 3442(function ($) { 3443 "use strict"; 3444 3445 // Object containing properties for each media type 3446 var defaults = { 3447 youtube: { 3448 matcher: /(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i, 3449 params: { 3450 autoplay: 1, 3451 autohide: 1, 3452 fs: 1, 3453 rel: 0, 3454 hd: 1, 3455 wmode: "transparent", 3456 enablejsapi: 1, 3457 html5: 1 3458 }, 3459 paramPlace: 8, 3460 type: "iframe", 3461 url: "https://www.youtube-nocookie.com/embed/$4", 3462 thumb: "https://img.youtube.com/vi/$4/hqdefault.jpg" 3463 }, 3464 3465 vimeo: { 3466 matcher: /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/, 3467 params: { 3468 autoplay: 1, 3469 hd: 1, 3470 show_title: 1, 3471 show_byline: 1, 3472 show_portrait: 0, 3473 fullscreen: 1 3474 }, 3475 paramPlace: 3, 3476 type: "iframe", 3477 url: "//player.vimeo.com/video/$2" 3478 }, 3479 3480 instagram: { 3481 matcher: /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i, 3482 type: "image", 3483 url: "//$1/p/$2/media/?size=l" 3484 }, 3485 3486 // Examples: 3487 // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16 3488 // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z 3489 // https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en 3490 // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572 3491 gmap_place: { 3492 matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i, 3493 type: "iframe", 3494 url: function (rez) { 3495 return ( 3496 "//maps.google." + 3497 rez[2] + 3498 "/?ll=" + 3499 (rez[9] ? rez[9] + "&z=" + Math.floor(rez[10]) + (rez[12] ? rez[12].replace(/^\//, "&") : "") : rez[12] + "").replace(/\?/, "&") + 3500 "&output=" + 3501 (rez[12] && rez[12].indexOf("layer=c") > 0 ? "svembed" : "embed") 3502 ); 3503 } 3504 }, 3505 3506 // Examples: 3507 // https://www.google.com/maps/search/Empire+State+Building/ 3508 // https://www.google.com/maps/search/?api=1&query=centurylink+field 3509 // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393 3510 gmap_search: { 3511 matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i, 3512 type: "iframe", 3513 url: function (rez) { 3514 return "//maps.google." + rez[2] + "/maps?q=" + rez[5].replace("query=", "q=").replace("api=1", "") + "&output=embed"; 3515 } 3516 } 3517 }; 3518 3519 // Formats matching url to final form 3520 var format = function (url, rez, params) { 3521 if (!url) { 3522 return; 3523 } 3524 3525 params = params || ""; 3526 3527 if ($.type(params) === "object") { 3528 params = $.param(params, true); 3529 } 3530 3531 $.each(rez, function (key, value) { 3532 url = url.replace("$" + key, value || ""); 3533 }); 3534 3535 if (params.length) { 3536 url += (url.indexOf("?") > 0 ? "&" : "?") + params; 3537 } 3538 3539 return url; 3540 }; 3541 3542 $(document).on("objectNeedsType.fb", function (e, instance, item) { 3543 var url = item.src || "", 3544 type = false, 3545 media, 3546 thumb, 3547 rez, 3548 params, 3549 urlParams, 3550 paramObj, 3551 provider; 3552 3553 media = $.extend(true, {}, defaults, item.opts.media); 3554 3555 // Look for any matching media type 3556 $.each(media, function (providerName, providerOpts) { 3557 rez = url.match(providerOpts.matcher); 3558 3559 if (!rez) { 3560 return; 3561 } 3562 3563 type = providerOpts.type; 3564 provider = providerName; 3565 paramObj = {}; 3566 3567 if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) { 3568 urlParams = rez[providerOpts.paramPlace]; 3569 3570 if (urlParams[0] == "?") { 3571 urlParams = urlParams.substring(1); 3572 } 3573 3574 urlParams = urlParams.split("&"); 3575 3576 for (var m = 0; m < urlParams.length; ++m) { 3577 var p = urlParams[m].split("=", 2); 3578 3579 if (p.length == 2) { 3580 paramObj[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); 3581 } 3582 } 3583 } 3584 3585 params = $.extend(true, {}, providerOpts.params, item.opts[providerName], paramObj); 3586 3587 url = 3588 $.type(providerOpts.url) === "function" ? providerOpts.url.call(this, rez, params, item) : format(providerOpts.url, rez, params); 3589 3590 thumb = 3591 $.type(providerOpts.thumb) === "function" ? providerOpts.thumb.call(this, rez, params, item) : format(providerOpts.thumb, rez); 3592 3593 if (providerName === "youtube") { 3594 url = url.replace(/&t=((\d+)m)?(\d+)s/, function (match, p1, m, s) { 3595 return "&start=" + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10)); 3596 }); 3597 } else if (providerName === "vimeo") { 3598 url = url.replace("&%23", "#"); 3599 } 3600 3601 return false; 3602 }); 3603 3604 // If it is found, then change content type and update the url 3605 3606 if (type) { 3607 if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) { 3608 item.opts.thumb = thumb; 3609 } 3610 3611 if (type === "iframe") { 3612 item.opts = $.extend(true, item.opts, { 3613 iframe: { 3614 preload: false, 3615 attr: { 3616 scrolling: "no" 3617 } 3618 } 3619 }); 3620 } 3621 3622 $.extend(item, { 3623 type: type, 3624 src: url, 3625 origSrc: item.src, 3626 contentSource: provider, 3627 contentType: type === "image" ? "image" : provider == "gmap_place" || provider == "gmap_search" ? "map" : "video" 3628 }); 3629 } else if (url) { 3630 item.type = item.opts.defaultType; 3631 } 3632 }); 3633 3634 // Load YouTube/Video API on request to detect when video finished playing 3635 var VideoAPILoader = { 3636 youtube: { 3637 src: "https://www.youtube.com/iframe_api", 3638 class: "YT", 3639 loading: false, 3640 loaded: false 3641 }, 3642 3643 vimeo: { 3644 src: "https://player.vimeo.com/api/player.js", 3645 class: "Vimeo", 3646 loading: false, 3647 loaded: false 3648 }, 3649 3650 load: function (vendor) { 3651 var _this = this, 3652 script; 3653 3654 if (this[vendor].loaded) { 3655 setTimeout(function () { 3656 _this.done(vendor); 3657 }); 3658 return; 3659 } 3660 3661 if (this[vendor].loading) { 3662 return; 3663 } 3664 3665 this[vendor].loading = true; 3666 3667 script = document.createElement("script"); 3668 script.type = "text/javascript"; 3669 script.src = this[vendor].src; 3670 3671 if (vendor === "youtube") { 3672 window.onYouTubeIframeAPIReady = function () { 3673 _this[vendor].loaded = true; 3674 _this.done(vendor); 3675 }; 3676 } else { 3677 script.onload = function () { 3678 _this[vendor].loaded = true; 3679 _this.done(vendor); 3680 }; 3681 } 3682 3683 document.body.appendChild(script); 3684 }, 3685 done: function (vendor) { 3686 var instance, $el, player; 3687 3688 if (vendor === "youtube") { 3689 delete window.onYouTubeIframeAPIReady; 3690 } 3691 3692 instance = $.fancybox.getInstance(); 3693 3694 if (instance) { 3695 $el = instance.current.$content.find("iframe"); 3696 3697 if (vendor === "youtube" && YT !== undefined && YT) { 3698 player = new YT.Player($el.attr("id"), { 3699 events: { 3700 onStateChange: function (e) { 3701 if (e.data == 0) { 3702 instance.next(); 3703 } 3704 } 3705 } 3706 }); 3707 } else if (vendor === "vimeo" && Vimeo !== undefined && Vimeo) { 3708 player = new Vimeo.Player($el); 3709 3710 player.on("ended", function () { 3711 instance.next(); 3712 }); 3713 } 3714 } 3715 } 3716 }; 3717 3718 $(document).on({ 3719 "afterShow.fb": function (e, instance, current) { 3720 if (instance.group.length > 1 && (current.contentSource === "youtube" || current.contentSource === "vimeo")) { 3721 VideoAPILoader.load(current.contentSource); 3722 } 3723 } 3724 }); 3725})(jQuery); 3726// ========================================================================== 3727// 3728// Guestures 3729// Adds touch guestures, handles click and tap events 3730// 3731// ========================================================================== 3732(function (window, document, $) { 3733 "use strict"; 3734 3735 var requestAFrame = (function () { 3736 return ( 3737 window.requestAnimationFrame || 3738 window.webkitRequestAnimationFrame || 3739 window.mozRequestAnimationFrame || 3740 window.oRequestAnimationFrame || 3741 // if all else fails, use setTimeout 3742 function (callback) { 3743 return window.setTimeout(callback, 1000 / 60); 3744 } 3745 ); 3746 })(); 3747 3748 var cancelAFrame = (function () { 3749 return ( 3750 window.cancelAnimationFrame || 3751 window.webkitCancelAnimationFrame || 3752 window.mozCancelAnimationFrame || 3753 window.oCancelAnimationFrame || 3754 function (id) { 3755 window.clearTimeout(id); 3756 } 3757 ); 3758 })(); 3759 3760 var getPointerXY = function (e) { 3761 var result = []; 3762 3763 e = e.originalEvent || e || window.e; 3764 e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e]; 3765 3766 for (var key in e) { 3767 if (e[key].pageX) { 3768 result.push({ 3769 x: e[key].pageX, 3770 y: e[key].pageY 3771 }); 3772 } else if (e[key].clientX) { 3773 result.push({ 3774 x: e[key].clientX, 3775 y: e[key].clientY 3776 }); 3777 } 3778 } 3779 3780 return result; 3781 }; 3782 3783 var distance = function (point2, point1, what) { 3784 if (!point1 || !point2) { 3785 return 0; 3786 } 3787 3788 if (what === "x") { 3789 return point2.x - point1.x; 3790 } else if (what === "y") { 3791 return point2.y - point1.y; 3792 } 3793 3794 return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)); 3795 }; 3796 3797 var isClickable = function ($el) { 3798 if ( 3799 $el.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe') || 3800 $.isFunction($el.get(0).onclick) || 3801 $el.data("selectable") 3802 ) { 3803 return true; 3804 } 3805 3806 // Check for attributes like data-fancybox-next or data-fancybox-close 3807 for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) { 3808 if (atts[i].nodeName.substr(0, 14) === "data-fancybox-") { 3809 return true; 3810 } 3811 } 3812 3813 return false; 3814 }; 3815 3816 var hasScrollbars = function (el) { 3817 var overflowY = window.getComputedStyle(el)["overflow-y"], 3818 overflowX = window.getComputedStyle(el)["overflow-x"], 3819 vertical = (overflowY === "scroll" || overflowY === "auto") && el.scrollHeight > el.clientHeight, 3820 horizontal = (overflowX === "scroll" || overflowX === "auto") && el.scrollWidth > el.clientWidth; 3821 3822 return vertical || horizontal; 3823 }; 3824 3825 var isScrollable = function ($el) { 3826 var rez = false; 3827 3828 while (true) { 3829 rez = hasScrollbars($el.get(0)); 3830 3831 if (rez) { 3832 break; 3833 } 3834 3835 $el = $el.parent(); 3836 3837 if (!$el.length || $el.hasClass("fancybox-stage") || $el.is("body")) { 3838 break; 3839 } 3840 } 3841 3842 return rez; 3843 }; 3844 3845 var Guestures = function (instance) { 3846 var self = this; 3847 3848 self.instance = instance; 3849 3850 self.$bg = instance.$refs.bg; 3851 self.$stage = instance.$refs.stage; 3852 self.$container = instance.$refs.container; 3853 3854 self.destroy(); 3855 3856 self.$container.on("touchstart.fb.touch mousedown.fb.touch", $.proxy(self, "ontouchstart")); 3857 }; 3858 3859 Guestures.prototype.destroy = function () { 3860 var self = this; 3861 3862 self.$container.off(".fb.touch"); 3863 3864 $(document).off(".fb.touch"); 3865 3866 if (self.requestId) { 3867 cancelAFrame(self.requestId); 3868 self.requestId = null; 3869 } 3870 3871 if (self.tapped) { 3872 clearTimeout(self.tapped); 3873 self.tapped = null; 3874 } 3875 }; 3876 3877 Guestures.prototype.ontouchstart = function (e) { 3878 var self = this, 3879 $target = $(e.target), 3880 instance = self.instance, 3881 current = instance.current, 3882 $slide = current.$slide, 3883 $content = current.$content, 3884 isTouchDevice = e.type == "touchstart"; 3885 3886 // Do not respond to both (touch and mouse) events 3887 if (isTouchDevice) { 3888 self.$container.off("mousedown.fb.touch"); 3889 } 3890 3891 // Ignore right click 3892 if (e.originalEvent && e.originalEvent.button == 2) { 3893 return; 3894 } 3895 3896 // Ignore taping on links, buttons, input elements 3897 if (!$slide.length || !$target.length || isClickable($target) || isClickable($target.parent())) { 3898 return; 3899 } 3900 // Ignore clicks on the scrollbar 3901 if (!$target.is("img") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) { 3902 return; 3903 } 3904 3905 // Ignore clicks while zooming or closing 3906 if (!current || instance.isAnimating || current.$slide.hasClass("fancybox-animated")) { 3907 e.stopPropagation(); 3908 e.preventDefault(); 3909 3910 return; 3911 } 3912 3913 self.realPoints = self.startPoints = getPointerXY(e); 3914 3915 if (!self.startPoints.length) { 3916 return; 3917 } 3918 3919 // Allow other scripts to catch touch event if "touch" is set to false 3920 if (current.touch) { 3921 e.stopPropagation(); 3922 } 3923 3924 self.startEvent = e; 3925 3926 self.canTap = true; 3927 self.$target = $target; 3928 self.$content = $content; 3929 self.opts = current.opts.touch; 3930 3931 self.isPanning = false; 3932 self.isSwiping = false; 3933 self.isZooming = false; 3934 self.isScrolling = false; 3935 self.canPan = instance.canPan(); 3936 3937 self.startTime = new Date().getTime(); 3938 self.distanceX = self.distanceY = self.distance = 0; 3939 3940 self.canvasWidth = Math.round($slide[0].clientWidth); 3941 self.canvasHeight = Math.round($slide[0].clientHeight); 3942 3943 self.contentLastPos = null; 3944 self.contentStartPos = $.fancybox.getTranslate(self.$content) || { 3945 top: 0, 3946 left: 0 3947 }; 3948 self.sliderStartPos = $.fancybox.getTranslate($slide); 3949 3950 // Since position will be absolute, but we need to make it relative to the stage 3951 self.stagePos = $.fancybox.getTranslate(instance.$refs.stage); 3952 3953 self.sliderStartPos.top -= self.stagePos.top; 3954 self.sliderStartPos.left -= self.stagePos.left; 3955 3956 self.contentStartPos.top -= self.stagePos.top; 3957 self.contentStartPos.left -= self.stagePos.left; 3958 3959 $(document) 3960 .off(".fb.touch") 3961 .on(isTouchDevice ? "touchend.fb.touch touchcancel.fb.touch" : "mouseup.fb.touch mouseleave.fb.touch", $.proxy(self, "ontouchend")) 3962 .on(isTouchDevice ? "touchmove.fb.touch" : "mousemove.fb.touch", $.proxy(self, "ontouchmove")); 3963 3964 if ($.fancybox.isMobile) { 3965 document.addEventListener("scroll", self.onscroll, true); 3966 } 3967 3968 // Skip if clicked outside the sliding area 3969 if (!(self.opts || self.canPan) || !($target.is(self.$stage) || self.$stage.find($target).length)) { 3970 if ($target.is(".fancybox-image")) { 3971 e.preventDefault(); 3972 } 3973 3974 if (!($.fancybox.isMobile && $target.parents(".fancybox-caption").length)) { 3975 return; 3976 } 3977 } 3978 3979 self.isScrollable = isScrollable($target) || isScrollable($target.parent()); 3980 3981 // Check if element is scrollable and try to prevent default behavior (scrolling) 3982 if (!($.fancybox.isMobile && self.isScrollable)) { 3983 e.preventDefault(); 3984 } 3985 3986 // One finger or mouse click - swipe or pan an image 3987 if (self.startPoints.length === 1 || current.hasError) { 3988 if (self.canPan) { 3989 $.fancybox.stop(self.$content); 3990 3991 self.isPanning = true; 3992 } else { 3993 self.isSwiping = true; 3994 } 3995 3996 self.$container.addClass("fancybox-is-grabbing"); 3997 } 3998 3999 // Two fingers - zoom image 4000 if (self.startPoints.length === 2 && current.type === "image" && (current.isLoaded || current.$ghost)) { 4001 self.canTap = false; 4002 self.isSwiping = false; 4003 self.isPanning = false; 4004 4005 self.isZooming = true; 4006 4007 $.fancybox.stop(self.$content); 4008 4009 self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft(); 4010 self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop(); 4011 4012 self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width; 4013 self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height; 4014 4015 self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]); 4016 } 4017 }; 4018 4019 Guestures.prototype.onscroll = function (e) { 4020 var self = this; 4021 4022 self.isScrolling = true; 4023 4024 document.removeEventListener("scroll", self.onscroll, true); 4025 }; 4026 4027 Guestures.prototype.ontouchmove = function (e) { 4028 var self = this; 4029 4030 // Make sure user has not released over iframe or disabled element 4031 if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) { 4032 self.ontouchend(e); 4033 return; 4034 } 4035 4036 if (self.isScrolling) { 4037 self.canTap = false; 4038 return; 4039 } 4040 4041 self.newPoints = getPointerXY(e); 4042 4043 if (!(self.opts || self.canPan) || !self.newPoints.length || !self.newPoints.length) { 4044 return; 4045 } 4046 4047 if (!(self.isSwiping && self.isSwiping === true)) { 4048 e.preventDefault(); 4049 } 4050 4051 self.distanceX = distance(self.newPoints[0], self.startPoints[0], "x"); 4052 self.distanceY = distance(self.newPoints[0], self.startPoints[0], "y"); 4053 4054 self.distance = distance(self.newPoints[0], self.startPoints[0]); 4055 4056 // Skip false ontouchmove events (Chrome) 4057 if (self.distance > 0) { 4058 if (self.isSwiping) { 4059 self.onSwipe(e); 4060 } else if (self.isPanning) { 4061 self.onPan(); 4062 } else if (self.isZooming) { 4063 self.onZoom(); 4064 } 4065 } 4066 }; 4067 4068 Guestures.prototype.onSwipe = function (e) { 4069 var self = this, 4070 instance = self.instance, 4071 swiping = self.isSwiping, 4072 left = self.sliderStartPos.left || 0, 4073 angle; 4074 4075 // If direction is not yet determined 4076 if (swiping === true) { 4077 // We need at least 10px distance to correctly calculate an angle 4078 if (Math.abs(self.distance) > 10) { 4079 self.canTap = false; 4080 4081 if (instance.group.length < 2 && self.opts.vertical) { 4082 self.isSwiping = "y"; 4083 } else if (instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) { 4084 self.isSwiping = "x"; 4085 } else { 4086 angle = Math.abs((Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI); 4087 4088 self.isSwiping = angle > 45 && angle < 135 ? "y" : "x"; 4089 } 4090 4091 if (self.isSwiping === "y" && $.fancybox.isMobile && self.isScrollable) { 4092 self.isScrolling = true; 4093 4094 return; 4095 } 4096 4097 instance.isDragging = self.isSwiping; 4098 4099 // Reset points to avoid jumping, because we dropped first swipes to calculate the angle 4100 self.startPoints = self.newPoints; 4101 4102 $.each(instance.slides, function (index, slide) { 4103 var slidePos, stagePos; 4104 4105 $.fancybox.stop(slide.$slide); 4106 4107 slidePos = $.fancybox.getTranslate(slide.$slide); 4108 stagePos = $.fancybox.getTranslate(instance.$refs.stage); 4109 4110 slide.$slide 4111 .css({ 4112 transform: "", 4113 opacity: "", 4114 "transition-duration": "" 4115 }) 4116 .removeClass("fancybox-animated") 4117 .removeClass(function (index, className) { 4118 return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" "); 4119 }); 4120 4121 if (slide.pos === instance.current.pos) { 4122 self.sliderStartPos.top = slidePos.top - stagePos.top; 4123 self.sliderStartPos.left = slidePos.left - stagePos.left; 4124 } 4125 4126 $.fancybox.setTranslate(slide.$slide, { 4127 top: slidePos.top - stagePos.top, 4128 left: slidePos.left - stagePos.left 4129 }); 4130 }); 4131 4132 // Stop slideshow 4133 if (instance.SlideShow && instance.SlideShow.isActive) { 4134 instance.SlideShow.stop(); 4135 } 4136 } 4137 4138 return; 4139 } 4140 4141 // Sticky edges 4142 if (swiping == "x") { 4143 if ( 4144 self.distanceX > 0 && 4145 (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop)) 4146 ) { 4147 left = left + Math.pow(self.distanceX, 0.8); 4148 } else if ( 4149 self.distanceX < 0 && 4150 (self.instance.group.length < 2 || 4151 (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop)) 4152 ) { 4153 left = left - Math.pow(-self.distanceX, 0.8); 4154 } else { 4155 left = left + self.distanceX; 4156 } 4157 } 4158 4159 self.sliderLastPos = { 4160 top: swiping == "x" ? 0 : self.sliderStartPos.top + self.distanceY, 4161 left: left 4162 }; 4163 4164 if (self.requestId) { 4165 cancelAFrame(self.requestId); 4166 4167 self.requestId = null; 4168 } 4169 4170 self.requestId = requestAFrame(function () { 4171 if (self.sliderLastPos) { 4172 $.each(self.instance.slides, function (index, slide) { 4173 var pos = slide.pos - self.instance.currPos; 4174 4175 $.fancybox.setTranslate(slide.$slide, { 4176 top: self.sliderLastPos.top, 4177 left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter 4178 }); 4179 }); 4180 4181 self.$container.addClass("fancybox-is-sliding"); 4182 } 4183 }); 4184 }; 4185 4186 Guestures.prototype.onPan = function () { 4187 var self = this; 4188 4189 // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit) 4190 if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) { 4191 self.startPoints = self.newPoints; 4192 return; 4193 } 4194 4195 self.canTap = false; 4196 4197 self.contentLastPos = self.limitMovement(); 4198 4199 if (self.requestId) { 4200 cancelAFrame(self.requestId); 4201 } 4202 4203 self.requestId = requestAFrame(function () { 4204 $.fancybox.setTranslate(self.$content, self.contentLastPos); 4205 }); 4206 }; 4207 4208 // Make panning sticky to the edges 4209 Guestures.prototype.limitMovement = function () { 4210 var self = this; 4211 4212 var canvasWidth = self.canvasWidth; 4213 var canvasHeight = self.canvasHeight; 4214 4215 var distanceX = self.distanceX; 4216 var distanceY = self.distanceY; 4217 4218 var contentStartPos = self.contentStartPos; 4219 4220 var currentOffsetX = contentStartPos.left; 4221 var currentOffsetY = contentStartPos.top; 4222 4223 var currentWidth = contentStartPos.width; 4224 var currentHeight = contentStartPos.height; 4225 4226 var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY; 4227 4228 if (currentWidth > canvasWidth) { 4229 newOffsetX = currentOffsetX + distanceX; 4230 } else { 4231 newOffsetX = currentOffsetX; 4232 } 4233 4234 newOffsetY = currentOffsetY + distanceY; 4235 4236 // Slow down proportionally to traveled distance 4237 minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5); 4238 minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5); 4239 4240 maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5); 4241 maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5); 4242 4243 // -> 4244 if (distanceX > 0 && newOffsetX > minTranslateX) { 4245 newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0; 4246 } 4247 4248 // <- 4249 if (distanceX < 0 && newOffsetX < maxTranslateX) { 4250 newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0; 4251 } 4252 4253 // \/ 4254 if (distanceY > 0 && newOffsetY > minTranslateY) { 4255 newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0; 4256 } 4257 4258 // /\ 4259 if (distanceY < 0 && newOffsetY < maxTranslateY) { 4260 newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0; 4261 } 4262 4263 return { 4264 top: newOffsetY, 4265 left: newOffsetX 4266 }; 4267 }; 4268 4269 Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) { 4270 var self = this; 4271 4272 var canvasWidth = self.canvasWidth; 4273 var canvasHeight = self.canvasHeight; 4274 4275 if (newWidth > canvasWidth) { 4276 newOffsetX = newOffsetX > 0 ? 0 : newOffsetX; 4277 newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX; 4278 } else { 4279 // Center horizontally 4280 newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2); 4281 } 4282 4283 if (newHeight > canvasHeight) { 4284 newOffsetY = newOffsetY > 0 ? 0 : newOffsetY; 4285 newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY; 4286 } else { 4287 // Center vertically 4288 newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2); 4289 } 4290 4291 return { 4292 top: newOffsetY, 4293 left: newOffsetX 4294 }; 4295 }; 4296 4297 Guestures.prototype.onZoom = function () { 4298 var self = this; 4299 4300 // Calculate current distance between points to get pinch ratio and new width and height 4301 var contentStartPos = self.contentStartPos; 4302 4303 var currentWidth = contentStartPos.width; 4304 var currentHeight = contentStartPos.height; 4305 4306 var currentOffsetX = contentStartPos.left; 4307 var currentOffsetY = contentStartPos.top; 4308 4309 var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]); 4310 4311 var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers; 4312 4313 var newWidth = Math.floor(currentWidth * pinchRatio); 4314 var newHeight = Math.floor(currentHeight * pinchRatio); 4315 4316 // This is the translation due to pinch-zooming 4317 var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX; 4318 var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY; 4319 4320 // Point between the two touches 4321 var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft(); 4322 var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop(); 4323 4324 // And this is the translation due to translation of the centerpoint 4325 // between the two fingers 4326 var translateFromTranslatingX = centerPointEndX - self.centerPointStartX; 4327 var translateFromTranslatingY = centerPointEndY - self.centerPointStartY; 4328 4329 // The new offset is the old/current one plus the total translation 4330 var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX); 4331 var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY); 4332 4333 var newPos = { 4334 top: newOffsetY, 4335 left: newOffsetX, 4336 scaleX: pinchRatio, 4337 scaleY: pinchRatio 4338 }; 4339 4340 self.canTap = false; 4341 4342 self.newWidth = newWidth; 4343 self.newHeight = newHeight; 4344 4345 self.contentLastPos = newPos; 4346 4347 if (self.requestId) { 4348 cancelAFrame(self.requestId); 4349 } 4350 4351 self.requestId = requestAFrame(function () { 4352 $.fancybox.setTranslate(self.$content, self.contentLastPos); 4353 }); 4354 }; 4355 4356 Guestures.prototype.ontouchend = function (e) { 4357 var self = this; 4358 4359 var swiping = self.isSwiping; 4360 var panning = self.isPanning; 4361 var zooming = self.isZooming; 4362 var scrolling = self.isScrolling; 4363 4364 self.endPoints = getPointerXY(e); 4365 self.dMs = Math.max(new Date().getTime() - self.startTime, 1); 4366 4367 self.$container.removeClass("fancybox-is-grabbing"); 4368 4369 $(document).off(".fb.touch"); 4370 4371 document.removeEventListener("scroll", self.onscroll, true); 4372 4373 if (self.requestId) { 4374 cancelAFrame(self.requestId); 4375 4376 self.requestId = null; 4377 } 4378 4379 self.isSwiping = false; 4380 self.isPanning = false; 4381 self.isZooming = false; 4382 self.isScrolling = false; 4383 4384 self.instance.isDragging = false; 4385 4386 if (self.canTap) { 4387 return self.onTap(e); 4388 } 4389 4390 self.speed = 100; 4391 4392 // Speed in px/ms 4393 self.velocityX = (self.distanceX / self.dMs) * 0.5; 4394 self.velocityY = (self.distanceY / self.dMs) * 0.5; 4395 4396 if (panning) { 4397 self.endPanning(); 4398 } else if (zooming) { 4399 self.endZooming(); 4400 } else { 4401 self.endSwiping(swiping, scrolling); 4402 } 4403 4404 return; 4405 }; 4406 4407 Guestures.prototype.endSwiping = function (swiping, scrolling) { 4408 var self = this, 4409 ret = false, 4410 len = self.instance.group.length, 4411 distanceX = Math.abs(self.distanceX), 4412 canAdvance = swiping == "x" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50), 4413 speedX = 300; 4414 4415 self.sliderLastPos = null; 4416 4417 // Close if swiped vertically / navigate if horizontally 4418 if (swiping == "y" && !scrolling && Math.abs(self.distanceY) > 50) { 4419 // Continue vertical movement 4420 $.fancybox.animate( 4421 self.instance.current.$slide, { 4422 top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150, 4423 opacity: 0 4424 }, 4425 200 4426 ); 4427 ret = self.instance.close(true, 250); 4428 } else if (canAdvance && self.distanceX > 0) { 4429 ret = self.instance.previous(speedX); 4430 } else if (canAdvance && self.distanceX < 0) { 4431 ret = self.instance.next(speedX); 4432 } 4433 4434 if (ret === false && (swiping == "x" || swiping == "y")) { 4435 self.instance.centerSlide(200); 4436 } 4437 4438 self.$container.removeClass("fancybox-is-sliding"); 4439 }; 4440 4441 // Limit panning from edges 4442 // ======================== 4443 Guestures.prototype.endPanning = function () { 4444 var self = this, 4445 newOffsetX, 4446 newOffsetY, 4447 newPos; 4448 4449 if (!self.contentLastPos) { 4450 return; 4451 } 4452 4453 if (self.opts.momentum === false || self.dMs > 350) { 4454 newOffsetX = self.contentLastPos.left; 4455 newOffsetY = self.contentLastPos.top; 4456 } else { 4457 // Continue movement 4458 newOffsetX = self.contentLastPos.left + self.velocityX * 500; 4459 newOffsetY = self.contentLastPos.top + self.velocityY * 500; 4460 } 4461 4462 newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height); 4463 4464 newPos.width = self.contentStartPos.width; 4465 newPos.height = self.contentStartPos.height; 4466 4467 $.fancybox.animate(self.$content, newPos, 366); 4468 }; 4469 4470 Guestures.prototype.endZooming = function () { 4471 var self = this; 4472 4473 var current = self.instance.current; 4474 4475 var newOffsetX, newOffsetY, newPos, reset; 4476 4477 var newWidth = self.newWidth; 4478 var newHeight = self.newHeight; 4479 4480 if (!self.contentLastPos) { 4481 return; 4482 } 4483 4484 newOffsetX = self.contentLastPos.left; 4485 newOffsetY = self.contentLastPos.top; 4486 4487 reset = { 4488 top: newOffsetY, 4489 left: newOffsetX, 4490 width: newWidth, 4491 height: newHeight, 4492 scaleX: 1, 4493 scaleY: 1 4494 }; 4495 4496 // Reset scalex/scaleY values; this helps for perfomance and does not break animation 4497 $.fancybox.setTranslate(self.$content, reset); 4498 4499 if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) { 4500 self.instance.scaleToFit(150); 4501 } else if (newWidth > current.width || newHeight > current.height) { 4502 self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150); 4503 } else { 4504 newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight); 4505 4506 $.fancybox.animate(self.$content, newPos, 150); 4507 } 4508 }; 4509 4510 Guestures.prototype.onTap = function (e) { 4511 var self = this; 4512 var $target = $(e.target); 4513 4514 var instance = self.instance; 4515 var current = instance.current; 4516 4517 var endPoints = (e && getPointerXY(e)) || self.startPoints; 4518 4519 var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0; 4520 var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0; 4521 4522 var where; 4523 4524 var process = function (prefix) { 4525 var action = current.opts[prefix]; 4526 4527 if ($.isFunction(action)) { 4528 action = action.apply(instance, [current, e]); 4529 } 4530 4531 if (!action) { 4532 return; 4533 } 4534 4535 switch (action) { 4536 case "close": 4537 instance.close(self.startEvent); 4538 4539 break; 4540 4541 case "toggleControls": 4542 instance.toggleControls(); 4543 4544 break; 4545 4546 case "next": 4547 instance.next(); 4548 4549 break; 4550 4551 case "nextOrClose": 4552 if (instance.group.length > 1) { 4553 instance.next(); 4554 } else { 4555 instance.close(self.startEvent); 4556 } 4557 4558 break; 4559 4560 case "zoom": 4561 if (current.type == "image" && (current.isLoaded || current.$ghost)) { 4562 if (instance.canPan()) { 4563 instance.scaleToFit(); 4564 } else if (instance.isScaledDown()) { 4565 instance.scaleToActual(tapX, tapY); 4566 } else if (instance.group.length < 2) { 4567 instance.close(self.startEvent); 4568 } 4569 } 4570 4571 break; 4572 } 4573 }; 4574 4575 // Ignore right click 4576 if (e.originalEvent && e.originalEvent.button == 2) { 4577 return; 4578 } 4579 4580 // Skip if clicked on the scrollbar 4581 if (!$target.is("img") && tapX > $target[0].clientWidth + $target.offset().left) { 4582 return; 4583 } 4584 4585 // Check where is clicked 4586 if ($target.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container")) { 4587 where = "Outside"; 4588 } else if ($target.is(".fancybox-slide")) { 4589 where = "Slide"; 4590 } else if ( 4591 instance.current.$content && 4592 instance.current.$content 4593 .find($target) 4594 .addBack() 4595 .filter($target).length 4596 ) { 4597 where = "Content"; 4598 } else { 4599 return; 4600 } 4601 4602 // Check if this is a double tap 4603 if (self.tapped) { 4604 // Stop previously created single tap 4605 clearTimeout(self.tapped); 4606 self.tapped = null; 4607 4608 // Skip if distance between taps is too big 4609 if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) { 4610 return this; 4611 } 4612 4613 // OK, now we assume that this is a double-tap 4614 process("dblclick" + where); 4615 } else { 4616 // Single tap will be processed if user has not clicked second time within 300ms 4617 // or there is no need to wait for double-tap 4618 self.tapX = tapX; 4619 self.tapY = tapY; 4620 4621 if (current.opts["dblclick" + where] && current.opts["dblclick" + where] !== current.opts["click" + where]) { 4622 self.tapped = setTimeout(function () { 4623 self.tapped = null; 4624 4625 if (!instance.isAnimating) { 4626 process("click" + where); 4627 } 4628 }, 500); 4629 } else { 4630 process("click" + where); 4631 } 4632 } 4633 4634 return this; 4635 }; 4636 4637 $(document) 4638 .on("onActivate.fb", function (e, instance) { 4639 if (instance && !instance.Guestures) { 4640 instance.Guestures = new Guestures(instance); 4641 } 4642 }) 4643 .on("beforeClose.fb", function (e, instance) { 4644 if (instance && instance.Guestures) { 4645 instance.Guestures.destroy(); 4646 } 4647 }); 4648})(window, document, jQuery); 4649// ========================================================================== 4650// 4651// SlideShow 4652// Enables slideshow functionality 4653// 4654// Example of usage: 4655// $.fancybox.getInstance().SlideShow.start() 4656// 4657// ========================================================================== 4658(function (document, $) { 4659 "use strict"; 4660 4661 $.extend(true, $.fancybox.defaults, { 4662 btnTpl: { 4663 slideShow: '<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}">' + 4664 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.5 5.4v13.2l11-6.6z"/></svg>' + 4665 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.33 5.75h2.2v12.5h-2.2V5.75zm5.15 0h2.2v12.5h-2.2V5.75z"/></svg>' + 4666 "</button>" 4667 }, 4668 slideShow: { 4669 autoStart: false, 4670 speed: 3000, 4671 progress: true 4672 } 4673 }); 4674 4675 var SlideShow = function (instance) { 4676 this.instance = instance; 4677 this.init(); 4678 }; 4679 4680 $.extend(SlideShow.prototype, { 4681 timer: null, 4682 isActive: false, 4683 $button: null, 4684 4685 init: function () { 4686 var self = this, 4687 instance = self.instance, 4688 opts = instance.group[instance.currIndex].opts.slideShow; 4689 4690 self.$button = instance.$refs.toolbar.find("[data-fancybox-play]").on("click", function () { 4691 self.toggle(); 4692 }); 4693 4694 if (instance.group.length < 2 || !opts) { 4695 self.$button.hide(); 4696 } else if (opts.progress) { 4697 self.$progress = $('<div class="fancybox-progress"></div>').appendTo(instance.$refs.inner); 4698 } 4699 }, 4700 4701 set: function (force) { 4702 var self = this, 4703 instance = self.instance, 4704 current = instance.current; 4705 4706 // Check if reached last element 4707 if (current && (force === true || current.opts.loop || instance.currIndex < instance.group.length - 1)) { 4708 if (self.isActive && current.contentType !== "video") { 4709 if (self.$progress) { 4710 $.fancybox.animate(self.$progress.show(), { 4711 scaleX: 1 4712 }, current.opts.slideShow.speed); 4713 } 4714 4715 self.timer = setTimeout(function () { 4716 if (!instance.current.opts.loop && instance.current.index == instance.group.length - 1) { 4717 instance.jumpTo(0); 4718 } else { 4719 instance.next(); 4720 } 4721 }, current.opts.slideShow.speed); 4722 } 4723 } else { 4724 self.stop(); 4725 instance.idleSecondsCounter = 0; 4726 instance.showControls(); 4727 } 4728 }, 4729 4730 clear: function () { 4731 var self = this; 4732 4733 clearTimeout(self.timer); 4734 4735 self.timer = null; 4736 4737 if (self.$progress) { 4738 self.$progress.removeAttr("style").hide(); 4739 } 4740 }, 4741 4742 start: function () { 4743 var self = this, 4744 current = self.instance.current; 4745 4746 if (current) { 4747 self.$button 4748 .attr("title", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_STOP) 4749 .removeClass("fancybox-button--play") 4750 .addClass("fancybox-button--pause"); 4751 4752 self.isActive = true; 4753 4754 if (current.isComplete) { 4755 self.set(true); 4756 } 4757 4758 self.instance.trigger("onSlideShowChange", true); 4759 } 4760 }, 4761 4762 stop: function () { 4763 var self = this, 4764 current = self.instance.current; 4765 4766 self.clear(); 4767 4768 self.$button 4769 .attr("title", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_START) 4770 .removeClass("fancybox-button--pause") 4771 .addClass("fancybox-button--play"); 4772 4773 self.isActive = false; 4774 4775 self.instance.trigger("onSlideShowChange", false); 4776 4777 if (self.$progress) { 4778 self.$progress.removeAttr("style").hide(); 4779 } 4780 }, 4781 4782 toggle: function () { 4783 var self = this; 4784 4785 if (self.isActive) { 4786 self.stop(); 4787 } else { 4788 self.start(); 4789 } 4790 } 4791 }); 4792 4793 $(document).on({ 4794 "onInit.fb": function (e, instance) { 4795 if (instance && !instance.SlideShow) { 4796 instance.SlideShow = new SlideShow(instance); 4797 } 4798 }, 4799 4800 "beforeShow.fb": function (e, instance, current, firstRun) { 4801 var SlideShow = instance && instance.SlideShow; 4802 4803 if (firstRun) { 4804 if (SlideShow && current.opts.slideShow.autoStart) { 4805 SlideShow.start(); 4806 } 4807 } else if (SlideShow && SlideShow.isActive) { 4808 SlideShow.clear(); 4809 } 4810 }, 4811 4812 "afterShow.fb": function (e, instance, current) { 4813 var SlideShow = instance && instance.SlideShow; 4814 4815 if (SlideShow && SlideShow.isActive) { 4816 SlideShow.set(); 4817 } 4818 }, 4819 4820 "afterKeydown.fb": function (e, instance, current, keypress, keycode) { 4821 var SlideShow = instance && instance.SlideShow; 4822 4823 // "P" or Spacebar 4824 if (SlideShow && current.opts.slideShow && (keycode === 80 || keycode === 32) && !$(document.activeElement).is("button,a,input")) { 4825 keypress.preventDefault(); 4826 4827 SlideShow.toggle(); 4828 } 4829 }, 4830 4831 "beforeClose.fb onDeactivate.fb": function (e, instance) { 4832 var SlideShow = instance && instance.SlideShow; 4833 4834 if (SlideShow) { 4835 SlideShow.stop(); 4836 } 4837 } 4838 }); 4839 4840 // Page Visibility API to pause slideshow when window is not active 4841 $(document).on("visibilitychange", function () { 4842 var instance = $.fancybox.getInstance(), 4843 SlideShow = instance && instance.SlideShow; 4844 4845 if (SlideShow && SlideShow.isActive) { 4846 if (document.hidden) { 4847 SlideShow.clear(); 4848 } else { 4849 SlideShow.set(); 4850 } 4851 } 4852 }); 4853})(document, jQuery); 4854// ========================================================================== 4855// 4856// FullScreen 4857// Adds fullscreen functionality 4858// 4859// ========================================================================== 4860(function (document, $) { 4861 "use strict"; 4862 4863 // Collection of methods supported by user browser 4864 var fn = (function () { 4865 var fnMap = [ 4866 ["requestFullscreen", "exitFullscreen", "fullscreenElement", "fullscreenEnabled", "fullscreenchange", "fullscreenerror"], 4867 // new WebKit 4868 [ 4869 "webkitRequestFullscreen", 4870 "webkitExitFullscreen", 4871 "webkitFullscreenElement", 4872 "webkitFullscreenEnabled", 4873 "webkitfullscreenchange", 4874 "webkitfullscreenerror" 4875 ], 4876 // old WebKit (Safari 5.1) 4877 [ 4878 "webkitRequestFullScreen", 4879 "webkitCancelFullScreen", 4880 "webkitCurrentFullScreenElement", 4881 "webkitCancelFullScreen", 4882 "webkitfullscreenchange", 4883 "webkitfullscreenerror" 4884 ], 4885 [ 4886 "mozRequestFullScreen", 4887 "mozCancelFullScreen", 4888 "mozFullScreenElement", 4889 "mozFullScreenEnabled", 4890 "mozfullscreenchange", 4891 "mozfullscreenerror" 4892 ], 4893 ["msRequestFullscreen", "msExitFullscreen", "msFullscreenElement", "msFullscreenEnabled", "MSFullscreenChange", "MSFullscreenError"] 4894 ]; 4895 4896 var ret = {}; 4897 4898 for (var i = 0; i < fnMap.length; i++) { 4899 var val = fnMap[i]; 4900 4901 if (val && val[1] in document) { 4902 for (var j = 0; j < val.length; j++) { 4903 ret[fnMap[0][j]] = val[j]; 4904 } 4905 4906 return ret; 4907 } 4908 } 4909 4910 return false; 4911 })(); 4912 4913 if (fn) { 4914 var FullScreen = { 4915 request: function (elem) { 4916 elem = elem || document.documentElement; 4917 4918 elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT); 4919 }, 4920 exit: function () { 4921 document[fn.exitFullscreen](); 4922 }, 4923 toggle: function (elem) { 4924 elem = elem || document.documentElement; 4925 4926 if (this.isFullscreen()) { 4927 this.exit(); 4928 } else { 4929 this.request(elem); 4930 } 4931 }, 4932 isFullscreen: function () { 4933 return Boolean(document[fn.fullscreenElement]); 4934 }, 4935 enabled: function () { 4936 return Boolean(document[fn.fullscreenEnabled]); 4937 } 4938 }; 4939 4940 $.extend(true, $.fancybox.defaults, { 4941 btnTpl: { 4942 fullScreen: '<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fsenter" title="{{FULL_SCREEN}}">' + 4943 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>' + 4944 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 16h3v3h2v-5H5zm3-8H5v2h5V5H8zm6 11h2v-3h3v-2h-5zm2-11V5h-2v5h5V8z"/></svg>' + 4945 "</button>" 4946 }, 4947 fullScreen: { 4948 autoStart: false 4949 } 4950 }); 4951 4952 $(document).on(fn.fullscreenchange, function () { 4953 var isFullscreen = FullScreen.isFullscreen(), 4954 instance = $.fancybox.getInstance(); 4955 4956 if (instance) { 4957 // If image is zooming, then force to stop and reposition properly 4958 if (instance.current && instance.current.type === "image" && instance.isAnimating) { 4959 instance.isAnimating = false; 4960 4961 instance.update(true, true, 0); 4962 4963 if (!instance.isComplete) { 4964 instance.complete(); 4965 } 4966 } 4967 4968 instance.trigger("onFullscreenChange", isFullscreen); 4969 4970 instance.$refs.container.toggleClass("fancybox-is-fullscreen", isFullscreen); 4971 4972 instance.$refs.toolbar 4973 .find("[data-fancybox-fullscreen]") 4974 .toggleClass("fancybox-button--fsenter", !isFullscreen) 4975 .toggleClass("fancybox-button--fsexit", isFullscreen); 4976 } 4977 }); 4978 } 4979 4980 $(document).on({ 4981 "onInit.fb": function (e, instance) { 4982 var $container; 4983 4984 if (!fn) { 4985 instance.$refs.toolbar.find("[data-fancybox-fullscreen]").remove(); 4986 4987 return; 4988 } 4989 4990 if (instance && instance.group[instance.currIndex].opts.fullScreen) { 4991 $container = instance.$refs.container; 4992 4993 $container.on("click.fb-fullscreen", "[data-fancybox-fullscreen]", function (e) { 4994 e.stopPropagation(); 4995 e.preventDefault(); 4996 4997 FullScreen.toggle(); 4998 }); 4999 5000 if (instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true) { 5001 FullScreen.request(); 5002 } 5003 5004 // Expose API 5005 instance.FullScreen = FullScreen; 5006 } else if (instance) { 5007 instance.$refs.toolbar.find("[data-fancybox-fullscreen]").hide(); 5008 } 5009 }, 5010 5011 "afterKeydown.fb": function (e, instance, current, keypress, keycode) { 5012 // "F" 5013 if (instance && instance.FullScreen && keycode === 70) { 5014 keypress.preventDefault(); 5015 5016 instance.FullScreen.toggle(); 5017 } 5018 }, 5019 5020 "beforeClose.fb": function (e, instance) { 5021 if (instance && instance.FullScreen && instance.$refs.container.hasClass("fancybox-is-fullscreen")) { 5022 FullScreen.exit(); 5023 } 5024 } 5025 }); 5026})(document, jQuery); 5027// ========================================================================== 5028// 5029// Thumbs 5030// Displays thumbnails in a grid 5031// 5032// ========================================================================== 5033(function (document, $) { 5034 "use strict"; 5035 5036 var CLASS = "fancybox-thumbs", 5037 CLASS_ACTIVE = CLASS + "-active"; 5038 5039 // Make sure there are default values 5040 $.fancybox.defaults = $.extend( 5041 true, { 5042 btnTpl: { 5043 thumbs: '<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}">' + 5044 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.59 14.59h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76H5.65V5.65z"/></svg>' + 5045 "</button>" 5046 }, 5047 thumbs: { 5048 autoStart: false, // Display thumbnails on opening 5049 hideOnClose: true, // Hide thumbnail grid when closing animation starts 5050 parentEl: ".fancybox-container", // Container is injected into this element 5051 axis: "y" // Vertical (y) or horizontal (x) scrolling 5052 } 5053 }, 5054 $.fancybox.defaults 5055 ); 5056 5057 var FancyThumbs = function (instance) { 5058 this.init(instance); 5059 }; 5060 5061 $.extend(FancyThumbs.prototype, { 5062 $button: null, 5063 $grid: null, 5064 $list: null, 5065 isVisible: false, 5066 isActive: false, 5067 5068 init: function (instance) { 5069 var self = this, 5070 group = instance.group, 5071 enabled = 0; 5072 5073 self.instance = instance; 5074 self.opts = group[instance.currIndex].opts.thumbs; 5075 5076 instance.Thumbs = self; 5077 5078 self.$button = instance.$refs.toolbar.find("[data-fancybox-thumbs]"); 5079 5080 // Enable thumbs if at least two group items have thumbnails 5081 for (var i = 0, len = group.length; i < len; i++) { 5082 if (group[i].thumb) { 5083 enabled++; 5084 } 5085 5086 if (enabled > 1) { 5087 break; 5088 } 5089 } 5090 5091 if (enabled > 1 && !!self.opts) { 5092 self.$button.removeAttr("style").on("click", function () { 5093 self.toggle(); 5094 }); 5095 5096 self.isActive = true; 5097 } else { 5098 self.$button.hide(); 5099 } 5100 }, 5101 5102 create: function () { 5103 var self = this, 5104 instance = self.instance, 5105 parentEl = self.opts.parentEl, 5106 list = [], 5107 src; 5108 5109 if (!self.$grid) { 5110 // Create main element 5111 self.$grid = $('<div class="' + CLASS + " " + CLASS + "-" + self.opts.axis + '"></div>').appendTo( 5112 instance.$refs.container 5113 .find(parentEl) 5114 .addBack() 5115 .filter(parentEl) 5116 ); 5117 5118 // Add "click" event that performs gallery navigation 5119 self.$grid.on("click", "a", function () { 5120 instance.jumpTo($(this).attr("data-index")); 5121 }); 5122 } 5123 5124 // Build the list 5125 if (!self.$list) { 5126 self.$list = $('<div class="' + CLASS + '__list">').appendTo(self.$grid); 5127 } 5128 5129 $.each(instance.group, function (i, item) { 5130 src = item.thumb; 5131 5132 if (!src && item.type === "image") { 5133 src = item.src; 5134 } 5135 5136 list.push( 5137 '<a href="javascript:;" tabindex="0" data-index="' + 5138 i + 5139 '"' + 5140 (src && src.length ? ' style="background-image:url(' + src + ')"' : 'class="fancybox-thumbs-missing"') + 5141 "></a>" 5142 ); 5143 }); 5144 5145 self.$list[0].innerHTML = list.join(""); 5146 5147 if (self.opts.axis === "x") { 5148 // Set fixed width for list element to enable horizontal scrolling 5149 self.$list.width( 5150 parseInt(self.$grid.css("padding-right"), 10) + 5151 instance.group.length * 5152 self.$list 5153 .children() 5154 .eq(0) 5155 .outerWidth(true) 5156 ); 5157 } 5158 }, 5159 5160 focus: function (duration) { 5161 var self = this, 5162 $list = self.$list, 5163 $grid = self.$grid, 5164 thumb, 5165 thumbPos; 5166 5167 if (!self.instance.current) { 5168 return; 5169 } 5170 5171 thumb = $list 5172 .children() 5173 .removeClass(CLASS_ACTIVE) 5174 .filter('[data-index="' + self.instance.current.index + '"]') 5175 .addClass(CLASS_ACTIVE); 5176 5177 thumbPos = thumb.position(); 5178 5179 // Check if need to scroll to make current thumb visible 5180 if (self.opts.axis === "y" && (thumbPos.top < 0 || thumbPos.top > $list.height() - thumb.outerHeight())) { 5181 $list.stop().animate({ 5182 scrollTop: $list.scrollTop() + thumbPos.top 5183 }, 5184 duration 5185 ); 5186 } else if ( 5187 self.opts.axis === "x" && 5188 (thumbPos.left < $grid.scrollLeft() || thumbPos.left > $grid.scrollLeft() + ($grid.width() - thumb.outerWidth())) 5189 ) { 5190 $list 5191 .parent() 5192 .stop() 5193 .animate({ 5194 scrollLeft: thumbPos.left 5195 }, 5196 duration 5197 ); 5198 } 5199 }, 5200 5201 update: function () { 5202 var that = this; 5203 that.instance.$refs.container.toggleClass("fancybox-show-thumbs", this.isVisible); 5204 5205 if (that.isVisible) { 5206 if (!that.$grid) { 5207 that.create(); 5208 } 5209 5210 that.instance.trigger("onThumbsShow"); 5211 5212 that.focus(0); 5213 } else if (that.$grid) { 5214 that.instance.trigger("onThumbsHide"); 5215 } 5216 5217 // Update content position 5218 that.instance.update(); 5219 }, 5220 5221 hide: function () { 5222 this.isVisible = false; 5223 this.update(); 5224 }, 5225 5226 show: function () { 5227 this.isVisible = true; 5228 this.update(); 5229 }, 5230 5231 toggle: function () { 5232 this.isVisible = !this.isVisible; 5233 this.update(); 5234 } 5235 }); 5236 5237 $(document).on({ 5238 "onInit.fb": function (e, instance) { 5239 var Thumbs; 5240 5241 if (instance && !instance.Thumbs) { 5242 Thumbs = new FancyThumbs(instance); 5243 5244 if (Thumbs.isActive && Thumbs.opts.autoStart === true) { 5245 Thumbs.show(); 5246 } 5247 } 5248 }, 5249 5250 "beforeShow.fb": function (e, instance, item, firstRun) { 5251 var Thumbs = instance && instance.Thumbs; 5252 5253 if (Thumbs && Thumbs.isVisible) { 5254 Thumbs.focus(firstRun ? 0 : 250); 5255 } 5256 }, 5257 5258 "afterKeydown.fb": function (e, instance, current, keypress, keycode) { 5259 var Thumbs = instance && instance.Thumbs; 5260 5261 // "G" 5262 if (Thumbs && Thumbs.isActive && keycode === 71) { 5263 keypress.preventDefault(); 5264 5265 Thumbs.toggle(); 5266 } 5267 }, 5268 5269 "beforeClose.fb": function (e, instance) { 5270 var Thumbs = instance && instance.Thumbs; 5271 5272 if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) { 5273 Thumbs.$grid.hide(); 5274 } 5275 } 5276 }); 5277})(document, jQuery); 5278//// ========================================================================== 5279// 5280// Share 5281// Displays simple form for sharing current url 5282// 5283// ========================================================================== 5284(function (document, $) { 5285 "use strict"; 5286 5287 $.extend(true, $.fancybox.defaults, { 5288 btnTpl: { 5289 share: '<button data-fancybox-share class="fancybox-button fancybox-button--share" title="{{SHARE}}">' + 5290 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2.55 19c1.4-8.4 9.1-9.8 11.9-9.8V5l7 7-7 6.3v-3.5c-2.8 0-10.5 2.1-11.9 4.2z"/></svg>' + 5291 "</button>" 5292 }, 5293 share: { 5294 url: function (instance, item) { 5295 return ( 5296 (!instance.currentHash && !(item.type === "inline" || item.type === "html") ? item.origSrc || item.src : false) || window.location 5297 ); 5298 }, 5299 tpl: '<div class="fancybox-share">' + 5300 "<h1>{{SHARE}}</h1>" + 5301 "<p>" + 5302 '<a class="fancybox-share__button fancybox-share__button--fb" href="https://www.facebook.com/sharer/sharer.php?u={{url}}">' + 5303 '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m287 456v-299c0-21 6-35 35-35h38v-63c-7-1-29-3-55-3-54 0-91 33-91 94v306m143-254h-205v72h196" /></svg>' + 5304 "<span>Facebook</span>" + 5305 "</a>" + 5306 '<a class="fancybox-share__button fancybox-share__button--tw" href="https://twitter.com/intent/tweet?url={{url}}&text={{descr}}">' + 5307 '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 133c-14 7-31 11-47 13 17-10 30-27 37-46-15 10-34 16-52 20-61-62-157-7-141 75-68-3-129-35-169-85-22 37-11 86 26 109-13 0-26-4-37-9 0 39 28 72 65 80-12 3-25 4-37 2 10 33 41 57 77 57-42 30-77 38-122 34 170 111 378-32 359-208 16-11 30-25 41-42z" /></svg>' + 5308 "<span>Twitter</span>" + 5309 "</a>" + 5310 '<a class="fancybox-share__button fancybox-share__button--pt" href="https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}">' + 5311 '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m265 56c-109 0-164 78-164 144 0 39 15 74 47 87 5 2 10 0 12-5l4-19c2-6 1-8-3-13-9-11-15-25-15-45 0-58 43-110 113-110 62 0 96 38 96 88 0 67-30 122-73 122-24 0-42-19-36-44 6-29 20-60 20-81 0-19-10-35-31-35-25 0-44 26-44 60 0 21 7 36 7 36l-30 125c-8 37-1 83 0 87 0 3 4 4 5 2 2-3 32-39 42-75l16-64c8 16 31 29 56 29 74 0 124-67 124-157 0-69-58-132-146-132z" fill="#fff"/></svg>' + 5312 "<span>Pinterest</span>" + 5313 "</a>" + 5314 "</p>" + 5315 '<p><input class="fancybox-share__input" type="text" value="{{url_raw}}" onclick="select()" /></p>' + 5316 "</div>" 5317 } 5318 }); 5319 5320 function escapeHtml(string) { 5321 var entityMap = { 5322 "&": "&", 5323 "<": "<", 5324 ">": ">", 5325 '"': """, 5326 "'": "'", 5327 "/": "/", 5328 "`": "`", 5329 "=": "=" 5330 }; 5331 5332 return String(string).replace(/[&<>"'`=\/]/g, function (s) { 5333 return entityMap[s]; 5334 }); 5335 } 5336 5337 $(document).on("click", "[data-fancybox-share]", function () { 5338 var instance = $.fancybox.getInstance(), 5339 current = instance.current || null, 5340 url, 5341 tpl; 5342 5343 if (!current) { 5344 return; 5345 } 5346 5347 if ($.type(current.opts.share.url) === "function") { 5348 url = current.opts.share.url.apply(current, [instance, current]); 5349 } 5350 5351 tpl = current.opts.share.tpl 5352 .replace(/\{\{media\}\}/g, current.type === "image" ? encodeURIComponent(current.src) : "") 5353 .replace(/\{\{url\}\}/g, encodeURIComponent(url)) 5354 .replace(/\{\{url_raw\}\}/g, escapeHtml(url)) 5355 .replace(/\{\{descr\}\}/g, instance.$caption ? encodeURIComponent(instance.$caption.text()) : ""); 5356 5357 $.fancybox.open({ 5358 src: instance.translate(instance, tpl), 5359 type: "html", 5360 opts: { 5361 touch: false, 5362 animationEffect: false, 5363 afterLoad: function (shareInstance, shareCurrent) { 5364 // Close self if parent instance is closing 5365 instance.$refs.container.one("beforeClose.fb", function () { 5366 shareInstance.close(null, 0); 5367 }); 5368 5369 // Opening links in a popup window 5370 shareCurrent.$content.find(".fancybox-share__button").click(function () { 5371 window.open(this.href, "Share", "width=550, height=450"); 5372 return false; 5373 }); 5374 }, 5375 mobile: { 5376 autoFocus: false 5377 } 5378 } 5379 }); 5380 }); 5381})(document, jQuery); 5382// ========================================================================== 5383// 5384// Hash 5385// Enables linking to each modal 5386// 5387// ========================================================================== 5388(function (window, document, $) { 5389 "use strict"; 5390 5391 // Simple $.escapeSelector polyfill (for jQuery prior v3) 5392 if (!$.escapeSelector) { 5393 $.escapeSelector = function (sel) { 5394 var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; 5395 var fcssescape = function (ch, asCodePoint) { 5396 if (asCodePoint) { 5397 // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER 5398 if (ch === "\0") { 5399 return "\uFFFD"; 5400 } 5401 5402 // Control characters and (dependent upon position) numbers get escaped as code points 5403 return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " "; 5404 } 5405 5406 // Other potentially-special ASCII characters get backslash-escaped 5407 return "\\" + ch; 5408 }; 5409 5410 return (sel + "").replace(rcssescape, fcssescape); 5411 }; 5412 } 5413 5414 // Get info about gallery name and current index from url 5415 function parseUrl() { 5416 var hash = window.location.hash.substr(1), 5417 rez = hash.split("-"), 5418 index = rez.length > 1 && /^\+?\d+$/.test(rez[rez.length - 1]) ? parseInt(rez.pop(-1), 10) || 1 : 1, 5419 gallery = rez.join("-"); 5420 5421 return { 5422 hash: hash, 5423 /* Index is starting from 1 */ 5424 index: index < 1 ? 1 : index, 5425 gallery: gallery 5426 }; 5427 } 5428 5429 // Trigger click evnt on links to open new fancyBox instance 5430 function triggerFromUrl(url) { 5431 if (url.gallery !== "") { 5432 // If we can find element matching 'data-fancybox' atribute, 5433 // then triggering click event should start fancyBox 5434 $("[data-fancybox='" + $.escapeSelector(url.gallery) + "']") 5435 .eq(url.index - 1) 5436 .focus() 5437 .trigger("click.fb-start"); 5438 } 5439 } 5440 5441 // Get gallery name from current instance 5442 function getGalleryID(instance) { 5443 var opts, ret; 5444 5445 if (!instance) { 5446 return false; 5447 } 5448 5449 opts = instance.current ? instance.current.opts : instance.opts; 5450 ret = opts.hash || (opts.$orig ? opts.$orig.data("fancybox") || opts.$orig.data("fancybox-trigger") : ""); 5451 5452 return ret === "" ? false : ret; 5453 } 5454 5455 // Start when DOM becomes ready 5456 $(function () { 5457 // Check if user has disabled this module 5458 if ($.fancybox.defaults.hash === false) { 5459 return; 5460 } 5461 5462 // Update hash when opening/closing fancyBox 5463 $(document).on({ 5464 "onInit.fb": function (e, instance) { 5465 var url, gallery; 5466 5467 if (instance.group[instance.currIndex].opts.hash === false) { 5468 return; 5469 } 5470 5471 url = parseUrl(); 5472 gallery = getGalleryID(instance); 5473 5474 // Make sure gallery start index matches index from hash 5475 if (gallery && url.gallery && gallery == url.gallery) { 5476 instance.currIndex = url.index - 1; 5477 } 5478 }, 5479 5480 "beforeShow.fb": function (e, instance, current, firstRun) { 5481 var gallery; 5482 5483 if (!current || current.opts.hash === false) { 5484 return; 5485 } 5486 5487 // Check if need to update window hash 5488 gallery = getGalleryID(instance); 5489 5490 if (!gallery) { 5491 return; 5492 } 5493 5494 // Variable containing last hash value set by fancyBox 5495 // It will be used to determine if fancyBox needs to close after hash change is detected 5496 instance.currentHash = gallery + (instance.group.length > 1 ? "-" + (current.index + 1) : ""); 5497 5498 // If current hash is the same (this instance most likely is opened by hashchange), then do nothing 5499 if (window.location.hash === "#" + instance.currentHash) { 5500 return; 5501 } 5502 5503 if (firstRun && !instance.origHash) { 5504 instance.origHash = window.location.hash; 5505 } 5506 5507 if (instance.hashTimer) { 5508 clearTimeout(instance.hashTimer); 5509 } 5510 5511 // Update hash 5512 instance.hashTimer = setTimeout(function () { 5513 if ("replaceState" in window.history) { 5514 window.history[firstRun ? "pushState" : "replaceState"]({}, 5515 document.title, 5516 window.location.pathname + window.location.search + "#" + instance.currentHash 5517 ); 5518 5519 if (firstRun) { 5520 instance.hasCreatedHistory = true; 5521 } 5522 } else { 5523 window.location.hash = instance.currentHash; 5524 } 5525 5526 instance.hashTimer = null; 5527 }, 300); 5528 }, 5529 5530 "beforeClose.fb": function (e, instance, current) { 5531 if (!current || current.opts.hash === false) { 5532 return; 5533 } 5534 5535 clearTimeout(instance.hashTimer); 5536 5537 // Goto previous history entry 5538 if (instance.currentHash && instance.hasCreatedHistory) { 5539 window.history.back(); 5540 } else if (instance.currentHash) { 5541 if ("replaceState" in window.history) { 5542 window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (instance.origHash || "")); 5543 } else { 5544 window.location.hash = instance.origHash; 5545 } 5546 } 5547 5548 instance.currentHash = null; 5549 } 5550 }); 5551 5552 // Check if need to start/close after url has changed 5553 $(window).on("hashchange.fb", function () { 5554 var url = parseUrl(), 5555 fb = null; 5556 5557 // Find last fancyBox instance that has "hash" 5558 $.each( 5559 $(".fancybox-container") 5560 .get() 5561 .reverse(), 5562 function (index, value) { 5563 var tmp = $(value).data("FancyBox"); 5564 5565 if (tmp && tmp.currentHash) { 5566 fb = tmp; 5567 return false; 5568 } 5569 } 5570 ); 5571 5572 if (fb) { 5573 // Now, compare hash values 5574 if (fb.currentHash !== url.gallery + "-" + url.index && !(url.index === 1 && fb.currentHash == url.gallery)) { 5575 fb.currentHash = null; 5576 5577 fb.close(); 5578 } 5579 } else if (url.gallery !== "") { 5580 triggerFromUrl(url); 5581 } 5582 }); 5583 5584 // Check current hash and trigger click event on matching element to start fancyBox, if needed 5585 setTimeout(function () { 5586 if (!$.fancybox.getInstance()) { 5587 triggerFromUrl(parseUrl()); 5588 } 5589 }, 50); 5590 }); 5591})(window, document, jQuery); 5592// ========================================================================== 5593// 5594// Wheel 5595// Basic mouse weheel support for gallery navigation 5596// 5597// ========================================================================== 5598(function (document, $) { 5599 "use strict"; 5600 5601 var prevTime = new Date().getTime(); 5602 5603 $(document).on({ 5604 "onInit.fb": function (e, instance, current) { 5605 instance.$refs.stage.on("mousewheel DOMMouseScroll wheel MozMousePixelScroll", function (e) { 5606 var current = instance.current, 5607 currTime = new Date().getTime(); 5608 5609 if (instance.group.length < 2 || current.opts.wheel === false || (current.opts.wheel === "auto" && current.type !== "image")) { 5610 return; 5611 } 5612 5613 e.preventDefault(); 5614 e.stopPropagation(); 5615 5616 if (current.$slide.hasClass("fancybox-animated")) { 5617 return; 5618 } 5619 5620 e = e.originalEvent || e; 5621 5622 if (currTime - prevTime < 250) { 5623 return; 5624 } 5625 5626 prevTime = currTime; 5627 5628 instance[(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0 ? "next" : "previous"](); 5629 }); 5630 } 5631 }); 5632})(document, jQuery); 5633/*! 5634 * Hook To - jQuery plugin 5635 * Move an element to another 5636 * with responsive back-in-place 5637 * @name jquery.hookto.js 5638 * @author Guillaume Bouillon <[email protected]> (Agence'O) 5639 * @see {@link https://github.com/Sade/jquery.hookTo|GitHub} 5640 * @usage (JS style) $('#element').hookTo('#hook-destination', {option_object, ...}); 5641 * @usage (DOM style) <element data-hook-to="#hook-destination" data-hook-to-return="pixel_value">...</element> 5642 */ 5643(function ($) { 5644 /** 5645 * The jQuery plugin namespace. 5646 * @external "jQuery.fn" 5647 * @see {@link http://docs.jquery.com/Plugins/Authoring The jQuery Plugin Guide} 5648 */ 5649 5650 /** 5651 * Hook To - jQuery plugin 5652 * @function external:"jQuery.fn".hookTo 5653 * @param destinationHook 5654 * @param {Object} options 5655 * @return {Array|Object|string|*} 5656 */ 5657 $.fn.hookTo = function (destinationHook, options) { 5658 5659 var _plugin = this; 5660 var settings = $.extend({ 5661 'hookOriginPrefix': 'hookto-orig', 5662 'position': 'after', 5663 'returnAt': '768', 5664 'mobileFirst': true, 5665 'onInit': function () { 5666 }, 5667 'onHook': function () { 5668 }, 5669 'onUnhook': function () { 5670 } 5671 }, options); 5672 5673 /** 5674 * Initialization of the plugin 5675 * @callback onInit 5676 * @param el 5677 */ 5678 _plugin.init = function (el) { 5679 var $element = $(el); 5680 var origHash = settings.hookOriginPrefix + '-' + _plugin.getHash(); 5681 var $origHook = $('<meta />').addClass('hookto-orig').attr({'id': origHash}); 5682 5683 $element.data({'hookedTo': origHash}); 5684 5685 $origHook.insertBefore($element); 5686 _plugin.setPosition(settings.position); 5687 5688 $(window).resize(function () { 5689 var condition = false;
5690 if (settings.mobileFirst) { 5691 condition = $(window).outerWidth(true) <= settings.returnAt; 5692 } else { 5693 condition = $(window).outerWidth(true) >= settings.returnAt; 5694 } 5695 5696 if (condition) { 5697 _plugin.retrievePosition($element); 5698 } else { 5699 _plugin.setPosition(settings.position); 5700 } 5701 5702 }).resize(); 5703 5704 settings.onInit.call($element); 5705 }; 5706 5707 /** 5708 * The element is hooked to its destination hook 5709 * @callback onHook 5710 * @param {String} position 5711 */ 5712 _plugin.setPosition = function (position) { 5713 switch (position) { 5714 case 'default': 5715 case 'after': 5716 $(this).insertAfter(destinationHook); 5717 break; 5718 case 'before': 5719 $(this).insertBefore(destinationHook); 5720 break; 5721 case 'inside': 5722 $(this).appendTo(destinationHook); 5723 break; 5724 } 5725 5726 settings.onHook.call($(this)); 5727 }; 5728 5729 /** 5730 * The hooked element return to its previous position 5731 * @callback onUnhook 5732 * @param {Object} el 5733 */ 5734 _plugin.retrievePosition = function (el) { 5735 var destination = $('#' + el.data('hookedTo')); 5736 if (destination[0] !== el.prev()[0]) { 5737 destination.after(el); 5738 } 5739 5740 settings.onUnhook.call(el); 5741 }; 5742 5743 /** 5744 * Get Hashed string name 5745 * @return {String} 5746 */ 5747 _plugin.getHash = function () { 5748 var random = ""; 5749 var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 5750 for (var i = 0; i < 12; i++) { 5751 random += possible.charAt(Math.floor(Math.random() * possible.length)); 5752 } 5753 5754 return random; 5755 }; 5756 5757 /** 5758 * Loop over all elements 5759 */ 5760 return this.each(function () { 5761 _plugin.init(this); 5762 }); 5763 }; 5764 5765 /** 5766 * Get all item with date attribute "hook-to" 5767 */ 5768 $('[data-hook-to]').each(function () { 5769 var hook = $(this).data('hookTo'); 5770 var options = {}; 5771 if ($(this).data('hookTo-return')) { 5772 $.extend(options, {'returnAt': $(this).data('hookTo-return')}); 5773 } 5774 if ($(this).data('hookTo-position')) { 5775 $.extend(options, {'position': $(this).data('hookTo-position')}); 5776 } 5777 if ($(this).data('hookTo-mobileFirst') !== '') { 5778 $.extend(options, {'mobileFirst': $(this).data('hookTo-mobileFirst')}); 5779 } 5780 if ($(this).data('hookTo-hookOriginPrefix')) { 5781 $.extend(options, {'hookOriginPrefix': $(this).data('hookTo-hookOriginPrefix')}); 5782 } 5783 5784 $(this).hookTo(hook, options); 5785 }); 5786 5787})(jQuery); 5788 5789/** 5790* jquery-match-height 0.7.2 by @liabru 5791* http://brm.io/jquery-match-height/ 5792* License: MIT 5793*/ 5794 5795;(function(factory) { // eslint-disable-line no-extra-semi 5796 'use strict'; 5797 if (typeof define === 'function' && define.amd) { 5798 // AMD 5799 define(['jquery'], factory); 5800 } else if (typeof module !== 'undefined' && module.exports) { 5801 // CommonJS 5802 module.exports = factory(require('jquery')); 5803 } else { 5804 // Global 5805 factory(jQuery); 5806 } 5807})(function($) { 5808 /* 5809 * internal 5810 */ 5811 5812 var _previousResizeWidth = -1, 5813 _updateTimeout = -1; 5814 5815 /* 5816 * _parse 5817 * value parse utility function 5818 */ 5819 5820 var _parse = function(value) { 5821 // parse value and convert NaN to 0 5822 return parseFloat(value) || 0; 5823 }; 5824 5825 /* 5826 * _rows 5827 * utility function returns array of jQuery selections representing each row 5828 * (as displayed after float wrapping applied by browser) 5829 */ 5830 5831 var _rows = function(elements) { 5832 var tolerance = 1, 5833 $elements = $(elements), 5834 lastTop = null, 5835 rows = []; 5836 5837 // group elements by their top position 5838 $elements.each(function(){ 5839 var $that = $(this), 5840 top = $that.offset().top - _parse($that.css('margin-top')), 5841 lastRow = rows.length > 0 ? rows[rows.length - 1] : null; 5842 5843 if (lastRow === null) { 5844 // first item on the row, so just push it 5845 rows.push($that); 5846 } else { 5847 // if the row top is the same, add to the row group 5848 if (Math.floor(Math.abs(lastTop - top)) <= tolerance) { 5849 rows[rows.length - 1] = lastRow.add($that); 5850 } else { 5851 // otherwise start a new row group 5852 rows.push($that); 5853 } 5854 } 5855 5856 // keep track of the last row top 5857 lastTop = top; 5858 }); 5859 5860 return rows; 5861 }; 5862 5863 /* 5864 * _parseOptions 5865 * handle plugin options 5866 */ 5867 5868 var _parseOptions = function(options) { 5869 var opts = { 5870 byRow: true, 5871 property: 'height', 5872 target: null, 5873 remove: false 5874 }; 5875 5876 if (typeof options === 'object') { 5877 return $.extend(opts, options); 5878 } 5879 5880 if (typeof options === 'boolean') { 5881 opts.byRow = options; 5882 } else if (options === 'remove') { 5883 opts.remove = true; 5884 } 5885 5886 return opts; 5887 }; 5888 5889 /* 5890 * matchHeight 5891 * plugin definition 5892 */ 5893 5894 var matchHeight = $.fn.matchHeight = function(options) { 5895 var opts = _parseOptions(options); 5896 5897 // handle remove 5898 if (opts.remove) { 5899 var that = this; 5900 5901 // remove fixed height from all selected elements 5902 this.css(opts.property, ''); 5903 5904 // remove selected elements from all groups 5905 $.each(matchHeight._groups, function(key, group) { 5906 group.elements = group.elements.not(that); 5907 }); 5908 5909 // TODO: cleanup empty groups 5910 5911 return this; 5912 } 5913 5914 if (this.length <= 1 && !opts.target) { 5915 return this; 5916 } 5917 5918 // keep track of this group so we can re-apply later on load and resize events 5919 matchHeight._groups.push({ 5920 elements: this, 5921 options: opts 5922 }); 5923 5924 // match each element's height to the tallest element in the selection 5925 matchHeight._apply(this, opts); 5926 5927 return this; 5928 }; 5929 5930 /* 5931 * plugin global options 5932 */ 5933 5934 matchHeight.version = '0.7.2'; 5935 matchHeight._groups = []; 5936 matchHeight._throttle = 80; 5937 matchHeight._maintainScroll = false;
vendor: 8,569 bytes, lines 5938-6197
5938 matchHeight._beforeUpdate = null; 5939 matchHeight._afterUpdate = null; 5940 matchHeight._rows = _rows; 5941 matchHeight._parse = _parse; 5942 matchHeight._parseOptions = _parseOptions; 5943 5944 /* 5945 * matchHeight._apply 5946 * apply matchHeight to given elements 5947 */ 5948 5949 matchHeight._apply = function(elements, options) { 5950 var opts = _parseOptions(options), 5951 $elements = $(elements), 5952 rows = [$elements]; 5953 5954 // take note of scroll position 5955 var scrollTop = $(window).scrollTop(), 5956 htmlHeight = $('html').outerHeight(true); 5957 5958 // get hidden parents 5959 var $hiddenParents = $elements.parents().filter(':hidden'); 5960 5961 // cache the original inline style 5962 $hiddenParents.each(function() { 5963 var $that = $(this); 5964 $that.data('style-cache', $that.attr('style')); 5965 }); 5966 5967 // temporarily must force hidden parents visible 5968 $hiddenParents.css('display', 'block'); 5969 5970 // get rows if using byRow, otherwise assume one row 5971 if (opts.byRow && !opts.target) { 5972 5973 // must first force an arbitrary equal height so floating elements break evenly 5974 $elements.each(function() { 5975 var $that = $(this), 5976 display = $that.css('display'); 5977 5978 // temporarily force a usable display value 5979 if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') { 5980 display = 'block'; 5981 } 5982 5983 // cache the original inline style 5984 $that.data('style-cache', $that.attr('style')); 5985 5986 $that.css({ 5987 'display': display, 5988 'padding-top': '0', 5989 'padding-bottom': '0', 5990 'margin-top': '0', 5991 'margin-bottom': '0', 5992 'border-top-width': '0', 5993 'border-bottom-width': '0', 5994 'height': '100px', 5995 'overflow': 'hidden' 5996 }); 5997 }); 5998 5999 // get the array of rows (based on element top position) 6000 rows = _rows($elements); 6001 6002 // revert original inline styles 6003 $elements.each(function() { 6004 var $that = $(this); 6005 $that.attr('style', $that.data('style-cache') || ''); 6006 }); 6007 } 6008 6009 $.each(rows, function(key, row) { 6010 var $row = $(row), 6011 targetHeight = 0; 6012 6013 if (!opts.target) { 6014 // skip apply to rows with only one item 6015 if (opts.byRow && $row.length <= 1) { 6016 $row.css(opts.property, ''); 6017 return; 6018 } 6019 6020 // iterate the row and find the max height 6021 $row.each(function(){ 6022 var $that = $(this), 6023 style = $that.attr('style'), 6024 display = $that.css('display'); 6025 6026 // temporarily force a usable display value 6027 if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') { 6028 display = 'block'; 6029 } 6030 6031 // ensure we get the correct actual height (and not a previously set height value) 6032 var css = { 'display': display }; 6033 css[opts.property] = ''; 6034 $that.css(css); 6035 6036 // find the max height (including padding, but not margin) 6037 if ($that.outerHeight(false) > targetHeight) { 6038 targetHeight = $that.outerHeight(false); 6039 } 6040 6041 // revert styles 6042 if (style) { 6043 $that.attr('style', style); 6044 } else { 6045 $that.css('display', ''); 6046 } 6047 }); 6048 } else { 6049 // if target set, use the height of the target element 6050 targetHeight = opts.target.outerHeight(false); 6051 } 6052 6053 // iterate the row and apply the height to all elements 6054 $row.each(function(){ 6055 var $that = $(this), 6056 verticalPadding = 0; 6057 6058 // don't apply to a target 6059 if (opts.target && $that.is(opts.target)) { 6060 return; 6061 } 6062 6063 // handle padding and border correctly (required when not using border-box) 6064 if ($that.css('box-sizing') !== 'border-box') { 6065 verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width')); 6066 verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom')); 6067 } 6068 6069 // set the height (accounting for padding and border) 6070 $that.css(opts.property, (targetHeight - verticalPadding) + 'px'); 6071 }); 6072 }); 6073 6074 // revert hidden parents 6075 $hiddenParents.each(function() { 6076 var $that = $(this); 6077 $that.attr('style', $that.data('style-cache') || null); 6078 }); 6079 6080 // restore scroll position if enabled 6081 if (matchHeight._maintainScroll) { 6082 $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true)); 6083 } 6084 6085 return this; 6086 }; 6087 6088 /* 6089 * matchHeight._applyDataApi 6090 * applies matchHeight to all elements with a data-match-height attribute 6091 */ 6092 6093 matchHeight._applyDataApi = function() { 6094 var groups = {}; 6095 6096 // generate groups by their groupId set by elements using data-match-height 6097 $('[data-match-height], [data-mh]').each(function() { 6098 var $this = $(this), 6099 groupId = $this.attr('data-mh') || $this.attr('data-match-height'); 6100 6101 if (groupId in groups) { 6102 groups[groupId] = groups[groupId].add($this); 6103 } else { 6104 groups[groupId] = $this; 6105 } 6106 }); 6107 6108 // apply matchHeight to each group 6109 $.each(groups, function() { 6110 this.matchHeight(true); 6111 }); 6112 }; 6113 6114 /* 6115 * matchHeight._update 6116 * updates matchHeight on all current groups with their correct options 6117 */ 6118 6119 var _update = function(event) { 6120 if (matchHeight._beforeUpdate) { 6121 matchHeight._beforeUpdate(event, matchHeight._groups); 6122 } 6123 6124 $.each(matchHeight._groups, function() { 6125 matchHeight._apply(this.elements, this.options); 6126 }); 6127 6128 if (matchHeight._afterUpdate) { 6129 matchHeight._afterUpdate(event, matchHeight._groups); 6130 } 6131 }; 6132 6133 matchHeight._update = function(throttle, event) { 6134 // prevent update if fired from a resize event 6135 // where the viewport width hasn't actually changed 6136 // fixes an event looping bug in IE8 6137 if (event && event.type === 'resize') { 6138 var windowWidth = $(window).width(); 6139 if (windowWidth === _previousResizeWidth) { 6140 return; 6141 } 6142 _previousResizeWidth = windowWidth; 6143 } 6144 6145 // throttle updates 6146 if (!throttle) { 6147 _update(event); 6148 } else if (_updateTimeout === -1) { 6149 _updateTimeout = setTimeout(function() { 6150 _update(event); 6151 _updateTimeout = -1; 6152 }, matchHeight._throttle); 6153 } 6154 }; 6155 6156 /* 6157 * bind events 6158 */ 6159 6160 // apply on DOM ready event 6161 $(matchHeight._applyDataApi); 6162 6163 // use on or bind where supported 6164 var on = $.fn.on ? 'on' : 'bind'; 6165 6166 // update heights on load and resize events 6167 $(window)[on]('load', function(event) { 6168 matchHeight._update(false, event); 6169 }); 6170 6171 // throttled update heights on resize events 6172 $(window)[on]('resize orientationchange', function(event) { 6173 matchHeight._update(true, event); 6174 }); 6175 6176}); 6177 6178/*! jQuery-QuickSearch - v2.4.0 - 2017-08-15 6179* https://deuxhuithuit.github.io/quicksearch/ 6180* Copyright (c) 2013 Deux Huit Huit, Rik Lomas. 6181* Copyright (c) 2017 Deux Huit Huit (https://deuxhuithuit.com/); 6182* License MIT http://deuxhuithuit.mit-license.org */ 6183(function ($, global, undefined) { 6184 'use strict'; 6185 6186 $.quicksearch = { 6187 defaults: { 6188 delay: 100, 6189 selector: null, 6190 stripeRows: null, 6191 loader: null, 6192 caseSensitive: false, 6193 noResults: '', 6194 matchedResultsCount: 0, 6195 keyCode : false, 6196 bind: 'keyup search input', 6197 resetBind: 'reset',
6198 removeDiacritics: false, 6199 minValLength: 0, 6200 onBefore: $.noop, 6201 onAfter: $.noop, 6202 onValTooSmall: $.noop, 6203 onNoResultFound: null, 6204 show: function () { 6205 $(this).show(); 6206 }, 6207 hide: function () { 6208 $(this).hide(); 6209 }, 6210 prepareQuery: function (val) { 6211 return val.toLowerCase().split(' '); 6212 }, 6213 testQuery: function (query, txt, _row) { 6214 for (var i = 0; i < query.length; i += 1) { 6215 if (txt.indexOf(query[i]) === -1) { 6216 return false; 6217 } 6218 } 6219 return true; 6220 } 6221 }, 6222 diacriticsRemovalMap: [ 6223 {'base':'A', 'letters':/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g}, 6224 {'base':'AA','letters':/[\uA732]/g}, 6225 {'base':'AE','letters':/[\u00C6\u01FC\u01E2]/g}, 6226 {'base':'AO','letters':/[\uA734]/g}, 6227 {'base':'AU','letters':/[\uA736]/g}, 6228 {'base':'AV','letters':/[\uA738\uA73A]/g}, 6229 {'base':'AY','letters':/[\uA73C]/g}, 6230 {'base':'B', 'letters':/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g}, 6231 {'base':'C', 'letters':/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g}, 6232 {'base':'D', 'letters':/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g}, 6233 {'base':'DZ','letters':/[\u01F1\u01C4]/g}, 6234 {'base':'Dz','letters':/[\u01F2\u01C5]/g}, 6235 {'base':'E', 'letters':/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g}, 6236 {'base':'F', 'letters':/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g}, 6237 {'base':'G', 'letters':/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g}, 6238 {'base':'H', 'letters':/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g}, 6239 {'base':'I', 'letters':/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g}, 6240 {'base':'J', 'letters':/[\u004A\u24BF\uFF2A\u0134\u0248]/g}, 6241 {'base':'K', 'letters':/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g}, 6242 {'base':'L', 'letters':/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g}, 6243 {'base':'LJ','letters':/[\u01C7]/g}, 6244 {'base':'Lj','letters':/[\u01C8]/g}, 6245 {'base':'M', 'letters':/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g}, 6246 {'base':'N', 'letters':/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g}, 6247 {'base':'NJ','letters':/[\u01CA]/g}, 6248 {'base':'Nj','letters':/[\u01CB]/g}, 6249 {'base':'O', 'letters':/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g}, 6250 {'base':'OI','letters':/[\u01A2]/g}, 6251 {'base':'OO','letters':/[\uA74E]/g}, 6252 {'base':'OU','letters':/[\u0222]/g}, 6253 {'base':'P', 'letters':/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g}, 6254 {'base':'Q', 'letters':/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g}, 6255 {'base':'R', 'letters':/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g}, 6256 {'base':'S', 'letters':/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g}, 6257 {'base':'T', 'letters':/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g}, 6258 {'base':'TZ','letters':/[\uA728]/g}, 6259 {'base':'U', 'letters':/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g}, 6260 {'base':'V', 'letters':/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g}, 6261 {'base':'VY','letters':/[\uA760]/g}, 6262 {'base':'W', 'letters':/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g}, 6263 {'base':'X', 'letters':/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g}, 6264 {'base':'Y', 'letters':/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g}, 6265 {'base':'Z', 'letters':/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g}, 6266 {'base':'a', 'letters':/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g}, 6267 {'base':'aa','letters':/[\uA733]/g}, 6268 {'base':'ae','letters':/[\u00E6\u01FD\u01E3]/g}, 6269 {'base':'ao','letters':/[\uA735]/g}, 6270 {'base':'au','letters':/[\uA737]/g}, 6271 {'base':'av','letters':/[\uA739\uA73B]/g}, 6272 {'base':'ay','letters':/[\uA73D]/g}, 6273 {'base':'b', 'letters':/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g}, 6274 {'base':'c', 'letters':/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g}, 6275 {'base':'d', 'letters':/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g}, 6276 {'base':'dz','letters':/[\u01F3\u01C6]/g},
6277 {'base':'e', 'letters':/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g}, 6278 {'base':'f', 'letters':/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g}, 6279 {'base':'g', 'letters':/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g}, 6280 {'base':'h', 'letters':/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g}, 6281 {'base':'hv','letters':/[\u0195]/g}, 6282 {'base':'i', 'letters':/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g}, 6283 {'base':'j', 'letters':/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g}, 6284 {'base':'k', 'letters':/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g}, 6285 {'base':'l', 'letters':/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g}, 6286 {'base':'lj','letters':/[\u01C9]/g}, 6287 {'base':'m', 'letters':/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g}, 6288 {'base':'n', 'letters':/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g}, 6289 {'base':'nj','letters':/[\u01CC]/g}, 6290 {'base':'o', 'letters':/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g}, 6291 {'base':'oi','letters':/[\u01A3]/g}, 6292 {'base':'ou','letters':/[\u0223]/g}, 6293 {'base':'oo','letters':/[\uA74F]/g}, 6294 {'base':'p','letters':/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g}, 6295 {'base':'q','letters':/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g}, 6296 {'base':'r','letters':/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g}, 6297 {'base':'s','letters':/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g}, 6298 {'base':'t','letters':/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g}, 6299 {'base':'tz','letters':/[\uA729]/g}, 6300 {'base':'u','letters':/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g}, 6301 {'base':'v','letters':/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g}, 6302 {'base':'vy','letters':/[\uA761]/g}, 6303 {'base':'w','letters':/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g}, 6304 {'base':'x','letters':/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g}, 6305 {'base':'y','letters':/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g}, 6306 {'base':'z','letters':/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g} 6307 ] 6308 }; 6309 6310 $.fn.quicksearch = function (target, opt) { 6311 6312 this.removeDiacritics = function(str) { 6313 var changes = $.quicksearch.diacriticsRemovalMap; 6314 for(var i=0; i<changes.length; i++) { 6315 str = str.replace(changes[i].letters, changes[i].base); 6316 } 6317 return str; 6318 }; 6319 6320 var timeout, cache, rowcache, jq_results, val = '', last_val = '', self = this, 6321 options = $.extend({}, $.quicksearch.defaults, opt); 6322 6323 // Assure selectors 6324 options.noResults = !options.noResults ? $() : $(options.noResults); 6325 options.loader = !options.loader ? $() : $(options.loader); 6326 6327 this.go = function () { 6328 6329 var i = 0, 6330 len = 0, 6331 numMatchedRows = 0, 6332 noresults = true, 6333 query, 6334 val_empty = (val.replace(' ', '').length === 0); 6335 6336 if (options.removeDiacritics) { 6337 val = self.removeDiacritics(val); 6338 } 6339 6340 query = options.prepareQuery(val); 6341 6342 for (i = 0, len = rowcache.length; i < len; i++) { 6343 if (query.length > 0 && query[0].length < options.minValLength) { 6344 options.show.apply(rowcache[i]); 6345 noresults = false;
6346 numMatchedRows++; 6347 } else if (val_empty || options.testQuery(query, cache[i], rowcache[i])) { 6348 options.show.apply(rowcache[i]); 6349 noresults = false; 6350 numMatchedRows++; 6351 } else { 6352 options.hide.apply(rowcache[i]); 6353 } 6354 } 6355 6356 if (noresults) { 6357 if($.isFunction(options.onNoResultFound)){ 6358 options.onNoResultFound(this); 6359 }else{ 6360 this.results(false); 6361 } 6362 6363 } else { 6364 this.results(true); 6365 this.stripe(); 6366 } 6367 6368 this.matchedResultsCount = numMatchedRows; 6369 this.loader(false); 6370 options.onAfter.call(this); 6371 last_val = val; 6372 return this; 6373 }; 6374 6375 /* 6376 * External API so that users can perform search programatically. 6377 * */ 6378 this.search = function (submittedVal) { 6379 val = submittedVal; 6380 self.trigger(); 6381 }; 6382 6383 /* 6384 * External API so that users can perform search programatically. 6385 * */ 6386 this.reset = function () { 6387 val = ''; 6388 this.loader(true); 6389 options.onBefore.call(this); 6390 global.clearTimeout(timeout); 6391 timeout = global.setTimeout(function () { 6392 self.go(); 6393 }, options.delay); 6394 }; 6395 6396 /* 6397 * External API to get the number of matched results as seen in 6398 * https://github.com/ruiz107/quicksearch/commit/f78dc440b42d95ce9caed1d087174dd4359982d6 6399 * */ 6400 this.currentMatchedResults = function() { 6401 return this.matchedResultsCount; 6402 }; 6403 6404 this.stripe = function () { 6405 6406 if (typeof options.stripeRows === "object" && options.stripeRows !== null) { 6407 var joined = options.stripeRows.join(' '); 6408 var stripeRows_length = options.stripeRows.length; 6409 6410 jq_results.not(':hidden').each(function (i) { 6411 $(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]); 6412 }); 6413 } 6414 6415 return this; 6416 }; 6417 6418 this.strip_html = function (input) { 6419 var output = input.replace(new RegExp('<[^<]+\\>', 'g'), ' '); 6420 if (!options.caseSensitive) { 6421 output = output.toLowerCase(); 6422 } 6423 output = $.trim(output); 6424 return output; 6425 }; 6426 6427 this.results = function (bool) { 6428 if (!!options.noResults.length) { 6429 options.noResults[bool ? 'hide' : 'show'](); 6430 } 6431 6432 return this; 6433 }; 6434 6435 this.loader = function (bool) { 6436 if (!!options.loader.length) { 6437 options.loader[bool ? 'show' : 'hide'](); 6438 } 6439 6440 return this; 6441 }; 6442 6443 this.cache = function (doRedraw) { 6444 6445 doRedraw = (typeof doRedraw === "undefined") ? true : doRedraw; 6446 6447 jq_results = $(target).not(options.noResults); 6448 6449 if (typeof options.selector === "string") { 6450 cache = jq_results.map(function() { 6451 return $(this).find(options.selector).map(function() { 6452 var temp = self.strip_html(this.innerHTML); 6453 return options.removeDiacritics ? self.removeDiacritics(temp) : temp; 6454 }).get().join(" "); 6455 }); 6456 } else { 6457 cache = jq_results.map(function () { 6458 var temp = self.strip_html(this.innerHTML); 6459 return options.removeDiacritics ? self.removeDiacritics(temp) : temp; 6460 }); 6461 } 6462 6463 rowcache = jq_results.map(function () { 6464 return this; 6465 }); 6466 6467 /* 6468 * Modified fix for sync-ing "val". 6469 * Original fix https://github.com/michaellwest/quicksearch/commit/4ace4008d079298a01f97f885ba8fa956a9703d1 6470 * */ 6471 val = val || this.val() || ""; 6472 6473 if (doRedraw) { 6474 this.go(); 6475 } 6476 6477 return this; 6478 }; 6479 6480 this.trigger = function () { 6481 if ((val.length < options.minValLength && val.length > last_val.length) || (val.length < options.minValLength-1 && val.length < last_val.length)) { 6482 options.onValTooSmall.call(this, val); 6483 self.go(); 6484 } else { 6485 this.loader(true); 6486 options.onBefore.call(this); 6487 global.clearTimeout(timeout); 6488 timeout = global.setTimeout(function () { 6489 self.go(); 6490 }, options.delay); 6491 } 6492 6493 return this; 6494 }; 6495 6496 this.cache(); 6497 this.stripe(); 6498 this.loader(false); 6499 6500 return this.each(function () { 6501 $(this).on(options.bind, function (e) { 6502 if (options.keyCode) { 6503 var keycode = e.keyCode || e.which; 6504 if (keycode === options.keyCode) { 6505 val = $(this).val(); 6506 self.trigger(); 6507 } 6508 } else { 6509 val = $(this).val(); 6510 self.trigger(); 6511 } 6512 }); 6513 6514 $(this).on(options.resetBind, function () { 6515 val = ''; 6516 self.reset(); 6517 }); 6518 }); 6519 }; 6520
6521 // node export 6522 if (global.module && global.module.exports) { 6523 module.exports = $.fn.quicksearch; 6524 } 6525 6526})(jQuery, window || global); 6527 6528/**! 6529 * MixItUp v3.3.1 6530 * A high-performance, dependency-free library for animated filtering, sorting and more 6531 * Build 94e0fbf6-cd0b-4987-b3c0-14b59b67b8a0 6532 * 6533 * @copyright Copyright 2014-2018 KunkaLabs Limited. 6534 * @author KunkaLabs Limited. 6535 * @link https://www.kunkalabs.com/mixitup/ 6536 * 6537 * @license Commercial use requires a commercial license. 6538 * https://www.kunkalabs.com/mixitup/licenses/ 6539 * 6540 * Non-commercial use permitted under same terms as CC BY-NC 3.0 license. 6541 * http://creativecommons.org/licenses/by-nc/3.0/
vendor: 52,211 bytes, lines 6541-8321
6541 6542 */ 6543 6544(function(window) { 6545 'use strict'; 6546 6547 var mixitup = null, 6548 h = null; 6549 6550 (function() { 6551 var VENDORS = ['webkit', 'moz', 'o', 'ms'], 6552 canary = window.document.createElement('div'), 6553 i = -1; 6554 6555 // window.requestAnimationFrame 6556 6557 for (i = 0; i < VENDORS.length && !window.requestAnimationFrame; i++) { 6558 window.requestAnimationFrame = window[VENDORS[i] + 'RequestAnimationFrame']; 6559 } 6560 6561 // Element.nextElementSibling 6562 6563 if (typeof canary.nextElementSibling === 'undefined') { 6564 Object.defineProperty(window.Element.prototype, 'nextElementSibling', { 6565 get: function() { 6566 var el = this.nextSibling; 6567 6568 while (el) { 6569 if (el.nodeType === 1) { 6570 return el; 6571 } 6572 6573 el = el.nextSibling; 6574 } 6575 6576 return null; 6577 } 6578 }); 6579 } 6580 6581 // Element.matches 6582 6583 (function(ElementPrototype) { 6584 ElementPrototype.matches = 6585 ElementPrototype.matches || 6586 ElementPrototype.machesSelector || 6587 ElementPrototype.mozMatchesSelector || 6588 ElementPrototype.msMatchesSelector || 6589 ElementPrototype.oMatchesSelector || 6590 ElementPrototype.webkitMatchesSelector || 6591 function (selector) { 6592 return Array.prototype.indexOf.call(this.parentElement.querySelectorAll(selector), this) > -1; 6593 }; 6594 })(window.Element.prototype); 6595 6596 // Object.keys 6597 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys 6598 6599 if (!Object.keys) { 6600 Object.keys = (function() { 6601 var hasOwnProperty = Object.prototype.hasOwnProperty, 6602 hasDontEnumBug = false, 6603 dontEnums = [], 6604 dontEnumsLength = -1; 6605 6606 hasDontEnumBug = !({ 6607 toString: null 6608 }) 6609 .propertyIsEnumerable('toString'); 6610 6611 dontEnums = [ 6612 'toString', 6613 'toLocaleString', 6614 'valueOf', 6615 'hasOwnProperty', 6616 'isPrototypeOf', 6617 'propertyIsEnumerable', 6618 'constructor' 6619 ]; 6620 6621 dontEnumsLength = dontEnums.length; 6622 6623 return function(obj) { 6624 var result = [], 6625 prop = '', 6626 i = -1; 6627 6628 if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { 6629 throw new TypeError('Object.keys called on non-object'); 6630 } 6631 6632 for (prop in obj) { 6633 if (hasOwnProperty.call(obj, prop)) { 6634 result.push(prop); 6635 } 6636 } 6637 6638 if (hasDontEnumBug) { 6639 for (i = 0; i < dontEnumsLength; i++) { 6640 if (hasOwnProperty.call(obj, dontEnums[i])) { 6641 result.push(dontEnums[i]); 6642 } 6643 } 6644 } 6645 6646 return result; 6647 }; 6648 }()); 6649 } 6650 6651 // Array.isArray 6652 // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray 6653 6654 if (!Array.isArray) { 6655 Array.isArray = function(arg) { 6656 return Object.prototype.toString.call(arg) === '[object Array]'; 6657 }; 6658 } 6659 6660 // Object.create 6661 // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create 6662 6663 if (typeof Object.create !== 'function') { 6664 Object.create = (function(undefined) { 6665 var Temp = function() {}; 6666 6667 return function (prototype, propertiesObject) { 6668 if (prototype !== Object(prototype) && prototype !== null) { 6669 throw TypeError('Argument must be an object, or null'); 6670 } 6671 6672 Temp.prototype = prototype || {}; 6673 6674 var result = new Temp(); 6675 6676 Temp.prototype = null; 6677 6678 if (propertiesObject !== undefined) { 6679 Object.defineProperties(result, propertiesObject); 6680 } 6681 6682 if (prototype === null) { 6683 /* jshint ignore:start */ 6684 result.__proto__ = null; 6685 /* jshint ignore:end */ 6686 } 6687 6688 return result; 6689 }; 6690 })(); 6691 } 6692 6693 // String.prototyoe.trim 6694 6695 if (!String.prototype.trim) { 6696 String.prototype.trim = function() { 6697 return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); 6698 }; 6699 } 6700 6701 // Array.prototype.indexOf 6702 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf 6703 6704 if (!Array.prototype.indexOf) { 6705 Array.prototype.indexOf = function(searchElement) { 6706 var n, k, t, len; 6707 6708 if (this === null) { 6709 throw new TypeError(); 6710 } 6711 6712 t = Object(this); 6713 6714 len = t.length >>> 0; 6715 6716 if (len === 0) { 6717 return -1; 6718 } 6719 6720 n = 0; 6721 6722 if (arguments.length > 1) { 6723 n = Number(arguments[1]); 6724 6725 if (n !== n) { 6726 n = 0; 6727 } else if (n !== 0 && n !== Infinity && n !== -Infinity) { 6728 n = (n > 0 || -1) * Math.floor(Math.abs(n)); 6729 } 6730 } 6731 6732 if (n >= len) { 6733 return -1; 6734 } 6735 6736 for (k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); k < len; k++) { 6737 if (k in t && t[k] === searchElement) { 6738 return k; 6739 } 6740 } 6741 6742 return -1; 6743 }; 6744 } 6745 6746 // Function.prototype.bind 6747 // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind 6748 6749 if (!Function.prototype.bind) { 6750 Function.prototype.bind = function(oThis) { 6751 var aArgs, self, FNOP, fBound; 6752 6753 if (typeof this !== 'function') { 6754 throw new TypeError(); 6755 } 6756 6757 aArgs = Array.prototype.slice.call(arguments, 1); 6758 6759 self = this; 6760 6761 FNOP = function() {}; 6762 6763 fBound = function() { 6764 return self.apply(this instanceof FNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); 6765 }; 6766 6767 if (this.prototype) { 6768 FNOP.prototype = this.prototype; 6769 } 6770 6771 fBound.prototype = new FNOP(); 6772 6773 return fBound; 6774 }; 6775 } 6776 6777 // Element.prototype.dispatchEvent 6778 6779 if (!window.Element.prototype.dispatchEvent) { 6780 window.Element.prototype.dispatchEvent = function(event) { 6781 try { 6782 return this.fireEvent('on' + event.type, event); 6783 } catch (err) {} 6784 }; 6785 } 6786 })(); 6787 6788 /** 6789 * The `mixitup()` "factory" function creates and returns individual instances 6790 * of MixItUp, known as "mixers", on which API methods can be called. 6791 * 6792 * When loading MixItUp via a script tag, the factory function is accessed 6793 * via the global variable `mixitup`. When using a module loading 6794 * system (e.g. ES2015, CommonJS, RequireJS), the factory function is 6795 * exported into your module when you require the MixItUp library. 6796 * 6797 * @example 6798 * mixitup(container [,config] [,foreignDoc]) 6799 * 6800 * @example <caption>Example 1: Creating a mixer instance with an element reference</caption> 6801 * var containerEl = document.querySelector('.container'); 6802 * 6803 * var mixer = mixitup(containerEl); 6804 * 6805 * @example <caption>Example 2: Creating a mixer instance with a selector string</caption> 6806 * var mixer = mixitup('.container'); 6807 * 6808 * @example <caption>Example 3: Passing a configuration object</caption> 6809 * var mixer = mixitup(containerEl, { 6810 * animation: { 6811 * effects: 'fade scale(0.5)' 6812 * } 6813 * }); 6814 * 6815 * @example <caption>Example 4: Passing an iframe reference</caption> 6816 * var mixer = mixitup(containerEl, config, foreignDocument); 6817 * 6818 * @global 6819 * @namespace 6820 * @public 6821 * @kind function 6822 * @since 3.0.0 6823 * @param {(Element|string)} container 6824 * A DOM element or selector string representing the container(s) on which to instantiate MixItUp. 6825 * @param {object} [config] 6826 * An optional "configuration object" used to customize the behavior of the MixItUp instance. 6827 * @param {object} [foreignDoc] 6828 * An optional reference to a `document`, which can be used to control a MixItUp instance in an iframe. 6829 * @return {mixitup.Mixer} 6830 * A "mixer" object holding the MixItUp instance. 6831 */ 6832 6833 mixitup = function(container, config, foreignDoc) { 6834 var el = null, 6835 returnCollection = false, 6836 instance = null, 6837 facade = null, 6838 doc = null, 6839 output = null, 6840 instances = [], 6841 id = '', 6842 elements = [], 6843 i = -1; 6844 6845 doc = foreignDoc || window.document; 6846 6847 if (returnCollection = arguments[3]) { 6848 // A non-documented 4th paramater enabling control of multiple instances 6849 6850 returnCollection = typeof returnCollection === 'boolean'; 6851 } 6852 6853 if (typeof container === 'string') { 6854 elements = doc.querySelectorAll(container); 6855 } else if (container && typeof container === 'object' && h.isElement(container, doc)) { 6856 elements = [container]; 6857 } else if (container && typeof container === 'object' && container.length) { 6858 // Although not documented, the container may also be an array-like list of 6859 // elements such as a NodeList or jQuery collection, is returnCollection is true 6860 6861 elements = container; 6862 } else { 6863 throw new Error(mixitup.messages.errorFactoryInvalidContainer()); 6864 } 6865 6866 if (elements.length < 1) { 6867 throw new Error(mixitup.messages.errorFactoryContainerNotFound()); 6868 } 6869 6870 for (i = 0; el = elements[i]; i++) { 6871 if (i > 0 && !returnCollection) break; 6872 6873 if (!el.id) { 6874 id = 'MixItUp' + h.randomHex(); 6875 6876 el.id = id; 6877 } else { 6878 id = el.id; 6879 } 6880 6881 if (mixitup.instances[id] instanceof mixitup.Mixer) { 6882 instance = mixitup.instances[id]; 6883 6884 if (!config || (config && config.debug && config.debug.showWarnings !== false)) { 6885 console.warn(mixitup.messages.warningFactoryPreexistingInstance()); 6886 } 6887 } else { 6888 instance = new mixitup.Mixer(); 6889 6890 instance.attach(el, doc, id, config); 6891 6892 mixitup.instances[id] = instance; 6893 } 6894 6895 facade = new mixitup.Facade(instance); 6896 6897 if (config && config.debug && config.debug.enable) { 6898 instances.push(instance); 6899 } else { 6900 instances.push(facade); 6901 } 6902 } 6903 6904 if (returnCollection) { 6905 output = new mixitup.Collection(instances); 6906 } else { 6907 // Return the first instance regardless 6908 6909 output = instances[0]; 6910 } 6911 6912 return output; 6913 }; 6914 6915 /** 6916 * The `.use()` static method is used to extend the functionality of mixitup with compatible 6917 * extensions and libraries in an environment with modular scoping e.g. ES2015, CommonJS, or RequireJS. 6918 * 6919 * You need only call the `.use()` function once per project, per extension, as module loaders 6920 * will cache a single reference to MixItUp inclusive of all changes made. 6921 * 6922 * @example 6923 * mixitup.use(extension) 6924 * 6925 * @example <caption>Example 1: Extending MixItUp with the Pagination Extension</caption> 6926 * 6927 * import mixitup from 'mixitup'; 6928 * import mixitupPagination from 'mixitup-pagination'; 6929 * 6930 * mixitup.use(mixitupPagination); 6931 * 6932 * // All mixers created by the factory function in all modules will now 6933 * // have pagination functionality 6934 * 6935 * var mixer = mixitup('.container'); 6936 * 6937 * @public 6938 * @name use 6939 * @memberof mixitup 6940 * @kind function 6941 * @static 6942 * @since 3.0.0 6943 * @param {*} extension A reference to the extension or library to be used. 6944 * @return {void} 6945 */ 6946 6947 mixitup.use = function(extension) { 6948 mixitup.Base.prototype.callActions.call(mixitup, 'beforeUse', arguments); 6949 6950 // Call the extension's factory function, passing 6951 // the mixitup factory as a paramater 6952 6953 if (typeof extension === 'function' && extension.TYPE === 'mixitup-extension') { 6954 // Mixitup extension 6955 6956 if (typeof mixitup.extensions[extension.NAME] === 'undefined') { 6957 extension(mixitup); 6958 6959 mixitup.extensions[extension.NAME] = extension; 6960 } 6961 } else if (extension.fn && extension.fn.jquery) { 6962 // jQuery 6963 6964 mixitup.libraries.$ = extension; 6965 } 6966 6967 mixitup.Base.prototype.callActions.call(mixitup, 'afterUse', arguments); 6968 }; 6969 6970 mixitup.instances = {}; 6971 mixitup.extensions = {}; 6972 mixitup.libraries = {}; 6973 6974 /** 6975 * @private 6976 */ 6977 6978 h = { 6979 6980 /** 6981 * @private 6982 * @param {HTMLElement} el 6983 * @param {string} cls 6984 * @return {boolean} 6985 */ 6986 6987 hasClass: function(el, cls) { 6988 return !!el.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')); 6989 }, 6990 6991 /** 6992 * @private 6993 * @param {HTMLElement} el 6994 * @param {string} cls 6995 * @return {void} 6996 */ 6997 6998 addClass: function(el, cls) { 6999 if (!this.hasClass(el, cls)) el.className += el.className ? ' ' + cls : cls; 7000 }, 7001 7002 /** 7003 * @private 7004 * @param {HTMLElement} el 7005 * @param {string} cls 7006 * @return {void} 7007 */ 7008 7009 removeClass: function(el, cls) { 7010 if (this.hasClass(el, cls)) { 7011 var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)'); 7012 7013 el.className = el.className.replace(reg, ' ').trim(); 7014 } 7015 }, 7016 7017 /** 7018 * Merges the properties of the source object onto the 7019 * target object. Alters the target object. 7020 * 7021 * @private 7022 * @param {object} destination 7023 * @param {object} source 7024 * @param {boolean} [deep=false] 7025 * @param {boolean} [handleErrors=false] 7026 * @return {void} 7027 */ 7028 7029 extend: function(destination, source, deep, handleErrors) { 7030 var sourceKeys = [], 7031 key = '', 7032 i = -1; 7033 7034 deep = deep || false; 7035 handleErrors = handleErrors || false; 7036 7037 try { 7038 if (Array.isArray(source)) { 7039 for (i = 0; i < source.length; i++) { 7040 sourceKeys.push(i); 7041 } 7042 } else if (source) { 7043 sourceKeys = Object.keys(source); 7044 } 7045 7046 for (i = 0; i < sourceKeys.length; i++) { 7047 key = sourceKeys[i]; 7048 7049 if (!deep || typeof source[key] !== 'object' || this.isElement(source[key])) { 7050 // All non-object properties, or all properties if shallow extend 7051 7052 destination[key] = source[key]; 7053 } else if (Array.isArray(source[key])) { 7054 // Arrays 7055 7056 if (!destination[key]) { 7057 destination[key] = []; 7058 } 7059 7060 this.extend(destination[key], source[key], deep, handleErrors); 7061 } else { 7062 // Objects 7063 7064 if (!destination[key]) { 7065 destination[key] = {}; 7066 } 7067 7068 this.extend(destination[key], source[key], deep, handleErrors); 7069 } 7070 } 7071 } catch(err) { 7072 if (handleErrors) { 7073 this.handleExtendError(err, destination); 7074 } else { 7075 throw err; 7076 } 7077 } 7078 7079 return destination; 7080 }, 7081 7082 /** 7083 * @private 7084 * @param {Error} err 7085 * @param {object} destination 7086 * @return {void} 7087 */ 7088 7089 handleExtendError: function(err, destination) { 7090 var re = /property "?(\w*)"?[,:] object/i, 7091 matches = null, 7092 erroneous = '', 7093 message = '', 7094 suggestion = '', 7095 probableMatch = '', 7096 key = '', 7097 mostMatchingChars = -1, 7098 i = -1; 7099 7100 if (err instanceof TypeError && (matches = re.exec(err.message))) { 7101 erroneous = matches[1]; 7102 7103 for (key in destination) { 7104 i = 0; 7105 7106 while (i < erroneous.length && erroneous.charAt(i) === key.charAt(i)) { 7107 i++; 7108 } 7109 7110 if (i > mostMatchingChars) { 7111 mostMatchingChars = i; 7112 probableMatch = key; 7113 } 7114 } 7115 7116 if (mostMatchingChars > 1) { 7117 suggestion = mixitup.messages.errorConfigInvalidPropertySuggestion({ 7118 probableMatch: probableMatch 7119 }); 7120 } 7121 7122 message = mixitup.messages.errorConfigInvalidProperty({ 7123 erroneous: erroneous, 7124 suggestion: suggestion 7125 }); 7126 7127 throw new TypeError(message); 7128 } 7129 7130 throw err; 7131 }, 7132 7133 /** 7134 * @private 7135 * @param {string} str 7136 * @return {function} 7137 */ 7138 7139 template: function(str) { 7140 var re = /\${([\w]*)}/g, 7141 dynamics = {}, 7142 matches = null; 7143 7144 while ((matches = re.exec(str))) { 7145 dynamics[matches[1]] = new RegExp('\\${' + matches[1] + '}', 'g'); 7146 } 7147 7148 return function(data) { 7149 var key = '', 7150 output = str; 7151 7152 data = data || {}; 7153 7154 for (key in dynamics) { 7155 output = output.replace(dynamics[key], typeof data[key] !== 'undefined' ? data[key] : ''); 7156 } 7157 7158 return output; 7159 }; 7160 }, 7161 7162 /** 7163 * @private 7164 * @param {HTMLElement} el 7165 * @param {string} type 7166 * @param {function} fn 7167 * @param {boolean} useCapture 7168 * @return {void} 7169 */ 7170 7171 on: function(el, type, fn, useCapture) { 7172 if (!el) return; 7173 7174 if (el.addEventListener) { 7175 el.addEventListener(type, fn, useCapture); 7176 } else if (el.attachEvent) { 7177 el['e' + type + fn] = fn; 7178 7179 el[type + fn] = function() { 7180 el['e' + type + fn](window.event); 7181 }; 7182 7183 el.attachEvent('on' + type, el[type + fn]); 7184 } 7185 }, 7186 7187 /** 7188 * @private 7189 * @param {HTMLElement} el 7190 * @param {string} type 7191 * @param {function} fn 7192 * @return {void} 7193 */ 7194 7195 off: function(el, type, fn) { 7196 if (!el) return; 7197 7198 if (el.removeEventListener) { 7199 el.removeEventListener(type, fn, false); 7200 } else if (el.detachEvent) { 7201 el.detachEvent('on' + type, el[type + fn]); 7202 el[type + fn] = null; 7203 } 7204 }, 7205 7206 /** 7207 * @private 7208 * @param {string} eventType 7209 * @param {object} detail 7210 * @param {Document} [doc] 7211 * @return {CustomEvent} 7212 */ 7213 7214 getCustomEvent: function(eventType, detail, doc) { 7215 var event = null; 7216 7217 doc = doc || window.document; 7218 7219 if (typeof window.CustomEvent === 'function') { 7220 event = new window.CustomEvent(eventType, { 7221 detail: detail, 7222 bubbles: true, 7223 cancelable: true 7224 }); 7225 } else if (typeof doc.createEvent === 'function') { 7226 event = doc.createEvent('CustomEvent'); 7227 event.initCustomEvent(eventType, true, true, detail); 7228 } else { 7229 event = doc.createEventObject(), 7230 event.type = eventType; 7231 7232 event.returnValue = false; 7233 event.cancelBubble = false; 7234 event.detail = detail; 7235 } 7236 7237 return event; 7238 }, 7239 7240 /** 7241 * @private 7242 * @param {Event} e 7243 * @return {Event} 7244 */ 7245 7246 getOriginalEvent: function(e) { 7247 if (e.touches && e.touches.length) { 7248 return e.touches[0]; 7249 } else if (e.changedTouches && e.changedTouches.length) { 7250 return e.changedTouches[0]; 7251 } else { 7252 return e; 7253 } 7254 }, 7255 7256 /** 7257 * @private 7258 * @param {HTMLElement} el 7259 * @param {string} selector 7260 * @return {Number} 7261 */ 7262 7263 index: function(el, selector) { 7264 var i = 0; 7265 7266 while ((el = el.previousElementSibling) !== null) { 7267 if (!selector || el.matches(selector)) { 7268 ++i; 7269 } 7270 } 7271 7272 return i; 7273 }, 7274 7275 /** 7276 * Converts a dash or snake-case string to camel case. 7277 * 7278 * @private 7279 * @param {string} str 7280 * @param {boolean} [isPascal] 7281 * @return {string} 7282 */ 7283 7284 camelCase: function(str) { 7285 return str.toLowerCase().replace(/([_-][a-z])/g, function($1) { 7286 return $1.toUpperCase().replace(/[_-]/, ''); 7287 }); 7288 }, 7289 7290 /** 7291 * Converts a dash or snake-case string to pascal case. 7292 * 7293 * @private 7294 * @param {string} str 7295 * @param {boolean} [isPascal] 7296 * @return {string} 7297 */ 7298 7299 pascalCase: function(str) { 7300 return (str = this.camelCase(str)).charAt(0).toUpperCase() + str.slice(1); 7301 }, 7302 7303 /** 7304 * Converts a camel or pascal-case string to dash case. 7305 * 7306 * @private 7307 * @param {string} str 7308 * @return {string} 7309 */ 7310 7311 dashCase: function(str) { 7312 return str.replace(/([A-Z])/g, '-$1').replace(/^-/, '').toLowerCase(); 7313 }, 7314 7315 /** 7316 * @private 7317 * @param {HTMLElement} el 7318 * @param {HTMLHtmlElement} [doc] 7319 * @return {boolean} 7320 */ 7321 7322 isElement: function(el, doc) { 7323 doc = doc || window.document; 7324 7325 if ( 7326 window.HTMLElement && 7327 el instanceof window.HTMLElement 7328 ) { 7329 return true; 7330 } else if ( 7331 doc.defaultView && 7332 doc.defaultView.HTMLElement && 7333 el instanceof doc.defaultView.HTMLElement 7334 ) { 7335 return true; 7336 } else { 7337 return ( 7338 el !== null && 7339 el.nodeType === 1 && 7340 typeof el.nodeName === 'string' 7341 ); 7342 } 7343 }, 7344 7345 /** 7346 * @private 7347 * @param {string} htmlString 7348 * @param {HTMLHtmlElement} [doc] 7349 * @return {DocumentFragment} 7350 */ 7351 7352 createElement: function(htmlString, doc) { 7353 var frag = null, 7354 temp = null; 7355 7356 doc = doc || window.document; 7357 7358 frag = doc.createDocumentFragment(); 7359 temp = doc.createElement('div'); 7360 7361 temp.innerHTML = htmlString.trim(); 7362 7363 while (temp.firstChild) { 7364 frag.appendChild(temp.firstChild); 7365 } 7366 7367 return frag; 7368 }, 7369 7370 /** 7371 * @private 7372 * @param {Node} node 7373 * @return {void} 7374 */ 7375 7376 removeWhitespace: function(node) { 7377 var deleting; 7378 7379 while (node && node.nodeName === '#text') { 7380 deleting = node; 7381 7382 node = node.previousSibling; 7383 7384 deleting.parentElement && deleting.parentElement.removeChild(deleting); 7385 } 7386 }, 7387 7388 /** 7389 * @private 7390 * @param {Array<*>} a 7391 * @param {Array<*>} b 7392 * @return {boolean} 7393 */ 7394 7395 isEqualArray: function(a, b) { 7396 var i = a.length; 7397 7398 if (i !== b.length) return false; 7399 7400 while (i--) { 7401 if (a[i] !== b[i]) return false; 7402 } 7403 7404 return true; 7405 }, 7406 7407 /** 7408 * @private 7409 * @param {object} a 7410 * @param {object} b 7411 * @return {boolean} 7412 */ 7413 7414 deepEquals: function(a, b) { 7415 var key; 7416 7417 if (typeof a === 'object' && a && typeof b === 'object' && b) { 7418 if (Object.keys(a).length !== Object.keys(b).length) return false; 7419 7420 for (key in a) { 7421 if (!b.hasOwnProperty(key) || !this.deepEquals(a[key], b[key])) return false; 7422 } 7423 } else if (a !== b) { 7424 return false; 7425 } 7426 7427 return true; 7428 }, 7429 7430 /** 7431 * @private 7432 * @param {Array<*>} oldArray 7433 * @return {Array<*>} 7434 */ 7435 7436 arrayShuffle: function(oldArray) { 7437 var newArray = oldArray.slice(), 7438 len = newArray.length, 7439 i = len, 7440 p = -1, 7441 t = []; 7442 7443 while (i--) { 7444 p = ~~(Math.random() * len); 7445 t = newArray[i]; 7446 7447 newArray[i] = newArray[p]; 7448 newArray[p] = t; 7449 } 7450 7451 return newArray; 7452 }, 7453 7454 /** 7455 * @private 7456 * @param {object} list 7457 */ 7458 7459 arrayFromList: function(list) { 7460 var output, i; 7461 7462 try { 7463 return Array.prototype.slice.call(list); 7464 } catch(err) { 7465 output = []; 7466 7467 for (i = 0; i < list.length; i++) { 7468 output.push(list[i]); 7469 } 7470 7471 return output; 7472 } 7473 }, 7474 7475 /** 7476 * @private 7477 * @param {function} func 7478 * @param {Number} wait 7479 * @param {boolean} immediate 7480 * @return {function} 7481 */ 7482 7483 debounce: function(func, wait, immediate) { 7484 var timeout; 7485 7486 return function() { 7487 var self = this, 7488 args = arguments, 7489 callNow = immediate && !timeout, 7490 later = null; 7491 7492 later = function() { 7493 timeout = null; 7494 7495 if (!immediate) { 7496 func.apply(self, args); 7497 } 7498 }; 7499 7500 clearTimeout(timeout); 7501 7502 timeout = setTimeout(later, wait); 7503 7504 if (callNow) func.apply(self, args); 7505 }; 7506 }, 7507 7508 /** 7509 * @private 7510 * @param {HTMLElement} element 7511 * @return {object} 7512 */ 7513 7514 position: function(element) { 7515 var xPosition = 0, 7516 yPosition = 0, 7517 offsetParent = element; 7518 7519 while (element) { 7520 xPosition -= element.scrollLeft; 7521 yPosition -= element.scrollTop; 7522 7523 if (element === offsetParent) { 7524 xPosition += element.offsetLeft; 7525 yPosition += element.offsetTop; 7526 7527 offsetParent = element.offsetParent; 7528 } 7529 7530 element = element.parentElement; 7531 } 7532 7533 return { 7534 x: xPosition, 7535 y: yPosition 7536 }; 7537 }, 7538 7539 /** 7540 * @private 7541 * @param {object} node1 7542 * @param {object} node2 7543 * @return {Number} 7544 */ 7545 7546 getHypotenuse: function(node1, node2) { 7547 var distanceX = node1.x - node2.x, 7548 distanceY = node1.y - node2.y; 7549 7550 distanceX = distanceX < 0 ? distanceX * -1 : distanceX, 7551 distanceY = distanceY < 0 ? distanceY * -1 : distanceY; 7552 7553 return Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2)); 7554 }, 7555 7556 /** 7557 * Calcuates the area of intersection between two rectangles and expresses it as 7558 * a ratio in comparison to the area of the first rectangle. 7559 * 7560 * @private 7561 * @param {Rect} box1 7562 * @param {Rect} box2 7563 * @return {number} 7564 */ 7565 7566 getIntersectionRatio: function(box1, box2) { 7567 var controlArea = box1.width * box1.height, 7568 intersectionX = -1, 7569 intersectionY = -1, 7570 intersectionArea = -1, 7571 ratio = -1; 7572 7573 intersectionX = 7574 Math.max(0, Math.min(box1.left + box1.width, box2.left + box2.width) - Math.max(box1.left, box2.left)); 7575 7576 intersectionY = 7577 Math.max(0, Math.min(box1.top + box1.height, box2.top + box2.height) - Math.max(box1.top, box2.top)); 7578 7579 intersectionArea = intersectionY * intersectionX; 7580 7581 ratio = intersectionArea / controlArea; 7582 7583 return ratio; 7584 }, 7585 7586 /** 7587 * @private 7588 * @param {object} el 7589 * @param {string} selector 7590 * @param {boolean} [includeSelf] 7591 * @param {HTMLHtmlElement} [doc] 7592 * @return {Element|null} 7593 */ 7594 7595 closestParent: function(el, selector, includeSelf, doc) { 7596 var parent = el.parentNode; 7597 7598 doc = doc || window.document; 7599 7600 if (includeSelf && el.matches(selector)) { 7601 return el; 7602 } 7603 7604 while (parent && parent != doc.body) { 7605 if (parent.matches && parent.matches(selector)) { 7606 return parent; 7607 } else if (parent.parentNode) { 7608 parent = parent.parentNode; 7609 } else { 7610 return null; 7611 } 7612 } 7613 7614 return null; 7615 }, 7616 7617 /** 7618 * @private 7619 * @param {HTMLElement} el 7620 * @param {string} selector 7621 * @param {HTMLHtmlElement} [doc] 7622 * @return {NodeList} 7623 */ 7624 7625 children: function(el, selector, doc) { 7626 var children = [], 7627 tempId = ''; 7628 7629 doc = doc || window.doc; 7630 7631 if (el) { 7632 if (!el.id) { 7633 tempId = 'Temp' + this.randomHexKey(); 7634 7635 el.id = tempId; 7636 } 7637 7638 children = doc.querySelectorAll('#' + el.id + ' > ' + selector); 7639 7640 if (tempId) { 7641 el.removeAttribute('id'); 7642 } 7643 } 7644 7645 return children; 7646 }, 7647 7648 /** 7649 * Creates a clone of a provided array, with any empty strings removed. 7650 * 7651 * @private 7652 * @param {Array<*>} originalArray 7653 * @return {Array<*>} 7654 */ 7655 7656 clean: function(originalArray) { 7657 var cleanArray = [], 7658 i = -1; 7659 7660 for (i = 0; i < originalArray.length; i++) { 7661 if (originalArray[i] !== '') { 7662 cleanArray.push(originalArray[i]); 7663 } 7664 } 7665 7666 return cleanArray; 7667 }, 7668 7669 /** 7670 * Abstracts an ES6 promise into a q-like deferred interface for storage and deferred resolution. 7671 * 7672 * @private 7673 * @param {object} libraries 7674 * @return {h.Deferred} 7675 */ 7676 7677 defer: function(libraries) { 7678 var deferred = null, 7679 promiseWrapper = null, 7680 $ = null; 7681 7682 promiseWrapper = new this.Deferred(); 7683 7684 if (mixitup.features.has.promises) { 7685 // ES6 native promise or polyfill 7686 7687 promiseWrapper.promise = new Promise(function(resolve, reject) { 7688 promiseWrapper.resolve = resolve; 7689 promiseWrapper.reject = reject; 7690 }); 7691 } else if (($ = (window.jQuery || libraries.$)) && typeof $.Deferred === 'function') { 7692 // jQuery 7693 7694 deferred = $.Deferred(); 7695 7696 promiseWrapper.promise = deferred.promise(); 7697 promiseWrapper.resolve = deferred.resolve; 7698 promiseWrapper.reject = deferred.reject; 7699 } else if (window.console) { 7700 // No implementation 7701 7702 console.warn(mixitup.messages.warningNoPromiseImplementation()); 7703 } 7704 7705 return promiseWrapper; 7706 }, 7707 7708 /** 7709 * @private 7710 * @param {Array<Promise>} tasks 7711 * @param {object} libraries 7712 * @return {Promise<Array>} 7713 */ 7714 7715 all: function(tasks, libraries) { 7716 var $ = null; 7717 7718 if (mixitup.features.has.promises) { 7719 return Promise.all(tasks); 7720 } else if (($ = (window.jQuery || libraries.$)) && typeof $.when === 'function') { 7721 return $.when.apply($, tasks) 7722 .done(function() { 7723 // jQuery when returns spread arguments rather than an array or resolutions 7724 7725 return arguments; 7726 }); 7727 } 7728 7729 // No implementation 7730 7731 if (window.console) { 7732 console.warn(mixitup.messages.warningNoPromiseImplementation()); 7733 } 7734 7735 return []; 7736 }, 7737 7738 /** 7739 * @private 7740 * @param {HTMLElement} el 7741 * @param {string} property 7742 * @param {Array<string>} vendors 7743 * @return {string} 7744 */ 7745 7746 getPrefix: function(el, property, vendors) { 7747 var i = -1, 7748 prefix = ''; 7749 7750 if (h.dashCase(property) in el.style) return ''; 7751 7752 for (i = 0; prefix = vendors[i]; i++) { 7753 if (prefix + property in el.style) { 7754 return prefix.toLowerCase(); 7755 } 7756 } 7757 7758 return 'unsupported'; 7759 }, 7760 7761 /** 7762 * @private 7763 * @return {string} 7764 */ 7765 7766 randomHex: function() { 7767 return ('00000' + (Math.random() * 16777216 << 0).toString(16)).substr(-6).toUpperCase(); 7768 }, 7769 7770 /** 7771 * @private 7772 * @param {HTMLDocument} [doc] 7773 * @return {object} 7774 */ 7775 7776 getDocumentState: function(doc) { 7777 doc = typeof doc.body === 'object' ? doc : window.document; 7778 7779 return { 7780 scrollTop: window.pageYOffset, 7781 scrollLeft: window.pageXOffset, 7782 docHeight: doc.documentElement.scrollHeight, 7783 docWidth: doc.documentElement.scrollWidth, 7784 viewportHeight: doc.documentElement.clientHeight, 7785 viewportWidth: doc.documentElement.clientWidth 7786 }; 7787 }, 7788 7789 /** 7790 * @private 7791 * @param {object} obj 7792 * @param {function} fn 7793 * @return {function} 7794 */ 7795 7796 bind: function(obj, fn) { 7797 return function() { 7798 return fn.apply(obj, arguments); 7799 }; 7800 }, 7801 7802 /** 7803 * @private 7804 * @param {HTMLElement} el 7805 * @return {boolean} 7806 */ 7807 7808 isVisible: function(el) { 7809 var styles = null; 7810 7811 if (el.offsetParent) return true; 7812 7813 styles = window.getComputedStyle(el); 7814 7815 if ( 7816 styles.position === 'fixed' && 7817 styles.visibility !== 'hidden' && 7818 styles.opacity !== '0' 7819 ) { 7820 // Fixed elements report no offsetParent, 7821 // but may still be invisible 7822 7823 return true; 7824 } 7825 7826 return false; 7827 }, 7828 7829 /** 7830 * @private 7831 * @param {object} obj 7832 */ 7833 7834 seal: function(obj) { 7835 if (typeof Object.seal === 'function') { 7836 Object.seal(obj); 7837 } 7838 }, 7839 7840 /** 7841 * @private 7842 * @param {object} obj 7843 */ 7844 7845 freeze: function(obj) { 7846 if (typeof Object.freeze === 'function') { 7847 Object.freeze(obj); 7848 } 7849 }, 7850 7851 /** 7852 * @private 7853 * @param {string} control 7854 * @param {string} specimen 7855 * @return {boolean} 7856 */ 7857 7858 compareVersions: function(control, specimen) { 7859 var controlParts = control.split('.'), 7860 specimenParts = specimen.split('.'), 7861 controlPart = -1, 7862 specimenPart = -1, 7863 i = -1; 7864 7865 for (i = 0; i < controlParts.length; i++) { 7866 controlPart = parseInt(controlParts[i].replace(/[^\d.]/g, '')); 7867 specimenPart = parseInt(specimenParts[i].replace(/[^\d.]/g, '') || 0); 7868 7869 if (specimenPart < controlPart) { 7870 return false; 7871 } else if (specimenPart > controlPart) { 7872 return true; 7873 } 7874 } 7875 7876 return true; 7877 }, 7878 7879 /** 7880 * @private 7881 * @constructor 7882 */ 7883 7884 Deferred: function() { 7885 this.promise = null; 7886 this.resolve = null; 7887 this.reject = null; 7888 this.id = h.randomHex(); 7889 }, 7890 7891 /** 7892 * @private 7893 * @param {object} obj 7894 * @return {boolean} 7895 */ 7896 7897 isEmptyObject: function(obj) { 7898 var key = ''; 7899 7900 if (typeof Object.keys === 'function') { 7901 return Object.keys(obj).length === 0; 7902 } 7903 7904 for (key in obj) { 7905 if (obj.hasOwnProperty(key)) { 7906 return false; 7907 } 7908 } 7909 7910 return true; 7911 }, 7912 7913 /** 7914 * @param {mixitup.Config.ClassNames} classNames 7915 * @param {string} elementName 7916 * @param {string} [modifier] 7917 * @return {string} 7918 */ 7919 7920 getClassname: function(classNames, elementName, modifier) { 7921 var classname = ''; 7922 7923 classname += classNames.block; 7924 7925 if (classname.length) { 7926 classname += classNames.delineatorElement; 7927 } 7928 7929 classname += classNames['element' + this.pascalCase(elementName)]; 7930 7931 if (!modifier) return classname; 7932 7933 if (classname.length) { 7934 classname += classNames.delineatorModifier; 7935 } 7936 7937 classname += modifier; 7938 7939 return classname; 7940 }, 7941 7942 /** 7943 * Returns the value of a property on a given object via its string key. 7944 * 7945 * @param {object} obj 7946 * @param {string} stringKey 7947 * @return {*} value 7948 */ 7949 7950 getProperty: function(obj, stringKey) { 7951 var parts = stringKey.split('.'), 7952 returnCurrent = null, 7953 current = '', 7954 i = 0; 7955 7956 if (!stringKey) { 7957 return obj; 7958 } 7959 7960 returnCurrent = function(obj) { 7961 if (!obj) { 7962 return null; 7963 } else { 7964 return obj[current]; 7965 } 7966 }; 7967 7968 while (i < parts.length) { 7969 current = parts[i]; 7970 7971 obj = returnCurrent(obj); 7972 7973 i++; 7974 } 7975 7976 if (typeof obj !== 'undefined') { 7977 return obj; 7978 } else { 7979 return null; 7980 } 7981 } 7982 }; 7983 7984 mixitup.h = h; 7985 7986 /** 7987 * The Base class adds instance methods to all other extensible MixItUp classes, 7988 * enabling the calling of any registered hooks. 7989 * 7990 * @constructor 7991 * @namespace 7992 * @memberof mixitup 7993 * @private 7994 * @since 3.0.0 7995 */ 7996 7997 mixitup.Base = function() {}; 7998 7999 mixitup.Base.prototype = { 8000 constructor: mixitup.Base, 8001 8002 /** 8003 * Calls any registered hooks for the provided action. 8004 * 8005 * @memberof mixitup.Base 8006 * @private 8007 * @instance 8008 * @since 2.0.0 8009 * @param {string} actionName 8010 * @param {Array<*>} args 8011 * @return {void} 8012 */ 8013 8014 callActions: function(actionName, args) { 8015 var self = this, 8016 hooks = self.constructor.actions[actionName], 8017 extensionName = ''; 8018 8019 if (!hooks || h.isEmptyObject(hooks)) return; 8020 8021 for (extensionName in hooks) { 8022 hooks[extensionName].apply(self, args); 8023 } 8024 }, 8025 8026 /** 8027 * Calls any registered hooks for the provided filter. 8028 * 8029 * @memberof mixitup.Base 8030 * @private 8031 * @instance 8032 * @since 2.0.0 8033 * @param {string} filterName 8034 * @param {*} input 8035 * @param {Array<*>} args 8036 * @return {*} 8037 */ 8038 8039 callFilters: function(filterName, input, args) { 8040 var self = this, 8041 hooks = self.constructor.filters[filterName], 8042 output = input, 8043 extensionName = ''; 8044 8045 if (!hooks || h.isEmptyObject(hooks)) return output; 8046 8047 args = args || []; 8048 8049 for (extensionName in hooks) { 8050 args = h.arrayFromList(args); 8051 8052 args.unshift(output); 8053 8054 output = hooks[extensionName].apply(self, args); 8055 } 8056 8057 return output; 8058 } 8059 }; 8060 8061 /** 8062 * The BaseStatic class holds a set of static methods which are then added to all other 8063 * extensible MixItUp classes as a means of integrating extensions via the addition of new 8064 * methods and/or actions and hooks. 8065 * 8066 * @constructor 8067 * @namespace 8068 * @memberof mixitup 8069 * @private 8070 * @since 3.0.0 8071 */ 8072 8073 mixitup.BaseStatic = function() { 8074 this.actions = {}; 8075 this.filters = {}; 8076 8077 /** 8078 * Performs a shallow extend on the class's prototype, adding one or more new members to 8079 * the class in a single operation. 8080 * 8081 * @memberof mixitup.BaseStatic 8082 * @public 8083 * @static 8084 * @since 2.1.0 8085 * @param {object} extension 8086 * @return {void} 8087 */ 8088 8089 this.extend = function(extension) { 8090 h.extend(this.prototype, extension); 8091 }; 8092 8093 /** 8094 * Registers a function to be called on the action hook of the provided name. 8095 * 8096 * @memberof mixitup.BaseStatic 8097 * @public 8098 * @static 8099 * @since 2.1.0 8100 * @param {string} hookName 8101 * @param {string} extensionName 8102 * @param {function} func 8103 * @return {void} 8104 */ 8105 8106 this.registerAction = function(hookName, extensionName, func) { 8107 (this.actions[hookName] = this.actions[hookName] || {})[extensionName] = func; 8108 }; 8109 8110 /** 8111 * Registers a function to be called on the filter of the provided name. 8112 * 8113 * @memberof mixitup.BaseStatic 8114 * @public 8115 * @static 8116 * @since 2.1.0 8117 * @param {string} hookName 8118 * @param {string} extensionName 8119 * @param {function} func 8120 * @return {void} 8121 */ 8122 8123 this.registerFilter = function(hookName, extensionName, func) { 8124 (this.filters[hookName] = this.filters[hookName] || {})[extensionName] = func; 8125 }; 8126 }; 8127 8128 /** 8129 * The `mixitup.Features` class performs all feature and CSS prefix detection 8130 * neccessary for MixItUp to function correctly, as well as storing various 8131 * string and array constants. All feature decection is on evaluation of the 8132 * library and stored in a singleton instance for use by other internal classes. 8133 * 8134 * @constructor 8135 * @namespace 8136 * @memberof mixitup 8137 * @private 8138 * @since 3.0.0 8139 */ 8140 8141 mixitup.Features = function() { 8142 mixitup.Base.call(this); 8143 8144 this.callActions('beforeConstruct'); 8145 8146 this.boxSizingPrefix = ''; 8147 this.transformPrefix = ''; 8148 this.transitionPrefix = ''; 8149 8150 this.boxSizingPrefix = ''; 8151 this.transformProp = ''; 8152 this.transformRule = ''; 8153 this.transitionProp = ''; 8154 this.perspectiveProp = ''; 8155 this.perspectiveOriginProp = ''; 8156 8157 this.has = new mixitup.Has(); 8158 8159 this.canary = null; 8160 8161 this.BOX_SIZING_PROP = 'boxSizing'; 8162 this.TRANSITION_PROP = 'transition'; 8163 this.TRANSFORM_PROP = 'transform'; 8164 this.PERSPECTIVE_PROP = 'perspective'; 8165 this.PERSPECTIVE_ORIGIN_PROP = 'perspectiveOrigin'; 8166 this.VENDORS = ['Webkit', 'moz', 'O', 'ms']; 8167 8168 this.TWEENABLE = [ 8169 'opacity', 8170 'width', 'height', 8171 'marginRight', 'marginBottom', 8172 'x', 'y', 8173 'scale', 8174 'translateX', 'translateY', 'translateZ', 8175 'rotateX', 'rotateY', 'rotateZ' 8176 ]; 8177 8178 this.callActions('afterConstruct'); 8179 }; 8180 8181 mixitup.BaseStatic.call(mixitup.Features); 8182 8183 mixitup.Features.prototype = Object.create(mixitup.Base.prototype); 8184 8185 h.extend(mixitup.Features.prototype, 8186 /** @lends mixitup.Features */ 8187 { 8188 constructor: mixitup.Features, 8189 8190 /** 8191 * @private 8192 * @return {void} 8193 */ 8194 8195 init: function() { 8196 var self = this; 8197 8198 self.callActions('beforeInit', arguments); 8199 8200 self.canary = document.createElement('div'); 8201 8202 self.setPrefixes(); 8203 self.runTests(); 8204 8205 self.callActions('beforeInit', arguments); 8206 }, 8207 8208 /** 8209 * @private 8210 * @return {void} 8211 */ 8212 8213 runTests: function() { 8214 var self = this; 8215 8216 self.callActions('beforeRunTests', arguments); 8217 8218 self.has.promises = typeof window.Promise === 'function'; 8219 self.has.transitions = self.transitionPrefix !== 'unsupported'; 8220 8221 self.callActions('afterRunTests', arguments); 8222 8223 h.freeze(self.has); 8224 }, 8225 8226 /** 8227 * @private 8228 * @return {void} 8229 */ 8230 8231 setPrefixes: function() { 8232 var self = this; 8233 8234 self.callActions('beforeSetPrefixes', arguments); 8235 8236 self.transitionPrefix = h.getPrefix(self.canary, 'Transition', self.VENDORS); 8237 self.transformPrefix = h.getPrefix(self.canary, 'Transform', self.VENDORS); 8238 self.boxSizingPrefix = h.getPrefix(self.canary, 'BoxSizing', self.VENDORS); 8239 8240 self.boxSizingProp = self.boxSizingPrefix ? 8241 self.boxSizingPrefix + h.pascalCase(self.BOX_SIZING_PROP) : self.BOX_SIZING_PROP; 8242 8243 self.transitionProp = self.transitionPrefix ? 8244 self.transitionPrefix + h.pascalCase(self.TRANSITION_PROP) : self.TRANSITION_PROP; 8245 8246 self.transformProp = self.transformPrefix ? 8247 self.transformPrefix + h.pascalCase(self.TRANSFORM_PROP) : self.TRANSFORM_PROP; 8248 8249 self.transformRule = self.transformPrefix ? 8250 '-' + self.transformPrefix + '-' + self.TRANSFORM_PROP : self.TRANSFORM_PROP; 8251 8252 self.perspectiveProp = self.transformPrefix ? 8253 self.transformPrefix + h.pascalCase(self.PERSPECTIVE_PROP) : self.PERSPECTIVE_PROP; 8254 8255 self.perspectiveOriginProp = self.transformPrefix ? 8256 self.transformPrefix + h.pascalCase(self.PERSPECTIVE_ORIGIN_PROP) : 8257 self.PERSPECTIVE_ORIGIN_PROP; 8258 8259 self.callActions('afterSetPrefixes', arguments); 8260 } 8261 }); 8262 8263 /** 8264 * @constructor 8265 * @memberof mixitup 8266 * @private 8267 * @since 3.0.0 8268 */ 8269 8270 mixitup.Has = function() { 8271 this.transitions = false; 8272 this.promises = false; 8273 8274 h.seal(this); 8275 }; 8276 8277 // Assign a singleton instance to `mixitup.features` and initialise: 8278 8279 mixitup.features = new mixitup.Features(); 8280 8281 mixitup.features.init(); 8282 8283 /** 8284 * A group of properties defining the mixer's animation and effects settings. 8285 * 8286 * @constructor 8287 * @memberof mixitup.Config 8288 * @name animation 8289 * @namespace 8290 * @public 8291 * @since 2.0.0 8292 */ 8293 8294 mixitup.ConfigAnimation = function() { 8295 mixitup.Base.call(this); 8296 8297 this.callActions('beforeConstruct'); 8298 8299 /** 8300 * A boolean dictating whether or not animation should be enabled for the MixItUp instance. 8301 * If `false`, all operations will occur instantly and syncronously, although callback 8302 * functions and any returned promises will still be fulfilled. 8303 * 8304 * @example <caption>Example: Create a mixer with all animations disabled</caption> 8305 * var mixer = mixitup(containerEl, { 8306 * animation: { 8307 * enable: false 8308 * } 8309 * }); 8310 * 8311 * @name enable 8312 * @memberof mixitup.Config.animation 8313 * @instance 8314 * @type {boolean} 8315 * @default true 8316 */ 8317 8318 this.enable = true; 8319 8320 /** 8321 * A string of one or more space-sep
8321erated properties to which transitions will be 8322 * applied for all filtering animations. 8323 * 8324 * Properties can be listed any order or combination, although they will be applied in a specific 8325 * predefined order to produce consistent results. 8326 * 8327 * To learn more about available effects, experiment with our <a href="https://www.kunkalabs.com/mixitup/"> 8328 * sandbox demo</a> and try out the "Export config" button in the Animation options drop down
vendor: 299,530 bytes, lines 8328-17208
8328. 8329 * 8330 * @example <caption>Example: Apply "fade" and "translateZ" effects to all animations</caption> 8331 * // As targets are filtered in and out, they will fade between 8332 * // opacity 1 and 0 and transform between translateZ(-100px) and 8333 * // translateZ(0). 8334 * 8335 * var mixer = mixitup(containerEl, { 8336 * animation: { 8337 * effects: 'fade translateZ(-100px)' 8338 * } 8339 * }); 8340 * 8341 * @name effects 8342 * @memberof mixitup.Config.animation 8343 * @instance 8344 * @type {string} 8345 * @default 'fade scale' 8346 */ 8347 8348 this.effects = 'fade scale'; 8349 8350 /** 8351 * A string of one or more space-seperated effects to be applied only to filter-in 8352 * animations, overriding `config.animation.effects` if set. 8353 * 8354 * @example <caption>Example: Apply downwards vertical translate to targets being filtered in</caption> 8355 * 8356 * var mixer = mixitup(containerEl, { 8357 * animation: { 8358 * effectsIn: 'fade translateY(-100%)' 8359 * } 8360 * }); 8361 * 8362 * @name effectsIn 8363 * @memberof mixitup.Config.animation 8364 * @instance 8365 * @type {string} 8366 * @default '' 8367 */ 8368 8369 this.effectsIn = ''; 8370 8371 /** 8372 * A string of one or more space-seperated effects to be applied only to filter-out 8373 * animations, overriding `config.animation.effects` if set. 8374 * 8375 * @example <caption>Example: Apply upwards vertical translate to targets being filtered out</caption> 8376 * 8377 * var mixer = mixitup(containerEl, { 8378 * animation: { 8379 * effectsOut: 'fade translateY(-100%)' 8380 * } 8381 * }); 8382 * 8383 * @name effectsOut 8384 * @memberof mixitup.Config.animation 8385 * @instance 8386 * @type {string} 8387 * @default '' 8388 */ 8389 8390 this.effectsOut = ''; 8391 8392 /** 8393 * An integer dictating the duration of all MixItUp animations in milliseconds, not 8394 * including any additional delay apllied via the `'stagger'` effect. 8395 * 8396 * @example <caption>Example: Apply an animation duration of 200ms to all mixitup animations</caption> 8397 * 8398 * var mixer = mixitup(containerEl, { 8399 * animation: { 8400 * duration: 200 8401 * } 8402 * }); 8403 * 8404 * @name duration 8405 * @memberof mixitup.Config.animation 8406 * @instance 8407 * @type {number} 8408 * @default 600 8409 */ 8410 8411 this.duration = 600; 8412 8413 /** 8414 * A valid CSS3 transition-timing function or shorthand. For a full list of accepted 8415 * values, visit <a href="http://easings.net" target="_blank">easings.net</a>. 8416 * 8417 * @example <caption>Example 1: Apply "ease-in-out" easing to all animations</caption> 8418 * 8419 * var mixer = mixitup(containerEl, { 8420 * animation: { 8421 * easing: 'ease-in-out' 8422 * } 8423 * }); 8424 * 8425 * @example <caption>Example 2: Apply a custom "cubic-bezier" easing function to all animations</caption> 8426 * var mixer = mixitup(containerEl, { 8427 * animation: { 8428 * easing: 'cubic-bezier(0.645, 0.045, 0.355, 1)' 8429 * } 8430 * }); 8431 * 8432 * @name easing 8433 * @memberof mixitup.Config.animation 8434 * @instance 8435 * @type {string} 8436 * @default 'ease' 8437 */ 8438 8439 this.easing = 'ease'; 8440 8441 /** 8442 * A boolean dictating whether or not to apply perspective to the MixItUp container 8443 * during animations. By default, perspective is always applied and creates the 8444 * illusion of three-dimensional space for effects such as `translateZ`, `rotateX`, 8445 * and `rotateY`. 8446 * 8447 * You may wish to disable this and define your own perspective settings via CSS. 8448 * 8449 * @example <caption>Example: Prevent perspective from being applied to any 3D transforms</caption> 8450 * var mixer = mixitup(containerEl, { 8451 * animation: { 8452 * applyPerspective: false 8453 * } 8454 * }); 8455 * 8456 * @name applyPerspective 8457 * @memberof mixitup.Config.animation 8458 * @instance 8459 * @type {bolean} 8460 * @default true 8461 */ 8462 8463 this.applyPerspective = true; 8464 8465 /** 8466 * The perspective distance value to be applied to the container during animations, 8467 * affecting any 3D-transform-based effects. 8468 * 8469 * @example <caption>Example: Set a perspective distance of 2000px</caption> 8470 * var mixer = mixitup(containerEl, { 8471 * animation: { 8472 * effects: 'rotateY(-25deg)', 8473 * perspectiveDistance: '2000px' 8474 * } 8475 * }); 8476 * 8477 * @name perspectiveDistance 8478 * @memberof mixitup.Config.animation 8479 * @instance 8480 * @type {string} 8481 * @default '3000px' 8482 */ 8483 8484 this.perspectiveDistance = '3000px'; 8485 8486 /** 8487 * The perspective-origin value to be applied to the container during animations, 8488 * affecting any 3D-transform-based effects. 8489 * 8490 * @example <caption>Example: Set a perspective origin in the top-right of the container</caption> 8491 * var mixer = mixitup(containerEl, { 8492 * animation: { 8493 * effects: 'transateZ(-200px)', 8494 * perspectiveOrigin: '100% 0' 8495 * } 8496 * }); 8497 * 8498 * @name perspectiveOrigin 8499 * @memberof mixitup.Config.animation 8500 * @instance 8501 * @type {string} 8502 * @default '50% 50%' 8503 */ 8504 8505 this.perspectiveOrigin = '50% 50%'; 8506 8507 /** 8508 * A boolean dictating whether or not to enable the queuing of operations. 8509 * 8510 * If `true` (default), and a control is clicked or an API call is made while another 8511 * operation is progress, the operation will go into the queue and will be automatically exectuted 8512 * when the previous operaitons is finished. 8513 * 8514 * If `false`, any requested operations will be ignored, and the `onMixBusy` callback and `mixBusy` 8515 * event will be fired. If `debug.showWarnings` is enabled, a console warning will also occur. 8516 * 8517 * @example <caption>Example: Disable queuing</caption> 8518 * var mixer = mixitup(containerEl, { 8519 * animation: { 8520 * queue: false 8521 * } 8522 * }); 8523 * 8524 * @name queue 8525 * @memberof mixitup.Config.animation 8526 * @instance 8527 * @type {boolean} 8528 * @default true 8529 */ 8530 8531 this.queue = true; 8532 8533 /** 8534 * An integer dictacting the maximum number of operations allowed in the queue at 8535 * any time, when queuing is enabled. 8536 * 8537 * @example <caption>Example: Allow a maximum of 5 operations in the queue at any time</caption> 8538 * var mixer = mixitup(containerEl, { 8539 * animation: { 8540 * queueLimit: 5 8541 * } 8542 * }); 8543 * 8544 * @name queueLimit 8545 * @memberof mixitup.Config.animation 8546 * @instance 8547 * @type {number} 8548 * @default 3 8549 */ 8550 8551 this.queueLimit = 3; 8552 8553 /** 8554 * A boolean dictating whether or not to transition the height and width of the 8555 * container as elements are filtered in and out. If disabled, the container height 8556 * will change abruptly. 8557 * 8558 * It may be desirable to disable this on mobile devices as the CSS `height` and 8559 * `width` properties do not receive GPU-acceleration and can therefore cause stuttering. 8560 * 8561 * @example <caption>Example 1: Disable the transitioning of the container height and/or width</caption> 8562 * var mixer = mixitup(containerEl, { 8563 * animation: { 8564 * animateResizeContainer: false 8565 * } 8566 * }); 8567 * 8568 * @example <caption>Example 2: Disable the transitioning of the container height and/or width for mobile devices only</caption> 8569 * var mixer = mixitup(containerEl, { 8570 * animation: { 8571 * animateResizeContainer: myFeatureTests.isMobile ? false : true 8572 * } 8573 * }); 8574 * 8575 * @name animateResizeContainer 8576 * @memberof mixitup.Config.animation 8577 * @instance 8578 * @type {boolean} 8579 * @default true 8580 */ 8581 8582 this.animateResizeContainer = true; 8583 8584 /** 8585 * A boolean dictating whether or not to transition the height and width of target 8586 * elements as they change throughout the course of an animation. 8587 * 8588 * This is often a must for flex-box grid layouts where the size of target elements may change 8589 * depending on final their position in relation to their siblings, or for `.changeLayout()` 8590 * operations where the size of targets change between layouts. 8591 * 8592 * NB: This feature requires additional calculations and manipulation to non-hardware-accelerated 8593 * properties which may adversely affect performance on slower devices, and is therefore 8594 * disabled by default. 8595 * 8596 * @example <caption>Example: Enable the transitioning of target widths and heights</caption> 8597 * var mixer = mixitup(containerEl, { 8598 * animation: { 8599 * animateResizeTargets: true 8600 * } 8601 * }); 8602 * 8603 * @name animateResizeTargets 8604 * @memberof mixitup.Config.animation 8605 * @instance 8606 * @type {boolean} 8607 * @default false 8608 */ 8609 8610 this.animateResizeTargets = false; 8611 8612 /** 8613 * A custom function used to manipulate the order in which the stagger delay is 8614 * incremented when using the âstaggerâ effect. 8615 * 8616 * When using the 'stagger' effect, the delay applied to each target element is incremented 8617 * based on its index. You may create a custom function to manipulate the order in which the 8618 * delay is incremented and create engaging non-linear stagger effects. 8619 * 8620 * The function receives the index of the target element as a parameter, and must 8621 * return an integer which serves as the multiplier for the stagger delay. 8622 * 8623 * @example <caption>Example 1: Stagger target elements by column in a 3-column grid</caption> 8624 * var mixer = mixitup(containerEl, { 8625 * animation: { 8626 * effects: 'fade stagger(100ms)', 8627 * staggerSequence: function(i) { 8628 * return i % 3; 8629 * } 8630 * } 8631 * }); 8632 * 8633 * @example <caption>Example 2: Using an algorithm to produce a more complex sequence</caption> 8634 * var mixer = mixitup(containerEl, { 8635 * animation: { 8636 * effects: 'fade stagger(100ms)', 8637 * staggerSequence: function(i) { 8638 * return (2*i) - (5*((i/3) - ((1/3) * (i%3)))); 8639 * } 8640 * } 8641 * }); 8642 * 8643 * @name staggerSequence 8644 * @memberof mixitup.Config.animation 8645 * @instance 8646 * @type {function} 8647 * @default null 8648 */ 8649 8650 this.staggerSequence = null; 8651 8652 /** 8653 * A boolean dictating whether or not to reverse the direction of `translate` 8654 * and `rotate` transforms for elements being filtered out. 8655 * 8656 * It can be used to create carousel-like animations where elements enter and exit 8657 * from opposite directions. If enabled, the effect `translateX(-100%)` for elements 8658 * being filtered in would become `translateX(100%)` for targets being filtered out. 8659 * 8660 * This functionality can also be achieved by providing seperate effects 8661 * strings for `config.animation.effectsIn` and `config.animation.effectsOut`. 8662 * 8663 * @example <caption>Example: Reverse the desired direction on any translate/rotate effect for targets being filtered out</caption> 8664 * // Elements being filtered in will be translated from '100%' to '0' while 8665 * // elements being filtered out will be translated from 0 to '-100%' 8666 * 8667 * var mixer = mixitup(containerEl, { 8668 * animation: { 8669 * effects: 'fade translateX(100%)', 8670 * reverseOut: true, 8671 * nudge: false // Disable nudging to create a carousel-like effect 8672 * } 8673 * }); 8674 * 8675 * @name reverseOut 8676 * @memberof mixitup.Config.animation 8677 * @instance 8678 * @type {boolean} 8679 * @default false 8680 */ 8681 8682 this.reverseOut = false; 8683 8684 /** 8685 * A boolean dictating whether or not to "nudge" the animation path of targets 8686 * when they are being filtered in and out simulatenously. 8687 * 8688 * This has been the default behavior of MixItUp since version 1, but it 8689 * may be desirable to disable this effect when filtering directly from 8690 * one exclusive set of targets to a different exclusive set of targets, 8691 * to create a carousel-like effect, or a generally more subtle animation. 8692 * 8693 * @example <caption>Example: Disable the "nudging" of targets being filtered in and out simulatenously</caption> 8694 * 8695 * var mixer = mixitup(containerEl, { 8696 * animation: { 8697 * nudge: false 8698 * } 8699 * }); 8700 * 8701 * @name nudge 8702 * @memberof mixitup.Config.animation 8703 * @instance 8704 * @type {boolean} 8705 * @default true 8706 */ 8707 8708 this.nudge = true; 8709 8710 /** 8711 * A boolean dictating whether or not to clamp the height of the container while MixItUp's 8712 * geometry tests are carried out before an operation. 8713 * 8714 * To prevent scroll-bar flicker, clamping is turned on by default. But in the case where the 8715 * height of the container might affect its vertical positioning in the viewport 8716 * (e.g. a vertically-centered container), this should be turned off to ensure accurate 8717 * test results and a smooth animation. 8718 * 8719 * @example <caption>Example: Disable container height-clamping</caption> 8720 * 8721 * var mixer = mixitup(containerEl, { 8722 * animation: { 8723 * clampHeight: false 8724 * } 8725 * }); 8726 * 8727 * @name clampHeight 8728 * @memberof mixitup.Config.animation 8729 * @instance 8730 * @type {boolean} 8731 * @default true 8732 */ 8733 8734 this.clampHeight = true; 8735 8736 /** 8737 * A boolean dictating whether or not to clamp the width of the container while MixItUp's 8738 * geometry tests are carried out before an operation. 8739 * 8740 * To prevent scroll-bar flicker, clamping is turned on by default. But in the case where the 8741 * width of the container might affect its horitzontal positioning in the viewport 8742 * (e.g. a horizontall-centered container), this should be turned off to ensure accurate 8743 * test results and a smooth animation. 8744 * 8745 * @example <caption>Example: Disable container width-clamping</caption> 8746 * 8747 * var mixer = mixitup(containerEl, { 8748 * animation: { 8749 * clampWidth: false 8750 * } 8751 * }); 8752 * 8753 * @name clampWidth 8754 * @memberof mixitup.Config.animation 8755 * @instance 8756 * @type {boolean} 8757 * @default true 8758 */ 8759 8760 this.clampWidth = true; 8761 8762 this.callActions('afterConstruct'); 8763 8764 h.seal(this); 8765 }; 8766 8767 mixitup.BaseStatic.call(mixitup.ConfigAnimation); 8768 8769 mixitup.ConfigAnimation.prototype = Object.create(mixitup.Base.prototype); 8770 8771 mixitup.ConfigAnimation.prototype.constructor = mixitup.ConfigAnimation; 8772 8773 /** 8774 * A group of properties relating to the behavior of the Mixer. 8775 * 8776 * @constructor 8777 * @memberof mixitup.Config 8778 * @name behavior 8779 * @namespace 8780 * @public 8781 * @since 3.1.12 8782 */ 8783 8784 mixitup.ConfigBehavior = function() { 8785 mixitup.Base.call(this); 8786 8787 this.callActions('beforeConstruct'); 8788 8789 /** 8790 * A boolean dictating whether to allow "live" sorting of the mixer. 8791 * 8792 * Because of the expensive nature of sorting, MixItUp makes use of several 8793 * internal optimizations to skip redundant sorting operations, such as when 8794 * the newly requested sort command is the same as the active one. The caveat 8795 * to this optimization is that "live" edits to the value of a target's sorting 8796 * attribute will be ignored when requesting a re-sort by the same attribute. 8797 * 8798 * By setting to `behavior.liveSort` to `true`, the mixer will always re-sort 8799 * regardless of whether or not the sorting attribute and order have changed. 8800 * 8801 * @example <caption>Example: Enabling `liveSort` to allow for re-sorting</caption> 8802 * 8803 * var mixer = mixitup(containerEl, { 8804 * behavior: { 8805 * liveSort: true 8806 * }, 8807 * load: { 8808 * sort: 'edited:desc' 8809 * } 8810 * }); 8811 * 8812 * var target = containerEl.children[3]; 8813 * 8814 * console.log(target.getAttribute('data-edited')); // '2015-04-24' 8815 * 8816 * target.setAttribute('data-edited', '2017-08-10'); // Update the target's edited date 8817 * 8818 * mixer.sort('edited:desc') 8819 * .then(function(state) { 8820 * // The target is now at the top of the list 8821 * 8822 * console.log(state.targets[0] === target); // true 8823 * }); 8824 * 8825 * @name liveSort 8826 * @memberof mixitup.Config.behavior 8827 * @instance 8828 * @type {boolean} 8829 * @default false 8830 */ 8831 8832 this.liveSort = false; 8833 8834 this.callActions('afterConstruct'); 8835 8836 h.seal(this); 8837 }; 8838 8839 mixitup.BaseStatic.call(mixitup.ConfigBehavior); 8840 8841 mixitup.ConfigBehavior.prototype = Object.create(mixitup.Base.prototype); 8842 8843 mixitup.ConfigBehavior.prototype.constructor = mixitup.ConfigBehavior; 8844 8845 /** 8846 * A group of optional callback functions to be invoked at various 8847 * points within the lifecycle of a mixer operation. 8848 * 8849 * Each function is analogous to an event of the same name triggered from the 8850 * container element, and is invoked immediately after it. 8851 * 8852 * All callback functions receive the current `state` object as their first 8853 * argument, as well as other more specific arguments described below. 8854 * 8855 * @constructor 8856 * @memberof mixitup.Config 8857 * @name callbacks 8858 * @namespace 8859 * @public 8860 * @since 2.0.0 8861 */ 8862 8863 mixitup.ConfigCallbacks = function() { 8864 mixitup.Base.call(this); 8865 8866 this.callActions('beforeConstruct'); 8867 8868 /** 8869 * A callback function invoked immediately after any MixItUp operation is requested 8870 * and before animations have begun. 8871 * 8872 * A second `futureState` argument is passed to the function which represents the final 8873 * state of the mixer once the requested operation has completed. 8874 * 8875 * @example <caption>Example: Adding an `onMixStart` callback function</caption> 8876 * var mixer = mixitup(containerEl, { 8877 * callbacks: { 8878 * onMixStart: function(state, futureState) { 8879 * console.log('Starting operation...'); 8880 * } 8881 * } 8882 * }); 8883 * 8884 * @name onMixStart 8885 * @memberof mixitup.Config.callbacks 8886 * @instance 8887 * @type {function} 8888 * @default null 8889 */ 8890 8891 this.onMixStart = null; 8892 8893 /** 8894 * A callback function invoked when a MixItUp operation is requested while another 8895 * operation is in progress, and the animation queue is full, or queueing 8896 * is disabled. 8897 * 8898 * @example <caption>Example: Adding an `onMixBusy` callback function</caption> 8899 * var mixer = mixitup(containerEl, { 8900 * callbacks: { 8901 * onMixBusy: function(state) { 8902 * console.log('Mixer busy'); 8903 * } 8904 * } 8905 * }); 8906 * 8907 * @name onMixBusy 8908 * @memberof mixitup.Config.callbacks 8909 * @instance 8910 * @type {function} 8911 * @default null 8912 */ 8913 8914 this.onMixBusy = null; 8915 8916 /** 8917 * A callback function invoked after any MixItUp operation has completed, and the 8918 * state has been updated. 8919 * 8920 * @example <caption>Example: Adding an `onMixEnd` callback function</caption> 8921 * var mixer = mixitup(containerEl, { 8922 * callbacks: { 8923 * onMixEnd: function(state) { 8924 * console.log('Operation complete'); 8925 * } 8926 * } 8927 * }); 8928 * 8929 * @name onMixEnd 8930 * @memberof mixitup.Config.callbacks 8931 * @instance 8932 * @type {function} 8933 * @default null 8934 */ 8935 8936 this.onMixEnd = null; 8937 8938 /** 8939 * A callback function invoked whenever an operation "fails", i.e. no targets 8940 * could be found matching the requested filter. 8941 * 8942 * @example <caption>Example: Adding an `onMixFail` callback function</caption> 8943 * var mixer = mixitup(containerEl, { 8944 * callbacks: { 8945 * onMixFail: function(state) { 8946 * console.log('No items could be found matching the requested filter'); 8947 * } 8948 * } 8949 * }); 8950 * 8951 * @name onMixFail 8952 * @memberof mixitup.Config.callbacks 8953 * @instance 8954 * @type {function} 8955 * @default null 8956 */ 8957 8958 this.onMixFail = null; 8959 8960 /** 8961 * A callback function invoked whenever a MixItUp control is clicked, and before its 8962 * respective operation is requested. 8963 * 8964 * The clicked element is assigned to the `this` keyword within the function. The original 8965 * click event is passed to the function as the second argument, which can be useful if 8966 * using `<a>` tags as controls where the default behavior needs to be prevented. 8967 * 8968 * Returning `false` from the callback will prevent the control click from triggering 8969 * an operation. 8970 * 8971 * @example <caption>Example 1: Adding an `onMixClick` callback function</caption> 8972 * var mixer = mixitup(containerEl, { 8973 * callbacks: { 8974 * onMixClick: function(state, originalEvent) { 8975 * console.log('The control "' + this.innerText + '" was clicked'); 8976 * } 8977 * } 8978 * }); 8979 * 8980 * @example <caption>Example 2: Using `onMixClick` to manipulate the original click event</caption> 8981 * var mixer = mixitup(containerEl, { 8982 * callbacks: { 8983 * onMixClick: function(state, originalEvent) { 8984 * // Prevent original click event from bubbling up: 8985 * originalEvent.stopPropagation(); 8986 * 8987 * // Prevent default behavior of clicked element: 8988 * originalEvent.preventDefault(); 8989 * } 8990 * } 8991 * }); 8992 * 8993 * @example <caption>Example 3: Using `onMixClick` to conditionally cancel operations</caption> 8994 * var mixer = mixitup(containerEl, { 8995 * callbacks: { 8996 * onMixClick: function(state, originalEvent) { 8997 * // Perform some conditional check: 8998 * 8999 * if (myApp.isLoading) { 9000 * // By returning false, we can prevent the control click from triggering an operation. 9001 * 9002 * return false; 9003 * } 9004 * } 9005 * } 9006 * }); 9007 * 9008 * @name onMixClick 9009 * @memberof mixitup.Config.callbacks 9010 * @instance 9011 * @type {function} 9012 * @default null 9013 */ 9014 9015 this.onMixClick = null; 9016 9017 this.callActions('afterConstruct'); 9018 9019 h.seal(this); 9020 }; 9021 9022 mixitup.BaseStatic.call(mixitup.ConfigCallbacks); 9023 9024 mixitup.ConfigCallbacks.prototype = Object.create(mixitup.Base.prototype); 9025 9026 mixitup.ConfigCallbacks.prototype.constructor = mixitup.ConfigCallbacks; 9027 9028 /** 9029 * A group of properties relating to clickable control elements. 9030 * 9031 * @constructor 9032 * @memberof mixitup.Config 9033 * @name controls 9034 * @namespace 9035 * @public 9036 * @since 2.0.0 9037 */ 9038 9039 mixitup.ConfigControls = function() { 9040 mixitup.Base.call(this); 9041 9042 this.callActions('beforeConstruct'); 9043 9044 /** 9045 * A boolean dictating whether or not controls should be enabled for the mixer instance. 9046 * 9047 * If `true` (default behavior), MixItUp will search the DOM for any clickable elements with 9048 * `data-filter`, `data-sort` or `data-toggle` attributes, and bind them for click events. 9049 * 9050 * If `false`, no click handlers will be bound, and all functionality must therefore be performed 9051 * via the mixer's API methods. 9052 * 9053 * If you do not intend to use the default controls, setting this property to `false` will 9054 * marginally improve the startup time of your mixer instance, and will also prevent any other active 9055 * mixer instances in the DOM which are bound to controls from controlling the instance. 9056 * 9057 * @example <caption>Example: Disabling controls</caption> 9058 * var mixer = mixitup(containerEl, { 9059 * controls: { 9060 * enable: false 9061 * } 9062 * }); 9063 * 9064 * // With the default controls disabled, we can only control 9065 * // the mixer via its API methods, e.g.: 9066 * 9067 * mixer.filter('.cat-1'); 9068 * 9069 * @name enable 9070 * @memberof mixitup.Config.controls 9071 * @instance 9072 * @type {boolean} 9073 * @default true 9074 */ 9075 9076 this.enable = true; 9077 9078 /** 9079 * A boolean dictating whether or not to use event delegation when binding click events 9080 * to the default controls. 9081 * 9082 * If `false` (default behavior), each control button in the DOM will be found and 9083 * individually bound when a mixer is instantiated, with their corresponding actions 9084 * cached for performance. 9085 * 9086 * If `true`, a single click handler will be applied to the `window` (or container element - see 9087 * `config.controls.scope`), and any click events triggered by elements with `data-filter`, 9088 * `data-sort` or `data-toggle` attributes present will be handled as they propagate upwards. 9089 * 9090 * If you require a user interface where control buttons may be added, removed, or changed during the 9091 * lifetime of a mixer, `controls.live` should be set to `true`. There is a marginal but unavoidable 9092 * performance deficit when using live controls, as the value of each control button must be read 9093 * from the DOM in real time once the click event has propagated. 9094 * 9095 * @example <caption>Example: Setting live controls</caption> 9096 * var mixer = mixitup(containerEl, { 9097 * controls: { 9098 * live: true 9099 * } 9100 * }); 9101 * 9102 * // Control buttons can now be added, remove and changed without breaking 9103 * // the mixer's UI 9104 * 9105 * @name live 9106 * @memberof mixitup.Config.controls 9107 * @instance 9108 * @type {boolean} 9109 * @default true 9110 */ 9111 9112 this.live = false; 9113 9114 /** 9115 * A string dictating the "scope" to use when binding or querying the default controls. The available 9116 * values are `'global'` or `'local'`. 9117 * 9118 * When set to `'global'` (default behavior), MixItUp will query the entire document for control buttons 9119 * to bind, or delegate click events from (see `config.controls.live`). 9120 * 9121 * When set to `'local'`, MixItUp will only query (or bind click events to) its own container element. 9122 * This may be desireable if you require multiple active mixer instances within the same document, with 9123 * controls that would otherwise intefere with each other if scoped globally. 9124 * 9125 * Conversely, if you wish to control multiple instances with a single UI, you would create one 9126 * set of controls and keep the controls scope of each mixer set to `global`. 9127 * 9128 * @example <caption>Example: Setting 'local' scoped controls</caption> 9129 * var mixerOne = mixitup(containerOne, { 9130 * controls: { 9131 * scope: 'local' 9132 * } 9133 * }); 9134 * 9135 * var mixerTwo = mixitup(containerTwo, { 9136 * controls: { 9137 * scope: 'local' 9138 * } 9139 * }); 9140 * 9141 * // Both mixers can now exist within the same document with 9142 * // isolated controls placed within their container elements. 9143 * 9144 * @name scope 9145 * @memberof mixitup.Config.controls 9146 * @instance 9147 * @type {string} 9148 * @default 'global' 9149 */ 9150 9151 this.scope = 'global'; // enum: ['local' ,'global'] 9152 9153 /** 9154 * A string dictating the type of logic to apply when concatenating the filter selectors of 9155 * active toggle buttons (i.e. any clickable element with a `data-toggle` attribute). 9156 * 9157 * If set to `'or'` (default behavior), selectors will be concatenated together as 9158 * a comma-seperated list. For example: 9159 * 9160 * `'.cat-1, .cat-2'` (shows any elements matching `'.cat-1'` OR `'.cat-2'`) 9161 * 9162 * If set to `'and'`, selectors will be directly concatenated together. For example: 9163 * 9164 * `'.cat-1.cat-2'` (shows any elements which match both `'.cat-1'` AND `'.cat-2'`) 9165 * 9166 * @example <caption>Example: Setting "and" toggle logic</caption> 9167 * var mixer = mixitup(containerEl, { 9168 * controls: { 9169 * toggleLogic: 'and' 9170 * } 9171 * }); 9172 * 9173 * @name toggleLogic 9174 * @memberof mixitup.Config.controls 9175 * @instance 9176 * @type {string} 9177 * @default 'or' 9178 */ 9179 9180 this.toggleLogic = 'or'; // enum: ['or', 'and'] 9181 9182 /** 9183 * A string dictating the filter behavior when all toggles are inactive. 9184 * 9185 * When set to `'all'` (default behavior), *all* targets will be shown by default 9186 * when no toggles are active, or at the moment all active toggles are toggled off. 9187 * 9188 * When set to `'none'`, no targets will be shown by default when no toggles are 9189 * active, or at the moment all active toggles are toggled off. 9190 * 9191 * @example <caption>Example 1: Setting the default toggle behavior to `'all'`</caption> 9192 * var mixer = mixitup(containerEl, { 9193 * controls: { 9194 * toggleDefault: 'all' 9195 * } 9196 * }); 9197 * 9198 * mixer.toggleOn('.cat-2') 9199 * .then(function() { 9200 * // Deactivate all active toggles 9201 * 9202 * return mixer.toggleOff('.cat-2') 9203 * }) 9204 * .then(function(state) { 9205 * console.log(state.activeFilter.selector); // 'all' 9206 * console.log(state.totalShow); // 12 9207 * }); 9208 * 9209 * @example <caption>Example 2: Setting the default toggle behavior to `'none'`</caption> 9210 * var mixer = mixitup(containerEl, { 9211 * controls: { 9212 * toggleDefault: 'none' 9213 * } 9214 * }); 9215 * 9216 * mixer.toggleOn('.cat-2') 9217 * .then(function() { 9218 * // Deactivate all active toggles 9219 * 9220 * return mixer.toggleOff('.cat-2') 9221 * }) 9222 * .then(function(state) { 9223 * console.log(state.activeFilter.selector); // 'none' 9224 * console.log(state.totalShow); // 0 9225 * }); 9226 * 9227 * @name toggleDefault 9228 * @memberof mixitup.Config.controls 9229 * @instance 9230 * @type {string} 9231 * @default 'all' 9232 */ 9233 9234 this.toggleDefault = 'all'; // enum: ['all', 'none'] 9235 9236 this.callActions('afterConstruct'); 9237 9238 h.seal(this); 9239 }; 9240 9241 mixitup.BaseStatic.call(mixitup.ConfigControls); 9242 9243 mixitup.ConfigControls.prototype = Object.create(mixitup.Base.prototype); 9244 9245 mixitup.ConfigControls.prototype.constructor = mixitup.ConfigControls; 9246 9247 /** 9248 * A group of properties defining the output and structure of class names programmatically 9249 * added to controls and containers to reflect the state of the mixer. 9250 * 9251 * Most commonly, class names are added to controls by MixItUp to indicate that 9252 * the control is active so that it can be styled accordingly - `'mixitup-control-active'` by default. 9253 * 9254 * Using a "BEM" like structure, each classname is broken into the three parts: 9255 * a block namespace (`'mixitup'`), an element name (e.g. `'control'`), and an optional modifier 9256 * name (e.g. `'active'`) reflecting the state of the element. 9257 * 9258 * By default, each part of the classname is concatenated together using single hyphens as 9259 * delineators, but this can be easily customised to match the naming convention and style of 9260 * your project. 9261 * 9262 * @constructor 9263 * @memberof mixitup.Config 9264 * @name classNames 9265 * @namespace 9266 * @public 9267 * @since 3.0.0 9268 */ 9269 9270 mixitup.ConfigClassNames = function() { 9271 mixitup.Base.call(this); 9272 9273 this.callActions('beforeConstruct'); 9274 9275 /** 9276 * The "block" portion, or top-level namespace added to the start of any class names created by MixItUp. 9277 * 9278 * @example <caption>Example 1: changing the `config.classNames.block` value</caption> 9279 * var mixer = mixitup(containerEl, { 9280 * classNames: { 9281 * block: 'portfolio' 9282 * } 9283 * }); 9284 * 9285 * // Active control output: "portfolio-control-active" 9286 * 9287 * @example <caption>Example 2: Removing `config.classNames.block`</caption> 9288 * var mixer = mixitup(containerEl, { 9289 * classNames: { 9290 * block: '' 9291 * } 9292 * }); 9293 * 9294 * // Active control output: "control-active" 9295 * 9296 * @name block 9297 * @memberof mixitup.Config.classNames 9298 * @instance 9299 * @type {string} 9300 * @default 'mixitup' 9301 */ 9302 9303 this.block = 'mixitup'; 9304 9305 /** 9306 * The "element" portion of the class name added to container. 9307 * 9308 * @name elementContainer 9309 * @memberof mixitup.Config.classNames 9310 * @instance 9311 * @type {string} 9312 * @default 'container' 9313 */ 9314 9315 this.elementContainer = 'container'; 9316 9317 /** 9318 * The "element" portion of the class name added to filter controls. 9319 * 9320 * By default, all filter, sort, multimix and toggle controls take the same element value of `'control'`, but 9321 * each type's element value can be individually overwritten to match the unique classNames of your controls as needed. 9322 * 9323 * @example <caption>Example 1: changing the `config.classNames.elementFilter` value</caption> 9324 * var mixer = mixitup(containerEl, { 9325 * classNames: { 9326 * elementFilter: 'filter' 9327 * } 9328 * }); 9329 * 9330 * // Active filter output: "mixitup-filter-active" 9331 * 9332 * @example <caption>Example 2: changing the `config.classNames.block` and `config.classNames.elementFilter` values</caption> 9333 * var mixer = mixitup(containerEl, { 9334 * classNames: { 9335 * block: 'portfolio', 9336 * elementFilter: 'filter' 9337 * } 9338 * }); 9339 * 9340 * // Active filter output: "portfolio-filter-active" 9341 * 9342 * @name elementFilter 9343 * @memberof mixitup.Config.classNames 9344 * @instance 9345 * @type {string} 9346 * @default 'control' 9347 */ 9348 9349 this.elementFilter = 'control'; 9350 9351 /** 9352 * The "element" portion of the class name added to sort controls. 9353 * 9354 * By default, all filter, sort, multimix and toggle controls take the same element value of `'control'`, but 9355 * each type's element value can be individually overwritten to match the unique classNames of your controls as needed. 9356 * 9357 * @example <caption>Example 1: changing the `config.classNames.elementSort` value</caption> 9358 * var mixer = mixitup(containerEl, { 9359 * classNames: { 9360 * elementSort: 'sort' 9361 * } 9362 * }); 9363 * 9364 * // Active sort output: "mixitup-sort-active" 9365 * 9366 * @example <caption>Example 2: changing the `config.classNames.block` and `config.classNames.elementSort` values</caption> 9367 * var mixer = mixitup(containerEl, { 9368 * classNames: { 9369 * block: 'portfolio', 9370 * elementSort: 'sort' 9371 * } 9372 * }); 9373 * 9374 * // Active sort output: "portfolio-sort-active" 9375 * 9376 * @name elementSort 9377 * @memberof mixitup.Config.classNames 9378 * @instance 9379 * @type {string} 9380 * @default 'control' 9381 */ 9382 9383 this.elementSort = 'control'; 9384 9385 /** 9386 * The "element" portion of the class name added to multimix controls. 9387 * 9388 * By default, all filter, sort, multimix and toggle controls take the same element value of `'control'`, but 9389 * each type's element value can be individually overwritten to match the unique classNames of your controls as needed. 9390 * 9391 * @example <caption>Example 1: changing the `config.classNames.elementMultimix` value</caption> 9392 * var mixer = mixitup(containerEl, { 9393 * classNames: { 9394 * elementMultimix: 'multimix' 9395 * } 9396 * }); 9397 * 9398 * // Active multimix output: "mixitup-multimix-active" 9399 * 9400 * @example <caption>Example 2: changing the `config.classNames.block` and `config.classNames.elementMultimix` values</caption> 9401 * var mixer = mixitup(containerEl, { 9402 * classNames: { 9403 * block: 'portfolio', 9404 * elementSort: 'multimix' 9405 * } 9406 * }); 9407 * 9408 * // Active multimix output: "portfolio-multimix-active" 9409 * 9410 * @name elementMultimix 9411 * @memberof mixitup.Config.classNames 9412 * @instance 9413 * @type {string} 9414 * @default 'control' 9415 */ 9416 9417 this.elementMultimix = 'control'; 9418 9419 /** 9420 * The "element" portion of the class name added to toggle controls. 9421 * 9422 * By default, all filter, sort, multimix and toggle controls take the same element value of `'control'`, but 9423 * each type's element value can be individually overwritten to match the unique classNames of your controls as needed. 9424 * 9425 * @example <caption>Example 1: changing the `config.classNames.elementToggle` value</caption> 9426 * var mixer = mixitup(containerEl, { 9427 * classNames: { 9428 * elementToggle: 'toggle' 9429 * } 9430 * }); 9431 * 9432 * // Active toggle output: "mixitup-toggle-active" 9433 * 9434 * @example <caption>Example 2: changing the `config.classNames.block` and `config.classNames.elementToggle` values</caption> 9435 * var mixer = mixitup(containerEl, { 9436 * classNames: { 9437 * block: 'portfolio', 9438 * elementToggle: 'toggle' 9439 * } 9440 * }); 9441 * 9442 * // Active toggle output: "portfolio-toggle-active" 9443 * 9444 * @name elementToggle 9445 * @memberof mixitup.Config.classNames 9446 * @instance 9447 * @type {string} 9448 * @default 'control' 9449 */ 9450 9451 this.elementToggle = 'control'; 9452 9453 /** 9454 * The "modifier" portion of the class name added to active controls. 9455 * @name modifierActive 9456 * @memberof mixitup.Config.classNames 9457 * @instance 9458 * @type {string} 9459 * @default 'active' 9460 */ 9461 9462 this.modifierActive = 'active'; 9463 9464 /** 9465 * The "modifier" portion of the class name added to disabled controls. 9466 * 9467 * @name modifierDisabled 9468 * @memberof mixitup.Config.classNames 9469 * @instance 9470 * @type {string} 9471 * @default 'disabled' 9472 */ 9473 9474 this.modifierDisabled = 'disabled'; 9475 9476 /** 9477 * The "modifier" portion of the class name added to the container when in a "failed" state. 9478 * 9479 * @name modifierFailed 9480 * @memberof mixitup.Config.classNames 9481 * @instance 9482 * @type {string} 9483 * @default 'failed' 9484 */ 9485 9486 this.modifierFailed = 'failed'; 9487 9488 /** 9489 * The delineator used between the "block" and "element" portions of any class name added by MixItUp. 9490 * 9491 * If the block portion is ommited by setting it to an empty string, no delineator will be added. 9492 * 9493 * @example <caption>Example: changing the delineator to match BEM convention</caption> 9494 * var mixer = mixitup(containerEl, { 9495 * classNames: { 9496 * delineatorElement: '__' 9497 * } 9498 * }); 9499 * 9500 * // example active control output: "mixitup__control-active" 9501 * 9502 * @name delineatorElement 9503 * @memberof mixitup.Config.classNames 9504 * @instance 9505 * @type {string} 9506 * @default '-' 9507 */ 9508 9509 this.delineatorElement = '-'; 9510 9511 /** 9512 * The delineator used between the "element" and "modifier" portions of any class name added by MixItUp. 9513 * 9514 * If the element portion is ommited by setting it to an empty string, no delineator will be added. 9515 * 9516 * @example <caption>Example: changing both delineators to match BEM convention</caption> 9517 * var mixer = mixitup(containerEl, { 9518 * classNames: { 9519 * delineatorElement: '__' 9520 * delineatorModifier: '--' 9521 * } 9522 * }); 9523 * 9524 * // Active control output: "mixitup__control--active" 9525 * 9526 * @name delineatorModifier 9527 * @memberof mixitup.Config.classNames 9528 * @instance 9529 * @type {string} 9530 * @default '-' 9531 */ 9532 9533 this.delineatorModifier = '-'; 9534 9535 this.callActions('afterConstruct'); 9536 9537 h.seal(this); 9538 }; 9539 9540 mixitup.BaseStatic.call(mixitup.ConfigClassNames); 9541 9542 mixitup.ConfigClassNames.prototype = Object.create(mixitup.Base.prototype); 9543 9544 mixitup.ConfigClassNames.prototype.constructor = mixitup.ConfigClassNames; 9545 9546 /** 9547 * A group of properties relating to MixItUp's dataset API. 9548 * 9549 * @constructor 9550 * @memberof mixitup.Config 9551 * @name data 9552 * @namespace 9553 * @public 9554 * @since 3.0.0 9555 */ 9556 9557 mixitup.ConfigData = function() { 9558 mixitup.Base.call(this); 9559 9560 this.callActions('beforeConstruct'); 9561 9562 /** 9563 * A string specifying the name of the key containing your data model's unique 9564 * identifier (UID). To use the dataset API, a UID key must be specified and 9565 * be present and unique on all objects in the dataset you provide to MixItUp. 9566 * 9567 * For example, if your dataset is made up of MongoDB documents, the UID 9568 * key would be `'id'` or `'_id'`. 9569 * 9570 * @example <caption>Example: Setting the UID to `'id'`</caption> 9571 * var mixer = mixitup(containerEl, { 9572 * data: { 9573 * uidKey: 'id' 9574 * } 9575 * }); 9576 * 9577 * @name uidKey 9578 * @memberof mixitup.Config.data 9579 * @instance 9580 * @type {string} 9581 * @default '' 9582 */ 9583 9584 this.uidKey = ''; 9585 9586 /** 9587 * A boolean dictating whether or not MixItUp should "dirty check" each object in 9588 * your dataset for changes whenever `.dataset()` is called, and re-render any targets 9589 * for which a change is found. 9590 * 9591 * Depending on the complexity of your data model, dirty checking can be expensive 9592 * and is therefore disabled by default. 9593 * 9594 * NB: For changes to be detected, a new immutable instance of the edited model must be 9595 * provided to mixitup, rather than manipulating properties on the existing instance. 9596 * If your changes are a result of a DB write and read, you will most likely be calling 9597 * `.dataset()` with a clean set of objects each time, so this will not be an issue. 9598 * 9599 * @example <caption>Example: Enabling dirty checking</caption> 9600 * 9601 * var myDataset = [ 9602 * { 9603 * id: 0, 9604 * title: "Blog Post Title 0" 9605 * ... 9606 * }, 9607 * { 9608 * id: 1, 9609 * title: "Blog Post Title 1" 9610 * ... 9611 * } 9612 * ]; 9613 * 9614 * // Instantiate a mixer with a pre-loaded dataset, and a target renderer 9615 * // function defined 9616 * 9617 * var mixer = mixitup(containerEl, { 9618 * data: { 9619 * uidKey: 'id', 9620 * dirtyCheck: true 9621 * }, 9622 * load: { 9623 * dataset: myDataset 9624 * }, 9625 * render: { 9626 * target: function() { ... } 9627 * } 9628 * }); 9629 * 9630 * // For illustration, we will clone and edit the second object in the dataset. 9631 * // NB: this would typically be done server-side in response to a DB update, 9632 * and then re-queried via an API. 9633 * 9634 * myDataset[1] = Object.assign({}, myDataset[1]); 9635 * 9636 * myDataset[1].title = 'Blog Post Title 11'; 9637 * 9638 * mixer.dataset(myDataset) 9639 * .then(function() { 9640 * // the target with ID "1", will be re-rendered reflecting its new title 9641 * }); 9642 * 9643 * @name dirtyCheck 9644 * @memberof mixitup.Config.data 9645 * @instance 9646 * @type {boolean} 9647 * @default false 9648 */ 9649 9650 this.dirtyCheck = false; 9651 9652 this.callActions('afterConstruct'); 9653 9654 h.seal(this); 9655 }; 9656 9657 mixitup.BaseStatic.call(mixitup.ConfigData); 9658 9659 mixitup.ConfigData.prototype = Object.create(mixitup.Base.prototype); 9660 9661 mixitup.ConfigData.prototype.constructor = mixitup.ConfigData; 9662 9663 /** 9664 * A group of properties allowing the toggling of various debug features. 9665 * 9666 * @constructor 9667 * @memberof mixitup.Config 9668 * @name debug 9669 * @namespace 9670 * @public 9671 * @since 3.0.0 9672 */ 9673 9674 mixitup.ConfigDebug = function() { 9675 mixitup.Base.call(this); 9676 9677 this.callActions('beforeConstruct'); 9678 9679 /** 9680 * A boolean dictating whether or not the mixer instance returned by the 9681 * `mixitup()` factory function should expose private properties and methods. 9682 * 9683 * By default, mixer instances only expose their public API, but enabling 9684 * debug mode will give you access to various mixer internals which may aid 9685 * in debugging, or the authoring of extensions. 9686 * 9687 * @example <caption>Example: Enabling debug mode</caption> 9688 * 9689 * var mixer = mixitup(containerEl, { 9690 * debug: { 9691 * enable: true 9692 * } 9693 * }); 9694 * 9695 * // Private properties and methods will now be visible on the mixer instance: 9696 * 9697 * console.log(mixer); 9698 * 9699 * @name enable 9700 * @memberof mixitup.Config.debug 9701 * @instance 9702 * @type {boolean} 9703 * @default false 9704 */ 9705 9706 this.enable = false; 9707 9708 /** 9709 * A boolean dictating whether or not warnings should be shown when various 9710 * common gotchas occur. 9711 * 9712 * Warnings are intended to provide insights during development when something 9713 * occurs that is not a fatal, but may indicate an issue with your integration, 9714 * and are therefore turned on by default. However, you may wish to disable 9715 * them in production. 9716 * 9717 * @example <caption>Example 1: Disabling warnings</caption> 9718 * 9719 * var mixer = mixitup(containerEl, { 9720 * debug: { 9721 * showWarnings: false 9722 * } 9723 * }); 9724 * 9725 * @example <caption>Example 2: Disabling warnings based on environment</caption> 9726 * 9727 * var showWarnings = myAppConfig.environment === 'development' ? true : false; 9728 * 9729 * var mixer = mixitup(containerEl, { 9730 * debug: { 9731 * showWarnings: showWarnings 9732 * } 9733 * }); 9734 * 9735 * @name showWarnings 9736 * @memberof mixitup.Config.debug 9737 * @instance 9738 * @type {boolean} 9739 * @default true 9740 */ 9741 9742 this.showWarnings = true; 9743 9744 /** 9745 * Used for server-side testing only. 9746 * 9747 * @private 9748 * @name fauxAsync 9749 * @memberof mixitup.Config.debug 9750 * @instance 9751 * @type {boolean} 9752 * @default false 9753 */ 9754 9755 this.fauxAsync = false; 9756 9757 this.callActions('afterConstruct'); 9758 9759 h.seal(this); 9760 }; 9761 9762 mixitup.BaseStatic.call(mixitup.ConfigDebug); 9763 9764 mixitup.ConfigDebug.prototype = Object.create(mixitup.Base.prototype); 9765 9766 mixitup.ConfigDebug.prototype.constructor = mixitup.ConfigDebug; 9767 9768 /** 9769 * A group of properties relating to the layout of the container. 9770 * 9771 * @constructor 9772 * @memberof mixitup.Config 9773 * @name layout 9774 * @namespace 9775 * @public 9776 * @since 3.0.0 9777 */ 9778 9779 mixitup.ConfigLayout = function() { 9780 mixitup.Base.call(this); 9781 9782 this.callActions('beforeConstruct'); 9783 9784 /** 9785 * A boolean dictating whether or not mixitup should query all descendants 9786 * of the container for targets, or only immediate children. 9787 * 9788 * By default, mixitup will query all descendants matching the 9789 * `selectors.target` selector when indexing targets upon instantiation. 9790 * This allows for targets to be nested inside a sub-container which is 9791 * useful when ring-fencing targets from locally scoped controls in your 9792 * markup (see `controls.scope`). 9793 * 9794 * However, if you are building a more complex UI requiring the nesting 9795 * of mixers within mixers, you will most likely want to limit targets to 9796 * immediate children of the container by setting this property to `false`. 9797 * 9798 * @example <caption>Example: Restricting targets to immediate children</caption> 9799 * 9800 * var mixer = mixitup(containerEl, { 9801 * layout: { 9802 * allowNestedTargets: false 9803 * } 9804 * }); 9805 * 9806 * @name allowNestedTargets 9807 * @memberof mixitup.Config.layout 9808 * @instance 9809 * @type {boolean} 9810 * @default true 9811 */ 9812 9813 this.allowNestedTargets = true; 9814 9815 /** 9816 * A string specifying an optional class name to apply to the container when in 9817 * its default state. 9818 * 9819 * By changing this class name or adding a class name to the container via the 9820 * `.changeLayout()` API method, the CSS layout of the container can be changed, 9821 * and MixItUp will attemp to gracefully animate the container and its targets 9822 * between states. 9823 * 9824 * @example <caption>Example 1: Specifying a container class name</caption> 9825 * 9826 * var mixer = mixitup(containerEl, { 9827 * layout: { 9828 * containerClassName: 'grid' 9829 * } 9830 * }); 9831 * 9832 * @example <caption>Example 2: Changing the default class name with `.changeLayout()`</caption> 9833 * 9834 * var mixer = mixitup(containerEl, { 9835 * layout: { 9836 * containerClassName: 'grid' 9837 * } 9838 * }); 9839 * 9840 * mixer.changeLayout('list') 9841 * .then(function(state) { 9842 * console.log(state.activeContainerClass); // "list" 9843 * }); 9844 * 9845 * @name containerClassName 9846 * @memberof mixitup.Config.layout 9847 * @instance 9848 * @type {string} 9849 * @default '' 9850 */ 9851 9852 this.containerClassName = ''; 9853 9854 /** 9855 * A reference to a non-target sibling element after which to insert targets 9856 * when there are no targets in the container. 9857 * 9858 * @example <caption>Example: Setting a `siblingBefore` reference element</caption> 9859 * 9860 * var addButton = containerEl.querySelector('button'); 9861 * 9862 * var mixer = mixitup(containerEl, { 9863 * layout: { 9864 * siblingBefore: addButton 9865 * } 9866 * }); 9867 * 9868 * @name siblingBefore 9869 * @memberof mixitup.Config.layout 9870 * @instance 9871 * @type {HTMLElement} 9872 * @default null 9873 */ 9874 9875 this.siblingBefore = null; 9876 9877 /** 9878 * A reference to a non-target sibling element before which to insert targets 9879 * when there are no targets in the container. 9880 * 9881 * @example <caption>Example: Setting an `siblingAfter` reference element</caption> 9882 * 9883 * var gap = containerEl.querySelector('.gap'); 9884 * 9885 * var mixer = mixitup(containerEl, { 9886 * layout: { 9887 * siblingAfter: gap 9888 * } 9889 * }); 9890 * 9891 * @name siblingAfter 9892 * @memberof mixitup.Config.layout 9893 * @instance 9894 * @type {HTMLElement} 9895 * @default null 9896 */ 9897 9898 this.siblingAfter = null; 9899 9900 this.callActions('afterConstruct'); 9901 9902 h.seal(this); 9903 }; 9904 9905 mixitup.BaseStatic.call(mixitup.ConfigLayout); 9906 9907 mixitup.ConfigLayout.prototype = Object.create(mixitup.Base.prototype); 9908 9909 mixitup.ConfigLayout.prototype.constructor = mixitup.ConfigLayout; 9910 9911 /** 9912 * A group of properties defining the initial state of the mixer on load (instantiation). 9913 * 9914 * @constructor 9915 * @memberof mixitup.Config 9916 * @name load 9917 * @namespace 9918 * @public 9919 * @since 2.0.0 9920 */ 9921 9922 mixitup.ConfigLoad = function() { 9923 mixitup.Base.call(this); 9924 9925 this.callActions('beforeConstruct'); 9926 9927 /** 9928 * A string defining any filtering to be statically applied to the mixer on load. 9929 * As per the `.filter()` API, this can be any valid selector string, or the 9930 * values `'all'` or `'none'`. 9931 * 9932 * @example <caption>Example 1: Defining an initial filter selector to be applied on load</caption> 9933 * 9934 * // The mixer will show only those targets matching '.category-a' on load. 9935 * 9936 * var mixer = mixitup(containerEl, { 9937 * load: { 9938 * filter: '.category-a' 9939 * } 9940 * }); 9941 * 9942 * @example <caption>Example 2: Hiding all targets on load</caption> 9943 * 9944 * // The mixer will show hide all targets on load. 9945 * 9946 * var mixer = mixitup(containerEl, { 9947 * load: { 9948 * filter: 'none' 9949 * } 9950 * }); 9951 * 9952 * @name filter 9953 * @memberof mixitup.Config.load 9954 * @instance 9955 * @type {string} 9956 * @default 'all' 9957 */ 9958 9959 this.filter = 'all'; 9960 9961 /** 9962 * A string defining any sorting to be statically applied to the mixer on load. 9963 * As per the `.sort()` API, this should be a valid "sort string" made up of 9964 * an attribute to sort by (or `'default'`) followed by an optional sorting 9965 * order, or the value `'random'`; 9966 * 9967 * @example <caption>Example: Defining sorting to be applied on load</caption> 9968 * 9969 * // The mixer will sort the container by the value of the `data-published-date` 9970 * // attribute, in descending order. 9971 * 9972 * var mixer = mixitup(containerEl, { 9973 * load: { 9974 * sort: 'published-date:desc' 9975 * } 9976 * }); 9977 * 9978 * @name sort 9979 * @memberof mixitup.Config.load 9980 * @instance 9981 * @type {string} 9982 * @default 'default:asc' 9983 */ 9984 9985 this.sort = 'default:asc'; 9986 9987 /** 9988 * An array of objects representing the underlying data of any pre-rendered targets, 9989 * when using the `.dataset()` API. 9990 * 9991 * NB: If targets are pre-rendered when the mixer is instantiated, this must be set. 9992 * 9993 * @example <caption>Example: Defining the initial underyling dataset</caption> 9994 * 9995 * var myDataset = [ 9996 * { 9997 * id: 0, 9998 * title: "Blog Post Title 0", 9999 * ... 10000 * }, 10001 * { 10002 * id: 1, 10003 * title: "Blog Post Title 1", 10004 * ... 10005 * } 10006 * ]; 10007 * 10008 * var mixer = mixitup(containerEl, { 10009 * data: { 10010 * uidKey: 'id' 10011 * }, 10012 * load: { 10013 * dataset: myDataset 10014 * } 10015 * }); 10016 * 10017 * @name dataset 10018 * @memberof mixitup.Config.load 10019 * @instance 10020 * @type {Array.<object>} 10021 * @default null 10022 */ 10023 10024 this.dataset = null; 10025 10026 this.callActions('afterConstruct'); 10027 10028 h.seal(this); 10029 }; 10030 10031 mixitup.BaseStatic.call(mixitup.ConfigLoad); 10032 10033 mixitup.ConfigLoad.prototype = Object.create(mixitup.Base.prototype); 10034 10035 mixitup.ConfigLoad.prototype.constructor = mixitup.ConfigLoad; 10036 10037 /** 10038 * A group of properties defining the selectors used to query elements within a mixitup container. 10039 * 10040 * @constructor 10041 * @memberof mixitup.Config 10042 * @name selectors 10043 * @namespace 10044 * @public 10045 * @since 3.0.0 10046 */ 10047 10048 mixitup.ConfigSelectors = function() { 10049 mixitup.Base.call(this); 10050 10051 this.callActions('beforeConstruct'); 10052 10053 /** 10054 * A selector string used to query and index target elements within the container. 10055 * 10056 * By default, the class selector `'.mix'` is used, but this can be changed to an 10057 * attribute or element selector to match the style of your project. 10058 * 10059 * @example <caption>Example 1: Changing the target selector</caption> 10060 * 10061 * var mixer = mixitup(containerEl, { 10062 * selectors: { 10063 * target: '.portfolio-item' 10064 * } 10065 * }); 10066 * 10067 * @example <caption>Example 2: Using an attribute selector as a target selector</caption> 10068 * 10069 * // The mixer will search for any children with the attribute `data-ref="mix"` 10070 * 10071 * var mixer = mixitup(containerEl, { 10072 * selectors: { 10073 * target: '[data-ref="mix"]' 10074 * } 10075 * }); 10076 * 10077 * @name target 10078 * @memberof mixitup.Config.selectors 10079 * @instance 10080 * @type {string} 10081 * @default '.mix' 10082 */ 10083 10084 this.target = '.mix'; 10085 10086 /** 10087 * A optional selector string used to add further specificity to the querying of control elements, 10088 * in addition to their mandatory data attribute (e.g. `data-filter`, `data-toggle`, `data-sort`). 10089 * 10090 * This can be used if other elements in your document must contain the above attributes 10091 * (e.g. for use in third-party scripts), and would otherwise interfere with MixItUp. Adding 10092 * an additional `control` selector of your choice allows MixItUp to restrict event handling 10093 * to only those elements matching the defined selector. 10094 * 10095 * @name control 10096 * @memberof mixitup.Config.selectors 10097 * @instance 10098 * @type {string} 10099 * @default '' 10100 * 10101 * @example <caption>Example 1: Adding a `selectors.control` selector</caption> 10102 * 10103 * var mixer = mixitup(containerEl, { 10104 * selectors: { 10105 * control: '.mixitup-control' 10106 * } 10107 * }); 10108 * 10109 * // Will not be handled: 10110 * // <button data-filter=".category-a"></button> 10111 * 10112 * // Will be handled: 10113 * // <button class="mixitup-control" data-filter=".category-a"></button> 10114 */ 10115 10116 this.control = ''; 10117 10118 this.callActions('afterConstruct'); 10119 10120 h.seal(this); 10121 }; 10122 10123 mixitup.BaseStatic.call(mixitup.ConfigSelectors); 10124 10125 mixitup.ConfigSelectors.prototype = Object.create(mixitup.Base.prototype); 10126 10127 mixitup.ConfigSelectors.prototype.constructor = mixitup.ConfigSelectors; 10128 10129 /** 10130 * A group of optional render functions for creating and updating elements. 10131 * 10132 * All render functions receive a data object, and should return a valid HTML string. 10133 * 10134 * @constructor 10135 * @memberof mixitup.Config 10136 * @name render 10137 * @namespace 10138 * @public 10139 * @since 3.0.0 10140 */ 10141 10142 mixitup.ConfigRender = function() { 10143 mixitup.Base.call(this); 10144 10145 this.callActions('beforeConstruct'); 10146 10147 /** 10148 * A function returning an HTML string representing a target element, or a reference to a 10149 * single DOM element. 10150 * 10151 * The function is invoked as part of the `.dataset()` API, whenever a new item is added 10152 * to the dataset, or an item in the dataset changes (if `dataset.dirtyCheck` is enabled). 10153 * 10154 * The function receives the relevant dataset item as its first parameter. 10155 * 10156 * @example <caption>Example 1: Using string concatenation</caption> 10157 * 10158 * var mixer = mixitup(containerEl, { 10159 * render: { 10160 * target: function(item) { 10161 * return ( 10162 * '<div class="mix">' + 10163 * '<h2>' + item.title + '</h2>' + 10164 * '</div>' 10165 * ); 10166 * } 10167 * } 10168 * }); 10169 * 10170 * @example <caption>Example 2: Using an ES2015 template literal</caption> 10171 * 10172 * var mixer = mixitup(containerEl, { 10173 * render: { 10174 * target: function(item) { 10175 * return ( 10176 * `<div class="mix"> 10177 * <h2>${item.title}</h2> 10178 * </div>` 10179 * ); 10180 * } 10181 * } 10182 * }); 10183 * 10184 * @example <caption>Example 3: Using a Handlebars template</caption> 10185 * 10186 * var targetTemplate = Handlebars.compile('<div class="mix"><h2>{{title}}</h2></div>'); 10187 * 10188 * var mixer = mixitup(containerEl, { 10189 * render: { 10190 * target: targetTemplate 10191 * } 10192 * }); 10193 * 10194 * @example <caption>Example 4: Returning a DOM element</caption> 10195 * 10196 * var mixer = mixitup(containerEl, { 10197 * render: { 10198 * target: function(item) { 10199 * // Create a single element using your framework's built-in renderer 10200 * 10201 * var el = ... 10202 * 10203 * return el; 10204 * } 10205 * } 10206 * }); 10207 * 10208 * @name target 10209 * @memberof mixitup.Config.render 10210 * @instance 10211 * @type {function} 10212 * @default 'null' 10213 */ 10214 10215 this.target = null; 10216 10217 this.callActions('afterConstruct'); 10218 10219 h.seal(this); 10220 }; 10221 10222 mixitup.BaseStatic.call(mixitup.ConfigRender); 10223 10224 mixitup.ConfigRender.prototype = Object.create(mixitup.Base.prototype); 10225 10226 mixitup.ConfigRender.prototype.constructor = mixitup.ConfigRender; 10227 10228 /** 10229 * @constructor 10230 * @memberof mixitup 10231 * @private 10232 * @since 3.0.0 10233 */ 10234 10235 mixitup.ConfigTemplates = function() { 10236 mixitup.Base.call(this); 10237 10238 this.callActions('beforeConstruct'); 10239 10240 this.callActions('afterConstruct'); 10241 10242 h.seal(this); 10243 }; 10244 10245 mixitup.BaseStatic.call(mixitup.ConfigTemplates); 10246 10247 mixitup.ConfigTemplates.prototype = Object.create(mixitup.Base.prototype); 10248 10249 mixitup.ConfigTemplates.prototype.constructor = mixitup.ConfigTemplates; 10250 10251 /** 10252 * `mixitup.Config` is an interface used for customising the functionality of a 10253 * mixer instance. It is organised into several semantically distinct sub-objects, 10254 * each one pertaining to a particular aspect of MixItUp functionality. 10255 * 10256 * An object literal containing any or all of the available properies, 10257 * known as the "configuration object", can be passed as the second parameter to 10258 * the `mixitup` factory function when creating a mixer instance to customise its 10259 * functionality as needed. 10260 * 10261 * If no configuration object is passed, the mixer instance will take on the default 10262 * configuration values detailed below. 10263 * 10264 * @example <caption>Example 1: Creating and passing the configuration object</caption> 10265 * // Create a configuration object with desired values 10266 * 10267 * var config = { 10268 * animation: { 10269 * enable: false 10270 * }, 10271 * selectors: { 10272 * target: '.item' 10273 * } 10274 * }; 10275 * 10276 * // Pass the configuration object to the mixitup factory function 10277 * 10278 * var mixer = mixitup(containerEl, config); 10279 * 10280 * @example <caption>Example 2: Passing the configuration object inline</caption> 10281 * // Typically, the configuration object is passed inline for brevity. 10282 * 10283 * var mixer = mixitup(containerEl, { 10284 * controls: { 10285 * live: true, 10286 * toggleLogic: 'and' 10287 * } 10288 * }); 10289 * 10290 * 10291 * @constructor 10292 * @memberof mixitup 10293 * @namespace 10294 * @public 10295 * @since 2.0.0 10296 */ 10297 10298 mixitup.Config = function() { 10299 mixitup.Base.call(this); 10300 10301 this.callActions('beforeConstruct'); 10302 10303 this.animation = new mixitup.ConfigAnimation(); 10304 this.behavior = new mixitup.ConfigBehavior(); 10305 this.callbacks = new mixitup.ConfigCallbacks(); 10306 this.controls = new mixitup.ConfigControls(); 10307 this.classNames = new mixitup.ConfigClassNames(); 10308 this.data = new mixitup.ConfigData(); 10309 this.debug = new mixitup.ConfigDebug(); 10310 this.layout = new mixitup.ConfigLayout(); 10311 this.load = new mixitup.ConfigLoad(); 10312 this.selectors = new mixitup.ConfigSelectors(); 10313 this.render = new mixitup.ConfigRender(); 10314 this.templates = new mixitup.ConfigTemplates(); 10315 10316 this.callActions('afterConstruct'); 10317 10318 h.seal(this); 10319 }; 10320 10321 mixitup.BaseStatic.call(mixitup.Config); 10322 10323 mixitup.Config.prototype = Object.create(mixitup.Base.prototype); 10324 10325 mixitup.Config.prototype.constructor = mixitup.Config; 10326 10327 /** 10328 * @constructor 10329 * @memberof mixitup 10330 * @private 10331 * @since 3.0.0 10332 */ 10333 10334 mixitup.MixerDom = function() { 10335 mixitup.Base.call(this); 10336 10337 this.callActions('beforeConstruct'); 10338 10339 this.document = null; 10340 this.body = null; 10341 this.container = null; 10342 this.parent = null; 10343 this.targets = []; 10344 10345 this.callActions('afterConstruct'); 10346 10347 h.seal(this); 10348 }; 10349 10350 mixitup.BaseStatic.call(mixitup.MixerDom); 10351 10352 mixitup.MixerDom.prototype = Object.create(mixitup.Base.prototype); 10353 10354 mixitup.MixerDom.prototype.constructor = mixitup.MixerDom; 10355 10356 /** 10357 * @constructor 10358 * @memberof mixitup 10359 * @private 10360 * @since 3.0.0 10361 */ 10362 10363 mixitup.UiClassNames = function() { 10364 mixitup.Base.call(this); 10365 10366 this.callActions('beforeConstruct'); 10367 10368 this.base = ''; 10369 this.active = ''; 10370 this.disabled = ''; 10371 10372 this.callActions('afterConstruct'); 10373 10374 h.seal(this); 10375 }; 10376 10377 mixitup.BaseStatic.call(mixitup.UiClassNames); 10378 10379 mixitup.UiClassNames.prototype = Object.create(mixitup.Base.prototype); 10380 10381 mixitup.UiClassNames.prototype.constructor = mixitup.UiClassNames; 10382 10383 /** 10384 * An object into which all arbitrary arguments sent to '.dataset()' are mapped. 10385 * 10386 * @constructor 10387 * @memberof mixitup 10388 * @private 10389 * @since 3.0.0 10390 */ 10391 10392 mixitup.CommandDataset = function() { 10393 mixitup.Base.call(this); 10394 10395 this.callActions('beforeConstruct'); 10396 10397 this.dataset = null; 10398 10399 this.callActions('afterConstruct'); 10400 10401 h.seal(this); 10402 }; 10403 10404 mixitup.BaseStatic.call(mixitup.CommandDataset); 10405 10406 mixitup.CommandDataset.prototype = Object.create(mixitup.Base.prototype); 10407 10408 mixitup.CommandDataset.prototype.constructor = mixitup.CommandDataset; 10409 10410 /** 10411 * An object into which all arbitrary arguments sent to '.multimix()' are mapped. 10412 * 10413 * @constructor 10414 * @memberof mixitup 10415 * @private 10416 * @since 3.0.0 10417 */ 10418 10419 mixitup.CommandMultimix = function() { 10420 mixitup.Base.call(this); 10421 10422 this.callActions('beforeConstruct'); 10423 10424 this.filter = null; 10425 this.sort = null; 10426 this.insert = null; 10427 this.remove = null; 10428 this.changeLayout = null; 10429 10430 this.callActions('afterConstruct'); 10431 10432 h.seal(this); 10433 }; 10434 10435 mixitup.BaseStatic.call(mixitup.CommandMultimix); 10436 10437 mixitup.CommandMultimix.prototype = Object.create(mixitup.Base.prototype); 10438 10439 mixitup.CommandMultimix.prototype.constructor = mixitup.CommandMultimix; 10440 10441 /** 10442 * An object into which all arbitrary arguments sent to '.filter()' are mapped. 10443 * 10444 * @constructor 10445 * @memberof mixitup 10446 * @private 10447 * @since 3.0.0 10448 */ 10449 10450 mixitup.CommandFilter = function() { 10451 mixitup.Base.call(this); 10452 10453 this.callActions('beforeConstruct'); 10454 10455 this.selector = ''; 10456 this.collection = null; 10457 this.action = 'show'; // enum: ['show', 'hide'] 10458 10459 this.callActions('afterConstruct'); 10460 10461 h.seal(this); 10462 }; 10463 10464 mixitup.BaseStatic.call(mixitup.CommandFilter); 10465 10466 mixitup.CommandFilter.prototype = Object.create(mixitup.Base.prototype); 10467 10468 mixitup.CommandFilter.prototype.constructor = mixitup.CommandFilter; 10469 10470 /** 10471 * An object into which all arbitrary arguments sent to '.sort()' are mapped. 10472 * 10473 * @constructor 10474 * @memberof mixitup 10475 * @private 10476 * @since 3.0.0 10477 */ 10478 10479 mixitup.CommandSort = function() { 10480 mixitup.Base.call(this); 10481 10482 this.callActions('beforeConstruct'); 10483 10484 this.sortString = ''; 10485 this.attribute = ''; 10486 this.order = 'asc'; 10487 this.collection = null; 10488 this.next = null; 10489 10490 this.callActions('afterConstruct'); 10491 10492 h.seal(this); 10493 }; 10494 10495 mixitup.BaseStatic.call(mixitup.CommandSort); 10496 10497 mixitup.CommandSort.prototype = Object.create(mixitup.Base.prototype); 10498 10499 mixitup.CommandSort.prototype.constructor = mixitup.CommandSort; 10500 10501 /** 10502 * An object into which all arbitrary arguments sent to '.insert()' are mapped. 10503 * 10504 * @constructor 10505 * @memberof mixitup 10506 * @private 10507 * @since 3.0.0 10508 */ 10509 10510 mixitup.CommandInsert = function() { 10511 mixitup.Base.call(this); 10512 10513 this.callActions('beforeConstruct'); 10514 10515 this.index = 0; 10516 this.collection = []; 10517 this.position = 'before'; // enum: ['before', 'after'] 10518 this.sibling = null; 10519 10520 this.callActions('afterConstruct'); 10521 10522 h.seal(this); 10523 }; 10524 10525 mixitup.BaseStatic.call(mixitup.CommandInsert); 10526 10527 mixitup.CommandInsert.prototype = Object.create(mixitup.Base.prototype); 10528 10529 mixitup.CommandInsert.prototype.constructor = mixitup.CommandInsert; 10530 10531 /** 10532 * An object into which all arbitrary arguments sent to '.remove()' are mapped. 10533 * 10534 * @constructor 10535 * @memberof mixitup 10536 * @private 10537 * @since 3.0.0 10538 */ 10539 10540 mixitup.CommandRemove = function() { 10541 mixitup.Base.call(this); 10542 10543 this.callActions('beforeConstruct'); 10544 10545 this.targets = []; 10546 this.collection = []; 10547 10548 this.callActions('afterConstruct'); 10549 10550 h.seal(this); 10551 }; 10552 10553 mixitup.BaseStatic.call(mixitup.CommandRemove); 10554 10555 mixitup.CommandRemove.prototype = Object.create(mixitup.Base.prototype); 10556 10557 mixitup.CommandRemove.prototype.constructor = mixitup.CommandRemove; 10558 10559 /** 10560 * An object into which all arbitrary arguments sent to '.changeLayout()' are mapped. 10561 * 10562 * @constructor 10563 * @memberof mixitup 10564 * @private 10565 * @since 3.0.0 10566 */ 10567 10568 mixitup.CommandChangeLayout = function() { 10569 mixitup.Base.call(this); 10570 10571 this.callActions('beforeConstruct'); 10572 10573 this.containerClassName = ''; 10574 10575 this.callActions('afterConstruct'); 10576 10577 h.seal(this); 10578 }; 10579 10580 mixitup.BaseStatic.call(mixitup.CommandChangeLayout); 10581 10582 mixitup.CommandChangeLayout.prototype = Object.create(mixitup.Base.prototype); 10583 10584 mixitup.CommandChangeLayout.prototype.constructor = mixitup.CommandChangeLayout; 10585 10586 /** 10587 * @constructor 10588 * @memberof mixitup 10589 * @private 10590 * @since 3.0.0 10591 * @param {string} type 10592 * @param {string} selector 10593 * @param {boolean} [live] 10594 * @param {string} [parent] 10595 * An optional string representing the name of the mixer.dom property containing a reference to a parent element. 10596 */ 10597 10598 mixitup.ControlDefinition = function(type, selector, live, parent) { 10599 mixitup.Base.call(this); 10600 10601 this.callActions('beforeConstruct'); 10602 10603 this.type = type; 10604 this.selector = selector; 10605 this.live = live || false; 10606 this.parent = parent || ''; 10607 10608 this.callActions('afterConstruct'); 10609 10610 h.freeze(this); 10611 h.seal(this); 10612 }; 10613 10614 mixitup.BaseStatic.call(mixitup.ControlDefinition); 10615 10616 mixitup.ControlDefinition.prototype = Object.create(mixitup.Base.prototype); 10617 10618 mixitup.ControlDefinition.prototype.constructor = mixitup.ControlDefinition; 10619 10620 mixitup.controlDefinitions = []; 10621 10622 mixitup.controlDefinitions.push(new mixitup.ControlDefinition('multimix', '[data-filter][data-sort]')); 10623 mixitup.controlDefinitions.push(new mixitup.ControlDefinition('filter', '[data-filter]')); 10624 mixitup.controlDefinitions.push(new mixitup.ControlDefinition('sort', '[data-sort]')); 10625 mixitup.controlDefinitions.push(new mixitup.ControlDefinition('toggle', '[data-toggle]')); 10626 10627 /** 10628 * @constructor 10629 * @memberof mixitup 10630 * @private 10631 * @since 3.0.0 10632 */ 10633 10634 mixitup.Control = function() { 10635 mixitup.Base.call(this); 10636 10637 this.callActions('beforeConstruct'); 10638 10639 this.el = null; 10640 this.selector = ''; 10641 this.bound = []; 10642 this.pending = -1; 10643 this.type = ''; 10644 this.status = 'inactive'; // enum: ['inactive', 'active', 'disabled', 'live'] 10645 this.filter = ''; 10646 this.sort = ''; 10647 this.canDisable = false; 10648 this.handler = null; 10649 this.classNames = new mixitup.UiClassNames(); 10650 10651 this.callActions('afterConstruct'); 10652 10653 h.seal(this); 10654 }; 10655 10656 mixitup.BaseStatic.call(mixitup.Control); 10657 10658 mixitup.Control.prototype = Object.create(mixitup.Base.prototype); 10659 10660 h.extend(mixitup.Control.prototype, 10661 /** @lends mixitup.Control */ 10662 { 10663 constructor: mixitup.Control, 10664 10665 /** 10666 * @private 10667 * @param {HTMLElement} el 10668 * @param {string} type 10669 * @param {string} selector 10670 */ 10671 10672 init: function(el, type, selector) { 10673 var self = this; 10674 10675 this.callActions('beforeInit', arguments); 10676 10677 self.el = el; 10678 self.type = type; 10679 self.selector = selector; 10680 10681 if (self.selector) { 10682 self.status = 'live'; 10683 } else { 10684 self.canDisable = typeof self.el.disable === 'boolean'; 10685 10686 switch (self.type) { 10687 case 'filter': 10688 self.filter = self.el.getAttribute('data-filter'); 10689 10690 break; 10691 case 'toggle': 10692 self.filter = self.el.getAttribute('data-toggle'); 10693 10694 break; 10695 case 'sort': 10696 self.sort = self.el.getAttribute('data-sort'); 10697 10698 break; 10699 case 'multimix': 10700 self.filter = self.el.getAttribute('data-filter'); 10701 self.sort = self.el.getAttribute('data-sort'); 10702 10703 break; 10704 } 10705 } 10706 10707 self.bindClick(); 10708 10709 mixitup.controls.push(self); 10710 10711 this.callActions('afterInit', arguments); 10712 }, 10713 10714 /** 10715 * @private 10716 * @param {mixitup.Mixer} mixer 10717 * @return {boolean} 10718 */ 10719 10720 isBound: function(mixer) { 10721 var self = this, 10722 isBound = false; 10723 10724 this.callActions('beforeIsBound', arguments); 10725 10726 isBound = self.bound.indexOf(mixer) > -1; 10727 10728 return self.callFilters('afterIsBound', isBound, arguments); 10729 }, 10730 10731 /** 10732 * @private 10733 * @param {mixitup.Mixer} mixer 10734 * @return {void} 10735 */ 10736 10737 addBinding: function(mixer) { 10738 var self = this; 10739 10740 this.callActions('beforeAddBinding', arguments); 10741 10742 if (!self.isBound()) { 10743 self.bound.push(mixer); 10744 } 10745 10746 this.callActions('afterAddBinding', arguments); 10747 }, 10748 10749 /** 10750 * @private 10751 * @param {mixitup.Mixer} mixer 10752 * @return {void} 10753 */ 10754 10755 removeBinding: function(mixer) { 10756 var self = this, 10757 removeIndex = -1; 10758 10759 this.callActions('beforeRemoveBinding', arguments); 10760 10761 if ((removeIndex = self.bound.indexOf(mixer)) > -1) { 10762 self.bound.splice(removeIndex, 1); 10763 } 10764 10765 if (self.bound.length < 1) { 10766 // No bindings exist, unbind event click handlers 10767 10768 self.unbindClick(); 10769 10770 // Remove from `mixitup.controls` list 10771 10772 removeIndex = mixitup.controls.indexOf(self); 10773 10774 mixitup.controls.splice(removeIndex, 1); 10775 10776 if (self.status === 'active') { 10777 self.renderStatus(self.el, 'inactive'); 10778 } 10779 } 10780 10781 this.callActions('afterRemoveBinding', arguments); 10782 }, 10783 10784 /** 10785 * @private 10786 * @return {void} 10787 */ 10788 10789 bindClick: function() { 10790 var self = this; 10791 10792 this.callActions('beforeBindClick', arguments); 10793 10794 self.handler = function(e) { 10795 self.handleClick(e); 10796 }; 10797 10798 h.on(self.el, 'click', self.handler); 10799 10800 this.callActions('afterBindClick', arguments); 10801 }, 10802 10803 /** 10804 * @private 10805 * @return {void} 10806 */ 10807 10808 unbindClick: function() { 10809 var self = this; 10810 10811 this.callActions('beforeUnbindClick', arguments); 10812 10813 h.off(self.el, 'click', self.handler); 10814 10815 self.handler = null; 10816 10817 this.callActions('afterUnbindClick', arguments); 10818 }, 10819 10820 /** 10821 * @private 10822 * @param {MouseEvent} e 10823 * @return {void} 10824 */ 10825 10826 handleClick: function(e) { 10827 var self = this, 10828 button = null, 10829 mixer = null, 10830 isActive = false, 10831 returnValue = void(0), 10832 command = {}, 10833 clone = null, 10834 commands = [], 10835 i = -1; 10836 10837 this.callActions('beforeHandleClick', arguments); 10838 10839 this.pending = 0; 10840 10841 mixer = self.bound[0]; 10842 10843 if (!self.selector) { 10844 button = self.el; 10845 } else { 10846 button = h.closestParent(e.target, mixer.config.selectors.control + self.selector, true, mixer.dom.document); 10847 } 10848 10849 if (!button) { 10850 self.callActions('afterHandleClick', arguments); 10851 10852 return; 10853 } 10854 10855 switch (self.type) { 10856 case 'filter': 10857 command.filter = self.filter || button.getAttribute('data-filter'); 10858 10859 break; 10860 case 'sort': 10861 command.sort = self.sort || button.getAttribute('data-sort'); 10862 10863 break; 10864 case 'multimix': 10865 command.filter = self.filter || button.getAttribute('data-filter'); 10866 command.sort = self.sort || button.getAttribute('data-sort'); 10867 10868 break; 10869 case 'toggle': 10870 command.filter = self.filter || button.getAttribute('data-toggle'); 10871 10872 if (self.status === 'live') { 10873 isActive = h.hasClass(button, self.classNames.active); 10874 } else { 10875 isActive = self.status === 'active'; 10876 } 10877 10878 break; 10879 } 10880 10881 for (i = 0; i < self.bound.length; i++) { 10882 // Create a clone of the command for each bound mixer instance 10883 10884 clone = new mixitup.CommandMultimix(); 10885 10886 h.extend(clone, command); 10887 10888 commands.push(clone); 10889 } 10890 10891 commands = self.callFilters('commandsHandleClick', commands, arguments); 10892 10893 self.pending = self.bound.length; 10894 10895 for (i = 0; mixer = self.bound[i]; i++) { 10896 command = commands[i]; 10897 10898 if (!command) { 10899 // An extension may set a command null to indicate that the click should not be handled 10900 10901 continue; 10902 } 10903 10904 if (!mixer.lastClicked) { 10905 mixer.lastClicked = button; 10906 } 10907 10908 mixitup.events.fire('mixClick', mixer.dom.container, { 10909 state: mixer.state, 10910 instance: mixer, 10911 originalEvent: e, 10912 control: mixer.lastClicked 10913 }, mixer.dom.document); 10914 10915 if (typeof mixer.config.callbacks.onMixClick === 'function') { 10916 returnValue = mixer.config.callbacks.onMixClick.call(mixer.lastClicked, mixer.state, e, mixer); 10917 10918 if (returnValue === false) { 10919 // User has returned `false` from the callback, so do not handle click 10920 10921 continue; 10922 } 10923 } 10924 10925 if (self.type === 'toggle') { 10926 isActive ? mixer.toggleOff(command.filter) : mixer.toggleOn(command.filter); 10927 } else { 10928 mixer.multimix(command); 10929 } 10930 } 10931 10932 this.callActions('afterHandleClick', arguments); 10933 }, 10934 10935 /** 10936 * @param {object} command 10937 * @param {Array<string>} toggleArray 10938 * @return {void} 10939 */ 10940 10941 update: function(command, toggleArray) { 10942 var self = this, 10943 actions = new mixitup.CommandMultimix(); 10944 10945 self.callActions('beforeUpdate', arguments); 10946 10947 self.pending--; 10948 10949 self.pending = Math.max(0, self.pending); 10950 10951 if (self.pending > 0) return; 10952 10953 if (self.status === 'live') { 10954 // Live control (status unknown) 10955 10956 self.updateLive(command, toggleArray); 10957 } else { 10958 // Static control 10959 10960 actions.sort = self.sort; 10961 actions.filter = self.filter; 10962 10963 self.callFilters('actionsUpdate', actions, arguments); 10964 10965 self.parseStatusChange(self.el, command, actions, toggleArray); 10966 } 10967 10968 self.callActions('afterUpdate', arguments); 10969 }, 10970 10971 /** 10972 * @param {mixitup.CommandMultimix} command 10973 * @param {Array<string>} toggleArray 10974 * @return {void} 10975 */ 10976 10977 updateLive: function(command, toggleArray) { 10978 var self = this, 10979 controlButtons = null, 10980 actions = null, 10981 button = null, 10982 i = -1; 10983 10984 self.callActions('beforeUpdateLive', arguments); 10985 10986 if (!self.el) return; 10987 10988 controlButtons = self.el.querySelectorAll(self.selector); 10989 10990 for (i = 0; button = controlButtons[i]; i++) { 10991 actions = new mixitup.CommandMultimix(); 10992 10993 switch (self.type) { 10994 case 'filter': 10995 actions.filter = button.getAttribute('data-filter'); 10996 10997 break; 10998 case 'sort': 10999 actions.sort = button.getAttribute('data-sort'); 11000 11001 break; 11002 case 'multimix': 11003 actions.filter = button.getAttribute('data-filter'); 11004 actions.sort = button.getAttribute('data-sort'); 11005 11006 break; 11007 case 'toggle': 11008 actions.filter = button.getAttribute('data-toggle'); 11009 11010 break; 11011 } 11012 11013 actions = self.callFilters('actionsUpdateLive', actions, arguments); 11014 11015 self.parseStatusChange(button, command, actions, toggleArray); 11016 } 11017 11018 self.callActions('afterUpdateLive', arguments); 11019 }, 11020 11021 /** 11022 * @param {HTMLElement} button 11023 * @param {mixitup.CommandMultimix} command 11024 * @param {mixitup.CommandMultimix} actions 11025 * @param {Array<string>} toggleArray 11026 * @return {void} 11027 */ 11028 11029 parseStatusChange: function(button, command, actions, toggleArray) { 11030 var self = this, 11031 alias = '', 11032 toggle = '', 11033 i = -1; 11034 11035 self.callActions('beforeParseStatusChange', arguments); 11036 11037 switch (self.type) { 11038 case 'filter': 11039 if (command.filter === actions.filter) { 11040 self.renderStatus(button, 'active'); 11041 } else { 11042 self.renderStatus(button, 'inactive'); 11043 } 11044 11045 break; 11046 case 'multimix': 11047 if (command.sort === actions.sort && command.filter === actions.filter) { 11048 self.renderStatus(button, 'active'); 11049 } else { 11050 self.renderStatus(button, 'inactive'); 11051 } 11052 11053 break; 11054 case 'sort': 11055 if (command.sort.match(/:asc/g)) { 11056 alias = command.sort.replace(/:asc/g, ''); 11057 } 11058 11059 if (command.sort === actions.sort || alias === actions.sort) { 11060 self.renderStatus(button, 'active'); 11061 } else { 11062 self.renderStatus(button, 'inactive'); 11063 } 11064 11065 break; 11066 case 'toggle': 11067 if (toggleArray.length < 1) self.renderStatus(button, 'inactive'); 11068 11069 if (command.filter === actions.filter) { 11070 self.renderStatus(button, 'active'); 11071 } 11072 11073 for (i = 0; i < toggleArray.length; i++) { 11074 toggle = toggleArray[i]; 11075 11076 if (toggle === actions.filter) { 11077 // Button matches one active toggle 11078 11079 self.renderStatus(button, 'active'); 11080 11081 break; 11082 } 11083 11084 self.renderStatus(button, 'inactive'); 11085 } 11086 11087 break; 11088 } 11089 11090 self.callActions('afterParseStatusChange', arguments); 11091 }, 11092 11093 /** 11094 * @param {HTMLElement} button 11095 * @param {string} status 11096 * @return {void} 11097 */ 11098 11099 renderStatus: function(button, status) { 11100 var self = this; 11101 11102 self.callActions('beforeRenderStatus', arguments); 11103 11104 switch (status) { 11105 case 'active': 11106 h.addClass(button, self.classNames.active); 11107 h.removeClass(button, self.classNames.disabled); 11108 11109 if (self.canDisable) self.el.disabled = false; 11110 11111 break; 11112 case 'inactive': 11113 h.removeClass(button, self.classNames.active); 11114 h.removeClass(button, self.classNames.disabled); 11115 11116 if (self.canDisable) self.el.disabled = false; 11117 11118 break; 11119 case 'disabled': 11120 if (self.canDisable) self.el.disabled = true; 11121 11122 h.addClass(button, self.classNames.disabled); 11123 h.removeClass(button, self.classNames.active); 11124 11125 break; 11126 } 11127 11128 if (self.status !== 'live') { 11129 // Update the control's status propery if not live 11130 11131 self.status = status; 11132 } 11133 11134 self.callActions('afterRenderStatus', arguments); 11135 } 11136 }); 11137 11138 mixitup.controls = []; 11139 11140 /** 11141 * @constructor 11142 * @memberof mixitup 11143 * @private 11144 * @since 3.0.0 11145 */ 11146 11147 mixitup.StyleData = function() { 11148 mixitup.Base.call(this); 11149 11150 this.callActions('beforeConstruct'); 11151 11152 this.x = 0; 11153 this.y = 0; 11154 this.top = 0; 11155 this.right = 0; 11156 this.bottom = 0; 11157 this.left = 0; 11158 this.width = 0; 11159 this.height = 0; 11160 this.marginRight = 0; 11161 this.marginBottom = 0; 11162 this.opacity = 0; 11163 this.scale = new mixitup.TransformData(); 11164 this.translateX = new mixitup.TransformData(); 11165 this.translateY = new mixitup.TransformData(); 11166 this.translateZ = new mixitup.TransformData(); 11167 this.rotateX = new mixitup.TransformData(); 11168 this.rotateY = new mixitup.TransformData(); 11169 this.rotateZ = new mixitup.TransformData(); 11170 11171 this.callActions('afterConstruct'); 11172 11173 h.seal(this); 11174 }; 11175 11176 mixitup.BaseStatic.call(mixitup.StyleData); 11177 11178 mixitup.StyleData.prototype = Object.create(mixitup.Base.prototype); 11179 11180 mixitup.StyleData.prototype.constructor = mixitup.StyleData; 11181 11182 /** 11183 * @constructor 11184 * @memberof mixitup 11185 * @private 11186 * @since 3.0.0 11187 */ 11188 11189 mixitup.TransformData = function() { 11190 mixitup.Base.call(this); 11191 11192 this.callActions('beforeConstruct'); 11193 11194 this.value = 0; 11195 this.unit = ''; 11196 11197 this.callActions('afterConstruct'); 11198 11199 h.seal(this); 11200 }; 11201 11202 mixitup.BaseStatic.call(mixitup.TransformData); 11203 11204 mixitup.TransformData.prototype = Object.create(mixitup.Base.prototype); 11205 11206 mixitup.TransformData.prototype.constructor = mixitup.TransformData; 11207 11208 /** 11209 * @constructor 11210 * @memberof mixitup 11211 * @private 11212 * @since 3.0.0 11213 */ 11214 11215 mixitup.TransformDefaults = function() { 11216 mixitup.StyleData.apply(this); 11217 11218 this.callActions('beforeConstruct'); 11219 11220 this.scale.value = 0.01; 11221 this.scale.unit = ''; 11222 11223 this.translateX.value = 20; 11224 this.translateX.unit = 'px'; 11225 11226 this.translateY.value = 20; 11227 this.translateY.unit = 'px'; 11228 11229 this.translateZ.value = 20; 11230 this.translateZ.unit = 'px'; 11231 11232 this.rotateX.value = 90; 11233 this.rotateX.unit = 'deg'; 11234 11235 this.rotateY.value = 90; 11236 this.rotateY.unit = 'deg'; 11237 11238 this.rotateX.value = 90; 11239 this.rotateX.unit = 'deg'; 11240 11241 this.rotateZ.value = 180; 11242 this.rotateZ.unit = 'deg'; 11243 11244 this.callActions('afterConstruct'); 11245 11246 h.seal(this); 11247 }; 11248 11249 mixitup.BaseStatic.call(mixitup.TransformDefaults); 11250 11251 mixitup.TransformDefaults.prototype = Object.create(mixitup.StyleData.prototype); 11252 11253 mixitup.TransformDefaults.prototype.constructor = mixitup.TransformDefaults; 11254 11255 /** 11256 * @private 11257 * @static 11258 * @since 3.0.0 11259 * @type {mixitup.TransformDefaults} 11260 */ 11261 11262 mixitup.transformDefaults = new mixitup.TransformDefaults(); 11263 11264 /** 11265 * @constructor 11266 * @memberof mixitup 11267 * @private 11268 * @since 3.0.0 11269 */ 11270 11271 mixitup.EventDetail = function() { 11272 this.state = null; 11273 this.futureState = null; 11274 this.instance = null; 11275 this.originalEvent = null; 11276 }; 11277 11278 /** 11279 * The `mixitup.Events` class contains all custom events dispatched by MixItUp at various 11280 * points within the lifecycle of a mixer operation. 11281 * 11282 * Each event is analogous to the callback function of the same name defined in 11283 * the `callbacks` configuration object, and is triggered immediately before it. 11284 * 11285 * Events are always triggered from the container element on which MixItUp is instantiated 11286 * upon. 11287 * 11288 * As with any event, registered event handlers receive the event object as a parameter 11289 * which includes a `detail` property containting references to the current `state`, 11290 * the `mixer` instance, and other event-specific properties described below. 11291 * 11292 * @constructor 11293 * @namespace 11294 * @memberof mixitup 11295 * @public 11296 * @since 3.0.0 11297 */ 11298 11299 mixitup.Events = function() { 11300 mixitup.Base.call(this); 11301 11302 this.callActions('beforeConstruct'); 11303 11304 /** 11305 * A custom event triggered immediately after any MixItUp operation is requested 11306 * and before animations have begun. 11307 * 11308 * The `mixStart` event also exposes a `futureState` property via the 11309 * `event.detail` object, which represents the final state of the mixer once 11310 * the requested operation has completed. 11311 * 11312 * @name mixStart 11313 * @memberof mixitup.Events 11314 * @static 11315 * @type {CustomEvent} 11316 */ 11317 11318 this.mixStart = null; 11319 11320 /** 11321 * A custom event triggered when a MixItUp operation is requested while another 11322 * operation is in progress, and the animation queue is full, or queueing 11323 * is disabled. 11324 * 11325 * @name mixBusy 11326 * @memberof mixitup.Events 11327 * @static 11328 * @type {CustomEvent} 11329 */ 11330 11331 this.mixBusy = null; 11332 11333 /** 11334 * A custom event triggered after any MixItUp operation has completed, and the 11335 * state has been updated. 11336 * 11337 * @name mixEnd 11338 * @memberof mixitup.Events 11339 * @static 11340 * @type {CustomEvent} 11341 */ 11342 11343 this.mixEnd = null; 11344 11345 /** 11346 * A custom event triggered whenever a filter operation "fails", i.e. no targets 11347 * could be found matching the requested filter. 11348 * 11349 * @name mixFail 11350 * @memberof mixitup.Events 11351 * @static 11352 * @type {CustomEvent} 11353 */ 11354 11355 this.mixFail = null; 11356 11357 /** 11358 * A custom event triggered whenever a MixItUp control is clicked, and before its 11359 * respective operation is requested. 11360 * 11361 * This event also exposes an `originalEvent` property via the `event.detail` 11362 * object, which holds a reference to the original click event. 11363 * 11364 * @name mixClick 11365 * @memberof mixitup.Events 11366 * @static 11367 * @type {CustomEvent} 11368 */ 11369 11370 this.mixClick = null; 11371 11372 this.callActions('afterConstruct'); 11373 11374 h.seal(this); 11375 }; 11376 11377 mixitup.BaseStatic.call(mixitup.Events); 11378 11379 mixitup.Events.prototype = Object.create(mixitup.Base.prototype); 11380 11381 mixitup.Events.prototype.constructor = mixitup.Events; 11382 11383 /** 11384 * @private 11385 * @param {string} eventType 11386 * @param {Element} el 11387 * @param {object} detail 11388 * @param {Document} [doc] 11389 */ 11390 11391 mixitup.Events.prototype.fire = function(eventType, el, detail, doc) { 11392 var self = this, 11393 event = null, 11394 eventDetail = new mixitup.EventDetail(); 11395 11396 self.callActions('beforeFire', arguments); 11397 11398 if (typeof self[eventType] === 'undefined') { 11399 throw new Error('Event type "' + eventType + '" not found.'); 11400 } 11401 11402 eventDetail.state = new mixitup.State(); 11403 11404 h.extend(eventDetail.state, detail.state); 11405 11406 if (detail.futureState) { 11407 eventDetail.futureState = new mixitup.State(); 11408 11409 h.extend(eventDetail.futureState, detail.futureState); 11410 } 11411 11412 eventDetail.instance = detail.instance; 11413 11414 if (detail.originalEvent) { 11415 eventDetail.originalEvent = detail.originalEvent; 11416 } 11417 11418 event = h.getCustomEvent(eventType, eventDetail, doc); 11419 11420 self.callFilters('eventFire', event, arguments); 11421 11422 el.dispatchEvent(event); 11423 }; 11424 11425 // Asign a singleton instance to `mixitup.events`: 11426 11427 mixitup.events = new mixitup.Events(); 11428 11429 /** 11430 * @constructor 11431 * @memberof mixitup 11432 * @private 11433 * @since 3.0.0 11434 */ 11435 11436 mixitup.QueueItem = function() { 11437 mixitup.Base.call(this); 11438 11439 this.callActions('beforeConstruct'); 11440 11441 this.args = []; 11442 this.instruction = null; 11443 this.triggerElement = null; 11444 this.deferred = null; 11445 this.isToggling = false; 11446 11447 this.callActions('afterConstruct'); 11448 11449 h.seal(this); 11450 }; 11451 11452 mixitup.BaseStatic.call(mixitup.QueueItem); 11453 11454 mixitup.QueueItem.prototype = Object.create(mixitup.Base.prototype); 11455 11456 mixitup.QueueItem.prototype.constructor = mixitup.QueueItem; 11457 11458 /** 11459 * The `mixitup.Mixer` class is used to hold discreet, user-configured 11460 * instances of MixItUp on a provided container element. 11461 * 11462 * Mixer instances are returned whenever the `mixitup()` factory function is called, 11463 * which expose a range of methods enabling API-based filtering, sorting, 11464 * insertion, removal and more. 11465 * 11466 * @constructor 11467 * @namespace 11468 * @memberof mixitup 11469 * @public 11470 * @since 3.0.0 11471 */ 11472 11473 mixitup.Mixer = function() { 11474 mixitup.Base.call(this); 11475 11476 this.callActions('beforeConstruct'); 11477 11478 this.config = new mixitup.Config(); 11479 11480 this.id = ''; 11481 11482 this.isBusy = false; 11483 this.isToggling = false; 11484 this.incPadding = true; 11485 11486 this.controls = []; 11487 this.targets = []; 11488 this.origOrder = []; 11489 this.cache = {}; 11490 11491 this.toggleArray = []; 11492 11493 this.targetsMoved = 0; 11494 this.targetsImmovable = 0; 11495 this.targetsBound = 0; 11496 this.targetsDone = 0; 11497 11498 this.staggerDuration = 0; 11499 this.effectsIn = null; 11500 this.effectsOut = null; 11501 this.transformIn = []; 11502 this.transformOut = []; 11503 this.queue = []; 11504 11505 this.state = null; 11506 this.lastOperation = null; 11507 this.lastClicked = null; 11508 this.userCallback = null; 11509 this.userDeferred = null; 11510 11511 this.dom = new mixitup.MixerDom(); 11512 11513 this.callActions('afterConstruct'); 11514 11515 h.seal(this); 11516 }; 11517 11518 mixitup.BaseStatic.call(mixitup.Mixer); 11519 11520 mixitup.Mixer.prototype = Object.create(mixitup.Base.prototype); 11521 11522 h.extend(mixitup.Mixer.prototype, 11523 /** @lends mixitup.Mixer */ 11524 { 11525 constructor: mixitup.Mixer, 11526 11527 /** 11528 * @private 11529 * @instance 11530 * @since 3.0.0 11531 * @param {HTMLElement} container 11532 * @param {HTMLElement} document 11533 * @param {string} id 11534 * @param {object} [config] 11535 */ 11536 11537 attach: function(container, document, id, config) { 11538 var self = this, 11539 target = null, 11540 i = -1; 11541 11542 self.callActions('beforeAttach', arguments); 11543 11544 self.id = id; 11545 11546 if (config) { 11547 h.extend(self.config, config, true, true); 11548 } 11549 11550 self.sanitizeConfig(); 11551 11552 self.cacheDom(container, document); 11553 11554 if (self.config.layout.containerClassName) { 11555 h.addClass(self.dom.container, self.config.layout.containerClassName); 11556 } 11557 11558 if (!mixitup.features.has.transitions) { 11559 self.config.animation.enable = false; 11560 } 11561 11562 if (typeof window.console === 'undefined') { 11563 self.config.debug.showWarnings = false; 11564 } 11565 11566 if (self.config.data.uidKey) { 11567 // If the dataset API is in use, force disable controls 11568 11569 self.config.controls.enable = false; 11570 } 11571 11572 self.indexTargets(); 11573 11574 self.state = self.getInitialState(); 11575 11576 for (i = 0; target = self.lastOperation.toHide[i]; i++) { 11577 target.hide(); 11578 } 11579 11580 if (self.config.controls.enable) { 11581 self.initControls(); 11582 11583 self.buildToggleArray(null, self.state); 11584 11585 self.updateControls({ 11586 filter: self.state.activeFilter, 11587 sort: self.state.activeSort 11588 }); 11589 } 11590 11591 self.parseEffects(); 11592 11593 self.callActions('afterAttach', arguments); 11594 }, 11595 11596 /** 11597 * @private 11598 * @instance 11599 * @since 3.0.0 11600 * @return {void} 11601 */ 11602 11603 sanitizeConfig: function() { 11604 var self = this; 11605 11606 self.callActions('beforeSanitizeConfig', arguments); 11607 11608 // Sanitize enum/string config options 11609 11610 self.config.controls.scope = self.config.controls.scope.toLowerCase().trim(); 11611 self.config.controls.toggleLogic = self.config.controls.toggleLogic.toLowerCase().trim(); 11612 self.config.controls.toggleDefault = self.config.controls.toggleDefault.toLowerCase().trim(); 11613 11614 self.config.animation.effects = self.config.animation.effects.trim(); 11615 11616 self.callActions('afterSanitizeConfig', arguments); 11617 }, 11618 11619 /** 11620 * @private 11621 * @instance 11622 * @since 3.0.0 11623 * @return {mixitup.State} 11624 */ 11625 11626 getInitialState: function() { 11627 var self = this, 11628 state = new mixitup.State(), 11629 operation = new mixitup.Operation(); 11630 11631 self.callActions('beforeGetInitialState', arguments); 11632 11633 // Map initial values into a mock state object in order to construct an operation 11634 11635 state.activeContainerClassName = self.config.layout.containerClassName; 11636 11637 if (self.config.load.dataset) { 11638 // Dataset API 11639 11640 if (!self.config.data.uidKey || typeof self.config.data.uidKey !== 'string') { 11641 throw new TypeError(mixitup.messages.errorConfigDataUidKeyNotSet()); 11642 } 11643 11644 operation.startDataset = operation.newDataset = state.activeDataset = self.config.load.dataset.slice(); 11645 operation.startContainerClassName = operation.newContainerClassName = state.activeContainerClassName; 11646 operation.show = self.targets.slice(); 11647 11648 state = self.callFilters('stateGetInitialState', state, arguments); 11649 } else { 11650 // DOM API 11651 11652 state.activeFilter = self.parseFilterArgs([self.config.load.filter]).command; 11653 state.activeSort = self.parseSortArgs([self.config.load.sort]).command; 11654 state.totalTargets = self.targets.length; 11655 11656 state = self.callFilters('stateGetInitialState', state, arguments); 11657 11658 if ( 11659 state.activeSort.collection || state.activeSort.attribute || 11660 state.activeSort.order === 'random' || state.activeSort.order === 'desc' 11661 ) { 11662 // Sorting on load 11663 11664 operation.newSort = state.activeSort; 11665 11666 self.sortOperation(operation); 11667 11668 self.printSort(false, operation); 11669 11670 self.targets = operation.newOrder; 11671 } else { 11672 operation.startOrder = operation.newOrder = self.targets; 11673 } 11674 11675 operation.startFilter = operation.newFilter = state.activeFilter; 11676 operation.startSort = operation.newSort = state.activeSort; 11677 operation.startContainerClassName = operation.newContainerClassName = state.activeContainerClassName; 11678 11679 if (operation.newFilter.selector === 'all') { 11680 operation.newFilter.selector = self.config.selectors.target; 11681 } else if (operation.newFilter.selector === 'none') { 11682 operation.newFilter.selector = ''; 11683 } 11684 } 11685 11686 operation = self.callFilters('operationGetInitialState', operation, [state]); 11687 11688 self.lastOperation = operation; 11689 11690 if (operation.newFilter) { 11691 self.filterOperation(operation); 11692 } 11693 11694 state = self.buildState(operation); 11695 11696 return state; 11697 }, 11698 11699 /** 11700 * Caches references of DOM elements neccessary for the mixer's functionality. 11701 * 11702 * @private 11703 * @instance 11704 * @since 3.0.0 11705 * @param {HTMLElement} el 11706 * @param {HTMLHtmlElement} document 11707 * @return {void} 11708 */ 11709 11710 cacheDom: function(el, document) { 11711 var self = this; 11712 11713 self.callActions('beforeCacheDom', arguments); 11714 11715 self.dom.document = document; 11716 self.dom.body = self.dom.document.querySelector('body'); 11717 self.dom.container = el; 11718 self.dom.parent = el; 11719 11720 self.callActions('afterCacheDom', arguments); 11721 }, 11722 11723 /** 11724 * Indexes all child elements of the mixer matching the `selectors.target` 11725 * selector, instantiating a mixitup.Target for each one. 11726 * 11727 * @private 11728 * @instance 11729 * @since 3.0.0 11730 * @return {void} 11731 */ 11732 11733 indexTargets: function() { 11734 var self = this, 11735 target = null, 11736 el = null, 11737 dataset = null, 11738 i = -1; 11739 11740 self.callActions('beforeIndexTargets', arguments); 11741 11742 self.dom.targets = self.config.layout.allowNestedTargets ? 11743 self.dom.container.querySelectorAll(self.config.selectors.target) : 11744 h.children(self.dom.container, self.config.selectors.target, self.dom.document); 11745 11746 self.dom.targets = h.arrayFromList(self.dom.targets); 11747 11748 self.targets = []; 11749 11750 if ((dataset = self.config.load.dataset) && dataset.length !== self.dom.targets.length) { 11751 throw new Error(mixitup.messages.errorDatasetPrerenderedMismatch()); 11752 } 11753 11754 if (self.dom.targets.length) { 11755 for (i = 0; el = self.dom.targets[i]; i++) { 11756 target = new mixitup.Target(); 11757 11758 target.init(el, self, dataset ? dataset[i] : void(0)); 11759 11760 target.isInDom = true; 11761 11762 self.targets.push(target); 11763 } 11764 11765 self.dom.parent = self.dom.targets[0].parentElement === self.dom.container ? 11766 self.dom.container : 11767 self.dom.targets[0].parentElement; 11768 } 11769 11770 self.origOrder = self.targets; 11771 11772 self.callActions('afterIndexTargets', arguments); 11773 }, 11774 11775 initControls: function() { 11776 var self = this, 11777 definition = '', 11778 controlElements = null, 11779 el = null, 11780 parent = null, 11781 delagators = null, 11782 control = null, 11783 i = -1, 11784 j = -1; 11785 11786 self.callActions('beforeInitControls', arguments); 11787 11788 switch (self.config.controls.scope) { 11789 case 'local': 11790 parent = self.dom.container; 11791 11792 break; 11793 case 'global': 11794 parent = self.dom.document; 11795 11796 break; 11797 default: 11798 throw new Error(mixitup.messages.errorConfigInvalidControlsScope()); 11799 } 11800 11801 for (i = 0; definition = mixitup.controlDefinitions[i]; i++) { 11802 if (self.config.controls.live || definition.live) { 11803 if (definition.parent) { 11804 delagators = self.dom[definition.parent]; 11805 11806 if (!delagators || delagators.length < 0) continue; 11807 11808 if (typeof delagators.length !== 'number') { 11809 delagators = [delagators]; 11810 } 11811 } else { 11812 delagators = [parent]; 11813 } 11814 11815 for (j = 0; (el = delagators[j]); j++) { 11816 control = self.getControl(el, definition.type, definition.selector); 11817 11818 self.controls.push(control); 11819 } 11820 } else { 11821 controlElements = parent.querySelectorAll(self.config.selectors.control + definition.selector); 11822 11823 for (j = 0; (el = controlElements[j]); j++) { 11824 control = self.getControl(el, definition.type, ''); 11825 11826 if (!control) continue; 11827 11828 self.controls.push(control); 11829 } 11830 } 11831 } 11832 11833 self.callActions('afterInitControls', arguments); 11834 }, 11835 11836 /** 11837 * @private 11838 * @instance 11839 * @since 3.0.0 11840 * @param {HTMLElement} el 11841 * @param {string} type 11842 * @param {string} selector 11843 * @return {mixitup.Control|null} 11844 */ 11845 11846 getControl: function(el, type, selector) { 11847 var self = this, 11848 control = null, 11849 i = -1; 11850 11851 self.callActions('beforeGetControl', arguments); 11852 11853 if (!selector) { 11854 // Static controls only 11855 11856 for (i = 0; control = mixitup.controls[i]; i++) { 11857 if (control.el === el && control.isBound(self)) { 11858 // Control already bound to this mixer (as another type). 11859 11860 // NB: This prevents duplicate controls from being registered where a selector 11861 // might collide, eg: "[data-filter]" and "[data-filter][data-sort]" 11862 11863 return self.callFilters('controlGetControl', null, arguments); 11864 } else if (control.el === el && control.type === type && control.selector === selector) { 11865 // Another mixer is already using this control, add this mixer as a binding 11866 11867 control.addBinding(self); 11868 11869 return self.callFilters('controlGetControl', control, arguments); 11870 } 11871 } 11872 } 11873 11874 // Create new control 11875 11876 control = new mixitup.Control(); 11877 11878 control.init(el, type, selector); 11879 11880 control.classNames.base = h.getClassname(self.config.classNames, type); 11881 control.classNames.active = h.getClassname(self.config.classNames, type, self.config.classNames.modifierActive); 11882 control.classNames.disabled = h.getClassname(self.config.classNames, type, self.config.classNames.modifierDisabled); 11883 11884 // Add a reference to this mixer as a binding 11885 11886 control.addBinding(self); 11887 11888 return self.callFilters('controlGetControl', control, arguments); 11889 }, 11890 11891 /** 11892 * Creates a compound selector by joining the `toggleArray` value as per the 11893 * defined toggle logic. 11894 * 11895 * @private 11896 * @instance 11897 * @since 3.0.0 11898 * @return {string} 11899 */ 11900 11901 getToggleSelector: function() { 11902 var self = this, 11903 delineator = self.config.controls.toggleLogic === 'or' ? ', ' : '', 11904 toggleSelector = ''; 11905 11906 self.callActions('beforeGetToggleSelector', arguments); 11907 11908 self.toggleArray = h.clean(self.toggleArray); 11909 11910 toggleSelector = self.toggleArray.join(delineator); 11911 11912 if (toggleSelector === '') { 11913 toggleSelector = self.config.controls.toggleDefault; 11914 } 11915 11916 return self.callFilters('selectorGetToggleSelector', toggleSelector, arguments); 11917 }, 11918 11919 /** 11920 * Breaks compound selector strings in an array of discreet selectors, 11921 * as per the active `controls.toggleLogic` configuration option. Accepts 11922 * either a dynamic command object, or a state object. 11923 * 11924 * @private 11925 * @instance 11926 * @since 2.0.0 11927 * @param {object} [command] 11928 * @param {mixitup.State} [state] 11929 * @return {void} 11930 */ 11931 11932 buildToggleArray: function(command, state) { 11933 var self = this, 11934 activeFilterSelector = ''; 11935 11936 self.callActions('beforeBuildToggleArray', arguments); 11937 11938 if (command && command.filter) { 11939 activeFilterSelector = command.filter.selector.replace(/\s/g, ''); 11940 } else if (state) { 11941 activeFilterSelector = state.activeFilter.selector.replace(/\s/g, ''); 11942 } else { 11943 return; 11944 } 11945 11946 if (activeFilterSelector === self.config.selectors.target || activeFilterSelector === 'all') { 11947 activeFilterSelector = ''; 11948 } 11949 11950 if (self.config.controls.toggleLogic === 'or') { 11951 self.toggleArray = activeFilterSelector.split(','); 11952 } else { 11953 self.toggleArray = self.splitCompoundSelector(activeFilterSelector); 11954 } 11955 11956 self.toggleArray = h.clean(self.toggleArray); 11957 11958 self.callActions('afterBuildToggleArray', arguments); 11959 }, 11960 11961 /** 11962 * Takes a compound selector (e.g. `.cat-1.cat-2`, `[data-cat="1"][data-cat="2"]`) 11963 * and breaks into its individual selectors. 11964 * 11965 * @private 11966 * @instance 11967 * @since 3.0.0 11968 * @param {string} compoundSelector 11969 * @return {string[]} 11970 */ 11971 11972 splitCompoundSelector: function(compoundSelector) { 11973 // Break at a `.` or `[`, capturing the delineator 11974 11975 var partials = compoundSelector.split(/([\.\[])/g), 11976 toggleArray = [], 11977 selector = '', 11978 i = -1; 11979 11980 if (partials[0] === '') { 11981 partials.shift(); 11982 } 11983 11984 for (i = 0; i < partials.length; i++) { 11985 if (i % 2 === 0) { 11986 selector = ''; 11987 } 11988 11989 selector += partials[i]; 11990 11991 if (i % 2 !== 0) { 11992 toggleArray.push(selector); 11993 } 11994 } 11995 11996 return toggleArray; 11997 }, 11998 11999 /** 12000 * Updates controls to their active/inactive state based on the command or 12001 * current state of the mixer. 12002 * 12003 * @private 12004 * @instance 12005 * @since 2.0.0 12006 * @param {object} command 12007 * @return {void} 12008 */ 12009 12010 updateControls: function(command) { 12011 var self = this, 12012 control = null, 12013 output = new mixitup.CommandMultimix(), 12014 i = -1; 12015 12016 self.callActions('beforeUpdateControls', arguments); 12017 12018 // Sanitise to defaults 12019 12020 if (command.filter) { 12021 output.filter = command.filter.selector; 12022 } else { 12023 output.filter = self.state.activeFilter.selector; 12024 } 12025 12026 if (command.sort) { 12027 output.sort = self.buildSortString(command.sort); 12028 } else { 12029 output.sort = self.buildSortString(self.state.activeSort); 12030 } 12031 12032 if (output.filter === self.config.selectors.target) { 12033 output.filter = 'all'; 12034 } 12035 12036 if (output.filter === '') { 12037 output.filter = 'none'; 12038 } 12039 12040 h.freeze(output); 12041 12042 for (i = 0; control = self.controls[i]; i++) { 12043 control.update(output, self.toggleArray); 12044 } 12045 12046 self.callActions('afterUpdateControls', arguments); 12047 }, 12048 12049 /** 12050 * @private 12051 * @instance 12052 * @since 3.0.0 12053 * @param {mixitup.CommandSort} command 12054 * @return {string} 12055 */ 12056 12057 buildSortString: function(command) { 12058 var self = this; 12059 var output = ''; 12060 12061 output += command.sortString; 12062 12063 if (command.next) { 12064 output += ' ' + self.buildSortString(command.next); 12065 } 12066 12067 return output; 12068 }, 12069 12070 /** 12071 * @private 12072 * @instance 12073 * @since 3.0.0 12074 * @param {object} command 12075 * @param {Operation} operation 12076 * @return {Promise.<mixitup.State>} 12077 */ 12078 12079 insertTargets: function(command, operation) { 12080 var self = this, 12081 nextSibling = null, 12082 insertionIndex = -1, 12083 frag = null, 12084 target = null, 12085 el = null, 12086 i = -1; 12087 12088 self.callActions('beforeInsertTargets', arguments); 12089 12090 if (typeof command.index === 'undefined') command.index = 0; 12091 12092 nextSibling = self.getNextSibling(command.index, command.sibling, command.position); 12093 frag = self.dom.document.createDocumentFragment(); 12094 12095 if (nextSibling) { 12096 insertionIndex = h.index(nextSibling, self.config.selectors.target); 12097 } else { 12098 insertionIndex = self.targets.length; 12099 } 12100 12101 if (command.collection) { 12102 for (i = 0; el = command.collection[i]; i++) { 12103 if (self.dom.targets.indexOf(el) > -1) { 12104 throw new Error(mixitup.messages.errorInsertPreexistingElement()); 12105 } 12106 12107 // Ensure elements are hidden when they are added to the DOM, so they can 12108 // be animated in gracefully 12109 12110 el.style.display = 'none'; 12111 12112 frag.appendChild(el); 12113 frag.appendChild(self.dom.document.createTextNode(' ')); 12114 12115 if (!h.isElement(el, self.dom.document) || !el.matches(self.config.selectors.target)) continue; 12116 12117 target = new mixitup.Target(); 12118 12119 target.init(el, self); 12120 12121 target.isInDom = true; 12122 12123 self.targets.splice(insertionIndex, 0, target); 12124 12125 insertionIndex++; 12126 } 12127 12128 self.dom.parent.insertBefore(frag, nextSibling); 12129 } 12130 12131 // Since targets have been added, the original order must be updated 12132 12133 operation.startOrder = self.origOrder = self.targets; 12134 12135 self.callActions('afterInsertTargets', arguments); 12136 }, 12137 12138 /** 12139 * @private 12140 * @instance 12141 * @since 3.0.0 12142 * @param {Number} [index] 12143 * @param {Element} [sibling] 12144 * @param {string} [position] 12145 * @return {Element} 12146 */ 12147 12148 getNextSibling: function(index, sibling, position) { 12149 var self = this, 12150 element = null; 12151 12152 index = Math.max(index, 0); 12153 12154 if (sibling && position === 'before') { 12155 // Explicit sibling 12156 12157 element = sibling; 12158 } else if (sibling && position === 'after') { 12159 // Explicit sibling 12160 12161 element = sibling.nextElementSibling || null; 12162 } else if (self.targets.length > 0 && typeof index !== 'undefined') { 12163 // Index and targets exist 12164 12165 element = (index < self.targets.length || !self.targets.length) ? 12166 self.targets[index].dom.el : 12167 self.targets[self.targets.length - 1].dom.el.nextElementSibling; 12168 } else if (self.targets.length === 0 && self.dom.parent.children.length > 0) { 12169 // No targets but other siblings 12170 12171 if (self.config.layout.siblingAfter) { 12172 element = self.config.layout.siblingAfter; 12173 } else if (self.config.layout.siblingBefore) { 12174 element = self.config.layout.siblingBefore.nextElementSibling; 12175 } else { 12176 self.dom.parent.children[0]; 12177 } 12178 } else { 12179 element === null; 12180 } 12181 12182 return self.callFilters('elementGetNextSibling', element, arguments); 12183 }, 12184 12185 /** 12186 * @private 12187 * @instance 12188 * @since 2.0.0 12189 * @param {Operation} operation 12190 * @return {void} 12191 */ 12192 12193 filterOperation: function(operation) { 12194 var self = this, 12195 testResult = false, 12196 index = -1, 12197 action = '', 12198 target = null, 12199 i = -1; 12200 12201 self.callActions('beforeFilterOperation', arguments); 12202 12203 action = operation.newFilter.action; 12204 12205 for (i = 0; target = operation.newOrder[i]; i++) { 12206 if (operation.newFilter.collection) { 12207 // show via collection 12208 12209 testResult = operation.newFilter.collection.indexOf(target.dom.el) > -1; 12210 } else { 12211 // show via selector 12212 12213 if (operation.newFilter.selector === '') { 12214 testResult = false; 12215 } else { 12216 testResult = target.dom.el.matches(operation.newFilter.selector); 12217 } 12218 } 12219 12220 self.evaluateHideShow(testResult, target, action, operation); 12221 } 12222 12223 if (operation.toRemove.length) { 12224 for (i = 0; target = operation.show[i]; i++) { 12225 if (operation.toRemove.indexOf(target) > -1) { 12226 // If any shown targets should be removed, move them into the toHide array 12227 12228 operation.show.splice(i, 1); 12229 12230 if ((index = operation.toShow.indexOf(target)) > -1) { 12231 operation.toShow.splice(index, 1); 12232 } 12233 12234 operation.toHide.push(target); 12235 operation.hide.push(target); 12236 12237 i--; 12238 } 12239 } 12240 } 12241 12242 operation.matching = operation.show.slice(); 12243 12244 if (operation.show.length === 0 && operation.newFilter.selector !== '' && self.targets.length !== 0) { 12245 operation.hasFailed = true; 12246 } 12247 12248 self.callActions('afterFilterOperation', arguments); 12249 }, 12250 12251 /** 12252 * @private 12253 * @instance 12254 * @since 3.0.0 12255 * @param {boolean} testResult 12256 * @param {Element} target 12257 * @param {string} action 12258 * @param {Operation} operation 12259 * @return {void} 12260 */ 12261 12262 evaluateHideShow: function(testResult, target, action, operation) { 12263 var self = this, 12264 filteredTestResult = false, 12265 args = Array.prototype.slice.call(arguments, 1); 12266 12267 filteredTestResult = self.callFilters('testResultEvaluateHideShow', testResult, args); 12268 12269 self.callActions('beforeEvaluateHideShow', arguments); 12270 12271 if ( 12272 filteredTestResult === true && action === 'show' || 12273 filteredTestResult === false && action === 'hide' 12274 ) { 12275 operation.show.push(target); 12276 12277 !target.isShown && operation.toShow.push(target); 12278 } else { 12279 operation.hide.push(target); 12280 12281 target.isShown && operation.toHide.push(target); 12282 } 12283 12284 self.callActions('afterEvaluateHideShow', arguments); 12285 }, 12286 12287 /** 12288 * @private 12289 * @instance 12290 * @since 2.0.0 12291 * @param {Operation} operation 12292 * @return {void} 12293 */ 12294 12295 sortOperation: function(operation) { 12296 var self = this, 12297 newOrder = [], 12298 target = null, 12299 el = null, 12300 i = -1; 12301 12302 self.callActions('beforeSortOperation', arguments); 12303 12304 operation.startOrder = self.targets; 12305 12306 if (operation.newSort.collection) { 12307 // Sort by collection 12308 12309 newOrder = []; 12310 12311 for (i = 0; (el = operation.newSort.collection[i]); i++) { 12312 if (self.dom.targets.indexOf(el) < 0) { 12313 throw new Error(mixitup.messages.errorSortNonExistentElement()); 12314 } 12315 12316 target = new mixitup.Target(); 12317 12318 target.init(el, self); 12319 12320 target.isInDom = true; 12321 12322 newOrder.push(target); 12323 } 12324 12325 operation.newOrder = newOrder; 12326 } else if (operation.newSort.order === 'random') { 12327 // Sort random 12328 12329 operation.newOrder = h.arrayShuffle(operation.startOrder); 12330 } else if (operation.newSort.attribute === '') { 12331 // Sort by default 12332 12333 operation.newOrder = self.origOrder.slice(); 12334 12335 if (operation.newSort.order === 'desc') { 12336 operation.newOrder.reverse(); 12337 } 12338 } else { 12339 // Sort by attribute 12340 12341 operation.newOrder = operation.startOrder.slice(); 12342 12343 operation.newOrder.sort(function(a, b) { 12344 return self.compare(a, b, operation.newSort); 12345 }); 12346 } 12347 12348 if (h.isEqualArray(operation.newOrder, operation.startOrder)) { 12349 operation.willSort = false; 12350 } 12351 12352 self.callActions('afterSortOperation', arguments); 12353 }, 12354 12355 /** 12356 * @private 12357 * @instance 12358 * @since 2.0.0 12359 * @param {mixitup.Target} a 12360 * @param {mixitup.Target} b 12361 * @param {mixitup.CommandSort} command 12362 * @return {Number} 12363 */ 12364 12365 compare: function(a, b, command) { 12366 var self = this, 12367 order = command.order, 12368 attrA = self.getAttributeValue(a, command.attribute), 12369 attrB = self.getAttributeValue(b, command.attribute); 12370 12371 if (isNaN(attrA * 1) || isNaN(attrB * 1)) { 12372 attrA = attrA.toLowerCase(); 12373 attrB = attrB.toLowerCase(); 12374 } else { 12375 attrA = attrA * 1; 12376 attrB = attrB * 1; 12377 } 12378 12379 if (attrA < attrB) { 12380 return order === 'asc' ? -1 : 1; 12381 } 12382 12383 if (attrA > attrB) { 12384 return order === 'asc' ? 1 : -1; 12385 } 12386 12387 if (attrA === attrB && command.next) { 12388 return self.compare(a, b, command.next); 12389 } 12390 12391 return 0; 12392 }, 12393 12394 /** 12395 * Reads the values of any data attributes present the provided target element 12396 * which match the current sort command. 12397 * 12398 * @private 12399 * @instance 12400 * @since 3.0.0 12401 * @param {mixitup.Target} target 12402 * @param {string} [attribute] 12403 * @return {(String|Number)} 12404 */ 12405 12406 getAttributeValue: function(target, attribute) { 12407 var self = this, 12408 value = ''; 12409 12410 value = target.dom.el.getAttribute('data-' + attribute); 12411 12412 if (value === null) { 12413 if (self.config.debug.showWarnings) { 12414 // Encourage users to assign values to all targets to avoid erroneous sorting 12415 // when types are mixed 12416 12417 console.warn(mixitup.messages.warningInconsistentSortingAttributes({ 12418 attribute: 'data-' + attribute 12419 })); 12420 } 12421 } 12422 12423 // If an attribute is not present, return 0 as a safety value 12424 12425 return self.callFilters('valueGetAttributeValue', value || 0, arguments); 12426 }, 12427 12428 /** 12429 * Inserts elements into the DOM in the appropriate 12430 * order using a document fragment for minimal 12431 * DOM thrashing 12432 * 12433 * @private 12434 * @instance 12435 * @since 2.0.0 12436 * @param {boolean} isResetting 12437 * @param {Operation} operation 12438 * @return {void} 12439 */ 12440 12441 printSort: function(isResetting, operation) { 12442 var self = this, 12443 startOrder = isResetting ? operation.newOrder : operation.startOrder, 12444 newOrder = isResetting ? operation.startOrder : operation.newOrder, 12445 nextSibling = startOrder.length ? startOrder[startOrder.length - 1].dom.el.nextElementSibling : null, 12446 frag = window.document.createDocumentFragment(), 12447 whitespace = null, 12448 target = null, 12449 el = null, 12450 i = -1; 12451 12452 self.callActions('beforePrintSort', arguments); 12453 12454 // Empty the container 12455 12456 for (i = 0; target = startOrder[i]; i++) { 12457 el = target.dom.el; 12458 12459 if (el.style.position === 'absolute') continue; 12460 12461 h.removeWhitespace(el.previousSibling); 12462 12463 el.parentElement.removeChild(el); 12464 } 12465 12466 whitespace = nextSibling ? nextSibling.previousSibling : self.dom.parent.lastChild; 12467 12468 if (whitespace && whitespace.nodeName === '#text') { 12469 h.removeWhitespace(whitespace); 12470 } 12471 12472 for (i = 0; target = newOrder[i]; i++) { 12473 // Add targets into a document fragment 12474 12475 el = target.dom.el; 12476 12477 if (h.isElement(frag.lastChild)) { 12478 frag.appendChild(window.document.createTextNode(' ')); 12479 } 12480 12481 frag.appendChild(el); 12482 } 12483 12484 // Insert the document fragment into the container 12485 // before any other non-target elements 12486 12487 if (self.dom.parent.firstChild && self.dom.parent.firstChild !== nextSibling) { 12488 frag.insertBefore(window.document.createTextNode(' '), frag.childNodes[0]); 12489 } 12490 12491 if (nextSibling) { 12492 frag.appendChild(window.document.createTextNode(' ')); 12493 12494 self.dom.parent.insertBefore(frag, nextSibling); 12495 } else { 12496 self.dom.parent.appendChild(frag); 12497 } 12498 12499 self.callActions('afterPrintSort', arguments); 12500 }, 12501 12502 /** 12503 * Parses user-defined sort strings (i.e. `default:asc`) into sort commands objects. 12504 * 12505 * @private 12506 * @instance 12507 * @since 3.0.0 12508 * @param {string} sortString 12509 * @param {mixitup.CommandSort} command 12510 * @return {mixitup.CommandSort} 12511 */ 12512 12513 parseSortString: function(sortString, command) { 12514 var self = this, 12515 rules = sortString.split(' '), 12516 current = command, 12517 rule = [], 12518 i = -1; 12519 12520 // command.sortString = sortString; 12521 12522 for (i = 0; i < rules.length; i++) { 12523 rule = rules[i].split(':'); 12524 12525 current.sortString = rules[i]; 12526 current.attribute = h.dashCase(rule[0]); 12527 current.order = rule[1] || 'asc'; 12528 12529 switch (current.attribute) { 12530 case 'default': 12531 // treat "default" as sorting by no attribute 12532 12533 current.attribute = ''; 12534 12535 break; 12536 case 'random': 12537 // treat "random" as an order not an attribute 12538 12539 current.attribute = ''; 12540 current.order = 'random'; 12541 12542 break; 12543 } 12544 12545 if (!current.attribute || current.order === 'random') break; 12546 12547 if (i < rules.length - 1) { 12548 // Embed reference to the next command 12549 12550 current.next = new mixitup.CommandSort(); 12551 12552 h.freeze(current); 12553 12554 current = current.next; 12555 } 12556 } 12557 12558 return self.callFilters('commandsParseSort', command, arguments); 12559 }, 12560 12561 /** 12562 * Parses all effects out of the user-defined `animation.effects` string into 12563 * their respective properties and units. 12564 * 12565 * @private 12566 * @instance 12567 * @since 2.0.0 12568 * @return {void} 12569 */ 12570 12571 parseEffects: function() { 12572 var self = this, 12573 transformName = '', 12574 effectsIn = self.config.animation.effectsIn || self.config.animation.effects, 12575 effectsOut = self.config.animation.effectsOut || self.config.animation.effects; 12576 12577 self.callActions('beforeParseEffects', arguments); 12578 12579 self.effectsIn = new mixitup.StyleData(); 12580 self.effectsOut = new mixitup.StyleData(); 12581 self.transformIn = []; 12582 self.transformOut = []; 12583 12584 self.effectsIn.opacity = self.effectsOut.opacity = 1; 12585 12586 self.parseEffect('fade', effectsIn, self.effectsIn, self.transformIn); 12587 self.parseEffect('fade', effectsOut, self.effectsOut, self.transformOut, true); 12588 12589 for (transformName in mixitup.transformDefaults) { 12590 if (!(mixitup.transformDefaults[transformName] instanceof mixitup.TransformData)) { 12591 continue; 12592 } 12593 12594 self.parseEffect(transformName, effectsIn, self.effectsIn, self.transformIn); 12595 self.parseEffect(transformName, effectsOut, self.effectsOut, self.transformOut, true); 12596 } 12597 12598 self.parseEffect('stagger', effectsIn, self.effectsIn, self.transformIn); 12599 self.parseEffect('stagger', effectsOut, self.effectsOut, self.transformOut, true); 12600 12601 self.callActions('afterParseEffects', arguments); 12602 }, 12603 12604 /** 12605 * @private 12606 * @instance 12607 * @since 2.0.0 12608 * @param {string} effectName 12609 * @param {string} effectString 12610 * @param {StyleData} effects 12611 * @param {String[]} transform 12612 * @param {boolean} [isOut] 12613 */ 12614 12615 parseEffect: function(effectName, effectString, effects, transform, isOut) { 12616 var self = this, 12617 re = /\(([^)]+)\)/, 12618 propIndex = -1, 12619 str = '', 12620 match = [], 12621 val = '', 12622 units = ['%', 'px', 'em', 'rem', 'vh', 'vw', 'deg'], 12623 unit = '', 12624 i = -1; 12625 12626 self.callActions('beforeParseEffect', arguments); 12627 12628 if (typeof effectString !== 'string') { 12629 throw new TypeError(mixitup.messages.errorConfigInvalidAnimationEffects()); 12630 } 12631 12632 if (effectString.indexOf(effectName) < 0) { 12633 // The effect is not present in the effects string 12634 12635 if (effectName === 'stagger') { 12636 // Reset stagger to 0 12637 12638 self.staggerDuration = 0; 12639 } 12640 12641 return; 12642 } 12643 12644 // The effect is present 12645 12646 propIndex = effectString.indexOf(effectName + '('); 12647 12648 if (propIndex > -1) { 12649 // The effect has a user defined value in parentheses 12650 12651 // Extract from the first parenthesis to the end of string 12652 12653 str = effectString.substring(propIndex); 12654 12655 // Match any number of characters between "(" and ")" 12656 12657 match = re.exec(str); 12658 12659 val = match[1]; 12660 } 12661 12662 switch (effectName) { 12663 case 'fade': 12664 effects.opacity = val ? parseFloat(val) : 0; 12665 12666 break; 12667 case 'stagger': 12668 self.staggerDuration = val ? parseFloat(val) : 100; 12669 12670 // TODO: Currently stagger must be applied globally, but 12671 // if seperate values are specified for in/out, this should 12672 // be respected 12673 12674 break; 12675 default: 12676 // All other effects are transforms following the same structure 12677 12678 if (isOut && self.config.animation.reverseOut && effectName !== 'scale') { 12679 effects[effectName].value = 12680 (val ? parseFloat(val) : mixitup.transformDefaults[effectName].value) * -1; 12681 } else { 12682 effects[effectName].value = 12683 (val ? parseFloat(val) : mixitup.transformDefaults[effectName].value); 12684 } 12685 12686 if (val) { 12687 for (i = 0; unit = units[i]; i++) { 12688 if (val.indexOf(unit) > -1) { 12689 effects[effectName].unit = unit; 12690 12691 break; 12692 } 12693 } 12694 } else { 12695 effects[effectName].unit = mixitup.transformDefaults[effectName].unit; 12696 } 12697 12698 transform.push( 12699 effectName + 12700 '(' + 12701 effects[effectName].value + 12702 effects[effectName].unit + 12703 ')' 12704 ); 12705 } 12706 12707 self.callActions('afterParseEffect', arguments); 12708 }, 12709 12710 /** 12711 * @private 12712 * @instance 12713 * @since 2.0.0 12714 * @param {Operation} operation 12715 * @return {State} 12716 */ 12717 12718 buildState: function(operation) { 12719 var self = this, 12720 state = new mixitup.State(), 12721 target = null, 12722 i = -1; 12723 12724 self.callActions('beforeBuildState', arguments); 12725 12726 // Map target elements into state arrays. 12727 // the real target objects should never be exposed 12728 12729 for (i = 0; target = self.targets[i]; i++) { 12730 if (!operation.toRemove.length || operation.toRemove.indexOf(target) < 0) { 12731 state.targets.push(target.dom.el); 12732 } 12733 } 12734 12735 for (i = 0; target = operation.matching[i]; i++) { 12736 state.matching.push(target.dom.el); 12737 } 12738 12739 for (i = 0; target = operation.show[i]; i++) { 12740 state.show.push(target.dom.el); 12741 } 12742 12743 for (i = 0; target = operation.hide[i]; i++) { 12744 if (!operation.toRemove.length || operation.toRemove.indexOf(target) < 0) { 12745 state.hide.push(target.dom.el); 12746 } 12747 } 12748 12749 state.id = self.id; 12750 state.container = self.dom.container; 12751 state.activeFilter = operation.newFilter; 12752 state.activeSort = operation.newSort; 12753 state.activeDataset = operation.newDataset; 12754 state.activeContainerClassName = operation.newContainerClassName; 12755 state.hasFailed = operation.hasFailed; 12756 state.totalTargets = self.targets.length; 12757 state.totalShow = operation.show.length; 12758 state.totalHide = operation.hide.length; 12759 state.totalMatching = operation.matching.length; 12760 state.triggerElement = operation.triggerElement; 12761 12762 return self.callFilters('stateBuildState', state, arguments); 12763 }, 12764 12765 /** 12766 * @private 12767 * @instance 12768 * @since 2.0.0 12769 * @param {boolean} shouldAnimate 12770 * @param {Operation} operation 12771 * @return {void} 12772 */ 12773 12774 goMix: function(shouldAnimate, operation) { 12775 var self = this, 12776 deferred = null; 12777 12778 self.callActions('beforeGoMix', arguments); 12779 12780 // If the animation duration is set to 0ms, 12781 // or no effects specified, 12782 // or the container is hidden 12783 // then abort animation 12784 12785 if ( 12786 !self.config.animation.duration || !self.config.animation.effects || !h.isVisible(self.dom.container) 12787 ) { 12788 shouldAnimate = false; 12789 } 12790 12791 if ( 12792 !operation.toShow.length && 12793 !operation.toHide.length && 12794 !operation.willSort && 12795 !operation.willChangeLayout 12796 ) { 12797 // If nothing to show or hide, and not sorting or 12798 // changing layout 12799 12800 shouldAnimate = false; 12801 } 12802 12803 if ( 12804 !operation.startState.show.length && 12805 !operation.show.length 12806 ) { 12807 // If nothing currently shown, nothing to show 12808 12809 shouldAnimate = false; 12810 } 12811 12812 mixitup.events.fire('mixStart', self.dom.container, { 12813 state: operation.startState, 12814 futureState: operation.newState, 12815 instance: self 12816 }, self.dom.document); 12817 12818 if (typeof self.config.callbacks.onMixStart === 'function') { 12819 self.config.callbacks.onMixStart.call( 12820 self.dom.container, 12821 operation.startState, 12822 operation.newState, 12823 self 12824 ); 12825 } 12826 12827 h.removeClass(self.dom.container, h.getClassname(self.config.classNames, 'container', self.config.classNames.modifierFailed)); 12828 12829 if (!self.userDeferred) { 12830 // Queue empty, no pending operations 12831 12832 deferred = self.userDeferred = h.defer(mixitup.libraries); 12833 } else { 12834 // Use existing deferred 12835 12836 deferred = self.userDeferred; 12837 } 12838 12839 self.isBusy = true; 12840 12841 if (!shouldAnimate || !mixitup.features.has.transitions) { 12842 // Abort 12843 12844 if (self.config.debug.fauxAsync) { 12845 setTimeout(function() { 12846 self.cleanUp(operation); 12847 }, self.config.animation.duration); 12848 } else { 12849 self.cleanUp(operation); 12850 } 12851 12852 return self.callFilters('promiseGoMix', deferred.promise, arguments); 12853 } 12854 12855 // If we should animate and the platform supports transitions, go for it 12856 12857 if (window.pageYOffset !== operation.docState.scrollTop) { 12858 window.scrollTo(operation.docState.scrollLeft, operation.docState.scrollTop); 12859 } 12860 12861 if (self.config.animation.applyPerspective) { 12862 self.dom.parent.style[mixitup.features.perspectiveProp] = 12863 self.config.animation.perspectiveDistance; 12864 12865 self.dom.parent.style[mixitup.features.perspectiveOriginProp] = 12866 self.config.animation.perspectiveOrigin; 12867 } 12868 12869 if ( 12870 self.config.animation.animateResizeContainer && 12871 operation.startHeight !== operation.newHeight && 12872 operation.viewportDeltaY !== operation.startHeight - operation.newHeight 12873 ) { 12874 self.dom.parent.style.height = operation.startHeight + 'px'; 12875 } 12876 12877 if ( 12878 self.config.animation.animateResizeContainer && 12879 operation.startWidth !== operation.newWidth && 12880 operation.viewportDeltaX !== operation.startWidth - operation.newWidth 12881 ) { 12882 self.dom.parent.style.width = operation.startWidth + 'px'; 12883 } 12884 12885 if (operation.startHeight === operation.newHeight) { 12886 self.dom.parent.style.height = operation.startHeight + 'px'; 12887 } 12888 12889 if (operation.startWidth === operation.newWidth) { 12890 self.dom.parent.style.width = operation.startWidth + 'px'; 12891 } 12892 12893 if (operation.startHeight === operation.newHeight && operation.startWidth === operation.newWidth) { 12894 self.dom.parent.style.overflow = 'hidden'; 12895 } 12896 12897 requestAnimationFrame(function() { 12898 self.moveTargets(operation); 12899 }); 12900 12901 return self.callFilters('promiseGoMix', deferred.promise, arguments); 12902 }, 12903 12904 /** 12905 * @private 12906 * @instance 12907 * @since 2.0.0 12908 * @param {Operation} operation 12909 * @return {void} 12910 */ 12911 12912 getStartMixData: function(operation) { 12913 var self = this, 12914 parentStyle = window.getComputedStyle(self.dom.parent), 12915 parentRect = self.dom.parent.getBoundingClientRect(), 12916 target = null, 12917 data = {}, 12918 i = -1, 12919 boxSizing = parentStyle[mixitup.features.boxSizingProp]; 12920 12921 self.incPadding = (boxSizing === 'border-box'); 12922 12923 self.callActions('beforeGetStartMixData', arguments); 12924 12925 for (i = 0; target = operation.show[i]; i++) { 12926 data = target.getPosData(); 12927 12928 operation.showPosData[i] = { 12929 startPosData: data 12930 }; 12931 } 12932 12933 for (i = 0; target = operation.toHide[i]; i++) { 12934 data = target.getPosData(); 12935 12936 operation.toHidePosData[i] = { 12937 startPosData: data 12938 }; 12939 } 12940 12941 operation.startX = parentRect.left; 12942 operation.startY = parentRect.top; 12943 12944 operation.startHeight = self.incPadding ? 12945 parentRect.height : 12946 parentRect.height - 12947 parseFloat(parentStyle.paddingTop) - 12948 parseFloat(parentStyle.paddingBottom) - 12949 parseFloat(parentStyle.borderTop) - 12950 parseFloat(parentStyle.borderBottom); 12951 12952 operation.startWidth = self.incPadding ? 12953 parentRect.width : 12954 parentRect.width - 12955 parseFloat(parentStyle.paddingLeft) - 12956 parseFloat(parentStyle.paddingRight) - 12957 parseFloat(parentStyle.borderLeft) - 12958 parseFloat(parentStyle.borderRight); 12959 12960 self.callActions('afterGetStartMixData', arguments); 12961 }, 12962 12963 /** 12964 * @private 12965 * @instance 12966 * @since 2.0.0 12967 * @param {Operation} operation 12968 * @return {void} 12969 */ 12970 12971 setInter: function(operation) { 12972 var self = this, 12973 target = null, 12974 i = -1; 12975 12976 self.callActions('beforeSetInter', arguments); 12977 12978 // Prevent scrollbar flicker on non-inertial scroll platforms by clamping height/width 12979 12980 if (self.config.animation.clampHeight) { 12981 self.dom.parent.style.height = operation.startHeight + 'px'; 12982 self.dom.parent.style.overflow = 'hidden'; 12983 } 12984 12985 if (self.config.animation.clampWidth) { 12986 self.dom.parent.style.width = operation.startWidth + 'px'; 12987 self.dom.parent.style.overflow = 'hidden'; 12988 } 12989 12990 for (i = 0; target = operation.toShow[i]; i++) { 12991 target.show(); 12992 } 12993 12994 if (operation.willChangeLayout) { 12995 h.removeClass(self.dom.container, operation.startContainerClassName); 12996 h.addClass(self.dom.container, operation.newContainerClassName); 12997 } 12998 12999 self.callActions('afterSetInter', arguments); 13000 }, 13001 13002 /** 13003 * @private 13004 * @instance 13005 * @since 2.0.0 13006 * @param {Operation} operation 13007 * @return {void} 13008 */ 13009 13010 getInterMixData: function(operation) { 13011 var self = this, 13012 target = null, 13013 i = -1; 13014 13015 self.callActions('beforeGetInterMixData', arguments); 13016 13017 for (i = 0; target = operation.show[i]; i++) { 13018 operation.showPosData[i].interPosData = target.getPosData(); 13019 } 13020 13021 for (i = 0; target = operation.toHide[i]; i++) { 13022 operation.toHidePosData[i].interPosData = target.getPosData(); 13023 } 13024 13025 self.callActions('afterGetInterMixData', arguments); 13026 }, 13027 13028 /** 13029 * @private 13030 * @instance 13031 * @since 2.0.0 13032 * @param {Operation} operation 13033 * @return {void} 13034 */ 13035 13036 setFinal: function(operation) { 13037 var self = this, 13038 target = null, 13039 i = -1; 13040 13041 self.callActions('beforeSetFinal', arguments); 13042 13043 operation.willSort && self.printSort(false, operation); 13044 13045 for (i = 0; target = operation.toHide[i]; i++) { 13046 target.hide(); 13047 } 13048 13049 self.callActions('afterSetFinal', arguments); 13050 }, 13051 13052 /** 13053 * @private 13054 * @instance 13055 * @since 2.0.0 13056 * @param {Operation} operation 13057 * @return {void} 13058 */ 13059 13060 getFinalMixData: function(operation) { 13061 var self = this, 13062 parentStyle = null, 13063 parentRect = null, 13064 target = null, 13065 i = -1; 13066 13067 self.callActions('beforeGetFinalMixData', arguments); 13068 13069 for (i = 0; target = operation.show[i]; i++) { 13070 operation.showPosData[i].finalPosData = target.getPosData(); 13071 } 13072 13073 for (i = 0; target = operation.toHide[i]; i++) { 13074 operation.toHidePosData[i].finalPosData = target.getPosData(); 13075 } 13076 13077 // Remove clamping 13078 13079 if (self.config.animation.clampHeight || self.config.animation.clampWidth) { 13080 self.dom.parent.style.height = 13081 self.dom.parent.style.width = 13082 self.dom.parent.style.overflow = ''; 13083 } 13084 13085 if (!self.incPadding) { 13086 parentStyle = window.getComputedStyle(self.dom.parent); 13087 } 13088 13089 parentRect = self.dom.parent.getBoundingClientRect(); 13090 13091 operation.newX = parentRect.left; 13092 operation.newY = parentRect.top; 13093 13094 operation.newHeight = self.incPadding ? 13095 parentRect.height : 13096 parentRect.height - 13097 parseFloat(parentStyle.paddingTop) - 13098 parseFloat(parentStyle.paddingBottom) - 13099 parseFloat(parentStyle.borderTop) - 13100 parseFloat(parentStyle.borderBottom); 13101 13102 operation.newWidth = self.incPadding ? 13103 parentRect.width : 13104 parentRect.width - 13105 parseFloat(parentStyle.paddingLeft) - 13106 parseFloat(parentStyle.paddingRight) - 13107 parseFloat(parentStyle.borderLeft) - 13108 parseFloat(parentStyle.borderRight); 13109 13110 operation.viewportDeltaX = operation.docState.viewportWidth - this.dom.document.documentElement.clientWidth; 13111 operation.viewportDeltaY = operation.docState.viewportHeight - this.dom.document.documentElement.clientHeight; 13112 13113 if (operation.willSort) { 13114 self.printSort(true, operation); 13115 } 13116 13117 for (i = 0; target = operation.toShow[i]; i++) { 13118 target.hide(); 13119 } 13120 13121 for (i = 0; target = operation.toHide[i]; i++) { 13122 target.show(); 13123 } 13124 13125 if (operation.willChangeLayout) { 13126 h.removeClass(self.dom.container, operation.newContainerClassName); 13127 h.addClass(self.dom.container, self.config.layout.containerClassName); 13128 } 13129 13130 self.callActions('afterGetFinalMixData', arguments); 13131 }, 13132 13133 /** 13134 * @private 13135 * @instance 13136 * @since 3.0.0 13137 * @param {Operation} operation 13138 */ 13139 13140 getTweenData: function(operation) { 13141 var self = this, 13142 target = null, 13143 posData = null, 13144 effectNames = Object.getOwnPropertyNames(self.effectsIn), 13145 effectName = '', 13146 effect = null, 13147 widthChange = -1, 13148 heightChange = -1, 13149 i = -1, 13150 j = -1; 13151 13152 self.callActions('beforeGetTweenData', arguments); 13153 13154 for (i = 0; target = operation.show[i]; i++) { 13155 posData = operation.showPosData[i]; 13156 posData.posIn = new mixitup.StyleData(); 13157 posData.posOut = new mixitup.StyleData(); 13158 posData.tweenData = new mixitup.StyleData(); 13159 13160 // Process x and y 13161 13162 if (target.isShown) { 13163 posData.posIn.x = posData.startPosData.x - posData.interPosData.x; 13164 posData.posIn.y = posData.startPosData.y - posData.interPosData.y; 13165 } else { 13166 posData.posIn.x = posData.posIn.y = 0; 13167 } 13168 13169 posData.posOut.x = posData.finalPosData.x - posData.interPosData.x; 13170 posData.posOut.y = posData.finalPosData.y - posData.interPosData.y; 13171 13172 // Process opacity 13173 13174 posData.posIn.opacity = target.isShown ? 1 : self.effectsIn.opacity; 13175 posData.posOut.opacity = 1; 13176 posData.tweenData.opacity = posData.posOut.opacity - posData.posIn.opacity; 13177 13178 // Adjust x and y if not nudging 13179 13180 if (!target.isShown && !self.config.animation.nudge) { 13181 posData.posIn.x = posData.posOut.x; 13182 posData.posIn.y = posData.posOut.y; 13183 } 13184 13185 posData.tweenData.x = posData.posOut.x - posData.posIn.x; 13186 posData.tweenData.y = posData.posOut.y - posData.posIn.y; 13187 13188 // Process width, height, and margins 13189 13190 if (self.config.animation.animateResizeTargets) { 13191 posData.posIn.width = posData.startPosData.width; 13192 posData.posIn.height = posData.startPosData.height; 13193 13194 // "||" Prevents width/height change from including 0 width/height if hiding or showing 13195 13196 widthChange = (posData.startPosData.width || posData.finalPosData.width) - posData.interPosData.width; 13197 13198 posData.posIn.marginRight = posData.startPosData.marginRight - widthChange; 13199 13200 heightChange = (posData.startPosData.height || posData.finalPosData.height) - posData.interPosData.height; 13201 13202 posData.posIn.marginBottom = posData.startPosData.marginBottom - heightChange; 13203 13204 posData.posOut.width = posData.finalPosData.width; 13205 posData.posOut.height = posData.finalPosData.height; 13206 13207 widthChange = (posData.finalPosData.width || posData.startPosData.width) - posData.interPosData.width; 13208 13209 posData.posOut.marginRight = posData.finalPosData.marginRight - widthChange; 13210 13211 heightChange = (posData.finalPosData.height || posData.startPosData.height) - posData.interPosData.height; 13212 13213 posData.posOut.marginBottom = posData.finalPosData.marginBottom - heightChange; 13214 13215 posData.tweenData.width = posData.posOut.width - posData.posIn.width; 13216 posData.tweenData.height = posData.posOut.height - posData.posIn.height; 13217 posData.tweenData.marginRight = posData.posOut.marginRight - posData.posIn.marginRight; 13218 posData.tweenData.marginBottom = posData.posOut.marginBottom - posData.posIn.marginBottom; 13219 } 13220 13221 // Process transforms 13222 13223 for (j = 0; effectName = effectNames[j]; j++) { 13224 effect = self.effectsIn[effectName]; 13225 13226 if (!(effect instanceof mixitup.TransformData) || !effect.value) continue; 13227 13228 posData.posIn[effectName].value = effect.value; 13229 posData.posOut[effectName].value = 0; 13230 13231 posData.tweenData[effectName].value = 13232 posData.posOut[effectName].value - posData.posIn[effectName].value; 13233 13234 posData.posIn[effectName].unit = 13235 posData.posOut[effectName].unit = 13236 posData.tweenData[effectName].unit = 13237 effect.unit; 13238 } 13239 } 13240 13241 for (i = 0; target = operation.toHide[i]; i++) { 13242 posData = operation.toHidePosData[i]; 13243 posData.posIn = new mixitup.StyleData(); 13244 posData.posOut = new mixitup.StyleData(); 13245 posData.tweenData = new mixitup.StyleData(); 13246 13247 // Process x and y 13248 13249 posData.posIn.x = target.isShown ? posData.startPosData.x - posData.interPosData.x : 0; 13250 posData.posIn.y = target.isShown ? posData.startPosData.y - posData.interPosData.y : 0; 13251 posData.posOut.x = self.config.animation.nudge ? 0 : posData.posIn.x; 13252 posData.posOut.y = self.config.animation.nudge ? 0 : posData.posIn.y; 13253 posData.tweenData.x = posData.posOut.x - posData.posIn.x; 13254 posData.tweenData.y = posData.posOut.y - posData.posIn.y; 13255 13256 // Process width, height, and margins 13257 13258 if (self.config.animation.animateResizeTargets) { 13259 posData.posIn.width = posData.startPosData.width; 13260 posData.posIn.height = posData.startPosData.height; 13261 13262 widthChange = posData.startPosData.width - posData.interPosData.width; 13263 13264 posData.posIn.marginRight = posData.startPosData.marginRight - widthChange; 13265 13266 heightChange = posData.startPosData.height - posData.interPosData.height; 13267 13268 posData.posIn.marginBottom = posData.startPosData.marginBottom - heightChange; 13269 } 13270 13271 // Process opacity 13272 13273 posData.posIn.opacity = 1; 13274 posData.posOut.opacity = self.effectsOut.opacity; 13275 posData.tweenData.opacity = posData.posOut.opacity - posData.posIn.opacity; 13276 13277 // Process transforms 13278 13279 for (j = 0; effectName = effectNames[j]; j++) { 13280 effect = self.effectsOut[effectName]; 13281 13282 if (!(effect instanceof mixitup.TransformData) || !effect.value) continue; 13283 13284 posData.posIn[effectName].value = 0; 13285 posData.posOut[effectName].value = effect.value; 13286 13287 posData.tweenData[effectName].value = 13288 posData.posOut[effectName].value - posData.posIn[effectName].value; 13289 13290 posData.posIn[effectName].unit = 13291 posData.posOut[effectName].unit = 13292 posData.tweenData[effectName].unit = 13293 effect.unit; 13294 } 13295 } 13296 13297 self.callActions('afterGetTweenData', arguments); 13298 }, 13299 13300 /** 13301 * @private 13302 * @instance 13303 * @since 3.0.0 13304 * @param {Operation} operation 13305 * @return {void} 13306 */ 13307 13308 moveTargets: function(operation) { 13309 var self = this, 13310 target = null, 13311 moveData = null, 13312 posData = null, 13313 statusChange = '', 13314 willTransition = false, 13315 staggerIndex = -1, 13316 i = -1, 13317 checkProgress = self.checkProgress.bind(self); 13318 13319 self.callActions('beforeMoveTargets', arguments); 13320 13321 // TODO: this is an extra loop in addition to the calcs 13322 // done in getOperation, could some of this be done there? 13323 13324 for (i = 0; target = operation.show[i]; i++) { 13325 moveData = new mixitup.IMoveData(); 13326 posData = operation.showPosData[i]; 13327 13328 statusChange = target.isShown ? 'none' : 'show'; 13329 13330 willTransition = self.willTransition( 13331 statusChange, 13332 operation.hasEffect, 13333 posData.posIn, 13334 posData.posOut 13335 ); 13336 13337 if (willTransition) { 13338 // Prevent non-transitioning targets from incrementing the staggerIndex 13339 13340 staggerIndex++; 13341 } 13342 13343 target.show(); 13344 13345 moveData.posIn = posData.posIn; 13346 moveData.posOut = posData.posOut; 13347 moveData.statusChange = statusChange; 13348 moveData.staggerIndex = staggerIndex; 13349 moveData.operation = operation; 13350 moveData.callback = willTransition ? checkProgress : null; 13351 13352 target.move(moveData); 13353 } 13354 13355 for (i = 0; target = operation.toHide[i]; i++) { 13356 posData = operation.toHidePosData[i]; 13357 moveData = new mixitup.IMoveData(); 13358 13359 statusChange = 'hide'; 13360 13361 willTransition = self.willTransition(statusChange, posData.posIn, posData.posOut); 13362 13363 moveData.posIn = posData.posIn; 13364 moveData.posOut = posData.posOut; 13365 moveData.statusChange = statusChange; 13366 moveData.staggerIndex = i; 13367 moveData.operation = operation; 13368 moveData.callback = willTransition ? checkProgress : null; 13369 13370 target.move(moveData); 13371 } 13372 13373 if (self.config.animation.animateResizeContainer) { 13374 self.dom.parent.style[mixitup.features.transitionProp] = 13375 'height ' + self.config.animation.duration + 'ms ease, ' + 13376 'width ' + self.config.animation.duration + 'ms ease '; 13377 13378 requestAnimationFrame(function() { 13379 if ( 13380 operation.startHeight !== operation.newHeight && 13381 operation.viewportDeltaY !== operation.startHeight - operation.newHeight 13382 ) { 13383 self.dom.parent.style.height = operation.newHeight + 'px'; 13384 } 13385 13386 if ( 13387 operation.startWidth !== operation.newWidth && 13388 operation.viewportDeltaX !== operation.startWidth - operation.newWidth 13389 ) { 13390 self.dom.parent.style.width = operation.newWidth + 'px'; 13391 } 13392 }); 13393 } 13394 13395 if (operation.willChangeLayout) { 13396 h.removeClass(self.dom.container, self.config.layout.ContainerClassName); 13397 h.addClass(self.dom.container, operation.newContainerClassName); 13398 } 13399 13400 self.callActions('afterMoveTargets', arguments); 13401 }, 13402 13403 /** 13404 * @private 13405 * @instance 13406 * @return {boolean} 13407 */ 13408 13409 hasEffect: function() { 13410 var self = this, 13411 EFFECTABLES = [ 13412 'scale', 13413 'translateX', 'translateY', 'translateZ', 13414 'rotateX', 'rotateY', 'rotateZ' 13415 ], 13416 effectName = '', 13417 effect = null, 13418 result = false, 13419 value = -1, 13420 i = -1; 13421 13422 if (self.effectsIn.opacity !== 1) { 13423 return self.callFilters('resultHasEffect', true, arguments); 13424 } 13425 13426 for (i = 0; effectName = EFFECTABLES[i]; i++) { 13427 effect = self.effectsIn[effectName]; 13428 value = (typeof effect && effect.value !== 'undefined') ? 13429 effect.value : effect; 13430 13431 if (value !== 0) { 13432 result = true; 13433 13434 break; 13435 } 13436 } 13437 13438 return self.callFilters('resultHasEffect', result, arguments); 13439 }, 13440 13441 /** 13442 * Determines if a target element will transition in 13443 * some fasion and therefore requires binding of 13444 * transitionEnd 13445 * 13446 * @private 13447 * @instance 13448 * @since 3.0.0 13449 * @param {string} statusChange 13450 * @param {boolean} hasEffect 13451 * @param {StyleData} posIn 13452 * @param {StyleData} posOut 13453 * @return {boolean} 13454 */ 13455 13456 willTransition: function(statusChange, hasEffect, posIn, posOut) { 13457 var self = this, 13458 result = false; 13459 13460 if (!h.isVisible(self.dom.container)) { 13461 // If the container is not visible, the transitionEnd 13462 // event will not occur and MixItUp will hang 13463 13464 result = false; 13465 } else if ( 13466 (statusChange !== 'none' && hasEffect) || 13467 posIn.x !== posOut.x || 13468 posIn.y !== posOut.y 13469 ) { 13470 // If opacity and/or translate will change 13471 13472 result = true; 13473 } else if (self.config.animation.animateResizeTargets) { 13474 // Check if width, height or margins will change 13475 13476 result = ( 13477 posIn.width !== posOut.width || 13478 posIn.height !== posOut.height || 13479 posIn.marginRight !== posOut.marginRight || 13480 posIn.marginTop !== posOut.marginTop 13481 ); 13482 } else { 13483 result = false; 13484 } 13485 13486 return self.callFilters('resultWillTransition', result, arguments); 13487 }, 13488 13489 /** 13490 * @private 13491 * @instance 13492 * @since 2.0.0 13493 * @param {Operation} operation 13494 * @return {void} 13495 */ 13496 13497 checkProgress: function(operation) { 13498 var self = this; 13499 13500 self.targetsDone++; 13501 13502 if (self.targetsBound === self.targetsDone) { 13503 self.cleanUp(operation); 13504 } 13505 }, 13506 13507 /** 13508 * @private 13509 * @instance 13510 * @since 2.0.0 13511 * @param {Operation} operation 13512 * @return {void} 13513 */ 13514 13515 cleanUp: function(operation) { 13516 var self = this, 13517 target = null, 13518 whitespaceBefore = null, 13519 whitespaceAfter = null, 13520 nextInQueue = null, 13521 i = -1; 13522 13523 self.callActions('beforeCleanUp', arguments); 13524 13525 self.targetsMoved = 13526 self.targetsImmovable = 13527 self.targetsBound = 13528 self.targetsDone = 0; 13529 13530 for (i = 0; target = operation.show[i]; i++) { 13531 target.cleanUp(); 13532 13533 target.show(); 13534 } 13535 13536 for (i = 0; target = operation.toHide[i]; i++) { 13537 target.cleanUp(); 13538 13539 target.hide(); 13540 } 13541 13542 if (operation.willSort) { 13543 self.printSort(false, operation); 13544 } 13545 13546 // Remove any styles applied to the parent container 13547 13548 self.dom.parent.style[mixitup.features.transitionProp] = 13549 self.dom.parent.style.height = 13550 self.dom.parent.style.width = 13551 self.dom.parent.style.overflow = 13552 self.dom.parent.style[mixitup.features.perspectiveProp] = 13553 self.dom.parent.style[mixitup.features.perspectiveOriginProp] = ''; 13554 13555 if (operation.willChangeLayout) { 13556 h.removeClass(self.dom.container, operation.startContainerClassName); 13557 h.addClass(self.dom.container, operation.newContainerClassName); 13558 } 13559 13560 if (operation.toRemove.length) { 13561 for (i = 0; target = self.targets[i]; i++) { 13562 if (operation.toRemove.indexOf(target) > -1) { 13563 if ( 13564 (whitespaceBefore = target.dom.el.previousSibling) && whitespaceBefore.nodeName === '#text' && 13565 (whitespaceAfter = target.dom.el.nextSibling) && whitespaceAfter.nodeName === '#text' 13566 ) { 13567 h.removeWhitespace(whitespaceBefore); 13568 } 13569 13570 if (!operation.willSort) { 13571 // NB: Sorting will remove targets as a bi-product of `printSort()` 13572 13573 self.dom.parent.removeChild(target.dom.el); 13574 } 13575 13576 self.targets.splice(i, 1); 13577 13578 target.isInDom = false; 13579 13580 i--; 13581 } 13582 } 13583 13584 // Since targets have been removed, the original order must be updated 13585 13586 self.origOrder = self.targets; 13587 } 13588 13589 if (operation.willSort) { 13590 self.targets = operation.newOrder; 13591 } 13592 13593 self.state = operation.newState; 13594 self.lastOperation = operation; 13595 13596 self.dom.targets = self.state.targets; 13597 13598 // mixEnd 13599 13600 mixitup.events.fire('mixEnd', self.dom.container, { 13601 state: self.state, 13602 instance: self 13603 }, self.dom.document); 13604 13605 if (typeof self.config.callbacks.onMixEnd === 'function') { 13606 self.config.callbacks.onMixEnd.call(self.dom.container, self.state, self); 13607 } 13608 13609 if (operation.hasFailed) { 13610 // mixFail 13611 13612 mixitup.events.fire('mixFail', self.dom.container, { 13613 state: self.state, 13614 instance: self 13615 }, self.dom.document); 13616 13617 if (typeof self.config.callbacks.onMixFail === 'function') { 13618 self.config.callbacks.onMixFail.call(self.dom.container, self.state, self); 13619 } 13620 13621 h.addClass(self.dom.container, h.getClassname(self.config.classNames, 'container', self.config.classNames.modifierFailed)); 13622 } 13623 13624 // User-defined callback function 13625 13626 if (typeof self.userCallback === 'function') { 13627 self.userCallback.call(self.dom.container, self.state, self); 13628 } 13629 13630 if (typeof self.userDeferred.resolve === 'function') { 13631 self.userDeferred.resolve(self.state); 13632 } 13633 13634 self.userCallback = null; 13635 self.userDeferred = null; 13636 self.lastClicked = null; 13637 self.isToggling = false; 13638 self.isBusy = false; 13639 13640 if (self.queue.length) { 13641 self.callActions('beforeReadQueueCleanUp', arguments); 13642 13643 nextInQueue = self.queue.shift(); 13644 13645 // Update non-public API properties stored in queue 13646 13647 self.userDeferred = nextInQueue.deferred; 13648 self.isToggling = nextInQueue.isToggling; 13649 self.lastClicked = nextInQueue.triggerElement; 13650 13651 if (nextInQueue.instruction.command instanceof mixitup.CommandMultimix) { 13652 self.multimix.apply(self, nextInQueue.args); 13653 } else { 13654 self.dataset.apply(self, nextInQueue.args); 13655 } 13656 } 13657 13658 self.callActions('afterCleanUp', arguments); 13659 }, 13660 13661 /** 13662 * @private 13663 * @instance 13664 * @since 2.0.0 13665 * @param {Array<*>} args 13666 * @return {mixitup.UserInstruction} 13667 */ 13668 13669 parseMultimixArgs: function(args) { 13670 var self = this, 13671 instruction = new mixitup.UserInstruction(), 13672 arg = null, 13673 i = -1; 13674 13675 instruction.animate = self.config.animation.enable; 13676 instruction.command = new mixitup.CommandMultimix(); 13677 13678 for (i = 0; i < args.length; i++) { 13679 arg = args[i]; 13680 13681 if (arg === null) continue; 13682 13683 if (typeof arg === 'object') { 13684 h.extend(instruction.command, arg); 13685 } else if (typeof arg === 'boolean') { 13686 instruction.animate = arg; 13687 } else if (typeof arg === 'function') { 13688 instruction.callback = arg; 13689 } 13690 } 13691 13692 // Coerce arbitrary command arguments into typed command objects 13693 13694 if (instruction.command.insert && !(instruction.command.insert instanceof mixitup.CommandInsert)) { 13695 instruction.command.insert = self.parseInsertArgs([instruction.command.insert]).command; 13696 } 13697 13698 if (instruction.command.remove && !(instruction.command.remove instanceof mixitup.CommandRemove)) { 13699 instruction.command.remove = self.parseRemoveArgs([instruction.command.remove]).command; 13700 } 13701 13702 if (instruction.command.filter && !(instruction.command.filter instanceof mixitup.CommandFilter)) { 13703 instruction.command.filter = self.parseFilterArgs([instruction.command.filter]).command; 13704 } 13705 13706 if (instruction.command.sort && !(instruction.command.sort instanceof mixitup.CommandSort)) { 13707 instruction.command.sort = self.parseSortArgs([instruction.command.sort]).command; 13708 } 13709 13710 if (instruction.command.changeLayout && !(instruction.command.changeLayout instanceof mixitup.CommandChangeLayout)) { 13711 instruction.command.changeLayout = self.parseChangeLayoutArgs([instruction.command.changeLayout]).command; 13712 } 13713 13714 instruction = self.callFilters('instructionParseMultimixArgs', instruction, arguments); 13715 13716 h.freeze(instruction); 13717 13718 return instruction; 13719 }, 13720 13721 /** 13722 * @private 13723 * @instance 13724 * @since 2.0.0 13725 * @param {Array<*>} args 13726 * @return {mixitup.UserInstruction} 13727 */ 13728 13729 parseFilterArgs: function(args) { 13730 var self = this, 13731 instruction = new mixitup.UserInstruction(), 13732 arg = null, 13733 i = -1; 13734 13735 instruction.animate = self.config.animation.enable; 13736 instruction.command = new mixitup.CommandFilter(); 13737 13738 for (i = 0; i < args.length; i++) { 13739 arg = args[i]; 13740 13741 if (typeof arg === 'string') { 13742 // Selector 13743 13744 instruction.command.selector = arg; 13745 } else if (arg === null) { 13746 instruction.command.collection = []; 13747 } else if (typeof arg === 'object' && h.isElement(arg, self.dom.document)) { 13748 // Single element 13749 13750 instruction.command.collection = [arg]; 13751 } else if (typeof arg === 'object' && typeof arg.length !== 'undefined') { 13752 // Multiple elements in array, NodeList or jQuery collection 13753 13754 instruction.command.collection = h.arrayFromList(arg); 13755 } else if (typeof arg === 'object') { 13756 // Filter command 13757 13758 h.extend(instruction.command, arg); 13759 } else if (typeof arg === 'boolean') { 13760 instruction.animate = arg; 13761 } else if (typeof arg === 'function') { 13762 instruction.callback = arg; 13763 } 13764 } 13765 13766 if (instruction.command.selector && instruction.command.collection) { 13767 throw new Error(mixitup.messages.errorFilterInvalidArguments()); 13768 } 13769 13770 instruction = self.callFilters('instructionParseFilterArgs', instruction, arguments); 13771 13772 h.freeze(instruction); 13773 13774 return instruction; 13775 }, 13776 13777 parseSortArgs: function(args) { 13778 var self = this, 13779 instruction = new mixitup.UserInstruction(), 13780 arg = null, 13781 sortString = '', 13782 i = -1; 13783 13784 instruction.animate = self.config.animation.enable; 13785 instruction.command = new mixitup.CommandSort(); 13786 13787 for (i = 0; i < args.length; i++) { 13788 arg = args[i]; 13789 13790 if (arg === null) continue; 13791 13792 switch (typeof arg) { 13793 case 'string': 13794 // Sort string 13795 13796 sortString = arg; 13797 13798 break; 13799 case 'object': 13800 // Array of element references 13801 13802 if (arg.length) { 13803 instruction.command.collection = h.arrayFromList(arg); 13804 } 13805 13806 break; 13807 case 'boolean': 13808 instruction.animate = arg; 13809 13810 break; 13811 case 'function': 13812 instruction.callback = arg; 13813 13814 break; 13815 } 13816 } 13817 13818 if (sortString) { 13819 instruction.command = self.parseSortString(sortString, instruction.command); 13820 } 13821 13822 instruction = self.callFilters('instructionParseSortArgs', instruction, arguments); 13823 13824 h.freeze(instruction); 13825 13826 return instruction; 13827 }, 13828 13829 /** 13830 * @private 13831 * @instance 13832 * @since 2.0.0 13833 * @param {Array<*>} args 13834 * @return {mixitup.UserInstruction} 13835 */ 13836 13837 parseInsertArgs: function(args) { 13838 var self = this, 13839 instruction = new mixitup.UserInstruction(), 13840 arg = null, 13841 i = -1; 13842 13843 instruction.animate = self.config.animation.enable; 13844 instruction.command = new mixitup.CommandInsert(); 13845 13846 for (i = 0; i < args.length; i++) { 13847 arg = args[i]; 13848 13849 if (arg === null) continue; 13850 13851 if (typeof arg === 'number') { 13852 // Insert index 13853 13854 instruction.command.index = arg; 13855 } else if (typeof arg === 'string' && ['before', 'after'].indexOf(arg) > -1) { 13856 // 'before'/'after' 13857 13858 instruction.command.position = arg; 13859 } else if (typeof arg === 'string') { 13860 // Markup 13861 13862 instruction.command.collection = 13863 h.arrayFromList(h.createElement(arg).childNodes); 13864 } else if (typeof arg === 'object' && h.isElement(arg, self.dom.document)) { 13865 // Single element 13866 13867 !instruction.command.collection.length ? 13868 (instruction.command.collection = [arg]) : 13869 (instruction.command.sibling = arg); 13870 } else if (typeof arg === 'object' && arg.length) { 13871 // Multiple elements in array or jQuery collection 13872 13873 !instruction.command.collection.length ? 13874 (instruction.command.collection = arg) : 13875 instruction.command.sibling = arg[0]; 13876 } else if (typeof arg === 'object' && arg.childNodes && arg.childNodes.length) { 13877 // Document fragment 13878 13879 !instruction.command.collection.length ? 13880 instruction.command.collection = h.arrayFromList(arg.childNodes) : 13881 instruction.command.sibling = arg.childNodes[0]; 13882 } else if (typeof arg === 'object') { 13883 // Insert command 13884 13885 h.extend(instruction.command, arg); 13886 } else if (typeof arg === 'boolean') { 13887 instruction.animate = arg; 13888 } else if (typeof arg === 'function') { 13889 instruction.callback = arg; 13890 } 13891 } 13892 13893 if (instruction.command.index && instruction.command.sibling) { 13894 throw new Error(mixitup.messages.errorInsertInvalidArguments()); 13895 } 13896 13897 if (!instruction.command.collection.length && self.config.debug.showWarnings) { 13898 console.warn(mixitup.messages.warningInsertNoElements()); 13899 } 13900 13901 instruction = self.callFilters('instructionParseInsertArgs', instruction, arguments); 13902 13903 h.freeze(instruction); 13904 13905 return instruction; 13906 }, 13907 13908 /** 13909 * @private 13910 * @instance 13911 * @since 3.0.0 13912 * @param {Array<*>} args 13913 * @return {mixitup.UserInstruction} 13914 */ 13915 13916 parseRemoveArgs: function(args) { 13917 var self = this, 13918 instruction = new mixitup.UserInstruction(), 13919 target = null, 13920 arg = null, 13921 i = -1; 13922 13923 instruction.animate = self.config.animation.enable; 13924 instruction.command = new mixitup.CommandRemove(); 13925 13926 for (i = 0; i < args.length; i++) { 13927 arg = args[i]; 13928 13929 if (arg === null) continue; 13930 13931 switch (typeof arg) { 13932 case 'number': 13933 if (self.targets[arg]) { 13934 instruction.command.targets[0] = self.targets[arg]; 13935 } 13936 13937 break; 13938 case 'string': 13939 instruction.command.collection = h.arrayFromList(self.dom.parent.querySelectorAll(arg)); 13940 13941 break; 13942 case 'object': 13943 if (arg && arg.length) { 13944 instruction.command.collection = arg; 13945 } else if (h.isElement(arg, self.dom.document)) { 13946 instruction.command.collection = [arg]; 13947 } else { 13948 // Remove command 13949 13950 h.extend(instruction.command, arg); 13951 } 13952 13953 break; 13954 case 'boolean': 13955 instruction.animate = arg; 13956 13957 break; 13958 case 'function': 13959 instruction.callback = arg; 13960 13961 break; 13962 } 13963 } 13964 13965 if (instruction.command.collection.length) { 13966 for (i = 0; target = self.targets[i]; i++) { 13967 if (instruction.command.collection.indexOf(target.dom.el) > -1) { 13968 instruction.command.targets.push(target); 13969 } 13970 } 13971 } 13972 13973 if (!instruction.command.targets.length && self.config.debug.showWarnings) { 13974 console.warn(mixitup.messages.warningRemoveNoElements()); 13975 } 13976 13977 h.freeze(instruction); 13978 13979 return instruction; 13980 }, 13981 13982 /** 13983 * @private 13984 * @instance 13985 * @since 3.0.0 13986 * @param {Array<*>} args 13987 * @return {mixitup.UserInstruction} 13988 */ 13989 13990 parseDatasetArgs: function(args) { 13991 var self = this, 13992 instruction = new mixitup.UserInstruction(), 13993 arg = null, 13994 i = -1; 13995 13996 instruction.animate = self.config.animation.enable; 13997 instruction.command = new mixitup.CommandDataset(); 13998 13999 for (i = 0; i < args.length; i++) { 14000 arg = args[i]; 14001 14002 if (arg === null) continue; 14003 14004 switch (typeof arg) { 14005 case 'object': 14006 if (Array.isArray(arg) || typeof arg.length === 'number') { 14007 instruction.command.dataset = arg; 14008 } else { 14009 // Change layout command 14010 14011 h.extend(instruction.command, arg); 14012 } 14013 14014 break; 14015 case 'boolean': 14016 instruction.animate = arg; 14017 14018 break; 14019 case 'function': 14020 instruction.callback = arg; 14021 14022 break; 14023 } 14024 } 14025 14026 h.freeze(instruction); 14027 14028 return instruction; 14029 }, 14030 14031 /** 14032 * @private 14033 * @instance 14034 * @since 3.0.0 14035 * @param {Array<*>} args 14036 * @return {mixitup.UserInstruction} 14037 */ 14038 14039 parseChangeLayoutArgs: function(args) { 14040 var self = this, 14041 instruction = new mixitup.UserInstruction(), 14042 arg = null, 14043 i = -1; 14044 14045 instruction.animate = self.config.animation.enable; 14046 instruction.command = new mixitup.CommandChangeLayout(); 14047 14048 for (i = 0; i < args.length; i++) { 14049 arg = args[i]; 14050 14051 if (arg === null) continue; 14052 14053 switch (typeof arg) { 14054 case 'string': 14055 instruction.command.containerClassName = arg; 14056 14057 break; 14058 case 'object': 14059 // Change layout command 14060 14061 h.extend(instruction.command, arg); 14062 14063 break; 14064 case 'boolean': 14065 instruction.animate = arg; 14066 14067 break; 14068 case 'function': 14069 instruction.callback = arg; 14070 14071 break; 14072 } 14073 } 14074 14075 h.freeze(instruction); 14076 14077 return instruction; 14078 }, 14079 14080 /** 14081 * @private 14082 * @instance 14083 * @since 3.0.0 14084 * @param {mixitup.QueueItem} queueItem 14085 * @return {Promise.<mixitup.State>} 14086 */ 14087 14088 queueMix: function(queueItem) { 14089 var self = this, 14090 deferred = null, 14091 toggleSelector = ''; 14092 14093 self.callActions('beforeQueueMix', arguments); 14094 14095 deferred = h.defer(mixitup.libraries); 14096 14097 if (self.config.animation.queue && self.queue.length < self.config.animation.queueLimit) { 14098 queueItem.deferred = deferred; 14099 14100 self.queue.push(queueItem); 14101 14102 // Keep controls in sync with user interactions. Mixer will catch up as it drains the queue. 14103 14104 if (self.config.controls.enable) { 14105 if (self.isToggling) { 14106 self.buildToggleArray(queueItem.instruction.command); 14107 14108 toggleSelector = self.getToggleSelector(); 14109 14110 self.updateControls({ 14111 filter: { 14112 selector: toggleSelector 14113 } 14114 }); 14115 } else { 14116 self.updateControls(queueItem.instruction.command); 14117 } 14118 } 14119 } else { 14120 if (self.config.debug.showWarnings) { 14121 console.warn(mixitup.messages.warningMultimixInstanceQueueFull()); 14122 } 14123 14124 deferred.resolve(self.state); 14125 14126 mixitup.events.fire('mixBusy', self.dom.container, { 14127 state: self.state, 14128 instance: self 14129 }, self.dom.document); 14130 14131 if (typeof self.config.callbacks.onMixBusy === 'function') { 14132 self.config.callbacks.onMixBusy.call(self.dom.container, self.state, self); 14133 } 14134 } 14135 14136 return self.callFilters('promiseQueueMix', deferred.promise, arguments); 14137 }, 14138 14139 /** 14140 * @private 14141 * @instance 14142 * @since 3.0.0 14143 * @param {Array.<object>} newDataset 14144 * @return {Operation} 14145 */ 14146 14147 getDataOperation: function(newDataset) { 14148 var self = this, 14149 operation = new mixitup.Operation(), 14150 startDataset = []; 14151 14152 operation = self.callFilters('operationUnmappedGetDataOperation', operation, arguments); 14153 14154 if (self.dom.targets.length && !(startDataset = (self.state.activeDataset || [])).length) { 14155 throw new Error(mixitup.messages.errorDatasetNotSet()); 14156 } 14157 14158 operation.id = h.randomHex(); 14159 operation.startState = self.state; 14160 operation.startDataset = startDataset; 14161 operation.newDataset = newDataset.slice(); 14162 14163 self.diffDatasets(operation); 14164 14165 operation.startOrder = self.targets; 14166 operation.newOrder = operation.show; 14167 14168 if (self.config.animation.enable) { 14169 self.getStartMixData(operation); 14170 self.setInter(operation); 14171 14172 operation.docState = h.getDocumentState(self.dom.document); 14173 14174 self.getInterMixData(operation); 14175 self.setFinal(operation); 14176 self.getFinalMixData(operation); 14177 14178 self.parseEffects(); 14179 14180 operation.hasEffect = self.hasEffect(); 14181 14182 self.getTweenData(operation); 14183 } 14184 14185 self.targets = operation.show.slice(); 14186 14187 operation.newState = self.buildState(operation); 14188 14189 // NB: Targets to be removed must be included in `self.targets` for removal during clean up, 14190 // but are added after state is built so that state is accurate 14191 14192 Array.prototype.push.apply(self.targets, operation.toRemove); 14193 14194 operation = self.callFilters('operationMappedGetDataOperation', operation, arguments); 14195 14196 return operation; 14197 }, 14198 14199 /** 14200 * @private 14201 * @instance 14202 * @since 3.0.0 14203 * @param {mixitup.Operation} operation 14204 * @return {void} 14205 */ 14206 14207 diffDatasets: function(operation) { 14208 var self = this, 14209 persistantStartIds = [], 14210 persistantNewIds = [], 14211 insertedTargets = [], 14212 data = null, 14213 target = null, 14214 el = null, 14215 frag = null, 14216 nextEl = null, 14217 uids = {}, 14218 id = '', 14219 i = -1; 14220 14221 self.callActions('beforeDiffDatasets', arguments); 14222 14223 for (i = 0; data = operation.newDataset[i]; i++) { 14224 if (typeof (id = data[self.config.data.uidKey]) === 'undefined' || id.toString().length < 1) { 14225 throw new TypeError(mixitup.messages.errorDatasetInvalidUidKey({ 14226 uidKey: self.config.data.uidKey 14227 })); 14228 } 14229 14230 if (!uids[id]) { 14231 uids[id] = true; 14232 } else { 14233 throw new Error(mixitup.messages.errorDatasetDuplicateUid({ 14234 uid: id 14235 })); 14236 } 14237 14238 if ((target = self.cache[id]) instanceof mixitup.Target) { 14239 // Already in cache 14240 14241 if (self.config.data.dirtyCheck && !h.deepEquals(data, target.data)) { 14242 // change detected 14243 14244 el = target.render(data); 14245 14246 target.data = data; 14247 14248 if (el !== target.dom.el) { 14249 // Update target element reference 14250 14251 if (target.isInDom) { 14252 target.unbindEvents(); 14253 14254 self.dom.parent.replaceChild(el, target.dom.el); 14255 } 14256 14257 if (!target.isShown) { 14258 el.style.display = 'none'; 14259 } 14260 14261 target.dom.el = el; 14262 14263 if (target.isInDom) { 14264 target.bindEvents(); 14265 } 14266 } 14267 } 14268 14269 el = target.dom.el; 14270 } else { 14271 // New target 14272 14273 target = new mixitup.Target(); 14274 14275 target.init(null, self, data); 14276 14277 target.hide(); 14278 } 14279 14280 if (!target.isInDom) { 14281 // Adding to DOM 14282 14283 if (!frag) { 14284 // Open frag 14285 14286 frag = self.dom.document.createDocumentFragment(); 14287 } 14288 14289 if (frag.lastElementChild) { 14290 frag.appendChild(self.dom.document.createTextNode(' ')); 14291 } 14292 14293 frag.appendChild(target.dom.el); 14294 14295 target.isInDom = true; 14296 14297 target.unbindEvents(); 14298 target.bindEvents(); 14299 target.hide(); 14300 14301 operation.toShow.push(target); 14302 14303 insertedTargets.push(target); 14304 } else { 14305 // Already in DOM 14306 14307 nextEl = target.dom.el.nextElementSibling; 14308 14309 persistantNewIds.push(id); 14310 14311 if (frag) { 14312 // Close and insert previously opened frag 14313 14314 if (frag.lastElementChild) { 14315 frag.appendChild(self.dom.document.createTextNode(' ')); 14316 } 14317 14318 self.insertDatasetFrag(frag, target.dom.el, insertedTargets); 14319 14320 frag = null; 14321 } 14322 } 14323 14324 operation.show.push(target); 14325 } 14326 14327 if (frag) { 14328 // Unclosed frag remaining 14329 14330 nextEl = nextEl || self.config.layout.siblingAfter; 14331 14332 if (nextEl) { 14333 frag.appendChild(self.dom.document.createTextNode(' ')); 14334 } 14335 14336 self.insertDatasetFrag(frag, nextEl, insertedTargets); 14337 } 14338 14339 for (i = 0; data = operation.startDataset[i]; i++) { 14340 id = data[self.config.data.uidKey]; 14341 14342 target = self.cache[id]; 14343 14344 if (operation.show.indexOf(target) < 0) { 14345 // Previously shown but now absent 14346 14347 operation.hide.push(target); 14348 operation.toHide.push(target); 14349 operation.toRemove.push(target); 14350 } else { 14351 persistantStartIds.push(id); 14352 } 14353 } 14354 14355 if (!h.isEqualArray(persistantStartIds, persistantNewIds)) { 14356 operation.willSort = true; 14357 } 14358 14359 self.callActions('afterDiffDatasets', arguments); 14360 }, 14361 14362 /** 14363 * @private 14364 * @instance 14365 * @since 3.1.5 14366 * @param {DocumentFragment} frag 14367 * @param {(HTMLElement|null)} nextEl 14368 * @param {Array.<mixitup.Target>} targets 14369 * @return {void} 14370 */ 14371 14372 insertDatasetFrag: function(frag, nextEl, targets) { 14373 var self = this; 14374 var insertAt = nextEl ? h.arrayFromList(self.dom.parent.children).indexOf(nextEl) : self.targets.length; 14375 14376 self.dom.parent.insertBefore(frag, nextEl); 14377 14378 while (targets.length) { 14379 self.targets.splice(insertAt, 0, targets.shift()); 14380 14381 insertAt++; 14382 } 14383 }, 14384 14385 /** 14386 * @private 14387 * @instance 14388 * @since 3.0.0 14389 * @param {mixitup.CommandSort} sortCommandA 14390 * @param {mixitup.CommandSort} sortCommandB 14391 * @return {boolean} 14392 */ 14393 14394 willSort: function(sortCommandA, sortCommandB) { 14395 var self = this, 14396 result = false; 14397 14398 if ( 14399 self.config.behavior.liveSort || 14400 sortCommandA.order === 'random' || 14401 sortCommandA.attribute !== sortCommandB.attribute || 14402 sortCommandA.order !== sortCommandB.order || 14403 sortCommandA.collection !== sortCommandB.collection || 14404 (sortCommandA.next === null && sortCommandB.next) || 14405 (sortCommandA.next && sortCommandB.next === null) 14406 ) { 14407 result = true; 14408 } else if (sortCommandA.next && sortCommandB.next) { 14409 result = self.willSort(sortCommandA.next, sortCommandB.next); 14410 } else { 14411 result = false; 14412 } 14413 14414 return self.callFilters('resultWillSort', result, arguments); 14415 }, 14416 14417 /** 14418 * A shorthand method for `.filter('all')`. Shows all targets in the container. 14419 * 14420 * @example 14421 * 14422 * .show() 14423 * 14424 * @example <caption>Example: Showing all targets</caption> 14425 * 14426 * mixer.show() 14427 * .then(function(state) { 14428 * console.log(state.totalShow === state.totalTargets); // true 14429 * }); 14430 * 14431 * @public 14432 * @instance 14433 * @since 3.0.0 14434 * @return {Promise.<mixitup.State>} 14435 */ 14436 14437 show: function() { 14438 var self = this; 14439 14440 return self.filter('all'); 14441 }, 14442 14443 /** 14444 * A shorthand method for `.filter('none')`. Hides all targets in the container. 14445 * 14446 * @example 14447 * 14448 * .hide() 14449 * 14450 * @example <caption>Example: Hiding all targets</caption> 14451 * 14452 * mixer.hide() 14453 * .then(function(state) { 14454 * console.log(state.totalShow === 0); // true 14455 * console.log(state.totalHide === state.totalTargets); // true 14456 * }); 14457 * 14458 * @public 14459 * @instance 14460 * @since 3.0.0 14461 * @return {Promise.<mixitup.State>} 14462 */ 14463 14464 hide: function() { 14465 var self = this; 14466 14467 return self.filter('none'); 14468 }, 14469 14470 /** 14471 * Returns a boolean indicating whether or not a MixItUp operation is 14472 * currently in progress. 14473 * 14474 * @example 14475 * 14476 * .isMixing() 14477 * 14478 * @example <caption>Example: Checking the status of a mixer</caption> 14479 * 14480 * mixer.sort('random', function() { 14481 * console.log(mixer.isMixing()) // false 14482 * }); 14483 * 14484 * console.log(mixer.isMixing()) // true 14485 * 14486 * @public 14487 * @instance 14488 * @since 2.0.0 14489 * @return {boolean} 14490 */ 14491 14492 isMixing: function() { 14493 var self = this; 14494 14495 return self.isBusy; 14496 }, 14497 14498 /** 14499 * Filters all targets in the container by a provided selector string, or the values `'all'` 14500 * or `'none'`. Only targets matching the selector will be shown. 14501 * 14502 * @example 14503 * 14504 * .filter(selector [, animate] [, callback]) 14505 * 14506 * @example <caption>Example 1: Filtering targets by a class selector</caption> 14507 * 14508 * mixer.filter('.category-a') 14509 * .then(function(state) { 14510 * console.log(state.totalShow === containerEl.querySelectorAll('.category-a').length); // true 14511 * }); 14512 * 14513 * @example <caption>Example 2: Filtering targets by an attribute selector</caption> 14514 * 14515 * mixer.filter('[data-category~="a"]') 14516 * .then(function(state) { 14517 * console.log(state.totalShow === containerEl.querySelectorAll('[data-category~="a"]').length); // true 14518 * }); 14519 * 14520 * @example <caption>Example 3: Filtering targets by a compound selector</caption> 14521 * 14522 * // Show only those targets with the classes 'category-a' AND 'category-b' 14523 * 14524 * mixer.filter('.category-a.category-c') 14525 * .then(function(state) { 14526 * console.log(state.totalShow === containerEl.querySelectorAll('.category-a.category-c').length); // true 14527 * }); 14528 * 14529 * @example <caption>Example 4: Filtering via an element collection</caption> 14530 * 14531 * var collection = Array.from(container.querySelectorAll('.mix')); 14532 * 14533 * console.log(collection.length); // 34 14534 * 14535 * // Filter the collection manually using Array.prototype.filter 14536 * 14537 * var filtered = collection.filter(function(target) { 14538 * return parseInt(target.getAttribute('data-price')) > 10; 14539 * }); 14540 * 14541 * console.log(filtered.length); // 22 14542 * 14543 * // Pass the filtered collection to MixItUp 14544 * 14545 * mixer.filter(filtered) 14546 * .then(function(state) { 14547 * console.log(state.activeFilter.collection.length === 22); // true 14548 * }); 14549 * 14550 * @public 14551 * @instance 14552 * @since 2.0.0 14553 * @param {(string|HTMLElement|Array.<HTMLElement>)} selector 14554 * Any valid CSS selector (i.e. `'.category-a'`), or the values `'all'` or `'none'`. The filter method also accepts a reference to single target element or a collection of target elements to show. 14555 * @param {boolean} [animate=true] 14556 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14557 * @param {function} [callback=null] 14558 * An optional callback function to be invoked after the operation has completed. 14559 * @return {Promise.<mixitup.State>} 14560 * A promise resolving with the current state object. 14561 */ 14562 14563 filter: function() { 14564 var self = this, 14565 instruction = self.parseFilterArgs(arguments); 14566 14567 return self.multimix({ 14568 filter: instruction.command 14569 }, instruction.animate, instruction.callback); 14570 }, 14571 14572 /** 14573 * Adds an additional selector to the currently active filter selector, concatenating 14574 * as per the logic defined in `controls.toggleLogic`. 14575 * 14576 * @example 14577 * 14578 * .toggleOn(selector [, animate] [, callback]) 14579 * 14580 * @example <caption>Example: Toggling on a filter selector</caption> 14581 * 14582 * console.log(mixer.getState().activeFilter.selector); // '.category-a' 14583 * 14584 * mixer.toggleOn('.category-b') 14585 * .then(function(state) { 14586 * console.log(state.activeFilter.selector); // '.category-a, .category-b' 14587 * }); 14588 * 14589 * @public 14590 * @instance 14591 * @since 3.0.0 14592 * @param {string} selector 14593 * Any valid CSS selector (i.e. `'.category-a'`) 14594 * @param {boolean} [animate=true] 14595 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14596 * @param {function} [callback=null] 14597 * An optional callback function to be invoked after the operation has completed. 14598 * @return {Promise.<mixitup.State>} 14599 * A promise resolving with the current state object. 14600 */ 14601 14602 toggleOn: function() { 14603 var self = this, 14604 instruction = self.parseFilterArgs(arguments), 14605 selector = instruction.command.selector, 14606 toggleSelector = ''; 14607 14608 self.isToggling = true; 14609 14610 if (self.toggleArray.indexOf(selector) < 0) { 14611 self.toggleArray.push(selector); 14612 } 14613 14614 toggleSelector = self.getToggleSelector(); 14615 14616 return self.multimix({ 14617 filter: toggleSelector 14618 }, instruction.animate, instruction.callback); 14619 }, 14620 14621 /** 14622 * Removes a selector from the active filter selector. 14623 * 14624 * @example 14625 * 14626 * .toggleOff(selector [, animate] [, callback]) 14627 * 14628 * @example <caption>Example: Toggling off a filter selector</caption> 14629 * 14630 * console.log(mixer.getState().activeFilter.selector); // '.category-a, .category-b' 14631 * 14632 * mixer.toggleOff('.category-b') 14633 * .then(function(state) { 14634 * console.log(state.activeFilter.selector); // '.category-a' 14635 * }); 14636 * 14637 * @public 14638 * @instance 14639 * @since 3.0.0 14640 * @param {string} selector 14641 * Any valid CSS selector (i.e. `'.category-a'`) 14642 * @param {boolean} [animate=true] 14643 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14644 * @param {function} [callback=null] 14645 * An optional callback function to be invoked after the operation has completed. 14646 * @return {Promise.<mixitup.State>} 14647 * A promise resolving with the current state object. 14648 */ 14649 14650 toggleOff: function() { 14651 var self = this, 14652 instruction = self.parseFilterArgs(arguments), 14653 selector = instruction.command.selector, 14654 selectorIndex = self.toggleArray.indexOf(selector), 14655 toggleSelector = ''; 14656 14657 self.isToggling = true; 14658 14659 if (selectorIndex > -1) { 14660 self.toggleArray.splice(selectorIndex, 1); 14661 } 14662 14663 toggleSelector = self.getToggleSelector(); 14664 14665 return self.multimix({ 14666 filter: toggleSelector 14667 }, instruction.animate, instruction.callback); 14668 }, 14669 14670 /** 14671 * Sorts all targets in the container according to a provided sort string. 14672 * 14673 * @example 14674 * 14675 * .sort(sortString [, animate] [, callback]) 14676 * 14677 * @example <caption>Example 1: Sorting by the default DOM order</caption> 14678 * 14679 * // Reverse the default order of the targets 14680 * 14681 * mixer.sort('default:desc') 14682 * .then(function(state) { 14683 * console.log(state.activeSort.attribute === 'default'); // true 14684 * console.log(state.activeSort.order === 'desc'); // true 14685 * }); 14686 * 14687 * @example <caption>Example 2: Sorting by a custom data-attribute</caption> 14688 * 14689 * // Sort the targets by the value of a `data-published-date` attribute 14690 * 14691 * mixer.sort('published-date:asc') 14692 * .then(function(state) { 14693 * console.log(state.activeSort.attribute === 'published-date'); // true 14694 * console.log(state.activeSort.order === 'asc'); // true 14695 * }); 14696 * 14697 * @example <caption>Example 3: Sorting by multiple attributes</caption> 14698 * 14699 * // Sort the targets by the value of a `data-published-date` attribute, then by `data-title` 14700 * 14701 * mixer.sort('published-date:desc data-title:asc') 14702 * .then(function(state) { 14703 * console.log(state.activeSort.attribute === 'published-date'); // true 14704 * console.log(state.activeSort.order === 'desc'); // true 14705 * 14706 * console.log(state.activeSort.next.attribute === 'title'); // true 14707 * console.log(state.activeSort.next.order === 'asc'); // true 14708 * }); 14709 * 14710 * @example <caption>Example 4: Sorting by random</caption> 14711 * 14712 * mixer.sort('random') 14713 * .then(function(state) { 14714 * console.log(state.activeSort.order === 'random') // true 14715 * }); 14716 * 14717 * @example <caption>Example 5: Sorting via an element collection</caption> 14718 * 14719 * var collection = Array.from(container.querySelectorAll('.mix')); 14720 * 14721 * // Swap the position of two elements in the collection: 14722 * 14723 * var temp = collection[1]; 14724 * 14725 * collection[1] = collection[0]; 14726 * collection[0] = temp; 14727 * 14728 * // Pass the sorted collection to MixItUp 14729 * 14730 * mixer.sort(collection) 14731 * .then(function(state) { 14732 * console.log(state.targets[0] === collection[0]); // true 14733 * }); 14734 * 14735 * @public 14736 * @instance 14737 * @since 2.0.0 14738 * @param {(string|Array.<HTMLElement>)} sortString 14739 * A valid sort string (e.g. `'default'`, `'published-date:asc'`, or `'random'`). The sort method also accepts an array of all target elements in a user-defined order. 14740 * @param {boolean} [animate=true] 14741 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14742 * @param {function} [callback=null] 14743 * An optional callback function to be invoked after the operation has completed. 14744 * @return {Promise.<mixitup.State>} 14745 * A promise resolving with the current state object. 14746 */ 14747 14748 sort: function() { 14749 var self = this, 14750 instruction = self.parseSortArgs(arguments); 14751 14752 return self.multimix({ 14753 sort: instruction.command 14754 }, instruction.animate, instruction.callback); 14755 }, 14756 14757 /** 14758 * Changes the layout of the container by adding, removing or updating a 14759 * layout-specific class name. If `animation.animateResizetargets` is 14760 * enabled, MixItUp will attempt to gracefully animate the width, height, 14761 * and position of targets between layout states. 14762 * 14763 * @example 14764 * 14765 * .changeLayout(containerClassName [, animate] [, callback]) 14766 * 14767 * @example <caption>Example 1: Adding a new class name to the container</caption> 14768 * 14769 * mixer.changeLayout('container-list') 14770 * .then(function(state) { 14771 * console.log(state.activeContainerClass === 'container-list'); // true 14772 * }); 14773 * 14774 * @example <caption>Example 2: Removing a previously added class name from the container</caption> 14775 * 14776 * mixer.changeLayout('') 14777 * .then(function(state) { 14778 * console.log(state.activeContainerClass === ''); // true 14779 * }); 14780 * 14781 * @public 14782 * @instance 14783 * @since 2.0.0 14784 * @param {string} containerClassName 14785 * A layout-specific class name to add to the container. 14786 * @param {boolean} [animate=true] 14787 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14788 * @param {function} [callback=null] 14789 * An optional callback function to be invoked after the operation has completed. 14790 * @return {Promise.<mixitup.State>} 14791 * A promise resolving with the current state object. 14792 */ 14793 14794 changeLayout: function() { 14795 var self = this, 14796 instruction = self.parseChangeLayoutArgs(arguments); 14797 14798 return self.multimix({ 14799 changeLayout: instruction.command 14800 }, instruction.animate, instruction.callback); 14801 }, 14802 14803 /** 14804 * Updates the contents and order of the container to reflect the provided dataset, 14805 * if the dataset API is in use. 14806 * 14807 * The dataset API is designed for use in API-driven JavaScript applications, and 14808 * can be used instead of DOM-based methods such as `.filter()`, `.sort()`, 14809 * `.insert()`, etc. When used, insertion, removal, sorting and pagination can be 14810 * achieved purely via changes to your data model, without the uglyness of having 14811 * to interact with or query the DOM directly. 14812 * 14813 * @example 14814 * 14815 * .dataset(dataset [, animate] [, callback]) 14816 * 14817 * @example <caption>Example 1: Rendering a dataset</caption> 14818 * 14819 * var myDataset = [ 14820 * {id: 1, ...}, 14821 * {id: 2, ...}, 14822 * {id: 3, ...} 14823 * ]; 14824 * 14825 * mixer.dataset(myDataset) 14826 * .then(function(state) { 14827 * console.log(state.totalShow === 3); // true 14828 * }); 14829 * 14830 * @example <caption>Example 2: Sorting a dataset</caption> 14831 * 14832 * // Create a new dataset in reverse order 14833 * 14834 * var newDataset = myDataset.slice().reverse(); 14835 * 14836 * mixer.dataset(newDataset) 14837 * .then(function(state) { 14838 * console.log(state.activeDataset[0] === myDataset[2]); // true 14839 * }); 14840 * 14841 * @example <caption>Example 3: Removing an item from the dataset</caption> 14842 * 14843 * console.log(myDataset.length); // 3 14844 * 14845 * // Create a new dataset with the last item removed. 14846 * 14847 * var newDataset = myDataset.slice().pop(); 14848 * 14849 * mixer.dataset(newDataset) 14850 * .then(function(state) { 14851 * console.log(state.totalShow === 2); // true 14852 * }); 14853 * 14854 * @public 14855 * @instance 14856 * @since 3.0.0 14857 * @param {Array.<object>} dataset 14858 * An array of objects, each one representing the underlying data model of a target to be rendered. 14859 * @param {boolean} [animate=true] 14860 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14861 * @param {function} [callback=null] 14862 * An optional callback function to be invoked after the operation has completed. 14863 * @return {Promise.<mixitup.State>} 14864 * A promise resolving with the current state object. 14865 */ 14866 14867 dataset: function() { 14868 var self = this, 14869 instruction = self.parseDatasetArgs(arguments), 14870 operation = null, 14871 queueItem = null, 14872 animate = false; 14873 14874 self.callActions('beforeDataset', arguments); 14875 14876 if (!self.isBusy) { 14877 if (instruction.callback) self.userCallback = instruction.callback; 14878 14879 animate = (instruction.animate ^ self.config.animation.enable) ? instruction.animate : self.config.animation.enable; 14880 14881 operation = self.getDataOperation(instruction.command.dataset); 14882 14883 return self.goMix(animate, operation); 14884 } else { 14885 queueItem = new mixitup.QueueItem(); 14886 14887 queueItem.args = arguments; 14888 queueItem.instruction = instruction; 14889 14890 return self.queueMix(queueItem); 14891 } 14892 }, 14893 14894 /** 14895 * Performs simultaneous `filter`, `sort`, `insert`, `remove` and `changeLayout` 14896 * operations as requested. 14897 * 14898 * @example 14899 * 14900 * .multimix(multimixCommand [, animate] [, callback]) 14901 * 14902 * @example <caption>Example 1: Performing simultaneous filtering and sorting</caption> 14903 * 14904 * mixer.multimix({ 14905 * filter: '.category-b', 14906 * sort: 'published-date:desc' 14907 * }) 14908 * .then(function(state) { 14909 * console.log(state.activeFilter.selector === '.category-b'); // true 14910 * console.log(state.activeSort.attribute === 'published-date'); // true 14911 * }); 14912 * 14913 * @example <caption>Example 2: Performing simultaneous sorting, insertion, and removal</caption> 14914 * 14915 * console.log(mixer.getState().totalShow); // 6 14916 * 14917 * // NB: When inserting via `multimix()`, an object should be provided as the value 14918 * // for the `insert` portion of the command, allowing for a collection of elements 14919 * // and an insertion index to be specified. 14920 * 14921 * mixer.multimix({ 14922 * sort: 'published-date:desc', // Sort the container, including any new elements 14923 * insert: { 14924 * collection: [newElementReferenceA, newElementReferenceB], // Add 2 new elements at index 5 14925 * index: 5 14926 * }, 14927 * remove: existingElementReference // Remove 1 existing element 14928 * }) 14929 * .then(function(state) { 14930 * console.log(state.activeSort.attribute === 'published-date'); // true 14931 * console.log(state.totalShow === 7); // true 14932 * }); 14933 * 14934 * @public 14935 * @instance 14936 * @since 2.0.0 14937 * @param {object} multimixCommand 14938 * An object containing one or more things to do 14939 * @param {boolean} [animate=true] 14940 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 14941 * @param {function} [callback=null] 14942 * An optional callback function to be invoked after the operation has completed. 14943 * @return {Promise.<mixitup.State>} 14944 * A promise resolving with the current state object. 14945 */ 14946 14947 multimix: function() { 14948 var self = this, 14949 operation = null, 14950 animate = false, 14951 queueItem = null, 14952 instruction = self.parseMultimixArgs(arguments); 14953 14954 self.callActions('beforeMultimix', arguments); 14955 14956 if (!self.isBusy) { 14957 operation = self.getOperation(instruction.command); 14958 14959 if (self.config.controls.enable) { 14960 // Update controls for API calls 14961 14962 if (instruction.command.filter && !self.isToggling) { 14963 // As we are not toggling, reset the toggle array 14964 // so new filter overrides existing toggles 14965 14966 self.toggleArray.length = 0; 14967 self.buildToggleArray(operation.command); 14968 } 14969 14970 if (self.queue.length < 1) { 14971 self.updateControls(operation.command); 14972 } 14973 } 14974 14975 if (instruction.callback) self.userCallback = instruction.callback; 14976 14977 // Always allow the instruction to override the instance setting 14978 14979 animate = (instruction.animate ^ self.config.animation.enable) ? 14980 instruction.animate : 14981 self.config.animation.enable; 14982 14983 self.callFilters('operationMultimix', operation, arguments); 14984 14985 return self.goMix(animate, operation); 14986 } else { 14987 queueItem = new mixitup.QueueItem(); 14988 14989 queueItem.args = arguments; 14990 queueItem.instruction = instruction; 14991 queueItem.triggerElement = self.lastClicked; 14992 queueItem.isToggling = self.isToggling; 14993 14994 return self.queueMix(queueItem); 14995 } 14996 }, 14997 14998 /** 14999 * @private 15000 * @instance 15001 * @since 3.0.0 15002 * @param {object} multimixCommand 15003 * @param {boolean} [isPreFetch] 15004 * An optional boolean indicating that the operation is being pre-fetched for execution at a later time. 15005 * @return {Operation|null} 15006 */ 15007 15008 getOperation: function(multimixCommand) { 15009 var self = this, 15010 sortCommand = multimixCommand.sort, 15011 filterCommand = multimixCommand.filter, 15012 changeLayoutCommand = multimixCommand.changeLayout, 15013 removeCommand = multimixCommand.remove, 15014 insertCommand = multimixCommand.insert, 15015 operation = new mixitup.Operation(); 15016 15017 operation = self.callFilters('operationUnmappedGetOperation', operation, arguments); 15018 15019 operation.id = h.randomHex(); 15020 operation.command = multimixCommand; 15021 operation.startState = self.state; 15022 operation.triggerElement = self.lastClicked; 15023 15024 if (self.isBusy) { 15025 if (self.config.debug.showWarnings) { 15026 console.warn(mixitup.messages.warningGetOperationInstanceBusy()); 15027 } 15028 15029 return null; 15030 } 15031 15032 if (insertCommand) { 15033 self.insertTargets(insertCommand, operation); 15034 } 15035 15036 if (removeCommand) { 15037 operation.toRemove = removeCommand.targets; 15038 } 15039 15040 operation.startSort = operation.newSort = operation.startState.activeSort; 15041 operation.startOrder = operation.newOrder = self.targets; 15042 15043 if (sortCommand) { 15044 operation.startSort = operation.startState.activeSort; 15045 operation.newSort = sortCommand; 15046 15047 operation.willSort = self.willSort(sortCommand, operation.startState.activeSort); 15048 15049 if (operation.willSort) { 15050 self.sortOperation(operation); 15051 } 15052 } 15053 15054 operation.startFilter = operation.startState.activeFilter; 15055 15056 if (filterCommand) { 15057 operation.newFilter = filterCommand; 15058 } else { 15059 operation.newFilter = h.extend(new mixitup.CommandFilter(), operation.startFilter); 15060 } 15061 15062 if (operation.newFilter.selector === 'all') { 15063 operation.newFilter.selector = self.config.selectors.target; 15064 } else if (operation.newFilter.selector === 'none') { 15065 operation.newFilter.selector = ''; 15066 } 15067 15068 self.filterOperation(operation); 15069 15070 operation.startContainerClassName = operation.startState.activeContainerClassName; 15071 15072 if (changeLayoutCommand) { 15073 operation.newContainerClassName = changeLayoutCommand.containerClassName; 15074 15075 if (operation.newContainerClassName !== operation.startContainerClassName) { 15076 operation.willChangeLayout = true; 15077 } 15078 } else { 15079 operation.newContainerClassName = operation.startContainerClassName; 15080 } 15081 15082 if (self.config.animation.enable) { 15083 // Populate the operation's position data 15084 15085 self.getStartMixData(operation); 15086 self.setInter(operation); 15087 15088 operation.docState = h.getDocumentState(self.dom.document); 15089 15090 self.getInterMixData(operation); 15091 self.setFinal(operation); 15092 self.getFinalMixData(operation); 15093 15094 self.parseEffects(); 15095 15096 operation.hasEffect = self.hasEffect(); 15097 15098 self.getTweenData(operation); 15099 } 15100 15101 if (operation.willSort) { 15102 self.targets = operation.newOrder; 15103 } 15104 15105 operation.newState = self.buildState(operation); 15106 15107 return self.callFilters('operationMappedGetOperation', operation, arguments); 15108 }, 15109 15110 /** 15111 * Renders a previously created operation at a specific point in its path, as 15112 * determined by a multiplier between 0 and 1. 15113 * 15114 * @example 15115 * .tween(operation, multiplier) 15116 * 15117 * @private 15118 * @instance 15119 * @since 3.0.0 15120 * @param {mixitup.Operation} operation 15121 * An operation object created via the `getOperation` method 15122 * 15123 * @param {Float} multiplier 15124 * Any number between 0 and 1 representing the percentage complete of the operation 15125 * @return {void} 15126 */ 15127 15128 tween: function(operation, multiplier) { 15129 var target = null, 15130 posData = null, 15131 toHideIndex = -1, 15132 i = -1; 15133 15134 multiplier = Math.min(multiplier, 1); 15135 multiplier = Math.max(multiplier, 0); 15136 15137 for (i = 0; target = operation.show[i]; i++) { 15138 posData = operation.showPosData[i]; 15139 15140 target.applyTween(posData, multiplier); 15141 } 15142 15143 for (i = 0; target = operation.hide[i]; i++) { 15144 if (target.isShown) { 15145 target.hide(); 15146 } 15147 15148 if ((toHideIndex = operation.toHide.indexOf(target)) > -1) { 15149 posData = operation.toHidePosData[toHideIndex]; 15150 15151 if (!target.isShown) { 15152 target.show(); 15153 } 15154 15155 target.applyTween(posData, multiplier); 15156 } 15157 } 15158 }, 15159 15160 /** 15161 * Inserts one or more new target elements into the container at a specified 15162 * index. 15163 * 15164 * To be indexed as targets, new elements must match the `selectors.target` 15165 * selector (`'.mix'` by default). 15166 * 15167 * @example 15168 * 15169 * .insert(newElements [, index] [, animate], [, callback]) 15170 * 15171 * @example <caption>Example 1: Inserting a single element via reference</caption> 15172 * 15173 * console.log(mixer.getState().totalShow); // 0 15174 * 15175 * // Create a new element 15176 * 15177 * var newElement = document.createElement('div'); 15178 * newElement.classList.add('mix'); 15179 * 15180 * mixer.insert(newElement) 15181 * .then(function(state) { 15182 * console.log(state.totalShow === 1); // true 15183 * }); 15184 * 15185 * @example <caption>Example 2: Inserting a single element via HTML string</caption> 15186 * 15187 * console.log(mixer.getState().totalShow); // 1 15188 * 15189 * // Create a new element via reference 15190 * 15191 * var newElementHtml = '<div class="mix"></div>'; 15192 * 15193 * // Create and insert the new element at index 1 15194 * 15195 * mixer.insert(newElementHtml, 1) 15196 * .then(function(state) { 15197 * console.log(state.totalShow === 2); // true 15198 * console.log(state.show[1].outerHTML === newElementHtml); // true 15199 * }); 15200 * 15201 * @example <caption>Example 3: Inserting multiple elements via reference</caption> 15202 * 15203 * console.log(mixer.getState().totalShow); // 2 15204 * 15205 * // Create an array of new elements to insert. 15206 * 15207 * var newElement1 = document.createElement('div'); 15208 * var newElement2 = document.createElement('div'); 15209 * 15210 * newElement1.classList.add('mix'); 15211 * newElement2.classList.add('mix'); 15212 * 15213 * var newElementsCollection = [newElement1, newElement2]; 15214 * 15215 * // Insert the new elements starting at index 1 15216 * 15217 * mixer.insert(newElementsCollection, 1) 15218 * .then(function(state) { 15219 * console.log(state.totalShow === 4); // true 15220 * console.log(state.show[1] === newElement1); // true 15221 * console.log(state.show[2] === newElement2); // true 15222 * }); 15223 * 15224 * @example <caption>Example 4: Inserting a jQuery collection object containing one or more elements</caption> 15225 * 15226 * console.log(mixer.getState().totalShow); // 4 15227 * 15228 * var $newElement = $('<div class="mix"></div>'); 15229 * 15230 * // Insert the new elements starting at index 3 15231 * 15232 * mixer.insert($newElement, 3) 15233 * .then(function(state) { 15234 * console.log(state.totalShow === 5); // true 15235 * console.log(state.show[3] === $newElement[0]); // true 15236 * }); 15237 * 15238 * @public 15239 * @instance 15240 * @since 2.0.0 15241 * @param {(HTMLElement|Array.<HTMLElement>|string)} newElements 15242 * A reference to a single element to insert, an array-like collection of elements, or an HTML string representing a single element. 15243 * @param {number} index=0 15244 * The index at which to insert the new element(s). `0` by default. 15245 * @param {boolean} [animate=true] 15246 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 15247 * @param {function} [callback=null] 15248 * An optional callback function to be invoked after the operation has completed. 15249 * @return {Promise.<mixitup.State>} 15250 * A promise resolving with the current state object. 15251 */ 15252 15253 insert: function() { 15254 var self = this, 15255 args = self.parseInsertArgs(arguments); 15256 15257 return self.multimix({ 15258 insert: args.command 15259 }, args.animate, args.callback); 15260 }, 15261 15262 /** 15263 * Inserts one or more new elements before a provided reference element. 15264 * 15265 * @example 15266 * 15267 * .insertBefore(newElements, referenceElement [, animate] [, callback]) 15268 * 15269 * @example <caption>Example: Inserting a new element before a reference element</caption> 15270 * 15271 * // An existing reference element is chosen at index 2 15272 * 15273 * var referenceElement = mixer.getState().show[2]; 15274 * 15275 * // Create a new element 15276 * 15277 * var newElement = document.createElement('div'); 15278 * newElement.classList.add('mix'); 15279 * 15280 * mixer.insertBefore(newElement, referenceElement) 15281 * .then(function(state) { 15282 * // The new element is inserted into the container at index 2, before the reference element 15283 * 15284 * console.log(state.show[2] === newElement); // true 15285 * 15286 * // The reference element is now at index 3 15287 * 15288 * console.log(state.show[3] === referenceElement); // true 15289 * }); 15290 * 15291 * @public 15292 * @instance 15293 * @since 3.0.0 15294 * @param {(HTMLElement|Array.<HTMLElement>|string)} newElements 15295 * A reference to a single element to insert, an array-like collection of elements, or an HTML string representing a single element. 15296 * @param {HTMLElement} referenceElement 15297 * A reference to an existing element in the container to insert new elements before. 15298 *@param {boolean} [animate=true] 15299 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 15300 * @param {function} [callback=null] 15301 * An optional callback function to be invoked after the operation has completed. 15302 * @return {Promise.<mixitup.State>} 15303 * A promise resolving with the current state object. 15304 */ 15305 15306 insertBefore: function() { 15307 var self = this, 15308 args = self.parseInsertArgs(arguments); 15309 15310 return self.insert(args.command.collection, 'before', args.command.sibling, args.animate, args.callback); 15311 }, 15312 15313 /** 15314 * Inserts one or more new elements after a provided reference element. 15315 * 15316 * @example 15317 * 15318 * .insertAfter(newElements, referenceElement [, animate] [, callback]) 15319 * 15320 * @example <caption>Example: Inserting a new element after a reference element</caption> 15321 * 15322 * // An existing reference element is chosen at index 2 15323 * 15324 * var referenceElement = mixer.getState().show[2]; 15325 * 15326 * // Create a new element 15327 * 15328 * var newElement = document.createElement('div'); 15329 * newElement.classList.add('mix'); 15330 * 15331 * mixer.insertAfter(newElement, referenceElement) 15332 * .then(function(state) { 15333 * // The new element is inserted into the container at index 3, after the reference element 15334 * 15335 * console.log(state.show[3] === newElement); // true 15336 * }); 15337 * 15338 * @public 15339 * @instance 15340 * @since 3.0.0 15341 * @param {(HTMLElement|Array.<HTMLElement>|string)} newElements 15342 * A reference to a single element to insert, an array-like collection of elements, or an HTML string representing a single element. 15343 * @param {HTMLElement} referenceElement 15344 * A reference to an existing element in the container to insert new elements after. 15345 * @param {boolean} [animate=true] 15346 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 15347 * @param {function} [callback=null] 15348 * An optional callback function to be invoked after the operation has completed. 15349 * @return {Promise.<mixitup.State>} 15350 * A promise resolving with the current state object. 15351 */ 15352 15353 insertAfter: function() { 15354 var self = this, 15355 args = self.parseInsertArgs(arguments); 15356 15357 return self.insert(args.command.collection, 'after', args.command.sibling, args.animate, args.callback); 15358 }, 15359 15360 /** 15361 * Inserts one or more new elements into the container before all existing targets. 15362 * 15363 * @example 15364 * 15365 * .prepend(newElements [,animate] [,callback]) 15366 * 15367 * @example <caption>Example: Prepending a new element</caption> 15368 * 15369 * // Create a new element 15370 * 15371 * var newElement = document.createElement('div'); 15372 * newElement.classList.add('mix'); 15373 * 15374 * // Insert the element into the container 15375 * 15376 * mixer.prepend(newElement) 15377 * .then(function(state) { 15378 * console.log(state.show[0] === newElement); // true 15379 * }); 15380 * 15381 * @public 15382 * @instance 15383 * @since 3.0.0 15384 * @param {(HTMLElement|Array.<HTMLElement>|string)} newElements 15385 * A reference to a single element to insert, an array-like collection of elements, or an HTML string representing a single element. 15386 * @param {boolean} [animate=true] 15387 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 15388 * @param {function} [callback=null] 15389 * An optional callback function to be invoked after the operation has completed. 15390 * @return {Promise.<mixitup.State>} 15391 * A promise resolving with the current state object. 15392 */ 15393 15394 prepend: function() { 15395 var self = this, 15396 args = self.parseInsertArgs(arguments); 15397 15398 return self.insert(0, args.command.collection, args.animate, args.callback); 15399 }, 15400 15401 /** 15402 * Inserts one or more new elements into the container after all existing targets. 15403 * 15404 * @example 15405 * 15406 * .append(newElements [,animate] [,callback]) 15407 * 15408 * @example <caption>Example: Appending a new element</caption> 15409 * 15410 * // Create a new element 15411 * 15412 * var newElement = document.createElement('div'); 15413 * newElement.classList.add('mix'); 15414 * 15415 * // Insert the element into the container 15416 * 15417 * mixer.append(newElement) 15418 * .then(function(state) { 15419 * console.log(state.show[state.show.length - 1] === newElement); // true 15420 * }); 15421 * 15422 * @public 15423 * @instance 15424 * @since 3.0.0 15425 * @param {(HTMLElement|Array.<HTMLElement>|string)} newElements 15426 * A reference to a single element to insert, an array-like collection of elements, or an HTML string representing a single element. 15427 * @param {boolean} [animate=true] 15428 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 15429 * @param {function} [callback=null] 15430 * An optional callback function to be invoked after the operation has completed. 15431 * @return {Promise.<mixitup.State>} 15432 * A promise resolving with the current state object. 15433 */ 15434 15435 append: function() { 15436 var self = this, 15437 args = self.parseInsertArgs(arguments); 15438 15439 return self.insert(self.state.totalTargets, args.command.collection, args.animate, args.callback); 15440 }, 15441 15442 /** 15443 * Removes one or more existing target elements from the container. 15444 * 15445 * @example 15446 * 15447 * .remove(elements [, animate] [, callback]) 15448 * 15449 * @example <caption>Example 1: Removing an element by reference</caption> 15450 * 15451 * var elementToRemove = containerEl.firstElementChild; 15452 * 15453 * mixer.remove(elementToRemove) 15454 * .then(function(state) { 15455 * console.log(state.targets.indexOf(elementToRemove) === -1); // true 15456 * }); 15457 * 15458 * @example <caption>Example 2: Removing a collection of elements by reference</caption> 15459 * 15460 * var elementsToRemove = containerEl.querySelectorAll('.category-a'); 15461 * 15462 * console.log(elementsToRemove.length) // 3 15463 * 15464 * mixer.remove(elementsToRemove) 15465 * .then(function() { 15466 * console.log(containerEl.querySelectorAll('.category-a').length); // 0 15467 * }); 15468 * 15469 * @example <caption>Example 3: Removing one or more elements by selector</caption> 15470 * 15471 * mixer.remove('.category-a') 15472 * .then(function() { 15473 * console.log(containerEl.querySelectorAll('.category-a').length); // 0 15474 * }); 15475 * 15476 * @example <caption>Example 4: Removing an element by index</caption> 15477 * 15478 * console.log(mixer.getState.totalShow); // 4 15479 * 15480 * // Remove the element at index 3 15481 * 15482 * mixer.remove(3) 15483 * .then(function(state) { 15484 * console.log(state.totalShow); // 3 15485 * console.log(state.show[3]); // undefined 15486 * }); 15487 * 15488 * 15489 * @public 15490 * @instance 15491 * @since 3.0.0 15492 * @param {(HTMLElement|Array.<HTMLElement>|string|number)} elements 15493 * A reference to a single element to remove, an array-like collection of elements, a selector string, or the index of an element to remove. 15494 * @param {boolean} [animate=true] 15495 * An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default. 15496 * @param {function} [callback=null] 15497 * An optional callback function to be invoked after the operation has completed. 15498 * @return {Promise.<mixitup.State>} 15499 * A promise resolving with the current state object. 15500 */ 15501 15502 remove: function() { 15503 var self = this, 15504 args = self.parseRemoveArgs(arguments); 15505 15506 return self.multimix({ 15507 remove: args.command 15508 }, args.animate, args.callback); 15509 }, 15510 15511 /** 15512 * Retrieves the the value of any property or sub-object within the current 15513 * mixitup configuration, or the whole configuration object. 15514 * 15515 * @example 15516 * 15517 * .getConfig([stringKey]) 15518 * 15519 * @example <caption>Example 1: retrieve the entire configuration object</caption> 15520 * 15521 * var config = mixer.getConfig(); // Config { ... } 15522 * 15523 * @example <caption>Example 2: retrieve a named sub-object of configuration object</caption> 15524 * 15525 * var animation = mixer.getConfig('animation'); // ConfigAnimation { ... } 15526 * 15527 * @example <caption>Example 3: retrieve a value of configuration object via a dot-notation string key</caption> 15528 * 15529 * var effects = mixer.getConfig('animation.effects'); // 'fade scale' 15530 * 15531 * @public 15532 * @instance 15533 * @since 2.0.0 15534 * @param {string} [stringKey] A "dot-notation" string key 15535 * @return {*} 15536 */ 15537 15538 getConfig: function(stringKey) { 15539 var self = this, 15540 value = null; 15541 15542 if (!stringKey) { 15543 value = self.config; 15544 } else { 15545 value = h.getProperty(self.config, stringKey); 15546 } 15547 15548 return self.callFilters('valueGetConfig', value, arguments); 15549 }, 15550 15551 /** 15552 * Updates the configuration of the mixer, after it has been instantiated. 15553 * 15554 * See the Configuration Object documentation for a full list of avilable 15555 * configuration options. 15556 * 15557 * @example 15558 * 15559 * .configure(config) 15560 * 15561 * @example <caption>Example 1: Updating animation options</caption> 15562 * 15563 * mixer.configure({ 15564 * animation: { 15565 * effects: 'fade translateX(-100%)', 15566 * duration: 300 15567 * } 15568 * }); 15569 * 15570 * @example <caption>Example 2: Removing a callback after it has been set</caption> 15571 * 15572 * var mixer; 15573 * 15574 * function handleMixEndOnce() { 15575 * // Do something .. 15576 * 15577 * // Then nullify the callback 15578 * 15579 * mixer.configure({ 15580 * callbacks: { 15581 * onMixEnd: null 15582 * } 15583 * }); 15584 * }; 15585 * 15586 * // Instantiate a mixer with a callback defined 15587 * 15588 * mixer = mixitup(containerEl, { 15589 * callbacks: { 15590 * onMixEnd: handleMixEndOnce 15591 * } 15592 * }); 15593 * 15594 * @public 15595 * @instance 15596 * @since 3.0.0 15597 * @param {object} config 15598 * An object containing one of more configuration options. 15599 * @return {void} 15600 */ 15601 15602 configure: function(config) { 15603 var self = this; 15604 15605 self.callActions('beforeConfigure', arguments); 15606 15607 h.extend(self.config, config, true, true); 15608 15609 self.callActions('afterConfigure', arguments); 15610 }, 15611 15612 /** 15613 * Returns an object containing information about the current state of the 15614 * mixer. See the State Object documentation for more information. 15615 * 15616 * NB: State objects are immutable and should therefore be regenerated 15617 * after any operation. 15618 * 15619 * @example 15620 * 15621 * .getState(); 15622 * 15623 * @example <caption>Example: Retrieving a state object</caption> 15624 * 15625 * var state = mixer.getState(); 15626 * 15627 * console.log(state.totalShow + 'targets are currently shown'); 15628 * 15629 * @public 15630 * @instance 15631 * @since 2.0.0 15632 * @return {mixitup.State} An object reflecting the current state of the mixer. 15633 */ 15634 15635 getState: function() { 15636 var self = this, 15637 state = null; 15638 15639 state = new mixitup.State(); 15640 15641 h.extend(state, self.state); 15642 15643 h.freeze(state); 15644 15645 return self.callFilters('stateGetState', state, arguments); 15646 }, 15647 15648 /** 15649 * Forces the re-indexing all targets within the container. 15650 * 15651 * This should only be used if some other piece of code in your application 15652 * has manipulated the contents of your container, which should be avoided. 15653 * 15654 * If you need to add or remove target elements from the container, use 15655 * the built-in `.insert()` or `.remove()` methods, and MixItUp will keep 15656 * itself up to date. 15657 * 15658 * @example 15659 * 15660 * .forceRefresh() 15661 * 15662 * @example <caption>Example: Force refreshing the mixer after external DOM manipulation</caption> 15663 * 15664 * console.log(mixer.getState().totalShow); // 3 15665 * 15666 * // An element is removed from the container via some external DOM manipulation code: 15667 * 15668 * containerEl.removeChild(containerEl.firstElementChild); 15669 * 15670 * // The mixer does not know that the number of targets has changed: 15671 * 15672 * console.log(mixer.getState().totalShow); // 3 15673 * 15674 * mixer.forceRefresh(); 15675 * 15676 * // After forceRefresh, the mixer is in sync again: 15677 * 15678 * console.log(mixer.getState().totalShow); // 2 15679 * 15680 * @public 15681 * @instance 15682 * @since 2.1.2 15683 * @return {void} 15684 */ 15685 15686 forceRefresh: function() { 15687 var self = this; 15688 15689 self.indexTargets(); 15690 }, 15691 15692 /** 15693 * Forces the re-rendering of all targets when using the Dataset API. 15694 * 15695 * By default, targets are only re-rendered when `data.dirtyCheck` is 15696 * enabled, and an item's data has changed when `dataset()` is called. 15697 * 15698 * The `forceRender()` method allows for the re-rendering of all targets 15699 * in response to some arbitrary event, such as the changing of the target 15700 * render function. 15701 * 15702 * Targets are rendered against their existing data. 15703 * 15704 * @example 15705 * 15706 * .forceRender() 15707 * 15708 * @example <caption>Example: Force render targets after changing the target render function</caption> 15709 * 15710 * console.log(container.innerHTML); // ... <span class="mix">Foo</span> ... 15711 * 15712 * mixer.configure({ 15713 * render: { 15714 * target: (item) => `<a href="/${item.slug}/" class="mix">${item.title}</a>` 15715 * } 15716 * }); 15717 * 15718 * mixer.forceRender(); 15719 * 15720 * console.log(container.innerHTML); // ... <a href="/foo/" class="mix">Foo</a> ... 15721 * 15722 * @public 15723 * @instance 15724 * @since 3.2.1 15725 * @return {void} 15726 */ 15727 15728 forceRender: function() { 15729 var self = this, 15730 target = null, 15731 el = null, 15732 id = ''; 15733 15734 for (id in self.cache) { 15735 target = self.cache[id]; 15736 15737 el = target.render(target.data); 15738 15739 if (el !== target.dom.el) { 15740 // Update target element reference 15741 15742 if (target.isInDom) { 15743 target.unbindEvents(); 15744 15745 self.dom.parent.replaceChild(el, target.dom.el); 15746 } 15747 15748 if (!target.isShown) { 15749 el.style.display = 'none'; 15750 } 15751 15752 target.dom.el = el; 15753 15754 if (target.isInDom) { 15755 target.bindEvents(); 15756 } 15757 } 15758 } 15759 15760 self.state = self.buildState(self.lastOperation); 15761 }, 15762 15763 /** 15764 * Removes mixitup functionality from the container, unbinds all control 15765 * event handlers, and deletes the mixer instance from MixItUp's internal 15766 * cache. 15767 * 15768 * This should be performed whenever a mixer's container is removed from 15769 * the DOM, such as during a page change in a single page application, 15770 * or React's `componentWillUnmount()`. 15771 * 15772 * @example 15773 * 15774 * .destroy([cleanUp]) 15775 * 15776 * @example <caption>Example: Destroying the mixer before removing its container element</caption> 15777 * 15778 * mixer.destroy(); 15779 * 15780 * containerEl.parentElement.removeChild(containerEl); 15781 * 15782 * @public 15783 * @instance 15784 * @since 2.0.0 15785 * @param {boolean} [cleanUp=false] 15786 * An optional boolean dictating whether or not to clean up any inline `display: none;` styling applied to hidden targets. 15787 * @return {void} 15788 */ 15789 15790 destroy: function(cleanUp) { 15791 var self = this, 15792 control = null, 15793 target = null, 15794 i = 0; 15795 15796 self.callActions('beforeDestroy', arguments); 15797 15798 for (i = 0; control = self.controls[i]; i++) { 15799 control.removeBinding(self); 15800 } 15801 15802 for (i = 0; target = self.targets[i]; i++) { 15803 if (cleanUp) { 15804 target.show(); 15805 } 15806 15807 target.unbindEvents(); 15808 } 15809 15810 if (self.dom.container.id.match(/^MixItUp/)) { 15811 self.dom.container.removeAttribute('id'); 15812 } 15813 15814 delete mixitup.instances[self.id]; 15815 15816 self.callActions('afterDestroy', arguments); 15817 } 15818 }); 15819 15820 /** 15821 * @constructor 15822 * @memberof mixitup 15823 * @private 15824 * @since 3.0.0 15825 */ 15826 15827 mixitup.IMoveData = function() { 15828 mixitup.Base.call(this); 15829 15830 this.callActions('beforeConstruct'); 15831 15832 this.posIn = null; 15833 this.posOut = null; 15834 this.operation = null; 15835 this.callback = null; 15836 this.statusChange = ''; 15837 this.duration = -1; 15838 this.staggerIndex = -1; 15839 15840 this.callActions('afterConstruct'); 15841 15842 h.seal(this); 15843 }; 15844 15845 mixitup.BaseStatic.call(mixitup.IMoveData); 15846 15847 mixitup.IMoveData.prototype = Object.create(mixitup.Base.prototype); 15848 15849 mixitup.IMoveData.prototype.constructor = mixitup.IMoveData; 15850 15851 /** 15852 * @constructor 15853 * @memberof mixitup 15854 * @private 15855 * @since 3.0.0 15856 */ 15857 15858 mixitup.TargetDom = function() { 15859 mixitup.Base.call(this); 15860 15861 this.callActions('beforeConstruct'); 15862 15863 this.el = null; 15864 15865 this.callActions('afterConstruct'); 15866 15867 h.seal(this); 15868 }; 15869 15870 mixitup.BaseStatic.call(mixitup.TargetDom); 15871 15872 mixitup.TargetDom.prototype = Object.create(mixitup.Base.prototype); 15873 15874 mixitup.TargetDom.prototype.constructor = mixitup.TargetDom; 15875 15876 /** 15877 * @constructor 15878 * @namespace 15879 * @memberof mixitup 15880 * @private 15881 * @since 3.0.0 15882 */ 15883 15884 mixitup.Target = function() { 15885 mixitup.Base.call(this); 15886 15887 this.callActions('beforeConstruct'); 15888 15889 this.id = ''; 15890 this.sortString = ''; 15891 this.mixer = null; 15892 this.callback = null; 15893 this.isShown = false; 15894 this.isBound = false; 15895 this.isExcluded = false; 15896 this.isInDom = false; 15897 this.handler = null; 15898 this.operation = null; 15899 this.data = null; 15900 this.dom = new mixitup.TargetDom(); 15901 15902 this.callActions('afterConstruct'); 15903 15904 h.seal(this); 15905 }; 15906 15907 mixitup.BaseStatic.call(mixitup.Target); 15908 15909 mixitup.Target.prototype = Object.create(mixitup.Base.prototype); 15910 15911 h.extend(mixitup.Target.prototype, { 15912 constructor: mixitup.Target, 15913 15914 /** 15915 * Initialises a newly instantiated Target. 15916 * 15917 * @private 15918 * @instance 15919 * @since 3.0.0 15920 * @param {(Element|null)} el 15921 * @param {object} mixer 15922 * @param {object} [data] 15923 * @return {void} 15924 */ 15925 15926 init: function(el, mixer, data) { 15927 var self = this, 15928 id = ''; 15929 15930 self.callActions('beforeInit', arguments); 15931 15932 self.mixer = mixer; 15933 15934 if (!el) { 15935 // If no element is provided, render it 15936 15937 el = self.render(data); 15938 } 15939 15940 self.cacheDom(el); 15941 15942 self.bindEvents(); 15943 15944 if (self.dom.el.style.display !== 'none') { 15945 self.isShown = true; 15946 } 15947 15948 if (data && mixer.config.data.uidKey) { 15949 if (typeof (id = data[mixer.config.data.uidKey]) === 'undefined' || id.toString().length < 1) { 15950 throw new TypeError(mixitup.messages.errorDatasetInvalidUidKey({ 15951 uidKey: mixer.config.data.uidKey 15952 })); 15953 } 15954 15955 self.id = id; 15956 self.data = data; 15957 15958 mixer.cache[id] = self; 15959 } 15960 15961 self.callActions('afterInit', arguments); 15962 }, 15963 15964 /** 15965 * Renders the target element using a user-defined renderer function. 15966 * 15967 * @private 15968 * @instance 15969 * @since 3.1.4 15970 * @param {object} data 15971 * @return {void} 15972 */ 15973 15974 render: function(data) { 15975 var self = this, 15976 render = null, 15977 el = null, 15978 temp = null, 15979 output = ''; 15980 15981 self.callActions('beforeRender', arguments); 15982 15983 render = self.callFilters('renderRender', self.mixer.config.render.target, arguments); 15984 15985 if (typeof render !== 'function') { 15986 throw new TypeError(mixitup.messages.errorDatasetRendererNotSet()); 15987 } 15988 15989 output = render(data); 15990 15991 if (output && typeof output === 'object' && h.isElement(output)) { 15992 el = output; 15993 } else if (typeof output === 'string') { 15994 temp = document.createElement('div'); 15995 temp.innerHTML = output; 15996 15997 el = temp.firstElementChild; 15998 } 15999 16000 return self.callFilters('elRender', el, arguments); 16001 }, 16002 16003 /** 16004 * Caches references of DOM elements neccessary for the target's functionality. 16005 * 16006 * @private 16007 * @instance 16008 * @since 3.0.0 16009 * @param {Element} el 16010 * @return {void} 16011 */ 16012 16013 cacheDom: function(el) { 16014 var self = this; 16015 16016 self.callActions('beforeCacheDom', arguments); 16017 16018 self.dom.el = el; 16019 16020 self.callActions('afterCacheDom', arguments); 16021 }, 16022 16023 /** 16024 * @private 16025 * @instance 16026 * @since 3.0.0 16027 * @param {string} attributeName 16028 * @return {void} 16029 */ 16030 16031 getSortString: function(attributeName) { 16032 var self = this, 16033 value = self.dom.el.getAttribute('data-' + attributeName) || ''; 16034 16035 self.callActions('beforeGetSortString', arguments); 16036 16037 value = isNaN(value * 1) ? 16038 value.toLowerCase() : 16039 value * 1; 16040 16041 self.sortString = value; 16042 16043 self.callActions('afterGetSortString', arguments); 16044 }, 16045 16046 /** 16047 * @private 16048 * @instance 16049 * @since 3.0.0 16050 * @return {void} 16051 */ 16052 16053 show: function() { 16054 var self = this; 16055 16056 self.callActions('beforeShow', arguments); 16057 16058 if (!self.isShown) { 16059 self.dom.el.style.display = ''; 16060 16061 self.isShown = true; 16062 } 16063 16064 self.callActions('afterShow', arguments); 16065 }, 16066 16067 /** 16068 * @private 16069 * @instance 16070 * @since 3.0.0 16071 * @return {void} 16072 */ 16073 16074 hide: function() { 16075 var self = this; 16076 16077 self.callActions('beforeHide', arguments); 16078 16079 if (self.isShown) { 16080 self.dom.el.style.display = 'none'; 16081 16082 self.isShown = false; 16083 } 16084 16085 self.callActions('afterHide', arguments); 16086 }, 16087 16088 /** 16089 * @private 16090 * @instance 16091 * @since 3.0.0 16092 * @param {mixitup.IMoveData} moveData 16093 * @return {void} 16094 */ 16095 16096 move: function(moveData) { 16097 var self = this; 16098 16099 self.callActions('beforeMove', arguments); 16100 16101 if (!self.isExcluded) { 16102 self.mixer.targetsMoved++; 16103 } 16104 16105 self.applyStylesIn(moveData); 16106 16107 requestAnimationFrame(function() { 16108 self.applyStylesOut(moveData); 16109 }); 16110 16111 self.callActions('afterMove', arguments); 16112 }, 16113 16114 /** 16115 * @private 16116 * @instance 16117 * @since 3.0.0 16118 * @param {object} posData 16119 * @param {number} multiplier 16120 * @return {void} 16121 */ 16122 16123 applyTween: function(posData, multiplier) { 16124 var self = this, 16125 propertyName = '', 16126 tweenData = null, 16127 posIn = posData.posIn, 16128 currentTransformValues = [], 16129 currentValues = new mixitup.StyleData(), 16130 i = -1; 16131 16132 self.callActions('beforeApplyTween', arguments); 16133 16134 currentValues.x = posIn.x; 16135 currentValues.y = posIn.y; 16136 16137 if (multiplier === 0) { 16138 self.hide(); 16139 } else if (!self.isShown) { 16140 self.show(); 16141 } 16142 16143 for (i = 0; propertyName = mixitup.features.TWEENABLE[i]; i++) { 16144 tweenData = posData.tweenData[propertyName]; 16145 16146 if (propertyName === 'x') { 16147 if (!tweenData) continue; 16148 16149 currentValues.x = posIn.x + (tweenData * multiplier); 16150 } else if (propertyName === 'y') { 16151 if (!tweenData) continue; 16152 16153 currentValues.y = posIn.y + (tweenData * multiplier); 16154 } else if (tweenData instanceof mixitup.TransformData) { 16155 if (!tweenData.value) continue; 16156 16157 currentValues[propertyName].value = 16158 posIn[propertyName].value + (tweenData.value * multiplier); 16159 16160 currentValues[propertyName].unit = tweenData.unit; 16161 16162 currentTransformValues.push( 16163 propertyName + '(' + currentValues[propertyName].value + tweenData.unit + ')' 16164 ); 16165 } else { 16166 if (!tweenData) continue; 16167 16168 currentValues[propertyName] = posIn[propertyName] + (tweenData * multiplier); 16169 16170 self.dom.el.style[propertyName] = currentValues[propertyName]; 16171 } 16172 } 16173 16174 if (currentValues.x || currentValues.y) { 16175 currentTransformValues.unshift('translate(' + currentValues.x + 'px, ' + currentValues.y + 'px)'); 16176 } 16177 16178 if (currentTransformValues.length) { 16179 self.dom.el.style[mixitup.features.transformProp] = currentTransformValues.join(' '); 16180 } 16181 16182 self.callActions('afterApplyTween', arguments); 16183 }, 16184 16185 /** 16186 * Applies the initial styling to a target element before any transition 16187 * is applied. 16188 * 16189 * @private 16190 * @instance 16191 * @param {mixitup.IMoveData} moveData 16192 * @return {void} 16193 */ 16194 16195 applyStylesIn: function(moveData) { 16196 var self = this, 16197 posIn = moveData.posIn, 16198 isFading = self.mixer.effectsIn.opacity !== 1, 16199 transformValues = []; 16200 16201 self.callActions('beforeApplyStylesIn', arguments); 16202 16203 transformValues.push('translate(' + posIn.x + 'px, ' + posIn.y + 'px)'); 16204 16205 if (self.mixer.config.animation.animateResizeTargets) { 16206 if (moveData.statusChange !== 'show') { 16207 // Don't apply posIn width or height or showing, as will be 0 16208 16209 self.dom.el.style.width = posIn.width + 'px'; 16210 self.dom.el.style.height = posIn.height + 'px'; 16211 } 16212 16213 self.dom.el.style.marginRight = posIn.marginRight + 'px'; 16214 self.dom.el.style.marginBottom = posIn.marginBottom + 'px'; 16215 } 16216 16217 isFading && (self.dom.el.style.opacity = posIn.opacity); 16218 16219 if (moveData.statusChange === 'show') { 16220 transformValues = transformValues.concat(self.mixer.transformIn); 16221 } 16222 16223 self.dom.el.style[mixitup.features.transformProp] = transformValues.join(' '); 16224 16225 self.callActions('afterApplyStylesIn', arguments); 16226 }, 16227 16228 /** 16229 * Applies a transition followed by the final styles for the element to 16230 * transition towards. 16231 * 16232 * @private 16233 * @instance 16234 * @param {mixitup.IMoveData} moveData 16235 * @return {void} 16236 */ 16237 16238 applyStylesOut: function(moveData) { 16239 var self = this, 16240 transitionRules = [], 16241 transformValues = [], 16242 isResizing = self.mixer.config.animation.animateResizeTargets, 16243 isFading = typeof self.mixer.effectsIn.opacity !== 'undefined'; 16244 16245 self.callActions('beforeApplyStylesOut', arguments); 16246 16247 // Build the transition rules 16248 16249 transitionRules.push(self.writeTransitionRule( 16250 mixitup.features.transformRule, 16251 moveData.staggerIndex 16252 )); 16253 16254 if (moveData.statusChange !== 'none') { 16255 transitionRules.push(self.writeTransitionRule( 16256 'opacity', 16257 moveData.staggerIndex, 16258 moveData.duration 16259 )); 16260 } 16261 16262 if (isResizing) { 16263 transitionRules.push(self.writeTransitionRule( 16264 'width', 16265 moveData.staggerIndex, 16266 moveData.duration 16267 )); 16268 16269 transitionRules.push(self.writeTransitionRule( 16270 'height', 16271 moveData.staggerIndex, 16272 moveData.duration 16273 )); 16274 16275 transitionRules.push(self.writeTransitionRule( 16276 'margin', 16277 moveData.staggerIndex, 16278 moveData.duration 16279 )); 16280 } 16281 16282 // If no callback was provided, the element will 16283 // not transition in any way so tag it as "immovable" 16284 16285 if (!moveData.callback) { 16286 self.mixer.targetsImmovable++; 16287 16288 if (self.mixer.targetsMoved === self.mixer.targetsImmovable) { 16289 // If the total targets moved is equal to the 16290 // number of immovable targets, the operation 16291 // should be considered finished 16292 16293 self.mixer.cleanUp(moveData.operation); 16294 } 16295 16296 return; 16297 } 16298 16299 // If the target will transition in some fasion, 16300 // assign a callback function 16301 16302 self.operation = moveData.operation; 16303 self.callback = moveData.callback; 16304 16305 // As long as the target is not excluded, increment 16306 // the total number of targets bound 16307 16308 !self.isExcluded && self.mixer.targetsBound++; 16309 16310 // Tag the target as bound to differentiate from transitionEnd 16311 // events that may come from stylesheet driven effects 16312 16313 self.isBound = true; 16314 16315 // Apply the transition 16316 16317 self.applyTransition(transitionRules); 16318 16319 // Apply width, height and margin negation 16320 16321 if (isResizing && moveData.posOut.width > 0 && moveData.posOut.height > 0) { 16322 self.dom.el.style.width = moveData.posOut.width + 'px'; 16323 self.dom.el.style.height = moveData.posOut.height + 'px'; 16324 self.dom.el.style.marginRight = moveData.posOut.marginRight + 'px'; 16325 self.dom.el.style.marginBottom = moveData.posOut.marginBottom + 'px'; 16326 } 16327 16328 if (!self.mixer.config.animation.nudge && moveData.statusChange === 'hide') { 16329 // If we're not nudging, the translation should be 16330 // applied before any other transforms to prevent 16331 // lateral movement 16332 16333 transformValues.push('translate(' + moveData.posOut.x + 'px, ' + moveData.posOut.y + 'px)'); 16334 } 16335 16336 // Apply fade 16337 16338 switch (moveData.statusChange) { 16339 case 'hide': 16340 isFading && (self.dom.el.style.opacity = self.mixer.effectsOut.opacity); 16341 16342 transformValues = transformValues.concat(self.mixer.transformOut); 16343 16344 break; 16345 case 'show': 16346 isFading && (self.dom.el.style.opacity = 1); 16347 } 16348 16349 if ( 16350 self.mixer.config.animation.nudge || 16351 (!self.mixer.config.animation.nudge && moveData.statusChange !== 'hide') 16352 ) { 16353 // Opposite of above - apply translate after 16354 // other transform 16355 16356 transformValues.push('translate(' + moveData.posOut.x + 'px, ' + moveData.posOut.y + 'px)'); 16357 } 16358 16359 // Apply transforms 16360 16361 self.dom.el.style[mixitup.features.transformProp] = transformValues.join(' '); 16362 16363 self.callActions('afterApplyStylesOut', arguments); 16364 }, 16365 16366 /** 16367 * Combines the name of a CSS property with the appropriate duration and delay 16368 * values to created a valid transition rule. 16369 * 16370 * @private 16371 * @instance 16372 * @since 3.0.0 16373 * @param {string} property 16374 * @param {number} staggerIndex 16375 * @param {number} duration 16376 * @return {string} 16377 */ 16378 16379 writeTransitionRule: function(property, staggerIndex, duration) { 16380 var self = this, 16381 delay = self.getDelay(staggerIndex), 16382 rule = ''; 16383 16384 rule = property + ' ' + 16385 (duration > 0 ? duration : self.mixer.config.animation.duration) + 'ms ' + 16386 delay + 'ms ' + 16387 (property === 'opacity' ? 'linear' : self.mixer.config.animation.easing); 16388 16389 return self.callFilters('ruleWriteTransitionRule', rule, arguments); 16390 }, 16391 16392 /** 16393 * Calculates the transition delay for each target element based on its index, if 16394 * staggering is applied. If defined, A custom `animation.staggerSeqeuence` 16395 * function can be used to manipulate the order of indices to produce custom 16396 * stagger effects (e.g. for use in a grid with irregular row lengths). 16397 * 16398 * @private 16399 * @instance 16400 * @since 2.0.0 16401 * @param {number} index 16402 * @return {number} 16403 */ 16404 16405 getDelay: function(index) { 16406 var self = this, 16407 delay = -1; 16408 16409 if (typeof self.mixer.config.animation.staggerSequence === 'function') { 16410 index = self.mixer.config.animation.staggerSequence.call(self, index, self.state); 16411 } 16412 16413 delay = !!self.mixer.staggerDuration ? index * self.mixer.staggerDuration : 0; 16414 16415 return self.callFilters('delayGetDelay', delay, arguments); 16416 }, 16417 16418 /** 16419 * @private 16420 * @instance 16421 * @since 3.0.0 16422 * @param {string[]} rules 16423 * @return {void} 16424 */ 16425 16426 applyTransition: function(rules) { 16427 var self = this, 16428 transitionString = rules.join(', '); 16429 16430 self.callActions('beforeApplyTransition', arguments); 16431 16432 self.dom.el.style[mixitup.features.transitionProp] = transitionString; 16433 16434 self.callActions('afterApplyTransition', arguments); 16435 }, 16436 16437 /** 16438 * @private 16439 * @instance 16440 * @since 3.0.0 16441 * @param {Event} e 16442 * @return {void} 16443 */ 16444 16445 handleTransitionEnd: function(e) { 16446 var self = this, 16447 propName = e.propertyName, 16448 canResize = self.mixer.config.animation.animateResizeTargets; 16449 16450 self.callActions('beforeHandleTransitionEnd', arguments); 16451 16452 if ( 16453 self.isBound && 16454 e.target.matches(self.mixer.config.selectors.target) && 16455 ( 16456 propName.indexOf('transform') > -1 || 16457 propName.indexOf('opacity') > -1 || 16458 canResize && propName.indexOf('height') > -1 || 16459 canResize && propName.indexOf('width') > -1 || 16460 canResize && propName.indexOf('margin') > -1 16461 ) 16462 ) { 16463 self.callback.call(self, self.operation); 16464 16465 self.isBound = false; 16466 self.callback = null; 16467 self.operation = null; 16468 } 16469 16470 self.callActions('afterHandleTransitionEnd', arguments); 16471 }, 16472 16473 /** 16474 * @private 16475 * @instance 16476 * @since 3.0.0 16477 * @param {Event} e 16478 * @return {void} 16479 */ 16480 16481 eventBus: function(e) { 16482 var self = this; 16483 16484 self.callActions('beforeEventBus', arguments); 16485 16486 switch (e.type) { 16487 case 'webkitTransitionEnd': 16488 case 'transitionend': 16489 self.handleTransitionEnd(e); 16490 } 16491 16492 self.callActions('afterEventBus', arguments); 16493 }, 16494 16495 /** 16496 * @private 16497 * @instance 16498 * @since 3.0.0 16499 * @return {void} 16500 */ 16501 16502 unbindEvents: function() { 16503 var self = this; 16504 16505 self.callActions('beforeUnbindEvents', arguments); 16506 16507 h.off(self.dom.el, 'webkitTransitionEnd', self.handler); 16508 h.off(self.dom.el, 'transitionend', self.handler); 16509 16510 self.callActions('afterUnbindEvents', arguments); 16511 }, 16512 16513 /** 16514 * @private 16515 * @instance 16516 * @since 3.0.0 16517 * @return {void} 16518 */ 16519 16520 bindEvents: function() { 16521 var self = this, 16522 transitionEndEvent = ''; 16523 16524 self.callActions('beforeBindEvents', arguments); 16525 16526 transitionEndEvent = mixitup.features.transitionPrefix === 'webkit' ? 'webkitTransitionEnd' : 'transitionend'; 16527 16528 self.handler = function(e) { 16529 return self.eventBus(e); 16530 }; 16531 16532 h.on(self.dom.el, transitionEndEvent, self.handler); 16533 16534 self.callActions('afterBindEvents', arguments); 16535 }, 16536 16537 /** 16538 * @private 16539 * @instance 16540 * @since 3.0.0 16541 * @param {boolean} [getBox] 16542 * @return {PosData} 16543 */ 16544 16545 getPosData: function(getBox) { 16546 var self = this, 16547 styles = {}, 16548 rect = null, 16549 posData = new mixitup.StyleData(); 16550 16551 self.callActions('beforeGetPosData', arguments); 16552 16553 posData.x = self.dom.el.offsetLeft; 16554 posData.y = self.dom.el.offsetTop; 16555 16556 if (self.mixer.config.animation.animateResizeTargets || getBox) { 16557 rect = self.dom.el.getBoundingClientRect(); 16558 16559 posData.top = rect.top; 16560 posData.right = rect.right; 16561 posData.bottom = rect.bottom; 16562 posData.left = rect.left; 16563 16564 posData.width = rect.width; 16565 posData.height = rect.height; 16566 } 16567 16568 if (self.mixer.config.animation.animateResizeTargets) { 16569 styles = window.getComputedStyle(self.dom.el); 16570 16571 posData.marginBottom = parseFloat(styles.marginBottom); 16572 posData.marginRight = parseFloat(styles.marginRight); 16573 } 16574 16575 return self.callFilters('posDataGetPosData', posData, arguments); 16576 }, 16577 16578 /** 16579 * @private 16580 * @instance 16581 * @since 3.0.0 16582 * @return {void} 16583 */ 16584 16585 cleanUp: function() { 16586 var self = this; 16587 16588 self.callActions('beforeCleanUp', arguments); 16589 16590 self.dom.el.style[mixitup.features.transformProp] = ''; 16591 self.dom.el.style[mixitup.features.transitionProp] = ''; 16592 self.dom.el.style.opacity = ''; 16593 16594 if (self.mixer.config.animation.animateResizeTargets) { 16595 self.dom.el.style.width = ''; 16596 self.dom.el.style.height = ''; 16597 self.dom.el.style.marginRight = ''; 16598 self.dom.el.style.marginBottom = ''; 16599 } 16600 16601 self.callActions('afterCleanUp', arguments); 16602 } 16603 }); 16604 16605 /** 16606 * A jQuery-collection-like wrapper around one or more `mixitup.Mixer` instances 16607 * allowing simultaneous control of said instances similar to the MixItUp 2 API. 16608 * 16609 * @example 16610 * new mixitup.Collection(instances) 16611 * 16612 * @constructor 16613 * @namespace 16614 * @memberof mixitup 16615 * @private 16616 * @since 3.0.0 16617 * @param {mixitup.Mixer[]} instances 16618 */ 16619 16620 mixitup.Collection = function(instances) { 16621 var instance = null, 16622 i = -1; 16623 16624 this.callActions('beforeConstruct'); 16625 16626 for (i = 0; instance = instances[i]; i++) { 16627 this[i] = instance; 16628 } 16629 16630 this.length = instances.length; 16631 16632 this.callActions('afterConstruct'); 16633 16634 h.freeze(this); 16635 }; 16636 16637 mixitup.BaseStatic.call(mixitup.Collection); 16638 16639 mixitup.Collection.prototype = Object.create(mixitup.Base.prototype); 16640 16641 h.extend(mixitup.Collection.prototype, 16642 /** @lends mixitup.Collection */ 16643 { 16644 constructor: mixitup.Collection, 16645 16646 /** 16647 * Calls a method on all instances in the collection by passing the method 16648 * name as a string followed by any applicable parameters to be curried into 16649 * to the method. 16650 * 16651 * @example 16652 * .mixitup(methodName[,arg1][,arg2..]); 16653 * 16654 * @example 16655 * var collection = new Collection([mixer1, mixer2]); 16656 * 16657 * return collection.mixitup('filter', '.category-a') 16658 * .then(function(states) { 16659 * state.forEach(function(state) { 16660 * console.log(state.activeFilter.selector); // .category-a 16661 * }); 16662 * }); 16663 * 16664 * @public 16665 * @instance 16666 * @since 3.0.0 16667 * @param {string} methodName 16668 * @return {Promise<Array<mixitup.State>>} 16669 */ 16670 16671 mixitup: function(methodName) { 16672 var self = this, 16673 instance = null, 16674 args = Array.prototype.slice.call(arguments), 16675 tasks = [], 16676 i = -1; 16677 16678 this.callActions('beforeMixitup'); 16679 16680 args.shift(); 16681 16682 for (i = 0; instance = self[i]; i++) { 16683 tasks.push(instance[methodName].apply(instance, args)); 16684 } 16685 16686 return self.callFilters('promiseMixitup', h.all(tasks, mixitup.libraries), arguments); 16687 } 16688 }); 16689 16690 /** 16691 * `mixitup.Operation` objects contain all data neccessary to describe the full 16692 * lifecycle of any MixItUp operation. They can be used to compute and store an 16693 * operation for use at a later time (e.g. programmatic tweening). 16694 * 16695 * @constructor 16696 * @namespace 16697 * @memberof mixitup 16698 * @private 16699 * @since 3.0.0 16700 */ 16701 16702 mixitup.Operation = function() { 16703 mixitup.Base.call(this); 16704 16705 this.callActions('beforeConstruct'); 16706 16707 this.id = ''; 16708 16709 this.args = []; 16710 this.command = null; 16711 this.showPosData = []; 16712 this.toHidePosData = []; 16713 16714 this.startState = null; 16715 this.newState = null; 16716 this.docState = null; 16717 16718 this.willSort = false; 16719 this.willChangeLayout = false; 16720 this.hasEffect = false; 16721 this.hasFailed = false; 16722 16723 this.triggerElement = null; 16724 16725 this.show = []; 16726 this.hide = []; 16727 this.matching = []; 16728 this.toShow = []; 16729 this.toHide = []; 16730 this.toMove = []; 16731 this.toRemove = []; 16732 this.startOrder = []; 16733 this.newOrder = []; 16734 this.startSort = null; 16735 this.newSort = null; 16736 this.startFilter = null; 16737 this.newFilter = null; 16738 this.startDataset = null; 16739 this.newDataset = null; 16740 this.viewportDeltaX = 0; 16741 this.viewportDeltaY = 0; 16742 this.startX = 0; 16743 this.startY = 0; 16744 this.startHeight = 0; 16745 this.startWidth = 0; 16746 this.newX = 0; 16747 this.newY = 0; 16748 this.newHeight = 0; 16749 this.newWidth = 0; 16750 this.startContainerClassName = ''; 16751 this.startDisplay = ''; 16752 this.newContainerClassName = ''; 16753 this.newDisplay = ''; 16754 16755 this.callActions('afterConstruct'); 16756 16757 h.seal(this); 16758 }; 16759 16760 mixitup.BaseStatic.call(mixitup.Operation); 16761 16762 mixitup.Operation.prototype = Object.create(mixitup.Base.prototype); 16763 16764 mixitup.Operation.prototype.constructor = mixitup.Operation; 16765 16766 /** 16767 * `mixitup.State` objects expose various pieces of data detailing the state of 16768 * a MixItUp instance. They are provided at the start and end of any operation via 16769 * callbacks and events, with the most recent state stored between operations 16770 * for retrieval at any time via the API. 16771 * 16772 * @constructor 16773 * @namespace 16774 * @memberof mixitup 16775 * @public 16776 * @since 3.0.0 16777 */ 16778 16779 mixitup.State = function() { 16780 mixitup.Base.call(this); 16781 16782 this.callActions('beforeConstruct'); 16783 16784 /** 16785 * The ID of the mixer instance. 16786 * 16787 * @name id 16788 * @memberof mixitup.State 16789 * @instance 16790 * @type {string} 16791 * @default '' 16792 */ 16793 16794 this.id = ''; 16795 16796 /** 16797 * The currently active filter command as set by a control click or API call. 16798 * 16799 * @name activeFilter 16800 * @memberof mixitup.State 16801 * @instance 16802 * @type {mixitup.CommandFilter} 16803 * @default null 16804 */ 16805 16806 this.activeFilter = null; 16807 16808 /** 16809 * The currently active sort command as set by a control click or API call. 16810 * 16811 * @name activeSort 16812 * @memberof mixitup.State 16813 * @instance 16814 * @type {mixitup.CommandSort} 16815 * @default null 16816 */ 16817 16818 this.activeSort = null; 16819 16820 /** 16821 * The current layout-specific container class name, if applied. 16822 * 16823 * @name activeContainerClassName 16824 * @memberof mixitup.State 16825 * @instance 16826 * @type {string} 16827 * @default '' 16828 */ 16829 16830 this.activeContainerClassName = ''; 16831 16832 /** 16833 * A reference to the container element that the mixer is instantiated on. 16834 * 16835 * @name container 16836 * @memberof mixitup.State 16837 * @instance 16838 * @type {Element} 16839 * @default null 16840 */ 16841 16842 this.container = null; 16843 16844 /** 16845 * An array of all target elements indexed by the mixer. 16846 * 16847 * @name targets 16848 * @memberof mixitup.State 16849 * @instance 16850 * @type {Array.<Element>} 16851 * @default [] 16852 */ 16853 16854 this.targets = []; 16855 16856 /** 16857 * An array of all target elements not matching the current filter. 16858 * 16859 * @name hide 16860 * @memberof mixitup.State 16861 * @instance 16862 * @type {Array.<Element>} 16863 * @default [] 16864 */ 16865 16866 this.hide = []; 16867 16868 /** 16869 * An array of all target elements matching the current filter and any additional 16870 * limits applied such as pagination. 16871 * 16872 * @name show 16873 * @memberof mixitup.State 16874 * @instance 16875 * @type {Array.<Element>} 16876 * @default [] 16877 */ 16878 16879 this.show = []; 16880 16881 /** 16882 * An array of all target elements matching the current filter irrespective of 16883 * any additional limits applied such as pagination. 16884 * 16885 * @name matching 16886 * @memberof mixitup.State 16887 * @instance 16888 * @type {Array.<Element>} 16889 * @default [] 16890 */ 16891 16892 this.matching = []; 16893 16894 /** 16895 * An integer representing the total number of target elements indexed by the 16896 * mixer. Equivalent to `state.targets.length`. 16897 * 16898 * @name totalTargets 16899 * @memberof mixitup.State 16900 * @instance 16901 * @type {number} 16902 * @default -1 16903 */ 16904 16905 this.totalTargets = -1; 16906 16907 /** 16908 * An integer representing the total number of target elements matching the 16909 * current filter and any additional limits applied such as pagination. 16910 * Equivalent to `state.show.length`. 16911 * 16912 * @name totalShow 16913 * @memberof mixitup.State 16914 * @instance 16915 * @type {number} 16916 * @default -1 16917 */ 16918 16919 this.totalShow = -1; 16920 16921 /** 16922 * An integer representing the total number of target elements not matching 16923 * the current filter. Equivalent to `state.hide.length`. 16924 * 16925 * @name totalHide 16926 * @memberof mixitup.State 16927 * @instance 16928 * @type {number} 16929 * @default -1 16930 */ 16931 16932 this.totalHide = -1; 16933 16934 /** 16935 * An integer representing the total number of target elements matching the 16936 * current filter irrespective of any other limits applied such as pagination. 16937 * Equivalent to `state.matching.length`. 16938 * 16939 * @name totalMatching 16940 * @memberof mixitup.State 16941 * @instance 16942 * @type {number} 16943 * @default -1 16944 */ 16945 16946 this.totalMatching = -1; 16947 16948 /** 16949 * A boolean indicating whether the last operation "failed", i.e. no targets 16950 * could be found matching the filter. 16951 * 16952 * @name hasFailed 16953 * @memberof mixitup.State 16954 * @instance 16955 * @type {boolean} 16956 * @default false 16957 */ 16958 16959 this.hasFailed = false; 16960 16961 /** 16962 * The DOM element that was clicked if the last operation was triggered by the 16963 * clicking of a control and not an API call. 16964 * 16965 * @name triggerElement 16966 * @memberof mixitup.State 16967 * @instance 16968 * @type {Element|null} 16969 * @default null 16970 */ 16971 16972 this.triggerElement = null; 16973 16974 /** 16975 * The currently active dataset underlying the rendered targets, if the 16976 * dataset API is in use. 16977 * 16978 * @name activeDataset 16979 * @memberof mixitup.State 16980 * @instance 16981 * @type {Array.<object>} 16982 * @default null 16983 */ 16984 16985 this.activeDataset = null; 16986 16987 this.callActions('afterConstruct'); 16988 16989 h.seal(this); 16990 }; 16991 16992 mixitup.BaseStatic.call(mixitup.State); 16993 16994 mixitup.State.prototype = Object.create(mixitup.Base.prototype); 16995 16996 mixitup.State.prototype.constructor = mixitup.State; 16997 16998 /** 16999 * @constructor 17000 * @memberof mixitup 17001 * @private 17002 * @since 3.0.0 17003 */ 17004 17005 mixitup.UserInstruction = function() { 17006 mixitup.Base.call(this); 17007 17008 this.callActions('beforeConstruct'); 17009 17010 this.command = {}; 17011 this.animate = false; 17012 this.callback = null; 17013 17014 this.callActions('afterConstruct'); 17015 17016 h.seal(this); 17017 }; 17018 17019 mixitup.BaseStatic.call(mixitup.UserInstruction); 17020 17021 mixitup.UserInstruction.prototype = Object.create(mixitup.Base.prototype); 17022 17023 mixitup.UserInstruction.prototype.constructor = mixitup.UserInstruction; 17024 17025 /** 17026 * @constructor 17027 * @memberof mixitup 17028 * @private 17029 * @since 3.0.0 17030 */ 17031 17032 mixitup.Messages = function() { 17033 mixitup.Base.call(this); 17034 17035 this.callActions('beforeConstruct'); 17036 17037 /* Errors 17038 ----------------------------------------------------------------------------- */ 17039 17040 this.ERROR_FACTORY_INVALID_CONTAINER = 17041 '[MixItUp] An invalid selector or element reference was passed to the mixitup factory function'; 17042 17043 this.ERROR_FACTORY_CONTAINER_NOT_FOUND = 17044 '[MixItUp] The provided selector yielded no container element'; 17045 17046 this.ERROR_CONFIG_INVALID_ANIMATION_EFFECTS = 17047 '[MixItUp] Invalid value for `animation.effects`'; 17048 17049 this.ERROR_CONFIG_INVALID_CONTROLS_SCOPE = 17050 '[MixItUp] Invalid value for `controls.scope`'; 17051 17052 this.ERROR_CONFIG_INVALID_PROPERTY = 17053 '[MixitUp] Invalid configuration object property "${erroneous}"${suggestion}'; 17054 17055 this.ERROR_CONFIG_INVALID_PROPERTY_SUGGESTION = 17056 '. Did you mean "${probableMatch}"?'; 17057 17058 this.ERROR_CONFIG_DATA_UID_KEY_NOT_SET = 17059 '[MixItUp] To use the dataset API, a UID key must be specified using `data.uidKey`'; 17060 17061 this.ERROR_DATASET_INVALID_UID_KEY = 17062 '[MixItUp] The specified UID key "${uidKey}" is not present on one or more dataset items'; 17063 17064 this.ERROR_DATASET_DUPLICATE_UID = 17065 '[MixItUp] The UID "${uid}" was found on two or more dataset items. UIDs must be unique.'; 17066 17067 this.ERROR_INSERT_INVALID_ARGUMENTS = 17068 '[MixItUp] Please provider either an index or a sibling and position to insert, not both'; 17069 17070 this.ERROR_INSERT_PREEXISTING_ELEMENT = 17071 '[MixItUp] An element to be inserted already exists in the container'; 17072 17073 this.ERROR_FILTER_INVALID_ARGUMENTS = 17074 '[MixItUp] Please provide either a selector or collection `.filter()`, not both'; 17075 17076 this.ERROR_DATASET_NOT_SET = 17077 '[MixItUp] To use the dataset API with pre-rendered targets, a starting dataset must be set using `load.dataset`'; 17078 17079 this.ERROR_DATASET_PRERENDERED_MISMATCH = 17080 '[MixItUp] `load.dataset` does not match pre-rendered targets'; 17081 17082 this.ERROR_DATASET_RENDERER_NOT_SET = 17083 '[MixItUp] To insert an element via the dataset API, a target renderer function must be provided to `render.target`'; 17084 17085 this.ERROR_SORT_NON_EXISTENT_ELEMENT = 17086 '[MixItUp] An element to be sorted does not already exist in the container'; 17087 17088 /* Warnings 17089 ----------------------------------------------------------------------------- */ 17090 17091 this.WARNING_FACTORY_PREEXISTING_INSTANCE = 17092 '[MixItUp] WARNING: This element already has an active MixItUp instance. The provided configuration object will be ignored.' + 17093 ' If you wish to perform additional methods on this instance, please create a reference.'; 17094 17095 this.WARNING_INSERT_NO_ELEMENTS = 17096 '[MixItUp] WARNING: No valid elements were passed to `.insert()`'; 17097 17098 this.WARNING_REMOVE_NO_ELEMENTS = 17099 '[MixItUp] WARNING: No valid elements were passed to `.remove()`'; 17100 17101 this.WARNING_MULTIMIX_INSTANCE_QUEUE_FULL = 17102 '[MixItUp] WARNING: An operation was requested but the MixItUp instance was busy. The operation was rejected because the ' + 17103 'queue is full or queuing is disabled.'; 17104 17105 this.WARNING_GET_OPERATION_INSTANCE_BUSY = 17106 '[MixItUp] WARNING: Operations can be be created while the MixItUp instance is busy.'; 17107 17108 this.WARNING_NO_PROMISE_IMPLEMENTATION = 17109 '[MixItUp] WARNING: No Promise implementations could be found. If you wish to use promises with MixItUp please install' + 17110 ' an ES6 Promise polyfill.'; 17111 17112 this.WARNING_INCONSISTENT_SORTING_ATTRIBUTES = 17113 '[MixItUp] WARNING: The requested sorting data attribute "${attribute}" was not present on one or more target elements' + 17114 ' which may product unexpected sort output'; 17115 17116 this.callActions('afterConstruct'); 17117 17118 this.compileTemplates(); 17119 17120 h.seal(this); 17121 }; 17122 17123 mixitup.BaseStatic.call(mixitup.Messages); 17124 17125 mixitup.Messages.prototype = Object.create(mixitup.Base.prototype); 17126 17127 mixitup.Messages.prototype.constructor = mixitup.Messages; 17128 17129 /** 17130 * @return {void} 17131 */ 17132 17133 mixitup.Messages.prototype.compileTemplates = function() { 17134 var errorKey = ''; 17135 var errorMessage = ''; 17136 17137 for (errorKey in this) { 17138 if (typeof (errorMessage = this[errorKey]) !== 'string') continue; 17139 17140 this[h.camelCase(errorKey)] = h.template(errorMessage); 17141 } 17142 }; 17143 17144 mixitup.messages = new mixitup.Messages(); 17145 17146 /** 17147 * @constructor 17148 * @memberof mixitup 17149 * @private 17150 * @since 3.0.0 17151 * @param {mixitup.Mixer} mixer 17152 */ 17153 17154 mixitup.Facade = function Mixer(mixer) { 17155 mixitup.Base.call(this); 17156 17157 this.callActions('beforeConstruct', arguments); 17158 17159 this.configure = mixer.configure.bind(mixer); 17160 this.show = mixer.show.bind(mixer); 17161 this.hide = mixer.hide.bind(mixer); 17162 this.filter = mixer.filter.bind(mixer); 17163 this.toggleOn = mixer.toggleOn.bind(mixer); 17164 this.toggleOff = mixer.toggleOff.bind(mixer); 17165 this.sort = mixer.sort.bind(mixer); 17166 this.changeLayout = mixer.changeLayout.bind(mixer); 17167 this.multimix = mixer.multimix.bind(mixer); 17168 this.dataset = mixer.dataset.bind(mixer); 17169 this.tween = mixer.tween.bind(mixer); 17170 this.insert = mixer.insert.bind(mixer); 17171 this.insertBefore = mixer.insertBefore.bind(mixer); 17172 this.insertAfter = mixer.insertAfter.bind(mixer); 17173 this.prepend = mixer.prepend.bind(mixer); 17174 this.append = mixer.append.bind(mixer); 17175 this.remove = mixer.remove.bind(mixer); 17176 this.destroy = mixer.destroy.bind(mixer); 17177 this.forceRefresh = mixer.forceRefresh.bind(mixer); 17178 this.forceRender = mixer.forceRender.bind(mixer); 17179 this.isMixing = mixer.isMixing.bind(mixer); 17180 this.getOperation = mixer.getOperation.bind(mixer); 17181 this.getConfig = mixer.getConfig.bind(mixer); 17182 this.getState = mixer.getState.bind(mixer); 17183 17184 this.callActions('afterConstruct', arguments); 17185 17186 h.freeze(this); 17187 h.seal(this); 17188 }; 17189 17190 mixitup.BaseStatic.call(mixitup.Facade); 17191 17192 mixitup.Facade.prototype = Object.create(mixitup.Base.prototype); 17193 17194 mixitup.Facade.prototype.constructor = mixitup.Facade; 17195 17196 if (typeof exports === 'object' && typeof module === 'object') { 17197 module.exports = mixitup; 17198 } else if (typeof define === 'function' && define.amd) { 17199 define(function() { 17200 return mixitup; 17201 }); 17202 } else if (typeof window.mixitup === 'undefined' || typeof window.mixitup !== 'function') { 17203 window.mixitup = mixitup; 17204 } 17205 mixitup.BaseStatic.call(mixitup.constructor); 17206 17207 mixitup.NAME = 'mixitup'; 17208 mixitup.CORE_VERSION = '3.3.
172081'; 17209})(window);
vendor: 42,733 bytes, line 17210
17210!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):(t=t||self).parsley=e(t.jQuery)}(this,function(h){"use strict";function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function l(){return(l=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var r in i)Object.prototype.hasOwnProperty.call(i,r)&&(t[r]=i[r])}return t}).apply(this,arguments)}function o(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){if(!(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t)))return;var i=[],r=!0,n=!1,s=void 0;try{for(var a,o=t[Symbol.iterator]();!(r=(a=o.next()).done)&&(i.push(a.value),!e||i.length!==e);r=!0);}catch(t){n=!0,s=t}finally{try{r||null==o.return||o.return()}finally{if(n)throw s}}return i}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function u(t){return function(t){if(Array.isArray(t)){for(var e=0,i=new Array(t.length);e<t.length;e++)i[e]=t[e];return i}}(t)||function(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var t=1,e={},d={attr:function(t,e,i){var r,n,s,a=new RegExp("^"+e,"i");if(void 0===i)i={};else for(r in i)i.hasOwnProperty(r)&&delete i[r];if(!t)return i;for(r=(s=t.attributes).length;r--;)(n=s[r])&&n.specified&&a.test(n.name)&&(i[this.camelize(n.name.slice(e.length))]=this.deserializeValue(n.value));return i},checkAttr:function(t,e,i){return t.hasAttribute(e+i)},setAttr:function(t,e,i,r){t.setAttribute(this.dasherize(e+i),String(r))},getType:function(t){return t.getAttribute("type")||"text"},generateID:function(){return""+t++},deserializeValue:function(e){var t;try{return e?"true"==e||"false"!=e&&("null"==e?null:isNaN(t=Number(e))?/^[\[\{]/.test(e)?JSON.parse(e):e:t):e}catch(t){return e}},camelize:function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},dasherize:function(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()},warn:function(){var t;window.console&&"function"==typeof window.console.warn&&(t=window.console).warn.apply(t,arguments)},warnOnce:function(t){e[t]||(e[t]=!0,this.warn.apply(this,arguments))},_resetWarnings:function(){e={}},trimString:function(t){return t.replace(/^\s+|\s+$/g,"")},parse:{date:function(t){var e=t.match(/^(\d{4,})-(\d\d)-(\d\d)$/);if(!e)return null;var i=o(e.map(function(t){return parseInt(t,10)}),4),r=(i[0],i[1]),n=i[2],s=i[3],a=new Date(r,n-1,s);return a.getFullYear()!==r||a.getMonth()+1!==n||a.getDate()!==s?null:a},string:function(t){return t},integer:function(t){return isNaN(t)?null:parseInt(t,10)},number:function(t){if(isNaN(t))throw null;return parseFloat(t)},boolean:function(t){return!/^\s*false\s*$/i.test(t)},object:function(t){return d.deserializeValue(t)},regexp:function(t){var e="";return t=/^\/.*\/(?:[gimy]*)$/.test(t)?(e=t.replace(/.*\/([gimy]*)$/,"$1"),t.replace(new RegExp("^/(.*?)/"+e+"$"),"$1")):"^"+t+"$",new RegExp(t,e)}},parseRequirement:function(t,e){var i=this.parse[t||"string"];if(!i)throw'Unknown requirement specification: "'+t+'"';var r=i(e);if(null===r)throw"Requirement is not a ".concat(t,': "').concat(e,'"');return r},namespaceEvents:function(t,e){return(t=this.trimString(t||"").split(/\s+/))[0]?h.map(t,function(t){return"".concat(t,".").concat(e)}).join(" "):""},difference:function(t,i){var r=[];return h.each(t,function(t,e){-1==i.indexOf(e)&&r.push(e)}),r},all:function(t){return h.when.apply(h,u(t).concat([42,42]))},objectCreate:Object.create||function(t){if(1<arguments.length)throw Error("Second argument not supported");if("object"!=n(t))throw TypeError("Argument must be an object");i.prototype=t;var e=new i;return i.prototype=null,e},_SubmitSelector:'input[type="submit"], button:submit'};function i(){}function r(){this.__id__=d.generateID()}var s={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,triggerAfterFailure:"input",errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(){},errorsContainer:function(){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"};r.prototype={asyncSupport:!0,_pipeAccordingToValidationResult:function(){function t(){var t=h.Deferred();return!0!==e.validationResult&&t.reject(),t.resolve().promise()}var e=this;return[t,t]},actualizeOptions:function(){return d.attr(this.element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(t){for(var e in this.domOptions=d.objectCreate(this.parent.options),this.options=d.objectCreate(this.domOptions),t)t.hasOwnProperty(e)&&(this.options[e]=t[e]);this.actualizeOptions()},_listeners:null,on:function(t,e){return this._listeners=this._listeners||{},(this._listeners[t]=this._listeners[t]||[]).push(e),this},subscribe:function(t,e){h.listenTo(this,t.toLowerCase(),e)},off:function(t,e){var i=this._listeners&&this._listeners[t];if(i)if(e)for(var r=i.length;r--;)i[r]===e&&i.splice(r,1);else delete this._listeners[t];return this},unsubscribe:function(t){h.unsubscribeTo(this,t.toLowerCase())},trigger:function(t,e,i){e=e||this;var r,n=this._listeners&&this._listeners[t];if(n)for(var s=n.length;s--;)if(!1===(r=n[s].call(e,e,i)))return r;return!this.parent||this.parent.trigger(t,e,i)},asyncIsValid:function(t,e){return d.warnOnce("asyncIsValid is deprecated; please use whenValid instead"),this.whenValid({group:t,force:e})},_findRelated:function(){return this.options.multiple?h(this.parent.element.querySelectorAll("[".concat(this.options.namespace,'multiple="').concat(this.options.multiple,'"]'))):this.$element}};function c(t){h.extend(!0,this,t)}c.prototype={validate:function(t,e){if(this.fn)return 3<arguments.length&&(e=[].slice.call(arguments,1,-1)),this.fn(t,e);if(Array.isArray(t)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}var i=arguments[arguments.length-1];if(this.validateDate&&i._isDateInput())return arguments[0]=d.parse.date(arguments[0]),null!==arguments[0]&&this.validateDate.apply(this,arguments);if(this.validateNumber)return!t||!isNaN(t)&&(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,e){if("string"!=typeof t)return Array.isArray(t)?t:[t];var i=this.requirementType;if(Array.isArray(i)){for(var r=function(t,e){var i=t.match(/^\s*\[(.*)\]\s*$/);if(!i)throw'Requirement is not an array: "'+t+'"';var r=i[1].split(",").map(d.trimString);if(r.length!==e)throw"Requirement has "+r.length+" values when "+e+" are needed";return r}(t,i.length),n=0;n<r.length;n++)r[n]=d.parseRequirement(i[n],r[n]);return r}return h.isPlainObject(i)?function(t,e,i){var r=null,n={};for(var s in t)if(s){var a=i(s);"string"==typeof a&&(a=d.parseRequirement(t[s],a)),n[s]=a}else r=d.parseRequirement(t[s],e);return[r,n]}(i,t,e):[d.parseRequirement(i,t)]},requirementType:"string",priority:2};function a(t,e){this.__class__="ValidatorRegistry",this.locale="en",this.init(t||{},e||{})}var p={email:/^((([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))$/,number:/^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,integer:/^-?\d+$/,digits:/^\d+$/,alphanum:/^\w+$/i,date:{test:function(t){return null!==d.parse.date(t)}},url:new RegExp("^(?:(?:https?|ftp)://)?(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-zA-Z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:/\\S*)?$")};p.range=p.number;function f(t){var e=(""+t).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return e?Math.max(0,(e[1]?e[1].length:0)-(e[2]?+e[2]:0)):0}function m(s,a){return function(t){for(var e=arguments.length,i=new Array(1<e?e-1:0),r=1;r<e;r++)i[r-1]=arguments[r];return i.pop(),a.apply(void 0,[t].concat(u((n=s,i.map(d.parse[n])))));var n}}function g(t){return{validateDate:m("date",t),validateNumber:m("number",t),requirementType:t.length<=2?"string":["string","string"],priority:30}}a.prototype={init:function(t,e){for(var i in this.catalog=e,this.validators=l({},this.validators),t)this.addValidator(i,t[i].fn,t[i].priority);window.Parsley.trigger("parsley:validator:init")},setLocale:function(t){if(void 0===this.catalog[t])throw new Error(t+" is not available in the catalog");return this.locale=t,this},addCatalog:function(t,e,i){return"object"===n(e)&&(this.catalog[t]=e),!0===i?this.setLocale(t):this},addMessage:function(t,e,i){return void 0===this.catalog[t]&&(this.catalog[t]={}),this.catalog[t][e]=i,this},addMessages:function(t,e){for(var i in e)this.addMessage(t,i,e[i]);return this},addValidator:function(t,e,i){if(this.validators[t])d.warn('Validator "'+t+'" is already defined.');else if(s.hasOwnProperty(t))return void d.warn('"'+t+'" is a restricted keyword and is not a valid validator name.');return this._setValidator.apply(this,arguments)},hasValidator:function(t){return!!this.validators[t]},updateValidator:function(t,e,i){return this.validators[t]?this._setValidator.apply(this,arguments):(d.warn('Validator "'+t+'" is not already defined.'),this.addValidator.apply(this,arguments))},removeValidator:function(t){return this.validators[t]||d.warn('Validator "'+t+'" is not defined.'),delete this.validators[t],this},_setValidator:function(t,e,i){for(var r in"object"!==n(e)&&(e={fn:e,priority:i}),e.validate||(e=new c(e)),(this.validators[t]=e).messages||{})this.addMessage(r,t,e.messages[r]);return this},getErrorMessage:function(t){var e;"type"===t.name?e=(this.catalog[this.locale][t.name]||{})[t.requirements]:e=this.formatMessage(this.catalog[this.locale][t.name],t.requirements);return e||this.catalog[this.locale].defaultMessage||this.catalog.en.defaultMessage},formatMessage:function(t,e){if("object"!==n(e))return"string"==typeof t?t.replace(/%s/i,e):"";for(var i in e)t=this.formatMessage(t,e[i]);return t},validators:{notblank:{validateString:function(t){return/\S/.test(t)},priority:2},required:{validateMultiple:function(t){return 0<t.length},validateString:function(t){return/\S/.test(t)},priority:512},type:{validateString:function(t,e,i){var r=2<arguments.length&&void 0!==i?i:{},n=r.step,s=void 0===n?"any":n,a=r.base,o=void 0===a?0:a,l=p[e];if(!l)throw new Error("validator type `"+e+"` is not supported");if(!t)return!0;if(!l.test(t))return!1;if("number"===e&&!/^any$/i.test(s||"")){var u=Number(t),d=Math.max(f(s),f(o));if(f(u)>d)return!1;var h=function(t){return Math.round(t*Math.pow(10,d))};if((h(u)-h(o))%h(s)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(t,e){return!t||e.test(t)},requirementType:"regexp",priority:64},minlength:{validateString:function(t,e){return!t||t.length>=e},requirementType:"integer",priority:30},maxlength:{validateString:function(t,e){return t.length<=e},requirementType:"integer",priority:30},length:{validateString:function(t,e,i){return!t||t.length>=e&&t.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(t,e){return t.length>=e},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(t,e){return t.length<=e},requirementType:"integer",priority:30},check:{validateMultiple:function(t,e,i){return t.length>=e&&t.length<=i},requirementType:["integer","integer"],priority:30},min:g(function(t,e){return e<=t}),max:g(function(t,e){return t<=e}),range:g(function(t,e,i){return e<=t&&t<=i}),equalto:{validateString:function(t,e){if(!t)return!0;var i=h(e);return i.length?t===i.val():t===e},priority:256},euvatin:{validateString:function(t){if(!t)return!0;return/^[A-Z][A-Z][A-Za-z0-9 -]{2,}$/.test(t)},priority:30}}};var v={};v.Form={_actualizeTriggers:function(){var e=this;this.$element.on("submit.Parsley",function(t){e.onSubmitValidate(t)}),this.$element.on("click.Parsley",d._SubmitSelector,function(t){e.onSubmitButton(t)}),!1!==this.options.uiEnabled&&this.element.setAttribute("novalidate","")},focus:function(){if(!(this._focusedField=null)===this.validationResult||"none"===this.options.focus)return null;for(var t=0;t<this.fields.length;t++){var e=this.fields[t];if(!0!==e.validationResult&&0<e.validationResult.length&&void 0===e.options.noFocus&&(this._focusedField=e.$element,"first"===this.options.focus))break}return null===this._focusedField?null:this._focusedField.focus()},_destroyUI:function(){this.$element.off(".Parsley")}},v.Field={_reflowUI:function(){if(this._buildUI(),this._ui){var t=function t(e,i,r){for(var n=[],s=[],a=0;a<e.length;a++){for(var o=!1,l=0;l<i.length;l++)if(e[a].assert.name===i[l].assert.name){o=!0;break}o?s.push(e[a]):n.push(e[a])}return{kept:s,added:n,removed:r?[]:t(i,e,!0).added}}(this.validationResult,this._ui.lastValidationResult);this._ui.lastValidationResult=this.validationResult,this._manageStatusClass(),this._manageErrorsMessages(t),this._actualizeTriggers(),!t.kept.length&&!t.added.length||this._failedOnce||(this._failedOnce=!0,this._actualizeTriggers())}},getErrorsMessages:function(){if(!0===this.validationResult)return[];for(var t=[],e=0;e<this.validationResult.length;e++)t.push(this.validationResult[e].errorMessage||this._getErrorMessage(this.validationResult[e].assert));return t},addError:function(t,e){var i=1<arguments.length&&void 0!==e?e:{},r=i.message,n=i.assert,s=i.updateClass,a=void 0===s||s;this._buildUI(),this._addError(t,{message:r,assert:n}),a&&this._errorClass()},updateError:function(t,e){var i=1<arguments.length&&void 0!==e?e:{},r=i.message,n=i.assert,s=i.updateClass,a=void 0===s||s;this._buildUI(),this._updateError(t,{message:r,assert:n}),a&&this._errorClass()},removeError:function(t,e){var i=(1<arguments.length&&void 0!==e?e:{}).updateClass,r=void 0===i||i;this._buildUI(),this._removeError(t),r&&this._manageStatusClass()},_manageStatusClass:function(){this.hasConstraints()&&this.needsValidation()&&!0===this.validationResult?this._successClass():0<this.validationResult.length?this._errorClass():this._resetClass()},_manageErrorsMessages:function(t){if(void 0===this.options.errorsMessagesDisabled){if(void 0!==this.options.errorMessage)return t.added.length||t.kept.length?(this._insertErrorWrapper(),0===this._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&this._ui.$errorsWrapper.append(h(this.options.errorTemplate).addClass("parsley-custom-error-message")),this._ui.$errorClassHandler.attr("aria-describedby",this._ui.errorsWrapperId),this._ui.$errorsWrapper.addClass("filled").attr("aria-hidden","false").find(".parsley-custom-error-message").html(this.options.errorMessage)):(this._ui.$errorClassHandler.removeAttr("aria-describedby"),this._ui.$errorsWrapper.removeClass("filled").attr("aria-hidden","true").find(".parsley-custom-error-message").remove());for(var e=0;e<t.removed.length;e++)this._removeError(t.removed[e].assert.name);for(e=0;e<t.added.length;e++)this._addError(t.added[e].assert.name,{message:t.added[e].errorMessage,assert:t.added[e].assert});for(e=0;e<t.kept.length;e++)this._updateError(t.kept[e].assert.name,{message:t.kept[e].errorMessage,assert:t.kept[e].assert})}},_addError:function(t,e){var i=e.message,r=e.assert;this._insertErrorWrapper(),this._ui.$errorClassHandler.attr("aria-describedby",this._ui.errorsWrapperId),this._ui.$errorsWrapper.addClass("filled").attr("aria-hidden","false").append(h(this.options.errorTemplate).addClass("parsley-"+t).html(i||this._getErrorMessage(r)))},_updateError:function(t,e){var i=e.message,r=e.assert;this._ui.$errorsWrapper.addClass("filled").find(".parsley-"+t).html(i||this._getErrorMessage(r))},_removeError:function(t){this._ui.$errorClassHandler.removeAttr("aria-describedby"),this._ui.$errorsWrapper.removeClass("filled").attr("aria-hidden","true").find(".parsley-"+t).remove()},_getErrorMessage:function(t){var e=t.name+"Message";return void 0!==this.options[e]?window.Parsley.formatMessage(this.options[e],t.requirements):window.Parsley.getErrorMessage(t)},_buildUI:function(){if(!this._ui&&!1!==this.options.uiEnabled){var t={};this.element.setAttribute(this.options.namespace+"id",this.__id__),t.$errorClassHandler=this._manageClassHandler(),t.errorsWrapperId="parsley-id-"+(this.options.multiple?"multiple-"+this.options.multiple:this.__id__),t.$errorsWrapper=h(this.options.errorsWrapper).attr("id",t.errorsWrapperId),t.lastValidationResult=[],t.validationInformationVisible=!1,this._ui=t}},_manageClassHandler:function(){if("string"==typeof this.options.classHandler&&h(this.options.classHandler).length)return h(this.options.classHandler);var t=this.options.classHandler;if("string"==typeof this.options.classHandler&&"function"==typeof window[this.options.classHandler]&&(t=window[this.options.classHandler]),"function"==typeof t){var e=t.call(this,this);if(void 0!==e&&e.length)return e}else{if("object"===n(t)&&t instanceof jQuery&&t.length)return t;t&&d.warn("The class handler `"+t+"` does not exist in DOM nor as a global JS function")}return this._inputHolder()},_inputHolder:function(){return this.options.multiple&&"SELECT"!==this.element.nodeName?this.$element.parent():this.$element},_insertErrorWrapper:function(){var t=this.options.errorsContainer;if(0!==this._ui.$errorsWrapper.parent().length)return this._ui.$errorsWrapper.parent();if("string"==typeof t){if(h(t).length)return h(t).append(this._ui.$errorsWrapper);"function"==typeof window[t]?t=window[t]:d.warn("The errors container `"+t+"` does not exist in DOM nor as a global JS function")}return"function"==typeof t&&(t=t.call(this,this)),"object"===n(t)&&t.length?t.append(this._ui.$errorsWrapper):this._inputHolder().after(this._ui.$errorsWrapper)},_actualizeTriggers:function(){var t,e=this,i=this._findRelated();i.off(".Parsley"),this._failedOnce?i.on(d.namespaceEvents(this.options.triggerAfterFailure,"Parsley"),function(){e._validateIfNeeded()}):(t=d.namespaceEvents(this.options.trigger,"Parsley"))&&i.on(t,function(t){e._validateIfNeeded(t)})},_validateIfNeeded:function(t){var e=this;t&&/key|input/.test(t.type)&&(!this._ui||!this._ui.validationInformationVisible)&&this.getValue().length<=this.options.validationThreshold||(this.options.debounce?(window.clearTimeout(this._debounced),this._debounced=window.setTimeout(function(){return e.validate()},this.options.debounce)):this.validate())},_resetUI:function(){this._failedOnce=!1,this._actualizeTriggers(),void 0!==this._ui&&(this._ui.$errorsWrapper.removeClass("filled").children().remove(),this._resetClass(),this._ui.lastValidationResult=[],this._ui.validationInformationVisible=!1)},_destroyUI:function(){this._resetUI(),void 0!==this._ui&&this._ui.$errorsWrapper.remove(),delete this._ui},_successClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass)},_errorClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass)},_resetClass:function(){this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass)}};function y(t,e,i){this.__class__="Form",this.element=t,this.$element=h(t),this.domOptions=e,this.options=i,this.parent=window.Parsley,this.fields=[],this.validationResult=null}var _={pending:null,resolved:!0,rejected:!1};y.prototype={onSubmitValidate:function(t){var e=this;if(!0!==t.parsley){var i=this._submitSource||this.$element.find(d._SubmitSelector)[0];if(this._submitSource=null,this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!0),!i||null===i.getAttribute("formnovalidate")){window.Parsley._remoteCache={};var r=this.whenValidate({event:t});"resolved"===r.state()&&!1!==this._trigger("submit")||(t.stopImmediatePropagation(),t.preventDefault(),"pending"===r.state()&&r.done(function(){e._submit(i)}))}}},onSubmitButton:function(t){this._submitSource=t.currentTarget},_submit:function(t){if(!1!==this._trigger("submit")){if(t){var e=this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!1);0===e.length&&(e=h('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element)),e.attr({name:t.getAttribute("name"),value:t.getAttribute("value")})}this.$element.trigger(l(h.Event("submit"),{parsley:!0}))}},validate:function(t){if(1<=arguments.length&&!h.isPlainObject(t)){d.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var e=Array.prototype.slice.call(arguments);t={group:e[0],force:e[1],event:e[2]}}return _[this.whenValidate(t).state()]},whenValidate:function(t){var e,i=this,r=0<arguments.length&&void 0!==t?t:{},n=r.group,s=r.force,a=r.event;(this.submitEvent=a)&&(this.submitEvent=l({},a,{preventDefault:function(){d.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),i.validationResult=!1}})),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var o=this._withoutReactualizingFormOptions(function(){return h.map(i.fields,function(t){return t.whenValidate({force:s,group:n})})});return(e=d.all(o).done(function(){i._trigger("success")}).fail(function(){i.validationResult=!1,i.focus(),i._trigger("error")}).always(function(){i._trigger("validated")})).pipe.apply(e,u(this._pipeAccordingToValidationResult()))},isValid:function(t){if(1<=arguments.length&&!h.isPlainObject(t)){d.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var e=Array.prototype.slice.call(arguments);t={group:e[0],force:e[1]}}return _[this.whenValid(t).state()]},whenValid:function(t){var e=this,i=0<arguments.length&&void 0!==t?t:{},r=i.group,n=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return h.map(e.fields,function(t){return t.whenValid({group:r,force:n})})});return d.all(s)},refresh:function(){return this._refreshFields(),this},reset:function(){for(var t=0;t<this.fields.length;t++)this.fields[t].reset();this._trigger("reset")},destroy:function(){this._destroyUI();for(var t=0;t<this.fields.length;t++)this.fields[t].destroy();this.$element.removeData("Parsley"),this._trigger("destroy")},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var n=this,t=this.fields;return this.fields=[],this.fieldsMappedById={},this._withoutReactualizingFormOptions(function(){n.$element.find(n.options.inputs).not(n.options.excluded).not("[".concat(n.options.namespace,"excluded=true]")).each(function(t,e){var i=new window.Parsley.Factory(e,{},n);if("Field"===i.__class__||"FieldMultiple"===i.__class__){var r=i.__class__+"-"+i.__id__;void 0===n.fieldsMappedById[r]&&(n.fieldsMappedById[r]=i,n.fields.push(i))}}),h.each(d.difference(t,n.fields),function(t,e){e.reset()})}),this},_withoutReactualizingFormOptions:function(t){var e=this.actualizeOptions;this.actualizeOptions=function(){return this};var i=t();return this.actualizeOptions=e,i},_trigger:function(t){return this.trigger("form:"+t)}};function b(t,e,i,r,n){var s=window.Parsley._validatorRegistry.validators[e],a=new c(s);l(this,{validator:a,name:e,requirements:i,priority:r=r||t.options[e+"Priority"]||a.priority,isDomConstraint:n=!0===n}),this._parseRequirements(t.options)}function w(t,e,i,r){this.__class__="Field",this.element=t,this.$element=h(t),void 0!==r&&(this.parent=r),this.options=i,this.domOptions=e,this.constraints=[],this.constraintsByName={},this.validationResult=!0,this._bindConstraints()}var F={pending:null,resolved:!0,rejected:!(b.prototype={validate:function(t,e){var i;return(i=this.validator).validate.apply(i,[t].concat(u(this.requirementList),[e]))},_parseRequirements:function(i){var r=this;this.requirementList=this.validator.parseRequirements(this.requirements,function(t){return i[r.name+((e=t)[0].toUpperCase()+e.slice(1))];var e})}})};w.prototype={validate:function(t){1<=arguments.length&&!h.isPlainObject(t)&&(d.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var e=this.whenValidate(t);if(!e)return!0;switch(e.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(t){var e,i=this,r=0<arguments.length&&void 0!==t?t:{},n=r.force,s=r.group;if(this.refresh(),!s||this._isInGroup(s))return this.value=this.getValue(),this._trigger("validate"),(e=this.whenValid({force:n,value:this.value,_refreshed:!0}).always(function(){i._reflowUI()}).done(function(){i._trigger("success")}).fail(function(){i._trigger("error")}).always(function(){i._trigger("validated")})).pipe.apply(e,u(this._pipeAccordingToValidationResult()))},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(t){return void 0===t&&(t=this.getValue()),!(!t.length&&!this._isRequired()&&void 0===this.options.validateIfEmpty)},_isInGroup:function(t){return Array.isArray(this.options.group)?-1!==h.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(1<=arguments.length&&!h.isPlainObject(t)){d.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var e=Array.prototype.slice.call(arguments);t={force:e[0],value:e[1]}}var i=this.whenValid(t);return!i||F[i.state()]},whenValid:function(t){var r=this,e=0<arguments.length&&void 0!==t?t:{},i=e.force,n=void 0!==i&&i,s=e.value,a=e.group;if(e._refreshed||this.refresh(),!a||this._isInGroup(a)){if(this.validationResult=!0,!this.hasConstraints())return h.when();if(null==s&&(s=this.getValue()),!this.needsValidation(s)&&!0!==n)return h.when();var o=this._getGroupedConstraints(),l=[];return h.each(o,function(t,e){var i=d.all(h.map(e,function(t){return r._validateConstraint(s,t)}));if(l.push(i),"rejected"===i.state())return!1}),d.all(l)}},_validateConstraint:function(t,e){var i=this,r=e.validate(t,this);return!1===r&&(r=h.Deferred().reject()),d.all([r]).fail(function(t){i.validationResult instanceof Array||(i.validationResult=[]),i.validationResult.push({assert:e,errorMessage:"string"==typeof t&&t})})},getValue:function(){var t;return null==(t="function"==typeof this.options.value?this.options.value(this):void 0!==this.options.value?this.options.value:this.$element.val())?"":this._handleWhitespace(t)},reset:function(){return this._resetUI(),this._trigger("reset")},destroy:function(){this._destroyUI(),this.$element.removeData("Parsley"),this.$element.removeData("FieldMultiple"),this._trigger("destroy")},refresh:function(){return this._refreshConstraints(),this},_refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},refreshConstraints:function(){return d.warnOnce("Parsley's refreshConstraints is deprecated. Please use refresh"),this.refresh()},addConstraint:function(t,e,i,r){if(window.Parsley._validatorRegistry.validators[t]){var n=new b(this,t,e,i,r);"undefined"!==this.constraintsByName[n.name]&&this.removeConstraint(n.name),this.constraints.push(n),this.constraintsByName[n.name]=n}return this},removeConstraint:function(t){for(var e=0;e<this.constraints.length;e++)if(t===this.constraints[e].name){this.constraints.splice(e,1);break}return delete this.constraintsByName[t],this},updateConstraint:function(t,e,i){return this.removeConstraint(t).addConstraint(t,e,i)},_bindConstraints:function(){for(var t=[],e={},i=0;i<this.constraints.length;i++)!1===this.constraints[i].isDomConstraint&&(t.push(this.constraints[i]),e[this.constraints[i].name]=this.constraints[i]);for(var r in this.constraints=t,this.constraintsByName=e,this.options)this.addConstraint(r,this.options[r],void 0,!0);return this._bindHtml5Constraints()},_bindHtml5Constraints:function(){null!==this.element.getAttribute("required")&&this.addConstraint("required",!0,void 0,!0),null!==this.element.getAttribute("pattern")&&this.addConstraint("pattern",this.element.getAttribute("pattern"),void 0,!0);var t=this.element.getAttribute("min"),e=this.element.getAttribute("max");null!==t&&null!==e?this.addConstraint("range",[t,e],void 0,!0):null!==t?this.addConstraint("min",t,void 0,!0):null!==e&&this.addConstraint("max",e,void 0,!0),null!==this.element.getAttribute("minlength")&&null!==this.element.getAttribute("maxlength")?this.addConstraint("length",[this.element.getAttribute("minlength"),this.element.getAttribute("maxlength")],void 0,!0):null!==this.element.getAttribute("minlength")?this.addConstraint("minlength",this.element.getAttribute("minlength"),void 0,!0):null!==this.element.getAttribute("maxlength")&&this.addConstraint("maxlength",this.element.getAttribute("maxlength"),void 0,!0);var i=d.getType(this.element);return"number"===i?this.addConstraint("type",["number",{step:this.element.getAttribute("step")||"1",base:t||this.element.getAttribute("value")}],void 0,!0):/^(email|url|range|date)$/i.test(i)?this.addConstraint("type",i,void 0,!0):this},_isRequired:function(){return void 0!==this.constraintsByName.required&&!1!==this.constraintsByName.required.requirements},_trigger:function(t){return this.trigger("field:"+t)},_handleWhitespace:function(t){return!0===this.options.trimValue&&d.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'),"squish"===this.options.whitespace&&(t=t.replace(/\s{2,}/g," ")),"trim"!==this.options.whitespace&&"squish"!==this.options.whitespace&&!0!==this.options.trimValue||(t=d.trimString(t)),t},_isDateInput:function(){var t=this.constraintsByName.type;return t&&"date"===t.requirements},_getGroupedConstraints:function(){if(!1===this.options.priorityEnabled)return[this.constraints];for(var t=[],e={},i=0;i<this.constraints.length;i++){var r=this.constraints[i].priority;e[r]||t.push(e[r]=[]),e[r].push(this.constraints[i])}return t.sort(function(t,e){return e[0].priority-t[0].priority}),t}};function C(){this.__class__="FieldMultiple"}C.prototype={addElement:function(t){return this.$elements.push(t),this},_refreshConstraints:function(){var t;if(this.constraints=[],"SELECT"===this.element.nodeName)return this.actualizeOptions()._bindConstraints(),this;for(var e=0;e<this.$elements.length;e++)if(h("html").has(this.$elements[e]).length){t=this.$elements[e].data("FieldMultiple")._refreshConstraints().constraints;for(var i=0;i<t.length;i++)this.addConstraint(t[i].name,t[i].requirements,t[i].priority,t[i].isDomConstraint)}else this.$elements.splice(e,1);return this},getValue:function(){if("function"==typeof this.options.value)return this.options.value(this);if(void 0!==this.options.value)return this.options.value;if("INPUT"===this.element.nodeName){var t=d.getType(this.element);if("radio"===t)return this._findRelated().filter(":checked").val()||"";if("checkbox"===t){var e=[];return this._findRelated().filter(":checked").each(function(){e.push(h(this).val())}),e}}return"SELECT"===this.element.nodeName&&null===this.$element.val()?[]:this.$element.val()},_init:function(){return this.$elements=[this.$element],this}};function A(t,e,i){this.element=t,this.$element=h(t);var r=this.$element.data("Parsley");if(r)return void 0!==i&&r.parent===window.Parsley&&(r.parent=i,r._resetOptions(r.options)),"object"===n(e)&&l(r.options,e),r;if(!this.$element.length)throw new Error("You must bind Parsley on an existing element.");if(void 0!==i&&"Form"!==i.__class__)throw new Error("Parent instance must be a Form instance");return this.parent=i||window.Parsley,this.init(e)}A.prototype={init:function(t){return this.__class__="Parsley",this.__version__="2.9.2",this.__id__=d.generateID(),this._resetOptions(t),"FORM"===this.element.nodeName||d.checkAttr(this.element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm"):this.isMultiple()?this.handleMultiple():this.bind("parsleyField")},isMultiple:function(){var t=d.getType(this.element);return"radio"===t||"checkbox"===t||"SELECT"===this.element.nodeName&&null!==this.element.getAttribute("multiple")},handleMultiple:function(){var t,e,r=this;if(this.options.multiple=this.options.multiple||(t=this.element.getAttribute("name"))||this.element.getAttribute("id"),"SELECT"===this.element.nodeName&&null!==this.element.getAttribute("multiple"))return this.options.multiple=this.options.multiple||this.__id__,this.bind("parsleyFieldMultiple");if(!this.options.multiple)return d.warn("To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;this.options.multiple=this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g,""),t&&h('input[name="'+t+'"]').each(function(t,e){var i=d.getType(e);"radio"!==i&&"checkbox"!==i||e.setAttribute(r.options.namespace+"multiple",r.options.multiple)});for(var i=this._findRelated(),n=0;n<i.length;n++)if(void 0!==(e=h(i.get(n)).data("Parsley"))){this.$element.data("FieldMultiple")||e.addElement(this.$element);break}return this.bind("parsleyField",!0),e||this.bind("parsleyFieldMultiple")},bind:function(t,e){var i;switch(t){case"parsleyForm":i=h.extend(new y(this.element,this.domOptions,this.options),new r,window.ParsleyExtend)._bindFields();break;case"parsleyField":i=h.extend(new w(this.element,this.domOptions,this.options,this.parent),new r,window.ParsleyExtend);break;case"parsleyFieldMultiple":i=h.extend(new w(this.element,this.domOptions,this.options,this.parent),new C,new r,window.ParsleyExtend)._init();break;default:throw new Error(t+"is not a supported Parsley type")}return this.options.multiple&&d.setAttr(this.element,this.options.namespace,"multiple",this.options.multiple),void 0!==e?this.$element.data("FieldMultiple",i):(this.$element.data("Parsley",i),i._actualizeTriggers(),i._trigger("init")),i}};var E=h.fn.jquery.split(".");if(parseInt(E[0])<=1&&parseInt(E[1])<8)throw"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.";E.forEach||d.warn("Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim");var x=l(new r,{element:document,$element:h(document),actualizeOptions:null,_resetOptions:null,Factory:A,version:"2.9.2"});l(w.prototype,v.Field,r.prototype),l(y.prototype,v.Form,r.prototype),l(A.prototype,r.prototype),h.fn.parsley=h.fn.psly=function(t){if(1<this.length){var e=[];return this.each(function(){e.push(h(this).parsley(t))}),e}if(0!=this.length)return new A(this[0],t)},void 0===window.ParsleyExtend&&(window.ParsleyExtend={}),x.options=l(d.objectCreate(s),window.ParsleyConfig),window.ParsleyConfig=x.options,window.Parsley=window.psly=x,x.Utils=d,window.ParsleyUtils={},h.each(d,function(t,e){"function"==typeof e&&(window.ParsleyUtils[t]=function(){return d.warnOnce("Accessing `window.ParsleyUtils` is deprecated. Use `window.Parsley.Utils` instead."),d[t].apply(d,arguments)})});var $=window.Parsley._validatorRegistry=new a(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},h.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator hasValidator".split(" "),function(t,e){window.Parsley[e]=function(){return $[e].apply($,arguments)},window.ParsleyValidator[e]=function(){var t;return d.warnOnce("Accessing the method '".concat(e,"' through Validator is deprecated. Simply call 'window.Parsley.").concat(e,"(...)'")),(t=window.Parsley)[e].apply(t,arguments)}}),window.Parsley.UI=v,window.ParsleyUI={removeError:function(t,e,i){var r=!0!==i;return d.warnOnce("Accessing UI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."),t.removeError(e,{updateClass:r})},getErrorsMessages:function(t){return d.warnOnce("Accessing UI is deprecated. Call 'getErrorsMessages' on the instance directly."),t.getErrorsMessages()}},h.each("addError updateError".split(" "),function(t,a){window.ParsleyUI[a]=function(t,e,i,r,n){var s=!0!==n;return d.warnOnce("Accessing UI is deprecated. Call '".concat(a,"' on the instance directly. Please comment in issue 1073 as to your need to call this method.")),t[a](e,{message:i,assert:r,updateClass:s})}}),!1!==window.ParsleyConfig.autoBind&&h(function(){h("[data-parsley-validate]").length&&h("[data-parsley-validate]").parsley()});function V(){d.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")}var P=h({});function O(e,i){return e.parsleyAdaptedCallback||(e.parsleyAdaptedCallback=function(){var t=Array.prototype.slice.call(arguments,0);t.unshift(this),e.apply(i||P,t)}),e.parsleyAdaptedCallback}var T="parsley:";function M(t){return 0===t.lastIndexOf(T,0)?t.substr(T.length):t}return h.listen=function(t,e){var i;if(V(),"object"===n(arguments[1])&&"function"==typeof arguments[2]&&(i=arguments[1],e=arguments[2]),"function"!=typeof e)throw new Error("Wrong parameters");window.Parsley.on(M(t),O(e,i))},h.listenTo=function(t,e,i){if(V(),!(t instanceof w||t instanceof y))throw new Error("Must give Parsley instance");if("string"!=typeof e||"function"!=typeof i)throw new Error("Wrong parameters");t.on(M(e),O(i))},h.unsubscribe=function(t,e){if(V(),"string"!=typeof t||"function"!=typeof e)throw new Error("Wrong arguments");window.Parsley.off(M(t),e.parsleyAdaptedCallback)},h.unsubscribeTo=function(t,e){if(V(),!(t instanceof w||t instanceof y))throw new Error("Must give Parsley instance");t.off(M(e))},h.unsubscribeAll=function(e){V(),window.Parsley.off(M(e)),h("form,input,textarea,select").each(function(){var t=h(this).data("Parsley");t&&t.off(M(e))})},h.emit=function(t,e){V();var i=e instanceof w||e instanceof y,r=Array.prototype.slice.call(arguments,i?2:1);r.unshift(M(t)),i||(e=window.Parsley),e.trigger.apply(e,u(r))},h.extend(!0,x,{asyncValidators:{default:{fn:function(t){return 200<=t.status&&t.status<300},url:!1},reverse:{fn:function(t){return t.status<200||300<=t.status},url:!1}},addAsyncValidator:function(t,e,i,r){return x.asyncValidators[t]={fn:e,url:i||!1,options:r||{}},this}}),x.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,e,i,r){var n,s,a={},o=i.validator||(!0===i.reverse?"reverse":"default");if(void 0===x.asyncValidators[o])throw new Error("Calling an undefined async validator: `"+o+"`");-1<(e=x.asyncValidators[o].url||e).indexOf("{value}")?e=e.replace("{value}",encodeURIComponent(t)):a[r.element.getAttribute("name")||r.element.getAttribute("id")]=t;var l=h.extend(!0,i.options||{},x.asyncValidators[o].options);n=h.extend(!0,{},{url:e,data:a,type:"GET"},l),r.trigger("field:ajaxoptions",r,n),s=h.param(n),void 0===x._remoteCache&&(x._remoteCache={});function u(){var t=x.asyncValidators[o].fn.call(r,d,e,i);return t=t||h.Deferred().reject(),h.when(t)}var d=x._remoteCache[s]=x._remoteCache[s]||h.ajax(n);return d.then(u,u)},priority:-1}),x.on("form:submit",function(){x._remoteCache={}}),r.prototype.addAsyncValidator=function(){return d.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),x.addAsyncValidator.apply(x,arguments)},x.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same.",euvatin:"It's not a valid VAT Identification Number."}),x.setLocale("en"),(new function(){var r=this,n=window||global;l(this,{isNativeEvent:function(t){return t.originalEvent&&!1!==t.originalEvent.isTrusted},fakeInputEvent:function(t){r.isNativeEvent(t)&&h(t.target).trigger("input")},misbehaves:function(t){r.isNativeEvent(t)&&(r.behavesOk(t),h(document).on("change.inputevent",t.data.selector,r.fakeInputEvent),r.fakeInputEvent(t))},behavesOk:function(t){r.isNativeEvent(t)&&h(document).off("input.inputevent",t.data.selector,r.behavesOk).off("change.inputevent",t.data.selector,r.misbehaves)},install:function(){if(!n.inputEventPatched){n.inputEventPatched="0.0.3";for(var t=0,e=["select",'input[type="checkbox"]','input[type="radio"]','input[type="file"]'];t<e.length;t++){var i=e[t];h(document).on("input.inputevent",i,{selector:i},r.behavesOk).on("change.inputevent",i,{selector:i},r.misbehaves)}}},uninstall:function(){delete n.inputEventPatched,h(document).off(".inputevent")}})}).install(),x});
vendor: 3,800 bytes, lines 17211-17330
17211 17212/* 17213 _ _ _ _ 17214 ___| (_) ___| | __ (_)___ 17215/ __| | |/ __| |/ / | / __| 17216\__ \ | | (__| < _ | \__ \ 17217|___/_|_|\___|_|\_(_)/ |___/ 17218 |__/ 17219 17220 Version: 1.8.0 17221 Author: Ken Wheeler 17222 Website: http://kenwheeler.github.io 17223 Docs: http://kenwheeler.github.io/slick 17224 Repo: http://github.com/kenwheeler/slick 17225 Issues: http://github.com/kenwheeler/slick/issues 17226 17227 */ 17228/* global window, document, define, jQuery, setInterval, clearInterval */ 17229;(function(factory) { 17230 'use strict'; 17231 if (typeof define === 'function' && define.amd) { 17232 define(['jquery'], factory); 17233 } else if (typeof exports !== 'undefined') { 17234 module.exports = factory(require('jquery')); 17235 } else { 17236 factory(jQuery); 17237 } 17238 17239}(function($) { 17240 'use strict'; 17241 var Slick = window.Slick || {}; 17242 17243 Slick = (function() { 17244 17245 var instanceUid = 0; 17246 17247 function Slick(element, settings) { 17248 17249 var _ = this, dataSettings; 17250 17251 _.defaults = { 17252 accessibility: true, 17253 adaptiveHeight: false, 17254 appendArrows: $(element), 17255 appendDots: $(element), 17256 arrows: true, 17257 asNavFor: null, 17258 prevArrow: '<button class="slick-prev" aria-label="Previous" type="button">Previous</button>', 17259 nextArrow: '<button class="slick-next" aria-label="Next" type="button">Next</button>', 17260 autoplay: false, 17261 autoplaySpeed: 3000, 17262 centerMode: false, 17263 centerPadding: '50px', 17264 cssEase: 'ease', 17265 customPaging: function(slider, i) { 17266 return $('<button type="button" />').text(i + 1); 17267 }, 17268 dots: false, 17269 dotsClass: 'slick-dots', 17270 draggable: true, 17271 easing: 'linear', 17272 edgeFriction: 0.35, 17273 fade: false, 17274 focusOnSelect: false, 17275 focusOnChange: false, 17276 infinite: true, 17277 initialSlide: 0, 17278 lazyLoad: 'ondemand', 17279 mobileFirst: false, 17280 pauseOnHover: true, 17281 pauseOnFocus: true, 17282 pauseOnDotsHover: false, 17283 respondTo: 'window', 17284 responsive: null, 17285 rows: 1, 17286 rtl: false, 17287 slide: '', 17288 slidesPerRow: 1, 17289 slidesToShow: 1, 17290 slidesToScroll: 1, 17291 speed: 500, 17292 swipe: true, 17293 swipeToSlide: false, 17294 touchMove: true, 17295 touchThreshold: 5, 17296 useCSS: true, 17297 useTransform: true, 17298 variableWidth: false, 17299 vertical: false, 17300 verticalSwiping: false, 17301 waitForAnimate: true, 17302 zIndex: 1000 17303 }; 17304 17305 _.initials = { 17306 animating: false, 17307 dragging: false, 17308 autoPlayTimer: null, 17309 currentDirection: 0, 17310 currentLeft: null, 17311 currentSlide: 0, 17312 direction: 1, 17313 $dots: null, 17314 listWidth: null, 17315 listHeight: null, 17316 loadIndex: 0, 17317 $nextArrow: null, 17318 $prevArrow: null, 17319 scrolling: false, 17320 slideCount: null, 17321 slideWidth: null, 17322 $slideTrack: null, 17323 $slides: null, 17324 sliding: false, 17325 slideOffset: 0, 17326 swipeLeft: null, 17327 swiping: false, 17328 $list: null, 17329 touchObject: {}, 17330 transformsEnabled: false,
17331 unslicked: false 17332 }; 17333 17334 $.extend(_, _.initials); 17335 17336 _.activeBreakpoint = null; 17337 _.animType = null; 17338 _.animProp = null; 17339 _.breakpoints = []; 17340 _.breakpointSettings = []; 17341 _.cssTransitions = false; 17342 _.focussed = false; 17343 _.interrupted = false; 17344 _.hidden = 'hidden'; 17345 _.paused = true; 17346 _.positionProp = null; 17347 _.respondTo = null; 17348 _.rowCount = 1; 17349 _.shouldClick = true; 17350 _.$slider = $(element); 17351 _.$slidesCache = null; 17352 _.transformType = null; 17353 _.transitionType = null; 17354 _.visibilityChange = 'visibilitychange'; 17355 _.windowWidth = 0; 17356 _.windowTimer = null; 17357 17358 dataSettings = $(element).data('slick') || {}; 17359 17360 _.options = $.extend({}, _.defaults, settings, dataSettings); 17361 17362 _.currentSlide = _.options.initialSlide; 17363 17364 _.originalSettings = _.options; 17365 17366 if (typeof document.mozHidden !== 'undefined') { 17367 _.hidden = 'mozHidden'; 17368 _.visibilityChange = 'mozvisibilitychange'; 17369 } else if (typeof document.webkitHidden !== 'undefined') { 17370 _.hidden = 'webkitHidden'; 17371 _.visibilityChange = 'webkitvisibilitychange'; 17372 } 17373 17374 _.autoPlay = $.proxy(_.autoPlay, _); 17375 _.autoPlayClear = $.proxy(_.autoPlayClear, _); 17376 _.autoPlayIterator = $.proxy(_.autoPlayIterator, _); 17377 _.changeSlide = $.proxy(_.changeSlide, _); 17378 _.clickHandler = $.proxy(_.clickHandler, _); 17379 _.selectHandler = $.proxy(_.selectHandler, _); 17380 _.setPosition = $.proxy(_.setPosition, _); 17381 _.swipeHandler = $.proxy(_.swipeHandler, _); 17382 _.dragHandler = $.proxy(_.dragHandler, _); 17383 _.keyHandler = $.proxy(_.keyHandler, _); 17384 17385 _.instanceUid = instanceUid++; 17386 17387 // A simple way to check for HTML strings 17388 // Strict HTML recognition (must start with <) 17389 // Extracted from jQuery v1.11 source 17390 _.htmlExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/; 17391 17392 17393 _.registerBreakpoints(); 17394 _.init(true); 17395 17396 } 17397 17398 return Slick; 17399 17400 }()); 17401 17402 Slick.prototype.activateADA = function() { 17403 var _ = this; 17404 17405 _.$slideTrack.find('.slick-active').attr({ 17406 'aria-hidden': 'false' 17407 }).find('a, input, button, select').attr({ 17408 'tabindex': '0' 17409 }); 17410 17411 }; 17412 17413 Slick.prototype.addSlide = Slick.prototype.slickAdd = function(markup, index, addBefore) { 17414 17415 var _ = this; 17416 17417 if (typeof(index) === 'boolean') { 17418 addBefore = index; 17419 index = null; 17420 } else if (index < 0 || (index >= _.slideCount)) { 17421 return false; 17422 } 17423 17424 _.unload(); 17425 17426 if (typeof(index) === 'number') { 17427 if (index === 0 && _.$slides.length === 0) { 17428 $(markup).appendTo(_.$slideTrack); 17429 } else if (addBefore) { 17430 $(markup).insertBefore(_.$slides.eq(index)); 17431 } else { 17432 $(markup).insertAfter(_.$slides.eq(index)); 17433 } 17434 } else { 17435 if (addBefore === true) { 17436 $(markup).prependTo(_.$slideTrack); 17437 } else { 17438 $(markup).appendTo(_.$slideTrack); 17439 } 17440 } 17441 17442 _.$slides = _.$slideTrack.children(this.options.slide); 17443 17444 _.$slideTrack.children(this.options.slide).detach(); 17445 17446 _.$slideTrack.append(_.$slides); 17447 17448 _.$slides.each(function(index, element) { 17449 $(element).attr('data-slick-index', index); 17450 }); 17451 17452 _.$slidesCache = _.$slides; 17453 17454 _.reinit(); 17455 17456 }; 17457 17458 Slick.prototype.animateHeight = function() { 17459 var _ = this; 17460 if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) { 17461 var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true); 17462 _.$list.animate({ 17463 height: targetHeight 17464 }, _.options.speed); 17465 } 17466 }; 17467 17468 Slick.prototype.animateSlide = function(targetLeft, callback) { 17469 17470 var animProps = {}, 17471 _ = this; 17472 17473 _.animateHeight(); 17474 17475 if (_.options.rtl === true && _.options.vertical === false) { 17476 targetLeft = -targetLeft; 17477 } 17478 if (_.transformsEnabled === false) { 17479 if (_.options.vertical === false) { 17480 _.$slideTrack.animate({ 17481 left: targetLeft 17482 }, _.options.speed, _.options.easing, callback); 17483 } else { 17484 _.$slideTrack.animate({ 17485 top: targetLeft 17486 }, _.options.speed, _.options.easing, callback); 17487 } 17488 17489 } else { 17490 17491 if (_.cssTransitions === false) { 17492 if (_.options.rtl === true) { 17493 _.currentLeft = -(_.currentLeft); 17494 } 17495 $({ 17496 animStart: _.currentLeft 17497 }).animate({ 17498 animStart: targetLeft 17499 }, { 17500 duration: _.options.speed, 17501 easing: _.options.easing, 17502 step: function(now) { 17503 now = Math.ceil(now); 17504 if (_.options.vertical === false) { 17505 animProps[_.animType] = 'translate(' + 17506 now + 'px, 0px)'; 17507 _.$slideTrack.css(animProps); 17508 } else { 17509 animProps[_.animType] = 'translate(0px,' + 17510 now + 'px)'; 17511 _.$slideTrack.css(animProps); 17512 } 17513 }, 17514 complete: function() { 17515 if (callback) { 17516 callback.call(); 17517 } 17518 } 17519 }); 17520 17521 } else { 17522 17523 _.applyTransition();
17524 targetLeft = Math.ceil(targetLeft); 17525 17526 if (_.options.vertical === false) { 17527 animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)'; 17528 } else { 17529 animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)'; 17530 } 17531 _.$slideTrack.css(animProps); 17532 17533 if (callback) { 17534 setTimeout(function() { 17535 17536 _.disableTransition(); 17537 17538 callback.call(); 17539 }, _.options.speed); 17540 } 17541 17542 } 17543 17544 } 17545 17546 }; 17547 17548 Slick.prototype.getNavTarget = function() { 17549 17550 var _ = this, 17551 asNavFor = _.options.asNavFor; 17552 17553 if ( asNavFor && asNavFor !== null ) { 17554 asNavFor = $(asNavFor).not(_.$slider); 17555 } 17556 17557 return asNavFor; 17558 17559 }; 17560 17561 Slick.prototype.asNavFor = function(index) { 17562 17563 var _ = this, 17564 asNavFor = _.getNavTarget(); 17565 17566 if ( asNavFor !== null && typeof asNavFor === 'object' ) { 17567 asNavFor.each(function() { 17568 var target = $(this).slick('getSlick'); 17569 if(!target.unslicked) { 17570 target.slideHandler(index, true); 17571 } 17572 }); 17573 } 17574 17575 }; 17576 17577 Slick.prototype.applyTransition = function(slide) { 17578 17579 var _ = this, 17580 transition = {}; 17581 17582 if (_.options.fade === false) { 17583 transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase; 17584 } else { 17585 transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase; 17586 } 17587 17588 if (_.options.fade === false) { 17589 _.$slideTrack.css(transition); 17590 } else { 17591 _.$slides.eq(slide).css(transition); 17592 } 17593 17594 }; 17595 17596 Slick.prototype.autoPlay = function() { 17597 17598 var _ = this; 17599 17600 _.autoPlayClear(); 17601 17602 if ( _.slideCount > _.options.slidesToShow ) { 17603 _.autoPlayTimer = setInterval( _.autoPlayIterator, _.options.autoplaySpeed ); 17604 } 17605 17606 }; 17607 17608 Slick.prototype.autoPlayClear = function() { 17609 17610 var _ = this; 17611 17612 if (_.autoPlayTimer) { 17613 clearInterval(_.autoPlayTimer); 17614 } 17615 17616 }; 17617 17618 Slick.prototype.autoPlayIterator = function() { 17619 17620 var _ = this, 17621 slideTo = _.currentSlide + _.options.slidesToScroll; 17622 17623 if ( !_.paused && !_.interrupted && !_.focussed ) { 17624 17625 if ( _.options.infinite === false ) { 17626 17627 if ( _.direction === 1 && ( _.currentSlide + 1 ) === ( _.slideCount - 1 )) { 17628 _.direction = 0; 17629 } 17630 17631 else if ( _.direction === 0 ) { 17632 17633 slideTo = _.currentSlide - _.options.slidesToScroll; 17634 17635 if ( _.currentSlide - 1 === 0 ) { 17636 _.direction = 1; 17637 } 17638 17639 } 17640 17641 } 17642 17643 _.slideHandler( slideTo ); 17644 17645 } 17646 17647 }; 17648 17649 Slick.prototype.buildArrows = function() { 17650 17651 var _ = this; 17652 17653 if (_.options.arrows === true ) { 17654 17655 _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow'); 17656 _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow'); 17657 17658 if( _.slideCount > _.options.slidesToShow ) { 17659 17660 _.$prevArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex'); 17661 _.$nextArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex'); 17662 17663 if (_.htmlExpr.test(_.options.prevArrow)) { 17664 _.$prevArrow.prependTo(_.options.appendArrows); 17665 } 17666 17667 if (_.htmlExpr.test(_.options.nextArrow)) { 17668 _.$nextArrow.appendTo(_.options.appendArrows); 17669 } 17670 17671 if (_.options.infinite !== true) { 17672 _.$prevArrow 17673 .addClass('slick-disabled') 17674 .attr('aria-disabled', 'true'); 17675 } 17676 17677 } else { 17678 17679 _.$prevArrow.add( _.$nextArrow ) 17680 17681 .addClass('slick-hidden') 17682 .attr({ 17683 'aria-disabled': 'true', 17684 'tabindex': '-1' 17685 }); 17686 17687 } 17688 17689 } 17690 17691 }; 17692 17693 Slick.prototype.buildDots = function() { 17694 17695 var _ = this, 17696 i, dot; 17697 17698 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 17699 17700 _.$slider.addClass('slick-dotted'); 17701 17702 dot = $('<ul />').addClass(_.options.dotsClass); 17703 17704 for (i = 0; i <= _.getDotCount(); i += 1) { 17705 dot.append($('<li />').append(_.options.customPaging.call(this, _, i))); 17706 } 17707 17708 _.$dots = dot.appendTo(_.options.appendDots); 17709 17710 _.$dots.find('li').first().addClass('slick-active'); 17711 17712 } 17713 17714 }; 17715 17716 Slick.prototype.buildOut = function() { 17717 17718 var _ = this; 17719 17720 _.$slides = 17721 _.$slider 17722 .children( _.options.slide + ':not(.slick-cloned)') 17723 .addClass('slick-slide'); 17724 17725 _.slideCount = _.$slides.length; 17726 17727 _.$slides.each(function(index, element) { 17728 $(element) 17729 .attr('data-slick-index', index) 17730 .data('originalStyling', $(element).attr('style') || ''); 17731 }); 17732 17733 _.$slider.addClass('slick-slider'); 17734 17735 _.$slideTrack = (_.slideCount === 0) ? 17736 $('<div class="slick-track"/>').appendTo(_.$slider) : 17737 _.$slides.wrapAll('<div class="slick-track"/>').parent(); 17738 17739 _.$list = _.$slideTrack.wrap( 17740 '<div class="slick-list"/>').parent(); 17741 _.$slideTrack.css('opacity', 0); 17742 17743 if (_.options.centerMode === true || _.options.swipeToSlide === true) {
17744 _.options.slidesToScroll = 1; 17745 } 17746 17747 $('img[data-lazy]', _.$slider).not('[src]').addClass('slick-loading'); 17748 17749 _.setupInfinite(); 17750 17751 _.buildArrows(); 17752 17753 _.buildDots(); 17754 17755 _.updateDots(); 17756 17757 17758 _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0); 17759 17760 if (_.options.draggable === true) { 17761 _.$list.addClass('draggable'); 17762 } 17763 17764 }; 17765 17766 Slick.prototype.buildRows = function() { 17767 17768 var _ = this, a, b, c, newSlides, numOfSlides, originalSlides,slidesPerSection; 17769 17770 newSlides = document.createDocumentFragment(); 17771 originalSlides = _.$slider.children(); 17772 17773 if(_.options.rows > 0) { 17774 17775 slidesPerSection = _.options.slidesPerRow * _.options.rows; 17776 numOfSlides = Math.ceil( 17777 originalSlides.length / slidesPerSection 17778 ); 17779 17780 for(a = 0; a < numOfSlides; a++){ 17781 var slide = document.createElement('div'); 17782 for(b = 0; b < _.options.rows; b++) { 17783 var row = document.createElement('div'); 17784 for(c = 0; c < _.options.slidesPerRow; c++) { 17785 var target = (a * slidesPerSection + ((b * _.options.slidesPerRow) + c)); 17786 if (originalSlides.get(target)) { 17787 row.appendChild(originalSlides.get(target)); 17788 } 17789 } 17790 slide.appendChild(row); 17791 } 17792 newSlides.appendChild(slide); 17793 } 17794 17795 _.$slider.empty().append(newSlides); 17796 _.$slider.children().children().children() 17797 .css({ 17798 'width':(100 / _.options.slidesPerRow) + '%', 17799 'display': 'inline-block' 17800 }); 17801 17802 } 17803 17804 }; 17805 17806 Slick.prototype.checkResponsive = function(initial, forceUpdate) { 17807 17808 var _ = this, 17809 breakpoint, targetBreakpoint, respondToWidth, triggerBreakpoint = false; 17810 var sliderWidth = _.$slider.width(); 17811 var windowWidth = window.innerWidth || $(window).width(); 17812 17813 if (_.respondTo === 'window') { 17814 respondToWidth = windowWidth; 17815 } else if (_.respondTo === 'slider') { 17816 respondToWidth = sliderWidth; 17817 } else if (_.respondTo === 'min') { 17818 respondToWidth = Math.min(windowWidth, sliderWidth); 17819 } 17820 17821 if ( _.options.responsive && 17822 _.options.responsive.length && 17823 _.options.responsive !== null) { 17824 17825 targetBreakpoint = null; 17826 17827 for (breakpoint in _.breakpoints) { 17828 if (_.breakpoints.hasOwnProperty(breakpoint)) { 17829 if (_.originalSettings.mobileFirst === false) { 17830 if (respondToWidth < _.breakpoints[breakpoint]) { 17831 targetBreakpoint = _.breakpoints[breakpoint]; 17832 } 17833 } else { 17834 if (respondToWidth > _.breakpoints[breakpoint]) { 17835 targetBreakpoint = _.breakpoints[breakpoint]; 17836 } 17837 } 17838 } 17839 } 17840 17841 if (targetBreakpoint !== null) { 17842 if (_.activeBreakpoint !== null) { 17843 if (targetBreakpoint !== _.activeBreakpoint || forceUpdate) { 17844 _.activeBreakpoint = 17845 targetBreakpoint; 17846 if (_.breakpointSettings[targetBreakpoint] === 'unslick') { 17847 _.unslick(targetBreakpoint); 17848 } else { 17849 _.options = $.extend({}, _.originalSettings, 17850 _.breakpointSettings[ 17851 targetBreakpoint]); 17852 if (initial === true) { 17853 _.currentSlide = _.options.initialSlide; 17854 } 17855 _.refresh(initial); 17856 }
17857 triggerBreakpoint = targetBreakpoint; 17858 } 17859 } else { 17860 _.activeBreakpoint = targetBreakpoint; 17861 if (_.breakpointSettings[targetBreakpoint] === 'unslick') { 17862 _.unslick(targetBreakpoint); 17863 } else { 17864 _.options = $.extend({}, _.originalSettings, 17865 _.breakpointSettings[ 17866 targetBreakpoint]); 17867 if (initial === true) { 17868 _.currentSlide = _.options.initialSlide; 17869 } 17870 _.refresh(initial); 17871 } 17872 triggerBreakpoint = targetBreakpoint; 17873 } 17874 } else { 17875 if (_.activeBreakpoint !== null) { 17876 _.activeBreakpoint = null; 17877 _.options = _.originalSettings; 17878 if (initial === true) { 17879 _.currentSlide = _.options.initialSlide; 17880 } 17881 _.refresh(initial); 17882 triggerBreakpoint = targetBreakpoint; 17883 } 17884 } 17885 17886 // only trigger breakpoints during an actual break. not on initialize. 17887 if( !initial && triggerBreakpoint !== false ) { 17888 _.$slider.trigger('breakpoint', [_, triggerBreakpoint]); 17889 } 17890 } 17891 17892 }; 17893 17894 Slick.prototype.changeSlide = function(event, dontAnimate) { 17895 17896 var _ = this, 17897 $target = $(event.currentTarget), 17898 indexOffset, slideOffset, unevenOffset; 17899 17900 // If target is a link, prevent default action. 17901 if($target.is('a')) { 17902 event.preventDefault(); 17903 } 17904 17905 // If target is not the <li> element (ie: a child), find the <li>. 17906 if(!$target.is('li')) { 17907 $target = $target.closest('li'); 17908 } 17909 17910 unevenOffset = (_.slideCount % _.options.slidesToScroll !== 0); 17911 indexOffset = unevenOffset ? 0 : (_.slideCount - _.currentSlide) % _.options.slidesToScroll; 17912 17913 switch (event.data.message) { 17914 17915 case 'previous': 17916 slideOffset = indexOffset === 0 ? _.options.slidesToScroll : _.options.slidesToShow - indexOffset; 17917 if (_.slideCount > _.options.slidesToShow) { 17918 _.slideHandler(_.currentSlide - slideOffset, false, dontAnimate); 17919 } 17920 break; 17921 17922 case 'next': 17923 slideOffset = indexOffset === 0 ? _.options.slidesToScroll : indexOffset; 17924 if (_.slideCount > _.options.slidesToShow) { 17925 _.slideHandler(_.currentSlide + slideOffset, false, dontAnimate); 17926 } 17927 break; 17928 17929 case 'index': 17930 var index = event.data.index === 0 ? 0 : 17931 event.data.index || $target.index() * _.options.slidesToScroll; 17932 17933 _.slideHandler(_.checkNavigable(index), false, dontAnimate); 17934 $target.children().trigger('focus'); 17935 break; 17936 17937 default: 17938 return; 17939 } 17940 17941 }; 17942 17943 Slick.prototype.checkNavigable = function(index) { 17944 17945 var _ = this, 17946 navigables, prevNavigable; 17947 17948 navigables = _.getNavigableIndexes(); 17949 prevNavigable = 0; 17950 if (index > navigables[navigables.length - 1]) { 17951 index = navigables[navigables.length - 1]; 17952 } else { 17953 for (var n in navigables) { 17954 if (index < navigables[n]) { 17955 index = prevNavigable; 17956 break; 17957 } 17958 prevNavigable = navigables[n]; 17959 } 17960 } 17961 17962 return index; 17963 }; 17964 17965 Slick.prototype.cleanUpEvents = function() { 17966 17967 var _ = this; 17968 17969 if (_.options.dots && _.$dots !== null) { 17970 17971 $('li', _.$dots) 17972 .off('click.slick', _.changeSlide) 17973 .off('mouseenter.slick', $.proxy(_.interrupt, _, true)) 17974 .off('mouseleave.slick', $.proxy(_.interrupt, _, false)); 17975 17976 if (_.options.accessibility === true) { 17977 _.$dots.off('keydown.slick', _.keyHandler); 17978 } 17979 } 17980 17981 _.$slider.off('focus.slick blur.slick'); 17982 17983 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 17984 _.$prevArrow && _.$prevArrow.off('click.slick', _.changeSlide); 17985 _.$nextArrow && _.$nextArrow.off('click.slick', _.changeSlide); 17986 17987 if (_.options.accessibility === true) { 17988 _.$prevArrow && _.$prevArrow.off('keydown.slick', _.keyHandler); 17989 _.$nextArrow && _.$nextArrow.off('keydown.slick', _.keyHandler); 17990 } 17991 } 17992 17993 _.$list.off('touchstart.slick mousedown.slick', _.swipeHandler); 17994 _.$list.off('touchmove.slick mousemove.slick', _.swipeHandler); 17995 _.$list.off('touchend.slick mouseup.slick', _.swipeHandler);
17996 _.$list.off('touchcancel.slick mouseleave.slick', _.swipeHandler); 17997 17998 _.$list.off('click.slick', _.clickHandler); 17999 18000 $(document).off(_.visibilityChange, _.visibility); 18001 18002 _.cleanUpSlideEvents(); 18003 18004 if (_.options.accessibility === true) { 18005 _.$list.off('keydown.slick', _.keyHandler); 18006 } 18007 18008 if (_.options.focusOnSelect === true) { 18009 $(_.$slideTrack).children().off('click.slick', _.selectHandler); 18010 } 18011 18012 $(window).off('orientationchange.slick.slick-' + _.instanceUid, _.orientationChange); 18013 18014 $(window).off('resize.slick.slick-' + _.instanceUid, _.resize); 18015 18016 $('[draggable!=true]', _.$slideTrack).off('dragstart', _.preventDefault); 18017 18018 $(window).off('load.slick.slick-' + _.instanceUid, _.setPosition); 18019 18020 }; 18021 18022 Slick.prototype.cleanUpSlideEvents = function() { 18023 18024 var _ = this; 18025 18026 _.$list.off('mouseenter.slick', $.proxy(_.interrupt, _, true)); 18027 _.$list.off('mouseleave.slick', $.proxy(_.interrupt, _, false)); 18028 18029 }; 18030 18031 Slick.prototype.cleanUpRows = function() { 18032 18033 var _ = this, originalSlides; 18034 18035 if(_.options.rows > 0) { 18036 originalSlides = _.$slides.children().children(); 18037 originalSlides.removeAttr('style'); 18038 _.$slider.empty().append(originalSlides); 18039 } 18040 18041 }; 18042 18043 Slick.prototype.clickHandler = function(event) { 18044 18045 var _ = this; 18046 18047 if (_.shouldClick === false) { 18048 event.stopImmediatePropagation(); 18049 event.stopPropagation(); 18050 event.preventDefault(); 18051 } 18052 18053 }; 18054 18055 Slick.prototype.destroy = function(refresh) { 18056 18057 var _ = this; 18058 18059 _.autoPlayClear(); 18060 18061 _.touchObject = {}; 18062 18063 _.cleanUpEvents(); 18064 18065 $('.slick-cloned', _.$slider).detach(); 18066 18067 if (_.$dots) { 18068 _.$dots.remove(); 18069 } 18070 18071 if ( _.$prevArrow && _.$prevArrow.length ) { 18072 18073 _.$prevArrow 18074 .removeClass('slick-disabled slick-arrow slick-hidden') 18075 .removeAttr('aria-hidden aria-disabled tabindex') 18076 .css('display',''); 18077 18078 if ( _.htmlExpr.test( _.options.prevArrow )) { 18079 _.$prevArrow.remove(); 18080 } 18081 } 18082 18083 if ( _.$nextArrow && _.$nextArrow.length ) { 18084 18085 _.$nextArrow 18086 .removeClass('slick-disabled slick-arrow slick-hidden') 18087 .removeAttr('aria-hidden aria-disabled tabindex') 18088 .css('display',''); 18089 18090 if ( _.htmlExpr.test( _.options.nextArrow )) { 18091 _.$nextArrow.remove(); 18092 } 18093 } 18094 18095 18096 if (_.$slides) { 18097 18098 _.$slides 18099 .removeClass('slick-slide slick-active slick-center slick-visible slick-current') 18100 .removeAttr('aria-hidden') 18101 .removeAttr('data-slick-index') 18102 .each(function(){ 18103 $(this).attr('style', $(this).data('originalStyling')); 18104 }); 18105 18106 _.$slideTrack.children(this.options.slide).detach(); 18107 18108 _.$slideTrack.detach(); 18109 18110 _.$list.detach(); 18111 18112 _.$slider.append(_.$slides); 18113 } 18114 18115 _.cleanUpRows(); 18116 18117 _.$slider.removeClass('slick-slider'); 18118 _.$slider.removeClass('slick-initialized'); 18119 _.$slider.removeClass('slick-dotted'); 18120 18121 _.unslicked = true; 18122 18123 if(!refresh) { 18124 _.$slider.trigger('destroy', [_]); 18125 } 18126 18127 }; 18128 18129 Slick.prototype.disableTransition = function(slide) { 18130 18131 var _ = this, 18132 transition = {}; 18133 18134 transition[_.transitionType] = ''; 18135 18136 if (_.options.fade === false) { 18137 _.$slideTrack.css(transition); 18138 } else { 18139 _.$slides.eq(slide).css(transition); 18140 } 18141 18142 }; 18143 18144 Slick.prototype.fadeSlide = function(slideIndex, callback) { 18145 18146 var _ = this; 18147 18148 if (_.cssTransitions === false) { 18149 18150 _.$slides.eq(slideIndex).css({ 18151 zIndex: _.options.zIndex 18152 }); 18153 18154 _.$slides.eq(slideIndex).animate({ 18155 opacity: 1 18156 }, _.options.speed, _.options.easing, callback); 18157 18158 } else { 18159 18160 _.applyTransition(slideIndex); 18161 18162 _.$slides.eq(slideIndex).css({ 18163 opacity: 1, 18164 zIndex: _.options.zIndex 18165 }); 18166 18167 if (callback) { 18168 setTimeout(function() { 18169 18170 _.disableTransition(slideIndex); 18171 18172 callback.call(); 18173 }, _.options.speed); 18174 } 18175 18176 } 18177 18178 }; 18179 18180 Slick.prototype.fadeSlideOut = function(slideIndex) { 18181 18182 var _ = this; 18183 18184 if (_.cssTransitions === false) { 18185 18186 _.$slides.eq(slideIndex).animate({ 18187 opacity: 0, 18188 zIndex: _.options.zIndex - 2 18189 }, _.options.speed, _.options.easing); 18190 18191 } else { 18192 18193 _.applyTransition(slideIndex); 18194 18195 _.$slides.eq(slideIndex).css({ 18196 opacity: 0, 18197 zIndex: _.options.zIndex - 2 18198 }); 18199 18200 } 18201 18202 }; 18203
18204 Slick.prototype.filterSlides = Slick.prototype.slickFilter = function(filter) { 18205 18206 var _ = this; 18207 18208 if (filter !== null) { 18209 18210 _.$slidesCache = _.$slides; 18211 18212 _.unload(); 18213 18214 _.$slideTrack.children(this.options.slide).detach(); 18215 18216 _.$slidesCache.filter(filter).appendTo(_.$slideTrack); 18217 18218 _.reinit(); 18219 18220 } 18221 18222 }; 18223 18224 Slick.prototype.focusHandler = function() { 18225 18226 var _ = this; 18227 18228 _.$slider 18229 .off('focus.slick blur.slick') 18230 .on('focus.slick blur.slick', '*', function(event) { 18231 18232 event.stopImmediatePropagation(); 18233 var $sf = $(this); 18234 18235 setTimeout(function() { 18236 18237 if( _.options.pauseOnFocus ) { 18238 _.focussed = $sf.is(':focus'); 18239 _.autoPlay(); 18240 } 18241 18242 }, 0); 18243 18244 }); 18245 }; 18246 18247 Slick.prototype.getCurrent = Slick.prototype.slickCurrentSlide = function() { 18248 18249 var _ = this; 18250 return _.currentSlide; 18251 18252 }; 18253 18254 Slick.prototype.getDotCount = function() { 18255 18256 var _ = this; 18257 18258 var breakPoint = 0; 18259 var counter = 0; 18260 var pagerQty = 0; 18261 18262 if (_.options.infinite === true) { 18263 if (_.slideCount <= _.options.slidesToShow) { 18264 ++pagerQty; 18265 } else { 18266 while (breakPoint < _.slideCount) { 18267 ++pagerQty; 18268 breakPoint = counter + _.options.slidesToScroll; 18269 counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow; 18270 } 18271 } 18272 } else if (_.options.centerMode === true) { 18273 pagerQty = _.slideCount; 18274 } else if(!_.options.asNavFor) { 18275 pagerQty = 1 + Math.ceil((_.slideCount - _.options.slidesToShow) / _.options.slidesToScroll); 18276 }else { 18277 while (breakPoint < _.slideCount) { 18278 ++pagerQty; 18279 breakPoint = counter + _.options.slidesToScroll; 18280 counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow; 18281 } 18282 } 18283 18284 return pagerQty - 1; 18285 18286 }; 18287 18288 Slick.prototype.getLeft = function(slideIndex) { 18289 18290 var _ = this, 18291 targetLeft, 18292 verticalHeight, 18293 verticalOffset = 0, 18294 targetSlide, 18295 coef; 18296 18297 _.slideOffset = 0; 18298 verticalHeight = _.$slides.first().outerHeight(true); 18299 18300 if (_.options.infinite === true) { 18301 if (_.slideCount > _.options.slidesToShow) { 18302 _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1; 18303 coef = -1 18304 18305 if (_.options.vertical === true && _.options.centerMode === true) { 18306 if (_.options.slidesToShow === 2) { 18307 coef = -1.5; 18308 } else if (_.options.slidesToShow === 1) { 18309 coef = -2 18310 } 18311 } 18312 verticalOffset = (verticalHeight * _.options.slidesToShow) * coef; 18313 } 18314 if (_.slideCount % _.options.slidesToScroll !== 0) { 18315 if (slideIndex + _.options.slidesToScroll > _.slideCount && _.slideCount > _.options.slidesToShow) { 18316 if (slideIndex > _.slideCount) { 18317 _.slideOffset = ((_.options.slidesToShow - (sl
18317ideIndex - _.slideCount)) * _.slideWidth) * -1; 18318 verticalOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * verticalHeight) * -1; 18319 } else { 18320 _.slideOffset = ((_.slideCount % _.options.slidesToScroll) * _.slideWidth) * -1; 18321 verticalOffset = ((_.slideCount % _.options.slidesToScroll) * verticalHeight) * -1; 18322 } 18323 } 18324 } 18325 } else { 18326 if (slideIndex + _.options.slidesToShow > _.slideCount) { 18327 _.slideOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * _.slideWidth; 18328 verticalOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * verticalHeight; 18329 } 18330 } 18331 18332 if (_.slideCount <= _.options.slidesToShow) { 18333 _.slideOffset = 0; 18334 verticalOffset = 0; 18335 } 18336 18337 if (_.options.centerMode === true && _.slideCount <= _.options.slidesToShow) { 18338 _.slideOffset = ((_.slideWidth * Math.floor(_.options.slidesToShow)) / 2) - ((_.slideWidth * _.slideCount) / 2); 18339 } else if (_.options.centerMode === true && _.options.infinite === true) { 18340 _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2) - _.slideWidth; 18341 } else if (_.options.centerMode === true) { 18342 _.slideOffset = 0; 18343 _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2); 18344 } 18345 18346 if (_.options.vertical === false) { 18347 targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset; 18348 } else { 18349 targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset; 18350 } 18351 18352 if (_.options.variableWidth === true) { 18353
18354 if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) { 18355 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex); 18356 } else { 18357 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow); 18358 } 18359 18360 if (_.options.rtl === true) { 18361 if (targetSlide[0]) { 18362 targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1; 18363 } else { 18364 targetLeft = 0; 18365 } 18366 } else { 18367 targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0; 18368 } 18369 18370 if (_.options.centerMode === true) { 18371 if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) { 18372 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex); 18373 } else { 18374 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow + 1); 18375 } 18376 18377 if (_.options.rtl === true) { 18378 if (targetSlide[0]) { 18379 targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1; 18380 } else { 18381 targetLeft = 0; 18382 } 18383 } else { 18384 targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0; 18385 } 18386 18387 targetLeft += (_.$list.width() - targetSlide.outerWidth()) / 2; 18388 } 18389 } 18390 18391 return targetLeft; 18392 18393 }; 18394 18395 Slick.prototype.getOption = Slick.prototype.slickGetOption = function(option) { 18396 18397 var _ = this; 18398 18399 return _.options[option]; 18400 18401 }; 18402 18403 Slick.prototype.getNavigableIndexes = function() { 18404 18405 var _ = this, 18406 breakPoint = 0, 18407 counter = 0, 18408 indexes = [], 18409 max; 18410 18411 if (_.options.infinite === false) { 18412 max = _.slideCount; 18413 } else { 18414 breakPoint = _.options.slidesToScroll * -1; 18415 counter = _.options.slidesToScroll * -1; 18416 max = _.slideCount * 2; 18417 } 18418 18419 while (breakPoint < max) { 18420 indexes.push(breakPoint); 18421 breakPoint = counter + _.options.slidesToScroll; 18422 counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow; 18423 } 18424 18425 return indexes; 18426 18427 }; 18428 18429 Slick.prototype.getSlick = function() { 18430 18431 return this; 18432 18433 }; 18434 18435 Slick.prototype.getSlideCount = function() { 18436 18437 var _ = this, 18438 slidesTraversed, swipedSlide, centerOffset; 18439 18440 centerOffset = _.options.centerMode === true ? _.slideWidth * Math.floor(_.options.slidesToShow / 2) : 0; 18441 18442 if (_.options.swipeToSlide === true) { 18443 _.$slideTrack.find('.slick-slide').each(function(index, slide) { 18444 if (slide.offsetLeft - centerOffset + ($(slide).outerWidth() / 2) > (_.swipeLeft * -1)) { 18445 swipedSlide = slide; 18446 return false; 18447 } 18448 }); 18449 18450 slidesTraversed = Math.abs($(swipedSlide).attr('data-slick-index') - _.currentSlide) || 1; 18451 18452 return slidesTraversed; 18453 18454 } else { 18455 return _.options.slidesToScroll; 18456 } 18457 18458 }; 18459 18460 Slick.prototype.goTo = Slick.prototype.slickGoTo = function(slide, dontAnimate) { 18461 18462 var _ = this; 18463 18464 _.changeSlide({ 18465 data: { 18466 message: 'index', 18467 index: parseInt(slide) 18468 } 18469 }, dontAnimate); 18470 18471 }; 18472 18473 Slick.prototype.init = function(creation) { 18474 18475 var _ = this; 18476 18477 if (!$(_.$slider).hasClass('slick-initialized')) { 18478 18479 $(_.$slider).addClass('slick-initialized'); 18480 18481 _.buildRows(); 18482 _.buildOut(); 18483 _.setProps(); 18484 _.startLoad(); 18485 _.loadSlider(); 18486 _.initializeEvents(); 18487 _.updateArrows(); 18488 _.updateDots(); 18489 _.checkResponsive(true); 18490 _.focusHandler(); 18491 18492 } 18493 18494 if (creation) { 18495 _.$slider.trigger('init', [_]); 18496 } 18497 18498 if (_.options.accessibility === true) { 18499 _.initADA(); 18500 } 18501 18502 if ( _.options.autoplay ) { 18503 18504 _.paused = false;
18505 _.autoPlay(); 18506 18507 } 18508 18509 }; 18510 18511 Slick.prototype.initADA = function() { 18512 var _ = this, 18513 numDotGroups = Math.ceil(_.slideCount / _.options.slidesToShow), 18514 tabControlIndexes = _.getNavigableIndexes().filter(function(val) { 18515 return (val >= 0) && (val < _.slideCount); 18516 }); 18517 18518 _.$slides.add(_.$slideTrack.find('.slick-cloned')).attr({ 18519 'aria-hidden': 'true', 18520 'tabindex': '-1' 18521 }).find('a, input, button, select').attr({ 18522 'tabindex': '-1' 18523 }); 18524 18525 if (_.$dots !== null) { 18526 _.$slides.not(_.$slideTrack.find('.slick-cloned')).each(function(i) { 18527 var slideControlIndex = tabControlIndexes.indexOf(i); 18528 18529 $(this).attr({ 18530 'role': 'tabpanel', 18531 'id': 'slick-slide' + _.instanceUid + i, 18532 'tabindex': -1 18533 }); 18534 18535 if (slideControlIndex !== -1) { 18536 var ariaButtonControl = 'slick-slide-control' + _.instanceUid + slideControlIndex 18537 if ($('#' + ariaButtonControl).length) { 18538 $(this).attr({ 18539 'aria-describedby': ariaButtonControl 18540 }); 18541 } 18542 } 18543 }); 18544 18545 _.$dots.attr('role', 'tablist').find('li').each(function(i) { 18546 var mappedSlideIndex = tabControlIndexes[i]; 18547 18548 $(this).attr({ 18549 'role': 'presentation' 18550 }); 18551 18552 $(this).find('button').first().attr({ 18553 'role': 'tab', 18554 'id': 'slick-slide-control' + _.instanceUid + i, 18555 'aria-controls': 'slick-slide' + _.instanceUid + mappedSlideIndex, 18556 'aria-label': (i + 1) + ' of ' + numDotGroups, 18557 'aria-selected': null, 18558 'tabindex': '-1' 18559 }); 18560 18561 }).eq(_.currentSlide).find('button').attr({ 18562 'aria-selected': 'true', 18563 'tabindex': '0' 18564 }).end(); 18565 } 18566 18567 for (var i=_.currentSlide, max=i+_.options.slidesToShow; i < max; i++) { 18568 if (_.options.focusOnChange) { 18569 _.$slides.eq(i).attr({'tabindex': '0'}); 18570 } else { 18571 _.$slides.eq(i).removeAttr('tabindex'); 18572 } 18573 } 18574 18575 _.activateADA(); 18576 18577 }; 18578 18579 Slick.prototype.initArrowEvents = function() { 18580 18581 var _ = this; 18582 18583 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 18584 _.$prevArrow 18585 .off('click.slick') 18586 .on('click.slick', { 18587 message: 'previous' 18588 }, _.changeSlide); 18589 _.$nextArrow 18590 .off('click.slick') 18591 .on('click.slick', { 18592 message: 'next' 18593 }, _.changeSlide); 18594 18595 if (_.options.accessibility === true) { 18596 _.$prevArrow.on('keydown.slick', _.keyHandler); 18597 _.$nextArrow.on('keydown.slick', _.keyHandler); 18598 } 18599 } 18600 18601 }; 18602 18603 Slick.prototype.initDotEvents = function() { 18604 18605 var _ = this; 18606 18607 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 18608 $('li', _.$dots).on('click.slick', { 18609 message: 'index' 18610 }, _.changeSlide); 18611 18612 if (_.options.accessibility === true) { 18613 _.$dots.on('keydown.slick', _.keyHandler); 18614 } 18615 } 18616 18617 if (_.options.dots === true && _.options.pauseOnDotsHover === true && _.slideCount > _.options.slidesToShow) { 18618 18619 $('li', _.$dots) 18620 .on('mouseenter.slick', $.proxy(_.interrupt, _, true)) 18621 .on('mouseleave.slick', $.proxy(_.interrupt, _, false)); 18622 18623 } 18624 18625 }; 18626 18627 Slick.prototype.initSlideEvents = function() { 18628 18629 var _ = this; 18630 18631 if ( _.options.pauseOnHover ) { 18632 18633 _.$list.on('mouseenter.slick', $.proxy(_.interrupt, _, true));
18634 _.$list.on('mouseleave.slick', $.proxy(_.interrupt, _, false)); 18635 18636 } 18637 18638 }; 18639 18640 Slick.prototype.initializeEvents = function() { 18641 18642 var _ = this; 18643 18644 _.initArrowEvents(); 18645 18646 _.initDotEvents(); 18647 _.initSlideEvents(); 18648 18649 _.$list.on('touchstart.slick mousedown.slick', { 18650 action: 'start' 18651 }, _.swipeHandler); 18652 _.$list.on('touchmove.slick mousemove.slick', { 18653 action: 'move' 18654 }, _.swipeHandler); 18655 _.$list.on('touchend.slick mouseup.slick', { 18656 action: 'end' 18657 }, _.swipeHandler); 18658 _.$list.on('touchcancel.slick mouseleave.slick', { 18659 action: 'end' 18660 }, _.swipeHandler); 18661 18662 _.$list.on('click.slick', _.clickHandler); 18663 18664 $(document).on(_.visibilityChange, $.proxy(_.visibility, _)); 18665 18666 if (_.options.accessibility === true) { 18667 _.$list.on('keydown.slick', _.keyHandler); 18668 } 18669 18670 if (_.options.focusOnSelect === true) { 18671 $(_.$slideTrack).children().on('click.slick', _.selectHandler); 18672 } 18673 18674 $(window).on('orientationchange.slick.slick-' + _.instanceUid, $.proxy(_.orientationChange, _)); 18675 18676 $(window).on('resize.slick.slick-' + _.instanceUid, $.proxy(_.resize, _)); 18677 18678 $('[draggable!=true]', _.$slideTrack).on('dragstart', _.preventDefault); 18679 18680 $(window).on('load.slick.slick-' + _.instanceUid, _.setPosition); 18681 $(_.setPosition); 18682 18683 }; 18684 18685 Slick.prototype.initUI = function() { 18686 18687 var _ = this; 18688 18689 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 18690 18691 _.$prevArrow.show(); 18692 _.$nextArrow.show(); 18693 18694 } 18695 18696 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 18697 18698 _.$dots.show(); 18699 18700 } 18701 18702 }; 18703 18704 Slick.prototype.keyHandler = function(event) { 18705 18706 var _ = this; 18707 //Dont slide if the cursor is inside the form fields and arrow keys are pressed 18708 if(!event.target.tagName.match('TEXTAREA|INPUT|SELECT')) { 18709 if (event.keyCode === 37 && _.options.accessibility === true) { 18710 _.changeSlide({ 18711 data: { 18712 message: _.options.rtl === true ? 'next' : 'previous' 18713 } 18714 }); 18715 } else if (event.keyCode === 39 && _.options.accessibility === true) { 18716 _.changeSlide({ 18717 data: { 18718 message: _.options.rtl === true ? 'previous' : 'next' 18719 } 18720 }); 18721 } 18722 } 18723 18724 }; 18725 18726 Slick.prototype.lazyLoad = function() { 18727 18728 var _ = this, 18729 loadRange, cloneRange, rangeStart, rangeEnd; 18730 18731 function loadImages(imagesScope) { 18732 18733 $('img[data-lazy]', imagesScope).each(function() { 18734 18735 var image = $(this), 18736 imageSource = $(this).attr('data-lazy'), 18737 imageSrcSet = $(this).attr('data-srcset'), 18738 imageSizes = $(this).attr('data-sizes') || _.$slider.attr('data-sizes'), 18739 imageToLoad = document.createElement('img'); 18740 18741 imageToLoad.onload = function() { 18742 18743 image 18744 .animate({ opacity: 0 }, 100, function() { 18745 18746 if (imageSrcSet) { 18747 image 18748 .attr('srcset', imageSrcSet ); 18749 18750 if (imageSizes) { 18751 image 18752 .attr('sizes', imageSizes ); 18753 } 18754 } 18755 18756 image 18757 .attr('src', imageSource) 18758 .animate({ opacity: 1 }, 200, function() { 18759 image 18760 .removeAttr('data-lazy data-srcset data-sizes') 18761 .removeClass('slick-loading'); 18762 }); 18763 _.$slider.trigger('lazyLoaded', [_, image, imageSource]); 18764 }); 18765 18766 }; 18767 18768 imageToLoad.onerror = function() { 18769 18770 image 18771 .removeAttr( 'data-lazy' ) 18772 .removeClass( 'slick-loading' ) 18773 .addClass( 'slick-lazyload-error' ); 18774 18775 _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]); 18776 18777 }; 18778 18779 imageToLoad.src = imageSource; 18780 18781 }); 18782 18783 } 18784 18785 if (_.options.centerMode === true) { 18786 if (_.options.infinite === true) { 18787 rangeStart = _.currentSlide + (_.options.slidesToShow / 2 + 1); 18788 rangeEnd = rangeStart + _.options.slidesToShow + 2; 18789 } else { 18790 rangeStart = Math.max(0, _.currentSlide - (_.options.slidesToShow / 2 + 1)); 18791 rangeEnd = 2 + (_.options.slidesToShow / 2 + 1) + _.currentSlide; 18792 } 18793 } else {
18794 rangeStart = _.options.infinite ? _.options.slidesToShow + _.currentSlide : _.currentSlide; 18795 rangeEnd = Math.ceil(rangeStart + _.options.slidesToShow); 18796 if (_.options.fade === true) { 18797 if (rangeStart > 0) rangeStart--; 18798 if (rangeEnd <= _.slideCount) rangeEnd++; 18799 } 18800 } 18801 18802 loadRange = _.$slider.find('.slick-slide').slice(rangeStart, rangeEnd); 18803 18804 if (_.options.lazyLoad === 'anticipated') { 18805 var prevSlide = rangeStart - 1, 18806 nextSlide = rangeEnd, 18807 $slides = _.$slider.find('.slick-slide'); 18808 18809 for (var i = 0; i < _.options.slidesToScroll; i++) { 18810 if (prevSlide < 0) prevSlide = _.slideCount - 1; 18811 loadRange = loadRange.add($slides.eq(prevSlide)); 18812 loadRange = loadRange.add($slides.eq(nextSlide)); 18813 prevSlide--; 18814 nextSlide++; 18815 } 18816 } 18817 18818 loadImages(loadRange); 18819 18820 if (_.slideCount <= _.options.slidesToShow) { 18821 cloneRange = _.$slider.find('.slick-slide'); 18822 loadImages(cloneRange); 18823 } else 18824 if (_.currentSlide >= _.slideCount - _.options.slidesToShow) { 18825 cloneRange = _.$slider.find('.slick-cloned').slice(0, _.options.slidesToShow); 18826 loadImages(cloneRange); 18827 } else if (_.currentSlide === 0) { 18828 cloneRange = _.$slider.find('.slick-cloned').slice(_.options.slidesToShow * -1); 18829 loadImages(cloneRange); 18830 } 18831 18832 }; 18833 18834 Slick.prototype.loadSlider = function() { 18835 18836 var _ = this; 18837 18838 _.setPosition(); 18839 18840 _.$slideTrack.css({ 18841 opacity: 1 18842 }); 18843 18844 _.$slider.removeClass('slick-loading'); 18845 18846 _.initUI(); 18847 18848 if (_.options.lazyLoad === 'progressive') { 18849 _.progressiveLazyLoad(); 18850 } 18851 18852 }; 18853 18854 Slick.prototype.next = Slick.prototype.slickNext = function() { 18855 18856 var _ = this; 18857 18858 _.changeSlide({ 18859 data: { 18860 message: 'next' 18861 } 18862 }); 18863 18864 }; 18865 18866 Slick.prototype.orientationChange = function() { 18867 18868 var _ = this; 18869 18870 _.checkResponsive(); 18871 _.setPosition(); 18872 18873 }; 18874 18875 Slick.prototype.pause = Slick.prototype.slickPause = function() { 18876 18877 var _ = this; 18878 18879 _.autoPlayClear(); 18880 _.paused = true; 18881 18882 }; 18883 18884 Slick.prototype.play = Slick.prototype.slickPlay = function() { 18885 18886 var _ = this; 18887 18888 _.autoPlay(); 18889 _.options.autoplay = true; 18890 _.paused = false; 18891 _.focussed = false; 18892 _.interrupted = false; 18893 18894 }; 18895 18896 Slick.prototype.postSlide = function(index) { 18897 18898 var _ = this; 18899 18900 if( !_.unslicked ) { 18901 18902 _.$slider.trigger('afterChange', [_, index]); 18903 18904 _.animating = false; 18905 18906 if (_.slideCount > _.options.slidesToShow) { 18907 _.setPosition(); 18908 } 18909 18910 _.swipeLeft = null; 18911 18912 if ( _.options.autoplay ) { 18913 _.autoPlay(); 18914 } 18915 18916 if (_.options.accessibility === true) { 18917 _.initADA(); 18918 18919 if (_.options.focusOnChange) { 18920 var $currentSlide = $(_.$slides.get(_.currentSlide)); 18921 $currentSlide.attr('tabindex', 0).focus(); 18922 } 18923 } 18924 18925 } 18926 18927 }; 18928 18929 Slick.prototype.prev = Slick.prototype.slickPrev = function() { 18930 18931 var _ = this; 18932 18933 _.changeSlide({ 18934 data: { 18935 message: 'previous' 18936 } 18937 }); 18938 18939 }; 18940 18941 Slick.prototype.preventDefault = function(event) { 18942 18943 event.preventDefault(); 18944 18945 }; 18946 18947 Slick.prototype.progressiveLazyLoad = function( tryCount ) { 18948 18949 tryCount = tryCount || 1; 18950 18951 var _ = this, 18952 $imgsToLoad = $( 'img[data-lazy]', _.$slider ), 18953 image, 18954 imageSource, 18955 imageSrcSet, 18956 imageSizes, 18957 imageToLoad; 18958 18959 if ( $imgsToLoad.length ) { 18960 18961 image = $imgsToLoad.first(); 18962 imageSource = image.attr('data-lazy'); 18963 imageSrcSet = image.attr('data-srcset'); 18964 imageSizes = image.attr('data-sizes') || _.$slider.attr('data-sizes'); 18965 imageToLoad = document.createElement('img'); 18966 18967 imageToLoad.onload = function() { 18968 18969 if (imageSrcSet) { 18970 image 18971 .attr('srcset', imageSrcSet ); 18972 18973 if (imageSizes) { 18974 image 18975 .attr('sizes', imageSizes ); 18976 } 18977 } 18978 18979 image 18980 .attr( 'src', imageSource ) 18981 .removeAttr('data-lazy data-srcset data-sizes') 18982 .removeClass('slick-loading'); 18983 18984 if ( _.options.adaptiveHeight === true ) { 18985 _.setPosition(); 18986 } 18987 18988 _.$slider.trigger('lazyLoaded', [ _, image, imageSource ]); 18989 _.progressiveLazyLoad(); 18990 18991 }; 18992 18993 imageToLoad.onerror = function() { 18994 18995 if ( tryCount < 3 ) { 18996 18997 /** 18998 * try to load the image 3 times, 18999 * leave a slight delay so we don't get 19000 * servers blocking the request. 19001 */ 19002 setTimeout( function() { 19003 _.progressiveLazyLoad( tryCount + 1 ); 19004 }, 500 ); 19005 19006 } else { 19007 19008 image 19009 .removeAttr( 'data-lazy' ) 19010 .removeClass( 'slick-loading' ) 19011 .addClass( 'slick-lazyload-error' ); 19012 19013 _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]); 19014 19015 _.progressiveLazyLoad(); 19016 19017 } 19018 19019 }; 19020 19021 imageToLoad.src = imageSource; 19022 19023 } else { 19024 19025 _.$slider.trigger('allImagesLoaded', [ _ ]); 19026 19027 } 19028 19029 }; 19030 19031 Slick.prototype.refresh = function( initializing ) { 19032 19033 var _ = this, currentSlide, lastVisibleIndex; 19034 19035 lastVisibleIndex = _.slideCount - _.options.slidesToShow; 19036 19037 // in non-infinite sliders, we don't want to go past the 19038 // last visible index. 19039 if( !_.options.infinite && ( _.currentSlide > lastVisibleIndex )) { 19040 _.currentSlide = lastVisibleIndex; 19041 } 19042 19043 // if less slides than to show, go to start. 19044 if ( _.slideCount <= _.options.slidesToShow ) { 19045 _.currentSlide = 0; 19046 19047 } 19048 19049 currentSlide = _.currentSlide; 19050 19051 _.destroy(true); 19052 19053 $.extend(_, _.initials, { currentSlide: currentSlide }); 19054
19055 _.init(); 19056 19057 if( !initializing ) { 19058 19059 _.changeSlide({ 19060 data: { 19061 message: 'index', 19062 index: currentSlide 19063 } 19064 }, false); 19065 19066 } 19067 19068 }; 19069 19070 Slick.prototype.registerBreakpoints = function() { 19071 19072 var _ = this, breakpoint, currentBreakpoint, l, 19073 responsiveSettings = _.options.responsive || null; 19074 19075 if ( $.type(responsiveSettings) === 'array' && responsiveSettings.length ) { 19076 19077 _.respondTo = _.options.respondTo || 'window'; 19078 19079 for ( breakpoint in responsiveSettings ) { 19080 19081 l = _.breakpoints.length-1; 19082 19083 if (responsiveSettings.hasOwnProperty(breakpoint)) { 19084 currentBreakpoint = responsiveSettings[breakpoint].breakpoint; 19085 19086 // loop through the breakpoints and cut out any existing 19087 // ones with the same breakpoint number, we don't want dupes. 19088 while( l >= 0 ) { 19089 if( _.breakpoints[l] && _.breakpoints[l] === currentBreakpoint ) { 19090 _.breakpoints.splice(l,1); 19091 } 19092 l--; 19093 } 19094 19095 _.breakpoints.push(currentBreakpoint); 19096 _.breakpointSettings[currentBreakpoint] = responsiveSettings[breakpoint].settings; 19097 19098 } 19099 19100 } 19101 19102 _.breakpoints.sort(function(a, b) { 19103 return ( _.options.mobileFirst ) ? a-b : b-a; 19104 }); 19105 19106 } 19107 19108 }; 19109 19110 Slick.prototype.reinit = function() { 19111 19112 var _ = this; 19113 19114 _.$slides = 19115 _.$slideTrack 19116 .children(_.options.slide) 19117 .addClass('slick-slide'); 19118 19119 _.slideCount = _.$slides.length; 19120 19121 if (_.currentSlide >= _.slideCount && _.currentSlide !== 0) { 19122 _.currentSlide = _.currentSlide - _.options.slidesToScroll; 19123 } 19124 19125 if (_.slideCount <= _.options.slidesToShow) { 19126 _.currentSlide = 0; 19127 } 19128 19129 _.registerBreakpoints(); 19130 19131 _.setProps(); 19132 _.setupInfinite(); 19133 _.buildArrows(); 19134 _.updateArrows(); 19135 _.initArrowEvents(); 19136 _.buildDots(); 19137 _.updateDots(); 19138 _.initDotEvents(); 19139 _.cleanUpSlideEvents(); 19140 _.initSlideEvents(); 19141 19142 _.checkResponsive(false, true); 19143 19144 if (_.options.focusOnSelect === true) { 19145 $(_.$slideTrack).children().on('click.slick', _.selectHandler); 19146 } 19147 19148 _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0); 19149 19150 _.setPosition(); 19151 _.focusHandler(); 19152 19153 _.paused = !_.options.autoplay; 19154 _.autoPlay(); 19155 19156 _.$slider.trigger('reInit', [_]); 19157 19158 }; 19159 19160 Slick.prototype.resize = function() { 19161 19162 var _ = this; 19163 19164 if ($(window).width() !== _.windowWidth) { 19165 clearTimeout(_.windowDelay); 19166 _.windowDelay = window.setTimeout(function() { 19167 _.windowWidth = $(window).width(); 19168 _.checkResponsive(); 19169 if( !_.unslicked ) { _.setPosition(); } 19170 }, 50); 19171 } 19172 }; 19173 19174 Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) { 19175 19176 var _ = this; 19177 19178 if (typeof(index) === 'boolean') { 19179 removeBefore = index; 19180 index = removeBefore === true ? 0 : _.slideCount - 1; 19181 } else { 19182 index = removeBefore === true ? --index : index; 19183 } 19184 19185 if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) { 19186 return false; 19187 } 19188 19189 _.unload(); 19190 19191 if (removeAll === true) { 19192 _.$slideTrack.children().remove(); 19193 } else { 19194 _.$slideTrack.children(this.options.slide).eq(index).remove(); 19195 } 19196 19197 _.$slides = _.$slideTrack.children(this.options.slide); 19198 19199 _.$slideTrack.children(this.options.slide).detach(); 19200 19201 _.$slideTrack.append(_.$slides); 19202 19203 _.$slidesCache = _.$slides; 19204 19205 _.reinit(); 19206 19207 }; 19208 19209 Slick.prototype.setCSS = function(position) { 19210 19211 var _ = this, 19212 positionProps = {}, 19213 x, y; 19214 19215 if (_.options.rtl === true) { 19216 position = -position; 19217 } 19218 x = _.positionProp == 'left' ? Math.ceil(position) + 'px' : '0px'; 19219 y = _.positionProp == 'top' ? Math.ceil(position) + 'px' : '0px'; 19220 19221 positionProps[_.positionProp] = position; 19222 19223 if (_.transformsEnabled === false) { 19224 _.$slideTrack.css(positionProps); 19225 } else { 19226 positionProps = {}; 19227 if (_.cssTransitions === false) { 19228 positionProps[_.animType] = 'translate(' + x + ', ' + y + ')'; 19229 _.$slideTrack.css(positionProps); 19230 } else { 19231 positionProps[_.animType] = 'translate3d(' + x + ', ' + y + ', 0px)'; 19232 _.$slideTrack.css(positionProps); 19233 } 19234 } 19235 19236 }; 19237 19238 Slick.prototype.setDimensions = function() { 19239 19240 var _ = this; 19241 19242 if (_.options.vertical === false) { 19243 if (_.options.centerMode === true) { 19244 _.$list.css({ 19245 padding: ('0px ' + _.options.centerPadding) 19246 }); 19247 } 19248 } else { 19249 _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow); 19250 if (_.options.centerMode === true) { 19251 _.$list.css({ 19252 padding: (_.options.centerPadding + ' 0px') 19253 }); 19254 } 19255 } 19256 19257 _.listWidth = _.$list.width(); 19258 _.listHeight = _.$list.height(); 19259 19260 19261 if (_.options.vertical === false && _.options.variableWidth === false) { 19262 _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow); 19263 _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length))); 19264 19265 } else if (_.options.variableWidth === true) { 19266 _.$slideTrack.width(5000 * _.slideCount); 19267 } else { 19268 _.slideWidth = Math.ceil(_.listWidth); 19269 _.$slideTrack.height(Math.ceil((_.$slides.first().outerHeight(true) * _.$slideTrack.children('.slick-slide').length))); 19270 } 19271 19272 var offset = _.$slides.first().outerWidth(true) - _.$slides.first().width(); 19273 if (_.options.variableWidth === false) _.$slideTrack.children('.slick-slide').width(_.slideWidth - offset); 19274 19275 }; 19276 19277 Slick.prototype.setFade = function() { 19278 19279 var _ = this, 19280 targetLeft; 19281 19282 _.$slides.each(function(index, element) { 19283 targetLeft = (_.slideWidth * index) * -1; 19284 if (_.options.rtl === true) { 19285 $(element).css({ 19286 position: 'relative', 19287 right: targetLeft, 19288 top: 0, 19289 zIndex: _.options.zIndex - 2, 19290 opacity: 0 19291 }); 19292 } else { 19293 $(element).css({ 19294 position: 'relative', 19295 left: targetLeft, 19296 top: 0, 19297 zIndex: _.options.zIndex - 2, 19298 opacity: 0 19299 }); 19300 } 19301 }); 19302 19303 _.$slides.eq(_.currentSlide).css({ 19304 zIndex: _.options.zIndex - 1, 19305 opacity: 1 19306 }); 19307 19308 }; 19309 19310 Slick.prototype.setHeight = function() { 19311 19312 var _ = this; 19313 19314 if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) { 19315 var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true); 19316 _.$list.css('height', targetHeight); 19317 } 19318 19319 }; 19320 19321 Slick.prototype.setOption = 19322 Slick.prototype.slickSetOption = function() { 19323 19324 /** 19325 * accepts arguments in format of: 19326 * 19327 * - for changing a single option's value: 19328 * .slick("setOption", option, value, refresh ) 19329 * 19330 * - for changing a set of responsive options: 19331 * .slick("setOption", 'responsive', [{}, ...], refresh ) 19332 * 19333 * - for updating multiple values at once (not responsive) 19334 * .slick("setOption", { 'option': value, ... }, refresh ) 19335 */ 19336 19337 var _ = this, l, item, option, value, refresh = false, t
19337ype; 19338 19339 if( $.type( arguments[0] ) === 'object' ) { 19340 19341 option = arguments[0]; 19342 refresh = arguments[1]; 19343 type = 'multiple'; 19344 19345 } else if ( $.type( arguments[0] ) === 'string' ) { 19346 19347 option = arguments[0]; 19348 value = arguments[1]; 19349 refresh = arguments[2]; 19350 19351 if ( arguments[0] === 'responsive' && $.type( arguments[1] ) === 'array' ) { 19352 19353 type = 'responsive'; 19354 19355 } else if ( typeof arguments[1] !== 'undefined' ) { 19356 19357 type = 'single'; 19358 19359 } 19360 19361 } 19362 19363 if ( type === 'single' ) { 19364 19365 _.options[option] = value; 19366 19367 19368 } else if ( type === 'multiple' ) { 19369 19370 $.each( option , function( opt, val ) { 19371 19372 _.options[opt] = val; 19373 19374 }); 19375 19376 19377 } else if ( type === 'responsive' ) { 19378 19379 for ( item in value ) { 19380 19381 if( $.type( _.options.responsive ) !== 'array' ) { 19382 19383 _.options.responsive = [ value[item] ]; 19384 19385 } else { 19386 19387 l = _.options.responsive.length-1; 19388 19389 // loop through the responsive object and splice out duplicates. 19390 while( l >= 0 ) { 19391 19392 if( _.options.responsive[l].breakpoint === value[item].breakpoint ) { 19393 19394 _.options.responsive.splice(l,1); 19395 19396 } 19397 19398 l--; 19399 19400 } 19401 19402 _.options.responsive.push( value[item] ); 19403 19404 } 19405 19406 } 19407 19408 } 19409 19410 if ( refresh ) { 19411 19412 _.unload(); 19413 _.reinit(); 19414 19415 } 19416 19417 }; 19418 19419 Slick.prototype.setPosition = function() { 19420 19421 var _ = this; 19422 19423 _.setDimensions(); 19424 19425 _.setHeight(); 19426 19427 if (_.options.fade === false) { 19428 _.setCSS(_.getLeft(_.currentSlide)); 19429 } else { 19430 _.setFade(); 19431 } 19432 19433 _.$slider.trigger('setPosition', [_]); 19434 19435 }; 19436 19437 Slick.prototype.setProps = function() { 19438 19439 var _ = this, 19440 bodyStyle = document.body.style; 19441 19442 _.positionProp = _.options.vertical === true ? 'top' : 'left'; 19443 19444 if (_.positionProp === 'top') { 19445 _.$slider.addClass('slick-vertical'); 19446 } else { 19447 _.$slider.removeClass('slick-vertical'); 19448 } 19449 19450 if (bodyStyle.WebkitTransition !== undefined || 19451 bodyStyle.MozTransition !== undefined || 19452 bodyStyle.msTransition !== undefined) { 19453 if (_.options.useCSS === true) { 19454 _.cssTransitions = true; 19455 } 19456 } 19457 19458 if ( _.options.fade ) { 19459 if ( typeof _.options.zIndex === 'number' ) { 19460 if( _.options.zIndex < 3 ) { 19461 _.options.zIndex = 3; 19462 } 19463 } else { 19464 _.options.zIndex = _.defaults.zIndex; 19465 } 19466 } 19467 19468 if (bodyStyle.OTransform !== undefined) { 19469 _.animType = 'OTransform'; 19470 _.transformType = '-o-transform'; 19471 _.transitionType = 'OTransition'; 19472 if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
19473 } 19474 if (bodyStyle.MozTransform !== undefined) { 19475 _.animType = 'MozTransform'; 19476 _.transformType = '-moz-transform'; 19477 _.transitionType = 'MozTransition'; 19478 if (bodyStyle.perspectiveProperty === undefined && bodyStyle.MozPerspective === undefined) _.animType = false; 19479 } 19480 if (bodyStyle.webkitTransform !== undefined) { 19481 _.animType = 'webkitTransform'; 19482 _.transformType = '-webkit-transform'; 19483 _.transitionType = 'webkitTransition'; 19484 if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false; 19485 } 19486 if (bodyStyle.msTransform !== undefined) { 19487 _.animType = 'msTransform'; 19488 _.transformType = '-ms-transform'; 19489 _.transitionType = 'msTransition'; 19490 if (bodyStyle.msTransform === undefined) _.animType = false; 19491 } 19492 if (bodyStyle.transform !== undefined && _.animType !== false) { 19493 _.animType = 'transform'; 19494 _.transformType = 'transform'; 19495 _.transitionType = 'transition'; 19496 } 19497 _.transformsEnabled = _.options.useTransform && (_.animType !== null && _.animType !== false); 19498 }; 19499 19500 19501 Slick.prototype.setSlideClasses = function(index) { 19502 19503 var _ = this, 19504 centerOffset, allSlides, indexOffset, remainder; 19505 19506 allSlides = _.$slider 19507 .find('.slick-slide') 19508 .removeClass('slick-active slick-center slick-current') 19509 .attr('aria-hidden', 'true'); 19510 19511 _.$slides 19512 .eq(index) 19513 .addClass('slick-current'); 19514 19515 if (_.options.centerMode === true) { 19516 19517 var evenCoef = _.options.slidesToShow % 2 === 0 ? 1 : 0; 19518 19519 centerOffset = Math.floor(_.options.slidesToShow / 2); 19520 19521 if (_.options.infinite === true) { 19522 19523 if (index >= centerOffset && index <= (_.slideCount - 1) - centerOffset) { 19524 _.$slides 19525 .slice(index - centerOffset + evenCoef, index + centerOffset + 1) 19526 .addClass('slick-active') 19527 .attr('aria-hidden', 'false'); 19528 19529 } else { 19530 19531 indexOffset = _.options.slidesToShow + index; 19532 allSlides 19533 .slice(indexOffset - centerOffset + 1 + evenCoef, indexOffset + centerOffset + 2) 19534 .addClass('slick-active') 19535 .attr('aria-hidden', 'false'); 19536 19537 } 19538 19539 if (index === 0) { 19540 19541 allSlides 19542 .eq(allSlides.length - 1 - _.options.slidesToShow) 19543 .addClass('slick-center'); 19544 19545 } else if (index === _.slideCount - 1) { 19546 19547 allSlides 19548 .eq(_.options.slidesToShow) 19549 .addClass('slick-center'); 19550 19551 } 19552 19553 } 19554 19555 _.$slides 19556 .eq(index) 19557 .addClass('slick-center'); 19558 19559 } else { 19560 19561 if (index >= 0 && index <= (_.slideCount - _.options.slidesToShow)) { 19562 19563 _.$slides 19564 .slice(index, index + _.options.slidesToShow) 19565 .addClass('slick-active') 19566 .attr('aria-hidden', 'false'); 19567 19568 } else if (allSlides.length <= _.options.slidesToShow) { 19569 19570 allSlides 19571 .addClass('slick-active') 19572 .attr('aria-hidden', 'false'); 19573 19574 } else { 19575 19576 remainder = _.slideCount % _.options.slidesToShow; 19577 indexOffset = _.options.infinite === true ? _.options.slidesToShow + index : index; 19578 19579 if (_.options.slidesToShow == _.options.slidesToScroll && (_.slideCount - index) < _.options.slidesToShow) { 19580 19581 allSlides 19582 .slice(indexOffset - (_.options.slidesToShow - remainder), indexOffset + remainder) 19583 .addClass('slick-active') 19584 .attr('aria-hidden', 'false'); 19585 19586 } else { 19587 19588 allSlides 19589 .slice(indexOffset, indexOffset + _.options.slidesToShow) 19590 .addClass('slick-active') 19591 .attr('aria-hidden', 'false'); 19592 19593 } 19594 19595 } 19596 19597 } 19598 19599 if (_.options.lazyLoad === 'ondemand' || _.options.lazyLoad === 'anticipated') { 19600 _.lazyLoad(); 19601 } 19602 }; 19603 19604 Slick.prototype.setupInfinite = function() { 19605 19606 var _ = this, 19607 i, slideIndex, infiniteCount; 19608 19609 if (_.options.fade === true) {
19610 _.options.centerMode = false; 19611 } 19612 19613 if (_.options.infinite === true && _.options.fade === false) { 19614 19615 slideIndex = null; 19616 19617 if (_.slideCount > _.options.slidesToShow) { 19618 19619 if (_.options.centerMode === true) { 19620 infiniteCount = _.options.slidesToShow + 1; 19621 } else { 19622 infiniteCount = _.options.slidesToShow; 19623 } 19624 19625 for (i = _.slideCount; i > (_.slideCount - 19626 infiniteCount); i -= 1) { 19627 slideIndex = i - 1; 19628 $(_.$slides[slideIndex]).clone(true).attr('id', '') 19629 .attr('data-slick-index', slideIndex - _.slideCount) 19630 .prependTo(_.$slideTrack).addClass('slick-cloned'); 19631 } 19632 for (i = 0; i < infiniteCount + _.slideCount; i += 1) { 19633 slideIndex = i; 19634 $(_.$slides[slideIndex]).clone(true).attr('id', '') 19635 .attr('data-slick-index', slideIndex + _.slideCount) 19636 .appendTo(_.$slideTrack).addClass('slick-cloned'); 19637 } 19638 _.$slideTrack.find('.slick-cloned').find('[id]').each(function() { 19639 $(this).attr('id', ''); 19640 }); 19641 19642 } 19643 19644 } 19645 19646 }; 19647 19648 Slick.prototype.interrupt = function( toggle ) { 19649 19650 var _ = this; 19651 19652 if( !toggle ) { 19653 _.autoPlay(); 19654 } 19655 _.interrupted = toggle; 19656 19657 }; 19658 19659 Slick.prototype.selectHandler = function(event) { 19660 19661 var _ = this; 19662 19663 var targetElement = 19664 $(event.target).is('.slick-slide') ? 19665 $(event.target) : 19666 $(event.target).parents('.slick-slide'); 19667 19668 var index = parseInt(targetElement.attr('data-slick-index')); 19669 19670 if (!index) index = 0; 19671 19672 if (_.slideCount <= _.options.slidesToShow) { 19673 19674 _.slideHandler(index, false, true); 19675 return; 19676 19677 } 19678 19679 _.slideHandler(index); 19680 19681 }; 19682 19683 Slick.prototype.slideHandler = function(index, sync, dontAnimate) { 19684 19685 var targetSlide, animSlide, oldSlide, slideLeft, targetLeft = null, 19686 _ = this, navTarget; 19687 19688 sync = sync || false; 19689 19690 if (_.animating === true && _.options.waitForAnimate === true) { 19691 return; 19692 } 19693 19694 if (_.options.fade === true && _.currentSlide === index) { 19695 return; 19696 } 19697 19698 if (sync === false) { 19699 _.asNavFor(index); 19700 } 19701 19702 targetSlide = index; 19703 targetLeft = _.getLeft(targetSlide); 19704 slideLeft = _.getLeft(_.currentSlide); 19705 19706 _.currentLeft = _.swipeLeft === null ? slideLeft : _.swipeLeft; 19707 19708 if (_.options.infinite === false && _.options.centerMode === false && (index < 0 || index > _.getDotCount() * _.options.slidesToScroll)) { 19709 if (_.options.fade === false) { 19710 targetSlide = _.currentSlide; 19711 if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) { 19712 _.animateSlide(slideLeft, function() { 19713 _.postSlide(targetSlide); 19714 }); 19715 } else { 19716 _.postSlide(targetSlide); 19717 } 19718 } 19719 return; 19720 } else if (_.options.infinite === false && _.options.centerMode === true && (index < 0 || index > (_.slideCount - _.options.slidesToScroll))) { 19721 if (_.options.fade === false) { 19722 targetSlide = _.currentSlide; 19723 if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) { 19724 _.animateSlide(slideLeft, function() { 19725 _.postSlide(targetSlide); 19726 }); 19727 } else { 19728 _.postSlide(targetSlide); 19729 } 19730 } 19731 return; 19732 } 19733 19734 if ( _.options.autoplay ) { 19735 clearInterval(_.autoPlayTimer); 19736 } 19737 19738 if (targetSlide < 0) { 19739 if (_.slideCount % _.options.slidesToScroll !== 0) { 19740 animSlide = _.slideCount - (_.slideCount % _.options.slidesToScroll); 19741 } else { 19742 animSlide = _.slideCount + targetSlide; 19743 } 19744 }
19744 else if (targetSlide >= _.slideCount) { 19745 if (_.slideCount % _.options.slidesToScroll !== 0) { 19746 animSlide = 0; 19747 } else { 19748 animSlide = targetSlide - _.slideCount; 19749 } 19750 } else { 19751 animSlide = targetSlide; 19752 } 19753 19754 _.animating = true; 19755 19756 _.$slider.trigger('beforeChange', [_, _.currentSlide, animSlide]); 19757 19758 oldSlide = _.currentSlide; 19759 _.currentSlide = animSlide; 19760 19761 _.setSlideClasses(_.currentSlide); 19762 19763 if ( _.options.asNavFor ) { 19764 19765 navTarget = _.getNavTarget(); 19766 navTarget = navTarget.slick('getSlick'); 19767 19768 if ( navTarget.slideCount <= navTarget.options.slidesToShow ) { 19769 navTarget.setSlideClasses(_.currentSlide); 19770 } 19771 19772 } 19773 19774 _.updateDots(); 19775 _.updateArrows(); 19776 19777 if (_.options.fade === true) { 19778 if (dontAnimate !== true) { 19779 19780 _.fadeSlideOut(oldSlide); 19781 19782 _.fadeSlide(animSlide, function() { 19783 _.postSlide(animSlide); 19784 }); 19785 19786 } else { 19787 _.postSlide(animSlide); 19788 } 19789 _.animateHeight(); 19790 return; 19791 } 19792 19793 if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) { 19794 _.animateSlide(targetLeft, function() { 19795 _.postSlide(animSlide); 19796 }); 19797 } else { 19798 _.postSlide(animSlide); 19799 } 19800 19801 }; 19802 19803 Slick.prototype.startLoad = function() { 19804 19805 var _ = this; 19806 19807 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 19808 19809 _.$prevArrow.hide(); 19810 _.$nextArrow.hide(); 19811 19812 } 19813 19814 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 19815 19816 _.$dots.hide(); 19817 19818 } 19819 19820 _.$slider.addClass('slick-loading'); 19821 19822 }; 19823 19824 Slick.prototype.swipeDirection = function() { 19825 19826 var xDist, yDist, r, swipeAngle, _ = this; 19827 19828 xDist = _.touchObject.startX - _.touchObject.curX; 19829 yDist = _.touchObject.startY - _.touchObject.curY; 19830 r = Math.atan2(yDist, xDist); 19831 19832 swipeAngle = Math.round(r * 180 / Math.PI); 19833 if (swipeAngle < 0) { 19834 swipeAngle = 360 - Math.abs(swipeAngle); 19835 } 19836 19837 if ((swipeAngle <= 45) && (swipeAngle >= 0)) { 19838 return (_.options.rtl === false ? 'left' : 'right'); 19839 } 19840 if ((swipeAngle <= 360) && (swipeAngle >= 315)) { 19841 return (_.options.rtl === false ? 'left' : 'right'); 19842 } 19843 if ((swipeAngle >= 135) && (swipeAngle <= 225)) { 19844 return (_.options.rtl === false ? 'right' : 'left'); 19845 } 19846 if (_.options.verticalSwiping === true) { 19847 if ((swipeAngle >= 35) && (swipeAngle <= 135)) { 19848 return 'down'; 19849 } else { 19850 return 'up'; 19851 } 19852 } 19853 19854 return 'vertical'; 19855 19856 }; 19857 19858 Slick.prototype.swipeEnd = function(event) { 19859 19860 var _ = this, 19861 slideCount, 19862 direction; 19863 19864 _.dragging = false; 19865 _.swiping = false; 19866 19867 if (_.scrolling) { 19868 _.scrolling = false; 19869 return false; 19870 } 19871 19872 _.interrupted = false; 19873 _.shouldClick = ( _.touchObject.swipeLength > 10 ) ? false : true; 19874 19875 if ( _.touchObject.curX === undefined ) { 19876 return false; 19877 } 19878 19879 if ( _.touchObject.edgeHit === true ) { 19880 _.$slider.trigger('edge', [_, _.swipeDirection() ]); 19881 } 19882 19883 if ( _.touchObject.swipeLength >= _.touchObject.minSwipe ) { 19884 19885 direction = _.swipeDirection(); 19886 19887 switch ( direction ) { 19888 19889 case 'left': 19890 case 'down': 19891 19892 slideCount = 19893 _.options.swipeToSlide ? 19894 _.checkNavigable( _.currentSlide + _.getSlideCount() ) : 19895 _.currentSlide + _.getSlideCount(); 19896 19897 _.currentDirection = 0; 19898 19899 break; 19900 19901 case 'right': 19902 case 'up': 19903 19904 slideCount =
19905 _.options.swipeToSlide ? 19906 _.checkNavigable( _.currentSlide - _.getSlideCount() ) : 19907 _.currentSlide - _.getSlideCount(); 19908 19909 _.currentDirection = 1; 19910 19911 break; 19912 19913 default: 19914 19915 19916 } 19917 19918 if( direction != 'vertical' ) { 19919 19920 _.slideHandler( slideCount ); 19921 _.touchObject = {}; 19922 _.$slider.trigger('swipe', [_, direction ]); 19923 19924 } 19925 19926 } else { 19927 19928 if ( _.touchObject.startX !== _.touchObject.curX ) { 19929 19930 _.slideHandler( _.currentSlide ); 19931 _.touchObject = {}; 19932 19933 } 19934 19935 } 19936 19937 }; 19938 19939 Slick.prototype.swipeHandler = function(event) { 19940 19941 var _ = this; 19942 19943 if ((_.options.swipe === false) || ('ontouchend' in document && _.options.swipe === false)) { 19944 return; 19945 } else if (_.options.draggable === false && event.type.indexOf('mouse') !== -1) { 19946 return; 19947 } 19948 19949 _.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ? 19950 event.originalEvent.touches.length : 1; 19951 19952 _.touchObject.minSwipe = _.listWidth / _.options 19953 .touchThreshold; 19954 19955 if (_.options.verticalSwiping === true) { 19956 _.touchObject.minSwipe = _.listHeight / _.options 19957 .touchThreshold; 19958 } 19959 19960 switch (event.data.action) { 19961 19962 case 'start': 19963 _.swipeStart(event); 19964 break; 19965 19966 case 'move': 19967 _.swipeMove(event); 19968 break; 19969 19970 case 'end': 19971 _.swipeEnd(event); 19972 break; 19973 19974 } 19975 19976 }; 19977 19978 Slick.prototype.swipeMove = function(event) { 19979 19980 var _ = this, 19981 edgeWasHit = false, 19982 curLeft, swipeDirection, swipeLength, positionOffset, touches, verticalSwipeLength; 19983 19984 touches = event.originalEvent !== undefined ? event.originalEvent.touches : null; 19985 19986 if (!_.dragging || _.scrolling || touches && touches.length !== 1) { 19987 return false; 19988 } 19989 19990 curLeft = _.getLeft(_.currentSlide); 19991 19992 _.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX; 19993 _.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY; 19994 19995 _.touchObject.swipeLength = Math.round(Math.sqrt( 19996 Math.pow(_.touchObject.curX - _.touchObject.startX, 2))); 19997 19998 verticalSwipeLength = Math.round(Math.sqrt( 19999 Math.pow(_.touchObject.curY - _.touchObject.startY, 2))); 20000 20001 if (!_.options.verticalSwiping && !_.swiping && verticalSwipeLength > 4) { 20002 _.scrolling = true; 20003 return false; 20004 } 20005 20006 if (_.options.verticalSwiping === true) { 20007 _.touchObject.swipeLength = verticalSwipeLength; 20008 } 20009 20010 swipeDirection = _.swipeDirection(); 20011 20012 if (event.originalEvent !== undefined && _.touchObject.swipeLength > 4) { 20013 _.swiping = true; 20014 event.preventDefault(); 20015 } 20016 20017 positionOffset = (_.options.rtl === false ? 1 : -1) * (_.touchObject.curX > _.touchObject.startX ? 1 : -1); 20018 if (_.options.verticalSwiping === true) { 20019 positionOffset = _.touchObject.curY > _.touchObject.startY ? 1 : -1; 20020 } 20021 20022 20023 swipeLength = _.touchObject.swipeLength; 20024 20025 _.touchObject.edgeHit = false; 20026 20027 if (_.options.infinite === false) { 20028 if ((_.currentSlide === 0 && swipeDirection === 'right') || (_.currentSlide >= _.getDotCount() && swipeDirection === 'left')) { 20029 swipeLength = _.touchObject.swipeLength * _.options.edgeFriction; 20030 _.touchObject.edgeHit = true; 20031 } 20032 } 20033 20034 if (_.options.vertical === false) { 20035 _.swipeLeft = curLeft + swipeLength * positionOffset; 20036 } else { 20037 _.swipeLeft = curLeft + (swipeLength * (_.$list.height() / _.listWidth)) * positionOffset; 20038 } 20039 if (_.options.verticalSwiping === true) { 20040 _.swipeLeft = curLeft + swipeLength * positionOffset; 20041 } 20042 20043 if (_.options.fade === true || _.options.touchMove === false) { 20044 return false;
20045 } 20046 20047 if (_.animating === true) { 20048 _.swipeLeft = null; 20049 return false; 20050 } 20051 20052 _.setCSS(_.swipeLeft); 20053 20054 }; 20055 20056 Slick.prototype.swipeStart = function(event) { 20057 20058 var _ = this, 20059 touches; 20060 20061 _.interrupted = true; 20062 20063 if (_.touchObject.fingerCount !== 1 || _.slideCount <= _.options.slidesToShow) { 20064 _.touchObject = {}; 20065 return false; 20066 } 20067 20068 if (event.originalEvent !== undefined && event.originalEvent.touches !== undefined) { 20069 touches = event.originalEvent.touches[0]; 20070 } 20071 20072 _.touchObject.startX = _.touchObject.curX = touches !== undefined ? touches.pageX : event.clientX; 20073 _.touchObject.startY = _.touchObject.curY = touches !== undefined ? touches.pageY : event.clientY; 20074 20075 _.dragging = true; 20076 20077 }; 20078 20079 Slick.prototype.unfilterSlides = Slick.prototype.slickUnfilter = function() { 20080 20081 var _ = this; 20082 20083 if (_.$slidesCache !== null) { 20084 20085 _.unload(); 20086 20087 _.$slideTrack.children(this.options.slide).detach(); 20088 20089 _.$slidesCache.appendTo(_.$slideTrack); 20090 20091 _.reinit(); 20092 20093 } 20094 20095 }; 20096 20097 Slick.prototype.unload = function() { 20098 20099 var _ = this; 20100 20101 $('.slick-cloned', _.$slider).remove(); 20102 20103 if (_.$dots) { 20104 _.$dots.remove(); 20105 } 20106 20107 if (_.$prevArrow && _.htmlExpr.test(_.options.prevArrow)) { 20108 _.$prevArrow.remove(); 20109 } 20110 20111 if (_.$nextArrow && _.htmlExpr.test(_.options.nextArrow)) { 20112 _.$nextArrow.remove(); 20113 } 20114 20115 _.$slides 20116 .removeClass('slick-slide slick-active slick-visible slick-current') 20117 .attr('aria-hidden', 'true') 20118 .css('width', ''); 20119 20120 }; 20121 20122 Slick.prototype.unslick = function(fromBreakpoint) { 20123 20124 var _ = this; 20125 _.$slider.trigger('unslick', [_, fromBreakpoint]); 20126 _.destroy(); 20127 20128 }; 20129 20130 Slick.prototype.updateArrows = function() { 20131 20132 var _ = this, 20133 centerOffset; 20134 20135 centerOffset = Math.floor(_.options.slidesToShow / 2); 20136 20137 if ( _.options.arrows === true && 20138 _.slideCount > _.options.slidesToShow && 20139 !_.options.infinite ) { 20140 20141 _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 20142 _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 20143 20144 if (_.currentSlide === 0) { 20145 20146 _.$prevArrow.addClass('slick-disabled').attr('aria-disabled', 'true'); 20147 _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 20148 20149 } else if (_.currentSlide >= _.slideCount - _.options.slidesToShow && _.options.centerMode === false) { 20150 20151 _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true'); 20152 _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 20153 20154 } else if (_.currentSlide >= _.slideCount - 1 && _.options.centerMode === true) { 20155 20156 _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true'); 20157 _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 20158 20159 } 20160 20161 } 20162 20163 }; 20164 20165 Slick.prototype.updateDots = function() { 20166 20167 var _ = this; 20168 20169 if (_.$dots !== null) { 20170 20171 _.$dots 20172 .find('li') 20173 .removeClass('slick-active') 20174 .end(); 20175 20176 _.$dots 20177 .find('li') 20178 .eq(Math.floor(_.currentSlide / _.options.slidesToScroll)) 20179 .addClass('slick-active'); 20180 20181 } 20182 20183 }; 20184 20185 Slick.prototype.visibility = function() { 20186 20187 var _ = this; 20188 20189 if ( _.options.autoplay ) { 20190 20191 if ( document[_.hidden] ) { 20192 20193 _.interrupted = true; 20194 20195 } else { 20196 20197 _.interrupted = false; 20198 20199 } 20200 20201 } 20202 20203 }; 20204 20205 $.fn.slick = function() { 20206 var _ = this, 20207 opt = arguments[0], 20208 args = Array.prototype.slice.call(arguments, 1), 20209 l = _.length, 20210 i, 20211 ret; 20212 for (i = 0; i < l; i++) { 20213 if (typeof opt == 'object' || typeof opt == 'undefined') 20214 _[i].slick = new Slick(_[i], opt); 20215 else 20216 ret = _[i].slick[opt].apply(_[i].slick, args); 20217 if (typeof ret != 'undefined') return ret; 20218 } 20219 return _; 20220 }; 20221 20222})); 20223 20224/* flatpickr v4.6.9,, @license MIT */ 20225!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).flatpickr=t()}(this,(function(){"use strict";var e=function(){return(e=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)};function t(){for(var e=0,t=0,n=arguments.length;t<n;t++)e+=arguments[t].length;var a=Array(e),i=0;for(t=0;t<n;t++)for(var o=arguments[t],r=0,l=o.length;r<l;r++,i++)a[i]=o[r];return a}var n=["onChange","onClose","onDayCreate","onDestroy","onKeyDown","onMonthChange","onOpen","onParseConfig","onReady","onValueUpdate","onYearChange","onPreCalendarPosition"],a={_disable:[],allowInput:!1,allowInvalidPreload:!1,altFormat:"F j, Y",altInput:!1,altInputClass:"form-control input",animate:"object"==typeof window&&-1===window.navigator.userAgent.indexOf("MSIE"),ariaDateFormat:"F j, Y",autoFillDefaultTime:!0,clickOpens:!0,closeOnSelect:!0,conjunction:", ",dateFormat:"Y-m-d",defaultHour:12,defaultMinute:0,defaultSeconds:0,disable:[],disableMobile:!1,enableSeconds:!1,enableTime:!1,errorHandler:function(e){return"undefined"!=typeof console&&console.warn(e)},getWeek:function(e){var t=new Date(e.getTime());t.setHours(0,0,0,0),t.setDate(t.getDate()+3-(t.getDay()+6)%7);var n=new Date(t.getFullYear(),0,4);return 1+Math.round(((t.getTime()-n.getTime())/864e5-3+(n.getDay()+6)%7)/7)},hourIncrement:1,ignoredFocusElements:[],inline:!1,locale:"default",minuteIncrement:5,mode:"single",monthSelectorType:"dropdown",nextArrow:"<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewB
20225ox='0 0 17 17'><g></g><path d='M13.207 8.472l-7.854 7.854-0.707-0.707 7.146-7.146-7.146-7.148 0.707-0.707 7.854 7.854z' /></svg>",noCalendar:!1,now:new Date,onChange:[],onClose:[],onDayCreate:[],onDestroy:[],onKeyDown:[],onMonthChange:[],onOpen:[],onParseConfig:[],onReady:[],onValueUpdate:[],onYearChange:[],onPreCalendarPosition:[],plugins:[],position:"auto",positionElement:void 0,prevArrow:"<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 17 17'><g></g><path d='M5.207 8.471l7.146 7.147-0.707 0.707-7.853-7.854 7.854-7.853 0.707 0.707-7.147 7.146z' /></svg>",shorthandCurrentMonth:!1,showMonths:1,static:!1,time_24hr:!1,weekNumbers:!1,wrap:!1},i={weekdays:{shorthand:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],longhand:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},months:{shorthand:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],longhand:["January","February","March","April","May","June","July","August","September","October","November","December"]},daysInMonth:[31,28,31,30,31,30,31,31,30,31,30,31],firstDayOfWeek:0,ordinal:function(e){var t=e%100;if(t>3&&t<21)return"th";switch(t%10){case 1:return"st";case 2:return"nd";case 3:return"rd";default:return"th"}},rangeSeparator:" to ",weekAbbreviation:"Wk",scrollTitle:"Scroll to increment",toggleTitle:"Click to toggle",amPM:["AM","PM"],yearAriaLabel:"Year",monthAriaLabel:"Month",hourAriaLabel:"Hour",minuteAriaLabel:"Minute",time_24hr:!1},o=function(e,t){return void 0===t&&(t=2),("000"+e).slice(-1*t)},r=function(e){return!0===e?1:0};function l(e,t){var n;return function(){var a=this;clearTimeout(n),n=setTimeout((function(){return e.apply(a,arguments)}),t)}}var c=function(e){return e instanceof Array?e:[e]};function d(e,t,n){if(!0===n)return e.classList.add(t);e.classList.remove(t)}function s(e,t,n){var a=window.document.createElement(e);return t=t||"",n=n||"",a.className=t,void 0!==n&&(a.textContent=n),a}function u(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function f(e,t){return t(e)?e:e.parentNode?f(e.parentNode,t):void 0}function m(e,t){var n=s("div","numInputWrapper"),a=s("input","numInput "+e),i=s("span","arrowUp"),o=s("span","arrowDown");if(-1===navigator.userAgent.indexOf("MSIE 9.0")?a.type="number":(a.type="text",a.pattern="\\d*"),void 0!==t)for(var r in t)a.setAttribute(r,t[r]);return n.appendChild(a),n.appendChild(i),n.appendChild(o),n}function g(e){try{return"function"==typeof e.composedPath?e.composedPath()[0]:e.target}catch(t){return e.target}}var p=function(){},h=function(e,t,n){return n.months[t?"shorthand":"longhand"][e]},v={D:p,F:function(e,t,n){e.setMonth(n.months.longhand.indexOf(t))},G:function(e,t){e.setHours(parseFloat(t))},H:function(e,t){e.setHours(parseFloat(t))},J:function(e,t){e.setDate(parseFloat(t))},K:function(e,t,n){e.setHours(e.getHours()%12+12*r(new RegExp(n.amPM[1],"i").test(t)))},M:function(e,t,n){e.setMonth(n.months.shorthand.indexOf(t))},S:function(e,t){e.setSeconds(parseFloat(t))},U:function(e,t){return new Date(1e3*parseFloat(t))},W:function(e,t,n){var a=parseInt(t),i=new Date(e.getFullYear(),0,2+7*(a-1),0,0,0,0);return i.setDate(i.getDate()-i.getDay()+n.firstDayOfWeek),i},Y:function(e,t){e.setFullYear(parseFloat(t))},Z:function(e,t){return new Date(t)},d:function(e,t){e.setDate(parseFloat(t))},h:function(e,t){e.setHours(parseFloat(t))},i:function(e,t){e.setMinutes(parseFloat(t))},j:function(e,t){e.setDate(parseFloat(t))},l:p,m:function(e,t){e.setMonth(parseFloat(t)-1)},n:function(e,t){e.setMonth(parseFloat(t)-1)},s:function(e,t){e.setSeconds(parseFloat(t))},u:function(e,t){return new Date(parseFloat(t))},w:p,y:function(e,t){e.setFullYear(2e3+parseFloat(t))}},D={D:"(\\w+)",F:"(\\w+)",G:"(\\d\\d|\\d)",H:"(\\d\\d|\\d)",J:"(\\d\\d|\\d)\\w+",K:"",M:"(\\w+)",S:"(\\d\\d|\\d)",U:"(.+)",W:"(\\d\\d|\\d)",Y:"(\\d{4})",Z:"(.+)",d:"(\\d\\d|\\d)",h:"(\\d\\d|\\d)",i:"(\\d\\d|\\d)",j:"(\\d\\d|\\d)",l:"(\\w+)",m:"(\\d\\d|\\d)",n:"(\\d\\d|\\d)",s:"(\\d\\d|\\d)",u:"(.+)",w:"(\\d\\d|\\d)",y:"(\\d{2})"},w={Z:function(e){return e.toISOString()}
vendor: 8,740 bytes, line 20225
20225,D:function(e,t,n){return t.weekdays.shorthand[w.w(e,t,n)]},F:function(e,t,n){return h(w.n(e,t,n)-1,!1,t)},G:function(e,t,n){return o(w.h(e,t,n))},H:function(e){return o(e.getHours())},J:function(e,t){return void 0!==t.ordinal?e.getDate()+t.ordinal(e.getDate()):e.getDate()},K:function(e,t){return t.amPM[r(e.getHours()>11)]},M:function(e,t){return h(e.getMonth(),!0,t)},S:function(e){return o(e.getSeconds())},U:function(e){return e.getTime()/1e3},W:function(e,t,n){return n.getWeek(e)},Y:function(e){return o(e.getFullYear(),4)},d:function(e){return o(e.getDate())},h:function(e){return e.getHours()%12?e.getHours()%12:12},i:function(e){return o(e.getMinutes())},j:function(e){return e.getDate()},l:function(e,t){return t.weekdays.longhand[e.getDay()]},m:function(e){return o(e.getMonth()+1)},n:function(e){return e.getMonth()+1},s:function(e){return e.getSeconds()},u:function(e){return e.getTime()},w:function(e){return e.getDay()},y:function(e){return String(e.getFullYear()).substring(2)}},b=function(e){var t=e.config,n=void 0===t?a:t,o=e.l10n,r=void 0===o?i:o,l=e.isMobile,c=void 0!==l&&l;return function(e,t,a){var i=a||r;return void 0===n.formatDate||c?t.split("").map((function(t,a,o){return w[t]&&"\\"!==o[a-1]?w[t](e,i,n):"\\"!==t?t:""})).join(""):n.formatDate(e,t,i)}},C=function(e){var t=e.config,n=void 0===t?a:t,o=e.l10n,r=void 0===o?i:o;return function(e,t,i,o){if(0===e||e){var l,c=o||r,d=e;if(e instanceof Date)l=new Date(e.getTime());else if("string"!=typeof e&&void 0!==e.toFixed)l=new Date(e);else if("string"==typeof e){var s=t||(n||a).dateFormat,u=String(e).trim();if("today"===u)l=new Date,i=!0;else if(/Z$/.test(u)||/GMT$/.test(u))l=new Date(e);else if(n&&n.parseDate)l=n.parseDate(e,s);else{l=n&&n.noCalendar?new Date((new Date).setHours(0,0,0,0)):new Date((new Date).getFullYear(),0,1,0,0,0,0);for(var f=void 0,m=[],g=0,p=0,h="";g<s.length;g++){var w=s[g],b="\\"===w,C="\\"===s[g-1]||b;if(D[w]&&!C){h+=D[w];var M=new RegExp(h).exec(e);M&&(f=!0)&&m["Y"!==w?"push":"unshift"]({fn:v[w],val:M[++p]})}else b||(h+=".");m.forEach((function(e){var t=e.fn,n=e.val;return l=t(l,n,c)||l}))}l=f?l:void 0}}if(l instanceof Date&&!isNaN(l.getTime()))return!0===i&&l.setHours(0,0,0,0),l;n.errorHandler(new Error("Invalid date provided: "+d))}}};function M(e,t,n){return void 0===n&&(n=!0),!1!==n?new Date(e.getTime()).setHours(0,0,0,0)-new Date(t.getTime()).setHours(0,0,0,0):e.getTime()-t.getTime()}var y=864e5;function x(e){var t=e.defaultHour,n=e.defaultMinute,a=e.defaultSeconds;if(void 0!==e.minDate){var i=e.minDate.getHours(),o=e.minDate.getMinutes(),r=e.minDate.getSeconds();t<i&&(t=i),t===i&&n<o&&(n=o),t===i&&n===o&&a<r&&(a=e.minDate.getSeconds())}if(void 0!==e.maxDate){var l=e.maxDate.getHours(),c=e.maxDate.getMinutes();(t=Math.min(t,l))===l&&(n=Math.min(c,n)),t===l&&n===c&&(a=e.maxDate.getSeconds())}return{hours:t,minutes:n,seconds:a}}"function"!=typeof Object.assign&&(Object.assign=function(e){for(var t=[],n=1;n<arguments.length;n++)t[n-1]=arguments[n];if(!e)throw TypeError("Cannot convert undefined or null to object");for(var a=function(t){t&&Object.keys(t).forEach((function(n){return e[n]=t[n]}))},i=0,o=t;i<o.length;i++){var r=o[i];a(r)}return e});function E(p,v){var w={config:e(e({},a),T.defaultConfig),l10n:i};function E(e){return e.bind(w)}function k(){var e=w.config;!1===e.weekNumbers&&1===e.showMonths||!0!==e.noCalendar&&window.requestAnimationFrame((function(){if(void 0!==w.calendarContainer&&(w.calendarContainer.style.visibility="hidden",w.calendarContainer.style.display="block"),void 0!==w.daysContainer){var t=(w.days.offsetWidth+1)*e.showMonths;w.daysContainer.style.width=t+"px",w.calendarContainer.style.width=t+(void 0!==w.weekWrapper?w.weekWrapper.offsetWidth:0)+"px",w.calendarContainer.style.removeProperty("visibility"),w.calendarContainer.style.removeProperty("display")}}))}function I(e){if(0===w.selectedDates.length){var t=void 0===w.config.minDate||M(new Date,w.config.minDate)>=0?new Date:new Date(w.config.minDate.getTime()),n=x(w.config);t.setHours(n.hours,n.minutes,n.seconds,t.getMilliseconds()),w.selectedDates=[t],w.latestSelectedDateObj=t}void 0!==e&&"blur"!==e.type&&function(e){e.preventDefault();var t="keydown"===e.type,n=g(e),a=n;void 0!==w.amPM&&n===w.amPM&&(w.amPM.textContent=w.l10n.amPM[r(w.amPM.textContent===w.l10n.amPM[0])]);var i=parseFloat(a.getAttribute("min")),l=parseFloat(a.getAttribute("max")),c=parseFloat(a.getAttribute("step")),d=parseInt(a.value,10),s=e.delta||(t?38===e.which?1:-1:0),u=d+c*s;if(void 0!==a.value&&2===a.value.length){var f=a===w.hourElement,m=a===w.minuteElement;u<i?(u=l+u+r(!f)+(r(f)&&r(!w.amPM)),m&&j(void 0,-1,w.hourElement)):u>l&&(u=a===w.hourElement?u-l-r(!w.amPM):i,m&&j(void 0,1,w.hourElement)),w.amPM&&f&&(1===c?u+d===23:Math.abs(u-d)>c)&&(w.amPM.textContent=w.l10n.amPM[r(w.amPM.textContent===w.l10n.amPM[0])]),a.value=o(u)}}(e);var a=w._input.value;S(),be(),w._input.value!==a&&w._debouncedChange()}function S(){if(void 0!==w.hourElement&&void 0!==w.minuteElement){var e,t,n=(parseInt(w.hourElement.value.slice(-2),10)||0)%24,a=(parseInt(w.minuteElement.value,10)||0)%60,i=void 0!==w.secondElement?(parseInt(w.secondElement.value,10)||0)%60:0;void 0!==w.amPM&&(e=n,t=w.amPM.textContent,n=e%12+12*r(t===w.l10n.amPM[1]));var o=void 0!==w.config.minTime||w.config.minDate&&w.minDateHasTime&&w.latestSelectedDateObj&&0===M(w.latestSelectedDateObj,w.config.minDate,!0);if(void 0!==w.config.maxTime||w.config.maxDate&&w.maxDateHasTime&&w.latestSelectedDateObj&&0===M(w.latestSelectedDateObj,w.config.maxDate,!0)){var l=void 0!==w.config.maxTime?w.config.maxTime:w.config.maxDate;(n=Math.min(n,l.getHours()))===l.getHours()&&(a=Math.min(a,l.getMinutes())),a===l.getMinutes()&&(i=Math.min(i,l.getSeconds()))}if(o){var c=void 0!==w.config.minTime?w.config.minTime:w.config.minDate;(n=Math.max(n,c.getHours()))===c.getHours()&&a<c.getMinutes()&&(a=c.getMinutes()),a===c.getMinutes()&&(i=Math.max(i,c.getSeconds()))}O(n,a,i)}}function _(e){var t=e||w.latestSelectedDateObj;t&&O(t.getHours(),t.getMinutes(),t.getSeconds())}function O(e,t,n){void 0!==w.latestSelectedDateObj&&w.latestSelectedDateObj.setHours(e%24,t,n||0,0),w.hourElement&&w.minuteElement&&!w.isMobile&&(w.hourElement.value=o(w.config.time_24hr?e:(12+e)%12+12*r(e%12==0)),w.minuteElement.value=o(t),void 0!==w.amPM&&(w.amPM.textContent=w.l10n.amPM[r(e>=12)]),void 0!==w.secondElement&&(w.secondElement.value=o(n)))}function F(e){var t=g(e),n=parseInt(t.value)+(e.delta||0);(n/1e3>1||"Enter"===e.key&&!/[^\d]/.test(n.toString()))&&Q(n)}function A(e,t,n,a){return t instanceof Array?t.forEach((function(t){return A(e,t,n,a)})):e instanceof Array?e.forEach((function(e){return A(e,t,n,a)})):(e.addEventListener(t,n,a),void w._handlers.push({remove:function(){return e.removeEventListener(t,n)}}))}function N(){pe("onChange")}function P(e,t){var n=void 0!==e?w.parseDate(e):w.latestSelectedDateObj||(w.config.minDate&&w.config.minDate>w.now?w.config.minDate:w.config.maxDate&&w.config.maxDate<w.now?w.config.maxDate:w.now),a=w.currentYear,i=w.currentMonth;try{void 0!==n&&(w.currentYear=n.getFullYear(),w.currentMonth=n.getMonth())}catch(e){e.message="Invalid date supplied: "+n,w.config.errorHandler(e)}t&&w.currentYear!==a&&(pe("onYearChange"),K()),!t||w.currentYear===a&&w.currentMonth===i||pe("onMonthChange"),w.redraw()}function Y(e){var t=g(e);~t.className.indexOf("arrow")&&j(e,t.classList.contains("arrowUp")?1:-1)}function j(e,t,n){var a=e&&g(e),i=n||a&&a.parentNode&&a.parentNode.firstChild,o=he("increment");o.delta=t,i&&i.dispatchEvent(o)}function H(e,t,n,a){var i=X(t,!0),o=s("span","flatpickr-day "+e,t.getDate().toString());return o.dateObj=t,o.$i=a,o.setAttribute("aria-label",w.formatDate(t,w.config.ariaDateFormat)),-1===e.indexOf("hidden")&&0===M(t,w.now)&&(w.todayDateElem=o,o.classList.add("today"),o.setAttribute("aria-current","date")),i?(o.tabIndex=-1,ve(t)&&(o.classList.add("selected"),w.selectedDateElem=o,"range"===w.config.mode&&(d(o,"startRange",w.selectedDates[0]&&0===M(t,w.selectedDates[0],!0)),d(o,"endRange",w.selectedDates[1]&&0===M(t,w.selectedDates[1],!0)),"nextMonthDay"===e&&o.classList.add("inRange")))):o.classList.add("flatpickr-disabled"),"range"===w.config.mode&&function(e){return!("range"!==w.config.mode||w.selectedDates.length<2)&&(M(e,w.selectedDates[0])>=0&&M(e,w.selectedDates[1])<=0)}(t)&&!ve(t)&&o.classList.add("inRange"),w.weekNumbers&&1===w.config.showMonths&&"prevMonthDay"!==e&&n%7==1&&w.weekNumbers.insertAdjacentHTML("beforeend","<span class='flatpickr-day'>"+w.config.getWeek(t)+"</span>"),pe("onDayCreate",o),o}function L(e){e.focus(),"range"===w.config.mode&&ae(e)}function W(e){for(var t=e>0?0:w.config.showMonths-1,n=e>0?w.config.showMonths:-1,a=t;a!=n;a+=e)for(var i=w.daysContainer.children[a],o=e>
vendor: 4,379 bytes, line 20225
202250?0:i.children.length-1,r=e>0?i.children.length:-1,l=o;l!=r;l+=e){var c=i.children[l];if(-1===c.className.indexOf("hidden")&&X(c.dateObj))return c}}function R(e,t){var n=ee(document.activeElement||document.body),a=void 0!==e?e:n?document.activeElement:void 0!==w.selectedDateElem&&ee(w.selectedDateElem)?w.selectedDateElem:void 0!==w.todayDateElem&&ee(w.todayDateElem)?w.todayDateElem:W(t>0?1:-1);void 0===a?w._input.focus():n?function(e,t){for(var n=-1===e.className.indexOf("Month")?e.dateObj.getMonth():w.currentMonth,a=t>0?w.config.showMonths:-1,i=t>0?1:-1,o=n-w.currentMonth;o!=a;o+=i)for(var r=w.daysContainer.children[o],l=n-w.currentMonth===o?e.$i+t:t<0?r.children.length-1:0,c=r.children.length,d=l;d>=0&&d<c&&d!=(t>0?c:-1);d+=i){var s=r.children[d];if(-1===s.className.indexOf("hidden")&&X(s.dateObj)&&Math.abs(e.$i-d)>=Math.abs(t))return L(s)}w.changeMonth(i),R(W(i),0)}(a,t):L(a)}function B(e,t){for(var n=(new Date(e,t,1).getDay()-w.l10n.firstDayOfWeek+7)%7,a=w.utils.getDaysInMonth((t-1+12)%12,e),i=w.utils.getDaysInMonth(t,e),o=window.document.createDocumentFragment(),r=w.config.showMonths>1,l=r?"prevMonthDay hidden":"prevMonthDay",c=r?"nextMonthDay hidden":"nextMonthDay",d=a+1-n,u=0;d<=a;d++,u++)o.appendChild(H(l,new Date(e,t-1,d),d,u));for(d=1;d<=i;d++,u++)o.appendChild(H("",new Date(e,t,d),d,u));for(var f=i+1;f<=42-n&&(1===w.config.showMonths||u%7!=0);f++,u++)o.appendChild(H(c,new Date(e,t+1,f%i),f,u));var m=s("div","dayContainer");return m.appendChild(o),m}function J(){if(void 0!==w.daysContainer){u(w.daysContainer),w.weekNumbers&&u(w.weekNumbers);for(var e=document.createDocumentFragment(),t=0;t<w.config.showMonths;t++){var n=new Date(w.currentYear,w.currentMonth,1);n.setMonth(w.currentMonth+t),e.appendChild(B(n.getFullYear(),n.getMonth()))}w.daysContainer.appendChild(e),w.days=w.daysContainer.firstChild,"range"===w.config.mode&&1===w.selectedDates.length&&ae()}}function K(){if(!(w.config.showMonths>1||"dropdown"!==w.config.monthSelectorType)){var e=function(e){return!(void 0!==w.config.minDate&&w.currentYear===w.config.minDate.getFullYear()&&e<w.config.minDate.getMonth())&&!(void 0!==w.config.maxDate&&w.currentYear===w.config.maxDate.getFullYear()&&e>w.config.maxDate.getMonth())};w.monthsDropdownContainer.tabIndex=-1,w.monthsDropdownContainer.innerHTML="";for(var t=0;t<12;t++)if(e(t)){var n=s("option","flatpickr-monthDropdown-month");n.value=new Date(w.currentYear,t).getMonth().toString(),n.textContent=h(t,w.config.shorthandCurrentMonth,w.l10n),n.tabIndex=-1,w.currentMonth===t&&(n.selected=!0),w.monthsDropdownContainer.appendChild(n)}}}function U(){var e,t=s("div","flatpickr-month"),n=window.document.createDocumentFragment();w.config.showMonths>1||"static"===w.config.monthSelectorType?e=s("span","cur-month"):(w.monthsDropdownContainer=s("select","flatpickr-monthDropdown-months"),w.monthsDropdownContainer.setAttribute("aria-label",w.l10n.monthAriaLabel),A(w.monthsDropdownContainer,"change",(function(e){var t=g(e),n=parseInt(t.value,10);w.changeMonth(n-w.currentMonth),pe("onMonthChange")})),K(),e=w.monthsDropdownContainer);var a=m("cur-year",{tabindex:"-1"}),i=a.getElementsByTagName("input")[0];i.setAttribute("aria-label",w.l10n.yearAriaLabel),w.config.minDate&&i.setAttribute("min",w.config.minDate.getFullYear().toString()),w.config.maxDate&&(i.setAttribute("max",w.config.maxDate.getFullYear().toString()),i.disabled=!!w.config.minDate&&w.config.minDate.getFullYear()===w.config.maxDate.getFullYear());var o=s("div","flatpickr-current-month");return o.appendChild(e),o.appendChild(a),n.appendChild(o),t.appendChild(n),{container:t,yearElement:i,monthElement:e}}function q(){u(w.monthNav),w.monthNav.appendChild(w.prevMonthNav),w.config.showMonths&&(w.yearElements=[],w.monthElements=[]);for(var e=w.config.showMonths;e--;){var t=U();w.yearElements.push(t.yearElement),w.monthElements.push(t.monthElement),w.monthNav.appendChild(t.container)}w.monthNav.appendChild(w.nextMonthNav)}function $(){w.weekdayContainer?u(w.weekdayContainer):w.weekdayContainer=s("div","flatpickr-weekdays");for(var e=w.config.showMonths;e--;){var t=s("div","flatpickr-weekdaycontainer");w.weekdayContainer.appendChild(t)}return z(),w.weekdayContainer}function z(){if(w.weekdayContainer){var e=w.l10n.firstDayOfWeek,n=t(w.l10n.weekdays.shorthand);e>0&&e<n.length&&(n=t(n.splice(e,n.length),n.splice(0,e)));for(var a=w.config.showMonths;a--;
vendor: 7,596 bytes, line 20225
20225)w.weekdayContainer.children[a].innerHTML="\n <span class='flatpickr-weekday'>\n "+n.join("</span><span class='flatpickr-weekday'>")+"\n </span>\n "}}function G(e,t){void 0===t&&(t=!0);var n=t?e:e-w.currentMonth;n<0&&!0===w._hidePrevMonthArrow||n>0&&!0===w._hideNextMonthArrow||(w.currentMonth+=n,(w.currentMonth<0||w.currentMonth>11)&&(w.currentYear+=w.currentMonth>11?1:-1,w.currentMonth=(w.currentMonth+12)%12,pe("onYearChange"),K()),J(),pe("onMonthChange"),De())}function V(e){return!(!w.config.appendTo||!w.config.appendTo.contains(e))||w.calendarContainer.contains(e)}function Z(e){if(w.isOpen&&!w.config.inline){var t=g(e),n=V(t),a=t===w.input||t===w.altInput||w.element.contains(t)||e.path&&e.path.indexOf&&(~e.path.indexOf(w.input)||~e.path.indexOf(w.altInput)),i="blur"===e.type?a&&e.relatedTarget&&!V(e.relatedTarget):!a&&!n&&!V(e.relatedTarget),o=!w.config.ignoredFocusElements.some((function(e){return e.contains(t)}));i&&o&&(void 0!==w.timeContainer&&void 0!==w.minuteElement&&void 0!==w.hourElement&&""!==w.input.value&&void 0!==w.input.value&&I(),w.close(),w.config&&"range"===w.config.mode&&1===w.selectedDates.length&&(w.clear(!1),w.redraw()))}}function Q(e){if(!(!e||w.config.minDate&&e<w.config.minDate.getFullYear()||w.config.maxDate&&e>w.config.maxDate.getFullYear())){var t=e,n=w.currentYear!==t;w.currentYear=t||w.currentYear,w.config.maxDate&&w.currentYear===w.config.maxDate.getFullYear()?w.currentMonth=Math.min(w.config.maxDate.getMonth(),w.currentMonth):w.config.minDate&&w.currentYear===w.config.minDate.getFullYear()&&(w.currentMonth=Math.max(w.config.minDate.getMonth(),w.currentMonth)),n&&(w.redraw(),pe("onYearChange"),K())}}function X(e,t){var n;void 0===t&&(t=!0);var a=w.parseDate(e,void 0,t);if(w.config.minDate&&a&&M(a,w.config.minDate,void 0!==t?t:!w.minDateHasTime)<0||w.config.maxDate&&a&&M(a,w.config.maxDate,void 0!==t?t:!w.maxDateHasTime)>0)return!1;if(!w.config.enable&&0===w.config.disable.length)return!0;if(void 0===a)return!1;for(var i=!!w.config.enable,o=null!==(n=w.config.enable)&&void 0!==n?n:w.config.disable,r=0,l=void 0;r<o.length;r++){if("function"==typeof(l=o[r])&&l(a))return i;if(l instanceof Date&&void 0!==a&&l.getTime()===a.getTime())return i;if("string"==typeof l){var c=w.parseDate(l,void 0,!0);return c&&c.getTime()===a.getTime()?i:!i}if("object"==typeof l&&void 0!==a&&l.from&&l.to&&a.getTime()>=l.from.getTime()&&a.getTime()<=l.to.getTime())return i}return!i}function ee(e){return void 0!==w.daysContainer&&(-1===e.className.indexOf("hidden")&&-1===e.className.indexOf("flatpickr-disabled")&&w.daysContainer.contains(e))}function te(e){!(e.target===w._input)||!(w.selectedDates.length>0||w._input.value.length>0)||e.relatedTarget&&V(e.relatedTarget)||w.setDate(w._input.value,!0,e.target===w.altInput?w.config.altFormat:w.config.dateFormat)}function ne(e){var t=g(e),n=w.config.wrap?p.contains(t):t===w._input,a=w.config.allowInput,i=w.isOpen&&(!a||!n),o=w.config.inline&&n&&!a;if(13===e.keyCode&&n){if(a)return w.setDate(w._input.value,!0,t===w.altInput?w.config.altFormat:w.config.dateFormat),t.blur();w.open()}else if(V(t)||i||o){var r=!!w.timeContainer&&w.timeContainer.contains(t);switch(e.keyCode){case 13:r?(e.preventDefault(),I(),se()):ue(e);break;case 27:e.preventDefault(),se();break;case 8:case 46:n&&!w.config.allowInput&&(e.preventDefault(),w.clear());break;case 37:case 39:if(r||n)w.hourElement&&w.hourElement.focus();else if(e.preventDefault(),void 0!==w.daysContainer&&(!1===a||document.activeElement&&ee(document.activeElement))){var l=39===e.keyCode?1:-1;e.ctrlKey?(e.stopPropagation(),G(l),R(W(1),0)):R(void 0,l)}break;case 38:case 40:e.preventDefault();var c=40===e.keyCode?1:-1;w.daysContainer&&void 0!==t.$i||t===w.input||t===w.altInput?e.ctrlKey?(e.stopPropagation(),Q(w.currentYear-c),R(W(1),0)):r||R(void 0,7*c):t===w.currentYearElement?Q(w.currentYear-c):w.config.enableTime&&(!r&&w.hourElement&&w.hourElement.focus(),I(e),w._debouncedChange());break;case 9:if(r){var d=[w.hourElement,w.minuteElement,w.secondElement,w.amPM].concat(w.pluginElements).filter((function(e){return e})),s=d.indexOf(t);if(-1!==s){var u=d[s+(e.shiftKey?-1:1)];e.preventDefault(),(u||w._input).focus()}}else!w.config.noCalendar&&w.daysContainer&&w.daysContainer.contains(t)&&e.shiftKey&&(e.preventDefault(),w._input.focus())}}if(void 0!==w.amPM&&t===w.amPM)switch(e.key){case w.l10n.amPM[0].charAt(0):case w.l10n.amPM[0].charAt(0).toLowerCase():w.amPM.textContent=w.l10n.amPM[0],S(),be();break;case w.l10n.amPM[1].charAt(0):case w.l10n.amPM[1].charAt(0).toLowerCase():w.amPM.textContent=w.l10n.amPM[1],S(),be()}(n||V(t))&&pe("onKeyDown",e)}function ae(e){if(1===w.selectedDates.length&&(!e||e.classList.contains("flatpickr-day")&&!e.classList.contains("flatpickr-disabled"))){for(var t=e?e.dateObj.getTime():w.days.firstElementChild.dateObj.getTime(),n=w.parseDate(w.selectedDates[0],void 0,!0).getTime(),a=Math.min(t,w.selectedDates[0].getTime()),i=Math.max(t,w.selectedDates[0].getTime()),o=!1,r=0,l=0,c=a;c<i;c+=y)X(new Date(c),!0)||(o=o||c>a&&c<i,c<n&&(!r||c>r)?r=c:c>n&&(!l||c<l)&&(l=c));for(var d=0;d<w.config.showMonths;d++)for(var s=w.daysContainer.children[d],u=function(a,i){var c,d,u,f=s.children[a],m=f.dateObj.getTime(),g=r>0&&m<r||l>0&&m>l;return g?(f.classList.add("notAllowed"),["inRange","startRange","endRange"].forEach((function(e){f.classList.remove(e)})),"continue"):o&&!g?"continue":(["startRange","inRange","endRange","notAllowed"].forEach((function(e){f.classList.remove(e)})),void(void 0!==e&&(e.classList.add(t<=w.selectedDates[0].getTime()?"startRange":"endRange"),n<t&&m===n?f.classList.add("startRange"):n>t&&m===n&&f.classList.add("endRange"),m>=r&&(0===l||m<=l)&&(d=n,u=t,(c=m)>Math.min(d,u)&&c<Math.max(d,u))&&f.classList.add("inRange"))))},f=0,m=s.children.length;f<m;f++)u(f)}}function ie(){!w.isOpen||w.config.static||w.config.inline||ce()}function oe(e){return function(t){var n=w.config["_"+e+"Date"]=w.parseDate(t,w.config.dateFormat),a=w.config["_"+("min"===e?"max":"min")+"Date"];void 0!==n&&(w["min"===e?"minDateHasTime":"maxDateHasTime"]=n.getHours()>0||n.getMinutes()>0||n.getSeconds()>0),w.selectedDates&&(w.selectedDates=w.selectedDates.filter((function(e){return X(e)})),w.selectedDates.length||"min"!==e||_(n),be()),w.daysContainer&&(de(),void 0!==n?w.currentYearElement[e]=n.getFullYear().toString():w.currentYearElement.removeAttribute(e),w.currentYearElement.disabled=!!a&&void 0!==n&&a.getFullYear()===n.getFullYear())}}function re(){return w.config.wrap?p.querySelector("[data-input]"):p}function le(){"object"!=typeof w.config.locale&&void 0===T.l10ns[w.config.locale]&&w.config.errorHandler(new Error("flatpickr: invalid locale "+w.config.locale)),w.l10n=e(e({},T.l10ns.default),"object"==typeof w.config.locale?w.config.locale:"default"!==w.config.locale?T.l10ns[w.config.locale]:void 0),D.K="("+w.l10n.amPM[0]+"|"+w.l10n.amPM[1]+"|"+w.l10n.amPM[0].toLowerCase()+"|"+w.l10n.amPM[1].toLowerCase()+")",void 0===e(e({},v),JSON.parse(JSON.stringify(p.dataset||{}))).time_24hr&&void 0===T.defaultConfig.time_24hr&&(w.config.time_24hr=w.l10n.time_24hr),w.formatDate=b(w),w.parseDate=C({config:w.config,l10n:w.l10n})}function ce(e){if("function"!=typeof w.config.position){if(void 0!==w.calendarContainer){pe("onPreCalendarPosition");var t=e||w._positionElement,n=Array.prototype.reduce.call(w.calendarContainer.children,(function(e,t){return e+t.offsetHeight}),0),a=w.calendarContainer.offsetWidth,i=w.config.position.split(" "),o=i[0],r=i.length>1?i[1]:null,l=t.getBoundingClientRect(),c=window.innerHeight-l.bottom,s="above"===o||"below"!==o&&c<n&&l.to
vendor: 21,416 bytes, line 20225
20225p>n,u=window.pageYOffset+l.top+(s?-n-2:t.offsetHeight+2);if(d(w.calendarContainer,"arrowTop",!s),d(w.calendarContainer,"arrowBottom",s),!w.config.inline){var f=window.pageXOffset+l.left,m=!1,g=!1;"center"===r?(f-=(a-l.width)/2,m=!0):"right"===r&&(f-=a-l.width,g=!0),d(w.calendarContainer,"arrowLeft",!m&&!g),d(w.calendarContainer,"arrowCenter",m),d(w.calendarContainer,"arrowRight",g);var p=window.document.body.offsetWidth-(window.pageXOffset+l.right),h=f+a>window.document.body.offsetWidth,v=p+a>window.document.body.offsetWidth;if(d(w.calendarContainer,"rightMost",h),!w.config.static)if(w.calendarContainer.style.top=u+"px",h)if(v){var D=function(){for(var e=null,t=0;t<document.styleSheets.length;t++){var n=document.styleSheets[t];try{n.cssRules}catch(e){continue}e=n;break}return null!=e?e:(a=document.createElement("style"),document.head.appendChild(a),a.sheet);var a}();if(void 0===D)return;var b=window.document.body.offsetWidth,C=Math.max(0,b/2-a/2),M=D.cssRules.length,y="{left:"+l.left+"px;right:auto;}";d(w.calendarContainer,"rightMost",!1),d(w.calendarContainer,"centerMost",!0),D.insertRule(".flatpickr-calendar.centerMost:before,.flatpickr-calendar.centerMost:after"+y,M),w.calendarContainer.style.left=C+"px",w.calendarContainer.style.right="auto"}else w.calendarContainer.style.left="auto",w.calendarContainer.style.right=p+"px";else w.calendarContainer.style.left=f+"px",w.calendarContainer.style.right="auto"}}}else w.config.position(w,e)}function de(){w.config.noCalendar||w.isMobile||(K(),De(),J())}function se(){w._input.focus(),-1!==window.navigator.userAgent.indexOf("MSIE")||void 0!==navigator.msMaxTouchPoints?setTimeout(w.close,0):w.close()}function ue(e){e.preventDefault(),e.stopPropagation();var t=f(g(e),(function(e){return e.classList&&e.classList.contains("flatpickr-day")&&!e.classList.contains("flatpickr-disabled")&&!e.classList.contains("notAllowed")}));if(void 0!==t){var n=t,a=w.latestSelectedDateObj=new Date(n.dateObj.getTime()),i=(a.getMonth()<w.currentMonth||a.getMonth()>w.currentMonth+w.config.showMonths-1)&&"range"!==w.config.mode;if(w.selectedDateElem=n,"single"===w.config.mode)w.selectedDates=[a];else if("multiple"===w.config.mode){var o=ve(a);o?w.selectedDates.splice(parseInt(o),1):w.selectedDates.push(a)}else"range"===w.config.mode&&(2===w.selectedDates.length&&w.clear(!1,!1),w.latestSelectedDateObj=a,w.selectedDates.push(a),0!==M(a,w.selectedDates[0],!0)&&w.selectedDates.sort((function(e,t){return e.getTime()-t.getTime()})));if(S(),i){var r=w.currentYear!==a.getFullYear();w.currentYear=a.getFullYear(),w.currentMonth=a.getMonth(),r&&(pe("onYearChange"),K()),pe("onMonthChange")}if(De(),J(),be(),i||"range"===w.config.mode||1!==w.config.showMonths?void 0!==w.selectedDateElem&&void 0===w.hourElement&&w.selectedDateElem&&w.selectedDateElem.focus():L(n),void 0!==w.hourElement&&void 0!==w.hourElement&&w.hourElement.focus(),w.config.closeOnSelect){var l="single"===w.config.mode&&!w.config.enableTime,c="range"===w.config.mode&&2===w.selectedDates.length&&!w.config.enableTime;(l||c)&&se()}N()}}w.parseDate=C({config:w.config,l10n:w.l10n}),w._handlers=[],w.pluginElements=[],w.loadedPlugins=[],w._bind=A,w._setHoursFromDate=_,w._positionCalendar=ce,w.changeMonth=G,w.changeYear=Q,w.clear=function(e,t){void 0===e&&(e=!0);void 0===t&&(t=!0);w.input.value="",void 0!==w.altInput&&(w.altInput.value="");void 0!==w.mobileInput&&(w.mobileInput.value="");w.selectedDates=[],w.latestSelectedDateObj=void 0,!0===t&&(w.currentYear=w._initialDate.getFullYear(),w.currentMonth=w._initialDate.getMonth());if(!0===w.config.enableTime){var n=x(w.config),a=n.hours,i=n.minutes,o=n.seconds;O(a,i,o)}w.redraw(),e&&pe("onChange")},w.close=function(){w.isOpen=!1,w.isMobile||(void 0!==w.calendarContainer&&w.calendarContainer.classList.remove("open"),void 0!==w._input&&w._input.classList.remove("active"));pe("onClose")},w._createElement=s,w.destroy=function(){void 0!==w.config&&pe("onDestroy");for(var e=w._handlers.length;e--;)w._handlers[e].remove();if(w._handlers=[],w.mobileInput)w.mobileInput.parentNode&&w.mobileInput.parentNode.removeChild(w.mobileInput),w.mobileInput=void 0;else if(w.calendarContainer&&w.calendarContainer.parentNode)if(w.config.static&&w.calendarContainer.parentNode){var t=w.calendarContainer.parentNode;if(t.lastChild&&t.removeChild(t.lastChild),t.parentNode){for(;t.firstChild;)t.parentNode.insertBefore(t.firstChild,t);t.parentNode.removeChild(t)}}else w.calendarContainer.parentNode.removeChild(w.calendarContainer);w.altInput&&(w.input.type="text",w.altInput.parentNode&&w.altInput.parentNode.removeChild(w.altInput),delete w.altInput);w.input&&(w.input.type=w.input._type,w.input.classList.remove("flatpickr-input"),w.input.removeAttribute("readonly"));["_showTimeInput","latestSelectedDateObj","_hideNextMonthArrow","_hidePrevMonthArrow","__hideNextMonthArrow","__hidePrevMonthArrow","isMobile","isOpen","selectedDateElem","minDateHasTime","maxDateHasTime","days","daysContainer","_input","_positionElement","innerContainer","rContainer","monthNav","todayDateElem","calendarContainer","weekdayContainer","prevMonthNav","nextMonthNav","monthsDropdownContainer","currentMonthElement","currentYearElement","navigationCurrentMonth","selectedDateElem","config"].forEach((function(e){try{delete w[e]}catch(e){}}))},w.isEnabled=X,w.jumpToDate=P,w.open=function(e,t){void 0===t&&(t=w._positionElement);if(!0===w.isMobile){if(e){e.preventDefault();var n=g(e);n&&n.blur()}return void 0!==w.mobileInput&&(w.mobileInput.focus(),w.mobileInput.click()),void pe("onOpen")}if(w._input.disabled||w.config.inline)return;var a=w.isOpen;w.isOpen=!0,a||(w.calendarContainer.classList.add("open"),w._input.classList.add("active"),pe("onOpen"),ce(t));!0===w.config.enableTime&&!0===w.config.noCalendar&&(!1!==w.config.allowInput||void 0!==e&&w.timeContainer.contains(e.relatedTarget)||setTimeout((function(){return w.hourElement.select()}),50))},w.redraw=de,w.set=function(e,t){if(null!==e&&"object"==typeof e)for(var a in Object.assign(w.config,e),e)void 0!==fe[a]&&fe[a].forEach((function(e){return e()}));else w.config[e]=t,void 0!==fe[e]?fe[e].forEach((function(e){return e()})):n.indexOf(e)>-1&&(w.config[e]=c(t));w.redraw(),be(!0)},w.setDate=function(e,t,n){void 0===t&&(t=!1);void 0===n&&(n=w.config.dateFormat);if(0!==e&&!e||e instanceof Array&&0===e.length)return w.clear(t);me(e,n),w.latestSelectedDateObj=w.selectedDates[w.selectedDates.length-1],w.redraw(),P(void 0,t),_(),0===w.selectedDates.length&&w.clear(!1);be(t),t&&pe("onChange")},w.toggle=function(e){if(!0===w.isOpen)return w.close();w.open(e)};var fe={locale:[le,z],showMonths:[q,k,$],minDate:[P],maxDate:[P],clickOpens:[function(){!0===w.config.clickOpens?(A(w._input,"focus",w.open),A(w._input,"click",w.open)):(w._input.removeEventListener("focus",w.open),w._input.removeEventListener("click",w.open))}]};function me(e,t){var n=[];if(e instanceof Array)n=e.map((function(e){return w.parseDate(e,t)}));else if(e instanceof Date||"number"==typeof e)n=[w.parseDate(e,t)];else if("string"==typeof e)switch(w.config.mode){case"single":case"time":n=[w.parseDate(e,t)];break;case"multiple":n=e.split(w.config.conjunction).map((function(e){return w.parseDate(e,t)}));break;case"range":n=e.split(w.l10n.rangeSeparator).map((function(e){return w.parseDate(e,t)}))}else w.config.errorHandler(new Error("Invalid date supplied: "+JSON.stringify(e)));w.selectedDates=w.config.allowInvalidPreload?n:n.filter((function(e){return e instanceof Date&&X(e,!1)})),"range"===w.config.mode&&w.selectedDates.sort((function(e,t){return e.getTime()-t.getTime()}))}function ge(e){return e.slice().map((function(e){return"string"==typeof e||"number"==typeof e||e instanceof Date?w.parseDate(e,void 0,!0):e&&"object"==typeof e&&e.from&&e.to?{from:w.parseDate(e.from,void 0),to:w.parseDate(e.to,void 0)}:e})).filter((function(e){return e}))}function pe(e,t){if(void 0!==w.config){var n=w.config[e];if(void 0!==n&&n.length>0)for(var a=0;n[a]&&a<n.length;a++)n[a](w.selectedDates,w.input.value,w,t);"onChange"===e&&(w.input.dispatchEvent(he("change")),w.input.dispatchEvent(he("input")))}}function he(e){var t=document.createEvent("Event");return t.initEvent(e,!0,!0),t}function ve(e){for(var t=0;t<w.selectedDates.length;t++)if(0===M(w.selectedDates[t],e))return""+t;return!1}function De(){w.config.noCalendar||w.isMobile||!w.monthNav||(w.yearElements.forEach((function(e,t){var n=new Date(w.currentYear,w.currentMonth,1);n.setMonth(w.currentMonth+t),w.config.showMonths>1||"static"===w.config.monthSelectorType?w.monthElements[t].textContent=h(n.getMonth(),w.config.shorthandCurrentMonth,w.l10n)+" ":w.monthsDropdownContainer.value=n.getMonth().toString(),e.value=n.getFullYear().toString()})),w._hidePrevMonthArrow=void 0!==w.config.minDate&&(w.currentYear===w.config.minDate.getFullYear()?w.currentMonth<=w.config.minDate.getMonth():w.currentYear<w.config.minDate.getFullYear()),w._hideNextMonthArrow=void 0!==w.config.maxDate&&(w.currentYear===w.config.maxDate.getFullYear()?w.currentMonth+1>w.config.maxDate.getMonth():w.currentYear>w.config.maxDate.getFullYear()))}function we(e){return w.selectedDates.map((function(t){return w.formatDate(t,e)})).filter((function(e,t,n){return"range"!==w.config.mode||w.config.enableTime||n.indexOf(e)===t})).join("range"!==w.config.mode?w.config.conjunction:w.l10n.rangeSeparator)}function be(e){void 0===e&&(e=!0),void 0!==w.mobileInput&&w.mobileFormatStr&&(w.mobileInput.value=void 0!==w.latestSelectedDateObj?w.formatDate(w.latestSelectedDateObj,w.mobileFormatStr):""),w.input.value=we(w.config.dateFormat),void 0!==w.altInput&&(w.altInput.value=we(w.config.altFormat)),!1!==e&&pe("onValueUpdate")}function Ce(e){var t=g(e),n=w.prevMonthNav.contains(t),a=w.nextMonthNav.contains(t);n||a?G(n?-1:1):w.yearElements.indexOf(t)>=0?t.select():t.classList.contains("arrowUp")?w.changeYear(w.currentYear+1):t.classList.contains("arrowDown")&&w.changeYear(w.currentYear-1)}return function(){w.element=w.input=p,w.isOpen=!1,function(){var t=["wrap","weekNumbers","allowInput","allowInvalidPreload","clickOpens","time_24hr","enableTime","noCalendar","altInput","shorthandCurrentMonth","inline","static","enableSeconds","disableMobile"],i=e(e({},JSON.parse(JSON.stringify(p.dataset||{}))),v),o={};w.config.parseDate=i.parseDate,w.config.formatDate=i.formatDate,Object.defineProperty(w.config,"enable",{get:function(){return w.config._enable},set:function(e){w.config._enable=ge(e)}}),Object.defineProperty(w.config,"disable",{get:function(){return w.config._disable},set:function(e){w.config._disable=ge(e)}});var r="time"===i.mode;if(!i.dateFormat&&(i.enableTime||r)){var l=T.defaultConfig.dateFormat||a.dateFormat;o.dateFormat=i.noCalendar||r?"H:i"+(i.enableSeconds?":S":""):l+" H:i"+(i.enableSeconds?":S":"")}if(i.altInput&&(i.enableTime||r)&&!i.altFormat){var d=T.defaultConfig.altFormat||a.altFormat;o.altFormat=i.noCalendar||r?"h:i"+(i.enableSeconds?":S K":" K"):d+" h:i"+(i.enableSeconds?":S":"")+" K"}Object.defineProperty(w.config,"minDate",{get:function(){return w.config._minDate},set:oe("min")}),Object.defineProperty(w.config,"maxDate",{get:function(){return w.config._maxDate},set:oe("max")});var s=function(e){return function(t){w.config["min"===e?"_minTime":"_maxTime"]=w.parseDate(t,"H:i:S")}};Object.defineProperty(w.config,"minTime",{get:function(){return w.config._minTime},set:s("min")}),Object.defineProperty(w.config,"maxTime",{get:function(){return w.config._maxTime},set:s("max")}),"time"===i.mode&&(w.config.noCalendar=!0,w.config.enableTime=!0);Object.assign(w.config,o,i);for(var u=0;u<t.length;u++)w.config[t[u]]=!0===w.config[t[u]]||"true"===w.config[t[u]];n.filter((function(e){return void 0!==w.config[e]})).forEach((function(e){w.config[e]=c(w.config[e]||[]).map(E)})),w.isMobile=!w.config.disableMobile&&!w.config.inline&&"single"===w.config.mode&&!w.config.disable.length&&!w.config.enable&&!w.config.weekNumbers&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);for(u=0;u<w.config.plugins.length;u++){var f=w.config.plugins[u](w)||{};for(var m in f)n.indexOf(m)>-1?w.config[m]=c(f[m]).map(E).concat(w.config[m]):void 0===i[m]&&(w.config[m]=f[m])}i.altInputClass||(w.config.altInputClass=re().className+" "+w.config.altInputClass);pe("onParseConfig")}(),le(),function(){if(w.input=re(),!w.input)return void w.config.errorHandler(new Error("Invalid input element specified"));w.input._type=w.input.type,w.input.type="text",w.input.classList.add("flatpickr-input"),w._input=w.input,w.config.altInput&&(w.altInput=s(w.input.nodeName,w.config.altInputClass),w._input=w.altInput,w.altInput.placeholder=w.input.placeholder,w.altInput.disabled=w.input.disabled,w.altInput.required=w.input.required,w.altInput.tabIndex=w.input.tabIndex,w.altInput.type="text",w.input.setAttribute("type","hidden"),!w.config.static&&w.input.parentNode&&w.input.parentNode.insertBefore(w.altInput,w.input.nextSibling));w.config.allowInput||w._input.setAttribute("readonly","readonly");w._positionElement=w.config.positionElement||w._input}(),function(){w.selectedDates=[],w.now=w.parseDate(w.config.now)||new Date;var e=w.config.defaultDate||("INPUT"!==w.input.nodeName&&"TEXTAREA"!==w.input.nodeName||!w.input.placeholder||w.input.value!==w.input.placeholder?w.input.value:null);e&&me(e,w.config.dateFormat);w._initialDate=w.selectedDates.length>0?w.selectedDates[0]:w.config.minDate&&w.config.minDate.getTime()>w.now.getTime()?w.config.minDate:w.config.maxDate&&w.config.maxDate.getTime()<w.now.getTime()?w.config.maxDate:w.now,w.currentYear=w._initialDate.getFullYear(),w.currentMonth=w._initialDate.getMonth(),w.selectedDates.length>0&&(w.latestSelectedDateObj=w.selectedDates[0]);void 0!==w.config.minTime&&(w.config.minTime=w.parseDate(w.config.minTime,"H:i"));void 0!==w.config.maxTime&&(w.config.maxTime=w.parseDate(w.config.maxTime,"H:i"));w.minDateHasTime=!!w.config.minDate&&(w.config.minDate.getHours()>0||w.config.minDate.getMinutes()>0||w.config.minDate.getSeconds()>0),w.maxDateHasTime=!!w.config.maxDate&&(w.config.maxDate.getHours()>0||w.config.maxDate.getMinutes()>0||w.config.maxDate.getSeconds()>0)}(),w.utils={getDaysInMonth:function(e,t){return void 0===e&&(e=w.currentMonth),void 0===t&&(t=w.currentYear),1===e&&(t%4==0&&t%100!=0||t%400==0)?29:w.l10n.daysInMonth[e]}},w.isMobile||function(){var e=window.document.createDocumentFragment();if(w.calendarContainer=s("div","flatpickr-calendar"),w.calendarContainer.tabIndex=-1,!w.config.noCalendar){if(e.appendChild((w.monthNav=s("div","flatpickr-months"),w.yearElements=[],w.monthElements=[],w.prevMonthNav=s("span","flatpickr-prev-month"),w.prevMonthNav.innerHTML=w.config.prevArrow,w.nextMonthNav=s("span","flatpickr-next-month"),w.nextMonthNav.innerHTML=w.config.nextArrow,q(),Object.defineProperty(w,"_hidePrevMonthArrow",{get:function(){return w.__hidePrevMonthArrow},set:function(e){w.__hidePrevMonthArrow!==e&&(d(w.prevMonthNav,"flatpickr-disabled",e),w.__hidePrevMonthArrow=e)}}),Object.defineProperty(w,"_hideNextMonthArrow",{get:function(){return w.__hideNextMonthArrow},set:function(e){w.__hideNextMonthArrow!==e&&(d(w.nextMonthNav,"flatpickr-disabled",e),w.__hideNextMonthArrow=e)}}),w.currentYearElement=w.yearElements[0],De(),w.monthNav)),w.innerContainer=s("div","flatpickr-innerContainer"),w.config.weekNumbers){var t=function(){w.calendarContainer.classList.add("hasWeeks");var e=s("div","flatpickr-weekwrapper");e.appendChild(s("span","flatpickr-weekday",w.l10n.weekAbbreviation));var t=s("div","flatpickr-weeks");return e.appendChild(t),{weekWrapper:e,weekNumbers:t}}(),n=t.weekWrapper,a=t.weekNumbers;w.innerContainer.appendChild(n),w.weekNumbers=a,w.weekWrapper=n}w.rContainer=s("div","flatpickr-rContainer"),w.rContainer.appendChild($()),w.daysContainer||(w.daysContainer=s("div","flatpickr-days"),w.daysContainer.tabIndex=-1),J(),w.rContainer.appendChild(w.daysContainer),w.innerContainer.appendChild(w.rContainer),e.appendChild(w.innerContainer)}w.config.enableTime&&e.appendChild(function(){w.calendarContainer.classList.add("hasTime"),w.config.noCalendar&&w.calendarContainer.classList.add("noCalendar");var e=x(w.config);w.timeContainer=s("div","flatpickr-time"),w.timeContainer.tabIndex=-1;var t=s("span","flatpickr-time-separator",":"),n=m("flatpickr-hour",{"aria-label":w.l10n.hourAriaLabel});w.hourElement=n.getElementsByTagName("input")[0];var a=m("flatpickr-minute",{"aria-label":w.l10n.minuteAriaLabel});w.minuteElement=a.getElementsByTagName("input")[0],w.hourElement.tabIndex=w.minuteElement.tabIndex=-1,w.hourElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getHours():w.config.time_24hr?e.hours:function(e){switch(e%24){case 0:case 12:return 12;default:return e%12}}(e.hours)),w.minuteElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getMinutes():e.minutes),w.hourElement.setAttribute("step",w.config.hourIncrement.toString()),w.minuteElement.setAttribute("step",w.config.minuteIncrement.toString()),w.hourElement.setAttribute("min",w.config.time_24hr?"0":"1"),w.hourElement.setAttribute("max",w.config.time_24hr?"23":"12"),w.hourElement.setAttribute("maxlength","2"),w.minuteElement.setAttribute("min","0"),w.minuteElement.setAttribute("max","59"),w.minuteElement.setAttribute("maxlength","2"),w.timeContainer.appendChild(n),w.timeContainer.appendChild(t),w.timeContainer.appendChild(a),w.config.time_24hr&&w.timeContainer.classList.add("time24hr");if(w.config.enableSeconds){w.timeContainer.classList.add("hasSeconds");var i=m("flatpickr-second");w.secondElement=i.getElementsByTagName("input")[0],w.secondElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getSeconds():e.seconds),w.secondElement.setAttribute("step",w.minuteElement.getAttribute("step")),w.secondElement.setAttribute("min","0"),w.secondElement.setAttribute("max","59"),w.secondElement.setAttribute("maxlength","2"),w.timeContainer.appendChild(s("span","flatpickr-time-separator",":")),w.timeContainer.appendChild(i)}w.config.time_24hr||(w.amPM=s("span","flatpickr-am-pm",w.l10n.amPM[r((w.latestSelectedDateObj?w.hourElement.value:w.config.defaultHour)>11)]),w.amPM.title=w.l10n.toggleTitle,w.amPM.tabIndex=-1,w.timeContainer.appendChild(w.amPM));return w.timeContainer}());d(w.calendarContainer,"rangeMode","range"===w.config.mode),d(w.calendarContainer,"animate",!0===w.config.animate),d(w.calendarContainer,"multiMonth",w.config.showMonths>1),w.calendarContainer.appendChild(e);var i=void 0!==w.config.appendTo&&void 0!==w.config.appendTo.nodeType;if((w.config.inline||w.config.static)&&(w.calendarContainer.classList.add(w.config.inline?"inline":"static"),w.config.inline&&(!i&&w.element.parentNode?w.element.parentNode.insertBefore(w.calendarContainer,w._input.nextSibling):void 0!==w.config.appendTo&&w.config.appendTo.appendChild(w.calendarContainer)),w.config.static)){var l=s("div","flatpickr-wrapper");w.element.parentNode&&w.element.parentNode.insertBefore(l,w.element),l.appendChild(w.element),w.altInput&&l.appendChild(w.altInput),l.appendChild(w.calendarContainer)}w.config.static||w.config.inline||(void 0!==w.config.appendTo?w.config.appendTo:window.document.body).appendChild(w.calendarContainer)}(),function(){w.config.wrap&&["open","close","toggle","clear"].forEach((function(e){Array.prototype.forEach.call(w.element.querySelectorAll("[data-"+e+"]"),(function(t){return A(t,"click",w[e])}))}));if(w.isMobile)return void function(){var e=w.config.enableTime?w.config.noCalendar?"time":"datetime-local":"date";w.mobileInput=s("input",w.input.className+" flatpickr-mobile"),w.mobileInput.tabIndex=1,w.mobileInput.type=e,w.mobileInput.disabled=w.input.disabled,w.mobileInput.required=w.input.required,w.mobileInput.placeholder=w.input.placeholder,w.mobileFormatStr="datetime-local"===e?"Y-m-d\\TH:i:S":"date"===e?"Y-m-d":"H:i:S",w.selectedDates.length>0&&(w.mobileInput.defaultValue=w.mobileInput.value=w.formatDate(w.selectedDates[0],w.mobileFormatStr));w.config.minDate&&(w.mobileInput.min=w.formatDate(w.config.minDate,"Y-m-d"));w.config.maxDate&&(w.mobileInput.max=w.formatDate(w.config.maxDate,"Y-m-d"));w.input.getAttribute("step")&&(w.mobileInput.step=String(w.input.getAttribute("step")));w.input.type="hidden",void 0!==w.altInput&&(w.altInput.type="hidden");try{w.input.parentNode&&w.input.parentNode.insertBefore(w.mobileInput,w.input.nextSibling)}catch(e){}A(w.mobileInput,"change",(function(e){w.setDate(g(e).value,!1,w.mobileFormatStr),pe("onChange"),pe("onClose")}))}();var e=l(ie,50);w._debouncedChange=l(N,300),w.daysContainer&&!/iPhone|iPad|iPod/i.test(navigator.userAgent)&&A(w.daysContainer,"mouseover",(function(e){"range"===w.config.mode&&ae(g(e))}));A(window.document.body,"keydown",ne),w.config.inline||w.config.static||A(window,"resize",e);void 0!==window.ontouchstart?A(window.document,"touchstart",Z):A(window.document,"mousedown",Z);A(window.document,"focus",Z,{capture:!0}),!0===w.config.clickOpens&&(A(w._input,"focus",w.open),A(w._input,"click",w.open));void 0!==w.daysContainer&&(A(w.monthNav,"click",Ce),A(w.monthNav,["keyup","increment"],F),A(w.daysContainer,"click",ue));if(void 0!==w.timeContainer&&void 0!==w.minuteElement&&void 0!==w.hourElement){var t=function(e){return g(e).select()};A(w.timeContainer,["increment"],I),A(w.timeContainer,"blur",I,{capture:!0}),A(w.timeContainer,"click",Y),A([w.hourElement,w.minuteElement],["focus","click"],t),void 0!==w.secondElement&&A(w.secondElement,"focus",(function(){return w.secondElement&&w.secondElement.select()}
20225)),void 0!==w.amPM&&A(w.amPM,"click",(function(e){I(e),N()}))}w.config.allowInput&&A(w._input,"blur",te)}(),(w.selectedDates.length||w.config.noCalendar)&&(w.config.enableTime&&_(w.config.noCalendar?w.latestSelectedDateObj:void 0),be(!1)),k();var t=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);!w.isMobile&&t&&ce(),pe("onReady")}(),w}function k(e,t){for(var n=Array.prototype.slice.call(e).filter((function(e){return e instanceof HTMLElement})),a=[],i=0;i<n.length;i++){var o=n[i];try{if(null!==o.getAttribute("data-fp-omit"))continue;void 0!==o._flatpickr&&(o._flatpickr.destroy(),o._flatpickr=void 0),o._flatpickr=E(o,t||{}),a.push(o._flatpickr)}catch(e){console.error(e)}}return 1===a.length?a[0]:a}"undefined"!=typeof HTMLElement&&"undefined"!=typeof HTMLCollection&&"undefined"!=typeof NodeList&&(HTMLCollection.prototype.flatpickr=NodeList.prototype.flatpickr=function(e){return k(this,e)},HTMLElement.prototype.flatpickr=function(e){return k([this],e)});var T=function(e,t){return"string"==typeof e?k(window.document.querySelectorAll(e),t):e instanceof Node?k([e],t):k(e,t)};return T.defaultConfig={},T.l10ns={en:e({},i),default:e({},i)},T.localize=function(t){T.l10ns.default=e(e({},T.l10ns.default),t)},T.setDefaults=function(t){T.defaultConfig=e(e({},T.defaultConfig),t)},T.parseDate=C({}),T.formatDate=b({}),T.compareDates=M,"undefined"!=typeof jQuery&&void 0!==jQuery.fn&&(jQuery.fn.flatpickr=function(e){return k(this,e)}),Date.prototype.fp_incr=function(e){return new Date(this.getFullYear(),this.getMonth(),this.getDate()+("string"==typeof e?parseInt(e,10):e))},"undefined"!=typeof window&&(window.flatpickr=T),T})); 20226(function (global, factory) { 20227 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 20228 typeof define === 'function' && define.amd ? define(['exports'], factory) : 20229 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.et = {})); 20230}(this, (function (exports) { 'use strict'; 20231 20232 var fp = typeof window !== "undefined" && window.flatpickr !== undefined 20233 ? window.flatpickr 20234 : { 20235 l10ns: {}, 20236 }; 20237 var Estonian = { 20238 weekdays: { 20239 shorthand: ["P", "E", "T", "K", "N", "R", "L"], 20240 longhand: [ 20241 "Pühapäev", 20242 "Esmaspäev", 20243 "Teisipäev", 20244 "Kolmapäev", 20245 "Neljapäev", 20246 "Reede", 20247 "Laupäev", 20248 ], 20249 }, 20250 months: { 20251 shorthand: [ 20252 "Jaan", 20253 "Veebr", 20254 "Märts", 20255 "Apr", 20256 "Mai", 20257 "Juuni", 20258 "Juuli", 20259 "Aug", 20260 "Sept", 20261 "Okt", 20262 "Nov", 20263 "Dets", 20264 ], 20265 longhand: [ 20266 "Jaanuar", 20267 "Veebruar", 20268 "Märts", 20269 "Aprill", 20270 "Mai", 20271 "Juuni", 20272 "Juuli", 20273 "August", 20274 "September", 20275 "Oktoober", 20276 "November", 20277 "Detsember", 20278 ], 20279 }, 20280 firstDayOfWeek: 1, 20281 ordinal: function () { 20282 return "."; 20283 }, 20284 weekAbbreviation: "Näd", 20285 rangeSeparator: " kuni ", 20286 scrollTitle: "Keri, et suurendada", 20287 toggleTitle: "Klõpsa, et vahetada", 20288 time_24hr: true, 20289 }; 20290 fp.l10ns.et = Estonian; 20291 var et = fp.l10ns; 20292 20293 exports.Estonian = Estonian; 20294 exports.default = et; 20295 20296 Object.defineProperty(exports, '__esModule', { value: true }); 20297 20298}))); 20299 20300(function (global, factory) { 20301 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 20302 typeof define === 'function' && define.amd ? define(factory) : 20303 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.monthSelectPlugin = factory()); 20304}(this, (function () { 'use strict'; 20305 20306 /*! ***************************************************************************** 20307 Copyright (c) Microsoft Corporation. 20308 20309 Permission to use, copy, modify, and/or distribute this software for any 20310 purpose with or without fee is hereby granted. 20311 20312 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 20313 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 20314 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 20315 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 20316 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 20317 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20318 PERFORMANCE OF THIS SOFTWARE. 20319 ***************************************************************************** */ 20320 20321 var __assign = function() { 20322 __assign = Object.assign || function __assign(t) { 20323 for (var s, i = 1, n = arguments.length; i < n; i++) { 20324 s = arguments[i]; 20325 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 20326 } 20327 return t; 20328 }; 20329 return __assign.apply(this, arguments); 20330 }; 20331 20332 var monthToStr = function (monthNumber, shorthand, locale) { return locale.months[shorthand ? "shorthand" : "longhand"][monthNumber]; }; 20333 20334 function getEventTarget(event) { 20335 try { 20336 if (typeof event.composedPath === "function") { 20337 var path = event.composedPath(); 20338 return path[0]; 20339 } 20340 return event.target; 20341 } 20342 catch (error) { 20343 return event.target; 20344 } 20345 } 20346 20347 var defaultConfig = { 20348 shorthand: false, 20349 dateFormat: "F Y", 20350 altFormat: "F Y", 20351 theme: "light", 20352 }; 20353 function monthSelectPlugin(pluginConfig) { 20354 var config = __assign(__assign({}, defaultConfig), pluginConfig); 20355 return function (fp) { 20356 fp.config.dateFormat = config.dateFormat; 20357 fp.config.altFormat = config.altFormat; 20358 var self = { monthsContainer: null }; 20359 function clearUnnecessaryDOMElements() { 20360 if (!fp.rContainer || !fp.daysContainer || !fp.weekdayContainer) 20361 return; 20362 fp.rContainer.removeChild(fp.daysContainer); 20363 fp.rContainer.removeChild(fp.weekdayContainer); 20364 for (var index = 0; index < fp.monthElements.length; index++) { 20365 var element = fp.monthElements[index]; 20366 if (!element.parentNode) 20367 continue; 20368 element.parentNode.removeChild(element); 20369 } 20370 } 20371 function addListeners() { 20372 fp._bind(fp.prevMonthNav, "click", function (e) { 20373 e.preventDefault(); 20374 e.stopPropagation(); 20375 fp.changeYear(fp.currentYear - 1); 20376 selectYear(); 20377 }); 20378 fp._bind(fp.nextMonthNav, "click", function (e) { 20379 e.preventDefault(); 20380 e.stopPropagation(); 20381 fp.changeYear(fp.currentYear + 1); 20382 selectYear(); 20383 }); 20384 } 20385 function addMonths() { 20386 if (!fp.rContainer) 20387 return; 20388 self.monthsContainer = fp._createElement("div", "flatpickr-monthSelect-months"); 20389 self.monthsContainer.tabIndex = -1; 20390 fp.calendarContainer.classList.add("flatpickr-monthSelect-theme-" + config.theme); 20391 for (var i = 0; i < 12; i++) {
20392 var month = fp._createElement("span", "flatpickr-monthSelect-month"); 20393 month.dateObj = new Date(fp.currentYear, i); 20394 month.$i = i; 20395 month.textContent = monthToStr(i, config.shorthand, fp.l10n); 20396 month.tabIndex = -1; 20397 month.addEventListener("click", selectMonth); 20398 self.monthsContainer.appendChild(month); 20399 if ((fp.config.minDate && month.dateObj < fp.config.minDate) || 20400 (fp.config.maxDate && month.dateObj > fp.config.maxDate)) { 20401 month.classList.add("disabled"); 20402 } 20403 } 20404 fp.rContainer.appendChild(self.monthsContainer); 20405 } 20406 function setCurrentlySelected() { 20407 if (!fp.rContainer) 20408 return; 20409 var currentlySelected = fp.rContainer.querySelectorAll(".flatpickr-monthSelect-month.selected"); 20410 for (var index = 0; index < currentlySelected.length; index++) { 20411 currentlySelected[index].classList.remove("selected"); 20412 } 20413 var targetMonth = (fp.selectedDates[0] || new Date()).getMonth(); 20414 var month = fp.rContainer.querySelector(".flatpickr-monthSelect-month:nth-child(" + (targetMonth + 1) + ")"); 20415 if (month) { 20416 month.classList.add("selected"); 20417 } 20418 } 20419 function selectYear() { 20420 var selectedDate = fp.selectedDates[0]; 20421 if (selectedDate) { 20422 selectedDate = new Date(selectedDate); 20423 selectedDate.setFullYear(fp.currentYear); 20424 if (fp.config.minDate && selectedDate < fp.config.minDate) { 20425 selectedDate = fp.config.minDate; 20426 } 20427 if (fp.config.maxDate && selectedDate > fp.config.maxDate) { 20428 selectedDate = fp.config.maxDate; 20429 } 20430 fp.currentYear = selectedDate.getFullYear(); 20431 } 20432 fp.currentYearElement.value = String(fp.currentYear); 20433 if (fp.rContainer) { 20434 var months = fp.rContainer.querySelectorAll(".flatpickr-monthSelect-month"); 20435 months.forEach(function (month) { 20436 month.dateObj.setFullYear(fp.currentYear); 20437 if ((fp.config.minDate && month.dateObj < fp.config.minDate) || 20438 (fp.config.maxDate && month.dateObj > fp.config.maxDate)) { 20439 month.classList.add("disabled"); 20440 } 20441 else { 20442 month.classList.remove("disabled"); 20443 } 20444 }); 20445 } 20446 setCurrentlySelected(); 20447 } 20448 function selectMonth(e) { 20449 e.preventDefault(); 20450 e.stopPropagation(); 20451 var eventTarget = getEventTarget(e); 20452 if (eventTarget instanceof Element && 20453 !eventTarget.classList.contains("disabled")) { 20454 setMonth(eventTarget.dateObj); 20455 fp.close(); 20456 } 20457 } 20458 function setMonth(date) { 20459 var selectedDate = new Date(date); 20460 selectedDate.setFullYear(fp.currentYear); 20461 fp.setDate(selectedDate, true); 20462 setCurrentlySelected(); 20463 } 20464 var shifts = { 20465 37: -1, 20466 39: 1, 20467 40: 3, 20468 38: -3, 20469 }; 20470 function onKeyDown(_, __, ___, e) { 20471 var shouldMove = shifts[e.keyCode] !== undefined; 20472 if (!shouldMove && e.keyCode !== 13) { 20473 return; 20474 } 20475 if (!fp.rContainer || !self.monthsContainer) 20476 return; 20477 var currentlySelected = fp.rContainer.querySelector(".flatpickr-monthSelect-month.selected"); 20478 var index = Array.prototype.indexOf.call(self.monthsContainer.children, document.activeElement); 20479 if (index === -1) { 20480 var target = currentlySelected || self.monthsContainer.firstElementChild;
20481 target.focus(); 20482 index = target.$i; 20483 } 20484 if (shouldMove) { 20485 self.monthsContainer.children[(12 + index + shifts[e.keyCode]) % 12].focus(); 20486 } 20487 else if (e.keyCode === 13 && 20488 self.monthsContainer.contains(document.activeElement)) { 20489 setMonth(document.activeElement.dateObj); 20490 } 20491 } 20492 function destroyPluginInstance() { 20493 if (self.monthsContainer !== null) { 20494 var months = self.monthsContainer.querySelectorAll(".flatpickr-monthSelect-month"); 20495 for (var index = 0; index < months.length; index++) { 20496 months[index].removeEventListener("click", selectMonth); 20497 } 20498 } 20499 } 20500 return { 20501 onParseConfig: function () { 20502 fp.config.mode = "single"; 20503 fp.config.enableTime = false; 20504 }, 20505 onValueUpdate: setCurrentlySelected, 20506 onKeyDown: onKeyDown, 20507 onReady: [ 20508 function () { 20509 fp.currentMonth = 0; 20510 }, 20511 clearUnnecessaryDOMElements, 20512 addListeners, 20513 addMonths, 20514 setCurrentlySelected, 20515 function () { 20516 fp.loadedPlugins.push("monthSelect"); 20517 }, 20518 ], 20519 onDestroy: destroyPluginInstance, 20520 }; 20521 }; 20522 } 20523 20524 return monthSelectPlugin; 20525 20526})));
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.