Implementing a Calendar Control in the Yahoo User Interface (YUI)

Exclusive offer: get 50% off this eBook here
Learning the Yahoo! User Interface library

Learning the Yahoo! User Interface library — Save 50%

Develop your next generation web applications with the YUI JavaScript development library

$26.99    $13.50
by Dan Wellman | April 2008 | AJAX Open Source Web Development

The Yahoo User Interface (YUI) Calendar control, allows you to easily create a variety of attractive and highly functional calendar interfaces which can allow your visitors to quickly and easily select single dates, or range of dates. There is also a range of different formats of Calendar that we can create; there's the basic, single-select, and one-page calendar control which displays one month at a time, or there's a larger, multi-page calendar which allows multiple months to be displayed at once. Multi-select calendars can come in either single or multiple month display formats. In this article by Dan Wellman, we will see how to implement a calendar control in the YUI.

The Basic Calendar Class

The most basic type of calendar is the single-panel Calendar which is created with the YAHOO.widget.Calendar class. To display a calendar, an HTML element is required to act as a container for the calendar. The screenshot shows a basic Calendar control:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

The constructor can then be called specifying, at the very least the id of the container element as an argument. You can also specify the id of the Calendar object as an argument, as well as an optional third argument that can accept a literal object containing various configuration properties.

The configuration object is defined within curly braces within the class constructor. It contains a range of configuration properties and keys that can be used to control different Calendar attributes such as its title, a comma-delimited range of pre-selected dates, or a close button shown on the calendar.

There are a large number of methods defined in the basic Calendar class; some of these are private methods that are used internally by the Calendar object to do certain things and which you normally wouldn't need to use yourself. Some of the more useful public methods include:

  • Initialization methods including init, initEvents, and initStyles which initialize either the calendar itself or the built-in custom events and style constants of the calendar.
  • A method for determining whether a date is outside of the current month: isDateOOM.
  • Navigation methods such as nextMonth, nextYear, previousMonth, and previousYear that can be used to programmatically change the month or year displayed in the current panel.
  • Operational methods such as addMonths, addYears, subtractMonths, and subtractYears which are used to change the month and year shown in the current panel by the specified number of months or years.
  • The render method is used to draw the calendar on the page and is called in for every implementation of a calendar, after it has been configured. Without this method, no Calendar appears on the page.
  • Two reset methods: reset which resets the Calendar to the month and year originally selected, and resetRenderers which resets the render stack of the calendar.
  • Selection methods that select or deselect dates such as deselect, deselectAll, desellectCell, select, and selectCell.

As you can see, there are many methods that you can call to take advantage of the advanced features of the calendar control.

The CalendarGroup Class

In addition to the basic calendar, you can also create a grouped calendar that displays two or more month panels at once using the YAHOO.widget.CalendarGroup class. The control automatically adjusts the Calendar's UI so that the navigation arrows are only displayed on the first and last calendar panels, and so that each panel has its own heading indicating which month it refers to.

The CalendarGroup class contains additional built-in functionality for updating the calendar panels on display, automatically. If you have a two-panel calendar displaying, for example, January and February, clicking the right navigation arrow will move February to the left of the panel so that March will display as the right-hand panel. All of this is automatic and nothing needs to be configured by you.

There are fewer methods in this class; some of those found in the basic Calendar class can also be found here, such as the navigation methods, selection methods, and some of the render methods. Native methods found only in the CalendarGroup class include:

  • The subscribing methods sub and unsub, which subscribe or unsubscribe to custom events of each child calendar.
  • Child functions such as the callChildFunction and setChildFunction methods which set and call functions within all child calendars in the calendar group.

Implementing a Calendar

To complete this example, the only tool other than the Yahoo User Interface (YUI) that you'll need is a basic text editor. Native support for the YUI is provided by some web authoring software packages, most notably Aptana, an open-source application that has been dubbed 'Dreamweaver Killer'. However, I always find that writing code manually while learning something is much more beneficial.

It is very quick and easy to add the calendar, as the basic default implementations require very little configuration. It can be especially useful in forms where the visitor must enter a date. Checking that a date has been entered correctly and in the correct format takes valuable processing time, but using the YUI calendar means that dates are always exactly as you expect them to be.

So far we've spent most of this article looking at a lot of the theoretical issues surrounding the library; I don't know about you, but I think it's definitely time to get on with some actual coding!

The Initial HTML Page

