A Small Calendar Utility For Reference
I created a rather small calendar utility for use during project management meetings. We usually brain storm a project and use the Windows date/time calendar (in the icon tray) to think out our time estimates. The problem is that calendar sucks and only has one month at a time (and moving from month to month is a pain). My small calendar utility, written in ColdFusion with some Javascript, displays a year's worth of calendars and allows the user to click and highlight a single time span.
Feel free to use it if you like:
http://www.bennadel.com/util/calendar
If anyone is interested in the code that goes behind this, it's fairly small.
Action Script
<cfscript> | |
// Get the current month. | |
REQUEST.ThisMonth = CreateDate( | |
Year( REQUEST.Environment.DateTime.Now ), | |
Month( REQUEST.Environment.DateTime.Now ), | |
1 | |
); | |
// Create an array of months. | |
REQUEST.Months = ArrayNew( 1 ); | |
// Add a date for each month to the array. Right now, we are going | |
// to be using one month previous to this one, plus 11 months going | |
// forward. This should give us just over a year going forward. | |
for (intI = -1 ; intI LTE 12 ; intI = (intI + 1)){ | |
ArrayAppend( | |
REQUEST.Months, | |
DateAdd( "m", intI, REQUEST.ThisMonth ) | |
); | |
} | |
</cfscript> |
Java Script Code
<script type="text/javascript"> | |
// These are the global variables neede to keep track of | |
// the calendar and to provide faster lookup via indexing. | |
var objStartDay = null; | |
var objEndDay = null; | |
var arrDays = new Array(); | |
var objToday = null; | |
// This loads the global properties based on the calendar. | |
function InitCalendars(){ | |
var objHolder = document.getElementById( "calendars" ); | |
var arrTBody = objHolder.getElementsByTagName( "tbody" ); | |
var arrTD = null; | |
var intI, intJ; | |
// Loop over tbodys and get their tds. | |
for (intI = 0 ; intI < arrTBody.length ; intI++){ | |
// Get all the TDs. | |
arrTD = arrTBody[ intI ].getElementsByTagName( "td" ); | |
// Loop over all the TDs to init. | |
for (intJ = 0 ; intJ < arrTD.length ; intJ ++){ | |
InitTD( arrTD[ intJ ] ); | |
} | |
} | |
} | |
// This initialized each TD within the calendar days. | |
function InitTD( objTD ){ | |
// Set the TD collection index. | |
objTD.dayIndex = arrDays.length; | |
// Add this TD to the collection. | |
arrDays[ arrDays.length ] = objTD; | |
// Store the original class name. | |
objTD.baseClassName = objTD.className; | |
// Check to see if this is today. | |
if (objTD.className == "today"){ | |
objToday = objTD; | |
} | |
// Set onclick handler. | |
objTD.onclick = function(){ | |
SetDay( this ); | |
} | |
} | |
// This is the onClick handler for each calendar day. It is | |
// used to set the start and end days of the selected day span, | |
// then it renders the calendar. | |
function SetDay( objTD ){ | |
// We can only set a day that is NOT an other month. If this | |
// an other day, just return out. | |
if (objTD.className == "othermonth"){ | |
return; | |
} | |
// Check to see if we if this is the day one. | |
if (objTD == objStartDay){ | |
// Set the start day to be the end day. | |
objStartDay = objEndDay; | |
// Turn off end day. | |
objEndDay = null; | |
} else if (objTD == objEndDay){ | |
// Turn off the end day. | |
objEndDay = null; | |
} else { | |
// We are turning ON a day. Check to see if there is an | |
// existing start and end day. | |
if (objStartDay && objEndDay){ | |
// Both days already exist. We need to alter the | |
// way the selection exists. Check to see the | |
// indexes. | |
if (objTD.dayIndex < objStartDay.dayIndex){ | |
// Expanding back. | |
objStartDay = objTD; | |
} else { | |
// We are going beyong the end day OR we are | |
// going somewhere in the middle of the | |
// existing range. Either way, when we do that, | |
// we are always going to change the END day, | |
// not the Start day. | |
objEndDay = objTD; | |
} | |
} else if (objStartDay){ | |
// Check to see if the new TD is less than or | |
// greater than the current start day. | |
if (objStartDay.dayIndex < objTD.dayIndex){ | |
objEndDay = objTD; | |
} else { | |
objEndDay = objStartDay; | |
objStartDay = objTD; | |
} | |
} else { | |
// We will never have JUST an end day. Set this to | |
// the start day. | |
objStartDay = objTD; | |
} | |
} | |
// Render the calendar with the new time span. | |
RenderCalendar(); | |
} | |
// This renders the calendar and turns the days on or off | |
// depending on where they fall in any selected time span. | |
function RenderCalendar(){ | |
var intDay = null; | |
// Loop over all the days in the collection. | |
for (intDay = 0 ; intDay < arrDays.length ; intDay++){ | |
// We cannot do anything to other month days. If this | |
// is an other month day, just continue the loop. | |
if (arrDays[ intDay ].className == "othermonth"){ | |
continue; | |
} | |
// Check to see if we have both start and end day. | |
if ( | |
objStartDay && | |
objEndDay && | |
(objStartDay.dayIndex <= arrDays[ intDay ].dayIndex) && | |
(objEndDay.dayIndex >= arrDays[ intDay ].dayIndex) | |
){ | |
// This is a selected day. | |
arrDays[ intDay ].className = ( | |
( (arrDays[ intDay ] == objToday) ? "today" : "" ) + | |
"selected" | |
); | |
} else if ( | |
(arrDays[ intDay ] == objStartDay) || | |
(arrDays[ intDay ] == objEndDay) | |
){ | |
// This is a selected day. | |
arrDays[ intDay ].className = ( | |
( (arrDays[ intDay ] == objToday) ? "today" : "" ) + | |
"selected" | |
); | |
} else { | |
// This is NOT a selected day. Turn off. | |
arrDays[ intDay ].className = arrDays[ intDay ].baseClassName; | |
} | |
} | |
} | |
</script> |
Calendar Display Code
<div id="calendars"> | |
<!--- Loop over the months in the array. ---> | |
<cfloop | |
index="intI" | |
from="1" | |
to="#ArrayLen( REQUEST.Months )#" | |
step="1"> | |
<cfsilent> | |
<!--- Get the pointer to the current date. ---> | |
<cfset dtThisMonth = REQUEST.Months[ intI ] /> | |
<!--- Get the starting day. ---> | |
<cfset dtStartDay = DateAdd( | |
"d", | |
-(DayOfWeek( dtThisMonth ) - 1), | |
dtThisMonth | |
) /> | |
<!--- Get the ending day. ---> | |
<cfset dtEndDay = (DateAdd( "m", 1, dtThisMonth ) - 1) /> | |
<!--- Stretch it to the end of the week. ---> | |
<cfset dtEndDay = DateAdd( | |
"d", | |
(7 - DayOfWeek( dtEndDay )), | |
dtEndDay | |
) /> | |
<!--- Get today's date. ---> | |
<cfset dtToday = Fix( REQUEST.Environment.DateTime.Now ) /> | |
</cfsilent> | |
<table width="100%" border="0" cellspacing="2" cellpadding="0" class="calendarmonth"> | |
<thead> | |
<tr> | |
<td colspan="7"> | |
#MonthAsString( Month( dtThisMonth ) )# #Year( dtThisMonth )# | |
</td> | |
</tr> | |
</thead> | |
<tbody> | |
<cfsilent> | |
<cfsavecontent variable="strMonthCode"> | |
<tr> | |
<!--- Loop over the days of the month. ---> | |
<cfloop index="dtDay" from="#dtStartDay#" to="#dtEndDay#" step="1"> | |
<td class="<cfif (dtDay EQ dtToday)>today<cfelseif (Month( dtDay ) EQ Month( dtThisMonth ))>thismonth<cfelse>othermonth</cfif>"> | |
#Day( dtDay )# | |
</td> | |
<cfif ( | |
(DayOfWeek( dtDay ) EQ 7) AND | |
(dtDay NEQ dtEndDay) | |
)> | |
</tr> | |
<tr> | |
</cfif> | |
</cfloop> | |
</tr> | |
</cfsavecontent> | |
</cfsilent> | |
<!--- Output code with as little white space as possible. ---> | |
#strMonthCode.ReplaceAll( ">\s+", ">" ).ReplaceAll( "\s+<", "<" )# | |
</tbody> | |
</table> | |
<!--- Flush for user feedback. ---> | |
<cfflush /> | |
</cfloop> | |
</div> | |
<!--- Initialize the Calendar javascript. ---> | |
<script type="text/javascript"> | |
InitCalendars(); | |
</script> |
CSS Code
table.calendarmonth { | |
margin-bottom: 20px ; | |
} | |
table.calendarmonth td { | |
border: 1px solid #999999 ; | |
cursor: default ; | |
padding: 5px 10px 5px 10px ; | |
} | |
table.calendarmonth thead td { | |
background-color: #F0F0F0 ; | |
border-bottom-width: 2px ; | |
font-size: 12px ; | |
font-weight: bold ; | |
text-align: center ; | |
} | |
table.calendarmonth td.today { | |
background-color: #FEEAB7 ; | |
border-color: #333333 ; /* #E4A705 ; */ | |
font-weight: bold ; | |
} | |
table.calendarmonth td.thismonth {} | |
table.calendarmonth td.othermonth { | |
background-color: #EAEAEA ; | |
border-color: #999999 ; | |
color: #AAAAAA ; | |
} | |
table.calendarmonth td.selected { | |
background-color: #FFE8E1 ; | |
border-color: #FF3333 ; | |
/* color: #FA3E0A ; */ | |
} | |
table.calendarmonth td.todayselected { | |
background-color: #FFB8A4 ; | |
border-color: #FF3333 ; | |
font-weight: bold ; | |
} |
Want to use code from this post? Check out the license.
Reader Comments
It's delicious!
http://del.icio.us/psenn
Awesome :) Glad you like it. Please feel free to suggest any changes you want to it. Someone already suggested dragging for creating time span.