Skip to content

Instantly share code, notes, and snippets.

@evikza
Last active March 12, 2026 12:17
Show Gist options
  • Select an option

  • Save evikza/51ace557584032355d59ac8676131ece to your computer and use it in GitHub Desktop.

Select an option

Save evikza/51ace557584032355d59ac8676131ece to your computer and use it in GitHub Desktop.
Added Rutube and VK Video embed to fancyBox v3.5.7
// ==================================================
// fancyBox v3.5.7
//
// Licensed GPLv3 for open source use
// or fancyBox Commercial License for commercial use
//
// http://fancyapps.com/fancybox/
// Copyright 2022 fancyApps
//
// ==================================================
(function (window, document, $, undefined) {
'use strict';
window.console = window.console || {
info: function (stuff) {},
};
// If there's no jQuery, fancyBox can't work
// =========================================
if (!$) {
return;
}
// Check if fancyBox is already initialized
// ========================================
if ($.fn.fancybox) {
console.info('fancyBox already initialized');
return;
}
// Private default settings
// ========================
var defaults = {
// Close existing modals
// Set this to false if you do not need to stack multiple instances
closeExisting: false,
// Enable infinite gallery navigation
loop: false,
// Horizontal space between slides
gutter: 50,
// Enable keyboard navigation
keyboard: true,
// Should allow caption to overlap the content
preventCaptionOverlap: true,
// Should display navigation arrows at the screen edges
arrows: true,
// Should display counter at the top left corner
infobar: true,
// Should display close button (using `btnTpl.smallBtn` template) over the content
// Can be true, false, "auto"
// If "auto" - will be automatically enabled for "html", "inline" or "ajax" items
smallBtn: 'auto',
// Should display toolbar (buttons at the top)
// Can be true, false, "auto"
// If "auto" - will be automatically hidden if "smallBtn" is enabled
toolbar: 'auto',
// What buttons should appear in the top right corner.
// Buttons will be created using templates from `btnTpl` option
// and they will be placed into toolbar (class="fancybox-toolbar"` element)
buttons: [
'zoom',
//"share",
'slideShow',
//"fullScreen",
//"download",
'thumbs',
'close',
],
// Detect "idle" time in seconds
idleTime: 3,
// Disable right-click and use simple image protection for images
protect: false,
// Shortcut to make content "modal" - disable keyboard navigtion, hide buttons, etc
modal: false,
image: {
// Wait for images to load before displaying
// true - wait for image to load and then display;
// false - display thumbnail and load the full-sized image over top,
// requires predefined image dimensions (`data-width` and `data-height` attributes)
preload: false,
},
ajax: {
// Object containing settings for ajax request
settings: {
// This helps to indicate that request comes from the modal
// Feel free to change naming
data: {
fancybox: true,
},
},
},
iframe: {
// Iframe template
tpl: '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen="allowfullscreen" allow="autoplay; fullscreen" src=""></iframe>',
// Preload iframe before displaying it
// This allows to calculate iframe content width and height
// (note: Due to "Same Origin Policy", you can't get cross domain data).
preload: true,
// Custom CSS styling for iframe wrapping element
// You can use this to set custom iframe dimensions
css: {},
// Iframe tag attributes
attr: {
scrolling: 'auto',
},
},
// For HTML5 video only
video: {
tpl:
'<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}">' +
'<source src="{{src}}" type="{{format}}" />' +
'Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!' +
'</video>',
format: '', // custom video format
autoStart: true,
},
// Default content type if cannot be detected automatically
defaultType: 'image',
// Open/close animation type
// Possible values:
// false - disable
// "zoom" - zoom images from/to thumbnail
// "fade"
// "zoom-in-out"
//
animationEffect: 'zoom',
// Duration in ms for open/close animation
animationDuration: 366,
// Should image change opacity while zooming
// If opacity is "auto", then opacity will be changed if image and thumbnail have different aspect ratios
zoomOpacity: 'auto',
// Transition effect between slides
//
// Possible values:
// false - disable
// "fade'
// "slide'
// "circular'
// "tube'
// "zoom-in-out'
// "rotate'
//
transitionEffect: 'fade',
// Duration in ms for transition animation
transitionDuration: 366,
// Custom CSS class for slide element
slideClass: '',
// Custom CSS class for layout
baseClass: '',
// Base template for layout
baseTpl:
'<div class="fancybox-container" role="dialog" tabindex="-1">' +
'<div class="fancybox-bg"></div>' +
'<div class="fancybox-inner">' +
'<div class="fancybox-infobar"><span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span></div>' +
'<div class="fancybox-toolbar">{{buttons}}</div>' +
'<div class="fancybox-navigation">{{arrows}}</div>' +
'<div class="fancybox-stage"></div>' +
'<div class="fancybox-caption"><div class="fancybox-caption__body"></div></div>' +
'</div>' +
'</div>',
// Loading indicator template
spinnerTpl: '<div class="fancybox-loading"></div>',
// Error message template
errorTpl: '<div class="fancybox-error"><p>{{ERROR}}</p></div>',
btnTpl: {
download:
'<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;">' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.62 17.09V19H5.38v-1.91zm-2.97-6.96L17 11.45l-5 4.87-5-4.87 1.36-1.32 2.68 2.64V5h1.92v7.77z"/></svg>' +
'</a>',
zoom:
'<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.7 17.3l-3-3a5.9 5.9 0 0 0-.6-7.6 5.9 5.9 0 0 0-8.4 0 5.9 5.9 0 0 0 0 8.4 5.9 5.9 0 0 0 7.7.7l3 3a1 1 0 0 0 1.3 0c.4-.5.4-1 0-1.5zM8.1 13.8a4 4 0 0 1 0-5.7 4 4 0 0 1 5.7 0 4 4 0 0 1 0 5.7 4 4 0 0 1-5.7 0z"/></svg>' +
'</button>',
close:
'<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 10.6L6.6 5.2 5.2 6.6l5.4 5.4-5.4 5.4 1.4 1.4 5.4-5.4 5.4 5.4 1.4-1.4-5.4-5.4 5.4-5.4-1.4-1.4-5.4 5.4z"/></svg>' +
'</button>',
// Arrows
arrowLeft:
'<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' +
'<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.28 15.7l-1.34 1.37L5 12l4.94-5.07 1.34 1.38-2.68 2.72H19v1.94H8.6z"/></svg></div>' +
'</button>',
arrowRight:
'<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' +
'<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.4 12.97l-2.68 2.72 1.34 1.38L19 12l-4.94-5.07-1.34 1.38 2.68 2.72H5v1.94z"/></svg></div>' +
'</button>',
// This small close button will be appended to your html/inline/ajax content by default,
// if "smallBtn" option is not set to false
smallBtn:
'<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}">' +
'<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 24 24"><path d="M13 12l5-5-1-1-5 5-5-5-1 1 5 5-5 5 1 1 5-5 5 5 1-1z"/></svg>' +
'</button>',
},
// Container is injected into this element
parentEl: 'body',
// Hide browser vertical scrollbars; use at your own risk
hideScrollbar: true,
// Focus handling
// ==============
// Try to focus on the first focusable element after opening
autoFocus: true,
// Put focus back to active element after closing
backFocus: true,
// Do not let user to focus on element outside modal content
trapFocus: true,
// Module specific options
// =======================
fullScreen: {
autoStart: false,
},
// Set `touch: false` to disable panning/swiping
touch: {
vertical: true, // Allow to drag content vertically
momentum: true, // Continue movement after releasing mouse/touch when panning
},
// Hash value when initializing manually,
// set `false` to disable hash change
hash: null,
// Customize or add new media types
// Example:
/*
media : {
youtube : {
params : {
autoplay : 0
}
}
}
*/
media: {},
slideShow: {
autoStart: false,
speed: 3000,
},
thumbs: {
autoStart: false, // Display thumbnails on opening
hideOnClose: true, // Hide thumbnail grid when closing animation starts
parentEl: '.fancybox-container', // Container is injected into this element
axis: 'y', // Vertical (y) or horizontal (x) scrolling
},
// Use mousewheel to navigate gallery
// If 'auto' - enabled for images only
wheel: 'auto',
// Callbacks
//==========
// See Documentation/API/Events for more information
// Example:
/*
afterShow: function( instance, current ) {
console.info( 'Clicked element:' );
console.info( current.opts.$orig );
}
*/
onInit: $.noop, // When instance has been initialized
beforeLoad: $.noop, // Before the content of a slide is being loaded
afterLoad: $.noop, // When the content of a slide is done loading
beforeShow: $.noop, // Before open animation starts
afterShow: $.noop, // When content is done loading and animating
beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close.
afterClose: $.noop, // After instance has been closed
onActivate: $.noop, // When instance is brought to front
onDeactivate: $.noop, // When other instance has been activated
// Interaction
// ===========
// Use options below to customize taken action when user clicks or double clicks on the fancyBox area,
// each option can be string or method that returns value.
//
// Possible values:
// "close" - close instance
// "next" - move to next gallery item
// "nextOrClose" - move to next gallery item or close if gallery has only one item
// "toggleControls" - show/hide controls
// "zoom" - zoom image (if loaded)
// false - do nothing
// Clicked on the content
clickContent: function (current, event) {
return current.type === 'image' ? 'zoom' : false;
},
// Clicked on the slide
clickSlide: 'close',
// Clicked on the background (backdrop) element;
// if you have not changed the layout, then most likely you need to use `clickSlide` option
clickOutside: 'close',
// Same as previous two, but for double click
dblclickContent: false,
dblclickSlide: false,
dblclickOutside: false,
// Custom options when mobile device is detected
// =============================================
mobile: {
preventCaptionOverlap: false,
idleTime: false,
clickContent: function (current, event) {
return current.type === 'image' ? 'toggleControls' : false;
},
clickSlide: function (current, event) {
return current.type === 'image' ? 'toggleControls' : 'close';
},
dblclickContent: function (current, event) {
return current.type === 'image' ? 'zoom' : false;
},
dblclickSlide: function (current, event) {
return current.type === 'image' ? 'zoom' : false;
},
},
// Internationalization
// ====================
lang: 'en',
i18n: {
en: {
CLOSE: 'Close',
NEXT: 'Next',
PREV: 'Previous',
ERROR:
'The requested content cannot be loaded. <br/> Please try again later.',
PLAY_START: 'Start slideshow',
PLAY_STOP: 'Pause slideshow',
FULL_SCREEN: 'Full screen',
THUMBS: 'Thumbnails',
DOWNLOAD: 'Download',
SHARE: 'Share',
ZOOM: 'Zoom',
},
de: {
CLOSE: 'Schlie&szlig;en',
NEXT: 'Weiter',
PREV: 'Zur&uuml;ck',
ERROR:
'Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es sp&auml;ter nochmal.',
PLAY_START: 'Diaschau starten',
PLAY_STOP: 'Diaschau beenden',
FULL_SCREEN: 'Vollbild',
THUMBS: 'Vorschaubilder',
DOWNLOAD: 'Herunterladen',
SHARE: 'Teilen',
ZOOM: 'Vergr&ouml;&szlig;ern',
},
},
};
// Few useful variables and methods
// ================================
var $W = $(window);
var $D = $(document);
var called = 0;
// Check if an object is a jQuery object and not a native JavaScript object
// ========================================================================
var isQuery = function (obj) {
return obj && obj.hasOwnProperty && obj instanceof $;
};
// Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame"
// ===============================================================================
var requestAFrame = (function () {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function (callback) {
return window.setTimeout(callback, 1000 / 60);
}
);
})();
var cancelAFrame = (function () {
return (
window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function (id) {
window.clearTimeout(id);
}
);
})();
// Detect the supported transition-end event property name
// =======================================================
var transitionEnd = (function () {
var el = document.createElement('fakeelement'),
t;
var transitions = {
transition: 'transitionend',
OTransition: 'oTransitionEnd',
MozTransition: 'transitionend',
WebkitTransition: 'webkitTransitionEnd',
};
for (t in transitions) {
if (el.style[t] !== undefined) {
return transitions[t];
}
}
return 'transitionend';
})();
// Force redraw on an element.
// This helps in cases where the browser doesn't redraw an updated element properly
// ================================================================================
var forceRedraw = function ($el) {
return $el && $el.length && $el[0].offsetHeight;
};
// Exclude array (`buttons`) options from deep merging
// ===================================================
var mergeOpts = function (opts1, opts2) {
var rez = $.extend(true, {}, opts1, opts2);
$.each(opts2, function (key, value) {
if ($.isArray(value)) {
rez[key] = value;
}
});
return rez;
};
// How much of an element is visible in viewport
// =============================================
var inViewport = function (elem) {
var elemCenter, rez;
if (!elem || elem.ownerDocument !== document) {
return false;
}
$('.fancybox-container').css('pointer-events', 'none');
elemCenter = {
x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
y: elem.getBoundingClientRect().top + elem.offsetHeight / 2,
};
rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem;
$('.fancybox-container').css('pointer-events', '');
return rez;
};
// Class definition
// ================
var FancyBox = function (content, opts, index) {
var self = this;
self.opts = mergeOpts(
{
index: index,
},
$.fancybox.defaults
);
if ($.isPlainObject(opts)) {
self.opts = mergeOpts(self.opts, opts);
}
if ($.fancybox.isMobile) {
self.opts = mergeOpts(self.opts, self.opts.mobile);
}
self.id = self.opts.id || ++called;
self.currIndex = parseInt(self.opts.index, 10) || 0;
self.prevIndex = null;
self.prevPos = null;
self.currPos = 0;
self.firstRun = true;
// All group items
self.group = [];
// Existing slides (for current, next and previous gallery items)
self.slides = {};
// Create group elements
self.addContent(content);
if (!self.group.length) {
return;
}
self.init();
};
$.extend(FancyBox.prototype, {
// Create DOM structure
// ====================
init: function () {
var self = this,
firstItem = self.group[self.currIndex],
firstItemOpts = firstItem.opts,
$container,
buttonStr;
if (firstItemOpts.closeExisting) {
$.fancybox.close(true);
}
// Hide scrollbars
// ===============
$('body').addClass('fancybox-active');
if (
!$.fancybox.getInstance() &&
firstItemOpts.hideScrollbar !== false &&
!$.fancybox.isMobile &&
document.body.scrollHeight > window.innerHeight
) {
$('head').append(
'<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:' +
(window.innerWidth - document.documentElement.clientWidth) +
'px;}</style>'
);
$('body').addClass('compensate-for-scrollbar');
}
// Build html markup and set references
// ====================================
// Build html code for buttons and insert into main template
buttonStr = '';
$.each(firstItemOpts.buttons, function (index, value) {
buttonStr += firstItemOpts.btnTpl[value] || '';
});
// Create markup from base template, it will be initially hidden to
// avoid unnecessary work like painting while initializing is not complete
$container = $(
self.translate(
self,
firstItemOpts.baseTpl
.replace('{{buttons}}', buttonStr)
.replace(
'{{arrows}}',
firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight
)
)
)
.attr('id', 'fancybox-container-' + self.id)
.addClass(firstItemOpts.baseClass)
.data('FancyBox', self)
.appendTo(firstItemOpts.parentEl);
// Create object holding references to jQuery wrapped nodes
self.$refs = {
container: $container,
};
[
'bg',
'inner',
'infobar',
'toolbar',
'stage',
'caption',
'navigation',
].forEach(function (item) {
self.$refs[item] = $container.find('.fancybox-' + item);
});
self.trigger('onInit');
// Enable events, deactive previous instances
self.activate();
// Build slides, load and reveal content
self.jumpTo(self.currIndex);
},
// Simple i18n support - replaces object keys found in template
// with corresponding values
// ============================================================
translate: function (obj, str) {
var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en;
return str.replace(/\{\{(\w+)\}\}/g, function (match, n) {
return arr[n] === undefined ? match : arr[n];
});
},
// Populate current group with fresh content
// Check if each object has valid type and content
// ===============================================
addContent: function (content) {
var self = this,
items = $.makeArray(content),
thumbs;
$.each(items, function (i, item) {
var obj = {},
opts = {},
$item,
type,
found,
src,
srcParts;
// Step 1 - Make sure we have an object
// ====================================
if ($.isPlainObject(item)) {
// We probably have manual usage here, something like
// $.fancybox.open( [ { src : "image.jpg", type : "image" } ] )
obj = item;
opts = item.opts || item;
} else if ($.type(item) === 'object' && $(item).length) {
// Here we probably have jQuery collection returned by some selector
$item = $(item);
// Support attributes like `data-options='{"touch" : false}'` and `data-touch='false'`
opts = $item.data() || {};
opts = $.extend(true, {}, opts, opts.options);
// Here we store clicked element
opts.$orig = $item;
obj.src = self.opts.src || opts.src || $item.attr('href');
// Assume that simple syntax is used, for example:
// `$.fancybox.open( $("#test"), {} );`
if (!obj.type && !obj.src) {
obj.type = 'inline';
obj.src = item;
}
} else {
// Assume we have a simple html code, for example:
// $.fancybox.open( '<div><h1>Hi!</h1></div>' );
obj = {
type: 'html',
src: item + '',
};
}
// Each gallery object has full collection of options
obj.opts = $.extend(true, {}, self.opts, opts);
// Do not merge buttons array
if ($.isArray(opts.buttons)) {
obj.opts.buttons = opts.buttons;
}
if ($.fancybox.isMobile && obj.opts.mobile) {
obj.opts = mergeOpts(obj.opts, obj.opts.mobile);
}
// Step 2 - Make sure we have content type, if not - try to guess
// ==============================================================
type = obj.type || obj.opts.type;
src = obj.src || '';
if (!type && src) {
if ((found = src.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))) {
type = 'video';
if (!obj.opts.video.format) {
obj.opts.video.format =
'video/' + (found[1] === 'ogv' ? 'ogg' : found[1]);
}
} else if (
src.match(
/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i
)
) {
type = 'image';
} else if (src.match(/\.(pdf)((\?|#).*)?$/i)) {
type = 'iframe';
obj = $.extend(true, obj, {
contentType: 'pdf',
opts: {
iframe: {
preload: false,
},
},
});
} else if (src.charAt(0) === '#') {
type = 'inline';
}
}
if (type) {
obj.type = type;
} else {
self.trigger('objectNeedsType', obj);
}
if (!obj.contentType) {
obj.contentType =
$.inArray(obj.type, ['html', 'inline', 'ajax']) > -1
? 'html'
: obj.type;
}
// Step 3 - Some adjustments
// =========================
obj.index = self.group.length;
if (obj.opts.smallBtn == 'auto') {
obj.opts.smallBtn =
$.inArray(obj.type, ['html', 'inline', 'ajax']) > -1;
}
if (obj.opts.toolbar === 'auto') {
obj.opts.toolbar = !obj.opts.smallBtn;
}
// Find thumbnail image, check if exists and if is in the viewport
obj.$thumb = obj.opts.$thumb || null;
if (obj.opts.$trigger && obj.index === self.opts.index) {
obj.$thumb = obj.opts.$trigger.find('img:first');
if (obj.$thumb.length) {
obj.opts.$orig = obj.opts.$trigger;
}
}
if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) {
obj.$thumb = obj.opts.$orig.find('img:first');
}
if (obj.$thumb && !obj.$thumb.length) {
obj.$thumb = null;
}
obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null);
// "caption" is a "special" option, it can be used to customize caption per gallery item
if ($.type(obj.opts.caption) === 'function') {
obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);
}
if ($.type(self.opts.caption) === 'function') {
obj.opts.caption = self.opts.caption.apply(item, [self, obj]);
}
// Make sure we have caption as a string or jQuery object
if (!(obj.opts.caption instanceof $)) {
obj.opts.caption =
obj.opts.caption === undefined ? '' : obj.opts.caption + '';
}
// Check if url contains "filter" used to filter the content
// Example: "ajax.html #something"
if (obj.type === 'ajax') {
srcParts = src.split(/\s+/, 2);
if (srcParts.length > 1) {
obj.src = srcParts.shift();
obj.opts.filter = srcParts.shift();
}
}
// Hide all buttons and disable interactivity for modal items
if (obj.opts.modal) {
obj.opts = $.extend(true, obj.opts, {
trapFocus: true,
// Remove buttons
infobar: 0,
toolbar: 0,
smallBtn: 0,
// Disable keyboard navigation
keyboard: 0,
// Disable some modules
slideShow: 0,
fullScreen: 0,
thumbs: 0,
touch: 0,
// Disable click event handlers
clickContent: false,
clickSlide: false,
clickOutside: false,
dblclickContent: false,
dblclickSlide: false,
dblclickOutside: false,
});
}
// Step 4 - Add processed object to group
// ======================================
self.group.push(obj);
});
// Update controls if gallery is already opened
if (Object.keys(self.slides).length) {
self.updateControls();
// Update thumbnails, if needed
thumbs = self.Thumbs;
if (thumbs && thumbs.isActive) {
thumbs.create();
thumbs.focus();
}
}
},
// Attach an event handler functions for:
// - navigation buttons
// - browser scrolling, resizing;
// - focusing
// - keyboard
// - detecting inactivity
// ======================================
addEvents: function () {
var self = this;
self.removeEvents();
// Make navigation elements clickable
// ==================================
self.$refs.container
.on('click.fb-close', '[data-fancybox-close]', function (e) {
e.stopPropagation();
e.preventDefault();
self.close(e);
})
.on(
'touchstart.fb-prev click.fb-prev',
'[data-fancybox-prev]',
function (e) {
e.stopPropagation();
e.preventDefault();
self.previous();
}
)
.on(
'touchstart.fb-next click.fb-next',
'[data-fancybox-next]',
function (e) {
e.stopPropagation();
e.preventDefault();
self.next();
}
)
.on('click.fb', '[data-fancybox-zoom]', function (e) {
// Click handler for zoom button
self[self.isScaledDown() ? 'scaleToActual' : 'scaleToFit']();
});
// Handle page scrolling and browser resizing
// ==========================================
$W.on('orientationchange.fb resize.fb', function (e) {
if (e && e.originalEvent && e.originalEvent.type === 'resize') {
if (self.requestId) {
cancelAFrame(self.requestId);
}
self.requestId = requestAFrame(function () {
self.update(e);
});
} else {
if (self.current && self.current.type === 'iframe') {
self.$refs.stage.hide();
}
setTimeout(
function () {
self.$refs.stage.show();
self.update(e);
},
$.fancybox.isMobile ? 600 : 250
);
}
});
$D.on('keydown.fb', function (e) {
var instance = $.fancybox ? $.fancybox.getInstance() : null,
current = instance.current,
keycode = e.keyCode || e.which;
// Trap keyboard focus inside of the modal
// =======================================
if (keycode == 9) {
if (current.opts.trapFocus) {
self.focus(e);
}
return;
}
// Enable keyboard navigation
// ==========================
if (
!current.opts.keyboard ||
e.ctrlKey ||
e.altKey ||
e.shiftKey ||
$(e.target).is('input,textarea,video,audio,select')
) {
return;
}
// Backspace and Esc keys
if (keycode === 8 || keycode === 27) {
e.preventDefault();
self.close(e);
return;
}
// Left arrow and Up arrow
if (keycode === 37 || keycode === 38) {
e.preventDefault();
self.previous();
return;
}
// Righ arrow and Down arrow
if (keycode === 39 || keycode === 40) {
e.preventDefault();
self.next();
return;
}
self.trigger('afterKeydown', e, keycode);
});
// Hide controls after some inactivity period
if (self.group[self.currIndex].opts.idleTime) {
self.idleSecondsCounter = 0;
$D.on(
'mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle',
function (e) {
self.idleSecondsCounter = 0;
if (self.isIdle) {
self.showControls();
}
self.isIdle = false;
}
);
self.idleInterval = window.setInterval(function () {
self.idleSecondsCounter++;
if (
self.idleSecondsCounter >=
self.group[self.currIndex].opts.idleTime &&
!self.isDragging
) {
self.isIdle = true;
self.idleSecondsCounter = 0;
self.hideControls();
}
}, 1000);
}
},
// Remove events added by the core
// ===============================
removeEvents: function () {
var self = this;
$W.off('orientationchange.fb resize.fb');
$D.off('keydown.fb .fb-idle');
this.$refs.container.off('.fb-close .fb-prev .fb-next');
if (self.idleInterval) {
window.clearInterval(self.idleInterval);
self.idleInterval = null;
}
},
// Change to previous gallery item
// ===============================
previous: function (duration) {
return this.jumpTo(this.currPos - 1, duration);
},
// Change to next gallery item
// ===========================
next: function (duration) {
return this.jumpTo(this.currPos + 1, duration);
},
// Switch to selected gallery item
// ===============================
jumpTo: function (pos, duration) {
var self = this,
groupLen = self.group.length,
firstRun,
isMoved,
loop,
current,
previous,
slidePos,
stagePos,
prop,
diff;
if (
self.isDragging ||
self.isClosing ||
(self.isAnimating && self.firstRun)
) {
return;
}
// Should loop?
pos = parseInt(pos, 10);
loop = self.current ? self.current.opts.loop : self.opts.loop;
if (!loop && (pos < 0 || pos >= groupLen)) {
return false;
}
// Check if opening for the first time; this helps to speed things up
firstRun = self.firstRun = !Object.keys(self.slides).length;
// Create slides
previous = self.current;
self.prevIndex = self.currIndex;
self.prevPos = self.currPos;
current = self.createSlide(pos);
if (groupLen > 1) {
if (loop || current.index < groupLen - 1) {
self.createSlide(pos + 1);
}
if (loop || current.index > 0) {
self.createSlide(pos - 1);
}
}
self.current = current;
self.currIndex = current.index;
self.currPos = current.pos;
self.trigger('beforeShow', firstRun);
self.updateControls();
// Validate duration length
current.forcedDuration = undefined;
if ($.isNumeric(duration)) {
current.forcedDuration = duration;
} else {
duration =
current.opts[firstRun ? 'animationDuration' : 'transitionDuration'];
}
duration = parseInt(duration, 10);
// Check if user has swiped the slides or if still animating
isMoved = self.isMoved(current);
// Make sure current slide is visible
current.$slide.addClass('fancybox-slide--current');
// Fresh start - reveal container, current slide and start loading content
if (firstRun) {
if (current.opts.animationEffect && duration) {
self.$refs.container.css('transition-duration', duration + 'ms');
}
self.$refs.container.addClass('fancybox-is-open').trigger('focus');
// Attempt to load content into slide
// This will later call `afterLoad` -> `revealContent`
self.loadSlide(current);
self.preload('image');
return;
}
// Get actual slide/stage positions (before cleaning up)
slidePos = $.fancybox.getTranslate(previous.$slide);
stagePos = $.fancybox.getTranslate(self.$refs.stage);
// Clean up all slides
$.each(self.slides, function (index, slide) {
$.fancybox.stop(slide.$slide, true);
});
if (previous.pos !== current.pos) {
previous.isComplete = false;
}
previous.$slide.removeClass(
'fancybox-slide--complete fancybox-slide--current'
);
// If slides are out of place, then animate them to correct position
if (isMoved) {
// Calculate horizontal swipe distance
diff =
slidePos.left -
(previous.pos * slidePos.width + previous.pos * previous.opts.gutter);
$.each(self.slides, function (index, slide) {
slide.$slide
.removeClass('fancybox-animated')
.removeClass(function (index, className) {
return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(
' '
);
});
// Make sure that each slide is in equal distance
// This is mostly needed for freshly added slides, because they are not yet positioned
var leftPos =
slide.pos * slidePos.width + slide.pos * slide.opts.gutter;
$.fancybox.setTranslate(slide.$slide, {
top: 0,
left: leftPos - stagePos.left + diff,
});
if (slide.pos !== current.pos) {
slide.$slide.addClass(
'fancybox-slide--' +
(slide.pos > current.pos ? 'next' : 'previous')
);
}
// Redraw to make sure that transition will start
forceRedraw(slide.$slide);
// Animate the slide
$.fancybox.animate(
slide.$slide,
{
top: 0,
left:
(slide.pos - current.pos) * slidePos.width +
(slide.pos - current.pos) * slide.opts.gutter,
},
duration,
function () {
slide.$slide
.css({
transform: '',
opacity: '',
})
.removeClass('fancybox-slide--next fancybox-slide--previous');
if (slide.pos === self.currPos) {
self.complete();
}
}
);
});
} else if (duration && current.opts.transitionEffect) {
// Set transition effect for previously active slide
prop = 'fancybox-animated fancybox-fx-' + current.opts.transitionEffect;
previous.$slide.addClass(
'fancybox-slide--' +
(previous.pos > current.pos ? 'next' : 'previous')
);
$.fancybox.animate(
previous.$slide,
prop,
duration,
function () {
previous.$slide
.removeClass(prop)
.removeClass('fancybox-slide--next fancybox-slide--previous');
},
false
);
}
if (current.isLoaded) {
self.revealContent(current);
} else {
self.loadSlide(current);
}
self.preload('image');
},
// Create new "slide" element
// These are gallery items that are actually added to DOM
// =======================================================
createSlide: function (pos) {
var self = this,
$slide,
index;
index = pos % self.group.length;
index = index < 0 ? self.group.length + index : index;
if (!self.slides[pos] && self.group[index]) {
$slide = $('<div class="fancybox-slide"></div>').appendTo(
self.$refs.stage
);
self.slides[pos] = $.extend(true, {}, self.group[index], {
pos: pos,
$slide: $slide,
isLoaded: false,
});
self.updateSlide(self.slides[pos]);
}
return self.slides[pos];
},
// Scale image to the actual size of the image;
// x and y values should be relative to the slide
// ==============================================
scaleToActual: function (x, y, duration) {
var self = this,
current = self.current,
$content = current.$content,
canvasWidth = $.fancybox.getTranslate(current.$slide).width,
canvasHeight = $.fancybox.getTranslate(current.$slide).height,
newImgWidth = current.width,
newImgHeight = current.height,
imgPos,
posX,
posY,
scaleX,
scaleY;
if (
self.isAnimating ||
self.isMoved() ||
!$content ||
!(current.type == 'image' && current.isLoaded && !current.hasError)
) {
return;
}
self.isAnimating = true;
$.fancybox.stop($content);
x = x === undefined ? canvasWidth * 0.5 : x;
y = y === undefined ? canvasHeight * 0.5 : y;
imgPos = $.fancybox.getTranslate($content);
imgPos.top -= $.fancybox.getTranslate(current.$slide).top;
imgPos.left -= $.fancybox.getTranslate(current.$slide).left;
scaleX = newImgWidth / imgPos.width;
scaleY = newImgHeight / imgPos.height;
// Get center position for original image
posX = canvasWidth * 0.5 - newImgWidth * 0.5;
posY = canvasHeight * 0.5 - newImgHeight * 0.5;
// Make sure image does not move away from edges
if (newImgWidth > canvasWidth) {
posX = imgPos.left * scaleX - (x * scaleX - x);
if (posX > 0) {
posX = 0;
}
if (posX < canvasWidth - newImgWidth) {
posX = canvasWidth - newImgWidth;
}
}
if (newImgHeight > canvasHeight) {
posY = imgPos.top * scaleY - (y * scaleY - y);
if (posY > 0) {
posY = 0;
}
if (posY < canvasHeight - newImgHeight) {
posY = canvasHeight - newImgHeight;
}
}
self.updateCursor(newImgWidth, newImgHeight);
$.fancybox.animate(
$content,
{
top: posY,
left: posX,
scaleX: scaleX,
scaleY: scaleY,
},
duration || 366,
function () {
self.isAnimating = false;
}
);
// Stop slideshow
if (self.SlideShow && self.SlideShow.isActive) {
self.SlideShow.stop();
}
},
// Scale image to fit inside parent element
// ========================================
scaleToFit: function (duration) {
var self = this,
current = self.current,
$content = current.$content,
end;
if (
self.isAnimating ||
self.isMoved() ||
!$content ||
!(current.type == 'image' && current.isLoaded && !current.hasError)
) {
return;
}
self.isAnimating = true;
$.fancybox.stop($content);
end = self.getFitPos(current);
self.updateCursor(end.width, end.height);
$.fancybox.animate(
$content,
{
top: end.top,
left: end.left,
scaleX: end.width / $content.width(),
scaleY: end.height / $content.height(),
},
duration || 366,
function () {
self.isAnimating = false;
}
);
},
// Calculate image size to fit inside viewport
// ===========================================
getFitPos: function (slide) {
var self = this,
$content = slide.$content,
$slide = slide.$slide,
width = slide.width || slide.opts.width,
height = slide.height || slide.opts.height,
maxWidth,
maxHeight,
minRatio,
aspectRatio,
rez = {};
if (!slide.isLoaded || !$content || !$content.length) {
return false;
}
maxWidth = $.fancybox.getTranslate(self.$refs.stage).width;
maxHeight = $.fancybox.getTranslate(self.$refs.stage).height;
maxWidth -=
parseFloat($slide.css('paddingLeft')) +
parseFloat($slide.css('paddingRight')) +
parseFloat($content.css('marginLeft')) +
parseFloat($content.css('marginRight'));
maxHeight -=
parseFloat($slide.css('paddingTop')) +
parseFloat($slide.css('paddingBottom')) +
parseFloat($content.css('marginTop')) +
parseFloat($content.css('marginBottom'));
if (!width || !height) {
width = maxWidth;
height = maxHeight;
}
minRatio = Math.min(1, maxWidth / width, maxHeight / height);
width = minRatio * width;
height = minRatio * height;
// Adjust width/height to precisely fit into container
if (width > maxWidth - 0.5) {
width = maxWidth;
}
if (height > maxHeight - 0.5) {
height = maxHeight;
}
if (slide.type === 'image') {
rez.top =
Math.floor((maxHeight - height) * 0.5) +
parseFloat($slide.css('paddingTop'));
rez.left =
Math.floor((maxWidth - width) * 0.5) +
parseFloat($slide.css('paddingLeft'));
} else if (slide.contentType === 'video') {
// Force aspect ratio for the video
// "I say the whole world must learn of our peaceful ways… by force!"
aspectRatio =
slide.opts.width && slide.opts.height
? width / height
: slide.opts.ratio || 16 / 9;
if (height > width / aspectRatio) {
height = width / aspectRatio;
} else if (width > height * aspectRatio) {
width = height * aspectRatio;
}
}
rez.width = width;
rez.height = height;
return rez;
},
// Update content size and position for all slides
// ==============================================
update: function (e) {
var self = this;
$.each(self.slides, function (key, slide) {
self.updateSlide(slide, e);
});
},
// Update slide content position and size
// ======================================
updateSlide: function (slide, e) {
var self = this,
$content = slide && slide.$content,
width = slide.width || slide.opts.width,
height = slide.height || slide.opts.height,
$slide = slide.$slide;
// First, prevent caption overlap, if needed
self.adjustCaption(slide);
// Then resize content to fit inside the slide
if (
$content &&
(width || height || slide.contentType === 'video') &&
!slide.hasError
) {
$.fancybox.stop($content);
$.fancybox.setTranslate($content, self.getFitPos(slide));
if (slide.pos === self.currPos) {
self.isAnimating = false;
self.updateCursor();
}
}
// Then some adjustments
self.adjustLayout(slide);
if ($slide.length) {
$slide.trigger('refresh');
if (slide.pos === self.currPos) {
self.$refs.toolbar
.add(self.$refs.navigation.find('.fancybox-button--arrow_right'))
.toggleClass(
'compensate-for-scrollbar',
$slide.get(0).scrollHeight > $slide.get(0).clientHeight
);
}
}
self.trigger('onUpdate', slide, e);
},
// Horizontally center slide
// =========================
centerSlide: function (duration) {
var self = this,
current = self.current,
$slide = current.$slide;
if (self.isClosing || !current) {
return;
}
$slide.siblings().css({
transform: '',
opacity: '',
});
$slide
.parent()
.children()
.removeClass('fancybox-slide--previous fancybox-slide--next');
$.fancybox.animate(
$slide,
{
top: 0,
left: 0,
opacity: 1,
},
duration === undefined ? 0 : duration,
function () {
// Clean up
$slide.css({
transform: '',
opacity: '',
});
if (!current.isComplete) {
self.complete();
}
},
false
);
},
// Check if current slide is moved (swiped)
// ========================================
isMoved: function (slide) {
var current = slide || this.current,
slidePos,
stagePos;
if (!current) {
return false;
}
stagePos = $.fancybox.getTranslate(this.$refs.stage);
slidePos = $.fancybox.getTranslate(current.$slide);
return (
!current.$slide.hasClass('fancybox-animated') &&
(Math.abs(slidePos.top - stagePos.top) > 0.5 ||
Math.abs(slidePos.left - stagePos.left) > 0.5)
);
},
// Update cursor style depending if content can be zoomed
// ======================================================
updateCursor: function (nextWidth, nextHeight) {
var self = this,
current = self.current,
$container = self.$refs.container,
canPan,
isZoomable;
if (!current || self.isClosing || !self.Guestures) {
return;
}
$container.removeClass(
'fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan'
);
canPan = self.canPan(nextWidth, nextHeight);
isZoomable = canPan ? true : self.isZoomable();
$container.toggleClass('fancybox-is-zoomable', isZoomable);
$('[data-fancybox-zoom]').prop('disabled', !isZoomable);
if (canPan) {
$container.addClass('fancybox-can-pan');
} else if (
isZoomable &&
(current.opts.clickContent === 'zoom' ||
($.isFunction(current.opts.clickContent) &&
current.opts.clickContent(current) == 'zoom'))
) {
$container.addClass('fancybox-can-zoomIn');
} else if (
current.opts.touch &&
(current.opts.touch.vertical || self.group.length > 1) &&
current.contentType !== 'video'
) {
$container.addClass('fancybox-can-swipe');
}
},
// Check if current slide is zoomable
// ==================================
isZoomable: function () {
var self = this,
current = self.current,
fitPos;
// Assume that slide is zoomable if:
// - image is still loading
// - actual size of the image is smaller than available area
if (
current &&
!self.isClosing &&
current.type === 'image' &&
!current.hasError
) {
if (!current.isLoaded) {
return true;
}
fitPos = self.getFitPos(current);
if (
fitPos &&
(current.width > fitPos.width || current.height > fitPos.height)
) {
return true;
}
}
return false;
},
// Check if current image dimensions are smaller than actual
// =========================================================
isScaledDown: function (nextWidth, nextHeight) {
var self = this,
rez = false,
current = self.current,
$content = current.$content;
if (nextWidth !== undefined && nextHeight !== undefined) {
rez = nextWidth < current.width && nextHeight < current.height;
} else if ($content) {
rez = $.fancybox.getTranslate($content);
rez = rez.width < current.width && rez.height < current.height;
}
return rez;
},
// Check if image dimensions exceed parent element
// ===============================================
canPan: function (nextWidth, nextHeight) {
var self = this,
current = self.current,
pos = null,
rez = false;
if (
current.type === 'image' &&
(current.isComplete || (nextWidth && nextHeight)) &&
!current.hasError
) {
rez = self.getFitPos(current);
if (nextWidth !== undefined && nextHeight !== undefined) {
pos = {
width: nextWidth,
height: nextHeight,
};
} else if (current.isComplete) {
pos = $.fancybox.getTranslate(current.$content);
}
if (pos && rez) {
rez =
Math.abs(pos.width - rez.width) > 1.5 ||
Math.abs(pos.height - rez.height) > 1.5;
}
}
return rez;
},
// Load content into the slide
// ===========================
loadSlide: function (slide) {
var self = this,
type,
$slide,
ajaxLoad;
if (slide.isLoading || slide.isLoaded) {
return;
}
slide.isLoading = true;
if (self.trigger('beforeLoad', slide) === false) {
slide.isLoading = false;
return false;
}
type = slide.type;
$slide = slide.$slide;
$slide.off('refresh').trigger('onReset').addClass(slide.opts.slideClass);
// Create content depending on the type
switch (type) {
case 'image':
self.setImage(slide);
break;
case 'iframe':
self.setIframe(slide);
break;
case 'html':
self.setContent(slide, slide.src || slide.content);
break;
case 'video':
self.setContent(
slide,
slide.opts.video.tpl
.replace(/\{\{src\}\}/gi, slide.src)
.replace(
'{{format}}',
slide.opts.videoFormat || slide.opts.video.format || ''
)
.replace('{{poster}}', slide.thumb || '')
);
break;
case 'inline':
if ($(slide.src).length) {
self.setContent(slide, $(slide.src));
} else {
self.setError(slide);
}
break;
case 'ajax':
self.showLoading(slide);
ajaxLoad = $.ajax(
$.extend({}, slide.opts.ajax.settings, {
url: slide.src,
success: function (data, textStatus) {
if (textStatus === 'success') {
self.setContent(slide, data);
}
},
error: function (jqXHR, textStatus) {
if (jqXHR && textStatus !== 'abort') {
self.setError(slide);
}
},
})
);
$slide.one('onReset', function () {
ajaxLoad.abort();
});
break;
default:
self.setError(slide);
break;
}
return true;
},
// Use thumbnail image, if possible
// ================================
setImage: function (slide) {
var self = this,
ghost;
// Check if need to show loading icon
setTimeout(function () {
var $img = slide.$image;
if (
!self.isClosing &&
slide.isLoading &&
(!$img || !$img.length || !$img[0].complete) &&
!slide.hasError
) {
self.showLoading(slide);
}
}, 50);
//Check if image has srcset
self.checkSrcset(slide);
// This will be wrapper containing both ghost and actual image
slide.$content = $('<div class="fancybox-content"></div>')
.addClass('fancybox-is-hidden')
.appendTo(slide.$slide.addClass('fancybox-slide--image'));
// If we have a thumbnail, we can display it while actual image is loading
// Users will not stare at black screen and actual image will appear gradually
if (
slide.opts.preload !== false &&
slide.opts.width &&
slide.opts.height &&
slide.thumb
) {
slide.width = slide.opts.width;
slide.height = slide.opts.height;
ghost = document.createElement('img');
ghost.onerror = function () {
$(this).remove();
slide.$ghost = null;
};
ghost.onload = function () {
self.afterLoad(slide);
};
slide.$ghost = $(ghost)
.addClass('fancybox-image')
.appendTo(slide.$content)
.attr('src', slide.thumb);
}
// Start loading actual image
self.setBigImage(slide);
},
// Check if image has srcset and get the source
// ============================================
checkSrcset: function (slide) {
var srcset = slide.opts.srcset || slide.opts.image.srcset,
found,
temp,
pxRatio,
windowWidth;
// If we have "srcset", then we need to find first matching "src" value.
// This is necessary, because when you set an src attribute, the browser will preload the image
// before any javascript or even CSS is applied.
if (srcset) {
pxRatio = window.devicePixelRatio || 1;
windowWidth = window.innerWidth * pxRatio;
temp = srcset.split(',').map(function (el) {
var ret = {};
el.trim()
.split(/\s+/)
.forEach(function (el, i) {
var value = parseInt(el.substring(0, el.length - 1), 10);
if (i === 0) {
return (ret.url = el);
}
if (value) {
ret.value = value;
ret.postfix = el[el.length - 1];
}
});
return ret;
});
// Sort by value
temp.sort(function (a, b) {
return a.value - b.value;
});
// Ok, now we have an array of all srcset values
for (var j = 0; j < temp.length; j++) {
var el = temp[j];
if (
(el.postfix === 'w' && el.value >= windowWidth) ||
(el.postfix === 'x' && el.value >= pxRatio)
) {
found = el;
break;
}
}
// If not found, take the last one
if (!found && temp.length) {
found = temp[temp.length - 1];
}
if (found) {
slide.src = found.url;
// If we have default width/height values, we can calculate height for matching source
if (slide.width && slide.height && found.postfix == 'w') {
slide.height = (slide.width / slide.height) * found.value;
slide.width = found.value;
}
slide.opts.srcset = srcset;
}
}
},
// Create full-size image
// ======================
setBigImage: function (slide) {
var self = this,
img = document.createElement('img'),
$img = $(img);
slide.$image = $img
.one('error', function () {
self.setError(slide);
})
.one('load', function () {
var sizes;
if (!slide.$ghost) {
self.resolveImageSlideSize(
slide,
this.naturalWidth,
this.naturalHeight
);
self.afterLoad(slide);
}
if (self.isClosing) {
return;
}
if (slide.opts.srcset) {
sizes = slide.opts.sizes;
if (!sizes || sizes === 'auto') {
sizes =
(slide.width / slide.height > 1 && $W.width() / $W.height() > 1
? '100'
: Math.round((slide.width / slide.height) * 100)) + 'vw';
}
$img.attr('sizes', sizes).attr('srcset', slide.opts.srcset);
}
// Hide temporary image after some delay
if (slide.$ghost) {
setTimeout(function () {
if (slide.$ghost && !self.isClosing) {
slide.$ghost.hide();
}
}, Math.min(300, Math.max(1000, slide.height / 1600)));
}
self.hideLoading(slide);
})
.addClass('fancybox-image')
.attr('src', slide.src)
.appendTo(slide.$content);
if (
(img.complete || img.readyState == 'complete') &&
$img.naturalWidth &&
$img.naturalHeight
) {
$img.trigger('load');
} else if (img.error) {
$img.trigger('error');
}
},
// Computes the slide size from image size and maxWidth/maxHeight
// ==============================================================
resolveImageSlideSize: function (slide, imgWidth, imgHeight) {
var maxWidth = parseInt(slide.opts.width, 10),
maxHeight = parseInt(slide.opts.height, 10);
// Sets the default values from the image
slide.width = imgWidth;
slide.height = imgHeight;
if (maxWidth > 0) {
slide.width = maxWidth;
slide.height = Math.floor((maxWidth * imgHeight) / imgWidth);
}
if (maxHeight > 0) {
slide.width = Math.floor((maxHeight * imgWidth) / imgHeight);
slide.height = maxHeight;
}
},
// Create iframe wrapper, iframe and bindings
// ==========================================
setIframe: function (slide) {
var self = this,
opts = slide.opts.iframe,
$slide = slide.$slide,
$iframe;
slide.$content = $(
'<div class="fancybox-content' +
(opts.preload ? ' fancybox-is-hidden' : '') +
'"></div>'
)
.css(opts.css)
.appendTo($slide);
$slide.addClass('fancybox-slide--' + slide.contentType);
slide.$iframe = $iframe = $(
opts.tpl.replace(/\{rnd\}/g, new Date().getTime())
)
.attr(opts.attr)
.appendTo(slide.$content);
if (opts.preload) {
self.showLoading(slide);
// Unfortunately, it is not always possible to determine if iframe is successfully loaded
// (due to browser security policy)
$iframe.on('load.fb error.fb', function (e) {
this.isReady = 1;
slide.$slide.trigger('refresh');
self.afterLoad(slide);
});
// Recalculate iframe content size
// ===============================
$slide.on('refresh.fb', function () {
var $content = slide.$content,
frameWidth = opts.css.width,
frameHeight = opts.css.height,
$contents,
$body;
if ($iframe[0].isReady !== 1) {
return;
}
try {
$contents = $iframe.contents();
$body = $contents.find('body');
} catch (ignore) {}
// Calculate content dimensions, if it is accessible
if ($body && $body.length && $body.children().length) {
// Avoid scrolling to top (if multiple instances)
$slide.css('overflow', 'visible');
$content.css({
width: '100%',
'max-width': '100%',
height: '9999px',
});
if (frameWidth === undefined) {
frameWidth = Math.ceil(
Math.max($body[0].clientWidth, $body.outerWidth(true))
);
}
$content
.css('width', frameWidth ? frameWidth : '')
.css('max-width', '');
if (frameHeight === undefined) {
frameHeight = Math.ceil(
Math.max($body[0].clientHeight, $body.outerHeight(true))
);
}
$content.css('height', frameHeight ? frameHeight : '');
$slide.css('overflow', 'auto');
}
$content.removeClass('fancybox-is-hidden');
});
} else {
self.afterLoad(slide);
}
$iframe.attr('src', slide.src);
// Remove iframe if closing or changing gallery item
$slide.one('onReset', function () {
// This helps IE not to throw errors when closing
try {
$(this).find('iframe').hide().unbind().attr('src', '//about:blank');
} catch (ignore) {}
$(this).off('refresh.fb').empty();
slide.isLoaded = false;
slide.isRevealed = false;
});
},
// Wrap and append content to the slide
// ======================================
setContent: function (slide, content) {
var self = this;
if (self.isClosing) {
return;
}
self.hideLoading(slide);
if (slide.$content) {
$.fancybox.stop(slide.$content);
}
slide.$slide.empty();
// If content is a jQuery object, then it will be moved to the slide.
// The placeholder is created so we will know where to put it back.
if (isQuery(content) && content.parent().length) {
// Make sure content is not already moved to fancyBox
if (
content.hasClass('fancybox-content') ||
content.parent().hasClass('fancybox-content')
) {
content.parents('.fancybox-slide').trigger('onReset');
}
// Create temporary element marking original place of the content
slide.$placeholder = $('<div>').hide().insertAfter(content);
// Make sure content is visible
content.css('display', 'inline-block');
} else if (!slide.hasError) {
// If content is just a plain text, try to convert it to html
if ($.type(content) === 'string') {
content = $('<div>').append($.trim(content)).contents();
}
// If "filter" option is provided, then filter content
if (slide.opts.filter) {
content = $('<div>').html(content).find(slide.opts.filter);
}
}
slide.$slide.one('onReset', function () {
// Pause all html5 video/audio
$(this).find('video,audio').trigger('pause');
// Put content back
if (slide.$placeholder) {
slide.$placeholder
.after(content.removeClass('fancybox-content').hide())
.remove();
slide.$placeholder = null;
}
// Remove custom close button
if (slide.$smallBtn) {
slide.$smallBtn.remove();
slide.$smallBtn = null;
}
// Remove content and mark slide as not loaded
if (!slide.hasError) {
$(this).empty();
slide.isLoaded = false;
slide.isRevealed = false;
}
});
$(content).appendTo(slide.$slide);
if ($(content).is('video,audio')) {
$(content).addClass('fancybox-video');
$(content).wrap('<div></div>');
slide.contentType = 'video';
slide.opts.width = slide.opts.width || $(content).attr('width');
slide.opts.height = slide.opts.height || $(content).attr('height');
}
slide.$content = slide.$slide
.children()
.filter('div,form,main,video,audio,article,.fancybox-content')
.first();
slide.$content.siblings().hide();
// Re-check if there is a valid content
// (in some cases, ajax response can contain various elements or plain text)
if (!slide.$content.length) {
slide.$content = slide.$slide
.wrapInner('<div></div>')
.children()
.first();
}
slide.$content.addClass('fancybox-content');
slide.$slide.addClass('fancybox-slide--' + slide.contentType);
self.afterLoad(slide);
},
// Display error message
// =====================
setError: function (slide) {
slide.hasError = true;
slide.$slide
.trigger('onReset')
.removeClass('fancybox-slide--' + slide.contentType)
.addClass('fancybox-slide--error');
slide.contentType = 'html';
this.setContent(slide, this.translate(slide, slide.opts.errorTpl));
if (slide.pos === this.currPos) {
this.isAnimating = false;
}
},
// Show loading icon inside the slide
// ==================================
showLoading: function (slide) {
var self = this;
slide = slide || self.current;
if (slide && !slide.$spinner) {
slide.$spinner = $(self.translate(self, self.opts.spinnerTpl))
.appendTo(slide.$slide)
.hide()
.fadeIn('fast');
}
},
// Remove loading icon from the slide
// ==================================
hideLoading: function (slide) {
var self = this;
slide = slide || self.current;
if (slide && slide.$spinner) {
slide.$spinner.stop().remove();
delete slide.$spinner;
}
},
// Adjustments after slide content has been loaded
// ===============================================
afterLoad: function (slide) {
var self = this;
if (self.isClosing) {
return;
}
slide.isLoading = false;
slide.isLoaded = true;
self.trigger('afterLoad', slide);
self.hideLoading(slide);
// Add small close button
if (
slide.opts.smallBtn &&
(!slide.$smallBtn || !slide.$smallBtn.length)
) {
slide.$smallBtn = $(
self.translate(slide, slide.opts.btnTpl.smallBtn)
).appendTo(slide.$content);
}
// Disable right click
if (slide.opts.protect && slide.$content && !slide.hasError) {
slide.$content.on('contextmenu.fb', function (e) {
if (e.button == 2) {
e.preventDefault();
}
return true;
});
// Add fake element on top of the image
// This makes a bit harder for user to select image
if (slide.type === 'image') {
$('<div class="fancybox-spaceball"></div>').appendTo(slide.$content);
}
}
self.adjustCaption(slide);
self.adjustLayout(slide);
if (slide.pos === self.currPos) {
self.updateCursor();
}
self.revealContent(slide);
},
// Prevent caption overlap,
// fix css inconsistency across browsers
// =====================================
adjustCaption: function (slide) {
var self = this,
current = slide || self.current,
caption = current.opts.caption,
preventOverlap = current.opts.preventCaptionOverlap,
$caption = self.$refs.caption,
$clone,
captionH = false;
$caption.toggleClass('fancybox-caption--separate', preventOverlap);
if (preventOverlap && caption && caption.length) {
if (current.pos !== self.currPos) {
$clone = $caption.clone().appendTo($caption.parent());
$clone.children().eq(0).empty().html(caption);
captionH = $clone.outerHeight(true);
$clone.empty().remove();
} else if (self.$caption) {
captionH = self.$caption.outerHeight(true);
}
current.$slide.css('padding-bottom', captionH || '');
}
},
// Simple hack to fix inconsistency across browsers, described here (affects Edge, too):
// https://bugzilla.mozilla.org/show_bug.cgi?id=748518
// ====================================================================================
adjustLayout: function (slide) {
var self = this,
current = slide || self.current,
scrollHeight,
marginBottom,
inlinePadding,
actualPadding;
if (current.isLoaded && current.opts.disableLayoutFix !== true) {
current.$content.css('margin-bottom', '');
// If we would always set margin-bottom for the content,
// then it would potentially break vertical align
if (current.$content.outerHeight() > current.$slide.height() + 0.5) {
inlinePadding = current.$slide[0].style['padding-bottom'];
actualPadding = current.$slide.css('padding-bottom');
if (parseFloat(actualPadding) > 0) {
scrollHeight = current.$slide[0].scrollHeight;
current.$slide.css('padding-bottom', 0);
if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) {
marginBottom = actualPadding;
}
current.$slide.css('padding-bottom', inlinePadding);
}
}
current.$content.css('margin-bottom', marginBottom);
}
},
// Make content visible
// This method is called right after content has been loaded or
// user navigates gallery and transition should start
// ============================================================
revealContent: function (slide) {
var self = this,
$slide = slide.$slide,
end = false,
start = false,
isMoved = self.isMoved(slide),
isRevealed = slide.isRevealed,
effect,
effectClassName,
duration,
opacity;
slide.isRevealed = true;
effect =
slide.opts[self.firstRun ? 'animationEffect' : 'transitionEffect'];
duration =
slide.opts[self.firstRun ? 'animationDuration' : 'transitionDuration'];
duration = parseInt(
slide.forcedDuration === undefined ? duration : slide.forcedDuration,
10
);
if (isMoved || slide.pos !== self.currPos || !duration) {
effect = false;
}
// Check if can zoom
if (effect === 'zoom') {
if (
slide.pos === self.currPos &&
duration &&
slide.type === 'image' &&
!slide.hasError &&
(start = self.getThumbPos(slide))
) {
end = self.getFitPos(slide);
} else {
effect = 'fade';
}
}
// Zoom animation
// ==============
if (effect === 'zoom') {
self.isAnimating = true;
end.scaleX = end.width / start.width;
end.scaleY = end.height / start.height;
// Check if we need to animate opacity
opacity = slide.opts.zoomOpacity;
if (opacity == 'auto') {
opacity =
Math.abs(slide.width / slide.height - start.width / start.height) >
0.1;
}
if (opacity) {
start.opacity = 0.1;
end.opacity = 1;
}
// Draw image at start position
$.fancybox.setTranslate(
slide.$content.removeClass('fancybox-is-hidden'),
start
);
forceRedraw(slide.$content);
// Start animation
$.fancybox.animate(slide.$content, end, duration, function () {
self.isAnimating = false;
self.complete();
});
return;
}
self.updateSlide(slide);
// Simply show content if no effect
// ================================
if (!effect) {
slide.$content.removeClass('fancybox-is-hidden');
if (
!isRevealed &&
isMoved &&
slide.type === 'image' &&
!slide.hasError
) {
slide.$content.hide().fadeIn('fast');
}
if (slide.pos === self.currPos) {
self.complete();
}
return;
}
// Prepare for CSS transiton
// =========================
$.fancybox.stop($slide);
//effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect;
effectClassName =
'fancybox-slide--' +
(slide.pos >= self.prevPos ? 'next' : 'previous') +
' fancybox-animated fancybox-fx-' +
effect;
$slide.addClass(effectClassName).removeClass('fancybox-slide--current'); //.addClass(effectClassName);
slide.$content.removeClass('fancybox-is-hidden');
// Force reflow
forceRedraw($slide);
if (slide.type !== 'image') {
slide.$content.hide().show(0);
}
$.fancybox.animate(
$slide,
'fancybox-slide--current',
duration,
function () {
$slide.removeClass(effectClassName).css({
transform: '',
opacity: '',
});
if (slide.pos === self.currPos) {
self.complete();
}
},
true
);
},
// Check if we can and have to zoom from thumbnail
//================================================
getThumbPos: function (slide) {
var rez = false,
$thumb = slide.$thumb,
thumbPos,
btw,
brw,
bbw,
blw;
if (!$thumb || !inViewport($thumb[0])) {
return false;
}
thumbPos = $.fancybox.getTranslate($thumb);
btw = parseFloat($thumb.css('border-top-width') || 0);
brw = parseFloat($thumb.css('border-right-width') || 0);
bbw = parseFloat($thumb.css('border-bottom-width') || 0);
blw = parseFloat($thumb.css('border-left-width') || 0);
rez = {
top: thumbPos.top + btw,
left: thumbPos.left + blw,
width: thumbPos.width - brw - blw,
height: thumbPos.height - btw - bbw,
scaleX: 1,
scaleY: 1,
};
return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false;
},
// Final adjustments after current gallery item is moved to position
// and it`s content is loaded
// ==================================================================
complete: function () {
var self = this,
current = self.current,
slides = {},
$el;
if (self.isMoved() || !current.isLoaded) {
return;
}
if (!current.isComplete) {
current.isComplete = true;
current.$slide.siblings().trigger('onReset');
self.preload('inline');
// Trigger any CSS transiton inside the slide
forceRedraw(current.$slide);
current.$slide.addClass('fancybox-slide--complete');
// Remove unnecessary slides
$.each(self.slides, function (key, slide) {
if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {
slides[slide.pos] = slide;
} else if (slide) {
$.fancybox.stop(slide.$slide);
slide.$slide.off().remove();
}
});
self.slides = slides;
}
self.isAnimating = false;
self.updateCursor();
self.trigger('afterShow');
// Autoplay first html5 video/audio
if (!!current.opts.video.autoStart) {
current.$slide
.find('video,audio')
.filter(':visible:first')
.trigger('play')
.one('ended', function () {
if (Document.exitFullscreen) {
Document.exitFullscreen();
} else if (this.webkitExitFullscreen) {
this.webkitExitFullscreen();
}
self.next();
});
}
// Try to focus on the first focusable element
if (current.opts.autoFocus && current.contentType === 'html') {
// Look for the first input with autofocus attribute
$el = current.$content.find('input[autofocus]:enabled:visible:first');
if ($el.length) {
$el.trigger('focus');
} else {
self.focus(null, true);
}
}
// Avoid jumping
current.$slide.scrollTop(0).scrollLeft(0);
},
// Preload next and previous slides
// ================================
preload: function (type) {
var self = this,
prev,
next;
if (self.group.length < 2) {
return;
}
next = self.slides[self.currPos + 1];
prev = self.slides[self.currPos - 1];
if (prev && prev.type === type) {
self.loadSlide(prev);
}
if (next && next.type === type) {
self.loadSlide(next);
}
},
// Try to find and focus on the first focusable element
// ====================================================
focus: function (e, firstRun) {
var self = this,
focusableStr = [
'a[href]',
'area[href]',
'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
'select:not([disabled]):not([aria-hidden])',
'textarea:not([disabled]):not([aria-hidden])',
'button:not([disabled]):not([aria-hidden])',
'iframe',
'object',
'embed',
'video',
'audio',
'[contenteditable]',
'[tabindex]:not([tabindex^="-"])',
].join(','),
focusableItems,
focusedItemIndex;
if (self.isClosing) {
return;
}
if (e || !self.current || !self.current.isComplete) {
// Focus on any element inside fancybox
focusableItems = self.$refs.container.find('*:visible');
} else {
// Focus inside current slide
focusableItems = self.current.$slide.find(
'*:visible' + (firstRun ? ':not(.fancybox-close-small)' : '')
);
}
focusableItems = focusableItems.filter(focusableStr).filter(function () {
return (
$(this).css('visibility') !== 'hidden' &&
!$(this).hasClass('disabled')
);
});
if (focusableItems.length) {
focusedItemIndex = focusableItems.index(document.activeElement);
if (e && e.shiftKey) {
// Back tab
if (focusedItemIndex < 0 || focusedItemIndex == 0) {
e.preventDefault();
focusableItems.eq(focusableItems.length - 1).trigger('focus');
}
} else {
// Outside or Forward tab
if (
focusedItemIndex < 0 ||
focusedItemIndex == focusableItems.length - 1
) {
if (e) {
e.preventDefault();
}
focusableItems.eq(0).trigger('focus');
}
}
} else {
self.$refs.container.trigger('focus');
}
},
// Activates current instance - brings container to the front and enables keyboard,
// notifies other instances about deactivating
// =================================================================================
activate: function () {
var self = this;
// Deactivate all instances
$('.fancybox-container').each(function () {
var instance = $(this).data('FancyBox');
// Skip self and closing instances
if (instance && instance.id !== self.id && !instance.isClosing) {
instance.trigger('onDeactivate');
instance.removeEvents();
instance.isVisible = false;
}
});
self.isVisible = true;
if (self.current || self.isIdle) {
self.update();
self.updateControls();
}
self.trigger('onActivate');
self.addEvents();
},
// Start closing procedure
// This will start "zoom-out" animation if needed and clean everything up afterwards
// =================================================================================
close: function (e, d) {
var self = this,
current = self.current,
effect,
duration,
$content,
domRect,
opacity,
start,
end;
var done = function () {
self.cleanUp(e);
};
if (self.isClosing) {
return false;
}
self.isClosing = true;
// If beforeClose callback prevents closing, make sure content is centered
if (self.trigger('beforeClose', e) === false) {
self.isClosing = false;
requestAFrame(function () {
self.update();
});
return false;
}
// Remove all events
// If there are multiple instances, they will be set again by "activate" method
self.removeEvents();
$content = current.$content;
effect = current.opts.animationEffect;
duration = $.isNumeric(d)
? d
: effect
? current.opts.animationDuration
: 0;
current.$slide.removeClass(
'fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated'
);
if (e !== true) {
$.fancybox.stop(current.$slide);
} else {
effect = false;
}
// Remove other slides
current.$slide.siblings().trigger('onReset').remove();
// Trigger animations
if (duration) {
self.$refs.container
.removeClass('fancybox-is-open')
.addClass('fancybox-is-closing')
.css('transition-duration', duration + 'ms');
}
// Clean up
self.hideLoading(current);
self.hideControls(true);
self.updateCursor();
// Check if possible to zoom-out
if (
effect === 'zoom' &&
!(
$content &&
duration &&
current.type === 'image' &&
!self.isMoved() &&
!current.hasError &&
(end = self.getThumbPos(current))
)
) {
effect = 'fade';
}
if (effect === 'zoom') {
$.fancybox.stop($content);
domRect = $.fancybox.getTranslate($content);
start = {
top: domRect.top,
left: domRect.left,
scaleX: domRect.width / end.width,
scaleY: domRect.height / end.height,
width: end.width,
height: end.height,
};
// Check if we need to animate opacity
opacity = current.opts.zoomOpacity;
if (opacity == 'auto') {
opacity =
Math.abs(current.width / current.height - end.width / end.height) >
0.1;
}
if (opacity) {
end.opacity = 0;
}
$.fancybox.setTranslate($content, start);
forceRedraw($content);
$.fancybox.animate($content, end, duration, done);
return true;
}
if (effect && duration) {
$.fancybox.animate(
current.$slide
.addClass('fancybox-slide--previous')
.removeClass('fancybox-slide--current'),
'fancybox-animated fancybox-fx-' + effect,
duration,
done
);
} else {
// If skip animation
if (e === true) {
setTimeout(done, duration);
} else {
done();
}
}
return true;
},
// Final adjustments after removing the instance
// =============================================
cleanUp: function (e) {
var self = this,
instance,
$focus = self.current.opts.$orig,
x,
y;
self.current.$slide.trigger('onReset');
self.$refs.container.empty().remove();
self.trigger('afterClose', e);
// Place back focus
if (!!self.current.opts.backFocus) {
if (!$focus || !$focus.length || !$focus.is(':visible')) {
$focus = self.$trigger;
}
if ($focus && $focus.length) {
x = window.scrollX;
y = window.scrollY;
$focus.trigger('focus');
$('html, body').scrollTop(y).scrollLeft(x);
}
}
self.current = null;
// Check if there are other instances
instance = $.fancybox.getInstance();
if (instance) {
instance.activate();
} else {
$('body').removeClass('fancybox-active compensate-for-scrollbar');
$('#fancybox-style-noscroll').remove();
}
},
// Call callback and trigger an event
// ==================================
trigger: function (name, slide) {
var args = Array.prototype.slice.call(arguments, 1),
self = this,
obj = slide && slide.opts ? slide : self.current,
rez;
if (obj) {
args.unshift(obj);
} else {
obj = self;
}
args.unshift(self);
if ($.isFunction(obj.opts[name])) {
rez = obj.opts[name].apply(obj, args);
}
if (rez === false) {
return rez;
}
if (name === 'afterClose' || !self.$refs) {
$D.trigger(name + '.fb', args);
} else {
self.$refs.container.trigger(name + '.fb', args);
}
},
// Update infobar values, navigation button states and reveal caption
// ==================================================================
updateControls: function () {
var self = this,
current = self.current,
index = current.index,
$container = self.$refs.container,
$caption = self.$refs.caption,
caption = current.opts.caption;
// Recalculate content dimensions
current.$slide.trigger('refresh');
// Set caption
if (caption && caption.length) {
self.$caption = $caption;
$caption.children().eq(0).html(caption);
} else {
self.$caption = null;
}
if (!self.hasHiddenControls && !self.isIdle) {
self.showControls();
}
// Update info and navigation elements
$container.find('[data-fancybox-count]').html(self.group.length);
$container.find('[data-fancybox-index]').html(index + 1);
$container
.find('[data-fancybox-prev]')
.prop('disabled', !current.opts.loop && index <= 0);
$container
.find('[data-fancybox-next]')
.prop('disabled', !current.opts.loop && index >= self.group.length - 1);
if (current.type === 'image') {
// Re-enable buttons; update download button source
$container
.find('[data-fancybox-zoom]')
.show()
.end()
.find('[data-fancybox-download]')
.attr('href', current.opts.image.src || current.src)
.show();
} else if (current.opts.toolbar) {
$container.find('[data-fancybox-download],[data-fancybox-zoom]').hide();
}
// Make sure focus is not on disabled button/element
if ($(document.activeElement).is(':hidden,[disabled]')) {
self.$refs.container.trigger('focus');
}
},
// Hide toolbar and caption
// ========================
hideControls: function (andCaption) {
var self = this,
arr = ['infobar', 'toolbar', 'nav'];
if (andCaption || !self.current.opts.preventCaptionOverlap) {
arr.push('caption');
}
this.$refs.container.removeClass(
arr
.map(function (i) {
return 'fancybox-show-' + i;
})
.join(' ')
);
this.hasHiddenControls = true;
},
showControls: function () {
var self = this,
opts = self.current ? self.current.opts : self.opts,
$container = self.$refs.container;
self.hasHiddenControls = false;
self.idleSecondsCounter = 0;
$container
.toggleClass('fancybox-show-toolbar', !!(opts.toolbar && opts.buttons))
.toggleClass(
'fancybox-show-infobar',
!!(opts.infobar && self.group.length > 1)
)
.toggleClass('fancybox-show-caption', !!self.$caption)
.toggleClass(
'fancybox-show-nav',
!!(opts.arrows && self.group.length > 1)
)
.toggleClass('fancybox-is-modal', !!opts.modal);
},
// Toggle toolbar and caption
// ==========================
toggleControls: function () {
if (this.hasHiddenControls) {
this.showControls();
} else {
this.hideControls();
}
},
});
$.fancybox = {
version: '3.5.7',
defaults: defaults,
// Get current instance and execute a command.
//
// Examples of usage:
//
// $instance = $.fancybox.getInstance();
// $.fancybox.getInstance().jumpTo( 1 );
// $.fancybox.getInstance( 'jumpTo', 1 );
// $.fancybox.getInstance( function() {
// console.info( this.currIndex );
// });
// ======================================================
getInstance: function (command) {
var instance = $(
'.fancybox-container:not(".fancybox-is-closing"):last'
).data('FancyBox'),
args = Array.prototype.slice.call(arguments, 1);
if (instance instanceof FancyBox) {
if ($.type(command) === 'string') {
instance[command].apply(instance, args);
} else if ($.type(command) === 'function') {
command.apply(instance, args);
}
return instance;
}
return false;
},
// Create new instance
// ===================
open: function (items, opts, index) {
return new FancyBox(items, opts, index);
},
// Close current or all instances
// ==============================
close: function (all) {
var instance = this.getInstance();
if (instance) {
instance.close();
// Try to find and close next instance
if (all === true) {
this.close(all);
}
}
},
// Close all instances and unbind all events
// =========================================
destroy: function () {
this.close(true);
$D.add('body').off('click.fb-start', '**');
},
// Try to detect mobile devices
// ============================
isMobile:
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
),
// Detect if 'translate3d' support is available
// ============================================
use3d: (function () {
var div = document.createElement('div');
return (
window.getComputedStyle &&
window.getComputedStyle(div) &&
window.getComputedStyle(div).getPropertyValue('transform') &&
!(document.documentMode && document.documentMode < 11)
);
})(),
// Helper function to get current visual state of an element
// returns array[ top, left, horizontal-scale, vertical-scale, opacity ]
// =====================================================================
getTranslate: function ($el) {
var domRect;
if (!$el || !$el.length) {
return false;
}
domRect = $el[0].getBoundingClientRect();
return {
top: domRect.top || 0,
left: domRect.left || 0,
width: domRect.width,
height: domRect.height,
opacity: parseFloat($el.css('opacity')),
};
},
// Shortcut for setting "translate3d" properties for element
// Can set be used to set opacity, too
// ========================================================
setTranslate: function ($el, props) {
var str = '',
css = {};
if (!$el || !props) {
return;
}
if (props.left !== undefined || props.top !== undefined) {
str =
(props.left === undefined ? $el.position().left : props.left) +
'px, ' +
(props.top === undefined ? $el.position().top : props.top) +
'px';
if (this.use3d) {
str = 'translate3d(' + str + ', 0px)';
} else {
str = 'translate(' + str + ')';
}
}
if (props.scaleX !== undefined && props.scaleY !== undefined) {
str += ' scale(' + props.scaleX + ', ' + props.scaleY + ')';
} else if (props.scaleX !== undefined) {
str += ' scaleX(' + props.scaleX + ')';
}
if (str.length) {
css.transform = str;
}
if (props.opacity !== undefined) {
css.opacity = props.opacity;
}
if (props.width !== undefined) {
css.width = props.width;
}
if (props.height !== undefined) {
css.height = props.height;
}
return $el.css(css);
},
// Simple CSS transition handler
// =============================
animate: function ($el, to, duration, callback, leaveAnimationName) {
var self = this,
from;
if ($.isFunction(duration)) {
callback = duration;
duration = null;
}
self.stop($el);
from = self.getTranslate($el);
$el.on(transitionEnd, function (e) {
// Skip events from child elements and z-index change
if (
e &&
e.originalEvent &&
(!$el.is(e.originalEvent.target) ||
e.originalEvent.propertyName == 'z-index')
) {
return;
}
self.stop($el);
if ($.isNumeric(duration)) {
$el.css('transition-duration', '');
}
if ($.isPlainObject(to)) {
if (to.scaleX !== undefined && to.scaleY !== undefined) {
self.setTranslate($el, {
top: to.top,
left: to.left,
width: from.width * to.scaleX,
height: from.height * to.scaleY,
scaleX: 1,
scaleY: 1,
});
}
} else if (leaveAnimationName !== true) {
$el.removeClass(to);
}
if ($.isFunction(callback)) {
callback(e);
}
});
if ($.isNumeric(duration)) {
$el.css('transition-duration', duration + 'ms');
}
// Start animation by changing CSS properties or class name
if ($.isPlainObject(to)) {
if (to.scaleX !== undefined && to.scaleY !== undefined) {
delete to.width;
delete to.height;
if ($el.parent().hasClass('fancybox-slide--image')) {
$el.parent().addClass('fancybox-is-scaling');
}
}
$.fancybox.setTranslate($el, to);
} else {
$el.addClass(to);
}
// Make sure that `transitionend` callback gets fired
$el.data(
'timer',
setTimeout(function () {
$el.trigger(transitionEnd);
}, duration + 33)
);
},
stop: function ($el, callCallback) {
if ($el && $el.length) {
clearTimeout($el.data('timer'));
if (callCallback) {
$el.trigger(transitionEnd);
}
$el.off(transitionEnd).css('transition-duration', '');
$el.parent().removeClass('fancybox-is-scaling');
}
},
};
// Default click handler for "fancyboxed" links
// ============================================
function _run(e, opts) {
var items = [],
index = 0,
$target,
value,
instance;
// Avoid opening multiple times
if (e && e.isDefaultPrevented()) {
return;
}
e.preventDefault();
opts = opts || {};
if (e && e.data) {
opts = mergeOpts(e.data.options, opts);
}
$target = opts.$target || $(e.currentTarget).trigger('blur');
instance = $.fancybox.getInstance();
if (instance && instance.$trigger && instance.$trigger.is($target)) {
return;
}
if (opts.selector) {
items = $(opts.selector);
} else {
// Get all related items and find index for clicked one
value = $target.attr('data-fancybox') || '';
if (value) {
items = e.data ? e.data.items : [];
items = items.length
? items.filter('[data-fancybox="' + value + '"]')
: $('[data-fancybox="' + value + '"]');
} else {
items = [$target];
}
}
index = $(items).index($target);
// Sometimes current item can not be found
if (index < 0) {
index = 0;
}
instance = $.fancybox.open(items, opts, index);
// Save last active element
instance.$trigger = $target;
}
// Create a jQuery plugin
// ======================
$.fn.fancybox = function (options) {
var selector;
options = options || {};
selector = options.selector || false;
if (selector) {
// Use body element instead of document so it executes first
$('body').off('click.fb-start', selector).on(
'click.fb-start',
selector,
{
options: options,
},
_run
);
} else {
this.off('click.fb-start').on(
'click.fb-start',
{
items: this,
options: options,
},
_run
);
}
return this;
};
// Self initializing plugin for all elements having `data-fancybox` attribute
// ==========================================================================
$D.on('click.fb-start', '[data-fancybox]', _run);
// Enable "trigger elements"
// =========================
$D.on('click.fb-start', '[data-fancybox-trigger]', function (e) {
$('[data-fancybox="' + $(this).attr('data-fancybox-trigger') + '"]')
.eq($(this).attr('data-fancybox-index') || 0)
.trigger('click.fb-start', {
$trigger: $(this),
});
});
// Track focus event for better accessibility styling
// ==================================================
(function () {
var buttonStr = '.fancybox-button',
focusStr = 'fancybox-focus',
$pressed = null;
$D.on('mousedown mouseup focus blur', buttonStr, function (e) {
switch (e.type) {
case 'mousedown':
$pressed = $(this);
break;
case 'mouseup':
$pressed = null;
break;
case 'focusin':
$(buttonStr).removeClass(focusStr);
if (!$(this).is($pressed) && !$(this).is('[disabled]')) {
$(this).addClass(focusStr);
}
break;
case 'focusout':
$(buttonStr).removeClass(focusStr);
break;
}
});
})();
})(window, document, jQuery);
// ==========================================================================
//
// Media
// Adds additional media type support
//
// ==========================================================================
(function ($) {
'use strict';
// Object containing properties for each media type
var defaults = {
youtube: {
matcher:
/(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,
params: {
autoplay: 1,
autohide: 1,
fs: 1,
rel: 0,
hd: 1,
wmode: 'transparent',
enablejsapi: 1,
html5: 1,
},
paramPlace: 8,
type: 'iframe',
url: 'https://www.youtube-nocookie.com/embed/$4',
thumb: 'https://img.youtube.com/vi/$4/hqdefault.jpg',
},
vimeo: {
matcher: /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,
params: {
autoplay: 1,
hd: 1,
show_title: 1,
show_byline: 1,
show_portrait: 0,
fullscreen: 1,
},
paramPlace: 3,
type: 'iframe',
url: '//player.vimeo.com/video/$2',
},
rutube: {
matcher: /^.+rutube.ru\/.*\/(.*\/)?([\w]+)(.*)\/?/,
params: {
frameBorder: 0,
},
paramPlace: 1,
type: 'iframe',
url: '//rutube.ru/play/embed/$2',
thumb: 'https://rutube.ru/api/video/$2/thumbnail/?redirect=1',
},
vk: {
matcher: /^.+(vk\.com|vk\.ru|vkvideo\.ru).+video(?:\?z=video|)(-?\d+)_(\d+)/,
params: {
autoplay: 1,
hd: 2,
js_api: 1,
frameBorder: 0,
},
paramPlace: 1,
type: 'iframe',
url: 'https://vk.ru/video_ext.php?oid=$2&id=$3',
},
instagram: {
matcher: /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,
type: 'image',
url: '//$1/p/$2/media/?size=l',
},
// Examples:
// http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
// https://www.google.com/maps/@37.7852006,-122.4146355,14.65z
// https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en
// https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572
gmap_place: {
matcher:
/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,
type: 'iframe',
url: function (rez) {
return (
'//maps.google.' +
rez[2] +
'/?ll=' +
(rez[9]
? rez[9] +
'&z=' +
Math.floor(rez[10]) +
(rez[12] ? rez[12].replace(/^\//, '&') : '')
: rez[12] + ''
).replace(/\?/, '&') +
'&output=' +
(rez[12] && rez[12].indexOf('layer=c') > 0 ? 'svembed' : 'embed')
);
},
},
// Examples:
// https://www.google.com/maps/search/Empire+State+Building/
// https://www.google.com/maps/search/?api=1&query=centurylink+field
// https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393
gmap_search: {
matcher:
/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,
type: 'iframe',
url: function (rez) {
return (
'//maps.google.' +
rez[2] +
'/maps?q=' +
rez[5].replace('query=', 'q=').replace('api=1', '') +
'&output=embed'
);
},
},
};
// Formats matching url to final form
var format = function (url, rez, params) {
if (!url) {
return;
}
params = params || '';
if ($.type(params) === 'object') {
params = $.param(params, true);
}
$.each(rez, function (key, value) {
url = url.replace('$' + key, value || '');
});
if (params.length) {
url += (url.indexOf('?') > 0 ? '&' : '?') + params;
}
return url;
};
$(document).on('objectNeedsType.fb', function (e, instance, item) {
var url = item.src || '',
type = false,
media,
thumb,
rez,
params,
urlParams,
paramObj,
provider;
media = $.extend(true, {}, defaults, item.opts.media);
// Look for any matching media type
$.each(media, function (providerName, providerOpts) {
rez = url.match(providerOpts.matcher);
if (!rez) {
return;
}
type = providerOpts.type;
provider = providerName;
paramObj = {};
if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) {
urlParams = rez[providerOpts.paramPlace];
if (urlParams[0] == '?') {
urlParams = urlParams.substring(1);
}
urlParams = urlParams.split('&');
for (var m = 0; m < urlParams.length; ++m) {
var p = urlParams[m].split('=', 2);
if (p.length == 2) {
paramObj[p[0]] = decodeURIComponent(p[1].replace(/\+/g, ' '));
}
}
}
params = $.extend(
true,
{},
providerOpts.params,
item.opts[providerName],
paramObj
);
url =
$.type(providerOpts.url) === 'function'
? providerOpts.url.call(this, rez, params, item)
: format(providerOpts.url, rez, params);
thumb =
$.type(providerOpts.thumb) === 'function'
? providerOpts.thumb.call(this, rez, params, item)
: format(providerOpts.thumb, rez);
if (providerName === 'youtube') {
url = url.replace(/&t=((\d+)m)?(\d+)s/, function (match, p1, m, s) {
return '&start=' + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10));
});
} else if (providerName === 'vimeo') {
url = url.replace('&%23', '#');
} else if (providerName === 'rutube') {
url = url.replace('&%23', '#');
}
return false;
});
// If it is found, then change content type and update the url
if (type) {
if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) {
item.opts.thumb = thumb;
}
if (type === 'iframe') {
item.opts = $.extend(true, item.opts, {
iframe: {
preload: false,
attr: {
scrolling: 'no',
},
},
});
}
$.extend(item, {
type: type,
src: url,
origSrc: item.src,
contentSource: provider,
contentType:
type === 'image'
? 'image'
: provider == 'gmap_place' || provider == 'gmap_search'
? 'map'
: 'video',
});
} else if (url) {
item.type = item.opts.defaultType;
}
});
// Load YouTube/Video API on request to detect when video finished playing
var VideoAPILoader = {
youtube: {
src: 'https://www.youtube.com/iframe_api',
class: 'YT',
loading: false,
loaded: false,
},
vimeo: {
src: 'https://player.vimeo.com/api/player.js',
class: 'Vimeo',
loading: false,
loaded: false,
},
rutube: {
src: 'https://cdn.jsdelivr.net/gh/evikza/rutube-player@178175923bd50cc759e2c3055c6b502e56b54e92/dist/fb.rt.js',
class: 'Rutube',
loading: false,
loaded: false,
},
vk: {
src: 'https://vk.com/js/api/videoplayer.js',
class: 'VK',
loading: false,
loaded: false,
},
load: function (vendor) {
var _this = this,
script;
if (this[vendor].loaded) {
setTimeout(function () {
_this.done(vendor);
});
return;
}
if (this[vendor].loading) {
return;
}
this[vendor].loading = true;
script = document.createElement('script');
script.type = 'text/javascript';
script.src = this[vendor].src;
if (vendor === 'youtube') {
window.onYouTubeIframeAPIReady = function () {
_this[vendor].loaded = true;
_this.done(vendor);
};
} else {
script.onload = function () {
_this[vendor].loaded = true;
_this.done(vendor);
};
}
document.body.appendChild(script);
},
done: function (vendor) {
var instance, $el, player;
if (vendor === 'youtube') {
delete window.onYouTubeIframeAPIReady;
}
instance = $.fancybox.getInstance();
if (instance) {
$el = instance.current.$content.find('iframe');
if (vendor === 'youtube' && YT !== undefined && YT) {
player = new YT.Player($el.attr('id'), {
events: {
onStateChange: function (e) {
if (e.data == 0) {
instance.next();
}
},
},
});
} else if (vendor === 'vimeo' && Vimeo !== undefined && Vimeo) {
player = new Vimeo.Player($el);
player.on('ended', function () {
instance.next();
});
} else if (vendor === 'rutube') {
player = new Rutube();
player.Player($el.attr('id'), {
events: {
onReady: function onPlayerReady() {
setTimeout(player.play(), 700);
},
onStateChange: function onPlayerStateChange(event) {
if (event.playerState.ENDED) {
instance.next();
}
},
},
});
} else if (vendor === 'vk') {
player = VK.VideoPlayer($el[0]);
player.on('ended', function () {
instance.next();
});
}
}
},
};
$(document).on({
'afterShow.fb': function (e, instance, current) {
if (
instance.group.length > 1 &&
(current.contentSource === 'youtube' ||
current.contentSource === 'vimeo' ||
current.contentSource === 'rutube' ||
current.contentSource === 'vk')
) {
VideoAPILoader.load(current.contentSource);
} else if (current.contentSource === 'rutube') {
VideoAPILoader.load(current.contentSource);
}
},
});
})(jQuery);
// ==========================================================================
//
// Guestures
// Adds touch guestures, handles click and tap events
//
// ==========================================================================
(function (window, document, $) {
'use strict';
var requestAFrame = (function () {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function (callback) {
return window.setTimeout(callback, 1000 / 60);
}
);
})();
var cancelAFrame = (function () {
return (
window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function (id) {
window.clearTimeout(id);
}
);
})();
var getPointerXY = function (e) {
var result = [];
e = e.originalEvent || e || window.e;
e =
e.touches && e.touches.length
? e.touches
: e.changedTouches && e.changedTouches.length
? e.changedTouches
: [e];
for (var key in e) {
if (e[key].pageX) {
result.push({
x: e[key].pageX,
y: e[key].pageY,
});
} else if (e[key].clientX) {
result.push({
x: e[key].clientX,
y: e[key].clientY,
});
}
}
return result;
};
var distance = function (point2, point1, what) {
if (!point1 || !point2) {
return 0;
}
if (what === 'x') {
return point2.x - point1.x;
} else if (what === 'y') {
return point2.y - point1.y;
}
return Math.sqrt(
Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)
);
};
var isClickable = function ($el) {
if (
$el.is(
'a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe'
) ||
$.isFunction($el.get(0).onclick) ||
$el.data('selectable')
) {
return true;
}
// Check for attributes like data-fancybox-next or data-fancybox-close
for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {
if (atts[i].nodeName.substr(0, 14) === 'data-fancybox-') {
return true;
}
}
return false;
};
var hasScrollbars = function (el) {
var overflowY = window.getComputedStyle(el)['overflow-y'],
overflowX = window.getComputedStyle(el)['overflow-x'],
vertical =
(overflowY === 'scroll' || overflowY === 'auto') &&
el.scrollHeight > el.clientHeight,
horizontal =
(overflowX === 'scroll' || overflowX === 'auto') &&
el.scrollWidth > el.clientWidth;
return vertical || horizontal;
};
var isScrollable = function ($el) {
var rez = false;
while (true) {
rez = hasScrollbars($el.get(0));
if (rez) {
break;
}
$el = $el.parent();
if (!$el.length || $el.hasClass('fancybox-stage') || $el.is('body')) {
break;
}
}
return rez;
};
var Guestures = function (instance) {
var self = this;
self.instance = instance;
self.$bg = instance.$refs.bg;
self.$stage = instance.$refs.stage;
self.$container = instance.$refs.container;
self.destroy();
self.$container.on(
'touchstart.fb.touch mousedown.fb.touch',
$.proxy(self, 'ontouchstart')
);
};
Guestures.prototype.destroy = function () {
var self = this;
self.$container.off('.fb.touch');
$(document).off('.fb.touch');
if (self.requestId) {
cancelAFrame(self.requestId);
self.requestId = null;
}
if (self.tapped) {
clearTimeout(self.tapped);
self.tapped = null;
}
};
Guestures.prototype.ontouchstart = function (e) {
var self = this,
$target = $(e.target),
instance = self.instance,
current = instance.current,
$slide = current.$slide,
$content = current.$content,
isTouchDevice = e.type == 'touchstart';
// Do not respond to both (touch and mouse) events
if (isTouchDevice) {
self.$container.off('mousedown.fb.touch');
}
// Ignore right click
if (e.originalEvent && e.originalEvent.button == 2) {
return;
}
// Ignore taping on links, buttons, input elements
if (
!$slide.length ||
!$target.length ||
isClickable($target) ||
isClickable($target.parent())
) {
return;
}
// Ignore clicks on the scrollbar
if (
!$target.is('img') &&
e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left
) {
return;
}
// Ignore clicks while zooming or closing
if (
!current ||
instance.isAnimating ||
current.$slide.hasClass('fancybox-animated')
) {
e.stopPropagation();
e.preventDefault();
return;
}
self.realPoints = self.startPoints = getPointerXY(e);
if (!self.startPoints.length) {
return;
}
// Allow other scripts to catch touch event if "touch" is set to false
if (current.touch) {
e.stopPropagation();
}
self.startEvent = e;
self.canTap = true;
self.$target = $target;
self.$content = $content;
self.opts = current.opts.touch;
self.isPanning = false;
self.isSwiping = false;
self.isZooming = false;
self.isScrolling = false;
self.canPan = instance.canPan();
self.startTime = new Date().getTime();
self.distanceX = self.distanceY = self.distance = 0;
self.canvasWidth = Math.round($slide[0].clientWidth);
self.canvasHeight = Math.round($slide[0].clientHeight);
self.contentLastPos = null;
self.contentStartPos = $.fancybox.getTranslate(self.$content) || {
top: 0,
left: 0,
};
self.sliderStartPos = $.fancybox.getTranslate($slide);
// Since position will be absolute, but we need to make it relative to the stage
self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);
self.sliderStartPos.top -= self.stagePos.top;
self.sliderStartPos.left -= self.stagePos.left;
self.contentStartPos.top -= self.stagePos.top;
self.contentStartPos.left -= self.stagePos.left;
$(document)
.off('.fb.touch')
.on(
isTouchDevice
? 'touchend.fb.touch touchcancel.fb.touch'
: 'mouseup.fb.touch mouseleave.fb.touch',
$.proxy(self, 'ontouchend')
)
.on(
isTouchDevice ? 'touchmove.fb.touch' : 'mousemove.fb.touch',
$.proxy(self, 'ontouchmove')
);
if ($.fancybox.isMobile) {
document.addEventListener('scroll', self.onscroll, true);
}
// Skip if clicked outside the sliding area
if (
!(self.opts || self.canPan) ||
!($target.is(self.$stage) || self.$stage.find($target).length)
) {
if ($target.is('.fancybox-image')) {
e.preventDefault();
}
if (
!($.fancybox.isMobile && $target.parents('.fancybox-caption').length)
) {
return;
}
}
self.isScrollable = isScrollable($target) || isScrollable($target.parent());
// Check if element is scrollable and try to prevent default behavior (scrolling)
if (!($.fancybox.isMobile && self.isScrollable)) {
e.preventDefault();
}
// One finger or mouse click - swipe or pan an image
if (self.startPoints.length === 1 || current.hasError) {
if (self.canPan) {
$.fancybox.stop(self.$content);
self.isPanning = true;
} else {
self.isSwiping = true;
}
self.$container.addClass('fancybox-is-grabbing');
}
// Two fingers - zoom image
if (
self.startPoints.length === 2 &&
current.type === 'image' &&
(current.isLoaded || current.$ghost)
) {
self.canTap = false;
self.isSwiping = false;
self.isPanning = false;
self.isZooming = true;
$.fancybox.stop(self.$content);
self.centerPointStartX =
(self.startPoints[0].x + self.startPoints[1].x) * 0.5 -
$(window).scrollLeft();
self.centerPointStartY =
(self.startPoints[0].y + self.startPoints[1].y) * 0.5 -
$(window).scrollTop();
self.percentageOfImageAtPinchPointX =
(self.centerPointStartX - self.contentStartPos.left) /
self.contentStartPos.width;
self.percentageOfImageAtPinchPointY =
(self.centerPointStartY - self.contentStartPos.top) /
self.contentStartPos.height;
self.startDistanceBetweenFingers = distance(
self.startPoints[0],
self.startPoints[1]
);
}
};
Guestures.prototype.onscroll = function (e) {
var self = this;
self.isScrolling = true;
document.removeEventListener('scroll', self.onscroll, true);
};
Guestures.prototype.ontouchmove = function (e) {
var self = this;
// Make sure user has not released over iframe or disabled element
if (
e.originalEvent.buttons !== undefined &&
e.originalEvent.buttons === 0
) {
self.ontouchend(e);
return;
}
if (self.isScrolling) {
self.canTap = false;
return;
}
self.newPoints = getPointerXY(e);
if (
!(self.opts || self.canPan) ||
!self.newPoints.length ||
!self.newPoints.length
) {
return;
}
if (!(self.isSwiping && self.isSwiping === true)) {
e.preventDefault();
}
self.distanceX = distance(self.newPoints[0], self.startPoints[0], 'x');
self.distanceY = distance(self.newPoints[0], self.startPoints[0], 'y');
self.distance = distance(self.newPoints[0], self.startPoints[0]);
// Skip false ontouchmove events (Chrome)
if (self.distance > 0) {
if (self.isSwiping) {
self.onSwipe(e);
} else if (self.isPanning) {
self.onPan();
} else if (self.isZooming) {
self.onZoom();
}
}
};
Guestures.prototype.onSwipe = function (e) {
var self = this,
instance = self.instance,
swiping = self.isSwiping,
left = self.sliderStartPos.left || 0,
angle;
// If direction is not yet determined
if (swiping === true) {
// We need at least 10px distance to correctly calculate an angle
if (Math.abs(self.distance) > 10) {
self.canTap = false;
if (instance.group.length < 2 && self.opts.vertical) {
self.isSwiping = 'y';
} else if (
instance.isDragging ||
self.opts.vertical === false ||
(self.opts.vertical === 'auto' && $(window).width() > 800)
) {
self.isSwiping = 'x';
} else {
angle = Math.abs(
(Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI
);
self.isSwiping = angle > 45 && angle < 135 ? 'y' : 'x';
}
if (
self.isSwiping === 'y' &&
$.fancybox.isMobile &&
self.isScrollable
) {
self.isScrolling = true;
return;
}
instance.isDragging = self.isSwiping;
// Reset points to avoid jumping, because we dropped first swipes to calculate the angle
self.startPoints = self.newPoints;
$.each(instance.slides, function (index, slide) {
var slidePos, stagePos;
$.fancybox.stop(slide.$slide);
slidePos = $.fancybox.getTranslate(slide.$slide);
stagePos = $.fancybox.getTranslate(instance.$refs.stage);
slide.$slide
.css({
transform: '',
opacity: '',
'transition-duration': '',
})
.removeClass('fancybox-animated')
.removeClass(function (index, className) {
return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(
' '
);
});
if (slide.pos === instance.current.pos) {
self.sliderStartPos.top = slidePos.top - stagePos.top;
self.sliderStartPos.left = slidePos.left - stagePos.left;
}
$.fancybox.setTranslate(slide.$slide, {
top: slidePos.top - stagePos.top,
left: slidePos.left - stagePos.left,
});
});
// Stop slideshow
if (instance.SlideShow && instance.SlideShow.isActive) {
instance.SlideShow.stop();
}
}
return;
}
// Sticky edges
if (swiping == 'x') {
if (
self.distanceX > 0 &&
(self.instance.group.length < 2 ||
(self.instance.current.index === 0 &&
!self.instance.current.opts.loop))
) {
left = left + Math.pow(self.distanceX, 0.8);
} else if (
self.distanceX < 0 &&
(self.instance.group.length < 2 ||
(self.instance.current.index === self.instance.group.length - 1 &&
!self.instance.current.opts.loop))
) {
left = left - Math.pow(-self.distanceX, 0.8);
} else {
left = left + self.distanceX;
}
}
self.sliderLastPos = {
top: swiping == 'x' ? 0 : self.sliderStartPos.top + self.distanceY,
left: left,
};
if (self.requestId) {
cancelAFrame(self.requestId);
self.requestId = null;
}
self.requestId = requestAFrame(function () {
if (self.sliderLastPos) {
$.each(self.instance.slides, function (index, slide) {
var pos = slide.pos - self.instance.currPos;
$.fancybox.setTranslate(slide.$slide, {
top: self.sliderLastPos.top,
left:
self.sliderLastPos.left +
pos * self.canvasWidth +
pos * slide.opts.gutter,
});
});
self.$container.addClass('fancybox-is-sliding');
}
});
};
Guestures.prototype.onPan = function () {
var self = this;
// Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)
if (
distance(self.newPoints[0], self.realPoints[0]) <
($.fancybox.isMobile ? 10 : 5)
) {
self.startPoints = self.newPoints;
return;
}
self.canTap = false;
self.contentLastPos = self.limitMovement();
if (self.requestId) {
cancelAFrame(self.requestId);
}
self.requestId = requestAFrame(function () {
$.fancybox.setTranslate(self.$content, self.contentLastPos);
});
};
// Make panning sticky to the edges
Guestures.prototype.limitMovement = function () {
var self = this;
var canvasWidth = self.canvasWidth;
var canvasHeight = self.canvasHeight;
var distanceX = self.distanceX;
var distanceY = self.distanceY;
var contentStartPos = self.contentStartPos;
var currentOffsetX = contentStartPos.left;
var currentOffsetY = contentStartPos.top;
var currentWidth = contentStartPos.width;
var currentHeight = contentStartPos.height;
var minTranslateX,
minTranslateY,
maxTranslateX,
maxTranslateY,
newOffsetX,
newOffsetY;
if (currentWidth > canvasWidth) {
newOffsetX = currentOffsetX + distanceX;
} else {
newOffsetX = currentOffsetX;
}
newOffsetY = currentOffsetY + distanceY;
// Slow down proportionally to traveled distance
minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);
minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);
maxTranslateX = Math.min(
canvasWidth - currentWidth,
canvasWidth * 0.5 - currentWidth * 0.5
);
maxTranslateY = Math.min(
canvasHeight - currentHeight,
canvasHeight * 0.5 - currentHeight * 0.5
);
// ->
if (distanceX > 0 && newOffsetX > minTranslateX) {
newOffsetX =
minTranslateX -
1 +
Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;
}
// <-
if (distanceX < 0 && newOffsetX < maxTranslateX) {
newOffsetX =
maxTranslateX +
1 -
Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;
}
// \/
if (distanceY > 0 && newOffsetY > minTranslateY) {
newOffsetY =
minTranslateY -
1 +
Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;
}
// /\
if (distanceY < 0 && newOffsetY < maxTranslateY) {
newOffsetY =
maxTranslateY +
1 -
Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;
}
return {
top: newOffsetY,
left: newOffsetX,
};
};
Guestures.prototype.limitPosition = function (
newOffsetX,
newOffsetY,
newWidth,
newHeight
) {
var self = this;
var canvasWidth = self.canvasWidth;
var canvasHeight = self.canvasHeight;
if (newWidth > canvasWidth) {
newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
newOffsetX =
newOffsetX < canvasWidth - newWidth
? canvasWidth - newWidth
: newOffsetX;
} else {
// Center horizontally
newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);
}
if (newHeight > canvasHeight) {
newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
newOffsetY =
newOffsetY < canvasHeight - newHeight
? canvasHeight - newHeight
: newOffsetY;
} else {
// Center vertically
newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);
}
return {
top: newOffsetY,
left: newOffsetX,
};
};
Guestures.prototype.onZoom = function () {
var self = this;
// Calculate current distance between points to get pinch ratio and new width and height
var contentStartPos = self.contentStartPos;
var currentWidth = contentStartPos.width;
var currentHeight = contentStartPos.height;
var currentOffsetX = contentStartPos.left;
var currentOffsetY = contentStartPos.top;
var endDistanceBetweenFingers = distance(
self.newPoints[0],
self.newPoints[1]
);
var pinchRatio =
endDistanceBetweenFingers / self.startDistanceBetweenFingers;
var newWidth = Math.floor(currentWidth * pinchRatio);
var newHeight = Math.floor(currentHeight * pinchRatio);
// This is the translation due to pinch-zooming
var translateFromZoomingX =
(currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
var translateFromZoomingY =
(currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
// Point between the two touches
var centerPointEndX =
(self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();
var centerPointEndY =
(self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();
// And this is the translation due to translation of the centerpoint
// between the two fingers
var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
// The new offset is the old/current one plus the total translation
var newOffsetX =
currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);
var newOffsetY =
currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);
var newPos = {
top: newOffsetY,
left: newOffsetX,
scaleX: pinchRatio,
scaleY: pinchRatio,
};
self.canTap = false;
self.newWidth = newWidth;
self.newHeight = newHeight;
self.contentLastPos = newPos;
if (self.requestId) {
cancelAFrame(self.requestId);
}
self.requestId = requestAFrame(function () {
$.fancybox.setTranslate(self.$content, self.contentLastPos);
});
};
Guestures.prototype.ontouchend = function (e) {
var self = this;
var swiping = self.isSwiping;
var panning = self.isPanning;
var zooming = self.isZooming;
var scrolling = self.isScrolling;
self.endPoints = getPointerXY(e);
self.dMs = Math.max(new Date().getTime() - self.startTime, 1);
self.$container.removeClass('fancybox-is-grabbing');
$(document).off('.fb.touch');
document.removeEventListener('scroll', self.onscroll, true);
if (self.requestId) {
cancelAFrame(self.requestId);
self.requestId = null;
}
self.isSwiping = false;
self.isPanning = false;
self.isZooming = false;
self.isScrolling = false;
self.instance.isDragging = false;
if (self.canTap) {
return self.onTap(e);
}
self.speed = 100;
// Speed in px/ms
self.velocityX = (self.distanceX / self.dMs) * 0.5;
self.velocityY = (self.distanceY / self.dMs) * 0.5;
if (panning) {
self.endPanning();
} else if (zooming) {
self.endZooming();
} else {
self.endSwiping(swiping, scrolling);
}
return;
};
Guestures.prototype.endSwiping = function (swiping, scrolling) {
var self = this,
ret = false,
len = self.instance.group.length,
distanceX = Math.abs(self.distanceX),
canAdvance =
swiping == 'x' &&
len > 1 &&
((self.dMs > 130 && distanceX > 10) || distanceX > 50),
speedX = 300;
self.sliderLastPos = null;
// Close if swiped vertically / navigate if horizontally
if (swiping == 'y' && !scrolling && Math.abs(self.distanceY) > 50) {
// Continue vertical movement
$.fancybox.animate(
self.instance.current.$slide,
{
top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,
opacity: 0,
},
200
);
ret = self.instance.close(true, 250);
} else if (canAdvance && self.distanceX > 0) {
ret = self.instance.previous(speedX);
} else if (canAdvance && self.distanceX < 0) {
ret = self.instance.next(speedX);
}
if (ret === false && (swiping == 'x' || swiping == 'y')) {
self.instance.centerSlide(200);
}
self.$container.removeClass('fancybox-is-sliding');
};
// Limit panning from edges
// ========================
Guestures.prototype.endPanning = function () {
var self = this,
newOffsetX,
newOffsetY,
newPos;
if (!self.contentLastPos) {
return;
}
if (self.opts.momentum === false || self.dMs > 350) {
newOffsetX = self.contentLastPos.left;
newOffsetY = self.contentLastPos.top;
} else {
// Continue movement
newOffsetX = self.contentLastPos.left + self.velocityX * 500;
newOffsetY = self.contentLastPos.top + self.velocityY * 500;
}
newPos = self.limitPosition(
newOffsetX,
newOffsetY,
self.contentStartPos.width,
self.contentStartPos.height
);
newPos.width = self.contentStartPos.width;
newPos.height = self.contentStartPos.height;
$.fancybox.animate(self.$content, newPos, 366);
};
Guestures.prototype.endZooming = function () {
var self = this;
var current = self.instance.current;
var newOffsetX, newOffsetY, newPos, reset;
var newWidth = self.newWidth;
var newHeight = self.newHeight;
if (!self.contentLastPos) {
return;
}
newOffsetX = self.contentLastPos.left;
newOffsetY = self.contentLastPos.top;
reset = {
top: newOffsetY,
left: newOffsetX,
width: newWidth,
height: newHeight,
scaleX: 1,
scaleY: 1,
};
// Reset scalex/scaleY values; this helps for perfomance and does not break animation
$.fancybox.setTranslate(self.$content, reset);
if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
self.instance.scaleToFit(150);
} else if (newWidth > current.width || newHeight > current.height) {
self.instance.scaleToActual(
self.centerPointStartX,
self.centerPointStartY,
150
);
} else {
newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);
$.fancybox.animate(self.$content, newPos, 150);
}
};
Guestures.prototype.onTap = function (e) {
var self = this;
var $target = $(e.target);
var instance = self.instance;
var current = instance.current;
var endPoints = (e && getPointerXY(e)) || self.startPoints;
var tapX = endPoints[0]
? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left
: 0;
var tapY = endPoints[0]
? endPoints[0].y - $(window).scrollTop() - self.stagePos.top
: 0;
var where;
var process = function (prefix) {
var action = current.opts[prefix];
if ($.isFunction(action)) {
action = action.apply(instance, [current, e]);
}
if (!action) {
return;
}
switch (action) {
case 'close':
instance.close(self.startEvent);
break;
case 'toggleControls':
instance.toggleControls();
break;
case 'next':
instance.next();
break;
case 'nextOrClose':
if (instance.group.length > 1) {
instance.next();
} else {
instance.close(self.startEvent);
}
break;
case 'zoom':
if (current.type == 'image' && (current.isLoaded || current.$ghost)) {
if (instance.canPan()) {
instance.scaleToFit();
} else if (instance.isScaledDown()) {
instance.scaleToActual(tapX, tapY);
} else if (instance.group.length < 2) {
instance.close(self.startEvent);
}
}
break;
}
};
// Ignore right click
if (e.originalEvent && e.originalEvent.button == 2) {
return;
}
// Skip if clicked on the scrollbar
if (
!$target.is('img') &&
tapX > $target[0].clientWidth + $target.offset().left
) {
return;
}
// Check where is clicked
if (
$target.is(
'.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container'
)
) {
where = 'Outside';
} else if ($target.is('.fancybox-slide')) {
where = 'Slide';
} else if (
instance.current.$content &&
instance.current.$content.find($target).addBack().filter($target).length
) {
where = 'Content';
} else {
return;
}
// Check if this is a double tap
if (self.tapped) {
// Stop previously created single tap
clearTimeout(self.tapped);
self.tapped = null;
// Skip if distance between taps is too big
if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {
return this;
}
// OK, now we assume that this is a double-tap
process('dblclick' + where);
} else {
// Single tap will be processed if user has not clicked second time within 300ms
// or there is no need to wait for double-tap
self.tapX = tapX;
self.tapY = tapY;
if (
current.opts['dblclick' + where] &&
current.opts['dblclick' + where] !== current.opts['click' + where]
) {
self.tapped = setTimeout(function () {
self.tapped = null;
if (!instance.isAnimating) {
process('click' + where);
}
}, 500);
} else {
process('click' + where);
}
}
return this;
};
$(document)
.on('onActivate.fb', function (e, instance) {
if (instance && !instance.Guestures) {
instance.Guestures = new Guestures(instance);
}
})
.on('beforeClose.fb', function (e, instance) {
if (instance && instance.Guestures) {
instance.Guestures.destroy();
}
});
})(window, document, jQuery);
// ==========================================================================
//
// SlideShow
// Enables slideshow functionality
//
// Example of usage:
// $.fancybox.getInstance().SlideShow.start()
//
// ==========================================================================
(function (document, $) {
'use strict';
$.extend(true, $.fancybox.defaults, {
btnTpl: {
slideShow:
'<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}">' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.5 5.4v13.2l11-6.6z"/></svg>' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.33 5.75h2.2v12.5h-2.2V5.75zm5.15 0h2.2v12.5h-2.2V5.75z"/></svg>' +
'</button>',
},
slideShow: {
autoStart: false,
speed: 3000,
progress: true,
},
});
var SlideShow = function (instance) {
this.instance = instance;
this.init();
};
$.extend(SlideShow.prototype, {
timer: null,
isActive: false,
$button: null,
init: function () {
var self = this,
instance = self.instance,
opts = instance.group[instance.currIndex].opts.slideShow;
self.$button = instance.$refs.toolbar
.find('[data-fancybox-play]')
.on('click', function () {
self.toggle();
});
if (instance.group.length < 2 || !opts) {
self.$button.hide();
} else if (opts.progress) {
self.$progress = $('<div class="fancybox-progress"></div>').appendTo(
instance.$refs.inner
);
}
},
set: function (force) {
var self = this,
instance = self.instance,
current = instance.current;
// Check if reached last element
if (
current &&
(force === true ||
current.opts.loop ||
instance.currIndex < instance.group.length - 1)
) {
if (self.isActive && current.contentType !== 'video') {
if (self.$progress) {
$.fancybox.animate(
self.$progress.show(),
{
scaleX: 1,
},
current.opts.slideShow.speed
);
}
self.timer = setTimeout(function () {
if (
!instance.current.opts.loop &&
instance.current.index == instance.group.length - 1
) {
instance.jumpTo(0);
} else {
instance.next();
}
}, current.opts.slideShow.speed);
}
} else {
self.stop();
instance.idleSecondsCounter = 0;
instance.showControls();
}
},
clear: function () {
var self = this;
clearTimeout(self.timer);
self.timer = null;
if (self.$progress) {
self.$progress.removeAttr('style').hide();
}
},
start: function () {
var self = this,
current = self.instance.current;
if (current) {
self.$button
.attr(
'title',
(current.opts.i18n[current.opts.lang] || current.opts.i18n.en)
.PLAY_STOP
)
.removeClass('fancybox-button--play')
.addClass('fancybox-button--pause');
self.isActive = true;
if (current.isComplete) {
self.set(true);
}
self.instance.trigger('onSlideShowChange', true);
}
},
stop: function () {
var self = this,
current = self.instance.current;
self.clear();
self.$button
.attr(
'title',
(current.opts.i18n[current.opts.lang] || current.opts.i18n.en)
.PLAY_START
)
.removeClass('fancybox-button--pause')
.addClass('fancybox-button--play');
self.isActive = false;
self.instance.trigger('onSlideShowChange', false);
if (self.$progress) {
self.$progress.removeAttr('style').hide();
}
},
toggle: function () {
var self = this;
if (self.isActive) {
self.stop();
} else {
self.start();
}
},
});
$(document).on({
'onInit.fb': function (e, instance) {
if (instance && !instance.SlideShow) {
instance.SlideShow = new SlideShow(instance);
}
},
'beforeShow.fb': function (e, instance, current, firstRun) {
var SlideShow = instance && instance.SlideShow;
if (firstRun) {
if (SlideShow && current.opts.slideShow.autoStart) {
SlideShow.start();
}
} else if (SlideShow && SlideShow.isActive) {
SlideShow.clear();
}
},
'afterShow.fb': function (e, instance, current) {
var SlideShow = instance && instance.SlideShow;
if (SlideShow && SlideShow.isActive) {
SlideShow.set();
}
},
'afterKeydown.fb': function (e, instance, current, keypress, keycode) {
var SlideShow = instance && instance.SlideShow;
// "P" or Spacebar
if (
SlideShow &&
current.opts.slideShow &&
(keycode === 80 || keycode === 32) &&
!$(document.activeElement).is('button,a,input')
) {
keypress.preventDefault();
SlideShow.toggle();
}
},
'beforeClose.fb onDeactivate.fb': function (e, instance) {
var SlideShow = instance && instance.SlideShow;
if (SlideShow) {
SlideShow.stop();
}
},
});
// Page Visibility API to pause slideshow when window is not active
$(document).on('visibilitychange', function () {
var instance = $.fancybox.getInstance(),
SlideShow = instance && instance.SlideShow;
if (SlideShow && SlideShow.isActive) {
if (document.hidden) {
SlideShow.clear();
} else {
SlideShow.set();
}
}
});
})(document, jQuery);
// ==========================================================================
//
// FullScreen
// Adds fullscreen functionality
//
// ==========================================================================
(function (document, $) {
'use strict';
// Collection of methods supported by user browser
var fn = (function () {
var fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror',
],
// new WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror',
],
// old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror',
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror',
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError',
],
];
var ret = {};
for (var i = 0; i < fnMap.length; i++) {
var val = fnMap[i];
if (val && val[1] in document) {
for (var j = 0; j < val.length; j++) {
ret[fnMap[0][j]] = val[j];
}
return ret;
}
}
return false;
})();
if (fn) {
var FullScreen = {
request: function (elem) {
elem = elem || document.documentElement;
elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT);
},
exit: function () {
document[fn.exitFullscreen]();
},
toggle: function (elem) {
elem = elem || document.documentElement;
if (this.isFullscreen()) {
this.exit();
} else {
this.request(elem);
}
},
isFullscreen: function () {
return Boolean(document[fn.fullscreenElement]);
},
enabled: function () {
return Boolean(document[fn.fullscreenEnabled]);
},
};
$.extend(true, $.fancybox.defaults, {
btnTpl: {
fullScreen:
'<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fsenter" title="{{FULL_SCREEN}}">' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 16h3v3h2v-5H5zm3-8H5v2h5V5H8zm6 11h2v-3h3v-2h-5zm2-11V5h-2v5h5V8z"/></svg>' +
'</button>',
},
fullScreen: {
autoStart: false,
},
});
$(document).on(fn.fullscreenchange, function () {
var isFullscreen = FullScreen.isFullscreen(),
instance = $.fancybox.getInstance();
if (instance) {
// If image is zooming, then force to stop and reposition properly
if (
instance.current &&
instance.current.type === 'image' &&
instance.isAnimating
) {
instance.isAnimating = false;
instance.update(true, true, 0);
if (!instance.isComplete) {
instance.complete();
}
}
instance.trigger('onFullscreenChange', isFullscreen);
instance.$refs.container.toggleClass(
'fancybox-is-fullscreen',
isFullscreen
);
instance.$refs.toolbar
.find('[data-fancybox-fullscreen]')
.toggleClass('fancybox-button--fsenter', !isFullscreen)
.toggleClass('fancybox-button--fsexit', isFullscreen);
}
});
}
$(document).on({
'onInit.fb': function (e, instance) {
var $container;
if (!fn) {
instance.$refs.toolbar.find('[data-fancybox-fullscreen]').remove();
return;
}
if (instance && instance.group[instance.currIndex].opts.fullScreen) {
$container = instance.$refs.container;
$container.on(
'click.fb-fullscreen',
'[data-fancybox-fullscreen]',
function (e) {
e.stopPropagation();
e.preventDefault();
FullScreen.toggle();
}
);
if (
instance.opts.fullScreen &&
instance.opts.fullScreen.autoStart === true
) {
FullScreen.request();
}
// Expose API
instance.FullScreen = FullScreen;
} else if (instance) {
instance.$refs.toolbar.find('[data-fancybox-fullscreen]').hide();
}
},
'afterKeydown.fb': function (e, instance, current, keypress, keycode) {
// "F"
if (instance && instance.FullScreen && keycode === 70) {
keypress.preventDefault();
instance.FullScreen.toggle();
}
},
'beforeClose.fb': function (e, instance) {
if (
instance &&
instance.FullScreen &&
instance.$refs.container.hasClass('fancybox-is-fullscreen')
) {
FullScreen.exit();
}
},
});
})(document, jQuery);
// ==========================================================================
//
// Thumbs
// Displays thumbnails in a grid
//
// ==========================================================================
(function (document, $) {
'use strict';
var CLASS = 'fancybox-thumbs',
CLASS_ACTIVE = CLASS + '-active';
// Make sure there are default values
$.fancybox.defaults = $.extend(
true,
{
btnTpl: {
thumbs:
'<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}">' +
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.59 14.59h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76H5.65V5.65z"/></svg>' +
'</button>',
},
thumbs: {
autoStart: false, // Display thumbnails on opening
hideOnClose: true, // Hide thumbnail grid when closing animation starts
parentEl: '.fancybox-container', // Container is injected into this element
axis: 'y', // Vertical (y) or horizontal (x) scrolling
},
},
$.fancybox.defaults
);
var FancyThumbs = function (instance) {
this.init(instance);
};
$.extend(FancyThumbs.prototype, {
$button: null,
$grid: null,
$list: null,
isVisible: false,
isActive: false,
init: function (instance) {
var self = this,
group = instance.group,
enabled = 0;
self.instance = instance;
self.opts = group[instance.currIndex].opts.thumbs;
instance.Thumbs = self;
self.$button = instance.$refs.toolbar.find('[data-fancybox-thumbs]');
// Enable thumbs if at least two group items have thumbnails
for (var i = 0, len = group.length; i < len; i++) {
if (group[i].thumb) {
enabled++;
}
if (enabled > 1) {
break;
}
}
if (enabled > 1 && !!self.opts) {
self.$button.removeAttr('style').on('click', function () {
self.toggle();
});
self.isActive = true;
} else {
self.$button.hide();
}
},
create: function () {
var self = this,
instance = self.instance,
parentEl = self.opts.parentEl,
list = [],
src;
if (!self.$grid) {
// Create main element
self.$grid = $(
'<div class="' +
CLASS +
' ' +
CLASS +
'-' +
self.opts.axis +
'"></div>'
).appendTo(
instance.$refs.container.find(parentEl).addBack().filter(parentEl)
);
// Add "click" event that performs gallery navigation
self.$grid.on('click', 'a', function () {
instance.jumpTo($(this).attr('data-index'));
});
}
// Build the list
if (!self.$list) {
self.$list = $('<div class="' + CLASS + '__list">').appendTo(
self.$grid
);
}
$.each(instance.group, function (i, item) {
src = item.thumb;
if (!src && item.type === 'image') {
src = item.src;
}
list.push(
'<a href="javascript:;" tabindex="0" data-index="' +
i +
'"' +
(src && src.length
? ' style="background-image:url(' + src + ')"'
: 'class="fancybox-thumbs-missing"') +
'></a>'
);
});
self.$list[0].innerHTML = list.join('');
if (self.opts.axis === 'x') {
// Set fixed width for list element to enable horizontal scrolling
self.$list.width(
parseInt(self.$grid.css('padding-right'), 10) +
instance.group.length * self.$list.children().eq(0).outerWidth(true)
);
}
},
focus: function (duration) {
var self = this,
$list = self.$list,
$grid = self.$grid,
thumb,
thumbPos;
if (!self.instance.current) {
return;
}
thumb = $list
.children()
.removeClass(CLASS_ACTIVE)
.filter('[data-index="' + self.instance.current.index + '"]')
.addClass(CLASS_ACTIVE);
thumbPos = thumb.position();
// Check if need to scroll to make current thumb visible
if (
self.opts.axis === 'y' &&
(thumbPos.top < 0 ||
thumbPos.top > $list.height() - thumb.outerHeight())
) {
$list.stop().animate(
{
scrollTop: $list.scrollTop() + thumbPos.top,
},
duration
);
} else if (
self.opts.axis === 'x' &&
(thumbPos.left < $grid.scrollLeft() ||
thumbPos.left >
$grid.scrollLeft() + ($grid.width() - thumb.outerWidth()))
) {
$list.parent().stop().animate(
{
scrollLeft: thumbPos.left,
},
duration
);
}
},
update: function () {
var that = this;
that.instance.$refs.container.toggleClass(
'fancybox-show-thumbs',
this.isVisible
);
if (that.isVisible) {
if (!that.$grid) {
that.create();
}
that.instance.trigger('onThumbsShow');
that.focus(0);
} else if (that.$grid) {
that.instance.trigger('onThumbsHide');
}
// Update content position
that.instance.update();
},
hide: function () {
this.isVisible = false;
this.update();
},
show: function () {
this.isVisible = true;
this.update();
},
toggle: function () {
this.isVisible = !this.isVisible;
this.update();
},
});
$(document).on({
'onInit.fb': function (e, instance) {
var Thumbs;
if (instance && !instance.Thumbs) {
Thumbs = new FancyThumbs(instance);
if (Thumbs.isActive && Thumbs.opts.autoStart === true) {
Thumbs.show();
}
}
},
'beforeShow.fb': function (e, instance, item, firstRun) {
var Thumbs = instance && instance.Thumbs;
if (Thumbs && Thumbs.isVisible) {
Thumbs.focus(firstRun ? 0 : 250);
}
},
'afterKeydown.fb': function (e, instance, current, keypress, keycode) {
var Thumbs = instance && instance.Thumbs;
// "G"
if (Thumbs && Thumbs.isActive && keycode === 71) {
keypress.preventDefault();
Thumbs.toggle();
}
},
'beforeClose.fb': function (e, instance) {
var Thumbs = instance && instance.Thumbs;
if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) {
Thumbs.$grid.hide();
}
},
});
})(document, jQuery);
// ==========================================================================
//
// Hash
// Enables linking to each modal
//
// ==========================================================================
(function (window, document, $) {
'use strict';
// Simple $.escapeSelector polyfill (for jQuery prior v3)
if (!$.escapeSelector) {
$.escapeSelector = function (sel) {
var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
var fcssescape = function (ch, asCodePoint) {
if (asCodePoint) {
// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
if (ch === '\0') {
return '\uFFFD';
}
// Control characters and (dependent upon position) numbers get escaped as code points
return (
ch.slice(0, -1) +
'\\' +
ch.charCodeAt(ch.length - 1).toString(16) +
' '
);
}
// Other potentially-special ASCII characters get backslash-escaped
return '\\' + ch;
};
return (sel + '').replace(rcssescape, fcssescape);
};
}
// Get info about gallery name and current index from url
function parseUrl() {
var hash = window.location.hash.substr(1),
rez = hash.split('-'),
index =
rez.length > 1 && /^\+?\d+$/.test(rez[rez.length - 1])
? parseInt(rez.pop(-1), 10) || 1
: 1,
gallery = rez.join('-');
return {
hash: hash,
/* Index is starting from 1 */
index: index < 1 ? 1 : index,
gallery: gallery,
};
}
// Trigger click evnt on links to open new fancyBox instance
function triggerFromUrl(url) {
if (url.gallery !== '') {
// If we can find element matching 'data-fancybox' atribute,
// then triggering click event should start fancyBox
$("[data-fancybox='" + $.escapeSelector(url.gallery) + "']")
.eq(url.index - 1)
.focus()
.trigger('click.fb-start');
}
}
// Get gallery name from current instance
function getGalleryID(instance) {
var opts, ret;
if (!instance) {
return false;
}
opts = instance.current ? instance.current.opts : instance.opts;
ret =
opts.hash ||
(opts.$orig
? opts.$orig.data('fancybox') || opts.$orig.data('fancybox-trigger')
: '');
return ret === '' ? false : ret;
}
// Start when DOM becomes ready
$(function () {
// Check if user has disabled this module
if ($.fancybox.defaults.hash === false) {
return;
}
// Update hash when opening/closing fancyBox
$(document).on({
'onInit.fb': function (e, instance) {
var url, gallery;
if (instance.group[instance.currIndex].opts.hash === false) {
return;
}
url = parseUrl();
gallery = getGalleryID(instance);
// Make sure gallery start index matches index from hash
if (gallery && url.gallery && gallery == url.gallery) {
instance.currIndex = url.index - 1;
}
},
'beforeShow.fb': function (e, instance, current, firstRun) {
var gallery;
if (!current || current.opts.hash === false) {
return;
}
// Check if need to update window hash
gallery = getGalleryID(instance);
if (!gallery) {
return;
}
// Variable containing last hash value set by fancyBox
// It will be used to determine if fancyBox needs to close after hash change is detected
instance.currentHash =
gallery +
(instance.group.length > 1 ? '-' + (current.index + 1) : '');
// If current hash is the same (this instance most likely is opened by hashchange), then do nothing
if (window.location.hash === '#' + instance.currentHash) {
return;
}
if (firstRun && !instance.origHash) {
instance.origHash = window.location.hash;
}
if (instance.hashTimer) {
clearTimeout(instance.hashTimer);
}
// Update hash
instance.hashTimer = setTimeout(function () {
if ('replaceState' in window.history) {
window.history[firstRun ? 'pushState' : 'replaceState'](
{},
document.title,
window.location.pathname +
window.location.search +
'#' +
instance.currentHash
);
if (firstRun) {
instance.hasCreatedHistory = true;
}
} else {
window.location.hash = instance.currentHash;
}
instance.hashTimer = null;
}, 300);
},
'beforeClose.fb': function (e, instance, current) {
if (!current || current.opts.hash === false) {
return;
}
clearTimeout(instance.hashTimer);
// Goto previous history entry
if (instance.currentHash && instance.hasCreatedHistory) {
window.history.back();
} else if (instance.currentHash) {
if ('replaceState' in window.history) {
window.history.replaceState(
{},
document.title,
window.location.pathname +
window.location.search +
(instance.origHash || '')
);
} else {
window.location.hash = instance.origHash;
}
}
instance.currentHash = null;
},
});
// Check if need to start/close after url has changed
$(window).on('hashchange.fb', function () {
var url = parseUrl(),
fb = null;
// Find last fancyBox instance that has "hash"
$.each($('.fancybox-container').get().reverse(), function (index, value) {
var tmp = $(value).data('FancyBox');
if (tmp && tmp.currentHash) {
fb = tmp;
return false;
}
});
if (fb) {
// Now, compare hash values
if (
fb.currentHash !== url.gallery + '-' + url.index &&
!(url.index === 1 && fb.currentHash == url.gallery)
) {
fb.currentHash = null;
fb.close();
}
} else if (url.gallery !== '') {
triggerFromUrl(url);
}
});
// Check current hash and trigger click event on matching element to start fancyBox, if needed
setTimeout(function () {
if (!$.fancybox.getInstance()) {
triggerFromUrl(parseUrl());
}
}, 50);
});
})(window, document, jQuery);
// ==========================================================================
//
// Wheel
// Basic mouse weheel support for gallery navigation
//
// ==========================================================================
(function (document, $) {
'use strict';
var prevTime = new Date().getTime();
$(document).on({
'onInit.fb': function (e, instance, current) {
instance.$refs.stage.on(
'mousewheel DOMMouseScroll wheel MozMousePixelScroll',
function (e) {
var current = instance.current,
currTime = new Date().getTime();
if (
instance.group.length < 2 ||
current.opts.wheel === false ||
(current.opts.wheel === 'auto' && current.type !== 'image')
) {
return;
}
e.preventDefault();
e.stopPropagation();
if (current.$slide.hasClass('fancybox-animated')) {
return;
}
e = e.originalEvent || e;
if (currTime - prevTime < 250) {
return;
}
prevTime = currTime;
instance[
(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0
? 'next'
: 'previous'
]();
}
);
},
});
})(document, jQuery);
// ==================================================
// fancyBox v3.5.7
//
// Licensed GPLv3 for open source use
// or fancyBox Commercial License for commercial use
//
// http://fancyapps.com/fancybox/
// Copyright 2022 fancyApps
//
// ==================================================
!function(t,e,n,o){"use strict";if(t.console=t.console||{info:function(t){}},n)if(n.fn.fancybox)console.info("fancyBox already initialized");else{var i,s,a={closeExisting:!1,loop:!1,gutter:50,keyboard:!0,preventCaptionOverlap:!0,arrows:!0,infobar:!0,smallBtn:"auto",toolbar:"auto",buttons:["zoom","slideShow","thumbs","close"],idleTime:3,protect:!1,modal:!1,image:{preload:!1},ajax:{settings:{data:{fancybox:!0}}},iframe:{tpl:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen="allowfullscreen" allow="autoplay; fullscreen" src=""></iframe>',preload:!0,css:{},attr:{scrolling:"auto"}},video:{tpl:'<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}"><source src="{{src}}" type="{{format}}" />Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!</video>',format:"",autoStart:!0},defaultType:"image",animationEffect:"zoom",animationDuration:366,zoomOpacity:"auto",transitionEffect:"fade",transitionDuration:366,slideClass:"",baseClass:"",baseTpl:'<div class="fancybox-container" role="dialog" tabindex="-1"><div class="fancybox-bg"></div><div class="fancybox-inner"><div class="fancybox-infobar"><span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span></div><div class="fancybox-toolbar">{{buttons}}</div><div class="fancybox-navigation">{{arrows}}</div><div class="fancybox-stage"></div><div class="fancybox-caption"><div class="fancybox-caption__body"></div></div></div></div>',spinnerTpl:'<div class="fancybox-loading"></div>',errorTpl:'<div class="fancybox-error"><p>{{ERROR}}</p></div>',btnTpl:{download:'<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.62 17.09V19H5.38v-1.91zm-2.97-6.96L17 11.45l-5 4.87-5-4.87 1.36-1.32 2.68 2.64V5h1.92v7.77z"/></svg></a>',zoom:'<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.7 17.3l-3-3a5.9 5.9 0 0 0-.6-7.6 5.9 5.9 0 0 0-8.4 0 5.9 5.9 0 0 0 0 8.4 5.9 5.9 0 0 0 7.7.7l3 3a1 1 0 0 0 1.3 0c.4-.5.4-1 0-1.5zM8.1 13.8a4 4 0 0 1 0-5.7 4 4 0 0 1 5.7 0 4 4 0 0 1 0 5.7 4 4 0 0 1-5.7 0z"/></svg></button>',close:'<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 10.6L6.6 5.2 5.2 6.6l5.4 5.4-5.4 5.4 1.4 1.4 5.4-5.4 5.4 5.4 1.4-1.4-5.4-5.4 5.4-5.4-1.4-1.4-5.4 5.4z"/></svg></button>',arrowLeft:'<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}"><div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.28 15.7l-1.34 1.37L5 12l4.94-5.07 1.34 1.38-2.68 2.72H19v1.94H8.6z"/></svg></div></button>',arrowRight:'<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}"><div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.4 12.97l-2.68 2.72 1.34 1.38L19 12l-4.94-5.07-1.34 1.38 2.68 2.72H5v1.94z"/></svg></div></button>',smallBtn:'<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}"><svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 24 24"><path d="M13 12l5-5-1-1-5 5-5-5-1 1 5 5-5 5 1 1 5-5 5 5 1-1z"/></svg></button>'},parentEl:"body",hideScrollbar:!0,autoFocus:!0,backFocus:!0,trapFocus:!0,fullScreen:{autoStart:!1},touch:{vertical:!0,momentum:!0},hash:null,media:{},slideShow:{autoStart:!1,speed:3e3},thumbs:{autoStart:!1,hideOnClose:!0,parentEl:".fancybox-container",axis:"y"},wheel:"auto",onInit:n.noop,beforeLoad:n.noop,afterLoad:n.noop,beforeShow:n.noop,afterShow:n.noop,beforeClose:n.noop,afterClose:n.noop,onActivate:n.noop,onDeactivate:n.noop,clickContent:function(t,e){return"image"===t.type&&"zoom"},clickSlide:"close",clickOutside:"close",dblclickContent:!1,dblclickSlide:!1,dblclickOutside:!1,mobile:{preventCaptionOverlap:!1,idleTime:!1,clickContent:function(t,e){return"image"===t.type&&"toggleControls"},clickSlide:function(t,e){return"image"===t.type?"toggleControls":"close"},dblclickContent:function(t,e){return"image"===t.type&&"zoom"},dblclickSlide:function(t,e){return"image"===t.type&&"zoom"}},lang:"en",i18n:{en:{CLOSE:"Close",NEXT:"Next",PREV:"Previous",ERROR:"The requested content cannot be loaded. <br/> Please try again later.",PLAY_START:"Start slideshow",PLAY_STOP:"Pause slideshow",FULL_SCREEN:"Full screen",THUMBS:"Thumbnails",DOWNLOAD:"Download",SHARE:"Share",ZOOM:"Zoom"},de:{CLOSE:"Schlie&szlig;en",NEXT:"Weiter",PREV:"Zur&uuml;ck",ERROR:"Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es sp&auml;ter nochmal.",PLAY_START:"Diaschau starten",PLAY_STOP:"Diaschau beenden",FULL_SCREEN:"Vollbild",THUMBS:"Vorschaubilder",DOWNLOAD:"Herunterladen",SHARE:"Teilen",ZOOM:"Vergr&ouml;&szlig;ern"}}},r=n(t),c=n(e),l=0,h=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||function(e){return t.setTimeout(e,1e3/60)},d=t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.mozCancelAnimationFrame||t.oCancelAnimationFrame||function(e){t.clearTimeout(e)},u=function(){var t,n=e.createElement("fakeelement"),o={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(t in o)if(void 0!==n.style[t])return o[t];return"transitionend"}(),f=function(t){return t&&t.length&&t[0].offsetHeight},p=function(t,e){var o=n.extend(!0,{},t,e);return n.each(e,function(t,e){n.isArray(e)&&(o[t]=e)}),o},g=function(t,e,o){this.opts=p({index:o},n.fancybox.defaults),n.isPlainObject(e)&&(this.opts=p(this.opts,e)),n.fancybox.isMobile&&(this.opts=p(this.opts,this.opts.mobile)),this.id=this.opts.id||++l,this.currIndex=parseInt(this.opts.index,10)||0,this.prevIndex=null,this.prevPos=null,this.currPos=0,this.firstRun=!0,this.group=[],this.slides={},this.addContent(t),this.group.length&&this.init()};n.extend(g.prototype,{init:function(){var o,i,s=this,a=s.group[s.currIndex].opts;a.closeExisting&&n.fancybox.close(!0),n("body").addClass("fancybox-active"),!n.fancybox.getInstance()&&!1!==a.hideScrollbar&&!n.fancybox.isMobile&&e.body.scrollHeight>t.innerHeight&&(n("head").append('<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:'+(t.innerWidth-e.documentElement.clientWidth)+"px;}</style>"),n("body").addClass("compensate-for-scrollbar")),i="",n.each(a.buttons,function(t,e){i+=a.btnTpl[e]||""}),o=n(s.translate(s,a.baseTpl.replace("{{buttons}}",i).replace("{{arrows}}",a.btnTpl.arrowLeft+a.btnTpl.arrowRight))).attr("id","fancybox-container-"+s.id).addClass(a.baseClass).data("FancyBox",s).appendTo(a.parentEl),s.$refs={container:o},["bg","inner","infobar","toolbar","stage","caption","navigation"].forEach(function(t){s.$refs[t]=o.find(".fancybox-"+t)}),s.trigger("onInit"),s.activate(),s.jumpTo(s.currIndex)},translate:function(t,e){var n=t.opts.i18n[t.opts.lang]||t.opts.i18n.en;return e.replace(/\{\{(\w+)\}\}/g,function(t,e){return void 0===n[e]?t:n[e]})},addContent:function(t){var e,o=this,i=n.makeArray(t);n.each(i,function(t,e){var i,s,a,r,c,l={},h={};n.isPlainObject(e)?(l=e,h=e.opts||e):"object"===n.type(e)&&n(e).length?(h=(i=n(e)).data()||{},(h=n.extend(!0,{},h,h.options)).$orig=i,l.src=o.opts.src||h.src||i.attr("href"),l.type||l.src||(l.type="inline",l.src=e)):l={type:"html",src:e+""},l.opts=n.extend(!0,{},o.opts,h),n.isArray(h.buttons)&&(l.opts.buttons=h.buttons),n.fancybox.isMobile&&l.opts.mobile&&(l.opts=p(l.opts,l.opts.mobile)),s=l.type||l.opts.type,r=l.src||"",!s&&r&&((a=r.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))?(s="video",l.opts.video.format||(l.opts.video.format="video/"+("ogv"===a[1]?"ogg":a[1]))):r.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)?s="image":r.match(/\.(pdf)((\?|#).*)?$/i)?(s="iframe",l=n.extend(!0,l,{contentType:"pdf",opts:{iframe:{preload:!1}}})):"#"===r.charAt(0)&&(s="inline")),s?l.type=s:o.trigger("objectNeedsType",l),l.contentType||(l.contentType=n.inArray(l.type,["html","inline","ajax"])>-1?"html":l.type),l.index=o.group.length,"auto"==l.opts.smallBtn&&(l.opts.smallBtn=n.inArray(l.type,["html","inline","ajax"])>-1),"auto"===l.opts.toolbar&&(l.opts.toolbar=!l.opts.smallBtn),l.$thumb=l.opts.$thumb||null,l.opts.$trigger&&l.index===o.opts.index&&(l.$thumb=l.opts.$trigger.find("img:first"),l.$thumb.length&&(l.opts.$orig=l.opts.$trigger)),l.$thumb&&l.$thumb.length||!l.opts.$orig||(l.$thumb=l.opts.$orig.find("img:first")),l.$thumb&&!l.$thumb.length&&(l.$thumb=null),l.thumb=l.opts.thumb||(l.$thumb?l.$thumb[0].src:null),"function"===n.type(l.opts.caption)&&(l.opts.caption=l.opts.caption.apply(e,[o,l])),"function"===n.type(o.opts.caption)&&(l.opts.caption=o.opts.caption.apply(e,[o,l])),l.opts.caption instanceof n||(l.opts.caption=void 0===l.opts.caption?"":l.opts.caption+""),"ajax"===l.type&&(c=r.split(/\s+/,2)).length>1&&(l.src=c.shift(),l.opts.filter=c.shift()),l.opts.modal&&(l.opts=n.extend(!0,l.opts,{trapFocus:!0,infobar:0,toolbar:0,smallBtn:0,keyboard:0,slideShow:0,fullScreen:0,thumbs:0,touch:0,clickContent:!1,clickSlide:!1,clickOutside:!1,dblclickContent:!1,dblclickSlide:!1,dblclickOutside:!1})),o.group.push(l)}),Object.keys(o.slides).length&&(o.updateControls(),(e=o.Thumbs)&&e.isActive&&(e.create(),e.focus()))},addEvents:function(){var e=this;e.removeEvents(),e.$refs.container.on("click.fb-close","[data-fancybox-close]",function(t){t.stopPropagation(),t.preventDefault(),e.close(t)}).on("touchstart.fb-prev click.fb-prev","[data-fancybox-prev]",function(t){t.stopPropagation(),t.preventDefault(),e.previous()}).on("touchstart.fb-next click.fb-next","[data-fancybox-next]",function(t){t.stopPropagation(),t.preventDefault(),e.next()}).on("click.fb","[data-fancybox-zoom]",function(t){e[e.isScaledDown()?"scaleToActual":"scaleToFit"]()}),r.on("orientationchange.fb resize.fb",function(t){t&&t.originalEvent&&"resize"===t.originalEvent.type?(e.requestId&&d(e.requestId),e.requestId=h(function(){e.update(t)})):(e.current&&"iframe"===e.current.type&&e.$refs.stage.hide(),setTimeout(function(){e.$refs.stage.show(),e.update(t)},n.fancybox.isMobile?600:250))}),c.on("keydown.fb",function(t){var o=(n.fancybox?n.fancybox.getInstance():null).current,i=t.keyCode||t.which;if(9!=i){if(!(!o.opts.keyboard||t.ctrlKey||t.altKey||t.shiftKey||n(t.target).is("input,textarea,video,audio,select")))return 8===i||27===i?(t.preventDefault(),void e.close(t)):37===i||38===i?(t.preventDefault(),void e.previous()):39===i||40===i?(t.preventDefault(),void e.next()):void e.trigger("afterKeydown",t,i)}else o.opts.trapFocus&&e.focus(t)}),e.group[e.currIndex].opts.idleTime&&(e.idleSecondsCounter=0,c.on("mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle",function(t){e.idleSecondsCounter=0,e.isIdle&&e.showControls(),e.isIdle=!1}),e.idleInterval=t.setInterval(function(){e.idleSecondsCounter++,e.idleSecondsCounter>=e.group[e.currIndex].opts.idleTime&&!e.isDragging&&(e.isIdle=!0,e.idleSecondsCounter=0,e.hideControls())},1e3))},removeEvents:function(){r.off("orientationchange.fb resize.fb"),c.off("keydown.fb .fb-idle"),this.$refs.container.off(".fb-close .fb-prev .fb-next"),this.idleInterval&&(t.clearInterval(this.idleInterval),this.idleInterval=null)},previous:function(t){return this.jumpTo(this.currPos-1,t)},next:function(t){return this.jumpTo(this.currPos+1,t)},jumpTo:function(t,e){var o,i,s,a,r,c,l,h,d,u=this,p=u.group.length;if(!(u.isDragging||u.isClosing||u.isAnimating&&u.firstRun)){if(t=parseInt(t,10),!(s=u.current?u.current.opts.loop:u.opts.loop)&&(t<0||t>=p))return!1;if(o=u.firstRun=!Object.keys(u.slides).length,r=u.current,u.prevIndex=u.currIndex,u.prevPos=u.currPos,a=u.createSlide(t),p>1&&((s||a.index<p-1)&&u.createSlide(t+1),(s||a.index>0)&&u.createSlide(t-1)),u.current=a,u.currIndex=a.index,u.currPos=a.pos,u.trigger("beforeShow",o),u.updateControls(),a.forcedDuration=void 0,n.isNumeric(e)?a.forcedDuration=e:e=a.opts[o?"animationDuration":"transitionDuration"],e=parseInt(e,10),i=u.isMoved(a),a.$slide.addClass("fancybox-slide--current"),o)return a.opts.animationEffect&&e&&u.$refs.container.css("transition-duration",e+"ms"),u.$refs.container.addClass("fancybox-is-open").trigger("focus"),u.loadSlide(a),void u.preload("image");c=n.fancybox.getTranslate(r.$slide),l=n.fancybox.getTranslate(u.$refs.stage),n.each(u.slides,function(t,e){n.fancybox.stop(e.$slide,!0)}),r.pos!==a.pos&&(r.isComplete=!1),r.$slide.removeClass("fancybox-slide--complete fancybox-slide--current"),i?(d=c.left-(r.pos*c.width+r.pos*r.opts.gutter),n.each(u.slides,function(t,o){o.$slide.removeClass("fancybox-animated").removeClass(function(t,e){return(e.match(/(^|\s)fancybox-fx-\S+/g)||[]).join(" ")});var i=o.pos*c.width+o.pos*o.opts.gutter;n.fancybox.setTranslate(o.$slide,{top:0,left:i-l.left+d}),o.pos!==a.pos&&o.$slide.addClass("fancybox-slide--"+(o.pos>a.pos?"next":"previous")),f(o.$slide),n.fancybox.animate(o.$slide,{top:0,left:(o.pos-a.pos)*c.width+(o.pos-a.pos)*o.opts.gutter},e,function(){o.$slide.css({transform:"",opacity:""}).removeClass("fancybox-slide--next fancybox-slide--previous"),o.pos===u.currPos&&u.complete()})})):e&&a.opts.transitionEffect&&(h="fancybox-animated fancybox-fx-"+a.opts.transitionEffect,r.$slide.addClass("fancybox-slide--"+(r.pos>a.pos?"next":"previous")),n.fancybox.animate(r.$slide,h,e,function(){r.$slide.removeClass(h).removeClass("fancybox-slide--next fancybox-slide--previous")},!1)),a.isLoaded?u.revealContent(a):u.loadSlide(a),u.preload("image")}},createSlide:function(t){var e,o;return o=(o=t%this.group.length)<0?this.group.length+o:o,!this.slides[t]&&this.group[o]&&(e=n('<div class="fancybox-slide"></div>').appendTo(this.$refs.stage),this.slides[t]=n.extend(!0,{},this.group[o],{pos:t,$slide:e,isLoaded:!1}),this.updateSlide(this.slides[t])),this.slides[t]},scaleToActual:function(t,e,o){var i,s,a,r,c,l=this,h=l.current,d=h.$content,u=n.fancybox.getTranslate(h.$slide).width,f=n.fancybox.getTranslate(h.$slide).height,p=h.width,g=h.height;l.isAnimating||l.isMoved()||!d||"image"!=h.type||!h.isLoaded||h.hasError||(l.isAnimating=!0,n.fancybox.stop(d),t=void 0===t?.5*u:t,e=void 0===e?.5*f:e,(i=n.fancybox.getTranslate(d)).top-=n.fancybox.getTranslate(h.$slide).top,i.left-=n.fancybox.getTranslate(h.$slide).left,r=p/i.width,c=g/i.height,s=.5*u-.5*p,a=.5*f-.5*g,p>u&&((s=i.left*r-(t*r-t))>0&&(s=0),s<u-p&&(s=u-p)),g>f&&((a=i.top*c-(e*c-e))>0&&(a=0),a<f-g&&(a=f-g)),l.updateCursor(p,g),n.fancybox.animate(d,{top:a,left:s,scaleX:r,scaleY:c},o||366,function(){l.isAnimating=!1}),l.SlideShow&&l.SlideShow.isActive&&l.SlideShow.stop())},scaleToFit:function(t){var e,o=this,i=o.current,s=i.$content;o.isAnimating||o.isMoved()||!s||"image"!=i.type||!i.isLoaded||i.hasError||(o.isAnimating=!0,n.fancybox.stop(s),e=o.getFitPos(i),o.updateCursor(e.width,e.height),n.fancybox.animate(s,{top:e.top,left:e.left,scaleX:e.width/s.width(),scaleY:e.height/s.height()},t||366,function(){o.isAnimating=!1}))},getFitPos:function(t){var e,o,i,s,a=t.$content,r=t.$slide,c=t.width||t.opts.width,l=t.height||t.opts.height,h={};return!!(t.isLoaded&&a&&a.length)&&(e=n.fancybox.getTranslate(this.$refs.stage).width,o=n.fancybox.getTranslate(this.$refs.stage).height,e-=parseFloat(r.css("paddingLeft"))+parseFloat(r.css("paddingRight"))+parseFloat(a.css("marginLeft"))+parseFloat(a.css("marginRight")),o-=parseFloat(r.css("paddingTop"))+parseFloat(r.css("paddingBottom"))+parseFloat(a.css("marginTop"))+parseFloat(a.css("marginBottom")),c&&l||(c=e,l=o),(c*=i=Math.min(1,e/c,o/l))>e-.5&&(c=e),(l*=i)>o-.5&&(l=o),"image"===t.type?(h.top=Math.floor(.5*(o-l))+parseFloat(r.css("paddingTop")),h.left=Math.floor(.5*(e-c))+parseFloat(r.css("paddingLeft"))):"video"===t.contentType&&(l>c/(s=t.opts.width&&t.opts.height?c/l:t.opts.ratio||16/9)?l=c/s:c>l*s&&(c=l*s)),h.width=c,h.height=l,h)},update:function(t){var e=this;n.each(e.slides,function(n,o){e.updateSlide(o,t)})},updateSlide:function(t,e){var o=t&&t.$content,i=t.width||t.opts.width,s=t.height||t.opts.height,a=t.$slide;this.adjustCaption(t),o&&(i||s||"video"===t.contentType)&&!t.hasError&&(n.fancybox.stop(o),n.fancybox.setTranslate(o,this.getFitPos(t)),t.pos===this.currPos&&(this.isAnimating=!1,this.updateCursor())),this.adjustLayout(t),a.length&&(a.trigger("refresh"),t.pos===this.currPos&&this.$refs.toolbar.add(this.$refs.navigation.find(".fancybox-button--arrow_right")).toggleClass("compensate-for-scrollbar",a.get(0).scrollHeight>a.get(0).clientHeight)),this.trigger("onUpdate",t,e)},centerSlide:function(t){var e=this,o=e.current,i=o.$slide;!e.isClosing&&o&&(i.siblings().css({transform:"",opacity:""}),i.parent().children().removeClass("fancybox-slide--previous fancybox-slide--next"),n.fancybox.animate(i,{top:0,left:0,opacity:1},void 0===t?0:t,function(){i.css({transform:"",opacity:""}),o.isComplete||e.complete()},!1))},isMoved:function(t){var e,o,i=t||this.current;return!!i&&(o=n.fancybox.getTranslate(this.$refs.stage),e=n.fancybox.getTranslate(i.$slide),!i.$slide.hasClass("fancybox-animated")&&(Math.abs(e.top-o.top)>.5||Math.abs(e.left-o.left)>.5))},updateCursor:function(t,e){var o,i,s=this.current,a=this.$refs.container;s&&!this.isClosing&&this.Guestures&&(a.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"),i=!!(o=this.canPan(t,e))||this.isZoomable(),a.toggleClass("fancybox-is-zoomable",i),n("[data-fancybox-zoom]").prop("disabled",!i),o?a.addClass("fancybox-can-pan"):i&&("zoom"===s.opts.clickContent||n.isFunction(s.opts.clickContent)&&"zoom"==s.opts.clickContent(s))?a.addClass("fancybox-can-zoomIn"):s.opts.touch&&(s.opts.touch.vertical||this.group.length>1)&&"video"!==s.contentType&&a.addClass("fancybox-can-swipe"))},isZoomable:function(){var t,e=this.current;if(e&&!this.isClosing&&"image"===e.type&&!e.hasError){if(!e.isLoaded)return!0;if((t=this.getFitPos(e))&&(e.width>t.width||e.height>t.height))return!0}return!1},isScaledDown:function(t,e){var o=!1,i=this.current,s=i.$content;return void 0!==t&&void 0!==e?o=t<i.width&&e<i.height:s&&(o=(o=n.fancybox.getTranslate(s)).width<i.width&&o.height<i.height),o},canPan:function(t,e){var o=this.current,i=null,s=!1;return"image"===o.type&&(o.isComplete||t&&e)&&!o.hasError&&(s=this.getFitPos(o),void 0!==t&&void 0!==e?i={width:t,height:e}:o.isComplete&&(i=n.fancybox.getTranslate(o.$content)),i&&s&&(s=Math.abs(i.width-s.width)>1.5||Math.abs(i.height-s.height)>1.5)),s},loadSlide:function(t){var e,o,i,s=this;if(!t.isLoading&&!t.isLoaded){if(t.isLoading=!0,!1===s.trigger("beforeLoad",t))return t.isLoading=!1,!1;switch(e=t.type,(o=t.$slide).off("refresh").trigger("onReset").addClass(t.opts.slideClass),e){case"image":s.setImage(t);break;case"iframe":s.setIframe(t);break;case"html":s.setContent(t,t.src||t.content);break;case"video":s.setContent(t,t.opts.video.tpl.replace(/\{\{src\}\}/gi,t.src).replace("{{format}}",t.opts.videoFormat||t.opts.video.format||"").replace("{{poster}}",t.thumb||""));break;case"inline":n(t.src).length?s.setContent(t,n(t.src)):s.setError(t);break;case"ajax":s.showLoading(t),i=n.ajax(n.extend({},t.opts.ajax.settings,{url:t.src,success:function(e,n){"success"===n&&s.setContent(t,e)},error:function(e,n){e&&"abort"!==n&&s.setError(t)}})),o.one("onReset",function(){i.abort()});break;default:s.setError(t)}return!0}},setImage:function(t){var o,i=this;setTimeout(function(){var e=t.$image;i.isClosing||!t.isLoading||e&&e.length&&e[0].complete||t.hasError||i.showLoading(t)},50),i.checkSrcset(t),t.$content=n('<div class="fancybox-content"></div>').addClass("fancybox-is-hidden").appendTo(t.$slide.addClass("fancybox-slide--image")),!1!==t.opts.preload&&t.opts.width&&t.opts.height&&t.thumb&&(t.width=t.opts.width,t.height=t.opts.height,(o=e.createElement("img")).onerror=function(){n(this).remove(),t.$ghost=null},o.onload=function(){i.afterLoad(t)},t.$ghost=n(o).addClass("fancybox-image").appendTo(t.$content).attr("src",t.thumb)),i.setBigImage(t)},checkSrcset:function(e){var n,o,i,s,a=e.opts.srcset||e.opts.image.srcset;if(a){i=t.devicePixelRatio||1,s=t.innerWidth*i,(o=a.split(",").map(function(t){var e={};return t.trim().split(/\s+/).forEach(function(t,n){var o=parseInt(t.substring(0,t.length-1),10);if(0===n)return e.url=t;o&&(e.value=o,e.postfix=t[t.length-1])}),e})).sort(function(t,e){return t.value-e.value});for(var r=0;r<o.length;r++){var c=o[r];if("w"===c.postfix&&c.value>=s||"x"===c.postfix&&c.value>=i){n=c;break}}!n&&o.length&&(n=o[o.length-1]),n&&(e.src=n.url,e.width&&e.height&&"w"==n.postfix&&(e.height=e.width/e.height*n.value,e.width=n.value),e.opts.srcset=a)}},setBigImage:function(t){var o=this,i=e.createElement("img"),s=n(i);t.$image=s.one("error",function(){o.setError(t)}).one("load",function(){var e;t.$ghost||(o.resolveImageSlideSize(t,this.naturalWidth,this.naturalHeight),o.afterLoad(t)),o.isClosing||(t.opts.srcset&&((e=t.opts.sizes)&&"auto"!==e||(e=(t.width/t.height>1&&r.width()/r.height()>1?"100":Math.round(t.width/t.height*100))+"vw"),s.attr("sizes",e).attr("srcset",t.opts.srcset)),t.$ghost&&setTimeout(function(){t.$ghost&&!o.isClosing&&t.$ghost.hide()},Math.min(300,Math.max(1e3,t.height/1600))),o.hideLoading(t))}).addClass("fancybox-image").attr("src",t.src).appendTo(t.$content),(i.complete||"complete"==i.readyState)&&s.naturalWidth&&s.naturalHeight?s.trigger("load"):i.error&&s.trigger("error")},resolveImageSlideSize:function(t,e,n){var o=parseInt(t.opts.width,10),i=parseInt(t.opts.height,10);t.width=e,t.height=n,o>0&&(t.width=o,t.height=Math.floor(o*n/e)),i>0&&(t.width=Math.floor(i*e/n),t.height=i)},setIframe:function(t){var e,o=this,i=t.opts.iframe,s=t.$slide;t.$content=n('<div class="fancybox-content'+(i.preload?" fancybox-is-hidden":"")+'"></div>').css(i.css).appendTo(s),s.addClass("fancybox-slide--"+t.contentType),t.$iframe=e=n(i.tpl.replace(/\{rnd\}/g,(new Date).getTime())).attr(i.attr).appendTo(t.$content),i.preload?(o.showLoading(t),e.on("load.fb error.fb",function(e){this.isReady=1,t.$slide.trigger("refresh"),o.afterLoad(t)}),s.on("refresh.fb",function(){var n,o=t.$content,a=i.css.width,r=i.css.height;if(1===e[0].isReady){try{n=e.contents().find("body")}catch(t){}n&&n.length&&n.children().length&&(s.css("overflow","visible"),o.css({width:"100%","max-width":"100%",height:"9999px"}),void 0===a&&(a=Math.ceil(Math.max(n[0].clientWidth,n.outerWidth(!0)))),o.css("width",a||"").css("max-width",""),void 0===r&&(r=Math.ceil(Math.max(n[0].clientHeight,n.outerHeight(!0)))),o.css("height",r||""),s.css("overflow","auto")),o.removeClass("fancybox-is-hidden")}})):o.afterLoad(t),e.attr("src",t.src),s.one("onReset",function(){try{n(this).find("iframe").hide().unbind().attr("src","//about:blank")}catch(t){}n(this).off("refresh.fb").empty(),t.isLoaded=!1,t.isRevealed=!1})},setContent:function(t,e){var o;this.isClosing||(this.hideLoading(t),t.$content&&n.fancybox.stop(t.$content),t.$slide.empty(),(o=e)&&o.hasOwnProperty&&o instanceof n&&e.parent().length?((e.hasClass("fancybox-content")||e.parent().hasClass("fancybox-content"))&&e.parents(".fancybox-slide").trigger("onReset"),t.$placeholder=n("<div>").hide().insertAfter(e),e.css("display","inline-block")):t.hasError||("string"===n.type(e)&&(e=n("<div>").append(n.trim(e)).contents()),t.opts.filter&&(e=n("<div>").html(e).find(t.opts.filter))),t.$slide.one("onReset",function(){n(this).find("video,audio").trigger("pause"),t.$placeholder&&(t.$placeholder.after(e.removeClass("fancybox-content").hide()).remove(),t.$placeholder=null),t.$smallBtn&&(t.$smallBtn.remove(),t.$smallBtn=null),t.hasError||(n(this).empty(),t.isLoaded=!1,t.isRevealed=!1)}),n(e).appendTo(t.$slide),n(e).is("video,audio")&&(n(e).addClass("fancybox-video"),n(e).wrap("<div></div>"),t.contentType="video",t.opts.width=t.opts.width||n(e).attr("width"),t.opts.height=t.opts.height||n(e).attr("height")),t.$content=t.$slide.children().filter("div,form,main,video,audio,article,.fancybox-content").first(),t.$content.siblings().hide(),t.$content.length||(t.$content=t.$slide.wrapInner("<div></div>").children().first()),t.$content.addClass("fancybox-content"),t.$slide.addClass("fancybox-slide--"+t.contentType),this.afterLoad(t))},setError:function(t){t.hasError=!0,t.$slide.trigger("onReset").removeClass("fancybox-slide--"+t.contentType).addClass("fancybox-slide--error"),t.contentType="html",this.setContent(t,this.translate(t,t.opts.errorTpl)),t.pos===this.currPos&&(this.isAnimating=!1)},showLoading:function(t){(t=t||this.current)&&!t.$spinner&&(t.$spinner=n(this.translate(this,this.opts.spinnerTpl)).appendTo(t.$slide).hide().fadeIn("fast"))},hideLoading:function(t){(t=t||this.current)&&t.$spinner&&(t.$spinner.stop().remove(),delete t.$spinner)},afterLoad:function(t){this.isClosing||(t.isLoading=!1,t.isLoaded=!0,this.trigger("afterLoad",t),this.hideLoading(t),!t.opts.smallBtn||t.$smallBtn&&t.$smallBtn.length||(t.$smallBtn=n(this.translate(t,t.opts.btnTpl.smallBtn)).appendTo(t.$content)),t.opts.protect&&t.$content&&!t.hasError&&(t.$content.on("contextmenu.fb",function(t){return 2==t.button&&t.preventDefault(),!0}),"image"===t.type&&n('<div class="fancybox-spaceball"></div>').appendTo(t.$content)),this.adjustCaption(t),this.adjustLayout(t),t.pos===this.currPos&&this.updateCursor(),this.revealContent(t))},adjustCaption:function(t){var e,n=t||this.current,o=n.opts.caption,i=n.opts.preventCaptionOverlap,s=this.$refs.caption,a=!1;s.toggleClass("fancybox-caption--separate",i),i&&o&&o.length&&(n.pos!==this.currPos?((e=s.clone().appendTo(s.parent())).children().eq(0).empty().html(o),a=e.outerHeight(!0),e.empty().remove()):this.$caption&&(a=this.$caption.outerHeight(!0)),n.$slide.css("padding-bottom",a||""))},adjustLayout:function(t){var e,n,o,i,s=t||this.current;s.isLoaded&&!0!==s.opts.disableLayoutFix&&(s.$content.css("margin-bottom",""),s.$content.outerHeight()>s.$slide.height()+.5&&(o=s.$slide[0].style["padding-bottom"],i=s.$slide.css("padding-bottom"),parseFloat(i)>0&&(e=s.$slide[0].scrollHeight,s.$slide.css("padding-bottom",0),Math.abs(e-s.$slide[0].scrollHeight)<1&&(n=i),s.$slide.css("padding-bottom",o))),s.$content.css("margin-bottom",n))},revealContent:function(t){var e,o,i,s,a=this,r=t.$slide,c=!1,l=!1,h=a.isMoved(t),d=t.isRevealed;return t.isRevealed=!0,e=t.opts[a.firstRun?"animationEffect":"transitionEffect"],i=t.opts[a.firstRun?"animationDuration":"transitionDuration"],i=parseInt(void 0===t.forcedDuration?i:t.forcedDuration,10),!h&&t.pos===a.currPos&&i||(e=!1),"zoom"===e&&(t.pos===a.currPos&&i&&"image"===t.type&&!t.hasError&&(l=a.getThumbPos(t))?c=a.getFitPos(t):e="fade"),"zoom"===e?(a.isAnimating=!0,c.scaleX=c.width/l.width,c.scaleY=c.height/l.height,"auto"==(s=t.opts.zoomOpacity)&&(s=Math.abs(t.width/t.height-l.width/l.height)>.1),s&&(l.opacity=.1,c.opacity=1),n.fancybox.setTranslate(t.$content.removeClass("fancybox-is-hidden"),l),f(t.$content),void n.fancybox.animate(t.$content,c,i,function(){a.isAnimating=!1,a.complete()})):(a.updateSlide(t),e?(n.fancybox.stop(r),o="fancybox-slide--"+(t.pos>=a.prevPos?"next":"previous")+" fancybox-animated fancybox-fx-"+e,r.addClass(o).removeClass("fancybox-slide--current"),t.$content.removeClass("fancybox-is-hidden"),f(r),"image"!==t.type&&t.$content.hide().show(0),void n.fancybox.animate(r,"fancybox-slide--current",i,function(){r.removeClass(o).css({transform:"",opacity:""}),t.pos===a.currPos&&a.complete()},!0)):(t.$content.removeClass("fancybox-is-hidden"),d||!h||"image"!==t.type||t.hasError||t.$content.hide().fadeIn("fast"),void(t.pos===a.currPos&&a.complete())))},getThumbPos:function(t){var o,i,s,a,r,c,l=t.$thumb;return!(!l||!function(t){var o,i;return!(!t||t.ownerDocument!==e)&&(n(".fancybox-container").css("pointer-events","none"),o={x:t.getBoundingClientRect().left+t.offsetWidth/2,y:t.getBoundingClientRect().top+t.offsetHeight/2},i=e.elementFromPoint(o.x,o.y)===t,n(".fancybox-container").css("pointer-events",""),i)}(l[0]))&&(i=n.fancybox.getTranslate(l),s=parseFloat(l.css("border-top-width")||0),a=parseFloat(l.css("border-right-width")||0),r=parseFloat(l.css("border-bottom-width")||0),c=parseFloat(l.css("border-left-width")||0),o={top:i.top+s,left:i.left+c,width:i.width-a-c,height:i.height-s-r,scaleX:1,scaleY:1},i.width>0&&i.height>0&&o)},complete:function(){var t,e=this,o=e.current,i={};!e.isMoved()&&o.isLoaded&&(o.isComplete||(o.isComplete=!0,o.$slide.siblings().trigger("onReset"),e.preload("inline"),f(o.$slide),o.$slide.addClass("fancybox-slide--complete"),n.each(e.slides,function(t,o){o.pos>=e.currPos-1&&o.pos<=e.currPos+1?i[o.pos]=o:o&&(n.fancybox.stop(o.$slide),o.$slide.off().remove())}),e.slides=i),e.isAnimating=!1,e.updateCursor(),e.trigger("afterShow"),o.opts.video.autoStart&&o.$slide.find("video,audio").filter(":visible:first").trigger("play").one("ended",function(){Document.exitFullscreen?Document.exitFullscreen():this.webkitExitFullscreen&&this.webkitExitFullscreen(),e.next()}),o.opts.autoFocus&&"html"===o.contentType&&((t=o.$content.find("input[autofocus]:enabled:visible:first")).length?t.trigger("focus"):e.focus(null,!0)),o.$slide.scrollTop(0).scrollLeft(0))},preload:function(t){var e,n;this.group.length<2||(n=this.slides[this.currPos+1],(e=this.slides[this.currPos-1])&&e.type===t&&this.loadSlide(e),n&&n.type===t&&this.loadSlide(n))},focus:function(t,o){var i,s,a=["a[href]","area[href]",'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',"select:not([disabled]):not([aria-hidden])","textarea:not([disabled]):not([aria-hidden])","button:not([disabled]):not([aria-hidden])","iframe","object","embed","video","audio","[contenteditable]",'[tabindex]:not([tabindex^="-"])'].join(",");this.isClosing||((i=(i=!t&&this.current&&this.current.isComplete?this.current.$slide.find("*:visible"+(o?":not(.fancybox-close-small)":"")):this.$refs.container.find("*:visible")).filter(a).filter(function(){return"hidden"!==n(this).css("visibility")&&!n(this).hasClass("disabled")})).length?(s=i.index(e.activeElement),t&&t.shiftKey?(s<0||0==s)&&(t.preventDefault(),i.eq(i.length-1).trigger("focus")):(s<0||s==i.length-1)&&(t&&t.preventDefault(),i.eq(0).trigger("focus"))):this.$refs.container.trigger("focus"))},activate:function(){var t=this;n(".fancybox-container").each(function(){var e=n(this).data("FancyBox");e&&e.id!==t.id&&!e.isClosing&&(e.trigger("onDeactivate"),e.removeEvents(),e.isVisible=!1)}),t.isVisible=!0,(t.current||t.isIdle)&&(t.update(),t.updateControls()),t.trigger("onActivate"),t.addEvents()},close:function(t,e){var o,i,s,a,r,c,l,d=this,u=d.current,p=function(){d.cleanUp(t)};return!d.isClosing&&(d.isClosing=!0,!1===d.trigger("beforeClose",t)?(d.isClosing=!1,h(function(){d.update()}),!1):(d.removeEvents(),s=u.$content,o=u.opts.animationEffect,i=n.isNumeric(e)?e:o?u.opts.animationDuration:0,u.$slide.removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated"),!0!==t?n.fancybox.stop(u.$slide):o=!1,u.$slide.siblings().trigger("onReset").remove(),i&&d.$refs.container.removeClass("fancybox-is-open").addClass("fancybox-is-closing").css("transition-duration",i+"ms"),d.hideLoading(u),d.hideControls(!0),d.updateCursor(),"zoom"!==o||s&&i&&"image"===u.type&&!d.isMoved()&&!u.hasError&&(l=d.getThumbPos(u))||(o="fade"),"zoom"===o?(n.fancybox.stop(s),c={top:(a=n.fancybox.getTranslate(s)).top,left:a.left,scaleX:a.width/l.width,scaleY:a.height/l.height,width:l.width,height:l.height},"auto"==(r=u.opts.zoomOpacity)&&(r=Math.abs(u.width/u.height-l.width/l.height)>.1),r&&(l.opacity=0),n.fancybox.setTranslate(s,c),f(s),n.fancybox.animate(s,l,i,p),!0):(o&&i?n.fancybox.animate(u.$slide.addClass("fancybox-slide--previous").removeClass("fancybox-slide--current"),"fancybox-animated fancybox-fx-"+o,i,p):!0===t?setTimeout(p,i):p(),!0)))},cleanUp:function(e){var o,i,s,a=this.current.opts.$orig;this.current.$slide.trigger("onReset"),this.$refs.container.empty().remove(),this.trigger("afterClose",e),this.current.opts.backFocus&&(a&&a.length&&a.is(":visible")||(a=this.$trigger),a&&a.length&&(i=t.scrollX,s=t.scrollY,a.trigger("focus"),n("html, body").scrollTop(s).scrollLeft(i))),this.current=null,(o=n.fancybox.getInstance())?o.activate():(n("body").removeClass("fancybox-active compensate-for-scrollbar"),n("#fancybox-style-noscroll").remove())},trigger:function(t,e){var o,i=Array.prototype.slice.call(arguments,1),s=e&&e.opts?e:this.current;if(s?i.unshift(s):s=this,i.unshift(this),n.isFunction(s.opts[t])&&(o=s.opts[t].apply(s,i)),!1===o)return o;"afterClose"!==t&&this.$refs?this.$refs.container.trigger(t+".fb",i):c.trigger(t+".fb",i)},updateControls:function(){var t=this.current,o=t.index,i=this.$refs.container,s=this.$refs.caption,a=t.opts.caption;t.$slide.trigger("refresh"),a&&a.length?(this.$caption=s,s.children().eq(0).html(a)):this.$caption=null,this.hasHiddenControls||this.isIdle||this.showControls(),i.find("[data-fancybox-count]").html(this.group.length),i.find("[data-fancybox-index]").html(o+1),i.find("[data-fancybox-prev]").prop("disabled",!t.opts.loop&&o<=0),i.find("[data-fancybox-next]").prop("disabled",!t.opts.loop&&o>=this.group.length-1),"image"===t.type?i.find("[data-fancybox-zoom]").show().end().find("[data-fancybox-download]").attr("href",t.opts.image.src||t.src).show():t.opts.toolbar&&i.find("[data-fancybox-download],[data-fancybox-zoom]").hide(),n(e.activeElement).is(":hidden,[disabled]")&&this.$refs.container.trigger("focus")},hideControls:function(t){var e=["infobar","toolbar","nav"];!t&&this.current.opts.preventCaptionOverlap||e.push("caption"),this.$refs.container.removeClass(e.map(function(t){return"fancybox-show-"+t}).join(" ")),this.hasHiddenControls=!0},showControls:function(){var t=this.current?this.current.opts:this.opts,e=this.$refs.container;this.hasHiddenControls=!1,this.idleSecondsCounter=0,e.toggleClass("fancybox-show-toolbar",!(!t.toolbar||!t.buttons)).toggleClass("fancybox-show-infobar",!!(t.infobar&&this.group.length>1)).toggleClass("fancybox-show-caption",!!this.$caption).toggleClass("fancybox-show-nav",!!(t.arrows&&this.group.length>1)).toggleClass("fancybox-is-modal",!!t.modal)},toggleControls:function(){this.hasHiddenControls?this.showControls():this.hideControls()}}),n.fancybox={version:"3.5.7",defaults:a,getInstance:function(t){var e=n('.fancybox-container:not(".fancybox-is-closing"):last').data("FancyBox"),o=Array.prototype.slice.call(arguments,1);return e instanceof g&&("string"===n.type(t)?e[t].apply(e,o):"function"===n.type(t)&&t.apply(e,o),e)},open:function(t,e,n){return new g(t,e,n)},close:function(t){var e=this.getInstance();e&&(e.close(),!0===t&&this.close(t))},destroy:function(){this.close(!0),c.add("body").off("click.fb-start","**")},isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),use3d:(i=e.createElement("div"),t.getComputedStyle&&t.getComputedStyle(i)&&t.getComputedStyle(i).getPropertyValue("transform")&&!(e.documentMode&&e.documentMode<11)),getTranslate:function(t){var e;return!(!t||!t.length)&&{top:(e=t[0].getBoundingClientRect()).top||0,left:e.left||0,width:e.width,height:e.height,opacity:parseFloat(t.css("opacity"))}},setTranslate:function(t,e){var n="",o={};if(t&&e)return void 0===e.left&&void 0===e.top||(n=(void 0===e.left?t.position().left:e.left)+"px, "+(void 0===e.top?t.position().top:e.top)+"px",n=this.use3d?"translate3d("+n+", 0px)":"translate("+n+")"),void 0!==e.scaleX&&void 0!==e.scaleY?n+=" scale("+e.scaleX+", "+e.scaleY+")":void 0!==e.scaleX&&(n+=" scaleX("+e.scaleX+")"),n.length&&(o.transform=n),void 0!==e.opacity&&(o.opacity=e.opacity),void 0!==e.width&&(o.width=e.width),void 0!==e.height&&(o.height=e.height),t.css(o)},animate:function(t,e,o,i,s){var a,r=this;n.isFunction(o)&&(i=o,o=null),r.stop(t),a=r.getTranslate(t),t.on(u,function(c){(!c||!c.originalEvent||t.is(c.originalEvent.target)&&"z-index"!=c.originalEvent.propertyName)&&(r.stop(t),n.isNumeric(o)&&t.css("transition-duration",""),n.isPlainObject(e)?void 0!==e.scaleX&&void 0!==e.scaleY&&r.setTranslate(t,{top:e.top,left:e.left,width:a.width*e.scaleX,height:a.height*e.scaleY,scaleX:1,scaleY:1}):!0!==s&&t.removeClass(e),n.isFunction(i)&&i(c))}),n.isNumeric(o)&&t.css("transition-duration",o+"ms"),n.isPlainObject(e)?(void 0!==e.scaleX&&void 0!==e.scaleY&&(delete e.width,delete e.height,t.parent().hasClass("fancybox-slide--image")&&t.parent().addClass("fancybox-is-scaling")),n.fancybox.setTranslate(t,e)):t.addClass(e),t.data("timer",setTimeout(function(){t.trigger(u)},o+33))},stop:function(t,e){t&&t.length&&(clearTimeout(t.data("timer")),e&&t.trigger(u),t.off(u).css("transition-duration",""),t.parent().removeClass("fancybox-is-scaling"))}},n.fn.fancybox=function(t){var e;return(e=(t=t||{}).selector||!1)?n("body").off("click.fb-start",e).on("click.fb-start",e,{options:t},b):this.off("click.fb-start").on("click.fb-start",{items:this,options:t},b),this},c.on("click.fb-start","[data-fancybox]",b),c.on("click.fb-start","[data-fancybox-trigger]",function(t){n('[data-fancybox="'+n(this).attr("data-fancybox-trigger")+'"]').eq(n(this).attr("data-fancybox-index")||0).trigger("click.fb-start",{$trigger:n(this)})}),s=null,c.on("mousedown mouseup focus blur",".fancybox-button",function(t){switch(t.type){case"mousedown":s=n(this);break;case"mouseup":s=null;break;case"focusin":n(".fancybox-button").removeClass("fancybox-focus"),n(this).is(s)||n(this).is("[disabled]")||n(this).addClass("fancybox-focus");break;case"focusout":n(".fancybox-button").removeClass("fancybox-focus")}})}function b(t,e){var o,i,s,a=[],r=0;t&&t.isDefaultPrevented()||(t.preventDefault(),e=e||{},t&&t.data&&(e=p(t.data.options,e)),o=e.$target||n(t.currentTarget).trigger("blur"),(s=n.fancybox.getInstance())&&s.$trigger&&s.$trigger.is(o)||(a=e.selector?n(e.selector):(i=o.attr("data-fancybox")||"")?(a=t.data?t.data.items:[]).length?a.filter('[data-fancybox="'+i+'"]'):n('[data-fancybox="'+i+'"]'):[o],(r=n(a).index(o))<0&&(r=0),(s=n.fancybox.open(a,e,r)).$trigger=o))}}(window,document,jQuery),function(t){"use strict";var e={youtube:{matcher:/(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,params:{autoplay:1,autohide:1,fs:1,rel:0,hd:1,wmode:"transparent",enablejsapi:1,html5:1},paramPlace:8,type:"iframe",url:"https://www.youtube-nocookie.com/embed/$4",thumb:"https://img.youtube.com/vi/$4/hqdefault.jpg"},vimeo:{matcher:/^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,params:{autoplay:1,hd:1,show_title:1,show_byline:1,show_portrait:0,fullscreen:1},paramPlace:3,type:"iframe",url:"//player.vimeo.com/video/$2"},rutube:{matcher:/^.+rutube.ru\/.*\/(.*\/)?([\w]+)(.*)\/?/,params:{frameBorder:0},paramPlace:1,type:"iframe",url:"//rutube.ru/play/embed/$2",thumb:"https://rutube.ru/api/video/$2/thumbnail/?redirect=1"},vk:{matcher:/^.+(vk\.com|vk\.ru|vkvideo\.ru).+video(?:\?z=video|)(-?\d+)_(\d+)/,params:{autoplay:1,hd:2,js_api:1,frameBorder:0},paramPlace:1,type:"iframe",url:"https://vk.ru/video_ext.php?oid=$2&id=$3"},instagram:{matcher:/(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,type:"image",url:"//$1/p/$2/media/?size=l"},gmap_place:{matcher:/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,type:"iframe",url:function(t){return"//maps.google."+t[2]+"/?ll="+(t[9]?t[9]+"&z="+Math.floor(t[10])+(t[12]?t[12].replace(/^\//,"&"):""):t[12]+"").replace(/\?/,"&")+"&output="+(t[12]&&t[12].indexOf("layer=c")>0?"svembed":"embed")}},gmap_search:{matcher:/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,type:"iframe",url:function(t){return"//maps.google."+t[2]+"/maps?q="+t[5].replace("query=","q=").replace("api=1","")+"&output=embed"}}},n=function(e,n,o){if(e)return o=o||"","object"===t.type(o)&&(o=t.param(o,!0)),t.each(n,function(t,n){e=e.replace("$"+t,n||"")}),o.length&&(e+=(e.indexOf("?")>0?"&":"?")+o),e};t(document).on("objectNeedsType.fb",function(o,i,s){var a,r,c,l,h,d,u,f=s.src||"",p=!1;a=t.extend(!0,{},e,s.opts.media),t.each(a,function(e,o){if(c=f.match(o.matcher)){if(p=o.type,u=e,d={},o.paramPlace&&c[o.paramPlace]){"?"==(h=c[o.paramPlace])[0]&&(h=h.substring(1)),h=h.split("&");for(var i=0;i<h.length;++i){var a=h[i].split("=",2);2==a.length&&(d[a[0]]=decodeURIComponent(a[1].replace(/\+/g," ")))}}return l=t.extend(!0,{},o.params,s.opts[e],d),f="function"===t.type(o.url)?o.url.call(this,c,l,s):n(o.url,c,l),r="function"===t.type(o.thumb)?o.thumb.call(this,c,l,s):n(o.thumb,c),"youtube"===e?f=f.replace(/&t=((\d+)m)?(\d+)s/,function(t,e,n,o){return"&start="+((n?60*parseInt(n,10):0)+parseInt(o,10))}):"vimeo"===e?f=f.replace("&%23","#"):"rutube"===e&&(f=f.replace("&%23","#")),!1}}),p?(s.opts.thumb||s.opts.$thumb&&s.opts.$thumb.length||(s.opts.thumb=r),"iframe"===p&&(s.opts=t.extend(!0,s.opts,{iframe:{preload:!1,attr:{scrolling:"no"}}})),t.extend(s,{type:p,src:f,origSrc:s.src,contentSource:u,contentType:"image"===p?"image":"gmap_place"==u||"gmap_search"==u?"map":"video"})):f&&(s.type=s.opts.defaultType)});var o={youtube:{src:"https://www.youtube.com/iframe_api",class:"YT",loading:!1,loaded:!1},vimeo:{src:"https://player.vimeo.com/api/player.js",class:"Vimeo",loading:!1,loaded:!1},rutube:{src:"https://cdn.jsdelivr.net/gh/evikza/rutube-player@178175923bd50cc759e2c3055c6b502e56b54e92/dist/fb.rt.js",class:"Rutube",loading:!1,loaded:!1},vk:{src:"https://vk.com/js/api/videoplayer.js",class:"VK",loading:!1,loaded:!1},load:function(t){var e,n=this;this[t].loaded?setTimeout(function(){n.done(t)}):this[t].loading||(this[t].loading=!0,(e=document.createElement("script")).type="text/javascript",e.src=this[t].src,"youtube"===t?window.onYouTubeIframeAPIReady=function(){n[t].loaded=!0,n.done(t)}:e.onload=function(){n[t].loaded=!0,n.done(t)},document.body.appendChild(e))},done:function(e){var n,o,i;"youtube"===e&&delete window.onYouTubeIframeAPIReady,(n=t.fancybox.getInstance())&&(o=n.current.$content.find("iframe"),"youtube"===e&&void 0!==YT&&YT?i=new YT.Player(o.attr("id"),{events:{onStateChange:function(t){0==t.data&&n.next()}}}):"vimeo"===e&&void 0!==Vimeo&&Vimeo?(i=new Vimeo.Player(o)).on("ended",function(){n.next()}):"rutube"===e?(i=new Rutube).Player(o.attr("id"),{events:{onReady:function(){setTimeout(i.play(),700)},onStateChange:function(t){t.playerState.ENDED&&n.next()}}}):"vk"===e&&(i=VK.VideoPlayer(o[0])).on("ended",function(){n.next()}))}};t(document).on({"afterShow.fb":function(t,e,n){e.group.length>1&&("youtube"===n.contentSource||"vimeo"===n.contentSource||"rutube"===n.contentSource||"vk"===n.contentSource)?o.load(n.contentSource):"rutube"===n.contentSource&&o.load(n.contentSource)}})}(jQuery),function(t,e,n){"use strict";var o=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||function(e){return t.setTimeout(e,1e3/60)},i=t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.mozCancelAnimationFrame||t.oCancelAnimationFrame||function(e){t.clearTimeout(e)},s=function(e){var n=[];for(var o in e=(e=e.originalEvent||e||t.e).touches&&e.touches.length?e.touches:e.changedTouches&&e.changedTouches.length?e.changedTouches:[e])e[o].pageX?n.push({x:e[o].pageX,y:e[o].pageY}):e[o].clientX&&n.push({x:e[o].clientX,y:e[o].clientY});return n},a=function(t,e,n){return e&&t?"x"===n?t.x-e.x:"y"===n?t.y-e.y:Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2)):0},r=function(t){if(t.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe')||n.isFunction(t.get(0).onclick)||t.data("selectable"))return!0;for(var e=0,o=t[0].attributes,i=o.length;e<i;e++)if("data-fancybox-"===o[e].nodeName.substr(0,14))return!0;return!1},c=function(e){for(var n,o,i,s,a,r=!1;n=e.get(0),o=void 0,i=void 0,s=void 0,a=void 0,o=t.getComputedStyle(n)["overflow-y"],i=t.getComputedStyle(n)["overflow-x"],s=("scroll"===o||"auto"===o)&&n.scrollHeight>n.clientHeight,a=("scroll"===i||"auto"===i)&&n.scrollWidth>n.clientWidth,!(r=s||a)&&(e=e.parent()).length&&!e.hasClass("fancybox-stage")&&!e.is("body"););return r},l=function(t){this.instance=t,this.$bg=t.$refs.bg,this.$stage=t.$refs.stage,this.$container=t.$refs.container,this.destroy(),this.$container.on("touchstart.fb.touch mousedown.fb.touch",n.proxy(this,"ontouchstart"))};l.prototype.destroy=function(){this.$container.off(".fb.touch"),n(e).off(".fb.touch"),this.requestId&&(i(this.requestId),this.requestId=null),this.tapped&&(clearTimeout(this.tapped),this.tapped=null)},l.prototype.ontouchstart=function(o){var i=n(o.target),l=this.instance,h=l.current,d=h.$slide,u=h.$content,f="touchstart"==o.type;if(f&&this.$container.off("mousedown.fb.touch"),(!o.originalEvent||2!=o.originalEvent.button)&&d.length&&i.length&&!r(i)&&!r(i.parent())&&(i.is("img")||!(o.originalEvent.clientX>i[0].clientWidth+i.offset().left))){if(!h||l.isAnimating||h.$slide.hasClass("fancybox-animated"))return o.stopPropagation(),void o.preventDefault();this.realPoints=this.startPoints=s(o),this.startPoints.length&&(h.touch&&o.stopPropagation(),this.startEvent=o,this.canTap=!0,this.$target=i,this.$content=u,this.opts=h.opts.touch,this.isPanning=!1,this.isSwiping=!1,this.isZooming=!1,this.isScrolling=!1,this.canPan=l.canPan(),this.startTime=(new Date).getTime(),this.distanceX=this.distanceY=this.distance=0,this.canvasWidth=Math.round(d[0].clientWidth),this.canvasHeight=Math.round(d[0].clientHeight),this.contentLastPos=null,this.contentStartPos=n.fancybox.getTranslate(this.$content)||{top:0,left:0},this.sliderStartPos=n.fancybox.getTranslate(d),this.stagePos=n.fancybox.getTranslate(l.$refs.stage),this.sliderStartPos.top-=this.stagePos.top,this.sliderStartPos.left-=this.stagePos.left,this.contentStartPos.top-=this.stagePos.top,this.contentStartPos.left-=this.stagePos.left,n(e).off(".fb.touch").on(f?"touchend.fb.touch touchcancel.fb.touch":"mouseup.fb.touch mouseleave.fb.touch",n.proxy(this,"ontouchend")).on(f?"touchmove.fb.touch":"mousemove.fb.touch",n.proxy(this,"ontouchmove")),n.fancybox.isMobile&&e.addEventListener("scroll",this.onscroll,!0),((this.opts||this.canPan)&&(i.is(this.$stage)||this.$stage.find(i).length)||(i.is(".fancybox-image")&&o.preventDefault(),n.fancybox.isMobile&&i.parents(".fancybox-caption").length))&&(this.isScrollable=c(i)||c(i.parent()),n.fancybox.isMobile&&this.isScrollable||o.preventDefault(),(1===this.startPoints.length||h.hasError)&&(this.canPan?(n.fancybox.stop(this.$content),this.isPanning=!0):this.isSwiping=!0,this.$container.addClass("fancybox-is-grabbing")),2===this.startPoints.length&&"image"===h.type&&(h.isLoaded||h.$ghost)&&(this.canTap=!1,this.isSwiping=!1,this.isPanning=!1,this.isZooming=!0,n.fancybox.stop(this.$content),this.centerPointStartX=.5*(this.startPoints[0].x+this.startPoints[1].x)-n(t).scrollLeft(),this.centerPointStartY=.5*(this.startPoints[0].y+this.startPoints[1].y)-n(t).scrollTop(),this.percentageOfImageAtPinchPointX=(this.centerPointStartX-this.contentStartPos.left)/this.contentStartPos.width,this.percentageOfImageAtPinchPointY=(this.centerPointStartY-this.contentStartPos.top)/this.contentStartPos.height,this.startDistanceBetweenFingers=a(this.startPoints[0],this.startPoints[1]))))}},l.prototype.onscroll=function(t){this.isScrolling=!0,e.removeEventListener("scroll",this.onscroll,!0)},l.prototype.ontouchmove=function(t){void 0===t.originalEvent.buttons||0!==t.originalEvent.buttons?this.isScrolling?this.canTap=!1:(this.newPoints=s(t),(this.opts||this.canPan)&&this.newPoints.length&&this.newPoints.length&&(this.isSwiping&&!0===this.isSwiping||t.preventDefault(),this.distanceX=a(this.newPoints[0],this.startPoints[0],"x"),this.distanceY=a(this.newPoints[0],this.startPoints[0],"y"),this.distance=a(this.newPoints[0],this.startPoints[0]),this.distance>0&&(this.isSwiping?this.onSwipe(t):this.isPanning?this.onPan():this.isZooming&&this.onZoom()))):this.ontouchend(t)},l.prototype.onSwipe=function(e){var s,a=this,r=a.instance,c=a.isSwiping,l=a.sliderStartPos.left||0;if(!0!==c)"x"==c&&(a.distanceX>0&&(a.instance.group.length<2||0===a.instance.current.index&&!a.instance.current.opts.loop)?l+=Math.pow(a.distanceX,.8):a.distanceX<0&&(a.instance.group.length<2||a.instance.current.index===a.instance.group.length-1&&!a.instance.current.opts.loop)?l-=Math.pow(-a.distanceX,.8):l+=a.distanceX),a.sliderLastPos={top:"x"==c?0:a.sliderStartPos.top+a.distanceY,left:l},a.requestId&&(i(a.requestId),a.requestId=null),a.requestId=o(function(){a.sliderLastPos&&(n.each(a.instance.slides,function(t,e){var o=e.pos-a.instance.currPos;n.fancybox.setTranslate(e.$slide,{top:a.sliderLastPos.top,left:a.sliderLastPos.left+o*a.canvasWidth+o*e.opts.gutter})}),a.$container.addClass("fancybox-is-sliding"))});else if(Math.abs(a.distance)>10){if(a.canTap=!1,r.group.length<2&&a.opts.vertical?a.isSwiping="y":r.isDragging||!1===a.opts.vertical||"auto"===a.opts.vertical&&n(t).width()>800?a.isSwiping="x":(s=Math.abs(180*Math.atan2(a.distanceY,a.distanceX)/Math.PI),a.isSwiping=s>45&&s<135?"y":"x"),"y"===a.isSwiping&&n.fancybox.isMobile&&a.isScrollable)return void(a.isScrolling=!0);r.isDragging=a.isSwiping,a.startPoints=a.newPoints,n.each(r.slides,function(t,e){var o,i;n.fancybox.stop(e.$slide),o=n.fancybox.getTranslate(e.$slide),i=n.fancybox.getTranslate(r.$refs.stage),e.$slide.css({transform:"",opacity:"","transition-duration":""}).removeClass("fancybox-animated").removeClass(function(t,e){return(e.match(/(^|\s)fancybox-fx-\S+/g)||[]).join(" ")}),e.pos===r.current.pos&&(a.sliderStartPos.top=o.top-i.top,a.sliderStartPos.left=o.left-i.left),n.fancybox.setTranslate(e.$slide,{top:o.top-i.top,left:o.left-i.left})}),r.SlideShow&&r.SlideShow.isActive&&r.SlideShow.stop()}},l.prototype.onPan=function(){var t=this;a(t.newPoints[0],t.realPoints[0])<(n.fancybox.isMobile?10:5)?t.startPoints=t.newPoints:(t.canTap=!1,t.contentLastPos=t.limitMovement(),t.requestId&&i(t.requestId),t.requestId=o(function(){n.fancybox.setTranslate(t.$content,t.contentLastPos)}))},l.prototype.limitMovement=function(){var t,e,n,o,i,s,a=this.canvasWidth,r=this.canvasHeight,c=this.distanceX,l=this.distanceY,h=this.contentStartPos,d=h.left,u=h.top,f=h.width,p=h.height;return i=f>a?d+c:d,s=u+l,t=Math.max(0,.5*a-.5*f),e=Math.max(0,.5*r-.5*p),n=Math.min(a-f,.5*a-.5*f),o=Math.min(r-p,.5*r-.5*p),c>0&&i>t&&(i=t-1+Math.pow(-t+d+c,.8)||0),c<0&&i<n&&(i=n+1-Math.pow(n-d-c,.8)||0),l>0&&s>e&&(s=e-1+Math.pow(-e+u+l,.8)||0),l<0&&s<o&&(s=o+1-Math.pow(o-u-l,.8)||0),{top:s,left:i}},l.prototype.limitPosition=function(t,e,n,o){var i=this.canvasWidth,s=this.canvasHeight;return t=n>i?(t=t>0?0:t)<i-n?i-n:t:Math.max(0,i/2-n/2),{top:e=o>s?(e=e>0?0:e)<s-o?s-o:e:Math.max(0,s/2-o/2),left:t}},l.prototype.onZoom=function(){var e=this,s=e.contentStartPos,r=s.width,c=s.height,l=s.left,h=s.top,d=a(e.newPoints[0],e.newPoints[1])/e.startDistanceBetweenFingers,u=Math.floor(r*d),f=Math.floor(c*d),p=(r-u)*e.percentageOfImageAtPinchPointX,g=(c-f)*e.percentageOfImageAtPinchPointY,b=(e.newPoints[0].x+e.newPoints[1].x)/2-n(t).scrollLeft(),m=(e.newPoints[0].y+e.newPoints[1].y)/2-n(t).scrollTop(),v=b-e.centerPointStartX,y={top:h+(g+(m-e.centerPointStartY)),left:l+(p+v),scaleX:d,scaleY:d};e.canTap=!1,e.newWidth=u,e.newHeight=f,e.contentLastPos=y,e.requestId&&i(e.requestId),e.requestId=o(function(){n.fancybox.setTranslate(e.$content,e.contentLastPos)})},l.prototype.ontouchend=function(t){var o=this.isSwiping,a=this.isPanning,r=this.isZooming,c=this.isScrolling;if(this.endPoints=s(t),this.dMs=Math.max((new Date).getTime()-this.startTime,1),this.$container.removeClass("fancybox-is-grabbing"),n(e).off(".fb.touch"),e.removeEventListener("scroll",this.onscroll,!0),this.requestId&&(i(this.requestId),this.requestId=null),this.isSwiping=!1,this.isPanning=!1,this.isZooming=!1,this.isScrolling=!1,this.instance.isDragging=!1,this.canTap)return this.onTap(t);this.speed=100,this.velocityX=this.distanceX/this.dMs*.5,this.velocityY=this.distanceY/this.dMs*.5,a?this.endPanning():r?this.endZooming():this.endSwiping(o,c)},l.prototype.endSwiping=function(t,e){var o=!1,i=this.instance.group.length,s=Math.abs(this.distanceX),a="x"==t&&i>1&&(this.dMs>130&&s>10||s>50);this.sliderLastPos=null,"y"==t&&!e&&Math.abs(this.distanceY)>50?(n.fancybox.animate(this.instance.current.$slide,{top:this.sliderStartPos.top+this.distanceY+150*this.velocityY,opacity:0},200),o=this.instance.close(!0,250)):a&&this.distanceX>0?o=this.instance.previous(300):a&&this.distanceX<0&&(o=this.instance.next(300)),!1!==o||"x"!=t&&"y"!=t||this.instance.centerSlide(200),this.$container.removeClass("fancybox-is-sliding")},l.prototype.endPanning=function(){var t,e,o;this.contentLastPos&&(!1===this.opts.momentum||this.dMs>350?(t=this.contentLastPos.left,e=this.contentLastPos.top):(t=this.contentLastPos.left+500*this.velocityX,e=this.contentLastPos.top+500*this.velocityY),(o=this.limitPosition(t,e,this.contentStartPos.width,this.contentStartPos.height)).width=this.contentStartPos.width,o.height=this.contentStartPos.height,n.fancybox.animate(this.$content,o,366))},l.prototype.endZooming=function(){var t,e,o,i,s=this.instance.current,a=this.newWidth,r=this.newHeight;this.contentLastPos&&(t=this.contentLastPos.left,i={top:e=this.contentLastPos.top,left:t,width:a,height:r,scaleX:1,scaleY:1},n.fancybox.setTranslate(this.$content,i),a<this.canvasWidth&&r<this.canvasHeight?this.instance.scaleToFit(150):a>s.width||r>s.height?this.instance.scaleToActual(this.centerPointStartX,this.centerPointStartY,150):(o=this.limitPosition(t,e,a,r),n.fancybox.animate(this.$content,o,150)))},l.prototype.onTap=function(e){var o,i=this,a=n(e.target),r=i.instance,c=r.current,l=e&&s(e)||i.startPoints,h=l[0]?l[0].x-n(t).scrollLeft()-i.stagePos.left:0,d=l[0]?l[0].y-n(t).scrollTop()-i.stagePos.top:0,u=function(t){var o=c.opts[t];if(n.isFunction(o)&&(o=o.apply(r,[c,e])),o)switch(o){case"close":r.close(i.startEvent);break;case"toggleControls":r.toggleControls();break;case"next":r.next();break;case"nextOrClose":r.group.length>1?r.next():r.close(i.startEvent);break;case"zoom":"image"==c.type&&(c.isLoaded||c.$ghost)&&(r.canPan()?r.scaleToFit():r.isScaledDown()?r.scaleToActual(h,d):r.group.length<2&&r.close(i.startEvent))}};if((!e.originalEvent||2!=e.originalEvent.button)&&(a.is("img")||!(h>a[0].clientWidth+a.offset().left))){if(a.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container"))o="Outside";else if(a.is(".fancybox-slide"))o="Slide";else{if(!r.current.$content||!r.current.$content.find(a).addBack().filter(a).length)return;o="Content"}if(i.tapped){if(clearTimeout(i.tapped),i.tapped=null,Math.abs(h-i.tapX)>50||Math.abs(d-i.tapY)>50)return this;u("dblclick"+o)}else i.tapX=h,i.tapY=d,c.opts["dblclick"+o]&&c.opts["dblclick"+o]!==c.opts["click"+o]?i.tapped=setTimeout(function(){i.tapped=null,r.isAnimating||u("click"+o)},500):u("click"+o);return this}},n(e).on("onActivate.fb",function(t,e){e&&!e.Guestures&&(e.Guestures=new l(e))}).on("beforeClose.fb",function(t,e){e&&e.Guestures&&e.Guestures.destroy()})}(window,document,jQuery),function(t,e){"use strict";e.extend(!0,e.fancybox.defaults,{btnTpl:{slideShow:'<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.5 5.4v13.2l11-6.6z"/></svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.33 5.75h2.2v12.5h-2.2V5.75zm5.15 0h2.2v12.5h-2.2V5.75z"/></svg></button>'},slideShow:{autoStart:!1,speed:3e3,progress:!0}});var n=function(t){this.instance=t,this.init()};e.extend(n.prototype,{timer:null,isActive:!1,$button:null,init:function(){var t=this,n=t.instance,o=n.group[n.currIndex].opts.slideShow;t.$button=n.$refs.toolbar.find("[data-fancybox-play]").on("click",function(){t.toggle()}),n.group.length<2||!o?t.$button.hide():o.progress&&(t.$progress=e('<div class="fancybox-progress"></div>').appendTo(n.$refs.inner))},set:function(t){var n=this.instance,o=n.current;o&&(!0===t||o.opts.loop||n.currIndex<n.group.length-1)?this.isActive&&"video"!==o.contentType&&(this.$progress&&e.fancybox.animate(this.$progress.show(),{scaleX:1},o.opts.slideShow.speed),this.timer=setTimeout(function(){n.current.opts.loop||n.current.index!=n.group.length-1?n.next():n.jumpTo(0)},o.opts.slideShow.speed)):(this.stop(),n.idleSecondsCounter=0,n.showControls())},clear:function(){clearTimeout(this.timer),this.timer=null,this.$progress&&this.$progress.removeAttr("style").hide()},start:function(){var t=this.instance.current;t&&(this.$button.attr("title",(t.opts.i18n[t.opts.lang]||t.opts.i18n.en).PLAY_STOP).removeClass("fancybox-button--play").addClass("fancybox-button--pause"),this.isActive=!0,t.isComplete&&this.set(!0),this.instance.trigger("onSlideShowChange",!0))},stop:function(){var t=this.instance.current;this.clear(),this.$button.attr("title",(t.opts.i18n[t.opts.lang]||t.opts.i18n.en).PLAY_START).removeClass("fancybox-button--pause").addClass("fancybox-button--play"),this.isActive=!1,this.instance.trigger("onSlideShowChange",!1),this.$progress&&this.$progress.removeAttr("style").hide()},toggle:function(){this.isActive?this.stop():this.start()}}),e(t).on({"onInit.fb":function(t,e){e&&!e.SlideShow&&(e.SlideShow=new n(e))},"beforeShow.fb":function(t,e,n,o){var i=e&&e.SlideShow;o?i&&n.opts.slideShow.autoStart&&i.start():i&&i.isActive&&i.clear()},"afterShow.fb":function(t,e,n){var o=e&&e.SlideShow;o&&o.isActive&&o.set()},"afterKeydown.fb":function(n,o,i,s,a){var r=o&&o.SlideShow;!r||!i.opts.slideShow||80!==a&&32!==a||e(t.activeElement).is("button,a,input")||(s.preventDefault(),r.toggle())},"beforeClose.fb onDeactivate.fb":function(t,e){var n=e&&e.SlideShow;n&&n.stop()}}),e(t).on("visibilitychange",function(){var n=e.fancybox.getInstance(),o=n&&n.SlideShow;o&&o.isActive&&(t.hidden?o.clear():o.set())})}(document,jQuery),function(t,e){"use strict";var n=function(){for(var e=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],n={},o=0;o<e.length;o++){var i=e[o];if(i&&i[1]in t){for(var s=0;s<i.length;s++)n[e[0][s]]=i[s];return n}}return!1}();if(n){var o={request:function(e){(e=e||t.documentElement)[n.requestFullscreen](e.ALLOW_KEYBOARD_INPUT)},exit:function(){t[n.exitFullscreen]()},toggle:function(e){e=e||t.documentElement,this.isFullscreen()?this.exit():this.request(e)},isFullscreen:function(){return Boolean(t[n.fullscreenElement])},enabled:function(){return Boolean(t[n.fullscreenEnabled])}};e.extend(!0,e.fancybox.defaults,{btnTpl:{fullScreen:'<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fsenter" title="{{FULL_SCREEN}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 16h3v3h2v-5H5zm3-8H5v2h5V5H8zm6 11h2v-3h3v-2h-5zm2-11V5h-2v5h5V8z"/></svg></button>'},fullScreen:{autoStart:!1}}),e(t).on(n.fullscreenchange,function(){var t=o.isFullscreen(),n=e.fancybox.getInstance();n&&(n.current&&"image"===n.current.type&&n.isAnimating&&(n.isAnimating=!1,n.update(!0,!0,0),n.isComplete||n.complete()),n.trigger("onFullscreenChange",t),n.$refs.container.toggleClass("fancybox-is-fullscreen",t),n.$refs.toolbar.find("[data-fancybox-fullscreen]").toggleClass("fancybox-button--fsenter",!t).toggleClass("fancybox-button--fsexit",t))})}e(t).on({"onInit.fb":function(t,e){n?e&&e.group[e.currIndex].opts.fullScreen?(e.$refs.container.on("click.fb-fullscreen","[data-fancybox-fullscreen]",function(t){t.stopPropagation(),t.preventDefault(),o.toggle()}),e.opts.fullScreen&&!0===e.opts.fullScreen.autoStart&&o.request(),e.FullScreen=o):e&&e.$refs.toolbar.find("[data-fancybox-fullscreen]").hide():e.$refs.toolbar.find("[data-fancybox-fullscreen]").remove()},"afterKeydown.fb":function(t,e,n,o,i){e&&e.FullScreen&&70===i&&(o.preventDefault(),e.FullScreen.toggle())},"beforeClose.fb":function(t,e){e&&e.FullScreen&&e.$refs.container.hasClass("fancybox-is-fullscreen")&&o.exit()}})}(document,jQuery),function(t,e){"use strict";var n="fancybox-thumbs";e.fancybox.defaults=e.extend(!0,{btnTpl:{thumbs:'<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.59 14.59h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76H5.65V5.65z"/></svg></button>'},thumbs:{autoStart:!1,hideOnClose:!0,parentEl:".fancybox-container",axis:"y"}},e.fancybox.defaults);var o=function(t){this.init(t)};e.extend(o.prototype,{$button:null,$grid:null,$list:null,isVisible:!1,isActive:!1,init:function(t){var e=this,n=t.group,o=0;e.instance=t,e.opts=n[t.currIndex].opts.thumbs,t.Thumbs=e,e.$button=t.$refs.toolbar.find("[data-fancybox-thumbs]");for(var i=0,s=n.length;i<s&&(n[i].thumb&&o++,!(o>1));i++);o>1&&e.opts?(e.$button.removeAttr("style").on("click",function(){e.toggle()}),e.isActive=!0):e.$button.hide()},create:function(){var t,o=this.instance,i=this.opts.parentEl,s=[];this.$grid||(this.$grid=e('<div class="'+n+" "+n+"-"+this.opts.axis+'"></div>').appendTo(o.$refs.container.find(i).addBack().filter(i)),this.$grid.on("click","a",function(){o.jumpTo(e(this).attr("data-index"))})),this.$list||(this.$list=e('<div class="'+n+'__list">').appendTo(this.$grid)),e.each(o.group,function(e,n){(t=n.thumb)||"image"!==n.type||(t=n.src),s.push('<a href="javascript:;" tabindex="0" data-index="'+e+'"'+(t&&t.length?' style="background-image:url('+t+')"':'class="fancybox-thumbs-missing"')+"></a>")}),this.$list[0].innerHTML=s.join(""),"x"===this.opts.axis&&this.$list.width(parseInt(this.$grid.css("padding-right"),10)+o.group.length*this.$list.children().eq(0).outerWidth(!0))},focus:function(t){var e,n,o=this.$list,i=this.$grid;this.instance.current&&(n=(e=o.children().removeClass("fancybox-thumbs-active").filter('[data-index="'+this.instance.current.index+'"]').addClass("fancybox-thumbs-active")).position(),"y"===this.opts.axis&&(n.top<0||n.top>o.height()-e.outerHeight())?o.stop().animate({scrollTop:o.scrollTop()+n.top},t):"x"===this.opts.axis&&(n.left<i.scrollLeft()||n.left>i.scrollLeft()+(i.width()-e.outerWidth()))&&o.parent().stop().animate({scrollLeft:n.left},t))},update:function(){this.instance.$refs.container.toggleClass("fancybox-show-thumbs",this.isVisible),this.isVisible?(this.$grid||this.create(),this.instance.trigger("onThumbsShow"),this.focus(0)):this.$grid&&this.instance.trigger("onThumbsHide"),this.instance.update()},hide:function(){this.isVisible=!1,this.update()},show:function(){this.isVisible=!0,this.update()},toggle:function(){this.isVisible=!this.isVisible,this.update()}}),e(t).on({"onInit.fb":function(t,e){var n;e&&!e.Thumbs&&(n=new o(e)).isActive&&!0===n.opts.autoStart&&n.show()},"beforeShow.fb":function(t,e,n,o){var i=e&&e.Thumbs;i&&i.isVisible&&i.focus(o?0:250)},"afterKeydown.fb":function(t,e,n,o,i){var s=e&&e.Thumbs;s&&s.isActive&&71===i&&(o.preventDefault(),s.toggle())},"beforeClose.fb":function(t,e){var n=e&&e.Thumbs;n&&n.isVisible&&!1!==n.opts.hideOnClose&&n.$grid.hide()}})}(document,jQuery),function(t,e,n){"use strict";function o(){var e=t.location.hash.substr(1),n=e.split("-"),o=n.length>1&&/^\+?\d+$/.test(n[n.length-1])&&parseInt(n.pop(-1),10)||1;return{hash:e,index:o<1?1:o,gallery:n.join("-")}}function i(t){""!==t.gallery&&n("[data-fancybox='"+n.escapeSelector(t.gallery)+"']").eq(t.index-1).focus().trigger("click.fb-start")}function s(t){var e,n;return!!t&&(""!==(n=(e=t.current?t.current.opts:t.opts).hash||(e.$orig?e.$orig.data("fancybox")||e.$orig.data("fancybox-trigger"):""))&&n)}n.escapeSelector||(n.escapeSelector=function(t){return(t+"").replace(/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,function(t,e){return e?"\0"===t?"�":t.slice(0,-1)+"\\"+t.charCodeAt(t.length-1).toString(16)+" ":"\\"+t})}),n(function(){!1!==n.fancybox.defaults.hash&&(n(e).on({"onInit.fb":function(t,e){var n,i;!1!==e.group[e.currIndex].opts.hash&&(n=o(),(i=s(e))&&n.gallery&&i==n.gallery&&(e.currIndex=n.index-1))},"beforeShow.fb":function(n,o,i,a){var r;i&&!1!==i.opts.hash&&(r=s(o))&&(o.currentHash=r+(o.group.length>1?"-"+(i.index+1):""),t.location.hash!=="#"+o.currentHash&&(a&&!o.origHash&&(o.origHash=t.location.hash),o.hashTimer&&clearTimeout(o.hashTimer),o.hashTimer=setTimeout(function(){"replaceState"in t.history?(t.history[a?"pushState":"replaceState"]({},e.title,t.location.pathname+t.location.search+"#"+o.currentHash),a&&(o.hasCreatedHistory=!0)):t.location.hash=o.currentHash,o.hashTimer=null},300)))},"beforeClose.fb":function(n,o,i){i&&!1!==i.opts.hash&&(clearTimeout(o.hashTimer),o.currentHash&&o.hasCreatedHistory?t.history.back():o.currentHash&&("replaceState"in t.history?t.history.replaceState({},e.title,t.location.pathname+t.location.search+(o.origHash||"")):t.location.hash=o.origHash),o.currentHash=null)}}),n(t).on("hashchange.fb",function(){var t=o(),e=null;n.each(n(".fancybox-container").get().reverse(),function(t,o){var i=n(o).data("FancyBox");if(i&&i.currentHash)return e=i,!1}),e?e.currentHash===t.gallery+"-"+t.index||1===t.index&&e.currentHash==t.gallery||(e.currentHash=null,e.close()):""!==t.gallery&&i(t)}),setTimeout(function(){n.fancybox.getInstance()||i(o())},50))})}(window,document,jQuery),function(t,e){"use strict";var n=(new Date).getTime();e(t).on({"onInit.fb":function(t,e,o){e.$refs.stage.on("mousewheel DOMMouseScroll wheel MozMousePixelScroll",function(t){var o=e.current,i=(new Date).getTime();e.group.length<2||!1===o.opts.wheel||"auto"===o.opts.wheel&&"image"!==o.type||(t.preventDefault(),t.stopPropagation(),o.$slide.hasClass("fancybox-animated")||(t=t.originalEvent||t,i-n<250||(n=i,e[(-t.deltaY||-t.deltaX||t.wheelDelta||-t.detail)<0?"next":"previous"]())))})}})}(document,jQuery);
@Valentine13
Copy link

Всю благодарность за этот апдейт для RuTube не передать словами. Автор, вы спасли столько нервных клеток, спасибо!

@evikza
Copy link
Author

evikza commented Apr 9, 2022

@Valentine13 здравствуйте.

Мы же с Вами общались в теме о Rutube на cyberforum? Я там ответил насчет обложки видео. Но, Вы так и не заходили. 😔

@Valentine13
Copy link

@evikza простите ( Я там уже исправилась! Временно появлялась надежда, что всё-таки обойдется без блокировки YouTube), но теперь стало очевидно, что не пронесёт :))) Думаю, ваше решение еще многим поможет! Спасибо еще раз!

