Commits

factormystic  committed 8b762a6

Massive rewrite to bring the internals up to par with HUD Time. Also, query weather data from Yahoo API, so international locales are now supported!

  • Participants
  • Parent commits 8002f65
  • Tags v2.2

Comments (0)

Files changed (11)

+HUD Weather
+Created by Factor Mystic
+http://factormystic.net
+
+
+Thanks for checking out HUD Weather! It's ok to hack on this program and host
+modifications yourself, but please leave this README.txt file intact and
+keep a link back to the original project site.
+
+Also, this project is open source (link on project page), so it'd be great
+if you forked that repository and committed your changes back!
+
+
+Thanks, and have fun!

File content.html

+<!DOCTYPE html>
 <html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=utf-8">
-<style> 
-body {
-	width: 675px;
-	height: 150px;
-	font-size: 12px;
-	margin: 0;
-	font-family: Verdana;
-	color: #FFFFFF;
-} 
-.gadget {
-	margin: 3px;
-} 
-</style>
+	<head>
+		<meta charset="utf-8" />
 
-<script>
-	var debug = true;
-	function alert(msg) { System.Debug.outputString(msg); }
-</script>
+		<script src='js/console.log.js'></script>
+		<script src='js/gadget.js'></script>
 
-<script type="text/javascript">
-var temp;
-var condition;
+		<link rel='stylesheet' type='text/css' href='css/gadget.css' />
+	</head>
 
-var xmlHttp = null;
-
-var zip_url = 'http://www.maxmind.com/app/mylocation';
-var last_zip = System.Gadget.Settings.readString("zip");
-alert("Last known zip value: "+last_zip);
-var zip = last_zip.length==5?last_zip:null;
-var weather_url = zip!=null?"http://xoap.weather.com/weather/local/"+zip+"?cc=*&dayf=6&link=xoap&prod=xoap&par=1127063443&key=af5d7d563b56d53c":null;
-
-System.Gadget.settingsUI = "settings.html";
-System.Gadget.onSettingsClosed = settingsClosed;
-
-var defaultColour = [255, 255, 255];
-var colour = defaultColour;
-var fonttype = System.Gadget.Settings.readString("fonttype");
-var fontSizer;
-var textcolor = "white";
-
-var last_temp = System.Gadget.Settings.readString("temp");
-var last_condition = System.Gadget.Settings.readString("condition");
-
-function settingsClosed()
-{
-	alert("settingsClosed");
-
-	if (System.Gadget.Settings.readString("fonttype") != "")
-		fonttype = System.Gadget.Settings.readString("fonttype");
-
-	temp.font = condition.font = fonttype;
-	
-	zip = System.Gadget.Settings.readString("zip");
-	weather_url = "http://xoap.weather.com/weather/local/"+zip+"?cc=*&dayf=6&link=xoap&prod=xoap&par=1127063443&key=af5d7d563b56d53c";
-
-	update();
-}
-
-function ProcessRequest() 
-{
-	if ( xmlHttp.readyState == 4 && xmlHttp.status == 200 ) 
-    {
-        if ( xmlHttp.responseText == "Not found" ) 
-        {
-			if(temp == null)
-			{
-				temp.value = xmlHttp.status;
-				condition.value = "Error";
-			}
-        }
-        else
-        {
-			var data = xmlHttp.responseText;
-			
-			if(zip==null)
-			{
-				var start = data.indexOf('Zipcode')+'Zipcode*</td> <td class=output align="center"> '.length;
-				zip = data.substr(start, 5);
-				
-				alert('Got zip code: '+zip);
-				System.Gadget.Settings.writeString("zip", zip);
-
-				weather_url = "http://xoap.weather.com/weather/local/"+zip+"?cc=*&dayf=6&link=xoap&prod=xoap&par=1127063443&key=af5d7d563b56d53c";
-				update();
-			}
-			else
-			{
-				var start = data.indexOf('<tmp>')+5;
-				var end = data.indexOf('</tmp>',end);
-				temp.value = data.substr(start, end-start) + "°";
-				System.Gadget.Settings.writeString("temp", temp.value);
-				alert("Temp is now: "+temp.value);
-
-				var start = data.indexOf('<t>',start)+3;
-				var end = data.indexOf('</t>',start);
-				condition.value = data.substr(start, end-start).toUpperCase().replace(" AND ", "/").replace("MOSTLY","");
-				System.Gadget.Settings.writeString("condition", condition.value);
-				alert("Condition is now: "+condition.value);
-
-				justify_right();
-			}
-        }                    
-    }
-	else
-		alert("HTTP Status: "+xmlHttp.readyState);
-}
-
-function justify_right()
-{
-	temp.width = temp.offsetWidth;
-	temp.left = 675-temp.width-10;
-	condition.width = condition.offsetWidth;
-	condition.left = 675-condition.width-10;
-}
-
-function update()
-{
-	alert('Updating HUD Weather Gadget...');
-
-	if (fonttype == "")
-	{
-		alert("Blank fonttype, defaulting to Arial");
-		fonttype = "Arial";
-	}
-
-	xmlHttp = new XMLHttpRequest(); 
-	xmlHttp.onreadystatechange = ProcessRequest;
-	xmlHttp.open("GET", zip==null?zip_url:weather_url, true);
-	xmlHttp.send(null);
-    
-	var bg = document.getElementById("bg");
-
-	if(fontSizer == null)
-		fontSizer = bg.addTextObject("Arial", "Arial", 18, "Black", 0, -1000);
-
-	if(temp == null)
-	{
-		alert("Creating temperature text object");
-		if(last_temp == "")
-		{
-			last_temp = "--°";
-			alert("Setting default temp of "+last_temp);
-		}
-		
-		temp = bg.addTextObject(last_temp, fonttype, 85, textcolor, 0, 0);
-		temp.opacity = 30;
-	}
-
-	if(condition == null)
-	{
-		alert("Creating condition text object");	
-		condition = bg.addTextObject(last_condition.replace("AND", "/").replace("MOSTLY",""), fonttype, 60, textcolor, 0, 70);
-		condition.opacity = 30;
-	}
-
-	justify_right();
-
-	setTimeout('update()', 60*1000*5);
-}
-</script>
-</head>
-<body onload="update();" style="align:right;">
-	<g:background id="bg" style="width:100%; height:100%; z-index:-1; position:absolute; top:0; left:0; font-weight:bold;" opacity="0%" />
-</body> 
+	<body onload='init();'>
+		<g:background id='bg' opacity='0%' />
+	</body>
 </html>

File css/gadget.css

+* {
+	margin: 0;
+	padding: 0;
+}
+.gadget {
+	margin: 3px;
+}
+
+#bg {
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	z-index: -1;
+	position: absolute;
+	font-weight:bold;
+}

File css/settings.css

+* {
+	font-family: Segoe UI;
+	font-size: 12px;
+}
+	
+body{ 
+	width: 221px;
+	height: 330px;
+	margin: 0px;
+	position: relative;
+}
+
+table {
+	border-collapse: collapse;
+}
+
+.about {
+	position: absolute;
+	bottom: 0px;
+	left: 0px;
+}
+
+.menusurround {
+	position: absolute;
+	overflow-x: hidden;
+	overflow-y: auto;
+	height: 150px;
+	width: 220px;
+	border: 1px 1px 1px 1px solid;
+	border-color: rgb(151,151,151);
+	border-spacing: 0px;
+	z-index: 100;
+}
+
+/* Menu item */
+.menuItem td{
+	border-style: solid;
+	border-width: 1px 0px 1px 0px;
+	border-color: rgb(245,245,245) rgb(226,226,226) rgb(245,245,245) rgb(245,245,245);
+	background-color: rgb(245,245,245);
+	font-size: 18px;
+	padding: 0px 4px 0px 4px;
+	white-space: nowrap;
+	height: 22px;
+	overflow: hidden;
+}
+
+.menuItemSelected td{
+	border-style: solid;
+	border-width: 1px 0px 1px 0px;
+	border-color: rgb(245,245,245) rgb(226,226,226) rgb(245,245,245) rgb(245,245,245);
+	background-color: rgb(255,214,109);
+	font-size: 18px;
+	padding: 0px 4px 0px 4px;
+	white-space: nowrap;
+	height: 22px;
+	overflow: hidden;
+}
+
+/* Menu item when mouse over */
+.menuItemHover td{
+	border-style: solid;
+	border-width: 1px 0px 1px 0px;
+	border-color: rgb(170,218,237) rgb(228,241,247) rgb(170,218,237) rgb(228,241,247);
+	background-color: rgb(228,241,247);
+	font-size: 18px;
+	padding: 0px 4px 0px 4px;
+	white-space: nowrap;
+	height: 22px;
+	overflow: hidden;
+}
+
+/* Selected menu item when mouse over */
+.menuItemHoverSelected td{
+	border-style: solid;
+	border-width: 1px 0px 1px 0px;
+	border-color: rgb(170,218,237) rgb(228,241,247) rgb(170,218,237) rgb(228,241,247);
+	background-color: rgb(255,222,133);
+	font-size: 18px;
+	padding: 0px 4px 0px 4px;
+	white-space: nowrap;
+	height: 22px;
+	overflow: hidden;
+}
 <gadget>
   <name>HUD Weather</name>
   <namespace>microsoft.windows</namespace>
