Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at the Nylon Technology 10 Year Anniversary (Jul. 2007) with:

A Small Calendar Utility For Reference

By Ben Nadel on

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 ;
  • }
Tweet This Titillating read by @BenNadel - A Small Calendar Utility For Reference Thanks my man — you rock the party that rocks the body!


Reader Comments

Awesome :) Glad you like it. Please feel free to suggest any changes you want to it. Someone already suggested dragging for creating time span.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.