PageSourceSearch

https://karacasu.bel.tr/tema/genel/assets/js/fancybox.js

js karacasu.bel.tr collected 2026-09-25 12:33:07 UTC 131,612 bytes, 4,344 lines download raw bytes

1// ==================================================
2// fancyBox v3.0.47
3//
4// Licensed GPLv3 for open source use
5// or fancyBox Commercial License for commercial use
6//
7// http://fancyapps.com/fancybox/
8// Copyright 2017 fancyApps
9//
10// ==================================================
11;(function (window, document, $, undefined) {
12    'use strict';
13
14    // If there's no jQuery, fancyBox can't work
15    // =========================================
16
17    if ( !$ ) {
18        return undefined;
19    }
20
21    // Private default settings
22    // ========================
23
24    var defaults = {
25
26        // Animation duration in ms
27        speed : 330,
28
29        // Enable infinite gallery navigation
30        loop : true,
31
32        // Should zoom animation change opacity, too
33        // If opacity is 'auto', then fade-out if image and thumbnail have different aspect ratios
34        opacity : 'auto',
35
36        // Space around image, ignored if zoomed-in or viewport smaller than 800px
37        margin : [44, 0],
38
39        // Horizontal space between slides
40        gutter : 30,
41
42        // Should display toolbars
43        infobar : true,
44        buttons : true,
45
46        // What buttons should appear in the toolbar
47        slideShow  : true,
48        fullScreen : true,
49        thumbs     : true,
50        closeBtn   : true,
51
52        // Should apply small close button at top right corner of the content
53        // If 'auto' - will be set for content having type 'html', 'inline' or 'ajax'
54        smallBtn : 'auto',
55
56        image : {
57
58            // Wait for images to load before displaying
59            // Requires predefined image dimensions
60            // If 'auto' - will zoom in thumbnail if 'width' and 'height' attributes are found
61            preload : "auto",
62
63            // Protect an image from downloading by right-click
64            protect : false
65
66        },
67
68        ajax : {
69
70            // Object containing settings for ajax request
71            settings : {
72
73                // This helps to indicate that request comes from the modal
74                // Feel free to change naming
75                data : {
76                    fancybox : true
77                }
78            }
79
80        },
81
82        iframe : {
83
84            // Iframe template
85            tpl : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" src=""></iframe>',
86
87            // Preload iframe before displaying it
88            // This allows to calculate iframe content width and height
89            // (note: Due to "Same Origin Policy", you can't get cross domain data).
90            preload : true,
91
92            // Scrolling attribute for iframe tag
93            scrolling : 'no',
94
95            // Custom CSS styling for iframe wrapping element
96            css : {}
97
98        },
99
100        // Custom CSS class for layout
101        baseClass : '',
102
103        // Custom CSS class for slide element
104        slideClass : '',
105
106        // Base template for layout
107        baseTpl : '<div class="fancybox-container" role="dialog" tabindex="-1">' +
108                '<div class="fancybox-bg"></div>' +
109                '<div class="fancybox-infobar">' +
110                    '<button data-fancybox-previous class="fancybox-button fancybox-button--left" title="Previous"></button>' +
111                    '<div class="fancybox-infobar__body">' +
112                        '<span class="js-fancybox-index"></span>&nbsp;/&nbsp;<span class="js-fancybox-count"></span>' +
113                    '</div>' +
114                    '<button data-fancybox-next class="fancybox-button fancybox-button--right" title="Next"></button>' +
115                '</div>' +
116                '<div class="fancybox-buttons">' +
117                    '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="Close (Esc)"></button>' +
118                '</div>' +
119                '<div class="fancybox-slider-wrap">' +
120                    '<div class="fancybox-slider"></div>' +
121                '</div>' +
122                '<div class="fancybox-caption-wrap"><div class="fancybox-caption"></div></div>' +
123            '</div>',
124
125        // Loading indicator template
126        spinnerTpl : '<div class="fancybox-loading"></div>',
127
128        // Error message template
129        errorTpl : '<div class="fancybox-error"><p>The requested content cannot be loaded. <br /> Please try again later.<p></div>',
130
131        // This will be appended to html content, if "smallBtn" option is not set to false
132        closeTpl : '<button data-fancybox-close class="fancybox-close-small"></button>',
133
134        // Container is injected into this element
135        parentEl : 'body',
136
137        // Enable gestures (tap, zoom, pan and pinch)
138        touch : false,
139
140        // Enable keyboard navigation
141        keyboard : true,
142
143        // Try to focus on first focusable element after opening
144        focus : true,
145
146        // Close when clicked outside of the content
147        closeClickOutside : true,
148
149        // Callbacks
150        beforeLoad   : $.noop,
151        afterLoad    : $.noop,
152        beforeMove   : $.noop,
153        afterMove    : $.noop,
154        onComplete   : $.noop,
155
156        onInit       : $.noop,
157        beforeClose  : $.noop,
158        afterClose   : $.noop,
159        onActivate   : $.noop,
160        onDeactivate : $.noop
161
162    };
163
164    var $W = $(window);
165    var $D = $(document);
166
167    var called = 0;
168
169    // Check if an object is a jQuery object and not a native JavaScript object
170    // ========================================================================
171
172    var isQuery = function (obj) {
173        return obj && obj.hasOwnProperty && obj instanceof $;
174    };
175
176    // Handle multiple browsers for requestAnimationFrame()
177    // ====================================================
178
179    var requestAFrame = (function() {
180        return  window.requestAnimationFrame ||
181                window.webkitRequestAnimationFrame ||
182                window.mozRequestAnimationFrame ||
183                function( callback ) {
184                    window.setTimeout(callback, 1000 / 60); };
185                })();
186
187
188    // Check if element is inside the viewport by at least 1 pixel
189    // ===========================================================
190
191    var isElementInViewport = function( el ) {
192        var rect;
193
194        if ( typeof $ === "function" && el instanceof $ ) {
195            el = el[0];
196        }
197
198        rect = el.getBoundingClientRect();
199
200        return rect.bottom > 0 && rect.right > 0 &&
201                rect.left < (window.innerWidth || document.documentElement.clientWidth)  &&
202                rect.top < (window.innerHeight || document.documentElement.clientHeight);
203    };
204
205
206    // Class definition
207    // ================
208
209    var FancyBox = function( content, opts, index ) {
210        var self = this;
211
212        self.opts  = $.extend( true, { index : index }, defaults, opts || {} );
213        self.id    = self.opts.id || ++called;
214        self.group = [];
215
216        self.currIndex = parseInt( self.opts.index, 10 ) || 0;
217        self.prevIndex = null;
218
219        self.prevPos = null;
220        self.currPos = 0;
221
222        self.firstRun = null;
223
224        // Create group elements from original item collection
225        self.createGroup( content );
226
227        if ( !self.group.length ) {
228            return;
229        }
230
231        // Save last active element and current scroll position
232        self.$lastFocus = $(document.activeElement).blur();
233
234        // Collection of gallery objects
235        self.slides = {};
236
237        self.init( content );
238
239    };
240
241    $.extend(FancyBox.prototype, {
242
243        // Create DOM structure
244        // ====================
245
246        init : function() {
247            var self = this;
248
249            var galleryHasHtml = false;
250
251            var testWidth;
252            var $container;
253
254            self.scrollTop  = $D.scrollTop();
255            self.scrollLeft = $D.scrollLeft();
256
257            if ( !$.fancybox.getInstance() ) {
258                testWidth = $( 'body' ).width();
259
260                $( 'html' ).addClass( 'fancybox-enabled' );
261
262                if ( $.fancybox.isTouch ) {
263
264                    // Ugly workaround for iOS page shifting issue (when input
264s get focus)
265                    // Do not apply for images, otherwise top/bottom bars will appear
266                    $.each( self.group, function( key, item ) {
267                        if ( item.type !== 'image' && item.type !== 'iframe' ) {
268                            galleryHasHtml = true;
269                            return false;
270                        }
271                    });
272
273                    if ( galleryHasHtml ) {
274                        $('body').css({
275                            position : 'fixed',
276                            width    : testWidth,
277                            top      : self.scrollTop * -1
278                        });
279                    }
280
281                } else {
282
283                    // Compare page width after adding "overflow:hidden"
284                    testWidth = $( 'body' ).width() - testWidth;
285
286                    // Width has changed - compensate missing scrollbars
287                    if ( testWidth > 1 ) {
288                        $( '<style id="fancybox-noscroll" type="text/css">' ).html( '.compensate-for-scrollbar, .fancybox-enabled body { margin-right: ' + testWidth + 'px; }' ).appendTo( 'head' );
289                    }
290
291                }
292            }
293
294            $container = $( self.opts.baseTpl )
295                .attr('id', 'fancybox-container-' + self.id)
296                .data( 'FancyBox', self )
297                .addClass( self.opts.baseClass )
298                .hide()
299                .prependTo( self.opts.parentEl );
300
301            // Create object holding references to jQuery wrapped nodes
302            self.$refs = {
303                container   : $container,
304                bg          : $container.find('.fancybox-bg'),
305                controls    : $container.find('.fancybox-controls'),
306                buttons     : $container.find('.fancybox-buttons'),
307                slider_wrap : $container.find('.fancybox-slider-wrap'),
308                slider      : $container.find('.fancybox-slider'),
309                caption     : $container.find('.fancybox-caption')
310            };
311
312            self.trigger( 'onInit' );
313
314            // Bring to front and enable events
315            self.activate();
316
317            // Try to avoid running multiple times
318            if ( self.current ) {
319                return;
320            }
321
322            self.jumpTo( self.currIndex );
323
324        },
325
326
327        // Create array of gally item objects
328        // Check if each object has valid type and content
329        // ===============================================
330
331        createGroup : function ( content ) {
332            var self  = this;
333            var items = $.makeArray( content );
334
335            $.each(items, function( i, item ) {
336                var obj  = {},
337                    opts = {},
338                    data = [],
339                    $item,
340                    type,
341                    src,
342                    srcParts;
343
344                // Step 1 - Make sure we have an object
345
346                if ( $.isPlainObject( item ) ) {
347
348                    obj  = item;
349                    opts = item.opts || {};
350
351                } else if ( $.type( item ) === 'object' && $( item ).length ) {
352
353                    $item = $( item );
354                    data  = $item.data();
355
356                    opts = 'options' in data ? data.options : {};
357
358                    opts = $.type( opts ) === 'object' ? opts : {};
359
360                    obj.type = 'type' in data ? data.type : opts.type;
361                    obj.src  = 'src'  in data ? data.src  : ( opts.src || $item.attr( 'href' ) );
362
363                    opts.width   = 'width'   in data ? data.width   : opts.width;
364                    opts.height  = 'height'  in data ? data.height  : opts.height;
365                    opts.thumb   = 'thumb'   in data ? data.thumb   : opts.thumb;
366
367                    opts.selector = 'selector'  in data ? data.selector  : opts.selector;
368
369                    if ( 'srcset' in data ) {
370                        opts.image = { srcset : data.srcset };
371                    }
372
373                    opts.$orig = $item;
374
375                } else {
376
377                    obj = {
378                        type    : 'html',
379                        content : item + ''
380                    };
381
382                }
383
384                obj.opts = $.extend( true, {}, self.opts, opts );
385
386                // Step 2 - Make sure we have supported content type
387
388                type = obj.type;
389                src  = obj.src || '';
390
391                if ( !type ) {
392
393                    if ( obj.content ) {
394                        type = 'html';
395
396                    } else if ( src.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i) ) {
397                        type = 'image';
398
399                    } else if ( src.match(/\.(pdf)((\?|#).*)?$/i) ) {
400                        type = 'pdf';
401
402                    } else if ( src.charAt(0) === '#' ) {
403                        type = 'inline';
404
405                    }
406
407                    obj.type = type;
408
409                }
410
411                // Step 3 - Some adjustments
412
413                obj.index = self.group.length;
414
415                // Check if $orig and $thumb objects exist
416                if ( obj.opts.$orig && !obj.opts.$orig.length ) {
417                    delete obj.opts.$orig;
418                }
419
420                if ( !obj.opts.$thumb && obj.opts.$orig ) {
421                    obj.opts.$thumb = obj.opts.$orig.find( 'img:first' );
422                }
423
424                if ( obj.opts.$thumb && !obj.opts.$thumb.length ) {
425                    delete obj.opts.$thumb;
426                }
427
428                // Caption is a "special" option, it can be passed as a method
429                if ( $.type( obj.opts.caption ) === 'function' ) {
430                    obj.opts.caption = obj.opts.caption.apply( item, [ self, obj ] );
431
432                } else if ( 'caption' in data ) {
433                    obj.opts.caption = data.caption;
434
435                } else if ( opts.$orig ) {
436                    obj.opts.caption = $item.attr( 'title' );
437                }
438
439                // Make sure we have caption as a string
440                obj.opts.caption = obj.opts.caption === undefined ? '' : obj.opts.caption + '';
441
442                // Check if url contains selector used to filter the content
443                // Example: "ajax.html #something"
444                if ( type === 'ajax' ) {
445                    srcParts = src.split(/\s+/, 2);
446
447                    if ( srcParts.length > 1 ) {
448                        obj.src = srcParts.shift();
449
450                        obj.opts.selector = srcParts.shift();
451                    }
452                }
453
454                if ( obj.opts.smallBtn == 'auto' ) {
455
456                    if ( $.inArray( type, ['html', 'inline', 'ajax'] ) > -1 ) {
457                        obj.opts.buttons  = false;
458                        obj.opts.smallBtn = true;
459
460                    } else {
461                        obj.opts.smallBtn = false;
462                    }
463
464                }
465
466                if ( type === 'pdf' ) {
467
468                    obj.type = 'iframe';
469
470                    obj.opts.closeBtn = true;
471                    obj.opts.smallBtn = false;
472
473                    obj.opts.iframe.preload = false;
474
475                }
476
477                if ( obj.opts.modal ) {
478
479                    $.extend(true, obj.opts, {
480                        infobar     : 0,
481                        buttons     : 0,
482                        keyboard    : 0,
483                        slideShow   : 0,
484                        fullScreen  : 0,
485                        closeClickOutside   : 0
486                    });
487
488                }
489
490                self.group.push( obj );
491
492            });
493
494        },
495
496
497        // Attach an event handler functions for:
498        //   - navigation elements
499        //   - browser scrolling, resizing;
500        //   - focusing
501        //   - keyboard
502        // =================
503
504        addEvents : function() {
505            var self = this;
506
507            self.removeEvents();
508
509            // Make navigation elements clickable
510
511            self.$refs.container.on('click.fb-close', '[data-fancybox-close]', function(e) {
512                e.stopPropagation();
513                e.preventDefault();
514
515                self.close( e );
516
517            }).on('click.fb-previous', '[data-fancybox-previous]', function(e) {
518                e.stopPropagation();
519                e.preventDefault();
520
521                self.previous();
522
523            }).on('click.fb-next', '[data-fancybox-next]', function(e) {
524                e.stopPropagation();
525                e.preventDefault();
526
527                self.next();
528            });
529
530
531            // Handle page scrolling and browser resizing
532
533            $( window ).on('orientationchange.fb resize.fb', function(e) {
534                requestAFrame(function() {
535
536                    if ( e && e.originalEvent && e.originalEvent.type === "resize" ) {
537                        self.update();
538
539                    } else {
540                        self.$refs.slider_wrap.hide();
541
542                        requestAFrame(function () {
543                            self.$refs.slider_wrap.show();
544
545                            self.update();
546                        });
547
548                    }
549
550                });
551            });
552
553
554            // Trap focus
555
556            $D.on('focusin.fb', function(e) {
557                var instance = $.fancybox ? $.fancybox.getInstance() : null;
558
559                if ( instance && !$( e.target ).hasClass( 'fancybox-container' ) && !$.contains( instance.$refs.container[0], e.target ) ) {
560                    e.stopPropagation();
561
562                    instance.focus();
563
564                    // Sometimes page gets scrolled, set it back
565                    $W.scrollTop( self.scrollTop ).scrollLeft( self.scrollLeft );
566                }
567
568            });
569
570            // Enable keyboard navigation
571
572            $D.on('keydown.fb', function (e) {
573                var current = self.current,
574                    keycode = e.keyCode || e.which;
575
576                if ( !current || !current.opts.keyboard ) {
577                    return;
578                }
579
580                if ( $(e.target).is('input') || $(e.target).is('textarea') ) {
581                    return;
582                }
583
584                // Backspace and Esc keys
585                if ( keycode === 8 || keycode === 27 ) {
586                    e.preventDefault();
587
588                    self.close( e );
589
590                    return;
591                }
592
593                switch ( keycode ) {
594
595                    case 37: // Left arrow
596                    case 38: // Up arrow
597
598                        e.preventDefault();
599
600                        self.previous();
601
602                    break;
603
604                    case 39: // Right arrow
605                    case 40: // Down arrow
606
607                        e.preventDefault();
608
609                        self.next();
610
611                    break;
612
613                    case 80: // "P"
614                    case 32: // Spacebar
615
616                        e.preventDefault();
617
618                        if ( self.SlideShow ) {
619                            e.preventDefault();
620
621                            self.SlideShow.toggle();
622                        }
623
624                    break;
625
626                    case 70: // "F"
627
628                        if ( self.FullScreen ) {
629                            e.preventDefault();
630
631                            self.FullScreen.toggle();
632                        }
633
634                    break;
635
636                    case 71: // "G"
637
638                        if ( self.Thumbs ) {
639                            e.preventDefault();
640
641                            self.Thumbs.toggle();
642                        }
643
644                    break;
645                }
646            });
647
648
649        },
650
651
652        // Remove events added by the core
653        // ===============================
654
655        removeEvents : function () {
656
657            $W.off( 'scroll.fb resize.fb orientationchange.fb' );
658            $D.off( 'keydown.fb focusin.fb click.fb-close' );
659
660            this.$refs.container.off('click.fb-close click.fb-previous click.fb-next');
661        },
662
663
664        // Slide to left
665        // ==================
666
667        previous : function( duration ) {
668            this.jumpTo( this.currIndex - 1, duration );
669        },
670
671
672        // Slide to right
673        // ===================
674
675        next : function( duration ) {
676            this.jumpTo( this.currIndex + 1, duration );
677        },
678
679
680        // Display current gallery item, move slider to current position
681        // =============================================================
682
683        jumpTo : function ( to, duration ) {
684            var self = this,
685                firstRun,
686                index,
687                pos,
688                loop;
689
690            firstRun = self.firstRun = ( self.firstRun === null );
691
692            index = pos = to = parseInt( to, 10 );
693            loop  = self.current ? self.current.opts.loop : false;
694
695            if ( self.isAnimating || ( index == self.currIndex && !firstRun ) ) {
696                return;
697            }
698
699            if ( self.group.length > 1 && loop ) {
700
701                index = index % self.group.length;
702                index = index < 0 ? self.group.length + index : index;
703
704                // Calculate closest position of upcoming item from the current one
705                if ( self.group.length == 2 ) {
706                    pos = to - self.currIndex + self.currPos;
707
708                } else {
709                    pos = index - self.currIndex + self.currPos;
710
711                    if ( Math.abs( self.currPos - ( pos + self.group.length ) ) < Math.abs( self.currPos - pos ) ) {
712                        pos = pos + self.group.length;
713
714                    } else if ( Math.abs( self.currPos - ( pos - self.group.length ) ) < Math.abs( self.currPos - pos ) ) {
715                        pos = pos - self.group.length;
716
717                    }
718                }
719
720            } else if ( !self.group[ index ] ) {
721                self.update( false, false, duration );
722
723                return;
724            }
725
726            if ( self.current ) {
727                self.current.$slide.removeClass('fancybox-slide--current fancybox-slide--complete');
728
729                self.updateSlide( self.current, true );
730            }
731
732            self.prevIndex = self.currIndex;
733            self.prevPos   = self.currPos;
734
735            self.currIndex = index;
736            self.currPos   = pos;
737
738            // Create slides
739
740            self.current = self.createSlide( pos );
741
742            if ( self.group.length > 1 ) {
743
744                if ( self.opts.loop || pos - 1 >= 0 ) {
745                    self.createSlide( pos - 1 );
746                }
747
748                if ( self.opts.loop || pos + 1 < self.group.length ) {
749                    self.createSlide( pos + 1 );
750                }
751            }
752
753            self.current.isMoved    = false;
754            self.current.isComplete = false;
755
756            duration = parseInt( duration === undefined ? self.current.opts.speed * 1.5 : duration, 10 );
757
758            // Move slider to the next position
759            // Note: the content might still be loading
760            self.trigger( 'beforeMove' );
761
762            self.updateControls();
763
764            if ( firstRun ) {
765                self.current.$slide.addClass('fancybox-slide--current');
766
767                self.$refs.container.show();
768
769                requestAFrame(function() {
770                    self.$refs.bg.css('transition-duration', self.current.opts.speed + 'ms');
771
772                    self.$refs.container.addClass( 'fancybox-container--ready' );
773                });
774            }
775
776            // Set position immediately on first opening
777            self.update( true, false, firstRun ? 0 : duration, function() {
778                self.afterMove();
779            });
780
781            self.loadSlide( self.current );
782
783            if ( !( firstRun && self.current.$ghost ) ) {
784                self.preload();
785            }
786
787        },
788
789
790        // Create new "slide" element
791        // These are gallery items  that are actually added to DOM
792        // =======================================================
793
794        createSlide : function( pos ) {
795
796            var self = this;
797            var $slide;
798            var index;
799            var found;
800
801            index = pos % self.group.length;
802            index = index < 0 ? self.group.length + index : index;
803
804            if ( !self.slides[ pos ] && self.group[ index ] ) {
805
806                // If we are looping and slide with that index already exists, then reuse it
807                if ( self.opts.loop && self.group.length > 2 ) {
808                    for (var key in self.slides) {
809                        if ( self.slides[ key ].index === index ) {
810                            found = self.slides[ key ];
811                            found.pos = pos;
812
813                            self.slides[ pos ] = found;
814
815                            delete self.slides[ key ];
816
817                            self.updateSlide( found );
818
819                            return found;
820                        }
821                    }
822                }
823
824                $slide = $('<div class="fancybox-slide"></div>').appendTo( self.$refs.slider );
825
826                self.slides[ pos ] = $.extend( true, {}, self.group[ index ], {
827                    pos      : pos,
828                    $slide   : $slide,
829                    isMoved  : false,
830                    isLoaded : false
831                });
832
833            }
834
835            return self.slides[ pos ];
836
837        },
838
839        zoomInOut : function( type, duration, callback ) {
840
841            var self     = this;
842            var current  = self.current;
843            var $what    = current.$placeholder;
844            var opacity  = current.opts.opacity;
845            var $thumb   = current.opts.$thumb;
846            var thumbPos = $thumb ? $thumb.offset() : 0;
847            var slidePos = current.$slide.offset();
848            var props;
849            var start;
850            var end;
851
852            if ( !$what || !current.isMoved || !thumbPos || !isElementInViewport( $thumb ) ) {
853                return false;
854            }
855
856            if ( type === 'In' && !self.firstRun ) {
857                return false;
858            }
859
860            $.fancybox.stop( $what );
861
862            self.isAnimating = true;
863
864            props = {
865                top    : thumbPos.top  - slidePos.top  + parseFloat( $thumb.css( "border-top-width" ) || 0 ),
866                left   : thumbPos.left - slidePos.left + parseFloat( $thumb.css( "border-left-width" ) || 0 ),
867                width  : $thumb.width(),
868                height : $thumb.height(),
869                scaleX : 1,
870                scaleY : 1
871            };
872
873            // Check if we need to animate opacity
874            if ( opacity == 'auto' ) {
875                opacity = Math.abs( current.width / current.height - props.width / props.height ) > 0.1;
876            }
877
878            if ( type === 'In' ) {
879                start = props;
880                end   = self.getFitPos( current );
881
882                end.scaleX = end.width  / start.width;
883                end.scaleY = end.height / start.height;
884
885                if ( opacity ) {
886                    start.opacity = 0.1;
887                    end.opacity   = 1;
888                }
889
890            } else {
891
892                start = $.fancybox.getTranslate( $what );
893                end   = props;
894
895                // Switch to thumbnail image to improve animation performance
896                if ( current.$ghost ) {
897                    current.$ghost.show();
898
899                    if ( current.$image ) {
900                        current.$image.remove();
901                    }
902                }
903
904                start.scaleX = start.width  / end.width;
905                start.scaleY = start.height / end.height;
906
907                start.width  = end.width;
908                start.height = end.height;
909
910                if ( opacity ) {
911                    end.opacity = 0;
912                }
913
914            }
915
916            self.updateCursor( end.width, end.height );
917
918            // There is no need to animate width/height properties
919            delete end.width;
920            delete end.height;
921
922            $.fancybox.setTranslate( $what, start );
923
924            $what.show();
925
926            self.trigger( 'beforeZoom' + type );
927
928            $what.css( 'transition', 'all ' + duration + 'ms' );
929
930            $.fancybox.setTranslate( $what, end );
931
932            setTimeout(function() {
933                var reset;
934
935                $what.css( 'transition', 'none' );
936
937                reset = $.fancybox.getTranslate( $what );
938
939                reset.scaleX = 1;
940                reset.scaleY = 1;
941
942                // Reset scalex/scaleY values; this helps for perfomance
943                $.fancybox.setTranslate( $what, reset );
944
945                self.trigger( 'afterZoom' + type );
946
947                callback.apply( self );
948
949                self.isAnimating = false;
950
951            }, duration);
952
953
954            return true;
955
956        },
957
958        // Check if image dimensions exceed parent element
959        // ===============================================
960
961        canPan : function() {
962
963            var self = this;
964
965            var current = self.current;
966            var $what   = current.$placeholder;
967
968            var rez = false;
969
970            if ( $what ) {
971                rez = self.getFitPos( current );
972                rez = Math.abs( $what.width() - rez.width ) > 1  || Math.abs( $what.height() - rez.height ) > 1;
973
974            }
975
976            return rez;
977
978        },
979
980
981        // Check if current image dimensions are smaller than actual
982        // =========================================================
983
984        isScaledDown : function() {
985
986            var self = this;
987
988            var current = self.current;
989            var $what   = current.$placeholder;
990
991            var rez = false;
992
993            if ( $what ) {
994                rez = $.fancybox.getTranslate( $what );
995                rez = rez.width < current.width || rez.height < current.height;
996            }
997
998            return rez;
999
1000        },
1001
1002
1003        // Scale image to the actual size of the image
1004        // ===========================================
1005
1006        scaleToActual : function( x, y, duration ) {
1007
1008            var self = this;
1009
1010            var current = self.current;
1011            var $what   = current.$placeholder;
1012
1013            var imgPos, posX, posY, scaleX, scaleY;
1014
1015            var canvasWidth  = parseInt( current.$slide.width(), 10 );
1016            var canvasHeight = parseInt( current.$slide.height(), 10 );
1017
1018            var newImgWidth  = current.width;
1019            var newImgHeight = current.height;
1020
1021            if ( !$what ) {
1022                return;
1023            }
1024
1025            self.isAnimating = true;
1026
1027            x = x === undefined ? canvasWidth  * 0.5  : x;
1028            y = y === undefined ? canvasHeight * 0.5  : y;
1029
1030            imgPos = $.fancybox.getTranslate( $what );
1031
1032            scaleX  = newImgWidth  / imgPos.width;
1033            scaleY  = newImgHeight / imgPos.height;
1034
1035            // Get center position for original image
1036            posX = ( canvasWidth * 0.5  - newImgWidth * 0.5 );
1037            posY = ( canvasHeight * 0.5 - newImgHeight * 0.5 );
1038
1039            // Make sure image does not move away from edges
1040
1041            if ( newImgWidth > canvasWidth ) {
1042                posX = imgPos.left * scaleX - ( ( x * scaleX ) - x );
1043
1044                if ( posX > 0 ) {
1045                    posX = 0;
1046                }
1047
1048                if ( posX <  canvasWidth - newImgWidth ) {
1049                    posX = canvasWidth - newImgWidth;
1050                }
1051            }
1052
1053            if ( newImgHeight > canvasHeight) {
1054                posY = imgPos.top  * scaleY - ( ( y * scaleY ) - y );
1055
1056                if ( posY > 0 ) {
1057                    posY = 0;
1058                }
1059
1060                if ( posY <  canvasHeight - newImgHeight ) {
1061                    posY = canvasHeight - newImgHeight;
1062                }
1063            }
1064
1065            self.updateCursor( newImgWidth, newImgHeight );
1066
1067            $.fancybox.animate( $what, null, {
1068                top    : posY,
1069                left   : posX,
1070                scaleX : scaleX,
1071                scaleY : scaleY
1072            }, duration || current.opts.speed, function() {
1073                self.isAnimating = false;
1074            });
1075
1076        },
1077
1078
1079        // Scale image to fit inside parent element
1080        // ========================================
1081
1082        scaleToFit : function( duration ) {
1083
1084            var self = this;
1085
1086            var current = self.current;
1087            var $what   = current.$placeholder;
1088            var end;
1089
1090            if ( !$what ) {
1091                return;
1092            }
1093
1094            self.isAnimating = true;
1095
1096            end = self.getFitPos( current );
1097
1098            self.updateCursor( end.width, end.height );
1099
1100            $.fancybox.animate( $what, null, {
1101                top    : end.top,
1102                left   : end.left,
1103                scaleX : end.width  / $what.width(),
1104                scaleY : end.height / $what.height()
1105            }, duration || current.opts.speed, function() {
1106                self.isAnimating = false;
1107            });
1108
1109        },
1110
1111        // Calculate image size to fit inside viewport
1112        // ===========================================
1113
1114        getFitPos : function( slide ) {
1115            var $what = slide.$placeholder || slide.$content;
1116
1117            var imgWidth  = slide.width;
1118            var imgHeight = slide.height;
1119
1120            var margin = slide.opts.margin;
1121
1122            var canvasWidth, canvasHeight, minRatio, top, left, width, height;
1123
1124            if ( !$what || !$what.length || ( !imgWidth && !imgHeight) ) {
1125                return false;
1126            }
1127
1128            // Convert "margin to CSS style: [ top, right, bottom, left ]
1129            if ( $.type( margin ) === "number" ) {
1130                margin = [ margin, margin ];
1131            }
1132
1133            if ( margin.length == 2 ) {
1134                margin = [ margin[0], margin[1], margin[0], margin[1] ];
1135            }
1136
1137            if ( $W.width() < 800 ) {
1138                margin = [0, 0, 0, 0];
1139            }
1140
1141            canvasWidth  = parseInt( slide.$slide.width(), 10 )  - ( margin[ 1 ] + margin[ 3 ] );
1142            canvasHeight = parseInt( slide.$slide.height(), 10 ) - ( margin[ 0 ] + margin[ 2 ] );
1143
1144            minRatio = Math.min(1, canvasWidth / imgWidth, canvasHeight / imgHeight );
1145
1146            // Use floor rounding to make sure it really fits
1147
1148            width  = Math.floor( minRatio * imgWidth );
1149            height = Math.floor( minRatio * imgHeight );
1150
1151            top  = Math.floor( ( canvasHeight - height ) * 0.5 ) + margin[ 0 ];
1152            left = Math.floor( ( canvasWidth  - width )  * 0.5 ) + margin[ 3 ];
1153
1154            return {
1155                top    : top,
1156                left   : left,
1157                width  : width,
1158                height : height
1159            };
1160
1161        },
1162
1163        // Move slider to current position
1164        // Update all slides (and their content)
1165        // =====================================
1166
1167        update : function( andSlides, andContent, duration, callback ) {
1168
1169            var self = this;
1170            var leftValue;
1171
1172            if ( self.isAnimating === true || !self.current ) {
1173                return;
1174            }
1175
1176            leftValue = ( self.current.pos * Math.floor( self.current.$slide.width() ) * -1 ) - ( self.current.pos * self.current.opts.gutter );
1177            duration  = parseInt( duration, 10 ) || 0;
1178
1179            $.fancybox.stop( self.$refs.slider );
1180
1181            if ( andSlides === false ) {
1182                self.updateSlide( self.current, andContent );
1183
1184            } else {
1185
1186                $.each( self.slides, function( key, slide ) {
1187                    self.updateSlide( slide, andContent );
1188                });
1189
1190            }
1191
1192            if ( duration ) {
1193
1194                $.fancybox.animate( self.$refs.slider, null, {
1195                    top  : 0,
1196                    left : leftValue
1197                }, duration, function() {
1198                    self.current.isMoved = true;
1199
1200                    if ( $.type( callback ) === 'function' ) {
1201                        callback.apply( self );
1202                    }
1203
1204                });
1205
1206            } else {
1207
1208                $.fancybox.setTranslate( self.$refs.slider, { top : 0, left : leftValue } );
1209
1210                self.current.isMoved = true;
1211
1212                if ( $.type( callback ) === 'function' ) {
1213                    callback.apply( self );
1214                }
1215
1216            }
1217
1218        },
1219
1220
1221        // Update slide position and scale content to fit
1222        // ==============================================
1223
1224        updateSlide : function( slide, andContent ) {
1225
1226            var self  = this;
1227            var $what = slide.$placeholder;
1228            var leftPos;
1229
1230            slide = slide || self.current;
1231
1232            if ( !slide || self.isClosing ) {
1233                return;
1234            }
1235
1236            leftPos = ( slide.pos * Math.floor( slide.$slide.width() )  ) + ( slide.pos * slide.opts.gutter);
1237
1238            if ( leftPos !== slide.leftPos ) {
1239                $.fancybox.setTranslate( slide.$slide, { top: 0, left : leftPos } );
1240
1241                slide.leftPos = leftPos;
1242            }
1243
1244            if ( andContent !== false && $what ) {
1245                $.fancybox.setTranslate( $what, self.getFitPos( slide ) );
1246
1247                if ( slide.pos === self.currPos ) {
1248                    self.updateCursor();
1249                }
1250            }
1251
1252            slide.$slide.trigger( 'refresh' );
1253
1254            self.trigger( 'onUpdate', slide );
1255        },
1256
1257        // Update cursor style depending if content can be zoomed
1258        // ======================================================
1259
1260        updateCursor : function( nextWidth, nextHeight ) {
1261
1262            var self = this;
1263            var canScale;
1264
1265            var $container = self.$refs.container.removeClass('fancybox-controls--canzoomIn fancybox-controls--canzoomOut fancybox-controls--canGrab');
1266
1267            if ( self.isClosing || !self.opts.touch ) {
1268                return;
1269            }
1270
1271            if ( nextWidth !== undefined && nextHeight !== undefined ) {
1272                canScale = nextWidth < self.current.width && nextHeight < self.current.height;
1273
1274            } else {
1275                canScale = self.isScaledDown();
1276            }
1277
1278            if ( canScale ) {
1279                $container.addClass('fancybox-controls--canzoomIn');
1280
1281            } else if ( self.group.length < 2 ) {
1282                $container.addClass('fancybox-controls--canzoomOut');
1283
1284            } else {
1285                $container.addClass('fancybox-controls--canGrab');
1286            }
1287
1288        },
1289
1290        // Load content into the slide
1291        // ===========================
1292
1293        loadSlide : function( slide ) {
1294
1295            var self = this, type, $slide;
1296            var ajaxLoad;
1297
1298            if ( !slide || slide.isLoaded || slide.isLoading ) {
1299                return;
1300            }
1301
1302            slide.isLoading = true;
1303
1304            self.trigger( 'beforeLoad', slide );
1305
1306            type   = slide.type;
1307            $slide = slide.$slide;
1308
1309            $slide
1310                .off( 'refresh' )
1311                .trigger( 'onReset' )
1312                .addClass( 'fancybox-slide--' + ( type || 'unknown' ) )
1313                .addClass( slide.opts.slideClass );
1314
1315            // Create content depending on the type
1316
1317            switch ( type ) {
1318
1319                case 'image':
1320
1321                    self.setImage( slide );
1322
1323                break;
1324
1325                case 'iframe':
1326
1327                    self.setIframe( slide );
1328
1329                break;
1330
1331                case 'html':
1332
1333                    self.setContent( slide, slide.content );
1334
1335                break;
1336
1337                case 'inline':
1338
1339                    if ( $( slide.src ).length ) {
1340                        self.setContent( slide, $( slide.src ) );
1341
1342                    } else {
1343                        self.setError( slide );
1344                    }
1345
1346                break;
1347
1348                case 'ajax':
1349
1350                    self.showLoading( slide );
1351
1352                    ajaxLoad = $.ajax( $.extend( {}, slide.opts.ajax.settings, {
1353
1354                        url: slide.src,
1355
1356                        success: function ( data, textStatus ) {
1357
1358                            if ( textStatus === 'success' ) {
1359                                self.setContent( slide, data );
1360                            }
1361
1362                        },
1363
1364                        error: function ( jqXHR, textStatus ) {
1365
1366                            if ( jqXHR && textStatus !== 'abort' ) {
1367                                self.setError( slide );
1368                            }
1369
1370                        }
1371
1372                    }));
1373
1374                    $slide.one( 'onReset', function () {
1375                        ajaxLoad.abort();
1376                    });
1377
1378                break;
1379
1380                default:
1381
1382                    self.setError( slide );
1383
1384                break;
1385
1386            }
1387
1388            return true;
1389
1390        },
1391
1392
1393        // Use thumbnail image, if possible
1394        // ================================
1395
1396        setImage : function( slide ) {
1397
1398            var self   = this;
1399            var srcset = slide.opts.image.srcset;
1400
1401            var found, temp, pxRatio, windowWidth;
1402
1403            if ( slide.isLoaded && !slide.hasError ) {
1404                self.afterLoad( slide );
1405
1406                return;
1407            }
1408
1409            // If we have "srcset", then we need to find matching "src" value.
1410            // This is necessary, because when you set an src attribute, the browser will preload the image
1411            // before any javascript or even CSS is applied.
1412            if ( srcset ) {
1413                pxRatio     = window.devicePixelRatio || 1;
1414                windowWidth = window.innerWidth  * pxRatio;
1415
1416                temp = srcset.split(',').map(function (el) {
1417                    var ret = {};
1418
1419                    el.trim().split(/\s+/).forEach(function (el, i) {
1420                        var value = parseInt(el.substring(0, el.length - 1), 10);
1421
1422                        if ( i === 0 ) {
1423                            return (ret.url = el);
1424                        }
1425
1426                        if ( value ) {
1427                            ret.value   = value;
1428                            ret.postfix = el[el.length - 1];
1429                        }
1430
1431                    });
1432
1433                    return ret;
1434                });
1435
1436                // Sort by value
1437                temp.sort(function (a, b) {
1438                  return a.value - b.value;
1439                });
1440
1441                // Ok, now we have an array of all srcset values
1442                for ( var j = 0; j < temp.length; j++ ) {
1443                    var el = temp[ j ];
1444
1445                    if ( ( el.postfix === 'w' && el.value >= windowWidth ) || ( el.postfix === 'x' && el.value >= pxRatio ) ) {
1446                        found = el;
1447                        break;
1448                    }
1449                }
1450
1451                // If not found, take the last one
1452                if ( !found && temp.length ) {
1453                    found = temp[ temp.length - 1 ];
1454                }
1455
1456                if ( found ) {
1457                    slide.src = found.url;
1458
1459                    // If we have default width/height values, we can calculate height for matching source
1460                    if ( slide.width && slide.height && found.postfix == 'w' ) {
1461                        slide.height = ( slide.width / slide.height ) * found.value;
1462                        slide.width  = found.value;
1463                    }
1464                }
1465            }
1466
1467            slide.$placeholder = $('<div class="fancybox-placeholder"></div>')
1468                .hide()
1469                .appendTo( slide.$slide );
1470
1471            if ( slide.opts.preload !== false && slide.opts.width && slide.opts.height && ( slide.opts.thumb || slide.opts.$thumb ) ) {
1472
1473                slide.width  = slide.opts.width;
1474                slide.height = slide.opts.height;
1475
1476                slide.$ghost = $('<img />')
1477                    .one('load error', function() {
1478
1479                        if ( self.isClosing ) {
1480                            return;
1481                        }
1482
1483                        // Start preloading full size image
1484                        $('<img/>')[0].src = slide.src;
1485
1486                        // zoomIn or just show
1487                        self.revealImage( slide, function() {
1488
1489                            self.setBigImage( slide );
1490
1491                            if ( self.firstRun && slide.index === self.currIndex ) {
1492                                self.preload();
1493                            }
1494                        });
1495
1496                    })
1497                    .addClass( 'fancybox-image' )
1498                    .appendTo( slide.$placeholder )
1499                    .attr( 'src', slide.opts.thumb || slide.opts.$thumb.attr( 'src' ) );
1500
1501            } else {
1502
1503                self.setBigImage( slide );
1504
1505            }
1506
1507        },
1508
1509
1510        // Create full-size image
1511        // ======================
1512
1513        setBigImage : function ( slide ) {
1514            var self = this;
1515            var $img = $('<img />');
1516
1517            slide.$image = $img
1518                .one('error', function() {
1519
1520                    self.setError( slide );
1521
1522                })
1523                .one('load', function() {
1524
1525                    // Clear timeout that checks if loading icon needs to be displayed
1526                    clearTimeout( slide.timouts );
1527
1528                    slide.timouts = null;
1529
1530                    if ( self.isClosing ) {
1531                        return;
1532                    }
1533
1534                    slide.width  = this.naturalWidth;
1535                    slide.height = this.naturalHeight;
1536
1537                    if ( slide.opts.image.srcset ) {
1538                        $img.attr('sizes', '100vw').attr('srcset', slide.opts.image.srcset);
1539                    }
1540
1541                    self.afterLoad( slide );
1542
1543                    if ( slide.$ghost ) {
1544                        slide.timouts = setTimeout(function() {
1545                            slide.$ghost.hide();
1546
1547                        }, 350);
1548                    }
1549
1550                })
1551                .addClass('fancybox-image')
1552                .attr('src', slide.src)
1553                .appendTo( slide.$placeholder );
1554
1555            if ( $img[0].complete ) {
1556                  $img.trigger('load');
1557
1558            } else if( $img[0].error ) {
1559                 $img.trigger('error');
1560
1561            } else {
1562
1563                slide.timouts = setTimeout(function() {
1564                    if ( !$img[0].complete && !slide.hasError ) {
1565                        self.showLoading( slide );
1566                    }
1567
1568                }, 150);
1569
1570            }
1571
1572            if ( slide.opts.image.protect ) {
1573                $('<div class="fancybox-spaceball"></div>').appendTo( slide.$placeholder ).on('contextmenu.fb',function(e){
1574                     if ( e.button == 2 ) {
1575                         e.preventDefault();
1576                     }
1577
1578                    return true;
1579                });
1580            }
1581
1582        },
1583
1584        // Simply show image holder without animation
1585        // It has been hidden initially to avoid flickering
1586        // ================================================
1587
1588        revealImage : function( slide, callback ) {
1589
1590            var self = this;
1591
1592            callback = callback || $.noop;
1593
1594            if ( slide.type !== 'image' || slide.hasError || slide.isRevealed === true ) {
1595
1596                callback.apply( self );
1597
1598                return;
1599            }
1600
1601            slide.isRevealed = true;
1602
1603            if ( !( slide.pos === self.currPos && self.zoomInOut( 'In', slide.opts.speed, callback ) ) ) {
1604
1605                if ( slide.$ghost && !slide.isLoaded ) {
1606                    self.updateSlide( slide, true );
1607                }
1608
1609                if ( slide.pos === self.currPos ) {
1610                    $.fancybox.animate( slide.$placeholder, { opacity: 0 }, { opacity: 1 }, 300, callback );
1611
1612                } else {
1613                    slide.$placeholder.show();
1614                }
1615
1616                callback.apply( self );
1617
1618            }
1619
1620        },
1621
1622        // Create iframe wrapper, iframe and bindings
1623        // ==========================================
1624
1625        setIframe : function( slide ) {
1626            var self    = this,
1627                opts    = slide.opts.iframe,
1628                $slide  = slide.$slide,
1629                $iframe;
1630
1631            slide.$content = $('<div class="fancybox-content"></div>')
1632                .css( opts.css )
1633                .appendTo( $slide );
1634
1635            $iframe = $( opts.tpl.replace(/\{rnd\}/g, new Date().getTime()) )
1636                .attr('scrolling', $.fancybox.isTouch ? 'auto' : opts.scrolling)
1637                .appendTo( slide.$content );
1638
1639            if ( opts.preload ) {
1640                slide.$content.addClass( 'fancybox-tmp' );
1641
1642                self.showLoading( slide );
1643
1644                // Unfortunately, it is not always possible to determine if iframe is successfully loaded
1645                // (due to browser security policy)
1646
1647                $iframe.on('load.fb error.fb', function(e) {
1648                    this.isReady = 1;
1649
1650                    slide.$slide.trigger( 'refresh' );
1651
1652                    self.afterLoad( slide );
1653
1654                });
1655
1656                // Recalculate iframe content size
1657
1658                $slide.on('refresh.fb', function() {
1659                    var $wrap = slide.$content,
1660                        $contents,
1661                        $body,
1662                        scrollWidth,
1663                        frameWidth,
1664                        frameHeight;
1665
1666                    if ( $iframe[0].isReady !== 1 ) {
1667                        return;
1668                    }
1669
1670                    // Check if content is accessible,
1671                    // it will fail if frame is not with the same origin
1672
1673                    try {
1674                        $contents = $iframe.contents();
1675                        $body     = $contents.find('body');
1676
1677                    } catch (ignore) {}
1678
1679                    // Calculate dimensions for the wrapper
1680
1681                    if ( $body && $body.length && !( opts.css.width !== undefined && opts.css.height !== undefined ) ) {
1682
1683                        scrollWidth = $iframe[0].contentWindow.document.documentElement.scrollWidth;
1684
1685                        frameWidth  = Math.ceil( $body.outerWidth(true) + ( $wrap.width() - scrollWidth ) );
1686                        frameHeight = Math.ceil( $body.outerHeight(true) );
1687
1688                        // Resize wrapper to fit iframe content
1689
1690                        $wrap.css({
1691                            'width'  : opts.css.width  === undefined ? frameWidth  + ( $wrap.outerWidth()  - $wrap.innerWidth() )  : opts.css.width,
1692                            'height' : opts.css.height === undefined ? frameHeight + ( $wrap.outerHeight() - $wrap.innerHeight() ) : opts.css.height
1693                        });
1694
1695                    }
1696
1697                    $wrap.removeClass( 'fancybox-tmp' );
1698
1699                });
1700
1701            } else {
1702
1703                this.afterLoad( slide );
1704
1705            }
1706
1707            $iframe.attr( 'src', slide.src );
1708
1709            if ( slide.opts.smallBtn ) {
1710                slide.$content.prepend( slide.opts.closeTpl );
1711            }
1712
1713            // Remove iframe if closing or changing gallery item
1714
1715            $slide.one('onReset', function () {
1716
1717                // This helps IE not to throw errors when closing
1718
1719                try {
1720
1721                    $(this).find('iframe').hide().attr('src', '//about:blank');
1722
1723                } catch (ignore) {}
1724
1725                $(this).empty();
1726
1727                slide.isLoaded = false;
1728
1729            });
1730
1731        },
1732
1733
1734        // Wrap and append content to the slide
1735        // ======================================
1736
1737        setContent : function ( slide, content ) {
1738
1739            var self = this;
1740
1741            if ( self.isClosing ) {
1742                return;
1743            }
1744
1745            self.hideLoading( slide );
1746
1747            slide.$slide.empty();
1748
1749            if ( isQuery( content ) && content.parent().length ) {
1750
1751                // If it is a jQuery object, then it will be moved to the box.
1752                // The placeholder is created so we will know where to put it back.
1753                // If user is navigating gallery fast, then the content might be already moved to the box
1754
1755                if ( content.data( 'placeholder' ) ) {
1756                    content.parents('.fancybox-slide').trigger( 'onReset' );
1757                }
1758
1759                content.data({'placeholder' : $('<div></div>' ).hide().insertAfter( content ) }).css('display', 'inline-block');
1760
1761            } else {
1762
1763                if ( $.type( content ) === 'string' ) {
1764
1765                    content = $('<div>').append( content ).contents();
1766
1767                    if ( content[0].nodeType === 3 ) {
1768                        content = $('<div>').html( content );
1769                    }
1770
1771                }
1772
1773                if ( slide.opts.selector ) {
1774                    content = $('<div>').html( content ).find( slide.opts.selector );
1775                }
1776
1777            }
1778
1779            slide.$slide.one('onReset', function () {
1780                var placeholder = isQuery( content ) ? content.data('placeholder') : 0;
1781
1782                if ( placeholder ) {
1783                    content.hide().replaceAll( placeholder );
1784
1785                    content.data( 'placeholder', null );
1786                }
1787
1788                if ( !slide.hasError ) {
1789                    $(this).empty();
1790
1791                    slide.isLoaded = false;
1792                }
1793
1794            });
1795
1796            slide.$content = $( content ).appendTo( slide.$slide );
1797
1798            if ( slide.opts.smallBtn === true ) {
1799                slide.$content.find( '.fancybox-close-small' ).remove().end().eq(0).append( slide.opts.closeTpl );
1800            }
1801
1802            this.afterLoad( slide );
1803
1804        },
1805
1806        // Display error message
1807        // =====================
1808
1809        setError : function ( slide ) {
1810
1811            slide.hasError = true;
1812
1813            this.setContent( slide, slide.opts.errorTpl );
1814
1815        },
1816
1817
1818        showLoading : function( slide ) {
1819            var self = this;
1820
1821            slide = slide || self.current;
1822
1823            if ( slide && !slide.$spinner ) {
1824                slide.$spinner = $( self.opts.spinnerTpl ).appendTo( slide.$slide );
1825            }
1826
1827        },
1828
1829        hideLoading : function( slide ) {
1830
1831            var self = this;
1832
1833            slide = slide || self.current;
1834
1835            if ( slide && slide.$spinner ) {
1836                slide.$spinner.remove();
1837
1838                delete slide.$spinner;
1839            }
1840
1841        },
1842
1843        afterMove : function() {
1844
1845            var self    = this;
1846            var current = self.current;
1847            var slides  = {};
1848
1849            if ( !current ) {
1850                return;
1851            }
1852
1853            current.$slide.siblings().trigger( 'onReset' );
1854
1855            // Remove unnecessary slides
1856            $.each( self.slides, function( key, slide ) {
1857
1858                if (  slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1 ) {
1859                    slides[ slide.pos ] = slide;
1860
1861                } else if ( slide ) {
1862                    slide.$slide.remove();
1863                }
1864
1865            });
1866
1867            self.slides = slides;
1868
1869            self.trigger( 'afterMove' );
1870
1871            if ( current.isLoaded ) {
1872                self.complete();
1873            }
1874
1875        },
1876
1877        // Adjustments after slide has been loaded
1878        // =======================================
1879
1880        afterLoad : function( slide ) {
1881
1882            var self = this;
1883
1884            if ( self.isClosing ) {
1885                return;
1886            }
1887
1888            slide.isLoading = false;
1889            slide.isLoaded  = true;
1890
1891            self.trigger( 'afterLoad', slide );
1892
1893            self.hideLoading( slide );
1894
1895            // Resize content to fit inside slide
1896            // Skip if slide has an $ghost element, because then it has been already processed
1897            if ( !slide.$ghost ) {
1898                self.updateSlide( slide, true );
1899            }
1900
1901            if ( slide.index === self.currIndex && slide.isMoved ) {
1902                self.complete();
1903
1904            } else if ( !slide.$ghost ) {
1905                self.revealImage( slide );
1906            }
1907
1908        },
1909
1910
1911        // Final adjustments after current gallery item is moved to position
1912        // and it`s content is loaded
1913        // ==================================================================
1914
1915        complete : function() {
1916
1917            var self = this;
1918
1919            var current = self.current;
1920
1921            self.revealImage( current, function() {
1922                current.isComplete = true;
1923
1924                current.$slide.addClass('fancybox-slide--complete');
1925
1926                self.updateCursor();
1927
1928                self.trigger( 'onComplete' );
1929
1930                // Try to focus on the first focusable element, skip for images and iframes
1931                if ( current.opts.focus && !( current.type === 'image' || current.type === 'iframe' ) ) {
1932                    self.focus();
1933                }
1934
1935            });
1936
1937        },
1938
1939
1940        // Preload next and previous slides
1941        // ================================
1942
1943        preload : function() {
1944            var self = this;
1945            var next, prev;
1946
1947            if ( self.group.length < 2 ) {
1948                return;
1949            }
1950
1951            next  = self.slides[ self.currPos + 1 ];
1952            prev  = self.slides[ self.currPos - 1 ];
1953
1954            if ( next && next.type === 'image' ) {
1955                self.loadSlide( next );
1956            }
1957
1958            if ( prev && prev.type === 'image' ) {
1959                self.loadSlide( prev );
1960            }
1961
1962        },
1963
1964
1965        // Try to find and focus on the first focusable element
1966        // ====================================================
1967
1968        focus : function() {
1969            var current = this.current;
1970            var $el;
1971
1972            $el = current && current.isComplete ? current.$slide.find('button,:input,[tabindex],a:not(".disabled")').filter(':visible:first') : null;
1973
1974            if ( !$el || !$el.length ) {
1975                $el = this.$refs.container;
1976            }
1977
1978            $el.focus();
1979
1980            // Scroll position of wrapper element sometimes changes after focusing (IE)
1981            this.$refs.slider_wrap.scrollLeft(0);
1982
1983            // And the same goes for slide element
1984            if ( current ) {
1985                current.$slide.scrollTop(0);
1986            }
1987
1988        },
1989
1990
1991        // Activates current instance - brings container to the front and enables keyboard,
1992        // notifies other instances about deactivating
1993        // =================================================================================
1994
1995        activate : function () {
1996            var self = this;
1997
1998            // Deactivate all instances
1999
2000            $( '.fancybox-container' ).each(function () {
2001                var instance = $(this).data( 'FancyBox' );
2002
2003                // Skip self and closing instances
2004
2005                if (instance && instance.uid !== self.uid && !instance.isClosing) {
2006                    instance.trigger( 'onDeactivate' );
2007                }
2008
2009            });
2010
2011            if ( self.current ) {
2012
2013                if ( self.$refs.container.index() > 0 ) {
2014                    self.$refs.container.prependTo( document.body );
2015                }
2016
2017                self.updateControls();
2018            }
2019
2020            self.trigger( 'onActivate' );
2021
2022            self.addEvents();
2023
2024        },
2025
2026
2027        // Start closing procedure
2028        // This will start "zoom-out" animation if needed and clean everything up afterwards
2029        // =================================================================================
2030
2031        close : function( e ) {
2032
2033            var self     = this;
2034            var current  = self.current;
2035            var duration = current.opts.speed;
2036
2037            var done = $.proxy(function() {
2038
2039                self.cleanUp( e );  // Now "this" is again our instance
2040
2041            }, this);
2042
2043            if ( self.isAnimating || self.isClosing ) {
2044                return false;
2045            }
2046
2047            // If beforeClose callback prevents closing, make sure content is centered
2048            if ( self.trigger( 'beforeClose', e ) === false ) {
2049                $.fancybox.stop( self.$refs.slider );
2050
2051                requestAFrame(function() {
2052                    self.update( true, true, 150 );
2053                });
2054
2055                return;
2056            }
2057
2058            self.isClosing = true;
2059
2060            if ( current.timouts ) {
2061                clearTimeout( current.timouts );
2062            }
2063
2064            if ( e !== true) {
2065                $.fancybox.stop( self.$refs.slider );
2066            }
2067
2068            self.$refs.container
2069                .removeClass('fancybox-container--active')
2070                .addClass('fancybox-container--closing');
2071
2072            current.$slide
2073                .removeClass('fancybox-slide--complete')
2074                .siblings()
2075                .remove();
2076
2077
2078            if ( !current.isMoved ) {
2079                current.$slide.css('overflow', 'visible');
2080            }
2081
2082            // Remove all events
2083            // If there are multiple instances, they will be set again by "activate" method
2084
2085            self.removeEvents();
2086
2087            // Clean up
2088
2089            self.hideLoading( current );
2090
2091            self.hideControls();
2092
2093            self.updateCursor();
2094
2095            self.$refs.bg.css('transition-duration', duration + 'ms');
2096
2097            this.$refs.container.removeClass( 'fancybox-container--ready' );
2098
2099            if ( e === true ) {
2100                setTimeout( done, duration );
2101
2102            } else if ( !self.zoomInOut( 'Out', duration, done ) ) {
2103                $.fancybox.animate( self.$refs.container, null, { opacity : 0 }, duration, "easeInSine", done );
2104            }
2105
2106        },
2107
2108
2109        // Final adjustments after removing the instance
2110        // =============================================
2111
2112        cleanUp : function( e ) {
2113            var self = this,
2114                instance;
2115
2116            self.$refs.slider.children().trigger( 'onReset' );
2117
2118            self.$refs.container.empty().remove();
2119
2120            self.trigger( 'afterClose', e );
2121
2122            self.current = null;
2123
2124            // Check if there are other instances
2125            instance = $.fancybox.getInstance();
2126
2127            if ( instance ) {
2128                instance.activate();
2129
2130            } else {
2131
2132                $( 'html' ).removeClass( 'fancybox-enabled' );
2133                $( 'body' ).removeAttr( 'style' );
2134
2135                $W.scrollTop( self.scrollTop ).scrollLeft( self.scrollLeft );
2136
2137                $( '#fancybox-noscroll' ).remove();
2138
2139            }
2140
2141            // Place back focus
2142            if ( self.$lastFocus ) {
2143                self.$lastFocus.focus();
2144            }
2145
2146        },
2147
2148
2149        // Call callback and trigger an event
2150        // ==================================
2151
2152        trigger : function( name, slide ) {
2153            var args  = Array.prototype.slice.call(arguments, 1),
2154                self  = this,
2155                obj   = slide && slide.opts ? slide : self.current,
2156                rez;
2157
2158            if ( obj ) {
2159                args.unshift( obj );
2160
2161            } else {
2162                obj = self;
2163            }
2164
2165            args.unshift( self );
2166
2167            if ( $.isFunction( obj.opts[ name ] ) ) {
2168                rez = obj.opts[ name ].apply( obj, args );
2169            }
2170
2171            if ( rez === false ) {
2172                return rez;
2173            }
2174
2175            if ( name === 'afterClose' ) {
2176                $( document ).trigger( name + '.fb', args );
2177
2178            } else {
2179                self.$refs.container.trigger( name + '.fb', args );
2180            }
2181
2182        },
2183
2184
2185        // Toggle toolbar and caption
2186        // ==========================
2187
2188        toggleControls : function( force ) {
2189
2190            if ( this.isHiddenControls ) {
2191                this.updateControls( force );
2192
2193            } else {
2194                this.hideControls();
2195            }
2196
2197
2198        },
2199
2200
2201        // Hide toolbar and caption
2202        // ========================
2203
2204        hideControls : function () {
2205
2206            this.isHiddenControls = true;
2207
2208            this.$refs.container.removeClass('fancybox-show-controls');
2209
2210            this.$refs.container.removeClass('fancybox-show-caption');
2211
2212        },
2213
2214
2215        // Update infobar values, navigation button states and reveal caption
2216        // ==================================================================
2217
2218        updateControls : function ( force ) {
2219
2220            var self = this;
2221
2222            var $container = self.$refs.container;
2223            var $caption   = self.$refs.caption;
2224
2225            // Toggle infobar and buttons
2226
2227            var current  = self.current;
2228            var index    = current.index;
2229            var opts     = current.opts;
2230            var caption  = opts.caption;
2231
2232            if ( this.isHiddenControls && force !== true ) {
2233                return;
2234            }
2235
2236            this.isHiddenControls = false;
2237
2238            $container
2239                .addClass('fancybox-show-controls')
2240                .toggleClass('fancybox-show-infobar', !!opts.infobar && self.group.length > 1)
2241                .toggleClass('fancybox-show-buttons', !!opts.buttons )
2242                .toggleClass('fancybox-is-modal',     !!opts.modal );
2243
2244            $('.fancybox-button--left',  $container).toggleClass( 'fancybox-button--disabled', (!opts.loop && index <= 0 ) );
2245            $('.fancybox-button--right', $container).toggleClass( 'fancybox-button--disabled', (!opts.loop && index >= self.group.length - 1) );
2246
2247            $('.fancybox-button--play',  $container).toggle( !!( opts.slideShow && self.group.length > 1) );
2248            $('.fancybox-button--close', $container).toggle( !!opts.closeBtn );
2249
2250            // Update infobar values
2251
2252            $('.js-fancybox-count', $container).html( self.group.length );
2253            $('.js-fancybox-index', $container).html( index + 1 );
2254
2255            // Recalculate content dimensions
2256            current.$slide.trigger( 'refresh' );
2257
2258            // Reveal or create new caption
2259            if ( $caption ) {
2260                $caption.empty();
2261            }
2262
2263            if ( caption && caption.length ) {
2264                $caption.html( caption );
2265
2266                this.$refs.container.addClass( 'fancybox-show-caption ');
2267
2268                self.$caption = $caption;
2269
2270            } else {
2271                this.$refs.container.removeClass( 'fancybox-show-caption' );
2272            }
2273
2274        }
2275
2276    });
2277
2278
2279    $.fancybox = {
2280
2281        version  : "3.0.47",
2282        defaults : defaults,
2283
2284
2285        // Get current instance and execute a command.
2286        //
2287        // Examples of usage:
2288        //
2289        //   $instance = $.fancybox.getInstance();
2290        //   $.fancybox.getInstance().jumpTo( 1 );
2291        //   $.fancybox.getInstance( 'jumpTo', 1 );
2292        //   $.fancybox.getInstance( function() {
2293        //       console.info( this.currIndex );
2294        //   });
2295        // ======================================================
2296
2297        getInstance : function ( command ) {
2298            var instance = $('.fancybox-container:not(".fancybox-container--closing"):first').data( 'FancyBox' );
2299            var args     = Array.prototype.slice.call(arguments, 1);
2300
2301            if ( instance instanceof FancyBox ) {
2302
2303                if ( $.type( command ) === 'string' ) {
2304                    instance[ command ].apply( instance, args );
2305
2306                } else if ( $.type( command ) === 'function' ) {
2307                    command.apply( instance, args );
2308
2309                }
2310
2311                return instance;
2312            }
2313
2314            return false;
2315
2316        },
2317
2318
2319        // Create new instance
2320        // ===================
2321
2322        open : function ( items, opts, index ) {
2323            return new FancyBox( items, opts, index );
2324        },
2325
2326
2327        // Close current or all instances
2328        // ==============================
2329
2330        close : function ( all ) {
2331            var instance = this.getInstance();
2332
2333            if ( instance ) {
2334                instance.close();
2335
2336                // Try to find and close next instance
2337
2338                if ( all === true ) {
2339                    this.close();
2340                }
2341            }
2342
2343        },
2344
2345
2346        // Test for the existence of touch events in the browser
2347        // Limit to mobile devices
2348        // ====================================================
2349
2350        isTouch : document.createTouch !== undefined && /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent),
2351
2352
2353        // Detect if 'translate3d' support is available
2354        // ============================================
2355
2356        use3d : (function() {
2357            var div = document.createElement('div');
2358
2359            return window.getComputedStyle( div ).getPropertyValue('transform') && !(document.documentMode && document.documentMode <= 11);
2360        }()),
2361
2362
2363        // Helper function to get current visual state of an element
2364        // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]
2365        // =====================================================================
2366
2367        getTranslate : function( $el ) {
2368            var position, matrix;
2369
2370            if ( !$el || !$el.length ) {
2371                return false;
2372            }
2373
2374            position = $el.get( 0 ).getBoundingClientRect();
2375            matrix   = $el.eq( 0 ).css('transform');
2376
2377            if ( matrix && matrix.indexOf( 'matrix' ) !== -1 ) {
2378                matrix = matrix.split('(')[1];
2379                matrix = matrix.split(')')[0];
2380                matrix = matrix.split(',');
2381            } else {
2382                matrix = [];
2383            }
2384
2385            if ( matrix.length ) {
2386
2387                // If IE
2388                if ( matrix.length > 10 ) {
2389                    matrix = [ matrix[13], matrix[12], matrix[0], matrix[5] ];
2390
2391                } else {
2392                    matrix = [ matrix[5], matrix[4], matrix[0], matrix[3]];
2393                }
2394
2395                matrix = matrix.map(parseFloat);
2396
2397            } else {
2398                matrix = [ 0, 0, 1, 1 ];
2399            }
2400
2401            return {
2402                top     : matrix[ 0 ],
2403                left    : matrix[ 1 ],
2404                scaleX  : matrix[ 2 ],
2405                scaleY  : matrix[ 3 ],
2406                opacity : parseFloat( $el.css('opacity') ),
2407                width   : position.width,
2408                height  : position.height
2409            };
2410
2411        },
2412
2413
2414        // Shortcut for setting "translate3d" properties for element
2415        // Can set be used to set opacity, too
2416        // ========================================================
2417
2418        setTranslate : function( $el, props ) {
2419            var str  = '';
2420            var css  = {};
2421
2422            if ( !$el || !props ) {
2423                return;
2424            }
2425
2426            if ( props.left !== undefined || props.top !== undefined ) {
2427
2428                str = ( props.left === undefined ? $el.position().top : props.left )  + 'px, ' + ( props.top === undefined ? $el.position().top : props.top ) + 'px';
2429
2430                if ( this.use3d ) {
2431                    str = 'translate3d(' + str + ', 0px)';
2432
2433                } else {
2434                    str = 'translate(' + str + ')';
2435                }
2436
2437            }
2438
2439            if ( props.scaleX !== undefined && props.scaleY !== undefined ) {
2440                str = (str.length ? str + ' ' : '') + 'scale(' + props.scaleX + ', ' + props.scaleY + ')';
2441            }
2442
2443            if ( str.length ) {
2444                css.transform = str;
2445            }
2446
2447            if ( props.opacity !== undefined ) {
2448                css.opacity = props.opacity;
2449            }
2450
2451            if ( props.width !== undefined ) {
2452                css.width = props.width;
2453            }
2454
2455            if ( props.height !== undefined ) {
2456                css.height = props.height;
2457            }
2458
2459            return $el.css( css );
2460
2461        },
2462
2463
2464        // Common easings for entrances and exits
2465        // t: current time, b: begInnIng value, c: change In value, d: duration
2466        // ====================================================================
2467
2468        easing : {
2469            easeOutCubic : function (t, b, c, d) {
2470                return c * ((t=t/d-1)*t*t + 1) + b;
2471            },
2472            easeInCubic : function (t, b, c, d) {
2473                return c * (t/=d)*t*t + b;
2474            },
2475            easeOutSine : function (t, b, c, d) {
2476                return c * Math.sin(t/d * (Math.PI/2)) + b;
2477            },
2478            easeInSine : function (t, b, c, d) {
2479                return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
2480            }
2481        },
2482
2483
2484        // Stop fancyBox animation
2485        // =======================
2486
2487        stop : function( $el ) {
2488
2489            $el.removeData( 'animateID' );
2490
2491        },
2492
2493        // Animate element using "translate3d"
2494        // Usage:
2495        // animate( element, start properties, end properties, duration, easing, callback )
2496        // or
2497        // animate( element, start properties, end properties, duration, callback )
2498        // =================================================================================
2499
2500        animate : function( $el, from, to, duration, easing, done ) {
2501
2502            var self = this;
2503
2504            var lastTime = null;
2505            var animTime = 0;
2506
2507            var curr;
2508            var diff;
2509            var id;
2510
2511            var finish = function() {
2512                if ( to.scaleX !== undefined && to.scaleY !== undefined && from && from.width !== undefined && from.height !== undefined ) {
2513                    to.width  = from.width  * to.scaleX;
2514                    to.height = from.height * to.scaleY;
2515
2516                    to.scaleX = 1;
2517                    to.scaleY = 1;
2518                }
2519
2520                self.setTranslate( $el, to );
2521
2522                done();
2523            };
2524
2525            var frame = function ( timestamp ) {
2526                curr = [];
2527                diff = 0;
2528
2529                // If "stop" method has been called on this element, then just stop
2530                if ( !$el.length || $el.data( 'animateID' ) !== id ) {
2531                    return;
2532                }
2533
2534                timestamp = timestamp || Date.now();
2535
2536                if ( lastTime ) {
2537                    diff = timestamp - lastTime;
2538                }
2539
2540                lastTime = timestamp;
2541                animTime += diff;
2542
2543                // Are we done?
2544                if ( animTime >= duration ) {
2545
2546                    finish();
2547
2548                    return;
2549                }
2550
2551                for ( var prop in to ) {
2552
2553                    if ( to.hasOwnProperty( prop ) && from[ prop ] !== undefined ) {
2554
2555                        if ( from[ prop ] == to[ prop ] ) {
2556                            curr[ prop ] = to[ prop ];
2557
2558                        } else {
2559                            curr[ prop ] = self.easing[ easing ]( animTime, from[ prop ], to[ prop ] - from[ prop ], duration );
2560                        }
2561
2562                    }
2563                }
2564
2565                self.setTranslate( $el, curr );
2566
2567                requestAFrame( frame );
2568            };
2569
2570            self.animateID = id = self.animateID === undefined ? 1 : self.animateID + 1;
2571
2572            $el.data( 'animateID', id );
2573
2574            if ( done === undefined && $.type(easing) == 'function' ) {
2575                done   = easing;
2576                easing = undefined;
2577            }
2578
2579            if ( !easing ) {
2580                easing = "easeOutCubic";
2581            }
2582
2583            done = done || $.noop;
2584
2585            if ( from ) {
2586                this.setTranslate( $el, from );
2587
2588            } else {
2589
2590                // We need current values to calculate change in time
2591                from = this.getTranslate( $el );
2592            }
2593
2594            if ( duration ) {
2595                $el.show();
2596
2597                requestAFrame( frame );
2598
2599            } else {
2600                finish();
2601            }
2602
2603        }
2604
2605    };
2606
2607
2608    // Event handler for click event to "fancyboxed" links
2609    // ===================================================
2610
2611    function _run( e ) {
2612        var target  = e.currentTarget,
2613            opts    = e.data ? e.data.options : {},
2614            items   = e.data ? e.data.items : [],
2615            value   = '',
2616            index   = 0;
2617
2618        e.preventDefault();
2619        e.stopPropagation();
2620
2621        // Get all related items and find index for clicked one
2622
2623        if ( $(target).attr( 'data-fancybox' ) ) {
2624            value = $(target).data( 'fancybox' );
2625        }
2626
2627        if ( value ) {
2628            items = items.length ? items.filter( '[data-fancybox="' + value + '"]' ) : $( '[data-fancybox=' + value + ']' );
2629            index = items.index( target );
2630
2631        } else {
2632            items = [ target ];
2633        }
2634
2635        $.fancybox.open( items, opts, index );
2636    }
2637
2638
2639    // Create a jQuery plugin
2640    // ======================
2641
2642    $.fn.fancybox = function (options) {
2643
2644        this.off('click.fb-start').on('click.fb-start', {
2645            items   : this,
2646            options : options || {}
2647        }, _run);
2648
2649        return this;
2650
2651    };
2652
2653
2654    // Self initializing plugin
2655    // ========================
2656
2657    $(document).on('click.fb-start', '[data-fancybox]', _run);
2658
2659}(window, document, window.jQuery));
2660
2661// ==========================================================================
2662//
2663// Media
2664// Adds additional media type support
2665//
2666// ==========================================================================
2667;(function ($) {
2668
2669    'use strict';
2670
2671    // Formats matching url to final form
2672
2673    var format = function (url, rez, params) {
2674        if ( !url ) {
2675            return;
2676        }
2677
2678        params = params || '';
2679
2680        if ( $.type(params) === "object" ) {
2681            params = $.param(params, true);
2682        }
2683
2684        $.each(rez, function (key, value) {
2685            url = url.replace('$' + key, value || '');
2686        });
2687
2688        if (params.length) {
2689            url += (url.indexOf('?') > 0 ? '&' : '?') + params;
2690        }
2691
2692        return url;
2693    };
2694
2695    // Object containing properties for each media type
2696
2697    var media = {
2698        youtube: {
2699            matcher: /(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,
2700            params: {
2701                autoplay: 1,
2702                autohide: 1,
2703                fs: 1,
2704                rel: 0,
2705                hd: 1,
2706                wmode: 'transparent',
2707                enablejsapi: 1,
2708                html5: 1
2709            },
2710            paramPlace : 8,
2711            type: 'iframe',
2712            url: '//www.youtube.com/embed/$4',
2713            thumb: '//img.youtube.com/vi/$4/hqdefault.jpg'
2714        },
2715
2716        vimeo: {
2717            matcher: /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,
2718            params: {
2719                autoplay: 1,
2720                hd: 1,
2721                show_title: 1,
2722                show_byline: 1,
2723                show_portrait: 0,
2724                fullscreen: 1,
2725                api: 1
2726            },
2727            paramPlace : 3,
2728            type: 'iframe',
2729            url: '//player.vimeo.com/video/$2'
2730        },
2731
2732        metacafe: {
2733            matcher: /metacafe.com\/watch\/(\d+)\/(.*)?/,
2734            type: 'iframe',
2735            url: '//www.metacafe.com/embed/$1/?ap=1'
2736        },
2737
2738        dailymotion: {
2739            matcher: /dailymotion.com\/video\/(.*)\/?(.*)/,
2740            params: {
2741                additionalInfos: 0,
2742                autoStart: 1
2743            },
2744            type: 'iframe',
2745            url: '//www.dailymotion.com/embed/video/$1'
2746        },
2747
2748        vine: {
2749            matcher: /vine.co\/v\/([a-zA-Z0-9\?\=\-]+)/,
2750            type: 'iframe',
2751            url: '//vine.co/v/$1/embed/simple'
2752        },
2753
2754        instagram: {
2755            matcher: /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,
2756            type: 'image',
2757            url: '//$1/p/$2/media/?size=l'
2758        },
2759
2760        // Examples:
2761        // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
2762        // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
2763        // https://www.google.lv/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572
2764        google_maps: {
2765            matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,
2766            type: 'iframe',
2767            url: function (rez) {
2768                return '//maps.google.' + rez[2] + '/?ll=' + ( rez[9] ? rez[9] + '&z=' + Math.floor(  rez[10]  ) + ( rez[12] ? rez[12].replace(/^\//, "&") : '' )  : rez[12] ) + '&output=' + ( rez[12] && rez[12].indexOf('layer=c') > 0 ? 'svembed' : 'embed' );
2769            }
2770        }
2771    };
2772
2773    $(document).on('onInit.fb', function (e, instance) {
2774
2775        $.each(instance.group, function( i, item ) {
2776
2777            var url  = item.src || '',
2778                type = false,
2779                thumb,
2780                rez,
2781                params,
2782                urlParams,
2783                o,
2784                provider;
2785
2786            // Skip items that already have content type
2787            if ( item.type ) {
2788                return;
2789            }
2790
2791            // Look for any matching media type
2792
2793            $.each(media, function ( n, el ) {
2794                rez = url.match(el.matcher);
2795                o   = {};
2796                provider = n;
2797
2798                if (!rez) {
2799                    return;
2800                }
2801
2802                type = el.type;
2803
2804                if ( el.paramPlace && rez[ el.paramPlace ] ) {
2805                    urlParams = rez[ el.paramPlace ];
2806
2807                    if ( urlParams[ 0 ] == '?' ) {
2808                        urlParams = urlParams.substring(1);
2809                    }
2810
2811                    urlParams = urlParams.split('&');
2812
2813                    for ( var m = 0; m < urlParams.length; ++m ) {
2814                        var p = urlParams[ m ].split('=', 2);
2815
2816                        if ( p.length == 2 ) {
2817                            o[ p[0] ] = decodeURIComponent( p[1].replace(/\+/g, " ") );
2818                        }
2819                    }
2820                }
2821
2822                params = $.extend( true, {}, el.params, item.opts[ n ], o );
2823
2824                url   = $.type(el.url) === "function" ? el.url.call(this, rez, params, item) : format(el.url, rez, params);
2825                thumb = $.type(el.thumb) === "function" ? el.thumb.call(this, rez, params, item) : format(el.thumb, rez);
2826
2827                if ( provider === 'vimeo' ) {
2828                    url = url.replace('&%23', '#');
2829                }
2830
2831                return false;
2832            });
2833
2834            // If it is found, then change content type and update the url
2835
2836            if ( type ) {
2837                item.src  = url;
2838                item.type = type;
2839
2840                if ( !item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length ) ) {
2841                    item.opts.thumb = thumb;
2842                }
2843
2844                if ( type === 'iframe' ) {
2845                    $.extend(true, item.opts, {
2846                        iframe : {
2847                            preload   : false,
2848                            scrolling : "no"
2849                        },
2850                        smallBtn   : false,
2851                        closeBtn   : true,
2852                        fullScreen : false,
2853                        slideShow  : false
2854                    });
2855
2856                    item.opts.slideClass += ' fancybox-slide--video';
2857                }
2858
2859            } else {
2860
2861                // If no content type is found, then set it to `iframe` as fallback
2862                item.type = 'iframe';
2863
2864            }
2865
2866        });
2867
2868    });
2869
2870}(window.jQuery));
2871
2872// ==========================================================================
2873//
2874// Guestures
2875// Adds touch guestures, handles click and tap events
2876//
2877// ==========================================================================
2878;(function (window, document, $) {
2879    'use strict';
2880
2881    var requestAFrame = (function() {
2882        return  window.requestAnimationFrame ||
2883                window.webkitRequestAnimationFrame ||
2884                window.mozRequestAnimationFrame ||
2885                function( callback ) {
2886                    window.setTimeout(callback, 1000 / 60); };
2887                })();
2888
2889
2890    var pointers = function( e ) {
2891        var result = [];
2892
2893        e = e.originalEvent || e || window.e;
2894        e = e.touches && e.touches.length ? e.touches : ( e.changedTouches && e.changedTouches.length ? e.changedTouches : [ e ] );
2895
2896        for ( var key in e ) {
2897
2898            if ( e[ key ].pageX ) {
2899                result.push( { x : e[ key ].pageX, y : e[ key ].pageY } );
2900
2901            } else if ( e[ key ].clientX ) {
2902                result.push( { x : e[ key ].clientX, y : e[ key ].clientY } );
2903            }
2904        }
2905
2906        return result;
2907    };
2908
2909    var distance = function( point2, point1, what ) {
2910
2911        if ( !point1 || !point2 ) {
2912            return 0;
2913        }
2914
2915        if ( what === 'x' ) {
2916            return point2.x - point1.x;
2917
2918        } else if ( what === 'y' ) {
2919            return point2.y - point1.y;
2920        }
2921
2922        return Math.sqrt( Math.pow( point2.x - point1.x, 2 ) + Math.pow( point2.y - point1.y, 2 ) );
2923
2924    };
2925
2926    var isClickable = function( $el ) {
2927
2928        return $el.is('a') || $el.is('button') || $el.is('input') || $el.is('select') || $el.is('textarea') || $.isFunction( $el.get(0).onclick );
2929
2930    };
2931
2932    var hasScrollbars = function( el ) {
2933        var overflowY = window.getComputedStyle( el )['overflow-y'];
2934        var overflowX = window.getComputedStyle( el )['overflow-x'];
2935
2936        var vertical   = (overflowY === 'scroll' || overflowY === 'auto') && el.scrollHeight > el.clientHeight;
2937        var horizontal = (overflowX === 'scroll' || overflowX === 'auto') && el.scrollWidth > el.clientWidth;
2938
2939        return vertical || horizontal;
2940    };
2941
2942    var isScrollable = function ( $el ) {
2943
2944        var rez = false;
2945
2946        while ( true ) {
2947            rez = hasScrollbars( $el.get(0) );
2948
2949            if ( rez ) {
2950                break;
2951            }
2952
2953            $el = $el.parent();
2954
2955            if ( !$el.length || $el.hasClass('fancybox-slider') || $el.is('body') ) {
2956                break;
2957            }
2958
2959        }
2960
2961        return rez;
2962
2963    };
2964
2965
2966    var Guestures = function ( instance ) {
2967
2968        var self = this;
2969
2970        self.instance = instance;
2971
2972        self.$wrap       = instance.$refs.slider_wrap;
2973        self.$slider     = instance.$refs.slider;
2974        self.$container  = instance.$refs.container;
2975
2976        self.destroy();
2977
2978        self.$wrap.on('touchstart.fb mousedown.fb', $.proxy(self, "ontouchstart"));
2979
2980    };
2981
2982    Guestures.prototype.destroy = function() {
2983
2984        this.$wrap.off('touchstart.fb mousedown.fb touchmove.fb mousemove.fb touchend.fb touchcancel.fb mouseup.fb mouseleave.fb');
2985
2986    };
2987
2988    Guestures.prototype.ontouchstart = function( e ) {
2989
2990        var self = this;
2991
2992        var $target  = $( e.target );
2993        var instance = self.instance;
2994        var current  = instance.current;
2995        var $content = current.$content || current.$placeholder;
2996
2997        self.startPoints = pointers( e );
2998
2999        self.$target  = $target;
3000        self.$content = $content;
3001
3002        self.canvasWidth  = Math.round( current.$slide[0].clientWidth );
3003        self.canvasHeight = Math.round( current.$slide[0].clientHeight );
3004
3005        self.startEvent = e;
3006
3007        // Skip if clicked on the scrollbar
3008        if ( e.originalEvent.clientX > self.canvasWidth + current.$slide.offset().left ) {
3009            return true;
3010        }
3011
3012        // Ignore taping on links, buttons and scrollable items
3013        if ( isClickable( $target ) || isClickable( $target.parent() ) || ( isScrollable( $target ) ) ) {
3014            return;
3015        }
3016
3017        // If "touch" is disabled, then handle click event
3018        if ( !current.opts.touch ) {
3019            self.endPoints = self.startPoints;
3020
3021            return self.ontap();
3022        }
3023
3024        // Ignore right click
3025        if ( e.originalEvent && e.originalEvent.button == 2 ) {
3026            return;
3027        }
3028
3029        e.stopPropagation();
3030        e.preventDefault();
3031
3032        if ( !current || self.instance.isAnimating || self.instance.isClosing ) {
3033            return;
3034        }
3035
3036        // Prevent zooming if already swiping
3037        if ( !self.startPoints || ( self.startPoints.length > 1 && !current.isMoved ) ) {
3038            return;
3039        }
3040
3041        self.$wrap.off('touchmove.fb mousemove.fb',  $.proxy(self, "ontouchmove"));
3042        self.$wrap.off('touchend.fb touchcancel.fb mouseup.fb mouseleave.fb',  $.proxy(self, "ontouchend"));
3043
3044        self.$wrap.on('touchend.fb touchcancel.fb mouseup.fb mouseleave.fb',  $.proxy(self, "ontouchend"));
3045        self.$wrap.on('touchmove.fb mousemove.fb',  $.proxy(self, "ontouchmove"));
3046
3047        self.startTime = new Date().getTime();
3048        self.distanceX = self.distanceY = self.distance = 0;
3049
3050        self.canTap    = false;
3051        self.isPanning = false;
3052        self.isSwiping = false;
3053        self.isZooming = false;
3054
3055        self.sliderStartPos = $.fancybox.getTranslate( self.$slider );
3056
3057        self.contentStartPos = $.fancybox.getTranslate( self.$content );
3058        self.contentLastPos  = null;
3059
3060        if ( self.startPoints.length === 1 && !self.isZooming ) {
3061            self.canTap = current.isMoved;
3062
3063            if ( current.type === 'image' && ( self.contentStartPos.width > self.canvasWidth + 1 || self.contentStartPos.height > self.canvasHeight + 1 ) ) {
3064
3065                $.fancybox.stop( self.$content );
3066
3067                self.isPanning = true;
3068
3069            } else {
3070
3071                $.fancybox.stop( self.$slider );
3072
3073                self.isSwiping = true;
3074            }
3075
3076            self.$container.addClass('fancybox-controls--isGrabbing');
3077
3078        }
3079
3080        if ( self.startPoints.length === 2 && current.isMoved  && !current.hasError && current.type === 'image' && ( current.isLoaded || current.$ghost ) ) {
3081
3082            self.isZooming = true;
3083
3084            self.isSwiping = false;
3085            self.isPanning = false;
3086
3087            $.fancybox.stop( self.$content );
3088
3089            self.centerPointStartX = ( ( self.startPoints[0].x + self.startPoints[1].x ) * 0.5 ) - $(window).scrollLeft();
3090            self.centerPointStartY = ( ( self.startPoints[0].y + self.startPoints[1].y ) * 0.5 ) - $(window).scrollTop();
3091
3092            self.percentageOfImageAtPinchPointX = ( self.centerPointStartX - self.contentStartPos.left ) / self.contentStartPos.width;
3093            self.percentageOfImageAtPinchPointY = ( self.centerPointStartY - self.contentStartPos.top  ) / self.contentStartPos.height;
3094
3095            self.startDistanceBetweenFingers = distance( self.startPoints[0], self.startPoints[1] );
3096        }
3097
3098    };
3099
3100    Guestures.prototype.ontouchmove = function( e ) {
3101
3102        var self = this;
3103
3104        e.preventDefault();
3105
3106        self.newPoints = pointers( e );
3107
3108        if ( !self.newPoints || !self.newPoints.length ) {
3109            return;
3110        }
3111
3112        self.distanceX = distance( self.newPoints[0], self.startPoints[0], 'x' );
3113        self.distanceY = distance( self.newPoints[0], self.startPoints[0], 'y' );
3114
3115        self.distance = distance( self.newPoints[0], self.startPoints[0] );
3116
3117        // Skip false ontouchmove events (Chrome)
3118        if ( self.distance > 0 ) {
3119
3120            if ( self.isSwiping ) {
3121                self.onSwipe();
3122
3123            } else if ( self.isPanning ) {
3124                self.onPan();
3125
3126            } else if ( self.isZooming ) {
3127                self.onZoom();
3128            }
3129
3130        }
3131
3132    };
3133
3134    Guestures.prototype.onSwipe = function() {
3135
3136        var self = this;
3137
3138        var swiping = self.isSwiping;
3139        var left    = self.sliderStartPos.left;
3140        var angle;
3141
3142        if ( swiping === true ) {
3143
3144            if ( Math.abs( self.distance ) > 10 )  {
3145
3146                if ( self.instance.group.length < 2 ) {
3147                    self.isSwiping  = 'y';
3148
3149                } else if ( !self.instance.current.isMoved || self.instance.opts.touch.vertical === false || ( self.instance.opts.touch.vertical === 'auto' && $( window ).width() > 800 ) ) {
3150                    self.isSwiping  = 'x';
3151
3152                } else {
3153                    angle = Math.abs( Math.atan2( self.distanceY, self.distanceX ) * 180 / Math.PI );
3154
3155                    self.isSwiping = ( angle > 45 && angle < 135 ) ? 'y' : 'x';
3156                }
3157
3158                self.canTap  = false;
3159
3160                self.instance.current.isMoved = false;
3161
3162                // Reset points to avoid jumping, because we dropped first swipes to calculate the angle
3163                self.startPoints = self.newPoints;
3164            }
3165
3166        } else {
3167
3168            if ( swiping == 'x' ) {
3169
3170                // Sticky edges
3171                if ( !self.instance.current.opts.loop && self.instance.current.index === 0  && self.distanceX > 0 ) {
3172                    left = left + Math.pow( self.distanceX, 0.8 );
3173
3174                } else if ( !self.instance.current.opts.loop &&self.instance.current.index === self.instance.group.length - 1 && self.distanceX < 0 ) {
3175                    left = left - Math.pow( -self.distanceX, 0.8 );
3176
3177                } else {
3178                    left = left + self.distanceX;
3179                }
3180
3181            }
3182
3183            self.sliderLastPos = {
3184                top  : swiping == 'x' ? 0 : self.sliderStartPos.top + self.distanceY,
3185                left : left
3186            };
3187
3188            requestAFrame(function() {
3189                $.fancybox.setTranslate( self.$slider, self.sliderLastPos );
3190            });
3191        }
3192
3193    };
3194
3195    Guestures.prototype.onPan = function() {
3196
3197        var self = this;
3198
3199        var newOffsetX, newOffsetY, newPos;
3200
3201        self.canTap = false;
3202
3203        if ( self.contentStartPos.width > self.canvasWidth ) {
3204            newOffsetX = self.contentStartPos.left + self.distanceX;
3205
3206        } else {
3207            newOffsetX = self.contentStartPos.left;
3208        }
3209
3210        newOffsetY = self.contentStartPos.top + self.distanceY;
3211
3212        newPos = self.limitMovement( newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height );
3213
3214        newPos.scaleX = self.contentStartPos.scaleX;
3215        newPos.scaleY = self.contentStartPos.scaleY;
3216
3217        self.contentLastPos = newPos;
3218
3219        requestAFrame(function() {
3220            $.fancybox.setTranslate( self.$content, self.contentLastPos );
3221        });
3222    };
3223
3224    // Make panning sticky to the edges
3225    Guestures.prototype.limitMovement = function( newOffsetX, newOffsetY, newWidth, newHeight ) {
3226
3227        var self = this;
3228
3229        var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY;
3230
3231        var canvasWidth  = self.canvasWidth;
3232        var canvasHeight = self.canvasHeight;
3233
3234        var currentOffsetX = self.contentStartPos.left;
3235        var currentOffsetY = self.contentStartPos.top;
3236
3237        var distanceX = self.distanceX;
3238        var distanceY = self.distanceY;
3239
3240        // Slow down proportionally to traveled distance
3241
3242        minTranslateX = Math.max(0, canvasWidth  * 0.5 - newWidth  * 0.5 );
3243        minTranslateY = Math.max(0, canvasHeight * 0.5 - newHeight * 0.5 );
3244
3245        maxTranslateX = Math.min( canvasWidth  - newWidth,  canvasWidth  * 0.5 - newWidth  * 0.5 );
3246        maxTranslateY = Math.min( canvasHeight - newHeight, canvasHeight * 0.5 - newHeight * 0.5 );
3247
3248        if ( newWidth > canvasWidth ) {
3249
3250            //   ->
3251            if ( distanceX > 0 && newOffsetX > minTranslateX ) {
3252                newOffsetX = minTranslateX - 1 + Math.pow( -minTranslateX + currentOffsetX + distanceX, 0.8 ) || 0;
3253            }
3254
3255            //    <-
3256            if ( distanceX  < 0 && newOffsetX < maxTranslateX ) {
3257                newOffsetX = maxTranslateX + 1 - Math.pow( maxTranslateX - currentOffsetX - distanceX, 0.8 ) || 0;
3258            }
3259
3260        }
3261
3262        if ( newHeight > canvasHeight ) {
3263
3264            //   \/
3265            if ( distanceY > 0 && newOffsetY > minTranslateY ) {
3266                newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8 ) || 0;
3267            }
3268
3269            //   /\
3270            if ( distanceY < 0 && newOffsetY < maxTranslateY ) {
3271                newOffsetY = maxTranslateY + 1 - Math.pow ( maxTranslateY - currentOffsetY - distanceY, 0.8 ) || 0;
3272            }
3273
3274        }
3275
3276        return {
3277            top  : newOffsetY,
3278            left : newOffsetX
3279        };
3280
3281    };
3282
3283
3284    Guestures.prototype.limitPosition = function( newOffsetX, newOffsetY, newWidth, newHeight ) {
3285
3286        var self = this;
3287
3288        var canvasWidth  = self.canvasWidth;
3289        var canvasHeight = self.canvasHeight;
3290
3291        if ( newWidth > canvasWidth ) {
3292            newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
3293            newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;
3294
3295        } else {
3296
3297            // Center horizontally
3298            newOffsetX = Math.max( 0, canvasWidth / 2 - newWidth / 2 );
3299
3300        }
3301
3302        if ( newHeight > canvasHeight ) {
3303            newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
3304            newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;
3305
3306        } else {
3307
3308            // Center vertically
3309            newOffsetY = Math.max( 0, canvasHeight / 2 - newHeight / 2 );
3310
3311        }
3312
3313        return {
3314            top  : newOffsetY,
3315            left : newOffsetX
3316        };
3317
3318    };
3319
3320    Guestures.prototype.onZoom = function() {
3321
3322        var self = this;
3323
3324        // Calculate current distance between points to get pinch ratio and new width and height
3325
3326        var currentWidth  = self.contentStartPos.width;
3327        var currentHeight = self.contentStartPos.height;
3328
3329        var currentOffsetX = self.contentStartPos.left;
3330        var currentOffsetY = self.contentStartPos.top;
3331
3332        var endDistanceBetweenFingers = distance( self.newPoints[0], self.newPoints[1] );
3333
3334        var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;
3335
3336        var newWidth  = Math.floor( currentWidth  * pinchRatio );
3337        var newHeight = Math.floor( currentHeight * pinchRatio );
3338
3339        // This is the translation due to pinch-zooming
3340        var translateFromZoomingX = (currentWidth  - newWidth)  * self.percentageOfImageAtPinchPointX;
3341        var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
3342
3343        //Point between the two touches
3344
3345        var centerPointEndX = ((self.newPoints[0].x + self.newPoints[1].x) / 2) - $(window).scrollLeft();
3346        var centerPointEndY = ((self.newPoints[0].y + self.newPoints[1].y) / 2) - $(window).scrollTop();
3347
3348        // And this is the translation due to translation of the centerpoint
3349        // between the two fingers
3350
3351        var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
3352        var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
3353
3354        // The new offset is the old/current one plus the total translation
3355
3356        var newOffsetX = currentOffsetX + ( translateFromZoomingX + translateFromTranslatingX );
3357        var newOffsetY = currentOffsetY + ( translateFromZoomingY + translateFromTranslatingY );
3358
3359        var newPos = {
3360            top    : newOffsetY,
3361            left   : newOffsetX,
3362            scaleX : self.contentStartPos.scaleX * pinchRatio,
3363            scaleY : self.contentStartPos.scaleY * pinchRatio
3364        };
3365
3366        self.canTap = false;
3367
3368        self.newWidth  = newWidth;
3369        self.newHeight = newHeight;
3370
3371        self.contentLastPos = newPos;
3372
3373        requestAFrame(function() {
3374            $.fancybox.setTranslate( self.$content, self.contentLastPos );
3375        });
3376
3377    };
3378
3379    Guestures.prototype.ontouchend = function( e ) {
3380
3381        var self = this;
3382
3383        var current = self.instance.current;
3384
3385        var dMs = Math.max( (new Date().getTime() ) - self.startTime, 1);
3386
3387        var swiping = self.isSwiping;
3388        var panning = self.isPanning;
3389        var zooming = self.isZooming;
3390
3391        self.endPoints = pointers( e );
3392
3393        self.$container.removeClass('fancybox-controls--isGrabbing');
3394
3395        self.$wrap.off('touchmove.fb mousemove.fb',  $.proxy(this, "ontouchmove"));
3396        self.$wrap.off('touchend.fb touchcancel.fb mouseup.fb mouseleave.fb',  $.proxy(this, "ontouchend"));
3397
3398        self.isSwiping = false;
3399        self.isPanning = false;
3400        self.isZooming = false;
3401
3402        if ( self.canTap )  {
3403            return self.ontap();
3404        }
3405
3406        // Speed in px/ms
3407        self.velocityX = self.distanceX / dMs * 0.5;
3408        self.velocityY = self.distanceY / dMs * 0.5;
3409
3410        self.speed = current.opts.speed || 330;
3411
3412        self.speedX = Math.max( self.speed * 0.75, Math.min( self.speed * 1.5, ( 1 / Math.abs( self.velocityX ) ) * self.speed ) );
3413        self.speedY = Math.max( self.speed * 0.75, Math.min( self.speed * 1.5, ( 1 / Math.abs( self.velocityY ) ) * self.speed ) );
3414
3415        if ( panning ) {
3416            self.endPanning();
3417
3418        } else if ( zooming ) {
3419            self.endZooming();
3420
3421        } else {
3422            self.endSwiping( swiping );
3423        }
3424
3425        return;
3426    };
3427
3428    Guestures.prototype.endSwiping = function( swiping ) {
3429
3430        var self = this;
3431
3432        // Close if swiped vertically / navigate if horizontally
3433
3434        if ( swiping == 'y' && Math.abs( self.distanceY ) > 50 ) {
3435
3436            // Continue vertical movement
3437
3438            $.fancybox.animate( self.$slider, null, {
3439                top     : self.sliderStartPos.top + self.distanceY + self.velocityY * 150,
3440                left    : self.sliderStartPos.left,
3441                opacity : 0
3442            }, self.speedY );
3443
3444            self.instance.close( true );
3445
3446        } else if ( swiping == 'x' && self.distanceX > 50 ) {
3447            self.instance.previous( self.speedX );
3448
3449        } else if ( swiping == 'x' && self.distanceX < -50 ) {
3450            self.instance.next( self.speedX );
3451
3452        } else {
3453
3454            // Move back to center
3455            self.instance.update( false, true, 150 );
3456
3457        }
3458
3459    };
3460
3461    Guestures.prototype.endPanning = function() {
3462
3463        var self = this;
3464        var newOffsetX, newOffsetY, newPos;
3465
3466        if ( !self.contentLastPos ) {
3467            return;
3468        }
3469
3470        newOffsetX = self.contentLastPos.left + ( self.velocityX * self.speed * 2 );
3471        newOffsetY = self.contentLastPos.top  + ( self.velocityY * self.speed * 2 );
3472
3473        newPos = self.limitPosition( newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height );
3474
3475         newPos.width  = self.contentStartPos.width;
3476         newPos.height = self.contentStartPos.height;
3477
3478        $.fancybox.animate( self.$content, null, newPos, self.speed, "easeOutSine" );
3479
3480    };
3481
3482
3483    Guestures.prototype.endZooming = function() {
3484
3485        var self = this;
3486
3487        var current = self.instance.current;
3488
3489        var newOffsetX, newOffsetY, newPos, reset;
3490
3491        var newWidth  = self.newWidth;
3492        var newHeight = self.newHeight;
3493
3494        if ( !self.contentLastPos ) {
3495            return;
3496        }
3497
3498        newOffsetX = self.contentLastPos.left;
3499        newOffsetY = self.contentLastPos.top;
3500
3501        reset = {
3502            top    : newOffsetY,
3503            left   : newOffsetX,
3504            width  : newWidth,
3505            height : newHeight,
3506            scaleX : 1,
3507            scaleY : 1
3508       };
3509
3510       // Reset scalex/scaleY values; this helps for perfomance and does not break animation
3511       $.fancybox.setTranslate( self.$content, reset );
3512
3513        if ( newWidth < self.canvasWidth && newHeight < self.canvasHeight ) {
3514            self.instance.scaleToFit( 150 );
3515
3516        } else if ( newWidth > current.width || newHeight > current.height ) {
3517            self.instance.scaleToActual( self.centerPointStartX, self.centerPointStartY, 150 );
3518
3519        } else {
3520
3521            newPos = self.limitPosition( newOffsetX, newOffsetY, newWidth, newHeight );
3522
3523            $.fancybox.animate( self.$content, null, newPos, self.speed, "easeOutSine" );
3524
3525        }
3526
3527    };
3528
3529    Guestures.prototype.ontap = function() {
3530
3531        var self = this;
3532
3533        var instance = self.instance;
3534        var current  = instance.current;
3535
3536        var x = self.endPoints[0].x;
3537        var y = self.endPoints[0].y;
3538
3539        x = x - self.$wrap.offset().left;
3540        y = y - self.$wrap.offset().top;
3541
3542        // Stop slideshow
3543        if ( instance.SlideShow && instance.SlideShow.isActive ) {
3544            instance.SlideShow.stop();
3545        }
3546
3547        if ( !$.fancybox.isTouch ) {
3548
3549            if ( current.opts.closeClickOutside && self.$target.is('.fancybox-slide') ) {
3550                instance.close( self.startEvent );
3551
3552                return;
3553            }
3554
3555            if ( current.type == 'image' && current.isMoved ) {
3556
3557                if ( instance.canPan() ) {
3558                    instance.scaleToFit();
3559
3560                } else if ( instance.isScaledDown() ) {
3561                    instance.scaleToActual( x, y );
3562
3563                } else if ( instance.group.length < 2 ) {
3564                    instance.close( self.startEvent );
3565                }
3566
3567            }
3568
3569            return;
3570        }
3571
3572
3573        // Double tap
3574        if ( self.tapped ) {
3575
3576            clearTimeout( self.tapped );
3577
3578            self.tapped = null;
3579
3580            if ( Math.abs( x - self.x ) > 50 || Math.abs( y - self.y ) > 50 || !current.isMoved ) {
3581                return this;
3582            }
3583
3584            if ( current.type == 'image' && ( current.isLoaded || current.$ghost ) ) {
3585
3586                if ( instance.canPan() ) {
3587                    instance.scaleToFit();
3588
3589                } else if ( instance.isScaledDown() ) {
3590                    instance.scaleToActual( x, y );
3591
3592                }
3593
3594            }
3595
3596        } else {
3597
3598            // Single tap
3599
3600            self.x = x;
3601            self.y = y;
3602
3603            self.tapped = setTimeout(function() {
3604                self.tapped = null;
3605
3606                instance.toggleControls( true );
3607
3608            }, 300);
3609        }
3610
3611        return this;
3612    };
3613
3614    $(document).on('onActivate.fb', function (e, instance) {
3615
3616        if ( instance && !instance.Guestures ) {
3617            instance.Guestures = new Guestures( instance );
3618        }
3619
3620    });
3621
3622    $(document).on('beforeClose.fb', function (e, instance) {
3623
3624        if ( instance && instance.Guestures ) {
3625            instance.Guestures.destroy();
3626        }
3627
3628    });
3629
3630
3631}(window, document, window.jQuery));
3632
3633// ==========================================================================
3634//
3635// SlideShow
3636// Enables slideshow functionality
3637//
3638// Example of usage:
3639// $.fancybox.getInstance().slideShow.start()
3640//
3641// ==========================================================================
3642;(function (document, $) {
3643    'use strict';
3644
3645    var SlideShow = function( instance ) {
3646
3647        this.instance = instance;
3648
3649        this.init();
3650
3651    };
3652
3653    $.extend( SlideShow.prototype, {
3654        timer    : null,
3655        isActive : false,
3656        $button  : null,
3657        speed    : 3000,
3658
3659        init : function() {
3660            var self = this;
3661
3662            self.$button = $('<button data-fancybox-play class="fancybox-button fancybox-button--play" title="Slideshow (P)"></button>')
3663                .appendTo( self.instance.$refs.buttons );
3664
3665            self.instance.$refs.container.on('click', '[data-fancybox-play]', function() {
3666                self.toggle();
3667            });
3668
3669        },
3670
3671        set : function() {
3672            var self = this;
3673
3674            // Check if reached last element
3675            if ( self.instance && self.instance.current && (self.instance.current.opts.loop || self.instance.currIndex < self.instance.group.length - 1 )) {
3676
3677                self.timer = setTimeout(function() {
3678                    self.instance.next();
3679
3680                }, self.instance.current.opts.slideShow.speed || self.speed);
3681
3682            } else {
3683                self.stop();
3684            }
3685        },
3686
3687        clear : function() {
3688            var self = this;
3689
3690            clearTimeout( self.timer );
3691
3692            self.timer = null;
3693        },
3694
3695        start : function() {
3696            var self = this;
3697
3698            self.stop();
3699
3700            if ( self.instance && self.instance.current && ( self.instance.current.opts.loop || self.instance.currIndex < self.instance.group.length - 1 )) {
3701
3702                self.instance.$refs.container.on({
3703                    'beforeLoad.fb.player'  : $.proxy(self, "clear"),
3704                    'onComplete.fb.player'  : $.proxy(self, "set"),
3705                });
3706
3707                self.isActive = true;
3708
3709                if ( self.instance.current.isComplete ) {
3710                    self.set();
3711                }
3712
3713                self.instance.$refs.container.trigger('onPlayStart');
3714
3715                self.$button.addClass('fancybox-button--pause');
3716            }
3717
3718        },
3719
3720        stop: function() {
3721            var self = this;
3722
3723            self.clear();
3724
3725            self.instance.$refs.container
3726                .trigger('onPlayEnd')
3727                .off('.player');
3728
3729            self.$button.removeClass('fancybox-button--pause');
3730
3731            self.isActive = false;
3732        },
3733
3734        toggle : function() {
3735            var self = this;
3736
3737            if ( self.isActive ) {
3738                self.stop();
3739
3740            } else {
3741                self.start();
3742            }
3743        }
3744
3745    });
3746
3747    $(document).on('onInit.fb', function(e, instance) {
3748
3749        if ( instance && instance.group.length > 1 && !!instance.opts.slideShow && !instance.SlideShow ) {
3750            instance.SlideShow = new SlideShow( instance );
3751        }
3752
3753    });
3754
3755    $(document).on('beforeClose.fb onDeactivate.fb', function(e, instance) {
3756
3757        if ( instance && instance.SlideShow ) {
3758            instance.SlideShow.stop();
3759        }
3760
3761    });
3762
3763}(document, window.jQuery));
3764
3765// ==========================================================================
3766//
3767// FullScreen
3768// Adds fullscreen functionality
3769//
3770// ==========================================================================
3771;(function (document, $) {
3772    'use strict';
3773
3774    // Collection of methods supported by user browser
3775    var fn = (function () {
3776
3777        var fnMap = [
3778            [
3779                'requestFullscreen',
3780                'exitFullscreen',
3781                'fullscreenElement',
3782                'fullscreenEnabled',
3783                'fullscreenchange',
3784                'fullscreenerror'
3785            ],
3786            // new WebKit
3787            [
3788                'webkitRequestFullscreen',
3789                'webkitExitFullscreen',
3790                'webkitFullscreenElement',
3791                'webkitFullscreenEnabled',
3792                'webkitfullscreenchange',
3793                'webkitfullscreenerror'
3794
3795            ],
3796            // old WebKit (Safari 5.1)
3797            [
3798                'webkitRequestFullScreen',
3799                'webkitCancelFullScreen',
3800                'webkitCurrentFullScreenElement',
3801                'webkitCancelFullScreen',
3802                'webkitfullscreenchange',
3803                'webkitfullscreenerror'
3804
3805            ],
3806            [
3807                'mozRequestFullScreen',
3808                'mozCancelFullScreen',
3809                'mozFullScreenElement',
3810                'mozFullScreenEnabled',
3811                'mozfullscreenchange',
3812                'mozfullscreenerror'
3813            ],
3814            [
3815                'msRequestFullscreen',
3816                'msExitFullscreen',
3817                'msFullscreenElement',
3818                'msFullscreenEnabled',
3819                'MSFullscreenChange',
3820                'MSFullscreenError'
3821            ]
3822        ];
3823
3824        var val;
3825        var ret = {};
3826        var i, j;
3827
3828        for ( i = 0; i < fnMap.length; i++ ) {
3829            val = fnMap[ i ];
3830
3831            if ( val && val[ 1 ] in document ) {
3832                for ( j = 0; j < val.length; j++ ) {
3833                    ret[ fnMap[ 0 ][ j ] ] = val[ j ];
3834                }
3835
3836                return ret;
3837            }
3838        }
3839
3840        return false;
3841    })();
3842
3843    if ( !fn ) {
3844        return;
3845    }
3846
3847    var FullScreen = {
3848        request : function ( elem ) {
3849
3850            elem = elem || document.documentElement;
3851
3852            elem[ fn.requestFullscreen ]( elem.ALLOW_KEYBOARD_INPUT );
3853
3854        },
3855        exit : function () {
3856            document[ fn.exitFullscreen ]();
3857        },
3858        toggle : function ( elem ) {
3859
3860            if ( this.isFullscreen() ) {
3861                this.exit();
3862            } else {
3863                this.request( elem );
3864            }
3865
3866        },
3867        isFullscreen : function()  {
3868            return Boolean( document[ fn.fullscreenElement ] );
3869        },
3870        enabled : function()  {
3871            return Boolean( document[ fn.fullscreenEnabled ] );
3872        }
3873    };
3874
3875    $(document).on({
3876        'onInit.fb' : function(e, instance) {
3877            var $container;
3878
3879            if ( instance && !!instance.opts.fullScreen && !instance.FullScreen) {
3880                $container = instance.$refs.container;
3881
3882                instance.$refs.button_fs = $('<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fullscreen" title="Full screen (F)"></button>')
3883                    .appendTo( instance.$refs.buttons );
3884
3885                $container.on('click.fb-fullscreen', '[data-fancybox-fullscreen]', function(e) {
3886
3887                    e.stopPropagation();
3888                    e.preventDefault();
3889
3890                    FullScreen.toggle( $container[ 0 ] );
3891
3892                });
3893
3894                if ( instance.opts.fullScreen.requestOnStart === true ) {
3895                    FullScreen.request( $container[ 0 ] );
3896                }
3897
3898            }
3899
3900        }, 'beforeMove.fb' : function(e, instance) {
3901
3902            if ( instance && instance.$refs.button_fs ) {
3903                instance.$refs.button_fs.toggle( !!instance.current.opts.fullScreen );
3904            }
3905
3906        }, 'beforeClose.fb':  function() {
3907            FullScreen.exit();
3908        }
3909    });
3910
3911    $(document).on(fn.fullscreenchange, function() {
3912        var instance = $.fancybox.getInstance();
3913        var  $what   = instance ? instance.current.$placeholder : null;
3914
3915        if ( $what ) {
3916
3917            // If image is zooming, then this will force it to stop and reposition properly
3918            $what.css( 'transition', 'none' );
3919
3920            instance.isAnimating = false;
3921
3922            instance.update( true, true, 0 );
3923        }
3924
3925    });
3926
3927}(document, window.jQuery));
3928
3929// ==========================================================================
3930//
3931// Thumbs
3932// Displays thumbnails in a grid
3933//
3934// ==========================================================================
3935;(function (document, $) {
3936    'use strict';
3937
3938    var FancyThumbs = function( instance ) {
3939
3940        this.instance = instance;
3941
3942        this.init();
3943
3944    };
3945
3946    $.extend( FancyThumbs.prototype, {
3947
3948        $button     : null,
3949        $grid       : null,
3950        $list       : null,
3951        isVisible   : false,
3952
3953        init : function() {
3954            var self = this;
3955
3956            self.$button = $('<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="Thumbnails (G)"></button>')
3957                .appendTo( this.instance.$refs.buttons )
3958                .on('touchend click', function(e) {
3959                    e.stopPropagation();
3960                    e.preventDefault();
3961
3962                    self.toggle();
3963                });
3964
3965        },
3966
3967        create : function() {
3968            var instance = this.instance,
3969                list,
3970                src;
3971
3972            this.$grid = $('<div class="fancybox-thumbs"></div>').appendTo( instance.$refs.container );
3973
3974            list = '<ul>';
3975
3976            $.each(instance.group, function( i, item ) {
3977
3978                src = item.opts.thumb || ( item.opts.$thumb ? item.opts.$thumb.attr('src') : null );
3979
3980                if ( !src && item.type === 'image' ) {
3981                    src = item.src;
3982                }
3983
3984                if ( src && src.length ) {
3985                    list += '<li data-index="' + i + '"  tabindex="0" class="fancybox-thumbs-loading"><img data-src="' + src + '" /></li>';
3986                }
3987
3988            });
3989
3990            list += '</ul>';
3991
3992            this.$list = $( list ).appendTo( this.$grid ).on('click touchstart', 'li', function() {
3993
3994                instance.jumpTo( $(this).data('index') );
3995
3996            });
3997
3998            this.$list.find('img').hide().one('load', function() {
3999
4000                var $parent     = $(this).parent().removeClass('fancybox-thumbs-loading'),
4001                    thumbWidth  = $parent.outerWidth(),
4002                    thumbHeight = $parent.outerHeight(),
4003                    width,
4004                    height,
4005                    widthRatio,
4006                    heightRatio;
4007
4008                width  = this.naturalWidth  || this.width;
4009                height = this.naturalHeight || this.height;
4010
4011                //Calculate thumbnail width/height and center it
4012
4013                widthRatio  = width  / thumbWidth;
4014                heightRatio = height / thumbHeight;
4015
4016                if (widthRatio >= 1 && heightRatio >= 1) {
4017                    if (widthRatio > heightRatio) {
4018                        width  = width / heightRatio;
4019                        height = thumbHeight;
4020
4021                    } else {
4022                        width  = thumbWidth;
4023                        height = height / widthRatio;
4024                    }
4025                }
4026
4027                $(this).css({
4028                    width         : Math.floor(width),
4029                    height        : Math.floor(height),
4030                    'margin-top'  : Math.min( 0, Math.floor(thumbHeight * 0.3 - he
4030ight * 0.3 ) ),
4031                    'margin-left' : Math.min( 0, Math.floor(thumbWidth  * 0.5 - width  * 0.5 ) )
4032                }).show();
4033
4034            })
4035            .each(function() {
4036                this.src = $( this ).data( 'src' );
4037            });
4038
4039        },
4040
4041        focus : function() {
4042
4043            if ( this.instance.current ) {
4044                this.$list
4045                    .children()
4046                    .removeClass('fancybox-thumbs-active')
4047                    .filter('[data-index="' + this.instance.current.index  + '"]')
4048                    .addClass('fancybox-thumbs-active')
4049                    .focus();
4050            }
4051
4052        },
4053
4054        close : function() {
4055
4056            this.$grid.hide();
4057
4058        },
4059
4060        update : function() {
4061
4062            this.instance.$refs.container.toggleClass('fancybox-container--thumbs', this.isVisible);
4063
4064            if ( this.isVisible ) {
4065
4066                if ( !this.$grid ) {
4067                    this.create();
4068                }
4069
4070                this.$grid.show();
4071
4072                this.focus();
4073
4074            } else if ( this.$grid ) {
4075                this.$grid.hide();
4076            }
4077
4078            this.instance.update();
4079
4080        },
4081
4082        hide : function() {
4083
4084            this.isVisible = false;
4085
4086            this.update();
4087
4088        },
4089
4090        show : function() {
4091
4092            this.isVisible = true;
4093
4094            this.update();
4095
4096        },
4097
4098        toggle : function() {
4099
4100            if ( this.isVisible ) {
4101                this.hide();
4102
4103            } else {
4104                this.show();
4105            }
4106        }
4107
4108    });
4109
4110    $(document).on('onInit.fb', function(e, instance) {
4111        var first  = instance.group[0],
4112            second = instance.group[1];
4113
4114        if ( !!instance.opts.thumbs && !instance.Thumbs && instance.group.length > 1 && (
4115                    ( first.type == 'image'  || first.opts.thumb  || first.opts.$thumb ) &&
4116                    ( second.type == 'image' || second.opts.thumb || second.opts.$thumb )
4117                )
4118           ) {
4119
4120            instance.Thumbs = new FancyThumbs( instance );
4121        }
4122
4123    });
4124
4125    $(document).on('beforeMove.fb', function(e, instance, item) {
4126        var self = instance && instance.Thumbs;
4127
4128        if ( !self ) {
4129            return;
4130        }
4131
4132        if ( item.modal ) {
4133
4134            self.$button.hide();
4135
4136            self.hide();
4137
4138        } else {
4139
4140            if ( instance.opts.thumbs.showOnStart === true && instance.firstRun ) {
4141                self.show();
4142
4143            }
4144
4145            self.$button.show();
4146
4147            if ( self.isVisible ) {
4148                self.focus();
4149            }
4150
4151        }
4152
4153    });
4154
4155    $(document).on('beforeClose.fb', function(e, instance) {
4156
4157        if ( instance && instance.Thumbs) {
4158            if ( instance.Thumbs.isVisible && instance.opts.thumbs.hideOnClosing !== false ) {
4159                instance.Thumbs.close();
4160            }
4161
4162            instance.Thumbs = null;
4163        }
4164
4165    });
4166
4167}(document, window.jQuery));
4168
4169// ==========================================================================
4170//
4171// Hash
4172// Enables linking to each modal
4173//
4174// ==========================================================================
4175;(function (document, window, $) {
4176    'use strict';
4177
4178    // Simple $.escapeSelector polyfill (for jQuery prior v3)
4179    if ( !$.escapeSelector ) {
4180        $.escapeSelector = function( sel ) {
4181            var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
4182            var fcssescape = function( ch, asCodePoint ) {
4183                if ( asCodePoint ) {
4184                    // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
4185                    if ( ch === "\0" ) {
4186                        return "\uFFFD";
4187                    }
4188
4189                    // Control characters and (dependent upon position) numbers get escaped as code points
4190                    return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
4191                }
4192
4193                // Other potentially-special ASCII characters get backslash-escaped
4194                return "\\" + ch;
4195            };
4196
4197            return ( sel + "" ).replace( rcssescape, fcssescape );
4198        };
4199    }
4200
4201    // Variable containing last hash value set by fancyBox
4202    // It will be used to determine if fancyBox needs to close after hash change is detected
4203    var currentHash = null;
4204
4205    // Get info about gallery name and current index from url
4206    function parseUrl() {
4207        var hash    = window.location.hash.substr( 1 );
4208        var rez     = hash.split( '-' );
4209        var index   = rez.length > 1 && /^\+?\d+$/.test( rez[ rez.length - 1 ] ) ? parseInt( rez.pop( -1 ), 10 ) || 1 : 1;
4210        var gallery = rez.join( '-' );
4211
4212        // Index is starting from 1
4213        if ( index < 1 ) {
4214            index = 1;
4215        }
4216
4217        return {
4218            hash    : hash,
4219            index   : index,
4220            gallery : gallery
4221        };
4222    }
4223
4224    // Trigger click evnt on links to open new fancyBox instance
4225    function triggerFromUrl( url ) {
4226        var $el;
4227
4228        if ( url.gallery !== '' ) {
4229
4230            // If we can find element matching 'data-fancybox' atribute, then trigger click event for that ..
4231            $el = $( "[data-fancybox='" + $.escapeSelector( url.gallery ) + "']" ).eq( url.index - 1 );
4232
4233            if ( $el.length ) {
4234                $el.trigger( 'click' );
4235
4236            } else {
4237
4238                // .. if not, try finding element by ID
4239                $( "#" + $.escapeSelector( url.gallery ) + "" ).trigger( 'click' );
4240
4241            }
4242
4243        }
4244    }
4245
4246    // Get gallery name from current instance
4247    function getGallery( instance ) {
4248        var opts;
4249
4250        if ( !instance ) {
4251            return false;
4252        }
4253
4254        opts = instance.current ? instance.current.opts : instance.opts;
4255
4256        return opts.$orig ? opts.$orig.data( 'fancybox' ) : ( opts.hash || '' );
4257    }
4258
4259    // Star when DOM becomes ready
4260    $(function() {
4261
4262        // Small delay is used to allow other scripts to process "dom ready" event
4263        setTimeout(function() {
4264
4265            // Check if this module is not disabled
4266            if ( $.fancybox.defaults.hash === false ) {
4267                return;
4268            }
4269
4270            // Check if need to close after url has changed
4271            $(window).on('hashchange.fb', function() {
4272                var url = parseUrl();
4273
4274                if ( $.fancybox.getInstance() ) {
4275                    if ( currentHash && currentHash !== url.gallery + '-' + url.index )  {
4276                        currentHash = null;
4277
4278                        $.fancybox.close();
4279                    }
4280
4281                } else if ( url.gallery !== '' ) {
4282                    triggerFromUrl( url );
4283                }
4284
4285            });
4286
4287            // Update hash when opening/closing fancyBox
4288            $(document).on({
4289                'onInit.fb' : function( e, instance ) {
4290                    var url     = parseUrl();
4291                    var gallery = getGallery( instance );
4292
4293                    // Make sure gallery start index matches index from hash
4294                    if ( gallery && url.gallery && gallery == url.gallery ) {
4295                        instance.currIndex = url.index - 1;
4296                    }
4297
4298                }, 'beforeMove.fb' : function( e, instance, current ) {
4299                    var gallery = getGallery( instance );
4300
4301                    // Update window hash
4302                    if ( gallery && gallery !== '' ) {
4303
4304                        if ( window.location.hash.indexOf( gallery ) < 0 ) {
4305                            instance.opts.origHash = window.location.hash;
4306                        }
4307
4308                        currentHash = gallery + ( instance.group.length > 1 ? '-' + ( current.index + 1 ) : '' );
4309
4310                        if ( "pushState" in history ) {
4311                            history.pushState( '', document.title, window.location.pathname + window.location.search + '#' +  currentHash );
4312
4313                        } else {
4314                            window.location.hash = currentHash;
4315                        }
4316
4317                    }
4318
4319                }, 'beforeClose.fb' : function( e, instance, current ) {
4320                    var gallery  = getGallery( instance );
4321                    var origHash = instance && instance.opts.origHash ? instance.opts.origHash : '';
4322
4323                    // Remove hash from location bar
4324                    if ( gallery && gallery !== '' ) {
4325                        if ( "pushState" in history ) {
4326                            history.pushState( '', document.title, window.location.pathname + window.location.search + origHash );
4327
4328                        } else {
4329                            window.location.hash = origHash;
4330                        }
4331                    }
4332
4333                    currentHash = null;
4334                }
4335            });
4336
4337            // Check current hash and trigger click event on matching element to start fancyBox, if needed
4338            triggerFromUrl( parseUrl() );
4339
4340        }, 50);
4341    });
4342
4343
4344}(document, window, window.jQuery));

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.