function ss_fixAllLinks() { // Get a list of all links in the page var allLinks = document.getElementsByTagName('a'); // Walk through the list for (var i=0;i<allLinks.length;i++) {   var lnk = allLinks[i];   if ((lnk.href && lnk.href.indexOf('#') != -1) &&         ( (lnk.pathname == location.pathname) ||   ('/'+lnk.pathname == location.pathname) ) &&         (lnk.search == location.search)) {     // If the link is internal to the page (begins in #)     // then attach the smoothScroll function as an onclick     // event handler     ss_addEvent(lnk,'click',smoothScroll);   } }}function smoothScroll(e) { // This is an event handler; get the clicked on element, // in a cross-browser fashion if (window.event) {   target = window.event.srcElement; } else if (e) {   target = e.target; } else return;  // Make sure that the target is an element, not a text node // within an element if (target.nodeType == 3) {   target = target.parentNode; }  // Paranoia; check this is an A tag if (target.nodeName.toLowerCase() != 'a') return;  // Find the <a name> tag corresponding to this href // First strip off the hash (first character) anchor = target.hash.substr(1); // Now loop all A tags until we find one with that name var allLinks = document.getElementsByTagName('a'); var destinationLink = null; for (var i=0;i<allLinks.length;i++) {   var lnk = allLinks[i];   if (lnk.name && (lnk.name == anchor)) {     destinationLink = lnk;     break;   } }  // If we didn't find a destination, give up and let the browser do // its thing if (!destinationLink) return true;  // Find the destination's position var destx = destinationLink.offsetLeft;   var desty = destinationLink.offsetTop; var thisNode = destinationLink; while (thisNode.offsetParent &&         (thisNode.offsetParent != document.body)) {   thisNode = thisNode.offsetParent;   destx += thisNode.offsetLeft;   desty += thisNode.offsetTop; }  // Stop any current scrolling clearInterval(ss_INTERVAL);  cypos = ss_getCurrentYPos();  ss_stepsize = parseInt((desty-cypos)/ss_STEPS); ss_INTERVAL = setInterval('ss_scrollWindow('+ss_stepsize+','+desty+',"'+anchor+'")',10);  // And stop the actual click happening if (window.event) {   window.event.cancelBubble = true;   window.event.returnValue = false; } if (e && e.preventDefault && e.stopPropagation) {   e.preventDefault();   e.stopPropagation(); }}function ss_scrollWindow(scramount,dest,anchor) { wascypos = ss_getCurrentYPos(); isAbove = (wascypos < dest); window.scrollTo(0,wascypos + scramount); iscypos = ss_getCurrentYPos(); isAboveNow = (iscypos < dest); if ((isAbove != isAboveNow) || (wascypos == iscypos)) {   // if we've just scrolled past the destination, or   // we haven't moved from the last scroll (i.e., we're at the   // bottom of the page) then scroll exactly to the link   window.scrollTo(0,dest);   // cancel the repeating timer   clearInterval(ss_INTERVAL);   // and jump to the link directly so the URL's right   location.hash = anchor; }}function ss_getCurrentYPos() { if (document.body && document.body.scrollTop)   return document.body.scrollTop; if (document.documentElement && document.documentElement.scrollTop)   return document.documentElement.scrollTop; if (window.pageYOffset)   return window.pageYOffset; return 0;}function ss_addEvent(elm, evType, fn, useCapture)// addEvent and removeEvent// cross-browser event handling for IE5+,  NS6 and Mozilla// By Scott Andrew{ if (elm.addEventListener){   elm.addEventListener(evType, fn, useCapture);   return true; } else if (elm.attachEvent){   var r = elm.attachEvent("on"+evType, fn);   return r; }}  var ss_INTERVAL;var ss_STEPS = 25;ss_addEvent(window,"load",ss_fixAllLinks);// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - ( weather info sliding panels ) - - - - - - - - - - - - - - - - - - - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function primeSlide()	{	// set the class name of the containing div to hide appropriate html elements	document.getElementById('weather-conditions').className = 'hide';		// create html elements using js	var make = createHTML();		// set panel vars (just for neatness' sake)	var infoPanel = document.getElementById('weatherinfo');	var infoTrigger = document.getElementById('weatherinfo-trigger');	var infoHide = document.getElementById('weatherinfo-hideme');	var dorsetPanel = document.getElementById('dorset');	var dorsetTrigger = document.getElementById('dorset-trigger');	var dorsetHide = document.getElementById('dorset-hideme');	var dorsetBack = document.getElementById('dorset-back');	var sanfranPanel = document.getElementById('sanfrancisco');	var sanfranTrigger = document.getElementById('sanfrancisco-trigger');	var sanfranHide = document.getElementById('sanfrancisco-hideme');	var sanfranBack = document.getElementById('sanfrancisco-back');		// add in the panel state variables	infoPanel.state = 'up';	dorsetPanel.state = 'up';	sanfranPanel.state = 'up';		// set event listeners	addEvent(infoTrigger, 'click', function(e){clearScreen(infoPanel)});	addEvent(infoHide, 'click', function(e){clearScreen(infoPanel)});	addEvent(dorsetTrigger, 'click', function(e){clearScreen(dorsetPanel)});	addEvent(dorsetHide, 'click', function(e){clearScreen(dorsetPanel)});	addEvent(dorsetBack, 'click', function(e){clearScreen(infoPanel)});	addEvent(sanfranTrigger, 'click', function(e){clearScreen(sanfranPanel)});	addEvent(sanfranHide, 'click', function(e){clearScreen(sanfranPanel)});	addEvent(sanfranBack, 'click', function(e){clearScreen(infoPanel)});	}function clearScreen(thisPanel)	{	// set panel vars	var infoPanel = document.getElementById('weatherinfo');	var dorsetPanel = document.getElementById('dorset');	var sanfranPanel = document.getElementById('sanfrancisco');	// loop through and close any open windows that aren't this panel	var panels = new Array(infoPanel, dorsetPanel, sanfranPanel);	for (var i=0; i<panels.length; i++)		{		if (((panels[i].state == 'down') || (panels[i].state == 'downing')) && (panels[i] != thisPanel))			{			setSlide(panels[i]);			}		}	// run for this panel	setSlide(thisPanel);	}function setSlide(thisPanel)	{		// grab the height (this is a number such as -500)	thisPanel.height = thisPanel.offsetHeight;		// if this panel is fully up	if (thisPanel.state == 'up')		{			// re-style the panel so it's only just out of site		thisPanel.style.top = "-"+thisPanel.height+"px";				// set number of frames the animation will take		var numFrames = 12;		}	else		{		// calculate the number of frames the animation will take		// (bearing in mind it could be halfway through an up or down movement)		var finPos = thisPanel.height;		var nowPos = thisPanel.style.top;		nowPos = nowPos.substring(0, (nowPos.length - 2));		var toGo = (finPos - nowPos);		var numFrames = Math.round((12 / thisPanel.height) * toGo);		numFrames = (numFrames == 0) ? 1 : numFrames;		}		// set y start position	var yStart = thisPanel.offsetTop;	// set y end position	switch (thisPanel.state)		{		case 'up':			thisPanel.state = 'downing';			var yEnd = 0;			break;		case 'downing':			thisPanel.state = 'uping';			var yEnd = 0;			break;		case 'down':			thisPanel.state = 'uping';			var yEnd = "-"+thisPanel.height;			break;		case 'uping':			thisPanel.state = 'downing';			var yEnd = "-"+thisPanel.height;			break;		}		// set current frame number	frameNum = 0;	// calculate y distance to be moved each frame	var yDist = (yEnd - yStart)/(numFrames - 1);		// run the sliding function	runSlide(thisPanel, yStart, yDist, frameNum, numFrames);	}function runSlide(thisPanel, yStart, yDist, frameNum, numFrames)	{	// if the animation still has frames left to run	if (frameNum < numFrames)		{		thisPanel.style.top = (yStart + yDist*frameNum) + "px";		frameNum++;		return setTimeout(function(){runSlide(thisPanel, yStart, yDist, frameNum, numFrames)}, 8);		}	// if the animation is complete	else		{		// if it was moving down		if (thisPanel.state == 'downing')			{			// set to all the way down			thisPanel.state = 'down';			}		else			{			thisPanel.state = 'up';			thisPanel.style.top = "-5000px";			}		}	}function createHTML()	{	// create weather info trigger elements	var infoTrigger = document.createElement('div');	infoTrigger.id = 'weatherinfo-trigger';	infoTrigger.setAttribute('title', 'View extra information on the weather banner');	document.body.appendChild(infoTrigger);		// create weather info elements	var infoPanel = document.createElement('div');	infoPanel.id = 'weatherinfo';	infoPanel.innerHTML = '<div class="border"><h3>Panorama information</h3><p>The image displayed above is a 1600 pixel-wide panoramic view from the top of my parents&#8217; house in Dorset, England. The system uses an XML weather feed from their local airbase to provide an up-to-the-minute graphical representation of the current weather, moon, and daylight conditions at their house. It\'s pretty cool, really.</p><p>You can <a href="/blog/colophon/#the-pano" title="View the panorama section in the colophon">read more about the panorama</a>, and how it was created, in the <a href="/blog/colophon/" title="View the colophon">Colophon</a>; or you can select an option from below and view detailed weather information for Dorset, or for San Francisco (where I currently live).</p><ul><li id="dorset-trigger" title="View the latest weather conditions at this location">View live weather information for Leigh, Dorset, UK.</li><li id="sanfrancisco-trigger" title="View the latest weather conditions at this location">View live weather information for San Francisco, California, USA.</li></ul><div id="weatherinfo-hideme" title="&#8593; Hide this panel">&#8593; Hide this panel</div></div>';	document.getElementById('right').appendChild(infoPanel);		// create dorset elements	var dorsetPanel = document.getElementById('dorset');	var dorsetHide = document.createElement('div');	dorsetHide.id = 'dorset-hideme';	dorsetHide.appendChild(document.createTextNode('\u2191 Hide this panel'));	dorsetPanel.getElementsByTagName('div')[0].appendChild(dorsetHide);	var dorsetBack = document.createElement('div');	dorsetBack.id = 'dorset-back';	dorsetBack.appendChild(document.createTextNode('\u2190 Go back to the info panel'));	dorsetPanel.getElementsByTagName('div')[0].appendChild(dorsetBack);		// create san francisco elements	var sanfranPanel = document.getElementById('sanfrancisco');	var sanfranHide = document.createElement('div');	sanfranHide.id = 'sanfrancisco-hideme';	sanfranHide.appendChild(document.createTextNode('\u2191 Hide this panel'));	sanfranPanel.getElementsByTagName('div')[0].appendChild(sanfranHide);	var sanfranBack = document.createElement('div');	sanfranBack.id = 'sanfrancisco-back';		sanfranBack.appendChild(document.createTextNode('\u2190 Go back to the info panel'));	sanfranPanel.getElementsByTagName('div')[0].appendChild(sanfranBack);	return;	}// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // run the onload scriptfunction runScripts()	{	ss_fixAllLinks();	primeSlide();	}window.onload = runScripts;
