A Small Calendar Utility For Reference

Posted December 7, 2006 at 3:18 PM by Ben Nadel

Tags: ColdFusion, Javascript / DHTML

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 ;
  • }


Reader Comments

Dec 13, 2006 at 6:13 PM // reply »
16 Comments

It's delicious!
http://del.icio.us/psenn


Dec 13, 2006 at 6:55 PM // reply »
11,238 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.


Post A Comment

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.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools