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