Our first example page contains a simple text field and an image, which once clicked will display the Calendar control on the page, thereby allowing for a date to be selected and added to the input. Begin with the following basic HTML page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html;
charset=utf-8">
<title>YUI Calendar Control Example</title>
<link rel="stylesheet"
type="text/css"
href="yui/build/calendar/assets/skins/sam/calendar.css">
<script type="text/javascript"
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="yui/build/yahoo-dom-event/
yahoo-dom-event.js"></script>
<script type="text/javascript"
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="yui/build/calendar/calendar-min.js"></script>
<style type="text/css">
input {
margin:0px 10px 0px 10px;
}
</style>
</head>
<body class="yui-skin-sam">
<div>
<label>Please enter your date of birth:</label>
<input type="text" name="dobfield" id="dobfield">
<img id="calico" src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="icons/cal.png"
alt="Open the Calendar control">
</div>
<div id="mycal"></div>
</body>
</html>

We begin with a valid DOCTYPE declaration, a must in any web page. For validity, we can also add the lang attribute to the opening <html> tag and for good measure, enforce the utf-8 character set. Nothing so far is YUI-specific, but coding in this way every time is a good habit.

We link to the stylesheet used to control the appearance of the calendar control, which is handled in this example by the sam skin within the <link> tag. Accordingly, we also need to add the appropriate class name to the <body> tag.

Following this, we link to the required library files with <script> tags; the calendar control is relatively simple and requires just the YAHOO, Document Object Model (DOM), and Event components (using the aggregated yahoo-dom-event.js file for efficiency), as well as the underlying source file calendar-min.js.

A brief <style> tag finishes the <head> section of the page with some CSS relevant to this particular example, and the <body> of the page at this stage contains just two <div> elements: the first holds a <label>, text field, and a calendar icon (which can be used to launch the control), while the second holds the calendar control. When viewed in a browser, the page at this point should appear like this:

Implementing a Calendar Control in the Yahoo User Interface (YUI)


The calendar icon used in this example was taken, with gratitude from Mark Carson at http://markcarson.com.

Beginning the Scripting

We want the calendar to appear when the icon next to the text field is clicked, rather than it being displayed on the page-load, so the first thing we need to do is to set a listener for the click event on the image.

Directly before closing </body> tag, add the following code:

<script type="text/javascript">
//create the namespace object for this example
YAHOO.namespace("yuibook.calendar");
//define the lauchCal function which creates the calendar
YAHOO.yuibook.calendar.launchCal = function() {
}
//create calendar on page load
YAHOO.util.Event.onDOMReady(YAHOO.yuibook.calendar.launchCal);
</script>

Let's look at each line of the above code. We first use the .namespace() method of the YAHOO utility to set up the namespace object used for this example. Next we define the anonymous launchCal function, which will hold all of the code that generates the calendar control.

Then we use the .onDOMReady() method of the Event utility to execute the launchCal function when the DOM is in an usable state. We'll be looking at the DOM utility in much greater detail later in the book.

Now we can add the extremely brief code that's required to actually produce the Calendar. Within the braces of our anonymous function, add the following code:

//create the calendar object, specifying the container
Var myCal = new YAHOO.widget.Calendar("mycal");
//draw the calendar on screen
myCal.render();
//hide it again straight away
myCal.hide();

This is all that we need to create the Calendar; we simply define myCal as a new Calendar object, specifying the underlying container HTML element as an argument of the constructor.

Once we have a Calendar object, we can call the .render() method on it to create the calendar and display it on the page. No arguments are required for this method. Since we want the calendar to be displayed when its icon is clicked, we hide the calendar from view straight away.

To display the calendar when the icon for it is clicked, we'll need one more anonymous function. Add the following code beneath the .hide() method:

//define the showCal function which shows the calendar
Var showCal = function() {
//show the calendar
myCal.show();
}

Now we can attach a listener which detects the click event on the calendar icon:

//attach listener for click event on calendar icon
YAHOO.util.Event.addListener("calico", "click", showCal);

Save the file that we've just created as calendar.html or similar in your yuisite directory. If you view it in your browser now and click the Calendar icon, you should see this:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

The calendar is automatically configured to display the current date, although this is something that can be changed using the configuration object mentioned earlier.

If you use a DOM explorer to view the current DOM of a page with an open calendar on it, you'll see that a basic Calendar control is rendered as a table with eight rows and seven columns.

