randomfox (randomfox) wrote,

Javascript: Yearly Calendar


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta http-equiv="Content-Language" content="en-us" />
<meta http-equiv="imagetoolbar" content="false" />
<meta name="MSSmartTagsPreventParsing" content="true" />
<meta name="author" content="Po Shan Cheah" />

<title>Yearly Calendar</title>

<script type="text/javascript">
// Clear the output area.
function clearOutput() {
    var output = document.getElementById("output");
    while (output.firstChild)
	output.removeChild(output.firstChild);
}

// Write a string to the output area.
function write(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    output.appendChild(txt);
}

// Write a bold string to the output area.
function writebold(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var bold = document.createElement("b");
    bold.appendChild(txt);
    output.appendChild(bold);
}

// Write a string with a newline to the output area.
function writeln(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var newline = document.createElement("br");
    output.appendChild(txt);
    output.appendChild(newline);
}

// Write a string in red to signify an error.
function errorln(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var newline = document.createElement("br");
    var span = document.createElement("span");
    // setAttribute("class" ...) does not work in IE.
    span.className = "error";
    span.appendChild(txt);
    span.appendChild(newline);
    output.appendChild(span);
}

// Use Zeller's congruence to determine the day of the week for 
// a specified date.
// Returns: 0-6 representing Sun-Sat
function dayofweek(day, month, year) {
    var century;
    var yr;

    if (month <= 2) {
	month += 10;
	--year;
    }
    else
	month -= 2;

    century = Math.floor(year / 100);
    yr = year % 100;

    return (Math.floor((26 * month - 2) / 10) + 
	    day + yr + 
	    Math.floor(yr / 4) + 
	    Math.floor(century / 4) +
	    203 - 2 * century) % 7;
}

// Returns true if leap year.
function leapyear(year) {
    return (year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0);
}

// Get last day of the month.
function getmaxday(month, year) {
    var monthlen = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    var maxday = monthlen[month - 1];
    if (month == 2 && leapyear(year))
	++maxday;
    return maxday;
}

// Returns a string of nspaces space characters.
function spacer(nspaces) {
    var str = "";
    for (var i = 0; i < nspaces; ++i)
	str += " ";
    return str;
}

// Format s flush right in a field of width characters.
function flushright(s, width) {
    var str = s.toString();
    return spacer(width - str.length) + str;
}

function generateCalendar(year) {
    var monthnames = [
	"January", "February", "March",
	"April", "May", "June",
	"July", "August", "September",
	"October", "November", "December"
    ];

    // Center the year at the top.
    write(spacer(Math.floor((70 - year.toString().length) / 2)));
    writebold(year);
    writeln("");
    // There needs to be at least one space between the two linebreaks
    // or IE will only render one linebreak.
    writeln(" ");

    for (var row = 0; row <= 3; ++row) {
	for (var col = 0; col <= 2; ++col) {
	    var monthname = monthnames[row * 3 + col];
	    var spacebefore = Math.floor((19 - monthname.length) / 2) + 2;

	    // Center the month name over the month.
	    write(spacer(spacebefore));
	    writebold(monthname);
	    write(spacer(24 - monthname.length - spacebefore));
	}
	writeln("");
	writeln(" ");

	// Write the day name headings.
	for (var col = 0; col <= 2; ++col) 
	    write("  S  M  T  W  T  F  S   ");
	writeln("");

	// Format the months one row at a time.
	for (var vcell = 0; vcell <= 5; ++vcell) {
	    for (var col = 0; col <= 2; ++col) {
		var month = row * 3 + col + 1;
		var maxday = getmaxday(month, year);
		var firstday = dayofweek(1, month, year);
		for (var hcell = 0; hcell <= 6; ++hcell) {
		    var day = vcell * 7 + hcell + 1 - firstday;
		    write(day > 0 && day <= maxday ? flushright(day,3) : "   ");
		}
		write("   ");
	    }
	    writeln("");
	}
	writeln(" ");
    }
} // generateCalendar

function main() {
    clearOutput();

    var field = document.getElementById("year");
    var year = parseInt(field.value);
    if (isNaN(year) || year < 1) {
	errorln("Invalid year '" + field.value + "'. Need a positive integer.");
	return;
    }

    generateCalendar(year);
}

// Set the year field to the current year.
function init() {
    var now = new Date();
    var field = document.getElementById("year");
    field.value = now.getFullYear();
    main();
}

// For moving to the next or previous year. delta should be 1 or -1.
function nextyear(delta) {
    var field = document.getElementById("year");
    var year = parseInt(field.value);
    if (!isNaN(year))
	field.value = year + delta;
    main();
}
</script>

<style type="text/css">
body {
    background: #fff;
    color: #000;
    font: normal 14px sans-serif;
}

h1 {
    font: bold 18px sans-serif;
}

.error {
    color: red;
}

#output {
    background: #cff;
    white-space: pre;    
    font: normal 14px monospace;
}

form {
    margin-bottom: 0.5em;
}
</style>
</head>

<body onload="init()">
    <h1>Yearly Calendar</h1>
    <noscript>
	<span class="error">
	    The Yearly Calendar requires a browser that supports Javascript.<br />
	    Your browser either does not support Javascript or it has Javascript disabled. If you wish to run the solver, please upgrade your browser or enable Javascript support.<br />&nbsp;<br />
	</span>
    </noscript>

    <script type="text/javascript">
<!--
// Test for W3C DOM API.
if (document.getElementById) {
}
else {
    document.write('<span class="error">The Yearly Calendar requires a browser that supports the W3C DOM API.<br \/>Your browser does not support this API. If you wish to run the solver, please upgrade your browser. The latest versions of Mozilla Firefox, Opera, and Internet Explorer have support for this API.<br \/>&nbsp;<br \/><\/span>');
}
// -->
    </script>

    <form action="#" onsubmit="main(); return false;">
	<a href="#" onclick="nextyear(-1); return false;">&lt;&lt;</a>
	<input type="text" name="year" id="year" size="10" value="" />
	<a href="#" onclick="nextyear(1); return false;">&gt;&gt;</a>
    </form>

    <hr />
    <table><tr><td><div id="output"></div></td></tr></table>
</body>
</html>
<!--
Last updated: April 13, 2007
-->
<!-- vim:set tw=0: -->

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 2 comments