PageSourceSearch

https://tod.org/scripts/photoalbum.js

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