diff --git a/dist/jquery.fancybox.css b/dist/jquery.fancybox.css index 7fee589e..c5f28e13 100644 --- a/dist/jquery.fancybox.css +++ b/dist/jquery.fancybox.css @@ -1,6 +1,5 @@ body.compensate-for-scrollbar { - overflow: hidden; - -ms-overflow-style: none; } + overflow: hidden; } .fancybox-active { height: auto; } @@ -100,8 +99,8 @@ body.compensate-for-scrollbar { .fancybox-stage { direction: ltr; overflow: visible; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); + -webkit-transform: translateZ(0); + transform: translateZ(0); z-index: 99994; } .fancybox-is-open .fancybox-stage { @@ -109,7 +108,7 @@ body.compensate-for-scrollbar { .fancybox-slide { -webkit-backface-visibility: hidden; - backface-visibility: hidden; + /* Using without prefix would break IE11 */ display: none; height: 100%; left: 0; @@ -145,11 +144,9 @@ body.compensate-for-scrollbar { z-index: 99995; } .fancybox-slide--image { + overflow: hidden; padding: 44px 0 0 0; } -.fancybox-slide--image { - overflow: visible; } - .fancybox-slide--image::before { display: none; } @@ -172,7 +169,6 @@ body.compensate-for-scrollbar { -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.14, 1); animation-timing-function: cubic-bezier(0.5, 0, 0.14, 1); -webkit-backface-visibility: hidden; - backface-visibility: hidden; background: transparent; background-repeat: no-repeat; background-size: 100% 100%; @@ -286,11 +282,13 @@ body.compensate-for-scrollbar { background: rgba(30, 30, 30, 0.6); border: 0; border-radius: 0; + box-shadow: none; cursor: pointer; display: inline-block; height: 44px; margin: 0; padding: 10px; + position: relative; transition: color .2s; vertical-align: top; visibility: inherit; @@ -337,6 +335,25 @@ body.compensate-for-scrollbar { .fancybox-button--fsexit svg:nth-child(1) { display: none; } +.fancybox-progress { + background: #ff5268; + height: 2px; + left: 0; + position: absolute; + right: 0; + top: 0; + -webkit-transform: scaleX(0); + -ms-transform: scaleX(0); + transform: scaleX(0); + -webkit-transform-origin: 0; + -ms-transform-origin: 0; + transform-origin: 0; + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + transition-timing-function: linear; + z-index: 99998; } + /* Close button on the top right corner of html content */ .fancybox-close-small { background: transparent; @@ -434,37 +451,31 @@ body.compensate-for-scrollbar { /* Loading indicator */ .fancybox-loading { - -webkit-animation: fancybox-rotate .8s infinite linear; - animation: fancybox-rotate .8s infinite linear; + -webkit-animation: fancybox-rotate 1s linear infinite; + animation: fancybox-rotate 1s linear infinite; background: transparent; - border: 6px solid rgba(100, 100, 100, 0.5); - border-radius: 100%; - border-top-color: #fff; - height: 60px; + border: 4px solid #888; + border-bottom-color: #fff; + border-radius: 50%; + height: 50px; left: 50%; - margin: -30px 0 0 -30px; - opacity: .6; + margin: -25px 0 0 -25px; + opacity: .7; padding: 0; position: absolute; top: 50%; - width: 60px; + width: 50px; z-index: 99999; } @-webkit-keyframes fancybox-rotate { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); } - to { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); } } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } @keyframes fancybox-rotate { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); } - to { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); } } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } /* Transition effects */ .fancybox-animated { @@ -664,7 +675,7 @@ body.compensate-for-scrollbar { /* Thumbs */ .fancybox-thumbs { - background: #fff; + background: #ddd; bottom: 0; display: none; margin: 0; @@ -737,7 +748,7 @@ body.compensate-for-scrollbar { width: 100px; } .fancybox-thumbs__list a::before { - border: 4px solid #4ea7f9; + border: 6px solid #ff5268; bottom: 0; content: ''; left: 0; diff --git a/dist/jquery.fancybox.js b/dist/jquery.fancybox.js index 914477a0..e456d124 100644 --- a/dist/jquery.fancybox.js +++ b/dist/jquery.fancybox.js @@ -1,5 +1,5 @@ // ================================================== -// fancyBox v3.4.1 +// fancyBox v3.4.2 // // Licensed GPLv3 for open source use // or fancyBox Commercial License for commercial use @@ -70,7 +70,7 @@ buttons: [ "zoom", //"share", - //"slideShow", + "slideShow", //"fullScreen", //"download", "thumbs", @@ -108,7 +108,7 @@ iframe: { // Iframe template tpl: - '', + '', // Preload iframe before displaying it // This allows to calculate iframe content width and height @@ -477,6 +477,51 @@ return rez; }; + // How much of an element is visible in viewport + // ============================================= + + var inViewport = function($el) { + var element = $el[0], + elementRect = element.getBoundingClientRect(), + parentRects = [], + visibleInAllParents, + windowHeight = $(window).height(), + pageScroll = $(document).scrollTop(), + elementTop = elementRect.top + pageScroll, + hiddenBefore = pageScroll - elementTop, + hiddenAfter = elementTop + elementRect.height - (pageScroll + windowHeight); + + // Check if the parent can hide its children + 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; + }); + + if (!visibleInAllParents || pageScroll > elementTop + elementRect.height || elementTop > pageScroll + windowHeight) { + return 0; + } + + if (hiddenBefore > 0) { + return 100 - (hiddenBefore * 100) / elementRect.height; + } + + if (hiddenAfter > 0) { + return 100 - (hiddenAfter * 100) / elementRect.height; + } + + return 100; + }; + // Class definition // ================ @@ -527,8 +572,6 @@ var self = this, firstItem = self.group[self.currIndex], firstItemOpts = firstItem.opts, - scrollbarWidth = $.fancybox.scrollbarWidth, - $scrollDiv, $container, buttonStr; @@ -547,18 +590,10 @@ !$.fancybox.isMobile && document.body.scrollHeight > window.innerHeight ) { - if (scrollbarWidth === undefined) { - $scrollDiv = $('
').appendTo("body"); - - scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth; - - $scrollDiv.remove(); - } - $("head").append( - '" + '" ); $("body").addClass("compensate-for-scrollbar"); @@ -779,6 +814,7 @@ // 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, @@ -1012,34 +1048,31 @@ loop, current, previous, - canvasWidth, - transitionProps; + slidePos, + stagePos, + diff; if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) { return; } - pos = parseInt(pos, 10); - // 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; - if (groupLen < 2 && !firstRun && !!self.isDragging) { - return; - } - + // Create slides previous = self.current; self.prevIndex = self.currIndex; self.prevPos = self.currPos; - // Create slides current = self.createSlide(pos); if (groupLen > 1) { @@ -1060,8 +1093,6 @@ self.updateControls(); - isMoved = self.isMoved(current); - // Validate duration length current.forcedDuration = undefined; @@ -1073,72 +1104,102 @@ duration = parseInt(duration, 10); + // Check if user has swiped the slides or if still animating + isMoved = self.isMoved(previous); + + // 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"); - - // Make current slide visible - current.$slide.addClass("fancybox-slide--previous"); + self.$refs.container.addClass("fancybox-is-open").trigger("focus"); // Attempt to load content into slide - // At this point image would start loading, but inline/html content would load immediately + // This will later call `afterLoad` -> `revealContent` self.loadSlide(current); - current.$slide.removeClass("fancybox-slide--previous").addClass("fancybox-slide--current"); - self.preload("image"); - self.$refs.container.trigger("focus"); - 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) { - // Make sure that animation callback gets fired $.fancybox.stop(slide.$slide, true); - - slide.$slide.removeClass("fancybox-animated").removeClass(function(index, className) { - return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" "); - }); }); - // Make current slide visible even if content is still loading - current.$slide.removeClass("fancybox-slide--next fancybox-slide--previous").addClass("fancybox-slide--current"); + if (previous.pos !== current.pos) { + previous.isComplete = false; + + previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current"); + } - // If slides have been dragged, animate them to correct position + // If slides are out of place, then animate them to correct position if (isMoved) { - canvasWidth = Math.round(current.$slide.width()); + // Calculate horizontal swipe distance + diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter); $.each(self.slides, function(index, slide) { - var pos = slide.pos - current.pos; + // 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.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"); + $.fancybox.setTranslate(slide.$slide, {top: 0, left: leftPos + diff - stagePos.left}); + + 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 + requestAFrame(function() { + $.fancybox.animate( + slide.$slide, + { + top: 0, + left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter + }, + duration, + function() { + slide.$slide.removeAttr("style").removeClass("fancybox-slide--next fancybox-slide--previous"); - if (slide.pos === self.currPos) { - self.complete(); + if (slide.pos === self.currPos) { + self.complete(); + } } - } - ); + ); + }); }); } else { - self.$refs.stage.children().removeAttr("style"); - } + current.$slide + .parent() + .children() + .removeAttr("style"); - // Start transition that reveals current content - // or wait when it will be loaded + // Handle previously active slide + if (duration && current.opts.transitionEffect) { + $.fancybox.animate( + previous.$slide, + "fancybox-animated fancybox-slide--" + + (previous.pos > current.pos ? "next" : "previous") + + " fancybox-fx-" + + current.opts.transitionEffect, + duration, + null, + false + ); + } + } if (current.isLoaded) { self.revealContent(current); @@ -1147,31 +1208,6 @@ } self.preload("image"); - - if (previous.pos === current.pos) { - return; - } - - // Handle previously active 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 || (!isMoved && !current.opts.transitionEffect)) { - return; - } - - if (isMoved) { - previous.$slide.addClass(transitionProps); - } else { - transitionProps = "fancybox-animated " + transitionProps + " fancybox-fx-" + current.opts.transitionEffect; - - $.fancybox.animate(previous.$slide, transitionProps, duration, null, false); - } }, // Create new "slide" element @@ -1366,9 +1402,17 @@ minRatio = Math.min(1, maxWidth / width, maxHeight / height); - // Use floor rounding to make sure it really fits - width = Math.floor(minRatio * width); - height = Math.floor(minRatio * 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")); @@ -1453,7 +1497,17 @@ opacity: 1 }, duration === undefined ? 0 : duration, - null, + function() { + // Clean up other slides + slide.$slide + .siblings() + .removeAttr("style") + .removeClass("fancybox-slide--previous fancybox-slide--next"); + + if (!slide.isComplete) { + self.complete(); + } + }, false ); } @@ -1464,9 +1518,20 @@ isMoved: function(slide) { var current = slide || this.current, - currentPos = $.fancybox.getTranslate(current.$slide); + slidePos, + stagePos; + + if (!current) { + return false; + } + + stagePos = $.fancybox.getTranslate(this.$refs.stage); + slidePos = $.fancybox.getTranslate(current.$slide); - return (currentPos.left !== 0 || currentPos.top !== 0) && !current.$slide.hasClass("fancybox-animated"); + return ( + (Math.abs(slidePos.top - stagePos.top) > 0 || Math.abs(slidePos.left - stagePos.left) > 0) && + !current.$slide.hasClass("fancybox-animated") + ); }, // Update cursor style depending if content can be zoomed @@ -1475,15 +1540,15 @@ updateCursor: function(nextWidth, nextHeight) { var self = this, current = self.current, - $container = self.$refs.container.removeClass( - "fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan" - ), + $container = self.$refs.container, isZoomable; - if (!current || self.isClosing) { + if (!current || self.isClosing || !self.Guestures) { return; } + $container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"); + isZoomable = self.isZoomable(); $container.toggleClass("fancybox-is-zoomable", isZoomable); @@ -1586,7 +1651,11 @@ slide.isLoading = true; - self.trigger("beforeLoad", slide); + if (self.trigger("beforeLoad", slide) === false) { + slide.isLoading = false; + + return false; + } type = slide.type; $slide = slide.$slide; @@ -1677,13 +1746,15 @@ windowWidth; // Check if need to show loading icon - slide.timouts = setTimeout(function() { - var $img = slide.$image; + requestAFrame(function() { + requestAFrame(function() { + var $img = slide.$image; - if (slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) { - self.showLoading(slide); - } - }, 350); + if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) { + self.showLoading(slide); + } + }); + }); // 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 @@ -1797,12 +1868,6 @@ self.afterLoad(slide); } - // Clear timeout that checks if loading icon needs to be displayed - if (slide.timouts) { - clearTimeout(slide.timouts); - slide.timouts = null; - } - if (self.isClosing) { return; } @@ -1922,24 +1987,21 @@ $content.css({ width: "100%", - height: "" + "max-width": "100%", + height: "9999px" }); if (frameWidth === undefined) { frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true))); } - if (frameWidth) { - $content.width(frameWidth); - } + $content.css("width", frameWidth ? frameWidth : "").css("max-width", ""); if (frameHeight === undefined) { frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true))); } - if (frameHeight) { - $content.height(frameHeight); - } + $content.css("height", frameHeight ? frameHeight : ""); $slide.css("overflow", "auto"); } @@ -1968,6 +2030,7 @@ .empty(); slide.isLoaded = false; + slide.isRevealed = false; }); }, @@ -2114,7 +2177,10 @@ slide = slide || self.current; if (slide && !slide.$spinner) { - slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)).appendTo(slide.$slide); + slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)) + .appendTo(slide.$slide) + .hide() + .fadeIn(); } }, @@ -2127,7 +2193,7 @@ slide = slide || self.current; if (slide && slide.$spinner) { - slide.$spinner.remove(); + slide.$spinner.stop().remove(); delete slide.$spinner; } @@ -2195,10 +2261,6 @@ duration, opacity; - if (isMoved && isRevealed) { - return; - } - slide.isRevealed = true; effect = slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"]; @@ -2209,7 +2271,7 @@ // Do not animate if revealing the same slide if (slide.pos === self.currPos) { if (slide.isComplete) { - effect = false; + //effect = false; } else { self.isAnimating = true; } @@ -2249,8 +2311,6 @@ // 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; @@ -2266,17 +2326,10 @@ // Simply show content if no effect // ================================ if (!effect) { - forceRedraw($slide); + slide.$content.removeClass("fancybox-is-hidden"); - if (!isRevealed) { - slide.$content - .removeClass("fancybox-is-hidden") - .hide() - .fadeIn("fast"); - } - - if (slide.pos === self.currPos) { - self.complete(); + if (!isRevealed && isMoved && slide.type === "image" && !slide.hasError) { + slide.$content.hide().fadeIn("fast"); } return; @@ -2288,15 +2341,12 @@ 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.removeClass("fancybox-slide--current").addClass(effectClassName); slide.$content.removeClass("fancybox-is-hidden"); // Force reflow - forceRedraw($slide); + $slide.hide().show(0); $.fancybox.animate( $slide, @@ -2323,38 +2373,7 @@ thumbPos = $thumb && $thumb.length && $thumb[0].ownerDocument === document ? $thumb.offset() : 0, slidePos; - // Check if element is inside the viewport by at least 1 pixel - var isElementVisible = function($el) { - var element = $el[0], - elementRect = element.getBoundingClientRect(), - parentRects = [], - 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() - ); - }; - - if (thumbPos && isElementVisible($thumb)) { + if (thumbPos && inViewport($thumb) >= 10) { slidePos = self.$refs.stage.offset(); rez = { @@ -2421,7 +2440,8 @@ current.$slide .find("video,audio") .filter(":visible:first") - .trigger("play"); + .trigger("play") + .on("ended", $.proxy(self.next, self)); } // Try to focus on the first focusable element @@ -2593,10 +2613,6 @@ // If there are multiple instances, they will be set again by "activate" method self.removeEvents(); - if (current.timouts) { - clearTimeout(current.timouts); - } - $content = current.$content; effect = current.opts.animationEffect; duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0; @@ -2848,7 +2864,7 @@ }); $.fancybox = { - version: "3.4.1", + version: "3.4.2", defaults: defaults, // Get current instance and execute a command. @@ -2980,7 +2996,9 @@ } if (props.scaleX !== undefined && props.scaleY !== undefined) { - str = (str.length ? str + " " : "") + "scale(" + props.scaleX + ", " + props.scaleY + ")"; + str += " scale(" + props.scaleX + ", " + props.scaleY + ")"; + } else if (props.scaleX !== undefined) { + str += " scaleX(" + props.scaleX + ")"; } if (str.length) { @@ -3006,7 +3024,8 @@ // ============================= animate: function($el, to, duration, callback, leaveAnimationName) { - var final = false, + var self = this, + final = false, from; if ($.isFunction(duration)) { @@ -3018,7 +3037,7 @@ $el.removeAttr("style"); } - $.fancybox.stop($el); + self.stop($el); $el.on(transitionEnd, function(e) { // Skip events from child elements and z-index change @@ -3026,10 +3045,10 @@ return; } - $.fancybox.stop($el); + self.stop($el); if (final) { - $.fancybox.setTranslate($el, final); + self.setTranslate($el, final); } if ($.isNumeric(duration)) { @@ -3242,32 +3261,7 @@ (function($) { "use strict"; - // 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; - }; - // 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, @@ -3295,8 +3289,7 @@ show_title: 1, show_byline: 1, show_portrait: 0, - fullscreen: 1, - api: 1 + fullscreen: 1 }, paramPlace: 3, type: "iframe", @@ -3342,6 +3335,29 @@ } }; + // 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, @@ -3433,6 +3449,98 @@ 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 + }, + + 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(); + }); + } + } + } + }; + + $(document).on({ + "afterShow.fb": function(e, instance, current) { + if (instance.group.length > 1 && (current.contentSource === "youtube" || current.contentSource === "vimeo")) { + VideoAPILoader.load(current.contentSource); + } + } + }); })(jQuery); // ========================================================================== @@ -3622,7 +3730,7 @@ self.startEvent = e; - self.canTap = true; + self.canTap = !current.$slide.hasClass("fancybox-animated"); self.$target = $target; self.$content = $content; self.opts = current.opts.touch; @@ -3682,8 +3790,6 @@ if (self.canPan) { $.fancybox.stop(self.$content); - self.$content.css("transition-duration", ""); - self.isPanning = true; } else { self.isSwiping = true; @@ -3702,8 +3808,6 @@ $.fancybox.stop(self.$content); - self.$content.css("transition-duration", ""); - 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(); @@ -3765,6 +3869,7 @@ Guestures.prototype.onSwipe = function(e) { var self = this, + instance = self.instance, swiping = self.isSwiping, left = self.sliderStartPos.left || 0, angle; @@ -3775,9 +3880,9 @@ if (Math.abs(self.distance) > 10) { self.canTap = false; - if (self.instance.group.length < 2 && self.opts.vertical) { + if (instance.group.length < 2 && self.opts.vertical) { self.isSwiping = "y"; - } else if (self.instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) { + } 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); @@ -3785,34 +3890,45 @@ self.isSwiping = angle > 45 && angle < 135 ? "y" : "x"; } - self.canTap = false; - if (self.isSwiping === "y" && $.fancybox.isMobile && self.isScrollable) { self.isScrolling = true; return; } - self.instance.isDragging = self.isSwiping; + instance.isDragging = self.isSwiping; // Reset points to avoid jumping, because we dropped first swipes to calculate the angle self.startPoints = self.newPoints; - $.each(self.instance.slides, function(index, slide) { + $.each(instance.slides, function(index, slide) { + var slidePos, stagePos; + $.fancybox.stop(slide.$slide); - slide.$slide.css("transition-duration", ""); + slidePos = $.fancybox.getTranslate(slide.$slide); + stagePos = $.fancybox.getTranslate(instance.$refs.stage); - slide.inTransition = false; + slide.$slide + .removeAttr("style") + .removeClass("fancybox-animated") + .removeClass(function(index, className) { + return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" "); + }); - if (slide.pos === self.instance.current.pos) { - self.sliderStartPos.left = $.fancybox.getTranslate(slide.$slide).left - $.fancybox.getTranslate(self.instance.$refs.stage).left; + if (slide.pos === instance.current.pos) { + self.sliderStartPos.left = slidePos.left - stagePos.left; } + + $.fancybox.setTranslate(slide.$slide, { + top: slidePos.top - stagePos.top, + left: slidePos.left - stagePos.left + }); }); // Stop slideshow - if (self.instance.SlideShow && self.instance.SlideShow.isActive) { - self.instance.SlideShow.stop(); + if (instance.SlideShow && instance.SlideShow.isActive) { + instance.SlideShow.stop(); } } @@ -4040,7 +4156,6 @@ Guestures.prototype.ontouchend = function(e) { var self = this; - var dMs = Math.max(new Date().getTime() - self.startTime, 1); var swiping = self.isSwiping; var panning = self.isPanning; @@ -4048,6 +4163,7 @@ var scrolling = self.isScrolling; self.endPoints = getPointerXY(e); + self.dMs = Math.max(new Date().getTime() - self.startTime, 1); self.$container.removeClass("fancybox-is-grabbing"); @@ -4072,13 +4188,11 @@ return self.onTap(e); } - self.speed = 366; + self.speed = 100; // Speed in px/ms - self.velocityX = (self.distanceX / dMs) * 0.5; - self.velocityY = (self.distanceY / dMs) * 0.5; - - self.speedX = Math.max(self.speed * 0.5, Math.min(self.speed * 1.5, (1 / Math.abs(self.velocityX)) * self.speed)); + self.velocityX = (self.distanceX / self.dMs) * 0.5; + self.velocityY = (self.distanceY / self.dMs) * 0.5; if (panning) { self.endPanning(); @@ -4094,7 +4208,11 @@ Guestures.prototype.endSwiping = function(swiping, scrolling) { var self = this, ret = false, - len = self.instance.group.length; + len = self.instance.group.length, + velocityX = Math.abs(self.velocityX), + distanceX = Math.abs(self.distanceX), + canAdvance = swiping == "x" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50), + speedX = Math.abs((velocityX * self.canvasWidth) / self.canvasWidth) > 0.8 ? 366 : 500; self.sliderLastPos = null; @@ -4111,18 +4229,14 @@ ); ret = self.instance.close(true, 200); - } else if (swiping == "x" && self.distanceX > 50 && len > 1) { - ret = self.instance.previous(self.speedX); - } else if (swiping == "x" && self.distanceX < -50 && len > 1) { - ret = self.instance.next(self.speedX); + } 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")) { - if (scrolling || len < 2) { - self.instance.centerSlide(self.instance.current, 150); - } else { - self.instance.jumpTo(self.instance.current.index); - } + self.instance.centerSlide(self.instance.current, 150); } self.$container.removeClass("fancybox-is-sliding"); @@ -4131,20 +4245,22 @@ // Limit panning from edges // ======================== Guestures.prototype.endPanning = function() { - var self = this; - var newOffsetX, newOffsetY, newPos; + var self = this, + newOffsetX, + newOffsetY, + newPos; if (!self.contentLastPos) { return; } - if (self.opts.momentum === false) { + 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 * self.speed; - newOffsetY = self.contentLastPos.top + self.velocityY * self.speed; + 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); @@ -4352,7 +4468,8 @@ }, slideShow: { autoStart: false, - speed: 3000 + speed: 3000, + progress: true } }); @@ -4367,42 +4484,37 @@ $button: null, init: function() { - var self = this; + var self = this, + instance = self.instance, + opts = instance.group[instance.currIndex].opts.slideShow; - self.$button = self.instance.$refs.toolbar.find("[data-fancybox-play]").on("click", function() { + self.$button = instance.$refs.toolbar.find("[data-fancybox-play]").on("click", function() { self.toggle(); }); - if (self.instance.group.length < 2 || !self.instance.group[self.instance.currIndex].opts.slideShow) { + if (instance.group.length < 2 || !opts) { self.$button.hide(); + } else if (opts.progress) { + self.$progress = $('').appendTo(instance.$refs.inner); } }, set: function(force) { var self = this, instance = self.instance, - current = instance.current, - advance = function() { - if (self.isActive) { - instance.jumpTo((instance.currIndex + 1) % instance.group.length); - } - }; + current = instance.current; // Check if reached last element if (current && (force === true || current.opts.loop || instance.currIndex < instance.group.length - 1)) { - self.timer = setTimeout(function() { - var $video; - - if (self.isActive) { - $video = current.$slide.find("video,audio").filter(":visible:first"); - - if ($video.length) { - $video.one("ended", advance); - } else { - advance(); - } + if (self.isActive && current.contentType !== "video") { + if (self.$progress) { + $.fancybox.animate(self.$progress.show(), {scaleX: 1}, current.opts.slideShow.speed); } - }, current.opts.slideShow.speed); + + self.timer = setTimeout(function() { + instance.jumpTo((instance.currIndex + 1) % instance.group.length); + }, current.opts.slideShow.speed); + } } else { self.stop(); instance.idleSecondsCounter = 0; @@ -4416,11 +4528,15 @@ clearTimeout(self.timer); self.timer = null; + + if (self.$progress) { + self.$progress.removeAttr("style").hide(); + } }, start: function() { - var self = this; - var current = self.instance.current; + var self = this, + current = self.instance.current; if (current) { self.$button @@ -4439,8 +4555,8 @@ }, stop: function() { - var self = this; - var current = self.instance.current; + var self = this, + current = self.instance.current; self.clear(); @@ -4452,6 +4568,10 @@ self.isActive = false; self.instance.trigger("onSlideShowChange", false); + + if (self.$progress) { + self.$progress.removeAttr("style").hide(); + } }, toggle: function() { @@ -4514,8 +4634,8 @@ // Page Visibility API to pause slideshow when window is not active $(document).on("visibilitychange", function() { - var instance = $.fancybox.getInstance(); - var SlideShow = instance && instance.SlideShow; + var instance = $.fancybox.getInstance(), + SlideShow = instance && instance.SlideShow; if (SlideShow && SlideShow.isActive) { if (document.hidden) { @@ -4813,8 +4933,8 @@ list.push( '' : "") + + '"' + + (src && src.length ? ' style="background-image:url(' + src + ')"' : "") + ">" ); }); diff --git a/dist/jquery.fancybox.min.css b/dist/jquery.fancybox.min.css index 7f2fb868..0637c0ef 100644 --- a/dist/jquery.fancybox.min.css +++ b/dist/jquery.fancybox.min.css @@ -1 +1 @@ -body.compensate-for-scrollbar{overflow:hidden;-ms-overflow-style:none}.fancybox-active{height:auto}.fancybox-is-hidden{left:-9999px;margin:0;position:absolute!important;top:-9999px;visibility:hidden}.fancybox-container{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;left:0;outline:none;position:fixed;-webkit-tap-highlight-color:transparent;top:0;-ms-touch-action:manipulation;touch-action:manipulation;-webkit-transform:translateZ(0);transform:translateZ(0);width:100%;z-index:99992}.fancybox-container *{box-sizing:border-box}.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-stage{bottom:0;left:0;position:absolute;right:0;top:0}.fancybox-outer{-webkit-overflow-scrolling:touch;overflow-y:auto}.fancybox-bg{background:#1e1e1e;opacity:0;transition-duration:inherit;transition-property:opacity;transition-timing-function:cubic-bezier(.47,0,.74,.71)}.fancybox-is-open .fancybox-bg{opacity:.87;transition-timing-function:cubic-bezier(.22,.61,.36,1)}.fancybox-caption,.fancybox-infobar,.fancybox-navigation .fancybox-button,.fancybox-toolbar{direction:ltr;opacity:0;position:absolute;transition:opacity .25s ease,visibility 0s ease .25s;visibility:hidden;z-index:99997}.fancybox-show-caption .fancybox-caption,.fancybox-show-infobar .fancybox-infobar,.fancybox-show-nav .fancybox-navigation .fancybox-button,.fancybox-show-toolbar .fancybox-toolbar{opacity:1;transition:opacity .25s ease 0s,visibility 0s ease 0s;visibility:visible}.fancybox-infobar{color:#ccc;font-size:13px;-webkit-font-smoothing:subpixel-antialiased;height:44px;left:0;line-height:44px;min-width:44px;mix-blend-mode:difference;padding:0 10px;pointer-events:none;top:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fancybox-toolbar{right:0;top:0}.fancybox-stage{direction:ltr;overflow:visible;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:99994}.fancybox-is-open .fancybox-stage{overflow:hidden}.fancybox-slide{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:none;height:100%;left:0;outline:none;overflow:auto;-webkit-overflow-scrolling:touch;padding:44px 44px 0;position:absolute;text-align:center;top:0;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform;white-space:normal;width:100%;z-index:99994}.fancybox-slide:before{content:"";display:inline-block;font-size:0;height:100%;vertical-align:middle;width:0}.fancybox-is-sliding .fancybox-slide,.fancybox-slide--current,.fancybox-slide--next,.fancybox-slide--previous{display:block}.fancybox-slide--next{z-index:99995}.fancybox-slide--image{padding:44px 0 0;overflow:visible}.fancybox-slide--image:before{display:none}.fancybox-slide--html{padding:6px 6px 0}.fancybox-content{background:#fff;display:inline-block;margin:0 0 44px;max-width:100%;overflow:auto;-webkit-overflow-scrolling:touch;padding:44px;position:relative;text-align:left;vertical-align:middle}.fancybox-slide--image .fancybox-content{-webkit-animation-timing-function:cubic-bezier(.5,0,.14,1);animation-timing-function:cubic-bezier(.5,0,.14,1);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:transparent;background-repeat:no-repeat;background-size:100% 100%;left:0;max-width:none;overflow:visible;padding:0;position:absolute;top:0;-webkit-transform-origin:top left;transform-origin:top left;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:99995}.fancybox-slide--html .fancybox-content{margin:0 0 6px}.fancybox-can-zoomOut .fancybox-content{cursor:zoom-out}.fancybox-can-zoomIn .fancybox-content{cursor:zoom-in}.fancybox-can-pan .fancybox-content,.fancybox-can-swipe .fancybox-content{cursor:-webkit-grab;cursor:grab}.fancybox-is-grabbing .fancybox-content{cursor:-webkit-grabbing;cursor:grabbing}.fancybox-container [data-selectable=true]{cursor:text}.fancybox-image,.fancybox-spaceball{background:transparent;border:0;height:100%;left:0;margin:0;max-height:none;max-width:none;padding:0;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:100%}.fancybox-spaceball{z-index:1}.fancybox-slide--iframe .fancybox-content,.fancybox-slide--map .fancybox-content,.fancybox-slide--video .fancybox-content{height:calc(100% - 44px);overflow:visible;padding:0;width:100%}.fancybox-slide--video .fancybox-content{background:#000}.fancybox-slide--map .fancybox-content{background:#e5e3df}.fancybox-slide--iframe .fancybox-content{background:#fff}.fancybox-iframe,.fancybox-video{background:transparent;border:0;display:block;height:100%;margin:0;overflow:hidden;padding:0;vertical-align:top;width:100%}.fancybox-error{background:#fff;cursor:default;max-width:400px;padding:40px;width:100%}.fancybox-error p{color:#444;font-size:16px;line-height:20px;margin:0;padding:0}.fancybox-button{background:rgba(30,30,30,.6);border:0;border-radius:0;cursor:pointer;display:inline-block;height:44px;margin:0;padding:10px;transition:color .2s;vertical-align:top;visibility:inherit;width:44px}.fancybox-button,.fancybox-button:link,.fancybox-button:visited{color:#ccc}.fancybox-button:hover{color:#fff}.fancybox-button:focus{outline:none}.fancybox-button.fancybox-focus{outline:1px dotted}.fancybox-button.disabled,.fancybox-button.disabled:hover,.fancybox-button[disabled],.fancybox-button[disabled]:hover{color:#888;cursor:default;outline:none}.fancybox-button svg{display:block;height:100%;overflow:visible;position:relative;width:100%}.fancybox-button svg path{fill:currentColor;stroke-width:0}.fancybox-button--fsenter svg:nth-child(2),.fancybox-button--fsexit svg:nth-child(1),.fancybox-button--pause svg:nth-child(1),.fancybox-button--play svg:nth-child(2){display:none}.fancybox-close-small{background:transparent;border:0;border-radius:0;color:#ccc;cursor:pointer;opacity:.8;padding:8px;position:absolute;right:-12px;top:-44px;z-index:401}.fancybox-close-small:hover{color:#fff;opacity:1}.fancybox-slide--html .fancybox-close-small{color:currentColor;padding:10px;right:0;top:0}.fancybox-is-scaling .fancybox-close-small,.fancybox-is-zoomable.fancybox-can-pan .fancybox-close-small{display:none}.fancybox-navigation .fancybox-button{background:transparent;height:100px;margin:0;opacity:0;position:absolute;top:calc(50% - 50px);width:70px}.fancybox-navigation .fancybox-button div{background:rgba(30,30,30,.6);height:100%;padding:7px}.fancybox-navigation .fancybox-button--arrow_left{left:0;padding:31px 26px 31px 6px}.fancybox-navigation .fancybox-button--arrow_right{padding:31px 6px 31px 26px;right:0}.fancybox-caption{bottom:0;color:#fff;font-size:14px;font-weight:400;left:0;line-height:1.5;padding:25px 44px;right:0}.fancybox-caption:before{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAEtCAQAAABjBcL7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHRJREFUKM+Vk8EOgDAIQ0vj/3+xBw8qIZZueFnIKC90MCAI8DlrkHGeqqGIU6lVigrBtpCWqeRWoHDNqs0F7VNVBVxmHRlvoVqjaYkdnDIaivH2HqZ5+oZj3JUzWB+cOz4G48Bg+tsJ/tqu4dLC/4Xb+0GcF5BwBC0AA53qAAAAAElFTkSuQmCC);background-repeat:repeat-x;background-size:contain;bottom:0;content:"";display:block;left:0;pointer-events:none;position:absolute;right:0;top:-25px;z-index:-1}.fancybox-caption:after{border-bottom:1px solid hsla(0,0%,100%,.3);content:"";display:block;left:44px;position:absolute;right:44px;top:0}.fancybox-caption a,.fancybox-caption a:link,.fancybox-caption a:visited{color:#ccc;text-decoration:none}.fancybox-caption a:hover{color:#fff;text-decoration:underline}.fancybox-loading{-webkit-animation:a .8s infinite linear;animation:a .8s infinite linear;background:transparent;border:6px solid hsla(0,0%,39%,.5);border-radius:100%;border-top-color:#fff;height:60px;left:50%;margin:-30px 0 0 -30px;opacity:.6;padding:0;position:absolute;top:50%;width:60px;z-index:99999}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fancybox-animated{transition-timing-function:cubic-bezier(0,0,.25,1)}.fancybox-fx-slide.fancybox-slide--previous{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.fancybox-fx-slide.fancybox-slide--next{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.fancybox-fx-slide.fancybox-slide--current{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}.fancybox-fx-fade.fancybox-slide--next,.fancybox-fx-fade.fancybox-slide--previous{opacity:0;transition-timing-function:cubic-bezier(.19,1,.22,1)}.fancybox-fx-fade.fancybox-slide--current{opacity:1}.fancybox-fx-zoom-in-out.fancybox-slide--previous{opacity:0;-webkit-transform:scale3d(1.5,1.5,1.5);transform:scale3d(1.5,1.5,1.5)}.fancybox-fx-zoom-in-out.fancybox-slide--next{opacity:0;-webkit-transform:scale3d(.5,.5,.5);transform:scale3d(.5,.5,.5)}.fancybox-fx-zoom-in-out.fancybox-slide--current{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}.fancybox-fx-rotate.fancybox-slide--previous{opacity:0;-webkit-transform:rotate(-1turn);transform:rotate(-1turn)}.fancybox-fx-rotate.fancybox-slide--next{opacity:0;-webkit-transform:rotate(1turn);transform:rotate(1turn)}.fancybox-fx-rotate.fancybox-slide--current{opacity:1;-webkit-transform:rotate(0deg);transform:rotate(0deg)}.fancybox-fx-circular.fancybox-slide--previous{opacity:0;-webkit-transform:scale3d(0,0,0) translate3d(-100%,0,0);transform:scale3d(0,0,0) translate3d(-100%,0,0)}.fancybox-fx-circular.fancybox-slide--next{opacity:0;-webkit-transform:scale3d(0,0,0) translate3d(100%,0,0);transform:scale3d(0,0,0) translate3d(100%,0,0)}.fancybox-fx-circular.fancybox-slide--current{opacity:1;-webkit-transform:scaleX(1) translateZ(0);transform:scaleX(1) translateZ(0)}.fancybox-fx-tube.fancybox-slide--previous{-webkit-transform:translate3d(-100%,0,0) scale(.1) skew(-10deg);transform:translate3d(-100%,0,0) scale(.1) skew(-10deg)}.fancybox-fx-tube.fancybox-slide--next{-webkit-transform:translate3d(100%,0,0) scale(.1) skew(10deg);transform:translate3d(100%,0,0) scale(.1) skew(10deg)}.fancybox-fx-tube.fancybox-slide--current{-webkit-transform:translateZ(0) scale(1);transform:translateZ(0) scale(1)}@media (max-height:576px){.fancybox-slide{padding-left:6px;padding-right:6px}.fancybox-slide--image{padding:6px 0 0}.fancybox-slide--image .fancybox-content{margin-bottom:6px}.fancybox-slide--image .fancybox-close-small{background:#4e4e4e;color:#f2f4f6;height:36px;opacity:1;padding:6px;right:0;top:0;width:36px}}.fancybox-share{background:#f4f4f4;border-radius:3px;max-width:90%;padding:30px;text-align:center}.fancybox-share h1{color:#222;font-size:35px;font-weight:700;margin:0 0 20px}.fancybox-share p{margin:0;padding:0}.fancybox-share__button{border:0;border-radius:3px;display:inline-block;font-size:14px;font-weight:700;line-height:40px;margin:0 5px 10px;min-width:130px;padding:0 15px;text-decoration:none;transition:all .2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap}.fancybox-share__button:link,.fancybox-share__button:visited{color:#fff}.fancybox-share__button:hover{text-decoration:none}.fancybox-share__button--fb{background:#3b5998}.fancybox-share__button--fb:hover{background:#344e86}.fancybox-share__button--pt{background:#bd081d}.fancybox-share__button--pt:hover{background:#aa0719}.fancybox-share__button--tw{background:#1da1f2}.fancybox-share__button--tw:hover{background:#0d95e8}.fancybox-share__button svg{height:25px;margin-right:7px;position:relative;top:-1px;vertical-align:middle;width:25px}.fancybox-share__button svg path{fill:#fff}.fancybox-share__input{background:transparent;border:0;border-bottom:1px solid #d7d7d7;border-radius:0;color:#5d5b5b;font-size:14px;margin:10px 0 0;outline:none;padding:10px 15px;width:100%}.fancybox-thumbs{background:#fff;bottom:0;display:none;margin:0;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;padding:2px 2px 4px;position:absolute;right:0;-webkit-tap-highlight-color:transparent;top:0;width:212px;z-index:99995}.fancybox-thumbs-x{overflow-x:auto;overflow-y:hidden}.fancybox-show-thumbs .fancybox-thumbs{display:block}.fancybox-show-thumbs .fancybox-inner{right:212px}.fancybox-thumbs__list{font-size:0;height:100%;list-style:none;margin:0;overflow-x:hidden;overflow-y:auto;padding:0;position:absolute;position:relative;white-space:nowrap;width:100%}.fancybox-thumbs-x .fancybox-thumbs__list{overflow:hidden}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar{width:7px}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-track{background:#fff;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,.3)}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-thumb{background:#2a2a2a;border-radius:10px}.fancybox-thumbs__list a{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:rgba(0,0,0,.1);background-position:50%;background-repeat:no-repeat;background-size:cover;cursor:pointer;float:left;height:75px;margin:2px;max-height:calc(100% - 8px);max-width:calc(50% - 4px);outline:none;overflow:hidden;padding:0;position:relative;-webkit-tap-highlight-color:transparent;width:100px}.fancybox-thumbs__list a:before{border:4px solid #4ea7f9;bottom:0;content:"";left:0;opacity:0;position:absolute;right:0;top:0;transition:all .2s cubic-bezier(.25,.46,.45,.94);z-index:99991}.fancybox-thumbs__list a:focus:before{opacity:.5}.fancybox-thumbs__list a.fancybox-thumbs-active:before{opacity:1}@media (max-width:768px){.fancybox-thumbs{width:110px}.fancybox-show-thumbs .fancybox-inner{right:110px}.fancybox-thumbs__list a{max-width:calc(100% - 10px)}} \ No newline at end of file +body.compensate-for-scrollbar{overflow:hidden}.fancybox-active{height:auto}.fancybox-is-hidden{left:-9999px;margin:0;position:absolute!important;top:-9999px;visibility:hidden}.fancybox-container{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;left:0;outline:none;position:fixed;-webkit-tap-highlight-color:transparent;top:0;-ms-touch-action:manipulation;touch-action:manipulation;-webkit-transform:translateZ(0);transform:translateZ(0);width:100%;z-index:99992}.fancybox-container *{box-sizing:border-box}.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-stage{bottom:0;left:0;position:absolute;right:0;top:0}.fancybox-outer{-webkit-overflow-scrolling:touch;overflow-y:auto}.fancybox-bg{background:#1e1e1e;opacity:0;transition-duration:inherit;transition-property:opacity;transition-timing-function:cubic-bezier(.47,0,.74,.71)}.fancybox-is-open .fancybox-bg{opacity:.87;transition-timing-function:cubic-bezier(.22,.61,.36,1)}.fancybox-caption,.fancybox-infobar,.fancybox-navigation .fancybox-button,.fancybox-toolbar{direction:ltr;opacity:0;position:absolute;transition:opacity .25s ease,visibility 0s ease .25s;visibility:hidden;z-index:99997}.fancybox-show-caption .fancybox-caption,.fancybox-show-infobar .fancybox-infobar,.fancybox-show-nav .fancybox-navigation .fancybox-button,.fancybox-show-toolbar .fancybox-toolbar{opacity:1;transition:opacity .25s ease 0s,visibility 0s ease 0s;visibility:visible}.fancybox-infobar{color:#ccc;font-size:13px;-webkit-font-smoothing:subpixel-antialiased;height:44px;left:0;line-height:44px;min-width:44px;mix-blend-mode:difference;padding:0 10px;pointer-events:none;top:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fancybox-toolbar{right:0;top:0}.fancybox-stage{direction:ltr;overflow:visible;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:99994}.fancybox-is-open .fancybox-stage{overflow:hidden}.fancybox-slide{-webkit-backface-visibility:hidden;display:none;height:100%;left:0;outline:none;overflow:auto;-webkit-overflow-scrolling:touch;padding:44px 44px 0;position:absolute;text-align:center;top:0;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform;white-space:normal;width:100%;z-index:99994}.fancybox-slide:before{content:"";display:inline-block;font-size:0;height:100%;vertical-align:middle;width:0}.fancybox-is-sliding .fancybox-slide,.fancybox-slide--current,.fancybox-slide--next,.fancybox-slide--previous{display:block}.fancybox-slide--next{z-index:99995}.fancybox-slide--image{overflow:hidden;padding:44px 0 0}.fancybox-slide--image:before{display:none}.fancybox-slide--html{padding:6px 6px 0}.fancybox-content{background:#fff;display:inline-block;margin:0 0 44px;max-width:100%;overflow:auto;-webkit-overflow-scrolling:touch;padding:44px;position:relative;text-align:left;vertical-align:middle}.fancybox-slide--image .fancybox-content{-webkit-animation-timing-function:cubic-bezier(.5,0,.14,1);animation-timing-function:cubic-bezier(.5,0,.14,1);-webkit-backface-visibility:hidden;background:transparent;background-repeat:no-repeat;background-size:100% 100%;left:0;max-width:none;overflow:visible;padding:0;position:absolute;top:0;-webkit-transform-origin:top left;transform-origin:top left;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:99995}.fancybox-slide--html .fancybox-content{margin:0 0 6px}.fancybox-can-zoomOut .fancybox-content{cursor:zoom-out}.fancybox-can-zoomIn .fancybox-content{cursor:zoom-in}.fancybox-can-pan .fancybox-content,.fancybox-can-swipe .fancybox-content{cursor:-webkit-grab;cursor:grab}.fancybox-is-grabbing .fancybox-content{cursor:-webkit-grabbing;cursor:grabbing}.fancybox-container [data-selectable=true]{cursor:text}.fancybox-image,.fancybox-spaceball{background:transparent;border:0;height:100%;left:0;margin:0;max-height:none;max-width:none;padding:0;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:100%}.fancybox-spaceball{z-index:1}.fancybox-slide--iframe .fancybox-content,.fancybox-slide--map .fancybox-content,.fancybox-slide--video .fancybox-content{height:calc(100% - 44px);overflow:visible;padding:0;width:100%}.fancybox-slide--video .fancybox-content{background:#000}.fancybox-slide--map .fancybox-content{background:#e5e3df}.fancybox-slide--iframe .fancybox-content{background:#fff}.fancybox-iframe,.fancybox-video{background:transparent;border:0;display:block;height:100%;margin:0;overflow:hidden;padding:0;vertical-align:top;width:100%}.fancybox-error{background:#fff;cursor:default;max-width:400px;padding:40px;width:100%}.fancybox-error p{color:#444;font-size:16px;line-height:20px;margin:0;padding:0}.fancybox-button{background:rgba(30,30,30,.6);border:0;border-radius:0;box-shadow:none;cursor:pointer;display:inline-block;height:44px;margin:0;padding:10px;position:relative;transition:color .2s;vertical-align:top;visibility:inherit;width:44px}.fancybox-button,.fancybox-button:link,.fancybox-button:visited{color:#ccc}.fancybox-button:hover{color:#fff}.fancybox-button:focus{outline:none}.fancybox-button.fancybox-focus{outline:1px dotted}.fancybox-button.disabled,.fancybox-button.disabled:hover,.fancybox-button[disabled],.fancybox-button[disabled]:hover{color:#888;cursor:default;outline:none}.fancybox-button svg{display:block;height:100%;overflow:visible;position:relative;width:100%}.fancybox-button svg path{fill:currentColor;stroke-width:0}.fancybox-button--fsenter svg:nth-child(2),.fancybox-button--fsexit svg:nth-child(1),.fancybox-button--pause svg:nth-child(1),.fancybox-button--play svg:nth-child(2){display:none}.fancybox-progress{background:#ff5268;height:2px;left:0;position:absolute;right:0;top:0;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:0;transform-origin:0;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;transition-timing-function:linear;z-index:99998}.fancybox-close-small{background:transparent;border:0;border-radius:0;color:#ccc;cursor:pointer;opacity:.8;padding:8px;position:absolute;right:-12px;top:-44px;z-index:401}.fancybox-close-small:hover{color:#fff;opacity:1}.fancybox-slide--html .fancybox-close-small{color:currentColor;padding:10px;right:0;top:0}.fancybox-is-scaling .fancybox-close-small,.fancybox-is-zoomable.fancybox-can-pan .fancybox-close-small{display:none}.fancybox-navigation .fancybox-button{background:transparent;height:100px;margin:0;opacity:0;position:absolute;top:calc(50% - 50px);width:70px}.fancybox-navigation .fancybox-button div{background:rgba(30,30,30,.6);height:100%;padding:7px}.fancybox-navigation .fancybox-button--arrow_left{left:0;padding:31px 26px 31px 6px}.fancybox-navigation .fancybox-button--arrow_right{padding:31px 6px 31px 26px;right:0}.fancybox-caption{bottom:0;color:#fff;font-size:14px;font-weight:400;left:0;line-height:1.5;padding:25px 44px;right:0}.fancybox-caption:before{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAEtCAQAAABjBcL7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHRJREFUKM+Vk8EOgDAIQ0vj/3+xBw8qIZZueFnIKC90MCAI8DlrkHGeqqGIU6lVigrBtpCWqeRWoHDNqs0F7VNVBVxmHRlvoVqjaYkdnDIaivH2HqZ5+oZj3JUzWB+cOz4G48Bg+tsJ/tqu4dLC/4Xb+0GcF5BwBC0AA53qAAAAAElFTkSuQmCC);background-repeat:repeat-x;background-size:contain;bottom:0;content:"";display:block;left:0;pointer-events:none;position:absolute;right:0;top:-25px;z-index:-1}.fancybox-caption:after{border-bottom:1px solid hsla(0,0%,100%,.3);content:"";display:block;left:44px;position:absolute;right:44px;top:0}.fancybox-caption a,.fancybox-caption a:link,.fancybox-caption a:visited{color:#ccc;text-decoration:none}.fancybox-caption a:hover{color:#fff;text-decoration:underline}.fancybox-loading{-webkit-animation:a 1s linear infinite;animation:a 1s linear infinite;background:transparent;border:4px solid #888;border-bottom-color:#fff;border-radius:50%;height:50px;left:50%;margin:-25px 0 0 -25px;opacity:.7;padding:0;position:absolute;top:50%;width:50px;z-index:99999}@-webkit-keyframes a{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes a{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fancybox-animated{transition-timing-function:cubic-bezier(0,0,.25,1)}.fancybox-fx-slide.fancybox-slide--previous{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.fancybox-fx-slide.fancybox-slide--next{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.fancybox-fx-slide.fancybox-slide--current{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}.fancybox-fx-fade.fancybox-slide--next,.fancybox-fx-fade.fancybox-slide--previous{opacity:0;transition-timing-function:cubic-bezier(.19,1,.22,1)}.fancybox-fx-fade.fancybox-slide--current{opacity:1}.fancybox-fx-zoom-in-out.fancybox-slide--previous{opacity:0;-webkit-transform:scale3d(1.5,1.5,1.5);transform:scale3d(1.5,1.5,1.5)}.fancybox-fx-zoom-in-out.fancybox-slide--next{opacity:0;-webkit-transform:scale3d(.5,.5,.5);transform:scale3d(.5,.5,.5)}.fancybox-fx-zoom-in-out.fancybox-slide--current{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}.fancybox-fx-rotate.fancybox-slide--previous{opacity:0;-webkit-transform:rotate(-1turn);transform:rotate(-1turn)}.fancybox-fx-rotate.fancybox-slide--next{opacity:0;-webkit-transform:rotate(1turn);transform:rotate(1turn)}.fancybox-fx-rotate.fancybox-slide--current{opacity:1;-webkit-transform:rotate(0deg);transform:rotate(0deg)}.fancybox-fx-circular.fancybox-slide--previous{opacity:0;-webkit-transform:scale3d(0,0,0) translate3d(-100%,0,0);transform:scale3d(0,0,0) translate3d(-100%,0,0)}.fancybox-fx-circular.fancybox-slide--next{opacity:0;-webkit-transform:scale3d(0,0,0) translate3d(100%,0,0);transform:scale3d(0,0,0) translate3d(100%,0,0)}.fancybox-fx-circular.fancybox-slide--current{opacity:1;-webkit-transform:scaleX(1) translateZ(0);transform:scaleX(1) translateZ(0)}.fancybox-fx-tube.fancybox-slide--previous{-webkit-transform:translate3d(-100%,0,0) scale(.1) skew(-10deg);transform:translate3d(-100%,0,0) scale(.1) skew(-10deg)}.fancybox-fx-tube.fancybox-slide--next{-webkit-transform:translate3d(100%,0,0) scale(.1) skew(10deg);transform:translate3d(100%,0,0) scale(.1) skew(10deg)}.fancybox-fx-tube.fancybox-slide--current{-webkit-transform:translateZ(0) scale(1);transform:translateZ(0) scale(1)}@media (max-height:576px){.fancybox-slide{padding-left:6px;padding-right:6px}.fancybox-slide--image{padding:6px 0 0}.fancybox-slide--image .fancybox-content{margin-bottom:6px}.fancybox-slide--image .fancybox-close-small{background:#4e4e4e;color:#f2f4f6;height:36px;opacity:1;padding:6px;right:0;top:0;width:36px}}.fancybox-share{background:#f4f4f4;border-radius:3px;max-width:90%;padding:30px;text-align:center}.fancybox-share h1{color:#222;font-size:35px;font-weight:700;margin:0 0 20px}.fancybox-share p{margin:0;padding:0}.fancybox-share__button{border:0;border-radius:3px;display:inline-block;font-size:14px;font-weight:700;line-height:40px;margin:0 5px 10px;min-width:130px;padding:0 15px;text-decoration:none;transition:all .2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap}.fancybox-share__button:link,.fancybox-share__button:visited{color:#fff}.fancybox-share__button:hover{text-decoration:none}.fancybox-share__button--fb{background:#3b5998}.fancybox-share__button--fb:hover{background:#344e86}.fancybox-share__button--pt{background:#bd081d}.fancybox-share__button--pt:hover{background:#aa0719}.fancybox-share__button--tw{background:#1da1f2}.fancybox-share__button--tw:hover{background:#0d95e8}.fancybox-share__button svg{height:25px;margin-right:7px;position:relative;top:-1px;vertical-align:middle;width:25px}.fancybox-share__button svg path{fill:#fff}.fancybox-share__input{background:transparent;border:0;border-bottom:1px solid #d7d7d7;border-radius:0;color:#5d5b5b;font-size:14px;margin:10px 0 0;outline:none;padding:10px 15px;width:100%}.fancybox-thumbs{background:#ddd;bottom:0;display:none;margin:0;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;padding:2px 2px 4px;position:absolute;right:0;-webkit-tap-highlight-color:transparent;top:0;width:212px;z-index:99995}.fancybox-thumbs-x{overflow-x:auto;overflow-y:hidden}.fancybox-show-thumbs .fancybox-thumbs{display:block}.fancybox-show-thumbs .fancybox-inner{right:212px}.fancybox-thumbs__list{font-size:0;height:100%;list-style:none;margin:0;overflow-x:hidden;overflow-y:auto;padding:0;position:absolute;position:relative;white-space:nowrap;width:100%}.fancybox-thumbs-x .fancybox-thumbs__list{overflow:hidden}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar{width:7px}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-track{background:#fff;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,.3)}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-thumb{background:#2a2a2a;border-radius:10px}.fancybox-thumbs__list a{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:rgba(0,0,0,.1);background-position:50%;background-repeat:no-repeat;background-size:cover;cursor:pointer;float:left;height:75px;margin:2px;max-height:calc(100% - 8px);max-width:calc(50% - 4px);outline:none;overflow:hidden;padding:0;position:relative;-webkit-tap-highlight-color:transparent;width:100px}.fancybox-thumbs__list a:before{border:6px solid #ff5268;bottom:0;content:"";left:0;opacity:0;position:absolute;right:0;top:0;transition:all .2s cubic-bezier(.25,.46,.45,.94);z-index:99991}.fancybox-thumbs__list a:focus:before{opacity:.5}.fancybox-thumbs__list a.fancybox-thumbs-active:before{opacity:1}@media (max-width:768px){.fancybox-thumbs{width:110px}.fancybox-show-thumbs .fancybox-inner{right:110px}.fancybox-thumbs__list a{max-width:calc(100% - 10px)}} \ No newline at end of file diff --git a/dist/jquery.fancybox.min.js b/dist/jquery.fancybox.min.js index ad9ca947..c02c00a5 100644 --- a/dist/jquery.fancybox.min.js +++ b/dist/jquery.fancybox.min.js @@ -1,5 +1,5 @@ // ================================================== -// fancyBox v3.4.1 +// fancyBox v3.4.2 // // Licensed GPLv3 for open source use // or fancyBox Commercial License for commercial use @@ -8,6 +8,6 @@ // Copyright 2018 fancyApps // // ================================================== -!function(t,e,n,o){"use strict";function i(t,e){var o,i,a,s=[],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"),a=n.fancybox.getInstance(),a&&a.$trigger&&a.$trigger.is(o)||(e.selector?s=n(e.selector):(i=o.attr("data-fancybox")||"",i?(s=t.data?t.data.items:[],s=s.length?s.filter('[data-fancybox="'+i+'"]'):n('[data-fancybox="'+i+'"]')):s=[o]),r=n(s).index(o),r<0&&(r=0),a=n.fancybox.open(s,e,r),a.$trigger=o))}if(t.console=t.console||{info:function(t){}},n){if(n.fn.fancybox)return void console.info("fancyBox already initialized");var a={closeExisting:!1,loop:!1,gutter:50,keyboard:!0,arrows:!0,infobar:!0,smallBtn:"auto",toolbar:"auto",buttons:["zoom","thumbs","close"],idleTime:3,protect:!1,modal:!1,image:{preload:!1},ajax:{settings:{data:{fancybox:!0}}},iframe:{tpl:'',preload:!0,css:{},attr:{scrolling:"auto"}},video:{tpl:'',format:"",autoStart:!0},defaultType:"image",animationEffect:"zoom",animationDuration:366,zoomOpacity:"auto",transitionEffect:"fade",transitionDuration:366,slideClass:"",baseClass:"",baseTpl:'{{ERROR}}
{{ERROR}}
- fancybox includes support for touch gestures and even supports pinch gestures for zooming. It is perfectly suited for both - mobile and desktop browsers. + fancybox includes support for touch gestures and even supports pinch gestures for zooming. + It is perfectly suited for both mobile and desktop browsers.
@@ -292,8 +292,8 @@
You can install fancybox by linking
.css
and
- .js
files to your html file. Make sure you also load the jQuery library. Below is a basic HTML template
- to use as an example:
+ .js
files to your html file. Make sure you also load the jQuery library. Below is a basic HTML
+ template to use as an example:
<!DOCTYPE html> @@ -346,7 +346,8 @@
The most basic way to use fancybox is by adding the
- data-fancybox
attribute to your element. This will automatically bind click event that will start
+ data-fancybox
attribute to your element. This will automatically bind click event that will
+ start
fancybox. Use
href
or
data-src
attribute to specify source of your content. Example:
@@ -376,7 +378,8 @@
If you have a group of items, you can use the same attribute
- data-fancybox
value for each of them to create a gallery. Each group should have a unique value.
+ data-fancybox
value for each of them to create a gallery. Each group should have a unique
+ value.
Example:
- Sometimes you have multiple links pointing to the same source and that creates duplicates in the gallery. To avoid that,
- simply use
+ Sometimes you have multiple links pointing to the same source and that creates duplicates in the gallery.
+ To avoid that, simply use
data-fancybox-trigger
attribute with the same value used for
data-fancybox
attribute for your other links. Optionally, use
data-fancybox-index
attribute to specify index of starting element:
@@ -414,7 +417,7 @@
Select your elements with a jQuery selector (you can use any valid selector) and call the @@ -432,8 +435,8 @@
Sometimes you might need to bind fancybox to dynamically added elements. Use
- selector
option to attach click event listener for elements that exist now or in the future. All
- selected items will be automatically grouped in the gallery. Example:
+ selector
option to attach click event listener for elements that exist now or in the future.
+ All selected items will be automatically grouped in the gallery. Example:
$().fancybox({
@@ -481,8 +484,8 @@
- fancybox attempts to automatically detect the type of content based on the given url. If it cannot be detected, the type
- can also be set manually using
+ fancybox attempts to automatically detect the type of content based on the given url. If it cannot be
+ detected, the type can also be set manually using
data-type
attribute (or
type
option). Example:
@@ -497,8 +500,8 @@
Media types
- fancybox is designed to display images, video, iframes and any HTML content. For your convenience, there is a built in support
- for inline content and ajax.
+ fancybox is designed to display images, video, iframes and any HTML content. For your convenience, there is
+ a built in support for inline content and ajax.
Images
@@ -516,8 +519,9 @@ Images
- By default, fancybox fully preloads an image before displaying it. You can choose to display the image right away. It will
- render and show the full size image while the data is being received. To do so, some attributes are necessary:
+ By default, fancybox fully preloads an image before displaying it. You can choose to display the image
+ right away. It will render and show the full size image while the data is being received. To do so, some
+ attributes are necessary:
@@ -537,8 +541,8 @@ Images
You can also use these
width
and
- height
properties to control size of the image. This can be used to make images look sharper on
- retina displays. Example:
+ height
properties to control size of the image. This can be used to make images look sharper
+ on retina displays. Example:
$('[data-fancybox="images"]').fancybox({
@@ -557,8 +561,8 @@ Images
- fancybox supports "srcset" so it can display different images based on viewport width. You can use this to improve download
- times for mobile users and over time save bandwidth. Example:
+ fancybox supports "srcset" so it can display different images based on viewport width. You can use this to
+ improve download times for mobile users and over time save bandwidth. Example:
<a href="medium.jpg" data-fancybox="images" data-srcset="large.jpg 1600w, medium.jpg 1200w, small.jpg 640w">
@@ -569,9 +573,9 @@ Images
- It is also possible to protect images from downloading by right-click. While this does not protect from truly determined
- users, it should discourage the vast majority from ripping off your files. Optionally, put the watermark over
- image.
+ It is also possible to protect images from downloading by right-click. While this does not protect from
+ truly determined users, it should discourage the vast majority from ripping off your files.
+ Optionally, put the watermark over image.
$('[data-fancybox]').fancybox({
@@ -585,9 +589,8 @@ Images
Video
- YouTube and Vimeo videos can be used with fancybox by just providing the page URL. Link to MP4 video directly or use trigger
- element to display hidden
- <video>
element.
+ YouTube and Vimeo videos can be used with fancybox by just providing the page URL. Link to MP4 video
+ directly or use trigger element to display hidden <video>
element.
@@ -660,9 +663,9 @@
Video
Iframe
- If you need to display content from another page, add data-fancybox
and data-type="iframe"
attributes
- to your link. This would create <iframe>
element that allows to embed an entire web
- document inside the modal.
+ If you need to display content from another page, add data-fancybox
and data-type="iframe"
+ attributes to your link. This would create <iframe>
element that allows to
+ embed an entire web document inside the modal.
<a data-fancybox data-type="iframe" data-src="http://codepen.io/fancyapps/full/jyEGGG/" href="javascript:;">
@@ -679,14 +682,15 @@ Iframe
If you have not disabled iframe preloading (using
- preload
option), the script will atempt to calculate content dimensions and will adjust width/height
- of <iframe>
to fit with content in it. Keep in mind, that due to
- same origin policy, there are
- some limitations.
+ preload
option), the script will atempt to calculate content dimensions and will adjust
+ width/height of <iframe>
to fit with content in it. Keep in mind, that due to
+ same origin policy, there
+ are some limitations.
- This example will disable iframe preloading and will display small close button next to iframe instead of the toolbar:
+ This example will disable iframe preloading and will display small close button next to iframe instead of
+ the toolbar:
$('[data-fancybox]').fancybox({
@@ -740,7 +744,8 @@ Iframe
Inline
- fancybox can be used to display any HTML element on the page. First, create a hidden element with unique ID:
+ fancybox can be used to display any HTML element on the page.
+ First, create a hidden element with unique ID:
<div style="display: none;" id="hidden-content">
@@ -750,9 +755,8 @@ Inline
Then simply create a link having
- data-src
attribute that matches ID of the element you want to open (preceded by a hash mark (#);
- in this example -
- #hidden-content
):
+ data-src
attribute that matches ID of the element you want to open (preceded by a hash mark
+ (#); in this example - #hidden-content
):
<a data-fancybox data-src="#hidden-content" href="javascript:;">
@@ -764,13 +768,13 @@ Inline
The script will append small close button (if you have not disabled by
- smallBtn:false
) and will not apply any styles except for centering. Therefore you can easily set
- custom dimensions using CSS.
+ smallBtn:false
) and will not apply any styles except for centering. Therefore you can easily
+ set custom dimensions using CSS.
- Info If necessary, you can make your element (and similarly any other html
- content) scrollable by adding additional wrapping element and some CSS -
+ Info If necessary, you can make your element (and similarly any other
+ html content) scrollable by adding additional wrapping element and some CSS -
view demo on CodePen.
@@ -792,8 +796,8 @@ Ajax
Additionally it is possible to define a selector with the
- data-filter
attribute to show only a part of the response. The selector can be any string, that
- is a valid jQuery selector:
+ data-filter
attribute to show only a part of the response. The selector can be any string,
+ that is a valid jQuery selector:
<a data-fancybox data-type="ajax" data-src="my_page.com/path/to/ajax/" data-filter="#two" href="javascript:;">
@@ -850,7 +854,7 @@ Options
buttons: [
"zoom",
//"share",
- //"slideShow",
+ "slideShow",
//"fullScreen",
//"download",
"thumbs",
@@ -888,7 +892,7 @@ Options
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>',
+ '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen allow="fullscreen autoplay" src=""></iframe>',
// Preload iframe before displaying it
// This allows to calculate iframe content width and height
@@ -901,7 +905,7 @@ Options
// Iframe tag attributes
attr: {
- scrolling: "auto"
+ scrolling: "auto"
}
},
@@ -962,9 +966,7 @@ Options
'<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-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>' +
@@ -980,39 +982,37 @@ Options
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>",
+ '<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>",
+ '<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>",
+ '<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:
- '<a data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}" href="javascript:;">' +
- '<svg viewBox="0 0 40 40">' +
- '<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>' +
- "</svg>" +
- "</a>",
+ '<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:
- '<a data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}" href="javascript:;">' +
- '<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>' +
- "</a>",
+ '<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>"
+ '<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
@@ -1054,12 +1054,12 @@ Options
// Example:
/*
media : {
- youtube : {
- params : {
- autoplay : 0
- }
+ youtube : {
+ params : {
+ autoplay : 0
}
}
+ }
*/
media: {},
@@ -1086,8 +1086,8 @@ Options
// Example:
/*
afterShow: function( instance, current ) {
- console.info( 'Clicked element:' );
- console.info( current.opts.$orig );
+ console.info( 'Clicked element:' );
+ console.info( current.opts.$orig );
}
*/
@@ -1192,8 +1192,7 @@ Options
- Set instance options by passing a valid object to
- fancybox()
method:
+ Set instance options by passing a valid object to fancybox()
method:
$("[data-fancybox]").fancybox({
@@ -1213,14 +1212,13 @@ Options
Custom options for each element individually can be set by adding a
- data-options
attribute to the element. This attribute should contain the properly formatted JSON
- object.
+ data-options
attribute to the element.
+ This attribute should contain the properly formatted JSON object.
It is also possible to quickly set any option using
parameterized name of the selected option, for example,
- animationEffect
would be
- data-animation-effect
:
+ animationEffect
would be data-animation-effect
:
<a data-fancybox data-options='{"caption" : "My caption", "src" : "https://codepen.io/about/", "type" : "iframe"}' href="javascript:;" class="btn btn-primary">
@@ -1241,8 +1239,8 @@ Options
API
- The fancybox API offers a couple of methods to control fancybox. This gives you the ability to extend the plugin and to integrate
- it with other web application components.
+ The fancybox API offers a couple of methods to control fancybox. This gives you the ability to extend the
+ plugin and to integrate it with other web application components.
Core methods
@@ -1268,7 +1266,6 @@ Core methods
Starting fancybox
-
When creating group objects manually, each item should follow this pattern:
@@ -1280,7 +1277,6 @@ Starting fancybox
}
-
Example of opening image gallery programmatically:
@@ -1326,8 +1322,8 @@ Starting fancybox
- If you wish to quickly display some html content (for example, a message), then you can use a simpler syntax. Do not forget
- to use a wrapping element around your content.
+ If you wish to quickly display some html content (for example, a message), then you can use a simpler
+ syntax. Do not forget to use a wrapping element around your content.
$.fancybox.open('<div class="message"><h2>Hello!</h2><p>You are awesome!</p></div>');
@@ -1336,7 +1332,8 @@ Starting fancybox
- Group items can be collection of jQuery objects, too. This can be used, for example, to display group of inline elements:
+ Group items can be collection of jQuery objects, too.
+ This can be used, for example, to display group of inline elements:
$('#test').on('click', function() {
@@ -1352,7 +1349,8 @@ Starting fancybox
Instance methods
- In order to use these methods, you need an instance of the plugin's object. There are 3 common ways to get the reference.
+ In order to use these methods, you need an instance of the plugin's object.
+ There are 3 common ways to get the reference.
@@ -1368,7 +1366,6 @@
Instance methods
// Your content and options
);
-
3) From within the callback - first argument is always a reference to current instance:
@@ -1382,7 +1379,6 @@ Instance methods
Once you have a reference to fancybox instance the following methods are available:
-
// Go to next gallery item
instance.next( duration );
@@ -1432,7 +1428,6 @@ Instance methods
instance.close();
-
You can also do something like this:
@@ -1465,7 +1460,8 @@ Events
onDeactivate : When other instance has been activated
- Event callbacks can be set as function properties of the options object passed to fancybox initialization function:
+ Event callbacks can be set as function properties of the options object passed to fancybox initialization
+ function:
<script type="text/javascript">
@@ -1496,10 +1492,9 @@ Events
- It is also possible to attach event handler for all instances. To prevent interfering with other scripts, these events have
- been namespaced to
- .fb
. These handlers receive 3 parameters - event, current fancybox instance and current gallery
- object.
+ It is also possible to attach event handler for all instances. To prevent interfering with other scripts,
+ these events have been namespaced to .fb
.
+ These handlers receive 3 parameters - event, current fancybox instance and current gallery object.
Here is an example of binding to the
@@ -1529,10 +1524,9 @@
Events
Modules
- fancybox code is split into several files (modules) that extend core functionality. You can build your own fancybox version
- by excluding unnecessary modules, if needed. Each one has their own
- js
and/or
- css
files.
+ fancybox code is split into several files (modules) that extend core functionality. You can build your own
+ fancybox version by excluding unnecessary modules, if needed.
+ Each one has their own js
and/or css
files.
@@ -1641,9 +1635,9 @@
Modules
- If you would inspect fancybox instance object, you would find that same keys ar captialized - these are references for each
- module object. Also, you would notice that fancybox uses common naming convention to prefix jQuery objects with
- $
.
+ If you would inspect fancybox instance object, you would find that same keys ar captialized - these are
+ references for each module object.
+ Also, you would notice that fancybox uses common naming convention to prefix jQuery objects with $
.
@@ -1695,9 +1689,8 @@
#1 Opening/closing causes fixed element to jump
- Simply add
- compensate-for-scrollbar
CSS class to your fixed positioned elements. Example of using Bootstrap
- navbar component:
+ Simply add compensate-for-scrollbar
CSS class to your fixed positioned elements.
+ Example of using Bootstrap navbar component:
<nav class="navbar navbar-inverse navbar-fixed-top compensate-for-scrollbar">
@@ -1731,8 +1724,8 @@
You can use
- caption
option that accepts a function and is called for each group element. Example of appending
- image download link:
+ caption
option that accepts a function and is called for each group element.
+ Example of appending image download link:
$( '[data-fancybox="images"]' ).fancybox({
@@ -1750,7 +1743,6 @@
View demo on CodePen
-
Add current image index and image count (the total number of images in the gallery) right in the caption:
@@ -1817,9 +1809,9 @@
- There is currenty no JS option to change thumbnail grid position. But fancybox is designed so that you can use CSS to change
- position or dimension for each block (e.g., content area, caption or thumbnail grid). This gives you freedom
- to completely change the look and feel of the modal window, if needed.
+ There is currenty no JS option to change thumbnail grid position. But fancybox is designed so that you can
+ use CSS to change position or dimension for each block (e.g., content area, caption or thumbnail grid).
+ This gives you freedom to completely change the look and feel of the modal window, if needed.
View demo on CodePen
@@ -1852,10 +1844,12 @@
- If you are combining fancybox with slider/carousel script and that script clones items to enable infinite navigation, then
- duplicated items will appear in the gallery. To avoid that - 1) initialise fancybox on all items except cloned;
- 2) add custom click event on cloned items and trigger click event on corresponding "real" item. Here is an example
- using Slick slider:
+ If you are combining fancybox with slider/carousel script and that script clones items to enable infinite
+ navigation, then duplicated items will appear in the gallery.
+ To avoid that -
+ 1) initialise fancybox on all items except cloned;
+ 2) add custom click event on cloned items and trigger click event on corresponding "real" item. Here is an
+ example using Slick slider:
// Init fancybox
// =============
diff --git a/package.json b/package.json
index 17f6c1ce..10278d20 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@fancyapps/fancybox",
"description": "Touch enabled, responsive and fully customizable jQuery lightbox script",
- "version": "3.4.1",
+ "version": "3.4.2",
"homepage": "https://fancyapps.com/fancybox/3/",
"main": "dist/jquery.fancybox.js",
"style": "dist/jquery.fancybox.css",
diff --git a/src/css/core.css b/src/css/core.css
index f3dd1cfc..b6a4057c 100644
--- a/src/css/core.css
+++ b/src/css/core.css
@@ -1,6 +1,5 @@
body.compensate-for-scrollbar {
overflow: hidden;
- -ms-overflow-style: none;
}
.fancybox-active {
@@ -107,7 +106,7 @@ body.compensate-for-scrollbar {
.fancybox-stage {
direction: ltr;
overflow: visible;
- transform: translate3d(0, 0, 0);
+ transform: translateZ(0);
z-index: 99994;
}
@@ -116,7 +115,7 @@ body.compensate-for-scrollbar {
}
.fancybox-slide {
- backface-visibility: hidden;
+ -webkit-backface-visibility: hidden; /* Using without prefix would break IE11 */
display: none;
height: 100%;
left: 0;
@@ -154,13 +153,10 @@ body.compensate-for-scrollbar {
}
.fancybox-slide--image {
+ overflow: hidden;
padding: 44px 0 0 0;
}
-.fancybox-slide--image {
- overflow: visible;
-}
-
.fancybox-slide--image::before {
display: none;
}
@@ -184,7 +180,7 @@ body.compensate-for-scrollbar {
.fancybox-slide--image .fancybox-content {
animation-timing-function: cubic-bezier(.5, 0, .14, 1);
- backface-visibility: hidden;
+ -webkit-backface-visibility: hidden;
background: transparent;
background-repeat: no-repeat;
background-size: 100% 100%;
@@ -301,11 +297,13 @@ body.compensate-for-scrollbar {
background: rgba(30, 30, 30, .6);
border: 0;
border-radius: 0;
+ box-shadow: none;
cursor: pointer;
display: inline-block;
height: 44px;
margin: 0;
padding: 10px;
+ position: relative;
transition: color .2s;
vertical-align: top;
visibility: inherit;
@@ -362,6 +360,19 @@ body.compensate-for-scrollbar {
display: none;
}
+.fancybox-progress {
+ background: #ff5268;
+ height: 2px;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+ transform: scaleX(0);
+ transform-origin: 0;
+ transition-property: transform;
+ transition-timing-function: linear;
+ z-index: 99998;
+}
/* Close button on the top right corner of html content */
.fancybox-close-small {
@@ -476,28 +487,25 @@ body.compensate-for-scrollbar {
/* Loading indicator */
.fancybox-loading {
- animation: fancybox-rotate .8s infinite linear;
+ animation: fancybox-rotate 1s linear infinite;
background: transparent;
- border: 6px solid rgba(100, 100, 100, .5);
- border-radius: 100%;
- border-top-color: #fff;
- height: 60px;
+ border: 4px solid #888;
+ border-bottom-color: #fff;
+ border-radius: 50%;
+ height: 50px;
left: 50%;
- margin: -30px 0 0 -30px;
- opacity: .6;
+ margin: -25px 0 0 -25px;
+ opacity: .7;
padding: 0;
position: absolute;
top: 50%;
- width: 60px;
+ width: 50px;
z-index: 99999;
}
@keyframes fancybox-rotate {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(359deg);
+ 100% {
+ transform: rotate(360deg);
}
}
diff --git a/src/css/thumbs.css b/src/css/thumbs.css
index 14a1b510..f07ea650 100644
--- a/src/css/thumbs.css
+++ b/src/css/thumbs.css
@@ -1,7 +1,7 @@
/* Thumbs */
.fancybox-thumbs {
- background: #fff;
+ background: #ddd;
bottom: 0;
display: none;
margin: 0;
@@ -83,7 +83,7 @@
}
.fancybox-thumbs__list a::before {
- border: 4px solid #4ea7f9;
+ border: 6px solid #ff5268;
bottom: 0;
content: '';
left: 0;
diff --git a/src/js/core.js b/src/js/core.js
index ad90aa46..da469452 100644
--- a/src/js/core.js
+++ b/src/js/core.js
@@ -60,7 +60,7 @@
buttons: [
"zoom",
//"share",
- //"slideShow",
+ "slideShow",
//"fullScreen",
//"download",
"thumbs",
@@ -98,7 +98,7 @@
iframe: {
// Iframe template
tpl:
- '',
+ '',
// Preload iframe before displaying it
// This allows to calculate iframe content width and height
@@ -467,6 +467,51 @@
return rez;
};
+ // How much of an element is visible in viewport
+ // =============================================
+
+ var inViewport = function($el) {
+ var element = $el[0],
+ elementRect = element.getBoundingClientRect(),
+ parentRects = [],
+ visibleInAllParents,
+ windowHeight = $(window).height(),
+ pageScroll = $(document).scrollTop(),
+ elementTop = elementRect.top + pageScroll,
+ hiddenBefore = pageScroll - elementTop,
+ hiddenAfter = elementTop + elementRect.height - (pageScroll + windowHeight);
+
+ // Check if the parent can hide its children
+ 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;
+ });
+
+ if (!visibleInAllParents || pageScroll > elementTop + elementRect.height || elementTop > pageScroll + windowHeight) {
+ return 0;
+ }
+
+ if (hiddenBefore > 0) {
+ return 100 - (hiddenBefore * 100) / elementRect.height;
+ }
+
+ if (hiddenAfter > 0) {
+ return 100 - (hiddenAfter * 100) / elementRect.height;
+ }
+
+ return 100;
+ };
+
// Class definition
// ================
@@ -517,8 +562,6 @@
var self = this,
firstItem = self.group[self.currIndex],
firstItemOpts = firstItem.opts,
- scrollbarWidth = $.fancybox.scrollbarWidth,
- $scrollDiv,
$container,
buttonStr;
@@ -537,18 +580,10 @@
!$.fancybox.isMobile &&
document.body.scrollHeight > window.innerHeight
) {
- if (scrollbarWidth === undefined) {
- $scrollDiv = $('').appendTo("body");
-
- scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth;
-
- $scrollDiv.remove();
- }
-
$("head").append(
- '"
+ '"
);
$("body").addClass("compensate-for-scrollbar");
@@ -769,6 +804,7 @@
// 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,
@@ -1002,34 +1038,31 @@
loop,
current,
previous,
- canvasWidth,
- transitionProps;
+ slidePos,
+ stagePos,
+ diff;
if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {
return;
}
- pos = parseInt(pos, 10);
-
// 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;
- if (groupLen < 2 && !firstRun && !!self.isDragging) {
- return;
- }
-
+ // Create slides
previous = self.current;
self.prevIndex = self.currIndex;
self.prevPos = self.currPos;
- // Create slides
current = self.createSlide(pos);
if (groupLen > 1) {
@@ -1050,8 +1083,6 @@
self.updateControls();
- isMoved = self.isMoved(current);
-
// Validate duration length
current.forcedDuration = undefined;
@@ -1063,72 +1094,102 @@
duration = parseInt(duration, 10);
+ // Check if user has swiped the slides or if still animating
+ isMoved = self.isMoved(previous);
+
+ // 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");
-
- // Make current slide visible
- current.$slide.addClass("fancybox-slide--previous");
+ self.$refs.container.addClass("fancybox-is-open").trigger("focus");
// Attempt to load content into slide
- // At this point image would start loading, but inline/html content would load immediately
+ // This will later call `afterLoad` -> `revealContent`
self.loadSlide(current);
- current.$slide.removeClass("fancybox-slide--previous").addClass("fancybox-slide--current");
-
self.preload("image");
- self.$refs.container.trigger("focus");
-
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) {
- // Make sure that animation callback gets fired
$.fancybox.stop(slide.$slide, true);
-
- slide.$slide.removeClass("fancybox-animated").removeClass(function(index, className) {
- return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" ");
- });
});
- // Make current slide visible even if content is still loading
- current.$slide.removeClass("fancybox-slide--next fancybox-slide--previous").addClass("fancybox-slide--current");
+ if (previous.pos !== current.pos) {
+ previous.isComplete = false;
+
+ previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current");
+ }
- // If slides have been dragged, animate them to correct position
+ // If slides are out of place, then animate them to correct position
if (isMoved) {
- canvasWidth = Math.round(current.$slide.width());
+ // Calculate horizontal swipe distance
+ diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter);
$.each(self.slides, function(index, slide) {
- var pos = slide.pos - current.pos;
+ // 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.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");
+ $.fancybox.setTranslate(slide.$slide, {top: 0, left: leftPos + diff - stagePos.left});
+
+ 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
+ requestAFrame(function() {
+ $.fancybox.animate(
+ slide.$slide,
+ {
+ top: 0,
+ left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter
+ },
+ duration,
+ function() {
+ slide.$slide.removeAttr("style").removeClass("fancybox-slide--next fancybox-slide--previous");
- if (slide.pos === self.currPos) {
- self.complete();
+ if (slide.pos === self.currPos) {
+ self.complete();
+ }
}
- }
- );
+ );
+ });
});
} else {
- self.$refs.stage.children().removeAttr("style");
- }
+ current.$slide
+ .parent()
+ .children()
+ .removeAttr("style");
- // Start transition that reveals current content
- // or wait when it will be loaded
+ // Handle previously active slide
+ if (duration && current.opts.transitionEffect) {
+ $.fancybox.animate(
+ previous.$slide,
+ "fancybox-animated fancybox-slide--" +
+ (previous.pos > current.pos ? "next" : "previous") +
+ " fancybox-fx-" +
+ current.opts.transitionEffect,
+ duration,
+ null,
+ false
+ );
+ }
+ }
if (current.isLoaded) {
self.revealContent(current);
@@ -1137,31 +1198,6 @@
}
self.preload("image");
-
- if (previous.pos === current.pos) {
- return;
- }
-
- // Handle previously active 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 || (!isMoved && !current.opts.transitionEffect)) {
- return;
- }
-
- if (isMoved) {
- previous.$slide.addClass(transitionProps);
- } else {
- transitionProps = "fancybox-animated " + transitionProps + " fancybox-fx-" + current.opts.transitionEffect;
-
- $.fancybox.animate(previous.$slide, transitionProps, duration, null, false);
- }
},
// Create new "slide" element
@@ -1356,9 +1392,17 @@
minRatio = Math.min(1, maxWidth / width, maxHeight / height);
- // Use floor rounding to make sure it really fits
- width = Math.floor(minRatio * width);
- height = Math.floor(minRatio * 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"));
@@ -1443,7 +1487,17 @@
opacity: 1
},
duration === undefined ? 0 : duration,
- null,
+ function() {
+ // Clean up other slides
+ slide.$slide
+ .siblings()
+ .removeAttr("style")
+ .removeClass("fancybox-slide--previous fancybox-slide--next");
+
+ if (!slide.isComplete) {
+ self.complete();
+ }
+ },
false
);
}
@@ -1454,9 +1508,20 @@
isMoved: function(slide) {
var current = slide || this.current,
- currentPos = $.fancybox.getTranslate(current.$slide);
+ slidePos,
+ stagePos;
+
+ if (!current) {
+ return false;
+ }
+
+ stagePos = $.fancybox.getTranslate(this.$refs.stage);
+ slidePos = $.fancybox.getTranslate(current.$slide);
- return (currentPos.left !== 0 || currentPos.top !== 0) && !current.$slide.hasClass("fancybox-animated");
+ return (
+ (Math.abs(slidePos.top - stagePos.top) > 0 || Math.abs(slidePos.left - stagePos.left) > 0) &&
+ !current.$slide.hasClass("fancybox-animated")
+ );
},
// Update cursor style depending if content can be zoomed
@@ -1465,15 +1530,15 @@
updateCursor: function(nextWidth, nextHeight) {
var self = this,
current = self.current,
- $container = self.$refs.container.removeClass(
- "fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"
- ),
+ $container = self.$refs.container,
isZoomable;
- if (!current || self.isClosing) {
+ if (!current || self.isClosing || !self.Guestures) {
return;
}
+ $container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan");
+
isZoomable = self.isZoomable();
$container.toggleClass("fancybox-is-zoomable", isZoomable);
@@ -1576,7 +1641,11 @@
slide.isLoading = true;
- self.trigger("beforeLoad", slide);
+ if (self.trigger("beforeLoad", slide) === false) {
+ slide.isLoading = false;
+
+ return false;
+ }
type = slide.type;
$slide = slide.$slide;
@@ -1667,13 +1736,15 @@
windowWidth;
// Check if need to show loading icon
- slide.timouts = setTimeout(function() {
- var $img = slide.$image;
+ requestAFrame(function() {
+ requestAFrame(function() {
+ var $img = slide.$image;
- if (slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) {
- self.showLoading(slide);
- }
- }, 350);
+ if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) {
+ self.showLoading(slide);
+ }
+ });
+ });
// 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
@@ -1787,12 +1858,6 @@
self.afterLoad(slide);
}
- // Clear timeout that checks if loading icon needs to be displayed
- if (slide.timouts) {
- clearTimeout(slide.timouts);
- slide.timouts = null;
- }
-
if (self.isClosing) {
return;
}
@@ -1912,24 +1977,21 @@
$content.css({
width: "100%",
- height: ""
+ "max-width": "100%",
+ height: "9999px"
});
if (frameWidth === undefined) {
frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true)));
}
- if (frameWidth) {
- $content.width(frameWidth);
- }
+ $content.css("width", frameWidth ? frameWidth : "").css("max-width", "");
if (frameHeight === undefined) {
frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true)));
}
- if (frameHeight) {
- $content.height(frameHeight);
- }
+ $content.css("height", frameHeight ? frameHeight : "");
$slide.css("overflow", "auto");
}
@@ -1958,6 +2020,7 @@
.empty();
slide.isLoaded = false;
+ slide.isRevealed = false;
});
},
@@ -2104,7 +2167,10 @@
slide = slide || self.current;
if (slide && !slide.$spinner) {
- slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)).appendTo(slide.$slide);
+ slide.$spinner = $(self.translate(self, self.opts.spinnerTpl))
+ .appendTo(slide.$slide)
+ .hide()
+ .fadeIn();
}
},
@@ -2117,7 +2183,7 @@
slide = slide || self.current;
if (slide && slide.$spinner) {
- slide.$spinner.remove();
+ slide.$spinner.stop().remove();
delete slide.$spinner;
}
@@ -2185,10 +2251,6 @@
duration,
opacity;
- if (isMoved && isRevealed) {
- return;
- }
-
slide.isRevealed = true;
effect = slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"];
@@ -2199,7 +2261,7 @@
// Do not animate if revealing the same slide
if (slide.pos === self.currPos) {
if (slide.isComplete) {
- effect = false;
+ //effect = false;
} else {
self.isAnimating = true;
}
@@ -2239,8 +2301,6 @@
// 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;
@@ -2256,17 +2316,10 @@
// Simply show content if no effect
// ================================
if (!effect) {
- forceRedraw($slide);
+ slide.$content.removeClass("fancybox-is-hidden");
- if (!isRevealed) {
- slide.$content
- .removeClass("fancybox-is-hidden")
- .hide()
- .fadeIn("fast");
- }
-
- if (slide.pos === self.currPos) {
- self.complete();
+ if (!isRevealed && isMoved && slide.type === "image" && !slide.hasError) {
+ slide.$content.hide().fadeIn("fast");
}
return;
@@ -2278,15 +2331,12 @@
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.removeClass("fancybox-slide--current").addClass(effectClassName);
slide.$content.removeClass("fancybox-is-hidden");
// Force reflow
- forceRedraw($slide);
+ $slide.hide().show(0);
$.fancybox.animate(
$slide,
@@ -2313,38 +2363,7 @@
thumbPos = $thumb && $thumb.length && $thumb[0].ownerDocument === document ? $thumb.offset() : 0,
slidePos;
- // Check if element is inside the viewport by at least 1 pixel
- var isElementVisible = function($el) {
- var element = $el[0],
- elementRect = element.getBoundingClientRect(),
- parentRects = [],
- 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()
- );
- };
-
- if (thumbPos && isElementVisible($thumb)) {
+ if (thumbPos && inViewport($thumb) >= 10) {
slidePos = self.$refs.stage.offset();
rez = {
@@ -2411,7 +2430,8 @@
current.$slide
.find("video,audio")
.filter(":visible:first")
- .trigger("play");
+ .trigger("play")
+ .on("ended", $.proxy(self.next, self));
}
// Try to focus on the first focusable element
@@ -2583,10 +2603,6 @@
// If there are multiple instances, they will be set again by "activate" method
self.removeEvents();
- if (current.timouts) {
- clearTimeout(current.timouts);
- }
-
$content = current.$content;
effect = current.opts.animationEffect;
duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0;
@@ -2970,7 +2986,9 @@
}
if (props.scaleX !== undefined && props.scaleY !== undefined) {
- str = (str.length ? str + " " : "") + "scale(" + props.scaleX + ", " + props.scaleY + ")";
+ str += " scale(" + props.scaleX + ", " + props.scaleY + ")";
+ } else if (props.scaleX !== undefined) {
+ str += " scaleX(" + props.scaleX + ")";
}
if (str.length) {
@@ -2996,7 +3014,8 @@
// =============================
animate: function($el, to, duration, callback, leaveAnimationName) {
- var final = false,
+ var self = this,
+ final = false,
from;
if ($.isFunction(duration)) {
@@ -3008,7 +3027,7 @@
$el.removeAttr("style");
}
- $.fancybox.stop($el);
+ self.stop($el);
$el.on(transitionEnd, function(e) {
// Skip events from child elements and z-index change
@@ -3016,10 +3035,10 @@
return;
}
- $.fancybox.stop($el);
+ self.stop($el);
if (final) {
- $.fancybox.setTranslate($el, final);
+ self.setTranslate($el, final);
}
if ($.isNumeric(duration)) {
diff --git a/src/js/guestures.js b/src/js/guestures.js
index 58e0b55b..5a729299 100644
--- a/src/js/guestures.js
+++ b/src/js/guestures.js
@@ -185,7 +185,7 @@
self.startEvent = e;
- self.canTap = true;
+ self.canTap = !current.$slide.hasClass("fancybox-animated");
self.$target = $target;
self.$content = $content;
self.opts = current.opts.touch;
@@ -245,8 +245,6 @@
if (self.canPan) {
$.fancybox.stop(self.$content);
- self.$content.css("transition-duration", "");
-
self.isPanning = true;
} else {
self.isSwiping = true;
@@ -265,8 +263,6 @@
$.fancybox.stop(self.$content);
- self.$content.css("transition-duration", "");
-
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();
@@ -328,6 +324,7 @@
Guestures.prototype.onSwipe = function(e) {
var self = this,
+ instance = self.instance,
swiping = self.isSwiping,
left = self.sliderStartPos.left || 0,
angle;
@@ -338,9 +335,9 @@
if (Math.abs(self.distance) > 10) {
self.canTap = false;
- if (self.instance.group.length < 2 && self.opts.vertical) {
+ if (instance.group.length < 2 && self.opts.vertical) {
self.isSwiping = "y";
- } else if (self.instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) {
+ } 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);
@@ -348,34 +345,45 @@
self.isSwiping = angle > 45 && angle < 135 ? "y" : "x";
}
- self.canTap = false;
-
if (self.isSwiping === "y" && $.fancybox.isMobile && self.isScrollable) {
self.isScrolling = true;
return;
}
- self.instance.isDragging = self.isSwiping;
+ instance.isDragging = self.isSwiping;
// Reset points to avoid jumping, because we dropped first swipes to calculate the angle
self.startPoints = self.newPoints;
- $.each(self.instance.slides, function(index, slide) {
+ $.each(instance.slides, function(index, slide) {
+ var slidePos, stagePos;
+
$.fancybox.stop(slide.$slide);
- slide.$slide.css("transition-duration", "");
+ slidePos = $.fancybox.getTranslate(slide.$slide);
+ stagePos = $.fancybox.getTranslate(instance.$refs.stage);
- slide.inTransition = false;
+ slide.$slide
+ .removeAttr("style")
+ .removeClass("fancybox-animated")
+ .removeClass(function(index, className) {
+ return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" ");
+ });
- if (slide.pos === self.instance.current.pos) {
- self.sliderStartPos.left = $.fancybox.getTranslate(slide.$slide).left - $.fancybox.getTranslate(self.instance.$refs.stage).left;
+ if (slide.pos === instance.current.pos) {
+ self.sliderStartPos.left = slidePos.left - stagePos.left;
}
+
+ $.fancybox.setTranslate(slide.$slide, {
+ top: slidePos.top - stagePos.top,
+ left: slidePos.left - stagePos.left
+ });
});
// Stop slideshow
- if (self.instance.SlideShow && self.instance.SlideShow.isActive) {
- self.instance.SlideShow.stop();
+ if (instance.SlideShow && instance.SlideShow.isActive) {
+ instance.SlideShow.stop();
}
}
@@ -603,7 +611,6 @@
Guestures.prototype.ontouchend = function(e) {
var self = this;
- var dMs = Math.max(new Date().getTime() - self.startTime, 1);
var swiping = self.isSwiping;
var panning = self.isPanning;
@@ -611,6 +618,7 @@
var scrolling = self.isScrolling;
self.endPoints = getPointerXY(e);
+ self.dMs = Math.max(new Date().getTime() - self.startTime, 1);
self.$container.removeClass("fancybox-is-grabbing");
@@ -635,13 +643,11 @@
return self.onTap(e);
}
- self.speed = 366;
+ self.speed = 100;
// Speed in px/ms
- self.velocityX = (self.distanceX / dMs) * 0.5;
- self.velocityY = (self.distanceY / dMs) * 0.5;
-
- self.speedX = Math.max(self.speed * 0.5, Math.min(self.speed * 1.5, (1 / Math.abs(self.velocityX)) * self.speed));
+ self.velocityX = (self.distanceX / self.dMs) * 0.5;
+ self.velocityY = (self.distanceY / self.dMs) * 0.5;
if (panning) {
self.endPanning();
@@ -657,7 +663,11 @@
Guestures.prototype.endSwiping = function(swiping, scrolling) {
var self = this,
ret = false,
- len = self.instance.group.length;
+ len = self.instance.group.length,
+ velocityX = Math.abs(self.velocityX),
+ distanceX = Math.abs(self.distanceX),
+ canAdvance = swiping == "x" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50),
+ speedX = Math.abs((velocityX * self.canvasWidth) / self.canvasWidth) > 0.8 ? 366 : 500;
self.sliderLastPos = null;
@@ -674,18 +684,14 @@
);
ret = self.instance.close(true, 200);
- } else if (swiping == "x" && self.distanceX > 50 && len > 1) {
- ret = self.instance.previous(self.speedX);
- } else if (swiping == "x" && self.distanceX < -50 && len > 1) {
- ret = self.instance.next(self.speedX);
+ } 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")) {
- if (scrolling || len < 2) {
- self.instance.centerSlide(self.instance.current, 150);
- } else {
- self.instance.jumpTo(self.instance.current.index);
- }
+ self.instance.centerSlide(self.instance.current, 150);
}
self.$container.removeClass("fancybox-is-sliding");
@@ -694,20 +700,22 @@
// Limit panning from edges
// ========================
Guestures.prototype.endPanning = function() {
- var self = this;
- var newOffsetX, newOffsetY, newPos;
+ var self = this,
+ newOffsetX,
+ newOffsetY,
+ newPos;
if (!self.contentLastPos) {
return;
}
- if (self.opts.momentum === false) {
+ 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 * self.speed;
- newOffsetY = self.contentLastPos.top + self.velocityY * self.speed;
+ 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);
diff --git a/src/js/media.js b/src/js/media.js
index d0c0d17c..f0600b2c 100644
--- a/src/js/media.js
+++ b/src/js/media.js
@@ -7,32 +7,7 @@
(function($) {
"use strict";
- // 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;
- };
-
// 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,
@@ -60,8 +35,7 @@
show_title: 1,
show_byline: 1,
show_portrait: 0,
- fullscreen: 1,
- api: 1
+ fullscreen: 1
},
paramPlace: 3,
type: "iframe",
@@ -107,6 +81,29 @@
}
};
+ // 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,
@@ -198,4 +195,96 @@
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
+ },
+
+ 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();
+ });
+ }
+ }
+ }
+ };
+
+ $(document).on({
+ "afterShow.fb": function(e, instance, current) {
+ if (instance.group.length > 1 && (current.contentSource === "youtube" || current.contentSource === "vimeo")) {
+ VideoAPILoader.load(current.contentSource);
+ }
+ }
+ });
})(jQuery);
diff --git a/src/js/slideshow.js b/src/js/slideshow.js
index 25282506..4dce352b 100644
--- a/src/js/slideshow.js
+++ b/src/js/slideshow.js
@@ -20,7 +20,8 @@
},
slideShow: {
autoStart: false,
- speed: 3000
+ speed: 3000,
+ progress: true
}
});
@@ -35,42 +36,37 @@
$button: null,
init: function() {
- var self = this;
+ var self = this,
+ instance = self.instance,
+ opts = instance.group[instance.currIndex].opts.slideShow;
- self.$button = self.instance.$refs.toolbar.find("[data-fancybox-play]").on("click", function() {
+ self.$button = instance.$refs.toolbar.find("[data-fancybox-play]").on("click", function() {
self.toggle();
});
- if (self.instance.group.length < 2 || !self.instance.group[self.instance.currIndex].opts.slideShow) {
+ if (instance.group.length < 2 || !opts) {
self.$button.hide();
+ } else if (opts.progress) {
+ self.$progress = $('').appendTo(instance.$refs.inner);
}
},
set: function(force) {
var self = this,
instance = self.instance,
- current = instance.current,
- advance = function() {
- if (self.isActive) {
- instance.jumpTo((instance.currIndex + 1) % instance.group.length);
- }
- };
+ current = instance.current;
// Check if reached last element
if (current && (force === true || current.opts.loop || instance.currIndex < instance.group.length - 1)) {
- self.timer = setTimeout(function() {
- var $video;
-
- if (self.isActive) {
- $video = current.$slide.find("video,audio").filter(":visible:first");
-
- if ($video.length) {
- $video.one("ended", advance);
- } else {
- advance();
- }
+ if (self.isActive && current.contentType !== "video") {
+ if (self.$progress) {
+ $.fancybox.animate(self.$progress.show(), {scaleX: 1}, current.opts.slideShow.speed);
}
- }, current.opts.slideShow.speed);
+
+ self.timer = setTimeout(function() {
+ instance.jumpTo((instance.currIndex + 1) % instance.group.length);
+ }, current.opts.slideShow.speed);
+ }
} else {
self.stop();
instance.idleSecondsCounter = 0;
@@ -84,11 +80,15 @@
clearTimeout(self.timer);
self.timer = null;
+
+ if (self.$progress) {
+ self.$progress.removeAttr("style").hide();
+ }
},
start: function() {
- var self = this;
- var current = self.instance.current;
+ var self = this,
+ current = self.instance.current;
if (current) {
self.$button
@@ -107,8 +107,8 @@
},
stop: function() {
- var self = this;
- var current = self.instance.current;
+ var self = this,
+ current = self.instance.current;
self.clear();
@@ -120,6 +120,10 @@
self.isActive = false;
self.instance.trigger("onSlideShowChange", false);
+
+ if (self.$progress) {
+ self.$progress.removeAttr("style").hide();
+ }
},
toggle: function() {
@@ -182,8 +186,8 @@
// Page Visibility API to pause slideshow when window is not active
$(document).on("visibilitychange", function() {
- var instance = $.fancybox.getInstance();
- var SlideShow = instance && instance.SlideShow;
+ var instance = $.fancybox.getInstance(),
+ SlideShow = instance && instance.SlideShow;
if (SlideShow && SlideShow.isActive) {
if (document.hidden) {
diff --git a/src/js/thumbs.js b/src/js/thumbs.js
index 44c6a6f7..f11b07b1 100644
--- a/src/js/thumbs.js
+++ b/src/js/thumbs.js
@@ -111,8 +111,8 @@
list.push(
'' : "") +
+ '"' +
+ (src && src.length ? ' style="background-image:url(' + src + ')"' : "") +
">"
);
});