YUI Library Home

Site Search (YDN & YUIBlog):

# YUI Library Examples: Calendar Control: Popup Calendar - Advanced

# Calendar Control: Popup Calendar - Advanced

The default Calendar/CalendarGroup controls do not provide positioning or dragdrop support natively, as the Container family's Overlay control and its subclasses do.

This example demonstrates how the Calendar control can be wrapped in a Container (a Dialog control in this case) which allows you to leverage Container family features to position the Calendar relative to a context element. It also show how you can setup click listeners on the document, to hide the dialog when the user clicks somewhere outside of the dialog.

View example in new window.

Date:

## Setting up the Calendar and Container

In this example, we'll see how we can leverage functionality present in the Container family's Dialog widget, to provide a more advanced popup Calendar, than the basic popup features which Calendar supports inherently.

- We'll use Dialog's `context` configuration property to position the Calendar relative to a calendar icon button.
- We also use Dialog's `buttons` property to provide a "Reset" button to set the calendar page to the selected date, and a more prominent "Close" button to hide the popup Calendar.
- We set the Dialog's `draggable` property to `false` for this example, however if the application required it, we could set `draggable` to `true` to get a draggable popup Calendar

The code we use to construct the Dialog which will hold the Calendar is shown below:

function resetHandler() { // Reset the current calendar page to the select date, or // to today if nothing is selected. var selDates = calendar.getSelectedDates(); var resetDate; if (selDates.length > 0) { resetDate = selDates[0]; } else { resetDate = calendar.today; } calendar.cfg.setProperty("pagedate", resetDate); calendar.render(); } function closeHandler() { dialog.hide(); } dialog = new YAHOO.widget.Dialog("container", { visible:false, context:["show", "tl", "bl"], buttons:[ {text:"Reset", handler: resetHandler, isDefault:true}, {text:"Close", handler: closeHandler}], draggable:false, close:true });

We don't set a width on the Dialog, so that it will shrink-wrap the Calendar, which does not have a specific width defined (the width of the calendar is controlled by the width of its contents).

The code to construct the Calendar is pretty straight forward, and is shown below:

calendar = new YAHOO.widget.Calendar("cal", { iframe:false, // Turn iframe off, since container has iframe support. hide_blank_weeks:true // Enable, to demonstrate how we handle changing height, using changeContent }); calendar.render();

For this example, both the Dialog and the Calendar are constructed lazily. That is, we don't construct them until the "calendar" button is clicked on for the first time.

### Container/Calendar Considerations

When creating a Calendar which is to be placed inside a Container control there are a few areas which require special attention.

1. Dialog Content Changes

   Whenever the contents of the Calendar are changed we fire Dialog's `changeContent` event so any of Dialog's rendered elements which need to be kept in sync are redrawn (such as the size of the shadow underlay for IE6/Safari2). We could optimize this, by checking for an actual change in dimensions before firing the `changeContent` event, using Calendar's `beforeRenderEvent` but the simpler approach is taken for the purposes of the example.

   The Calendar has `hide_blank_weeks` set to `true` to illustrate the fact that the shadow is resized when the height of the Calendar changes.

   calendar.renderEvent.subscribe(function() { // Tell Dialog it's contents have changed. dialog.fireEvent("changeContent"); });

   Since we're using the `yui-overlay-hidden` class to hide all tables in IE, while the container is hidden (see the discussion on border-collapse:collapse, below), we also fire the `changeContent` event for IE when showing the Dialog, to let it know that the tables have been re-shown, which may impact the height of the Dialog:

   dialog.showEvent.subscribe(function() { if (YAHOO.env.ua.ie) { // Since we're hiding the table using yui-overlay-hidden, we // want to let the dialog know that the content size has changed, // when shown dialog.fireEvent("changeContent"); } });

   NOTE: Normally if you were to change the contents of the Dialog's header, body or footer elements (e.g. using `dialog.setBody(...)`), `changeContent` would be fired automatically, but in this case, we're changing the contents of the Calendar, and not the body element directly so we need to inform the Dialog that something inside the body changed.

2. Handling Calendar's Float

   Since dialog has a form element, we'll use it to clear Calendar's float:left and allow the Dialog body element to wrap the Calendar.

   /* Clear calendar's float for browsers which support :after */ #container .bd form {clear:left}

   For IE6/7, we want to avoid activating `hasLayout` (e.g. `zoom:1;`) to clear the float for IE. If `hasLayout` was activated, the Dialog would not shrink-wrap the Calendar correctly in IE6/7 and we'd need to define a specific width for the Dialog, hence we use an element to clear the left float.

3. Double Iframe Shims

   Calendar's `iframe` property is set to `false` since the Dialog already provides iframe shim support and we want to avoid duplicating shims for performance reasons.

4. Workaround IE's `border-collapse:collapse` Issue

   IE6 and IE7 have a known issue related to collapsed table borders remaining visible even though the table's containing element has its `visibility` set to `hidden` (See Container known issues).

   Since the Sam skin Calendar uses `border-collapse:collapse` and the Dialog is hidden using `visibility:hidden`, we need to use the workaround mentioned in the known issues section above, to make sure Calendar's table borders get hidden when the Dialog is hidden. We use the `yui-overlay-hidden` class to define a rule which hides all tables, using `display:none`, when the container is hidden:

   /* Prevent border-collapse:collapse from bleeding through in IE6, IE7 */ #container_c.yui-overlay-hidden table { *display:none; }

### Hiding the Calendar

The example also shows how you can hide the dialog, when the user clicks on an area of the document outside of the dialog. A `click` listener is set up on the document, so it receives notification whenever the user clicks on the document. Inside the listener, we try to determine if the element the user clicked on (the event target) is inside the dialog's containing element (`dialog.element`) or the button which is used to display the dialog. It if is not, the dialog is hidden:

// Hide Calendar if we click anywhere in the document other than the calendar Event.on(document, "click", function(e) { var el = Event.getTarget(e); var dialogEl = dialog.element; if (el != dialogEl && !Dom.isAncestor(dialogEl, el) && el != showBtn && !Dom.isAncestor(showBtn, el)) { dialog.hide(); } });

As a side note, this example also shows how you can use the simpler version of the Calendar constructor, providing only the container id (available as of 2.4.0) and also how you can use Calendar's locale properties to create long date strings from a JavaScript Date object.

## Configuration for This Example

You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.

### Calendar Control Examples:

### More Calendar Control Resources:

- User's Guide (external)
- API Documentation
- Cheat Sheet PDF (external)

Copyright © 2010 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings