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