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.