You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2017/11/20 17:35:29 UTC
svn commit: r1815824 [8/19] - in /ofbiz/ofbiz-framework/trunk/themes/common:
template/includes/ webapp/common/js/jquery/
webapp/common/js/jquery/plugins/browser-plugin/
webapp/common/js/jquery/plugins/fancybox/
webapp/common/js/jquery/plugins/validate/...
Added: ofbiz/ofbiz-framework/trunk/themes/common/webapp/common/js/jquery/plugins/fancybox/jquery.fancybox.js
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/themes/common/webapp/common/js/jquery/plugins/fancybox/jquery.fancybox.js?rev=1815824&view=auto
==============================================================================
--- ofbiz/ofbiz-framework/trunk/themes/common/webapp/common/js/jquery/plugins/fancybox/jquery.fancybox.js (added)
+++ ofbiz/ofbiz-framework/trunk/themes/common/webapp/common/js/jquery/plugins/fancybox/jquery.fancybox.js Mon Nov 20 17:35:27 2017
@@ -0,0 +1,5127 @@
+// ==================================================
+// fancyBox v3.2.3
+//
+// Licensed GPLv3 for open source use
+// or fancyBox Commercial License for commercial use
+//
+// http://fancyapps.com/fancybox/
+// Copyright 2017 fancyApps
+//
+// ==================================================
+;(function (window, document, $, undefined) {
+ 'use strict';
+
+ // If there's no jQuery, fancyBox can't work
+ // =========================================
+
+ if ( !$ ) {
+ return;
+ }
+
+ // Check if fancyBox is already initialized
+ // ========================================
+
+ if ( $.fn.fancybox ) {
+
+ if ( 'console' in window ) {
+ console.log( 'fancyBox already initialized' );
+ }
+
+ return;
+ }
+
+ // Private default settings
+ // ========================
+
+ var defaults = {
+
+ // Enable infinite gallery navigation
+ loop : false,
+
+ // Space around image, ignored if zoomed-in or viewport width is smaller than 800px
+ margin : [44, 0],
+
+ // Horizontal space between slides
+ gutter : 50,
+
+ // Enable keyboard navigation
+ keyboard : true,
+
+ // Should display navigation arrows at the screen edges
+ arrows : true,
+
+ // Should display infobar (counter and arrows at the top)
+ infobar : true,
+
+ // Should display toolbar (buttons at the top)
+ toolbar : true,
+
+ // 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 : [
+ 'slideShow',
+ 'fullScreen',
+ 'thumbs',
+ 'share',
+ //'download',
+ //'zoom',
+ 'close'
+ ],
+
+ // Detect "idle" time in seconds
+ idleTime : 3,
+
+ // Should display buttons at top right corner of the content
+ // If 'auto' - they will be created for content having type 'html', 'inline' or 'ajax'
+ // Use template from `btnTpl.smallBtn` for customization
+ smallBtn : 'auto',
+
+ // 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
+ // Requires predefined image dimensions
+ // If 'auto' - will zoom in thumbnail if 'width' and 'height' attributes are found
+ preload : "auto"
+
+ },
+
+ 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" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" 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'
+ }
+
+ },
+
+ // 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 : 500,
+
+ // 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> / <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-wrap"><div class="fancybox-caption"></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}}">' +
+ '<svg viewBox="0 0 40 40">' +
+ '<path d="M20,23 L20,8 L20,23 L13,16 L20,23 L27,16 L20,23 M9,28 L31,28" />' +
+ '</svg>' +
+ '</a>',
+
+ zoom : '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' +
+ '<svg viewBox="0 0 40 40">' +
+ '<path d="M 18,17 m -8, 0 a 8,8 0 1,0 16,0 a 8,8 0 1,0 -16,0 M25,23 L31,29 L25,23"></path>' +
+ '</svg>' +
+ '</button>',
+
+ close : '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' +
+ '<svg viewBox="0 0 40 40">' +
+ '<path d="M10,10 L30,30 M30,10 L10,30" />' +
+ '</svg>' +
+ '</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 data-fancybox-close class="fancybox-close-small" title="{{CLOSE}}"></button>',
+
+ // Arrows
+ arrowLeft : '<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' +
+ '<svg viewBox="0 0 40 40">' +
+ '<path d="M10,20 L30,20 L10,20 L18,28 L10,20 L18,12 L10,20"></path>' +
+ '</svg>' +
+ '</button>',
+
+ arrowRight : '<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' +
+ '<svg viewBox="0 0 40 40">' +
+ '<path d="M30,20 L10,20 L30,20 L22,28 L30,20 L22,12 L30,20"></path>' +
+ '</svg>' +
+ '</button>'
+ },
+
+ // Container is injected into this element
+ parentEl : 'body',
+
+
+ // Focus handling
+ // ==============
+
+ // Try to focus on the first focusable element after opening
+ autoFocus : false,
+
+ // 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 dragging/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 : 4000
+ },
+
+ 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)
+ },
+
+ // 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
+ clickOutside : 'close',
+
+ // Same as previous two, but for double click
+ dblclickContent : false,
+ dblclickSlide : false,
+ dblclickOutside : false,
+
+
+ // Custom options when mobile device is detected
+ // =============================================
+
+ mobile : {
+ margin : 0,
+
+ 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 : 'Schliessen',
+ NEXT : 'Weiter',
+ PREV : 'Zurück',
+ ERROR : 'Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.',
+ PLAY_START : 'Diaschau starten',
+ PLAY_STOP : 'Diaschau beenden',
+ FULL_SCREEN : 'Vollbild',
+ THUMBS : 'Vorschaubilder',
+ DOWNLOAD : 'Herunterladen',
+ SHARE : 'Teilen',
+ ZOOM : 'MaÃstab'
+ }
+ }
+
+ };
+
+ // 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);
+ };
+ })();
+
+
+ // Detect the supported transition-end event property name
+ // =======================================================
+
+ var transitionEnd = (function () {
+ var t, el = document.createElement("fakeelement");
+
+ var transitions = {
+ "transition" : "transitionend",
+ "OTransition" : "oTransitionEnd",
+ "MozTransition" : "transitionend",
+ "WebkitTransition": "webkitTransitionEnd"
+ };
+
+ for (t in transitions) {
+ if (el.style[t] !== undefined){
+ return transitions[t];
+ }
+ }
+ })();
+
+
+ // 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 );
+ };
+
+
+ // Class definition
+ // ================
+
+ var FancyBox = function( content, opts, index ) {
+ var self = this;
+
+ self.opts = $.extend( true, { index : index }, $.fancybox.defaults, opts || {} );
+
+ if ( $.fancybox.isMobile ) {
+ self.opts = $.extend( true, {}, self.opts, self.opts.mobile );
+ }
+
+ // Exclude buttons option from deep merging
+ if ( opts && $.isArray( opts.buttons ) ) {
+ self.opts.buttons = opts.buttons;
+ }
+
+ self.id = self.opts.id || ++called;
+ self.group = [];
+
+ self.currIndex = parseInt( self.opts.index, 10 ) || 0;
+ self.prevIndex = null;
+
+ self.prevPos = null;
+ self.currPos = 0;
+
+ self.firstRun = null;
+
+ // Create group elements from original item collection
+ self.createGroup( content );
+
+ if ( !self.group.length ) {
+ return;
+ }
+
+ // Save last active element and current scroll position
+ self.$lastFocus = $(document.activeElement).blur();
+
+ // Collection of gallery objects
+ self.slides = {};
+
+ self.init();
+ };
+
+ $.extend(FancyBox.prototype, {
+
+ // Create DOM structure
+ // ====================
+
+ init : function() {
+ var self = this,
+ firstItem = self.group[ self.currIndex ],
+ firstItemOpts = firstItem.opts,
+ scrollbarWidth = $.fancybox.scrollbarWidth,
+ $scrollDiv,
+ $container,
+ buttonStr;
+
+ self.scrollTop = $D.scrollTop();
+ self.scrollLeft = $D.scrollLeft();
+
+
+ // Hide scrollbars
+ // ===============
+
+ if ( !$.fancybox.getInstance() ) {
+
+ $( 'body' ).addClass( 'fancybox-active' );
+
+ // iOS hack
+ if ( /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream ) {
+
+ // iOS has problems for input elements inside fixed containers,
+ // the workaround is to apply `position: fixed` to `<body>` element,
+ // unfortunately, this makes it lose the scrollbars and forces address bar to appear.
+
+ if ( firstItem.type !== 'image' ) {
+ $( 'body' ).css( 'top', $( 'body' ).scrollTop() * -1 ).addClass( 'fancybox-iosfix' );
+ }
+
+ } else if ( !$.fancybox.isMobile && document.body.scrollHeight > window.innerHeight ) {
+
+ if ( scrollbarWidth === undefined ) {
+ $scrollDiv = $('<div style="width:50px;height:50px;overflow:scroll;" />').appendTo( 'body' );
+
+ scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth;
+
+ $scrollDiv.remove();
+ }
+
+ $( 'head' ).append( '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar { margin-right: ' + scrollbarWidth + '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( 'fancybox-is-hidden' )
+ .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 ];
+
+ return str.replace(/\{\{(\w+)\}\}/g, function(match, n) {
+ var value = arr[n];
+
+ if ( value === undefined ) {
+ return match;
+ }
+
+ return value;
+ });
+ },
+
+ // Create array of gally item objects
+ // Check if each object has valid type and content
+ // ===============================================
+
+ createGroup : function ( content ) {
+ var self = this;
+ var items = $.makeArray( content );
+
+ $.each(items, function( i, item ) {
+ var obj = {},
+ opts = {},
+ $item,
+ type,
+ 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 );
+
+ opts = $item.data();
+ opts = $.extend( {}, opts, opts.options || {} );
+
+ // Here we store clicked element
+ opts.$orig = $item;
+
+ obj.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;
+ }
+
+
+ // 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 ( 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 = 'pdf';
+
+ } else if ( src.charAt(0) === '#' ) {
+ type = 'inline';
+ }
+ }
+
+ if ( type ) {
+ obj.type = type;
+
+ } else {
+ self.trigger( 'objectNeedsType', obj );
+ }
+
+
+ // Step 3 - Some adjustments
+ // =========================
+
+ obj.index = self.group.length;
+
+ // Check if $orig and $thumb objects exist
+ if ( obj.opts.$orig && !obj.opts.$orig.length ) {
+ delete obj.opts.$orig;
+ }
+
+ if ( !obj.opts.$thumb && obj.opts.$orig ) {
+ obj.opts.$thumb = obj.opts.$orig.find( 'img:first' );
+ }
+
+ if ( obj.opts.$thumb && !obj.opts.$thumb.length ) {
+ delete obj.opts.$thumb;
+ }
+
+ // Caption is a "special" option, it can be passed as a method
+ 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 ( type === 'ajax' ) {
+ srcParts = src.split(/\s+/, 2);
+
+ if ( srcParts.length > 1 ) {
+ obj.src = srcParts.shift();
+
+ obj.opts.filter = srcParts.shift();
+ }
+ }
+
+ if ( obj.opts.smallBtn == 'auto' ) {
+
+ if ( $.inArray( type, ['html', 'inline', 'ajax'] ) > -1 ) {
+ obj.opts.toolbar = false;
+ obj.opts.smallBtn = true;
+
+ } else {
+ obj.opts.smallBtn = false;
+ }
+
+ }
+
+ // If the type is "pdf", then simply load file into iframe
+ if ( type === 'pdf' ) {
+ obj.type = 'iframe';
+
+ obj.opts.iframe.preload = false;
+ }
+
+ // Hide all buttons and disable interactivity for modal items
+ if ( obj.opts.modal ) {
+
+ obj.opts = $.extend(true, obj.opts, {
+ // 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 );
+
+ });
+
+ },
+
+
+ // Attach an event handler functions for:
+ // - navigation buttons
+ // - browser scrolling, resizing;
+ // - focusing
+ // - keyboard
+ // - detect idle
+ // ======================================
+
+ 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( 'click.fb-prev touchend.fb-prev', '[data-fancybox-prev]', function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ self.previous();
+
+ }).on( 'click.fb-next touchend.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" ) {
+
+ requestAFrame(function() {
+ self.update();
+ });
+
+ } else {
+
+ self.$refs.stage.hide();
+
+ setTimeout(function() {
+ self.$refs.stage.show();
+
+ self.update();
+ }, 600);
+
+ }
+
+ });
+
+ // Trap keyboard focus inside of the modal, so the user does not accidentally tab outside of the modal
+ // (a.k.a. "escaping the modal")
+ $D.on('focusin.fb', function(e) {
+ var instance = $.fancybox ? $.fancybox.getInstance() : null;
+
+ if ( instance.isClosing || !instance.current || !instance.current.opts.trapFocus || $( e.target ).hasClass( 'fancybox-container' ) || $( e.target ).is( document ) ) {
+ return;
+ }
+
+ if ( instance && $( e.target ).css( 'position' ) !== 'fixed' && !instance.$refs.container.has( e.target ).length ) {
+ e.stopPropagation();
+
+ instance.focus();
+
+ // Sometimes page gets scrolled, set it back
+ $W.scrollTop( self.scrollTop ).scrollLeft( self.scrollLeft );
+ }
+ });
+
+
+ // Enable keyboard navigation
+ $D.on('keydown.fb', function (e) {
+ var current = self.current,
+ keycode = e.keyCode || e.which;
+
+ if ( !current || !current.opts.keyboard ) {
+ return;
+ }
+
+ if ( $(e.target).is('input') || $(e.target).is('textarea') ) {
+ 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.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( 'focusin.fb 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, slide ) {
+ var self = this,
+ firstRun,
+ loop,
+ current,
+ previous,
+ canvasWidth,
+ currentPos,
+ transitionProps;
+
+ var groupLen = self.group.length;
+
+ if ( self.isSliding || self.isClosing || ( self.isAnimating && self.firstRun ) ) {
+ return;
+ }
+
+ pos = parseInt( pos, 10 );
+ loop = self.current ? self.current.opts.loop : self.opts.loop;
+
+ if ( !loop && ( pos < 0 || pos >= groupLen ) ) {
+ return false;
+ }
+
+ firstRun = self.firstRun = ( self.firstRun === null );
+
+ if ( groupLen < 2 && !firstRun && !!self.isSliding ) {
+ return;
+ }
+
+ previous = self.current;
+
+ self.prevIndex = self.currIndex;
+ self.prevPos = self.currPos;
+
+ // Create slides
+ current = self.createSlide( pos );
+
+ if ( groupLen > 1 ) {
+ if ( loop || current.index > 0 ) {
+ self.createSlide( pos - 1 );
+ }
+
+ if ( loop || current.index < groupLen - 1 ) {
+ self.createSlide( pos + 1 );
+ }
+ }
+
+ self.current = current;
+ self.currIndex = current.index;
+ self.currPos = current.pos;
+
+ self.trigger( 'beforeShow', firstRun );
+
+ self.updateControls();
+
+ currentPos = $.fancybox.getTranslate( current.$slide );
+
+ current.isMoved = ( currentPos.left !== 0 || currentPos.top !== 0 ) && !current.$slide.hasClass( 'fancybox-animated' );
+ current.forcedDuration = undefined;
+
+ if ( $.isNumeric( duration ) ) {
+ current.forcedDuration = duration;
+ } else {
+ duration = current.opts[ firstRun ? 'animationDuration' : 'transitionDuration' ];
+ }
+
+ duration = parseInt( duration, 10 );
+
+ // 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.removeClass( 'fancybox-is-hidden' );
+
+ forceRedraw( self.$refs.container );
+
+ self.$refs.container.addClass( 'fancybox-is-open' );
+
+ // Make first slide visible (to display loading icon, if needed)
+ current.$slide.addClass( 'fancybox-slide--current' );
+
+ self.loadSlide( current );
+
+ self.preload();
+
+ return;
+ }
+
+ // Clean up
+ $.each(self.slides, function( index, slide ) {
+ $.fancybox.stop( slide.$slide );
+ });
+
+ // Make current that slide is visible even if content is still loading
+ current.$slide.removeClass( 'fancybox-slide--next fancybox-slide--previous' ).addClass( 'fancybox-slide--current' );
+
+ // If slides have been dragged, animate them to correct position
+ if ( current.isMoved ) {
+ canvasWidth = Math.round( current.$slide.width() );
+
+ $.each(self.slides, function( index, slide ) {
+ var pos = slide.pos - current.pos;
+
+ $.fancybox.animate( slide.$slide, {
+ top : 0,
+ left : ( pos * canvasWidth ) + ( pos * slide.opts.gutter )
+ }, duration, function() {
+
+ slide.$slide.removeAttr('style').removeClass( 'fancybox-slide--next fancybox-slide--previous' );
+
+ if ( slide.pos === self.currPos ) {
+ current.isMoved = false;
+
+ self.complete();
+ }
+ });
+ });
+
+ } else {
+ self.$refs.stage.children().removeAttr( 'style' );
+ }
+
+ // Start transition that reveals current content
+ // or wait when it will be loaded
+
+ if ( current.isLoaded ) {
+ self.revealContent( current );
+
+ } else {
+ self.loadSlide( current );
+ }
+
+ self.preload();
+
+ if ( previous.pos === current.pos ) {
+ return;
+ }
+
+ // Handle previous slide
+ // =====================
+
+ transitionProps = 'fancybox-slide--' + ( previous.pos > current.pos ? 'next' : 'previous' );
+
+ previous.$slide.removeClass( 'fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous' );
+
+ previous.isComplete = false;
+
+ if ( !duration || ( !current.isMoved && !current.opts.transitionEffect ) ) {
+ return;
+ }
+
+ if ( current.isMoved ) {
+ previous.$slide.addClass( transitionProps );
+
+ } else {
+
+ transitionProps = 'fancybox-animated ' + transitionProps + ' fancybox-fx-' + current.opts.transitionEffect;
+
+ $.fancybox.animate( previous.$slide, transitionProps, duration, function() {
+ previous.$slide.removeClass( transitionProps ).removeAttr( 'style' );
+ });
+
+ }
+
+ },
+
+
+ // Create new "slide" element
+ // These are gallery items that are actually added to DOM
+ // =======================================================
+
+ createSlide : function( pos ) {
+
+ var self = this;
+ var $slide;
+ var 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
+ // ===========================================
+
+ scaleToActual : function( x, y, duration ) {
+
+ var self = this;
+
+ var current = self.current;
+ var $what = current.$content;
+
+ var imgPos, posX, posY, scaleX, scaleY;
+
+ var canvasWidth = parseInt( current.$slide.width(), 10 );
+ var canvasHeight = parseInt( current.$slide.height(), 10 );
+
+ var newImgWidth = current.width;
+ var newImgHeight = current.height;
+
+ if ( !( current.type == 'image' && !current.hasError) || !$what || self.isAnimating) {
+ return;
+ }
+
+ $.fancybox.stop( $what );
+
+ self.isAnimating = true;
+
+ x = x === undefined ? canvasWidth * 0.5 : x;
+ y = y === undefined ? canvasHeight * 0.5 : y;
+
+ imgPos = $.fancybox.getTranslate( $what );
+
+ 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( $what, {
+ top : posY,
+ left : posX,
+ scaleX : scaleX,
+ scaleY : scaleY
+ }, duration || 330, 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;
+
+ var current = self.current;
+ var $what = current.$content;
+ var end;
+
+ if ( !( current.type == 'image' && !current.hasError) || !$what || self.isAnimating ) {
+ return;
+ }
+
+ $.fancybox.stop( $what );
+
+ self.isAnimating = true;
+
+ end = self.getFitPos( current );
+
+ self.updateCursor( end.width, end.height );
+
+ $.fancybox.animate( $what, {
+ top : end.top,
+ left : end.left,
+ scaleX : end.width / $what.width(),
+ scaleY : end.height / $what.height()
+ }, duration || 330, function() {
+ self.isAnimating = false;
+ });
+
+ },
+
+ // Calculate image size to fit inside viewport
+ // ===========================================
+
+ getFitPos : function( slide ) {
+ var self = this;
+ var $what = slide.$content;
+
+ var imgWidth = slide.width;
+ var imgHeight = slide.height;
+
+ var margin = slide.opts.margin;
+
+ var canvasWidth, canvasHeight, minRatio, width, height;
+
+ if ( !$what || !$what.length || ( !imgWidth && !imgHeight) ) {
+ return false;
+ }
+
+ // Convert "margin to CSS style: [ top, right, bottom, left ]
+ if ( $.type( margin ) === "number" ) {
+ margin = [ margin, margin ];
+ }
+
+ if ( margin.length == 2 ) {
+ margin = [ margin[0], margin[1], margin[0], margin[1] ];
+ }
+
+ // We can not use $slide width here, because it can have different diemensions while in transiton
+ canvasWidth = parseInt( self.$refs.stage.width(), 10 ) - ( margin[ 1 ] + margin[ 3 ] );
+ canvasHeight = parseInt( self.$refs.stage.height(), 10 ) - ( margin[ 0 ] + margin[ 2 ] );
+
+ minRatio = Math.min(1, canvasWidth / imgWidth, canvasHeight / imgHeight );
+
+ width = Math.floor( minRatio * imgWidth );
+ height = Math.floor( minRatio * imgHeight );
+
+ // Use floor rounding to make sure it really fits
+ return {
+ top : Math.floor( ( canvasHeight - height ) * 0.5 ) + margin[ 0 ],
+ left : Math.floor( ( canvasWidth - width ) * 0.5 ) + margin[ 3 ],
+ width : width,
+ height : height
+ };
+
+ },
+
+
+ // Update position and content of all slides
+ // =========================================
+
+ update : function() {
+
+ var self = this;
+
+ $.each( self.slides, function( key, slide ) {
+ self.updateSlide( slide );
+ });
+
+ },
+
+
+ // Update slide position and scale content to fit
+ // ==============================================
+
+ updateSlide : function( slide ) {
+
+ var self = this;
+ var $what = slide.$content;
+
+ if ( $what && ( slide.width || slide.height ) ) {
+ $.fancybox.stop( $what );
+
+ $.fancybox.setTranslate( $what, self.getFitPos( slide ) );
+
+ if ( slide.pos === self.currPos ) {
+ self.updateCursor();
+ }
+ }
+
+ slide.$slide.trigger( 'refresh' );
+
+ self.trigger( 'onUpdate', slide );
+
+ },
+
+ // Update cursor style depending if content can be zoomed
+ // ======================================================
+
+ updateCursor : function( nextWidth, nextHeight ) {
+
+ var self = this;
+ var isScaledDown;
+
+ var $container = self.$refs.container.removeClass( 'fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut' );
+
+ if ( !self.current || self.isClosing ) {
+ return;
+ }
+
+ if ( self.isZoomable() ) {
+
+ $container.addClass( 'fancybox-is-zoomable' );
+
+ if ( nextWidth !== undefined && nextHeight !== undefined ) {
+ isScaledDown = nextWidth < self.current.width && nextHeight < self.current.height;
+
+ } else {
+ isScaledDown = self.isScaledDown();
+ }
+
+ if ( isScaledDown ) {
+
+ // If image is scaled down, then, obviously, it can be zoomed to full size
+ $container.addClass( 'fancybox-can-zoomIn' );
+
+ } else {
+
+ if ( self.current.opts.touch ) {
+
+ // If image size ir largen than available available and touch module is not disable,
+ // then user can do panning
+ $container.addClass( 'fancybox-can-drag' );
+
+ } else {
+ $container.addClass( 'fancybox-can-zoomOut' );
+ }
+
+ }
+
+ } else if ( self.current.opts.touch ) {
+ $container.addClass( 'fancybox-can-drag' );
+ }
+
+ },
+
+
+ // Check if current slide is zoomable
+ // ==================================
+
+ isZoomable : function() {
+
+ var self = this;
+
+ var current = self.current;
+ var fitPos;
+
+ if ( !current || self.isClosing ) {
+ return;
+ }
+
+ // Assume that slide is zoomable if
+ // - image is loaded successfuly
+ // - click action is "zoom"
+ // - actual size of the image is smaller than available area
+ if ( current.type === 'image' && current.isLoaded && !current.hasError &&
+ ( current.opts.clickContent === 'zoom' || ( $.isFunction( current.opts.clickContent ) && current.opts.clickContent( current ) === "zoom" ) )
+ ) {
+
+ fitPos = self.getFitPos( current );
+
+ if ( current.width > fitPos.width || current.height > fitPos.height ) {
+ return true;
+ }
+
+ }
+
+ return false;
+
+ },
+
+
+ // Check if current image dimensions are smaller than actual
+ // =========================================================
+
+ isScaledDown : function() {
+
+ var self = this;
+
+ var current = self.current;
+ var $what = current.$content;
+
+ var rez = false;
+
+ if ( $what ) {
+ rez = $.fancybox.getTranslate( $what );
+ rez = rez.width < current.width || rez.height < current.height;
+ }
+
+ return rez;
+
+ },
+
+
+ // Check if image dimensions exceed parent element
+ // ===============================================
+
+ canPan : function() {
+
+ var self = this;
+
+ var current = self.current;
+ var $what = current.$content;
+
+ var rez = false;
+
+ if ( $what ) {
+ rez = self.getFitPos( current );
+ rez = Math.abs( $what.width() - rez.width ) > 1 || Math.abs( $what.height() - rez.height ) > 1;
+
+ }
+
+ return rez;
+
+ },
+
+
+ // Load content into the slide
+ // ===========================
+
+ loadSlide : function( slide ) {
+
+ var self = this, type, $slide;
+ var ajaxLoad;
+
+ if ( slide.isLoading ) {
+ return;
+ }
+
+ if ( slide.isLoaded ) {
+ return;
+ }
+
+ slide.isLoading = true;
+
+ self.trigger( 'beforeLoad', slide );
+
+ type = slide.type;
+ $slide = slide.$slide;
+
+ $slide
+ .off( 'refresh' )
+ .trigger( 'onReset' )
+ .addClass( 'fancybox-slide--' + ( type || 'unknown' ) )
+ .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 '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;
+ var srcset = slide.opts.srcset || slide.opts.image.srcset;
+
+ var found, temp, pxRatio, windowWidth;
+
+ // If we have "srcset", then we need to find 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;
+ }
+ }
+ }
+
+ // This will be wrapper containing both ghost and actual image
+ slide.$content = $('<div class="fancybox-image-wrap"></div>')
+ .addClass( 'fancybox-is-hidden' )
+ .appendTo( slide.$slide );
+
+
+ // 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.opts.thumb || slide.opts.$thumb ) ) {
+
+ slide.width = slide.opts.width;
+ slide.height = slide.opts.height;
+
+ slide.$ghost = $('<img />')
+ .one('error', function() {
+
+ $(this).remove();
+
+ slide.$ghost = null;
+
+ self.setBigImage( slide );
+
+ })
+ .one('load', function() {
+
+ self.afterLoad( slide );
+
+ self.setBigImage( slide );
+
+ })
+ .addClass( 'fancybox-image' )
+ .appendTo( slide.$content )
+ .attr( 'src', slide.opts.thumb || slide.opts.$thumb.attr( 'src' ) );
+
+ } else {
+
+ self.setBigImage( slide );
+
+ }
+
+ },
+
+
+ // Create full-size image
+ // ======================
+
+ setBigImage : function ( slide ) {
+ var self = this;
+ var $img = $('<img />');
+
+ slide.$image = $img
+ .one('error', function() {
+
+ self.setError( slide );
+
+ })
+ .one('load', function() {
+
+ // Clear timeout that checks if loading icon needs to be displayed
+ clearTimeout( slide.timouts );
+
+ slide.timouts = null;
+
+ if ( self.isClosing ) {
+ return;
+ }
+
+ slide.width = this.naturalWidth;
+ slide.height = this.naturalHeight;
+
+ if ( slide.opts.image.srcset ) {
+ $img.attr( 'sizes', '100vw' ).attr( 'srcset', slide.opts.image.srcset );
+ }
+
+ self.hideLoading( slide );
+
+ if ( slide.$ghost ) {
+
+ slide.timouts = setTimeout(function() {
+ slide.timouts = null;
+
+ slide.$ghost.hide();
+
+ }, Math.min( 300, Math.max( 1000, slide.height / 1600 ) ) );
+
+ } else {
+ self.afterLoad( slide );
+ }
+
+ })
+ .addClass( 'fancybox-image' )
+ .attr('src', slide.src)
+ .appendTo( slide.$content );
+
+ if ( ( $img[0].complete || $img[0].readyState == "complete" ) && $img[0].naturalWidth && $img[0].naturalHeight ) {
+ $img.trigger( 'load' );
+
+ } else if( $img[0].error ) {
+ $img.trigger( 'error' );
+
+ } else {
+
+ slide.timouts = setTimeout(function() {
+ if ( !$img[0].complete && !slide.hasError ) {
+ self.showLoading( slide );
+ }
+
+ }, 100);
+
+ }
+
+ },
+
+
+ // 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 );
+
+ $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 $wrap = slide.$content,
+ frameWidth = opts.css.width,
+ frameHeight = opts.css.height,
+ scrollWidth,
+ $contents,
+ $body;
+
+ if ( $iframe[0].isReady !== 1 ) {
+ return;
+ }
+
+ // Check if content is accessible,
+ // it will fail if frame is not with the same origin
+
+ try {
+ $contents = $iframe.contents();
+ $body = $contents.find('body');
+
+ } catch (ignore) {}
+
+ // Calculate dimensions for the wrapper
+ if ( $body && $body.length ) {
+
+ if ( frameWidth === undefined ) {
+ scrollWidth = $iframe[0].contentWindow.document.documentElement.scrollWidth;
+
+ frameWidth = Math.ceil( $body.outerWidth(true) + ( $wrap.width() - scrollWidth ) );
+ frameWidth += $wrap.outerWidth() - $wrap.innerWidth();
+ }
+
+ if ( frameHeight === undefined ) {
+ frameHeight = Math.ceil( $body.outerHeight(true) );
+ frameHeight += $wrap.outerHeight() - $wrap.innerHeight();
+ }
+
+ // Resize wrapper to fit iframe content
+ if ( frameWidth ) {
+ $wrap.width( frameWidth );
+ }
+
+ if ( frameHeight ) {
+ $wrap.height( frameHeight );
+ }
+ }
+
+ $wrap.removeClass( 'fancybox-is-hidden' );
+
+ });
+
+ } else {
+
+ this.afterLoad( slide );
+
+ }
+
+ $iframe.attr( 'src', slide.src );
+
+ if ( slide.opts.smallBtn === true ) {
+ slide.$content.prepend( self.translate( slide, slide.opts.btnTpl.smallBtn ) );
+ }
+
+ // 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().attr( 'src', '//about:blank' );
+
+ } catch ( ignore ) {}
+
+ $( this ).empty();
+
+ slide.isLoaded = false;
+
+ });
+
+ },
+
+
+ // Wrap and append content to the slide
+ // ======================================
+
+ setContent : function ( slide, content ) {
+
+ var self = this;
+
+ if ( self.isClosing ) {
+ return;
+ }
+
+ self.hideLoading( slide );
+
+ slide.$slide.empty();
+
+ if ( isQuery( content ) && content.parent().length ) {
+
+ // 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 user is navigating gallery fast, then the content might be already inside fancyBox
+ // =====================================================================================
+
+ // Make sure content is not already moved to fancyBox
+ content.parent( '.fancybox-slide--inline' ).trigger( 'onReset' );
+
+ // Create temporary element marking original place of the content
+ slide.$placeholder = $( '<div></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 we have text node, then add wrapping element to make vertical alignment work
+ if ( content[0].nodeType === 3 ) {
+ content = $('<div>').html( content );
+ }
+ }
+
+ // 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 () {
+
+ // Put content back
+ if ( slide.$placeholder ) {
+ slide.$placeholder.after( 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.$content = $( content ).appendTo( slide.$slide );
+
+ this.afterLoad( slide );
+ },
+
+ // Display error message
+ // =====================
+
+ setError : function ( slide ) {
+
+ slide.hasError = true;
+
+ slide.$slide.removeClass( 'fancybox-slide--' + slide.type );
+
+ this.setContent( slide, this.translate( slide, slide.opts.errorTpl ) );
+
+ },
+
+
+ // Show loading icon inside the slide
+ // ==================================
+
+ showLoading : function( slide ) {
+
+ var self = this;
+
+ slide = slide || self.current;
+
+ if ( slide && !slide.$spinner ) {
+ slide.$spinner = $( self.opts.spinnerTpl ).appendTo( slide.$slide );
+ }
+
+ },
+
+ // Remove loading icon from the slide
+ // ==================================
+
+ hideLoading : function( slide ) {
+
+ var self = this;
+
+ slide = slide || self.current;
+
+ if ( slide && slide.$spinner ) {
+ slide.$spinner.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 );
+
+ if ( slide.opts.smallBtn && !slide.$smallBtn ) {
+ slide.$smallBtn = $( self.translate( slide, slide.opts.btnTpl.smallBtn ) ).appendTo( slide.$content.filter('div,form').first() );
+ }
+
+ if ( slide.opts.protect && slide.$content && !slide.hasError ) {
+
+ // Disable right click
+ 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.revealContent( slide );
+
+ },
+
+
+ // 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;
+ var $slide = slide.$slide;
+
+ var effect, effectClassName, duration, opacity, end, start = false;
+
+ effect = slide.opts[ self.firstRun ? 'animationEffect' : 'transitionEffect' ];
+ duration = slide.opts[ self.firstRun ? 'animationDuration' : 'transitionDuration' ];
+
+ duration = parseInt( slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10 );
+
+ if ( slide.isMoved || slide.pos !== self.currPos || !duration ) {
+ effect = false;
+ }
+
+ // Check if can zoom
+ if ( effect === 'zoom' && !( slide.pos === self.currPos && duration && slide.type === 'image' && !slide.hasError && ( start = self.getThumbPos( slide ) ) ) ) {
+ effect = 'fade';
+ }
+
+ // Zoom animation
+ // ==============
+
+ if ( effect === 'zoom' ) {
+ end = self.getFitPos( slide );
+
+ end.scaleX = end.width / start.width;
+ end.scaleY = end.height / start.height;
+
+ delete end.width;
+ delete end.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.complete();
+ });
+
+ return;
+ }
+
+
+ self.updateSlide( slide );
+
+
+ // Simply show content
+ // ===================
+
+ if ( !effect ) {
+ forceRedraw( $slide );
+
+ slide.$content.removeClass( 'fancybox-is-hidden' );
+
+ if ( slide.pos === self.currPos ) {
+ self.complete();
+ }
+
+ return;
+ }
+
+ $.fancybox.stop( $slide );
+
+ effectClassName = 'fancybox-animated fancybox-slide--' + ( slide.pos >= self.prevPos ? 'next' : 'previous' ) + ' fancybox-fx-' + effect;
+
+ $slide.removeAttr( 'style' ).removeClass( 'fancybox-slide--current fancybox-slide--next fancybox-slide--previous' ).addClass( effectClassName );
+
+ slide.$content.removeClass( 'fancybox-is-hidden' );
+
+ //Force reflow for CSS3 transitions
+ forceRedraw( $slide );
+
+ $.fancybox.animate( $slide, 'fancybox-slide--current', duration, function(e) {
+ $slide.removeClass( effectClassName ).removeAttr( 'style' );
+
+ if ( slide.pos === self.currPos ) {
+ self.complete();
+ }
+
+ }, true);
+
+ },
+
+
+ // Check if we can and have to zoom from thumbnail
+ //================================================
+
+ getThumbPos : function( slide ) {
+
+ var self = this;
+ var rez = false;
+
+ // Check if element is inside the viewport by at least 1 pixel
+ var isElementVisible = function( $el ) {
+ var element = $el[0];
+
+ var elementRect = element.getBoundingClientRect();
+ var parentRects = [];
+
+ var visibleInAllParents;
+
+ while ( element.parentElement !== null ) {
+ if ( $(element.parentElement).css('overflow') === 'hidden' || $(element.parentElement).css('overflow') === 'auto' ) {
+ parentRects.push(element.parentElement.getBoundingClientRect());
+ }
+
+ element = element.parentElement;
+ }
+
+ visibleInAllParents = parentRects.every(function(parentRect){
+ var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
+ var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
+
+ return visiblePixelX > 0 && visiblePixelY > 0;
+ });
+
+ return visibleInAllParents &&
+ elementRect.bottom > 0 && elementRect.right > 0 &&
+ elementRect.left < $(window).width() && elementRect.top < $(window).height();
+ };
+
+ var $thumb = slide.opts.$thumb;
+ var thumbPos = $thumb ? $thumb.offset() : 0;
+ var slidePos;
+
+ if ( thumbPos && $thumb[0].ownerDocument === document && isElementVisible( $thumb ) ) {
+ slidePos = self.$refs.stage.offset();
+
+ rez = {
+ top : thumbPos.top - slidePos.top + parseFloat( $thumb.css( "border-top-width" ) || 0 ),
+ left : thumbPos.left - slidePos.left + parseFloat( $thumb.css( "border-left-width" ) || 0 ),
+ width : $thumb.width(),
+ height : $thumb.height(),
+ scaleX : 1,
+ scaleY : 1
+ };
+ }
+
+ return rez;
+ },
+
+
+ // Final adjustments after current gallery item is moved to position
+ // and it`s content is loaded
+ // ==================================================================
+
+ complete : function() {
+
+ var self = this;
+
+ var current = self.current;
+ var slides = {};
+
+ if ( current.isMoved || !current.isLoaded || current.isComplete ) {
+ return;
+ }
+
+ current.isComplete = true;
+
+ current.$slide.siblings().trigger( 'onReset' );
+
+ // Trigger any CSS3 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.updateCursor();
+
+ self.trigger( 'afterShow' );
+
+ // Try to focus on the first focusable element
+ if ( $( document.activeElement ).is( '[disabled]' ) || ( current.opts.autoFocus && !( current.type == 'image' || current.type === 'iframe' ) ) ) {
+ self.focus();
+ }
+
+ },
+
+
+ // Preload next and previous slides
+ // ================================
+
+ preload : function() {
+ var self = this;
+ var next, prev;
+
+ if ( self.group.length < 2 ) {
+ return;
+ }
+
+ next = self.slides[ self.currPos + 1 ];
+ prev = self.slides[ self.currPos - 1 ];
+
+ if ( next && next.type === 'image' ) {
+ self.loadSlide( next );
+ }
+
+ if ( prev && prev.type === 'image' ) {
+ self.loadSlide( prev );
+ }
+
+ },
+
+
+ // Try to find and focus on the first focusable element
+ // ====================================================
+
+ focus : function() {
+ var current = this.current;
+ var $el;
+
+ if ( this.isClosing ) {
+ return;
+ }
+
+ if ( current && current.isComplete ) {
+
+ // Look for first input with autofocus attribute
+ $el = current.$slide.find('input[autofocus]:enabled:visible:first');
+
+ if ( !$el.length ) {
+ $el = current.$slide.find('button,:input,[tabindex],a').filter(':enabled:visible:first');
+ }
+ }
+
+ $el = $el && $el.length ? $el : this.$refs.container;
+
+ $el.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;
+ var current = self.current;
+
+ var effect, duration;
+ var $what, 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();
+
+ if ( current.timouts ) {
+ clearTimeout( current.timouts );
+ }
+
+ $what = current.$content;
+ effect = current.opts.animationEffect;
+ duration = $.isNumeric( d ) ? d : ( effect ? current.opts.animationDuration : 0 );
+
+ // Remove other slides
+ current.$slide.off( transitionEnd ).removeClass( 'fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated' );
+
+ current.$slide.siblings().trigger( 'onReset' ).remove();
+
+ // Trigger animations
+ if ( duration ) {
+ self.$refs.container.removeClass( 'fancybox-is-open' ).addClass( 'fancybox-is-closing' );
+ }
+
+ // Clean up
+ self.hideLoading( current );
+
+ self.hideControls();
+
+ self.updateCursor();
+
+ // Check if possible to zoom-out
+ if ( effect === 'zoom' && !( e !== true && $what && duration && current.type === 'image' && !current.hasError && ( end = self.getThumbPos( current ) ) ) ) {
+ effect = 'fade';
+ }
+
+ if ( effect === 'zoom' ) {
+ $.fancybox.stop( $what );
+
+ start = $.fancybox.getTranslate( $what );
+
+ start.width = start.width * start.scaleX;
+ start.height = start.height * start.scaleY;
+
+ // 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;
+ }
+
+ start.scaleX = start.width / end.width;
+ start.scaleY = start.height / end.height;
+
+ start.width = end.width;
+ start.height = end.height;
+
+ $.fancybox.setTranslate( current.$content, start );
+
+ $.fancybox.animate( current.$content, end, duration, done );
+
+ return true;
+ }
+
+ if ( effect && duration ) {
+
+ // If skip animation
+ if ( e === true ) {
+ setTimeout( done, duration );
+
+ } else {
+ $.fancybox.animate( current.$slide.removeClass( 'fancybox-slide--current' ), 'fancybox-animated fancybox-slide--previous fancybox-fx-' + effect, duration, done );
+ }
+
+ } else {
+ done();
+ }
+
+ return true;
+ },
+
+
+ // Final adjustments after removing the instance
+ // =============================================
+
+ cleanUp : function( e ) {
+ var self = this,
+ $body = $( 'body' ),
+ instance,
+ offset;
+
+ self.current.$slide.trigger( 'onReset' );
+
+ self.$refs.container.empty().remove();
+
+ self.trigger( 'afterClose', e );
+
+ // Place back focus
+ if ( self.$lastFocus && !!self.current.opts.backFocus ) {
+ self.$lastFocus.focus();
+ }
+
+ self.current = null;
+
+ // Check if there are other instances
+ instance = $.fancybox.getInstance();
+
+ if ( instance ) {
+ instance.activate();
+
+ } else {
+
+ $W.scrollTop( self.scrollTop ).scrollLeft( self.scrollLeft );
+
+ $body.removeClass( 'fancybox-active compensate-for-scrollbar' );
+
+ if ( $body.hasClass( 'fancybox-iosfix' ) ) {
+
+ offset = parseInt(document.body.style.top, 10);
+
+ $body.removeClass( 'fancybox-iosfix' ).css( 'top', '' ).scrollTop( offset * -1 );
+ }
+
+ $( '#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 ( force ) {
+
+ var self = this;
+
+ var current = self.current,
+ index = current.index,
+ caption = current.opts.caption,
+ $container = self.$refs.container,
+ $caption = self.$refs.caption;
+
+ // Recalculate content dimensions
+ current.$slide.trigger( 'refresh' );
+
+ self.$caption = caption && caption.length ? $caption.html( caption ) : null;
+
+ if ( !self.isHiddenControls && !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' ) {
+
+ // Update download button source
+ $container.find('[data-fancybox-download]').attr( 'href', current.opts.image.src || current.src ).show();
+
+ } else {
+ $container.find('[data-fancybox-download],[data-fancybox-zoom]').hide();
+ }
+ },
+
+ // Hide toolbar and caption
+ // ========================
+
+ hideControls : function () {
+
+ this.isHiddenControls = true;
+
+ this.$refs.container.removeClass( 'fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav' );
+
+ },
+
+ showControls : function() {
+ var self = this;
+ var opts = self.current ? self.current.opts : self.opts;
+ var $container = self.$refs.container;
+
+ self.isHiddenControls = 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-nav', !!( opts.arrows && self.group.length > 1 ) )
+ .toggleClass( 'fancybox-is-modal', !!opts.modal );
+
+ if ( self.$caption ) {
+ $container.addClass( 'fancybox-show-caption ');
+
+ } else {
+ $container.removeClass( 'fancybox-show-caption' );
+ }
+
+ },
+
+
+ // Toggle toolbar and caption
+ // ==========================
+
+ toggleControls : function() {
+ if ( this.isHiddenControls ) {
+ this.showControls();
+
+ } else {
+ this.hideControls();
+ }
+
+ },
+
+
+ });
+
+
+ $.fancybox = {
+
+ version : "3.2.3",
+ 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' );
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ if ( instance instanceof FancyBox ) {
+
[... 2398 lines stripped ...]