| /*! Magnific Popup - v0.9.3 - 2013-07-16 |
| * http://dimsemenov.com/plugins/magnific-popup/ |
| * Copyright (c) 2013 Dmitry Semenov; */ |
| ;(function($) { |
| |
| /*>>core*/ |
| /** |
| * |
| * Magnific Popup Core JS file |
| * |
| */ |
| |
| |
| /** |
| * Private static constants |
| */ |
| var CLOSE_EVENT = 'Close', |
| BEFORE_CLOSE_EVENT = 'BeforeClose', |
| AFTER_CLOSE_EVENT = 'AfterClose', |
| BEFORE_APPEND_EVENT = 'BeforeAppend', |
| MARKUP_PARSE_EVENT = 'MarkupParse', |
| OPEN_EVENT = 'Open', |
| CHANGE_EVENT = 'Change', |
| NS = 'mfp', |
| EVENT_NS = '.' + NS, |
| READY_CLASS = 'mfp-ready', |
| REMOVING_CLASS = 'mfp-removing', |
| PREVENT_CLOSE_CLASS = 'mfp-prevent-close'; |
| |
| |
| /** |
| * Private vars |
| */ |
| var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this' |
| MagnificPopup = function(){}, |
| _isJQ = !!(window.jQuery), |
| _prevStatus, |
| _window = $(window), |
| _body, |
| _document, |
| _prevContentType, |
| _wrapClasses, |
| _currPopupType; |
| |
| |
| /** |
| * Private functions |
| */ |
| var _mfpOn = function(name, f) { |
| mfp.ev.on(NS + name + EVENT_NS, f); |
| }, |
| _getEl = function(className, appendTo, html, raw) { |
| var el = document.createElement('div'); |
| el.className = 'mfp-'+className; |
| if(html) { |
| el.innerHTML = html; |
| } |
| if(!raw) { |
| el = $(el); |
| if(appendTo) { |
| el.appendTo(appendTo); |
| } |
| } else if(appendTo) { |
| appendTo.appendChild(el); |
| } |
| return el; |
| }, |
| _mfpTrigger = function(e, data) { |
| mfp.ev.triggerHandler(NS + e, data); |
| |
| if(mfp.st.callbacks) { |
| // converts "mfpEventName" to "eventName" callback and triggers it if it's present |
| e = e.charAt(0).toLowerCase() + e.slice(1); |
| if(mfp.st.callbacks[e]) { |
| mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]); |
| } |
| } |
| }, |
| _setFocus = function() { |
| (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).trigger('focus'); |
| }, |
| _getCloseBtn = function(type) { |
| if(type !== _currPopupType || !mfp.currTemplate.closeBtn) { |
| mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) ); |
| _currPopupType = type; |
| } |
| return mfp.currTemplate.closeBtn; |
| }, |
| // Initialize Magnific Popup only when called at least once |
| _checkInstance = function() { |
| if(!$.magnificPopup.instance) { |
| mfp = new MagnificPopup(); |
| mfp.init(); |
| $.magnificPopup.instance = mfp; |
| } |
| }, |
| // Check to close popup or not |
| // "target" is an element that was clicked |
| _checkIfClose = function(target) { |
| |
| if($(target).hasClass(PREVENT_CLOSE_CLASS)) { |
| return; |
| } |
| |
| var closeOnContent = mfp.st.closeOnContentClick; |
| var closeOnBg = mfp.st.closeOnBgClick; |
| |
| if(closeOnContent && closeOnBg) { |
| return true; |
| } else { |
| |
| // We close the popup if click is on close button or on preloader. Or if there is no content. |
| if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) { |
| return true; |
| } |
| |
| // if click is outside the content |
| if( (target !== mfp.content[0] && !$.contains(mfp.content[0], target)) ) { |
| if(closeOnBg) { |
| // last check, if the clicked element is in DOM, (in case it's removed onclick) |
| if( $.contains(document, target) ) { |
| return true; |
| } |
| } |
| } else if(closeOnContent) { |
| return true; |
| } |
| |
| } |
| return false; |
| }, |
| // CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr |
| supportsTransitions = function() { |
| var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist |
| v = ['ms','O','Moz','Webkit']; // 'v' for vendor |
| |
| if( s['transition'] !== undefined ) { |
| return true; |
| } |
| |
| while( v.length ) { |
| if( v.pop() + 'Transition' in s ) { |
| return true; |
| } |
| } |
| |
| return false; |
| }; |
| |
| |
| |
| /** |
| * Public functions |
| */ |
| MagnificPopup.prototype = { |
| |
| constructor: MagnificPopup, |
| |
| /** |
| * Initializes Magnific Popup plugin. |
| * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed |
| */ |
| init: function() { |
| var appVersion = navigator.appVersion; |
| mfp.isIE7 = appVersion.indexOf("MSIE 7.") !== -1; |
| mfp.isIE8 = appVersion.indexOf("MSIE 8.") !== -1; |
| mfp.isLowIE = mfp.isIE7 || mfp.isIE8; |
| mfp.isAndroid = (/android/gi).test(appVersion); |
| mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion); |
| mfp.supportsTransition = supportsTransitions(); |
| |
| // We disable fixed positioned lightbox on devices that don't handle it nicely. |
| // If you know a better way of detecting this - let me know. |
| mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) ); |
| _body = $(document.body); |
| _document = $(document); |
| |
| mfp.popupsCache = {}; |
| }, |
| |
| /** |
| * Opens popup |
| * @param data [description] |
| */ |
| open: function(data) { |
| |
| var i; |
| |
| if(data.isObj === false) { |
| // convert jQuery collection to array to avoid conflicts later |
| mfp.items = data.items.toArray(); |
| |
| mfp.index = 0; |
| var items = data.items, |
| item; |
| for(i = 0; i < items.length; i++) { |
| item = items[i]; |
| if(item.parsed) { |
| item = item.el[0]; |
| } |
| if(item === data.el[0]) { |
| mfp.index = i; |
| break; |
| } |
| } |
| } else { |
| mfp.items = $.isArray(data.items) ? data.items : [data.items]; |
| mfp.index = data.index || 0; |
| } |
| |
| // if popup is already opened - we just update the content |
| if(mfp.isOpen) { |
| mfp.updateItemHTML(); |
| return; |
| } |
| |
| mfp.types = []; |
| _wrapClasses = ''; |
| if(data.mainEl && data.mainEl.length) { |
| mfp.ev = data.mainEl.eq(0); |
| } else { |
| mfp.ev = _document; |
| } |
| |
| if(data.key) { |
| if(!mfp.popupsCache[data.key]) { |
| mfp.popupsCache[data.key] = {}; |
| } |
| mfp.currTemplate = mfp.popupsCache[data.key]; |
| } else { |
| mfp.currTemplate = {}; |
| } |
| |
| |
| |
| mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data ); |
| mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos; |
| |
| if(mfp.st.modal) { |
| mfp.st.closeOnContentClick = false; |
| mfp.st.closeOnBgClick = false; |
| mfp.st.showCloseBtn = false; |
| mfp.st.enableEscapeKey = false; |
| } |
| |
| |
| // Building markup |
| // main containers are created only once |
| if(!mfp.bgOverlay) { |
| |
| // Dark overlay |
| mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() { |
| mfp.close(); |
| }); |
| |
| mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) { |
| if(_checkIfClose(e.target)) { |
| mfp.close(); |
| } |
| }); |
| |
| mfp.container = _getEl('container', mfp.wrap); |
| } |
| |
| mfp.contentContainer = _getEl('content'); |
| if(mfp.st.preloader) { |
| mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading); |
| } |
| |
| |
| // Initializing modules |
| var modules = $.magnificPopup.modules; |
| for(i = 0; i < modules.length; i++) { |
| var n = modules[i]; |
| n = n.charAt(0).toUpperCase() + n.slice(1); |
| mfp['init'+n].call(mfp); |
| } |
| _mfpTrigger('BeforeOpen'); |
| |
| |
| if(mfp.st.showCloseBtn) { |
| // Close button |
| if(!mfp.st.closeBtnInside) { |
| mfp.wrap.append( _getCloseBtn() ); |
| } else { |
| _mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) { |
| values.close_replaceWith = _getCloseBtn(item.type); |
| }); |
| _wrapClasses += ' mfp-close-btn-in'; |
| } |
| } |
| |
| if(mfp.st.alignTop) { |
| _wrapClasses += ' mfp-align-top'; |
| } |
| |
| |
| |
| if(mfp.fixedContentPos) { |
| mfp.wrap.css({ |
| overflow: mfp.st.overflowY, |
| overflowX: 'hidden', |
| overflowY: mfp.st.overflowY |
| }); |
| } else { |
| mfp.wrap.css({ |
| top: _window.scrollTop(), |
| position: 'absolute' |
| }); |
| } |
| if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) { |
| mfp.bgOverlay.css({ |
| height: _document.height(), |
| position: 'absolute' |
| }); |
| } |
| |
| |
| |
| if(mfp.st.enableEscapeKey) { |
| // Close on ESC key |
| _document.on('keyup' + EVENT_NS, function(e) { |
| if(e.keyCode === 27) { |
| mfp.close(); |
| } |
| }); |
| } |
| |
| _window.on('resize' + EVENT_NS, function() { |
| mfp.updateSize(); |
| }); |
| |
| |
| if(!mfp.st.closeOnContentClick) { |
| _wrapClasses += ' mfp-auto-cursor'; |
| } |
| |
| if(_wrapClasses) |
| mfp.wrap.addClass(_wrapClasses); |
| |
| |
| // this triggers recalculation of layout, so we get it once to not to trigger twice |
| var windowHeight = mfp.wH = _window.height(); |
| |
| |
| var windowStyles = {}; |
| |
| if( mfp.fixedContentPos ) { |
| if(mfp._hasScrollBar(windowHeight)){ |
| var s = mfp._getScrollbarSize(); |
| if(s) { |
| windowStyles.paddingRight = s; |
| } |
| } |
| } |
| |
| if(mfp.fixedContentPos) { |
| if(!mfp.isIE7) { |
| windowStyles.overflow = 'hidden'; |
| } else { |
| // ie7 double-scroll bug |
| $('body, html').css('overflow', 'hidden'); |
| } |
| } |
| |
| |
| |
| var classesToadd = mfp.st.mainClass; |
| if(mfp.isIE7) { |
| classesToadd += ' mfp-ie7'; |
| } |
| if(classesToadd) { |
| mfp._addClassToMFP( classesToadd ); |
| } |
| |
| // add content |
| mfp.updateItemHTML(); |
| |
| _mfpTrigger('BuildControls'); |
| |
| |
| // remove scrollbar, add padding e.t.c |
| $('html').css(windowStyles); |
| |
| // add everything to DOM |
| mfp.bgOverlay.add(mfp.wrap).prependTo( document.body ); |
| |
| |
| |
| // Save last focused element |
| mfp._lastFocusedEl = document.activeElement; |
| |
| // Wait for next cycle to allow CSS transition |
| setTimeout(function() { |
| |
| if(mfp.content) { |
| mfp._addClassToMFP(READY_CLASS); |
| _setFocus(); |
| } else { |
| // if content is not defined (not loaded e.t.c) we add class only for BG |
| mfp.bgOverlay.addClass(READY_CLASS); |
| } |
| |
| // Trap the focus in popup |
| _document.on('focusin' + EVENT_NS, function (e) { |
| if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) { |
| _setFocus(); |
| return false; |
| } |
| }); |
| |
| }, 16); |
| |
| mfp.isOpen = true; |
| mfp.updateSize(windowHeight); |
| _mfpTrigger(OPEN_EVENT); |
| }, |
| |
| /** |
| * Closes the popup |
| */ |
| close: function() { |
| if(!mfp.isOpen) return; |
| _mfpTrigger(BEFORE_CLOSE_EVENT); |
| |
| mfp.isOpen = false; |
| // for CSS3 animation |
| if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition ) { |
| mfp._addClassToMFP(REMOVING_CLASS); |
| setTimeout(function() { |
| mfp._close(); |
| }, mfp.st.removalDelay); |
| } else { |
| mfp._close(); |
| } |
| }, |
| |
| /** |
| * Helper for close() function |
| */ |
| _close: function() { |
| _mfpTrigger(CLOSE_EVENT); |
| |
| var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' '; |
| |
| mfp.bgOverlay.detach(); |
| mfp.wrap.detach(); |
| mfp.container.empty(); |
| |
| if(mfp.st.mainClass) { |
| classesToRemove += mfp.st.mainClass + ' '; |
| } |
| |
| mfp._removeClassFromMFP(classesToRemove); |
| |
| if(mfp.fixedContentPos) { |
| var windowStyles = {paddingRight: ''}; |
| if(mfp.isIE7) { |
| $('body, html').css('overflow', ''); |
| } else { |
| windowStyles.overflow = ''; |
| } |
| $('html').css(windowStyles); |
| } |
| |
| _document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS); |
| mfp.ev.off(EVENT_NS); |
| |
| // clean up DOM elements that aren't removed |
| mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style'); |
| mfp.bgOverlay.attr('class', 'mfp-bg'); |
| mfp.container.attr('class', 'mfp-container'); |
| |
| // remove close button from target element |
| if(mfp.st.showCloseBtn && |
| (!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) { |
| if(mfp.currTemplate.closeBtn) |
| mfp.currTemplate.closeBtn.detach(); |
| } |
| |
| |
| if(mfp._lastFocusedEl) { |
| $(mfp._lastFocusedEl).trigger('focus'); // put tab focus back |
| } |
| mfp.currItem = null; |
| mfp.content = null; |
| mfp.currTemplate = null; |
| mfp.prevHeight = 0; |
| |
| _mfpTrigger(AFTER_CLOSE_EVENT); |
| }, |
| |
| updateSize: function(winHeight) { |
| |
| if(mfp.isIOS) { |
| // fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2 |
| var zoomLevel = document.documentElement.clientWidth / window.innerWidth; |
| var height = window.innerHeight * zoomLevel; |
| mfp.wrap.css('height', height); |
| mfp.wH = height; |
| } else { |
| mfp.wH = winHeight || _window.height(); |
| } |
| // Fixes #84: popup incorrectly positioned with position:relative on body |
| if(!mfp.fixedContentPos) { |
| mfp.wrap.css('height', mfp.wH); |
| } |
| |
| _mfpTrigger('Resize'); |
| |
| }, |
| |
| /** |
| * Set content of popup based on current index |
| */ |
| updateItemHTML: function() { |
| var item = mfp.items[mfp.index]; |
| |
| // Detach and perform modifications |
| mfp.contentContainer.detach(); |
| |
| if(mfp.content) |
| mfp.content.detach(); |
| |
| if(!item.parsed) { |
| item = mfp.parseEl( mfp.index ); |
| } |
| |
| var type = item.type; |
| |
| _mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]); |
| // BeforeChange event works like so: |
| // _mfpOn('BeforeChange', function(e, prevType, newType) { }); |
| |
| mfp.currItem = item; |
| |
| |
| |
| |
| |
| if(!mfp.currTemplate[type]) { |
| var markup = mfp.st[type] ? mfp.st[type].markup : false; |
| |
| // allows to modify markup |
| _mfpTrigger('FirstMarkupParse', markup); |
| |
| if(markup) { |
| mfp.currTemplate[type] = $(markup); |
| } else { |
| // if there is no markup found we just define that template is parsed |
| mfp.currTemplate[type] = true; |
| } |
| } |
| |
| if(_prevContentType && _prevContentType !== item.type) { |
| mfp.container.removeClass('mfp-'+_prevContentType+'-holder'); |
| } |
| |
| var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]); |
| mfp.appendContent(newContent, type); |
| |
| item.preloaded = true; |
| |
| _mfpTrigger(CHANGE_EVENT, item); |
| _prevContentType = item.type; |
| |
| // Append container back after its content changed |
| mfp.container.prepend(mfp.contentContainer); |
| |
| _mfpTrigger('AfterChange'); |
| }, |
| |
| |
| /** |
| * Set HTML content of popup |
| */ |
| appendContent: function(newContent, type) { |
| mfp.content = newContent; |
| |
| if(newContent) { |
| if(mfp.st.showCloseBtn && mfp.st.closeBtnInside && |
| mfp.currTemplate[type] === true) { |
| // if there is no markup, we just append close button element inside |
| if(!mfp.content.find('.mfp-close').length) { |
| mfp.content.append(_getCloseBtn()); |
| } |
| } else { |
| mfp.content = newContent; |
| } |
| } else { |
| mfp.content = ''; |
| } |
| |
| _mfpTrigger(BEFORE_APPEND_EVENT); |
| mfp.container.addClass('mfp-'+type+'-holder'); |
| |
| mfp.contentContainer.append(mfp.content); |
| }, |
| |
| |
| |
| |
| /** |
| * Creates Magnific Popup data object based on given data |
| * @param {int} index Index of item to parse |
| */ |
| parseEl: function(index) { |
| var item = mfp.items[index], |
| type = item.type; |
| |
| if(item.tagName) { |
| item = { el: $(item) }; |
| } else { |
| item = { data: item, src: item.src }; |
| } |
| |
| if(item.el) { |
| var types = mfp.types; |
| |
| // check for 'mfp-TYPE' class |
| for(var i = 0; i < types.length; i++) { |
| if( item.el.hasClass('mfp-'+types[i]) ) { |
| type = types[i]; |
| break; |
| } |
| } |
| |
| item.src = item.el.attr('data-mfp-src'); |
| if(!item.src) { |
| item.src = item.el.attr('href'); |
| } |
| } |
| |
| item.type = type || mfp.st.type || 'inline'; |
| item.index = index; |
| item.parsed = true; |
| mfp.items[index] = item; |
| _mfpTrigger('ElementParse', item); |
| |
| return mfp.items[index]; |
| }, |
| |
| |
| /** |
| * Initializes single popup or a group of popups |
| */ |
| addGroup: function(el, options) { |
| var eHandler = function(e) { |
| e.mfpEl = this; |
| mfp._openClick(e, el, options); |
| }; |
| |
| if(!options) { |
| options = {}; |
| } |
| |
| var eName = 'click.magnificPopup'; |
| options.mainEl = el; |
| |
| if(options.items) { |
| options.isObj = true; |
| el.off(eName).on(eName, eHandler); |
| } else { |
| options.isObj = false; |
| if(options.delegate) { |
| el.off(eName).on(eName, options.delegate , eHandler); |
| } else { |
| options.items = el; |
| el.off(eName).on(eName, eHandler); |
| } |
| } |
| }, |
| _openClick: function(e, el, options) { |
| var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick; |
| |
| |
| if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey ) ) { |
| return; |
| } |
| |
| var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn; |
| |
| if(disableOn) { |
| if($.isFunction(disableOn)) { |
| if( !disableOn.call(mfp) ) { |
| return true; |
| } |
| } else { // else it's number |
| if( _window.width() < disableOn ) { |
| return true; |
| } |
| } |
| } |
| |
| if(e.type) { |
| e.preventDefault(); |
| |
| // This will prevent popup from closing if element is inside and popup is already opened |
| if(mfp.isOpen) { |
| e.stopPropagation(); |
| } |
| } |
| |
| |
| options.el = $(e.mfpEl); |
| if(options.delegate) { |
| options.items = el.find(options.delegate); |
| } |
| mfp.open(options); |
| }, |
| |
| |
| /** |
| * Updates text on preloader |
| */ |
| updateStatus: function(status, text) { |
| |
| if(mfp.preloader) { |
| if(_prevStatus !== status) { |
| mfp.container.removeClass('mfp-s-'+_prevStatus); |
| } |
| |
| if(!text && status === 'loading') { |
| text = mfp.st.tLoading; |
| } |
| |
| var data = { |
| status: status, |
| text: text |
| }; |
| // allows to modify status |
| _mfpTrigger('UpdateStatus', data); |
| |
| status = data.status; |
| text = data.text; |
| |
| mfp.preloader.html(text); |
| |
| mfp.preloader.find('a').on('click', function(e) { |
| e.stopImmediatePropagation(); |
| }); |
| |
| mfp.container.addClass('mfp-s-'+status); |
| _prevStatus = status; |
| } |
| }, |
| |
| |
| /* |
| "Private" helpers that aren't private at all |
| */ |
| _addClassToMFP: function(cName) { |
| mfp.bgOverlay.addClass(cName); |
| mfp.wrap.addClass(cName); |
| }, |
| _removeClassFromMFP: function(cName) { |
| this.bgOverlay.removeClass(cName); |
| mfp.wrap.removeClass(cName); |
| }, |
| _hasScrollBar: function(winHeight) { |
| return ( (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) ); |
| }, |
| _parseMarkup: function(template, values, item) { |
| var arr; |
| if(item.data) { |
| values = $.extend(item.data, values); |
| } |
| _mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] ); |
| |
| $.each(values, function(key, value) { |
| if(value === undefined || value === false) { |
| return true; |
| } |
| arr = key.split('_'); |
| if(arr.length > 1) { |
| var el = template.find(EVENT_NS + '-'+arr[0]); |
| |
| if(el.length > 0) { |
| var attr = arr[1]; |
| if(attr === 'replaceWith') { |
| if(el[0] !== value[0]) { |
| el.replaceWith(value); |
| } |
| } else if(attr === 'img') { |
| if(el.is('img')) { |
| el.attr('src', value); |
| } else { |
| el.replaceWith( '<img src="'+value+'" class="' + el.attr('class') + '" />' ); |
| } |
| } else { |
| el.attr(arr[1], value); |
| } |
| } |
| |
| } else { |
| template.find(EVENT_NS + '-'+key).html(value); |
| } |
| }); |
| }, |
| |
| _getScrollbarSize: function() { |
| // thx David |
| if(mfp.scrollbarSize === undefined) { |
| var scrollDiv = document.createElement("div"); |
| scrollDiv.id = "mfp-sbm"; |
| scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; |
| document.body.appendChild(scrollDiv); |
| mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth; |
| document.body.removeChild(scrollDiv); |
| } |
| return mfp.scrollbarSize; |
| } |
| |
| }; /* MagnificPopup core prototype end */ |
| |
| |
| |
| |
| /** |
| * Public static functions |
| */ |
| $.magnificPopup = { |
| instance: null, |
| proto: MagnificPopup.prototype, |
| modules: [], |
| |
| open: function(options, index) { |
| _checkInstance(); |
| |
| if(!options) |
| options = {}; |
| |
| options.isObj = true; |
| options.index = index || 0; |
| return this.instance.open(options); |
| }, |
| |
| close: function() { |
| return $.magnificPopup.instance.close(); |
| }, |
| |
| registerModule: function(name, module) { |
| if(module.options) { |
| $.magnificPopup.defaults[name] = module.options; |
| } |
| $.extend(this.proto, module.proto); |
| this.modules.push(name); |
| }, |
| |
| defaults: { |
| |
| // Info about options is in docs: |
| // http://dimsemenov.com/plugins/magnific-popup/documentation.html#options |
| |
| disableOn: 0, |
| |
| key: null, |
| |
| midClick: false, |
| |
| mainClass: '', |
| |
| preloader: true, |
| |
| focus: '', // CSS selector of input to focus after popup is opened |
| |
| closeOnContentClick: false, |
| |
| closeOnBgClick: true, |
| |
| closeBtnInside: true, |
| |
| showCloseBtn: true, |
| |
| enableEscapeKey: true, |
| |
| modal: false, |
| |
| alignTop: false, |
| |
| removalDelay: 0, |
| |
| fixedContentPos: 'auto', |
| |
| fixedBgPos: 'auto', |
| |
| overflowY: 'auto', |
| |
| closeMarkup: '<button title="%title%" type="button" class="mfp-close">×</button>', |
| |
| tClose: 'Close (Esc)', |
| |
| tLoading: 'Loading...' |
| |
| } |
| }; |
| |
| |
| |
| $.fn.magnificPopup = function(options) { |
| _checkInstance(); |
| |
| var jqEl = $(this); |
| |
| // We call some API method of first param is a string |
| if (typeof options === "string" ) { |
| |
| if(options === 'open') { |
| var items, |
| itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup, |
| index = parseInt(arguments[1], 10) || 0; |
| |
| if(itemOpts.items) { |
| items = itemOpts.items[index]; |
| } else { |
| items = jqEl; |
| if(itemOpts.delegate) { |
| items = items.find(itemOpts.delegate); |
| } |
| items = items.eq( index ); |
| } |
| mfp._openClick({mfpEl:items}, jqEl, itemOpts); |
| } else { |
| if(mfp.isOpen) |
| mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1)); |
| } |
| |
| } else { |
| |
| /* |
| * As Zepto doesn't support .data() method for objects |
| * and it works only in normal browsers |
| * we assign "options" object directly to the DOM element. FTW! |
| */ |
| if(_isJQ) { |
| jqEl.data('magnificPopup', options); |
| } else { |
| jqEl[0].magnificPopup = options; |
| } |
| |
| mfp.addGroup(jqEl, options); |
| |
| } |
| return jqEl; |
| }; |
| |
| |
| //Quick benchmark |
| /* |
| var start = performance.now(), |
| i, |
| rounds = 1000; |
| |
| for(i = 0; i < rounds; i++) { |
| |
| } |
| console.log('Test #1:', performance.now() - start); |
| |
| start = performance.now(); |
| for(i = 0; i < rounds; i++) { |
| |
| } |
| console.log('Test #2:', performance.now() - start); |
| */ |
| |
| |
| /*>>core*/ |
| |
| /*>>inline*/ |
| |
| var INLINE_NS = 'inline', |
| _hiddenClass, |
| _inlinePlaceholder, |
| _lastInlineElement, |
| _putInlineElementsBack = function() { |
| if(_lastInlineElement) { |
| _inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach(); |
| _lastInlineElement = null; |
| } |
| }; |
| |
| $.magnificPopup.registerModule(INLINE_NS, { |
| options: { |
| hiddenClass: 'hide', // will be appended with `mfp-` prefix |
| markup: '', |
| tNotFound: 'Content not found' |
| }, |
| proto: { |
| |
| initInline: function() { |
| mfp.types.push(INLINE_NS); |
| |
| _mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() { |
| _putInlineElementsBack(); |
| }); |
| }, |
| |
| getInline: function(item, template) { |
| |
| _putInlineElementsBack(); |
| |
| if(item.src) { |
| var inlineSt = mfp.st.inline, |
| el = $(item.src); |
| |
| if(el.length) { |
| |
| // If target element has parent - we replace it with placeholder and put it back after popup is closed |
| var parent = el[0].parentNode; |
| if(parent && parent.tagName) { |
| if(!_inlinePlaceholder) { |
| _hiddenClass = inlineSt.hiddenClass; |
| _inlinePlaceholder = _getEl(_hiddenClass); |
| _hiddenClass = 'mfp-'+_hiddenClass; |
| } |
| // replace target inline element with placeholder |
| _lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass); |
| } |
| |
| mfp.updateStatus('ready'); |
| } else { |
| mfp.updateStatus('error', inlineSt.tNotFound); |
| el = $('<div>'); |
| } |
| |
| item.inlineElement = el; |
| return el; |
| } |
| |
| mfp.updateStatus('ready'); |
| mfp._parseMarkup(template, {}, item); |
| return template; |
| } |
| } |
| }); |
| |
| /*>>inline*/ |
| |
| /*>>ajax*/ |
| var AJAX_NS = 'ajax', |
| _ajaxCur, |
| _removeAjaxCursor = function() { |
| if(_ajaxCur) { |
| _body.removeClass(_ajaxCur); |
| } |
| }; |
| |
| $.magnificPopup.registerModule(AJAX_NS, { |
| |
| options: { |
| settings: null, |
| cursor: 'mfp-ajax-cur', |
| tError: '<a href="%url%">The content</a> could not be loaded.' |
| }, |
| |
| proto: { |
| initAjax: function() { |
| mfp.types.push(AJAX_NS); |
| _ajaxCur = mfp.st.ajax.cursor; |
| |
| _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, function() { |
| _removeAjaxCursor(); |
| if(mfp.req) { |
| mfp.req.abort(); |
| } |
| }); |
| }, |
| |
| getAjax: function(item) { |
| |
| if(_ajaxCur) |
| _body.addClass(_ajaxCur); |
| |
| mfp.updateStatus('loading'); |
| |
| var opts = $.extend({ |
| url: item.src, |
| success: function(data, textStatus, jqXHR) { |
| var temp = { |
| data:data, |
| xhr:jqXHR |
| }; |
| |
| _mfpTrigger('ParseAjax', temp); |
| |
| mfp.appendContent( $(temp.data), AJAX_NS ); |
| |
| item.finished = true; |
| |
| _removeAjaxCursor(); |
| |
| _setFocus(); |
| |
| setTimeout(function() { |
| mfp.wrap.addClass(READY_CLASS); |
| }, 16); |
| |
| mfp.updateStatus('ready'); |
| |
| _mfpTrigger('AjaxContentAdded'); |
| }, |
| error: function() { |
| _removeAjaxCursor(); |
| item.finished = item.loadError = true; |
| mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src)); |
| } |
| }, mfp.st.ajax.settings); |
| |
| mfp.req = $.ajax(opts); |
| |
| return ''; |
| } |
| } |
| }); |
| |
| |
| |
| |
| |
| |
| |
| /*>>ajax*/ |
| |
| /*>>image*/ |
| var _imgInterval, |
| _getTitle = function(item) { |
| if(item.data && item.data.title !== undefined) |
| return item.data.title; |
| |
| var src = mfp.st.image.titleSrc; |
| |
| if(src) { |
| if($.isFunction(src)) { |
| return src.call(mfp, item); |
| } else if(item.el) { |
| return item.el.attr(src) || ''; |
| } |
| } |
| return ''; |
| }; |
| |
| $.magnificPopup.registerModule('image', { |
| |
| options: { |
| markup: '<div class="mfp-figure">'+ |
| '<div class="mfp-close"></div>'+ |
| '<div class="mfp-img"></div>'+ |
| '<div class="mfp-bottom-bar">'+ |
| '<div class="mfp-title"></div>'+ |
| '<div class="mfp-counter"></div>'+ |
| '</div>'+ |
| '</div>', |
| cursor: 'mfp-zoom-out-cur', |
| titleSrc: 'title', |
| verticalFit: true, |
| tError: '<a href="%url%">The image</a> could not be loaded.' |
| }, |
| |
| proto: { |
| initImage: function() { |
| var imgSt = mfp.st.image, |
| ns = '.image'; |
| |
| mfp.types.push('image'); |
| |
| _mfpOn(OPEN_EVENT+ns, function() { |
| if(mfp.currItem.type === 'image' && imgSt.cursor) { |
| _body.addClass(imgSt.cursor); |
| } |
| }); |
| |
| _mfpOn(CLOSE_EVENT+ns, function() { |
| if(imgSt.cursor) { |
| _body.removeClass(imgSt.cursor); |
| } |
| _window.off('resize' + EVENT_NS); |
| }); |
| |
| _mfpOn('Resize'+ns, mfp.resizeImage); |
| if(mfp.isLowIE) { |
| _mfpOn('AfterChange', mfp.resizeImage); |
| } |
| }, |
| resizeImage: function() { |
| var item = mfp.currItem; |
| if(!item.img) return; |
| |
| if(mfp.st.image.verticalFit) { |
| var decr = 0; |
| // fix box-sizing in ie7/8 |
| if(mfp.isLowIE) { |
| decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10); |
| } |
| item.img.css('max-height', mfp.wH-decr); |
| } |
| }, |
| _onImageHasSize: function(item) { |
| if(item.img) { |
| |
| item.hasSize = true; |
| |
| if(_imgInterval) { |
| clearInterval(_imgInterval); |
| } |
| |
| item.isCheckingImgSize = false; |
| |
| _mfpTrigger('ImageHasSize', item); |
| |
| if(item.imgHidden) { |
| if(mfp.content) |
| mfp.content.removeClass('mfp-loading'); |
| |
| item.imgHidden = false; |
| } |
| |
| } |
| }, |
| |
| /** |
| * Function that loops until the image has size to display elements that rely on it asap |
| */ |
| findImageSize: function(item) { |
| |
| var counter = 0, |
| img = item.img[0], |
| mfpSetInterval = function(delay) { |
| |
| if(_imgInterval) { |
| clearInterval(_imgInterval); |
| } |
| // decelerating interval that checks for size of an image |
| _imgInterval = setInterval(function() { |
| if(img.naturalWidth > 0) { |
| mfp._onImageHasSize(item); |
| return; |
| } |
| |
| if(counter > 200) { |
| clearInterval(_imgInterval); |
| } |
| |
| counter++; |
| if(counter === 3) { |
| mfpSetInterval(10); |
| } else if(counter === 40) { |
| mfpSetInterval(50); |
| } else if(counter === 100) { |
| mfpSetInterval(500); |
| } |
| }, delay); |
| }; |
| |
| mfpSetInterval(1); |
| }, |
| |
| getImage: function(item, template) { |
| |
| var guard = 0, |
| |
| // image load complete handler |
| onLoadComplete = function() { |
| if(item) { |
| if (item.img[0].complete) { |
| item.img.off('.mfploader'); |
| |
| if(item === mfp.currItem){ |
| mfp._onImageHasSize(item); |
| |
| mfp.updateStatus('ready'); |
| } |
| |
| item.hasSize = true; |
| item.loaded = true; |
| |
| _mfpTrigger('ImageLoadComplete'); |
| |
| } |
| else { |
| // if image complete check fails 200 times (20 sec), we assume that there was an error. |
| guard++; |
| if(guard < 200) { |
| setTimeout(onLoadComplete,100); |
| } else { |
| onLoadError(); |
| } |
| } |
| } |
| }, |
| |
| // image error handler |
| onLoadError = function() { |
| if(item) { |
| item.img.off('.mfploader'); |
| if(item === mfp.currItem){ |
| mfp._onImageHasSize(item); |
| mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) ); |
| } |
| |
| item.hasSize = true; |
| item.loaded = true; |
| item.loadError = true; |
| } |
| }, |
| imgSt = mfp.st.image; |
| |
| |
| var el = template.find('.mfp-img'); |
| if(el.length) { |
| var img = new Image(); |
| img.className = 'mfp-img'; |
| item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError); |
| img.src = item.src; |
| |
| // without clone() "error" event is not firing when IMG is replaced by new IMG |
| // TODO: find a way to avoid such cloning |
| if(el.is('img')) { |
| item.img = item.img.clone(); |
| } |
| if(item.img[0].naturalWidth > 0) { |
| item.hasSize = true; |
| } |
| } |
| |
| mfp._parseMarkup(template, { |
| title: _getTitle(item), |
| img_replaceWith: item.img |
| }, item); |
| |
| mfp.resizeImage(); |
| |
| if(item.hasSize) { |
| if(_imgInterval) clearInterval(_imgInterval); |
| |
| if(item.loadError) { |
| template.addClass('mfp-loading'); |
| mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) ); |
| } else { |
| template.removeClass('mfp-loading'); |
| mfp.updateStatus('ready'); |
| } |
| return template; |
| } |
| |
| mfp.updateStatus('loading'); |
| item.loading = true; |
| |
| if(!item.hasSize) { |
| item.imgHidden = true; |
| template.addClass('mfp-loading'); |
| mfp.findImageSize(item); |
| } |
| |
| return template; |
| } |
| } |
| }); |
| |
| |
| |
| /*>>image*/ |
| |
| /*>>zoom*/ |
| 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'; |
| |
| 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(); |
| } |
| } |
| }); |
| }, |
| |
| _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; |
| } |
| |
| } |
| }); |
| |
| |
| |
| /*>>zoom*/ |
| |
| /*>>iframe*/ |
| |
| var IFRAME_NS = 'iframe', |
| _emptyPage = '//about:blank', |
| |
| _fixIframeBugs = function(isShowing) { |
| if(mfp.currTemplate[IFRAME_NS]) { |
| var el = mfp.currTemplate[IFRAME_NS].find('iframe'); |
| if(el.length) { |
| // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug |
| if(!isShowing) { |
| el[0].src = _emptyPage; |
| } |
| |
| // IE8 black screen bug fix |
| if(mfp.isIE8) { |
| el.css('display', isShowing ? 'block' : 'none'); |
| } |
| } |
| } |
| }; |
| |
| $.magnificPopup.registerModule(IFRAME_NS, { |
| |
| options: { |
| markup: '<div class="mfp-iframe-scaler">'+ |
| '<div class="mfp-close"></div>'+ |
| '<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+ |
| '</div>', |
| |
| srcAction: 'iframe_src', |
| |
| // we don't care and support only one default type of URL by default |
| patterns: { |
| youtube: { |
| index: 'youtube.com', |
| id: 'v=', |
| src: '//www.youtube.com/embed/%id%?autoplay=1' |
| }, |
| vimeo: { |
| index: 'vimeo.com/', |
| id: '/', |
| src: '//player.vimeo.com/video/%id%?autoplay=1' |
| }, |
| gmaps: { |
| index: '//maps.google.', |
| src: '%id%&output=embed' |
| } |
| } |
| }, |
| |
| proto: { |
| initIframe: function() { |
| mfp.types.push(IFRAME_NS); |
| |
| _mfpOn('BeforeChange', function(e, prevType, newType) { |
| if(prevType !== newType) { |
| if(prevType === IFRAME_NS) { |
| _fixIframeBugs(); // iframe if removed |
| } else if(newType === IFRAME_NS) { |
| _fixIframeBugs(true); // iframe is showing |
| } |
| }// else { |
| // iframe source is switched, don't do anything |
| //} |
| }); |
| |
| _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() { |
| _fixIframeBugs(); |
| }); |
| }, |
| |
| getIframe: function(item, template) { |
| var embedSrc = item.src; |
| var iframeSt = mfp.st.iframe; |
| |
| $.each(iframeSt.patterns, function() { |
| if(embedSrc.indexOf( this.index ) > -1) { |
| if(this.id) { |
| if(typeof this.id === 'string') { |
| embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length); |
| } else { |
| embedSrc = this.id.call( this, embedSrc ); |
| } |
| } |
| embedSrc = this.src.replace('%id%', embedSrc ); |
| return false; // break; |
| } |
| }); |
| |
| var dataObj = {}; |
| if(iframeSt.srcAction) { |
| dataObj[iframeSt.srcAction] = embedSrc; |
| } |
| mfp._parseMarkup(template, dataObj, item); |
| |
| mfp.updateStatus('ready'); |
| |
| return template; |
| } |
| } |
| }); |
| |
| |
| |
| /*>>iframe*/ |
| |
| /*>>gallery*/ |
| /** |
| * Get looped index depending on number of slides |
| */ |
| var _getLoopedId = function(index) { |
| var numSlides = mfp.items.length; |
| if(index > numSlides - 1) { |
| return index - numSlides; |
| } else if(index < 0) { |
| return numSlides + index; |
| } |
| return index; |
| }, |
| _replaceCurrTotal = function(text, curr, total) { |
| return text.replace('%curr%', curr + 1).replace('%total%', total); |
| }; |
| |
| $.magnificPopup.registerModule('gallery', { |
| |
| options: { |
| enabled: false, |
| arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>', |
| preload: [0,2], |
| navigateByImgClick: true, |
| arrows: true, |
| |
| tPrev: 'Previous (Left arrow key)', |
| tNext: 'Next (Right arrow key)', |
| tCounter: '%curr% of %total%' |
| }, |
| |
| proto: { |
| initGallery: function() { |
| |
| var gSt = mfp.st.gallery, |
| ns = '.mfp-gallery', |
| supportsFastClick = Boolean($.fn.mfpFastClick); |
| |
| mfp.direction = true; // true - next, false - prev |
| |
| if(!gSt || !gSt.enabled ) return false; |
| |
| _wrapClasses += ' mfp-gallery'; |
| |
| _mfpOn(OPEN_EVENT+ns, function() { |
| |
| if(gSt.navigateByImgClick) { |
| mfp.wrap.on('click'+ns, '.mfp-img', function() { |
| if(mfp.items.length > 1) { |
| mfp.next(); |
| return false; |
| } |
| }); |
| } |
| |
| _document.on('keydown'+ns, function(e) { |
| if (e.keyCode === 37) { |
| mfp.prev(); |
| } else if (e.keyCode === 39) { |
| mfp.next(); |
| } |
| }); |
| }); |
| |
| _mfpOn('UpdateStatus'+ns, function(e, data) { |
| if(data.text) { |
| data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length); |
| } |
| }); |
| |
| _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) { |
| var l = mfp.items.length; |
| values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : ''; |
| }); |
| |
| _mfpOn('BuildControls' + ns, function() { |
| if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) { |
| var markup = gSt.arrowMarkup, |
| arrowLeft = mfp.arrowLeft = $( markup.replace('%title%', gSt.tPrev).replace('%dir%', 'left') ).addClass(PREVENT_CLOSE_CLASS), |
| arrowRight = mfp.arrowRight = $( markup.replace('%title%', gSt.tNext).replace('%dir%', 'right') ).addClass(PREVENT_CLOSE_CLASS); |
| |
| var eName = supportsFastClick ? 'mfpFastClick' : 'click'; |
| arrowLeft[eName](function() { |
| mfp.prev(); |
| }); |
| arrowRight[eName](function() { |
| mfp.next(); |
| }); |
| |
| // Polyfill for :before and :after (adds elements with classes mfp-a and mfp-b) |
| if(mfp.isIE7) { |
| _getEl('b', arrowLeft[0], false, true); |
| _getEl('a', arrowLeft[0], false, true); |
| _getEl('b', arrowRight[0], false, true); |
| _getEl('a', arrowRight[0], false, true); |
| } |
| |
| mfp.container.append(arrowLeft.add(arrowRight)); |
| } |
| }); |
| |
| _mfpOn(CHANGE_EVENT+ns, function() { |
| if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout); |
| |
| mfp._preloadTimeout = setTimeout(function() { |
| mfp.preloadNearbyImages(); |
| mfp._preloadTimeout = null; |
| }, 16); |
| }); |
| |
| |
| _mfpOn(CLOSE_EVENT+ns, function() { |
| _document.off(ns); |
| mfp.wrap.off('click'+ns); |
| |
| if(mfp.arrowLeft && supportsFastClick) { |
| mfp.arrowLeft.add(mfp.arrowRight).destroyMfpFastClick(); |
| } |
| mfp.arrowRight = mfp.arrowLeft = null; |
| }); |
| |
| }, |
| next: function() { |
| mfp.direction = true; |
| mfp.index = _getLoopedId(mfp.index + 1); |
| mfp.updateItemHTML(); |
| }, |
| prev: function() { |
| mfp.direction = false; |
| mfp.index = _getLoopedId(mfp.index - 1); |
| mfp.updateItemHTML(); |
| }, |
| goTo: function(newIndex) { |
| mfp.direction = (newIndex >= mfp.index); |
| mfp.index = newIndex; |
| mfp.updateItemHTML(); |
| }, |
| preloadNearbyImages: function() { |
| var p = mfp.st.gallery.preload, |
| preloadBefore = Math.min(p[0], mfp.items.length), |
| preloadAfter = Math.min(p[1], mfp.items.length), |
| i; |
| |
| for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) { |
| mfp._preloadItem(mfp.index+i); |
| } |
| for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) { |
| mfp._preloadItem(mfp.index-i); |
| } |
| }, |
| _preloadItem: function(index) { |
| index = _getLoopedId(index); |
| |
| if(mfp.items[index].preloaded) { |
| return; |
| } |
| |
| var item = mfp.items[index]; |
| if(!item.parsed) { |
| item = mfp.parseEl( index ); |
| } |
| |
| _mfpTrigger('LazyLoad', item); |
| |
| if(item.type === 'image') { |
| item.img = $('<img class="mfp-img" />').on('load.mfploader', function() { |
| item.hasSize = true; |
| }).on('error.mfploader', function() { |
| item.hasSize = true; |
| item.loadError = true; |
| _mfpTrigger('LazyLoadError', item); |
| }).attr('src', item.src); |
| } |
| |
| |
| item.preloaded = true; |
| } |
| } |
| }); |
| |
| /* |
| Touch Support that might be implemented some day |
| |
| addSwipeGesture: function() { |
| var startX, |
| moved, |
| multipleTouches; |
| |
| return; |
| |
| var namespace = '.mfp', |
| addEventNames = function(pref, down, move, up, cancel) { |
| mfp._tStart = pref + down + namespace; |
| mfp._tMove = pref + move + namespace; |
| mfp._tEnd = pref + up + namespace; |
| mfp._tCancel = pref + cancel + namespace; |
| }; |
| |
| if(window.navigator.msPointerEnabled) { |
| addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel'); |
| } else if('ontouchstart' in window) { |
| addEventNames('touch', 'start', 'move', 'end', 'cancel'); |
| } else { |
| return; |
| } |
| _window.on(mfp._tStart, function(e) { |
| var oE = e.originalEvent; |
| multipleTouches = moved = false; |
| startX = oE.pageX || oE.changedTouches[0].pageX; |
| }).on(mfp._tMove, function(e) { |
| if(e.originalEvent.touches.length > 1) { |
| multipleTouches = e.originalEvent.touches.length; |
| } else { |
| //e.preventDefault(); |
| moved = true; |
| } |
| }).on(mfp._tEnd + ' ' + mfp._tCancel, function(e) { |
| if(moved && !multipleTouches) { |
| var oE = e.originalEvent, |
| diff = startX - (oE.pageX || oE.changedTouches[0].pageX); |
| |
| if(diff > 20) { |
| mfp.next(); |
| } else if(diff < -20) { |
| mfp.prev(); |
| } |
| } |
| }); |
| }, |
| */ |
| |
| |
| /*>>gallery*/ |
| |
| /*>>retina*/ |
| |
| var RETINA_NS = 'retina'; |
| |
| $.magnificPopup.registerModule(RETINA_NS, { |
| options: { |
| replaceSrc: function(item) { |
| return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; }); |
| }, |
| ratio: 1 // Function or number. Set to 1 to disable. |
| }, |
| proto: { |
| initRetina: function() { |
| if(window.devicePixelRatio > 1) { |
| |
| var st = mfp.st.retina, |
| ratio = st.ratio; |
| |
| ratio = !isNaN(ratio) ? ratio : ratio(); |
| |
| if(ratio > 1) { |
| _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) { |
| item.img.css({ |
| 'max-width': item.img[0].naturalWidth / ratio, |
| 'width': '100%' |
| }); |
| }); |
| _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) { |
| item.src = st.replaceSrc(item, ratio); |
| }); |
| } |
| } |
| |
| } |
| } |
| }); |
| |
| /*>>retina*/ |
| |
| /*>>fastclick*/ |
| /** |
| * FastClick event implementation. (removes 300ms delay on touch devices) |
| * Based on https://developers.google.com/mobile/articles/fast_buttons |
| * |
| * You may use it outside the Magnific Popup by calling just: |
| * |
| * $('.your-el').mfpFastClick(function() { |
| * console.log('Clicked!'); |
| * }); |
| * |
| * To unbind: |
| * $('.your-el').destroyMfpFastClick(); |
| * |
| * |
| * Note that it's a very basic and simple implementation, it blocks ghost click on the same element where it was bound. |
| * If you need something more advanced, use plugin by FT Labs https://github.com/ftlabs/fastclick |
| * |
| */ |
| |
| (function() { |
| var ghostClickDelay = 1000, |
| supportsTouch = 'ontouchstart' in window, |
| unbindTouchMove = function() { |
| _window.off('touchmove'+ns+' touchend'+ns); |
| }, |
| eName = 'mfpFastClick', |
| ns = '.'+eName; |
| |
| |
| // As Zepto.js doesn't have an easy way to add custom events (like jQuery), so we implement it in this way |
| $.fn.mfpFastClick = function(callback) { |
| |
| return $(this).each(function() { |
| |
| var elem = $(this), |
| lock; |
| |
| if( supportsTouch ) { |
| |
| var timeout, |
| startX, |
| startY, |
| pointerMoved, |
| point, |
| numPointers; |
| |
| elem.on('touchstart' + ns, function(e) { |
| pointerMoved = false; |
| numPointers = 1; |
| |
| point = e.originalEvent ? e.originalEvent.touches[0] : e.touches[0]; |
| startX = point.clientX; |
| startY = point.clientY; |
| |
| _window.on('touchmove'+ns, function(e) { |
| point = e.originalEvent ? e.originalEvent.touches : e.touches; |
| numPointers = point.length; |
| point = point[0]; |
| if (Math.abs(point.clientX - startX) > 10 || |
| Math.abs(point.clientY - startY) > 10) { |
| pointerMoved = true; |
| unbindTouchMove(); |
| } |
| }).on('touchend'+ns, function(e) { |
| unbindTouchMove(); |
| if(pointerMoved || numPointers > 1) { |
| return; |
| } |
| lock = true; |
| e.preventDefault(); |
| clearTimeout(timeout); |
| timeout = setTimeout(function() { |
| lock = false; |
| }, ghostClickDelay); |
| callback(); |
| }); |
| }); |
| |
| } |
| |
| elem.on('click' + ns, function() { |
| if(!lock) { |
| callback(); |
| } |
| }); |
| }); |
| }; |
| |
| $.fn.destroyMfpFastClick = function() { |
| $(this).off('touchstart' + ns + ' click' + ns); |
| if(supportsTouch) _window.off('touchmove'+ns+' touchend'+ns); |
| }; |
| })(); |
| |
| /*>>fastclick*/ |
| })(window.jQuery || window.Zepto); |