PageSourceSearch

https://pirkis.lt/components/com_prekes/js/jquery.fancybox.js

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