@Djekswon
Copy link

Спасибо за сделанную доработку!

@Alex4Codes
Copy link

Добрый день, а как можно еще добавить поддержку VK Видео?

@evikza
Copy link
Author

evikza commented Oct 1, 2024

@Alex4Codes Здравствуйте.

На днях постараюсь добавить такую возможность.

@Djekswon
Copy link

Djekswon commented Oct 1, 2024

@evikza Здравствуйте!
Я уже решал такую задачу, вот код:

vk: {
  matcher: /^.+vk.com\/video([-0-9]*)_([-0-9]*)?/,
  params: {
    frameBorder: 0,
    autoplay: 1,
  },
  paramPlace: 1,
  type: 'iframe',
  url: 'https://vk.com/video_ext.php?oid=$1&id=$2',
},

@evikza
Copy link
Author

evikza commented Oct 1, 2024

@Djekswon Добрый вечер. Увидел Ваше сообщение, когда уже добавил правки в код. Но, спасибо большое за участие. 😊

@Alex4Codes добавлена поддержка VK Видео.

@levongziryan
Copy link

Здравствуйте! Можно ли настроить автовоспроизведение для rutube?

@evikza
Copy link
Author

evikza commented Oct 22, 2024

@levongziryan Здравствуйте. 👋

Теперь работает автоматическое воспроизведение для Rutube.

