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
ESCwhile a Calendar is displaying dismisses it - pressing
DELwhile 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-DDformat
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”