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