Так же, если видео находится в галерее data-fancybox="video-gallery" — после окончания происходит запуск следующего видео.

@Golden-Puma
Copy link

@levongziryan Здравствуйте. 👋

Теперь работает автоматическое воспроизведение для Rutube.

Так же, если видео находится в галерее data-fancybox="video-gallery" — после окончания происходит запуск следующего видео.

у меня через раз автовоспризведение срабатывает

@uhogorlonos
Copy link

uhogorlonos commented Oct 3, 2025

Здравствуйте, поломалось воспроизведение видео вконтакте (скорее всего, из-за того, что они переехали на vk.ru) Подскажите что в скрипте и как поменять надо. Просто поменть com на ru не сработало - видимо там сам формат ссылок поменялся
Спустя минут 20 нашел сам: (с 3715 строчки)

vk: {
      matcher: /^.+(vkvideo.ru).+video(?:\?z=video|)(-?\d+)_(\d+)/,
      params: {
        autoplay: 1,
        hd: 2,
        js_api: 1,
        frameBorder: 0,
      },
      paramPlace: 1,
      type: 'iframe',
      url: 'https://vkvideo.ru/video_ext.php?oid=$2&id=$3',
    },

кроме js файла надо подключить стили:
<link href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" rel="stylesheet">
вызов на странице:
<a data-fancybox href="[ссылка на видео типа https://vkvideo.ru/video-ХХХХХХХХХ_хХХХХХхХХ">

@Djekswon
Copy link

Djekswon commented Nov 4, 2025

@uhogorlonos Здравствуйте! Спасибо, что опубликовали код. Пригодился 🙏

@evikza
Copy link
Author

evikza commented Nov 8, 2025

Обновил файл. Поддерживаются ссылки VK вида:

https://vk.com/username?z=videoXXXXXXXXX_XXXXXXXXX
https://vk.ru/vkvideo?z=video-XXXXXXXXX_XXXXXXXXX
https://vkvideo.ru/video-XXXXXXXXX_XXXXXXXXX

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment