jquery.magnific-popup.js 45 KB

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