David Janes' Code Weblog

December 25, 2009

Make INPUT fields select dates using the YUI Calendar Control

code fragments,javascript,tips,yui · David Janes · 3:57 pm ·

Here’s a lengthy Javascript code segment that can be dropped into any of your existing forms that provide for a date selection range. It has the following functionality:

  • clicking a date field pops up a YUI Calendar control to change the date
  • the date field is made read only by this code
  • pressing ESC while a Calendar is displaying dismisses it
  • pressing DEL while a Calendar is displaying clears the input field
  • there is an Input field for the start date and an Input field for the end date
  • you cannot make the end date before the start date, and you cannot make the start date after the end date
  • that the dates are optional
  • dates are displayed in the standard ISO YYYY-MM-DD format

This code sample demonstrates:

  • the YUI Calendar control, including
    • setting the date in the control
    • getting the date from the control (after selection)
    • dynamically displaying and hiding the control
    • manipulating ISO dates into the format that YUI requires
    • setting min and max dates on the fly – specifically, this shows you how to manipulate YUI “config” parameters which the documentation implies are readonly (look for functions in source code named like configMinDate)
    • simple YUI animations (to show that a field value has been changed)
    • detecting keystrokes (DEL and ESC) using YUI
    • adding functionality using Javascript, after the DOM loads

    This assumes:

    • you have an Input field for the start date with DOM id="id_event_start"
    • you have an Input field for the end date with DOM id="id_event_end"
    • that the Form (or a parent element of the Form, up to Body) has DOM class="yui-skin-sam"

    Add the following Script inclusions to your HTML (note: not all of these are probably needed, and there’s more efficient ways to include YUI JS, especially for production deployments):

    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/json/json-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/event/event-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/connection/connection-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/dom/dom-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/element/element-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/button/button-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/dragdrop/dragdrop-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/container/container-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/container/container_core-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/calendar/calendar-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/animation/animation-min.js"></script>
    

    Add the following CSS inclusions to your HTML:

    <link rel="stylesheet" type="text/css"
     href="http://yui.yahooapis.com/2.8.0r4/build/button/assets/skins/sam/button.css" />
    <link rel="stylesheet" type="text/css"
     href="http://yui.yahooapis.com/2.8.0r4/build/container/assets/skins/sam/container.css" />
    <link rel="stylesheet" type="text/css"
     href="http://yui.yahooapis.com/2.8.0r4/build/calendar/assets/skins/sam/calendar.css" />
    

    Add the following CSS to your HTML:

    <style type="text/css">
    
    #id_calendar {
     position: absolute;
     z-index: 15;
    }
    .yui-skin-sam .yui-panel .bd, .yui-skin-sam .yui-panel .ft {
     background-color:#FFFFFF;
    }
    </style>
    

    Add the following HTML fragment:

    <div id="id_calendar_wrapper">
     <div id="id_calendar"></div>
    </div>
    

    And finally, here’s the JS that makes it all work

    <script type="text/javascript">
    calendar_js = {
     c : null,
     start_e : null,
     end_e : null,
     current_e : 0,
     supress : 0,
    
     create : function() {
     calendar_js.start_e = YAHOO.util.Dom.get("id_event_start");
     calendar_js.end_e = YAHOO.util.Dom.get("id_event_end");
    
     YAHOO.util.Event.addListener(calendar_js.start_e, "click", calendar_js.onclick, this);
     YAHOO.util.Event.addListener(calendar_js.end_e, "click", calendar_js.onclick, this);
    
     YAHOO.util.Dom.get(calendar_js.start_e).readOnly = true;
     YAHOO.util.Dom.get(calendar_js.end_e).readOnly = true;
    
     (new YAHOO.util.KeyListener(document, { keys:27 }, { fn:calendar_js.onesc })).enable();
     (new YAHOO.util.KeyListener(document, { keys:8 }, { fn:calendar_js.ondel })).enable();
     },
    
     onesc : function() {
     calendar_js.current_e = null;
     if (calendar_js.c) {
     calendar_js.c.hide();
     }
    
     },
    
     ondel : function() {
     if (calendar_js.current_e) {
     calendar_js.current_e.value = "";
     calendar_js.current_e = null;
     }
     if (calendar_js.c) {
     calendar_js.c.hide();
     }
    
     },
    
     toydate : function(d) {
     if (!d) {
     return null;
     }
     if (d.value) {
     d = d.value;
     }
     if (d && d.length) {
     d = d.replace(/(\d\d\d\d)-(\d\d)-(\d\d)/, "$2/$3/$1");
     if (d.indexOf('/') == 2) {
     return d;
     }
     }
     return null;
     },
    
     onclick : function(evt, obj) {
     var e_e = YAHOO.util.Event.getTarget(evt);
    
     if (calendar_js.c == null) {
     calendar_js.c = new YAHOO.widget.Calendar(null, "id_calendar");
     calendar_js.c.render();
    
     calendar_js.c.selectEvent.subscribe(calendar_js.ondate, calendar_js.c, true);
     }
    
     var c_e = YAHOO.util.Dom.get("id_calendar");
     if (calendar_js.current_e == e_e) {
     calendar_js.current_e = null;
     calendar_js.c.hide();
     } else {
     YAHOO.util.Dom.setAttribute(c_e, "display", "block");
     calendar_js.current_e = e_e;
    
     var region = YAHOO.util.Region.getRegion(e_e);
    
     calendar_js.c.show();
    
     if (e_e.value.length) {
     var d = calendar_js.toydate(e_e);
     if (d) {
     calendar_js.supress = 1;
     calendar_js.c.select(d);
     }
     }
    
     if (e_e == calendar_js.start_e) {
     var d = calendar_js.toydate(calendar_js.end_e);
     if (d) {
     calendar_js.c.configMaxDate(null, [ d ], null);
     calendar_js.c.configMinDate(null, [ "01/01/1970" ], null);
     }
     } else {
     var d = calendar_js.toydate(calendar_js.start_e);
     if (d) {
     calendar_js.c.configMinDate(null, [ d ], null);
     calendar_js.c.configMaxDate(null, [ "01/01/2200" ], null);
     }
     }
    
     calendar_js.c.render();
     YAHOO.util.Dom.setXY(c_e, [ region.right + 2, region.top ]);
     }
     },
    
     ondate : function(type, args, obj) {
     if (calendar_js.supress) {
     calendar_js.supress = 0;
     return;
     }
    
     var date = this.toDate(args[0][0]);
    
     var year = "" + date.getFullYear();
     var month = "" + ( 1 + date.getMonth() );
     while (month.length < 2) {
     month = "0" + month;
     }
     var day = "" + date.getDate();
     while (day.length < 2) {
     day = "0" + day;
     }
    
     var animate = new YAHOO.util.ColorAnim(calendar_js.current_e,
     {backgroundColor: { from: '#ffff99', to: '#FFFFFF' } }
     );
     animate.duration = 0.75;
     animate.method = YAHOO.util.Easing.easeOut;
     animate.animate();
    
     calendar_js.current_e.value = year + "-" + month + "-" + day;
     calendar_js.c.hide();
     calendar_js.current_e = null;
     },
    
     end : 0
    };
    YAHOO.util.Event.onDOMReady(calendar_js.oninit);
    </script>
    

    Notes:

    • no apologies for verboseness – I write code so I can understand it in 24 months time
    • my original code is a lot more “tabby” – I flattened to a single space so they’d fit in the space constraints here
    • the code should be fairly self explanatory if you step through it – the hard stuff is probably YUI weirdness and you can probably just accept that “that’s just the way it is”

Powered by WordPress

Switch to our mobile site