1/** 2 * jQuery Lightbox Plugin (balupton edition) - Lightboxes for jQuery 3 * Copyright (C) 2008 Benjamin Arthur Lupton 4 * http://jquery.com/plugins/project/jquerylightbox_bal 5 * 6 * This file is part of jQuery Lightbox (balupton edition). 7 * 8 * jQuery Lightbox (balupton edition) is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as 10 * published by the Free Software Foundation, either version 3 of the 11 * License, or (at your option) any later version. 12 * 13 * jQuery Lightbox (balupton edition) is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with jQuery Lightbox (balupton edition). If not, see <http://www.gnu.org/licenses/>. 20 * 21 * @name jquery_lightbox: jquery.lightbox.js 22 * @package jQuery Lightbox Plugin (balupton edition) 23 * @version 1.3.0-rc1 24 * @date August 24, 2008 25 * @category jQuery plugin 26 * @author Benjamin "balupton" Lupton {@link http://www.balupton.com} 27 * @copyright (c) 2008 Benjamin Arthur Lupton {@link http://www.balupton.com} 28 * @license GNU Affero General Public License - {@link http://www.gnu.org/licenses/agpl.html} 29 * @example Visit {@link http://jquery.com/plugins/project/jquerylightbox_bal} for more information. 30 */ 31 32// Start of our jQuery Plugin 33(function($) 34{ // Create our Plugin function, with $ as the argument (we pass the jQuery object over later) 35 // More info: http://docs.jquery.com/Plugins/Authoring#Custom_Alias 36 37 // Debug 38 $.log = $.log || function ( options ) 39 { // Can we debug? - Do we have firebug 40 var con = null; 41 if ( typeof console !== 'undefined' && typeof $.log !== 'undefined' ) 42 { con = console; } 43 else if ( typeof window.console !== 'undefined' && typeof window.$.log !== 'undefined') 44 { con = window.console; } 45 46 // Do the log 47 if ( con ) 48 { // Do we support arguments? 49 if ( typeof arguments !== 'undefined' && arguments.length > 1) 50 { con.log(arguments); return arguments; } 51 else 52 { con.log(options); return options; } 53 } 54 }; 55 56 // Pre-Req 57 $.params_to_json = $.params_to_json || function ( params ) 58 { // Turns a params string or url into an array of params 59 // Adjust 60 params = String(params); 61 // Remove url if need be 62 params = params.substring(params.indexOf('?')+1); 63 // params = params.substring(params.indexOf('#')+1); 64 // Change + to %20, the %20 is fixed up later with the decode 65 params = params.replace(/\+/g, '%20'); 66 // Do we have JSON string 67 if ( params.substring(0,1) === '{' && params.substring(params.length-1) === '}' ) 68 { // We have a JSON string 69 return eval(decodeURIComponent(params)); 70 } 71 // We have a params string 72 params = params.split(/\&|\&\;/); 73 var json = {}; 74 // We have params 75 for ( var i = 0, n = params.length; i < n; ++i ) 76 { 77 // Adjust 78 var param = params[i] || null; 79 if ( param === null ) { continue; } 80 param = param.split('='); 81 if ( param === null ) { continue; } 82 // ^ We now have "var=blah" into ["var","blah"] 83 84 // Get 85 var key = param[0] || null; 86 if ( key === null ) { continue; } 87 if ( typeof param[1] === 'undefined' ) { continue; } 88 var value = param[1]; 89 // ^ We now have the parts 90 91 // Fix 92 key = decodeURIComponent(key); 93 value = decodeURIComponent(value); 94 try { 95 // value can be converted 96 value = eval(value); 97 } catch ( e ) { 98 // value is a normal string 99 } 100 101 // Set 102 // console.log({'key':key,'value':value}, split); 103 var keys = key.split('.'); 104 if ( keys.length === 1 ) 105 { // Simple 106 json[key] = value; 107 } 108 else 109 { // Advanced 110 var path = ''; 111 for ( ii in keys ) 112 { // 113 key = keys[ii]; 114 path += '.'+key; 115 eval('json'+path+' = json'+path+' || {}'); 116 } 117 eval('json'+path+' = value'); 118 } 119 // ^ We now have the parts added to your JSON object 120 } 121 return json; 122 }; 123 124 // Declare our class 125 $.LightboxClass = function ( ) 126 { // This is the handler for our constructor 127 this.construct(); 128 }; 129 130 // Extend jQuery elements for Lightbox 131 $.fn.lightbox = function ( options ) 132 { // Init a el for Lightbox 133 // Eg. $('#gallery a').lightbox(); 134 135 // If need be: Instantiate $.LightboxClass to $.Lightbox 136 $.Lightbox = $.Lightbox || new $.LightboxClass(); 137 138 // Handle IE6 appropriatly 139 if ( $.Lightbox.ie6 && !$.Lightbox.ie6_support ) 140 { // We are IE6 and we want to ignore 141 return this; // chain 142 } 143 144 // Establish options 145 options = $.extend({start:false,events:true} /* default options */, options); 146 147 // Get group 148 var group = $(this); 149 150 // Events? 151 if ( options.events ) 152 { // Add events 153 $(group).unbind().click(function(){ 154 // Get obj 155 var obj = $(this); 156 // Get rel 157 // var rel = $(obj).attr('rel'); 158 // Init group 159 if ( !$.Lightbox.init($(obj)[0], group) ) 160 { return false; } 161 // Display lightbox 162 if ( !$.Lightbox.start() ) 163 { return false; } 164 // Cancel href 165 return false;
166 }); 167 // Add style 168 $(group).addClass('lightbox-enabled'); 169 } 170 171 // Start? 172 if ( options.start ) 173 { // Start 174 // Get obj 175 var obj = $(this); 176 // Get rel 177 // var rel = $(obj).attr('rel'); 178 // Init group 179 if ( !$.Lightbox.init($(obj)[0], group) ) 180 { return this; } 181 // Display lightbox 182 if ( !$.Lightbox.start() ) 183 { return this; } 184 } 185 186 // And chain 187 return this; 188 }; 189 190 // Define our class 191 $.extend($.LightboxClass.prototype, 192 { // Our LightboxClass definition 193 194 // ----------------- 195 // Everyting to do with images 196 197 images: { 198 199 // ----------------- 200 // Variables 201 202 // Our array of images 203 list:[], /* [ { 204 src: 'url to image', 205 link: 'a link to a page', 206 title: 'title of the image', 207 name: 'name of the image', 208 description: 'description of the image' 209 } ], */ 210 211 // The current active image 212 image: false, 213 214 // ----------------- 215 // Functions 216 217 prev: function ( image ) 218 { // Get previous image 219 220 // Get previous from current? 221 if ( typeof image === 'undefined' ) 222 { image = this.active(); 223 if ( !image ) { return image; } 224 } 225 226 // Is there a previous? 227 if ( this.first(image) ) 228 { return false; } 229 230 // Get the previous 231 return this.get(image.index-1); 232 }, 233 234 next: function ( image ) 235 { // Get next image 236 237 // Get next from current? 238 if ( typeof image === 'undefined' ) 239 { image = this.active(); 240 if ( !image ) { return image; } 241 } 242 243 // Is there a next? 244 if ( this.last(image) ) 245 { return false; } 246 247 // Get the next 248 return this.get(image.index+1); 249 }, 250 251 first: function ( image ) 252 { // 253 // Get the first image? 254 if ( typeof image === 'undefined' ) 255 { return this.get(0); } 256 257 // Are we the first? 258 return image.index === 0; 259 }, 260 261 last: function ( image ) 262 { // 263 // Get the last image? 264 if ( typeof image === 'undefined' ) 265 { return this.get(this.size()-1); } 266 267 // Are we the last? 268 return image.index === this.size()-1; 269 }, 270 271 single: function ( ) 272 { // Are we only one 273 return this.size() === 1; 274 }, 275 276 size: function ( ) 277 { // How many images do we have 278 return this.list.length; 279 }, 280 281 empty: function ( ) 282 { // Are we empty 283 return this.size() === 0; 284 }, 285 286 clear: function ( ) 287 { // Clear image arrray 288 this.list = []; 289 this.image = false; 290 }, 291 292 active: function ( image ) 293 { // Set or get the active image 294 // Use false to reset 295 296 // Get the active image? 297 if ( typeof image === 'undefined' ) 298 { return this.image; } 299 300 // Set the ative image 301 if ( image !== false ) 302 { // Make sure image exists 303 image = this.get(image); 304 if ( !image ) 305 { // Error 306 return image; 307 } 308 } 309 310 // Set the active image 311 this.image = image; 312 return true; 313 }, 314 315 add: function ( obj ) 316 { 317 // Do we need to recurse? 318 if ( obj[0] ) 319 { // We have a lot of images 320 for ( var i = 0; i < obj.length; i++ ) 321 { this.add(obj[i]); } 322 return true; 323 } 324 325 // Default image 326 327 // Try and create a image 328 var image = this.create(obj); 329 if ( !image ) { return image; } 330 331 // Set image index 332 image.index = this.size(); 333 334 // Push image 335 this.list.push(image); 336 337 // Success 338 return true; 339 }, 340 341 create: function ( obj ) 342 { // Create image 343 344 // Define 345 var image = { // default 346 src: '', 347 title: 'Untitled', 348 description: '', 349 name: '', 350 index: -1, 351 color: null, 352 width: null, 353 height: null, 354 image: true 355 }; 356 357 // Create 358 if ( obj.image ) 359 { // Already a image, so copy over values 360 image.src = obj.src || image.src; 361 image.title = obj.title || image.title; 362 image.description = obj.description || image.description; 363 image.name = obj.name || image.name; 364 image.color = obj.color || image.color; 365 image.width = obj.width || image.width; 366 image.height = obj.height || image.height; 367 image.index = obj.index || image.index; 368 } 369 else if ( obj.tagName ) 370 { // We are an element 371 obj = $(obj); 372 if ( obj.attr('src') || obj.attr('href') ) 373 { 374 image.src = obj.attr('src') || obj.attr('href'); 375 image.title = obj.attr('title') || obj.attr('alt') || image.title; 376 image.name = obj.attr('name') || ''; 377 image.color = obj.css('background-color'); 378 // Extract description from title
379 var s = image.title.indexOf(': '); 380 if ( s > 0 ) 381 { // Description exists 382 image.description = image.title.substring(s+2) || image.description; 383 image.title = image.title.substring(0,s) || image.title; 384 } 385 } 386 else 387 { // Unsupported element 388 image = false; 389 } 390 } 391 else 392 { // Unknown 393 image = false; 394 } 395 396 if ( !image ) 397 { // Error 398 $.log('ERROR', 'We dont know what we have:', obj); 399 return false; 400 } 401 402 // Success 403 return image; 404 }, 405 406 get: function ( image ) 407 { // Get the active, or specified image 408 409 // Establish image 410 if ( typeof image === 'undefined' || image === null ) 411 { // Get the active image 412 return this.active(); 413 } 414 else 415 if ( typeof image === 'number' ) 416 { // We have a index 417 418 // Get image 419 image = this.list[image] || false; 420 } 421 else 422 { // Create 423 image = this.create(image); 424 if ( !image ) { return false; } 425 426 // Find 427 var f = false; 428 for ( var i = 0; i < this.size(); i++ ) 429 { 430 var c = this.list[i]; 431 if ( c.src === image.src && c.title === image.title && c.description === image.description ) 432 { f = c; } 433 } 434 435 // Found? 436 image = f; 437 } 438 439 // Determine image 440 if ( !image ) 441 { // Image doesn't exist 442 $.log('ERROR', 'The desired image doesn\'t exist: ', image, this.list); 443 return false; 444 } 445 446 // Return image 447 return image; 448 }, 449 450 debug: function ( ) 451 { 452 return $.Lightbox.debug(arguments); 453 } 454 455 }, 456 457 // ----------------- 458 // Options 459 460 constructed: false, 461 462 src: null, // the source location of our js file 463 baseurl: null, 464 465 files: { 466 // If you are doing a repack with packer (http://dean.edwards.name/packer/) then append ".packed" onto the js and css files before you pack it. 467 js: { 468 lightbox: 'js/jquery.lightbox.js', 469 colorBlend: 'js/jQuery.colorBlend.pack.js' 470 }, 471 css: { 472 lightbox: 'css/jquery.lightbox.css' 473 }, 474 images: { 475 prev: 'images/prev.gif', 476 next: 'images/next.gif', 477 blank: 'images/blank.gif', 478 loading: 'images/loading.gif' 479 } 480 }, 481 482 text: { 483 // For translating 484 image: 'Image', 485 of: 'of', 486 close: 'Close X', 487 closeInfo: 'You can also click anywhere outside the image to close.', 488 download: 'Direct link to download the image.', 489 help: { 490 close: 'www.webexhibits.org/causesofcolor', 491 interact: 'click anywhere to close' 492 }, 493 about: { 494 text: 'jQuery Lightbox Plugin (balupton edition)', 495 title: 'Licenced under the GNU Affero General Public License.', 496 link: 'http://jquery.com/plugins/project/jquerylightbox_bal' 497 } 498 }, 499 show_linkback: false, 500 501 keys: { 502 close: 'c', 503 prev: 'p', 504 next: 'n' 505 }, 506 507 handlers: { 508 // For custom actions 509 show: null 510 }, 511 512 opacity: 0.9, 513 padding: null, // if null - autodetect 514 515 speed: 50, // Duration of effect, milliseconds 516 517 rel: 'lightbox', // What to look for in the rels 518 519 auto_relify: true, // should we automaticly do the rels? 520 521 scroll: 'follow', // should the lightbox scroll with the page? 522 523 ie6: null, // are we ie6? 524 ie6_support: true, // have ie6 support 525 ie6_upgrade: true, // show ie6 upgrade message 526 527 colorBlend: null, // null - auto-detect, true - force, false - no 528 529 // names of the options that can be modified 530 options: ['ie6_support', 'ie6_upgrade', 'colorBlend', 'baseurl', 'files', 'text', 'show_linkback', 'keys', 'opacity', 'padding', 'speed', 'rel', 'auto_relify', 'scroll_with'], 531 532 // ----------------- 533 // Functions 534 535 construct: function ( options ) 536 { // Construct our Lightbox 537 538 // ------------------- 539 // Prepare 540 541 // Initial construct 542 var initial = typeof this.constructed === 'undefined' || this.constructed === false; 543 this.constructed = true; 544 545 // Perform domReady 546 var domReady = initial; 547 548 // Prepare options 549 options = $.extend({}, options); 550 551 // ------------------- 552 // Handle files 553 554 // Add baseurl 555 if ( initial && (typeof options.files === 'undefined') ) 556 { // Load the files like default 557 558 // Get the src of the first script tag that includes our js file (with or without an appendix) 559 this.src = $('script[src*='+this.files.js.lightbox+']:first').attr('src'); 560 561 // Make sure we found ourselves 562 if ( !this.src ) 563 { // We didn't 564 // $.log('WARNING', 'Lightbox was not able to find it\'s javascript script tag necessary for auto-inclusion.'); 565 // We don't work with files anymore, so don't care for domReady 566 domReady = false;
567 } 568 else 569 { // We found ourself 570 571 // The baseurl is the src up until the start of our js file 572 this.baseurl = this.src.substring(0, this.src.indexOf(this.files.js.lightbox)); 573 574 // Apply baseurl to files 575 var me = this; 576 $.each(this.files, function(group, val){ 577 $.each(this, function(file, val){ 578 me.files[group][file] = me.baseurl+val; 579 }); 580 }); 581 delete me; 582 583 // Now as we have source, we may have more params 584 options = $.extend(options, $.params_to_json(this.src)); 585 } 586 587 } 588 else 589 if ( typeof options.files === 'object' ) 590 { // We have custom files 591 var me = this; 592 $.each(options.files, function(group, val){ 593 $.each(this, function(file, val){ 594 this[file] = me.baseurl+val; 595 }); 596 }); 597 delete me; 598 } 599 else 600 { // Don't have any files, so no need to perform domReady 601 domReady = false; 602 } 603 604 // ------------------- 605 // Apply options 606 607 for ( i in this.options ) 608 { // Cycle through the options 609 var name = this.options[i]; 610 if ( (typeof options[name] === 'object') && (typeof this[name] === 'object') ) 611 { // We have a group like text or files 612 this[name] = $.extend(this[name], options[name]); 613 } 614 else if ( typeof options[name] !== 'undefined' ) 615 { // We have that option, so apply it 616 this[name] = options[name]; 617 } 618 } 619 620 // ------------------- 621 // Figure out what to do 622 623 // Handle IE6 624 if ( initial && navigator.userAgent.indexOf('MSIE 6') >= 0 ) 625 { // Is IE6 626 this.ie6 = true; 627 } 628 else 629 { // We are not IE6 630 this.ie6 = false; 631 } 632 633 // ------------------- 634 // Handle our DOM 635 636 if ( domReady || typeof options.colorBlend !== 'undefined' || typeof options.files === 'object' || typeof options.text === 'object' || typeof options.show_linkback !== 'undefined' || typeof options.scroll_with !== 'undefined' ) 637 { // We have reason to handle the dom 638 $(function() { 639 // DOM is ready, so fire our DOM handler 640 $.Lightbox.domReady(); 641 }); 642 } 643 644 // ------------------- 645 // Finish Up 646 647 // All good 648 return true; 649 }, 650 651 domReady: function ( ) 652 { 653 // ------------------- 654 // Include resources 655 656 // Grab resources 657 var bodyEl = document.getElementsByTagName($.browser.safari ? 'head' : 'body')[0]; 658 var stylesheets = this.files.css; 659 var scripts = this.files.js; 660 661 // Handle IE6 appropriatly 662 if ( this.ie6 && this.ie6_upgrade ) 663 { // Add the upgrade message 664 scripts.ie6 = 'http://www.savethedevelopers.org/say.no.to.ie.6.js'; 665 } 666 667 // colorBlend 668 if ( this.colorBlend === true && typeof $.colorBlend === 'undefined' ) 669 { // Force colorBlend 670 this.colorBlend = true; 671 // Leave file in place to be loaded 672 } 673 else 674 { // We either have colorBlend or we don't 675 this.colorBlend = typeof $.colorBlend !== 'undefined'; 676 // Remove colorBlend file 677 delete scripts.colorBlend; 678 } 679 680 // Include stylesheets 681 for ( stylesheet in stylesheets ) 682 { 683 var linkEl = document.createElement('link'); 684 linkEl.type = 'text/css'; 685 linkEl.rel = 'stylesheet'; 686 linkEl.media = 'screen'; 687 linkEl.href = stylesheets[stylesheet]; 688 linkEl.id = 'lightbox-stylesheet-'+stylesheet.replace(/[^a-zA-Z0-9]/g, ''); 689 $('#'+linkEl.id).remove(); 690 bodyEl.appendChild(linkEl); 691 } 692 693 // Include javascripts 694 for ( script in scripts ) 695 { 696 var scriptEl = document.createElement('script'); 697 scriptEl.type = 'text/javascript'; 698 scriptEl.src = scripts[script]; 699 scriptEl.id = 'lightbox-script-'+script.replace(/[^a-zA-Z0-9]/g, ''); 700 $('#'+scriptEl.id).remove(); 701 bodyEl.appendChild(scriptEl); 702 } 703 704 // Cleanup 705 delete scripts; 706 delete stylesheets; 707 delete bodyEl; 708 709 // ------------------- 710 // Append display 711 712 // Append markup 713 $('#lightbox,#lightbox-overlay').remove(); 714 $('body').append('<div id="lightbox-overlay"><div id="lightbox-overlay-text">'+(this.show_linkback?'<p><span id="lightbox-overlay-text-about"><a href="#" title="'+this.text.about.title+'">'+this.text.about.text+'</a></span></p><p> </p>':'')+'<p><span id="lightbox-overlay-text-close">'+this.text.help.close+'</span><br/> <span id="lightbox-overlay-text-interact">'+this.text.help.interact+'</span></p></div></div><div id="lightbox"><div id="lightbox-imageBox"><div id="lightbox-imageContainer"><img id="lightbox-image" /><div id="lightbox-nav"><a href="#" id="lightbox-nav-btnPrev"></a><a href="#" id="lightbox-nav-btnNext"></a></div><div id="lightbox-loading"><a href="#" id="lightbox-loading-link"><img src="' + this.files.images.loading + '" /></a></div></div></div><div id="lightbox-infoBox"><div id="lightbox-infoContainer"><div id="lightbox-infoHeader"><span id="lightbox-caption"><a id="lightbox-caption-title" href="#" title="' + this.text.download + '"></a><span id="lightbox-caption-seperator"></span><span id="lightbox-caption-description"></span></span></div><div id="lightbox-infoFooter"><span id="lightbox-currentNumber"></span><span id="lightbox-close"><a href="#" id="lightbox-close-button" title="'+this.text.closeInfo+'">' + this.text.close + '</a></span></div><div id="lightbox-infoContainer-clear"></div></div></div></div>'); 715 716 // Update Boxes - for some crazy reason this has to be before the hide in safari and konqueror 717 this.resizeBoxes(); 718 this.repositionBoxes(); 719 720 // Hide 721 $('#lightbox,#lightbox-overlay,#lightbox-overlay-text-interact').hide(); 722 723 // ------------------- 724 // Browser specifics 725 726 // Handle IE6 727 if ( this.ie6 && this.ie6_support )
728 { // Support IE6 729 // IE6 does not support fixed positioning so absolute it 730 // ^ This is okay as we disable scrolling 731 $('#lightbox-overlay').css({ 732 position: 'absolute', 733 top: '0px', 734 left: '0px' 735 }); 736 } 737 738 // ------------------- 739 // Preload Images 740 741 // Cycle and preload 742 $.each(this.files.images, function() 743 { // Proload the image 744 var preloader = new Image(); 745 preloader.onload = function() { 746 preloader.onload = null; 747 preloader = null; 748 }; preloader.src = this; 749 }); 750 751 // ------------------- 752 // Apply events 753 754 // If the window resizes, act appropriatly 755 $(window).unbind().resize(function () 756 { // The window has been resized 757 $.Lightbox.resizeBoxes('resized'); 758 }); 759 760 // If the window scrolls, act appropriatly 761 if ( this.scroll === 'follow' ) 762 { // We want to 763 $(window).scroll(function () 764 { // The window has scrolled 765 $.Lightbox.repositionBoxes(); 766 }); 767 } 768 769 // Prev 770 $('#lightbox-nav-btnPrev').unbind().hover(function() { // over 771 $(this).css({ 'background' : 'url(' + $.Lightbox.files.images.prev + ') left 45% no-repeat' }); 772 },function() { // out 773 $(this).css({ 'background' : 'transparent url(' + $.Lightbox.files.images.blank + ') no-repeat' }); 774 }).click(function() { 775 $.Lightbox.showImage($.Lightbox.images.prev()); 776 return false; 777 }); 778 779 // Next 780 $('#lightbox-nav-btnNext').unbind().hover(function() { // over 781 $(this).css({ 'background' : 'url(' + $.Lightbox.files.images.next + ') right 45% no-repeat' }); 782 },function() { // out 783 $(this).css({ 'background' : 'transparent url(' + $.Lightbox.files.images.blank + ') no-repeat' }); 784 }).click(function() { 785 $.Lightbox.showImage($.Lightbox.images.next()); 786 return false; 787 }); 788 789 // Help 790 if ( this.show_linkback ) 791 { // Linkback exists so add handler 792 $('#lightbox-overlay-text-about a').click(function(){window.open($.Lightbox.text.about.link); return false;}); 793 } 794 $('#lightbox-overlay-text-close').unbind().hover( 795 function(){ 796 $('#lightbox-overlay-text-interact').fadeIn(); 797 }, 798 function(){ 799 $('#lightbox-overlay-text-interact').fadeOut(); 800 } 801 ); 802 803 // Image link 804 $('#lightbox-caption-title').click(function(){window.open($(this).attr('href')); return false;}); 805 806 // Assign close clicks 807 $('#lightbox-overlay, #lightbox, #lightbox-loading-link, #lightbox-btnClose').unbind().click(function() { 808 $.Lightbox.finish(); 809 return false; 810 }); 811 812 // ------------------- 813 // Finish Up 814 815 // Relify 816 if ( this.auto_relify ) 817 { // We want to relify, no the user 818 this.relify(); 819 } 820 821 // All good 822 return true; 823 }, 824 825 relify: function ( ) 826 { // Create event 827 828 // 829 var groups = {}; 830 var groups_n = 0; 831 var orig_rel = this.rel; 832 // Create the groups 833 $.each($('[@rel*='+orig_rel+']'), function(index, obj){ 834 // Get the group 835 var rel = $(obj).attr('rel'); 836 // Are we really a group 837 if ( rel === orig_rel ) 838 { // We aren't 839 rel = groups_n; // we are individual 840 } 841 // Does the group exist 842 if ( typeof groups[rel] === 'undefined' ) 843 { // Make the group 844 groups[rel] = []; 845 groups_n++; 846 } 847 // Append the image 848 groups[rel].push(obj); 849 }); 850 // Lightbox groups 851 $.each(groups, function(index, group){ 852 $(group).lightbox(); 853 }); 854 // Done 855 return true; 856 }, 857 858 init: function ( image, images ) 859 { // Init a batch of lightboxes 860 861 // Establish images 862 if ( typeof images === 'undefined' ) 863 { 864 images = image; 865 image = 0; 866 } 867 868 // Clear 869 this.images.clear(); 870 871 // Add images 872 if ( !this.images.add(images) ) 873 { return false; } 874 875 // Do we need to bother 876 if ( this.images.empty() ) 877 { // No images 878 $.log('WARNING', 'Lightbox started, but no images: ', image, images); 879 return false; 880 } 881 882 // Set active 883 if ( !this.images.active(image) ) 884 { return false; } 885 886 // Done 887 return true; 888 }, 889 890 start: function ( ) 891 { // Display the lightbox 892 893 // We are alive 894 this.visible = true; 895 896 // Adjust scrolling 897 if ( this.scroll === 'disable' ) 898 { // 899 $(document.body).css('overflow', 'hidden'); 900 } 901 902 // Fix attention seekers 903 $('embed, object, select').css('visibility', 'hidden');//.hide(); - don't use this, give it a go, find out why! 904 905 // Resize the boxes appropriatly 906 this.resizeBoxes('general'); 907 908 // Reposition the Boxes 909 this.repositionBoxes({'speed':0}); 910 911 // Hide things 912 $('#lightbox-infoFooter').hide(); // we hide this here because it makes the display smoother 913 $('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-infoBox').hide(); 914 915 // Display the boxes 916 $('#lightbox-overlay').css('opacity',this.opacity).fadeIn(400, function(){ 917 // Show the lightbox 918 $('#lightbox').fadeIn(300); 919 920 // Display first image 921 if ( !$.Lightbox.showImage($.Lightbox.images.active()) ) 922 { $.Lightbox.finish(); return false; } 923 }); 924 925 // All done 926 return true; 927 }, 928 929 finish: function ( ) 930 { // Get rid of lightbox 931 932 // Hide lightbox 933 $('#lightbox').hide(); 934 $('#lightbox-overlay').fadeOut(function() { $('#lightbox-overlay').hide(); }); 935 936 // Fix attention seekers 937 $('embed, object, select').css({ 'visibility' : 'visible' });//.show(); 938 939 // Kill active image 940 this.images.active(false); 941 942 // Adjust scrolling 943 if ( this.scroll === 'disable' ) 944 { // 945 $(document.body).css('overflow', 'visible'); 946 } 947 948 // We are dead 949 this.visible = false;
950 951 }, 952 953 resizeBoxes: function ( type ) 954 { // Resize the boxes 955 // Used on transition or window resize 956 957 // Resize Overlay 958 if ( type !== 'transition' ) 959 { // We don't care for transition 960 var $body = $(this.ie6 ? document.body : document); 961 $('#lightbox-overlay').css({ 962 width: $body.width(), 963 height: $body.height() 964 }); 965 delete $body; 966 } 967 968 // We no longer care if we are general 969 if ( type === 'general' ) 970 { // Done 971 return true; 972 } 973 974 // Get image 975 var image = this.images.active(); 976 if ( !image || !image.width || !this.visible ) 977 { // No image or no visible lightbox, so we don't care 978 $.log('WARNING', 'A resize occured while no image or no lightbox...'); 979 return false; 980 } 981 982 // Resize image box 983 // i:image, w:window, b:box, c:current, n:new, d:difference 984 985 // Get image dimensions 986 var iWidth = image.width; 987 var iHeight = image.height; 988 989 // Get window dimensions 990 var wWidth = $(window).width(); 991 var wHeight = $(window).height(); 992 993 // Check if we are in size 994 // Lightbox can take up 4/5 of size 995 var maxWidth = Math.floor(wWidth*(4/5)); 996 var maxHeight = Math.floor(wHeight*(4/5)); 997 var resizeRatio; 998 while ( iWidth > maxWidth || iHeight > maxHeight ) 999 { // We need to resize 1000 if ( iWidth > maxWidth ) 1001 { // Resize width, then height proportionally 1002 resizeRatio = maxWidth/iWidth; 1003 iWidth = maxWidth; 1004 iHeight = Math.floor(iHeight*resizeRatio); 1005 } 1006 if ( iHeight > maxHeight ) 1007 { // Resize height, then width proportionally 1008 resizeRatio = maxHeight/iHeight; 1009 iHeight = maxHeight; 1010 iWidth = Math.floor(iWidth*resizeRatio); 1011 } 1012 } 1013 1014 // Get current width and height 1015 var cWidth = $('#lightbox-imageBox').width(); 1016 var cHeight = $('#lightbox-imageBox').height(); 1017 1018 // Get the width and height of the selected image plus the padding 1019 // padding*2 for both sides (left+right || top+bottom) 1020 var nWidth = (iWidth + (this.padding * 2)); 1021 var nHeight = (iHeight + (this.padding * 2)); 1022 1023 // Diferences 1024 var dWidth = cWidth - nWidth; 1025 var dHeight = cHeight - nHeight; 1026 1027 // Set the overlay buttons height and the infobox width 1028 // Other dimensions specified by CSS 1029 $('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css('height', nHeight); 1030 $('#lightbox-infoBox').css('width', nWidth); 1031 1032 // Handle final action 1033 if ( type === 'transition' ) 1034 { // We are transition 1035 // Do we need to wait? (just a nice effect to counter the other 1036 if ( dWidth === 0 && dHeight === 0 ) 1037 { // We are the same size 1038 this.pause(this.speed/3); 1039 this.showImage(null, 3); 1040 } 1041 else 1042 { // We are not the same size 1043 // Animate 1044 $('#lightbox-image').width(iWidth).height(iHeight); 1045 $('#lightbox-imageBox').animate({width: nWidth, height: nHeight}, this.speed, function ( ) { $.Lightbox.showImage(null, 3); } ); 1046 this.repositionBoxes({'nHeight':nHeight, 'speed':this.speed}); 1047 } 1048 } 1049 else 1050 { // We are a resize 1051 // Animate Lightbox 1052 $('#lightbox-image').animate({width:iWidth, height:iHeight}, this.speed); 1053 $('#lightbox-imageBox').animate({width: nWidth, height: nHeight}, this.speed); 1054 this.repositionBoxes({'nHeight':nHeight, 'speed':this.speed}); 1055 } 1056 1057 // Done 1058 return true; 1059 }, 1060 1061 repositioning: false, // are we currently repositioning 1062 reposition_failsafe: false, // failsafe 1063 repositionBoxes: function ( options ) 1064 { 1065 // Prepare 1066 if ( this.repositioning ) 1067 { // Already here 1068 this.reposition_failsafe = true; 1069 return null; 1070 } 1071 this.repositioning = true; 1072 1073 // Options 1074 options = $.extend({}, options); 1075 options.callback = options.callback || null; 1076 options.speed = options.speed || 'slow'; 1077 1078 // Get page scroll 1079 var pageScroll = this.getPageScroll(); 1080 1081 // Figure it out 1082 // alert($(window).height()+"\n"+$(document.body).height()+"\n"+$(document).height()); 1083 // var nHeight = options.nHeight || parseInt($('#lightbox').height(),10) || $(document).height()/3; 1084 var nHeight = options.nHeight || parseInt($('#lightbox').height(),10); 1085 1086 // Display lightbox in center 1087 // var nTop = pageScroll.yScroll + ($(document.body).height() /*frame height*/ - nHeight) / 2.5; 1088 var nTop = pageScroll.yScroll + ($(window).height() /*frame height*/ - nHeight) / 2.5; 1089 var nLeft = pageScroll.xScroll; 1090 1091 // Animate 1092 var css = { 1093 left: nLeft, 1094 top: nTop 1095 }; 1096 if (options.speed) { 1097 $('#lightbox').animate(css, 'slow', function(){ 1098 if ( $.Lightbox.reposition_failsafe ) 1099 { // Fire again 1100 $.Lightbox.repositioning = $.Lightbox.reposition_failsafe = false;
1101 $.Lightbox.repositionBoxes(options); 1102 } 1103 else 1104 { // Done 1105 $.Lightbox.repositioning = false; 1106 if ( options.callback ) 1107 { // Call the user callback 1108 options.callback(); 1109 } 1110 } 1111 }); 1112 } 1113 else 1114 { 1115 $('#lightbox').css(css); 1116 if ( this.reposition_failsafe ) 1117 { // Fire again 1118 this.repositioning = this.reposition_failsafe = false; 1119 this.repositionBoxes(options); 1120 } 1121 else 1122 { // Done 1123 this.repositioning = false; 1124 } 1125 } 1126 1127 // Done 1128 return true; 1129 }, 1130 1131 visible: false, 1132 showImage: function ( image, step ) 1133 { 1134 // Establish image 1135 image = this.images.get(image); 1136 if ( !image ) { return image; } 1137 1138 // Default step 1139 step = step || 1; 1140 1141 // Split up below for jsLint compliance 1142 var skipped_step_1 = step > 1 && this.images.active().src !== image.src; 1143 var skipped_step_2 = step > 2 && $('#lightbox-image').attr('src') !== image.src; 1144 if ( skipped_step_1 || skipped_step_2 ) 1145 { // Force step 1 1146 $.log('We wanted to skip a few steps: ', image, step, skipped_step_1, skipped_step_2); 1147 step = 1; 1148 } 1149 1150 // What do we need to do 1151 switch ( step ) 1152 { 1153 // --------------------------------- 1154 // We need to preload 1155 case 1: 1156 1157 // Disable keyboard nav 1158 this.KeyboardNav_Disable(); 1159 1160 // Show the loading image 1161 $('#lightbox-loading').show(); 1162 1163 // Hide things 1164 $('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-infoBox').hide(); 1165 1166 // Remove show info events 1167 $('#lightbox-imageBox').unbind(); 1168 // ^ Why? Because otherwise when the image is changing, the info pops out, not good! 1169 1170 // Make the image the active image 1171 if ( !this.images.active(image) ) { return false; } 1172 1173 // Check if we need to preload 1174 if ( image.width && image.height ) 1175 { // We don't 1176 // Continue to next step 1177 this.showImage(null, 2); 1178 } 1179 else 1180 { // We do 1181 // Create preloader 1182 var preloader = new Image(); 1183 // Set callback 1184 preloader.onload = function() 1185 { // We have preloaded the image 1186 // Update image with our new info 1187 image.width = preloader.width; 1188 image.height = preloader.height; 1189 // Continue to next step 1190 $.Lightbox.showImage(null, 2); 1191 // Kill preloader 1192 preloader.onload = null; 1193 preloader = null; 1194 }; 1195 // Start preload 1196 preloader.src = image.src; 1197 } 1198 1199 // Done 1200 break; 1201 1202 1203 // --------------------------------- 1204 // Resize the container 1205 case 2: 1206 1207 // Apply image changes 1208 $('#lightbox-image').attr('src', image.src); 1209 1210 // Set container border (Moved here for Konqueror fix - Credits to Blueyed) 1211 if ( typeof this.padding === 'undefined' || this.padding === null || isNaN(this.padding) ) 1212 { // Autodetect 1213 this.padding = parseInt($('#lightbox-imageContainer').css('padding-left'), 10) || parseInt($('#lightbox-imageContainer').css('padding'), 10) || 0; 1214 } 1215 1216 // Use colorBlend? 1217 if ( this.colorBlend ) 1218 { // We have colorBlend 1219 $('#lightbox-overlay').colorBlend([{ 1220 param: 'background-color', 1221 fromColor: $('#lightbox-overlay').css('background-color'), 1222 toColor: image.color, 1223 cycles: 1, 1224 isFade: false 1225 }]); 1226 } 1227 1228 // Resize boxes 1229 this.resizeBoxes('transition'); 1230 // ^ contains callback to next step 1231 1232 // Done 1233 break; 1234 1235 1236 // --------------------------------- 1237 // Display the image 1238 case 3: 1239 1240 // Hide loading 1241 $('#lightbox-loading').hide(); 1242 1243 // Animate image 1244 $('#lightbox-image').fadeIn(500, function() {$.Lightbox.showImage(null, 4); }); 1245 1246 // Start the proloading of other images 1247 this.preloadNeighbours(); 1248 1249 // Fire custom handler show 1250 if ( this.handlers.show !== null ) 1251 { // Fire it 1252 this.handlers.show(image); 1253 } 1254 1255 // Done 1256 break; 1257 1258 1259 // --------------------------------- 1260 // Set image info / Set navigation 1261 case 4: 1262 1263 // --------------------------------- 1264 // Set image info 1265 1266 // Hide and set image info 1267 $('#lightbox-caption-title').html(image.title || 'Untitled').attr('href', image.src); 1268 $('#lightbox-caption-seperator').html(image.description ? ': ' : ''); 1269 $('#lightbox-caption-description').html(image.description || ' '); 1270 1271 // If we have a set, display image position 1272 if ( this.images.size() > 1 ) 1273 { // Display 1274 $('#lightbox-currentNumber').html(this.text.image + ' ' + ( image.index + 1 ) + ' ' + this.text.of + ' ' + this.images.size()); 1275 } else 1276 { // Empty 1277 $('#lightbox-currentNumber').html(' '); 1278 } 1279 1280 // --------------------------------- 1281 // Info events 1282 1283 // Apply event 1284 $('#lightbox-imageBox').unbind('mouseover').mouseover(function(){ 1285 $('#lightbox-infoBox').slideDown('fast'); 1286 }); 1287 1288 // Apply event 1289 $('#lightbox-infoBox').unbind('mouseover').mouseover(function(){ 1290 $('#lightbox-infoFooter').slideDown('fast'); 1291 }); 1292 1293 // --------------------------------- 1294 // Set navigation 1295 1296 // Instead to define this configuration in CSS file, we define here. And it's need to IE. Just. 1297 $('#lightbox-nav-btnPrev, #lightbox-nav-btnNext').css({ 'background' : 'transparent url(' + this.files.images.blank + ') no-repeat' }); 1298 1299 // If not first, show previous button 1300 if ( !this.images.first(image) ) { 1301 // Not first, show button 1302 $('#lightbox-nav-btnPrev').show(); 1303 } 1304 1305 // If not last, show next button 1306 if ( !this.images.last(image) ) { 1307 // Not first, show button 1308 $('#lightbox-nav-btnNext').show(); 1309 } 1310 1311 // Make navigation active / show it 1312 $('#lightbox-nav').show(); 1313 1314 // Enable keyboard navigation 1315 this.KeyboardNav_Enable(); 1316 1317 // Done 1318 break; 1319 1320 1321 // --------------------------------- 1322 // Error handling 1323 default: 1324 $.log('ERROR', 'Don\'t know what to do: ', image, step); 1325 return this.showImage(image, 1); 1326 // break; 1327 1328 } 1329 1330 // All done 1331 return true; 1332 }, 1333 1334 preloadNeighbours: function ( ) 1335 { // Preload all neighbour images 1336 1337 // Do we need to do this? 1338 if ( this.images.single() || this.images.empty() ) 1339 { return true; } 1340 1341 // Get active image 1342 var image = this.images.active(); 1343 if ( !image ) { return image; } 1344 1345 // Load previous 1346 var prev = this.images.prev(image); 1347 var objNext; 1348 if ( prev ) { 1349 objNext = new Image(); 1350 objNext.src = prev.src; 1351 } 1352 1353 // Load next 1354 var next = this.images.next(image); 1355 if ( next ) { 1356 objNext = new Image(); 1357 objNext.src = next.src; 1358 } 1359 }, 1360 1361 // -------------------------------------------------- 1362 // Things we don't really care about 1363 1364 KeyboardNav_Enable: function ( ) { 1365 $(document).keydown(function(objEvent) { 1366 $.Lightbox.KeyboardNav_Action(objEvent); 1367 }); 1368 }, 1369 1370 KeyboardNav_Disable: function ( ) { 1371 $(document).unbind(); 1372 }, 1373 1374 KeyboardNav_Action: function ( objEvent ) { 1375 // Prepare 1376 objEvent = objEvent || window.event; 1377 1378 // Get the keycode 1379 var keycode = objEvent.keyCode; 1380 var escapeKey = objEvent.DOM_VK_ESCAPE /* moz */ || 27; 1381 1382 // Get key 1383 var key = String.fromCharCode(keycode).toLowerCase(); 1384 1385 // Close? 1386 if ( key === this.keys.close || keycode === escapeKey ) 1387 { return $.Lightbox.finish(); } 1388 1389 // Prev? 1390 if ( key === this.keys.prev || keycode === 37 ) 1391 { // We want previous 1392 return $.Lightbox.showImage($.Lightbox.images.prev()); 1393 } 1394 1395 // Next? 1396 if ( key === this.keys.next || keycode === 39 ) 1397 { // We want next 1398 return $.Lightbox.showImage($.Lightbox.images.next()); 1399 } 1400 1401 // Unknown 1402 return true; 1403 }, 1404 1405 getPageScroll: function ( ) { 1406 var xScroll, yScroll; 1407 if (self.pageYOffset) 1408 { // Some browser 1409 yScroll = self.pageYOffset; 1410 xScroll = self.pageXOffset; 1411 } else if (document.documentElement && document.documentElement.scrollTop) 1412 { // Explorer 6 Strict 1413 yScroll = document.documentElement.scrollTop; 1414 xScroll = document.documentElement.scrollLeft; 1415 } else if (document.body) 1416 { // All other browsers 1417 yScroll = document.body.scrollTop; 1418 xScroll = document.body.scrollLeft; 1419 } 1420 var arrayPageScroll = {'xScroll':xScroll,'yScroll':yScroll}; 1421 return arrayPageScroll; 1422 }, 1423 1424 pause: function ( ms ) { 1425 var date = new Date(); 1426 var curDate = null; 1427 do { curDate = new Date(); } 1428 while ( curDate - date < ms); 1429 } 1430 1431 }); // We have finished extending/defining our LightboxClass 1432 1433 1434 // --------------------------------------------------
1435 // Finish up 1436 1437 // Instantiate 1438 if ( typeof $.Lightbox === 'undefined' ) 1439 { // 1440 $.Lightbox = new $.LightboxClass(); 1441 } 1442 1443// Finished definition 1444 1445})(jQuery); // We are done with our plugin, so lets call it with jQuery as the argument
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.