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