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