/* jQuery UI Date Picker v3.4.3 (previously jQuery Calendar)
Written by Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au).
Copyright (c) 2007 Marc Grabanski (http://marcgrabanski.com/code/ui-datepicker)
Dual licensed under the MIT (MIT-LICENSE.txt)
and GPL (GPL-LICENSE.txt) licenses.
Date: 09-03-2007 */
;(function($) { // hide the namespace
/* Date picker manager.
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
Settings for (groups of) date pickers are maintained in an instance object
(DatepickerInstance), allowing multiple different settings on the same page. */
function Datepicker() {
this.debug = false; // Change this to true to start debugging
this._nextId = 0; // Next ID for a date picker instance
this._inst = []; // List of instances indexed by ID
this._curInst = null; // The current instance in use
this._disabledInputs = []; // List of date picker inputs that have been disabled
this._datepickerShowing = false; // True if the popup picker is showing , false if not
this._inDialog = false; // True if showing within a "dialog", false if not
this.regional = []; // Available regional settings, indexed by language code
this.regional[''] = { // Default regional settings
clearText: 'Clear', // Display text for clear link
clearStatus: 'Erase the current date', // Status text for clear link
closeText: 'Close', // Display text for close link
closeStatus: 'Close without change', // Status text for close link
prevText: '<Prev', // Display text for previous month link
prevStatus: 'Show the previous month', // Status text for previous month link
nextText: 'Next>', // Display text for next month link
nextStatus: 'Show the next month', // Status text for next month link
currentText: 'Today', // Display text for current month link
currentStatus: 'Show the current month', // Status text for current month link
monthNames: ['January','February','March','April','May','June',
'July','August','September','October','November','December'], // Names of months for drop-down and formatting
monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
monthStatus: 'Show a different month', // Status text for selecting a month
yearStatus: 'Show a different year', // Status text for selecting a year
weekHeader: 'Wk', // Header for the week of the year column
weekStatus: 'Week of the year', // Status text for the week of the year column
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
dateStatus: 'Select DD, M d', // Status text for the date selection
dateFormat: 'mm/dd/yy', // See format options on parseDate
firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
initStatus: 'Select a date', // Initial Status text on opening
isRTL: false // True if right-to-left language, false if left-to-right
};
this._defaults = { // Global defaults for all the date picker instances
showOn: 'focus', // 'focus' for popup on focus,
// 'button' for trigger button, or 'both' for either
showAnim: 'show', // Name of jQuery animation for popup
defaultDate: null, // Used when field is blank: actual date,
// +/-number for offset from today, null for today
appendText: '', // Display text following the input box, e.g. showing the format
buttonText: '...', // Text for trigger button
buttonImage: '', // URL for trigger button image
buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
closeAtTop: true, // True to have the clear/close at the top,
// false to have them at the bottom
mandatory: false, // True to hide the Clear link, false to include it
hideIfNoPrevNext: false, // True to hide next/previous month links
// if not applicable, false to just disable them
changeMonth: true, // True if month can be selected directly, false if only prev/next
changeYear: true, // True if year can be selected directly, false if only prev/next
yearRange: '-10:+10', // Range of years to display in drop-down,
// either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
changeFirstDay: true, // True to click on day name to change, false to remain as set
showOtherMonths: false, // True to show dates in other months, false to leave blank
showWeeks: false, // True to show week of the year, false to omit
calculateWeek: this.iso8601Week, // How to calculate the week of the year,
// takes a Date and returns the number of the week for it
shortYearCutoff: '+10', // Short year values < this are in the current century,
// > this are in the previous century,
// string value starting with '+' for current year + value
showStatus: false, // True to show status bar at bottom, false to not show it
statusForDate: this.dateStatus, // Function to provide status text for a date -
// takes date and instance as parameters, returns display text
minDate: null, // The earliest selectable date, or null for no limit
maxDate: null, // The latest selectable date, or null for no limit
speed: 'normal', // Speed of display/closure
beforeShowDay: null, // Function that takes a date and returns an array with
// [0] = true if selectable, false if not,
// [1] = custom CSS class name(s) or '', e.g. $.datepicker.noWeekends
beforeShow: null, // Function that takes an input field and
// returns a set of custom settings for the date picker
onSelect: null, // Define a callback function when a date is selected
onClose: null, // Define a callback function when the datepicker is closed
numberOfMonths: 1, // Number of months to show at a time
stepMonths: 1, // Number of months to step back/forward
rangeSelect: false, // Allows for selecting a date range on one date picker
rangeSeparator: ' - ' // Text between two dates in a range
};
$.extend(this._defaults, this.regional['']);
this._datepickerDiv = $('
');
}
$.extend(Datepicker.prototype, {
/* Class name added to elements to indicate already configured with a date picker. */
markerClassName: 'hasDatepicker',
/* Debug logging (if enabled). */
log: function () {
if (this.debug)
console.log.apply('', arguments);
},
/* Register a new date picker instance - with custom settings. */
_register: function(inst) {
var id = this._nextId++;
this._inst[id] = inst;
return id;
},
/* Retrieve a particular date picker instance based on its ID. */
_getInst: function(id) {
return this._inst[id] || id;
},
/* Override the default settings for all instances of the date picker.
@param settings object - the new settings to use as defaults (anonymous object)
@return the manager object */
setDefaults: function(settings) {
extendRemove(this._defaults, settings || {});
return this;
},
/* Attach the date picker to a jQuery selection.
@param target element - the target input field or division or span
@param settings object - the new settings to use for this date picker instance (anonymous) */
_attachDatepicker: function(target, settings) {
// check for settings on the control itself - in namespace 'date:'
var inlineSettings = null;
for (attrName in this._defaults) {
var attrValue = target.getAttribute('date:' + attrName);
if (attrValue) {
inlineSettings = inlineSettings || {};
try {
inlineSettings[attrName] = eval(attrValue);
} catch (err) {
inlineSettings[attrName] = attrValue;
}
}
}
var nodeName = target.nodeName.toLowerCase();
var instSettings = (inlineSettings ?
$.extend(settings || {}, inlineSettings || {}) : settings);
if (nodeName == 'input') {
var inst = (inst && !inlineSettings ? inst :
new DatepickerInstance(instSettings, false));
this._connectDatepicker(target, inst);
} else if (nodeName == 'div' || nodeName == 'span') {
var inst = new DatepickerInstance(instSettings, true);
this._inlineDatepicker(target, inst);
}
},
/* Detach a datepicker from its control.
@param target element - the target input field or division or span */
_destroyDatepicker: function(target) {
var nodeName = target.nodeName.toLowerCase();
var calId = target._calId;
target._calId = null;
var $target = $(target);
if (nodeName == 'input') {
$target.siblings('.datepicker_append').replaceWith('').end()
.siblings('.datepicker_trigger').replaceWith('').end()
.removeClass(this.markerClassName)
.unbind('focus', this._showDatepicker)
.unbind('keydown', this._doKeyDown)
.unbind('keypress', this._doKeyPress);
var wrapper = $target.parents('.datepicker_wrap');
if (wrapper)
wrapper.replaceWith(wrapper.html());
} else if (nodeName == 'div' || nodeName == 'span')
$target.removeClass(this.markerClassName).empty();
if ($('input[_calId=' + calId + ']').length == 0)
// clean up if last for this ID
this._inst[calId] = null;
},
/* Enable the date picker to a jQuery selection.
@param target element - the target input field or division or span */
_enableDatepicker: function(target) {
target.disabled = false;
$(target).siblings('button.datepicker_trigger').each(function() { this.disabled = false; }).end()
.siblings('img.datepicker_trigger').css({opacity: '1.0', cursor: ''});
this._disabledInputs = $.map(this._disabledInputs,
function(value) { return (value == target ? null : value); }); // delete entry
},
/* Disable the date picker to a jQuery selection.
@param target element - the target input field or division or span */
_disableDatepicker: function(target) {
target.disabled = true;
$(target).siblings('button.datepicker_trigger').each(function() { this.disabled = true; }).end()
.siblings('img.datepicker_trigger').css({opacity: '0.5', cursor: 'default'});
this._disabledInputs = $.map($.datepicker._disabledInputs,
function(value) { return (value == target ? null : value); }); // delete entry
this._disabledInputs[$.datepicker._disabledInputs.length] = target;
},
/* Is the first field in a jQuery collection disabled as a datepicker?
@param target element - the target input field or division or span
@return boolean - true if disabled, false if enabled */
_isDisabledDatepicker: function(target) {
if (!target)
return false;
for (var i = 0; i < this._disabledInputs.length; i++) {
if (this._disabledInputs[i] == target)
return true;
}
return false;
},
/* Update the settings for a date picker attached to an input field or division.
@param target element - the target input field or division or span
@param name string - the name of the setting to change or
object - the new settings to update
@param value any - the new value for the setting (omit if above is an object) */
_changeDatepicker: function(target, name, value) {
var settings = name || {};
if (typeof name == 'string') {
settings = {};
settings[name] = value;
}
if (inst = this._getInst(target._calId)) {
extendRemove(inst._settings, settings);
this._updateDatepicker(inst);
}
},
/* Set the dates for a jQuery selection.
@param target element - the target input field or division or span
@param date Date - the new date
@param endDate Date - the new end date for a range (optional) */
_setDateDatepicker: function(target, date, endDate) {
if (inst = this._getInst(target._calId)) {
inst._setDate(date, endDate);
this._updateDatepicker(inst);
}
},
/* Get the date(s) for the first entry in a jQuery selection.
@param target element - the target input field or division or span
@return Date - the current date or
Date[2] - the current dates for a range */
_getDateDatepicker: function(target) {
var inst = this._getInst(target._calId);
return (inst ? inst._getDate() : null);
},
/* Handle keystrokes. */
_doKeyDown: function(e) {
var inst = $.datepicker._getInst(this._calId);
if ($.datepicker._datepickerShowing)
switch (e.keyCode) {
case 9: $.datepicker._hideDatepicker(null, '');
break; // hide on tab out
case 13: $.datepicker._selectDay(inst, inst._selectedMonth, inst._selectedYear,
$('td.datepicker_daysCellOver', inst._datepickerDiv)[0]);
return false; // don't submit the form
break; // select the value on enter
case 27: $.datepicker._hideDatepicker(null, inst._get('speed'));
break; // hide on escape
case 33: $.datepicker._adjustDate(inst,
(e.ctrlKey ? -1 : -inst._get('stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
break; // previous month/year on page up/+ ctrl
case 34: $.datepicker._adjustDate(inst,
(e.ctrlKey ? +1 : +inst._get('stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
break; // next month/year on page down/+ ctrl
case 35: if (e.ctrlKey) $.datepicker._clearDate(inst);
break; // clear on ctrl+end
case 36: if (e.ctrlKey) $.datepicker._gotoToday(inst);
break; // current on ctrl+home
case 37: if (e.ctrlKey) $.datepicker._adjustDate(inst, -1, 'D');
break; // -1 day on ctrl+left
case 38: if (e.ctrlKey) $.datepicker._adjustDate(inst, -7, 'D');
break; // -1 week on ctrl+up
case 39: if (e.ctrlKey) $.datepicker._adjustDate(inst, +1, 'D');
break; // +1 day on ctrl+right
case 40: if (e.ctrlKey) $.datepicker._adjustDate(inst, +7, 'D');
break; // +1 week on ctrl+down
}
else if (e.keyCode == 36 && e.ctrlKey) // display the date picker on ctrl+home
$.datepicker._showDatepicker(this);
},
/* Filter entered characters - based on date format. */
_doKeyPress: function(e) {
var inst = $.datepicker._getInst(this._calId);
var chars = $.datepicker._possibleChars(inst._get('dateFormat'));
var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
return e.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
},
/* Attach the date picker to an input field. */
_connectDatepicker: function(target, inst) {
var input = $(target);
if (input.is('.' + this.markerClassName))
return;
var appendText = inst._get('appendText');
var isRTL = inst._get('isRTL');
if (appendText) {
if (isRTL)
input.before('' + appendText);
else
input.after('' + appendText);
}
var showOn = inst._get('showOn');
if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
input.focus(this._showDatepicker);
if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
input.wrap('');
var buttonText = inst._get('buttonText');
var buttonImage = inst._get('buttonImage');
var trigger = $(inst._get('buttonImageOnly') ?
$('').addClass('datepicker_trigger').attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
$('