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