The first row contains the images used to navigate between previous or forthcoming months and the title of the current month and year. The next row holds the two-letter representations of each of the different days of the week, and the rest of the rows hold the squares representing the individual days of the current month. The screenshot on the next page show some of the DOM representation of the Calendar control used in our example page:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

Now that we can call up the Calendar control by clicking on our Calendar icon, we need to customize it slightly. Unless the person completing the form is very young, they will need to navigate through a large number of calendar pages in order to find their date of birth. This is where the Calendar Navigator interface comes into play.

We can easily enable this feature using a configuration object passed into the Calendar constructor. Alter your code so that it appears as follows:

//create the calendar object, using container & config object
myCal = new YAHOO.widget.Calendar("mycal", {navigator:true});

Clicking on the Month or Year label will now open an interface which allows your visitors to navigate directly to any given month and year:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

The configuration object can be used to set a range of calendar configuration properties including the original month and year displayed by the Calendar, the minimum and maximum dates available to the calendar, a title for the calendar, a close button, and various other properties.

Learning the Yahoo! User Interface library Develop your next generation web applications with the YUI JavaScript development library
Published: March 2008
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Let's update our Calendar instance so that it features a title and a close button. Add the following properties to the literal object in our constructor:

//create the calendar object, specifying the container and a literal
//configuration object
myCal = new YAHOO.widget.Calendar("mycal",
{navigator:true, title:"Choose your Date Of Birth", close:true});

This is what our Calendar should now look like:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

Configuration properties like those we have just set, can also be set outside of the constructor using the .queueProperty() and .fireQueue() methods, or by using the .setProperty() method. Let's use these to alter our Calendar so that the first column header is set to Monday instead of Sunday. Add the following code directly before the call to the .render() method:

//configure the calendar to begin on Monday
myCal.cfg.setProperty("start_weekday", "1");

When the calendar is displayed now, Monday will be the first day instead of Sunday:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

Finally, we need to add some additional code that will allow the date that is selected to be inserted into the text field. We can do this using some of the custom events defined by the calendar classes.

Highly Eventful

Both the Calendar and CalendarGroup classes have a series of custom events defined for them which allow for easily listening and reacting to interesting moments during any calendar or calendar group interaction.

The two classes both have the same set of events defined for them, including:

  • beforeDeselectEvent: Fired before a cell is deselected, allowing you to abort the operation if needed
  • beforeHideEvent: Fired just before the calendar is hidden
  • beforeHideNavEvent: Fired just before the calendar navigator is hidden
  • beforeRenderEvent: Fired before the calendar is drawn on screen
  • beforeSelectEvent: Fired before a cell is selected
  • beforeShowEvent: Fired just before the calendar is shown
  • beforeShowNavEvent: Fired just before the calendar navigator is shown
  • changePageEvent: Fired once the current calendar page has been changed
  • clearEvent: Fired once the calendar has been cleared
  • deselectEvent: Fired once the cell has been deselected
  • hideEvent: Fired once the calendar has been hidden
  • hideNavEvent: Fired once the calendar navigator has been hidden
  • renderEvent: Fired once the calendar has been drawn on screen
  • resetEvent: Fired once the calendar has been reset
  • selectEvent: Fired once a cell, or range of cells, has been selected
  • showEvent: Fired once the calendar has been shown
  • showNavEvent: Fired once the calendar navigator has been shown

This rich event system allows you to easily watch for cells being selected or deselected, month panel changes, render events, or even the reset method being called, and add code to deal with these key moments effectively. As you can see, most of the events form pairs of before and after events, which allows you to easily cancel or abort an operation before it has any visual impact.

Let's now take a look at how these custom Calendar events can be used. First define the function that will handle the select event; add the following code directly after the showCall() function:

//attach listener for click event on calendar icon
YAHOO.util.Event.addListener("calico", "click", showCal);
//define the ripDate function which gets the selected date
var ripDate = function(type, args) {
}
//subscribe to the select event on Calendar cells
myCal.selectEvent.subscribe(ripDate);

The type and args objects are automatically created by the control; the args object is what we are interested in here, because it gives us easy access to an array of information about our Calendar.

Now, within the curly braces of the ripDate() function set the following variables:

//get the date components
Var dates = args[0];
Var date = dates[0];
Var theYear = date[0];
Var theMonth = date[1];
Var theDay = date[2];

