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