You can try inverting the hex value of the color. So #FFFFFF becomes #000000 and #AAAAAA becomes #555555. Of course, this method falls through when you have #888888 which when inverted, gives you #777777 (they don't contrast as much).
This blog post describes another way (they only use black or white for the foreground color, depending on the background color). I've translated it into Javascript:
function idealTextColor(bgColor) {
var nThreshold = 105;
var components = getRGBComponents(bgColor);
var bgDelta = (components.R * 0.299) + (components.G * 0.587) + (components.B * 0.114);
return ((255 - bgDelta) < nThreshold) ? "#000000" : "#ffffff";
}
function getRGBComponents(color) {
var r = color.substring(1, 3);
var g = color.substring(3, 5);
var b = color.substring(5, 7);
return {
R: parseInt(r, 16),
G: parseInt(g, 16),
B: parseInt(b, 16)
};
}