var hasMozTransform, getHasMozTransform = function() { if(hasMozTransform === undefined) { hasMozTransform = document.createElement('p').style.MozTransform !== undefined; } return hasMozTransform; }; $.magnificPopup.registerModule('zoom', { options: { enabled: false, easing: 'ease-in-out', duration: 300, opener: function(element) { return element.is('img') ? element : element.find('img'); } }, proto: { initZoom: function() { var zoomSt = mfp.st.zoom, ns = '.zoom', image; if(!zoomSt.enabled || !mfp.supportsTransition) { return; } var duration = zoomSt.duration, getElToAnimate = function(image) { var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'), transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing, cssObj = { position: 'fixed', zIndex: 9999, left: 0, top: 0, '-webkit-backface-visibility': 'hidden' }, t = 'transition'; cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition; newImg.css(cssObj); return newImg; }, showMainContent = function() { mfp.content.css('visibility', 'visible'); }, openTimeout, animatedImg; _mfpOn('BuildControls'+ns, function() { if(mfp._allowZoom()) { clearTimeout(openTimeout); mfp.content.css('visibility', 'hidden'); // Basically, all code below does is clones existing image, puts in on top of the current one and animated it image = mfp._getItemToZoom(); if(!image) { showMainContent(); return; } animatedImg = getElToAnimate(image); animatedImg.css( mfp._getOffset() ); mfp.wrap.append(animatedImg); openTimeout = setTimeout(function() { animatedImg.css( mfp._getOffset( true ) ); openTimeout = setTimeout(function() { showMainContent(); setTimeout(function() { animatedImg.remove(); image = animatedImg = null; _mfpTrigger('ZoomAnimationEnded'); }, 16); // avoid blink when switching images }, duration); // this timeout equals animation duration }, 16); // by adding this timeout we avoid short glitch at the beginning of animation // Lots of timeouts... } }); _mfpOn(BEFORE_CLOSE_EVENT+ns, function() { if(mfp._allowZoom()) { clearTimeout(openTimeout); mfp.st.removalDelay = duration; if(!image) { image = mfp._getItemToZoom(); if(!image) { return; } animatedImg = getElToAnimate(image); } animatedImg.css( mfp._getOffset(true) ); mfp.wrap.append(animatedImg); mfp.content.css('visibility', 'hidden'); setTimeout(function() { animatedImg.css( mfp._getOffset() ); }, 16); } }); _mfpOn(CLOSE_EVENT+ns, function() { if(mfp._allowZoom()) { showMainContent(); if(animatedImg) { animatedImg.remove(); } image = null; } }); }, _allowZoom: function() { return mfp.currItem.type === 'image'; }, _getItemToZoom: function() { if(mfp.currItem.hasSize) { return mfp.currItem.img; } else { return false; } }, // Get element postion relative to viewport _getOffset: function(isLarge) { var el; if(isLarge) { el = mfp.currItem.img; } else { el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem); } var offset = el.offset(); var paddingTop = parseInt(el.css('padding-top'),10); var paddingBottom = parseInt(el.css('padding-bottom'),10); offset.top -= ( $(window).scrollTop() - paddingTop ); /* Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa. */ var obj = { width: el.width(), // fix Zepto height+padding issue height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop }; // I hate to do this, but there is no another option if( getHasMozTransform() ) { obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)'; } else { obj.left = offset.left; obj.top = offset.top; } return obj; } } });