The first item in the args array is an array of selected dates, so we first save this to the variable dates. As this is a single-select calendar, only the first item of the dates array will contain data, so this is also saved to a variable: the date variable.

Each date is itself an array, with the first item corresponding to the year, the second item equaling the month, and the third item mapped to the individual date. All of these values are saved into variables.

Var theDate = theMonth + "/" + theDay + "/" + theYear;

This part of the function uses standard concatenation techniques to build a string containing the individual date components in the format in which we want to present them (so that, for example, it would be extremely easy to express dates in UK format, where the date appears before the month):

//get a reference to the text field
Var field = YAHOO.util.Dom.get("dobfield");
//insert the formatted date into the text field
field.value = theDate;
//hide the calendar once more
myCal.hide();

Finally, we use the very handy DOM utility's .get() method to grab a reference to the text field, set the value of the text field to our date string, and then hide the calendar once more.

Save the file once more and view it again in your browser of choice. After clicking the Calendar icon and choosing a date, it should be displayed in the text field:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

At this point, we can take a brief look at how we can override the default styling of the calendar. I think we should change the calendar's close button and make it look a little more like a traditional close button. This can be done with the following simple CSS rule, which should be inserted into the <style> tag in the <head> of our document:

.yui-skin-sam .yui-calcontainer .calclose {
background:url("icons/myclose.gif") no-repeat;
}

Because we're using the default sam skin, we should begin the selector with this class name and then target the name of the container and close elements. Other elements of the calendar, such as the navigation arrows, can easily be styled in this way. Using a DOM explorer to expose the names of other parts of the calendar is also an easy way to change other elements of the calendar. Our Close button should now appear like this:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

The DateMath Class

In addition to the two classes catering for two different types of calendar, a class, YAHOO.widget.DateMath, defines a series of utilities for performing simple mathematical calculations or comparisons on dates. It has only a small number of static properties and a small set of methods. There are no events defined in this class and no configuration attributes.

All of its methods return either a Boolean value indicating whether the comparison was true or false, or a modified date object. Some of them will be used very frequently, while others will be used only rarely (but are still very useful).

Our date of birth calendar isn't really appropriate for seeing how the DateMath calls can be used. In order to examine some of the available methods, we should create a new calendar. In a blank page of your text editor, begin with the following HTML:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html;
charset=utf-8">
<title>YUI MathDate Class Example</title>
<link rel="stylesheet"
type="text/css"
href="yui/build/calendar/assets/skins/sam/calendar.css">
<script type="text/javascript"
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="yui/build/yahoo-dom-event/yahoo-dom-event.js">
</script>
<script type="text/javascript"
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="yui/build/calendar/calendar-min.js"></script>
</head>
<body class="yui-skin-sam">
<div id="mycal"></div>
<div id="results"></div>
</body>
</html>

This very simple page will form the basis of our example. Next, add the following <script> tag to the <body> tag of the page, directly below the results <div> tag:

<script type="text/javascript">
//create the namespace object for this example
YAHOO.namespace("yuibook.calendar");
//define the initCal function which creates the calendar
YAHOO.yuibook.calendar.initCal = function() {
}
//create calendar on page load
YAHOO.util.Event.onDOMReady(YAHOO.yuibook.calendar.initCal);
</script>

We create the same namespace object for this page and initially generate the calendar using the .onDOMReady() method and an anonymous function inexactly the same way as we did before. Next, add the following code to the YAHOO.yuibook.calendar.initCal() function:

//create the calendar object, specifying the container
var myCal = new YAHOO.widget.Calendar("mycal");
//draw the calendar on screen
myCal.render();

We create the calendar in the same way as in the previous example and render it on the page. This time, we don't need to worry about hiding it again as it will be a permanent fixture of the page.

Before we start looking at the DateMath methods, let's get a reference to the current date. Add the following code directly below the .render() method call:

//get and display today's date
var dayNum = myCal.today.getDay();
var dayString = myCal.Locale.WEEKDAYS_LONG[dayNum];
var date = myCal.today.getDate();
var monthNum = myCal.today.getMonth();
var monthString = myCal.Locale.MONTHS_LONG[monthNum];
var year = myCal.today.getFullYear();
var results1 = document.createElement("div");
results1.innerHTML = "Today is " + dayString + ", " + date + "
" + monthString + " " + year;
YAHOO.util.Dom.get("results").appendChild(results1);

