PageSourceSearch

https://daringfireball.net/js/js-global/FancyZoom.js

js daringfireball.net collected 2026-10-01 06:06:36 UTC 23,681 bytes, 777 lines download raw bytes

1// FancyZoom.js - v1.1 - http://www.fancyzoom.com
2//
3// Copyright (c) 2008 Cabel Sasser / Panic Inc
4// All rights reserved.
5// 
6//     Requires: FancyZoomHTML.js
7// Instructions: Include JS files in page, call setupZoom() in onLoad. That's it!
8//               Any <a href> links to images will be updated to zoom inline.
9//               Add rel="nozoom" to your <a href> to disable zooming for an image.
10// 
11// Redistribution and use of this effect in source form, with or without modification,
12// are permitted provided that the following conditions are met:
13// 
14// * USE OF SOURCE ON COMMERCIAL (FOR-PROFIT) WEBSITE REQUIRES ONE-TIME LICENSE FEE PER DOMAIN.
15//   Reasonably priced! Visit www.fancyzoom.com for licensing instructions. Thanks!
16//
17// * Non-commercial (personal) website use is permitted without license/payment!
18//
19// * Redistribution of source code must retain the above copyright notice,
20//   this list of conditions and the following disclaimer.
21//
22// * Redistribution of source code and derived works cannot be sold without specific
23//   written prior permission.
24//
25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37var includeCaption = true; // Turn on the "caption" feature, and write out the caption HTML
38var zoomTime       = 5;    // Milliseconds between frames of zoom animation
39var zoomSteps      = 15;   // Number of zoom animation frames
40var includeFade    = 1;    // Set to 1 to fade the image in / out as it zooms
41var minBorder      = 90;   // Amount of padding between large, scaled down images, and the window edges
42var shadowSettings = '0px 5px 25px rgba(0, 0, 0, '; // Blur, radius, color of shadow for compatible browsers
43
44var zoomImagesURI   = '/js/images-global/zoom/'; // Location of the zoom and shadow images
45
46// Init. Do not add anything below this line, unless it's something awesome.
47
48var myWidth = 0, myHeight = 0, myScroll = 0; myScrollWidth = 0; myScrollHeight = 0;
49var zoomOpen = false, preloadFrame = 1, preloadActive = false, preloadTime = 0, imgPreload = new Image();
50var preloadAnimTimer = 0;
51
52var zoomActive = new Array(); var zoomTimer  = new Array(); 
53var zoomOrigW  = new Array(); var zoomOrigH  = new Array();
54var zoomOrigX  = new Array(); var zoomOrigY  = new Array();
55
56var zoomID         = "ZoomBox";
57var theID          = "ZoomImage";
58var zoomCaption    = "ZoomCaption";
59var zoomCaptionDiv = "ZoomCapDiv";
60
61if (navigator.userAgent.indexOf("MSIE") != -1) {
62	var browserIsIE = true;
63}
64
65// Zoom: Setup The Page! Called in your <body>'s onLoad handler.
66
67function setupZoom() {
68	prepZooms();
69	insertZoomHTML();
70	zoomdiv = document.getElementById(zoomID);  
71	zoomimg = document.getElementById(theID);
72}
73
74// Zoom: Inject Javascript functions into hrefs pointing to images, one by one!
75// Skip any href that contains a rel="nozoom" tag.
76// This is done at page load time via an onLoad() handler.
77
78function prepZooms() {
79	if (! document.getElementsByTagName) {
80		return;
81	}
82	var links = document.getElementsByTagName("a");
83	for (i = 0; i < links.length; i++) {
84		if (links[i].getAttribute("href")) {
85			if (links[i].getAttribute("href").search(/(.*)\.(jpg|jpeg|gif|png|bmp|tif|tiff)/gi) != -1) {
86				if (links[i].getAttribute("rel") != "nozoom") {
87					links[i].onclick = function (event) { return zoomClick(this, event); };
88					links[i].onmouseover = function () { zoomPreload(this); };
89				}
90			}
91		}
92	}
93}
94
95// Zoom: Load an image into an image object. When done loading, function sets preloadActive to false,
96// so other bits know that they can proceed with the zoom.
97// Preloaded image is stored in imgPreload and swapped out in the zoom function.
98
99function zoomPreload(from) {
100
101	var theimage = from.getAttribute("href");
102
103	// Only preload if we have to, i.e. the image isn't this image already
104
105	if (imgPreload.src.indexOf(from.getAttribute("href").substr(from.getAttribute("href").lastIndexOf("/"))) == -1) {
106		preloadActive = true;
107		imgPreload = new Image();
108
109		// Set a function to fire when the preload is complete, setting flags along the way.
110
111		imgPreload.onload = function() {
112			preloadActive = false;
113		}
114
115		// Load it!
116		imgPreload.src = theimage;
117	}
118}
119
120// Zoom: Start the preloading animation cycle.
121
122function preloadAnimStart() {
123	preloadTime = new Date();
124	document.getElementById("ZoomSpin").style.left = (myWidth / 2) + 'px';
125	document.getElementById("ZoomSpin").style.top = ((myHeight / 2) + myScroll) + 'px';
126	document.getElementById("ZoomSpin").style.visibility = "visible";	
127	preloadFrame = 1;
128	document.getElementById("SpinImage").src = zoomImagesURI+'zoom-spin-'+preloadFrame+'.png';  
129	preloadAnimTimer = setInterval("preloadAnim()", 100);
130}
131
132// Zoom: Display and ANIMATE the jibber-jabber widget. Once preloadActive is false, bail and zoom it up!
133
134function preloadAnim(from) {
135	if (preloadActive != false) {
136		document.getElementById("SpinImage").src = zoomImagesURI+'zoom-spin-'+preloadFrame+'.png';
137		preloadFrame++;
138		if (preloadFrame > 12) preloadFrame = 1;
139	} else {
140		document.getElementById("ZoomSpin").style.visibility = "hidden";    
141		clearInterval(preloadAnimTimer);
142		preloadAnimTimer = 0;
143		zoomIn(preloadFrom);
144	}
145}
146
147// ZOOM CLICK: We got a click! Should we do the zoom? Or wait for the preload to complete?
148// todo?: Double check that imgPreload src = clicked src
149
150function zoomClick(from, evt) {
151
152	var shift = getShift(evt);
153
154	// Check for Command / Alt key. If pressed, pass them through -- don't zoom!
155	if (! evt && window.event && (window.event.metaKey || window.event.altKey)) {
156		return true;
157	} else if (evt && (evt.metaKey|| evt.altKey)) {
158		return true;
159	}
160
161	// Get browser dimensions
162	getSize();
163
164	// If preloading still, wait, and display the spinner.
165	if (preloadActive == true) {
166		// But only display the spinner if it's not already being displayed!
167		if (preloadAnimTimer == 0) {
168			preloadFrom = from;
169			preloadAnimStart();	
170		}
171	} else {
172		// Otherwise, we're loaded: do the zoom!
173		zoomIn(from, shift);
174	}
175	
176	return false;
177	
178}
179
180// Zoom: Move an element in to endH endW, using zoomHost as a starting point.
181// "from" is an object reference to the href that spawned the zoom.
182
183function zoomIn(from, shift) {
184
185	zoomimg.src = from.getAttribute("href");
186
187	// Determine the zoom settings from where we came from, the element in the <a>.
188	// If there's no element in the <a>, or we can't get the width, make stuff up
189
190	if (from.childNodes[0].width) {
191		startW = from.childNodes[0].width;
192		startH = from.childNodes[0].height;
193		startPos = findElementPos(from.childNodes[0]);
194	} else {
195		startW = 50;
196		startH = 12;
197		startPos = findElementPos(from);
198	}
199
200	hostX = startPos[0];
201	hostY = startPos[1];
202
203	// Make up for a scrolled containing div.
204	// TODO: This HAS to move into findElementPos.
205	
206	if (document.getElementById('scroller')) {
207		hostX = hostX - document.getElementById('scroller').scrollLeft;
208	}
209
210	// Determine the target zoom settings from the preloaded image object
211
212	endW = imgPreload.width;
213	endH = imgPreload.height;
214
215	// Start! But only if we're not zooming already!
216
217	if (zoomActive[theID] != true) {
218
219		// Clear everything out just in case something is already open
220
221		if (document.getElementById("ShadowBox")) {
222			document.getElementById("ShadowBox").style.visibility = "hidden";
223		} else if (! browserIsIE) {
224		
225			// Wipe timer if shadow is fading in still
226			if (fadeActive["ZoomImage"]) {
227				clearInterval(fadeTimer["ZoomImage"]);
228				fadeActive["ZoomImage"] = false;
229				fadeTimer["ZoomImage"] = false;			
230			}
231			
232			document.getElementById("ZoomImage").style.webkitBoxShadow = shadowSettings + '0.0)';			
233		}
234		
235		document.getElementById("ZoomClose").style.visibility = "hidden";     
236
237		// Setup the CAPTION, if existing. Hide it first, set the text.
238
239		if (includeCaption) {
240			document.getElementById(zoomCaptionDiv).style.visibility = "hidden";
241			if (from.getAttribute('title') && includeCaption) {
242				// Yes, there's a caption, set it up
243				document.getElementById(zoomCaption).innerHTML = from.getAttribute('title');
244			} else {
245				document.getElementById(zoomCaption).innerHTML = "";
246			}
247		}
248
249		// Store original position in an array for future zoomOut.
250
251		zoomOrigW[theID] = startW;
252		zoomOrigH[theID] = startH;
253		zoomOrigX[theID] = hostX;
254		zoomOrigY[theID] = hostY;
255
256		// Now set the starting dimensions
257
258		zoomimg.style.width = startW + 'px';
259		zoomimg.style.height = startH + 'px';
260		zoomdiv.style.left = hostX + 'px';
261		zoomdiv.style.top = hostY + 'px';
262
263		// Show the zooming image container, make it invisible
264
265		if (includeFade == 1) {
266			setOpacity(0, zoomID);
267		}
268		zoomdiv.style.visibility = "visible";
269
270		// If it's too big to fit in the window, shrink the width and height to fit (with ratio).
271
272		sizeRatio = endW / endH;
273		if (endW > myWidth - minBorder) {
274			endW = myWidth - minBorder;
275			endH = endW / sizeRatio;
276		}
277		if (endH > myHeight - minBorder) {
278			endH = myHeight - minBorder;
279			endW = endH * sizeRatio;
280		}
281
282		zoomChangeX = ((myWidth / 2) - (endW / 2) - hostX);
283		zoomChangeY = (((myHeight / 2) - (endH / 2) - hostY) + myScroll);
284		zoomChangeW = (endW - startW);
285		zoomChangeH = (endH - startH);
286		
287		// Shift key?
288	
289		if (shift) {
290			tempSteps = zoomSteps * 7;
291		} else {
292			tempSteps = zoomSteps;
293		}
294
295		// Setup Zoom
296
297		zoomCurrent = 0;
298
299		// Setup Fade with Zoom, If Requested
300
301		if (includeFade == 1) {
302			fadeCurrent = 0;
303			fadeAmount = (0 - 100) / tempSteps;
304		} else {
305			fadeAmount = 0;
306		}
307
308		// Do It!
309		// 2026-04-18: setTimeout() calls were setInterval(), patch from JJ
310		zoomTimer[theID] = setTimeout("zoomElement('"+zoomID+"', '"+theID+"', "+zoomCurrent+", "+startW+", "+zoomChangeW+", "+startH+", "+zoomChangeH+", "+hostX+", "+zoomChangeX+", "+hostY+", "+zoomChangeY+", "+tempSteps+", "+includeFade+", "+fadeAmount+", 'zoomDoneIn(zoomID)')", zoomTime);		
311		zoomActive[theID] = true; 
312	}
313}
314
315// Zoom it back out.
316
317function zoomOut(from, evt) {
318
319	// Get shift key status.
320	// IE events don't seem to get passed through the function, so grab it from the window.
321
322	if (getShift(evt)) {
323		tempSteps = zoomSteps * 7;
324	} else {
325		tempSteps = zoomSteps;
326	}	
327
328	// Check to see if something is happening/open
329  
330	if (zoomActive[theID] != true) {
331
332		// First, get rid of the shadow if necessary.
333
334		if (document.getElementById("ShadowBox")) {
335			document.getElementById("ShadowBox").style.visibility = "hidden";
336		} else if (! browserIsIE) {
337		
338			// Wipe timer if shadow is fading in still
339			if (fadeActive["ZoomImage"]) {
340				clearInterval(fadeTimer["ZoomImage"]);
341				fadeActive["ZoomImage"] = false;
342				fadeTimer["ZoomImage"] = false;			
343			}
344			
345			document.getElementById("ZoomImage").style.webkitBoxShadow = shadowSettings + '0.0)';			
346		}
347
348		// ..and the close box...
349
350		document.getElementById("ZoomClose").style.visibility = "hidden";
351
352		// ...and the caption if necessary!
353
354		if (includeCaption && document.getElementById(zoomCaption).innerHTML != "") {
355			// fadeElementSetup(zoomCaptionDiv, 100, 0, 5, 1);
356			document.getElementById(zoomCaptionDiv).style.visibility = "hidden";
357		}
358
359		// Now, figure out where we came from, to get back there
360
361		startX = parseInt(zoomdiv.style.left);
362		startY = parseInt(zoomdiv.style.top);
363		startW = zoomimg.width;
364		startH = zoomimg.height;
365		zoomChangeX = zoomOrigX[theID] - startX;
366		zoomChangeY = zoomOrigY[theID] - startY;
367		zoomChangeW = zoomOrigW[theID] - startW;
368		zoomChangeH = zoomOrigH[theID] - startH;
369
370		// Setup Zoom
371
372		zoomCurrent = 0;
373
374		// Setup Fade with Zoom, If Requested
375
376		if (includeFade == 1) {
377			fadeCurrent = 0;
378			fadeAmount = (100 - 0) / tempSteps;
379		} else {
380			fadeAmount = 0;
381		}
382
383		// Do It!
384
385		zoomTimer[theID] = setTimeout("zoomElement('"+zoomID+"', '"+theID+"', "+zoomCurrent+", "+startW+", "+zoomChangeW+", "+startH+", "+zoomChangeH+", "+startX+", "+zoomChangeX+", "+startY+", "+zoomChangeY+", "+tempSteps+", "+includeFade+", "+fadeAmount+", 'zoomDone(zoomID, theID)')", zoomTime);	
386		zoomActive[theID] = true;
387	}
388}
389
390// Finished Zooming In
391
392function zoomDoneIn(zoomdiv, theID) {
393
394	// Note that it's open
395  
396	zoomOpen = true;
397	zoomdiv = document.getElementById(zoomdiv);
398
399	// Position the table shadow behind the zoomed in image, and display it
400
401	if (document.getElementById("ShadowBox")) {
402
403		setOpacity(0, "ShadowBox");
404		shadowdiv = document.getElementById("ShadowBox");
405
406		shadowLeft = parseInt(zoomdiv.style.left) - 13;
407		shadowTop = parseInt(zoomdiv.style.top) - 8;
408		shadowWidth = zoomdiv.offsetWidth + 26;
409		shadowHeight = zoomdiv.offsetHeight + 26; 
410	
411		shadowdiv.style.width = shadowWidth + 'px';
412		shadowdiv.style.height = shadowHeight + 'px';
413		shadowdiv.style.left = shadowLeft + 'px';
414		shadowdiv.style.top = shadowTop + 'px';
415
416		document.getElementById("ShadowBox").style.visibility = "visible";
417		fadeElementSetup("ShadowBox", 0, 100, 5);
418		
419	} else if (! browserIsIE) {
420		// Or, do a fade of the modern shadow
421		fadeElementSetup("ZoomImage", 0, .8, 5, 0, "shadow");
422	}
423	
424	// Position and display the CAPTION, if existing
425  
426	if (includeCaption && document.getElementById(zoomCaption).innerHTML != "") {
427		// setOpacity(0, zoomCaptionDiv);
428		zoomcapd = document.getElementById(zoomCaptionDiv);
429		zoomcapd.style.top = parseInt(zoomdiv.style.top) + (zoomdiv.offsetHeight + 15) + 'px';
430		zoomcapd.style.left = (myWidth / 2) - (zoomcapd.offsetWidth / 2) + 'px';
431		zoomcapd.style.visibility = "visible";
432		// fadeElementSetup(zoomCaptionDiv, 0, 100, 5);
433	}   
434	
435	// Display Close Box (fade it if it's not IE)
436
437	if (!browserIsIE) setOpacity(0, "ZoomClose");
438	document.getElementById("ZoomClose").style.visibility = "visible";
439	if (!browserIsIE) fadeElementSetup("ZoomClose", 0, 100, 5);
440
441	// Get keypresses
442	document.onkeydown = getKey;
443
444	// Start listening for outside clicks
445	setTimeout(function() {
446		document.addEventListener('click', outsideClickHandler, true);
447	}, 0);
448}
449
450// Finished Zooming Out
451
452function zoomDone(zoomdiv, theID) {
453
454	// No longer open
455  
456	zoomOpen = false;
457
458	// Clear stuff out, clean up
459
460	zoomOrigH[theID] = "";
461	zoomOrigW[theID] = "";
462	document.getElementById(zoomdiv).style.visibility = "hidden";
463	zoomActive[theID] == false;
464
465	// Stop getting keypresses
466	document.onkeydown = null;
467
468	// Stop listening for outside clicks
469	document.removeEventListener('click', outsideClickHandler, true);
470}
471
472// Actually zoom the element
473
474function zoomElement(zoomdiv, theID, zoomCurrent, zoomStartW, zoomChangeW, zoomStartH, zoomChangeH, zoomStartX, zoomChangeX, zoomStartY, zoomChangeY, zoomSteps, includeFade, fadeAmount, execWhenDone) {
475
476	// console.log("Zooming Step #"+zoomCurrent+ " of "+zoomSteps+" (zoom " + zoomStartW + "/" + zoomChangeW + ") (zoom " + zoomStartH + "/" + zoomChangeH + ")  (zoom " + zoomStartX + "/" + zoomChangeX + ")  (zoom " + zoomStartY + "/" + zoomChangeY + ") Fade: "+fadeAmount);
477    
478	// Test if we're done, or if we continue
479
480	if (zoomCurrent == (zoomSteps + 1)) {
481		zoomActive[theID] = false;
482		clearInterval(zoomTimer[theID]);
483
484		if (execWhenDone != "") {
485			eval(execWhenDone);
486		}
487	} else {
488	
489		// Do the Fade!
490	  
491		if (includeFade == 1) {
492			if (fadeAmount < 0) {
493				setOpacity(Math.abs(zoomCurrent * fadeAmount), zoomdiv);
494			} else {
495				setOpacity(100 - (zoomCurrent * fadeAmount), zoomdiv);
496			}
497		}
498	  
499		// Calculate this step's difference, and move it!
500		
501		moveW = cubicInOut(zoomCurrent, zoomStartW, zoomChangeW, zoomSteps);
502		moveH = cubicInOut(zoomCurrent, zoomStartH, zoomChangeH, zoomSteps);
503		moveX = cubicInOut(zoomCurrent, zoomStartX, zoomChangeX, zoomSteps);
504		moveY = cubicInOut(zoomCurrent, zoomStartY, zoomChangeY, zoomSteps);
505	
506		document.getElementById(zoomdiv).style.left = moveX + 'px';
507		document.getElementById(zoomdiv).style.top = moveY + 'px';
508		zoomimg.style.width = moveW + 'px';
509		zoomimg.style.height = moveH + 'px';
510	
511		zoomCurrent++;
512		
513		clearInterval(zoomTimer[theID]);
514		zoomTimer[theID] = setTimeout("zoomElement('"+zoomdiv+"', '"+theID+"', "+zoomCurrent+", "+zoomStartW+", "+zoomChangeW+", "+zoomStartH+", "+zoomChangeH+", "+zoomStartX+", "+zoomChangeX+", "+zoomStartY+", "+zoomChangeY+", "+zoomSteps+", "+includeFade+", "+fadeAmount+", '"+execWhenDone+"')", zoomTime);
515	}
516}
517
518// Zoom Utility: Click outside the zoom to dismiss it
519
520function outsideClickHandler(evt) {
521	var target = evt.target || evt.srcElement;
522	var zoomBox = document.getElementById(zoomID);
523	var closeBox = document.getElementById("ZoomClose");
524	if (zoomOpen && !zoomBox.contains(target) && !closeBox.contains(target)) {
525		zoomOut(target, evt);
526	}
527}
528
529// Zoom Utility: Get Key Press when image is open, and act accordingly
530
531function getKey(evt) {
532	if (! evt) {
533		theKey = event.keyCode;
534	} else {
535		theKey = evt.keyCode;
536	}
537
538	if (theKey == 27) { // ESC
539		zoomOut(this, evt);
540	}
541}
542
543////////////////////////////
544//
545// FADE Functions
546//
547
548function fadeOut(elem) {
549	if (elem.id) {
550		fadeElementSetup(elem.id, 100, 0, 10);
551	}
552}
553
554function fadeIn(elem) {
555	if (elem.id) {
556		fadeElementSetup(elem.id, 0, 100, 10);	
557	}
558}
559
560// Fade: Initialize the fade function
561
562var fadeActive = new Array();
563var fadeQueue  = new Array();
564var fadeTimer  = new Array();
565var fadeClose  = new Array();
566var fadeMode   = new Array();
567
568function fadeElementSetup(theID, fdStart, fdEnd, fdSteps, fdClose, fdMode) {
569
570	// alert("Fading: "+theID+" Steps: "+fdSteps+" Mode: "+fdMode);
571
572	if (fadeActive[theID] == true) {
573		// Already animating, queue up this command
574		fadeQueue[theID] = new Array(theID, fdStart, fdEnd, fdSteps);
575	} else {
576		fadeSteps = fdSteps;
577		fadeCurrent = 0;
578		fadeAmount = (fdStart - fdEnd) / fadeSteps;
579		fadeTimer[theID] = setTimeout("fadeElement('"+theID+"', '"+fadeCurrent+"', '"+fadeAmount+"', '"+fadeSteps+"')", 15);
580		fadeActive[theID] = true;
581		fadeMode[theID] = fdMode;
582		
583		if (fdClose == 1) {
584			fadeClose[theID] = true;
585		} else {
586			fadeClose[theID] = false;
587		}
588	}
589}
590
591// Fade: Do the fade. This function will call itself, modifying the parameters, so
592// many instances can run concurrently. Can fade using opacity, or fade using a box-shadow.
593
594function fadeElement(theID, fadeCurrent, fadeAmount, fadeSteps) {
595
596	if (fadeCurrent == fadeSteps) {
597
598		// We're done, so clear.
599
600		clearInterval(fadeTimer[theID]);
601		fadeActive[theID] = false;
602		fadeTimer[theID] = false;
603
604		// Should we close it once the fade is complete?
605
606		if (fadeClose[theID] == true) {
607			document.getElementById(theID).style.visibility = "hidden";
608		}
609
610		// Hang on.. did a command queue while we were working? If so, make it happen now
611
612		if (fadeQueue[theID] && fadeQueue[theID] != false) {
613			fadeElementSetup(fadeQueue[theID][0], fadeQueue[theID][1], fadeQueue[theID][2], fadeQueue[theID][3]);
614			fadeQueue[theID] = false;
615		}
616	} else {
617
618		fadeCurrent++;
619		
620		// Now actually do the fade adjustment.
621		
622		if (fadeMode[theID] == "shadow") {
623
624			// Do a special fade on the webkit-box-shadow of the object
625		
626			if (fadeAmount < 0) {
627				document.getElementById(theID).style.webkitBoxShadow = shadowSettings + (Math.abs(fadeCurrent * fadeAmount)) + ')';
628			} else {
629				document.getElementById(theID).style.webkitBoxShadow = shadowSettings + (100 - (fadeCurrent * fadeAmount)) + ')';
630			}
631			
632		} else {
633		
634			// Set the opacity depending on if we're adding or subtracting (pos or neg)
635			
636			if (fadeAmount < 0) {
637				setOpacity(Math.abs(fadeCurrent * fadeAmount), theID);
638			} else {
639				setOpacity(100 - (fadeCurrent * fadeAmount), theID);
640			}
641		}
642
643		// Keep going, and send myself the updated variables
644		clearInterval(fadeTimer[theID]);
645		fadeTimer[theID] = setTimeout("fadeElement('"+theID+"', '"+fadeCurrent+"', '"+fadeAmount+"', '"+fadeSteps+"')", 15);
646	}
647}
648
649////////////////////////////
650//
651// UTILITY functions
652//
653
654// Utility: Set the opacity, compatible with a number of browsers. Value from 0 to 100.
655
656function setOpacity(opacity, theID) {
657
658	var object = document.getElementById(theID).style;
659
660	// If it's 100, set it to 99 for Firefox.
661
662	if (navigator.userAgent.indexOf("Firefox") != -1) {
663		if (opacity == 100) { opacity = 99.9999; } // This is majorly awkward
664	}
665
666	// Multi-browser opacity setting
667
668	object.filter = "alpha(opacity=" + opacity + ")"; // IE/Win
669	object.opacity = (opacity / 100);                 // Safari 1.2, Firefox+Mozilla
670
671}
672
673// Utility: Math functions for animation calucations - From http://www.robertpenner.com/easing/
674//
675// t = time, b = begin, c = change, d = duration
676// time = current frame, begin is fixed, change is basically finish - begin, duration is fixed (frames),
677
678function linear(t, b, c, d)
679{
680	return c*t/d + b;
681}
682
683function sineInOut(t, b, c, d)
684{
685	return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
686}
687
688function cubicIn(t, b, c, d) {
689	return c*(t/=d)*t*t + b;
690}
691
692function cubicOut(t, b, c, d) {
693	return c*((t=t/d-1)*t*t + 1) + b;
694}
695
696function cubicInOut(t, b, c, d)
697{
698	if ((t/=d/2) < 1) return c/2*t*t*t + b;
699	return c/2*((t-=2)*t*t + 2) + b;
700}
701
702function bounceOut(t, b, c, d)
703{
704	if ((t/=d) < (1/2.75)){
705		return c*(7.5625*t*t) + b;
706	} else if (t < (2/2.75)){
707		return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
708	} else if (t < (2.5/2.75)){
709		return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
710	} else {
711		return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
712	}
713}
714
715
716// Utility: Get the size of the window, and set myWidth and myHeight
717// Credit to quirksmode.org
718
719function getSize() {
720
721	// Window Size
722
723	if (self.innerHeight) { // Everyone but IE
724		myWidth = window.innerWidth;
725		myHeight = window.innerHeight;
726		myScroll = window.pageYOffset;
727	} else if (document.documentElement && document.documentElement.clientHeight) { // IE6 Strict
728		myWidth = document.documentElement.clientWidth;
729		myHeight = document.documentElement.clientHeight;
730		myScroll = document.documentElement.scrollTop;
731	} else if (document.body) { // Other IE, such as IE7
732		myWidth = document.body.clientWidth;
733		myHeight = document.body.clientHeight;
734		myScroll = document.body.scrollTop;
735	}
736
737	// Page size w/offscreen areas
738
739	if (window.innerHeight && window.scrollMaxY) {	
740		myScrollWidth = document.body.scrollWidth;
741		myScrollHeight = window.innerHeight + window.scrollMaxY;
742	} else if (document.body.scrollHeight > document.body.offsetHeight) { // All but Explorer Mac
743		myScrollWidth = document.body.scrollWidth;
744		myScrollHeight = document.body.scrollHeight;
745	} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
746		myScrollWidth = document.body.offsetWidth;
747		myScrollHeight = document.body.offsetHeight;
748	}
749}
750
751// Utility: Get Shift Key Status
752// IE events don't seem to get passed through the function, so grab it from the window.
753
754function getShift(evt) {
755	var shift = false;
756	if (! evt && window.event) {
757		shift = window.event.shiftKey;
758	} else if (evt) {
759		shift = evt.shiftKey;
760		if (shift) evt.stopPropagation(); // Prevents Firefox from doing shifty things
761	}
762	return shift;
763}
764
765// Utility: Find the Y position of an element on a page. Return Y and X as an array
766
767function findElementPos(elemFind)
768{
769	var elemX = 0;
770	var elemY = 0;
771	do {
772		elemX += elemFind.offsetLeft;
773		elemY += elemFind.offsetTop;
774	} while ( elemFind = elemFind.offsetParent )
775
776	return Array(elemX, elemY);
777}

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.