I created a jQuery plugin that converts a text field to a 3 drop down, datepicker. It allows the user to select a Day, Month and Year rather than type the date in an input box.
The original input element is hidden and a callback function is provided where the user can format the value for the input box. The id
and name
attributes are replaced by the original name and id of the element postfixed with Day
, Month
and Year
respectively.
I would like your inputs on the code below. It may be anything from "writing better comments", "architectural improvements" to "performance improvements" or anything that comes to your mind.
JavaScript
/**
jQuery Date picker.
Convert a text box into a 3 drop down date picker with day, month and year as
drop downs.
Allowed Parameters:
startDate: restrict the user to this Start date.
endDate: restrict the user to this End date.
dateFormat: a function that returns a string that will be used to fill the
hidden input box.
Gautham PJ
*/
(function ($) {
'use strict';
// The function that handles the Datepicker.
$.fn.datepicker = function (userOptions) {
var $this,
$dayElement,
$monthElement,
$yearElement,
// Keep track of the Months and the number of days in them.
MONTHS = [
{ month: 0, name: 'January', days: 31 },
{ month: 1, name: 'February', days: 28 },
{ month: 2, name: 'March', days: 31 },
{ month: 3, name: 'April', days: 30 },
{ month: 4, name: 'May', days: 31 },
{ month: 5, name: 'June', days: 30 },
{ month: 6, name: 'July', days: 31 },
{ month: 7, name: 'August', days: 31 },
{ month: 8, name: 'September', days: 30 },
{ month: 9, name: 'October', days: 31 },
{ month: 10, name: 'November', days: 30 },
{ month: 11, name: 'December', days: 31 }
],
// The default options for the plugin.
defaults = {
startDate: new Date(),
endDate: new Date(),
'class': 'datepicker',
dateFormat: function (day, month, year) {
return day + '/' + month + '/' + year;
}
},
// Merge the default and User options into "options".
options = $.extend({}, defaults, userOptions),
// Create the Day, Month and Year drop downs necessary for the
// Date picker and add it to the page before the selected element.
createHTMLElements = function () {
var name = $this.prop('name');
$dayElement = $('<select>')
.prop({ id: name + 'Day', name: name + 'Day' })
.addClass(options.class + ' ' + name + 'Day');
$monthElement = $('<select>')
.prop({ id: name + 'Month', name: name + 'Month' })
.addClass(options.class + ' ' + name + 'Month');
$yearElement = $('<select>')
.prop({ id: name + 'Year', name: name + 'Year' })
.addClass(options.class + ' ' + name + 'Year');
$this.before($dayElement);
$this.before($monthElement);
$this.before($yearElement);
},
// Check if the Starting Year has been selected.
isStartYearSelected = function () {
return $yearElement.val() == options.startDate.getFullYear();
},
// Check if the Ending Year hsa been selected.
isEndYearSelected = function () {
return $yearElement.val() == options.endDate.getFullYear();
},
// Check if the Starting Month has been selected.
isStartMonthSelected = function () {
return $monthElement.val() == options.startDate.getMonth();
},
// Check if the Ending Month has been selected.
isEndMonthSelected = function () {
return $monthElement.val() == options.endDate.getMonth();
},
// Check if the drop down contains the value that needs to be selected.
selectValueIfExists = function ($element, value) {
if (value) {
if ($element.find('option[value=' + value + ']').length > 0) {
$element.val(value);
}
}
},
// Populate the Year drop down with the values or Options.
populateYear = function () {
var i,
$option,
previousSlectedValue = $yearElement.val();
$yearElement.empty();
for (i = options.startDate.getFullYear();
i <= options.endDate.getFullYear(); i++) {
$option = $('<option>').val(i).text(i);
$yearElement.append($option);
}
selectValueIfExists($yearElement, previousSlectedValue);
},
// Populate the Month values based on the selected year.
populateMonth = function () {
var i,
startMonth = 0,
endMonth = 11,
$option,
previousSlectedValue = $monthElement.val();
// Check for Leap Year
if (parseInt($yearElement.val(), 10) % 4 === 0) {
MONTHS[1].days = 29;
} else {
MONTHS[1].days = 28;
}
// Check for the Start and End Year and limit the Selectable days.
if (isStartYearSelected()) {
startMonth = options.startDate.getMonth();
}
if (isEndYearSelected()) {
endMonth = options.endDate.getMonth();
}
// Empty and Populate the Month field.
$monthElement.empty();
for (i = startMonth; i <= endMonth; i++) {
$option = $('<option>').val(i).text(MONTHS[i].name);
$monthElement.append($option);
}
selectValueIfExists($monthElement, previousSlectedValue);
},
// Populate the Day drop down based on the month and year selected.
populateDay = function () {
var i,
startDay = 1,
endDay = MONTHS[$monthElement.val()].days,
$option,
previousSlectedValue = $dayElement.val();
if (isStartYearSelected() && isStartMonthSelected()) {
startDay = options.startDate.getDate();
}
if (isEndYearSelected() && isEndMonthSelected()) {
endDay = options.endDate.getDate();
}
$dayElement.empty();
for (i = startDay; i <= endDay; i++) {
$option = $('<option>').val(i).text(i);
$dayElement.append($option);
}
selectValueIfExists($dayElement, previousSlectedValue);
},
// Update the drop down values.
update = function () {
populateYear();
populateMonth();
populateDay();
if (typeof options.dateFormat === 'function') {
var value = options.dateFormat.call($this, $dayElement.val(),
parseInt($monthElement.val(), 10) + 1, $yearElement.val());
$this.val(value);
}
},
// Initialize the components and perform the necessary steps to
// get the Date picker ready.
init = function () {
options.startDate.setFullYear(
parseInt(options.startDate.getFullYear(), 10) - 30
);
createHTMLElements();
$this.hide();
update();
// Add Event Handlers for all the elements.
$yearElement.change(update);
$monthElement.change(update);
$dayElement.change(update);
};
// Return the selected element for jQuery Chaining.
return this.each(function () {
$this = $(this);
init();
});
};
}(jQuery));
HTML
<input type="text" name="dob" id="dob" />
To call the plugin in the HTML page
$(function () {
'use strict';
$('#dob').datepicker();
});