PageSourceSearch

https://us-rse.org/assets/js/jquery.magnific-popup.js

js us-rse.org collected 2026-09-24 09:52:55 UTC 48,977 bytes, 1,860 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.