/*! magnific popup - v0.9.9 - 2013-11-15 * 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]); } } }, _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; } }, // 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(mfp._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.marginright = 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 margin 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); mfp._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, mfp._onfocusin); }, 16); mfp.isopen = true; mfp.updatesize(windowheight); _mfptrigger(open_event); return data; }, /** * 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 = {marginright: ''}; 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).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 */ // 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; }, _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()) ); }, _setfocus: function() { (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus(); }, _onfocusin: function(e) { if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) { mfp._setfocus(); return false; } }, _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( '' ); } } 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 = {}; } else { options = $.extend(true, {}, options); } options.isobj = true; options.index = index || 0; return this.instance.open(options); }, close: function() { return $.magnificpopup.instance && $.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: '', 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 { // clone options obj options = $.extend(true, {}, options); /* * 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 = $('
'); } 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); } }, _destroyajaxrequest = function() { _removeajaxcursor(); if(mfp.req) { mfp.req.abort(); } }; $.magnificpopup.registermodule(ajax_ns, { options: { settings: null, cursor: 'mfp-ajax-cur', terror: 'the content could not be loaded.' }, proto: { initajax: function() { mfp.types.push(ajax_ns); _ajaxcur = mfp.st.ajax.cursor; _mfpon(close_event+'.'+ajax_ns, _destroyajaxrequest); _mfpon('beforechange.' + ajax_ns, _destroyajaxrequest); }, 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(); mfp._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: '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
', cursor: 'mfp-zoom-out-cur', titlesrc: 'title', verticalfit: true, terror: 'the image 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 || !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 = document.createelement('img'); 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', 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; } } }); /*>>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: '
'+ '
'+ ''+ '
', 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%/gi, curr + 1).replace(/%total%/gi, total); }; $.magnificpopup.registermodule('gallery', { options: { enabled: false, arrowmarkup: '', 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%/gi, gst.tprev).replace(/%dir%/gi, 'left') ).addclass(prevent_close_class), arrowright = mfp.arrowright = $( markup.replace(/%title%/gi, gst.tnext).replace(/%dir%/gi, '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 = $('').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*/ _checkinstance(); })(window.jquery || window.zepto);