PageSourceSearch

https://azcapitoltimes.com/wp-content/themes/hello-elementor/js/gallery.js?ver=1.0.0.08.38.25.09.24.2026

js azcapitoltimes.com collected 2026-09-24 08:55:04 UTC 178,290 bytes, 6,166 lines download raw bytes

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: true,
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:
114          '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen="allowfullscreen" allow="autoplay; fullscreen" src=""></iframe>',
115  
116        // Preload iframe before displaying it
117        // This allows to calculate iframe content width and height
118        // (note: Due to "Same Origin Policy", you can't get cross domain data).
119        preload: true,
120  
121        // Custom CSS styling for iframe wrapping element
122        // You can use this to set custom iframe dimensions
123        css: {},
124  
125        // Iframe tag attributes
126        attr: {
127          scrolling: "auto",
128        },
129      },
130  
131      // For HTML5 video only
132      video: {
133        tpl:
134          '<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}">' +
135          '<source src="{{src}}" type="{{format}}" />' +
136          'Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!' +
137          "</video>",
138        format: "", // custom video format
139        autoStart: true,
140      },
141  
142      // Default content type if cannot be detected automatically
143      defaultType: "image",
144  
145      // Open/close animation type
146      // Possible values:
147      //   false            - disable
148      //   "zoom"           - zoom images from/to thumbnail
149      //   "fade"
150      //   "zoom-in-out"
151      //
152      animationEffect: "zoom",
153  
154      // Duration in ms for open/close animation
155      animationDuration: 366,
156  
157      // Should image change opacity while zooming
158      // If opacity is "auto", then opacity will be changed if image and thumbnail have different aspect ratios
159      zoomOpacity: "auto",
160  
161      // Transition effect between slides
162      //
163      // Possible values:
164      //   false            - disable
165      //   "fade'
166      //   "slide'
167      //   "circular'
168      //   "tube'
169      //   "zoom-in-out'
170      //   "rotate'
171      //
172      transitionEffect: "fade",
173  
174      // Duration in ms for transition animation
175      transitionDuration: 366,
176  
177      // Custom CSS class for slide element
178      slideClass: "",
179  
180      // Custom CSS class for layout
181      baseClass: "",
182  
183      // Base template for layout
184      baseTpl:
185        '<div class="fancybox-container" role="dialog" tabindex="-1">' +
186        '<div class="fancybox-bg"></div>' +
187        '<div class="fancybox-inner">' +
188        '<div class="fancybox-infobar"><span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span></div>' +
189        '<div class="fancybox-toolbar">{{buttons}}</div>' +
190        '<div class="fancybox-navigation">{{arrows}}</div>' +
191        '<div class="fancybox-stage"><div class="fancybox-caption"><div class="fancybox-caption__body"></div></div></div>' +
192        "</di>" +
193        "</div>",
194  
195      // Loading indicator template
196      spinnerTpl: '<div class="fancybox-loading"></div>',
197  
198      // Error message template
199      errorTpl: '<div class="fancybox-error"><p>{{ERROR}}</p></div>',
200  
201      btnTpl: {
202        download:
203          '<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;">' +
204          '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
204<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>' +
205          "</a>",
206  
207        zoom:
208          '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' +
209          '<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>' +
210          "</button>",
211  
212        close:
213          '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' +
214          '<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>' +
215          "</button>",
216  
217        // Arrows
218        arrowLeft:
219          '<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' +
220          '<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>' +
221          "</button>",
222  
223        arrowRight:
224          '<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' +
225          '<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>' +
226          "</button>",
227  
228        // This small close button will be appended to your html/inline/ajax content by default,
229        // if "smallBtn" option is not set to false
230        smallBtn:
231          '<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}">' +
232          '<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>' +
233          "</button>",
234      },
235  
236      // Container is injected into this element
237      parentEl: "body",
238  
239      // Hide browser vertical scrollbars; use at your own risk
240      hideScrollbar: true,
241  
242      // Focus handling
243      // ==============
244  
245      // Try to focus on the first focusable element after opening
246      autoFocus: true,
247  
248      // Put focus back to active element after closing
249      backFocus: true,
250  
251      // Do not let user to focus on element outside modal content
252      trapFocus: true,
253  
254      // Module specific options
255      // =======================
256  
257      fullScreen: {
258        autoStart: false,
259      },
260  
261      // Set `touch: false` to disable panning/swiping
262      touch: {
263        vertical: true, // Allow to drag content vertically
264        momentum: true, // Continue movement after releasing mouse/touch when panning
265      },
266  
267      // Hash value when initializing manually,
268      // set `false` to disable hash change
269      hash: null,
270  
271      // Customize or add new media types
272      // Example:
273      /*
274          media : {
275            youtube : {
276              params : {
277                autoplay : 0
278              }
279            }
280          }
281        */
282      media: {},
283  
284      slideShow: {
285        autoStart: false,
286        speed: 3000,
287      },
288  
289      thumbs: {
290        autoStart: false, // Display thumbnails on opening
291        hideOnClose: true, // Hide thumbnail grid when closing animation starts
292        parentEl: ".fancybox-container", // Container is injected into this element
293        axis: "y", // Vertical (y) or horizontal (x) scrolling
294      },
295  
296      // Use mousewheel to navigate gallery
297      // If 'auto' - enabled for images only
298      wheel: "auto",
299  
300      // Callbacks
301      //==========
302  
303      // See Documentation/API/Events for more information
304      // Example:
305      /*
306          afterShow: function( instance, current ) {
307            console.info( 'Clicked element:' );
308            console.info( current.opts.$orig );
309          }
310        */
311  
312      onInit: $.noop, // When instance has been initialized
313  
314      beforeLoad: $.noop, // Before the content of a slide is being loaded
315      afterLoad: $.noop, // When the content of a slide is done loading
316  
317      beforeShow: $.noop, // Before open animation starts
318      afterShow: $.noop, // When content is done loading and animating
319  
320      beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close.
321      afterClose: $.noop, // After instance has been closed
322  
323      onActivate: $.noop, // When instance is brought to front
324      onDeactivate: $.noop, // When other instance has been activated
325  
326      // Interaction
327      // ===========
328  
329      // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,
330      // each option can be string or method that returns value.
331      //
332      // Possible values:
333      //   "close"           - close instance
334      //   "next"            - move to next gallery item
335      //   "nextOrClose"     - move to next gallery item or close if gallery has only one item
336      //   "toggleControls"  - show/hide controls
337      //   "zoom"            - zoom image (if loaded)
338      //   false             - do nothing
339  
340      // Clicked on the content
341      clickContent: function (current, event) {
342        return current.type === "image" ? "zoom" : false;
vendor: 166,321 bytes, lines 343-6166
343      },
344  
345      // Clicked on the slide
346      clickSlide: "close",
347  
348      // Clicked on the background (backdrop) element;
349      // if you have not changed the layout, then most likely you need to use `clickSlide` option
350      clickOutside: "close",
351  
352      // Same as previous two, but for double click
353      dblclickContent: false,
354      dblclickSlide: false,
355      dblclickOutside: false,
356  
357      // Custom options when mobile device is detected
358      // =============================================
359  
360      mobile: {
361        preventCaptionOverlap: false,
362        idleTime: false,
363        clickContent: function (current, event) {
364          return current.type === "image" ? "toggleControls" : false;
365        },
366        clickSlide: function (current, event) {
367          return current.type === "image" ? "toggleControls" : "close";
368        },
369        dblclickContent: function (current, event) {
370          return current.type === "image" ? "zoom" : false;
371        },
372        dblclickSlide: function (current, event) {
373          return current.type === "image" ? "zoom" : false;
374        },
375      },
376  
377      // Internationalization
378      // ====================
379  
380      lang: "en",
381      i18n: {
382        en: {
383          CLOSE: "Close",
384          NEXT: "Next",
385          PREV: "Previous",
386          ERROR:
387            "The requested content cannot be loaded. <br/> Please try again later.",
388          PLAY_START: "Start slideshow",
389          PLAY_STOP: "Pause slideshow",
390          FULL_SCREEN: "Full screen",
391          THUMBS: "Thumbnails",
392          DOWNLOAD: "Download",
393          SHARE: "Share",
394          ZOOM: "Zoom",
395        },
396        de: {
397          CLOSE: "Schlie&szlig;en",
398          NEXT: "Weiter",
399          PREV: "Zur&uuml;ck",
400          ERROR:
401            "Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es sp&auml;ter nochmal.",
402          PLAY_START: "Diaschau starten",
403          PLAY_STOP: "Diaschau beenden",
404          FULL_SCREEN: "Vollbild",
405          THUMBS: "Vorschaubilder",
406          DOWNLOAD: "Herunterladen",
407          SHARE: "Teilen",
408          ZOOM: "Vergr&ouml;&szlig;ern",
409        },
410      },
411    };
412  
413    // Few useful variables and methods
414    // ================================
415  
416    var $W = $(window);
417    var $D = $(document);
418  
419    var called = 0;
420  
421    // Check if an object is a jQuery object and not a native JavaScript object
422    // ========================================================================
423    var isQuery = function (obj) {
424      return obj && obj.hasOwnProperty && obj instanceof $;
425    };
426  
427    // Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame"
428    // ===============================================================================
429    var requestAFrame = (function () {
430      return (
431        window.requestAnimationFrame ||
432        window.webkitRequestAnimationFrame ||
433        window.mozRequestAnimationFrame ||
434        window.oRequestAnimationFrame ||
435        // if all else fails, use setTimeout
436        function (callback) {
437          return window.setTimeout(callback, 1000 / 60);
438        }
439      );
440    })();
441  
442    var cancelAFrame = (function () {
443      return (
444        window.cancelAnimationFrame ||
445        window.webkitCancelAnimationFrame ||
446        window.mozCancelAnimationFrame ||
447        window.oCancelAnimationFrame ||
448        function (id) {
449          window.clearTimeout(id);
450        }
451      );
452    })();
453  
454    // Detect the supported transition-end event property name
455    // =======================================================
456    var transitionEnd = (function () {
457      var el = document.createElement("fakeelement"),
458        t;
459  
460      var transitions = {
461        transition: "transitionend",
462        OTransition: "oTransitionEnd",
463        MozTransition: "transitionend",
464        WebkitTransition: "webkitTransitionEnd",
465      };
466  
467      for (t in transitions) {
468        if (el.style[t] !== undefined) {
469          return transitions[t];
470        }
471      }
472  
473      return "transitionend";
474    })();
475  
476    // Force redraw on an element.
477    // This helps in cases where the browser doesn't redraw an updated element properly
478    // ================================================================================
479    var forceRedraw = function ($el) {
480      return $el && $el.length && $el[0].offsetHeight;
481    };
482  
483    // Exclude array (`buttons`) options from deep merging
484    // ===================================================
485    var mergeOpts = function (opts1, opts2) {
486      var rez = $.extend(true, {}, opts1, opts2);
487  
488      $.each(opts2, function (key, value) {
489        if ($.isArray(value)) {
490          rez[key] = value;
491        }
492      });
493  
494      return rez;
495    };
496  
497    // How much of an element is visible in viewport
498    // =============================================
499  
500    var inViewport = function (elem) {
501      var elemCenter, rez;
502  
503      if (!elem || elem.ownerDocument !== document) {
504        return false;
505      }
506  
507      $(".fancybox-container").css("pointer-events", "none");
508  
509      elemCenter = {
510        x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
511        y: elem.getBoundingClientRect().top + elem.offsetHeight / 2,
512      };
513  
514      rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem;
515  
516      $(".fancybox-container").css("pointer-events", "");
517  
518      return rez;
519    };
520  
521    // Class definition
522    // ================
523  
524    var FancyBox = function (content, opts, index) {
525      var self = this;
526  
527      self.opts = mergeOpts(
528        {
529          index: index,
530        },
531        $.fancybox.defaults
532      );
533  
534      if ($.isPlainObject(opts)) {
535        self.opts = mergeOpts(self.opts, opts);
536      }
537  
538      if ($.fancybox.isMobile) {
539        self.opts = mergeOpts(self.opts, self.opts.mobile);
540      }
541  
542      self.id = self.opts.id || ++called;
543  
544      self.currIndex = parseInt(self.opts.index, 10) || 0;
545      self.prevIndex = null;
546  
547      self.prevPos = null;
548      self.currPos = 0;
549  
550      self.firstRun = true;
551  
552      // All group items
553      self.group = [];
554  
555      // Existing slides (for current, next and previous gallery items)
556      self.slides = {};
557  
558      // Create group elements
559      self.addContent(content);
560  
561      if (!self.group.length) {
562        return;
563      }
564  
565      self.init();
566    };
567  
568    $.extend(FancyBox.prototype, {
569      // Create DOM structure
570      // ====================
571  
572      init: function () {
573        var self = this,
574          firstItem = self.group[self.currIndex],
575          firstItemOpts = firstItem.opts,
576          $container,
577          buttonStr;
578  
579        if (firstItemOpts.closeExisting) {
580          $.fancybox.close(true);
581        }
582  
583        // Hide scrollbars
584        // ===============
585  
586        $("body").addClass("fancybox-active");
587  
588        if (
589          !$.fancybox.getInstance() &&
590          firstItemOpts.hideScrollbar !== false &&
591          !$.fancybox.isMobile &&
592          document.body.scrollHeight > window.innerHeight
593        ) {
594          $("head").append(
595            '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:' +
596              (window.innerWidth - document.documentElement.clientWidth) +
597              "px;}</style>"
598          );
599  
600          $("body").addClass("compensate-for-scrollbar");
601        }
602  
603        // Build html markup and set references
604        // ====================================
605  
606        // Build html code for buttons and insert into main template
607        buttonStr = "";
608  
609        $.each(firstItemOpts.buttons, function (index, value) {
610          buttonStr += firstItemOpts.btnTpl[value] || "";
611        });
612  
613        // Create markup from base template, it will be initially hidden to
614        // avoid unnecessary work like painting while initializing is not complete
615        $container = $(
616          self.translate(
617            self,
618            firstItemOpts.baseTpl
619              .replace("{{buttons}}", buttonStr)
620              .replace(
621                "{{arrows}}",
622                firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight
623              )
624          )
625        )
626          .attr("id", "fancybox-container-" + self.id)
627          .addClass(firstItemOpts.baseClass)
628          .data("FancyBox", self)
629          .appendTo(firstItemOpts.parentEl);
630  
631        // Create object holding references to jQuery wrapped nodes
632        self.$refs = {
633          container: $container,
634        };
635  
636        [
637          "bg",
638          "inner",
639          "infobar",
640          "toolbar",
641          "stage",
642          "caption",
643          "navigation",
644        ].forEach(function (item) {
645          self.$refs[item] = $container.find(".fancybox-" + item);
646        });
647  
648        self.trigger("onInit");
649  
650        // Enable events, deactive previous instances
651        self.activate();
652  
653        // Build slides, load and reveal content
654        self.jumpTo(self.currIndex);
655      },
656  
657      // Simple i18n support - replaces object keys found in template
658      // with corresponding values
659      // ============================================================
660  
661      translate: function (obj, str) {
662        var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en;
663  
664        return str.replace(/\{\{(\w+)\}\}/g, function (match, n) {
665          return arr[n] === undefined ? match : arr[n];
666        });
667      },
668  
669      // Populate current group with fresh content
670      // Check if each object has valid type and content
671      // ===============================================
672  
673      addContent: function (content) {
674        var self = this,
675          items = $.makeArray(content),
676          thumbs;
677  
678        $.each(items, function (i, item) {
679          var obj = {},
680            opts = {},
681            $item,
682            type,
683            found,
684            src,
685            srcParts;
686  
687          // Step 1 - Make sure we have an object
688          // ====================================
689  
690          if ($.isPlainObject(item)) {
691            // We probably have manual usage here, something like
692            // $.fancybox.open( [ { src : "image.jpg", type : "image" } ] )
693  
694            obj = item;
695            opts = item.opts || item;
696          } else if ($.type(item) === "object" && $(item).length) {
697            // Here we probably have jQuery collection returned by some selector
698            $item = $(item);
699  
700            // Support attributes like `data-options='{"touch" : false}'` and `data-touch='false'`
701            opts = $item.data() || {};
702            opts = $.extend(true, {}, opts, opts.options);
703  
704            // Here we store clicked element
705            opts.$orig = $item;
706  
707            obj.src = self.opts.src || opts.src || $item.attr("href");
708  
709            // Assume that simple syntax is used, for example:
710            //   `$.fancybox.open( $("#test"), {} );`
711            if (!obj.type && !obj.src) {
712              obj.type = "inline";
713              obj.src = item;
714            }
715          } else {
716            // Assume we have a simple html code, for example:
717            //   $.fancybox.open( '<div><h1>Hi!</h1></div>' );
718            obj = {
719              type: "html",
720              src: item + "",
721            };
722          }
723  
724          // Each gallery object has full collection of options
725          obj.opts = $.extend(true, {}, self.opts, opts);
726  
727          // Do not merge buttons array
728          if ($.isArray(opts.buttons)) {
729            obj.opts.buttons = opts.buttons;
730          }
731  
732          if ($.fancybox.isMobile && obj.opts.mobile) {
733            obj.opts = mergeOpts(obj.opts, obj.opts.mobile);
734          }
735  
736          // Step 2 - Make sure we have content type, if not - try to guess
737          // ==============================================================
738  
739          type = obj.type || obj.opts.type;
740          src = obj.src || "";
741  
742          if (!type && src) {
743            if ((found = src.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))) {
744              type = "video";
745  
746              if (!obj.opts.video.format) {
747                obj.opts.video.format =
748                  "video/" + (found[1] === "ogv" ? "ogg" : found[1]);
749              }
750            } else if (
751              src.match(
752                /(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i
753              )
754            ) {
755              type = "image";
756            } else if (src.match(/\.(pdf)((\?|#).*)?$/i)) {
757              type = "iframe";
758              obj = $.extend(true, obj, {
759                contentType: "pdf",
760                opts: {
761                  iframe: {
762                    preload: false,
763                  },
764                },
765              });
766            } else if (src.charAt(0) === "#") {
767              type = "inline";
768            }
769          }
770  
771          if (type) {
772            obj.type = type;
773          } else {
774            self.trigger("objectNeedsType", obj);
775          }
776  
777          if (!obj.contentType) {
778            obj.contentType =
779              $.inArray(obj.type, ["html", "inline", "ajax"]) > -1
780                ? "html"
781                : obj.type;
782          }
783  
784          // Step 3 - Some adjustments
785          // =========================
786  
787          obj.index = self.group.length;
788  
789          if (obj.opts.smallBtn == "auto") {
790            obj.opts.smallBtn =
791              $.inArray(obj.type, ["html", "inline", "ajax"]) > -1;
792          }
793  
794          if (obj.opts.toolbar === "auto") {
795            obj.opts.toolbar = !obj.opts.smallBtn;
796          }
797  
798          // Find thumbnail image, check if exists and if is in the viewport
799          obj.$thumb = obj.opts.$thumb || null;
800  
801          if (obj.opts.$trigger && obj.index === self.opts.index) {
802            obj.$thumb = obj.opts.$trigger.find("img:first");
803  
804            if (obj.$thumb.length) {
805              obj.opts.$orig = obj.opts.$trigger;
806            }
807          }
808  
809          if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) {
810            obj.$thumb = obj.opts.$orig.find("img:first");
811          }
812  
813          if (obj.$thumb && !obj.$thumb.length) {
814            obj.$thumb = null;
815          }
816  
817          obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null);
818  
819          // "caption" is a "special" option, it can be used to customize caption per gallery item
820          if ($.type(obj.opts.caption) === "function") {
821            obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);
822          }
823  
824          if ($.type(self.opts.caption) === "function") {
825            obj.opts.caption = self.opts.caption.apply(item, [self, obj]);
826          }
827  
828          // Make sure we have caption as a string or jQuery object
829          if (!(obj.opts.caption instanceof $)) {
830            obj.opts.caption =
831              obj.opts.caption === undefined ? "" : obj.opts.caption + "";
832          }
833  
834          // Check if url contains "filter" used to filter the content
835          // Example: "ajax.html #something"
836          if (obj.type === "ajax") {
837            srcParts = src.split(/\s+/, 2);
838  
839            if (srcParts.length > 1) {
840              obj.src = srcParts.shift();
841  
842              obj.opts.filter = srcParts.shift();
843            }
844          }
845  
846          // Hide all buttons and disable interactivity for modal items
847          if (obj.opts.modal) {
848            obj.opts = $.extend(true, obj.opts, {
849              trapFocus: true,
850              // Remove buttons
851              infobar: 0,
852              toolbar: 0,
853  
854              smallBtn: 0,
855  
856              // Disable keyboard navigation
857              keyboard: 0,
858  
859              // Disable some modules
860              slideShow: 0,
861              fullScreen: 0,
862              thumbs: 0,
863              touch: 0,
864  
865              // Disable click event handlers
866              clickContent: false,
867              clickSlide: false,
868              clickOutside: false,
869              dblclickContent: false,
870              dblclickSlide: false,
871              dblclickOutside: false,
872            });
873          }
874  
875          // Step 4 - Add processed object to group
876          // ======================================
877  
878          self.group.push(obj);
879        });
880  
881        // Update controls if gallery is already opened
882        if (Object.keys(self.slides).length) {
883          self.updateControls();
884  
885          // Update thumbnails, if needed
886          thumbs = self.Thumbs;
887  
888          if (thumbs && thumbs.isActive) {
889            thumbs.create();
890  
891            thumbs.focus();
892          }
893        }
894      },
895  
896      // Attach an event handler functions for:
897      //   - navigation buttons
898      //   - browser scrolling, resizing;
899      //   - focusing
900      //   - keyboard
901      //   - detecting inactivity
902      // ======================================
903  
904      addEvents: function () {
905        var self = this;
906  
907        self.removeEvents();
908  
909        // Make navigation elements clickable
910        // ==================================
911  
912        self.$refs.container
913          .on("click.fb-close", "[data-fancybox-close]", function (e) {
914            e.stopPropagation();
915            e.preventDefault();
916  
917            self.close(e);
918          })
919          .on(
920            "touchstart.fb-prev click.fb-prev",
921            "[data-fancybox-prev]",
922            function (e) {
923              e.stopPropagation();
924              e.preventDefault();
925  
926              self.previous();
927            }
928          )
929          .on(
930            "touchstart.fb-next click.fb-next",
931            "[data-fancybox-next]",
932            function (e) {
933              e.stopPropagation();
934              e.preventDefault();
935  
936              self.next();
937            }
938          )
939          .on("click.fb", "[data-fancybox-zoom]", function (e) {
940            // Click handler for zoom button
941            self[self.isScaledDown() ? "scaleToActual" : "scaleToFit"]();
942          });
943  
944        // Handle page scrolling and browser resizing
945        // ==========================================
946  
947        $W.on("orientationchange.fb resize.fb", function (e) {
948          if (e && e.originalEvent && e.originalEvent.type === "resize") {
949            if (self.requestId) {
950              cancelAFrame(self.requestId);
951            }
952  
953            self.requestId = requestAFrame(function () {
954              self.update(e);
955            });
956          } else {
957            if (self.current && self.current.type === "iframe") {
958              self.$refs.stage.hide();
959            }
960  
961            setTimeout(
962              function () {
963                self.$refs.stage.show();
964  
965                self.update(e);
966              },
967              $.fancybox.isMobile ? 600 : 250
968            );
969          }
970        });
971  
972        $D.on("keydown.fb", function (e) {
973          var instance = $.fancybox ? $.fancybox.getInstance() : null,
974            current = instance.current,
975            keycode = e.keyCode || e.which;
976  
977          // Trap keyboard focus inside of the modal
978          // =======================================
979  
980          if (keycode == 9) {
981            if (current.opts.trapFocus) {
982              self.focus(e);
983            }
984  
985            return;
986          }
987  
988          // Enable keyboard navigation
989          // ==========================
990  
991          if (
992            !current.opts.keyboard ||
993            e.ctrlKey ||
994            e.altKey ||
995            e.shiftKey ||
996            $(e.target).is("input,textarea,video,audio,select")
997          ) {
998            return;
999          }
1000  
1001          // Backspace and Esc keys
1002          if (keycode === 8 || keycode === 27) {
1003            e.preventDefault();
1004  
1005            self.close(e);
1006  
1007            return;
1008          }
1009  
1010          // Left arrow and Up arrow
1011          if (keycode === 37 || keycode === 38) {
1012            e.preventDefault();
1013  
1014            self.previous();
1015  
1016            return;
1017          }
1018  
1019          // Righ arrow and Down arrow
1020          if (keycode === 39 || keycode === 40) {
1021            e.preventDefault();
1022  
1023            self.next();
1024  
1025            return;
1026          }
1027  
1028          self.trigger("afterKeydown", e, keycode);
1029        });
1030  
1031        // Hide controls after some inactivity period
1032        if (self.group[self.currIndex].opts.idleTime) {
1033          self.idleSecondsCounter = 0;
1034  
1035          $D.on(
1036            "mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle",
1037            function (e) {
1038              self.idleSecondsCounter = 0;
1039  
1040              if (self.isIdle) {
1041                self.showControls();
1042              }
1043  
1044              self.isIdle = false;
1045            }
1046          );
1047  
1048          self.idleInterval = window.setInterval(function () {
1049            self.idleSecondsCounter++;
1050  
1051            if (
1052              self.idleSecondsCounter >=
1053                self.group[self.currIndex].opts.idleTime &&
1054              !self.isDragging
1055            ) {
1056              self.isIdle = true;
1057              self.idleSecondsCounter = 0;
1058  
1059              self.hideControls();
1060            }
1061          }, 1000);
1062        }
1063      },
1064  
1065      // Remove events added by the core
1066      // ===============================
1067  
1068      removeEvents: function () {
1069        var self = this;
1070  
1071        $W.off("orientationchange.fb resize.fb");
1072        $D.off("keydown.fb .fb-idle");
1073  
1074        this.$refs.container.off(".fb-close .fb-prev .fb-next");
1075  
1076        if (self.idleInterval) {
1077          window.clearInterval(self.idleInterval);
1078  
1079          self.idleInterval = null;
1080        }
1081      },
1082  
1083      // Change to previous gallery item
1084      // ===============================
1085  
1086      previous: function (duration) {
1087        return this.jumpTo(this.currPos - 1, duration);
1088      },
1089  
1090      // Change to next gallery item
1091      // ===========================
1092  
1093      next: function (duration) {
1094        return this.jumpTo(this.currPos + 1, duration);
1095      },
1096  
1097      // Switch to selected gallery item
1098      // ===============================
1099  
1100      jumpTo: function (pos, duration) {
1101        var self = this,
1102          groupLen = self.group.length,
1103          firstRun,
1104          isMoved,
1105          loop,
1106          current,
1107          previous,
1108          slidePos,
1109          stagePos,
1110          prop,
1111          diff;
1112  
1113        if (
1114          self.isDragging ||
1115          self.isClosing ||
1116          (self.isAnimating && self.firstRun)
1117        ) {
1118          return;
1119        }
1120  
1121        // Should loop?
1122        pos = parseInt(pos, 10);
1123        loop = self.current ? self.current.opts.loop : self.opts.loop;
1124  
1125        if (!loop && (pos < 0 || pos >= groupLen)) {
1126          return false;
1127        }
1128  
1129        // Check if opening for the first time; this helps to speed things up
1130        firstRun = self.firstRun = !Object.keys(self.slides).length;
1131  
1132        // Create slides
1133        previous = self.current;
1134  
1135        self.prevIndex = self.currIndex;
1136        self.prevPos = self.currPos;
1137  
1138        current = self.createSlide(pos);
1139  
1140        if (groupLen > 1) {
1141          if (loop || current.index < groupLen - 1) {
1142            self.createSlide(pos + 1);
1143          }
1144  
1145          if (loop || current.index > 0) {
1146            self.createSlide(pos - 1);
1147          }
1148        }
1149  
1150        self.current = current;
1151        self.currIndex = current.index;
1152        self.currPos = current.pos;
1153  
1154        self.trigger("beforeShow", firstRun);
1155  
1156        self.updateControls();
1157  
1158        // Validate duration length
1159        current.forcedDuration = undefined;
1160  
1161        if ($.isNumeric(duration)) {
1162          current.forcedDuration = duration;
1163        } else {
1164          duration =
1165            current.opts[firstRun ? "animationDuration" : "transitionDuration"];
1166        }
1167  
1168        duration = parseInt(duration, 10);
1169  
1170        // Check if user has swiped the slides or if still animating
1171        isMoved = self.isMoved(current);
1172  
1173        // Make sure current slide is visible
1174        current.$slide.addClass("fancybox-slide--current");
1175  
1176        // Fresh start - reveal container, current slide and start loading content
1177        if (firstRun) {
1178          if (current.opts.animationEffect && duration) {
1179            self.$refs.container.css("transition-duration", duration + "ms");
1180          }
1181  
1182          self.$refs.container.addClass("fancybox-is-open").trigger("focus");
1183  
1184          // Attempt to load content into slide
1185          // This will later call `afterLoad` -> `revealContent`
1186          self.loadSlide(current);
1187  
1188          self.preload("image");
1189  
1190          return;
1191        }
1192  
1193        // Get actual slide/stage positions (before cleaning up)
1194        slidePos = $.fancybox.getTranslate(previous.$slide);
1195        stagePos = $.fancybox.getTranslate(self.$refs.stage);
1196  
1197        // Clean up all slides
1198        $.each(self.slides, function (index, slide) {
1199          $.fancybox.stop(slide.$slide, true);
1200        });
1201  
1202        if (previous.pos !== current.pos) {
1203          previous.isComplete = false;
1204        }
1205  
1206        previous.$slide.removeClass(
1207          "fancybox-slide--complete fancybox-slide--current"
1208        );
1209  
1210        // If slides are out of place, then animate them to correct position
1211        if (isMoved) {
1212          // Calculate horizontal swipe distance
1213          diff =
1214            slidePos.left -
1215            (previous.pos * slidePos.width + previous.pos * previous.opts.gutter);
1216  
1217          $.each(self.slides, function (index, slide) {
1218            slide.$slide
1219              .removeClass("fancybox-animated")
1220              .removeClass(function (index, className) {
1221                return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(
1222                  " "
1223                );
1224              });
1225  
1226            // Make sure that each slide is in equal distance
1227            // This is mostly needed for freshly added slides, because they are not yet positioned
1228            var leftPos =
1229              slide.pos * slidePos.width + slide.pos * slide.opts.gutter;
1230  
1231            $.fancybox.setTranslate(slide.$slide, {
1232              top: 0,
1233              left: leftPos - stagePos.left + diff,
1234            });
1235  
1236            if (slide.pos !== current.pos) {
1237              slide.$slide.addClass(
1238                "fancybox-slide--" +
1239                  (slide.pos > current.pos ? "next" : "previous")
1240              );
1241            }
1242  
1243            // Redraw to make sure that transition will start
1244            forceRedraw(slide.$slide);
1245  
1246            // Animate the slide
1247            $.fancybox.animate(
1248              slide.$slide,
1249              {
1250                top: 0,
1251                left:
1252                  (slide.pos - current.pos) * slidePos.width +
1253                  (slide.pos - current.pos) * slide.opts.gutter,
1254              },
1255              duration,
1256              function () {
1257                slide.$slide
1258                  .css({
1259                    transform: "",
1260                    opacity: "",
1261                  })
1262                  .removeClass("fancybox-slide--next fancybox-slide--previous");
1263  
1264                if (slide.pos === self.currPos) {
1265                  self.complete();
1266                }
1267              }
1268            );
1269          });
1270        } else if (duration && current.opts.transitionEffect) {
1271          // Set transition effect for previously active slide
1272          prop = "fancybox-animated fancybox-fx-" + current.opts.transitionEffect;
1273  
1274          previous.$slide.addClass(
1275            "fancybox-slide--" +
1276              (previous.pos > current.pos ? "next" : "previous")
1277          );
1278  
1279          $.fancybox.animate(
1280            previous.$slide,
1281            prop,
1282            duration,
1283            function () {
1284              previous.$slide
1285                .removeClass(prop)
1286                .removeClass("fancybox-slide--next fancybox-slide--previous");
1287            },
1288            false
1289          );
1290        }
1291  
1292        if (current.isLoaded) {
1293          self.revealContent(current);
1294        } else {
1295          self.loadSlide(current);
1296        }
1297  
1298        self.preload("image");
1299      },
1300  
1301      // Create new "slide" element
1302      // These are gallery items  that are actually added to DOM
1303      // =======================================================
1304  
1305      createSlide: function (pos) {
1306        var self = this,
1307          $slide,
1308          index;
1309  
1310        index = pos % self.group.length;
1311        index = index < 0 ? self.group.length + index : index;
1312  
1313        if (!self.slides[pos] && self.group[index]) {
1314          $slide = $('<div class="fancybox-slide"></div>').prependTo(
1315            self.$refs.stage
1316          );
1317  
1318          self.slides[pos] = $.extend(true, {}, self.group[index], {
1319            pos: pos,
1320            $slide: $slide,
1321            isLoaded: false,
1322          });
1323  
1324          self.updateSlide(self.slides[pos]);
1325        }
1326  
1327        return self.slides[pos];
1328      },
1329  
1330      // Scale image to the actual size of the image;
1331      // x and y values should be relative to the slide
1332      // ==============================================
1333  
1334      scaleToActual: function (x, y, duration) {
1335        var self = this,
1336          current = self.current,
1337          $content = current.$content,
1338          canvasWidth = $.fancybox.getTranslate(current.$slide).width,
1339          canvasHeight = $.fancybox.getTranslate(current.$slide).height,
1340          newImgWidth = current.width,
1341          newImgHeight = current.height,
1342          imgPos,
1343          posX,
1344          posY,
1345          scaleX,
1346          scaleY;
1347  
1348        if (
1349          self.isAnimating ||
1350          self.isMoved() ||
1351          !$content ||
1352          !(current.type == "image" && current.isLoaded && !current.hasError)
1353        ) {
1354          return;
1355        }
1356  
1357        self.isAnimating = true;
1358  
1359        $.fancybox.stop($content);
1360  
1361        x = x === undefined ? canvasWidth * 0.5 : x;
1362        y = y === undefined ? canvasHeight * 0.5 : y;
1363  
1364        imgPos = $.fancybox.getTranslate($content);
1365  
1366        imgPos.top -= $.fancybox.getTranslate(current.$slide).top;
1367        imgPos.left -= $.fancybox.getTranslate(current.$slide).left;
1368  
1369        scaleX = newImgWidth / imgPos.width;
1370        scaleY = newImgHeight / imgPos.height;
1371  
1372        // Get center position for original image
1373        posX = canvasWidth * 0.5 - newImgWidth * 0.5;
1374        posY = canvasHeight * 0.5 - newImgHeight * 0.5;
1375  
1376        // Make sure image does not move away from edges
1377        if (newImgWidth > canvasWidth) {
1378          posX = imgPos.left * scaleX - (x * scaleX - x);
1379  
1380          if (posX > 0) {
1381            posX = 0;
1382          }
1383  
1384          if (posX < canvasWidth - newImgWidth) {
1385            posX = canvasWidth - newImgWidth;
1386          }
1387        }
1388  
1389        if (newImgHeight > canvasHeight) {
1390          posY = imgPos.top * scaleY - (y * scaleY - y);
1391  
1392          if (posY > 0) {
1393            posY = 0;
1394          }
1395  
1396          if (posY < canvasHeight - newImgHeight) {
1397            posY = canvasHeight - newImgHeight;
1398          }
1399        }
1400  
1401        self.updateCursor(newImgWidth, newImgHeight);
1402  
1403        $.fancybox.animate(
1404          $content,
1405          {
1406            top: posY,
1407            left: posX,
1408            scaleX: scaleX,
1409            scaleY: scaleY,
1410          },
1411          duration || 366,
1412          function () {
1413            self.isAnimating = false;
1414          }
1415        );
1416  
1417        // Stop slideshow
1418        if (self.SlideShow && self.SlideShow.isActive) {
1419          self.SlideShow.stop();
1420        }
1421      },
1422  
1423      // Scale image to fit inside parent element
1424      // ========================================
1425  
1426      scaleToFit: function (duration) {
1427        var self = this,
1428          current = self.current,
1429          $content = current.$content,
1430          end;
1431  
1432        if (
1433          self.isAnimating ||
1434          self.isMoved() ||
1435          !$content ||
1436          !(current.type == "image" && current.isLoaded && !current.hasError)
1437        ) {
1438          return;
1439        }
1440  
1441        self.isAnimating = true;
1442  
1443        $.fancybox.stop($content);
1444  
1445        end = self.getFitPos(current);
1446  
1447        self.updateCursor(end.width, end.height);
1448  
1449        $.fancybox.animate(
1450          $content,
1451          {
1452            top: end.top,
1453            left: end.left,
1454            scaleX: end.width / $content.width(),
1455            scaleY: end.height / $content.height(),
1456          },
1457          duration || 366,
1458          function () {
1459            self.isAnimating = false;
1460          }
1461        );
1462      },
1463  
1464      // Calculate image size to fit inside viewport
1465      // ===========================================
1466  
1467      getFitPos: function (slide) {
1468        var self = this,
1469          $content = slide.$content,
1470          $slide = slide.$slide,
1471          width = slide.width || slide.opts.width,
1472          height = slide.height || slide.opts.height,
1473          maxWidth,
1474          maxHeight,
1475          minRatio,
1476          aspectRatio,
1477          rez = {};
1478  
1479        if (!slide.isLoaded || !$content || !$content.length) {
1480          return false;
1481        }
1482  
1483        maxWidth = $.fancybox.getTranslate(self.$refs.stage).width;
1484        maxHeight = $.fancybox.getTranslate(self.$refs.stage).height;
1485  
1486        maxWidth -=
1487          parseFloat($slide.css("paddingLeft")) +
1488          parseFloat($slide.css("paddingRight")) +
1489          parseFloat($content.css("marginLeft")) +
1490          parseFloat($content.css("marginRight"));
1491  
1492        maxHeight -=
1493          parseFloat($slide.css("paddingTop")) +
1494          parseFloat($slide.css("paddingBottom")) +
1495          parseFloat($content.css("marginTop")) +
1496          parseFloat($content.css("marginBottom"));
1497  
1498        if (!width || !height) {
1499          width = maxWidth;
1500          height = maxHeight;
1501        }
1502  
1503        minRatio = Math.min(1, maxWidth / width, maxHeight / height);
1504  
1505        width = minRatio * width;
1506        height = minRatio * height;
1507  
1508        // Adjust width/height to precisely fit into container
1509        if (width > maxWidth - 0.5) {
1510          width = maxWidth;
1511        }
1512  
1513        if (height > maxHeight - 0.5) {
1514          height = maxHeight;
1515        }
1516  
1517        if (slide.type === "image") {
1518          rez.top =
1519            Math.floor((maxHeight - height) * 0.5) +
1520            parseFloat($slide.css("paddingTop"));
1521          rez.left =
1522            Math.floor((maxWidth - width) * 0.5) +
1523            parseFloat($slide.css("paddingLeft"));
1524        } else if (slide.contentType === "video") {
1525          // Force aspect ratio for the video
1526          // "I say the whole world must learn of our peaceful ways… by force!"
1527          aspectRatio =
1528            slide.opts.width && slide.opts.height
1529              ? width / height
1530              : slide.opts.ratio || 16 / 9;
1531  
1532          if (height > width / aspectRatio) {
1533            height = width / aspectRatio;
1534          } else if (width > height * aspectRatio) {
1535            width = height * aspectRatio;
1536          }
1537        }
1538  
1539        rez.width = width;
1540        rez.height = height;
1541  
1542        return rez;
1543      },
1544  
1545      // Update content size and position for all slides
1546      // ==============================================
1547  
1548      update: function (e) {
1549        var self = this;
1550  
1551        $.each(self.slides, function (key, slide) {
1552          self.updateSlide(slide, e);
1553        });
1554      },
1555  
1556      // Update slide content position and size
1557      // ======================================
1558  
1559      updateSlide: function (slide, e) {
1560        var self = this,
1561          $content = slide && slide.$content,
1562          width = slide.width || slide.opts.width,
1563          height = slide.height || slide.opts.height,
1564          $slide = slide.$slide;
1565  
1566        // First, prevent caption overlap, if needed
1567        self.adjustCaption(slide);
1568  
1569        // Then resize content to fit inside the slide
1570        if (
1571          $content &&
1572          (width || height || slide.contentType === "video") &&
1573          !slide.hasError
1574        ) {
1575          $.fancybox.stop($content);
1576  
1577          $.fancybox.setTranslate($content, self.getFitPos(slide));
1578  
1579          if (slide.pos === self.currPos) {
1580            self.isAnimating = false;
1581  
1582            self.updateCursor();
1583          }
1584        }
1585  
1586        // Then some adjustments
1587        self.adjustLayout(slide);
1588  
1589        if ($slide.length) {
1590          $slide.trigger("refresh");
1591  
1592          if (slide.pos === self.currPos) {
1593            self.$refs.toolbar
1594              .add(self.$refs.navigation.find(".fancybox-button--arrow_right"))
1595              .toggleClass(
1596                "compensate-for-scrollbar",
1597                $slide.get(0).scrollHeight > $slide.get(0).clientHeight
1598              );
1599          }
1600        }
1601  
1602        self.trigger("onUpdate", slide, e);
1603      },
1604  
1605      // Horizontally center slide
1606      // =========================
1607  
1608      centerSlide: function (duration) {
1609        var self = this,
1610          current = self.current,
1611          $slide = current.$slide;
1612  
1613        if (self.isClosing || !current) {
1614          return;
1615        }
1616  
1617        $slide.siblings().css({
1618          transform: "",
1619          opacity: "",
1620        });
1621  
1622        $slide
1623          .parent()
1624          .children()
1625          .removeClass("fancybox-slide--previous fancybox-slide--next");
1626  
1627        $.fancybox.animate(
1628          $slide,
1629          {
1630            top: 0,
1631            left: 0,
1632            opacity: 1,
1633          },
1634          duration === undefined ? 0 : duration,
1635          function () {
1636            // Clean up
1637            $slide.css({
1638              transform: "",
1639              opacity: "",
1640            });
1641  
1642            if (!current.isComplete) {
1643              self.complete();
1644            }
1645          },
1646          false
1647        );
1648      },
1649  
1650      // Check if current slide is moved (swiped)
1651      // ========================================
1652  
1653      isMoved: function (slide) {
1654        var current = slide || this.current,
1655          slidePos,
1656          stagePos;
1657  
1658        if (!current) {
1659          return false;
1660        }
1661  
1662        stagePos = $.fancybox.getTranslate(this.$refs.stage);
1663        slidePos = $.fancybox.getTranslate(current.$slide);
1664  
1665        return (
1666          !current.$slide.hasClass("fancybox-animated") &&
1667          (Math.abs(slidePos.top - stagePos.top) > 0.5 ||
1668            Math.abs(slidePos.left - stagePos.left) > 0.5)
1669        );
1670      },
1671  
1672      // Update cursor style depending if content can be zoomed
1673      // ======================================================
1674  
1675      updateCursor: function (nextWidth, nextHeight) {
1676        var self = this,
1677          current = self.current,
1678          $container = self.$refs.container,
1679          canPan,
1680          isZoomable;
1681  
1682        if (!current || self.isClosing || !self.Guestures) {
1683          return;
1684        }
1685  
1686        $container.removeClass(
1687          "fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"
1688        );
1689  
1690        canPan = self.canPan(nextWidth, nextHeight);
1691  
1692        isZoomable = canPan ? true : self.isZoomable();
1693  
1694        $container.toggleClass("fancybox-is-zoomable", isZoomable);
1695  
1696        $("[data-fancybox-zoom]").prop("disabled", !isZoomable);
1697  
1698        if (canPan) {
1699          $container.addClass("fancybox-can-pan");
1700        } else if (
1701          isZoomable &&
1702          (current.opts.clickContent === "zoom" ||
1703            ($.isFunction(current.opts.clickContent) &&
1704              current.opts.clickContent(current) == "zoom"))
1705        ) {
1706          $container.addClass("fancybox-can-zoomIn");
1707        } else if (
1708          current.opts.touch &&
1709          (current.opts.touch.vertical || self.group.length > 1) &&
1710          current.contentType !== "video"
1711        ) {
1712          $container.addClass("fancybox-can-swipe");
1713        }
1714      },
1715  
1716      // Check if current slide is zoomable
1717      // ==================================
1718  
1719      isZoomable: function () {
1720        var self = this,
1721          current = self.current,
1722          fitPos;
1723  
1724        // Assume that slide is zoomable if:
1725        //   - image is still loading
1726        //   - actual size of the image is smaller than available area
1727        if (
1728          current &&
1729          !self.isClosing &&
1730          current.type === "image" &&
1731          !current.hasError
1732        ) {
1733          if (!current.isLoaded) {
1734            return true;
1735          }
1736  
1737          fitPos = self.getFitPos(current);
1738  
1739          if (
1740            fitPos &&
1741            (current.width > fitPos.width || current.height > fitPos.height)
1742          ) {
1743            return true;
1744          }
1745        }
1746  
1747        return false;
1748      },
1749  
1750      // Check if current image dimensions are smaller than actual
1751      // =========================================================
1752  
1753      isScaledDown: function (nextWidth, nextHeight) {
1754        var self = this,
1755          rez = false,
1756          current = self.current,
1757          $content = current.$content;
1758  
1759        if (nextWidth !== undefined && nextHeight !== undefined) {
1760          rez = nextWidth < current.width && nextHeight < current.height;
1761        } else if ($content) {
1762          rez = $.fancybox.getTranslate($content);
1763          rez = rez.width < current.width && rez.height < current.height;
1764        }
1765  
1766        return rez;
1767      },
1768  
1769      // Check if image dimensions exceed parent element
1770      // ===============================================
1771  
1772      canPan: function (nextWidth, nextHeight) {
1773        var self = this,
1774          current = self.current,
1775          pos = null,
1776          rez = false;
1777  
1778        if (
1779          current.type === "image" &&
1780          (current.isComplete || (nextWidth && nextHeight)) &&
1781          !current.hasError
1782        ) {
1783          rez = self.getFitPos(current);
1784  
1785          if (nextWidth !== undefined && nextHeight !== undefined) {
1786            pos = {
1787              width: nextWidth,
1788              height: nextHeight,
1789            };
1790          } else if (current.isComplete) {
1791            pos = $.fancybox.getTranslate(current.$content);
1792          }
1793  
1794          if (pos && rez) {
1795            rez =
1796              Math.abs(pos.width - rez.width) > 1.5 ||
1797              Math.abs(pos.height - rez.height) > 1.5;
1798          }
1799        }
1800  
1801        return rez;
1802      },
1803  
1804      // Load content into the slide
1805      // ===========================
1806  
1807      loadSlide: function (slide) {
1808        var self = this,
1809          type,
1810          $slide,
1811          ajaxLoad;
1812  
1813        if (slide.isLoading || slide.isLoaded) {
1814          return;
1815        }
1816  
1817        slide.isLoading = true;
1818  
1819        if (self.trigger("beforeLoad", slide) === false) {
1820          slide.isLoading = false;
1821  
1822          return false;
1823        }
1824  
1825        type = slide.type;
1826        $slide = slide.$slide;
1827  
1828        $slide.off("refresh").trigger("onReset").addClass(slide.opts.slideClass);
1829  
1830        // Create content depending on the type
1831        switch (type) {
1832          case "image":
1833            self.setImage(slide);
1834  
1835            break;
1836  
1837          case "iframe":
1838            self.setIframe(slide);
1839  
1840            break;
1841  
1842          case "html":
1843            self.setContent(slide, slide.src || slide.content);
1844  
1845            break;
1846  
1847          case "video":
1848            self.setContent(
1849              slide,
1850              slide.opts.video.tpl
1851                .replace(/\{\{src\}\}/gi, slide.src)
1852                .replace(
1853                  "{{format}}",
1854                  slide.opts.videoFormat || slide.opts.video.format || ""
1855                )
1856                .replace("{{poster}}", slide.thumb || "")
1857            );
1858  
1859            break;
1860  
1861          case "inline":
1862            if ($(slide.src).length) {
1863              self.setContent(slide, $(slide.src));
1864            } else {
1865              self.setError(slide);
1866            }
1867  
1868            break;
1869  
1870          case "ajax":
1871            self.showLoading(slide);
1872  
1873            ajaxLoad = $.ajax(
1874              $.extend({}, slide.opts.ajax.settings, {
1875                url: slide.src,
1876                success: function (data, textStatus) {
1877                  if (textStatus === "success") {
1878                    self.setContent(slide, data);
1879                  }
1880                },
1881                error: function (jqXHR, textStatus) {
1882                  if (jqXHR && textStatus !== "abort") {
1883                    self.setError(slide);
1884                  }
1885                },
1886              })
1887            );
1888  
1889            $slide.one("onReset", function () {
1890              ajaxLoad.abort();
1891            });
1892  
1893            break;
1894  
1895          default:
1896            self.setError(slide);
1897  
1898            break;
1899        }
1900  
1901        return true;
1902      },
1903  
1904      // Use thumbnail image, if possible
1905      // ================================
1906  
1907      setImage: function (slide) {
1908        var self = this,
1909          ghost;
1910  
1911        // Check if need to show loading icon
1912        setTimeout(function () {
1913          var $img = slide.$image;
1914  
1915          if (
1916            !self.isClosing &&
1917            slide.isLoading &&
1918            (!$img || !$img.length || !$img[0].complete) &&
1919            !slide.hasError
1920          ) {
1921            self.showLoading(slide);
1922          }
1923        }, 50);
1924  
1925        //Check if image has srcset
1926        self.checkSrcset(slide);
1927  
1928        // This will be wrapper containing both ghost and actual image
1929        slide.$content = $('<div class="fancybox-content"><div class="cloned-caption"></div></div>')
1930          .addClass("fancybox-is-hidden")
1931          .appendTo(slide.$slide.addClass("fancybox-slide--image"));
1932  
1933        // If we have a thumbnail, we can display it while actual image is loading
1934        // Users will not stare at black screen and actual image will appear gradually
1935        if (
1936          slide.opts.preload !== false &&
1937          slide.opts.width &&
1938          slide.opts.height &&
1939          slide.thumb
1940        ) {
1941          slide.width = slide.opts.width;
1942          slide.height = slide.opts.height;
1943  
1944          ghost = document.createElement("img");
1945  
1946          ghost.onerror = function () {
1947            $(this).remove();
1948  
1949            slide.$ghost = null;
1950          };
1951  
1952          ghost.onload = function () {
1953            self.afterLoad(slide);
1954          };
1955  
1956          slide.$ghost = $(ghost)
1957            .addClass("fancybox-image")
1958            .prependTo(slide.$content)
1959            .attr("src", slide.thumb);
1960        }
1961  
1962        // Start loading actual image
1963        self.setBigImage(slide);
1964      },
1965  
1966      // Check if image has srcset and get the source
1967      // ============================================
1968      checkSrcset: function (slide) {
1969        var srcset = slide.opts.srcset || slide.opts.image.srcset,
1970          found,
1971          temp,
1972          pxRatio,
1973          windowWidth;
1974  
1975        // If we have "srcset", then we need to find first matching "src" value.
1976        // This is necessary, because when you set an src attribute, the browser will preload the image
1977        // before any javascript or even CSS is applied.
1978        if (srcset) {
1979          pxRatio = window.devicePixelRatio || 1;
1980          windowWidth = window.innerWidth * pxRatio;
1981  
1982          temp = srcset.split(",").map(function (el) {
1983            var ret = {};
1984  
1985            el.trim()
1986              .split(/\s+/)
1987              .forEach(function (el, i) {
1988                var value = parseInt(el.substring(0, el.length - 1), 10);
1989  
1990                if (i === 0) {
1991                  return (ret.url = el);
1992                }
1993  
1994                if (value) {
1995                  ret.value = value;
1996                  ret.postfix = el[el.length - 1];
1997                }
1998              });
1999  
2000            return ret;
2001          });
2002  
2003          // Sort by value
2004          temp.sort(function (a, b) {
2005            return a.value - b.value;
2006          });
2007  
2008          // Ok, now we have an array of all srcset values
2009          for (var j = 0; j < temp.length; j++) {
2010            var el = temp[j];
2011  
2012            if (
2013              (el.postfix === "w" && el.value >= windowWidth) ||
2014              (el.postfix === "x" && el.value >= pxRatio)
2015            ) {
2016              found = el;
2017              break;
2018            }
2019          }
2020  
2021          // If not found, take the last one
2022          if (!found && temp.length) {
2023            found = temp[temp.length - 1];
2024          }
2025  
2026          if (found) {
2027            slide.src = found.url;
2028  
2029            // If we have default width/height values, we can calculate height for matching source
2030            if (slide.width && slide.height && found.postfix == "w") {
2031              slide.height = (slide.width / slide.height) * found.value;
2032              slide.width = found.value;
2033            }
2034  
2035            slide.opts.srcset = srcset;
2036          }
2037        }
2038      },
2039  
2040      // Create full-size image
2041      // ======================
2042  
2043      setBigImage: function (slide) {
2044        var self = this,
2045          img = document.createElement("img"),
2046          $img = $(img);
2047  
2048        slide.$image = $img
2049          .one("error", function () {
2050            self.setError(slide);
2051          })
2052          .one("load", function () {
2053            var sizes;
2054  
2055            if (!slide.$ghost) {
2056              self.resolveImageSlideSize(
2057                slide,
2058                this.naturalWidth,
2059                this.naturalHeight
2060              );
2061  
2062              self.afterLoad(slide);
2063            }
2064  
2065            if (self.isClosing) {
2066              return;
2067            }
2068  
2069            if (slide.opts.srcset) {
2070              sizes = slide.opts.sizes;
2071  
2072              if (!sizes || sizes === "auto") {
2073                sizes =
2074                  (slide.width / slide.height > 1 && $W.width() / $W.height() > 1
2075                    ? "100"
2076                    : Math.round((slide.width / slide.height) * 100)) + "vw";
2077              }
2078  
2079              $img.attr("sizes", sizes).attr("srcset", slide.opts.srcset);
2080            }
2081  
2082            // Hide temporary image after some delay
2083            if (slide.$ghost) {
2084              setTimeout(function () {
2085                if (slide.$ghost && !self.isClosing) {
2086                  slide.$ghost.hide();
2087                }
2088              }, Math.min(300, Math.max(1000, slide.height / 1600)));
2089            }
2090  
2091            self.hideLoading(slide);
2092          })
2093          .addClass("fancybox-image")
2094          .attr("src", slide.src)
2095          .prependTo(slide.$content);
2096  
2097        if (
2098          (img.complete || img.readyState == "complete") &&
2099          $img.naturalWidth &&
2100          $img.naturalHeight
2101        ) {
2102          $img.trigger("load");
2103        } else if (img.error) {
2104          $img.trigger("error");
2105        }
2106      },
2107  
2108      // Computes the slide size from image size and maxWidth/maxHeight
2109      // ==============================================================
2110  
2111      resolveImageSlideSize: function (slide, imgWidth, imgHeight) {
2112        var maxWidth = parseInt(slide.opts.width, 10),
2113          maxHeight = parseInt(slide.opts.height, 10);
2114  
2115        // Sets the default values from the image
2116        slide.width = imgWidth;
2117        slide.height = imgHeight;
2118  
2119        if (maxWidth > 0) {
2120          slide.width = maxWidth;
2121          slide.height = Math.floor((maxWidth * imgHeight) / imgWidth);
2122        }
2123  
2124        if (maxHeight > 0) {
2125          slide.width = Math.floor((maxHeight * imgWidth) / imgHeight);
2126          slide.height = maxHeight;
2127        }
2128      },
2129  
2130      // Create iframe wrapper, iframe and bindings
2131      // ==========================================
2132  
2133      setIframe: function (slide) {
2134        var self = this,
2135          opts = slide.opts.iframe,
2136          $slide = slide.$slide,
2137          $iframe;
2138  
2139        slide.$content = $(
2140          '<div class="fancybox-content' +
2141            (opts.preload ? " fancybox-is-hidden" : "") +
2142            '"></div>'
2143        )
2144          .css(opts.css)
2145          .appendTo($slide);
2146  
2147        $slide.addClass("fancybox-slide--" + slide.contentType);
2148  
2149        slide.$iframe = $iframe = $(
2150          opts.tpl.replace(/\{rnd\}/g, new Date().getTime())
2151        )
2152          .attr(opts.attr)
2153          .appendTo(slide.$content);
2154  
2155        if (opts.preload) {
2156          self.showLoading(slide);
2157  
2158          // Unfortunately, it is not always possible to determine if iframe is successfully loaded
2159          // (due to browser security policy)
2160  
2161          $iframe.on("load.fb error.fb", function (e) {
2162            this.isReady = 1;
2163  
2164            slide.$slide.trigger("refresh");
2165  
2166            self.afterLoad(slide);
2167          });
2168  
2169          // Recalculate iframe content size
2170          // ===============================
2171  
2172          $slide.on("refresh.fb", function () {
2173            var $content = slide.$content,
2174              frameWidth = opts.css.width,
2175              frameHeight = opts.css.height,
2176              $contents,
2177              $body;
2178  
2179            if ($iframe[0].isReady !== 1) {
2180              return;
2181            }
2182  
2183            try {
2184              $contents = $iframe.contents();
2185              $body = $contents.find("body");
2186            } catch (ignore) {}
2187  
2188            // Calculate content dimensions, if it is accessible
2189            if ($body && $body.length && $body.children().length) {
2190              // Avoid scrolling to top (if multiple instances)
2191              $slide.css("overflow", "visible");
2192  
2193              $content.css({
2194                width: "100%",
2195                "max-width": "100%",
2196                height: "9999px",
2197              });
2198  
2199              if (frameWidth === undefined) {
2200                frameWidth = Math.ceil(
2201                  Math.max($body[0].clientWidth, $body.outerWidth(true))
2202                );
2203              }
2204  
2205              $content
2206                .css("width", frameWidth ? frameWidth : "")
2207                .css("max-width", "");
2208  
2209              if (frameHeight === undefined) {
2210                frameHeight = Math.ceil(
2211                  Math.max($body[0].clientHeight, $body.outerHeight(true))
2212                );
2213              }
2214  
2215              $content.css("height", frameHeight ? frameHeight : "");
2216  
2217              $slide.css("overflow", "auto");
2218            }
2219  
2220            $content.removeClass("fancybox-is-hidden");
2221          });
2222        } else {
2223          self.afterLoad(slide);
2224        }
2225  
2226        $iframe.attr("src", slide.src);
2227  
2228        // Remove iframe if closing or changing gallery item
2229        $slide.one("onReset", function () {
2230          // This helps IE not to throw errors when closing
2231          try {
2232            $(this).find("iframe").hide().unbind().attr("src", "//about:blank");
2233          } catch (ignore) {}
2234  
2235          $(this).off("refresh.fb").empty();
2236  
2237          slide.isLoaded = false;
2238          slide.isRevealed = false;
2239        });
2240      },
2241  
2242      // Wrap and append content to the slide
2243      // ======================================
2244  
2245      setContent: function (slide, content) {
2246        var self = this;
2247  
2248        if (self.isClosing) {
2249          return;
2250        }
2251  
2252        self.hideLoading(slide);
2253  
2254        if (slide.$content) {
2255          $.fancybox.stop(slide.$content);
2256        }
2257  
2258        slide.$slide.empty();
2259  
2260        // If content is a jQuery object, then it will be moved to the slide.
2261        // The placeholder is created so we will know where to put it back.
2262        if (isQuery(content) && content.parent().length) {
2263          // Make sure content is not already moved to fancyBox
2264          if (
2265            content.hasClass("fancybox-content") ||
2266            content.parent().hasClass("fancybox-content")
2267          ) {
2268            content.parents(".fancybox-slide").trigger("onReset");
2269          }
2270  
2271          // Create temporary element marking original place of the content
2272          slide.$placeholder = $("<div>").hide().insertAfter(content);
2273  
2274          // Make sure content is visible
2275          content.css("display", "inline-block");
2276        } else if (!slide.hasError) {
2277          // If content is just a plain text, try to convert it to html
2278          if ($.type(content) === "string") {
2279            content = $("<div>").append($.trim(content)).contents();
2280          }
2281  
2282          // If "filter" option is provided, then filter content
2283          if (slide.opts.filter) {
2284            content = $("<div>").html(content).find(slide.opts.filter);
2285          }
2286        }
2287  
2288        slide.$slide.one("onReset", function () {
2289          // Pause all html5 video/audio
2290          $(this).find("video,audio").trigger("pause");
2291  
2292          // Put content back
2293          if (slide.$placeholder) {
2294            slide.$placeholder
2295              .after(content.removeClass("fancybox-content").hide())
2296              .remove();
2297  
2298            slide.$placeholder = null;
2299          }
2300  
2301          // Remove custom close button
2302          if (slide.$smallBtn) {
2303            slide.$smallBtn.remove();
2304  
2305            slide.$smallBtn = null;
2306          }
2307  
2308          // Remove content and mark slide as not loaded
2309          if (!slide.hasError) {
2310            $(this).empty();
2311  
2312            slide.isLoaded = false;
2313            slide.isRevealed = false;
2314          }
2315        });
2316  
2317        $(content).appendTo(slide.$slide);
2318  
2319        if ($(content).is("video,audio")) {
2320          $(content).addClass("fancybox-video");
2321  
2322          $(content).wrap("<div></div>");
2323  
2324          slide.contentType = "video";
2325  
2326          slide.opts.width = slide.opts.width || $(content).attr("width");
2327          slide.opts.height = slide.opts.height || $(content).attr("height");
2328        }
2329  
2330        slide.$content = slide.$slide
2331          .children()
2332          .filter("div,form,main,video,audio,article,.fancybox-content")
2333          .first();
2334  
2335        slide.$content.siblings().hide();
2336  
2337        // Re-check if there is a valid content
2338        // (in some cases, ajax response can contain various elements or plain text)
2339        if (!slide.$content.length) {
2340          slide.$content = slide.$slide
2341            .wrapInner("<div></div>")
2342            .children()
2343            .first();
2344        }
2345  
2346        slide.$content.addClass("fancybox-content");
2347  
2348        slide.$slide.addClass("fancybox-slide--" + slide.contentType);
2349  
2350        self.afterLoad(slide);
2351      },
2352  
2353      // Display error message
2354      // =====================
2355  
2356      setError: function (slide) {
2357        slide.hasError = true;
2358  
2359        slide.$slide
2360          .trigger("onReset")
2361          .removeClass("fancybox-slide--" + slide.contentType)
2362          .addClass("fancybox-slide--error");
2363  
2364        slide.contentType = "html";
2365  
2366        this.setContent(slide, this.translate(slide, slide.opts.errorTpl));
2367  
2368        if (slide.pos === this.currPos) {
2369          this.isAnimating = false;
2370        }
2371      },
2372  
2373      // Show loading icon inside the slide
2374      // ==================================
2375  
2376      showLoading: function (slide) {
2377        var self = this;
2378  
2379        slide = slide || self.current;
2380  
2381        if (slide && !slide.$spinner) {
2382          slide.$spinner = $(self.translate(self, self.opts.spinnerTpl))
2383            .appendTo(slide.$slide)
2384            .hide()
2385            .fadeIn("fast");
2386        }
2387      },
2388  
2389      // Remove loading icon from the slide
2390      // ==================================
2391  
2392      hideLoading: function (slide) {
2393        var self = this;
2394  
2395        slide = slide || self.current;
2396  
2397        if (slide && slide.$spinner) {
2398          slide.$spinner.stop().remove();
2399  
2400          delete slide.$spinner;
2401        }
2402      },
2403  
2404      // Adjustments after slide content has been loaded
2405      // ===============================================
2406  
2407      afterLoad: function (slide) {
2408        var self = this;
2409  
2410        if (self.isClosing) {
2411          return;
2412        }
2413  
2414        slide.isLoading = false;
2415        slide.isLoaded = true;
2416  
2417        self.trigger("afterLoad", slide);
2418  
2419        self.hideLoading(slide);
2420  
2421        // Add small close button
2422        if (
2423          slide.opts.smallBtn &&
2424          (!slide.$smallBtn || !slide.$smallBtn.length)
2425        ) {
2426          slide.$smallBtn = $(
2427            self.translate(slide, slide.opts.btnTpl.smallBtn)
2428          ).appendTo(slide.$content);
2429        }
2430  
2431        // Disable right click
2432        if (slide.opts.protect && slide.$content && !slide.hasError) {
2433          slide.$content.on("contextmenu.fb", function (e) {
2434            if (e.button == 2) {
2435              e.preventDefault();
2436            }
2437  
2438            return true;
2439          });
2440  
2441          // Add fake element on top of the image
2442          // This makes a bit harder for user to select image
2443          if (slide.type === "image") {
2444            $('<div class="fancybox-spaceball"></div>').appendTo(slide.$content);
2445          }
2446        }
2447  
2448        self.adjustCaption(slide);
2449  
2450        self.adjustLayout(slide);
2451  
2452        if (slide.pos === self.currPos) {
2453          self.updateCursor();
2454        }
2455  
2456        self.revealContent(slide);
2457      },
2458  
2459      // Prevent caption overlap,
2460      // fix css inconsistency across browsers
2461      // =====================================
2462  
2463      adjustCaption: function (slide) {
2464        var self = this,
2465          current = slide || self.current,
2466          caption = current.opts.caption,
2467          preventOverlap = current.opts.preventCaptionOverlap,
2468          $caption = self.$refs.caption,
2469          $clone,
2470          captionH = false;
2471  
2472        $caption.toggleClass("fancybox-caption--separate", preventOverlap);
2473        $('.fancybox-caption').remove();
2474        $caption.appendTo('.cloned-caption');
2475        if (preventOverlap && caption && caption.length) {
2476          if (current.pos !== self.currPos) {
2477            $clone = $caption.clone().appendTo($caption.parent());
2478  
2479            $clone.children().eq(0).empty().html(caption);
2480  
2481            captionH = $clone.outerHeight(true);
2482  
2483            $clone.empty().remove();
2484          } else if (self.$caption) {
2485            captionH = self.$caption.outerHeight(true);
2486          }
2487  
2488          current.$slide.css("padding-bottom", captionH || "");
2489        }
2490      },
2491  
2492      // Simple hack to fix inconsistency across browsers, described here (affects Edge, too):
2493      // https://bugzilla.mozilla.org/show_bug.cgi?id=748518
2494      // ====================================================================================
2495  
2496      adjustLayout: function (slide) {
2497        var self = this,
2498          current = slide || self.current,
2499          scrollHeight,
2500          marginBottom,
2501          inlinePadding,
2502          actualPadding;
2503  
2504        if (current.isLoaded && current.opts.disableLayoutFix !== true) {
2505          current.$content.css("margin-bottom", "");
2506  
2507          // If we would always set margin-bottom for the content,
2508          // then it would potentially break vertical align
2509          if (current.$content.outerHeight() > current.$slide.height() + 0.5) {
2510            inlinePadding = current.$slide[0].style["padding-bottom"];
2511            actualPadding = current.$slide.css("padding-bottom");
2512  
2513            if (parseFloat(actualPadding) > 0) {
2514              scrollHeight = current.$slide[0].scrollHeight;
2515  
2516              current.$slide.css("padding-bottom", 0);
2517  
2518              if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) {
2519                marginBottom = actualPadding;
2520              }
2521  
2522              current.$slide.css("padding-bottom", inlinePadding);
2523            }
2524          }
2525  
2526          current.$content.css("margin-bottom", marginBottom);
2527        }
2528      },
2529  
2530      // Make content visible
2531      // This method is called right after content has been loaded or
2532      // user navigates gallery and transition should start
2533      // ============================================================
2534  
2535      revealContent: function (slide) {
2536        var self = this,
2537          $slide = slide.$slide,
2538          end = false,
2539          start = false,
2540          isMoved = self.isMoved(slide),
2541          isRevealed = slide.isRevealed,
2542          effect,
2543          effectClassName,
2544          duration,
2545          opacity;
2546  
2547        slide.isRevealed = true;
2548  
2549        effect =
2550          slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"];
2551        duration =
2552          slide.opts[self.firstRun ? "animationDuration" : "transitionDuration"];
2553  
2554        duration = parseInt(
2555          slide.forcedDuration === undefined ? duration : slide.forcedDuration,
2556          10
2557        );
2558  
2559        if (isMoved || slide.pos !== self.currPos || !duration) {
2560          effect = false;
2561        }
2562  
2563        // Check if can zoom
2564        if (effect === "zoom") {
2565          if (
2566            slide.pos === self.currPos &&
2567            duration &&
2568            slide.type === "image" &&
2569            !slide.hasError &&
2570            (start = self.getThumbPos(slide))
2571          ) {
2572            end = self.getFitPos(slide);
2573          } else {
2574            effect = "fade";
2575          }
2576        }
2577  
2578        // Zoom animation
2579        // ==============
2580        if (effect === "zoom") {
2581          self.isAnimating = true;
2582  
2583          end.scaleX = end.width / start.width;
2584          end.scaleY = end.height / start.height;
2585  
2586          // Check if we need to animate opacity
2587          opacity = slide.opts.zoomOpacity;
2588  
2589          if (opacity == "auto") {
2590            opacity =
2591              Math.abs(slide.width / slide.height - start.width / start.height) >
2592              0.1;
2593          }
2594  
2595          if (opacity) {
2596            start.opacity = 0.1;
2597            end.opacity = 1;
2598          }
2599  
2600          // Draw image at start position
2601          $.fancybox.setTranslate(
2602            slide.$content.removeClass("fancybox-is-hidden"),
2603            start
2604          );
2605  
2606          forceRedraw(slide.$content);
2607  
2608          // Start animation
2609          $.fancybox.animate(slide.$content, end, duration, function () {
2610            self.isAnimating = false;
2611  
2612            self.complete();
2613          });
2614  
2615          return;
2616        }
2617  
2618        self.updateSlide(slide);
2619  
2620        // Simply show content if no effect
2621        // ================================
2622        if (!effect) {
2623          slide.$content.removeClass("fancybox-is-hidden");
2624  
2625          if (
2626            !isRevealed &&
2627            isMoved &&
2628            slide.type === "image" &&
2629            !slide.hasError
2630          ) {
2631            slide.$content.hide().fadeIn("fast");
2632          }
2633  
2634          if (slide.pos === self.currPos) {
2635            self.complete();
2636          }
2637  
2638          return;
2639        }
2640  
2641        // Prepare for CSS transiton
2642        // =========================
2643        $.fancybox.stop($slide);
2644  
2645        //effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect;
2646        effectClassName =
2647          "fancybox-slide--" +
2648          (slide.pos >= self.prevPos ? "next" : "previous") +
2649          " fancybox-animated fancybox-fx-" +
2650          effect;
2651  
2652        $slide.addClass(effectClassName).removeClass("fancybox-slide--current"); //.addClass(effectClassName);
2653  
2654        slide.$content.removeClass("fancybox-is-hidden");
2655  
2656        // Force reflow
2657        forceRedraw($slide);
2658  
2659        if (slide.type !== "image") {
2660          slide.$content.hide().show(0);
2661        }
2662  
2663        $.fancybox.animate(
2664          $slide,
2665          "fancybox-slide--current",
2666          duration,
2667          function () {
2668            $slide.removeClass(effectClassName).css({
2669              transform: "",
2670              opacity: "",
2671            });
2672  
2673            if (slide.pos === self.currPos) {
2674              self.complete();
2675            }
2676          },
2677          true
2678        );
2679      },
2680  
2681      // Check if we can and have to zoom from thumbnail
2682      //================================================
2683  
2684      getThumbPos: function (slide) {
2685        var rez = false,
2686          $thumb = slide.$thumb,
2687          thumbPos,
2688          btw,
2689          brw,
2690          bbw,
2691          blw;
2692  
2693        if (!$thumb || !inViewport($thumb[0])) {
2694          return false;
2695        }
2696  
2697        thumbPos = $.fancybox.getTranslate($thumb);
2698  
2699        btw = parseFloat($thumb.css("border-top-width") || 0);
2700        brw = parseFloat($thumb.css("border-right-width") || 0);
2701        bbw = parseFloat($thumb.css("border-bottom-width") || 0);
2702        blw = parseFloat($thumb.css("border-left-width") || 0);
2703  
2704        rez = {
2705          top: thumbPos.top + btw,
2706          left: thumbPos.left + blw,
2707          width: thumbPos.width - brw - blw,
2708          height: thumbPos.height - btw - bbw,
2709          scaleX: 1,
2710          scaleY: 1,
2711        };
2712  
2713        return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false;
2714      },
2715  
2716      // Final adjustments after current gallery item is moved to position
2717      // and it`s content is loaded
2718      // ==================================================================
2719  
2720      complete: function () {
2721        var self = this,
2722          current = self.current,
2723          slides = {},
2724          $el;
2725  
2726        if (self.isMoved() || !current.isLoaded) {
2727          return;
2728        }
2729  
2730        if (!current.isComplete) {
2731          current.isComplete = true;
2732  
2733          current.$slide.siblings().trigger("onReset");
2734  
2735          self.preload("inline");
2736  
2737          // Trigger any CSS transiton inside the slide
2738          forceRedraw(current.$slide);
2739  
2740          current.$slide.addClass("fancybox-slide--complete");
2741  
2742          // Remove unnecessary slides
2743          $.each(self.slides, function (key, slide) {
2744            if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {
2745              slides[slide.pos] = slide;
2746            } else if (slide) {
2747              $.fancybox.stop(slide.$slide);
2748  
2749              slide.$slide.off().remove();
2750            }
2751          });
2752  
2753          self.slides = slides;
2754        }
2755  
2756        self.isAnimating = false;
2757  
2758        self.updateCursor();
2759  
2760        self.trigger("afterShow");
2761  
2762        // Autoplay first html5 video/audio
2763        if (!!current.opts.video.autoStart) {
2764          current.$slide
2765            .find("video,audio")
2766            .filter(":visible:first")
2767            .trigger("play")
2768            .one("ended", function () {
2769              if (Document.exitFullscreen) {
2770                Document.exitFullscreen();
2771              } else if (this.webkitExitFullscreen) {
2772                this.webkitExitFullscreen();
2773              }
2774  
2775              self.next();
2776            });
2777        }
2778  
2779        // Try to focus on the first focusable element
2780        if (current.opts.autoFocus && current.contentType === "html") {
2781          // Look for the first input with autofocus attribute
2782          $el = current.$content.find("input[autofocus]:enabled:visible:first");
2783  
2784          if ($el.length) {
2785            $el.trigger("focus");
2786          } else {
2787            self.focus(null, true);
2788          }
2789        }
2790  
2791        // Avoid jumping
2792        current.$slide.scrollTop(0).scrollLeft(0);
2793      },
2794  
2795      // Preload next and previous slides
2796      // ================================
2797  
2798      preload: function (type) {
2799        var self = this,
2800          prev,
2801          next;
2802  
2803        if (self.group.length < 2) {
2804          return;
2805        }
2806  
2807        next = self.slides[self.currPos + 1];
2808        prev = self.slides[self.currPos - 1];
2809  
2810        if (prev && prev.type === type) {
2811          self.loadSlide(prev);
2812        }
2813  
2814        if (next && next.type === type) {
2815          self.loadSlide(next);
2816        }
2817      },
2818  
2819      // Try to find and focus on the first focusable element
2820      // ====================================================
2821  
2822      focus: function (e, firstRun) {
2823        var self = this,
2824          focusableStr = [
2825            "a[href]",
2826            "area[href]",
2827            'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
2828            "select:not([disabled]):not([aria-hidden])",
2829            "textarea:not([disabled]):not([aria-hidden])",
2830            "button:not([disabled]):not([aria-hidden])",
2831            "iframe",
2832            "object",
2833            "embed",
2834            "video",
2835            "audio",
2836            "[contenteditable]",
2837            '[tabindex]:not([tabindex^="-"])',
2838          ].join(","),
2839          focusableItems,
2840          focusedItemIndex;
2841  
2842        if (self.isClosing) {
2843          return;
2844        }
2845  
2846        if (e || !self.current || !self.current.isComplete) {
2847          // Focus on any element inside fancybox
2848          focusableItems = self.$refs.container.find("*:visible");
2849        } else {
2850          // Focus inside current slide
2851          focusableItems = self.current.$slide.find(
2852            "*:visible" + (firstRun ? ":not(.fancybox-close-small)" : "")
2853          );
2854        }
2855  
2856        focusableItems = focusableItems.filter(focusableStr).filter(function () {
2857          return (
2858            $(this).css("visibility") !== "hidden" &&
2859            !$(this).hasClass("disabled")
2860          );
2861        });
2862  
2863        if (focusableItems.length) {
2864          focusedItemIndex = focusableItems.index(document.activeElement);
2865  
2866          if (e && e.shiftKey) {
2867            // Back tab
2868            if (focusedItemIndex < 0 || focusedItemIndex == 0) {
2869              e.preventDefault();
2870  
2871              focusableItems.eq(focusableItems.length - 1).trigger("focus");
2872            }
2873          } else {
2874            // Outside or Forward tab
2875            if (
2876              focusedItemIndex < 0 ||
2877              focusedItemIndex == focusableItems.length - 1
2878            ) {
2879              if (e) {
2880                e.preventDefault();
2881              }
2882  
2883              focusableItems.eq(0).trigger("focus");
2884            }
2885          }
2886        } else {
2887          self.$refs.container.trigger("focus");
2888        }
2889      },
2890  
2891      // Activates current instance - brings container to the front and enables keyboard,
2892      // notifies other instances about deactivating
2893      // =================================================================================
2894  
2895      activate: function () {
2896        var self = this;
2897  
2898        // Deactivate all instances
2899        $(".fancybox-container").each(function () {
2900          var instance = $(this).data("FancyBox");
2901  
2902          // Skip self and closing instances
2903          if (instance && instance.id !== self.id && !instance.isClosing) {
2904            instance.trigger("onDeactivate");
2905  
2906            instance.removeEvents();
2907  
2908            instance.isVisible = false;
2909          }
2910        });
2911  
2912        self.isVisible = true;
2913  
2914        if (self.current || self.isIdle) {
2915          self.update();
2916  
2917          self.updateControls();
2918        }
2919  
2920        self.trigger("onActivate");
2921  
2922        self.addEvents();
2923      },
2924  
2925      // Start closing procedure
2926      // This will start "zoom-out" animation if needed and clean everything up afterwards
2927      // =================================================================================
2928  
2929      close: function (e, d) {
2930        var self = this,
2931          current = self.current,
2932          effect,
2933          duration,
2934          $content,
2935          domRect,
2936          opacity,
2937          start,
2938          end;
2939  
2940        var done = function () {
2941          self.cleanUp(e);
2942        };
2943  
2944        if (self.isClosing) {
2945          return false;
2946        }
2947  
2948        self.isClosing = true;
2949  
2950        // If beforeClose callback prevents closing, make sure content is centered
2951        if (self.trigger("beforeClose", e) === false) {
2952          self.isClosing = false;
2953  
2954          requestAFrame(function () {
2955            self.update();
2956          });
2957  
2958          return false;
2959        }
2960  
2961        // Remove all events
2962        // If there are multiple instances, they will be set again by "activate" method
2963        self.removeEvents();
2964  
2965        $content = current.$content;
2966        effect = current.opts.animationEffect;
2967        duration = $.isNumeric(d)
2968          ? d
2969          : effect
2970          ? current.opts.animationDuration
2971          : 0;
2972  
2973        current.$slide.removeClass(
2974          "fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated"
2975        );
2976  
2977        if (e !== true) {
2978          $.fancybox.stop(current.$slide);
2979        } else {
2980          effect = false;
2981        }
2982  
2983        // Remove other slides
2984        current.$slide.siblings().trigger("onReset").remove();
2985  
2986        // Trigger animations
2987        if (duration) {
2988          self.$refs.container
2989            .removeClass("fancybox-is-open")
2990            .addClass("fancybox-is-closing")
2991            .css("transition-duration", duration + "ms");
2992        }
2993  
2994        // Clean up
2995        self.hideLoading(current);
2996  
2997        self.hideControls(true);
2998  
2999        self.updateCursor();
3000  
3001        // Check if possible to zoom-out
3002        if (
3003          effect === "zoom" &&
3004          !(
3005            $content &&
3006            duration &&
3007            current.type === "image" &&
3008            !self.isMoved() &&
3009            !current.hasError &&
3010            (end = self.getThumbPos(current))
3011          )
3012        ) {
3013          effect = "fade";
3014        }
3015  
3016        if (effect === "zoom") {
3017          $.fancybox.stop($content);
3018  
3019          domRect = $.fancybox.getTranslate($content);
3020  
3021          start = {
3022            top: domRect.top,
3023            left: domRect.left,
3024            scaleX: domRect.width / end.width,
3025            scaleY: domRect.height / end.height,
3026            width: end.width,
3027            height: end.height,
3028          };
3029  
3030          // Check if we need to animate opacity
3031          opacity = current.opts.zoomOpacity;
3032  
3033          if (opacity == "auto") {
3034            opacity =
3035              Math.abs(current.width / current.height - end.width / end.height) >
3036              0.1;
3037          }
3038  
3039          if (opacity) {
3040            end.opacity = 0;
3041          }
3042  
3043          $.fancybox.setTranslate($content, start);
3044  
3045          forceRedraw($content);
3046  
3047          $.fancybox.animate($content, end, duration, done);
3048  
3049          return true;
3050        }
3051  
3052        if (effect && duration) {
3053          $.fancybox.animate(
3054            current.$slide
3055              .addClass("fancybox-slide--previous")
3056              .removeClass("fancybox-slide--current"),
3057            "fancybox-animated fancybox-fx-" + effect,
3058            duration,
3059            done
3060          );
3061        } else {
3062          // If skip animation
3063          if (e === true) {
3064            setTimeout(done, duration);
3065          } else {
3066            done();
3067          }
3068        }
3069  
3070        return true;
3071      },
3072  
3073      // Final adjustments after removing the instance
3074      // =============================================
3075  
3076      cleanUp: function (e) {
3077        var self = this,
3078          instance,
3079          $focus = self.current.opts.$orig,
3080          x,
3081          y;
3082  
3083        self.current.$slide.trigger("onReset");
3084  
3085        self.$refs.container.empty().remove();
3086  
3087        self.trigger("afterClose", e);
3088  
3089        // Place back focus
3090        if (!!self.current.opts.backFocus) {
3091          if (!$focus || !$focus.length || !$focus.is(":visible")) {
3092            $focus = self.$trigger;
3093          }
3094  
3095          if ($focus && $focus.length) {
3096            x = window.scrollX;
3097            y = window.scrollY;
3098  
3099            $focus.trigger("focus");
3100  
3101            $("html, body").scrollTop(y).scrollLeft(x);
3102          }
3103        }
3104  
3105        self.current = null;
3106  
3107        // Check if there are other instances
3108        instance = $.fancybox.getInstance();
3109  
3110        if (instance) {
3111          instance.activate();
3112        } else {
3113          $("body").removeClass("fancybox-active compensate-for-scrollbar");
3114  
3115          $("#fancybox-style-noscroll").remove();
3116        }
3117      },
3118  
3119      // Call callback and trigger an event
3120      // ==================================
3121  
3122      trigger: function (name, slide) {
3123        var args = Array.prototype.slice.call(arguments, 1),
3124          self = this,
3125          obj = slide && slide.opts ? slide : self.current,
3126          rez;
3127  
3128        if (obj) {
3129          args.unshift(obj);
3130        } else {
3131          obj = self;
3132        }
3133  
3134        args.unshift(self);
3135  
3136        if ($.isFunction(obj.opts[name])) {
3137          rez = obj.opts[name].apply(obj, args);
3138        }
3139  
3140        if (rez === false) {
3141          return rez;
3142        }
3143  
3144        if (name === "afterClose" || !self.$refs) {
3145          $D.trigger(name + ".fb", args);
3146        } else {
3147          self.$refs.container.trigger(name + ".fb", args);
3148        }
3149      },
3150  
3151      // Update infobar values, navigation button states and reveal caption
3152      // ==================================================================
3153  
3154      updateControls: function () {
3155        var self = this,
3156          current = self.current,
3157          index = current.index,
3158          $container = self.$refs.container,
3159          $caption = self.$refs.caption,
3160          caption = current.opts.caption;
3161  
3162        // Recalculate content dimensions
3163        current.$slide.trigger("refresh");
3164  
3165        // Set caption
3166        if (caption && caption.length) {
3167          self.$caption = $caption;
3168  
3169          $caption.children().eq(0).html(caption);
3170        } else {
3171          self.$caption = null;
3172        }
3173  
3174        if (!self.hasHiddenControls && !self.isIdle) {
3175          self.showControls();
3176        }
3177  
3178        // Update info and navigation elements
3179        $container.find("[data-fancybox-count]").html(self.group.length);
3180        $container.find("[data-fancybox-index]").html(index + 1);
3181  
3182        $container
3183          .find("[data-fancybox-prev]")
3184          .prop("disabled", !current.opts.loop && index <= 0);
3185        $container
3186          .find("[data-fancybox-next]")
3187          .prop("disabled", !current.opts.loop && index >= self.group.length - 1);
3188  
3189        if (current.type === "image") {
3190          // Re-enable buttons; update download button source
3191          $container
3192            .find("[data-fancybox-zoom]")
3193            .show()
3194            .end()
3195            .find("[data-fancybox-download]")
3196            .attr("href", current.opts.image.src || current.src)
3197            .show();
3198        } else if (current.opts.toolbar) {
3199          $container.find("[data-fancybox-download],[data-fancybox-zoom]").hide();
3200        }
3201  
3202        // Make sure focus is not on disabled button/element
3203        if ($(document.activeElement).is(":hidden,[disabled]")) {
3204          self.$refs.container.trigger("focus");
3205        }
3206      },
3207  
3208      // Hide toolbar and caption
3209      // ========================
3210  
3211      hideControls: function (andCaption) {
3212        var self = this,
3213          arr = ["infobar", "toolbar", "nav"];
3214  
3215        if (andCaption || !self.current.opts.preventCaptionOverlap) {
3216          arr.push("caption");
3217        }
3218  
3219        this.$refs.container.removeClass(
3220          arr
3221            .map(function (i) {
3222              return "fancybox-show-" + i;
3223            })
3224            .join(" ")
3225        );
3226  
3227        this.hasHiddenControls = true;
3228      },
3229  
3230      showControls: function () {
3231        var self = this,
3232          opts = self.current ? self.current.opts : self.opts,
3233          $container = self.$refs.container;
3234  
3235        self.hasHiddenControls = false;
3236        self.idleSecondsCounter = 0;
3237  
3238        $container
3239          .toggleClass("fancybox-show-toolbar", !!(opts.toolbar && opts.buttons))
3240          .toggleClass(
3241            "fancybox-show-infobar",
3242            !!(opts.infobar && self.group.length > 1)
3243          )
3244          .toggleClass("fancybox-show-caption", !!self.$caption)
3245          .toggleClass(
3246            "fancybox-show-nav",
3247            !!(opts.arrows && self.group.length > 1)
3248          )
3249          .toggleClass("fancybox-is-modal", !!opts.modal);
3250      },
3251  
3252      // Toggle toolbar and caption
3253      // ==========================
3254  
3255      toggleControls: function () {
3256        if (this.hasHiddenControls) {
3257          this.showControls();
3258        } else {
3259          this.hideControls();
3260        }
3261      },
3262    });
3263  
3264    $.fancybox = {
3265      version: "3.5.7",
3266      defaults: defaults,
3267  
3268      // Get current instance and execute a command.
3269      //
3270      // Examples of usage:
3271      //
3272      //   $instance = $.fancybox.getInstance();
3273      //   $.fancybox.getInstance().jumpTo( 1 );
3274      //   $.fancybox.getInstance( 'jumpTo', 1 );
3275      //   $.fancybox.getInstance( function() {
3276      //       console.info( this.currIndex );
3277      //   });
3278      // ======================================================
3279  
3280      getInstance: function (command) {
3281        var instance = $(
3282            '.fancybox-container:not(".fancybox-is-closing"):last'
3283          ).data("FancyBox"),
3284          args = Array.prototype.slice.call(arguments, 1);
3285  
3286        if (instance instanceof FancyBox) {
3287          if ($.type(command) === "string") {
3288            instance[command].apply(instance, args);
3289          } else if ($.type(command) === "function") {
3290            command.apply(instance, args);
3291          }
3292  
3293          return instance;
3294        }
3295  
3296        return false;
3297      },
3298  
3299      // Create new instance
3300      // ===================
3301  
3302      open: function (items, opts, index) {
3303        return new FancyBox(items, opts, index);
3304      },
3305  
3306      // Close current or all instances
3307      // ==============================
3308  
3309      close: function (all) {
3310        var instance = this.getInstance();
3311  
3312        if (instance) {
3313          instance.close();
3314  
3315          // Try to find and close next instance
3316          if (all === true) {
3317            this.close(all);
3318          }
3319        }
3320      },
3321  
3322      // Close all instances and unbind all events
3323      // =========================================
3324  
3325      destroy: function () {
3326        this.close(true);
3327  
3328        $D.add("body").off("click.fb-start", "**");
3329      },
3330  
3331      // Try to detect mobile devices
3332      // ============================
3333  
3334      isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
3335        navigator.userAgent
3336      ),
3337  
3338      // Detect if 'translate3d' support is available
3339      // ============================================
3340  
3341      use3d: (function () {
3342        var div = document.createElement("div");
3343  
3344        return (
3345          window.getComputedStyle &&
3346          window.getComputedStyle(div) &&
3347          window.getComputedStyle(div).getPropertyValue("transform") &&
3348          !(document.documentMode && document.documentMode < 11)
3349        );
3350      })(),
3351  
3352      // Helper function to get current visual state of an element
3353      // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]
3354      // =====================================================================
3355  
3356      getTranslate: function ($el) {
3357        var domRect;
3358  
3359        if (!$el || !$el.length) {
3360          return false;
3361        }
3362  
3363        domRect = $el[0].getBoundingClientRect();
3364  
3365        return {
3366          top: domRect.top || 0,
3367          left: domRect.left || 0,
3368          width: domRect.width,
3369          height: domRect.height,
3370          opacity: parseFloat($el.css("opacity")),
3371        };
3372      },
3373  
3374      // Shortcut for setting "translate3d" properties for element
3375      // Can set be used to set opacity, too
3376      // ========================================================
3377  
3378      setTranslate: function ($el, props) {
3379        var str = "",
3380          css = {};
3381  
3382        if (!$el || !props) {
3383          return;
3384        }
3385  
3386        if (props.left !== undefined || props.top !== undefined) {
3387          str =
3388            (props.left === undefined ? $el.position().left : props.left) +
3389            "px, " +
3390            (props.top === undefined ? $el.position().top : props.top) +
3391            "px";
3392  
3393          if (this.use3d) {
3394            str = "translate3d(" + str + ", 0px)";
3395          } else {
3396            str = "translate(" + str + ")";
3397          }
3398        }
3399  
3400        if (props.scaleX !== undefined && props.scaleY !== undefined) {
3401          str += " scale(" + props.scaleX + ", " + props.scaleY + ")";
3402        } else if (props.scaleX !== undefined) {
3403          str += " scaleX(" + props.scaleX + ")";
3404        }
3405  
3406        if (str.length) {
3407          css.transform = str;
3408        }
3409  
3410        if (props.opacity !== undefined) {
3411          css.opacity = props.opacity;
3412        }
3413  
3414        if (props.width !== undefined) {
3415          css.width = props.width;
3416        }
3417  
3418        if (props.height !== undefined) {
3419          css.height = props.height;
3420        }
3421  
3422        return $el.css(css);
3423      },
3424  
3425      // Simple CSS transition handler
3426      // =============================
3427  
3428      animate: function ($el, to, duration, callback, leaveAnimationName) {
3429        var self = this,
3430          from;
3431  
3432        if ($.isFunction(duration)) {
3433          callback = duration;
3434          duration = null;
3435        }
3436  
3437        self.stop($el);
3438  
3439        from = self.getTranslate($el);
3440  
3441        $el.on(transitionEnd, function (e) {
3442          // Skip events from child elements and z-index change
3443          if (
3444            e &&
3445            e.originalEvent &&
3446            (!$el.is(e.originalEvent.target) ||
3447              e.originalEvent.propertyName == "z-index")
3448          ) {
3449            return;
3450          }
3451  
3452          self.stop($el);
3453  
3454          if ($.isNumeric(duration)) {
3455            $el.css("transition-duration", "");
3456          }
3457  
3458          if ($.isPlainObject(to)) {
3459            if (to.scaleX !== undefined && to.scaleY !== undefined) {
3460              self.setTranslate($el, {
3461                top: to.top,
3462                left: to.left,
3463                width: from.width * to.scaleX,
3464                height: from.height * to.scaleY,
3465                scaleX: 1,
3466                scaleY: 1,
3467              });
3468            }
3469          } else if (leaveAnimationName !== true) {
3470            $el.removeClass(to);
3471          }
3472  
3473          if ($.isFunction(callback)) {
3474            callback(e);
3475          }
3476        });
3477  
3478        if ($.isNumeric(duration)) {
3479          $el.css("transition-duration", duration + "ms");
3480        }
3481  
3482        // Start animation by changing CSS properties or class name
3483        if ($.isPlainObject(to)) {
3484          if (to.scaleX !== undefined && to.scaleY !== undefined) {
3485            delete to.width;
3486            delete to.height;
3487  
3488            if ($el.parent().hasClass("fancybox-slide--image")) {
3489              $el.parent().addClass("fancybox-is-scaling");
3490            }
3491          }
3492  
3493          $.fancybox.setTranslate($el, to);
3494        } else {
3495          $el.addClass(to);
3496        }
3497  
3498        // Make sure that `transitionend` callback gets fired
3499        $el.data(
3500          "timer",
3501          setTimeout(function () {
3502            $el.trigger(transitionEnd);
3503          }, duration + 33)
3504        );
3505      },
3506  
3507      stop: function ($el, callCallback) {
3508        if ($el && $el.length) {
3509          clearTimeout($el.data("timer"));
3510  
3511          if (callCallback) {
3512            $el.trigger(transitionEnd);
3513          }
3514  
3515          $el.off(transitionEnd).css("transition-duration", "");
3516  
3517          $el.parent().removeClass("fancybox-is-scaling");
3518        }
3519      },
3520    };
3521  
3522    // Default click handler for "fancyboxed" links
3523    // ============================================
3524  
3525    function _run(e, opts) {
3526      var items = [],
3527        index = 0,
3528        $target,
3529        value,
3530        instance;
3531  
3532      // Avoid opening multiple times
3533      if (e && e.isDefaultPrevented()) {
3534        return;
3535      }
3536  
3537      e.preventDefault();
3538  
3539      opts = opts || {};
3540  
3541      if (e && e.data) {
3542        opts = mergeOpts(e.data.options, opts);
3543      }
3544  
3545      $target = opts.$target || $(e.currentTarget).trigger("blur");
3546      instance = $.fancybox.getInstance();
3547  
3548      if (instance && instance.$trigger && instance.$trigger.is($target)) {
3549        return;
3550      }
3551  
3552      if (opts.selector) {
3553        items = $(opts.selector);
3554      } else {
3555        // Get all related items and find index for clicked one
3556        value = $target.attr("data-fancybox") || "";
3557  
3558        if (value) {
3559          items = e.data ? e.data.items : [];
3560          items = items.length
3561            ? items.filter('[data-fancybox="' + value + '"]')
3562            : $('[data-fancybox="' + value + '"]');
3563        } else {
3564          items = [$target];
3565        }
3566      }
3567  
3568      index = $(items).index($target);
3569  
3570      // Sometimes current item can not be found
3571      if (index < 0) {
3572        index = 0;
3573      }
3574  
3575      instance = $.fancybox.open(items, opts, index);
3576  
3577      // Save last active element
3578      instance.$trigger = $target;
3579    }
3580  
3581    // Create a jQuery plugin
3582    // ======================
3583  
3584    $.fn.fancybox = function (options) {
3585      var selector;
3586  
3587      options = options || {};
3588      selector = options.selector || false;
3589  
3590      if (selector) {
3591        // Use body element instead of document so it executes first
3592        $("body").off("click.fb-start", selector).on(
3593          "click.fb-start",
3594          selector,
3595          {
3596            options: options,
3597          },
3598          _run
3599        );
3600      } else {
3601        this.off("click.fb-start").on(
3602          "click.fb-start",
3603          {
3604            items: this,
3605            options: options,
3606          },
3607          _run
3608        );
3609      }
3610  
3611      return this;
3612    };
3613  
3614    // Self initializing plugin for all elements having `data-fancybox` attribute
3615    // ==========================================================================
3616  
3617    $D.on("click.fb-start", "[data-fancybox]", _run);
3618  
3619    // Enable "trigger elements"
3620    // =========================
3621  
3622    $D.on("click.fb-start", "[data-fancybox-trigger]", function (e) {
3623      $('[data-fancybox="' + $(this).attr("data-fancybox-trigger") + '"]')
3624        .eq($(this).attr("data-fancybox-index") || 0)
3625        .trigger("click.fb-start", {
3626          $trigger: $(this),
3627        });
3628    });
3629  
3630    // Track focus event for better accessibility styling
3631    // ==================================================
3632    (function () {
3633      var buttonStr = ".fancybox-button",
3634        focusStr = "fancybox-focus",
3635        $pressed = null;
3636  
3637      $D.on("mousedown mouseup focus blur", buttonStr, function (e) {
3638        switch (e.type) {
3639          case "mousedown":
3640            $pressed = $(this);
3641            break;
3642          case "mouseup":
3643            $pressed = null;
3644            break;
3645          case "focusin":
3646            $(buttonStr).removeClass(focusStr);
3647  
3648            if (!$(this).is($pressed) && !$(this).is("[disabled]")) {
3649              $(this).addClass(focusStr);
3650            }
3651            break;
3652          case "focusout":
3653            $(buttonStr).removeClass(focusStr);
3654            break;
3655        }
3656      });
3657    })();
3658  })(window, document, jQuery);
3659  // ==========================================================================
3660  //
3661  // Media
3662  // Adds additional media type support
3663  //
3664  // ==========================================================================
3665  (function ($) {
3666    "use strict";
3667  
3668    // Object containing properties for each media type
3669    var defaults = {
3670      youtube: {
3671        matcher: /(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,
3672        params: {
3673          autoplay: 1,
3674          autohide: 1,
3675          fs: 1,
3676          rel: 0,
3677          hd: 1,
3678          wmode: "transparent",
3679          enablejsapi: 1,
3680          html5: 1,
3681        },
3682        paramPlace: 8,
3683        type: "iframe",
3684        url: "https://www.youtube-nocookie.com/embed/$4",
3685        thumb: "https://img.youtube.com/vi/$4/hqdefault.jpg",
3686      },
3687  
3688      vimeo: {
3689        matcher: /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,
3690        params: {
3691          autoplay: 1,
3692          hd: 1,
3693          show_title: 1,
3694          show_byline: 1,
3695          show_portrait: 0,
3696          fullscreen: 1,
3697        },
3698        paramPlace: 3,
3699        type: "iframe",
3700        url: "//player.vimeo.com/video/$2",
3701      },
3702  
3703      instagram: {
3704        matcher: /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,
3705        type: "image",
3706        url: "//$1/p/$2/media/?size=l",
3707      },
3708  
3709      // Examples:
3710      // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
3711      // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z
3712      // https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en
3713      // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572
3714      gmap_place: {
3715        matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,
3716        type: "iframe",
3717        url: function (rez) {
3718          return (
3719            "//maps.google." +
3720            rez[2] +
3721            "/?ll=" +
3722            (rez[9]
3723              ? rez[9] +
3724                "&z=" +
3725                Math.floor(rez[10]) +
3726                (rez[12] ? rez[12].replace(/^\//, "&") : "")
3727              : rez[12] + ""
3728            ).replace(/\?/, "&") +
3729            "&output=" +
3730            (rez[12] && rez[12].indexOf("layer=c") > 0 ? "svembed" : "embed")
3731          );
3732        },
3733      },
3734  
3735      // Examples:
3736      // https://www.google.com/maps/search/Empire+State+Building/
3737      // https://www.google.com/maps/search/?api=1&query=centurylink+field
3738      // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393
3739      gmap_search: {
3740        matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,
3741        type: "iframe",
3742        url: function (rez) {
3743          return (
3744            "//maps.google." +
3745            rez[2] +
3746            "/maps?q=" +
3747            rez[5].replace("query=", "q=").replace("api=1", "") +
3748            "&output=embed"
3749          );
3750        },
3751      },
3752    };
3753  
3754    // Formats matching url to final form
3755    var format = function (url, rez, params) {
3756      if (!url) {
3757        return;
3758      }
3759  
3760      params = params || "";
3761  
3762      if ($.type(params) === "object") {
3763        params = $.param(params, true);
3764      }
3765  
3766      $.each(rez, function (key, value) {
3767        url = url.replace("$" + key, value || "");
3768      });
3769  
3770      if (params.length) {
3771        url += (url.indexOf("?") > 0 ? "&" : "?") + params;
3772      }
3773  
3774      return url;
3775    };
3776  
3777    $(document).on("objectNeedsType.fb", function (e, instance, item) {
3778      var url = item.src || "",
3779        type = false,
3780        media,
3781        thumb,
3782        rez,
3783        params,
3784        urlParams,
3785        paramObj,
3786        provider;
3787  
3788      media = $.extend(true, {}, defaults, item.opts.media);
3789  
3790      // Look for any matching media type
3791      $.each(media, function (providerName, providerOpts) {
3792        rez = url.match(providerOpts.matcher);
3793  
3794        if (!rez) {
3795          return;
3796        }
3797  
3798        type = providerOpts.type;
3799        provider = providerName;
3800        paramObj = {};
3801  
3802        if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) {
3803          urlParams = rez[providerOpts.paramPlace];
3804  
3805          if (urlParams[0] == "?") {
3806            urlParams = urlParams.substring(1);
3807          }
3808  
3809          urlParams = urlParams.split("&");
3810  
3811          for (var m = 0; m < urlParams.length; ++m) {
3812            var p = urlParams[m].split("=", 2);
3813  
3814            if (p.length == 2) {
3815              paramObj[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
3816            }
3817          }
3818        }
3819  
3820        params = $.extend(
3821          true,
3822          {},
3823          providerOpts.params,
3824          item.opts[providerName],
3825          paramObj
3826        );
3827  
3828        url =
3829          $.type(providerOpts.url) === "function"
3830            ? providerOpts.url.call(this, rez, params, item)
3831            : format(providerOpts.url, rez, params);
3832  
3833        thumb =
3834          $.type(providerOpts.thumb) === "function"
3835            ? providerOpts.thumb.call(this, rez, params, item)
3836            : format(providerOpts.thumb, rez);
3837  
3838        if (providerName === "youtube") {
3839          url = url.replace(/&t=((\d+)m)?(\d+)s/, function (match, p1, m, s) {
3840            return "&start=" + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10));
3841          });
3842        } else if (providerName === "vimeo") {
3843          url = url.replace("&%23", "#");
3844        }
3845  
3846        return false;
3847      });
3848  
3849      // If it is found, then change content type and update the url
3850  
3851      if (type) {
3852        if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) {
3853          item.opts.thumb = thumb;
3854        }
3855  
3856        if (type === "iframe") {
3857          item.opts = $.extend(true, item.opts, {
3858            iframe: {
3859              preload: false,
3860              attr: {
3861                scrolling: "no",
3862              },
3863            },
3864          });
3865        }
3866  
3867        $.extend(item, {
3868          type: type,
3869          src: url,
3870          origSrc: item.src,
3871          contentSource: provider,
3872          contentType:
3873            type === "image"
3874              ? "image"
3875              : provider == "gmap_place" || provider == "gmap_search"
3876              ? "map"
3877              : "video",
3878        });
3879      } else if (url) {
3880        item.type = item.opts.defaultType;
3881      }
3882    });
3883  
3884    // Load YouTube/Video API on request to detect when video finished playing
3885    var VideoAPILoader = {
3886      youtube: {
3887        src: "https://www.youtube.com/iframe_api",
3888        class: "YT",
3889        loading: false,
3890        loaded: false,
3891      },
3892  
3893      vimeo: {
3894        src: "https://player.vimeo.com/api/player.js",
3895        class: "Vimeo",
3896        loading: false,
3897        loaded: false,
3898      },
3899  
3900      load: function (vendor) {
3901        var _this = this,
3902          script;
3903  
3904        if (this[vendor].loaded) {
3905          setTimeout(function () {
3906            _this.done(vendor);
3907          });
3908          return;
3909        }
3910  
3911        if (this[vendor].loading) {
3912          return;
3913        }
3914  
3915        this[vendor].loading = true;
3916  
3917        script = document.createElement("script");
3918        script.type = "text/javascript";
3919        script.src = this[vendor].src;
3920  
3921        if (vendor === "youtube") {
3922          window.onYouTubeIframeAPIReady = function () {
3923            _this[vendor].loaded = true;
3924            _this.done(vendor);
3925          };
3926        } else {
3927          script.onload = function () {
3928            _this[vendor].loaded = true;
3929            _this.done(vendor);
3930          };
3931        }
3932  
3933        document.body.appendChild(script);
3934      },
3935      done: function (vendor) {
3936        var instance, $el, player;
3937  
3938        if (vendor === "youtube") {
3939          delete window.onYouTubeIframeAPIReady;
3940        }
3941  
3942        instance = $.fancybox.getInstance();
3943  
3944        if (instance) {
3945          $el = instance.current.$content.find("iframe");
3946  
3947          if (vendor === "youtube" && YT !== undefined && YT) {
3948            player = new YT.Player($el.attr("id"), {
3949              events: {
3950                onStateChange: function (e) {
3951                  if (e.data == 0) {
3952                    instance.next();
3953                  }
3954                },
3955              },
3956            });
3957          } else if (vendor === "vimeo" && Vimeo !== undefined && Vimeo) {
3958            player = new Vimeo.Player($el);
3959  
3960            player.on("ended", function () {
3961              instance.next();
3962            });
3963          }
3964        }
3965      },
3966    };
3967  
3968    $(document).on({
3969      "afterShow.fb": function (e, instance, current) {
3970        if (
3971          instance.group.length > 1 &&
3972          (current.contentSource === "youtube" ||
3973            current.contentSource === "vimeo")
3974        ) {
3975          VideoAPILoader.load(current.contentSource);
3976        }
3977      },
3978    });
3979  })(jQuery);
3980  // ==========================================================================
3981  //
3982  // Guestures
3983  // Adds touch guestures, handles click and tap events
3984  //
3985  // ==========================================================================
3986  (function (window, document, $) {
3987    "use strict";
3988  
3989    var requestAFrame = (function () {
3990      return (
3991        window.requestAnimationFrame ||
3992        window.webkitRequestAnimationFrame ||
3993        window.mozRequestAnimationFrame ||
3994        window.oRequestAnimationFrame ||
3995        // if all else fails, use setTimeout
3996        function (callback) {
3997          return window.setTimeout(callback, 1000 / 60);
3998        }
3999      );
4000    })();
4001  
4002    var cancelAFrame = (function () {
4003      return (
4004        window.cancelAnimationFrame ||
4005        window.webkitCancelAnimationFrame ||
4006        window.mozCancelAnimationFrame ||
4007        window.oCancelAnimationFrame ||
4008        function (id) {
4009          window.clearTimeout(id);
4010        }
4011      );
4012    })();
4013  
4014    var getPointerXY = function (e) {
4015      var result = [];
4016  
4017      e = e.originalEvent || e || window.e;
4018      e =
4019        e.touches && e.touches.length
4020          ? e.touches
4021          : e.changedTouches && e.changedTouches.length
4022          ? e.changedTouches
4023          : [e];
4024  
4025      for (var key in e) {
4026        if (e[key].pageX) {
4027          result.push({
4028            x: e[key].pageX,
4029            y: e[key].pageY,
4030          });
4031        } else if (e[key].clientX) {
4032          result.push({
4033            x: e[key].clientX,
4034            y: e[key].clientY,
4035          });
4036        }
4037      }
4038  
4039      return result;
4040    };
4041  
4042    var distance = function (point2, point1, what) {
4043      if (!point1 || !point2) {
4044        return 0;
4045      }
4046  
4047      if (what === "x") {
4048        return point2.x - point1.x;
4049      } else if (what === "y") {
4050        return point2.y - point1.y;
4051      }
4052  
4053      return Math.sqrt(
4054        Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)
4055      );
4056    };
4057  
4058    var isClickable = function ($el) {
4059      if (
4060        $el.is(
4061          'a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe'
4062        ) ||
4063        $.isFunction($el.get(0).onclick) ||
4064        $el.data("selectable")
4065      ) {
4066        return true;
4067      }
4068  
4069      // Check for attributes like data-fancybox-next or data-fancybox-close
4070      for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {
4071        if (atts[i].nodeName.substr(0, 14) === "data-fancybox-") {
4072          return true;
4073        }
4074      }
4075  
4076      return false;
4077    };
4078  
4079    var hasScrollbars = function (el) {
4080      var overflowY = window.getComputedStyle(el)["overflow-y"],
4081        overflowX = window.getComputedStyle(el)["overflow-x"],
4082        vertical =
4083          (overflowY === "scroll" || overflowY === "auto") &&
4084          el.scrollHeight > el.clientHeight,
4085        horizontal =
4086          (overflowX === "scroll" || overflowX === "auto") &&
4087          el.scrollWidth > el.clientWidth;
4088  
4089      return vertical || horizontal;
4090    };
4091  
4092    var isScrollable = function ($el) {
4093      var rez = false;
4094  
4095      while (true) {
4096        rez = hasScrollbars($el.get(0));
4097  
4098        if (rez) {
4099          break;
4100        }
4101  
4102        $el = $el.parent();
4103  
4104        if (!$el.length || $el.hasClass("fancybox-stage") || $el.is("body")) {
4105          break;
4106        }
4107      }
4108  
4109      return rez;
4110    };
4111  
4112    var Guestures = function (instance) {
4113      var self = this;
4114  
4115      self.instance = instance;
4116  
4117      self.$bg = instance.$refs.bg;
4118      self.$stage = instance.$refs.stage;
4119      self.$container = instance.$refs.container;
4120  
4121      self.destroy();
4122  
4123      self.$container.on(
4124        "touchstart.fb.touch mousedown.fb.touch",
4125        $.proxy(self, "ontouchstart")
4126      );
4127    };
4128  
4129    Guestures.prototype.destroy = function () {
4130      var self = this;
4131  
4132      self.$container.off(".fb.touch");
4133  
4134      $(document).off(".fb.touch");
4135  
4136      if (self.requestId) {
4137        cancelAFrame(self.requestId);
4138        self.requestId = null;
4139      }
4140  
4141      if (self.tapped) {
4142        clearTimeout(self.tapped);
4143        self.tapped = null;
4144      }
4145    };
4146  
4147    Guestures.prototype.ontouchstart = function (e) {
4148      var self = this,
4149        $target = $(e.target),
4150        instance = self.instance,
4151        current = instance.current,
4152        $slide = current.$slide,
4153        $content = current.$content,
4154        isTouchDevice = e.type == "touchstart";
4155  
4156      // Do not respond to both (touch and mouse) events
4157      if (isTouchDevice) {
4158        self.$container.off("mousedown.fb.touch");
4159      }
4160  
4161      // Ignore right click
4162      if (e.originalEvent && e.originalEvent.button == 2) {
4163        return;
4164      }
4165  
4166      // Ignore taping on links, buttons, input elements
4167      if (
4168        !$slide.length ||
4169        !$target.length ||
4170        isClickable($target) ||
4171        isClickable($target.parent())
4172      ) {
4173        return;
4174      }
4175      // Ignore clicks on the scrollbar
4176      if (
4177        !$target.is("img") &&
4178        e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left
4179      ) {
4180        return;
4181      }
4182  
4183      // Ignore clicks while zooming or closing
4184      if (
4185        !current ||
4186        instance.isAnimating ||
4187        current.$slide.hasClass("fancybox-animated")
4188      ) {
4189        e.stopPropagation();
4190        e.preventDefault();
4191  
4192        return;
4193      }
4194  
4195      self.realPoints = self.startPoints = getPointerXY(e);
4196  
4197      if (!self.startPoints.length) {
4198        return;
4199      }
4200  
4201      // Allow other scripts to catch touch event if "touch" is set to false
4202      if (current.touch) {
4203        e.stopPropagation();
4204      }
4205  
4206      self.startEvent = e;
4207  
4208      self.canTap = true;
4209      self.$target = $target;
4210      self.$content = $content;
4211      self.opts = current.opts.touch;
4212  
4213      self.isPanning = false;
4214      self.isSwiping = false;
4215      self.isZooming = false;
4216      self.isScrolling = false;
4217      self.canPan = instance.canPan();
4218  
4219      self.startTime = new Date().getTime();
4220      self.distanceX = self.distanceY = self.distance = 0;
4221  
4222      self.canvasWidth = Math.round($slide[0].clientWidth);
4223      self.canvasHeight = Math.round($slide[0].clientHeight);
4224  
4225      self.contentLastPos = null;
4226      self.contentStartPos = $.fancybox.getTranslate(self.$content) || {
4227        top: 0,
4228        left: 0,
4229      };
4230      self.sliderStartPos = $.fancybox.getTranslate($slide);
4231  
4232      // Since position will be absolute, but we need to make it relative to the stage
4233      self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);
4234  
4235      self.sliderStartPos.top -= self.stagePos.top;
4236      self.sliderStartPos.left -= self.stagePos.left;
4237  
4238      self.contentStartPos.top -= self.stagePos.top;
4239      self.contentStartPos.left -= self.stagePos.left;
4240  
4241      $(document)
4242        .off(".fb.touch")
4243        .on(
4244          isTouchDevice
4245            ? "touchend.fb.touch touchcancel.fb.touch"
4246            : "mouseup.fb.touch mouseleave.fb.touch",
4247          $.proxy(self, "ontouchend")
4248        )
4249        .on(
4250          isTouchDevice ? "touchmove.fb.touch" : "mousemove.fb.touch",
4251          $.proxy(self, "ontouchmove")
4252        );
4253  
4254      if ($.fancybox.isMobile) {
4255        document.addEventListener("scroll", self.onscroll, true);
4256      }
4257  
4258      // Skip if clicked outside the sliding area
4259      if (
4260        !(self.opts || self.canPan) ||
4261        !($target.is(self.$stage) || self.$stage.find($target).length)
4262      ) {
4263        if ($target.is(".fancybox-image")) {
4264          e.preventDefault();
4265        }
4266  
4267        if (
4268          !($.fancybox.isMobile && $target.parents(".fancybox-caption").length)
4269        ) {
4270          return;
4271        }
4272      }
4273  
4274      self.isScrollable = isScrollable($target) || isScrollable($target.parent());
4275  
4276      // Check if element is scrollable and try to prevent default behavior (scrolling)
4277      if (!($.fancybox.isMobile && self.isScrollable)) {
4278        e.preventDefault();
4279      }
4280  
4281      // One finger or mouse click - swipe or pan an image
4282      if (self.startPoints.length === 1 || current.hasError) {
4283        if (self.canPan) {
4284          $.fancybox.stop(self.$content);
4285  
4286          self.isPanning = true;
4287        } else {
4288          self.isSwiping = true;
4289        }
4290  
4291        self.$container.addClass("fancybox-is-grabbing");
4292      }
4293  
4294      // Two fingers - zoom image
4295      if (
4296        self.startPoints.length === 2 &&
4297        current.type === "image" &&
4298        (current.isLoaded || current.$ghost)
4299      ) {
4300        self.canTap = false;
4301        self.isSwiping = false;
4302        self.isPanning = false;
4303  
4304        self.isZooming = true;
4305  
4306        $.fancybox.stop(self.$content);
4307  
4308        self.centerPointStartX =
4309          (self.startPoints[0].x + self.startPoints[1].x) * 0.5 -
4310          $(window).scrollLeft();
4311        self.centerPointStartY =
4312          (self.startPoints[0].y + self.startPoints[1].y) * 0.5 -
4313          $(window).scrollTop();
4314  
4315        self.percentageOfImageAtPinchPointX =
4316          (self.centerPointStartX - self.contentStartPos.left) /
4317          self.contentStartPos.width;
4318        self.percentageOfImageAtPinchPointY =
4319          (self.centerPointStartY - self.contentStartPos.top) /
4320          self.contentStartPos.height;
4321  
4322        self.startDistanceBetweenFingers = distance(
4323          self.startPoints[0],
4324          self.startPoints[1]
4325        );
4326      }
4327    };
4328  
4329    Guestures.prototype.onscroll = function (e) {
4330      var self = this;
4331  
4332      self.isScrolling = true;
4333  
4334      document.removeEventListener("scroll", self.onscroll, true);
4335    };
4336  
4337    Guestures.prototype.ontouchmove = function (e) {
4338      var self = this;
4339  
4340      // Make sure user has not released over iframe or disabled element
4341      if (
4342        e.originalEvent.buttons !== undefined &&
4343        e.originalEvent.buttons === 0
4344      ) {
4345        self.ontouchend(e);
4346        return;
4347      }
4348  
4349      if (self.isScrolling) {
4350        self.canTap = false;
4351        return;
4352      }
4353  
4354      self.newPoints = getPointerXY(e);
4355  
4356      if (
4357        !(self.opts || self.canPan) ||
4358        !self.newPoints.length ||
4359        !self.newPoints.length
4360      ) {
4361        return;
4362      }
4363  
4364      if (!(self.isSwiping && self.isSwiping === true)) {
4365        e.preventDefault();
4366      }
4367  
4368      self.distanceX = distance(self.newPoints[0], self.startPoints[0], "x");
4369      self.distanceY = distance(self.newPoints[0], self.startPoints[0], "y");
4370  
4371      self.distance = distance(self.newPoints[0], self.startPoints[0]);
4372  
4373      // Skip false ontouchmove events (Chrome)
4374      if (self.distance > 0) {
4375        if (self.isSwiping) {
4376          self.onSwipe(e);
4377        } else if (self.isPanning) {
4378          self.onPan();
4379        } else if (self.isZooming) {
4380          self.onZoom();
4381        }
4382      }
4383    };
4384  
4385    Guestures.prototype.onSwipe = function (e) {
4386      var self = this,
4387        instance = self.instance,
4388        swiping = self.isSwiping,
4389        left = self.sliderStartPos.left || 0,
4390        angle;
4391  
4392      // If direction is not yet determined
4393      if (swiping === true) {
4394        // We need at least 10px distance to correctly calculate an angle
4395        if (Math.abs(self.distance) > 10) {
4396          self.canTap = false;
4397  
4398          if (instance.group.length < 2 && self.opts.vertical) {
4399            self.isSwiping = "y";
4400          } else if (
4401            instance.isDragging ||
4402            self.opts.vertical === false ||
4403            (self.opts.vertical === "auto" && $(window).width() > 800)
4404          ) {
4405            self.isSwiping = "x";
4406          } else {
4407            angle = Math.abs(
4408              (Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI
4409            );
4410  
4411            self.isSwiping = angle > 45 && angle < 135 ? "y" : "x";
4412          }
4413  
4414          if (
4415            self.isSwiping === "y" &&
4416            $.fancybox.isMobile &&
4417            self.isScrollable
4418          ) {
4419            self.isScrolling = true;
4420  
4421            return;
4422          }
4423  
4424          instance.isDragging = self.isSwiping;
4425  
4426          // Reset points to avoid jumping, because we dropped first swipes to calculate the angle
4427          self.startPoints = self.newPoints;
4428  
4429          $.each(instance.slides, function (index, slide) {
4430            var slidePos, stagePos;
4431  
4432            $.fancybox.stop(slide.$slide);
4433  
4434            slidePos = $.fancybox.getTranslate(slide.$slide);
4435            stagePos = $.fancybox.getTranslate(instance.$refs.stage);
4436  
4437            slide.$slide
4438              .css({
4439                transform: "",
4440                opacity: "",
4441                "transition-duration": "",
4442              })
4443              .removeClass("fancybox-animated")
4444              .removeClass(function (index, className) {
4445                return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(
4446                  " "
4447                );
4448              });
4449  
4450            if (slide.pos === instance.current.pos) {
4451              self.sliderStartPos.top = slidePos.top - stagePos.top;
4452              self.sliderStartPos.left = slidePos.left - stagePos.left;
4453            }
4454  
4455            $.fancybox.setTranslate(slide.$slide, {
4456              top: slidePos.top - stagePos.top,
4457              left: slidePos.left - stagePos.left,
4458            });
4459          });
4460  
4461          // Stop slideshow
4462          if (instance.SlideShow && instance.SlideShow.isActive) {
4463            instance.SlideShow.stop();
4464          }
4465        }
4466  
4467        return;
4468      }
4469  
4470      // Sticky edges
4471      if (swiping == "x") {
4472        if (
4473          self.distanceX > 0 &&
4474          (self.instance.group.length < 2 ||
4475            (self.instance.current.index === 0 &&
4476              !self.instance.current.opts.loop))
4477        ) {
4478          left = left + Math.pow(self.distanceX, 0.8);
4479        } else if (
4480          self.distanceX < 0 &&
4481          (self.instance.group.length < 2 ||
4482            (self.instance.current.index === self.instance.group.length - 1 &&
4483              !self.instance.current.opts.loop))
4484        ) {
4485          left = left - Math.pow(-self.distanceX, 0.8);
4486        } else {
4487          left = left + self.distanceX;
4488        }
4489      }
4490  
4491      self.sliderLastPos = {
4492        top: swiping == "x" ? 0 : self.sliderStartPos.top + self.distanceY,
4493        left: left,
4494      };
4495  
4496      if (self.requestId) {
4497        cancelAFrame(self.requestId);
4498  
4499        self.requestId = null;
4500      }
4501  
4502      self.requestId = requestAFrame(function () {
4503        if (self.sliderLastPos) {
4504          $.each(self.instance.slides, function (index, slide) {
4505            var pos = slide.pos - self.instance.currPos;
4506  
4507            $.fancybox.setTranslate(slide.$slide, {
4508              top: self.sliderLastPos.top,
4509              left:
4510                self.sliderLastPos.left +
4511                pos * self.canvasWidth +
4512                pos * slide.opts.gutter,
4513            });
4514          });
4515  
4516          self.$container.addClass("fancybox-is-sliding");
4517        }
4518      });
4519    };
4520  
4521    Guestures.prototype.onPan = function () {
4522      var self = this;
4523  
4524      // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)
4525      if (
4526        distance(self.newPoints[0], self.realPoints[0]) <
4527        ($.fancybox.isMobile ? 10 : 5)
4528      ) {
4529        self.startPoints = self.newPoints;
4530        return;
4531      }
4532  
4533      self.canTap = false;
4534  
4535      self.contentLastPos = self.limitMovement();
4536  
4537      if (self.requestId) {
4538        cancelAFrame(self.requestId);
4539      }
4540  
4541      self.requestId = requestAFrame(function () {
4542        $.fancybox.setTranslate(self.$content, self.contentLastPos);
4543      });
4544    };
4545  
4546    // Make panning sticky to the edges
4547    Guestures.prototype.limitMovement = function () {
4548      var self = this;
4549  
4550      var canvasWidth = self.canvasWidth;
4551      var canvasHeight = self.canvasHeight;
4552  
4553      var distanceX = self.distanceX;
4554      var distanceY = self.distanceY;
4555  
4556      var contentStartPos = self.contentStartPos;
4557  
4558      var currentOffsetX = contentStartPos.left;
4559      var currentOffsetY = contentStartPos.top;
4560  
4561      var currentWidth = contentStartPos.width;
4562      var currentHeight = contentStartPos.height;
4563  
4564      var minTranslateX,
4565        minTranslateY,
4566        maxTranslateX,
4567        maxTranslateY,
4568        newOffsetX,
4569        newOffsetY;
4570  
4571      if (currentWidth > canvasWidth) {
4572        newOffsetX = currentOffsetX + distanceX;
4573      } else {
4574        newOffsetX = currentOffsetX;
4575      }
4576  
4577      newOffsetY = currentOffsetY + distanceY;
4578  
4579      // Slow down proportionally to traveled distance
4580      minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);
4581      minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);
4582  
4583      maxTranslateX = Math.min(
4584        canvasWidth - currentWidth,
4585        canvasWidth * 0.5 - currentWidth * 0.5
4586      );
4587      maxTranslateY = Math.min(
4588        canvasHeight - currentHeight,
4589        canvasHeight * 0.5 - currentHeight * 0.5
4590      );
4591  
4592      //   ->
4593      if (distanceX > 0 && newOffsetX > minTranslateX) {
4594        newOffsetX =
4595          minTranslateX -
4596            1 +
4597            Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;
4598      }
4599  
4600      //    <-
4601      if (distanceX < 0 && newOffsetX < maxTranslateX) {
4602        newOffsetX =
4603          maxTranslateX +
4604            1 -
4605            Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;
4606      }
4607  
4608      //   \/
4609      if (distanceY > 0 && newOffsetY > minTranslateY) {
4610        newOffsetY =
4611          minTranslateY -
4612            1 +
4613            Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;
4614      }
4615  
4616      //   /\
4617      if (distanceY < 0 && newOffsetY < maxTranslateY) {
4618        newOffsetY =
4619          maxTranslateY +
4620            1 -
4621            Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;
4622      }
4623  
4624      return {
4625        top: newOffsetY,
4626        left: newOffsetX,
4627      };
4628    };
4629  
4630    Guestures.prototype.limitPosition = function (
4631      newOffsetX,
4632      newOffsetY,
4633      newWidth,
4634      newHeight
4635    ) {
4636      var self = this;
4637  
4638      var canvasWidth = self.canvasWidth;
4639      var canvasHeight = self.canvasHeight;
4640  
4641      if (newWidth > canvasWidth) {
4642        newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
4643        newOffsetX =
4644          newOffsetX < canvasWidth - newWidth
4645            ? canvasWidth - newWidth
4646            : newOffsetX;
4647      } else {
4648        // Center horizontally
4649        newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);
4650      }
4651  
4652      if (newHeight > canvasHeight) {
4653        newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
4654        newOffsetY =
4655          newOffsetY < canvasHeight - newHeight
4656            ? canvasHeight - newHeight
4657            : newOffsetY;
4658      } else {
4659        // Center vertically
4660        newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);
4661      }
4662  
4663      return {
4664        top: newOffsetY,
4665        left: newOffsetX,
4666      };
4667    };
4668  
4669    Guestures.prototype.onZoom = function () {
4670      var self = this;
4671  
4672      // Calculate current distance between points to get pinch ratio and new width and height
4673      var contentStartPos = self.contentStartPos;
4674  
4675      var currentWidth = contentStartPos.width;
4676      var currentHeight = contentStartPos.height;
4677  
4678      var currentOffsetX = contentStartPos.left;
4679      var currentOffsetY = contentStartPos.top;
4680  
4681      var endDistanceBetweenFingers = distance(
4682        self.newPoints[0],
4683        self.newPoints[1]
4684      );
4685  
4686      var pinchRatio =
4687        endDistanceBetweenFingers / self.startDistanceBetweenFingers;
4688  
4689      var newWidth = Math.floor(currentWidth * pinchRatio);
4690      var newHeight = Math.floor(currentHeight * pinchRatio);
4691  
4692      // This is the translation due to pinch-zooming
4693      var translateFromZoomingX =
4694        (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
4695      var translateFromZoomingY =
4696        (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
4697  
4698      // Point between the two touches
4699      var centerPointEndX =
4700        (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();
4701      var centerPointEndY =
4702        (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();
4703  
4704      // And this is the translation due to translation of the centerpoint
4705      // between the two fingers
4706      var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
4707      var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
4708  
4709      // The new offset is the old/current one plus the total translation
4710      var newOffsetX =
4711        currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);
4712      var newOffsetY =
4713        currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);
4714  
4715      var newPos = {
4716        top: newOffsetY,
4717        left: newOffsetX,
4718        scaleX: pinchRatio,
4719        scaleY: pinchRatio,
4720      };
4721  
4722      self.canTap = false;
4723  
4724      self.newWidth = newWidth;
4725      self.newHeight = newHeight;
4726  
4727      self.contentLastPos = newPos;
4728  
4729      if (self.requestId) {
4730        cancelAFrame(self.requestId);
4731      }
4732  
4733      self.requestId = requestAFrame(function () {
4734        $.fancybox.setTranslate(self.$content, self.contentLastPos);
4735      });
4736    };
4737  
4738    Guestures.prototype.ontouchend = function (e) {
4739      var self = this;
4740  
4741      var swiping = self.isSwiping;
4742      var panning = self.isPanning;
4743      var zooming = self.isZooming;
4744      var scrolling = self.isScrolling;
4745  
4746      self.endPoints = getPointerXY(e);
4747      self.dMs = Math.max(new Date().getTime() - self.startTime, 1);
4748  
4749      self.$container.removeClass("fancybox-is-grabbing");
4750  
4751      $(document).off(".fb.touch");
4752  
4753      document.removeEventListener("scroll", self.onscroll, true);
4754  
4755      if (self.requestId) {
4756        cancelAFrame(self.requestId);
4757  
4758        self.requestId = null;
4759      }
4760  
4761      self.isSwiping = false;
4762      self.isPanning = false;
4763      self.isZooming = false;
4764      self.isScrolling = false;
4765  
4766      self.instance.isDragging = false;
4767  
4768      if (self.canTap) {
4769        return self.onTap(e);
4770      }
4771  
4772      self.speed = 100;
4773  
4774      // Speed in px/ms
4775      self.velocityX = (self.distanceX / self.dMs) * 0.5;
4776      self.velocityY = (self.distanceY / self.dMs) * 0.5;
4777  
4778      if (panning) {
4779        self.endPanning();
4780      } else if (zooming) {
4781        self.endZooming();
4782      } else {
4783        self.endSwiping(swiping, scrolling);
4784      }
4785  
4786      return;
4787    };
4788  
4789    Guestures.prototype.endSwiping = function (swiping, scrolling) {
4790      var self = this,
4791        ret = false,
4792        len = self.instance.group.length,
4793        distanceX = Math.abs(self.distanceX),
4794        canAdvance =
4795          swiping == "x" &&
4796          len > 1 &&
4797          ((self.dMs > 130 && distanceX > 10) || distanceX > 50),
4798        speedX = 300;
4799  
4800      self.sliderLastPos = null;
4801  
4802      // Close if swiped vertically / navigate if horizontally
4803      if (swiping == "y" && !scrolling && Math.abs(self.distanceY) > 50) {
4804        // Continue vertical movement
4805        $.fancybox.animate(
4806          self.instance.current.$slide,
4807          {
4808            top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,
4809            opacity: 0,
4810          },
4811          200
4812        );
4813        ret = self.instance.close(true, 250);
4814      } else if (canAdvance && self.distanceX > 0) {
4815        ret = self.instance.previous(speedX);
4816      } else if (canAdvance && self.distanceX < 0) {
4817        ret = self.instance.next(speedX);
4818      }
4819  
4820      if (ret === false && (swiping == "x" || swiping == "y")) {
4821        self.instance.centerSlide(200);
4822      }
4823  
4824      self.$container.removeClass("fancybox-is-sliding");
4825    };
4826  
4827    // Limit panning from edges
4828    // ========================
4829    Guestures.prototype.endPanning = function () {
4830      var self = this,
4831        newOffsetX,
4832        newOffsetY,
4833        newPos;
4834  
4835      if (!self.contentLastPos) {
4836        return;
4837      }
4838  
4839      if (self.opts.momentum === false || self.dMs > 350) {
4840        newOffsetX = self.contentLastPos.left;
4841        newOffsetY = self.contentLastPos.top;
4842      } else {
4843        // Continue movement
4844        newOffsetX = self.contentLastPos.left + self.velocityX * 500;
4845        newOffsetY = self.contentLastPos.top + self.velocityY * 500;
4846      }
4847  
4848      newPos = self.limitPosition(
4849        newOffsetX,
4850        newOffsetY,
4851        self.contentStartPos.width,
4852        self.contentStartPos.height
4853      );
4854  
4855      newPos.width = self.contentStartPos.width;
4856      newPos.height = self.contentStartPos.height;
4857  
4858      $.fancybox.animate(self.$content, newPos, 366);
4859    };
4860  
4861    Guestures.prototype.endZooming = function () {
4862      var self = this;
4863  
4864      var current = self.instance.current;
4865  
4866      var newOffsetX, newOffsetY, newPos, reset;
4867  
4868      var newWidth = self.newWidth;
4869      var newHeight = self.newHeight;
4870  
4871      if (!self.contentLastPos) {
4872        return;
4873      }
4874  
4875      newOffsetX = self.contentLastPos.left;
4876      newOffsetY = self.contentLastPos.top;
4877  
4878      reset = {
4879        top: newOffsetY,
4880        left: newOffsetX,
4881        width: newWidth,
4882        height: newHeight,
4883        scaleX: 1,
4884        scaleY: 1,
4885      };
4886  
4887      // Reset scalex/scaleY values; this helps for perfomance and does not break animation
4888      $.fancybox.setTranslate(self.$content, reset);
4889  
4890      if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
4891        self.instance.scaleToFit(150);
4892      } else if (newWidth > current.width || newHeight > current.height) {
4893        self.instance.scaleToActual(
4894          self.centerPointStartX,
4895          self.centerPointStartY,
4896          150
4897        );
4898      } else {
4899        newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);
4900  
4901        $.fancybox.animate(self.$content, newPos, 150);
4902      }
4903    };
4904  
4905    Guestures.prototype.onTap = function (e) {
4906      var self = this;
4907      var $target = $(e.target);
4908  
4909      var instance = self.instance;
4910      var current = instance.current;
4911  
4912      var endPoints = (e && getPointerXY(e)) || self.startPoints;
4913  
4914      var tapX = endPoints[0]
4915        ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left
4916        : 0;
4917      var tapY = endPoints[0]
4918        ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top
4919        : 0;
4920  
4921      var where;
4922  
4923      var process = function (prefix) {
4924        var action = current.opts[prefix];
4925  
4926        if ($.isFunction(action)) {
4927          action = action.apply(instance, [current, e]);
4928        }
4929  
4930        if (!action) {
4931          return;
4932        }
4933  
4934        switch (action) {
4935          case "close":
4936            instance.close(self.startEvent);
4937  
4938            break;
4939  
4940          case "toggleControls":
4941            instance.toggleControls();
4942  
4943            break;
4944  
4945          case "next":
4946            instance.next();
4947  
4948            break;
4949  
4950          case "nextOrClose":
4951            if (instance.group.length > 1) {
4952              instance.next();
4953            } else {
4954              instance.close(self.startEvent);
4955            }
4956  
4957            break;
4958  
4959          case "zoom":
4960            if (current.type == "image" && (current.isLoaded || current.$ghost)) {
4961              if (instance.canPan()) {
4962                instance.scaleToFit();
4963              } else if (instance.isScaledDown()) {
4964                instance.scaleToActual(tapX, tapY);
4965              } else if (instance.group.length < 2) {
4966                instance.close(self.startEvent);
4967              }
4968            }
4969  
4970            break;
4971        }
4972      };
4973  
4974      // Ignore right click
4975      if (e.originalEvent && e.originalEvent.button == 2) {
4976        return;
4977      }
4978  
4979      // Skip if clicked on the scrollbar
4980      if (
4981        !$target.is("img") &&
4982        tapX > $target[0].clientWidth + $target.offset().left
4983      ) {
4984        return;
4985      }
4986  
4987      // Check where is clicked
4988      if (
4989        $target.is(
4990          ".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container"
4991        )
4992      ) {
4993        where = "Outside";
4994      } else if ($target.is(".fancybox-slide")) {
4995        where = "Slide";
4996      } else if (
4997        instance.current.$content &&
4998        instance.current.$content.find($target).addBack().filter($target).length
4999      ) {
5000        where = "Content";
5001      } else {
5002        return;
5003      }
5004  
5005      // Check if this is a double tap
5006      if (self.tapped) {
5007        // Stop previously created single tap
5008        clearTimeout(self.tapped);
5009        self.tapped = null;
5010  
5011        // Skip if distance between taps is too big
5012        if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {
5013          return this;
5014        }
5015  
5016        // OK, now we assume that this is a double-tap
5017        process("dblclick" + where);
5018      } else {
5019        // Single tap will be processed if user has not clicked second time within 300ms
5020        // or there is no need to wait for double-tap
5021        self.tapX = tapX;
5022        self.tapY = tapY;
5023  
5024        if (
5025          current.opts["dblclick" + where] &&
5026          current.opts["dblclick" + where] !== current.opts["click" + where]
5027        ) {
5028          self.tapped = setTimeout(function () {
5029            self.tapped = null;
5030  
5031            if (!instance.isAnimating) {
5032              process("click" + where);
5033            }
5034          }, 500);
5035        } else {
5036          process("click" + where);
5037        }
5038      }
5039  
5040      return this;
5041    };
5042  
5043    $(document)
5044      .on("onActivate.fb", function (e, instance) {
5045        if (instance && !instance.Guestures) {
5046          instance.Guestures = new Guestures(instance);
5047        }
5048      })
5049      .on("beforeClose.fb", function (e, instance) {
5050        if (instance && instance.Guestures) {
5051          instance.Guestures.destroy();
5052        }
5053      });
5054  })(window, document, jQuery);
5055  // ==========================================================================
5056  //
5057  // SlideShow
5058  // Enables slideshow functionality
5059  //
5060  // Example of usage:
5061  // $.fancybox.getInstance().SlideShow.start()
5062  //
5063  // ==========================================================================
5064  (function (document, $) {
5065    "use strict";
5066  
5067    $.extend(true, $.fancybox.defaults, {
5068      btnTpl: {
5069        slideShow:
5070          '<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}">' +
5071          '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.5 5.4v13.2l11-6.6z"/></svg>' +
5072          '<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>' +
5073          "</button>",
5074      },
5075      slideShow: {
5076        autoStart: false,
5077        speed: 3000,
5078        progress: true,
5079      },
5080    });
5081  
5082    var SlideShow = function (instance) {
5083      this.instance = instance;
5084      this.init();
5085    };
5086  
5087    $.extend(SlideShow.prototype, {
5088      timer: null,
5089      isActive: false,
5090      $button: null,
5091  
5092      init: function () {
5093        var self = this,
5094          instance = self.instance,
5095          opts = instance.group[instance.currIndex].opts.slideShow;
5096  
5097        self.$button = instance.$refs.toolbar
5098          .find("[data-fancybox-play]")
5099          .on("click", function () {
5100            self.toggle();
5101          });
5102  
5103        if (instance.group.length < 2 || !opts) {
5104          self.$button.hide();
5105        } else if (opts.progress) {
5106          self.$progress = $('<div class="fancybox-progress"></div>').appendTo(
5107            instance.$refs.inner
5108          );
5109        }
5110      },
5111  
5112      set: function (force) {
5113        var self = this,
5114          instance = self.instance,
5115          current = instance.current;
5116  
5117        // Check if reached last element
5118        if (
5119          current &&
5120          (force === true ||
5121            current.opts.loop ||
5122            instance.currIndex < instance.group.length - 1)
5123        ) {
5124          if (self.isActive && current.contentType !== "video") {
5125            if (self.$progress) {
5126              $.fancybox.animate(
5127                self.$progress.show(),
5128                {
5129                  scaleX: 1,
5130                },
5131                current.opts.slideShow.speed
5132              );
5133            }
5134  
5135            self.timer = setTimeout(function () {
5136              if (
5137                !instance.current.opts.loop &&
5138                instance.current.index == instance.group.length - 1
5139              ) {
5140                instance.jumpTo(0);
5141              } else {
5142                instance.next();
5143              }
5144            }, current.opts.slideShow.speed);
5145          }
5146        } else {
5147          self.stop();
5148          instance.idleSecondsCounter = 0;
5149          instance.showControls();
5150        }
5151      },
5152  
5153      clear: function () {
5154        var self = this;
5155  
5156        clearTimeout(self.timer);
5157  
5158        self.timer = null;
5159  
5160        if (self.$progress) {
5161          self.$progress.removeAttr("style").hide();
5162        }
5163      },
5164  
5165      start: function () {
5166        var self = this,
5167          current = self.instance.current;
5168  
5169        if (current) {
5170          self.$button
5171            .attr(
5172              "title",
5173              (current.opts.i18n[current.opts.lang] || current.opts.i18n.en)
5174                .PLAY_STOP
5175            )
5176            .removeClass("fancybox-button--play")
5177            .addClass("fancybox-button--pause");
5178  
5179          self.isActive = true;
5180  
5181          if (current.isComplete) {
5182            self.set(true);
5183          }
5184  
5185          self.instance.trigger("onSlideShowChange", true);
5186        }
5187      },
5188  
5189      stop: function () {
5190        var self = this,
5191          current = self.instance.current;
5192  
5193        self.clear();
5194  
5195        self.$button
5196          .attr(
5197            "title",
5198            (current.opts.i18n[current.opts.lang] || current.opts.i18n.en)
5199              .PLAY_START
5200          )
5201          .removeClass("fancybox-button--pause")
5202          .addClass("fancybox-button--play");
5203  
5204        self.isActive = false;
5205  
5206        self.instance.trigger("onSlideShowChange", false);
5207  
5208        if (self.$progress) {
5209          self.$progress.removeAttr("style").hide();
5210        }
5211      },
5212  
5213      toggle: function () {
5214        var self = this;
5215  
5216        if (self.isActive) {
5217          self.stop();
5218        } else {
5219          self.start();
5220        }
5221      },
5222    });
5223  
5224    $(document).on({
5225      "onInit.fb": function (e, instance) {
5226        if (instance && !instance.SlideShow) {
5227          instance.SlideShow = new SlideShow(instance);
5228        }
5229      },
5230  
5231      "beforeShow.fb": function (e, instance, current, firstRun) {
5232        var SlideShow = instance && instance.SlideShow;
5233  
5234        if (firstRun) {
5235          if (SlideShow && current.opts.slideShow.autoStart) {
5236            SlideShow.start();
5237          }
5238        } else if (SlideShow && SlideShow.isActive) {
5239          SlideShow.clear();
5240        }
5241      },
5242  
5243      "afterShow.fb": function (e, instance, current) {
5244        var SlideShow = instance && instance.SlideShow;
5245  
5246        if (SlideShow && SlideShow.isActive) {
5247          SlideShow.set();
5248        }
5249      },
5250  
5251      "afterKeydown.fb": function (e, instance, current, keypress, keycode) {
5252        var SlideShow = instance && instance.SlideShow;
5253  
5254        // "P" or Spacebar
5255        if (
5256          SlideShow &&
5257          current.opts.slideShow &&
5258          (keycode === 80 || keycode === 32) &&
5259          !$(document.activeElement).is("button,a,input")
5260        ) {
5261          keypress.preventDefault();
5262  
5263          SlideShow.toggle();
5264        }
5265      },
5266  
5267      "beforeClose.fb onDeactivate.fb": function (e, instance) {
5268        var SlideShow = instance && instance.SlideShow;
5269  
5270        if (SlideShow) {
5271          SlideShow.stop();
5272        }
5273      },
5274    });
5275  
5276    // Page Visibility API to pause slideshow when window is not active
5277    $(document).on("visibilitychange", function () {
5278      var instance = $.fancybox.getInstance(),
5279        SlideShow = instance && instance.SlideShow;
5280  
5281      if (SlideShow && SlideShow.isActive) {
5282        if (document.hidden) {
5283          SlideShow.clear();
5284        } else {
5285          SlideShow.set();
5286        }
5287      }
5288    });
5289  })(document, jQuery);
5290  // ==========================================================================
5291  //
5292  // FullScreen
5293  // Adds fullscreen functionality
5294  //
5295  // ==========================================================================
5296  (function (document, $) {
5297    "use strict";
5298  
5299    // Collection of methods supported by user browser
5300    var fn = (function () {
5301      var fnMap = [
5302        [
5303          "requestFullscreen",
5304          "exitFullscreen",
5305          "fullscreenElement",
5306          "fullscreenEnabled",
5307          "fullscreenchange",
5308          "fullscreenerror",
5309        ],
5310        // new WebKit
5311        [
5312          "webkitRequestFullscreen",
5313          "webkitExitFullscreen",
5314          "webkitFullscreenElement",
5315          "webkitFullscreenEnabled",
5316          "webkitfullscreenchange",
5317          "webkitfullscreenerror",
5318        ],
5319        // old WebKit (Safari 5.1)
5320        [
5321          "webkitRequestFullScreen",
5322          "webkitCancelFullScreen",
5323          "webkitCurrentFullScreenElement",
5324          "webkitCancelFullScreen",
5325          "webkitfullscreenchange",
5326          "webkitfullscreenerror",
5327        ],
5328        [
5329          "mozRequestFullScreen",
5330          "mozCancelFullScreen",
5331          "mozFullScreenElement",
5332          "mozFullScreenEnabled",
5333          "mozfullscreenchange",
5334          "mozfullscreenerror",
5335        ],
5336        [
5337          "msRequestFullscreen",
5338          "msExitFullscreen",
5339          "msFullscreenElement",
5340          "msFullscreenEnabled",
5341          "MSFullscreenChange",
5342          "MSFullscreenError",
5343        ],
5344      ];
5345  
5346      var ret = {};
5347  
5348      for (var i = 0; i < fnMap.length; i++) {
5349        var val = fnMap[i];
5350  
5351        if (val && val[1] in document) {
5352          for (var j = 0; j < val.length; j++) {
5353            ret[fnMap[0][j]] = val[j];
5354          }
5355  
5356          return ret;
5357        }
5358      }
5359  
5360      return false;
5361    })();
5362  
5363    if (fn) {
5364      var FullScreen = {
5365        request: function (elem) {
5366          elem = elem || document.documentElement;
5367  
5368          elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT);
5369        },
5370        exit: function () {
5371          document[fn.exitFullscreen]();
5372        },
5373        toggle: function (elem) {
5374          elem = elem || document.documentElement;
5375  
5376          if (this.isFullscreen()) {
5377            this.exit();
5378          } else {
5379            this.request(elem);
5380          }
5381        },
5382        isFullscreen: function () {
5383          return Boolean(document[fn.fullscreenElement]);
5384        },
5385        enabled: function () {
5386          return Boolean(document[fn.fullscreenEnabled]);
5387        },
5388      };
5389  
5390      $.extend(true, $.fancybox.defaults, {
5391        btnTpl: {
5392          fullScreen:
5393            '<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fsenter" title="{{FULL_SCREEN}}">' +
5394            '<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>' +
5395            '<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>' +
5396            "</button>",
5397        },
5398        fullScreen: {
5399          autoStart: false,
5400        },
5401      });
5402  
5403      $(document).on(fn.fullscreenchange, function () {
5404        var isFullscreen = FullScreen.isFullscreen(),
5405          instance = $.fancybox.getInstance();
5406  
5407        if (instance) {
5408          // If image is zooming, then force to stop and reposition properly
5409          if (
5410            instance.current &&
5411            instance.current.type === "image" &&
5412            instance.isAnimating
5413          ) {
5414            instance.isAnimating = false;
5415  
5416            instance.update(true, true, 0);
5417  
5418            if (!instance.isComplete) {
5419              instance.complete();
5420            }
5421          }
5422  
5423          instance.trigger("onFullscreenChange", isFullscreen);
5424  
5425          instance.$refs.container.toggleClass(
5426            "fancybox-is-fullscreen",
5427            isFullscreen
5428          );
5429  
5430          instance.$refs.toolbar
5431            .find("[data-fancybox-fullscreen]")
5432            .toggleClass("fancybox-button--fsenter", !isFullscreen)
5433            .toggleClass("fancybox-button--fsexit", isFullscreen);
5434        }
5435      });
5436    }
5437  
5438    $(document).on({
5439      "onInit.fb": function (e, instance) {
5440        var $container;
5441  
5442        if (!fn) {
5443          instance.$refs.toolbar.find("[data-fancybox-fullscreen]").remove();
5444  
5445          return;
5446        }
5447  
5448        if (instance && instance.group[instance.currIndex].opts.fullScreen) {
5449          $container = instance.$refs.container;
5450  
5451          $container.on(
5452            "click.fb-fullscreen",
5453            "[data-fancybox-fullscreen]",
5454            function (e) {
5455              e.stopPropagation();
5456              e.preventDefault();
5457  
5458              FullScreen.toggle();
5459            }
5460          );
5461  
5462          if (
5463            instance.opts.fullScreen &&
5464            instance.opts.fullScreen.autoStart === true
5465          ) {
5466            FullScreen.request();
5467          }
5468  
5469          // Expose API
5470          instance.FullScreen = FullScreen;
5471        } else if (instance) {
5472          instance.$refs.toolbar.find("[data-fancybox-fullscreen]").hide();
5473        }
5474      },
5475  
5476      "afterKeydown.fb": function (e, instance, current, keypress, keycode) {
5477        // "F"
5478        if (instance && instance.FullScreen && keycode === 70) {
5479          keypress.preventDefault();
5480  
5481          instance.FullScreen.toggle();
5482        }
5483      },
5484  
5485      "beforeClose.fb": function (e, instance) {
5486        if (
5487          instance &&
5488          instance.FullScreen &&
5489          instance.$refs.container.hasClass("fancybox-is-fullscreen")
5490        ) {
5491          FullScreen.exit();
5492        }
5493      },
5494    });
5495  })(document, jQuery);
5496  // ==========================================================================
5497  //
5498  // Thumbs
5499  // Displays thumbnails in a grid
5500  //
5501  // ==========================================================================
5502  (function (document, $) {
5503    "use strict";
5504  
5505    var CLASS = "fancybox-thumbs",
5506      CLASS_ACTIVE = CLASS + "-active";
5507  
5508    // Make sure there are default values
5509    $.fancybox.defaults = $.extend(
5510      true,
5511      {
5512        btnTpl: {
5513          thumbs:
5514            '<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}">' +
5515            '<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>' +
5516            "</button>",
5517        },
5518        thumbs: {
5519          autoStart: false, // Display thumbnails on opening
5520          hideOnClose: true, // Hide thumbnail grid when closing animation starts
5521          parentEl: ".fancybox-container", // Container is injected into this element
5522          axis: "y", // Vertical (y) or horizontal (x) scrolling
5523        },
5524      },
5525      $.fancybox.defaults
5526    );
5527  
5528    var FancyThumbs = function (instance) {
5529      this.init(instance);
5530    };
5531  
5532    $.extend(FancyThumbs.prototype, {
5533      $button: null,
5534      $grid: null,
5535      $list: null,
5536      isVisible: false,
5537      isActive: false,
5538  
5539      init: function (instance) {
5540        var self = this,
5541          group = instance.group,
5542          enabled = 0;
5543  
5544        self.instance = instance;
5545        self.opts = group[instance.currIndex].opts.thumbs;
5546  
5547        instance.Thumbs = self;
5548  
5549        self.$button = instance.$refs.toolbar.find("[data-fancybox-thumbs]");
5550  
5551        // Enable thumbs if at least two group items have thumbnails
5552        for (var i = 0, len = group.length; i < len; i++) {
5553          if (group[i].thumb) {
5554            enabled++;
5555          }
5556  
5557          if (enabled > 1) {
5558            break;
5559          }
5560        }
5561  
5562        if (enabled > 1 && !!self.opts) {
5563          self.$button.removeAttr("style").on("click", function () {
5564            self.toggle();
5565          });
5566  
5567          self.isActive = true;
5568        } else {
5569          self.$button.hide();
5570        }
5571      },
5572  
5573      create: function () {
5574        var self = this,
5575          instance = self.instance,
5576          parentEl = self.opts.parentEl,
5577          list = [],
5578          src;
5579  
5580        if (!self.$grid) {
5581          // Create main element
5582          self.$grid = $(
5583            '<div class="' +
5584              CLASS +
5585              " " +
5586              CLASS +
5587              "-" +
5588              self.opts.axis +
5589              '"></div>'
5590          ).appendTo(
5591            instance.$refs.container.find(parentEl).addBack().filter(parentEl)
5592          );
5593  
5594          // Add "click" event that performs gallery navigation
5595          self.$grid.on("click", "a", function () {
5596            instance.jumpTo($(this).attr("data-index"));
5597          });
5598        }
5599  
5600        // Build the list
5601        if (!self.$list) {
5602          self.$list = $('<div class="' + CLASS + '__list">').appendTo(
5603            self.$grid
5604          );
5605        }
5606  
5607        $.each(instance.group, function (i, item) {
5608          src = item.thumb;
5609  
5610          if (!src && item.type === "image") {
5611            src = item.src;
5612          }
5613  
5614          list.push(
5615            '<a href="javascript:;" tabindex="0" data-index="' +
5616              i +
5617              '"' +
5618              (src && src.length
5619                ? ' style="background-image:url(' + src + ')"'
5620                : 'class="fancybox-thumbs-missing"') +
5621              "></a>"
5622          );
5623        });
5624  
5625        self.$list[0].innerHTML = list.join("");
5626  
5627        if (self.opts.axis === "x") {
5628          // Set fixed width for list element to enable horizontal scrolling
5629          self.$list.width(
5630            parseInt(self.$grid.css("padding-right"), 10) +
5631              instance.group.length * self.$list.children().eq(0).outerWidth(true)
5632          );
5633        }
5634      },
5635  
5636      focus: function (duration) {
5637        var self = this,
5638          $list = self.$list,
5639          $grid = self.$grid,
5640          thumb,
5641          thumbPos;
5642  
5643        if (!self.instance.current) {
5644          return;
5645        }
5646  
5647        thumb = $list
5648          .children()
5649          .removeClass(CLASS_ACTIVE)
5650          .filter('[data-index="' + self.instance.current.index + '"]')
5651          .addClass(CLASS_ACTIVE);
5652  
5653        thumbPos = thumb.position();
5654  
5655        // Check if need to scroll to make current thumb visible
5656        if (
5657          self.opts.axis === "y" &&
5658          (thumbPos.top < 0 ||
5659            thumbPos.top > $list.height() - thumb.outerHeight())
5660        ) {
5661          $list.stop().animate(
5662            {
5663              scrollTop: $list.scrollTop() + thumbPos.top,
5664            },
5665            duration
5666          );
5667        } else if (
5668          self.opts.axis === "x" &&
5669          (thumbPos.left < $grid.scrollLeft() ||
5670            thumbPos.left >
5671              $grid.scrollLeft() + ($grid.width() - thumb.outerWidth()))
5672        ) {
5673          $list.parent().stop().animate(
5674            {
5675              scrollLeft: thumbPos.left,
5676            },
5677            duration
5678          );
5679        }
5680      },
5681  
5682      update: function () {
5683        var that = this;
5684        that.instance.$refs.container.toggleClass(
5685          "fancybox-show-thumbs",
5686          this.isVisible
5687        );
5688  
5689        if (that.isVisible) {
5690          if (!that.$grid) {
5691            that.create();
5692          }
5693  
5694          that.instance.trigger("onThumbsShow");
5695  
5696          that.focus(0);
5697        } else if (that.$grid) {
5698          that.instance.trigger("onThumbsHide");
5699        }
5700  
5701        // Update content position
5702        that.instance.update();
5703      },
5704  
5705      hide: function () {
5706        this.isVisible = false;
5707        this.update();
5708      },
5709  
5710      show: function () {
5711        this.isVisible = true;
5712        this.update();
5713      },
5714  
5715      toggle: function () {
5716        this.isVisible = !this.isVisible;
5717        this.update();
5718      },
5719    });
5720  
5721    $(document).on({
5722      "onInit.fb": function (e, instance) {
5723        var Thumbs;
5724  
5725        if (instance && !instance.Thumbs) {
5726          Thumbs = new FancyThumbs(instance);
5727  
5728          if (Thumbs.isActive && Thumbs.opts.autoStart === true) {
5729            Thumbs.show();
5730          }
5731        }
5732      },
5733  
5734      "beforeShow.fb": function (e, instance, item, firstRun) {
5735        var Thumbs = instance && instance.Thumbs;
5736  
5737        if (Thumbs && Thumbs.isVisible) {
5738          Thumbs.focus(firstRun ? 0 : 250);
5739        }
5740      },
5741  
5742      "afterKeydown.fb": function (e, instance, current, keypress, keycode) {
5743        var Thumbs = instance && instance.Thumbs;
5744  
5745        // "G"
5746        if (Thumbs && Thumbs.isActive && keycode === 71) {
5747          keypress.preventDefault();
5748  
5749          Thumbs.toggle();
5750        }
5751      },
5752  
5753      "beforeClose.fb": function (e, instance) {
5754        var Thumbs = instance && instance.Thumbs;
5755  
5756        if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) {
5757          Thumbs.$grid.hide();
5758        }
5759      },
5760    });
5761  })(document, jQuery);
5762  //// ==========================================================================
5763  //
5764  // Share
5765  // Displays simple form for sharing current url
5766  //
5767  // ==========================================================================
5768  (function (document, $) {
5769    "use strict";
5770  
5771    $.extend(true, $.fancybox.defaults, {
5772      btnTpl: {
5773        share:
5774          '<button data-fancybox-share class="fancybox-button fancybox-button--share" title="{{SHARE}}">' +
5775          '<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>' +
5776          "</button>",
5777      },
5778      share: {
5779        url: function (instance, item) {
5780          return (
5781            (!instance.currentHash &&
5782            !(item.type === "inline" || item.type === "html")
5783              ? item.origSrc || item.src
5784              : false) || window.location
5785          );
5786        },
5787        tpl:
5788          '<div class="fancybox-share">' +
5789          "<h1>{{SHARE}}</h1>" +
5790          "<p>" +
5791          '<a class="fancybox-share__button fancybox-share__button--fb" href="https://www.facebook.com/sharer/sharer.php?u={{url}}">' +
5792          '<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>' +
5793          "<span>Facebook</span>" +
5794          "</a>" +
5795          '<a class="fancybox-share__button fancybox-share__button--tw" href="https://twitter.com/intent/tweet?url={{url}}&text={{descr}}">' +
5796          '<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>' +
5797          "<span>Twitter</span>" +
5798          "</a>" +
5799          '<a class="fancybox-share__button fancybox-share__button--pt" href="https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}">' +
5800          '<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>' +
5801          "<span>Pinterest</span>" +
5802          "</a>" +
5803          "</p>" +
5804          '<p><input class="fancybox-share__input" type="text" value="{{url_raw}}" onclick="select()" /></p>' +
5805          "</div>",
5806      },
5807    });
5808  
5809    function escapeHtml(string) {
5810      var entityMap = {
5811        "&": "&amp;",
5812        "<": "&lt;",
5813        ">": "&gt;",
5814        '"': "&quot;",
5815        "'": "&#39;",
5816        "/": "&#x2F;",
5817        "`": "&#x60;",
5818        "=": "&#x3D;",
5819      };
5820  
5821      return String(string).replace(/[&<>"'`=\/]/g, function (s) {
5822        return entityMap[s];
5823      });
5824    }
5825  
5826    $(document).on("click", "[data-fancybox-share]", function () {
5827      var instance = $.fancybox.getInstance(),
5828        current = instance.current || null,
5829        url,
5830        tpl;
5831  
5832      if (!current) {
5833        return;
5834      }
5835  
5836      if ($.type(current.opts.share.url) === "function") {
5837        url = current.opts.share.url.apply(current, [instance, current]);
5838      }
5839  
5840      tpl = current.opts.share.tpl
5841        .replace(
5842          /\{\{media\}\}/g,
5843          current.type === "image" ? encodeURIComponent(current.src) : ""
5844        )
5845        .replace(/\{\{url\}\}/g, encodeURIComponent(url))
5846        .replace(/\{\{url_raw\}\}/g, escapeHtml(url))
5847        .replace(
5848          /\{\{descr\}\}/g,
5849          instance.$caption ? encodeURIComponent(instance.$caption.text()) : ""
5850        );
5851  
5852      $.fancybox.open({
5853        src: instance.translate(instance, tpl),
5854        type: "html",
5855        opts: {
5856          touch: false,
5857          animationEffect: false,
5858          afterLoad: function (shareInstance, shareCurrent) {
5859            // Close self if parent instance is closing
5860            instance.$refs.container.one("beforeClose.fb", function () {
5861              shareInstance.close(null, 0);
5862            });
5863  
5864            // Opening links in a popup window
5865            shareCurrent.$content
5866              .find(".fancybox-share__button")
5867              .click(function () {
5868                window.open(this.href, "Share", "width=550, height=450");
5869                return false;
5870              });
5871          },
5872          mobile: {
5873            autoFocus: false,
5874          },
5875        },
5876      });
5877    });
5878  })(document, jQuery);
5879  // ==========================================================================
5880  //
5881  // Hash
5882  // Enables linking to each modal
5883  //
5884  // ==========================================================================
5885  (function (window, document, $) {
5886    "use strict";
5887  
5888    // Simple $.escapeSelector polyfill (for jQuery prior v3)
5889    if (!$.escapeSelector) {
5890      $.escapeSelector = function (sel) {
5891        var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
5892        var fcssescape = function (ch, asCodePoint) {
5893          if (asCodePoint) {
5894            // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
5895            if (ch === "\0") {
5896              return "\uFFFD";
5897            }
5898  
5899            // Control characters and (dependent upon position) numbers get escaped as code points
5900            return (
5901              ch.slice(0, -1) +
5902              "\\" +
5903              ch.charCodeAt(ch.length - 1).toString(16) +
5904              " "
5905            );
5906          }
5907  
5908          // Other potentially-special ASCII characters get backslash-escaped
5909          return "\\" + ch;
5910        };
5911  
5912        return (sel + "").replace(rcssescape, fcssescape);
5913      };
5914    }
5915  
5916    // Get info about gallery name and current index from url
5917    function parseUrl() {
5918      var hash = window.location.hash.substr(1),
5919        rez = hash.split("-"),
5920        index =
5921          rez.length > 1 && /^\+?\d+$/.test(rez[rez.length - 1])
5922            ? parseInt(rez.pop(-1), 10) || 1
5923            : 1,
5924        gallery = rez.join("-");
5925  
5926      return {
5927        hash: hash,
5928        /* Index is starting from 1 */
5929        index: index < 1 ? 1 : index,
5930        gallery: gallery,
5931      };
5932    }
5933  
5934    // Trigger click evnt on links to open new fancyBox instance
5935    function triggerFromUrl(url) {
5936      if (url.gallery !== "") {
5937        // If we can find element matching 'data-fancybox' atribute,
5938        // then triggering click event should start fancyBox
5939        $("[data-fancybox='" + $.escapeSelector(url.gallery) + "']")
5940          .eq(url.index - 1)
5941          .focus()
5942          .trigger("click.fb-start");
5943      }
5944    }
5945  
5946    // Get gallery name from current instance
5947    function getGalleryID(instance) {
5948      var opts, ret;
5949  
5950      if (!instance) {
5951        return false;
5952      }
5953  
5954      opts = instance.current ? instance.current.opts : instance.opts;
5955      ret =
5956        opts.hash ||
5957        (opts.$orig
5958          ? opts.$orig.data("fancybox") || opts.$orig.data("fancybox-trigger")
5959          : "");
5960  
5961      return ret === "" ? false : ret;
5962    }
5963  
5964    // Start when DOM becomes ready
5965    $(function () {
5966      // Check if user has disabled this module
5967      if ($.fancybox.defaults.hash === false) {
5968        return;
5969      }
5970  
5971      // Update hash when opening/closing fancyBox
5972      $(document).on({
5973        "onInit.fb": function (e, instance) {
5974          var url, gallery;
5975  
5976          if (instance.group[instance.currIndex].opts.hash === false) {
5977            return;
5978          }
5979  
5980          url = parseUrl();
5981          gallery = getGalleryID(instance);
5982  
5983          // Make sure gallery start index matches index from hash
5984          if (gallery && url.gallery && gallery == url.gallery) {
5985            instance.currIndex = url.index - 1;
5986          }
5987        },
5988  
5989        "beforeShow.fb": function (e, instance, current, firstRun) {
5990          var gallery;
5991  
5992          if (!current || current.opts.hash === false) {
5993            return;
5994          }
5995  
5996          // Check if need to update window hash
5997          gallery = getGalleryID(instance);
5998  
5999          if (!gallery) {
6000            return;
6001          }
6002  
6003          // Variable containing last hash value set by fancyBox
6004          // It will be used to determine if fancyBox needs to close after hash change is detected
6005          instance.currentHash =
6006            gallery +
6007            (instance.group.length > 1 ? "-" + (current.index + 1) : "");
6008  
6009          // If current hash is the same (this instance most likely is opened by hashchange), then do nothing
6010          if (window.location.hash === "#" + instance.currentHash) {
6011            return;
6012          }
6013  
6014          if (firstRun && !instance.origHash) {
6015            instance.origHash = window.location.hash;
6016          }
6017  
6018          if (instance.hashTimer) {
6019            clearTimeout(instance.hashTimer);
6020          }
6021  
6022          // Update hash
6023          instance.hashTimer = setTimeout(function () {
6024            if ("replaceState" in window.history) {
6025              window.history[firstRun ? "pushState" : "replaceState"](
6026                {},
6027                document.title,
6028                window.location.pathname +
6029                  window.location.search +
6030                  "#" +
6031                  instance.currentHash
6032              );
6033  
6034              if (firstRun) {
6035                instance.hasCreatedHistory = true;
6036              }
6037            } else {
6038              window.location.hash = instance.currentHash;
6039            }
6040  
6041            instance.hashTimer = null;
6042          }, 300);
6043        },
6044  
6045        "beforeClose.fb": function (e, instance, current) {
6046          if (!current || current.opts.hash === false) {
6047            return;
6048          }
6049  
6050          clearTimeout(instance.hashTimer);
6051  
6052          // Goto previous history entry
6053          if (instance.currentHash && instance.hasCreatedHistory) {
6054            window.history.back();
6055          } else if (instance.currentHash) {
6056            if ("replaceState" in window.history) {
6057              window.history.replaceState(
6058                {},
6059                document.title,
6060                window.location.pathname +
6061                  window.location.search +
6062                  (instance.origHash || "")
6063              );
6064            } else {
6065              window.location.hash = instance.origHash;
6066            }
6067          }
6068  
6069          instance.currentHash = null;
6070        },
6071      });
6072  
6073      // Check if need to start/close after url has changed
6074      $(window).on("hashchange.fb", function () {
6075        var url = parseUrl(),
6076          fb = null;
6077  
6078        // Find last fancyBox instance that has "hash"
6079        $.each($(".fancybox-container").get().reverse(), function (index, value) {
6080          var tmp = $(value).data("FancyBox");
6081  
6082          if (tmp && tmp.currentHash) {
6083            fb = tmp;
6084            return false;
6085          }
6086        });
6087  
6088        if (fb) {
6089          // Now, compare hash values
6090          if (
6091            fb.currentHash !== url.gallery + "-" + url.index &&
6092            !(url.index === 1 && fb.currentHash == url.gallery)
6093          ) {
6094            fb.currentHash = null;
6095  
6096            fb.close();
6097          }
6098        } else if (url.gallery !== "") {
6099          triggerFromUrl(url);
6100        }
6101      });
6102  
6103      // Check current hash and trigger click event on matching element to start fancyBox, if needed
6104      setTimeout(function () {
6105        if (!$.fancybox.getInstance()) {
6106          triggerFromUrl(parseUrl());
6107        }
6108      }, 50);
6109    });
6110  })(window, document, jQuery);
6111  // ==========================================================================
6112  //
6113  // Wheel
6114  // Basic mouse weheel support for gallery navigation
6115  //
6116  // ==========================================================================
6117  (function (document, $) {
6118    "use strict";
6119  
6120    var prevTime = new Date().getTime();
6121  
6122    $(document).on({
6123      "onInit.fb": function (e, instance, current) {
6124        instance.$refs.stage.on(
6125          "mousewheel DOMMouseScroll wheel MozMousePixelScroll",
6126          function (e) {
6127            var current = instance.current,
6128              currTime = new Date().getTime();
6129  
6130            if (
6131              instance.group.length < 2 ||
6132              current.opts.wheel === false ||
6133              (current.opts.wheel === "auto" && current.type !== "image")
6134            ) {
6135              return;
6136            }
6137  
6138            e.preventDefault();
6139            e.stopPropagation();
6140  
6141            if (current.$slide.hasClass("fancybox-animated")) {
6142              return;
6143            }
6144  
6145            e = e.originalEvent || e;
6146  
6147            if (currTime - prevTime < 250) {
6148              return;
6149            }
6150  
6151            prevTime = currTime;
6152  
6153            instance[
6154              (-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0
6155                ? "next"
6156                : "previous"
6157            ]();
6158          }
6159        );
6160      },
6161    });
6162  })(document, jQuery);
6163  
6164  
6165  
6166  

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.