PageSourceSearch

https://surrogate-solutions.com/scripts/photoalbum.js

js surrogate-solutions.com collected 2026-10-02 01:44:57 UTC 62,295 bytes, 1,645 lines download raw bytes

1/* 			####### Animator.js code starts here ########## */
2		/*  
3		Animator.js 1.1.9
4		
5		This library is released under the BSD license:
6
7		Copyright (c) 2006, Bernard Sumption. All rights reserved.
8		
9		Redistribution and use in source and binary forms, with or without
10		modification, are permitted provided that the following conditions are met:
11		
12		Redistributions of source code must retain the above copyright notice, this
13		list of conditions and the following disclaimer. Redistributions in binary
14		form must reproduce the above copyright notice, this list of conditions and
15		the following disclaimer in the documentation and/or other materials
16		provided with the distribution. Neither the name BernieCode nor
17		the names of its contributors may be used to endorse or promote products
18		derived from this software without specific prior written permission. 
19		
20		THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21		AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22		IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23		ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
24		ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25		DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26		SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27		CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28		LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29		OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30		DAMAGE.
31
32	*/
33
34
35	// Applies a sequence of numbers between 0 and 1 to a number of subjects
36	// construct - see setOptions for parameters
37	function Animator(options) {
38		this.setOptions(options);
39		var _this = this;
40		this.timerDelegate = function(){_this.onTimerEvent()};
41		this.subjects = [];
42		this.target = 0;
43		this.state = 0;
44		this.lastTime = null;
45	};
46	Animator.prototype = {
47		// apply defaults
48		setOptions: function(options) {
49			this.options = Animator.applyDefaults({
50				interval: 20,  // time between animation frames
51				duration: 400, // length of animation
52				onComplete: function(){},
53				onStep: function(){},
54				transition: Animator.tx.easeInOut
55			}, options);
56		},
57		// animate from the current state to provided value
58		seekTo: function(to) {
59			this.seekFromTo(this.state, to);
60		},
61		// animate from the current state to provided value
62		seekFromTo: function(from, to) {
63			this.target = Math.max(0, Math.min(1, to));
64			this.state = Math.max(0, Math.min(1, from));
65			this.lastTime = new Date().getTime();
66			if (!this.intervalId) {
67				this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
68			}
69		},
70		// animate from the current state to provided value
71		jumpTo: function(to) {
72			this.target = this.state = Math.max(0, Math.min(1, to));
73			this.propagate();
74		},
75		// seek to the opposite of the current target
76		toggle: function() {
77			this.seekTo(1 - this.target);
78		},
79		// add a function or an object with a method setState(state) that will be called with a number
80		// between 0 and 1 on each frame of the animation
81		addSubject: function(subject) {
82			this.subjects[this.subjects.length] = subject;
83			return this;
84		},
85		// remove all subjects
86		clearSubjects: function() {
87			this.subjects = [];
88		},
89		// forward the current state to the animation subjects
90		propagate: function() {
91			var value = this.options.transition(this.state);
92			for (var i=0; i<this.subjects.length; i++) {
93				if (this.subjects[i].setState) {
94					this.subjects[i].setState(value);
95				} else {
96					this.subjects[i](value);
97				}
98			}
99		},
100		// called once per frame to update the current state
101		onTimerEvent: function() {
102			var now = new Date().getTime();
103			var timePassed = now - this.lastTime;
104			this.lastTime = now;
105			var movement = (timePassed / this.options.duration) * (this.state < this.target ? 1 : -1);
106			if (Math.abs(movement) >= Math.abs(this.state - this.target)) {
107				this.state = this.target;
108			} else {
109				this.state += movement;
110			}
111			
112			try {
113				this.propagate();
114			} finally {
115				this.options.onStep.call(this);
116				if (this.target == this.state) {
117					window.clearInterval(this.intervalId);
118					this.intervalId = null;
119					this.options.onComplete.call(this);
120				}
121			}
122		},
123		// shortcuts
124		play: function() {this.seekFromTo(0, 1)},
125		reverse: function() {this.seekFromTo(1, 0)},
126		// return a string describing this Animator, for debugging
127		inspect: function() {
128			var str = "#<Animator:\n";
129			for (var i=0; i<this.subjects.length; i++) {
130				str += this.subjects[i].inspect();
131			}
132			str += ">";
133			return str;
134		}
135	}
136	// merge the properties of two objects
137	Animator.applyDefaults = function(defaults, prefs) {
138		prefs = prefs || {};
139		var prop, result = {};
140		for (prop in defaults) result[prop] = prefs[prop] !== undefined ? prefs[prop] : defaults[prop];
141		return result;
142	}
143	// make an array from any object
144	Animator.makeArray = function(o) {
145		if (o == null) return [];
146		if (!o.length) return [o];
147		var result = [];
148		for (var i=0; i<o.length; i++) result[i] = o[i];
149		return result;
150	}
151	// convert a dash-delimited-property to a camelCaseProperty (c/o Prototype, thanks Sam!)
152	Animator.camelize = function(string) {
153		var oStringList = string.split('-');
154		if (oStringList.length == 1) return oStringList[0];
155		
156		var camelizedString = string.indexOf('-') == 0
157			? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
158			: oStringList[0];
159		
160		for (var i = 1, len = oStringList.length; i < len; i++) {
161			var s = oStringList[i];
162			camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
163		}
164		return camelizedString;
165	}
166	// syntactic sugar for creating CSSStyleSubjects 
167	Animator.apply = function(el, style, options) {
168		if (style instanceof Array) {
169			return new Animator(options).addSubject(new CSSStyleSubject(el, style[0], style[1]));
170		}
171		return new Animator(options).addSubject(new CSSStyleSubject(el, style));
172	}
173	// make a transition function that gradually accelerates. pass a=1 for smooth
174	// gravitational acceleration, higher values for an exaggerated effect
175	Animator.makeEaseIn = function(a) {
176		return function(state) {
177			return Math.pow(state, a*2); 
178		}
179	}
180	// as makeEaseIn but for deceleration
181	Animator.makeEaseOut = function(a) {
182		return function(state) {
183			return 1 - Math.pow(1 - state, a*2); 
184		}
185	}
186	// make a transition function that, like an object with momentum being attracted to a point,
187	// goes past the target then returns
188	Animator.makeElastic = function(bounces) {
189		return function(state) {
190			state = Animator.tx.easeInOut(state);
191			return ((1-Math.cos(state * Math.PI * bounces)) * (1 - state)) + state; 
192		}
193	}
194	// make an Attack Decay Sustain Release envelope that starts and finishes on the same level
195	// 
196	Animator.makeADSR = function(attackEnd, decayEnd, sustainEnd, sustainLevel) {
197		if (sustainLevel == null) sustainLevel = 0.5;
198		return function(state) {
199			if (state < attackEnd) {
200				return state / attackEnd;
201			}
202			if (state < decayEnd) {
203				return 1 - ((state - attackEnd) / (decayEnd - attackEnd) * (1 - sustainLevel));
204			}
205			if (state < sustainEnd) {
206				return sustainLevel;
207			}
208			return sustainLevel * (1 - ((state - sustainEnd) / (1 - sustainEnd)));
209		}
210	}
211	// make a transition function that, like a ball falling to floor, reaches the target and/
212	// bounces back again
213	Animator.makeBounce = function(bounces) {
214		var fn = Animator.makeElastic(bounces);
215		return function(state) {
216			state = fn(state); 
217			return state <= 1 ? state : 2-state;
218		}
219	}
220	 
221	// pre-made transition functions to use with the 'transition' option
222	Animator.tx = {
223		easeInOut: function(pos){
224			return ((-Math.cos(pos*Math.PI)/2) + 0.5);
225		},
226		linear: function(x) {
227			return x;
228		},
229		easeIn: Animator.makeEaseIn(1.5),
230		easeOut: Animator.makeEaseOut(1.5),
231		strongEaseIn: Animator.makeEaseIn(2.5),
232		strongEaseOut: Animator.makeEaseOut(2.5),
233		elastic: Animator.makeElastic(1),
234		veryElastic: Animator.makeElastic(3),
235		bouncy: Animator.makeBounce(1),
236		veryBouncy: Animator.makeBounce(3)
237	}
238
239	// animates a pixel-based style property between two integer values
240	function NumericalStyleSubject(els, property, from, to, units) {
241		this.els = Animator.makeArray(els);
242		if (property == 'opacity' && window.ActiveXObject) {
243			this.property = 'filter';
244		} else {
245			this.property = Animator.camelize(property);
246		}
247		this.from = parseFloat(from);
248		this.to = parseFloat(to);
249		this.units = units != null ? units : 'px';
250	}
251	NumericalStyleSubject.prototype = {
252		setState: function(state) {
253			var style = this.getStyle(state);
254			var visibility = (this.property == 'opacity' && state == 0) ? 'hidden' : '';
255			var j=0;
256			for (var i=0; i<this.els.length; i++) {
257				try {
258					this.els[i].style[this.property] = style;
259				} catch (e) {
260					// ignore fontWeight - intermediate numerical values cause exeptions in firefox
261					if (this.property != 'fontWeight') throw e;
262				}
263				if (j++ > 20) return;
264			}
265		},
266		getStyle: function(state) {
267			state = this.from + ((this.to - this.from) * state);
268			if (this.property == 'filter') return "alpha(opacity=" + Math.round(state*100) + ")";
269			if (this.property == 'opacity') return state;
270			return Math.round(state) + this.units;
271		},
272		inspect: function() {
273			return "\t" + this.property + "(" + this.from + this.units + " to " + this.to + this.units + ")\n";
274		}
275	}
276
277	// animates a colour based style property between two hex values
278	function ColorStyleSubject(els, property, from, to) {
279		this.els = Animator.makeArray(els);
280		this.property = Animator.camelize(property);
281		this.to = this.expandColor(to);
282		this.from = this.expandColor(from);
283		this.origFrom = from;
284		this.origTo = to;
285	}
286
287	ColorStyleSubject.prototype = {
288		// parse "#FFFF00" to [256, 256, 0]
289		expandColor: function(color) {
290			var hexColor, red, green, blue;
291			hexColor = ColorStyleSubject.parseColor(color);
292			if (hexColor) {
293				red = parseInt(hexColor.slice(1, 3), 16);
294				green = parseInt(hexColor.slice(3, 5), 16);
295				blue = parseInt(hexColor.slice(5, 7), 16);
296				return [red,green,blue]
297			}
298			if (window.DEBUG) {
299				//alert("Invalid colour: '" + color + "'");
300				alert(ICaltgopub.pa_txt1 + color + "' ");
301			}
302		},
303		getValueForState: function(color, state) {
304			return Math.round(this.from[color] + ((this.to[color] - this.from[color]) * state));
305		},
306		setState: function(state) {
307			var color = '#'
308					+ ColorStyleSubject.toColorPart(this.getValueForState(0, state))
309					+ ColorStyleSubject.toColorPart(this.getValueForState(1, state))
310					+ ColorStyleSubject.toColorPart(this.getValueForState(2, state));
311			for (var i=0; i<this.els.length; i++) {
312				this.els[i].style[this.property] = color;
313			}
314		},
315		inspect: function() {
316			return "\t" + this.property + "(" + this.origFrom + " to " + this.origTo + ")\n";
317		}
318	}
319
320	// return a properly formatted 6-digit hex colour spec, or false
321	ColorStyleSubject.parseColor = function(string) {
322		var color = '#', match;
323		if(match = ColorStyleSubject.parseColor.rgbRe.exec(string)) {
324			var part;
325			for (var i=1; i<=3; i++) {
326				part = Math.max(0, Math.min(255, parseInt(match[i])));
327				color += ColorStyleSubject.toColorPart(part);
328			}
329			return color;
330		}
331		if (match = ColorStyleSubject.parseColor.hexRe.exec(string)) {
332			if(match[1].length == 3) {
333				for (var i=0; i<3; i++) {
334					color += match[1].charAt(i) + match[1].charAt(i);
335				}
336				return color;
337			}
338			return '#' + match[1];
339		}
340		return false;
341	}
342	// convert a number to a 2 digit hex string
343	ColorStyleSubject.toColorPart = function(number) {
344		if (number > 255) number = 255;
345		var digits = number.toString(16);
346		if (number < 16) return '0' + digits;
347		return digits;
348	}
349	ColorStyleSubject.parseColor.rgbRe = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
350	ColorStyleSubject.parseColor.hexRe = /^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
351
352	// Animates discrete styles, i.e. ones that do not scale but have discrete values
353	// that can't be interpolated
354	function DiscreteStyleSubject(els, property, from, to, threshold) {
355		this.els = Animator.makeArray(els);
356		this.property = Animator.camelize(property);
357		this.from = from;
358		this.to = to;
359		this.threshold = threshold || 0.5;
360	}
361
362	DiscreteStyleSubject.prototype = {
363		setState: function(state) {
364			var j=0;
365			for (var i=0; i<this.els.length; i++) {
366				this.els[i].style[this.property] = state <= this.threshold ? this.from : this.to; 
367			}
368		},
369		inspect: function() {
370			return "\t" + this.property + "(" + this.from + " to " + this.to + " @ " + this.threshold + ")\n";
371		}
372	}
373
374	// animates between two styles defined using CSS.
375	// if style1 and style2 are present, animate between them, if only style1
376	// is present, animate between the element's current style and style1
377	function CSSStyleSubject(els, style1, style2) {
378		els = Animator.makeArray(els);
379		this.subjects = [];
380		if (els.length == 0) return;
381		var prop, toStyle, fromStyle;
382		if (style2) {
383			fromStyle = this.parseStyle(style1, els[0]);
384			toStyle = this.parseStyle(style2, els[0]);
385		} else {
386			toStyle = this.parseStyle(style1, els[0]);
387			fromStyle = {};
388			for (prop in toStyle) {
389				fromStyle[prop] = CSSStyleSubject.getStyle(els[0], prop);
390			}
391		}
392		// remove unchanging properties
393		var prop;
394		for (prop in fromStyle) {
395			if (fromStyle[prop] == toStyle[prop]) {
396				delete fromStyle[prop];
397				delete toStyle[prop];
398			}
399		}
400		// discover the type (numerical or colour) of each style
401		var prop, units, match, type, from, to;
402		for (prop in fromStyle) {
403			var fromProp = String(fromStyle[prop]);
404			var toProp = String(toStyle[prop]);
405			if (toStyle[prop] == null) {
406				if (window.DEBUG) alert(ICaltgopub.pa_txt2 + prop + '"');
407				continue;
408			}
409			
410			if (from = ColorStyleSubject.parseColor(fromProp)) {
411				to = ColorStyleSubject.parseColor(toProp);
412				type = ColorStyleSubject;
413			} else if (fromProp.match(CSSStyleSubject.numericalRe)
414					&& toProp.match(CSSStyleSubject.numericalRe)) {
415				from = parseFloat(fromProp);
416				to = parseFloat(toProp);
417				type = NumericalStyleSubject;
418				match = CSSStyleSubject.numericalRe.exec(fromProp);
419				var reResult = CSSStyleSubject.numericalRe.exec(toProp);
420				if (match[1] != null) {
421					units = match[1];
422				} else if (reResult[1] != null) {
423					units = reResult[1];
424				} else {
425					units = reResult;
426				}
427			} else if (fromProp.match(CSSStyleSubject.discreteRe)
428					&& toProp.match(CSSStyleSubject.discreteRe)) {
429				from = fromProp;
430				to = toProp;
431				type = DiscreteStyleSubject;
432				units = 0;   // hack - how to get an animator option down to here
433			} else {
434				if (window.DEBUG) {
435					alert(ICaltgopub.pa_txt3 + prop + ": '" + fromStyle[prop] + "'");
436				}
437				continue;
438			}
439			this.subjects[this.subjects.length] = new type(els, prop, from, to, units);
440		}
441	}
442
443	CSSStyleSubject.prototype = {
444		// parses "width: 400px; color: #FFBB2E" to {width: "400px", color: "#FFBB2E"}
445		parseStyle: function(style, el) {
446			var rtn = {};
447			// if style is a rule set
448			if (style.indexOf(":") != -1) {
449				var styles = style.split(";");
450				for (var i=0; i<styles.length; i++) {
451					var parts = CSSStyleSubject.ruleRe.exec(styles[i]);
452					if (parts) {
453						rtn[parts[1]] = parts[2];
454					}
455				}
456			}
457			// else assume style is a class name
458			else {
459				var prop, value, oldClass;
460				oldClass = el.className;
461				el.className = style;
462				for (var i=0; i<CSSStyleSubject.cssProperties.length; i++) {
463					prop = CSSStyleSubject.cssProperties[i];
464					value = CSSStyleSubject.getStyle(el, prop);
465					if (value != null) {
466						rtn[prop] = value;
467					}
468				}
469				el.className = oldClass;
470			}
471			return rtn;
472			
473		},
474		setState: function(state) {
475			for (var i=0; i<this.subjects.length; i++) {
476				this.subjects[i].setState(state);
477			}
478		},
479		inspect: function() {
480			var str = "";
481			for (var i=0; i<this.subjects.length; i++) {
482				str += this.subjects[i].inspect();
483			}
484			return str;
485		}
486	}
487	// get the current value of a css property, 
488	/*
489	CSSStyleSubject.getStyle = function(el, property){
490		var style;
491		if(document.defaultView && document.defaultView.getComputedStyle){
492			style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
493			if (style) {
494				return style;
495			} else {
496				return('none');
497			}
498		}
499		
500		
501		property = Animator.camelize(property);
502		if(el.currentStyle){
503			style = el.currentStyle[property];
504		}
505		return style || el.style[property]
506	}
507	*/
508	CSSStyleSubject.getStyle = function(el, property){
509	if (document.defaultView) {
510		var computedStyle = document.defaultView.getComputedStyle(el, null);
511		// Safari returns null from computed style if the display of the element is none
512		// if this is the case, then we just return 'none' if the user is asking for the
513		// 'display' property, or we temporarily set the display to 'block' and re-fetch
514		// the computed style
515		if (computedStyle) {
516			style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
517		} else if (property == 'display') {
518			style = 'none';
519		} else {
520			property = Animator.camelize(property);
521		if(el.currentStyle){
522			style = el.currentStyle[property];
523		}
524		}
525		return style || el.style[property];
526	}
527	}
528
529	CSSStyleSubject.ruleRe = /^\s*([a-zA-Z\-]+)\s*:\s*(\S(.+\S)?)\s*$/;
530	CSSStyleSubject.numericalRe = /^-?\d+(?:\.\d+)?(%|[a-zA-Z]{2})?$/;
531	CSSStyleSubject.discreteRe = /^\w+$/;
532
533	// required because the style object of elements isn't enumerable in Safari
534	/*
535	CSSStyleSubject.cssProperties = ['background-color','border','border-color','border-spacing',
536	'border-style','border-top','border-right','border-bottom','border-left','border-top-color',
537	'border-right-color','border-bottom-color','border-left-color','border-top-width','border-right-width',
538	'border-bottom-width','border-left-width','border-width','bottom','color','font-size','font-size-adjust',
539	'font-stretch','font-style','height','left','letter-spacing','line-height','margin','margin-top',
540	'margin-right','margin-bottom','margin-left','marker-offset','max-height','max-width','min-height',
541	'min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding',
542	'padding-top','padding-right','padding-bottom','padding-left','quotes','right','size','text-indent',
543	'top','width','word-spacing','z-index','opacity','outline-offset'];*/
544
545
546	CSSStyleSubject.cssProperties = ['azimuth','background','background-attachment','background-color','background-image','background-position','background-repeat','border-collapse','border-color','border-spacing','border-style','border-top','border-top-color','border-right-color','border-bottom-color','border-left-color','border-top-style','border-right-style','border-bottom-style','border-left-style','border-top-width','border-right-width','border-bottom-width','border-left-width','border-width','bottom','clear','clip','color','content','cursor','direction','display','elevation','empty-cells','css-float','font','font-family','font-size','font-size-adjust','font-stretch','font-style','font-variant','font-weight','height','left','letter-spacing','line-height','list-style','list-style-image','list-style-position','list-style-type','margin','margin-top','margin-right','margin-bottom','margin-left','max-height','max-width','min-height','min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding','padding-top','padding-right','padding-bottom','padding-left','pause','position','right','size','table-layout','text-align','text-decoration','text-indent','text-shadow','text-transform','top','vertical-align','visibility','white-space','width','word-spacing','z-index','opacity','outline-offset','overflow-x','overflow-y'];
547
548
549	// chains several Animator objects together
550	function AnimatorChain(animators, options) {
551		this.animators = animators;
552		this.setOptions(options);
553		for (var i=0; i<this.animators.length; i++) {
554			this.listenTo(this.animators[i]);
555		}
556		this.forwards = false;
557		this.current = 0;
558	}
559
560	AnimatorChain.prototype = {
561		// apply defaults
562		setOptions: function(options) {
563			this.options = Animator.applyDefaults({
564				// by default, each call to AnimatorChain.play() calls jumpTo(0) of each animator
565				// before playing, which can cause flickering if you have multiple animators all
566				// targeting the same element. Set this to false to avoid this.
567				resetOnPlay: true
568			}, options);
569		},
570		// play each animator in turn
571		play: function() {
572			this.forwards = true;
573			this.current = -1;
574			if (this.options.resetOnPlay) {
575				for (var i=0; i<this.animators.length; i++) {
576					this.animators[i].jumpTo(0);
577				}
578			}
579			this.advance();
580		},
581		// play all animators backwards
582		reverse: function() {
583			this.forwards = false;
584			this.current = this.animators.length;
585			if (this.options.resetOnPlay) {
586				for (var i=0; i<this.animators.length; i++) {
587					this.animators[i].jumpTo(1);
588				}
589			}
590			this.advance();
591		},
592		// if we have just play()'d, then call reverse(), and vice versa
593		toggle: function() {
594			if (this.forwards) {
595				this.seekTo(0);
596			} else {
597				this.seekTo(1);
598			}
599		},
600		// internal: install an event listener on an animator's onComplete option
601		// to trigger the next animator
602		listenTo: function(animator) {
603			var oldOnComplete = animator.options.onComplete;
604			var _this = this;
605			animator.options.onComplete = function() {
606				if (oldOnComplete) oldOnComplete.call(animator);
607				_this.advance();
608			}
609		},
610		// play the next animator
611		advance: function() {
612			if (this.forwards) {
613				if (this.animators[this.current + 1] == null) return;
614				this.current++;
615				this.animators[this.current].play();
616			} else {
617				if (this.animators[this.current - 1] == null) return;
618				this.current--;
619				this.animators[this.current].reverse();
620			}
621		},
622		// this function is provided for drop-in compatibility with Animator objects,
623		// but only accepts 0 and 1 as target values
624		seekTo: function(target) {
625			if (target <= 0) {
626				this.forwards = false;
627				this.animators[this.current].seekTo(0);
628			} else {
629				this.forwards = true;
630				this.animators[this.current].seekTo(1);
631			}
632		}
633	}
634
635	// an Accordion is a class that creates and controls a number of Animators. An array of elements is passed in,
636	// and for each element an Animator and a activator button is created. When an Animator's activator button is
637	// clicked, the Animator and all before it seek to 0, and all Animators after it seek to 1. This can be used to
638	// create the classic Accordion effect, hence the name.
639	// see setOptions for arguments
640	function Accordion(options) {
641		this.setOptions(options);
642		var selected = this.options.initialSection, current;
643		if (this.options.rememberance) {
644			current = document.location.hash.substring(1);
645		}
646		this.rememberanceTexts = [];
647		this.ans = [];
648		var _this = this;
649		for (var i=0; i<this.options.sections.length; i++) {
650			var el = this.options.sections[i];
651			var an = new Animator(this.options.animatorOptions);
652			var from = this.options.from + (this.options.shift * i);
653			var to = this.options.to + (this.options.shift * i);
654			an.addSubject(new NumericalStyleSubject(el, this.options.property, from, to, this.options.units));
655			an.jumpTo(0);
656			var activator = this.options.getActivator(el);
657			activator.index = i;
658			activator.onclick = function(){_this.show(this.index)};
659			this.ans[this.ans.length] = an;
660			this.rememberanceTexts[i] = activator.innerHTML.replace(/\s/g, "");
661			if (this.rememberanceTexts[i] === current) {
662				selected = i;
663			}
664		}
665		this.show(selected);
666	}
667
668	Accordion.prototype = {
669		// apply defaults
670		setOptions: function(options) {
671			this.options = Object.extend({
672				// REQUIRED: an array of elements to use as the accordion sections
673				sections: null,
674				// a function that locates an activator button element given a section element.
675				// by default it takes a button id from the section's "activator" attibute
676				getActivator: function(el) {return document.getElementById(el.getAttribute("activator"))},
677				// shifts each animator's range, for example with options {from:0,to:100,shift:20}
678				// the animators' ranges will be 0-100, 20-120, 40-140 etc.
679				shift: 0,
680				// the first page to show
681				initialSection: 0,
682				// if set to true, document.location.hash will be used to preserve the open section across page reloads 
683				rememberance: true,
684				// constructor arguments to the Animator objects
685				animatorOptions: {}
686			}, options || {});
687		},
688		show: function(section) {
689			for (var i=0; i<this.ans.length; i++) {
690				this.ans[i].seekTo(i > section ? 1 : 0);
691			}
692			if (this.options.rememberance) {
693				document.location.hash = this.rememberanceTexts[section];
694			}
695		}
696	}
697		
698	/* 			####### Animator.js code ends here ########## */ 		
699	
700	/* 			####### Photoalbum.js code starts here ########## */
701	
702	
703	  /***** GLOBALS *****/
704        
705		var slowest = 5000;
706		var slow = 4000;
707        var med = 3000;
708        var fast = 2000;        
709		var fastest = 1000;
710        var slideTime;
711        var randTime;
712        
713         /*****These are our events****/
714        
715        //parent.content.onscroll = adjustoverlay;
716		window.onscroll = adjustOverlay;
717		//window.onresize = adjustOverlay;
718		
719	   /***** Event Functions*****/
720
721         function checkMouseover(evt) {
722			
723			//alert(evt);
724			
725			if (!evt) var evt = window.event;
726        
727            if(document.all)    
728                evtObj = evt.srcElement; 
729            else
730                evtObj = evt.target;
731			
732				if (evtObj.id.substring(0,5) == 'thumb' && evtObj.parentNode.offsetWidth < 75)
733				{	
734					var positionX = getCoords(evtObj).x;
735					var positionY = getCoords(evtObj).y;
736					enlargedImage = $('enlargedImage'+this.photoNum);				
737					
738					enlargedImage.style.width = Math.floor(evtObj.width * 2.25) + 'px'; 
739					enlargedImage.style.height = Math.floor(evtObj.height * 2.25) + 'px'; 
740					enlargedImage.style.position = "absolute";
741					enlargedImage.style.top = positionY - Math.floor(evtObj.height * 0.75) + 'px';
742					enlargedImage.style.left = positionX - Math.floor(evtObj.width * 0.75)+ 'px';
743					enlargedImage.src = this.imageAttributes[this.currentImage].olpath;  // so we size down rather than up
744					//alert(enlargedImage.style.width);
745					enlargedImage.style.display = 'block';					
746				}						
747		}
748	   
749	    function checkDoubleClicks(evt) {
750        
751            if (!evt) var evt = window.event;
752        
753            if(document.all)    
754                evtObj = evt.srcElement; 
755            else
756                evtObj = evt.target;
757            
758            if (((evtObj.id.substring(0, 5) == "thumb") || (evtObj.id.substring(0, 8) == 'enlarged')) && this.mainViewer == 1) 
759            {                               
760			   //setting height & width of background gray area. 
761			   PA_ID = this.photoNum;			   
762			   
763			   window.document.body.appendChild($('detailScreen'));
764	           window.document.body.appendChild($('detailsContainer' + PA_ID));
765			   $('detailScreen').style.height = getWinHeight();
766               $('detailScreen').style.width = getWinWidth();
767               this.showDetails(evtObj);                
768               if ($('pausebutton'+this.photoNum).style.display == 'block') 
769				{
770				//this.stop();
771				this.midPlay = 1;
772				}
773            }   
774            else return;
775        }
776			
777        function checkClickables(evt)    {            
778            //alert(evt.target.id);
779			//alert(this.currentImage);
780			
781			if (!evt) var evt = window.event;
782            
783            if(document.all)    
784                evtObj = evt.srcElement; 
785            else
786                evtObj = evt.target;            
787            
788            if (((evtObj.id.substring(0, 5) == 'thumb') || (evtObj.id.substring(0, 8) == 'enlarged')) && (evtObj.id.substring(5, 8) != "Con")) 
789                {
790                	thumbID = evtObj.id.split("_");
791                	                               
792                    this.lastImage=this.currentImage;                   
793                    this.currentImage = parseInt(thumbID[2]);  //image container
794                    this.currentImage = parseInt(thumbID[2]);  //image                   
795                     
796                     this.findCurrent();
797					 this.showCurrent(evtObj);
798                }
799			/*if ((evtObj.id.substring(0, 8) == "enlarged")) {
800				this.lastImage = this.currentImage;
801				this.currentImage = parseInt($('enlargedImage'+this.photoNum).name);
802				this.findCurrent();
803				this.showCurrent();
804			}*/
805             if((evtObj.id == ("mainImage"+this.photoNum) || evtObj.id == ("imageContainer"+this.photoNum)) || (evtObj.id.substring(0, 5) == "thumb" && this.mainViewer == 0) || ((evtObj.id.substring(0, 8) == "enlarged") && (this.mainViewer == 0)))
806                {
807					//setting height & width of background gray area.
808					PA_ID = this.photoNum;
809				   //detailsScreen = $('detailscreen');
810				   
811				   window.document.body.appendChild($('detailScreen'));
812		           window.document.body.appendChild($('detailsContainer' + PA_ID));
813				   $('detailScreen').style.height = getWinHeight();
814	               $('detailScreen').style.width = getWinWidth();
815                    this.showDetails(evtObj);                
816                    //this.stop();
817                    this.midPlay = 1;                              
818                }           
819            }
820      	//document.onmouseout = checkMouseout	
821		
822		PhotoAlbum.prototype.calcRatio = calcRatio;
823		PhotoAlbum.prototype.buildThumbs = buildThumbs;
824		PhotoAlbum.prototype.updateCounter = updateCounter;
825		PhotoAlbum.prototype.buildMainViewer = buildMainViewer;		
826		PhotoAlbum.prototype.showDetails = showDetails;
827		PhotoAlbum.prototype.showNextDetail = showNextDetail;
828		PhotoAlbum.prototype.showPrevDetail = showPrevDetail;
829		PhotoAlbum.prototype.closeDetails = closeDetails;
830		PhotoAlbum.prototype.next = next;
831		PhotoAlbum.prototype.previous = previous;
832		PhotoAlbum.prototype.findCurrent = findCurrent;
833		PhotoAlbum.prototype.showCurrent = showCurrent;
834		PhotoAlbum.prototype.initPlay = initPlay;
835		PhotoAlbum.prototype.linearPlay = linearPlay;
836		PhotoAlbum.prototype.randPlay = randPlay;
837		PhotoAlbum.prototype.stop = stop;
838		PhotoAlbum.prototype.f_Slide = f_Slide;
839		PhotoAlbum.prototype.l_Slide = l_Slide;
840		PhotoAlbum.prototype.changeSpeed = changeSpeed;
841		PhotoAlbum.prototype.adjustOverlay = adjustOverlay;
842		PhotoAlbum.prototype.hideDetails = hideDetails;
843		PhotoAlbum.prototype.checkClickables = checkClickables;
844		PhotoAlbum.prototype.checkDoubleClicks = checkDoubleClicks;
845		PhotoAlbum.prototype.checkMouseover = checkMouseover;		
846		
847        /*****The PhotoAlbum object ****/ 		
848      	
849      	function PhotoAlbum(photoNum, mainWidth,photoAlbumType,imageBackColor,titleColor, thumbWidth,numOfThumbs,aspectRatio,titles, imageAttributes,textFont,specifyBoxWidth, newIC) {
850		
851		this.photoNum=photoNum; //The photo number
852		
853        this.mainWidth = mainWidth;     //colum width of the web page - should determine the size of the entire photo album
854        this.photoAlbumType = photoAlbumType; //PhotoAlbum Type 1-5		       
855		this.imageBackColor = imageBackColor;        //color of overlay matte and thumbnail BG:  defualt is WHITE        
856		this.titleColor = titleColor;   //title/desc text color
857		this.textFont = textFont;
858		this.specifyBoxWidth = specifyBoxWidth;
859		
860		if(this.specifyBoxWidth == "true"){
861		   this.numOfThumbs = 0;
862		   if (thumbWidth.length == 0) {
863			  this.thumbWidth = 0;
864		   } else {
865			  this.thumbWidth = parseInt(thumbWidth);  //advance option
866		   }
867		}
868		else{
869		   this.thumbWidth = 0;
870		   if (numOfThumbs.length == 0) {
871			  this.numOfThumbs = 0;
872		   } else	{
873			  this.numOfThumbs = parseInt(numOfThumbs);   //calculated based on mainWidth, 0 means nothing specified and use 'thumbWidth' advance option
874		   }
875		}
876        
877		this.aspectRatio = aspectRatio;  //could be "square", "portrait", "landscape":  default should be SQUARE per the specs, landscape might be better :-P       
878		
879		if (titles.length == 0 || titles == "false") {
880			this.titles = 0;
881		} else {
882			this.titles = 1;
883		}
884		    	   
885        this.slideSpeed = med;         //default is medium, 2 seconds        
886        this.imageAttributes = imageAttributes;   //should be an array
887         
888		 this.imageTotal = imageAttributes.length;
889		      
890		for(i=0; i<this.imageTotal; i++) {
891			imgObject = new Image();
892			imgObject.src=imageAttributes[i].sspath;
893			imgObject.src=imageAttributes[i].tnpath;
894			imgObject.src=imageAttributes[i].olpath;
895			//alert(imgObject.height);
896		}
897		
898		this.newIC = newIC;
899		
900		 this.mainHeight;   //calculated in calcRatio() 
901    	 this.thumbHeight;   //calculated in calcRatio()   
902
903 
904        /*** Init Variables ****/
905        
906        this.imageTotal = imageAttributes.length;
907		
908		this.controls = 0;    //show controls?  
909        this.thumbnails = 0;    //show thmbnails?   
910        this.mainViewer = 0;  //show main viewer?
911        this.randomSlideShow = 0;    //random?
912        this.defaultPlay = 0;   //make automatic if thumbs and controls are off   
913        this.currentImage = 0;
914        //this.currentDetail = 0;
915        this.lastImage = 0;
916        this.stopSlide = 0;
917        this.firstPlay = 1;
918        this.midPlay = 0;
919        this.Xcoord = 0;
920        this.Ycoord = 0;
921        this.playInterval = 0;
922		this.randInterval = 0;
923		this.mainDiv;
924		this.mainIMG;
925		this.thumbDiv;
926		this.thumbIMG;
927        this.thumbTitle;
928		this.largestDiv = [];
929		this.enlargedImage;
930		this.mainContainer = $('mainContainer' + this.photoNum);
931		
932        this.anContainer = new Animator({transition: Animator.makeEaseOut(4), duration: 1000});
933        this.anImage = new Animator({transition: Animator.makeEaseOut(3), duration: 600});
934        this.anTitle = new Animator({transition: Animator.makeEaseOut(3), duration: 600});
935        this.anScreen = new Animator({duration: 500});
936		
937        //anDesc = new Animator({transition: Animator.makeEaseOut(3), duration: 600});
938        //anClose = new Animator({transition: Animator.makeEaseOut(3), duration: 600});	
939		
940       // document.ondblclick = this.checkDoubleClicks;
941		//document.onmouseover = this.checkMouseover;		
942			
943			this.calcRatio();
944
945            //if(this.thumbnails ==1 ){this.buildThumbs();} 
946			this.buildThumbs();
947			this.findCurrent();
948            //if(this.mainViewer == 1){this.buildMainViewer();}
949			this.buildMainViewer();
950            this.showCurrent();   
951            
952            var PA_ID = this.photoNum;
953            var oldhandler = window.onload;            
954            if(this.newIC=="true")
955            	window.onload = function() {oldhandler(); buildOverlay(PA_ID);}
956            
957            //this.buildOverlay(this.photoNum); 
958           
959            this.anContainer.addSubject(new CSSStyleSubject($('details'+this.photoNum), "position: relative; top: 30px; left: 500px; opacity: 0.0; filter: alpha(opacity = 0); width: 400px; height: 400px; border: 1px solid #cccccc; margin: auto; overflow: hidden;", "opacity: 1; filter: alpha(opacity = 100); width: 500px; height: 690px; border: 2px solid #56A7EF; margin: auto;"));
960            
961            //anContainer.addSubject(new CSSStyleSubject($('details'), "detailsPre", "detailsPost")); 
962            
963            this.anImage.addSubject(new CSSStyleSubject($('popImage'+this.photoNum), "opacity: 0;filter: alpha(opacity = 0);", "opacity: 1; filter: alpha(opacity = 100);"));
964            this.anTitle.addSubject(new CSSStyleSubject($('popTitle'+this.photoNum), "opacity: 0;filter: alpha(opacity = 0);", "opacity: 1; filter: alpha(opacity = 100);"));
965            this.anScreen.addSubject(new CSSStyleSubject($('detailScreen'), "opacity: 0;filter: alpha(opacity = 0);", "opacity: 0.5; filter: alpha(opacity = 50);"));
966            //anDesc.addSubject(new CSSStyleSubject($('popDesc'+photoNum), "opacity: 0;filter: alpha(opacity = 0);", "opacity: 1; filter: alpha(opacity = 100);"));
967                      
968            
969			switch(this.photoAlbumType)
970			{
971				case (this.photoAlbumType=1):
972					this.mainViewer=1;
973					this.controls=1;
974					this.thumbnails=1;
975					this.defaultPlay=0;
976					break;
977				case (this.photoAlbumType=2):
978					this.mainViewer=1;
979					this.controls=0;
980					this.thumbnails=1;
981					this.defaultPlay=1;
982					break;
983				case (this.photoAlbumType=3):
984					this.mainViewer=1;
985					this.controls=1;
986					this.thumbnails=0;
987					this.defaultPlay=0;
988					break;
989				case (this.photoAlbumType=4):
990					this.mainViewer=1;
991					this.controls=0;
992					this.thumbnails=0;
993					this.defaultPlay=1;
994					break;
995				default:
996					this.mainViewer=0;
997					this.controls=0;
998					this.thumbnails=1;
999					this.defaultPlay=0;
1000					$('photoFoot' + this.photoNum).style.display = 'none';					
1001			}
1002			
1003			$("imageContainer"+this.photoNum).style.backgroundColor = this.imageBackColor;
1004            $("imageContainer"+this.photoNum).style.borderColor = this.imageBackColor;	
1005			
1006			if (this.defaultPlay ==1) {
1007                swap('detailplaybtn'+this.photoNum,'detailpausebtn'+this.photoNum);	 		
1008                swap('playbutton'+this.photoNum,'pausebutton'+this.photoNum);
1009				this.initPlay();
1010            }
1011            if (this.controls == 0) {
1012                $("controls"+this.photoNum).style.display = "none";                
1013            }
1014            
1015            if (this.thumbnails == 0) {
1016                $('thumbContainer'+this.photoNum).style.display = 'none';
1017                //initPlay();                
1018            }
1019            
1020            if(this.mainViewer == 0) {
1021                $("controls"+this.photoNum).style.display = "none";
1022                $("imageContainer"+this.photoNum).style.display = "none";
1023				this.defaultPlay = 0;
1024            }
1025            
1026			//alert($('thumbContainer'+this.photoNum));
1027            
1028            $("photoFoot"+this.photoNum).style.width = mainWidth + "px";
1029            $("controls"+this.photoNum).style.width = (mainWidth-6) + "px";
1030            $("details"+this.photoNum).style.backgroundColor = imageBackColor;
1031            $("details"+this.photoNum).style.borderColor = "#CCCCCC";
1032            $("popTitle"+this.photoNum).style.color = titleColor;
1033            $("popTitle"+this.photoNum).style.backgroundColor = imageBackColor;   //fix IE Bold glitch
1034            if(this.textFont != ""){
1035               $("popTitle"+this.photoNum).style.fontFamily = this.textFont;
1036            }        
1037            $("popDesc"+this.photoNum).style.color = titleColor;
1038            $("popDesc"+this.photoNum).style.backgroundColor = imageBackColor;   //fix IE Bold glitch
1039            if(this.textFont != ""){
1040               $("popDesc"+this.photoNum).style.fontFamily = this.textFont;
1041            }          
1042            this.updateCounter(this.photoNum); 
1043			
1044			//var pa_self = this;
1045			//normAddEvent(this.mainDiv, "click", function(e){
1046			// 		pa_self.checkClick(pa_self.mainDiv);
1047			// });
1048			
1049			
1050			 if (this.mainContainer.addEventListener){
1051			   this.mainContainer.addEventListener('click', createObjectCallback(this, this.checkClickables), false); 
1052			   this.mainContainer.addEventListener('dblclick', createObjectCallback(this, this.checkDoubleClicks), false); 
1053  			   //this.mainContainer.addEventListener('mouseover', createObjectCallback(this, this.checkMouseover), false);
1054			} else if (this.mainContainer.attachEvent){
1055			   this.mainContainer.attachEvent('onclick', createObjectCallback(this, this.checkClickables));
1056			   this.mainContainer.attachEvent('ondblclick', createObjectCallback(this, this.checkDoubleClicks)); 
1057  			   //this.mainContainer.attachEvent('onmouseover', createObjectCallback(this, this.checkMouseover));
1058			}
1059			
1060			
1061			if(this.largestDiv.length > 0) {
1062				for(var i=0; i<this.largestDiv.length; i++) {	
1063					//alert(getStyle(this.largestDiv[i], 'height'));
1064				}
1065			}
1066		
1067				//alert('returned zero-length array');
1068			
1069        }
1070        
1071        function buildOverlay(PA_ID) {
1072	    	
1073		    	window.document.body.appendChild($('detailScreen'));
1074		        window.document.body.appendChild($('detailsContainer' + PA_ID));
1075	        	        
1076        }
1077        
1078        function calcRatio() {
1079            
1080            if (this.aspectRatio == "landscape") {
1081                this.thumbHeight = Math.floor(this.thumbWidth*0.75);
1082                this.mainHeight = Math.floor(this.mainWidth*0.75);
1083            }
1084            else if (this.aspectRatio == "portrait") {
1085                this.thumbHeight =Math.floor(this.thumbWidth*1.33);
1086                this.mainHeight = Math.floor(this.mainWidth*1.33);
1087            }
1088            else //if "square"
1089            {
1090                this.thumbHeight = this.thumbWidth;
1091                this.mainHeight = this.mainWidth;
1092            }            
1093			
1094			//alert("mainHeight: "+this.mainHeight);
1095			
1096        }
1097        
1098        function updateCounter() {
1099            this.currentNum = this.currentImage + 1;  
1100            if ($("SlideNum"+this.photoNum)) {          
1101            	$("SlideNum"+this.photoNum).innerHTML = this.currentNum + "/" + this.imageTotal;
1102            } 
1103        }
1104        
1105         function buildThumbs() {
1106           
1107           //var largestTitle = 0;  //height added by thumbnail titles
1108          
1109           var j=0;
1110           var largestTitle = [j];  //height added by thumbnail titles
1111            
1112             if (this.numOfThumbs > 0 ) {
1113                 if (document.all)
1114                     this.thumbWidth = Math.floor(this.mainWidth/this.numOfThumbs) - 13;   //18 is padding+ border + left/right extremes
1115                 else
1116                     this.thumbWidth = Math.floor(this.mainWidth/this.numOfThumbs) - 12;                 
1117             }             
1118             
1119            this.calcRatio();
1120			 
1121             $('thumbContainer'+this.photoNum).style.width = this.mainWidth + "px";             
1122             
1123             
1124			 this.thumbDiv = new Array;
1125             this.thumbIMG = new Array;
1126             this.thumbTitle = new Array;
1127			 this.thumbTable = new Array;
1128			 this.thumbTBody = new Array;
1129			 this.thumbTR = new Array;
1130			 this.thumbTD = new Array;
1131						 
1132             for(i=0; i<this.imageTotal; i++) {
1133                 this.thumbDiv[i] = document.createElement("div");
1134                 this.thumbTitle[i] = document.createElement("div");
1135				 this.thumbIMG[i] = document.createElement("IMG");
1136                 this.thumbTable[i] = document.createElement("table");
1137			 	 this.thumbTBody[i] = document.createElement("tbody");
1138			 	 this.thumbTR[i] = document.createElement("tr");
1139			 	 this.thumbTD[i] = document.createElement("td");
1140			 	 
1141			 	 			 	 
1142			 	 this.thumbTable[i].cellPadding = 0;
1143			 	 this.thumbTable[i].cellSpacing = 0;
1144			 	 this.thumbTable[i].height = this.thumbHeight+"px";
1145			 	 this.thumbTable[i].width = this.thumbWidth+"px";
1146			 	 this.thumbTD[i].height = this.thumbHeight+"px";
1147			 	 this.thumbTD[i].width = this.thumbWidth+"px";
1148			 	 this.thumbTD[i].vAlign = "middle";
1149                   
1150                 this.thumbDiv[i].className="imageThumb";
1151                 this.thumbDiv[i].id="thumbDiv_"+this.photoNum + "_" + i;  
1152                 this.thumbDiv[i].style.width = this.thumbWidth + "px";                  
1153                 this.thumbDiv[i].style.height = this.thumbHeight + "px";                   
1154                 this.thumbDiv[i].style.backgroundColor = this.imageBackColor;
1155                 this.thumbDiv[i].style.borderColor = this.imageBackColor;  
1156                 this.thumbDiv[i].style.lineHeight = this.thumbHeight + "px";				   
1157				  
1158				 this.thumbIMG[i].src = this.imageAttributes[i].tnpath;
1159                 this.thumbIMG[i].alt = this.imageAttributes[i].alt;
1160                 this.thumbIMG[i].id = "thumb_"+this.photoNum + "_" + i;
1161				 this.thumbIMG[i].style.margin = "auto";				  
1162                 this.thumbIMG[i].style.display = "block";  //IE fix
1163                 this.thumbIMG[i].style.textAlign = "center";  //IE fix
1164                 
1165                 this.thumbTitle[i].className = 'thumbTitle';
1166                 this.thumbTitle[i].innerHTML = this.imageAttributes[i].title;                 
1167				 this.thumbTitle[i].style.color = this.titleColor;
1168				 this.thumbTitle[i].style.fontFamily = this.textFont;
1169				 this.thumbTitle[i].style.textAlign = "center";
1170				 this.thumbTitle[i].style.cursor = "default";
1171				 
1172				if(this.imageAttributes[i].title.length > largestTitle[j]) {
1173			 		largestTitle[j] = this.imageAttributes[i].title.length;
1174			 		this.largestDiv[j] = this.thumbTitle[i];
1175			 		//alert(this.largestDiv[j].offsetHeight);			 		
1176			 	}
1177				  
1178				 if(((i+1)%this.numOfThumbs) == 0) {
1179				 	j++;
1180				 	largestTitle[j] = 0;
1181				 	this.largestDiv[j] = this.thumbTitle[i];				 	
1182				 }
1183				
1184				
1185				/*
1186			 	if(this.imageAttributes[i].title.length > largestTitle)
1187			 		largestTitle = this.imageAttributes[i].title.length;
1188				 */ 
1189				                             
1190                 /**Attach**/                   
1191                 $("thumbContainer"+this.photoNum).appendChild(this.thumbDiv[i]);
1192                 this.thumbDiv[i].appendChild(this.thumbTable[i]);
1193                 this.thumbTable[i].appendChild(this.thumbTBody[i]);
1194                 this.thumbTBody[i].appendChild(this.thumbTR[i]);                 
1195                 this.thumbTR[i].appendChild(this.thumbTD[i]);                             
1196                 this.thumbTD[i].appendChild(this.thumbIMG[i]);
1197                 this.thumbDiv[i].appendChild(this.thumbTitle[i]);
1198              }  
1199              		
1200	             //Calculate height with titles PER ROW	             
1201	             
1202	             var newHeight = [];
1203	             
1204	             if (this.titles == 1) {
1205	             
1206	             	//get specific height per row
1207	             	for(i=0; i<=j; i++) {
1208		             	approxWidth = Math.ceil(largestTitle[i]*11);   //font size is 11px
1209		             		             	
1210		             	if(approxWidth > this.thumbWidth)	
1211		             		rowUnit = Math.ceil(approxWidth/this.thumbWidth);
1212		             	else if(largestTitle[i] == 0)
1213		             		rowUnit = 0;
1214		             	else
1215		             		rowUnit = 1;
1216		             	
1217		             	newHeight[i] = rowUnit * 16;  //line-height is set to 16px
1218	             	}
1219	             	
1220	             	j=0; //reset row counter
1221	             		             	
1222	             	for(i=0; i<this.imageTotal; i++) {	             		
1223	             			             		
1224	             		
1225	             		//alert(parseInt(getStyle(this.thumbDiv[i], 'height')) + ' +  ' + parseInt(getStyle(this.largestDiv[j], 'height')));
1226	             		
1227	             		
1228	             		//if(document.all)
1229	             			this.thumbDiv[i].style.height = parseInt(this.thumbDiv[i].style.height) + newHeight[j] + "px";
1230	             		//else
1231	             		//	this.thumbDiv[i].style.height = parseInt(getStyle(this.thumbDiv[i], 'height')) + parseInt(getStyle(this.largestDiv[j], 'height')) + "px";	             		
1232	             		
1233	             		//alert('should equal this: ' + this.thumbDiv[i].style.height);
1234	             		if(((i+1)%this.numOfThumbs) == 0) {
1235				 			//alert(this.largestDiv[j].offsetHeight);
1236				 			j++;				 			
1237				 		}             		
1238	             	}
1239	             }	         
1240             }    
1241             
1242             
1243             function getStyle(node, sStyle) {				
1244				var style;
1245				if (document.all) {
1246					nodeStyle = node.offsetHeight;
1247				} else {
1248					try {
1249					nodeStyle = document.defaultView.getComputedStyle(node,null).getPropertyValue(sStyle);
1250				  } catch(e) { }
1251				}
1252				return nodeStyle;
1253			}
1254             
1255             
1256             
1257             
1258                           
1259                      
1260           function buildMainViewer() {
1261             //this.mainDiv = document.createElement("div");
1262             this.mainIMG = document.createElement("IMG");     
1263             
1264             $("imageContainer"+this.photoNum).width = this.mainWidth;
1265             $("imageContainer"+this.photoNum).height = this.mainHeight;             
1266             //this.mainDiv.className = "mainImageDiv";
1267             //this.mainDiv.id = "imageContainer"+this.photoNum;			 
1268			 $("imageContainer"+this.photoNum).appendChild(this.mainIMG);
1269			 $('detailScreen').style.height = getWinHeight();
1270	     	 $('detailScreen').style.width = getWinWidth();
1271	     	 
1272	     	 if(this.newIC == 'false' && document.all) {
1273	     	 	$('details'+this.photoNum).style.position = 'absolute';	     	 	
1274	     	 }
1275	         
1276         }
1277    
1278	    /*****Behavioral Functions****/
1279        
1280		function getWinWidth(){
1281			var w;
1282			if(document.innerWidth) {
1283				w=document.innerWidth;
1284			} else if(document.documentElement.clientWidth) {
1285				w=document.documentElement.clientWidth;
1286			} else if(document.body) {
1287				w=document.body.clientWidth; 
1288			}
1289			return w;
1290		}
1291		function getWinHeight(){
1292			var h;
1293			if(document.innerHeight){ 
1294				h=document.innerHeight;
1295			} else if(document.documentElement.clientHeight) { 
1296				h=document.documentElement.clientHeight;
1297			} else if(document.body) { 
1298				h=document.body.clientHeight; 
1299			}
1300			return h;
1301		}        
1302        
1303        function showDetails(evtObj) {            
1304           
1305          // this.mainIMG.style.display = 'none';
1306           
1307           //Hide all dropdowns in page id IE
1308           if(document.all) {
1309	            var dropdowns = document.getElementsByTagName('select');			
1310				for (var j = 0; j < dropdowns.length; j++) { 
1311				    dropdowns[j].style.visibility = 'hidden';
1312				}
1313           }
1314            
1315            if (document.all) {
1316                
1317                if(this.newIC == 'false') {
1318	             	if (((evtObj.id.substring(0, 5) == 'thumb') || (evtObj.id.substring(0, 8) == 'enlarged')) && (evtObj.id.substring(5, 8) != "Con")) {
1319		             	$('detailsContainer'+this.photoNum).style.marginTop = getCoords(evtObj).y - 20 + "px";
1320		             	$('detailsContainer'+this.photoNum).style.marginLeft = getCoords($('mainContainer'+this.photoNum)).x + "px";
1321		             }
1322		             else {
1323	                	$("detailsContainer"+this.photoNum).style.marginTop = getCoords($('mainContainer'+this.photoNum)).y + "px";
1324	                	$("detailsContainer"+this.photoNum).style.marginLeft = getCoords($('mainContainer'+this.photoNum)).x + "px";
1325	                }
1326	            }
1327	            else {	              
1328	               $("detailsContainer"+this.photoNum).style.top = document.documentElement.scrollTop + 10 + "px";
1329	               $("detailScreen").style.top = document.documentElement.scrollTop + "px";
1330	            }
1331	            
1332	            if(navigator.appVersion.indexOf("MSIE 7.")!=-1) {
1333	            	$("detailScreen").style.top = "0px";
1334	            }
1335             }
1336            else  { //anything other than IE            	
1337                $("detailsContainer"+this.photoNum).style.top =  window.pageYOffset + 10 + "px";
1338                $("detailScreen").style.top =  "0px";     
1339             }
1340             
1341            $("detailsContainer"+this.photoNum).style.display = "block";
1342            $("detailScreen").style.display = "block";
1343            $("popImage"+this.photoNum).src = this.imageAttributes[this.currentImage].olpath;
1344            //$("popImage"+this.photoNum).style.marginTop = Math.floor((500 - $("popImage"+this.photoNum).height)/2) + "px";
1345            //alert(this.imageAttributes[this.currentImage].title.length);
1346            $("popTitle"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].title;
1347            $("popDesc"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].desc;
1348                       
1349            this.anContainer.toggle();
1350			if(this.newIC == 'true')	
1351				this.anScreen.toggle();
1352			this.anImage.toggle();
1353			this.anTitle.toggle();
1354			
1355           /* window.setTimeout('anScreen.toggle()', 600);
1356            window.setTimeout('anImage.toggle()', 400);
1357            window.setTimeout('anTitle.toggle()', 400); */
1358        }
1359        
1360        function closeDetails() {
1361            
1362            
1363            if ($('playbutton'+this.photoNum).style.display == 'none' || (this.defaultPlay == 1 && this.controls == 0)) {
1364                window.setTimeout(createObjectCallback(this, this.initPlay), 500);
1365            }
1366                          
1367             this.anImage.toggle();
1368             this.anTitle.toggle();             
1369             this.anContainer.toggle();
1370             if(this.newIC == 'true')	
1371				this.anScreen.toggle();
1372             window.setTimeout(createObjectCallback(this, this.hideDetails), 1000);
1373        }
1374         
1375		 function hideDetails() {
1376		 	$("detailsContainer"+this.photoNum).style.display = "none";
1377			$("detailScreen").style.display = "none";
1378			this.mainIMG.style.display = 'block';
1379			
1380			//Show all dropdowns in page if IE
1381           if(document.all) {
1382	            var dropdowns = document.getElementsByTagName('select');			
1383				for (var i = 0; i < dropdowns.length; i++) { 
1384				    dropdowns[i].style.visibility = 'visible';
1385				}
1386           }
1387		 }
1388		 
1389		  function stop() {
1390            if (this.randomSlideShow == 1) {
1391                 clearInterval(this.randInterval);
1392             }
1393             else {
1394				 /**if (playInterval != "")**/ 
1395				 clearInterval(this.playInterval);
1396             }
1397             this.midPlay = 0;
1398         }
1399         
1400         function f_Slide() {
1401             this.lastImage = this.currentImage;
1402             this.currentImage = 0;
1403             
1404             this.findCurrent();
1405             this.showCurrent();
1406         }
1407         
1408         function l_Slide() {
1409             this.lastImage = this.currentImage;
1410             this.currentImage = this.imageTotal -1;
1411             
1412             this.findCurrent();
1413             this.showCurrent();
1414         }
1415         
1416         function findCurrent() {             
1417			 //alert("thumb"+this.photoNum + this.lastImage);
1418			 //$("thumb_"+this.photoNum + "_" + this.lastImage).parentNode.className = "imageThumb";
1419             //$("thumb_"+this.photoNum + "_" + i).parentNode.className = "imageThumbSelected";
1420             this.updateCounter(this.currentImage);
1421         }       
1422         
1423          function showCurrent() {             
1424             
1425             this.mainIMG.src = this.imageAttributes[this.currentImage].sspath;             
1426             this.mainIMG.alt = this.imageAttributes[this.currentImage].alt;
1427             
1428             this.mainIMG.id = "mainImage"+this.photoNum;                    
1429        	
1430        	$("popImage"+this.photoNum).src = this.imageAttributes[this.currentImage].olpath;
1431        	if ($("popTitle"+this.photoNum))
1432            	$("popTitle"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].title;
1433            if ($("popDesc"+this.photoNum))
1434            	$("popDesc"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].desc;
1435        
1436         }
1437         
1438         function initPlay() {
1439			//alert(this);
1440
1441			var speed = this.slideSpeed;
1442
1443			 if (this.randomSlideShow == 1) {                 
1444                 if(this.firstPlay == 0) clearInterval(this.randInterval);
1445                 this.randInterval = window.setInterval(createObjectCallback(this, this.linearPlay), speed);
1446             }
1447             else  {                 
1448                 if(this.firstPlay == 0) clearInterval(this.playInterval);
1449				
1450				//alert(this.id);
1451			
1452				 this.playInterval = window.setInterval(createObjectCallback(this, this.linearPlay), speed);
1453             }
1454			 
1455			 //alert(this.linearPlay);
1456			 			 
1457            this.firstPlay = 0;
1458         }
1459         
1460		  function linearPlay() {             
1461             //alert("linear play: " + this);
1462			 //if (this.stopSlide != 1) {                 
1463                //  if ($('detailScreen').style.display == 'block') {
1464				// 	if (this.currentDetail != this.imageTotal -1)
1465		      //          this.currentDetail++;
1466		     //       else
1467		        //        this.currentDetail = 0;
1468		            
1469		      //      $("popImage"+this.photoNum).src = this.imageAttributes[currentDetail].olpath;
1470		      //      $("popTitle"+this.photoNum).innerHTML = this.imageAttributes[currentDetail].title;
1471		     //       $("popDesc"+this.photoNum).innerHTML = this.imageAttributes[currentDetail].desc;
1472			//	 }	
1473				 
1474					 this.showNextDetail();
1475             //}
1476             //else return;
1477         }
1478         
1479         function next() {
1480              //alert("Next this: "+ this);
1481			  if (this.currentImage < this.imageTotal-1) {   
1482                 this.lastImage=this.currentImage;
1483                 this.currentImage++;                 
1484              }
1485              else {
1486                  this.currentImage=0;
1487                  this.lastImage = this.imageTotal - 1;
1488              }
1489            this.findCurrent();
1490            this.showCurrent();
1491         }
1492         
1493           function showNextDetail() {
1494            
1495			/*
1496            if (this.currentImage != this.imageTotal -1)
1497                this.currentImage++;
1498            else
1499                this.currentImage = 0;
1500			*/
1501            
1502            this.next();
1503			
1504            $("popImage"+this.photoNum).src = this.imageAttributes[this.currentImage].olpath;
1505            $("popTitle"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].title;
1506            $("popDesc"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].desc;
1507        }
1508         
1509         function previous() {
1510             if (this.currentImage > 0) {
1511                 this.lastImage=this.currentImage;
1512                 this.currentImage--;               
1513             }
1514             else {
1515                 this.currentImage=this.imageTotal-1;
1516                 this.lastImage = 0;
1517             }
1518             this.findCurrent();
1519             this.showCurrent();
1520         }
1521        
1522        function showPrevDetail() {
1523            /*
1524            if (this.currentImage != 0)
1525                this.currentImage--;
1526            else
1527                this.currentImage = this.imageTotal-1;
1528            */
1529			
1530			this.previous();
1531			
1532            $("popImage"+this.photoNum).src = this.imageAttributes[this.currentImage].olpath;
1533            $("popTitle"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].title;
1534            $("popDesc"+this.photoNum).innerHTML = this.imageAttributes[this.currentImage].desc;
1535            
1536        }
1537         
1538         function randPlay() {
1539             
1540                 if (stopSlide != 1) {
1541                     if (this.currentImage <= this.imageTotal) 
1542                     {    
1543                         
1544                         this.lastImage = this.currentImage;
1545                         
1546                         while (this.lastImage == this.currentImage) {
1547                             this.currentImage = randNum(0, (this.imageTotal-1));
1548                         }
1549                         
1550                         this.findCurrent();
1551                         this.showCurrent();                  
1552                                          
1553                     }                     
1554                 }
1555                     else return;
1556         }
1557         
1558         function changeSpeed(speed, num, relative_path)
1559         {    
1560             this.slideSpeed = speed;
1561             //speed = this.slideSpeed;  //just trust me
1562			 
1563			 for (i=num; i<6; i++)
1564			 {
1565			 	$('speed'+i+this.photoNum).src = relative_path+'images/photoalbum/button_photoSpeed'+i+'.jpg';
1566				//$('detailspeed'+i).src = 'images/photoalbum/button_photoSpeed'+i+'.jpg';
1567			 }
1568			 for (i=1; i<=num; i++)
1569			 {
1570			 	$('speed'+i+this.photoNum).src = relative_path+'images/photoalbum/button_photoSpeed'+i+'_ON.jpg';
1571				//$('detailspeed'+i).src = 'images/button_photoSpeed'+i+'_ON.jpg';
1572			 }
1573			 
1574             if (this.randomSlideShow == 1) {
1575                 clearInterval(this.randInterval);
1576                 this.randInterval = window.setInterval(createObjectCallback(this, this.randPlay), this.slideSpeed);
1577             }
1578             else if($('playbutton'+this.photoNum).style.display == 'none')
1579                 {				 	
1580				 	 clearInterval(this.playInterval);
1581	                 this.playInterval = window.setInterval(createObjectCallback(this, this.linearPlay), this.slideSpeed);
1582				 }
1583         }
1584		 
1585		 
1586	 function swap(a, b) {
1587	   	$(a).style.display = 'none';
1588		$(b).style.display = 'inline';
1589	   }
1590	   
1591	   function $(id) {
1592			return document.getElementById(id);
1593		}
1594         
1595          function randNum(x, y) {
1596             var range = y - x + 1;
1597             return Math.floor(Math.random() * range) + x;
1598         }
1599         
1600         function getCoords(element)
1601			{
1602                   var valueT = 0, valueL = 0;
1603            
1604                   do
1605                   {
1606                           valueT += element.offsetTop  || 0;
1607                           valueL += element.offsetLeft || 0;
1608                           element = element.offsetParent;
1609                   }
1610                   while (element);
1611            
1612                   return {x: valueL, y: valueT};
1613            }
1614		
1615		function adjustOverlay() {  //onscroll
1616           try{
1617	           if (document.all &&(navigator.appVersion.indexOf("MSIE 7.")==-1)) {
1618	            $('detailScreen').style.height = getWinHeight();  //adjust for resize
1619	     	 	$('detailScreen').style.width = getWinWidth();   //adjust for resize
1620	                //$("detailsContainer"+this.photoNum).style.top =   document.documentElement.scrollTop + 10 + "px";
1621	                if(this.newIC == 'false') {  //legacy frames
1622	                	//$("detailScreen").style.top = parent.content.document.body.scrollTop + "px";
1623	                }
1624	                else {
1625	                	$("detailScreen").style.top = document.documentElement.scrollTop + "px";
1626	                }	                
1627	             }
1628	           }
1629	        catch(e){return false;}
1630					 //else  {
1631		            //    $("detailsContainer").style.top =  window.pageYOffset + 10 + "px";
1632		            //    $("detailScreen").style.top =  window.pageYOffset + "px";
1633		            // } 
1634
1635        }
1636		
1637		function createObjectCallback(obj, fn)
1638		{
1639			return function() 
1640				{ 
1641					fn.apply(obj, arguments);
1642				};
1643		}
1644         
1645	/* 			####### Photoalbum.js code ends here ########## */

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.