Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Making the Microsoft Calendar.htc DHTML Behaviour Better?

0.00/5 (No votes)
12 Dec 2004 2  
The Microsoft Calendar.htc is a great DHTML Behaviour, I try and make it better and quicker and easier to use.

The Problem

Date pickers and calendar popup are a great way for a user to accurately select the date they require. The main problem with most date pickers is that they take an eternity to popup a new window and initialize, this has a negative effect and the user tends to avoid the popup and enter the date manually which may induce errors. In this article, I’ll make use of one of the best calendars on the web today – Microsoft’s calendar.htc and expose it in a more efficient manner.

The Solution

In my last article, I had demonstrated how to use DHTML behaviours to expose common functionality as a CSS style and briefly talked about element behaviours. The Microsoft calendar.htc is an element behaviour that exposes a fully functional DHTML calendar. Microsoft’s calendar is great, and apart from adding a double click event and a bit of styling, I’ve left it intact. Instead of changing the calendar, I decided to create an element behaviour and embed the calendar.htc into it, this way we leave the calendar relatively untouched. The wrapper will expose the calendar in the form of a popup; the popup object is a special type of overlapped window that is very much like a div/layer, but unlike the layer it hides itself when losing the focus and can go over select elements. Here are the main benefits of the control:

  • Totally encapsulated date picker / calendar.
  • Quick loading.
  • Immune to popup blockers (when opening from script).
  • RAD.
  • Targets HTML controls or ASP.NET web controls.

Requirements

First of all, we need to declare our namespace, this is to ensure that the calendar element has a unique qualifier. The HTML element has a xmlns attribute that declares the namespace astutemedia. Setting this attribute allows us to use the prefix astutemedia in the document. The next step is to import the calendar element into the namespace with the import directive.

<html xmlns:astutemedia>
<head>
<?import namespace="astutemedia" implementation="CalendarPopup.htc">
</head>

The import directive is really the key to implementing an element behaviour in the primary document. When the browser begins processing the “import” directive, it waits until the contents of the HTC file have been downloaded completely before continuing. The way this instruction is processed is the reason why the behaviour is bound synchronously to the custom element.

Using the CalendarPopup.htc

Element behaviours are implemented the same as ASP.NET server controls, but all of the processing is done on the client. As you can see from the code snippet below, "Calendar1" has a target attribute that references a textbox, which gets populated by the selected date. The second element doesn’t provide a target but gets the selected date from the onDateSelected event via the selectedDate event attribute.

<input class="FormTextBox" id="Date1" type="text" 
   maxlength="10" name="Date1">
<astutemedia:calendar id="Calendar1" target="Date1"></astutemedia:calendar>
<astutemedia:calendar id="Calendar2" 
   onDateSelected="alert(window.event.selectedDate)">
</astutemedia:calendar>

Creating the Behaviour

The solution has four files:

  • Calendar.gif – This is the calendar icon that gets rendered by the behaviour.
  • Calendar.htc – This is Microsoft’s Calendar behaviour.
  • Calendar.htm – This is the popup’s body, encapsulated into a HTML file.
  • CalendarPopup.htc – This is the main behaviour.

The Calendar.htc behaviour has one minor change that allows us to double click on a date to select it. This is achieved by adding a custom event called OnCalendarDblClick.

 <public:event id="onCalendarDblClick" name="oncalendardblclick">

This gets called when the inner table of the calendar gets double clicked. We reference the innerTableElem and attach the DblClick function to the ondblclick event.

window.document.all.innerTableElem.attachEvent("ondblclick", DblClick);

The function…

function DblClick()
{
   var oEvent = createEventObject();
   onCalendarDblClick.fire(oEvent);
}

We make use of this event in the Calendar.htm file. On the OnCalendarDblClick event, we call a function called CloseCalendar which exposes the value of the selected date.

 oncalendardblclick="CloseCalendar()"

This function is strictly necessary, as we could have called Unload function from the CalendarPopup.htc directly. But adding this function allows readability.

