1/*! 2 * fancyBox - jQuery Plugin 3 * version: 2.0.6 (16/04/2012) 4 * @requires jQuery v1.6 or later 5 * 6 * Examples at http://fancyapps.com/fancybox/ 7 * License: www.fancyapps.com/fancybox/#license 8 * 9 * Copyright 2012 Janis Skarnelis - [email protected] 10 * 11 */ 12 13(function (window, document, $, undefined) { 14 "use strict"; 15 16 var W = $(window), 17 D = $(document), 18 F = $.fancybox = function () { 19 F.open.apply( this, arguments ); 20 }, 21 didResize = false, 22 resizeTimer = null, 23 isTouch = document.createTouch !== undefined, 24 isString = function(str) { 25 return $.type(str) === "string"; 26 }, 27 isPercentage = function(str) { 28 return isString(str) && str.indexOf('%') > 0; 29 }, 30 getValue = function(value, dim) { 31 if (dim && isPercentage(value)) { 32 value = F.getViewport()[ dim ] / 100 * parseInt(value, 10); 33 } 34 35 return Math.round(value) + 'px'; 36 }; 37 38 $.extend(F, { 39 // The current version of fancyBox 40 version: '2.0.5', 41 42 defaults: { 43 padding: 15, 44 margin: 20, 45 width: 820, 46 height: 800, 47 minWidth: 100, 48 minHeight: 100, 49 maxWidth: 9999, 50 maxHeight: 9999, 51 52 autoSize: true, 53 autoResize: !isTouch, 54 autoCenter : !isTouch, 55 fitToView: true, 56 aspectRatio: false, 57 topRatio: 0.5, 58 59 fixed: false, 60 scrolling: 'auto', // 'auto', 'yes' or 'no' 61 wrapCSS: '', 62 63 arrows: false, 64 closeBtn: true, 65 closeClick: false, 66 nextClick : false, 67 mouseWheel: true, 68 autoPlay: false, 69 playSpeed: 3000, 70 preload : 3, 71 72 modal: false, 73 loop: true, 74 ajax: { dataType: 'html', headers: { 'X-fancyBox': true } }, 75 keys: { 76 next: [13, 32, 34, 39, 40], // enter, space, page down, right arrow, down arrow 77 prev: [8, 33, 37, 38], // backspace, page up, left arrow, up arrow 78 close: [27] // escape key 79 }, 80 81 // Override some properties 82 index: 0, 83 type: null, 84 href: null, 85 content: null, 86 title: null, 87 88 // HTML templates 89 tpl: { 90 wrap: '<div class="fancybox-wrap"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>', 91 image: '<img class="fancybox-image" src="{href}" alt="" />', 92 iframe: '<iframe class="fancybox-iframe" name="fancybox-frame{rnd}" frameborder="0" hspace="0"' + ($.browser.msie ? ' allowtransparency="true"' : '') + '></iframe>', 93 swf: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="wmode" value="transparent" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{href}" /><embed src="{href}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="100%" height="100%" wmode="transparent"></embed></object>', 94 error: '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>', 95 closeBtn: '<div title="Close" class="fancybox-item fancybox-close"></div>', 96 next: '<a title="Next" class="fancybox-nav fancybox-next"><span></span></a>', 97 prev: '<a title="Previous" class="fancybox-nav fancybox-prev"><span></span></a>' 98 }, 99 100 // Properties for each animation type 101 // Opening fancyBox 102 openEffect: 'fade', // 'elastic', 'fade' or 'none' 103 openSpeed: 300, 104 openEasing: 'swing', 105 openOpacity: true, 106 openMethod: 'zoomIn', 107 108 // Closing fancyBox 109 closeEffect: 'fade', // 'elastic', 'fade' or 'none' 110 closeSpeed: 300, 111 closeEasing: 'swing', 112 closeOpacity: true, 113 closeMethod: 'zoomOut', 114 115 // Changing next gallery item 116 nextEffect: 'elastic', // 'elastic', 'fade' or 'none' 117 nextSpeed: 300, 118 nextEasing: 'swing', 119 nextMethod: 'changeIn', 120 121 // Changing previous gallery item 122 prevEffect: 'elastic', // 'elastic', 'fade' or 'none' 123 prevSpeed: 300, 124 prevEasing: 'swing', 125 prevMethod: 'changeOut', 126 127 // Enabled helpers 128 helpers: { 129 overlay: { 130 speedIn: 0, 131 speedOut: 300, 132 opacity: 0.8, 133 css: { 134 cursor: 'pointer' 135 }, 136 closeClick: true 137 }, 138 title: { 139 type: 'float' // 'float', 'inside', 'outside' or 'over' 140 } 141 }, 142 143 // Callbacks 144 onCancel: $.noop, // If canceling 145 beforeLoad: $.noop, // Before loading 146 afterLoad: $.noop, // After loading 147 beforeShow: $.noop, // Before changing in current item 148 afterShow: $.noop, // After opening 149 beforeClose: $.noop, // Before closing 150 afterClose: $.noop // After closing 151 }, 152 153 //Current state 154 group: {}, // Selected group 155 opts: {}, // Group options 156 coming: null, // Element being loaded 157 current: null, // Currently loaded element 158 isOpen: false, // Is currently open 159 isOpened: false, // Have been fully opened at least once 160 wrap: null, 161 skin: null, 162 outer: null, 163 inner: null, 164 165 player: { 166 timer: null, 167 isActive: false 168 }, 169 170 // Loaders 171 ajaxLoad: null, 172 imgPreload: null, 173 174 // Some collections 175 transitions: {}, 176 helpers: {}, 177 178 /* 179 * Static methods 180 */ 181 182 open: function (group, opts) { 183 //Kill existing instances 184 F.close(true); 185 186 //Normalize group 187 if (group && !$.isArray(group)) { 188 group = group instanceof $ ? $(group).get() : [group]; 189 } 190 191 F.isActive = true; 192 193 //Extend the defaults 194 F.opts = $.extend(true, {}, F.defaults, opts); 195 196 //All options are merged recursive except keys 197 if ($.isPlainObject(opts) && opts.keys !== undefined) { 198 F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; 199 } 200 201 F.group = group; 202 203 F._start(F.opts.index || 0); 204 }, 205 206 cancel: function () { 207 if (F.coming && false === F.trigger('onCancel')) { 208 return; 209 } 210 211 F.coming = null; 212 213 F.hideLoading(); 214 215 if (F.ajaxLoad) { 216 F.ajaxLoad.abort(); 217 } 218 219 F.ajaxLoad = null; 220 221 if (F.imgPreload) { 222 F.imgPreload.onload = F.imgPreload.onabort = F.imgPreload.onerror = null; 223 } 224 }, 225 226 close: function (a) { 227 F.cancel(); 228 229 if (!F.current || false === F.trigger('beforeClose')) { 230 return; 231 } 232 233 F.unbindEvents(); 234 235 //If forced or is still opening then remove immediately 236 if (!F.isOpen || (a && a[0] === true)) { 237 $('.fancybox-wrap').stop().trigger('onReset').remove(); 238 239 F._afterZoomOut(); 240 241 } else { 242 F.isOpen = F.isOpened = false; 243 244 $('.fancybox-item, .fancybox-nav').remove(); 245 246 F.wrap.stop(true).removeClass('fancybox-opened'); 247 F.inner.css('overflow', 'hidden'); 248 249 F.transitions[F.current.closeMethod](); 250 } 251 }, 252 253 // Start/stop slideshow 254 play: function (a) { 255 var clear = function () { 256 clearTimeout(F.player.timer); 257 }, 258 set = function () { 259 clear(); 260 261 if (F.current && F.player.isActive) { 262 F.player.timer = setTimeout(F.next, F.current.playSpeed); 263 } 264 }, 265 stop = function () { 266 clear(); 267 268 $('body').unbind('.player'); 269 270 F.player.isActive = false; 271 272 F.trigger('onPlayEnd'); 273 }, 274 start = function () { 275 if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { 276 F.player.isActive = true; 277 278 $('body').bind({ 279 'afterShow.player onUpdate.player': set, 280 'onCancel.player beforeClose.player': stop, 281 'beforeLoad.player': clear 282 });
283 284 set(); 285 286 F.trigger('onPlayStart'); 287 } 288 }; 289 290 if (F.player.isActive || (a && a[0] === false)) { 291 stop(); 292 } else { 293 start(); 294 } 295 }, 296 297 next: function () { 298 if (F.current) { 299 F.jumpto(F.current.index + 1); 300 } 301 }, 302 303 prev: function () { 304 if (F.current) { 305 F.jumpto(F.current.index - 1); 306 } 307 }, 308 309 jumpto: function (index) { 310 if (!F.current) { 311 return; 312 } 313 314 index = parseInt(index, 10); 315 316 if (F.group.length > 1 && F.current.loop) { 317 if (index >= F.group.length) { 318 index = 0; 319 320 } else if (index < 0) { 321 index = F.group.length - 1; 322 } 323 } 324 325 if (F.group[index] !== undefined) { 326 F.cancel(); 327 328 F._start(index); 329 } 330 }, 331 332 reposition: function (e, onlyAbsolute) { 333 var pos; 334 335 if (F.isOpen) { 336 pos = F._getPosition(onlyAbsolute); 337 338 if (e && e.type === 'scroll') { 339 delete pos.position; 340 341 F.wrap.stop(true, true).animate(pos, 200); 342 343 } else { 344 F.wrap.css(pos); 345 } 346 } 347 }, 348 349 update: function (e) { 350 if (!F.isOpen) { 351 return; 352 } 353 354 // Run this code after a delay for better performance 355 if (!didResize) { 356 resizeTimer = setTimeout(function () { 357 var current = F.current, anyway = !e || (e && e.type === 'orientationchange'); 358 359 if (didResize) { 360 didResize = false; 361 362 if (!current) { 363 return; 364 } 365 366 if ((!e || e.type !== 'scroll') || anyway) { 367 if (current.autoSize && current.type !== 'iframe') { 368 F.inner.height('auto'); 369 current.height = F.inner.height(); 370 } 371 372 if (current.autoResize || anyway) { 373 F._setDimension(); 374 } 375 376 if (current.canGrow && current.type !== 'iframe') { 377 F.inner.height('auto'); 378 } 379 } 380 381 if (current.autoCenter || anyway) { 382 F.reposition(e); 383 } 384 385 F.trigger('onUpdate'); 386 } 387 }, 200); 388 } 389 390 didResize = true; 391 }, 392 393 toggle: function () { 394 if (F.isOpen) { 395 F.current.fitToView = !F.current.fitToView; 396 397 F.update(); 398 } 399 }, 400 401 hideLoading: function () { 402 D.unbind('keypress.fb'); 403 404 $('#fancybox-loading').remove(); 405 }, 406 407 showLoading: function () { 408 F.hideLoading(); 409 410 //If user will press the escape-button, the request will be canceled 411 D.bind('keypress.fb', function(e) { 412 if (e.keyCode === 27) { 413 e.preventDefault(); 414 F.cancel(); 415 } 416 }); 417 418 $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body'); 419 }, 420 421 getViewport: function () { 422 // See http://bugs.jquery.com/ticket/6724 423 return { 424 x: W.scrollLeft(), 425 y: W.scrollTop(), 426 w: isTouch && window.innerWidth ? window.innerWidth : W.width(), 427 h: isTouch && window.innerHeight ? window.innerHeight : W.height() 428 }; 429 }, 430 431 // Unbind the keyboard / clicking actions 432 unbindEvents: function () { 433 if (F.wrap) { 434 F.wrap.unbind('.fb'); 435 } 436 437 D.unbind('.fb'); 438 W.unbind('.fb'); 439 }, 440 441 bindEvents: function () { 442 var current = F.current, 443 keys = current.keys; 444 445 if (!current) { 446 return; 447 } 448 449 W.bind('resize.fb orientationchange.fb' + (current.autoCenter && !current.fixed ? ' scroll.fb' : ''), F.update); 450 451 if (keys) { 452 D.bind('keydown.fb', function (e) { 453 var code, target = e.target || e.srcElement; 454 455 // Ignore key combinations and key events within form elements 456 if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { 457 code = e.keyCode; 458 459 if ($.inArray(code, keys.close) > -1) { 460 F.close(); 461 e.preventDefault(); 462 463 } else if ($.inArray(code, keys.next) > -1) { 464 F.next(); 465 e.preventDefault(); 466 467 } else if ($.inArray(code, keys.prev) > -1) { 468 F.prev(); 469 e.preventDefault(); 470 } 471 } 472 }); 473 } 474 475 if ($.fn.mousewheel && current.mouseWheel && F.group.length > 1) { 476 F.wrap.bind('mousewheel.fb', function (e, delta) { 477 var target = e.target || null; 478 479 if (delta !== 0 && (!target || target.clientHeight === 0 || (target.scrollHeight === target.clientHeight && target.scrollWidth === target.clientWidth))) { 480 e.preventDefault(); 481 482 F[delta > 0 ? 'prev' : 'next'](); 483 } 484 }); 485 } 486 }, 487 488 trigger: function (event, o) { 489 var ret, obj = o || F[ $.inArray(event, ['onCancel', 'beforeLoad', 'afterLoad']) > -1 ? 'coming' : 'current' ]; 490 491 if (!obj) { 492 return; 493 } 494 495 if ($.isFunction( obj[event] )) { 496 ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); 497 } 498 499 if (ret === false) { 500 return false; 501 } 502 503 if (obj.helpers) { 504 $.each(obj.helpers, function (helper, opts) { 505 if (opts && $.isPlainObject(F.helpers[helper]) && $.isFunction(F.helpers[helper][event])) { 506 F.helpers[helper][event](opts, obj); 507 } 508 }); 509 } 510 511 $.event.trigger(event + '.fb'); 512 }, 513 514 isImage: function (str) { 515 return isString(str) && str.match(/\.(jpe?g|gif|png|bmp)((\?|#).*)?$/i); 516 }, 517 518 isSWF: function (str) { 519 return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); 520 }, 521 522 _start: function (index) { 523 var coming = {}, 524 element = F.group[index] || null, 525 isDom, 526 href, 527 type, 528 rez, 529 hrefParts; 530 531 if (element && (element.nodeType || element instanceof $)) { 532 isDom = true; 533 534 if ($.metadata) { 535 coming = $(element).metadata(); 536 } 537 } 538 539 coming = $.extend(true, {}, F.opts, {index : index, element : element}, ($.isPlainObject(element) ? element : coming)); 540 541 // Re-check overridable options 542 $.each(['href', 'title', 'content', 'type'], function(i,v) { 543 coming[v] = F.opts[ v ] || (isDom && $(element).attr( v )) || coming[ v ] || null; 544 }); 545 546 // Convert margin property to array - top, right, bottom, left 547 if (typeof coming.margin === 'number') { 548 coming.margin = [coming.margin, coming.margin, coming.margin, coming.margin]; 549 } 550 551 // 'modal' propery is just a shortcut 552 if (coming.modal) { 553 $.extend(true, coming, { 554 closeBtn : false, 555 closeClick: false, 556 nextClick : false, 557 arrows : false, 558 mouseWheel : false, 559 keys : null, 560 helpers: { 561 overlay : { 562 css: { 563 cursor : 'auto' 564 }, 565 closeClick : false 566 } 567 } 568 }); 569 } 570 571 //Give a chance for callback or helpers to update coming item (type, title, etc) 572 F.coming = coming; 573 574 if (false === F.trigger('beforeLoad')) { 575 F.coming = null; 576 return; 577 } 578 579 type = coming.type; 580 href = coming.href || element; 581 582 ///Check if content type is set, if not, try to get 583 if (!type) { 584 if (isDom) { 585 type = $(element).data('fancybox-type'); 586 587 if (!type) { 588 rez = element.className.match(/fancybox\.(\w+)/); 589 type = rez ? rez[1] : null; 590 } 591 } 592 593 if (!type && isString(href)) { 594 if (F.isImage(href)) { 595 type = 'image'; 596 597 } else if (F.isSWF(href)) { 598 type = 'swf'; 599 600 } else if (href.match(/^#/)) { 601 type = 'inline'; 602 } 603 } 604 605 // ...if not - display element itself 606 if (!type) { 607 type = isDom ? 'inline' : 'html'; 608 } 609 610 coming.type = type; 611 } 612 613 // Check before try to load; 'inline' and 'html' types need content, others - href 614 if (type === 'inline' || type === 'html') { 615 if (!coming.content) { 616 if (type === 'inline') { 617 coming.content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7 618 619 } else { 620 coming.content = element; 621 } 622 } 623 624 if (!coming.content || !coming.content.length) { 625 type = null; 626 } 627 628 } else if (!href) { 629 type = null; 630 } 631 632 /* 633 * Add reference to the group, so it`s possible to access from callbacks, example: 634 * afterLoad : function() { 635 * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); 636 * } 637 */ 638 639 if (type === 'ajax' && isString(href)) { 640 hrefParts = href.split(/\s+/, 2); 641 642 href = hrefParts.shift(); 643 coming.selector = hrefParts.shift(); 644 } 645 646 coming.href = href; 647 coming.group = F.group;
648 coming.isDom = isDom; 649 650 switch (type) { 651 case 'image': 652 F._loadImage(); 653 break; 654 655 case 'ajax': 656 F._loadAjax(); 657 break; 658 659 case 'inline': 660 case 'iframe': 661 case 'swf': 662 case 'html': 663 F._afterLoad(); 664 break; 665 666 default: 667 F._error( 'type' ); 668 } 669 }, 670 671 _error: function ( type ) { 672 F.hideLoading(); 673 674 $.extend(F.coming, { 675 type : 'html', 676 autoSize : true, 677 minWidth : 0, 678 minHeight : 0, 679 padding : 15, 680 hasError : type, 681 content : F.coming.tpl.error 682 }); 683 684 F._afterLoad(); 685 }, 686 687 _loadImage: function () { 688 // Reset preload image so it is later possible to check "complete" property 689 var img = F.imgPreload = new Image(); 690 691 img.onload = function () { 692 this.onload = this.onerror = null; 693 694 F.coming.width = this.width; 695 F.coming.height = this.height; 696 697 F._afterLoad(); 698 }; 699 700 img.onerror = function () { 701 this.onload = this.onerror = null; 702 703 F._error( 'image' ); 704 }; 705 706 img.src = F.coming.href; 707 708 if (img.complete === undefined || !img.complete) { 709 F.showLoading(); 710 } 711 }, 712 713 _loadAjax: function () { 714 F.showLoading(); 715 716 F.ajaxLoad = $.ajax($.extend({}, F.coming.ajax, { 717 url: F.coming.href, 718 error: function (jqXHR, textStatus) { 719 if (F.coming && textStatus !== 'abort') { 720 F._error( 'ajax', jqXHR ); 721 722 } else { 723 F.hideLoading(); 724 } 725 }, 726 success: function (data, textStatus) { 727 if (textStatus === 'success') { 728 F.coming.content = data; 729 730 F._afterLoad(); 731 } 732 } 733 })); 734 }, 735 736 _preloadImages: function() { 737 var group = F.group, 738 current = F.current, 739 len = group.length, 740 item, 741 href, 742 i, 743 cnt = Math.min(current.preload, len - 1); 744 745 if (!current.preload || group.length < 2) { 746 return; 747 } 748 749 for (i = 1; i <= cnt; i += 1) { 750 item = group[ (current.index + i ) % len ]; 751 href = item.href || $( item ).attr('href') || item; 752 753 if (item.type === 'image' || F.isImage(href)) { 754 new Image().src = href; 755 } 756 } 757 }, 758 759 _afterLoad: function () { 760 F.hideLoading(); 761 762 if (!F.coming || false === F.trigger('afterLoad', F.current)) { 763 F.coming = false; 764 765 return; 766 } 767 768 if (F.isOpened) { 769 $('.fancybox-item, .fancybox-nav').remove(); 770 771 F.wrap.stop(true).removeClass('fancybox-opened'); 772 F.inner.css('overflow', 'hidden'); 773 774 F.transitions[F.current.prevMethod](); 775 776 } else { 777 $('.fancybox-wrap').stop().trigger('onReset').remove(); 778 779 F.trigger('afterClose'); 780 } 781 782 F.unbindEvents(); 783 784 F.isOpen = false; 785 F.current = F.coming; 786 787 //Build the neccessary markup 788 F.wrap = $(F.current.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + F.current.type + ' fancybox-tmp ' + F.current.wrapCSS).appendTo('body'); 789 F.skin = $('.fancybox-skin', F.wrap).css('padding', getValue(F.current.padding)); 790 F.outer = $('.fancybox-outer', F.wrap); 791 F.inner = $('.fancybox-inner', F.wrap); 792 793 F._setContent(); 794 }, 795 796 _setContent: function () { 797 var current = F.current, 798 content = current.content, 799 type = current.type, 800 minWidth = current.minWidth, 801 minHeight = current.minHeight, 802 maxWidth = current.maxWidth, 803 maxHeight = current.maxHeight, 804 loadingBay; 805 806 switch (type) { 807 case 'inline': 808 case 'ajax': 809 case 'html': 810 if (current.selector) { 811 content = $('<div>').html(content).find(current.selector); 812 813 } else if (content instanceof $) { 814 if (content.parent().hasClass('fancybox-inner')) { 815 content.parents('.fancybox-wrap').unbind('onReset'); 816 } 817 818 content = content.show().detach(); 819 820 $(F.wrap).bind('onReset', function () { 821 content.appendTo('body').hide(); 822 }); 823 } 824 825 if (current.autoSize) { 826 loadingBay = $('<div class="fancybox-wrap ' + F.current.wrapCSS + ' fancybox-tmp"></div>') 827 .appendTo('body') 828 .css({ 829 minWidth : getValue(minWidth, 'w'), 830 minHeight : getValue(minHeight, 'h'), 831 maxWidth : getValue(maxWidth, 'w'), 832 maxHeight : getValue(maxHeight, 'h') 833 }) 834 .append(content); 835 836 current.width = loadingBay.width(); 837 current.height = loadingBay.height(); 838 839 // Re-check to fix 1px bug in some browsers 840 loadingBay.width( F.current.width ); 841 842 if (loadingBay.height() > current.height) { 843 loadingBay.width(current.width + 1); 844 845 current.width = loadingBay.width(); 846 current.height = loadingBay.height(); 847 } 848 849 content = loadingBay.contents().detach(); 850 851 loadingBay.remove(); 852 } 853 854 break; 855 856 case 'image': 857 content = current.tpl.image.replace('{href}', current.href); 858 859 current.aspectRatio = true; 860 break; 861 862 case 'swf': 863 content = current.tpl.swf.replace(/\{width\}/g, current.width).replace(/\{height\}/g, current.height).replace(/\{href\}/g, current.href); 864 break; 865 866 case 'iframe': 867 content = $(current.tpl.iframe.replace('{rnd}', new Date().getTime()) ) 868 .attr('scrolling', current.scrolling) 869 .attr('src', current.href); 870 871 current.scrolling = isTouch ? 'scroll' : 'auto'; 872 873 break; 874 } 875 876 if (type === 'image' || type === 'swf') { 877 current.autoSize = false; 878 current.scrolling = 'visible'; 879 } 880 881 if (type === 'iframe' && current.autoSize) { 882 F.showLoading(); 883 884 F._setDimension(); 885 886 F.inner.css('overflow', current.scrolling); 887 888 content.bind({ 889 onCancel : function() { 890 $(this).unbind(); 891 892 F._afterZoomOut(); 893 }, 894 load : function() { 895 F.hideLoading(); 896 897 try { 898 if (this.contentWindow.document.location) { 899 F.current.height = $(this).contents().find('body').height(); 900 } 901 } catch (e) { 902 F.current.autoSize = false; 903 } 904 905 F[ F.isOpen ? '_afterZoomIn' : '_beforeShow'](); 906 } 907 }).appendTo(F.inner); 908 909 } else { 910 F.inner.append(content); 911 912 F._beforeShow(); 913 } 914 }, 915 916 _beforeShow : function() { 917 F.coming = null; 918 919 //Give a chance for helpers or callbacks to update elements 920 F.trigger('beforeShow'); 921 922 //Set initial dimensions and hide
923 F._setDimension(); 924 F.wrap.hide().removeClass('fancybox-tmp'); 925 926 F.bindEvents(); 927 928 F._preloadImages(); 929 930 F.transitions[ F.isOpened ? F.current.nextMethod : F.current.openMethod ](); 931 }, 932 933 _setDimension: function () { 934 var wrap = F.wrap, 935 inner = F.inner, 936 current = F.current, 937 viewport = F.getViewport(), 938 margin = current.margin, 939 padding2 = current.padding * 2, 940 width = current.width, 941 height = current.height, 942 maxWidth = current.maxWidth + padding2, 943 maxHeight = current.maxHeight + padding2, 944 minWidth = current.minWidth + padding2, 945 minHeight = current.minHeight + padding2, 946 ratio, 947 height_; 948 949 viewport.w -= (margin[1] + margin[3]); 950 viewport.h -= (margin[0] + margin[2]); 951 952 if (isPercentage(width)) { 953 width = (((viewport.w - padding2) * parseFloat(width)) / 100); 954 } 955 956 if (isPercentage(height)) { 957 height = (((viewport.h - padding2) * parseFloat(height)) / 100); 958 } 959 960 ratio = width / height; 961 width += padding2; 962 height += padding2; 963 964 if (current.fitToView) { 965 maxWidth = Math.min(viewport.w, maxWidth); 966 maxHeight = Math.min(viewport.h, maxHeight); 967 } 968 969 if (current.aspectRatio) { 970 if (width > maxWidth) { 971 width = maxWidth; 972 height = ((width - padding2) / ratio) + padding2; 973 } 974 975 if (height > maxHeight) { 976 height = maxHeight; 977 width = ((height - padding2) * ratio) + padding2; 978 } 979 980 if (width < minWidth) { 981 width = minWidth; 982 height = ((width - padding2) / ratio) + padding2; 983 } 984 985 if (height < minHeight) { 986 height = minHeight; 987 width = ((height - padding2) * ratio) + padding2; 988 } 989 990 } else { 991 width = Math.max(minWidth, Math.min(width, maxWidth)); 992 height = Math.max(minHeight, Math.min(height, maxHeight)); 993 } 994 995 width = Math.round(width); 996 height = Math.round(height); 997 998 //Reset dimensions 999 $(wrap.add(inner)).width('auto').height('auto'); 1000 1001 inner.width(width - padding2).height(height - padding2); 1002 wrap.width(width); 1003 1004 height_ = wrap.height(); // Real wrap height 1005 1006 //Fit wrapper inside 1007 if (width > maxWidth || height_ > maxHeight) { 1008 while ((width > maxWidth || height_ > maxHeight) && width > minWidth && height_ > minHeight) { 1009 height = height - 10; 1010 1011 if (current.aspectRatio) { 1012 width = Math.round(((height - padding2) * ratio) + padding2); 1013 1014 if (width < minWidth) { 1015 width = minWidth; 1016 height = ((width - padding2) / ratio) + padding2; 1017 } 1018 1019 } else { 1020 width = width - 10; 1021 } 1022 1023 inner.width(width - padding2).height(height - padding2); 1024 wrap.width(width); 1025 1026 height_ = wrap.height(); 1027 } 1028 } 1029 1030 current.dim = { 1031 width : getValue(width), 1032 height : getValue(height_) 1033 }; 1034 1035 current.canGrow = current.autoSize && height > minHeight && height < maxHeight; 1036 current.canShrink = false; 1037 current.canExpand = false; 1038 1039 if ((width - padding2) < current.width || (height - padding2) < current.height) { 1040 current.canExpand = true; 1041 1042 } else if ((width > viewport.w || height_ > viewport.h) && width > minWidth && height > minHeight) { 1043 current.canShrink = true; 1044 } 1045 1046 F.innerSpace = height_ - padding2 - inner.height(); 1047 }, 1048 1049 _getPosition: function (onlyAbsolute) { 1050 var current = F.current, 1051 viewport = F.getViewport(), 1052 margin = current.margin, 1053 width = F.wrap.width() + margin[1] + margin[3], 1054 height = F.wrap.height() + margin[0] + margin[2], 1055 rez = { 1056 position: 'absolute', 1057 top : margin[0] + viewport.y, 1058 left : margin[3] + viewport.x 1059 }; 1060 1061 if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { 1062 rez = { 1063 position: 'fixed', 1064 top : margin[0], 1065 left : margin[3] 1066 }; 1067 } 1068 1069 rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))); 1070 rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * 0.5))); 1071 1072 return rez; 1073 }, 1074 1075 _afterZoomIn: function () { 1076 var current = F.current, scrolling = current ? current.scrolling : 'no'; 1077 1078 if (!current) { 1079 return; 1080 } 1081 1082 F.isOpen = F.isOpened = true; 1083 1084 F.wrap.addClass('fancybox-opened'); 1085 1086 F.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling)); 1087 1088 F.trigger('afterShow'); 1089 1090 F.update(); 1091 1092 //Assign a click event 1093 if (current.closeClick || current.nextClick) { 1094 F.inner.css('cursor', 'pointer').bind('click.fb', function(e) { 1095 if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { 1096 F[ current.closeClick ? 'close' : 'next' ](); 1097 } 1098 }); 1099 } 1100 1101 //Create a close button 1102 if (current.closeBtn) { 1103 $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', F.close); 1104 } 1105 1106 //Create navigation arrows 1107 if (current.arrows && F.group.length > 1) { 1108 if (current.loop || current.index > 0) { 1109 $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); 1110 } 1111 1112 if (current.loop || current.index < F.group.length - 1) { 1113 $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); 1114 } 1115 } 1116 1117 if (F.opts.autoPlay && !F.player.isActive) { 1118 F.opts.autoPlay = false; 1119 1120 F.play(); 1121 } 1122 }, 1123 1124 _afterZoomOut: function () { 1125 var current = F.current; 1126 1127 F.wrap.trigger('onReset').remove(); 1128 1129 $.extend(F, { 1130 group: {}, 1131 opts: {}, 1132 current: null, 1133 isActive: false, 1134 isOpened: false, 1135 isOpen: false, 1136 wrap: null, 1137 skin: null, 1138 outer: null, 1139 inner: null 1140 }); 1141 1142 F.trigger('afterClose', current); 1143 } 1144 }); 1145 1146 /* 1147 * Default transitions 1148 */ 1149 1150 F.transitions = { 1151 getOrigPosition: function () { 1152 var current = F.current, 1153 element = current.element, 1154 padding = current.padding, 1155 orig = $(current.orig), 1156 pos = {}, 1157 width = 50, 1158 height = 50, 1159 viewport; 1160 1161 if (!orig.length && current.isDom && $(element).is(':visible')) { 1162 orig = $(element).find('img:first'); 1163 1164 if (!orig.length) { 1165 orig = $(element); 1166 } 1167 } 1168 1169 if (orig.length) { 1170 pos = orig.offset(); 1171 1172 if (orig.is('img')) { 1173 width = orig.outerWidth(); 1174 height = orig.outerHeight(); 1175 } 1176 1177 } else { 1178 viewport = F.getViewport(); 1179 1180 pos.top = viewport.y + (viewport.h - height) * 0.5; 1181 pos.left = viewport.x + (viewport.w - width) * 0.5; 1182 } 1183 1184 pos = { 1185 top : getValue(pos.top - padding), 1186 left : getValue(pos.left - padding), 1187 width : getValue(width + padding * 2), 1188 height : getValue(height + padding * 2) 1189 }; 1190 1191 return pos; 1192 }, 1193 1194 step: function (now, fx) { 1195 var prop = fx.prop, value, ratio; 1196 1197 if (prop === 'width' || prop === 'height') {
1198 value = Math.ceil(now - (F.current.padding * 2)); 1199 1200 if (prop === 'height') { 1201 ratio = (now - fx.start) / (fx.end - fx.start); 1202 1203 if (fx.start > fx.end) { 1204 ratio = 1 - ratio; 1205 } 1206 1207 value -= F.innerSpace * ratio; 1208 } 1209 1210 F.inner[prop](value); 1211 } 1212 }, 1213 1214 zoomIn: function () { 1215 var wrap = F.wrap, 1216 current = F.current, 1217 effect = current.openEffect, 1218 elastic = effect === 'elastic', 1219 dim = current.dim, 1220 startPos = $.extend({}, dim, F._getPosition( elastic )), 1221 endPos = $.extend({opacity : 1}, startPos); 1222 1223 //Remove "position" property that breaks older IE 1224 delete endPos.position; 1225 1226 if (elastic) { 1227 startPos = this.getOrigPosition(); 1228 1229 if (current.openOpacity) { 1230 startPos.opacity = 0; 1231 } 1232 1233 F.outer.add(F.inner).width('auto').height('auto'); 1234 1235 } else if (effect === 'fade') { 1236 startPos.opacity = 0; 1237 } 1238 1239 wrap.css(startPos) 1240 .show() 1241 .animate(endPos, { 1242 duration : effect === 'none' ? 0 : current.openSpeed, 1243 easing : current.openEasing, 1244 step : elastic ? this.step : null, 1245 complete : F._afterZoomIn 1246 }); 1247 }, 1248 1249 zoomOut: function () { 1250 var wrap = F.wrap, 1251 current = F.current, 1252 effect = current.openEffect, 1253 elastic = effect === 'elastic', 1254 endPos = {opacity : 0}; 1255 1256 if (elastic) { 1257 if (wrap.css('position') === 'fixed') { 1258 wrap.css(F._getPosition(true)); 1259 } 1260 1261 endPos = this.getOrigPosition(); 1262 1263 if (current.closeOpacity) { 1264 endPos.opacity = 0; 1265 } 1266 } 1267 1268 wrap.animate(endPos, { 1269 duration : effect === 'none' ? 0 : current.closeSpeed, 1270 easing : current.closeEasing, 1271 step : elastic ? this.step : null, 1272 complete : F._afterZoomOut 1273 }); 1274 }, 1275 1276 changeIn: function () { 1277 var wrap = F.wrap, 1278 current = F.current, 1279 effect = current.nextEffect, 1280 elastic = effect === 'elastic', 1281 startPos = F._getPosition( elastic ), 1282 endPos = { opacity : 1 }; 1283 1284 startPos.opacity = 0; 1285 1286 if (elastic) { 1287 startPos.top = getValue(parseInt(startPos.top, 10) - 200); 1288 endPos.top = '+=200px'; 1289 } 1290 1291 wrap.css(startPos) 1292 .show() 1293 .animate(endPos, { 1294 duration : effect === 'none' ? 0 : current.nextSpeed, 1295 easing : current.nextEasing, 1296 complete : F._afterZoomIn 1297 }); 1298 }, 1299 1300 changeOut: function () { 1301 var wrap = F.wrap, 1302 current = F.current, 1303 effect = current.prevEffect, 1304 endPos = { opacity : 0 }, 1305 cleanUp = function () { 1306 $(this).trigger('onReset').remove(); 1307 }; 1308 1309 wrap.removeClass('fancybox-opened'); 1310 1311 if (effect === 'elastic') { 1312 endPos.top = '+=200px'; 1313 } 1314 1315 wrap.animate(endPos, { 1316 duration : effect === 'none' ? 0 : current.prevSpeed, 1317 easing : current.prevEasing, 1318 complete : cleanUp 1319 }); 1320 } 1321 }; 1322 1323 /* 1324 * Overlay helper 1325 */ 1326 1327 F.helpers.overlay = { 1328 overlay: null, 1329 1330 update: function () { 1331 var width, scrollWidth, offsetWidth; 1332 1333 //Reset width/height so it will not mess 1334 this.overlay.width('100%').height('100%'); 1335 1336 if ($.browser.msie || isTouch) { 1337 scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth); 1338 offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); 1339 1340 width = scrollWidth < offsetWidth ? W.width() : scrollWidth; 1341 1342 } else { 1343 width = D.width(); 1344 } 1345 1346 this.overlay.width(width).height(D.height()); 1347 }, 1348 1349 beforeShow: function (opts) { 1350 if (this.overlay) { 1351 return; 1352 } 1353 1354 opts = $.extend(true, {}, F.defaults.helpers.overlay, opts); 1355 1356 this.overlay = $('<div id="fancybox-overlay"></div>').css(opts.css).appendTo('body'); 1357 1358 if (opts.closeClick) { 1359 this.overlay.bind('click.fb', F.close); 1360 } 1361 1362 if (F.current.fixed && !isTouch) { 1363 this.overlay.addClass('overlay-fixed'); 1364 1365 } else { 1366 this.update(); 1367 1368 this.onUpdate = function () { 1369 this.update(); 1370 }; 1371 } 1372 1373 this.overlay.fadeTo(opts.speedIn, opts.opacity); 1374 }, 1375 1376 afterClose: function (opts) { 1377 if (this.overlay) { 1378 this.overlay.fadeOut(opts.speedOut || 0, function () { 1379 $(this).remove(); 1380 }); 1381 } 1382
1383 this.overlay = null; 1384 } 1385 }; 1386 1387 /* 1388 * Title helper 1389 */ 1390 1391 F.helpers.title = { 1392 beforeShow: function (opts) { 1393 var title, text = F.current.title; 1394 1395 if (text) { 1396 title = $('<div class="fancybox-title fancybox-title-' + opts.type + '-wrap">' + text + '</div>').appendTo('body'); 1397 1398 if (opts.type === 'float') { 1399 //This helps for some browsers 1400 title.width(title.width()); 1401 1402 title.wrapInner('<span class="child"></span>'); 1403 1404 //Increase bottom margin so this title will also fit into viewport 1405 F.current.margin[2] += Math.abs(parseInt(title.css('margin-bottom'), 10)); 1406 } 1407 1408 title.appendTo(opts.type === 'over' ? F.inner : (opts.type === 'outside' ? F.wrap : F.skin)); 1409 } 1410 } 1411 }; 1412 1413 // jQuery plugin initialization 1414 $.fn.fancybox = function (options) { 1415 var that = $(this), 1416 selector = this.selector || '', 1417 index, 1418 run = function(e) { 1419 var what = this, idx = index, relType, relVal; 1420 1421 if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !$(what).is('.fancybox-wrap')) { 1422 e.preventDefault(); 1423 1424 relType = options.groupAttr || 'data-fancybox-group'; 1425 relVal = $(what).attr(relType); 1426 1427 if (!relVal) { 1428 relType = 'rel'; 1429 relVal = what[ relType ]; 1430 } 1431 1432 if (relVal && relVal !== '' && relVal !== 'nofollow') { 1433 what = selector.length ? $(selector) : that; 1434 what = what.filter('[' + relType + '="' + relVal + '"]'); 1435 idx = what.index(this); 1436 } 1437 1438 options.index = idx; 1439 1440 F.open(what, options); 1441 } 1442 }; 1443 1444 options = options || {}; 1445 index = options.index || 0; 1446 1447 if (selector) { 1448 D.undelegate(selector, 'click.fb-start').delegate(selector, 'click.fb-start', run); 1449 1450 } else { 1451 that.unbind('click.fb-start').bind('click.fb-start', run); 1452 } 1453 1454 return this; 1455 }; 1456 1457 // Test for fixedPosition needs a body at doc ready 1458 $(document).ready(function() { 1459 F.defaults.fixed = $.support.fixedPosition || (!($.browser.msie && $.browser.version <= 6) && !isTouch); 1460 }); 1461 1462}(window, document, jQuery));
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.