PageSourceSearch

https://www.webexhibits.org/causesofcolor/js/jquery.lightbox.js

js webexhibits.org collected 2026-10-01 08:37:35 UTC 38,607 bytes, 1,445 lines download raw bytes

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(/\&|\&amp\;/);
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>&nbsp;</p>':'')+'<p><span id="lightbox-overlay-text-close">'+this.text.help.close+'</span><br/>&nbsp;<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 || '&nbsp;');
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 + '&nbsp;' + ( image.index + 1 ) + '&nbsp;' + this.text.of + '&nbsp;' + this.images.size());
1275					} else
1276					{	// Empty
1277						$('#lightbox-currentNumber').html('&nbsp;');
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.