jquery.magnific-popup.js 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945
  1. /*!
  2. Magnific Popup
  3. Version: 1.2.0 - 2024-06-08
  4. Plugin URL: http://dimsemenov.com/plugins/magnific-popup/
  5. License: Copyright (c) 2024 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, Array.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 = Array.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).trigger('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(typeof disableOn === "function") {
  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. if (mfp.st.allowHTMLInStatusIndicator) {
  564. mfp.preloader.html(text);
  565. } else {
  566. mfp.preloader.text(text);
  567. }
  568. mfp.preloader.find('a').on('click', function(e) {
  569. e.stopImmediatePropagation();
  570. });
  571. mfp.container.addClass('mfp-s-'+status);
  572. _prevStatus = status;
  573. }
  574. },
  575. /*
  576. "Private" helpers that aren't private at all
  577. */
  578. // Check to close popup or not
  579. // "target" is an element that was clicked
  580. _checkIfClose: function(target) {
  581. if($(target).closest('.' + PREVENT_CLOSE_CLASS).length) {
  582. return;
  583. }
  584. var closeOnContent = mfp.st.closeOnContentClick;
  585. var closeOnBg = mfp.st.closeOnBgClick;
  586. if(closeOnContent && closeOnBg) {
  587. return true;
  588. } else {
  589. // We close the popup if click is on close button or on preloader. Or if there is no content.
  590. if(!mfp.content || $(target).closest('.mfp-close').length || (mfp.preloader && target === mfp.preloader[0]) ) {
  591. return true;
  592. }
  593. // if click is outside the content
  594. if( (target !== mfp.content[0] && !$.contains(mfp.content[0], target)) ) {
  595. if(closeOnBg) {
  596. // last check, if the clicked element is in DOM, (in case it's removed onclick)
  597. if( $.contains(document, target) ) {
  598. return true;
  599. }
  600. }
  601. } else if(closeOnContent) {
  602. return true;
  603. }
  604. }
  605. return false;
  606. },
  607. _addClassToMFP: function(cName) {
  608. mfp.bgOverlay.addClass(cName);
  609. mfp.wrap.addClass(cName);
  610. },
  611. _removeClassFromMFP: function(cName) {
  612. this.bgOverlay.removeClass(cName);
  613. mfp.wrap.removeClass(cName);
  614. },
  615. _hasScrollBar: function(winHeight) {
  616. return ( (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) );
  617. },
  618. _setFocus: function() {
  619. (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).trigger('focus');
  620. },
  621. _onFocusIn: function(e) {
  622. if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) {
  623. mfp._setFocus();
  624. return false;
  625. }
  626. },
  627. _parseMarkup: function(template, values, item) {
  628. var arr;
  629. if(item.data) {
  630. values = $.extend(item.data, values);
  631. }
  632. _mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] );
  633. $.each(values, function(key, value) {
  634. if(value === undefined || value === false) {
  635. return true;
  636. }
  637. arr = key.split('_');
  638. if(arr.length > 1) {
  639. var el = template.find(EVENT_NS + '-'+arr[0]);
  640. if(el.length > 0) {
  641. var attr = arr[1];
  642. if(attr === 'replaceWith') {
  643. if(el[0] !== value[0]) {
  644. el.replaceWith(value);
  645. }
  646. } else if(attr === 'img') {
  647. if(el.is('img')) {
  648. el.attr('src', value);
  649. } else {
  650. el.replaceWith( $('<img>').attr('src', value).attr('class', el.attr('class')) );
  651. }
  652. } else {
  653. el.attr(arr[1], value);
  654. }
  655. }
  656. } else {
  657. if (mfp.st.allowHTMLInTemplate) {
  658. template.find(EVENT_NS + '-'+key).html(value);
  659. } else {
  660. template.find(EVENT_NS + '-'+key).text(value);
  661. }
  662. }
  663. });
  664. },
  665. _getScrollbarSize: function() {
  666. // thx David
  667. if(mfp.scrollbarSize === undefined) {
  668. var scrollDiv = document.createElement("div");
  669. scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
  670. document.body.appendChild(scrollDiv);
  671. mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  672. document.body.removeChild(scrollDiv);
  673. }
  674. return mfp.scrollbarSize;
  675. }
  676. }; /* MagnificPopup core prototype end */
  677. /**
  678. * Public static functions
  679. */
  680. $.magnificPopup = {
  681. instance: null,
  682. proto: MagnificPopup.prototype,
  683. modules: [],
  684. open: function(options, index) {
  685. _checkInstance();
  686. if(!options) {
  687. options = {};
  688. } else {
  689. options = $.extend(true, {}, options);
  690. }
  691. options.isObj = true;
  692. options.index = index || 0;
  693. return this.instance.open(options);
  694. },
  695. close: function() {
  696. return $.magnificPopup.instance && $.magnificPopup.instance.close();
  697. },
  698. registerModule: function(name, module) {
  699. if(module.options) {
  700. $.magnificPopup.defaults[name] = module.options;
  701. }
  702. $.extend(this.proto, module.proto);
  703. this.modules.push(name);
  704. },
  705. defaults: {
  706. // Info about options is in docs:
  707. // http://dimsemenov.com/plugins/magnific-popup/documentation.html#options
  708. disableOn: 0,
  709. key: null,
  710. midClick: false,
  711. mainClass: '',
  712. preloader: true,
  713. focus: '', // CSS selector of input to focus after popup is opened
  714. closeOnContentClick: false,
  715. closeOnBgClick: true,
  716. closeBtnInside: true,
  717. showCloseBtn: true,
  718. enableEscapeKey: true,
  719. modal: false,
  720. alignTop: false,
  721. removalDelay: 0,
  722. prependTo: null,
  723. fixedContentPos: 'auto',
  724. fixedBgPos: 'auto',
  725. overflowY: 'auto',
  726. closeMarkup: '<button title="%title%" type="button" class="mfp-close">&#215;</button>',
  727. tClose: 'Close (Esc)',
  728. tLoading: 'Loading...',
  729. autoFocusLast: true,
  730. allowHTMLInStatusIndicator: false,
  731. allowHTMLInTemplate: false
  732. }
  733. };
  734. $.fn.magnificPopup = function(options) {
  735. _checkInstance();
  736. var jqEl = $(this);
  737. // We call some API method of first param is a string
  738. if (typeof options === "string" ) {
  739. if(options === 'open') {
  740. var items,
  741. itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup,
  742. index = parseInt(arguments[1], 10) || 0;
  743. if(itemOpts.items) {
  744. items = itemOpts.items[index];
  745. } else {
  746. items = jqEl;
  747. if(itemOpts.delegate) {
  748. items = items.find(itemOpts.delegate);
  749. }
  750. items = items.eq( index );
  751. }
  752. mfp._openClick({mfpEl:items}, jqEl, itemOpts);
  753. } else {
  754. if(mfp.isOpen)
  755. mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1));
  756. }
  757. } else {
  758. // clone options obj
  759. options = $.extend(true, {}, options);
  760. /*
  761. * As Zepto doesn't support .data() method for objects
  762. * and it works only in normal browsers
  763. * we assign "options" object directly to the DOM element. FTW!
  764. */
  765. if(_isJQ) {
  766. jqEl.data('magnificPopup', options);
  767. } else {
  768. jqEl[0].magnificPopup = options;
  769. }
  770. mfp.addGroup(jqEl, options);
  771. }
  772. return jqEl;
  773. };
  774. /*>>core*/
  775. /*>>inline*/
  776. var INLINE_NS = 'inline',
  777. _hiddenClass,
  778. _inlinePlaceholder,
  779. _lastInlineElement,
  780. _putInlineElementsBack = function() {
  781. if(_lastInlineElement) {
  782. _inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach();
  783. _lastInlineElement = null;
  784. }
  785. };
  786. $.magnificPopup.registerModule(INLINE_NS, {
  787. options: {
  788. hiddenClass: 'hide', // will be appended with `mfp-` prefix
  789. markup: '',
  790. tNotFound: 'Content not found'
  791. },
  792. proto: {
  793. initInline: function() {
  794. mfp.types.push(INLINE_NS);
  795. _mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() {
  796. _putInlineElementsBack();
  797. });
  798. },
  799. getInline: function(item, template) {
  800. _putInlineElementsBack();
  801. if(item.src) {
  802. var inlineSt = mfp.st.inline,
  803. el = $(item.src);
  804. if(el.length) {
  805. // If target element has parent - we replace it with placeholder and put it back after popup is closed
  806. var parent = el[0].parentNode;
  807. if(parent && parent.tagName) {
  808. if(!_inlinePlaceholder) {
  809. _hiddenClass = inlineSt.hiddenClass;
  810. _inlinePlaceholder = _getEl(_hiddenClass);
  811. _hiddenClass = 'mfp-'+_hiddenClass;
  812. }
  813. // replace target inline element with placeholder
  814. _lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass);
  815. }
  816. mfp.updateStatus('ready');
  817. } else {
  818. mfp.updateStatus('error', inlineSt.tNotFound);
  819. el = $('<div>');
  820. }
  821. item.inlineElement = el;
  822. return el;
  823. }
  824. mfp.updateStatus('ready');
  825. mfp._parseMarkup(template, {}, item);
  826. return template;
  827. }
  828. }
  829. });
  830. /*>>inline*/
  831. /*>>ajax*/
  832. var AJAX_NS = 'ajax',
  833. _ajaxCur,
  834. _removeAjaxCursor = function() {
  835. if(_ajaxCur) {
  836. $(document.body).removeClass(_ajaxCur);
  837. }
  838. },
  839. _destroyAjaxRequest = function() {
  840. _removeAjaxCursor();
  841. if(mfp.req) {
  842. mfp.req.abort();
  843. }
  844. };
  845. $.magnificPopup.registerModule(AJAX_NS, {
  846. options: {
  847. settings: null,
  848. cursor: 'mfp-ajax-cur',
  849. tError: 'The content could not be loaded.'
  850. },
  851. proto: {
  852. initAjax: function() {
  853. mfp.types.push(AJAX_NS);
  854. _ajaxCur = mfp.st.ajax.cursor;
  855. _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
  856. _mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
  857. },
  858. getAjax: function(item) {
  859. if(_ajaxCur) {
  860. $(document.body).addClass(_ajaxCur);
  861. }
  862. mfp.updateStatus('loading');
  863. var opts = $.extend({
  864. url: item.src,
  865. success: function(data, textStatus, jqXHR) {
  866. var temp = {
  867. data:data,
  868. xhr:jqXHR
  869. };
  870. _mfpTrigger('ParseAjax', temp);
  871. mfp.appendContent( $(temp.data), AJAX_NS );
  872. item.finished = true;
  873. _removeAjaxCursor();
  874. mfp._setFocus();
  875. setTimeout(function() {
  876. mfp.wrap.addClass(READY_CLASS);
  877. }, 16);
  878. mfp.updateStatus('ready');
  879. _mfpTrigger('AjaxContentAdded');
  880. },
  881. error: function() {
  882. _removeAjaxCursor();
  883. item.finished = item.loadError = true;
  884. mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
  885. }
  886. }, mfp.st.ajax.settings);
  887. mfp.req = $.ajax(opts);
  888. return '';
  889. }
  890. }
  891. });
  892. /*>>ajax*/
  893. /*>>image*/
  894. var _imgInterval,
  895. _getTitle = function(item) {
  896. if(item.data && item.data.title !== undefined)
  897. return item.data.title;
  898. var src = mfp.st.image.titleSrc;
  899. if(src) {
  900. if(typeof src === "function") {
  901. return src.call(mfp, item);
  902. } else if(item.el) {
  903. return item.el.attr(src) || '';
  904. }
  905. }
  906. return '';
  907. };
  908. $.magnificPopup.registerModule('image', {
  909. options: {
  910. markup: '<div class="mfp-figure">'+
  911. '<div class="mfp-close"></div>'+
  912. '<figure>'+
  913. '<div class="mfp-img"></div>'+
  914. '<figcaption>'+
  915. '<div class="mfp-bottom-bar">'+
  916. '<div class="mfp-title"></div>'+
  917. '<div class="mfp-counter"></div>'+
  918. '</div>'+
  919. '</figcaption>'+
  920. '</figure>'+
  921. '</div>',
  922. cursor: 'mfp-zoom-out-cur',
  923. titleSrc: 'title',
  924. verticalFit: true,
  925. tError: 'The image could not be loaded.'
  926. },
  927. proto: {
  928. initImage: function() {
  929. var imgSt = mfp.st.image,
  930. ns = '.image';
  931. mfp.types.push('image');
  932. _mfpOn(OPEN_EVENT+ns, function() {
  933. if(mfp.currItem.type === 'image' && imgSt.cursor) {
  934. $(document.body).addClass(imgSt.cursor);
  935. }
  936. });
  937. _mfpOn(CLOSE_EVENT+ns, function() {
  938. if(imgSt.cursor) {
  939. $(document.body).removeClass(imgSt.cursor);
  940. }
  941. _window.off('resize' + EVENT_NS);
  942. });
  943. _mfpOn('Resize'+ns, mfp.resizeImage);
  944. if(mfp.isLowIE) {
  945. _mfpOn('AfterChange', mfp.resizeImage);
  946. }
  947. },
  948. resizeImage: function() {
  949. var item = mfp.currItem;
  950. if(!item || !item.img) return;
  951. if(mfp.st.image.verticalFit) {
  952. var decr = 0;
  953. // fix box-sizing in ie7/8
  954. if(mfp.isLowIE) {
  955. decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
  956. }
  957. item.img.css('max-height', mfp.wH-decr);
  958. }
  959. },
  960. _onImageHasSize: function(item) {
  961. if(item.img) {
  962. item.hasSize = true;
  963. if(_imgInterval) {
  964. clearInterval(_imgInterval);
  965. }
  966. item.isCheckingImgSize = false;
  967. _mfpTrigger('ImageHasSize', item);
  968. if(item.imgHidden) {
  969. if(mfp.content)
  970. mfp.content.removeClass('mfp-loading');
  971. item.imgHidden = false;
  972. }
  973. }
  974. },
  975. /**
  976. * Function that loops until the image has size to display elements that rely on it asap
  977. */
  978. findImageSize: function(item) {
  979. var counter = 0,
  980. img = item.img[0],
  981. mfpSetInterval = function(delay) {
  982. if(_imgInterval) {
  983. clearInterval(_imgInterval);
  984. }
  985. // decelerating interval that checks for size of an image
  986. _imgInterval = setInterval(function() {
  987. if(img.naturalWidth > 0) {
  988. mfp._onImageHasSize(item);
  989. return;
  990. }
  991. if(counter > 200) {
  992. clearInterval(_imgInterval);
  993. }
  994. counter++;
  995. if(counter === 3) {
  996. mfpSetInterval(10);
  997. } else if(counter === 40) {
  998. mfpSetInterval(50);
  999. } else if(counter === 100) {
  1000. mfpSetInterval(500);
  1001. }
  1002. }, delay);
  1003. };
  1004. mfpSetInterval(1);
  1005. },
  1006. getImage: function(item, template) {
  1007. var guard = 0,
  1008. imgSt = mfp.st.image,
  1009. // image error handler
  1010. onLoadError = function() {
  1011. if(item) {
  1012. item.img.off('.mfploader');
  1013. if(item === mfp.currItem){
  1014. mfp._onImageHasSize(item);
  1015. mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
  1016. }
  1017. item.hasSize = true;
  1018. item.loaded = true;
  1019. item.loadError = true;
  1020. }
  1021. },
  1022. // image load complete handler
  1023. onLoadComplete = function() {
  1024. if(item) {
  1025. if (item.img[0].complete) {
  1026. item.img.off('.mfploader');
  1027. if(item === mfp.currItem){
  1028. mfp._onImageHasSize(item);
  1029. mfp.updateStatus('ready');
  1030. }
  1031. item.hasSize = true;
  1032. item.loaded = true;
  1033. _mfpTrigger('ImageLoadComplete');
  1034. }
  1035. else {
  1036. // if image complete check fails 200 times (20 sec), we assume that there was an error.
  1037. guard++;
  1038. if(guard < 200) {
  1039. setTimeout(onLoadComplete,100);
  1040. } else {
  1041. onLoadError();
  1042. }
  1043. }
  1044. }
  1045. };
  1046. var el = template.find('.mfp-img');
  1047. if(el.length) {
  1048. var img = document.createElement('img');
  1049. img.className = 'mfp-img';
  1050. if(item.el && item.el.find('img').length) {
  1051. img.alt = item.el.find('img').attr('alt');
  1052. }
  1053. item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
  1054. img.src = item.src;
  1055. // without clone() "error" event is not firing when IMG is replaced by new IMG
  1056. // TODO: find a way to avoid such cloning
  1057. if(el.is('img')) {
  1058. item.img = item.img.clone();
  1059. }
  1060. img = item.img[0];
  1061. if(img.naturalWidth > 0) {
  1062. item.hasSize = true;
  1063. } else if(!img.width) {
  1064. item.hasSize = false;
  1065. }
  1066. }
  1067. mfp._parseMarkup(template, {
  1068. title: _getTitle(item),
  1069. img_replaceWith: item.img
  1070. }, item);
  1071. mfp.resizeImage();
  1072. if(item.hasSize) {
  1073. if(_imgInterval) clearInterval(_imgInterval);
  1074. if(item.loadError) {
  1075. template.addClass('mfp-loading');
  1076. mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
  1077. } else {
  1078. template.removeClass('mfp-loading');
  1079. mfp.updateStatus('ready');
  1080. }
  1081. return template;
  1082. }
  1083. mfp.updateStatus('loading');
  1084. item.loading = true;
  1085. if(!item.hasSize) {
  1086. item.imgHidden = true;
  1087. template.addClass('mfp-loading');
  1088. mfp.findImageSize(item);
  1089. }
  1090. return template;
  1091. }
  1092. }
  1093. });
  1094. /*>>image*/
  1095. /*>>zoom*/
  1096. var hasMozTransform,
  1097. getHasMozTransform = function() {
  1098. if(hasMozTransform === undefined) {
  1099. hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
  1100. }
  1101. return hasMozTransform;
  1102. };
  1103. $.magnificPopup.registerModule('zoom', {
  1104. options: {
  1105. enabled: false,
  1106. easing: 'ease-in-out',
  1107. duration: 300,
  1108. opener: function(element) {
  1109. return element.is('img') ? element : element.find('img');
  1110. }
  1111. },
  1112. proto: {
  1113. initZoom: function() {
  1114. var zoomSt = mfp.st.zoom,
  1115. ns = '.zoom',
  1116. image;
  1117. if(!zoomSt.enabled || !mfp.supportsTransition) {
  1118. return;
  1119. }
  1120. var duration = zoomSt.duration,
  1121. getElToAnimate = function(image) {
  1122. var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
  1123. transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
  1124. cssObj = {
  1125. position: 'fixed',
  1126. zIndex: 9999,
  1127. left: 0,
  1128. top: 0,
  1129. '-webkit-backface-visibility': 'hidden'
  1130. },
  1131. t = 'transition';
  1132. cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;
  1133. newImg.css(cssObj);
  1134. return newImg;
  1135. },
  1136. showMainContent = function() {
  1137. mfp.content.css('visibility', 'visible');
  1138. },
  1139. openTimeout,
  1140. animatedImg;
  1141. _mfpOn('BuildControls'+ns, function() {
  1142. if(mfp._allowZoom()) {
  1143. clearTimeout(openTimeout);
  1144. mfp.content.css('visibility', 'hidden');
  1145. // Basically, all code below does is clones existing image, puts in on top of the current one and animated it
  1146. image = mfp._getItemToZoom();
  1147. if(!image) {
  1148. showMainContent();
  1149. return;
  1150. }
  1151. animatedImg = getElToAnimate(image);
  1152. animatedImg.css( mfp._getOffset() );
  1153. mfp.wrap.append(animatedImg);
  1154. openTimeout = setTimeout(function() {
  1155. animatedImg.css( mfp._getOffset( true ) );
  1156. openTimeout = setTimeout(function() {
  1157. showMainContent();
  1158. setTimeout(function() {
  1159. animatedImg.remove();
  1160. image = animatedImg = null;
  1161. _mfpTrigger('ZoomAnimationEnded');
  1162. }, 16); // avoid blink when switching images
  1163. }, duration); // this timeout equals animation duration
  1164. }, 16); // by adding this timeout we avoid short glitch at the beginning of animation
  1165. // Lots of timeouts...
  1166. }
  1167. });
  1168. _mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
  1169. if(mfp._allowZoom()) {
  1170. clearTimeout(openTimeout);
  1171. mfp.st.removalDelay = duration;
  1172. if(!image) {
  1173. image = mfp._getItemToZoom();
  1174. if(!image) {
  1175. return;
  1176. }
  1177. animatedImg = getElToAnimate(image);
  1178. }
  1179. animatedImg.css( mfp._getOffset(true) );
  1180. mfp.wrap.append(animatedImg);
  1181. mfp.content.css('visibility', 'hidden');
  1182. setTimeout(function() {
  1183. animatedImg.css( mfp._getOffset() );
  1184. }, 16);
  1185. }
  1186. });
  1187. _mfpOn(CLOSE_EVENT+ns, function() {
  1188. if(mfp._allowZoom()) {
  1189. showMainContent();
  1190. if(animatedImg) {
  1191. animatedImg.remove();
  1192. }
  1193. image = null;
  1194. }
  1195. });
  1196. },
  1197. _allowZoom: function() {
  1198. return mfp.currItem.type === 'image';
  1199. },
  1200. _getItemToZoom: function() {
  1201. if(mfp.currItem.hasSize) {
  1202. return mfp.currItem.img;
  1203. } else {
  1204. return false;
  1205. }
  1206. },
  1207. // Get element postion relative to viewport
  1208. _getOffset: function(isLarge) {
  1209. var el;
  1210. if(isLarge) {
  1211. el = mfp.currItem.img;
  1212. } else {
  1213. el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
  1214. }
  1215. var offset = el.offset();
  1216. var paddingTop = parseInt(el.css('padding-top'),10);
  1217. var paddingBottom = parseInt(el.css('padding-bottom'),10);
  1218. offset.top -= ( $(window).scrollTop() - paddingTop );
  1219. /*
  1220. Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.
  1221. */
  1222. var obj = {
  1223. width: el.width(),
  1224. // fix Zepto height+padding issue
  1225. height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
  1226. };
  1227. // I hate to do this, but there is no another option
  1228. if( getHasMozTransform() ) {
  1229. obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
  1230. } else {
  1231. obj.left = offset.left;
  1232. obj.top = offset.top;
  1233. }
  1234. return obj;
  1235. }
  1236. }
  1237. });
  1238. /*>>zoom*/
  1239. /*>>iframe*/
  1240. var IFRAME_NS = 'iframe',
  1241. _emptyPage = '//about:blank',
  1242. _fixIframeBugs = function(isShowing) {
  1243. if(mfp.currTemplate[IFRAME_NS]) {
  1244. var el = mfp.currTemplate[IFRAME_NS].find('iframe');
  1245. if(el.length) {
  1246. // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
  1247. if(!isShowing) {
  1248. el[0].src = _emptyPage;
  1249. }
  1250. // IE8 black screen bug fix
  1251. if(mfp.isIE8) {
  1252. el.css('display', isShowing ? 'block' : 'none');
  1253. }
  1254. }
  1255. }
  1256. };
  1257. $.magnificPopup.registerModule(IFRAME_NS, {
  1258. options: {
  1259. markup: '<div class="mfp-iframe-scaler">'+
  1260. '<div class="mfp-close"></div>'+
  1261. '<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
  1262. '</div>',
  1263. srcAction: 'iframe_src',
  1264. // we don't care and support only one default type of URL by default
  1265. patterns: {
  1266. youtube: {
  1267. index: 'youtube.com',
  1268. id: 'v=',
  1269. src: '//www.youtube.com/embed/%id%?autoplay=1'
  1270. },
  1271. vimeo: {
  1272. index: 'vimeo.com/',
  1273. id: '/',
  1274. src: '//player.vimeo.com/video/%id%?autoplay=1'
  1275. },
  1276. gmaps: {
  1277. index: '//maps.google.',
  1278. src: '%id%&output=embed'
  1279. }
  1280. }
  1281. },
  1282. proto: {
  1283. initIframe: function() {
  1284. mfp.types.push(IFRAME_NS);
  1285. _mfpOn('BeforeChange', function(e, prevType, newType) {
  1286. if(prevType !== newType) {
  1287. if(prevType === IFRAME_NS) {
  1288. _fixIframeBugs(); // iframe if removed
  1289. } else if(newType === IFRAME_NS) {
  1290. _fixIframeBugs(true); // iframe is showing
  1291. }
  1292. }// else {
  1293. // iframe source is switched, don't do anything
  1294. //}
  1295. });
  1296. _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
  1297. _fixIframeBugs();
  1298. });
  1299. },
  1300. getIframe: function(item, template) {
  1301. var embedSrc = item.src;
  1302. var iframeSt = mfp.st.iframe;
  1303. $.each(iframeSt.patterns, function() {
  1304. if(embedSrc.indexOf( this.index ) > -1) {
  1305. if(this.id) {
  1306. if(typeof this.id === 'string') {
  1307. embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
  1308. } else {
  1309. embedSrc = this.id.call( this, embedSrc );
  1310. }
  1311. }
  1312. embedSrc = this.src.replace('%id%', embedSrc );
  1313. return false; // break;
  1314. }
  1315. });
  1316. var dataObj = {};
  1317. if(iframeSt.srcAction) {
  1318. dataObj[iframeSt.srcAction] = embedSrc;
  1319. }
  1320. mfp._parseMarkup(template, dataObj, item);
  1321. mfp.updateStatus('ready');
  1322. return template;
  1323. }
  1324. }
  1325. });
  1326. /*>>iframe*/
  1327. /*>>gallery*/
  1328. /**
  1329. * Get looped index depending on number of slides
  1330. */
  1331. var _getLoopedId = function(index) {
  1332. var numSlides = mfp.items.length;
  1333. if(index > numSlides - 1) {
  1334. return index - numSlides;
  1335. } else if(index < 0) {
  1336. return numSlides + index;
  1337. }
  1338. return index;
  1339. },
  1340. _replaceCurrTotal = function(text, curr, total) {
  1341. return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
  1342. };
  1343. $.magnificPopup.registerModule('gallery', {
  1344. options: {
  1345. enabled: false,
  1346. arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',
  1347. preload: [0,2],
  1348. navigateByImgClick: true,
  1349. arrows: true,
  1350. tPrev: 'Previous (Left arrow key)',
  1351. tNext: 'Next (Right arrow key)',
  1352. tCounter: '%curr% of %total%',
  1353. langDir: null,
  1354. loop: true,
  1355. },
  1356. proto: {
  1357. initGallery: function() {
  1358. var gSt = mfp.st.gallery,
  1359. ns = '.mfp-gallery';
  1360. mfp.direction = true; // true - next, false - prev
  1361. if(!gSt || !gSt.enabled ) return false;
  1362. if (!gSt.langDir) {
  1363. gSt.langDir = document.dir || 'ltr';
  1364. }
  1365. _wrapClasses += ' mfp-gallery';
  1366. _mfpOn(OPEN_EVENT+ns, function() {
  1367. if(gSt.navigateByImgClick) {
  1368. mfp.wrap.on('click'+ns, '.mfp-img', function() {
  1369. if(mfp.items.length > 1) {
  1370. mfp.next();
  1371. return false;
  1372. }
  1373. });
  1374. }
  1375. _document.on('keydown'+ns, function(e) {
  1376. if (e.keyCode === 37) {
  1377. if (gSt.langDir === 'rtl') mfp.next();
  1378. else mfp.prev();
  1379. } else if (e.keyCode === 39) {
  1380. if (gSt.langDir === 'rtl') mfp.prev();
  1381. else mfp.next();
  1382. }
  1383. });
  1384. mfp.updateGalleryButtons();
  1385. });
  1386. _mfpOn('UpdateStatus'+ns, function(/*e, data*/) {
  1387. mfp.updateGalleryButtons();
  1388. });
  1389. _mfpOn('UpdateStatus'+ns, function(e, data) {
  1390. if(data.text) {
  1391. data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
  1392. }
  1393. });
  1394. _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
  1395. var l = mfp.items.length;
  1396. values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
  1397. });
  1398. _mfpOn('BuildControls' + ns, function() {
  1399. if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
  1400. var arrowLeftDesc, arrowRightDesc, arrowLeftAction, arrowRightAction;
  1401. if (gSt.langDir === 'rtl') {
  1402. arrowLeftDesc = gSt.tNext;
  1403. arrowRightDesc = gSt.tPrev;
  1404. arrowLeftAction = 'next';
  1405. arrowRightAction = 'prev';
  1406. } else {
  1407. arrowLeftDesc = gSt.tPrev;
  1408. arrowRightDesc = gSt.tNext;
  1409. arrowLeftAction = 'prev';
  1410. arrowRightAction = 'next';
  1411. }
  1412. var markup = gSt.arrowMarkup,
  1413. arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, arrowLeftDesc).replace(/%action%/gi, arrowLeftAction).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),
  1414. arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, arrowRightDesc).replace(/%action%/gi, arrowRightAction).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);
  1415. if (gSt.langDir === 'rtl') {
  1416. mfp.arrowNext = arrowLeft;
  1417. mfp.arrowPrev = arrowRight;
  1418. } else {
  1419. mfp.arrowNext = arrowRight;
  1420. mfp.arrowPrev = arrowLeft;
  1421. }
  1422. arrowLeft.on('click', function() {
  1423. if (gSt.langDir === 'rtl') mfp.next();
  1424. else mfp.prev();
  1425. });
  1426. arrowRight.on('click', function() {
  1427. if (gSt.langDir === 'rtl') mfp.prev();
  1428. else mfp.next();
  1429. });
  1430. mfp.container.append(arrowLeft.add(arrowRight));
  1431. }
  1432. });
  1433. _mfpOn(CHANGE_EVENT+ns, function() {
  1434. if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);
  1435. mfp._preloadTimeout = setTimeout(function() {
  1436. mfp.preloadNearbyImages();
  1437. mfp._preloadTimeout = null;
  1438. }, 16);
  1439. });
  1440. _mfpOn(CLOSE_EVENT+ns, function() {
  1441. _document.off(ns);
  1442. mfp.wrap.off('click'+ns);
  1443. mfp.arrowRight = mfp.arrowLeft = null;
  1444. });
  1445. },
  1446. next: function() {
  1447. var newIndex = _getLoopedId(mfp.index + 1);
  1448. if (!mfp.st.gallery.loop && newIndex === 0 ) return false;
  1449. mfp.direction = true;
  1450. mfp.index = newIndex;
  1451. mfp.updateItemHTML();
  1452. },
  1453. prev: function() {
  1454. var newIndex = mfp.index - 1;
  1455. if (!mfp.st.gallery.loop && newIndex < 0) return false;
  1456. mfp.direction = false;
  1457. mfp.index = _getLoopedId(newIndex);
  1458. mfp.updateItemHTML();
  1459. },
  1460. goTo: function(newIndex) {
  1461. mfp.direction = (newIndex >= mfp.index);
  1462. mfp.index = newIndex;
  1463. mfp.updateItemHTML();
  1464. },
  1465. preloadNearbyImages: function() {
  1466. var p = mfp.st.gallery.preload,
  1467. preloadBefore = Math.min(p[0], mfp.items.length),
  1468. preloadAfter = Math.min(p[1], mfp.items.length),
  1469. i;
  1470. for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
  1471. mfp._preloadItem(mfp.index+i);
  1472. }
  1473. for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
  1474. mfp._preloadItem(mfp.index-i);
  1475. }
  1476. },
  1477. _preloadItem: function(index) {
  1478. index = _getLoopedId(index);
  1479. if(mfp.items[index].preloaded) {
  1480. return;
  1481. }
  1482. var item = mfp.items[index];
  1483. if(!item.parsed) {
  1484. item = mfp.parseEl( index );
  1485. }
  1486. _mfpTrigger('LazyLoad', item);
  1487. if(item.type === 'image') {
  1488. item.img = $('<img class="mfp-img" />').on('load.mfploader', function() {
  1489. item.hasSize = true;
  1490. }).on('error.mfploader', function() {
  1491. item.hasSize = true;
  1492. item.loadError = true;
  1493. _mfpTrigger('LazyLoadError', item);
  1494. }).attr('src', item.src);
  1495. }
  1496. item.preloaded = true;
  1497. },
  1498. /**
  1499. * Show/hide the gallery prev/next buttons if we're at the start/end, if looping is turned off
  1500. * Added by Joloco for Veg
  1501. */
  1502. updateGalleryButtons: function() {
  1503. if ( !mfp.st.gallery.loop && typeof mfp.arrowPrev === 'object' && mfp.arrowPrev !== null) {
  1504. if (mfp.index === 0) mfp.arrowPrev.hide();
  1505. else mfp.arrowPrev.show();
  1506. if (mfp.index === (mfp.items.length - 1)) mfp.arrowNext.hide();
  1507. else mfp.arrowNext.show();
  1508. }
  1509. },
  1510. }
  1511. });
  1512. /*>>gallery*/
  1513. /*>>retina*/
  1514. var RETINA_NS = 'retina';
  1515. $.magnificPopup.registerModule(RETINA_NS, {
  1516. options: {
  1517. replaceSrc: function(item) {
  1518. return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
  1519. },
  1520. ratio: 1 // Function or number. Set to 1 to disable.
  1521. },
  1522. proto: {
  1523. initRetina: function() {
  1524. if(window.devicePixelRatio > 1) {
  1525. var st = mfp.st.retina,
  1526. ratio = st.ratio;
  1527. ratio = !isNaN(ratio) ? ratio : ratio();
  1528. if(ratio > 1) {
  1529. _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
  1530. item.img.css({
  1531. 'max-width': item.img[0].naturalWidth / ratio,
  1532. 'width': '100%'
  1533. });
  1534. });
  1535. _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
  1536. item.src = st.replaceSrc(item, ratio);
  1537. });
  1538. }
  1539. }
  1540. }
  1541. }
  1542. });
  1543. /*>>retina*/
  1544. _checkInstance(); }));