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