-  <version>1.3.0.0</version>
+
+  <version value="2.2.0.0" MinPlatformVersion ="0.3">2.2.0.0</version>
+  <copyright>&#169; 2009</copyright>
+  <description>"Heads up display" style weather report</description>
   <author name="Factor Mystic">
-	<info url="http://factormystic.net/projects/gadgets/hud-weather" />
+    <info url="http://factormystic.net/projects/gadgets/hud-weather" />
   </author>
-  <copyright>&#169; 2010</copyright>
-  <description>"Heads up display" style weather report</description>
-  <version value="1.0.0.0" MinPlatformVersion ="0.3"/>
+  <icons>
+    <icon src="images/logo.png" />
+  </icons>
+
   <hosts>
     <host name="sidebar">
       <base type="HTML" apiVersion="1.0.0" src="content.html"/>

File images/logo.png

Added
New image

File js/color-picker.js

+/*
+Based on Jonathan Abbott's Flip Calendar gadget
+http://vistagadgets.spaces.live.com/
+*/
+
+console.log('loaded: color-picker.js');
+
+var colorPicker = {
+	fillYield: 50,	// Yield back to IE every X ms
+
+	colortypeIndex: 135,
+	currentColor: 'white',
+	selectingColor: -1,
+
+	init: function() {
+		console.log('[init]');
+
+		// System.Gadget.onSettingsClosing = this.settingsClosing;
+
+		this.currentColor = System.Gadget.Settings.readString('color') || this.currentColor;
+
+		// divColortype.innerText = this.currentColor;
+		divColortype.innerHTML = '<span style="color='+this.currentColor+'; font-family:Wingdings; font-size:16px;">l</span>'+this.currentColor;
+		divColortype.style.fontSize = '16px';
+
+		//remove focus from the 1st checkbox
+		document.body.focus();
+		
+		//read the colors from the registry and build the table
+		this.buildList(this.readColors());
+
+		// setColor(currentColor, 0);
+		tdColors.rows(this.colortypeIndex).className = 'menuItemSelected';
+	},
+
+	settingsClosing: function(event) {
+		console.log('[settingsClosing]');
+		
+		if (event.closeAction == event.Action.commit) {
+			System.Gadget.Settings.writeString('color', divColortype.innerText.substr(1));
+		}
+		// event.cancel = false;
+	},
+
+	readColors: function() {
+		console.log('[readColors]');
+
+		var sNames = ['aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkturquoise', 'darkslategray', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen'];
+
+		return sNames;
+	},
+
+	buildList: function(listItems) {
+		console.log('[buildList]');
+
+		var counter = new Date();
+
+		while (listItems.length > 0 && (new Date())-counter<this.fillYield) {
+			var colorName = listItems[0];
+			// console.log('Using color: '+colorName);
+
+			var tRow = tdColors.insertRow(tdColors.rows.length);
+			tRow.className = 'menuItem';
+			
+			var tCell = tRow.insertCell(0);
+			// tCell.innerText = colorName;
+			tCell.innerHTML = '<span style="color='+colorName+'; font-family:Wingdings; font-size:16px;">l</span>'+colorName;
+			// tCell.style.color = colorName;
+			//divColortype.style.color = colorName;
+
+			if (colorName == this.currentColor) {
+				this.colortypeIndex = tdColors.rows.length - 1;
+				// tRow.className = 'menuItemSelected';
+			}
+
+			listItems.shift();
+		}
+
+		//possible, but unhelpful, as it makes the selected color hard to read
+		// divColortype.style.color = this.currentColor;
+
+		if (listItems.length > 0) {
+			var context = this;
+			setTimeout(function() { context.buildList(listItems); }, 20);
+		}
+	},
+
+	showColorMenu: function(id, x, y) {
+		console.log('[showColorMenu]');
+
+		if (id == -1) {
+			if (colorMenu.style.display != 'none') {
+				id = this.selectingColor;
+			} else {
+				return;
+			}
+		}
+			
+		colorMenu.style.display = (colorMenu.style.display == 'none') ? 'inline' : 'none';
+
+		if (colorMenu.style.display == 'none') {
+			console.log('[showColorMenu] hidden');
+
+			switch (this.selectingColor) {
+				case 0:
+					colorDropPNG.src = 'images/dropmenu.png';
+					break;
+			}
+			this.selectingColor = -1;
+		} else {
+			console.log('[showColorMenu] displayed '+id+' @ x:'+x+', y:'+y);
+
+			colorMenu.style.top = y;
+			colorMenu.style.left = x;
+			this.selectingColor = id;
+			
+			// console.log(tdColors.rows(colortypeIndex).className);
+			// console.log(id);
+
+			switch (id) {
+				case 0:
+					colorMenu.scrollTop = tdColors.rows(this.colortypeIndex).offsetTop - 65;
+					tdColors.rows(this.colortypeIndex).className = 'menuItemSelected';
+					break;
+			}
+
+			// console.log(tdColors.rows(colortypeIndex).className);
+		}
+	},
+
+	setColor: function(index, viaKey) {
+		console.log('[setColor] '+index+', '+viaKey);
+
+		var sColor = tdColors.rows(index).cells(0).innerText.substr(1);
+
+		var selecting = (viaKey != null) ? viaKey : this.selectingColor;
+		switch (selecting) {
+			case 0:
+				// divColortype.style.color = sColor;
+				divColortype.innerHTML = '<span style="color='+sColor+'; font-family:Wingdings; font-size:16px;">l</span>'+sColor;
+				tdColors.rows(this.colortypeIndex).className = 'menuItem';
+				this.colortypeIndex = index;
+				tdColors.rows(this.colortypeIndex).className = 'menuItemSelected';
+				break;
+		}
+
+		// adjust the scrollbar if needed
+		if (colorMenu.scrollTop > tdColors.rows(index).offsetTop) {
+			colorMenu.scrollTop = tdColors.rows(index).offsetTop;
+		}
+
+		if (colorMenu.scrollTop < tdColors.rows(index).offsetTop+tdColors.rows(index).offsetHeight-150) {
+			colorMenu.scrollTop = tdColors.rows(index).offsetTop+tdColors.rows(index).offsetHeight-150;
+		}
+	},
+
+	keyPress: function(i) {
+		console.log('[keyPress]');
+
+		switch (event.keyCode)
+		{
+			case 40:	//down arrow
+				if (i == 0) {
+					if (this.colortypeIndex < tdColors.rows.length-1) {
+						this.setColor(this.colortypeIndex+1, i);
+					}
+				}
+				break;
+			case 38:	//up arrow
+				if (i == 0) {
+					if (this.colortypeIndex > 0) {
+						this.setColor(this.colortypeIndex-1, i);
+					}
+				}
+				break;
+			case 36:	//home
+				this.setColor(0, i);
+				break;
+			case 35:	//end
+				this.setColor(tdColors.rows.length - 1, i);
+				break;
+		}
+	},
+
+	mouseOver: function(mouseEntered, id) {
+		// console.log('[mouseOver]');
+
+		var selected = (this.selectingColor == 0) ? this.colortypeIndex : 0;
+
+		if (mouseEntered) {
+			id.className = (id.rowIndex == selected) ? 'menuItemHoverSelected' : 'menuItemHover';
+		} else {
+			id.className = (id.rowIndex == selected) ? 'menuItemSelected' : 'menuItem';
+		}
+	}
+}

File js/console.log.js

+if(!window.console) {
+	//no console, create console.log and send it to system debug
+	window.console = { };
+
+	console.log = function(msg) {
+		System.Debug.outputString('['+window.location+'] '+msg);
+	}
+
+	console.log('console.log is now set up');
+} else {
+	console.log('[console.log.js] window already has a console object');
+}
+
+window.onerror = function(msg, url, line) {
+	console.log('Error: '+msg+' @ '+line+' in '+url);
+}

File js/font-picker.js

+/*
+Based on Jonathan Abbott's Flip Calendar gadget
+http://vistagadgets.spaces.live.com/
+*/
+
+console.log('loaded: font-picker.js');
+
+var fontPicker = {
+	supportedFontTypes: ' (truetype) ',
+	fontsToSkip: ':Bookshelf Symbol 7:'+':MS Outlook:'+':MS Reference Specialty:'+':MT Extra:'+':Symbol:'+':Webdings:'+':Wingdings:'+':Wingdings 2:'+':Wingdings 3:',
+
+	fillYield: 50,	// Yield back to IE every X ms
+
+	fontSizer: null,
+	fonttypeIndex: 0,
+	currentFont: System.Gadget.document.parentWindow.font,
+	selectingFont: -1,
+
+	init: function() {
+		console.log('[init]');
+
+		// System.Gadget.onSettingsClosing = this.settingsClosing;
+
+		divFonttype.style.fontFamily = divFonttype.innerText = this.currentFont;
+		divFonttype.style.fontSize = '16px';
+
+		this.fontSizer = document.createElement('<g:background />').addTextObject(this.currentFont, this.currentFont, 16, 'black', 0, 0);
+
+		//remove focus from the 1st checkbox
+		document.body.focus();
+		
+		//read the fonts from the registry and build the table
+		this.buildList(this.readFonts());
+
+		// setFont(currentFont, 0);
+		// console.log(tdFonts);
+		// console.log(this.fonttypeIndex);
+		tdFonts.rows(this.fonttypeIndex).className = 'menuItemSelected';
+	},
+
+	settingsClosing: function(event) {
+		console.log('[settingsClosing]');
+		
+		if (event.closeAction == event.Action.commit) {
+			System.Gadget.Settings.writeString('font', divFonttype.innerText);
+		}
+		// event.cancel = false;
+	},
+
+	readFonts: function() {
+		console.log('[readFonts]');
+
+		var HKLM = 2147483650;
+		var rPath = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\';
+
+		// connect to the registry
+		var oSwbem = new ActiveXObject('WbemScripting.SwbemLocator');
+		var oSvc = oSwbem.ConnectServer(null, 'root\\default');
+		var oReg = oSvc.Get('StdRegProv');
+
+		// enumerate the values 
+		var oMethod = oReg.Methods_.Item('EnumValues');
+		var oInParam = oMethod.InParameters.SpawnInstance_();
+		oInParam.hDefKey = HKLM;
+		oInParam.sSubKeyName = rPath;
+		var oOutParam = oReg.ExecMethod_(oMethod.Name, oInParam);
+
+		// get the values into an array
+		var sNames = oOutParam.sNames.toArray();
+
+		// sort it
+		sNames.sort();
+
+		return sNames;
+	},
+
+	buildList: function(listItems) {
+		console.log('[buildList]');
+
+		// try{
+			var counter = new Date();
+
+			while (listItems.length > 0 && (new Date())-counter<this.fillYield) {
+				// is the font one we can use
+				var fontType = ' ' + listItems[0].substring(listItems[0].lastIndexOf('(')).toLowerCase() + ' ';
+				var fontName = listItems[0].substring(0, listItems[0].length - fontType.length + 1);
+
+				if(this.supportedFontTypes.indexOf(fontType) > -1 && this.fontsToSkip.indexOf(':' + fontName + ':') == -1) {
+					//check the height, to see if it's a font we can use
+					this.fontSizer.font = this.fontSizer.value = fontName;
+					this.fontSizer.height = 0;
+
+					if (this.fontSizer.height != 0) {
+						// console.log('Using font: '+fontName);
+
+						var tRow = tdFonts.insertRow(tdFonts.rows.length);
+						tRow.className = 'menuItem';
+						
+						var tCell = tRow.insertCell(0);
+						tCell.innerText = fontName;
+						tCell.style.fontFamily = fontName;
+						tCell.style.fontSize = divFonttype.style.fontSize;
+
+						if (fontName == this.currentFont) {
+							this.fonttypeIndex = tdFonts.rows.length - 1;
+							// tRow.className = 'menuItemSelected';
+						}
+
+					} else {
+						// console.log('Cant use font: '+fontName);
+					}
+				}
+				listItems.shift();
+			}
+
+			if (listItems.length > 0) {
+				var context = this;
+				setTimeout(function() { context.buildList(listItems); }, 20);
+			}
+		// } catch(err) {
+			// console.log('buildList: '+err.name+' - '+err.message);
+		// }
+	},
+
+	showFontMenu: function(id, x, y) {
+		console.log('[showFontMenu]');
+
+		if (id == -1) {
+			if (fontMenu.style.display != 'none') {
+				id = this.selectingFont;
+			} else {
+				return;
+			}
+		}
+			
+		fontMenu.style.display = (fontMenu.style.display == 'none') ? 'inline' : 'none';
+
+		if (fontMenu.style.display == 'none') {
+			console.log('[showFontMenu] hidden');
+
+			switch (this.selectingFont) {
+				case 0:
+					fontDropPNG.src = 'images/dropmenu.png';
+					break;
+			}
+			this.selectingFont = -1;
+		} else {
+			console.log('[showFontMenu] displayed');
+
+			fontMenu.style.top = y;
+			fontMenu.style.left = x;
+			this.selectingFont = id;
+			
+			// console.log(tdFonts.rows(fonttypeIndex).className);
+			// console.log(id);
+
+			switch (id) {
+				case 0:
+					fontMenu.scrollTop = tdFonts.rows(this.fonttypeIndex).offsetTop - 65;
+					tdFonts.rows(this.fonttypeIndex).className = 'menuItemSelected';
+					break;
+			}
+
+			// console.log(tdFonts.rows(fonttypeIndex).className);
+		}
+	},
+
+	setFont: function(index, viaKey) {
+		console.log('[setFont] '+index+', '+viaKey);
+
+		var sFont = tdFonts.rows(index).cells(0).innerText;
+
+		var selecting = (viaKey != null) ? viaKey : this.selectingFont;
+		switch (selecting) {
+			case 0:
+				divFonttype.style.fontFamily = sFont;
+				divFonttype.innerText = sFont;
+				tdFonts.rows(this.fonttypeIndex).className = 'menuItem';
+				this.fonttypeIndex = index;
+				tdFonts.rows(this.fonttypeIndex).className = 'menuItemSelected';
+				break;
+		}
+
+		// adjust the scrollbar if needed
+		if (fontMenu.scrollTop > tdFonts.rows(index).offsetTop) {
+			fontMenu.scrollTop = tdFonts.rows(index).offsetTop;
+		}
+
+		if (fontMenu.scrollTop < tdFonts.rows(index).offsetTop+tdFonts.rows(index).offsetHeight-150) {
+			fontMenu.scrollTop = tdFonts.rows(index).offsetTop+tdFonts.rows(index).offsetHeight-150;
+		}
+	},
+
+	setFontStyle: function(i) {
+		console.log('[setFontStyle]');
+
+		switch (i) {
+			case 0:
+				divFonttype.style.fontWeight = divFonttypeBold.checked ? 'bold' : '';
+				divFonttype.style.fontStyle = divFonttypeItalic.checked ? 'italic' : '';
+				break;
+		}
+	},
+
+	keyPress: function(i) {
+		console.log('[keyPress]');
+
+		switch (event.keyCode)
+		{
+			case 40:	//down arrow
+				if (i == 0) {
+					if (this.fonttypeIndex < tdFonts.rows.length-1) {
+						this.setFont(this.fonttypeIndex+1, i);
+					}
+				}
+				break;
+			case 38:	//up arrow
+				if (i == 0) {
+					if (this.fonttypeIndex > 0) {
+						this.setFont(this.fonttypeIndex-1, i);
+					}
+				}
+				break;
+			case 36:	//home
+				this.setFont(0, i);
+				break;
+			case 35:	//end
+				this.setFont(tdFonts.rows.length - 1, i);
+				break;
+		}
+	},
+
+	mouseOver: function(mouseEntered, id) {
+		// console.log('[mouseOver]');
+
+		var selected = (this.selectingFont == 0) ? this.fonttypeIndex : 0;
+
+		if (mouseEntered) {
+			id.className = (id.rowIndex == selected) ? 'menuItemHoverSelected' : 'menuItemHover';
+		} else {
+			id.className = (id.rowIndex == selected) ? 'menuItemSelected' : 'menuItem';
+		}
+	}
+}

File js/gadget.js

+console.log('loaded: gadget.js');
+
+var font;
+var color;
+var opacity;
+// var negativeVerticalMargin;
+// var negativeHorizontalMargin;
+var woeid;
+var isF;
+
+var toTemp;
+var toCondition;
+
+var targetWidth;
+var targetHeight;
+
+function init() {
+	console.log('[init]');
+
+	System.Gadget.settingsUI = 'settings.html';
+	System.Gadget.onSettingsClosed = function() {
+		readSettings();
+		createTextObjects();
+		refresh(false);
+	};
+
+	readSettings();
+	createTextObjects();
+
+	ensureWoeid(function() {
+		refresh(true);
+	}, function(msg){
+		toTemp.value = '';
+		toCondition.value = msg;
+		toCondition.left = targetWidth - toCondition.width;
+
+		refresh(true);
+	});
+}
+
+function readSettings() {
+	console.log('[readSettings]');
+
+	font = System.Gadget.Settings.readString('font') || 'Arial';
+	color = System.Gadget.Settings.readString('color') || 'white';
+	opacity = System.Gadget.Settings.read('opacity') || 30;
+	// negativeVerticalMargin = System.Gadget.Settings.read('negativeVerticalMargin') || 0;
+	// negativeHorizontalMargin = System.Gadget.Settings.read('negativeHorizontalMargin') || 0;
+	woeid = System.Gadget.Settings.readString('woeid') || '';
+	isF = typeof System.Gadget.Settings.read('isF') == 'string' ? true : System.Gadget.Settings.read('isF');
+
+	console.log('    font: '+font);
+	console.log('    color: '+color);
+	console.log('    opacity: '+opacity);
+	console.log('    woeid: '+woeid);
+}
+
+function createTextObjects() {
+	console.log('[createTextObjects]');
+
+	var bg = document.getElementById('bg');
+	bg.removeObjects();
+
+	//dummy chars for initial text object alignment
+	//http://developer.yahoo.com/weather/ for labels (this is the longest uncompacted one)
+	toTemp = bg.addTextObject("---°", font, 85, color, 0, 0);
+	toTemp.font = font;
+	toTemp.color = color;
+	toTemp.opacity = opacity;
+
+	toCondition = bg.addTextObject('SCATTERED SNOW SHOWERS', font, 60, color, 0, 70);
+	toCondition.opacity = opacity;
+	toCondition.font = font;
+	toCondition.color = color;
+	toCondition.opacity = opacity;
+
+	//same layout rationale as HUD Time
+
+	targetWidth = document.getElementsByTagName('body')[0].style.width = toCondition.width;
+	targetHeight = document.getElementsByTagName('body')[0].style.height = toTemp.height + toCondition.height;
+
+	toCondition.value = 'CHECK SETTINGS'
+}
+
+function refresh(autoreload) {
+	console.log('[refresh]');
+
+	ensureWoeid(function(){
+		getWeather(woeid, function(currentTemp, currentCondition) {
+			console.log('    font: '+font);
+			console.log('    color: '+color);
+			console.log('    opacity: '+opacity);
+
+
+			toTemp.value = currentTemp;
+			toTemp.font = font;
+			toTemp.color = color;
+			toTemp.opacity = opacity;
+
+			toTemp.left = targetWidth - toTemp.width;
+			toTemp.top = 0;
+
+
+			toCondition.value = currentCondition;
+			toCondition.font = font;
+			toCondition.color = color;
+			toCondition.opacity = opacity;
+
+			toCondition.left = targetWidth - toCondition.width;
+			toCondition.top = 90;
+
+			// console.log('    width: '+toTime.width+', height: '+toDay.top + toDay.height);
+			// console.log('    toTime: x='+toTime.left+', y='+toTime.top+', h='+toTime.height+', w='+toTime.width);
+		});
+
+		if (autoreload) {
+				setTimeout(function() { refresh(true); }, 60*5000);
+		}
+	}, function(msg) {
+		toTemp.value = '';
+		toCondition.value = msg;
+		toCondition.left = targetWidth - toCondition.width;
+	});
+}
+
+function getWeather(known_woeid, callback) {
+	console.log('[getWeather] woeid: '+known_woeid);
+
+	if(typeof known_woeid == "undefined" || known_woeid.length == 0) {
+		return;
+	}
+
+	var url = 'http://weather.yahooapis.com/forecastrss?w='+known_woeid+'&u='+(isF ? 'f' : 'c');
+	console.log('    url: '+url);
+
+	var req = new XMLHttpRequest();
+	req.onreadystatechange = function() {
+		console.log('[onreadystatechange] state: '+req.readyState+', status: '+req.status+', response length: '+(req.responseText || '').length);
+
+		if(req.readyState == 4 && req.status == 200) {
+			var weather_el = req.responseXML.getElementsByTagName('yweather:condition')[0];
+
+			console.log('    weather_el: '+weather_el);
+
+			var currentTemp = weather_el.getAttribute('temp')+'°';
+			var currentCondition = compact(weather_el.getAttribute('text'));
+
+			console.log('    currentTemp: '+currentTemp);
+			console.log('    currentCondition: '+currentCondition);
+
+			callback(currentTemp, currentCondition);
+			return;
+		}
+	};
+
+	req.open('get', url);
+	req.send(null);
+}
+
+function compact(condition) {
+	return condition.toUpperCase().replace('THUNDERSHOWER', 'T-SHOWER').replace('THUNDERSTORM', 'T-STORM').replace(' AND ', '/');
+}
+
+function ensureWoeid(success, otherwise) {
+	console.log('[ensureWoeid]');
+
+	if (typeof woeid != "undefined" && woeid.length > 0) {
+		success();
+		return;
+	}
+
+	detectZipCode(function(zip) {
+		console.log('Autodetected ZIP code: '+zip);
+
+		detectWoeID(zip, function(detected_woeid) {
+			console.log('Successfully detected WOEID: '+detected_woeid);
+
+			woeid = detected_woeid;
+			System.Gadget.Settings.writeString('woeid', detected_woeid);
+
+			success();
+
+		}, function() {
+			console.log('No luck autodetecting WOEID');
+			otherwise('Check Settings');
+		});
+	}, function() {
+		console.log('No luck autodetecting zip code');
+		otherwise('Check Settings');
+	});
+}
+
+function detectZipCode(success, otherwise) {
+	console.log('[detectZipCode]');
+
+	var url = 'http://www.maxmind.com/app/mylocation';
+	console.log('    url: '+url);
+
+	var req = new XMLHttpRequest();
+	req.onreadystatechange = function() {
+		console.log('[onreadystatechange] state: '+req.readyState+', status: '+req.status+', response length: '+(req.responseText || '').length);
+
+		if(req.readyState == 4 && req.status == 200) {
+			var data = req.responseText;
+			var start = data.indexOf('Zipcode')+'Zipcode*</td> <td class=output align="center"> '.length;
+			var zip = data.substr(start, 5);
+
+			success(zip);
+		}
+
+		if(req.status != 200) {
+			otherwise();
+		}
+	};
+
+	req.open('get', url);
+	req.send(null);
+}
+
+function detectWoeID(zip, success, otherwise) {
+	console.log('[detectWoeID]');
+
+	var url = 'http://query.yahooapis.com/v1/public/yql?q='+encodeURIComponent('select * from geo.places where text="'+zip+'"')+'&format=json';
+	console.log('    url: '+url);
+
+	var req = new XMLHttpRequest();
+	req.onreadystatechange = function() {
+		console.log('[onreadystatechange] state: '+req.readyState+', status: '+req.status+', response length: '+(req.responseText || '').length);
+
+		if(req.readyState == 4 && req.status == 200) {
+			var data = req.responseText;
+			var start = data.indexOf('"woeid":"')+'"woeid":"'.length;
+			var end = data.indexOf('"', start+1);
+			var woeid = data.substr(start, end-start);
+
+			console.log('    detected woeid: '+woeid);
+
+			success(woeid);
+		}
+
+		if(req.status != 200) {
+			otherwise();
+		}
+	};
+
+	req.open('get', url);
+	req.send(null);
+}

File settings.html

-<!--
-Majority of settings file contents including font and color picker from
-Jonathan Abbott's (http://vistagadgets.spaces.live.com/) excellent Flip Calendar gadget
--->	
+<!DOCTYPE html>
 <html>
-  <head>
-    <style>
-    	* {
-    		font-family:Segoe UI;
-    		font-size:12px;
-    	}
-    		
-		body{ 
-			width:221px;
-			height:294px;
-			margin:0px;
-		}
-		
-		table {
-			border-collapse:collapse;
-		}
-		
-		.fontmenusurround {
-			position:absolute;
-			overflow-x:hidden;
-			overflow-y:auto;
-			height:150px;
-			width:220px;
-			border:1px 1px 1px 1px solid;
-			border-color:rgb(151,151,151);
-			border-spacing:0px;
-			z-index:2;
-		}
-		
-		/* Menu item */
-		.fontmenuItem td{
-			border-style:solid;
-			border-width:1px 0px 1px 0px;
-			border-color:rgb(245,245,245) rgb(226,226,226) rgb(245,245,245) rgb(245,245,245);
-			background-color:rgb(245,245,245);
-			font-size:18px;
-			padding:0px 4px 0px 4px;
-			white-space:nowrap;
-			height:22px;
-			overflow:hidden;
-		}
-		
-		.fontmenuItemSelected td{
-			border-style:solid;
-			border-width:1px 0px 1px 0px;
-			border-color:rgb(245,245,245) rgb(226,226,226) rgb(245,245,245) rgb(245,245,245);
-			background-color:rgb(255,214,109);
-			font-size:18px;
-			padding:0px 4px 0px 4px;
-			white-space:nowrap;
-			height:22px;
-			overflow:hidden;
-		}
-		
-		/* Menu item when mouse over */
-		.fontmenuItemHover td{
-			border-style:solid;
-			border-width:1px 0px 1px 0px;
-			border-color:rgb(170,218,237) rgb(228,241,247) rgb(170,218,237) rgb(228,241,247);
-			background-color:rgb(228,241,247);
-			font-size:18px;
-			padding:0px 4px 0px 4px;
-			white-space:nowrap;
-			height:22px;
-			overflow:hidden;
-		}
+	<head>
+		<script type="text/javascript" src="js/console.log.js"></script>
+		<script type="text/javascript" src="js/font-picker.js"></script>
+		<script type="text/javascript" src="js/color-picker.js"></script>
+		<script type="text/javascript">
+			System.Gadget.onSettingsClosing = function(e) {
+				fontPicker.settingsClosing(e);
+				colorPicker.settingsClosing(e);
+				
+				System.Gadget.Settings.write('opacity', document.getElementById('foregroundOpacity').value);
+				// System.Gadget.Settings.write('negativeVerticalMargin', document.getElementById('negativeVerticalMargin').value);
+				// System.Gadget.Settings.write('negativeHorizontalMargin', document.getElementById('negativeHorizontalMargin').value);
 
-		/* Selected menu item when mouse over */
-		.fontmenuItemHoverSelected td{
-			border-style:solid;
-			border-width:1px 0px 1px 0px;
-			border-color:rgb(170,218,237) rgb(228,241,247) rgb(170,218,237) rgb(228,241,247);
-			background-color:rgb(255,222,133);
-			font-size:18px;
-			padding:0px 4px 0px 4px;
-			white-space:nowrap;
-			height:22px;
-			overflow:hidden;
-		}
-
-		.colourPicker {
-			position:relative;
-			border-style:solid;
-			border-width:1px;
-			border-color:rgb(149,154,162);
-			width:103px;
-			height:6px;
-		}
-		
-		.colourBar {
-			position:absolute;
-			cursor:hand;
-			top:0px;
-			left:0px;
-			border-style:solid;
-			border-width:1px;
-			border-color:rgb(149,154,162);
-		}
-		
-		.currentColour {
- 			position:absolute;
- 			top:202px;
- 			left:165px;
- 			width:55px;
- 			height:50px;
-			border-style:solid;
-			border-width:1px;
-			border-color:rgb(149,154,162);
- 		}
-    </style>	
-	<script>
-		var debug = true;
-		function alert(msg) { System.Debug.outputString(msg); }
-	</script>
-    <script language="javascript" type="text/javascript">
-		var supportedFontTypes = " (truetype) ";
-		var fontsToSkip = ":Bookshelf Symbol 7:"
-		                 +":MS Outlook:"
-		                 +":MS Reference Specialty:"
-		                 +":MT Extra:"
-		                 +":Symbol:"
-		                 +":Webdings:"
-		                 +":Wingdings:"
-		                 +":Wingdings 2:"
-		                 +":Wingdings 3:";
-
-		var fillYield = 50;	// Yield back to IE every X ms
-		var fillYield2 = 5;	// Yield back to IE every X ms
-		var sliderYield = 1;
-
-		var fontSizer = System.Gadget.document.parentWindow.fontSizer;
-		var fonttypeIndex = 0;
-		var fonttypeCalendarIndex = 0;
-		var colour = System.Gadget.document.parentWindow.colour;
-		
-		System.Gadget.onSettingsClosing = settingsClosing;
-
-
-		// save the settings
-		function settingsClosing(event) {
-			alert("settingsClosing");
-			try{
-				if (event.closeAction == event.Action.commit) {
-					//write settings to INI
-					System.Gadget.Settings.writeString("fonttype", divFonttype.innerText);
-					System.Gadget.Settings.writeString("colour", colour.join());
-					var new_zip = document.getElementById('zip_code').value;
-					System.Gadget.Settings.writeString("zip", new_zip);
-				}
-				event.cancel = false;
-			} catch(err) {alert("settingsClosing: "+err.name+" - "+err.message)}
-		}
-
-
-		//read the font list from the registry
-		var sNames;
-		function readFonts() {
-			var HKLM = 2147483650;
-			var rPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
-			var rValue;
-	
-			// connect to the registry
-			var oSwbem = new ActiveXObject("WbemScripting.SwbemLocator");
-			var oSvc = oSwbem.ConnectServer(null, "root\\default");
-			var oReg = oSvc.Get("StdRegProv");
-	
-			// enumerate the values 
-			var oMethod = oReg.Methods_.Item("EnumValues");
-			var oInParam = oMethod.InParameters.SpawnInstance_();
-			oInParam.hDefKey = HKLM;
-			oInParam.sSubKeyName = rPath;
-			var oOutParam = oReg.ExecMethod_(oMethod.Name, oInParam);
-	
-			// get the values into an array
-			sNames = oOutParam.sNames.toArray();
-
-			// sort it
-			sNames.sort();
-		}
-
-
-		//build the font selection table
-    	function buildFontList() {
-    	try{
-			var counter = new Date();
-
-			var fontName, fontType, tRow, tCell, bold, italic;
-			while (sNames.length > 0 && (new Date())-counter<fillYield) {
-				// is the font one we can use
-				fontType = " " + sNames[0].substring(sNames[0].lastIndexOf("(")).toLowerCase() + " ";
-				
-				fontName = sNames[0].substring(0, sNames[0].length - fontType.length + 1);
-				if(supportedFontTypes.indexOf(fontType) > -1 && fontsToSkip.indexOf(":" + fontName + ":") == -1) {
-					//check the height, to see if it's a font we can use
-					fontSizer.font = fontSizer.value = fontName;
-					fontSizer.height = 0;
-
-					if (fontSizer.height != 0) {
-						tRow = tdFonts.insertRow(tdFonts.rows.length);
-
-						//is this one of the current fonts?
-						if (fontName == System.Gadget.document.parentWindow.fonttype)
-							fonttypeIndex = tdFonts.rows.length - 1;
-						else if (fontName == System.Gadget.document.parentWindow.fonttypeCalendar)
-							fonttypeCalendarIndex = tdFonts.rows.length - 1;
-
-						tRow.className = "fontmenuItem";
-						tCell = tRow.insertCell(0);
-						tCell.innerText = fontName;
-						tCell.style.fontFamily = fontName;
-					}
-				}
-				sNames.shift();
+				System.Gadget.Settings.writeString('woeid', document.getElementById('woeidText').value);
+				System.Gadget.Settings.write('isF', document.getElementById('isF').checked);
 			}
 
-			if (sNames.length > 0) window.setTimeout(buildFontList, 20);
-		} catch(err) {alert("buildFontList: "+err.name+" - "+err.message)}
-		}
+			function init() {
+				fontPicker.init();
+				colorPicker.init();
 
+				document.getElementById('foregroundOpacity').value = System.Gadget.Settings.read('opacity') || 30;
+				// document.getElementById('negativeVerticalMargin').value = System.Gadget.Settings.read('negativeVerticalMargin') || 0;
+				// document.getElementById('negativeHorizontalMargin').value = System.Gadget.Settings.read('negativeHorizontalMargin') || 0;
 
-		//initialize the Settings page
-		function init() {
-			//remove focus from the 1st checkbox
-			document.body.focus();
-			
-			//read the fonts from the registry and build the table
-			readFonts();
-			buildFontList();
+				document.getElementById('woeidText').value = System.Gadget.Settings.readString('woeid') || '';
+				// document.getElementById('woeidLocation').value = System.Gadget.Settings.readString('woeidLocation') || '?';
 
-			// main font
-			divFonttype.style.fontFamily = divFonttype.innerText = System.Gadget.document.parentWindow.fonttype;
-			divFonttype.style.fontSize = "16px";
+				console.log(System.Gadget.Settings.read('isF'));
+				document.getElementById('isF').checked = (typeof System.Gadget.Settings.read('isF') == 'string') ? true : System.Gadget.Settings.read('isF');
+				document.getElementById('isC').checked = !document.getElementById('isF').checked;
+			}
+		</script>
 
-			document.getElementById('zip_code').value = System.Gadget.Settings.readString("zip");
-
-			/*
-			//setup the colour picker
-			buildColourSliders(red, 0);
-			buildColourSliders(green, 1);
-			buildColourSliders(blue, 2);
-			setColourSliders();
-			*/
-		}
-
-
-
-		//set the colour sliders to the current colour
-		function setColourSliders() {
-			redSlider.style.left = parseInt(colour[0] / 2.55);
-			greenSlider.style.left = parseInt(colour[1] / 2.55);
-			blueSlider.style.left = parseInt(colour[2] / 2.55);
-
-			currentColour.style.backgroundColor = "rgb(" + colour[0] + "," + colour[1] + "," + colour[2] + ")";
-		}
-
-
-		//initiate mouse dragging of a slider
-		var dragStartX, colourChanging;
-		function moveSlider(id) {
-			colourChanging = id;
-			var obj = document.getElementById(id);
-			dragStartX = obj.parentNode.offsetLeft + obj.parentNode.parentNode.offsetLeft + 2;
-			document.body.setCapture();
-		
-		 	document.body.onmouseup = function () {
-		 		document.body.onmousemove = null;
-		 		document.body.releaseCapture();
-				document.body.onmouseup = null;
-		 	}
-		
-			document.body.onmousemove = function() {
-				try{
-					var v = event.clientX - dragStartX;
-					if (v<0) v=0;
-					else if (v>100) v=100;
-
-					switch (colourChanging) {
-						case "red":
-							redSlider.style.left = v;
-							colour[0] = Math.round(v * 2.55);
-							updateGreenSlider(true);
-							updateBlueSlider(true);
-							break;
-						case "green":
-							greenSlider.style.left = v;
-							colour[1] = Math.round(v * 2.55);
-							updateRedSlider(true);
-							updateBlueSlider(true);
-							break;
-						case "blue":
-							blueSlider.style.left = v;
-							colour[2] = Math.round(v * 2.55);
-							updateRedSlider(true);
-							updateGreenSlider(true);
-							break;
-					}
-
-					currentColour.style.backgroundColor = "rgb(" + colour[0] + "," + colour[1] + "," + colour[2] + ")";
-				} catch(err) {alert("moveSlider: "+err.name + " - "+err.message)}
-			}
-
-		}
-
-
-
-		//update the rgb values of the red slider
-		var redIndex = 0;
-		function updateRedSlider(init) {
-			if (init) redIndex = 0;
-
-			var counter = new Date();
-			while (redIndex<101 && (new Date())-counter<fillYield2) {
-				document.getElementById("c0" + redIndex).style.backgroundColor = "rgb(" + parseInt(redIndex*2.55) + "," + colour[1] + "," + colour[2] + ")";
-				redIndex++;
-			}
-			if (redIndex != 101) window.setTimeout(updateRedSlider, sliderYield);
-		}
-
-		//update the rgb values of the green slider
-		var greenIndex = 0;
-		function updateGreenSlider(init) {
-			if (init) greenIndex = 0;
-
-			var counter = new Date();
-			while (greenIndex<101 && (new Date())-counter<fillYield2) {
-				document.getElementById("c1" + greenIndex).style.backgroundColor = "rgb(" + colour[0] + "," + parseInt(greenIndex*2.55) + "," + colour[2] + ")";
-				greenIndex++;
-			}
-			if (greenIndex != 101) window.setTimeout(updateGreenSlider, sliderYield);
-		}
-
-		//update the rgb values of the blue slider
-		var blueIndex = 0;
-		function updateBlueSlider(init) {
-			if (init) blueIndex = 0;
-
-			var counter = new Date();
-			while (blueIndex<101 && (new Date())-counter<fillYield2) {
-				document.getElementById("c2" + blueIndex).style.backgroundColor = "rgb(" + colour[0] + "," + colour[1] + "," + parseInt(blueIndex*2.55) + ")";
-				blueIndex++;
-			}
-			if (blueIndex != 101) window.setTimeout(updateBlueSlider, sliderYield);
-		}
-
-
-		//create the div elements to allow dynamic colour in the sliders
-		function buildColourSliders(id, index) {
-			var obj, newColour;
-
-			for (var i=0; i<101; i++) {
-				switch (index) {
-					case 0:
-						newColour = [parseInt(i*2.55), colour[1], colour[2]];
-						break;
-					case 1:
-						newColour = [colour[0], parseInt(i*2.55), colour[2]];
-						break;
-					case 2:
-						newColour = [colour[0], colour[1], parseInt(i*2.55)];
-						break;
-				}
-				obj = document.createElement("<div id='c" + index + i +"' style='position:absolute; top:0px; left:" + i + "px; width:1px; height:100%; background-color:rgb(" + newColour[0] + "," + newColour[1] + "," + newColour[2] + "); overflow:hidden;'></div>");
-				id.appendChild(obj);
-			}
-		}
-
-
-
-		// *********
-		// The following code was written by Mark Kahn, I've modified it slightly to meet this Gadgets needs
-		// Full article: http://www.webreference.com/programming/javascript/mk/column3
-		function setColour() {
-			// width, height of the colour selector image
-			var width=190;
-			var height=15;
-			
-			// get the width of each colour section
-			var sWidth = width/6;
-	
-				// get the mouse X,Y positions
-			var C = event.offsetX;
-			var R = event.offsetY;
-			// bound them
-			if (C<0) C=0;
-			if (R<0) R=0;
-	
-				//get the column in the current colour group
-			var c = C % sWidth;
-			var r, g, b, h;
-	
-				// get the colour % within the current group
-			var l = (255 / sWidth) * c;
-			 
-			r=C<sWidth ? 255 : C<sWidth*2 ? 255-l : C<sWidth*4 ? 0 : C<sWidth*5 ? l : 255; 
-			g=C<sWidth ? l : C<sWidth*3 ? 255 : C<sWidth*4 ? 255-l : 0; 
-			b=C<sWidth*2 ? 0 : C<sWidth*3 ? l : C<sWidth*5 ? 255 : 255-l; 
-	
-	
-			if(R < (height/2)){ 
-				// adjust for the bottom half of the colour map
-				var base = 255 - (255 * 2/height) * R;
-
-				r = base + (r * R * 2 / height);
-				g = base + (g * R * 2 / height);
-				b = base + (b * R * 2 / height);
-			} else if( R > (height/2)){
-				// adjust for the top half of the colour map
-				var base = (height - R) / (height / 2);
-
-				r=r*base;
-				g=g*base;
-				b=b*base;
-			}
-
-			colour[0] = Math.round(r);
-			colour[1] = Math.round(g);
-			colour[2] = Math.round(b);
-
-			setColourSliders();
-			updateRedSlider(true);
-			updateGreenSlider(true);
-			updateBlueSlider(true);
-	 	}
-		// *********
-
-
-		//show the font selection menu
-		var selectingFont = -1;
-		function showFontMenu(id, x, y) {
-			if (id == -1) {
-				if (fontMenu.style.display != 'none')
-					id = selectingFont;
-				else
-					return;
-			}
-				
-			fontMenu.style.display = (fontMenu.style.display == 'none') ? 'inline' : 'none';
-
-			if (fontMenu.style.display == "none") {
-				switch (selectingFont) {
-					case 0:
-						dropPNG.src = "images/dropmenu.png";
-						break;
-					case 1:
-						dropPNG2.src = "images/dropmenu.png";
-						break;
-				}
-				selectingFont = -1;
-			} else {
-				fontMenu.style.top = y;
-				fontMenu.style.left = x;
-				selectingFont = id;
-				switch (id) {
-					case 0:
-						fontMenu.scrollTop = tdFonts.rows(fonttypeIndex).offsetTop - 65;
-						tdFonts.rows(fonttypeIndex).className = "fontmenuItemselected";
-						break;
-					case 1:
-						fontMenu.scrollTop = tdFonts.rows(fonttypeCalendarIndex).offsetTop - 65;
-						tdFonts.rows(fonttypeCalendarIndex).className = "fontmenuItemselected";
-						break;
-				}
-			}
-		}
-
-
-
-		//user has selected a font
-		function setFont(index, viaKey) {
-			var sFont = tdFonts.rows(index).cells(0).innerText;
-
-			var selecting = (viaKey != null) ? viaKey : selectingFont;
-			switch (selecting) {
-				case 0:
-					divFonttype.style.fontFamily = sFont;
-					divFonttype.innerText = sFont;
-					tdFonts.rows(fonttypeIndex).className = "fontmenuItem";
-					fonttypeIndex = index;
-					tdFonts.rows(fonttypeIndex).className = "fontmenuItemSelected";
-					break;
-				case 1: break;
-			}
-
-			// adjust the scrollbar if needed
-			if (fontMenu.scrollTop > tdFonts.rows(index).offsetTop)
-				fontMenu.scrollTop = tdFonts.rows(index).offsetTop;
-			if (fontMenu.scrollTop < tdFonts.rows(index).offsetTop+tdFonts.rows(index).offsetHeight-150)
-				fontMenu.scrollTop = tdFonts.rows(index).offsetTop+tdFonts.rows(index).offsetHeight-150;
-		}
-
-
-
-		//user has changed a font style
-		function setFontStyle(i) {
-			switch (i) {
-				case 0:
-					divFonttype.style.fontWeight = divFonttypeBold.checked ? "bold" : "";
-					divFonttype.style.fontStyle = divFonttypeItalic.checked ? "italic" : "";
-					break;
-				case 1: break;
-			}
-		}
-		
-		//handle key presses to allow arrow keys in font selection
-		function keyPress(i) {
-			switch (event.keyCode)
-			{
-				case 40:	//down arrow
-					if (i == 0) {
-						if (fonttypeIndex < tdFonts.rows.length-1)
-							setFont(fonttypeIndex+1, i);
-					} else {
-						if (fonttypeCalendarIndex < tdFonts.rows.length-1)
-							setFont(fonttypeCalendarIndex+1, i);
-					}
-					break;
-				case 38:	//up arrow
-					if (i == 0) {
-						if (fonttypeIndex > 0)
-							setFont(fonttypeIndex-1, i);
-					} else {
-						if (fonttypeCalendarIndex > 0)
-							setFont(fonttypeCalendarIndex-1, i);
-					}
-					break;
-				case 36:	//home
-					setFont(0, i);
-					break;
-				case 35:	//end
-					setFont(tdFonts.rows.length - 1, i);
-					break;
-			}
-		}
-
-
-
-		//handle highlighting on the font menu
-		function mouseOver(mouseEntered, id) {
-			var selected = (selectingFont == 0) ? fonttypeIndex : fonttypeCalendarIndex;
-
-			if (mouseEntered) {
-				id.className = (id.rowIndex == selected) ? "fontmenuItemHoverSelected" : "fontmenuItemHover";
-			} else {
-				id.className = (id.rowIndex == selected) ? "fontmenuItemSelected" : "fontmenuItem";
-			}
-		}
-    </script>
-</head>
-<body onload="init()" onclick="showFontMenu(-1)">
-  	<table>
-  		<tr>
-  			<td>Please select the font to be used:</td>
-  		</tr>
-  		<tr>
-  			<td>
-	  			<div onclick="javascript:showFontMenu(0, 1, 38); event.cancelBubble=true;" style="height:22px; width:220px; overflow:hidden;"
-					onMouseOver="dropPNG.src='images/dropmenuhover.png'"
-					onMouseOut="javascript:if(selectingFont!=0) dropPNG.src='images/dropmenu.png'"
-					onKeyDown="keyPress(0)">
-					<img id="dropPNG" src="images/dropmenu.png" />
-					<div style="position:relative; top:-22px; left:5px; width:195px; height:17px; overflow:hidden; white-space:nowrap;">
-						<div style="position:absolute; top:50%;">
-							<div id="divFonttype" style="position:relative; top:-50%;"></div>
+		<link rel="stylesheet" type="text/css" href="css/settings.css" />
+	</head>
+	<body onload="init();" onclick="fontPicker.showFontMenu(-1, 0, 0); colorPicker.showColorMenu(-1, 0, 0);">
+		<table>
+			<tr>
+				<td>Pick a font:</td>
+			</tr>
+			<tr>
+				<td>
+					<div onclick="javascript:fontPicker.showFontMenu(0, 1, 38); event.cancelBubble=true;" style="height:22px; width:220px; overflow:hidden;" onMouseOver="fontDropPNG.src='images/dropmenuhover.png'" onMouseOut="javascript:if(fontPicker.selectingFont!=0) fontDropPNG.src='images/dropmenu.png'" onKeyDown="fontPicker.keyPress(0)">
+						<img id="fontDropPNG" src="images/dropmenu.png" />
+						<div style="position:relative; top:-22px; left:5px; width:195px; height:17px; overflow:hidden; white-space:nowrap;">
+							<div style="position:absolute; top:50%;">
+								<div id="divFonttype" style="position:relative; top:-50%;"></div>
+							</div>
 						</div>
 					</div>
-				</div>
-				<!-- 
-				<input unselectable="on" type="checkbox" id="divFonttypeBold" onclick="setFontStyle(0)">Bold
-				<input unselectable="on" type="checkbox" id="divFonttypeItalic" onclick="setFontStyle(0)">Italic
-				-->
-  			</td>
-  		</tr>
-		<tr>
-  			<td><br>Please input your zip code:<br></td>
-  		</tr>
-  		<tr>
-  			<td>
-  				<input type="text" id="zip_code" />
-  			</td>
-  		</tr>
-		<!-- 
-  		<tr>
-  			<td><br>Please select the colour of the header:<br></td>
-  		</tr>
-  		<tr>
-  			<td>
-  				<div style="position:relative; left:0px;">
-  					r
-  					<div style="position:absolute; top:4px; left:10px;">
-  						<div id="red" class="colourPicker" style="position:absolute; top:0px; left:3px;"></div>
-  						<img id="redSlider" src="images/colourpickerslider.png" style="cursor:hand; position:absolute; top:7px; left:0px;" onmousedown="moveSlider('red')" />
-  				</div>
-  			</td>
-  		</tr>
-  		<tr>
-  			<td>
-  				<div style="position:relative; left:0px;">
-  					g
-  					<div style="position:absolute; top:4px; left:10px;">
-  						<div id="green" class="colourPicker" style="position:absolute; top:0px; left:3px;"></div>
-  						<img id="greenSlider" src="images/colourpickerslider.png" style="cursor:hand; position:absolute; top:7px; left:0px;" onmousedown="moveSlider('green')" />
-  					</div>
-  				</div>
-  			</td>
-  		</tr>
-  		<tr>
-  			<td>
-  				<div style="position:relative; left:0px;">
-  					b
-  					<div style="position:absolute; top:4px; left:10px;">
-  						<div id="blue" class="colourPicker" style="position:absolute; top:0px; left:3px;"></div>
-  						<img id="blueSlider" src="images/colourpickerslider.png" style="cursor:hand; position:absolute; top:7px; left:0px;" onmousedown="moveSlider('blue')" />
-  					</div>
-  				</div>
-  			</td>
-  		</tr>
-  		<tr>
-  			<td><br>
-  				<div style="position:relative; left:13px;">
-	  				<img src="images/colourpicker.png" class="colourBar" onclick="setColour()" />
-	  			</div>
-  			</td>
-  		</tr>
-	-->
-  	</table>
-  	<div id="fontMenu" class="fontmenusurround" style="display:none;">
-		<table id="tdFonts" style="position:absolute; top:0px; left:0px;" cellspacing=0
-	  		onMouseOut="javascript:mouseOver(false, this.rows((event.srcElement.parentNode.rowIndex!=null) ? event.srcElement.parentNode.rowIndex : event.srcElement.parentNode.parentNode.rowIndex))"
-			onMouseOver="javascript:mouseOver(true, this.rows((event.srcElement.parentNode.rowIndex!=null) ? event.srcElement.parentNode.rowIndex : event.srcElement.parentNode.parentNode.rowIndex));"
-			onClick="javascript:setFont(event.srcElement.parentNode.rowIndex); event.cancelBubble=true;"
-			>
+
+					<!--
+					<input unselectable="on" type="checkbox" id="divFonttypeBold" onclick="setFontStyle(0)">Bold
+					<input unselectable="on" type="checkbox" id="divFonttypeItalic" onclick="setFontStyle(0)">Italic
+					-->
+				</td>
+			</tr>
+			
+			
+			<tr>
+				<td>Pick a color:</td>
+			</tr>
+			<tr>
+				<td>
+					<div onclick="javascript:colorPicker.showColorMenu(0, 1, 79); event.cancelBubble=true;" style="height:22px; width:220px; overflow:hidden;" onMouseOver="colorDropPNG.src='images/dropmenuhover.png'" onMouseOut="javascript:if(colorPicker.selectingColor!=0) colorDropPNG.src='images/dropmenu.png'" onKeyDown="colorPicker.keyPress(0)">
+						<img id="colorDropPNG" src="images/dropmenu.png" />
+						<div style="position:relative; top:-22px; left:5px; width:195px; height:17px; overflow:hidden; white-space:nowrap;">
+							<div style="position:absolute; top:50%;">
+								<div id="divColortype" style="position:relative; top:-50%;"></div>
+							</div>
+						</div>
+					</div>
+				</td>
+			</tr>
+
+
+			<tr>
+				<td>Foreground opacity:</td>
+			</tr>
+			<tr>
+				<td>
+					<input id="foregroundOpacity" type="text" size="2" onkeyup="this.value=this.value.replace(/[^\d]/, '');">%
+				</td>
+			</tr>
+
+			<!--
+			<tr>
+				<td>Negative margins:</td>
+			</tr>
+			<tr>
+				<td>
+					<input id="negativeVerticalMargin" type="text" size="2" onkeyup="this.value=this.value.replace(/[^\d]/, '');">px (Y), 
+					<input id="negativeHorizontalMargin" type="text" size="2" onkeyup="this.value=this.value.replace(/[^\d]/, '');">px (X)
+				</td>
+			</tr>
+			-->
+
+			<tr><td>&nbsp;</td></tr>
+
+			<tr>
+				<td>"Where On Earth" ID:</td>
+			</tr>
+			<tr>
+				<td>
+					<input id="woeidText" type="text" size="20" onkeyup="this.value=this.value.replace(/[^\d]/, '');">
+				</td>
+			</tr>
+			<!--
+			<tr>
+				<td>This WOEID is for <span id="woeidLocation"></span></td>
+			</tr>
+			-->
+			<tr>
+				<td><a href="http://woeid.factormystic.net">Find out the WOEID for your location</a></td>
+			</tr>
+
+
+			<tr><td>&nbsp;</td></tr>
+
+
+			<tr>
+				<td>Temperature Scale:</td>
+			</tr>
+			<tr>
+				<td>
+					<input id="isF" name="scale" type="radio" /><label for="isF">Fahrenheit</label><br/>
+					<input id="isC" name="scale" type="radio" /><label for="isC">Celcius</label>
+				</td>
+			</tr>
+
 		</table>
-	</div>
-	<!-- <div id="currentColour" class="currentColour"></div> -->
-  </body>
-</html>
+
+
+		<div id="colorMenu" class="menusurround" style="display:none;">
+			<table id="tdColors" style="position:absolute; top:0px; left:0px;" cellspacing="0" onMouseOut="javascript:colorPicker.mouseOver(false, this.rows((event.srcElement.parentNode.rowIndex!=null) ? event.srcElement.parentNode.rowIndex : event.srcElement.parentNode.parentNode.rowIndex))" onMouseOver="javascript:colorPicker.mouseOver(true, this.rows((event.srcElement.parentNode.rowIndex!=null) ? event.srcElement.parentNode.rowIndex : event.srcElement.parentNode.parentNode.rowIndex));" onClick="javascript:colorPicker.setColor(event.srcElement.parentNode.rowIndex); colorPicker.showColorMenu(-1, 0, 0); event.cancelBubble=true;"></table>
+		</div>
+
+		<div id="fontMenu" class="menusurround" style="display:none;">
+			<table id="tdFonts" style="position:absolute; top:0px; left:0px;" cellspacing="0" onMouseOut="javascript:fontPicker.mouseOver(false, this.rows((event.srcElement.parentNode.rowIndex!=null) ? event.srcElement.parentNode.rowIndex : event.srcElement.parentNode.parentNode.rowIndex))" onMouseOver="javascript:fontPicker.mouseOver(true, this.rows((event.srcElement.parentNode.rowIndex!=null) ? event.srcElement.parentNode.rowIndex : event.srcElement.parentNode.parentNode.rowIndex));" onClick="javascript:fontPicker.setFont(event.srcElement.parentNode.rowIndex); fontPicker.showFontMenu(-1, 0, 0); event.cancelBubble=true;"></table>
+		</div>
+
+		<div class="about">
+			<a href="http://factormystic.net/projects/gadgets/hud-weather">HUD Weather homepage</a>
+		</div>
+
+	</body>
+</html>