function CloseCalendar()
{
    var val = Calendar.value;
    var id = parent.document.body.children[0].ParentId;
    parent.parent.document.getElementById(id).Unload(val);
}

The CalendarPopup.htc holds the main functionality. It exposes the calendar as a custom element and produces the date picker as a popup. We first start off by declaring the component.

<public:component tagname="Calendar">
 <public:defaults  viewLinkContent="true" /> 
 <public:property  name="Version" value="Calendar 1.0" />
 <public:property  name="Target" value="" />
 <public:event id="onDateSelected" name="ondateselected">
 <public:method name="Unload" />
 <public:attach event="oncontentready" onevent="Init()" />
</public:component>

As you can see from the above code sample, we expose a Target property and give it a default property of an empty string. We also expose an event called onDateSelected, which gets called when the popup unloads. The Unload method gets called by the CloseCalendar function in the Calendar.htm file. We then attach the “Init” function to an event on the holding page (the page where we want to use the behaviour), the event is onContentReady, this event gets fired when the content on the holding page is fully loaded.

The Init function first checks to see if the Target property is set, and if so attaches the onDblClick event to the element. This will allow the double click of the element to show the calendar. We then create the popup itself and populate it with the Calendar.htm file.

function Init()
{
    // Check to see if there is a target element.
    if(Target != null && Target != "")
   {
    // Add a double click to the target elem, to show the calendar
    winDoc.getElementById(Target).attachEvent("ondblclick", ShowPopup);
    }
    // Create a popup object
    popup = win.createPopup();
    popupBody = popup.document.body;
    // Add the scriptlet to the popups body.
    popupBody.innerHTML = "<object id='cal' width='100%' 
      ParentId='" + id + "' height='100%' type='text/x-scriptlet' 
      data='Calendar.htm'></object>"; 
}

The Unload function fires the onDateSelected event and if a target exists, populate it with the selected date value. It then hides the popup.

function Unload(val)
{
    // Create a new event.
    var e = createEventObject();
    // Expose the selected value with the event.
    e.selectedDate = val;
    // Fire the event.
    onDateSelected.fire(e);
    if(Target != null && Target != "")
    {
    // Find the target in the parent document and set the value.
    winDoc.getElementById(Target).value = val;
    }
    // Hide the popup.
    popup.hide();
}

The last function is the ShowPopup function; this function shows the popup when the the calendar icon is clicked or the target element is double clicked. It positions the popup 22 pixels from where the click/double-click occurred. It also makes sure that it doesn’t conflict with the boundaries of the browser window.

function ShowPopup()
{
   var wEvent = win.event;
   var winDocBody = winDoc.body;
   var popupWidth = 320;
   var popupHeight = 250;
   // Set the x and y from where the mouse clicks.
   x = wEvent.x + 22;
   y = wEvent.y - 22;
   // Check to see if the popup goes out of bounds.
   if (x + popupWidth > winDocBody.clientWidth)
   x = wEvent.x - (popupWidth + winDocBody.scrollLeft + 22);
   else 
   x += winDocBody.scrollLeft;
   if (y + popupHeight > winDocBody.offsetHeight)
   y = wEvent.y - (popupHeight + winDocBody.scrollTop + 22);
   else 
   y += winDocBody.scrollTop;
   popupBody.style.border = "1px solid #333333";
   // Show the popup.
   popup.show(40, -80, popupWidth, popupHeight, document.body); 
}

Finally, we output our calendar icon and add an onClick event to show the popup.

<body id="TheBody">
   <img src="Calendar.gif" width="16" height="15" style="cursor:hand" 
   onclick="ShowPopup()" title="Click to show calendar" align="absMiddle">
</body>

Conclusion

This behaviour makes calendars and date pickers a quick and easy solution to a very common problem. Element behaviours are a great way to implement and encapsulate common functionality and are very quick to use. If you are using ASP.NET, you can wrap the element behaviour in a server control to expose the selected date on the server side.

Links and Resources

Downloads and Demos

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here