jquery.magnific-popup.js 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864
  1. /*!
  2. Magnific Popup
  3. Version: 1.1.0 - 2016-02-20
  4. Plugin URL: http://dimsemenov.com/plugins/magnific-popup/
  5. License: Copyright (c) 2016 Dmitry Semenov
  6. !*/
  7. (function (factory) {
  8. if (typeof define === 'function' && define.amd) {
  9. // AMD. Register as an anonymous module.
  10. define(['jquery'], factory);
  11. } else if (typeof exports === 'object') {
  12. // Node/CommonJS
  13. factory(require('jquery'));
  14. } else {
  15. // Browser globals
  16. factory(window.jQuery || window.Zepto);
  17. }
  18. }(function($) {
  19. /*>>core*/
  20. /**
  21. *
  22. * Magnific Popup Core JS file
  23. *
  24. */
  25. /**
  26. * Private static constants
  27. */
  28. var CLOSE_EVENT = 'Close',
  29. BEFORE_CLOSE_EVENT = 'BeforeClose',
  30. AFTER_CLOSE_EVENT = 'AfterClose',
  31. BEFORE_APPEND_EVENT = 'BeforeAppend',
  32. MARKUP_PARSE_EVENT = 'MarkupParse',
  33. OPEN_EVENT = 'Open',
  34. CHANGE_EVENT = 'Change',
  35. NS = 'mfp',
  36. EVENT_NS = '.' + NS,
  37. READY_CLASS = 'mfp-ready',
  38. REMOVING_CLASS = 'mfp-removing',
  39. PREVENT_CLOSE_CLASS = 'mfp-prevent-close';
  40. /**
  41. * Private vars
  42. */
  43. /*jshint -W079 */
  44. var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this'
  45. MagnificPopup = function(){},
  46. _isJQ = !!(window.jQuery),
  47. _prevStatus,
  48. _window = $(window),
  49. _document,
  50. _prevContentType,
  51. _wrapClasses,
  52. _currPopupType;
  53. /**
  54. * Private functions
  55. */
  56. var _mfpOn = function(name, f) {
  57. mfp.ev.on(NS + name + EVENT_NS, f);
  58. },
  59. _getEl = function(className, appendTo, html, raw) {
  60. var el = document.createElement('div');
  61. el.className = 'mfp-'+className;
  62. if(html) {
  63. el.innerHTML = html;
  64. }
  65. if(!raw) {
  66. el = $(el);
  67. if(appendTo) {
  68. el.appendTo(appendTo);
  69. }
  70. } else if(appendTo) {
  71. appendTo.appendChild(el);
  72. }
  73. return el;
  74. },
  75. _mfpTrigger = function(e, data) {
  76. mfp.ev.triggerHandler(NS + e, data);
  77. if(mfp.st.callbacks) {
  78. // converts "mfpEventName" to "eventName" callback and triggers it if it's present
  79. e = e.charAt(0).toLowerCase() + e.slice(1);
  80. if(mfp.st.callbacks[e]) {
  81. mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]);
  82. }
  83. }
  84. },
  85. _getCloseBtn = function(type) {
  86. if(type !== _currPopupType || !mfp.currTemplate.closeBtn) {
  87. mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) );
  88. _currPopupType = type;
  89. }
  90. return mfp.currTemplate.closeBtn;
  91. },
  92. // Initialize Magnific Popup only when called at least once
  93. _checkInstance = function() {
  94. if(!$.magnificPopup.instance) {
  95. /*jshint -W020 */
  96. mfp = new MagnificPopup();
  97. mfp.init();
  98. $.magnificPopup.instance = mfp;
  99. }
  100. },
  101. // CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
  102. supportsTransitions = function() {
  103. var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist
  104. v = ['ms','O','Moz','Webkit']; // 'v' for vendor
  105. if( s['transition'] !== undefined ) {
  106. return true;
  107. }
  108. while( v.length ) {
  109. if( v.pop() + 'Transition' in s ) {
  110. return true;
  111. }
  112. }
  113. return false;
  114. };
  115. /**
  116. * Public functions
  117. */
  118. MagnificPopup.prototype = {
  119. constructor: MagnificPopup,
  120. /**
  121. * Initializes Magnific Popup plugin.
  122. * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed
  123. */
  124. init: function() {
  125. var appVersion = navigator.appVersion;
  126. mfp.isLowIE = mfp.isIE8 = document.all && !document.addEventListener;
  127. mfp.isAndroid = (/android/gi).test(appVersion);
  128. mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion);
  129. mfp.supportsTransition = supportsTransitions();
  130. // We disable fixed positioned lightbox on devices that don't handle it nicely.
  131. // If you know a better way of detecting this - let me know.
  132. mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) );
  133. _document = $(document);
  134. mfp.popupsCache = {};
  135. },
  136. /**
  137. * Opens popup
  138. * @param data [description]
  139. */
  140. open: function(data) {
  141. var i;
  142. if(data.isObj === false) {
  143. // convert jQuery collection to array to avoid conflicts later
  144. mfp.items = data.items.toArray();
  145. mfp.index = 0;
  146. var items = data.items,
  147. item;
  148. for(i = 0; i < items.length; i++) {
  149. item = items[i];
  150. if(item.parsed) {
  151. item = item.el[0];
  152. }
  153. if(item === data.el[0]) {
  154. mfp.index = i;
  155. break;
  156. }
  157. }
  158. } else {
  159. mfp.items = $.isArray(data.items) ? data.items : [data.items];
  160. mfp.index = data.index || 0;
  161. }
  162. // if popup is already opened - we just update the content
  163. if(mfp.isOpen) {
  164. mfp.updateItemHTML();
  165. return;
  166. }
  167. mfp.types = [];
  168. _wrapClasses = '';
  169. if(data.mainEl && data.mainEl.length) {
  170. mfp.ev = data.mainEl.eq(0);
  171. } else {
  172. mfp.ev = _document;
  173. }
  174. if(data.key) {
  175. if(!mfp.popupsCache[data.key]) {
  176. mfp.popupsCache[data.key] = {};
  177. }
  178. mfp.currTemplate = mfp.popupsCache[data.key];
  179. } else {
  180. mfp.currTemplate = {};
  181. }
  182. mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data );
  183. mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos;
  184. if(mfp.st.modal) {
  185. mfp.st.closeOnContentClick = false;
  186. mfp.st.closeOnBgClick = false;
  187. mfp.st.showCloseBtn = false;
  188. mfp.st.enableEscapeKey = false;
  189. }
  190. // Building markup
  191. // main containers are created only once
  192. if(!mfp.bgOverlay) {
  193. // Dark overlay
  194. mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() {
  195. mfp.close();
  196. });
  197. mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) {
  198. if(mfp._checkIfClose(e.target)) {
  199. mfp.close();
  200. }
  201. });
  202. mfp.container = _getEl('container', mfp.wrap);
  203. }
  204. mfp.contentContainer = _getEl('content');
  205. if(mfp.st.preloader) {
  206. mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading);
  207. }
  208. // Initializing modules
  209. var modules = $.magnificPopup.modules;
  210. for(i = 0; i < modules.length; i++) {
  211. var n = modules[i];
  212. n = n.charAt(0).toUpperCase() + n.slice(1);
  213. mfp['init'+n].call(mfp);
  214. }
  215. _mfpTrigger('BeforeOpen');
  216. if(mfp.st.showCloseBtn) {
  217. // Close button
  218. if(!mfp.st.closeBtnInside) {
  219. mfp.wrap.append( _getCloseBtn() );
  220. } else {
  221. _mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) {
  222. values.close_replaceWith = _getCloseBtn(item.type);
  223. });
  224. _wrapClasses += ' mfp-close-btn-in';
  225. }
  226. }
  227. if(mfp.st.alignTop) {
  228. _wrapClasses += ' mfp-align-top';
  229. }
  230. if(mfp.fixedContentPos) {
  231. mfp.wrap.css({
  232. overflow: mfp.st.overflowY,
  233. overflowX: 'hidden',
  234. overflowY: mfp.st.overflowY
  235. });
  236. } else {
  237. mfp.wrap.css({
  238. top: _window.scrollTop(),
  239. position: 'absolute'
  240. });
  241. }
  242. if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) {
  243. mfp.bgOverlay.css({
  244. height: _document.height(),
  245. position: 'absolute'
  246. });
  247. }
  248. if(mfp.st.enableEscapeKey) {
  249. // Close on ESC key
  250. _document.on('keyup' + EVENT_NS, function(e) {
  251. if(e.keyCode === 27) {
  252. mfp.close();
  253. }
  254. });
  255. }
  256. _window.on('resize' + EVENT_NS, function() {
  257. mfp.updateSize();
  258. });
  259. if(!mfp.st.closeOnContentClick) {
  260. _wrapClasses += ' mfp-auto-cursor';
  261. }
  262. if(_wrapClasses)
  263. mfp.wrap.addClass(_wrapClasses);
  264. // this triggers recalculation of layout, so we get it once to not to trigger twice
  265. var windowHeight = mfp.wH = _window.height();
  266. var windowStyles = {};
  267. if( mfp.fixedContentPos ) {
  268. if(mfp._hasScrollBar(windowHeight)){
  269. var s = mfp._getScrollbarSize();
  270. if(s) {
  271. windowStyles.marginRight = s;
  272. }
  273. }
  274. }
  275. if(mfp.fixedContentPos) {
  276. if(!mfp.isIE7) {
  277. windowStyles.overflow = 'hidden';
  278. } else {
  279. // ie7 double-scroll bug
  280. $('body, html').css('overflow', 'hidden');
  281. }
  282. }
  283. var classesToadd = mfp.st.mainClass;
  284. if(mfp.isIE7) {
  285. classesToadd += ' mfp-ie7';
  286. }
  287. if(classesToadd) {
  288. mfp._addClassToMFP( classesToadd );
  289. }
  290. // add content
  291. mfp.updateItemHTML();
  292. _mfpTrigger('BuildControls');
  293. // remove scrollbar, add margin e.t.c
  294. $('html').css(windowStyles);
  295. // add everything to DOM
  296. mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || $(document.body) );
  297. // Save last focused element
  298. mfp._lastFocusedEl = document.activeElement;
  299. // Wait for next cycle to allow CSS transition
  300. setTimeout(function() {
  301. if(mfp.content) {
  302. mfp._addClassToMFP(READY_CLASS);
  303. mfp._setFocus();
  304. } else {
  305. // if content is not defined (not loaded e.t.c) we add class only for BG
  306. mfp.bgOverlay.addClass(READY_CLASS);
  307. }
  308. // Trap the focus in popup
  309. _document.on('focusin' + EVENT_NS, mfp._onFocusIn);
  310. }, 16);
  311. mfp.isOpen = true;
  312. mfp.updateSize(windowHeight);
  313. _mfpTrigger(OPEN_EVENT);
  314. return data;
  315. },
  316. /**
  317. * Closes the popup
  318. */
  319. close: function() {
  320. if(!mfp.isOpen) return;
  321. _mfpTrigger(BEFORE_CLOSE_EVENT);
  322. mfp.isOpen = false;
  323. // for CSS3 animation
  324. if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition ) {
  325. mfp._addClassToMFP(REMOVING_CLASS);
  326. setTimeout(function() {
  327. mfp._close();
  328. }, mfp.st.removalDelay);
  329. } else {
  330. mfp._close();
  331. }
  332. },
  333. /**
  334. * Helper for close() function
  335. */
  336. _close: function() {
  337. _mfpTrigger(CLOSE_EVENT);
  338. var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' ';
  339. mfp.bgOverlay.detach();
  340. mfp.wrap.detach();
  341. mfp.container.empty();
  342. if(mfp.st.mainClass) {
  343. classesToRemove += mfp.st.mainClass + ' ';
  344. }
  345. mfp._removeClassFromMFP(classesToRemove);
  346. if(mfp.fixedContentPos) {
  347. var windowStyles = {marginRight: ''};
  348. if(mfp.isIE7) {
  349. $('body, html').css('overflow', '');
  350. } else {
  351. windowStyles.overflow = '';
  352. }
  353. $('html').css(windowStyles);
  354. }
  355. _document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS);
  356. mfp.ev.off(EVENT_NS);
  357. // clean up DOM elements that aren't removed
  358. mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style');
  359. mfp.bgOverlay.attr('class', 'mfp-bg');
  360. mfp.container.attr('class', 'mfp-container');
  361. // remove close button from target element
  362. if(mfp.st.showCloseBtn &&
  363. (!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) {
  364. if(mfp.currTemplate.closeBtn)
  365. mfp.currTemplate.closeBtn.detach();
  366. }
  367. if(mfp.st.autoFocusLast && mfp._lastFocusedEl) {
  368. $(mfp._lastFocusedEl).focus(); // put tab focus back
  369. }
  370. mfp.currItem = null;
  371. mfp.content = null;
  372. mfp.currTemplate = null;
  373. mfp.prevHeight = 0;
  374. _mfpTrigger(AFTER_CLOSE_EVENT);
  375. },
  376. updateSize: function(winHeight) {
  377. if(mfp.isIOS) {
  378. // fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2
  379. var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
  380. var height = window.innerHeight * zoomLevel;
  381. mfp.wrap.css('height', height);
  382. mfp.wH = height;
  383. } else {
  384. mfp.wH = winHeight || _window.height();
  385. }
  386. // Fixes #84: popup incorrectly positioned with position:relative on body
  387. if(!mfp.fixedContentPos) {
  388. mfp.wrap.css('height', mfp.wH);
  389. }
  390. _mfpTrigger('Resize');
  391. },
  392. /**
  393. * Set content of popup based on current index
  394. */
  395. updateItemHTML: function() {
  396. var item = mfp.items[mfp.index];
  397. // Detach and perform modifications
  398. mfp.contentContainer.detach();
  399. if(mfp.content)
  400. mfp.content.detach();
  401. if(!item.parsed) {
  402. item = mfp.parseEl( mfp.index );
  403. }
  404. var type = item.type;
  405. _mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]);
  406. // BeforeChange event works like so:
  407. // _mfpOn('BeforeChange', function(e, prevType, newType) { });
  408. mfp.currItem = item;
  409. if(!mfp.currTemplate[type]) {
  410. var markup = mfp.st[type] ? mfp.st[type].markup : false;
  411. // allows to modify markup
  412. _mfpTrigger('FirstMarkupParse', markup);
  413. if(markup) {
  414. mfp.currTemplate[type] = $(markup);
  415. } else {
  416. // if there is no markup found we just define that template is parsed
  417. mfp.currTemplate[type] = true;
  418. }
  419. }
  420. if(_prevContentType && _prevContentType !== item.type) {
  421. mfp.container.removeClass('mfp-'+_prevContentType+'-holder');
  422. }
  423. var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]);
  424. mfp.appendContent(newContent, type);
  425. item.preloaded = true;
  426. _mfpTrigger(CHANGE_EVENT, item);
  427. _prevContentType = item.type;
  428. // Append container back after its content changed
  429. mfp.container.prepend(mfp.contentContainer);
  430. _mfpTrigger('AfterChange');
  431. },
  432. /**
  433. * Set HTML content of popup
  434. */
  435. appendContent: function(newContent, type) {
  436. mfp.content = newContent;
  437. if(newContent) {
  438. if(mfp.st.showCloseBtn && mfp.st.closeBtnInside &&
  439. mfp.currTemplate[type] === true) {
  440. // if there is no markup, we just append close button element inside
  441. if(!mfp.content.find('.mfp-close').length) {
  442. mfp.content.append(_getCloseBtn());
  443. }
  444. } else {
  445. mfp.content = newContent;
  446. }
  447. } else {
  448. mfp.content = '';
  449. }
  450. _mfpTrigger(BEFORE_APPEND_EVENT);
  451. mfp.container.addClass('mfp-'+type+'-holder');
  452. mfp.contentContainer.append(mfp.content);
  453. },
  454. /**
  455. * Creates Magnific Popup data object based on given data
  456. * @param {int} index Index of item to parse
  457. */
  458. parseEl: function(index) {
  459. var item = mfp.items[index],
  460. type;
  461. if(item.tagName) {
  462. item = { el: $(item) };
  463. } else {
  464. type = item.type;
  465. item = { data: item, src: item.src };
  466. }
  467. if(item.el) {
  468. var types = mfp.types;
  469. // check for 'mfp-TYPE' class
  470. for(var i = 0; i < types.length; i++) {
  471. if( item.el.hasClass('mfp-'+types[i]) ) {
  472. type = types[i];
  473. break;
  474. }
  475. }
  476. item.src = item.el.attr('data-mfp-src');
  477. if(!item.src) {
  478. item.src = item.el.attr('href');
  479. }
  480. }
  481. item.type = type || mfp.st.type || 'inline';
  482. item.index = index;
  483. item.parsed = true;
  484. mfp.items[index] = item;
  485. _mfpTrigger('ElementParse', item);
  486. return mfp.items[index];
  487. },
  488. /**
  489. * Initializes single popup or a group of popups
  490. */
  491. addGroup: function(el, options) {
  492. var eHandler = function(e) {
  493. e.mfpEl = this;
  494. mfp._openClick(e, el, options);
  495. };
  496. if(!options) {
  497. options = {};
  498. }
  499. var eName = 'click.magnificPopup';
  500. options.mainEl = el;
  501. if(options.items) {
  502. options.isObj = true;
  503. el.off(eName).on(eName, eHandler);
  504. } else {
  505. options.isObj = false;
  506. if(options.delegate) {
  507. el.off(eName).on(eName, options.delegate , eHandler);
  508. } else {
  509. options.items = el;
  510. el.off(eName).on(eName, eHandler);
  511. }
  512. }
  513. },
  514. _openClick: function(e, el, options) {
  515. var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick;
  516. if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey ) ) {
  517. return;
  518. }
  519. var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn;
  520. if(disableOn) {
  521. if($.isFunction(disableOn)) {
  522. if( !disableOn.call(mfp) ) {
  523. return true;
  524. }
  525. } else { // else it's number
  526. if( _window.width() < disableOn ) {
  527. return true;
  528. }
  529. }
  530. }
  531. if(e.type) {
  532. e.preventDefault();
  533. // This will prevent popup from closing if element is inside and popup is already opened
  534. if(mfp.isOpen) {
  535. e.stopPropagation();
  536. }
  537. }
  538. options.el = $(e.mfpEl);
  539. if(options.delegate) {
  540. options.items = el.find(options.delegate);
  541. }
  542. mfp.open(options);
  543. },
  544. /**
  545. * Updates text on preloader
  546. */
  547. updateStatus: function(status, text) {
  548. if(mfp.preloader) {
  549. if(_prevStatus !== status) {
  550. mfp.container.removeClass('mfp-s-'+_prevStatus);
  551. }
  552. if(!text && status === 'loading') {
  553. text = mfp.st.tLoading;
  554. }
  555. var data = {
  556. status: status,
  557. text: text
  558. };
  559. // allows to modify status
  560. _mfpTrigger('UpdateStatus', data);
  561. status = data.status;
  562. text = data.text;
  563. mfp.preloader.html(text);
  564. mfp.preloader.find('a').on('click', function(e) {
  565. e.stopImmediatePropagation();
  566. });
  567. mfp.container.addClass('mfp-s-'+status);
  568. _prevStatus = status;
  569. }
  570. },
  571. /*
  572. "Private" helpers that aren't private at all
  573. */
  574. // Check to close popup or not
  575. // "target" is an element that was clicked
  576. _checkIfClose: function(target) {
  577. if($(target).hasClass(PREVENT_CLOSE_CLASS)) {
  578. return;
  579. }
  580. var closeOnContent = mfp.st.closeOnContentClick;
  581. var closeOnBg = mfp.st.closeOnBgClick;
  582. if(closeOnContent && closeOnBg) {
  583. return true;
  584. } else {
  585. // We close the popup if click is on close button or on preloader. Or if there is no content.
  586. if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) {
  587. return true;
  588. }
  589. // if click is outside the content
  590. if( (target !== mfp.content[0] && !$.contains(mfp.content[0], target)) ) {
  591. if(closeOnBg) {
  592. // last check, if the clicked element is in DOM, (in case it's removed onclick)
  593. if( $.contains(document, target) ) {
  594. return true;
  595. }
  596. }
  597. } else if(closeOnContent) {
  598. return true;
  599. }
  600. }
  601. return false;
  602. },
  603. _addClassToMFP: function(cName) {
  604. mfp.bgOverlay.addClass(cName);
  605. mfp.wrap.addClass(cName);
  606. },
  607. _removeClassFromMFP: function(cName) {
  608. this.bgOverlay.removeClass(cName);
  609. mfp.wrap.removeClass(cName);
  610. },
  611. _hasScrollBar: function(winHeight) {
  612. return ( (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) );
  613. },
  614. _setFocus: function() {
  615. (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus();
  616. },
  617. _onFocusIn: function(e) {
  618. if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) {
  619. mfp._setFocus();
  620. return false;
  621. }
  622. },
  623. _parseMarkup: function(template, values, item) {
  624. var arr;
  625. if(item.data) {
  626. values = $.extend(item.data, values);
  627. }
  628. _mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] );
  629. $.each(values, function(key, value) {
  630. if(value === undefined || value === false) {
  631. return true;
  632. }
  633. arr = key.split('_');
  634. if(arr.length > 1) {
  635. var el = template.find(EVENT_NS + '-'+arr[0]);
  636. if(el.length > 0) {
  637. var attr = arr[1];
  638. if(attr === 'replaceWith') {
  639. if(el[0] !== value[0]) {
  640. el.replaceWith(value);
  641. }
  642. } else if(attr === 'img') {
  643. if(el.is('img')) {
  644. el.attr('src', value);
  645. } else {
  646. el.replaceWith( $('<img>').attr('src', value).attr('class', el.attr('class')) );
  647. }
  648. } else {
  649. el.attr(arr[1], value);
  650. }
  651. }
  652. } else {
  653. template.find(EVENT_NS + '-'+key).html(value);
  654. }
  655. });
  656. },
  657. _getScrollbarSize: function() {
  658. // thx David
  659. if(mfp.scrollbarSize === undefined) {
  660. var scrollDiv = document.createElement("div");
  661. scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
  662. document.body.appendChild(scrollDiv);
  663. mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  664. document.body.removeChild(scrollDiv);
  665. }
  666. return mfp.scrollbarSize;
  667. }
  668. }; /* MagnificPopup core prototype end */
  669. /**
  670. * Public static functions
  671. */
  672. $.magnificPopup = {
  673. instance: null,
  674. proto: MagnificPopup.prototype,
  675. modules: [],
  676. open: function(options, index) {
  677. _checkInstance();
  678. if(!options) {
  679. options = {};
  680. } else {
  681. options = $.extend(true, {}, options);
  682. }
  683. options.isObj = true;
  684. options.index = index || 0;
  685. return this.instance.open(options);
  686. },
  687. close: function() {
  688. return $.magnificPopup.instance && $.magnificPopup.instance.close();
  689. },
  690. registerModule: function(name, module) {
  691. if(module.options) {
  692. $.magnificPopup.defaults[name] = module.options;
  693. }
  694. $.extend(this.proto, module.proto);
  695. this.modules.push(name);
  696. },
  697. defaults: {
  698. // Info about options is in docs:
  699. // http://dimsemenov.com/plugins/magnific-popup/documentation.html#options
  700. disableOn: 0,
  701. key: null,
  702. midClick: false,
  703. mainClass: '',
  704. preloader: true,
  705. focus: '', // CSS selector of input to focus after popup is opened
  706. closeOnContentClick: false,
  707. closeOnBgClick: true,
  708. closeBtnInside: true,
  709. showCloseBtn: true,
  710. enableEscapeKey: true,
  711. modal: false,
  712. alignTop: false,
  713. removalDelay: 0,
  714. prependTo: null,
  715. fixedContentPos: 'auto',
  716. fixedBgPos: 'auto',
  717. overflowY: 'auto',
  718. closeMarkup: '<button title="%title%" type="button" class="mfp-close">&#215;</button>',
  719. tClose: 'Close (Esc)',
  720. tLoading: 'Loading...',
  721. autoFocusLast: true
  722. }
  723. };
  724. $.fn.magnificPopup = function(options) {
  725. _checkInstance();
  726. var jqEl = $(this);
  727. // We call some API method of first param is a string
  728. if (typeof options === "string" ) {
  729. if(options === 'open') {
  730. var items,
  731. itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup,
  732. index = parseInt(arguments[1], 10) || 0;
  733. if(itemOpts.items) {
  734. items = itemOpts.items[index];
  735. } else {
  736. items = jqEl;
  737. if(itemOpts.delegate) {
  738. items = items.find(itemOpts.delegate);
  739. }
  740. items = items.eq( index );
  741. }
  742. mfp._openClick({mfpEl:items}, jqEl, itemOpts);
  743. } else {
  744. if(mfp.isOpen)
  745. mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1));
  746. }
  747. } else {
  748. // clone options obj
  749. options = $.extend(true, {}, options);
  750. /*
  751. * As Zepto doesn't support .data() method for objects
  752. * and it works only in normal browsers
  753. * we assign "options" object directly to the DOM element. FTW!
  754. */
  755. if(_isJQ) {
  756. jqEl.data('magnificPopup', options);
  757. } else {
  758. jqEl[0].magnificPopup = options;
  759. }
  760. mfp.addGroup(jqEl, options);
  761. }
  762. return jqEl;
  763. };
  764. /*>>core*/
  765. /*>>inline*/
  766. var INLINE_NS = 'inline',
  767. _hiddenClass,
  768. _inlinePlaceholder,
  769. _lastInlineElement,
  770. _putInlineElementsBack = function() {
  771. if(_lastInlineElement) {
  772. _inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach();
  773. _lastInlineElement = null;
  774. }
  775. };
  776. $.magnificPopup.registerModule(INLINE_NS, {
  777. options: {
  778. hiddenClass: 'hide', // will be appended with `mfp-` prefix
  779. markup: '',
  780. tNotFound: 'Content not found'
  781. },
  782. proto: {
  783. initInline: function() {
  784. mfp.types.push(INLINE_NS);
  785. _mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() {
  786. _putInlineElementsBack();
  787. });
  788. },
  789. getInline: function(item, template) {
  790. _putInlineElementsBack();
  791. if(item.src) {
  792. var inlineSt = mfp.st.inline,
  793. el = $(item.src);
  794. if(el.length) {
  795. // If target element has parent - we replace it with placeholder and put it back after popup is closed
  796. var parent = el[0].parentNode;
  797. if(parent && parent.tagName) {
  798. if(!_inlinePlaceholder) {
  799. _hiddenClass = inlineSt.hiddenClass;
  800. _inlinePlaceholder = _getEl(_hiddenClass);
  801. _hiddenClass = 'mfp-'+_hiddenClass;
  802. }
  803. // replace target inline element with placeholder
  804. _lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass);
  805. }
  806. mfp.updateStatus('ready');
  807. } else {
  808. mfp.updateStatus('error', inlineSt.tNotFound);
  809. el = $('<div>');
  810. }
  811. item.inlineElement = el;
  812. return el;
  813. }
  814. mfp.updateStatus('ready');
  815. mfp._parseMarkup(template, {}, item);
  816. return template;
  817. }
  818. }
  819. });
  820. /*>>inline*/
  821. /*>>ajax*/
  822. var AJAX_NS = 'ajax',
  823. _ajaxCur,
  824. _removeAjaxCursor = function() {
  825. if(_ajaxCur) {
  826. $(document.body).removeClass(_ajaxCur);
  827. }
  828. },
  829. _destroyAjaxRequest = function() {
  830. _removeAjaxCursor();
  831. if(mfp.req) {
  832. mfp.req.abort();
  833. }
  834. };
  835. $.magnificPopup.registerModule(AJAX_NS, {
  836. options: {
  837. settings: null,
  838. cursor: 'mfp-ajax-cur',
  839. tError: '<a href="%url%">The content</a> could not be loaded.'
  840. },
  841. proto: {
  842. initAjax: function() {
  843. mfp.types.push(AJAX_NS);
  844. _ajaxCur = mfp.st.ajax.cursor;
  845. _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
  846. _mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
  847. },
  848. getAjax: function(item) {
  849. if(_ajaxCur) {
  850. $(document.body).addClass(_ajaxCur);
  851. }
  852. mfp.updateStatus('loading');
  853. var opts = $.extend({
  854. url: item.src,
  855. success: function(data, textStatus, jqXHR) {
  856. var temp = {
  857. data:data,
  858. xhr:jqXHR
  859. };
  860. _mfpTrigger('ParseAjax', temp);
  861. mfp.appendContent( $(temp.data), AJAX_NS );
  862. item.finished = true;
  863. _removeAjaxCursor();
  864. mfp._setFocus();
  865. setTimeout(function() {
  866. mfp.wrap.addClass(READY_CLASS);
  867. }, 16);
  868. mfp.updateStatus('ready');
  869. _mfpTrigger('AjaxContentAdded');
  870. },
  871. error: function() {
  872. _removeAjaxCursor();
  873. item.finished = item.loadError = true;
  874. mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
  875. }
  876. }, mfp.st.ajax.settings);
  877. mfp.req = $.ajax(opts);
  878. return '';
  879. }
  880. }
  881. });
  882. /*>>ajax*/
  883. /*>>image*/
  884. var _imgInterval,
  885. _getTitle = function(item) {
  886. if(item.data && item.data.title !== undefined)
  887. return item.data.title;
  888. var src = mfp.st.image.titleSrc;
  889. if(src) {
  890. if($.isFunction(src)) {
  891. return src.call(mfp, item);
  892. } else if(item.el) {
  893. return item.el.attr(src) || '';
  894. }
  895. }
  896. return '';
  897. };
  898. $.magnificPopup.registerModule('image', {
  899. options: {
  900. markup: '<div class="mfp-figure">'+
  901. '<div class="mfp-close"></div>'+
  902. '<figure>'+
  903. '<div class="mfp-img"></div>'+
  904. '<figcaption>'+
  905. '<div class="mfp-bottom-bar">'+
  906. '<div class="mfp-title"></div>'+
  907. '<div class="mfp-counter"></div>'+
  908. '</div>'+
  909. '</figcaption>'+
  910. '</figure>'+
  911. '</div>',
  912. cursor: 'mfp-zoom-out-cur',
  913. titleSrc: 'title',
  914. verticalFit: true,
  915. tError: '<a href="%url%">The image</a> could not be loaded.'
  916. },
  917. proto: {
  918. initImage: function() {
  919. var imgSt = mfp.st.image,
  920. ns = '.image';
  921. mfp.types.push('image');
  922. _mfpOn(OPEN_EVENT+ns, function() {
  923. if(mfp.currItem.type === 'image' && imgSt.cursor) {
  924. $(document.body).addClass(imgSt.cursor);
  925. }
  926. });
  927. _mfpOn(CLOSE_EVENT+ns, function() {
  928. if(imgSt.cursor) {
  929. $(document.body).removeClass(imgSt.cursor);
  930. }
  931. _window.off('resize' + EVENT_NS);
  932. });
  933. _mfpOn('Resize'+ns, mfp.resizeImage);
  934. if(mfp.isLowIE) {
  935. _mfpOn('AfterChange', mfp.resizeImage);
  936. }
  937. },
  938. resizeImage: function() {
  939. var item = mfp.currItem;
  940. if(!item || !item.img) return;
  941. if(mfp.st.image.verticalFit) {
  942. var decr = 0;
  943. // fix box-sizing in ie7/8
  944. if(mfp.isLowIE) {
  945. decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
  946. }
  947. item.img.css('max-height', mfp.wH-decr);
  948. }
  949. },
  950. _onImageHasSize: function(item) {
  951. if(item.img) {
  952. item.hasSize = true;
  953. if(_imgInterval) {
  954. clearInterval(_imgInterval);
  955. }
  956. item.isCheckingImgSize = false;
  957. _mfpTrigger('ImageHasSize', item);
  958. if(item.imgHidden) {
  959. if(mfp.content)
  960. mfp.content.removeClass('mfp-loading');
  961. item.imgHidden = false;
  962. }
  963. }
  964. },
  965. /**
  966. * Function that loops until the image has size to display elements that rely on it asap
  967. */
  968. findImageSize: function(item) {
  969. var counter = 0,
  970. img = item.img[0],
  971. mfpSetInterval = function(delay) {
  972. if(_imgInterval) {
  973. clearInterval(_imgInterval);
  974. }
  975. // decelerating interval that checks for size of an image
  976. _imgInterval = setInterval(function() {
  977. if(img.naturalWidth > 0) {
  978. mfp._onImageHasSize(item);
  979. return;
  980. }
  981. if(counter > 200) {
  982. clearInterval(_imgInterval);
  983. }
  984. counter++;
  985. if(counter === 3) {
  986. mfpSetInterval(10);
  987. } else if(counter === 40) {
  988. mfpSetInterval(50);
  989. } else if(counter === 100) {
  990. mfpSetInterval(500);
  991. }
  992. }, delay);
  993. };
  994. mfpSetInterval(1);
  995. },
  996. getImage: function(item, template) {
  997. var guard = 0,
  998. // image load complete handler
  999. onLoadComplete = function() {
  1000. if(item) {
  1001. if (item.img[0].complete) {
  1002. item.img.off('.mfploader');
  1003. if(item === mfp.currItem){
  1004. mfp._onImageHasSize(item);
  1005. mfp.updateStatus('ready');
  1006. }
  1007. item.hasSize = true;
  1008. item.loaded = true;
  1009. _mfpTrigger('ImageLoadComplete');
  1010. }
  1011. else {
  1012. // if image complete check fails 200 times (20 sec), we assume that there was an error.
  1013. guard++;
  1014. if(guard < 200) {
  1015. setTimeout(onLoadComplete,100);
  1016. } else {
  1017. onLoadError();
  1018. }
  1019. }
  1020. }
  1021. },
  1022. // image error handler
  1023. onLoadError = function() {
  1024. if(item) {
  1025. item.img.off('.mfploader');
  1026. if(item === mfp.currItem){
  1027. mfp._onImageHasSize(item);
  1028. mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
  1029. }
  1030. item.hasSize = true;
  1031. item.loaded = true;
  1032. item.loadError = true;
  1033. }
  1034. },
  1035. imgSt = mfp.st.image;
  1036. var el = template.find('.mfp-img');
  1037. if(el.length) {
  1038. var img = document.createElement('img');
  1039. img.className = 'mfp-img';
  1040. if(item.el && item.el.find('img').length) {
  1041. img.alt = item.el.find('img').attr('alt');
  1042. }
  1043. item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
  1044. img.src = item.src;
  1045. // without clone() "error" event is not firing when IMG is replaced by new IMG
  1046. // TODO: find a way to avoid such cloning
  1047. if(el.is('img')) {
  1048. item.img = item.img.clone();
  1049. }
  1050. img = item.img[0];
  1051. if(img.naturalWidth > 0) {
  1052. item.hasSize = true;
  1053. } else if(!img.width) {
  1054. item.hasSize = false;
  1055. }
  1056. }
  1057. mfp._parseMarkup(template, {
  1058. title: _getTitle(item),
  1059. img_replaceWith: item.img
  1060. }, item);
  1061. mfp.resizeImage();
  1062. if(item.hasSize) {
  1063. if(_imgInterval) clearInterval(_imgInterval);
  1064. if(item.loadError) {
  1065. template.addClass('mfp-loading');
  1066. mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
  1067. } else {
  1068. template.removeClass('mfp-loading');
  1069. mfp.updateStatus('ready');
  1070. }
  1071. return template;
  1072. }
  1073. mfp.updateStatus('loading');
  1074. item.loading = true;
  1075. if(!item.hasSize) {
  1076. item.imgHidden = true;
  1077. template.addClass('mfp-loading');
  1078. mfp.findImageSize(item);
  1079. }
  1080. return template;
  1081. }
  1082. }
  1083. });
  1084. /*>>image*/
  1085. /*>>zoom*/
  1086. var hasMozTransform,
  1087. getHasMozTransform = function() {
  1088. if(hasMozTransform === undefined) {
  1089. hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
  1090. }
  1091. return hasMozTransform;
  1092. };
  1093. $.magnificPopup.registerModule('zoom', {
  1094. options: {
  1095. enabled: false,
  1096. easing: 'ease-in-out',
  1097. duration: 300,
  1098. opener: function(element) {
  1099. return element.is('img') ? element : element.find('img');
  1100. }
  1101. },
  1102. proto: {
  1103. initZoom: function() {
  1104. var zoomSt = mfp.st.zoom,
  1105. ns = '.zoom',
  1106. image;
  1107. if(!zoomSt.enabled || !mfp.supportsTransition) {
  1108. return;
  1109. }
  1110. var duration = zoomSt.duration,
  1111. getElToAnimate = function(image) {
  1112. var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
  1113. transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
  1114. cssObj = {
  1115. position: 'fixed',
  1116. zIndex: 9999,
  1117. left: 0,
  1118. top: 0,
  1119. '-webkit-backface-visibility': 'hidden'
  1120. },
  1121. t = 'transition';
  1122. cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;
  1123. newImg.css(cssObj);
  1124. return newImg;
  1125. },
  1126. showMainContent = function() {
  1127. mfp.content.css('visibility', 'visible');
  1128. },
  1129. openTimeout,
  1130. animatedImg;
  1131. _mfpOn('BuildControls'+ns, function() {
  1132. if(mfp._allowZoom()) {
  1133. clearTimeout(openTimeout);
  1134. mfp.content.css('visibility', 'hidden');
  1135. // Basically, all code below does is clones existing image, puts in on top of the current one and animated it
  1136. image = mfp._getItemToZoom();
  1137. if(!image) {
  1138. showMainContent();
  1139. return;
  1140. }
  1141. animatedImg = getElToAnimate(image);
  1142. animatedImg.css( mfp._getOffset() );
  1143. mfp.wrap.append(animatedImg);
  1144. openTimeout = setTimeout(function() {
  1145. animatedImg.css( mfp._getOffset( true ) );
  1146. openTimeout = setTimeout(function() {
  1147. showMainContent();
  1148. setTimeout(function() {
  1149. animatedImg.remove();
  1150. image = animatedImg = null;
  1151. _mfpTrigger('ZoomAnimationEnded');
  1152. }, 16); // avoid blink when switching images
  1153. }, duration); // this timeout equals animation duration
  1154. }, 16); // by adding this timeout we avoid short glitch at the beginning of animation
  1155. // Lots of timeouts...
  1156. }
  1157. });
  1158. _mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
  1159. if(mfp._allowZoom()) {
  1160. clearTimeout(openTimeout);
  1161. mfp.st.removalDelay = duration;
  1162. if(!image) {
  1163. image = mfp._getItemToZoom();
  1164. if(!image) {
  1165. return;
  1166. }
  1167. animatedImg = getElToAnimate(image);
  1168. }
  1169. animatedImg.css( mfp._getOffset(true) );
  1170. mfp.wrap.append(animatedImg);
  1171. mfp.content.css('visibility', 'hidden');
  1172. setTimeout(function() {
  1173. animatedImg.css( mfp._getOffset() );
  1174. }, 16);
  1175. }
  1176. });
  1177. _mfpOn(CLOSE_EVENT+ns, function() {
  1178. if(mfp._allowZoom()) {
  1179. showMainContent();
  1180. if(animatedImg) {
  1181. animatedImg.remove();
  1182. }
  1183. image = null;
  1184. }
  1185. });
  1186. },
  1187. _allowZoom: function() {
  1188. return mfp.currItem.type === 'image';
  1189. },
  1190. _getItemToZoom: function() {
  1191. if(mfp.currItem.hasSize) {
  1192. return mfp.currItem.img;
  1193. } else {
  1194. return false;
  1195. }
  1196. },
  1197. // Get element postion relative to viewport
  1198. _getOffset: function(isLarge) {
  1199. var el;
  1200. if(isLarge) {
  1201. el = mfp.currItem.img;
  1202. } else {
  1203. el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
  1204. }
  1205. var offset = el.offset();
  1206. var paddingTop = parseInt(el.css('padding-top'),10);
  1207. var paddingBottom = parseInt(el.css('padding-bottom'),10);
  1208. offset.top -= ( $(window).scrollTop() - paddingTop );
  1209. /*
  1210. Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.
  1211. */
  1212. var obj = {
  1213. width: el.width(),
  1214. // fix Zepto height+padding issue
  1215. height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
  1216. };
  1217. // I hate to do this, but there is no another option
  1218. if( getHasMozTransform() ) {
  1219. obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
  1220. } else {
  1221. obj.left = offset.left;
  1222. obj.top = offset.top;
  1223. }
  1224. return obj;
  1225. }
  1226. }
  1227. });
  1228. /*>>zoom*/
  1229. /*>>iframe*/
  1230. var IFRAME_NS = 'iframe',
  1231. _emptyPage = '//about:blank',
  1232. _fixIframeBugs = function(isShowing) {
  1233. if(mfp.currTemplate[IFRAME_NS]) {
  1234. var el = mfp.currTemplate[IFRAME_NS].find('iframe');
  1235. if(el.length) {
  1236. // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
  1237. if(!isShowing) {
  1238. el[0].src = _emptyPage;
  1239. }
  1240. // IE8 black screen bug fix
  1241. if(mfp.isIE8) {
  1242. el.css('display', isShowing ? 'block' : 'none');
  1243. }
  1244. }
  1245. }
  1246. };
  1247. $.magnificPopup.registerModule(IFRAME_NS, {
  1248. options: {
  1249. markup: '<div class="mfp-iframe-scaler">'+
  1250. '<div class="mfp-close"></div>'+
  1251. '<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
  1252. '</div>',
  1253. srcAction: 'iframe_src',
  1254. // we don't care and support only one default type of URL by default
  1255. patterns: {
  1256. youtube: {
  1257. index: 'youtube.com',
  1258. id: 'v=',
  1259. src: '//www.youtube.com/embed/%id%?autoplay=1'
  1260. },
  1261. vimeo: {
  1262. index: 'vimeo.com/',
  1263. id: '/',
  1264. src: '//player.vimeo.com/video/%id%?autoplay=1'
  1265. },
  1266. gmaps: {
  1267. index: '//maps.google.',
  1268. src: '%id%&output=embed'
  1269. }
  1270. }
  1271. },
  1272. proto: {
  1273. initIframe: function() {
  1274. mfp.types.push(IFRAME_NS);
  1275. _mfpOn('BeforeChange', function(e, prevType, newType) {
  1276. if(prevType !== newType) {
  1277. if(prevType === IFRAME_NS) {
  1278. _fixIframeBugs(); // iframe if removed
  1279. } else if(newType === IFRAME_NS) {
  1280. _fixIframeBugs(true); // iframe is showing
  1281. }
  1282. }// else {
  1283. // iframe source is switched, don't do anything
  1284. //}
  1285. });
  1286. _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
  1287. _fixIframeBugs();
  1288. });
  1289. },
  1290. getIframe: function(item, template) {
  1291. var embedSrc = item.src;
  1292. var iframeSt = mfp.st.iframe;
  1293. $.each(iframeSt.patterns, function() {
  1294. if(embedSrc.indexOf( this.index ) > -1) {
  1295. if(this.id) {
  1296. if(typeof this.id === 'string') {
  1297. embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
  1298. } else {
  1299. embedSrc = this.id.call( this, embedSrc );
  1300. }
  1301. }
  1302. embedSrc = this.src.replace('%id%', embedSrc );
  1303. return false; // break;
  1304. }
  1305. });
  1306. var dataObj = {};
  1307. if(iframeSt.srcAction) {
  1308. dataObj[iframeSt.srcAction] = embedSrc;
  1309. }
  1310. mfp._parseMarkup(template, dataObj, item);
  1311. mfp.updateStatus('ready');
  1312. return template;
  1313. }
  1314. }
  1315. });
  1316. /*>>iframe*/
  1317. /*>>gallery*/
  1318. /**
  1319. * Get looped index depending on number of slides
  1320. */
  1321. var _getLoopedId = function(index) {
  1322. var numSlides = mfp.items.length;
  1323. if(index > numSlides - 1) {
  1324. return index - numSlides;
  1325. } else if(index < 0) {
  1326. return numSlides + index;
  1327. }
  1328. return index;
  1329. },
  1330. _replaceCurrTotal = function(text, curr, total) {
  1331. return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
  1332. };
  1333. $.magnificPopup.registerModule('gallery', {
  1334. options: {
  1335. enabled: false,
  1336. arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',
  1337. preload: [0,2],
  1338. navigateByImgClick: true,
  1339. arrows: true,
  1340. tPrev: 'Previous (Left arrow key)',
  1341. tNext: 'Next (Right arrow key)',
  1342. tCounter: '%curr% of %total%'
  1343. },
  1344. proto: {
  1345. initGallery: function() {
  1346. var gSt = mfp.st.gallery,
  1347. ns = '.mfp-gallery';
  1348. mfp.direction = true; // true - next, false - prev
  1349. if(!gSt || !gSt.enabled ) return false;
  1350. _wrapClasses += ' mfp-gallery';
  1351. _mfpOn(OPEN_EVENT+ns, function() {
  1352. if(gSt.navigateByImgClick) {
  1353. mfp.wrap.on('click'+ns, '.mfp-img', function() {
  1354. if(mfp.items.length > 1) {
  1355. mfp.next();
  1356. return false;
  1357. }
  1358. });
  1359. }
  1360. _document.on('keydown'+ns, function(e) {
  1361. if (e.keyCode === 37) {
  1362. mfp.prev();
  1363. } else if (e.keyCode === 39) {
  1364. mfp.next();
  1365. }
  1366. });
  1367. });
  1368. _mfpOn('UpdateStatus'+ns, function(e, data) {
  1369. if(data.text) {
  1370. data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
  1371. }
  1372. });
  1373. _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
  1374. var l = mfp.items.length;
  1375. values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
  1376. });
  1377. _mfpOn('BuildControls' + ns, function() {
  1378. if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
  1379. var markup = gSt.arrowMarkup,
  1380. arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),
  1381. arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);
  1382. arrowLeft.click(function() {
  1383. mfp.prev();
  1384. });
  1385. arrowRight.click(function() {
  1386. mfp.next();
  1387. });
  1388. mfp.container.append(arrowLeft.add(arrowRight));
  1389. }
  1390. });
  1391. _mfpOn(CHANGE_EVENT+ns, function() {
  1392. if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);
  1393. mfp._preloadTimeout = setTimeout(function() {
  1394. mfp.preloadNearbyImages();
  1395. mfp._preloadTimeout = null;
  1396. }, 16);
  1397. });
  1398. _mfpOn(CLOSE_EVENT+ns, function() {
  1399. _document.off(ns);
  1400. mfp.wrap.off('click'+ns);
  1401. mfp.arrowRight = mfp.arrowLeft = null;
  1402. });
  1403. },
  1404. next: function() {
  1405. mfp.direction = true;
  1406. mfp.index = _getLoopedId(mfp.index + 1);
  1407. mfp.updateItemHTML();
  1408. },
  1409. prev: function() {
  1410. mfp.direction = false;
  1411. mfp.index = _getLoopedId(mfp.index - 1);
  1412. mfp.updateItemHTML();
  1413. },
  1414. goTo: function(newIndex) {
  1415. mfp.direction = (newIndex >= mfp.index);
  1416. mfp.index = newIndex;
  1417. mfp.updateItemHTML();
  1418. },
  1419. preloadNearbyImages: function() {
  1420. var p = mfp.st.gallery.preload,
  1421. preloadBefore = Math.min(p[0], mfp.items.length),
  1422. preloadAfter = Math.min(p[1], mfp.items.length),
  1423. i;
  1424. for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
  1425. mfp._preloadItem(mfp.index+i);
  1426. }
  1427. for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
  1428. mfp._preloadItem(mfp.index-i);
  1429. }
  1430. },
  1431. _preloadItem: function(index) {
  1432. index = _getLoopedId(index);
  1433. if(mfp.items[index].preloaded) {
  1434. return;
  1435. }
  1436. var item = mfp.items[index];
  1437. if(!item.parsed) {
  1438. item = mfp.parseEl( index );
  1439. }
  1440. _mfpTrigger('LazyLoad', item);
  1441. if(item.type === 'image') {
  1442. item.img = $('<img class="mfp-img" />').on('load.mfploader', function() {
  1443. item.hasSize = true;
  1444. }).on('error.mfploader', function() {
  1445. item.hasSize = true;
  1446. item.loadError = true;
  1447. _mfpTrigger('LazyLoadError', item);
  1448. }).attr('src', item.src);
  1449. }
  1450. item.preloaded = true;
  1451. }
  1452. }
  1453. });
  1454. /*>>gallery*/
  1455. /*>>retina*/
  1456. var RETINA_NS = 'retina';
  1457. $.magnificPopup.registerModule(RETINA_NS, {
  1458. options: {
  1459. replaceSrc: function(item) {
  1460. return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
  1461. },
  1462. ratio: 1 // Function or number. Set to 1 to disable.
  1463. },
  1464. proto: {
  1465. initRetina: function() {
  1466. if(window.devicePixelRatio > 1) {
  1467. var st = mfp.st.retina,
  1468. ratio = st.ratio;
  1469. ratio = !isNaN(ratio) ? ratio : ratio();
  1470. if(ratio > 1) {
  1471. _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
  1472. item.img.css({
  1473. 'max-width': item.img[0].naturalWidth / ratio,
  1474. 'width': '100%'
  1475. });
  1476. });
  1477. _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
  1478. item.src = st.replaceSrc(item, ratio);
  1479. });
  1480. }
  1481. }
  1482. }
  1483. }
  1484. });
  1485. /*>>retina*/
  1486. _checkInstance(); }));