PageSourceSearch

https://orienteerumine.ee/wp-content/themes/eol/assets/dist/js/pp-vendors.js?ver=221129-91308

js orienteerumine.ee collected 2026-09-24 20:49:36 UTC 737,493 bytes, 20,526 lines download raw bytes

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>&nbsp;/&nbsp;<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&szlig;en",
389        NEXT: "Weiter",
390        PREV: "Zur&uuml;ck",
391        ERROR: "Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es sp&auml;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&ouml;&szlig;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      "&": "&amp;",
5323      "<": "&lt;",
5324      ">": "&gt;",
5325      '"': "&quot;",
5326      "'": "&#39;",
5327      "/": "&#x2F;",
5328      "`": "&#x60;",
5329      "=": "&#x3D;"
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         *                 '&lt;div class="mix"&gt;' +
10163         *                     '&lt;h2&gt;' + item.title + '&lt;/h2&gt;' +
10164         *                 '&lt;/div&gt;'
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         *                 `&lt;div class="mix"&gt;
10177         *                     &lt;h2&gt;${item.title}&lt;/h2&gt;
10178         *                  &lt;/div&gt;`
10179         *             );
10180         *         }
10181         *     }
10182         * });
10183         *
10184         * @example <caption>Example 3: Using a Handlebars template</caption>
10185         *
10186         * var targetTemplate = Handlebars.compile('&lt;div class="mix"&gt;&lt;h2&gt;{{title}}&lt;/h2&gt;&lt;/div&gt;');
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 = '&lt;div class="mix"&gt;&lt;/div&gt;';
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 = $('&lt;div class="mix"&gt;&lt;/div&gt;');
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); // ... &lt;span class="mix"&gt;Foo&lt;/span&gt; ...
15711         *
15712         * mixer.configure({
15713         *     render: {
15714         *         target: (item) => `&lt;a href="/${item.slug}/" class="mix"&gt;${item.title}&lt;/a&gt;`
15715         *     }
15716         * });
15717         *
15718         * mixer.forceRender();
15719         *
15720         * console.log(container.innerHTML); // ... &lt;a href="/foo/" class="mix"&gt;Foo&lt;/a&gt; ...
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.