It is easy to obtain today's date in UTC format using the today property of the Calendar class. Once we have this, we can get references to the date and month numerical representations and from these we can get the full day name and month name using Locale.WEEKDAYS_LONG[dayNum] and Locale.MONTHS_LONG[monthNum].

The Locale object is automatically created by the control and contains localized day and month names. It is primarily used to add new locales and specify alternative day and month names, but because it defaults to English, we can simply read the properties and pull out what we want.

Once we have the information we need, it is simple enough to create a new <div> element, populate it with our formatted date string and then attach it to our results <div> element. Your page should look similar to the following screenshot:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

Now we can have some fun with a few of the DateMath methods. First, add the following directly beneath our last block of code:

//work out date in 10 days time
var futureDate = YAHOO.widget.DateMath.add(myCal.today,
YAHOO.widget.DateMath.DAY, 10);
var results2 = document.createElement("div");
results2.innerHTML = "In ten days time it will be " + futureDate;
YAHOO.util.Dom.get("results").appendChild(results2);

We can use the .add() method of the YAHOO.widget.DateMath class to add a specified amount of time to a date object. In this example, the date object is obtained using the myCal.today property once more (as we can't use the date variable that already exists as this is a number not a full date object), but any date object could be used.

The .add() method takes three arguments. The first is the date object on which the addition should be carried out, the second is one of the built-in field constants representing the unit to be added (which could be days, weeks, months, years), and the final argument is the actual amount to be added.

For the purposes of this example, I have left the futureDate field in full UTC format, but we could easily extract just the parts of the date that we want, just as we did to get the today date.

Let's now look at the almost identical .subtract() method. Add the following code:

//work out date two months ago
var pastDate = YAHOO.widget.DateMath.subtract(myCal.today,
YAHOO.widget.DateMath.MONTH, 2);
var results3 = document.createElement("div");
results3.innerHTML = "Two months ago the date was " + pastDate;
YAHOO.util.Dom.get("results").appendChild(results3);

You can see how easy the DateMath class makes addition and subtraction of date objects. The class has other useful methods such as the .getDayOffset() and .getWeekNumber() methods. We can expose the functionality of these two methods with the following code:

//work out day and week numbers of current date
var numberOfDays = YAHOO.widget.DateMath.getDayOffset(myCal.today,
year);
var weekNumber = YAHOO.widget.DateMath.getWeekNumber(myCal.today,
year);
results4 = document.createElement("div");
results4.innerHTML = numberOfDays + " days have elapsed so far this
year";
results5 = document.createElement("div");
results5.innerHTML = "We are in week number " + weekNumber;
YAHOO.util.Dom.get("results").appendChild(results4);
YAHOO.util.Dom.get("results").appendChild(results5);

Save the file as datemath.html and view it in your browser of choice:

Implementing a Calendar Control in the Yahoo User Interface (YUI)

Summary

In this article, we had a look at the basic Calendar class and the GroupCalendar class. Further, we had a look at the various custom events defined for the Calendar and CalendarGroup classes, which allow for listening and reacting to interesting moments during calendar or calendar group interaction. Next, we implemented a Calendar control in the YUI and also worked with one of its supporting classes: the DateMath class. This example has shown us how easy it is to implement YUI components.

 

Learning the Yahoo! User Interface library Develop your next generation web applications with the YUI JavaScript development library
Published: March 2008
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Dan Wellman

Dan Wellman is an author and frontend engineer living on the South Coast of the UK and working in London. By day he works for Skype and has a blast writing application-grade JavaScript. By night he writes books and tutorials focused mainly on frontend web development. He is also a staff writer for the Tuts+ arm of the Envato network, and occasionally writes for .Net magazine. He's the proud father of four amazing children, and the grateful husband of a wonderful wife.

Books From Packt

Learning the Yahoo! User Interface library
Learning the Yahoo! User Interface library

Building Powerful and Robust Websites with Drupal 6
Building Powerful and Robust Websites with Drupal 6

Building Websites with Joomla! v1.0
Building Websites with Joomla! v1.0

Smarty PHP Template Programming and Applications
Smarty PHP Template Programming and Applications

Joomla! Accessibility
Joomla! Accessibility

Drupal 5 Themes
Drupal 5 Themes

Learning Drupal 6 Module Development
Learning Drupal 6 Module Development

AJAX and PHP: Building Responsive Web Applications
AJAX and PHP: Building Responsive Web Applications


 

 

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software