PageSourceSearch

https://www.canaltrust.org/wp-content/plugins/booking.bl.8.7.10/js/datepick/jquery.datepick.js?ver=1.1

js canaltrust.org collected 2026-09-24 08:53:41 UTC 99,649 bytes, 2,182 lines download raw bytes

1/* http://keith-wood.name/datepick.html
2   Datepicker for jQuery 3.7.1.
3   Written by Marc Grabanski ([email protected]) and
4              Keith Wood (kbwood{at}iinet.com.au).
5   Dual licensed under the GPL (http://dev.jQuery.com/browser/trunk/jQuery/GPL-LICENSE.txt) and
6   MIT (http://dev.jQuery.com/browser/trunk/jQuery/MIT-LICENSE.txt) licenses.
7   Please attribute the authors if you use it. */
8
9(function($) { // Hide the namespace
10
11var PROP_NAME = 'datepick';
12
13
14    // https://github.com/jquery/jquery-migrate/blob/master/src/core.js#L50
15	//FixIn: 8.7.10.1
16    if (!$.browser_is_supported_datepick) {
17        var uaMatch = function(ua) {
18            ua = ua.toLowerCase();
19
20            var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
21
22            return match[2] || '0';
23        };
24
25        $.browser_is_supported_datepick = {
26            mozilla: /mozilla/.test(navigator.userAgent.toLowerCase()) && !/webkit/.test(navigator.userAgent.toLowerCase()),
27            webkit: /webkit/.test(navigator.userAgent.toLowerCase()),
28            opera: /opera/.test(navigator.userAgent.toLowerCase()),
29            msie: /msie/.test(navigator.userAgent.toLowerCase()),
30            android: (navigator.userAgent.toLowerCase().indexOf('mozilla/5.0') > -1 && navigator.userAgent.toLowerCase().indexOf('android ') > -1 && navigator.userAgent.toLowerCase().indexOf('applewebkit') > -1),
31            version: uaMatch(navigator.userAgent)
32        };
33    }
34
35/* Date picker manager.
36   Use the singleton instance of this class, $.datepick, to interact with the date picker.
37   Settings for (groups of) date pickers are maintained in an instance object,
38   allowing multiple different settings on the same page. */
39
40function Datepick() {
41	this._uuid = new Date().getTime(); // Unique identifier seed
42	this._curInst = null; // The current instance in use
43	this._keyEvent = false; // If the last event was a key event
44	this._disabledInputs = []; // List of date picker inputs that have been disabled
45	this._datepickerShowing = false; // True if the popup picker is showing , false if not
46	this._inDialog = false; // True if showing within a "dialog", false if not
47	this.regional = []; // Available regional settings, indexed by language code
48	this.regional[''] = { // Default regional settings
49		clearText: 'Clear', // Display text for clear link
50		clearStatus: 'Erase the current date', // Status text for clear link
51		closeText: 'Close', // Display text for close link
52		closeStatus: 'Close without change', // Status text for close link
53		prevText: '&#x3c;Prev', // Display text for previous month link
54		prevStatus: 'Show the previous month', // Status text for previous month link
55		prevBigText: '&#x3c;&#x3c;', // Display text for previous year link
56		prevBigStatus: 'Show the previous year', // Status text for previous year link
57		nextText: 'Next&#x3e;', // Display text for next month link
58		nextStatus: 'Show the next month', // Status text for next month link
59		nextBigText: '&#x3e;&#x3e;', // Display text for next year link
60		nextBigStatus: 'Show the next year', // Status text for next year link
61		currentText: 'Today', // Display text for current month link
62		currentStatus: 'Show the current month', // Status text for current month link
63		monthNames: ['January','February','March','April','May','June',
64			'July','August','September','October','November','December'], // Names of months for drop-down and formatting
65		monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
66		monthStatus: 'Show a different month', // Status text for selecting a month
67		yearStatus: 'Show a different year', // Status text for selecting a year
68		weekHeader: 'Wk', // Header for the week of the year column
69		weekStatus: 'Week of the year', // Status text for the week of the year column
70		dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
71		dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
72		dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
73		dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
74		dateStatus: 'Select DD, M d', // Status text for the date selection
75		dateFormat: 'mm/dd/yy', // See format options on parseDate
76		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
77		initStatus: 'Select a date', // Initial Status text on opening
78		isRTL: false, // True if right-to-left language, false if left-to-right
79		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
80		yearSuffix: '' // Additional text to append to the year in the month headers
81	};
82	this._defaults = { // Global defaults for all the date picker instances
83		useThemeRoller: false, // True to apply ThemeRoller styling, false for default styling
84		showOn: 'focus', // 'focus' for popup on focus,
85			// 'button' for trigger button, or 'both' for either
86		showAnim: 'show', // Name of jQuery animation for popup
87		showOptions: {}, // Options for enhanced animations
88		duration: 'normal', // Duration of display/closure
89		buttonText: '...', // Text for trigger button
90		buttonImage: '', // URL for trigger button image
91		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
92		alignment: 'bottom', // Alignment of popup - with nominated corner of input:
93			// 'top' or 'bottom' aligns depending on language direction,
94			// 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'
95		autoSize: false, // True to size the input for the date format, false to leave as is
96		defaultDate: null, // Used when field is blank: actual date,
97			// +/-number for offset from today, null for today
98		showDefault: false, // True to populate field with the default date
99		appendText: '', // Display text following the input box, e.g. showing the format
100		closeAtTop: true, // True to have the clear/close at the top,
101			// false to have them at the bottom
102		mandatory: false, // True to hide the Clear link, false to include it
103		hideIfNoPrevNext: false, // True to hide next/previous month links
104			// if not applicable, false to just disable them
105		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
106		showBigPrevNext: false, // True to show big prev/next links
107		stepMonths: 1, // Number of months to step back/forward
108		stepBigMonths: 12, // Number of months to step back/forward for the big links
109		gotoCurrent: false, // True if today link goes back to current selection instead
110		changeMonth: true, // True if month can be selected directly, false if only prev/next
111		changeYear: true, // True if year can be selected directly, false if only prev/next
112		yearRange: '-10:+10', // Range of years to display in drop-down,
113			// either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
114		changeFirstDay: false, // True to click on day name to change, false to remain as set
115		showOtherMonths: false, // True to show dates in other months, false to leave blank
116		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
117		highlightWeek: false, // True to highlight the selected week
118		showWeeks: false, // True to show week of the year, false to omit
119		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
120			// takes a Date and returns the number of the week for it
121		shortYearCutoff: '+10', // Short year values < this are in the current century,
122			// > this are in the previous century, string value starting with '+'
123			// for current year + value, -1 for no change
124		showStatus: false, // True to show status bar at bottom, false to not show it
125		statusForDate: this.dateStatus, // Function to provide status text for a date -
126			// takes date and instance as parameters, returns display text
127		minDate: null, // The earliest selectable date, or null for no limit
128		maxDate: null, // The latest selectable date, or null for no limit
129		numberOfMonths: 1, // Number of months to show at a time
130		showCurrentAtPos: 0, // The position in multiple months at which to show the current month (starting at 0)
131		rangeSelect: false, // Allows for selecting a date range on one date picker
132		rangeSeparator: ' - ', // Text between two dates in a range
133		multiSelect: 0, // Maximum number of selectable dates
134		multiSeparator: ',', // Text between multiple dates
135		beforeShow: null, // Function that takes an input field and
136			// returns a set of custom settings for the date picker
137		beforeShowDay: null, // Function that takes a date and returns an array with
138			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
139			// [2] = cell title (optional), e.g. $.datepick.noWeekends
140		onChangeMonthYear: null, // Define a callback function when the month or year is changed
141		onHover: null, // Define a callback function when hovering over a day
142		onSelect: null, // Define a callback function when a date is selected
143		onClose: null, // Define a callback function when the datepicker is closed
144		altField: '', // Selector for an alternate field to store selected dates into
145		altFormat: '', // The date format to use for the alternate field
146		constrainInput: true // The input is constrained by the current date format
147	};
148	$.extend(this._defaults, this.regional['']);
149	this.dpDiv = $('<div style="display: none;"></div>');
150}
151
152$.extend(Datepick.prototype, {
153	version: '3.7.0', // Current version
154	
155	/* Class name added to elements to indicate already configured with a date picker. */
156	markerClassName: 'hasDatepick', // Responsive Skin
157
158	// Class/id names for default and ThemeRoller stylings
159	_mainDivId: ['datepick-div', 'ui-datepicker-div'], // The main datepicker division
160	_mainDivClass: ['', 'ui-datepicker ' +
161		'ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'], // Popup class
162	_inlineClass: ['datepick-inline', 'ui-datepicker-inline ui-datepicker ' +
163		'ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'], // Inline class
164	_multiClass: ['datepick-multi', 'ui-datepicker-multi'], // Multi-month class
165	_rtlClass: ['datepick-rtl', 'ui-datepicker-rtl'], // Right-to-left class
166	_appendClass: ['datepick-append', 'ui-datepicker-append'], // Append text class
167	_triggerClass: ['datepick-trigger', 'ui-datepicker-trigger'], // Trigger class
168	_dialogClass: ['datepick-dialog', 'ui-datepicker-dialog'], // Dialog class
169	_promptClass: ['datepick-prompt', 'ui-datepicker-prompt'], // Dialog prompt class
170	_disableClass: ['datepick-disabled', 'ui-datepicker-disabled'], // Disabled covering class
171	_controlClass: ['datepick-control', 'ui-datepicker-header ' +
172		'ui-widget-header ui-helper-clearfix ui-corner-all'], // Control bar class
173	_clearClass: ['datepick-clear', 'ui-datepicker-clear'], // Clear class
174	_closeClass: ['datepick-close', 'ui-datepicker-close'], // Close class
175	_linksClass: ['datepick-links', 'ui-datepicker-header ' +
176		'ui-widget-header ui-helper-clearfix ui-corner-all'], // Links bar class
177	_prevClass: ['datepick-prev', 'ui-datepicker-prev'], // Previous class
178	_nextClass: ['datepick-next', 'ui-datepicker-next'], // Next class
179	_currentClass: ['datepick-current', 'ui-datepicker-current'], // Current class
180	_oneMonthClass: ['datepick-one-month', 'ui-datepicker-group'], // Single month class
181	_newRowClass: ['datepick-new-row', 'ui-datepicker-row-break'], // New month row class
182	_monthYearClass: ['datepick-header', 'ui-datepicker-header ' +
183		'ui-widget-header ui-helper-clearfix ui-corner-all'], // Month/year header class
184	_monthSelectClass: ['datepick-new-month', 'ui-datepicker-month'], // Month select class
185	_monthClass: ['', 'ui-datepicker-month'], // Month text class
186	_yearSelectClass: ['datepick-new-year', 'ui-datepicker-year'], // Year select class
187	_yearClass: ['', 'ui-datepicker-year'], // Year text class
188	_tableClass: ['datepick', 'ui-datepicker-calendar'], // Month table class
189	_tableHeaderClass: ['datepick-title-row', ''], // Week header class
190	_weekColClass: ['datepick-week-col', 'ui-datepicker-week-col'], // Week number column class
191	_weekRowClass: ['datepick-days-row', ''], // Week row class
192	_weekendClass: ['datepick-week-end-cell', 'ui-datepicker-week-end'], // Weekend class
193	_dayClass: ['datepick-days-cell', ''], // Single day class
194	_otherMonthClass: ['datepick-other-month', 'ui-datepicker-other-month'], // Other month class
195	_todayClass: ['datepick-today', 'ui-state-highlight'], // Today class
196	_selectableClass: ['', 'ui-state-default'], // Selectable cell class
197	_unselectableClass: ['datepick-unselectable',
198		'ui-datepicker-unselectable ui-state-disabled'], // Unselectable cell class
199	_selectedClass: ['datepick-current-day', 'ui-state-active'], // Selected day class
200	_dayOverClass: ['datepick-days-cell-over', 'ui-state-hover'], // Day hover class
201	_weekOverClass: ['datepick-week-over', 'ui-state-hover'], // Week hover class
202	_statusClass: ['datepick-status', 'ui-datepicker-status'], // Status bar class
203	_statusId: ['datepick-status-', 'ui-datepicker-status-'], // Status bar ID prefix
204	_coverClass: ['datepick-cover', 'ui-datepicker-cover'], // IE6- iframe class
205
206	/* Override the default settings for all instances of the date picker.
207	   @param  settings  (object) the new settings to use as defaults (anonymous object)
208	   @return  (Datepick) the manager object */
209	setDefaults: function(settings) {
210		extendRemove(this._defaults, settings || {});
211		return this;
212	},
213
214	/* Attach the date picker to a jQuery selection.
215	   @param  target    (element) the target input field or division or span
216	   @param  settings  (object) the new settings to use for this date picker instance */
217	_attachDatepick: function(target, settings) {
218		if (!target.id)
219			target.id = 'dp' + (++this._uuid);
220		var nodeName = target.nodeName.toLowerCase();
221		var inst = this._newInst($(target), (nodeName == 'div' || nodeName == 'span'));
222		// Check for settings on the control itself
223		var inlineSettings = ($.fn.metadata ? $(target).metadata() : {});
224		inst.settings = $.extend({}, settings || {}, inlineSettings || {});
225		if (inst.inline) {
226			inst.dpDiv.addClass(this._inlineClass[
227				this._get(inst, 'useThemeRoller') ? 1 : 0]);
228			this._inlineDatepick(target, inst);
229		}
230		else
231			this._connectDatepick(target, inst);
232	},
233
234	/* Create a new instance object.
235	   @param  target  (jQuery) the target input field or division or span
236	   @param  inline  (boolean) true if this datepicker appears inline */
237	_newInst: function(target, inline) {
238		var id = target[0].id.replace(/([:\[\]\.\$])/g, '\\\\$1'); // Escape jQuery meta chars
239		return {id: id, input: target, // Associated target
240			cursorDate: this._daylightSavingAdjust(new Date()), // Current position
241			drawMonth: 0, drawYear: 0, // Month being drawn
242			dates: [], // Selected dates
243			inline: inline, // Is datepicker inline or not
244			dpDiv: (!inline ? this.dpDiv : $('<div></div>')), // presentation div
245			siblings: $([])}; // Created siblings (trigger/append)
246	},
247
248	/* Attach the date picker to an input field.
249	   @param  target  (element) the target input field or division or span
250	   @param  inst    (object) the instance settings for this datepicker */
251	_connectDatepick: function(target, inst) {
252		var input = $(target);
253		if (input.hasClass(this.markerClassName))
254			return;
255		var appendText = this._get(inst, 'appendText');
256		var isRTL = this._get(inst, 'isRTL');
257		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
258		if (appendText) {
259			var append = $('<span class="' + this._appendClass[useTR] + '">' + appendText + '</span>');
260			input[isRTL ? 'before' : 'after'](append);
261			inst.siblings = inst.siblings.add(append);
262		}
263		var showOn = this._get(inst, 'showOn');
264		if (showOn == 'focus' || showOn == 'both') // Pop-up date picker when in the marked field
265			input.focus(this._showDatepick);
266		if (showOn == 'button' || showOn == 'both') { // Pop-up date picker when button clicked
267			var buttonText = this._get(inst, 'buttonText');
268			var buttonImage = this._get(inst, 'buttonImage');
269			var trigger = $(this._get(inst, 'buttonImageOnly') ?
270				$('<img/>').addClass(this._triggerClass[useTR]).
271					attr({src: buttonImage, alt: buttonText, title: buttonText}) :
272				$('<button type="button"></button>').addClass(this._triggerClass[useTR]).
273					html(buttonImage == '' ? buttonText : $('<img/>').attr(
274					{src: buttonImage, alt: buttonText, title: buttonText})));
275			input[isRTL ? 'before' : 'after'](trigger);
276			inst.siblings = inst.siblings.add(trigger);
277			trigger.click(function() {
278				if ($.datepick._datepickerShowing && $.datepick._lastInput == target)
279					$.datepick._hideDatepick();
280				else
281					$.datepick._showDatepick(target);
282				return false;
283			});
284		}
285		input.addClass(this.markerClassName).keydown(this._doKeyDown).
286			keypress(this._doKeyPress).keyup(this._doKeyUp);
287		if (this._get(inst, 'showDefault') && !inst.input.val()) {
288			inst.dates = [this._getDefaultDate(inst)];
289			this._showDate(inst);
290		}
291		this._autoSize(inst);
292		$.data(target, PROP_NAME, inst);
293	},
294
295	/* Apply the maximum length for the date format.
296	   @param  inst  (object) the instance settings for this datepicker */
297	_autoSize: function(inst) {
298		if (this._get(inst, 'autoSize') && !inst.inline) {
299			var date = new Date(2009, 12 - 1, 20); // Ensure double digits
300			var dateFormat = this._get(inst, 'dateFormat');
301			if (dateFormat.match(/[DM]/)) {
302				var findMax = function(names) {
303					var max = 0;
304					var maxI = 0;
305					for (var i = 0; i < names.length; i++) {
306						if (names[i].length > max) {
307							max = names[i].length;
308							maxI = i;
309						}
310					}
311					return maxI;
312				};
313				date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
314					'monthNames' : 'monthNamesShort'))));
315				date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
316					'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
317			}
318			inst.input.attr('size', this._formatDate(inst, date).length);
319		}
320	},
321
322	/* Attach an inline date picker to a div.
323	   @param  target  (element) the target input field or division or span
324	   @param  inst    (object) the instance settings for this datepicker */
325	_inlineDatepick: function(target, inst) {
326		var divSpan = $(target);
327		if (divSpan.hasClass(this.markerClassName))
328			return;
329		divSpan.addClass(this.markerClassName);
330		$.data(target, PROP_NAME, inst);
331		inst.drawMonth = inst.cursorDate.getMonth();
332		inst.drawYear = inst.cursorDate.getFullYear();
333		$('body').append(inst.dpDiv);
334		this._updateDatepick(inst);
335		// Fix width for dynamic number of date pickers
336		inst.dpDiv.width(this._getNumberOfMonths(inst)[1] *
337			$('.' + this._oneMonthClass[this._get(inst, 'useThemeRoller') ? 1 : 0],
338			inst.dpDiv)[0].offsetWidth);
339		divSpan.append(inst.dpDiv);
340		this._updateAlternate(inst);
341	},
342
343	/* Pop-up the date picker in a "dialog" box.
344	   @param  input     (element) ignored
345	   @param  date      (string or Date) the initial date to display
346	   @param  onSelect  (function) the function to call when a date is selected
347	   @param  settings  (object) update the dialog date picker instance's settings
348	   @param  pos       (int[2]) coordinates for the dialog's position within the screen or
349	                     (event) with x/y coordinates or
350	                     leave empty for default (screen centre) */
351	_dialogDatepick: function(input, date, onSelect, settings, pos) {
352		var inst = this._dialogInst; // Internal instance
353		if (!inst) {
354			var id = 'dp' + (++this._uuid);
355			this._dialogInput = $('<input type="text" id="' + id +
356				'" style="position: absolute; width: 1px; z-index: -1"/>');
357			this._dialogInput.keydown(this._doKeyDown);
358			$('body').append(this._dialogInput);
359			inst = this._dialogInst = this._newInst(this._dialogInput, false);
360			inst.settings = {};
361			$.data(this._dialogInput[0], PROP_NAME, inst);
362		}
363		extendRemove(inst.settings, settings || {});
364		date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
365		this._dialogInput.val(date);
366		this._pos = (pos ? (isArray(pos) ? pos : [pos.pageX, pos.pageY]) : null);
367		if (!this._pos) {
368			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
369			var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
370			this._pos = // Should use actual width/height below
371				[(document.documentElement.clientWidth / 2) - 100 + scrollX,
372				(document.documentElement.clientHeight / 2) - 150 + scrollY];
373		}
374
375		// Move input on screen for focus, but hidden behind dialog
376		this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
377		inst.settings.onSelect = onSelect;
378		this._inDialog = true;
379		this.dpDiv.addClass(this._dialogClass[this._get(inst, 'useThemeRoller') ? 1 : 0]);
380		this._showDatepick(this._dialogInput[0]);
381		if ($.blockUI)
382			$.blockUI(this.dpDiv);
383		$.data(this._dialogInput[0], PROP_NAME, inst);
384	},
385
386	/* Detach a datepicker from its control.
387	   @param  target  (element) the target input field or division or span */
388	_destroyDatepick: function(target) {
389		var $target = $(target);
390		if (!$target.hasClass(this.markerClassName)) {
391			return;
392		}
393		var inst = $.data(target, PROP_NAME);
394		$.removeData(target, PROP_NAME);
395		if (inst.inline)
396			$target.removeClass(this.markerClassName).empty();
397		else {
398			$(inst.siblings).remove();
399			$target.removeClass(this.markerClassName).
400				unbind('focus', this._showDatepick).unbind('keydown', this._doKeyDown).
401				unbind('keypress', this._doKeyPress).unbind('keyup', this._doKeyUp);
402		}
403	},
404
405	/* Enable the date picker to a jQuery selection.
406	   @param  target  (element) the target input field or division or span */
407	_enableDatepick: function(target) {
408		var $target = $(target);
409		if (!$target.hasClass(this.markerClassName))
410			return;
411		var inst = $.data(target, PROP_NAME);
412		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
413		if (inst.inline)
414			$target.children('.' + this._disableClass[useTR]).remove().end().
415				find('select').attr('disabled', '');
416		else {
417			target.disabled = false;
418			inst.siblings.filter('button.' + this._triggerClass[useTR]).
419				each(function() { this.disabled = false; }).end().
420				filter('img.' + this._triggerClass[useTR]).
421				css({opacity: '1.0', cursor: ''});
422		}
423		this._disabledInputs = $.map(this._disabledInputs,
424			function(value) { return (value == target ? null : value); }); // Delete entry
425	},
426
427	/* Disable the date picker to a jQuery selection.
428	   @param  target  (element) the target input field or division or span */
429	_disableDatepick: function(target) {
430		var $target = $(target);
431		if (!$target.hasClass(this.markerClassName))
432			return;
433		var inst = $.data(target, PROP_NAME);
434		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
435		if (inst.inline) {
436			var inline = $target.children('.' + this._inlineClass[useTR]);
437			var offset = inline.offset();
438			var relOffset = {left: 0, top: 0};
439			inline.parents().each(function() {
440				if ($(this).css('position') == 'relative') {
441					relOffset = $(this).offset();
442					return false;
443				}
444			});
445			$target.prepend('<div class="' + this._disableClass[useTR] + '" style="' +
446				'width: ' + inline.width() + 'px; height: ' + inline.height() +
447				'px; left: ' + (offset.left - relOffset.left) +
448				'px; top: ' + (offset.top - relOffset.top) + 'px;"></div>').
449				find('select').attr('disabled', 'disabled');
450		}
451		else {
452			target.disabled = true;
453			inst.siblings.filter('button.' + this._triggerClass[useTR]).
454				each(function() { this.disabled = true; }).end().
455				filter('img.' + this._triggerClass[useTR]).
456				css({opacity: '0.5', cursor: 'default'});
457		}
458		this._disabledInputs = $.map(this._disabledInputs,
459			function(value) { return (value == target ? null : value); }); // Delete entry
460		this._disabledInputs.push(target);
461	},
462
463	/* Is the first field in a jQuery collection disabled as a datepicker?
464	   @param  target  (element) the target input field or division or span
465	   @return  (boolean) true if disabled, false if enabled */
466	_isDisabledDatepick: function(target) {
467		return (!target ? false : $.inArray(target, this._disabledInputs) > -1);
468	},
469
470	/* Retrieve the instance data for the target control.
471	   @param  target  (element) the target input field or division or span
472	   @return  (object) the associated instance data
473	   @throws  error if a jQuery problem getting data */
474	_getInst: function(target) {//alert(target.id);
475		try {
476			return $.data(target, PROP_NAME);
477		}
478		catch (err) {
479			throw 'Missing instance data for this datepicker';
480		}
481	},
482
483	/* Update or retrieve the settings for a date picker attached to an input field or division.
484	   @param  target  (element) the target input field or division or span
485	   @param  name    (object) the new settings to update or
486	                   (string) the name of the setting to change or retrieve,
487	                   when retrieving also 'all' for all instance settings or
488	                   'defaults' for all global defaults
489	   @param  value   (any) the new value for the setting
490	                   (omit if above is an object or to retrieve value) */
491	_optionDatepick: function(target, name, value) {
492		var inst = this._getInst(target);
493		if (arguments.length == 2 && typeof name == 'string') {
494			return (name == 'defaults' ? $.extend({}, $.datepick._defaults) :
495				(inst ? (name == 'all' ? $.extend({}, inst.settings) :
496				this._get(inst, name)) : null));
497		}
498		var settings = name || {};
499		if (typeof name == 'string') {
500			settings = {};
501			settings[name] = value;
502		}
503		if (inst) {
504			if (this._curInst == inst) {
505				this._hideDatepick(null);
506			}
507			var dates = this._getDateDatepick(target);
508			extendRemove(inst.settings, settings);
509			this._autoSize(inst);
510			extendRemove(inst, {dates: []});
511			var blank = (!dates || isArray(dates));
512			if (isArray(dates))
513				for (var i = 0; i < dates.length; i++)
514					if (dates[i]) {
515						blank = false;
516						break;
517					}
518			if (!blank)
519				this._setDateDatepick(target, dates);
520			if (inst.inline)
521				$(target).children('div').removeClass(this._inlineClass.join(' ')).
522					addClass(this._inlineClass[this._get(inst, 'useThemeRoller') ? 1 : 0]);
523			this._updateDatepick(inst);
524		}
525	},
526
527	// Change method deprecated
528	_changeDatepick: function(target, name, value) {
529		this._optionDatepick(target, name, value);
530	},
531
532	/* Redraw the date picker attached to an input field or division.
533	   @param  target  (element) the target input field or division or span */
534	_refreshDatepick: function(target) {
535		var inst = this._getInst(target);
536		if (inst) {
537			this._updateDatepick(inst);
538		}
539	},
540
541	/* Set the dates for a jQuery selection.
542	   @param  target   (element) the target input field or division or span
543	   @param  date     (Date) the new date
544	   @param  endDate  (Date) the new end date for a range (optional) */
545	_setDateDatepick: function(target, date, endDate) {
546		var inst = this._getInst(target);
547		if (inst) {
548			this._setDate(inst, date, endDate);
549			this._updateDatepick(inst);
550			this._updateAlternate(inst);
551		}
552	},
553
554	/* Get the date(s) for the first entry in a jQuery selection.
555	   @param  target  (element) the target input field or division or span
556	   @return (Date) the current date or
557	           (Date[2]) the current dates for a range */
558	_getDateDatepick: function(target) {
559		var inst = this._getInst(target);
560		if (inst && !inst.inline)
561			this._setDateFromField(inst);
562		return (inst ? this._getDate(inst) : null);
563	},
564
565	/* Handle keystrokes.
566	   @param  event  (KeyEvent) the keystroke details
567	   @return  (boolean) true to continue, false to discard */
568	_doKeyDown: function(event) {
569		var inst = $.datepick._getInst(event.target);
570		inst.keyEvent = true;
571		var handled = true;
572		var isRTL = $.datepick._get(inst, 'isRTL');
573		var useTR = $.datepick._get(inst, 'useThemeRoller') ? 1 : 0;
574		if ($.datepick._datepickerShowing)
575			switch (event.keyCode) {
576				case 9:  $.datepick._hideDatepick(null, '');
577						break; // Hide on tab out
578				case 13: var sel = $('td.' + $.datepick._dayOverClass[useTR], inst.dpDiv);
579						if (sel.length == 0)
580							sel = $('td.' + $.datepick._selectedClass[useTR] + ':first', inst.dpDiv);
581						if (sel[0])
582							$.datepick._selectDay(sel[0], event.target, inst.cursorDate.getTime());
583						else
584							$.datepick._hideDatepick(null, $.datepick._get(inst, 'duration'));
585						break; // Select the value on enter
586				case 27: $.datepick._hideDatepick(null, $.datepick._get(inst, 'duration'));
587						break; // Hide on escape
588				case 33: $.datepick._adjustDate(event.target, (event.ctrlKey ?
589							-$.datepick._get(inst, 'stepBigMonths') :
590							-$.datepick._get(inst, 'stepMonths')), 'M');
591						break; // Previous month/year on page up/+ ctrl
592				case 34: $.datepick._adjustDate(event.target, (event.ctrlKey ?
593							+$.datepick._get(inst, 'stepBigMonths') :
594							+$.datepick._get(inst, 'stepMonths')), 'M');
595						break; // Next month/year on page down/+ ctrl
596				case 35: if (event.ctrlKey || event.metaKey)
597							$.datepick._clearDate(event.target);
598						handled = event.ctrlKey || event.metaKey;
599						break; // Clear on ctrl or command + end
600				case 36: if (event.ctrlKey || event.metaKey)
601							$.datepick._gotoToday(event.target);
602						handled = event.ctrlKey || event.metaKey;
603						break; // Current on ctrl or command + home
604				case 37: if (event.ctrlKey || event.metaKey)
605							$.datepick._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
606						handled = event.ctrlKey || event.metaKey;
607						// -1 day on ctrl or command + left
608						if (event.originalEvent.altKey)
609							$.datepick._adjustDate(event.target,
610								(event.ctrlKey ? -$.datepick._get(inst, 'stepBigMonths') :
611								-$.datepick._get(inst, 'stepMonths')), 'M');
612						// Next month/year on alt + left/+ ctrl
613						break;
614				case 38: if (event.ctrlKey || event.metaKey)
615							$.datepick._adjustDate(event.target, -7, 'D');
616						handled = event.ctrlKey || event.metaKey;
617						break; // -1 week on ctrl or command + up
618				case 39: if (event.ctrlKey || event.metaKey)
619							$.datepick._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
620						handled = event.ctrlKey || event.metaKey;
621						// +1 day on ctrl or command + right
622						if (event.originalEvent.altKey)
623							$.datepick._adjustDate(event.target,
624								(event.ctrlKey ? +$.datepick._get(inst, 'stepBigMonths') :
625								+$.datepick._get(inst, 'stepMonths')), 'M');
626						// Next month/year on alt + right/+ ctrl
627						break;
628				case 40: if (event.ctrlKey || event.metaKey)
629							$.datepick._adjustDate(event.target, +7, 'D');
630						handled = event.ctrlKey || event.metaKey;
631						break; // +1 week on ctrl or command + down
632				default: handled = false;
633			}
634		else if (event.keyCode == 36 && event.ctrlKey) // Display the date picker on ctrl+home
635			$.datepick._showDatepick(this);
636		else
637			handled = false;
638		if (handled) {
639			event.preventDefault();
640			event.stopPropagation();
641		}
642		inst.ctrlKey = (event.keyCode < 48);
643		return !handled;
644	},
645
646	/* Filter entered characters - based on date format.
647	   @param  event  (KeyEvent) the keystroke details
648	   @return  (boolean) true to continue, false to discard */
649	_doKeyPress: function(event) {
650		var inst = $.datepick._getInst(event.target);
651		if ($.datepick._get(inst, 'constrainInput')) {
652			var chars = $.datepick._possibleChars(inst);
653			var chr = String.fromCharCode(event.keyCode || event.charCode);
654			return inst.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
655		}
656	},
657
658	/* Synchronise manual entry and field/alternate field.
659	   @param  event  (KeyEvent) the keystroke details
660	   @return  (boolean) true to continue */
661	_doKeyUp: function(event) {
662		var inst = $.datepick._getInst(event.target);
663		if (inst.input.val() != inst.lastVal) {
664			try {
665				var separator = ($.datepick._get(inst, 'rangeSelect') ?
666					$.datepick._get(inst, 'rangeSeparator') :
667					($.datepick._get(inst, 'multiSelect') ?
668					$.datepick._get(inst, 'multiSeparator') : ''));
669				var dates = (inst.input ? inst.input.val() : '');
670				dates = (separator ? dates.split(separator) : [dates]);
671				var ok = true;
672				for (var i = 0; i < dates.length; i++) {
673					if (!$.datepick.parseDate($.datepick._get(inst, 'dateFormat'),
674							dates[i], $.datepick._getFormatConfig(inst))) {
675						ok = false;
676						break;
677					}
678				}
679				if (ok) { // Only if valid
680					$.datepick._setDateFromField(inst);
681					$.datepick._updateAlternate(inst);
682					$.datepick._updateDatepick(inst);
683				}
684			}
685			catch (event) {
686				// Ignore
687			}
688		}
689		return true;
690	},
691
692	/* Extract all possible characters from the date format.
693	   @param  inst  (object) the instance settings for this datepicker
694	   @return  (string) the set of characters allowed by this format */
695	_possibleChars: function (inst) {
696		var dateFormat = $.datepick._get(inst, 'dateFormat');
697		var chars = ($.datepick._get(inst, 'rangeSelect') ?
698			$.datepick._get(inst, 'rangeSeparator') :
699			($.datepick._get(inst, 'multiSelect') ?
700			$.datepick._get(inst, 'multiSeparator') : ''));
701		var literal = false;
702		for (var iFormat = 0; iFormat < dateFormat.length; iFormat++)
703			if (literal)
704				if (dateFormat.charAt(iFormat) == "'" && !lookAhead("'"))
705					literal = false;
706				else
707					chars += dateFormat.charAt(iFormat);
708			else
709				switch (dateFormat.charAt(iFormat)) {
710					case 'd': case 'm': case 'y': case '@':
711						chars += '0123456789';
712						break;
713					case 'D': case 'M':
714						return null; // Accept anything
715					case "'":
716						if (lookAhead("'"))
717							chars += "'";
718						else
719							literal = true;
720						break;
721					default:
722						chars += dateFormat.charAt(iFormat);
723				}
724		return chars;
725	},
726
727	/* Update the datepicker when hovering over a date.
728	   @param  td         (element) the current cell
729	   @param  id         (string) the ID of the datepicker instance
730	   @param  timestamp  (number) the timestamp for this date */
731	_doMouseOver: function(td, id, timestamp) {
732		var inst = $.datepick._getInst($('#' + id)[0]);
733		var useTR = $.datepick._get(inst, 'useThemeRoller') ? 1 : 0;
734		$(td).parents('tbody').find('td').
735			removeClass($.datepick._dayOverClass[useTR]).end().end().
736			addClass($.datepick._dayOverClass[useTR]);
737		if ($.datepick._get(inst, 'highlightWeek'))
738			$(td).parent().parent().find('tr').
739				removeClass($.datepick._weekOverClass[useTR]).end().end().
740				addClass($.datepick._weekOverClass[useTR]);
741		if ($(td).text()) {
742			var date = new Date(timestamp);
743			if ($.datepick._get(inst, 'showStatus')) {
744				var status = ($.datepick._get(inst, 'statusForDate').apply(
745					(inst.input ? inst.input[0] : null), [date, inst]) ||
746					$.datepick._get(inst, 'initStatus'));
747				$('#' + $.datepick._statusId[useTR] + id).html(status);
748			}
749			if ($.datepick._get(inst, 'onHover'))
750				$.datepick._doHover(td, '#' + id, date.getFullYear(), date.getMonth());
751		}
752	},
753
754	/* Update the datepicker when no longer hovering over a date.
755	   @param  td  (element) the current cell
756	   @param  id  (string) the ID of the datepicker instance */
757	_doMouseOut: function(td, id) {
758		var inst = $.datepick._getInst($('#' + id)[0]);
759		var useTR = $.datepick._get(inst, 'useThemeRoller') ? 1 : 0;
760		$(td).removeClass($.datepick._dayOverClass[useTR]).
761			removeClass($.datepick._weekOverClass[useTR]);
762		if ($.datepick._get(inst, 'showStatus'))
763			$('#' + $.datepick._statusId[useTR] + id).html($.datepick._get(inst, 'initStatus'));
764		if ($.datepick._get(inst, 'onHover'))
765			$.datepick._doHover(td, '#' + id);
766	},
767
768	/* Hover over a particular day.
769	   @param  td     (element) the table cell containing the selection
770	   @param  id     (string) the ID of the target field
771	   @param  year   (number) the year for this day
772	   @param  month  (number) the month for this day */
773	_doHover: function(td, id, year, month) {
774		var inst = this._getInst($(id)[0]);
775		var useTR = $.datepick._get(inst, 'useThemeRoller') ? 1 : 0;
776		//if ($(td).hasClass(this._unselectableClass[useTR]))
777		//	return;
778		var onHover = this._get(inst, 'onHover');
779		var date = (year ?
780			this._daylightSavingAdjust(new Date(year, month, $(td).find('a').text())) : null);
781		onHover.apply((inst.input ? inst.input[0] : null),
782			[(date ? this._formatDate(inst, date) : ''), date, inst]);
783	},
784
785	/* Pop-up the date picker for a given input field.
786	   @param  input  (element) the input field attached to the date picker or
787	                  (event) if triggered by focus */
788	_showDatepick: function(input) {
789		input = input.target || input;
790		if ($.datepick._isDisabledDatepick(input) || $.datepick._lastInput == input) // Already here
791			return;
792		var inst = $.datepick._getInst(input);
793		var beforeShow = $.datepick._get(inst, 'beforeShow');
794		var useTR = $.datepick._get(inst, 'useThemeRoller') ? 1 : 0;
795		extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
796		$.datepick._hideDatepick(null, '');
797		$.datepick._lastInput = input;
798		$.datepick._setDateFromField(inst);
799		if ($.datepick._inDialog) // Hide cursor
800			input.value = '';
801		if (!$.datepick._pos) { // Position below input
802			$.datepick._pos = $.datepick._findPos(input);
803			$.datepick._pos[1] += input.offsetHeight; // Add the height
804		}
805		var isFixed = false;
806		$(input).parents().each(function() {
807			isFixed |= $(this).css('position') == 'fixed';
808			return !isFixed;
809		});
810		if (isFixed && $.browser_is_supported_datepick.opera) { // Correction for Opera when fixed and scrolled
811			$.datepick._pos[0] -= document.documentElement.scrollLeft;
812			$.datepick._pos[1] -= document.documentElement.scrollTop;
813		}
814		var offset = {left: $.datepick._pos[0], top: $.datepick._pos[1]};
815		$.datepick._pos = null;
816		// Determine sizing offscreen
817		inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
818		$.datepick._updateDatepick(inst);
819		// Fix width for dynamic number of date pickers
820		inst.dpDiv.width($.datepick._getNumberOfMonths(inst)[1] *
821			$('.' + $.datepick._oneMonthClass[useTR], inst.dpDiv).width());
822		// And adjust position before showing
823		offset = $.datepick._checkOffset(inst, offset, isFixed);
824		inst.dpDiv.css({position: ($.datepick._inDialog && $.blockUI ?
825			'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
826			left: offset.left + 'px', top: offset.top + 'px'});
827		if (!inst.inline) {
828			var showAnim = $.datepick._get(inst, 'showAnim') || 'show';
829			var duration = $.datepick._get(inst, 'duration');
830			var postProcess = function() {
831				$.datepick._datepickerShowing = true;
832				var borders = $.datepick._getBorders(inst.dpDiv);
833				inst.dpDiv.find('iframe.' + $.datepick._coverClass[useTR]). // IE6- only
834					css({left: -borders[0], top: -borders[1],
835						width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
836			};
837			if ($.effects && $.effects[showAnim])
838				inst.dpDiv.show(showAnim, $.datepick._get(inst, 'showOptions'), duration, postProcess);
839			else
840				inst.dpDiv[showAnim](duration, postProcess);
841			if (duration == '')
842				postProcess();
843			if (inst.input[0].type != 'hidden')
844				inst.input.focus();
845			$.datepick._curInst = inst;
846		}
847	},
848
849	/* Generate the date picker content.
850	   @param  inst  (object) the instance settings for this datepicker */
851	_updateDatepick: function(inst) {
852		var borders = this._getBorders(inst.dpDiv);
853		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
854		inst.dpDiv.empty().append(this._generateHTML(inst)).
855			find('iframe.' + this._coverClass[useTR]). // IE6- only
856			css({left: -borders[0], top: -borders[1],
857				width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
858		var numMonths = this._getNumberOfMonths(inst);
859		if (!inst.inline)
860			inst.dpDiv.attr('id', this._mainDivId[useTR]);
861		if (!inst.inline) inst.dpDiv.attr('class', 'datepick-inline');  // Added by wpdevelop for the correct  showing of calendar in the search form.
862		inst.dpDiv.removeClass(this._mainDivClass[1 - useTR]).
863			addClass(this._mainDivClass[useTR]).
864			removeClass(this._multiClass.join(' ')).
865			addClass(numMonths[0] != 1 || numMonths[1] != 1 ? this._multiClass[useTR] : '').
866			removeClass(this._rtlClass.join(' ')).
867			addClass(this._get(inst, 'isRTL') ? this._rtlClass[useTR] : '');
868		if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepick._curInst)
869			$(inst.input).focus();
870	},
871
872	/* Retrieve the size of left and top borders for an element.
873	   @param  elem  (jQuery object) the element of interest
874	   @return  (number[2]) the left and top borders */
875	_getBorders: function(elem) {
876		var convert = function(value) {
877			var extra = ($.browser_is_supported_datepick.msie ? 1 : 0);
878			return {thin: 1 + extra, medium: 3 + extra, thick: 5 + extra}[value] || value;
879		};
880		return [parseFloat(convert(elem.css('border-left-width'))),
881			parseFloat(convert(elem.css('border-top-width')))];
882	},
883
884	/* Check positioning to remain on the screen.
885	   @param  inst     (object) the instance settings for this datepicker
886	   @param  offset   (object) the offset of the attached field
887	   @param  isFixed  (boolean) true if control or a parent is 'fixed' in position
888	   @return  (object) the updated offset for the datepicker */
889	_checkOffset: function(inst, offset, isFixed) {
890		var alignment = this._get(inst, 'alignment');
891		var isRTL = this._get(inst, 'isRTL');
892		var pos = inst.input ? this._findPos(inst.input[0]) : null;
893		var browserWidth = document.documentElement.clientWidth;
894		var browserHeight = document.documentElement.clientHeight;
895		if (browserWidth == 0)
896			return offset;
897		var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
898		var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
899		var above = pos[1] - (this._inDialog ? 0 : inst.dpDiv.outerHeight()) -
900			(isFixed && $.browser_is_supported_datepick.opera ? document.documentElement.scrollTop : 0);
901		var below = offset.top;
902		var alignL = offset.left;
903		var alignR = pos[0] + (inst.input ? inst.input.outerWidth() : 0) - inst.dpDiv.outerWidth() -
904			(isFixed && $.browser_is_supported_datepick.opera ? document.documentElement.scrollLeft : 0);
905		var tooWide = (offset.left + inst.dpDiv.outerWidth() - scrollX) > browserWidth;
906		var tooHigh = (offset.top + inst.dpDiv.outerHeight() - scrollY) > browserHeight;
907		if (alignment == 'topLeft') {
908			offset = {left: alignL, top: above};
909		}
910		else if (alignment == 'topRight') {
911			offset = {left: alignR, top: above};
912		}
913		else if (alignment == 'bottomLeft') {
914			offset = {left: alignL, top: below};
915		}
916		else if (alignment == 'bottomRight') {
917			offset = {left: alignR, top: below};
918		}
919		else if (alignment == 'top') {
920			offset = {left: (isRTL || tooWide ? alignR : alignL), top: above};
921		}
922		else { // bottom
923			offset = {left: (isRTL || tooWide ? alignR : alignL),
924				top: (tooHigh ? above : below)};
925		}
926		offset.left = Math.max((isFixed ? 0 : scrollX), offset.left - (isFixed ? scrollX : 0));
927		offset.top = Math.max((isFixed ? 0 : scrollY), offset.top - (isFixed ? scrollY : 0));
928		return offset;
929	},
930
931	/* Find an element's position on the screen.
932	   @param  elem  (element) the element to check
933	   @return  (number[2]) the x- and y-coordinates for the object */
934	_findPos: function(elem) {
935        while (elem && (elem.type == 'hidden' || elem.nodeType != 1)) {
936            elem = elem.nextSibling;
937        }
938        var position = $(elem).offset();
939	    return [position.left, position.top];
940	},
941
942	/* Hide the date picker from view.
943	   @param  input     (element) the input field attached to the date picker
944	   @param  duration  (string) the duration over which to close the date picker */
945	_hideDatepick: function(input, duration) {
946		var inst = this._curInst;
947		if (!inst || (input && inst != $.data(input, PROP_NAME)))
948			return false;
949		var rangeSelect = this._get(inst, 'rangeSelect');
950		if (rangeSelect && inst.stayOpen)
951			this._updateInput('#' + inst.id);
952		inst.stayOpen = false;
953		if (this._datepickerShowing) {
954			duration = (duration != null ? duration : this._get(inst, 'duration'));
955			var showAnim = this._get(inst, 'showAnim');
956			var postProcess = function() {
957				$.datepick._tidyDialog(inst);
958			};
959			if (duration != '' && $.effects && $.effects[showAnim])
960				inst.dpDiv.hide(showAnim, $.datepick._get(inst, 'showOptions'),
961					duration, postProcess);
962			else
963				inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
964					(showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
965			if (duration == '')
966				this._tidyDialog(inst);
967			var onClose = this._get(inst, 'onClose');
968			if (onClose)  // Trigger custom callback
969				onClose.apply((inst.input ? inst.input[0] : null),
970					[(inst.input ? inst.input.val() : ''), this._getDate(inst), inst]);
971			this._datepickerShowing = false;
972			this._lastInput = null;
973			inst.settings.prompt = null;
974			if (this._inDialog) {
975				this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
976				this.dpDiv.removeClass(this._dialogClass[this._get(inst, 'useThemeRoller') ? 1 : 0]);
977				if ($.blockUI) {
978					$.unblockUI();
979					$('body').append(this.dpDiv);
980				}
981			}
982			this._inDialog = false;
983		}
984		this._curInst = null;
985		return false;
986	},
987
988	/* Tidy up after a dialog display.
989	   @param  inst  (object) the instance settings for this datepicker */
990	_tidyDialog: function(inst) {
991		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
992		inst.dpDiv.removeClass(this._dialogClass[useTR]).unbind('.datepick');
993		$('.' + this._promptClass[useTR], inst.dpDiv).remove();
994	},
995
996	/* Close date picker if clicked elsewhere.
997	   @param  event  (MouseEvent) the mouse click to check */
998	_checkExternalClick: function(event) {
999		if (!$.datepick._curInst)
1000			return;
1001		var $target = $(event.target);
1002		var useTR = $.datepick._get($.datepick._curInst, 'useThemeRoller') ? 1 : 0;
1003		if (!$target.parents().andSelf().is('#' + $.datepick._mainDivId[useTR]) &&
1004				!$target.hasClass($.datepick.markerClassName) &&
1005				!$target.parents().andSelf().hasClass($.datepick._triggerClass[useTR]) &&
1006				$.datepick._datepickerShowing && !($.datepick._inDialog && $.blockUI))
1007			$.datepick._hideDatepick(null, '');
1008	},
1009
1010	/* Adjust one of the date sub-fields.
1011	   @param  id      (string) the ID of the target field
1012	   @param  offset  (number) the amount to change by
1013	   @param  period  (string) 'D' for days, 'M' for months, 'Y' for years */
1014	_adjustDate: function(id, offset, period) {
1015		var inst = this._getInst($(id)[0]);
1016		this._adjustInstDate(inst, offset +
1017			(period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // Undo positioning
1018			period);
1019		this._updateDatepick(inst);
1020		return false;
1021	},
1022
1023	/* Show the month for today or the current selection.
1024	   @param  id  (string) the ID of the target field */
1025	_gotoToday: function(id) {
1026		var target = $(id);
1027		var inst = this._getInst(target[0]);
1028		if (this._get(inst, 'gotoCurrent') && inst.dates[0])
1029			inst.cursorDate = new Date(inst.dates[0].getTime());
1030		else
1031			inst.cursorDate = this._daylightSavingAdjust(new Date());
1032		inst.drawMonth = inst.cursorDate.getMonth();
1033		inst.drawYear = inst.cursorDate.getFullYear();
1034		this._notifyChange(inst);
1035		this._adjustDate(target);
1036		return false;
1037	},
1038
1039	/* Selecting a new month/year.
1040	   @param  id      (string) the ID of the target field
1041	   @param  select  (element) the select being chosen from
1042	   @param  period  (string) 'M' for month, 'Y' for year */
1043	_selectMonthYear: function(id, select, period) {
1044		var target = $(id);
1045		var inst = this._getInst(target[0]);
1046		inst.selectingMonthYear = false;
1047		var value = parseInt(select.options[select.selectedIndex].value, 10);
1048		inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
1049		inst['draw' + (period == 'M' ? 'Month' : 'Year')] = value;
1050		inst.cursorDate.setDate(Math.min(inst.cursorDate.getDate(),
1051			$.datepick._getDaysInMonth(inst.drawYear, inst.drawMonth)));
1052		inst.cursorDate['set' + (period == 'M' ? 'Month' : 'FullYear')](value);
1053		this._notifyChange(inst);
1054		this._adjustDate(target);
1055	},
1056
1057	/* Restore input focus after not changing month/year.
1058	   @param  id  (string) the ID of the target field */
1059	_clickMonthYear: function(id) {
1060		var inst = this._getInst($(id)[0]);
1061		if (inst.input && inst.selectingMonthYear && !$.browser_is_supported_datepick.msie)
1062			inst.input.focus();
1063		inst.selectingMonthYear = !inst.selectingMonthYear;
1064	},
1065
1066	/* Action for changing the first week day.
1067	   @param  id   (string) the ID of the target field
1068	   @param  day  (number) the number of the first day, 0 = Sun, 1 = Mon, ... */
1069	_changeFirstDay: function(id, day) {
1070		var inst = this._getInst($(id)[0]);
1071		inst.settings.firstDay = day;
1072		this._updateDatepick(inst);
1073		return false;
1074	},
1075
1076	/* Select a particular day.
1077	   @param  td         (element) the table cell containing the selection
1078	   @param  id         (string) the ID of the target field
1079	   @param  timestamp  (number) the timestamp for this day */
1080	_selectDay: function(td, id, timestamp) {
1081		var inst = this._getInst($(id)[0]);
1082		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
1083		if ($(td).hasClass(this._unselectableClass[useTR]))
1084			return false;
1085		var rangeSelect = this._get(inst, 'rangeSelect');
1086		var multiSelect = this._get(inst, 'multiSelect');
1087		if (rangeSelect)
1088			inst.stayOpen = !inst.stayOpen;
1089		else if (multiSelect)
1090			inst.stayOpen = true;
1091		if (inst.stayOpen) {
1092			$('.datepick td', inst.dpDiv).removeClass(this._selectedClass[useTR]);
1093			$(td).addClass(this._selectedClass[useTR]);
1094		}
1095		inst.cursorDate = this._daylightSavingAdjust(new Date(timestamp));
1096		var date = new Date(inst.cursorDate.getTime());
1097		if (rangeSelect && !inst.stayOpen)
1098			inst.dates[1] = date;
1099		else if (multiSelect) {
1100			var pos = -1;
1101			for (var i = 0; i < inst.dates.length; i++)
1102				if (inst.dates[i] && date.getTime() == inst.dates[i].getTime()) {
1103					pos = i;
1104					break;
1105				}
1106			if (pos > -1)
1107				inst.dates.splice(pos, 1);
1108			else if (inst.dates.length < multiSelect) {
1109				if (inst.dates[0])
1110					inst.dates.push(date);
1111				else
1112					inst.dates = [date];
1113				inst.stayOpen = (inst.dates.length != multiSelect);
1114			}
1115		}
1116		else
1117			inst.dates = [date];
1118		this._updateInput(id);
1119		if (inst.stayOpen)
1120			this._updateDatepick(inst);
1121		else if ((rangeSelect || multiSelect) && inst.inline)
1122			this._updateDatepick(inst);
1123		return false;
1124	},
1125
1126	/* Erase the input field and hide the date picker.
1127	   @param  id  (string) the ID of the target field */
1128	_clearDate: function(id) {
1129		var target = $(id);
1130		var inst = this._getInst(target[0]);
1131		if (this._get(inst, 'mandatory'))
1132			return false;
1133		inst.stayOpen = false;
1134		inst.dates = (this._get(inst, 'showDefault') ?
1135			[this._getDefaultDate(inst)] : []);
1136		this._updateInput(target);
1137		return false;
1138	},
1139
1140	/* Update the input field with the selected date.
1141	   @param  id       (string) the ID of the target field or
1142	                    (element) the target object */
1143	_updateInput: function(id) {
1144		var inst = this._getInst($(id)[0]);
1145		var dateStr = this._showDate(inst);
1146		this._updateAlternate(inst);
1147		var onSelect = this._get(inst, 'onSelect');
1148		if (onSelect)
1149			onSelect.apply((inst.input ? inst.input[0] : null),
1150				[dateStr, this._getDate(inst), inst]);  // Trigger custom callback
1151		else if (inst.input)
1152			inst.input.trigger('change'); // Fire the change event
1153		if (inst.inline)
1154			this._updateDatepick(inst);
1155		else if (!inst.stayOpen) {
1156			this._hideDatepick(null, this._get(inst, 'duration'));
1157			this._lastInput = inst.input[0];
1158			if (typeof(inst.input[0]) != 'object')
1159				inst.input.focus(); // Restore focus
1160			this._lastInput = null;
1161		}
1162		return false;
1163	},
1164
1165	/* Update the input field with the current date(s).
1166	   @param  inst  (object) the instance settings for this datepicker
1167	   @return  (string) the formatted date(s) */
1168	_showDate: function(inst) {
1169		var dateStr = '';
1170		if (inst.input) {
1171			dateStr = (inst.dates.length == 0 ? '' : this._formatDate(inst, inst.dates[0]));
1172			if (dateStr) {
1173				if (this._get(inst, 'rangeSelect'))
1174					dateStr += this._get(inst, 'rangeSeparator') +
1175						this._formatDate(inst, inst.dates[1] || inst.dates[0]);
1176				else if (this._get(inst, 'multiSelect'))
1177					for (var i = 1; i < inst.dates.length; i++)
1178						dateStr += this._get(inst, 'multiSeparator') +
1179							this._formatDate(inst, inst.dates[i]);
1180			}
1181			inst.input.val(dateStr);
1182		}
1183		return dateStr;
1184	},
1185
1186	/* Update any alternate field to synchronise with the main field.
1187	   @param  inst  (object) the instance settings for this datepicker */
1188	_updateAlternate: function(inst) {
1189		var altField = this._get(inst, 'altField');
1190		if (altField) { // Update alternate field too
1191			var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
1192			var settings = this._getFormatConfig(inst);
1193			var dateStr = this.formatDate(altFormat, inst.dates[0], settings);
1194			if (dateStr && this._get(inst, 'rangeSelect'))
1195				dateStr += this._get(inst, 'rangeSeparator') + this.formatDate(
1196					altFormat, inst.dates[1] || inst.dates[0], settings);
1197			else if (this._get(inst, 'multiSelect'))
1198				for (var i = 1; i < inst.dates.length; i++)
1199					dateStr += this._get(inst, 'multiSeparator') +
1200						this.formatDate(altFormat, inst.dates[i], settings);
1201			$(altField).val(dateStr);
1202		}
1203	},
1204
1205	/* Set as beforeShowDay function to prevent selection of weekends.
1206	   @param  date  (Date) the date to customise
1207	   @return  ([boolean, string]) is this date selectable?, what is its CSS class? */
1208	noWeekends: function(date) {
1209		return [(date.getDay() || 7) < 6, ''];
1210	},
1211
1212	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
1213	   @param  date  (Date) the date to get the week for
1214	   @return  (number) the number of the week within the year that contains this date */
1215	iso8601Week: function(date) {
1216		var checkDate = new Date(date.getTime());
1217		// Find Thursday of this week starting on Monday
1218		checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
1219		var time = checkDate.getTime();
1220		checkDate.setMonth(0); // Compare with Jan 1
1221		checkDate.setDate(1);
1222		return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
1223	},
1224
1225	/* Provide status text for a particular date.
1226	   @param  date  (Date) the date to get the status for
1227	   @param  inst  (object) the current datepicker instance
1228	   @return  (string) the status display text for this date */
1229	dateStatus: function(date, inst) {
1230		return $.datepick.formatDate($.datepick._get(inst, 'dateStatus'),
1231			date, $.datepick._getFormatConfig(inst));
1232	},
1233
1234	/* Parse a string value into a date object.
1235	   See formatDate below for the possible formats.
1236	   @param  format    (string) the expected format of the date
1237	   @param  value     (string) the date in the above format
1238	   @param  settings  (object) attributes include:
1239	                     shortYearCutoff  (number) the cutoff year for determining the century (optional)
1240	                     dayNamesShort    (string[7]) abbreviated names of the days from Sunday (optional)
1241	                     dayNames         (string[7]) names of the days from Sunday (optional)
1242	                     monthNamesShort  (string[12]) abbreviated names of the months (optional)
1243	                     monthNames       (string[12]) names of the months (optional)
1244	   @return  (Date) the extracted date value or null if value is blank */
1245	parseDate: function (format, value, settings) {
1246		if (format == null || value == null)
1247			throw 'Invalid arguments';
1248		value = (typeof value == 'object' ? value.toString() : value + '');
1249		if (value == '')
1250			return null;
1251		settings = settings || {};
1252		var shortYearCutoff = settings.shortYearCutoff || this._defaults.shortYearCutoff;
1253		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
1254			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
1255		var dayNamesShort = settings.dayNamesShort || this._defaults.dayNamesShort;
1256		var dayNames = settings.dayNames || this._defaults.dayNames;
1257		var monthNamesShort = settings.monthNamesShort || this._defaults.monthNamesShort;
1258		var monthNames = settings.monthNames || this._defaults.monthNames;
1259		var year = -1;
1260		var month = -1;
1261		var day = -1;
1262		var doy = -1;
1263		var literal = false;
1264		// Check whether a format character is doubled
1265		var lookAhead = function(match) {
1266			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
1267			if (matches)
1268				iFormat++;
1269			return matches;
1270		};
1271		// Extract a number from the string value
1272		var getNumber = function(match) {
1273			lookAhead(match);
1274			var size = (match == '@' ? 14 : (match == '!' ? 20 :
1275				(match == 'y' ? 4 : (match == 'o' ? 3 : 2))));
1276			var digits = new RegExp('^\\d{1,' + size + '}');
1277			var num = value.substring(iValue).match(digits);
1278			if (!num)
1279				throw 'Missing number at position ' + iValue;
1280			iValue += num[0].length;
1281			return parseInt(num[0], 10);
1282		};
1283		// Extract a name from the string value and convert to an index
1284		var getName = function(match, shortNames, longNames) {
1285			var names = (lookAhead(match) ? longNames : shortNames);
1286			for (var i = 0; i < names.length; i++) {
1287				if (value.substr(iValue, names[i].length) == names[i]) {
1288					iValue += names[i].length;
1289					return i + 1;
1290				}
1291			}
1292			throw 'Unknown name at position ' + iValue;
1293		};
1294		// Confirm that a literal character matches the string value
1295		var checkLiteral = function() {
1296			if (value.charAt(iValue) != format.charAt(iFormat))
1297				throw 'Unexpected literal at position ' + iValue;
1298			iValue++;
1299		};
1300		var iValue = 0;
1301		for (var iFormat = 0; iFormat < format.length; iFormat++) {
1302			if (literal)
1303				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
1304					literal = false;
1305				else
1306					checkLiteral();
1307			else
1308				switch (format.charAt(iFormat)) {
1309					case 'd':
1310						day = getNumber('d');
1311						break;
1312					case 'D':
1313						getName('D', dayNamesShort, dayNames);
1314						break;
1315					case 'o':
1316						doy = getNumber('o');
1317						break;
1318					case 'w':
1319						getNumber('w');
1320						break;
1321					case 'm':
1322						month = getNumber('m');
1323						break;
1324					case 'M':
1325						month = getName('M', monthNamesShort, monthNames);
1326						break;
1327					case 'y':
1328						year = getNumber('y');
1329						break;
1330					case '@':
1331						var date = new Date(getNumber('@'));
1332						year = date.getFullYear();
1333						month = date.getMonth() + 1;
1334						day = date.getDate();
1335						break;
1336					case '!':
1337						var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
1338						year = date.getFullYear();
1339						month = date.getMonth() + 1;
1340						day = date.getDate();
1341						break;
1342					case "'":
1343						if (lookAhead("'"))
1344							checkLiteral();
1345						else
1346							literal = true;
1347						break;
1348					default:
1349						checkLiteral();
1350				}
1351		}
1352		if (iValue < value.length)
1353			throw 'Additional text found at end';
1354		if (year == -1)
1355			year = new Date().getFullYear();
1356		else if (year < 100)
1357			year += (shortYearCutoff == -1 ? 1900 : new Date().getFullYear() -
1358				new Date().getFullYear() % 100 - (year <= shortYearCutoff ? 0 : 100));
1359		if (doy > -1) {
1360			month = 1;
1361			day = doy;
1362			do {
1363				var dim = this._getDaysInMonth(year, month - 1);
1364				if (day <= dim)
1365					break;
1366				month++;
1367				day -= dim;
1368			} while (true);
1369		}
1370		var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
1371		if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
1372			throw 'Invalid date'; // E.g. 31/02/*
1373		return date;
1374	},
1375
1376	/* Standard date formats. */
1377	ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
1378	COOKIE: 'D, dd M yy',
1379	ISO_8601: 'yy-mm-dd',
1380	RFC_822: 'D, d M y',
1381	RFC_850: 'DD, dd-M-y',
1382	RFC_1036: 'D, d M y',
1383	RFC_1123: 'D, d M yy',
1384	RFC_2822: 'D, d M yy',
1385	RSS: 'D, d M y', // RFC 822
1386	TICKS: '!',
1387	TIMESTAMP: '@',
1388	W3C: 'yy-mm-dd', // ISO 8601
1389
1390	_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
1391		Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
1392
1393	/* Format a date object into a string value.
1394	   The format can be combinations of the following:
1395	   d  - day of month (no leading zero)
1396	   dd - day of month (two digit)
1397	   o  - day of year (no leading zeros)
1398	   oo - day of year (three digit)
1399	   D  - day name short
1400	   DD - day name long
1401	   w  - week of year (no leading zero)
1402	   ww - week of year (two digit)
1403	   m  - month of year (no leading zero)
1404	   mm - month of year (two digit)
1405	   M  - month name short
1406	   MM - month name long
1407	   y  - year (two digit)
1408	   yy - year (four digit)
1409	   @ - Unix timestamp (ms since 01/01/1970)
1410	   ! - Windows ticks (100ns since 01/01/0001)
1411	   '...' - literal text
1412	   '' - single quote
1413	   @param  format    (string) the desired format of the date
1414	   @param  date      (Date) the date value to format
1415	   @param  settings  (object) attributes include:
1416	                     dayNamesShort    (string[7]) abbreviated names of the days from Sunday (optional)
1417	                     dayNames         (string[7]) names of the days from Sunday (optional)
1418	                     monthNamesShort  (string[12]) abbreviated names of the months (optional)
1419	                     monthNames       (string[12]) names of the months (optional)
1420						 calculateWeek    (function) function that determines week of the year (optional)
1421	   @return  (string) the date in the above format */
1422	formatDate: function (format, date, settings) {
1423		if (!date)
1424			return '';
1425		settings = settings || {};
1426		var dayNamesShort = settings.dayNamesShort || this._defaults.dayNamesShort;
1427		var dayNames = settings.dayNames || this._defaults.dayNames;
1428		var monthNamesShort = settings.monthNamesShort || this._defaults.monthNamesShort;
1429		var monthNames = settings.monthNames || this._defaults.monthNames;
1430		var calculateWeek = settings.calculateWeek || this._defaults.calculateWeek;
1431		// Check whether a format character is doubled
1432		var lookAhead = function(match) {
1433			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
1434			if (matches)
1435				iFormat++;
1436			return matches;
1437		};
1438		// Format a number, with leading zero if necessary
1439		var formatNumber = function(match, value, len) {
1440			var num = '' + value;
1441			if (lookAhead(match))
1442				while (num.length < len)
1443					num = '0' + num;
1444			return num;
1445		};
1446		// Format a name, short or long as requested
1447		var formatName = function(match, value, shortNames, longNames) {
1448			return (lookAhead(match) ? longNames[value] : shortNames[value]);
1449		};
1450		var output = '';
1451		var literal = false;
1452		if (date)
1453			for (var iFormat = 0; iFormat < format.length; iFormat++) {
1454				if (literal)
1455					if (format.charAt(iFormat) == "'" && !lookAhead("'"))
1456						literal = false;
1457					else
1458						output += format.charAt(iFormat);
1459				else
1460					switch (format.charAt(iFormat)) {
1461						case 'd':
1462							output += formatNumber('d', date.getDate(), 2);
1463							break;
1464						case 'D':
1465							output += formatName('D', date.getDay(), dayNamesShort, dayNames);
1466							break;
1467						case 'o':
1468							output += formatNumber('o',
1469								(date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3);
1470							break;
1471						case 'w':
1472							output += formatNumber('w', calculateWeek(date), 2);
1473							break;
1474						case 'm':
1475							output += formatNumber('m', date.getMonth() + 1, 2);
1476							break;
1477						case 'M':
1478							output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
1479							break;
1480						case 'y':
1481							output += (lookAhead('y') ? date.getFullYear() :
1482								(date.getFullYear() % 100 < 10 ? '0' : '') + date.getFullYear() % 100);
1483							break;
1484						case '@':
1485							output += date.getTime();
1486							break;
1487						case '!':
1488							output += date.getTime() * 10000 + this._ticksTo1970;
1489							break;
1490						case "'":
1491							if (lookAhead("'"))
1492								output += "'";
1493							else
1494								literal = true;
1495							break;
1496						default:
1497							output += format.charAt(iFormat);
1498					}
1499			}
1500		return output;
1501	},
1502
1503	/* Get a setting value, defaulting if necessary.
1504	   @param  inst  (object) the instance settings for this datepicker
1505	   @param  name  (string) the name of the property
1506	   @return  (any) the property's value */
1507	_get: function(inst, name) {
1508		return inst.settings[name] !== undefined ?
1509			inst.settings[name] : this._defaults[name];
1510	},
1511
1512	/* Parse existing date and initialise date picker.
1513	   @param  inst  (object) the instance settings for this datepicker */
1514	_setDateFromField: function(inst) {
1515		var dateFormat = this._get(inst, 'dateFormat');
1516		var rangeSelect = this._get(inst, 'rangeSelect');
1517		var multiSelect = this._get(inst, 'multiSelect');
1518		inst.lastVal = (inst.input ? inst.input.val() : '');
1519		var dates = inst.lastVal;
1520		dates = (rangeSelect ? dates.split(this._get(inst, 'rangeSeparator')) :
1521			(multiSelect ? dates.split(this._get(inst, 'multiSeparator')) : [dates]));
1522		inst.dates = [];
1523		var settings = this._getFormatConfig(inst);
1524		for (var i = 0; i < dates.length; i++)
1525			try {
1526				inst.dates[i] = this.parseDate(dateFormat, dates[i], settings);
1527			}
1528			catch (event) {
1529				inst.dates[i] = null;
1530			}
1531		for (var i = inst.dates.length - 1; i >= 0; i--)
1532			if (!inst.dates[i])
1533				inst.dates.splice(i, 1);
1534		if (rangeSelect && inst.dates.length < 2)
1535			inst.dates[1] = inst.dates[0];
1536		if (multiSelect && inst.dates.length > multiSelect)
1537			inst.dates.splice(multiSelect, inst.dates.length);
1538		inst.cursorDate = new Date((inst.dates[0] || this._getDefaultDate(inst)).getTime());
1539		inst.drawMonth = inst.cursorDate.getMonth();
1540		inst.drawYear = inst.cursorDate.getFullYear();
1541		this._adjustInstDate(inst);
1542	},
1543
1544	/* Retrieve the default date shown on opening.
1545	   @param  inst  (object) the instance settings for this datepicker
1546	   @return  (Date) the default date */
1547	_getDefaultDate: function(inst) {
1548		return this._restrictMinMax(inst,
1549			this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
1550	},
1551
1552	/* A date may be specified as an exact value or a relative one.
1553	   @param  inst         (object) the instance settings for this datepicker
1554	   @param  date         (Date or number or string) the date or offset
1555	   @param  defaultDate  (Date) the date to use if no other supplied
1556	   @return  (Date) the decoded date */
1557	_determineDate: function(inst, date, defaultDate) {
1558		var offsetNumeric = function(offset) {
1559			var date = new Date();
1560			date.setDate(date.getDate() + offset);
1561			return date;
1562		};
1563		var offsetString = function(offset) {
1564			try {
1565				return $.datepick.parseDate($.datepick._get(inst, 'dateFormat'),
1566					offset, $.datepick._getFormatConfig(inst));
1567			}
1568			catch (e) {
1569				// Ignore
1570			}
1571			var date = (offset.toLowerCase().match(/^c/) ?
1572				$.datepick._getDate(inst) : null) || new Date();
1573			var year = date.getFullYear();
1574			var month = date.getMonth();
1575			var day = date.getDate();
1576			var pattern = /([+-]?[0-9]+)\s*(d|w|m|y)?/g;
1577			var matches = pattern.exec(offset.toLowerCase());
1578			while (matches) {
1579				switch (matches[2] || 'd') {
1580					case 'd':
1581						day += parseInt(matches[1], 10); break;
1582					case 'w':
1583						day += parseInt(matches[1], 10) * 7; break;
1584					case 'm':
1585						month += parseInt(matches[1], 10);
1586						day = Math.min(day, $.datepick._getDaysInMonth(year, month));
1587						break;
1588					case 'y':
1589						year += parseInt(matches[1], 10);
1590						day = Math.min(day, $.datepick._getDaysInMonth(year, month));
1591						break;
1592				}
1593				matches = pattern.exec(offset.toLowerCase());
1594			}
1595			return new Date(year, month, day);
1596		};
1597		date = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) :
1598			(typeof date == 'number' ? (isNaN(date) || date == Infinity || date == -Infinity ?
1599			defaultDate : offsetNumeric(date)) : date)));
1600		date = (date && (date.toString() == 'Invalid Date' ||
1601			date.toString() == 'NaN') ? defaultDate : date);
1602		if (date) {
1603			date.setHours(0);
1604			date.setMinutes(0);
1605			date.setSeconds(0);
1606			date.setMilliseconds(0);
1607		}
1608		return this._daylightSavingAdjust(date);
1609	},
1610
1611	/* Handle switch to/from daylight saving.
1612	   Hours may be non-zero on daylight saving cut-over:
1613	   > 12 when midnight changeover, but then cannot generate
1614	   midnight datetime, so jump to 1AM, otherwise reset.
1615	   @param  date  (Date) the date to check
1616	   @return  (Date) the corrected date */
1617	_daylightSavingAdjust: function(date) {
1618		if (!date) return null;
1619		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
1620		return date;
1621	},
1622
1623	/* Set the date(s) directly.
1624	   @param  inst     (object) the instance settings for this datepicker
1625	   @param  date     (Date or Date[] or number or string) the new date or start of a range
1626	   @param  endDate  (Date or number or string) the end of a range */
1627	_setDate: function(inst, date, endDate) {
1628		date = (!date ? [] : (isArray(date) ? date : [date]));
1629		if (endDate)
1630			date.push(endDate);
1631		var clear = (date.length == 0);
1632		var origMonth = inst.cursorDate.getMonth();
1633		var origYear = inst.cursorDate.getFullYear();
1634		inst.dates = [this._restrictMinMax(inst, this._determineDate(inst, date[0], new Date()))];
1635		inst.cursorDate = new Date(inst.dates[0].getTime());
1636		inst.drawMonth = inst.cursorDate.getMonth();
1637		inst.drawYear = inst.cursorDate.getFullYear();
1638		if (this._get(inst, 'rangeSelect'))
1639			inst.dates[1] = (date.length < 1 ? inst.dates[0] :
1640				this._restrictMinMax(inst, this._determineDate(inst, date[1], null)));
1641		else if (this._get(inst, 'multiSelect'))
1642			for (var i = 1; i < date.length; i++)
1643				inst.dates[i] = this._restrictMinMax(inst, this._determineDate(inst, date[i], null));
1644		if (origMonth != inst.cursorDate.getMonth() || origYear != inst.cursorDate.getFullYear())
1645			this._notifyChange(inst);
1646		this._adjustInstDate(inst);
1647		this._showDate(inst);
1648	},
1649
1650	/* Retrieve the date(s) directly.
1651	   @param  inst  (object) the instance settings for this datepicker
1652	   @return  (Date or Date[2] or Date[]) the current date or dates
1653	            (for a range or multiples) */
1654	_getDate: function(inst) {
1655		var startDate = (inst.input && inst.input.val() == '' ? null : inst.dates[0]);
1656		if (this._get(inst, 'rangeSelect'))
1657			return (startDate ? [inst.dates[0], inst.dates[1] || inst.dates[0]] : [null, null]);
1658		else if (this._get(inst, 'multiSelect'))
1659			return inst.dates.slice(0, inst.dates.length);
1660		else
1661			return startDate;
1662	},
1663
1664
1665	/* Generate the HTML for the current state of the date picker.
1666	   @param  inst  (object) the instance settings for this datepicker
1667	   @return  (string) the new HTML for the datepicker */
1668	_generateHTML: function(inst) {
1669		var today = new Date();
1670		today = this._daylightSavingAdjust(
1671			new Date(today.getFullYear(), today.getMonth(), today.getDate())); // Clear time
1672
1673
1674		var showStatus = this._get(inst, 'showStatus');
1675		var initStatus = this._get(inst, 'initStatus') || '&#xa0;';
1676		var isRTL = this._get(inst, 'isRTL');
1677		var useTR = this._get(inst, 'useThemeRoller') ? 1 : 0;
1678		// Build the date picker HTML
1679		var clear = (this._get(inst, 'mandatory') ? '' :
1680			'<div class="' + this._clearClass[useTR] + '"><a href="javascript:void(0)" ' +
1681			'onclick="jQuery.datepick._clearDate(\'#' + inst.id + '\');"' +
1682			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'clearStatus'), initStatus) +
1683			'>' + this._get(inst, 'clearText') + '</a></div>');
1684		var controls = '<div class="' + this._controlClass[useTR] + '">' + (isRTL ? '' : clear) +
1685			'<div class="' + this._closeClass[useTR] + '"><a href="javascript:void(0)" ' +
1686			'onclick="jQuery.datepick._hideDatepick();"' +
1687			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'closeStatus'), initStatus) +
1688			'>' + this._get(inst, 'closeText') + '</a></div>' + (isRTL ? clear : '')  + '</div>';
1689		var prompt = this._get(inst, 'prompt');
1690		var closeAtTop = this._get(inst, 'closeAtTop');
1691		var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
1692		var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
1693		var showBigPrevNext = this._get(inst, 'showBigPrevNext');
1694		var numMonths = this._getNumberOfMonths(inst);
1695		var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
1696		var stepMonths = this._get(inst, 'stepMonths');
1697		var stepBigMonths = this._get(inst, 'stepBigMonths');
1698		var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
1699		var minDate = this._getMinMaxDate(inst, 'min', true);
1700		var maxDate = this._getMinMaxDate(inst, 'max');
1701		var drawMonth = inst.drawMonth - showCurrentAtPos;
1702		var drawYear = inst.drawYear;
1703		if (drawMonth < 0) {
1704			drawMonth += 12;
1705			drawYear--;
1706		}
1707		if (maxDate) { // Don't show past maximum unless also restricted by minimum
1708			var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
1709				maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
1710			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
1711			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
1712				drawMonth--;
1713				if (drawMonth < 0) {
1714					drawMonth = 11;
1715					drawYear--;
1716				}
1717			}
1718		}
1719		inst.drawMonth = drawMonth;
1720		inst.drawYear = drawYear;
1721		// Controls and links
1722		var prevText = this._get(inst, 'prevText');
1723		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
1724			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
1725			this._getFormatConfig(inst)));
1726		var prevBigText = (showBigPrevNext ? this._get(inst, 'prevBigText') : '');
1727		prevBigText = (!navigationAsDateFormat ? prevBigText : this.formatDate(prevBigText,
1728			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepBigMonths, 1)),
1729			this._getFormatConfig(inst)));
1730		var prev = '<div class="' + this._prevClass[useTR] + '">' +
1731			(this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
1732			(showBigPrevNext ? '<a href="javascript:void(0)" onclick="jQuery.datepick._adju
1732stDate(\'#' +
1733			inst.id + '\', -' + stepBigMonths + ', \'M\');"' +
1734			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'prevBigStatus'), initStatus) +
1735			'>' + prevBigText + '</a>' : '') +
1736			'<a href="javascript:void(0)" onclick="jQuery.datepick._adjustDate(\'#' +
1737			inst.id + '\', -' + stepMonths + ', \'M\');"' +
1738			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'prevStatus'), initStatus) +
1739			'>' + prevText + '</a>' :
1740			(hideIfNoPrevNext ? '&#xa0;' : (showBigPrevNext ? '<label>' + prevBigText + '</label>' : '') +
1741			'<label>' + prevText + '</label>')) + '</div>';
1742		var nextText = this._get(inst, 'nextText');
1743		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
1744			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
1745			this._getFormatConfig(inst)));
1746		var nextBigText = (showBigPrevNext ? this._get(inst, 'nextBigText') : '');
1747		nextBigText = (!navigationAsDateFormat ? nextBigText : this.formatDate(nextBigText,
1748			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepBigMonths, 1)),
1749			this._getFormatConfig(inst)));
1750		var next = '<div class="' + this._nextClass[useTR] + '">' +
1751			(this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
1752			'<a href="javascript:void(0)" onclick="jQuery.datepick._adjustDate(\'#' +
1753			inst.id + '\', +' + stepMonths + ', \'M\');"' +
1754			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'nextStatus'), initStatus) +
1755			'>' + nextText + '</a>' +
1756			(showBigPrevNext ? '<a href="javascript:void(0)" onclick="jQuery.datepick._adjustDate(\'#' +
1757			inst.id + '\', +' + stepBigMonths + ', \'M\');"' +
1758			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'nextBigStatus'), initStatus) +
1759			'>' + nextBigText + '</a>' : '') :
1760			(hideIfNoPrevNext ? '&#xa0;' : '<label>' + nextText + '</label>' +
1761			(showBigPrevNext ? '<label>' + nextBigText + '</label>' : ''))) + '</div>';
1762		var currentText = this._get(inst, 'currentText');
1763		var gotoDate = (this._get(inst, 'gotoCurrent') && inst.dates[0] ? inst.dates[0] : today);
1764		currentText = (!navigationAsDateFormat ? currentText :
1765			this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
1766		var html = (closeAtTop && !inst.inline ? controls : '');/* +
1767			'<div class="' + this._linksClass[useTR] + '">' + (isRTL ? next : prev) +
1768			'<div class="' + this._currentClass[useTR] + '">' + (this._isInRange(inst, gotoDate) ?
1769			'<a href="javascript:void(0)" onclick="jQuery.datepick._gotoToday(\'#' + inst.id + '\');"' +
1770			this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'currentStatus'), initStatus) + '>' +
1771			currentText + '</a>' : (hideIfNoPrevNext ? '&#xa0;' : '<label>' + currentText + '</label>')) +
1772			'</div>' + (isRTL ? prev : next) + '</div>' +
1773			(prompt ? '<div class="' + this._promptClass[useTR] + '"><span>' +
1774			prompt + '</span></div>' : '');/**/
1775                    html +=  '<div class="calendar-links">' + (isRTL ? next : prev)   ;
1776                    html +=    (isRTL ? prev : next) + '</div>' ;
1777		var firstDay = parseInt(this._get(inst, 'firstDay'), 10);
1778		firstDay = (isNaN(firstDay) ? 0 : firstDay);
1779		var changeFirstDay = this._get(inst, 'changeFirstDay');
1780		var dayNames = this._get(inst, 'dayNames');
1781		var dayNamesShort = this._get(inst, 'dayNamesShort');
1782		var dayNamesMin = this._get(inst, 'dayNamesMin');
1783		var monthNames = this._get(inst, 'monthNames');
1784		var beforeShowDay = this._get(inst, 'beforeShowDay');
1785		var showOtherMonths = this._get(inst, 'showOtherMonths');
1786		var selectOtherMonths = this._get(inst, 'selectOtherMonths');
1787		var showWeeks = this._get(inst, 'showWeeks');
1788		var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
1789		var weekStatus = this._get(inst, 'weekStatus');
1790		var status = (showStatus ? this._get(inst, 'dayStatus') || initStatus : '');
1791		var dateStatus = this._get(inst, 'statusForDate') || this.dateStatus;
1792		var defaultDate = this._getDefaultDate(inst);
1793		for (var row = 0; row < numMonths[0]; row++) {
1794			for (var col = 0; col < numMonths[1]; col++) {
1795				var cursorDate = this._daylightSavingAdjust(
1796					new Date(drawYear, drawMonth, inst.cursorDate.getDate()));
1797				html += '<div class="' + this._oneMonthClass[useTR] +            // Responsive skin
1798					(col == 0 && !useTR ? ' ' + this._newRowClass[useTR] : '') + '">' +
1799					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
1800					cursorDate, row > 0 || col > 0, useTR, showStatus, initStatus, monthNames) + // Draw month headers
1801					'<table class="' + this._tableClass[useTR] + '" cellpadding="0" cellspacing="0"><thead>' +
1802					'<tr class="' + this._tableHeaderClass[useTR] + '">' + (showWeeks ? '<th' +
1803					this._addStatus(useTR, showStatus, inst.id, weekStatus, initStatus) + '>' +
1804					this._get(inst, 'weekHeader') + '</th>' : '');
1805				for (var dow = 0; dow < 7; dow++) { // Days of the week
1806					var day = (dow + firstDay) % 7;
1807					var dayStatus = (!showStatus || !changeFirstDay ? '' :
1808						status.replace(/DD/, dayNames[day]).replace(/D/, dayNamesShort[day]));
1809					html += '<th' + ((dow + firstDay + 6) % 7 < 5 ? '' :
1810						' class="' + this._weekendClass[useTR] + '"') + '>
1810' +
1811						(!changeFirstDay ? '<span' +
1812						this._addStatus(useTR, showStatus, inst.id, dayNames[day], initStatus) :
1813						'<a href="javascript:void(0)" onclick="jQuery.datepick._changeFirstDay(\'#' +
1814						inst.id + '\', ' + day + ');"' +
1815						this._addStatus(useTR, showStatus, inst.id, dayStatus, initStatus)) +
1816						' title="' + dayNames[day] + '">' +
1817						dayNamesMin[day] + (changeFirstDay ? '</a>' : '</span>') + '</th>';
1818				}
1819				html += '</tr></thead><tbody>';
1820				var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
1821				if (drawYear == inst.cursorDate.getFullYear() && drawMonth == inst.cursorDate.getMonth())
1822					inst.cursorDate.setDate(Math.min(inst.cursorDate.getDate(), daysInMonth));
1823				var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
1824				var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7));
1825				var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
1826				for (var dRow = 0; dRow < numRows; dRow++) { // Create datepicker rows
1827					html += '<tr class="' + this._weekRowClass[useTR] + '">' +
1828						(showWeeks ? '<td class="' + this._weekColClass[useTR] + '"' +
1829						this._addStatus(useTR, showStatus, inst.id, weekStatus, initStatus) + '>' +
1830						calculateWeek(printDate) + '</td>' : '');
1831					for (var dow = 0; dow < 7; dow++) { // Create datepicker days
1832						var daySettings = (beforeShowDay ?
1833							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
1834						var otherMonth = (printDate.getMonth() != drawMonth);
1835						var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
1836							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
1837						var selected = (this._get(inst, 'rangeSelect') && inst.dates[0] &&
1838							printDate.getTime() >= inst.dates[0].getTime() &&
1839							printDate.getTime() <= (inst.dates[1] || inst.dates[0]).getTime());
1840						for (var i = 0; i < inst.dates.length; i++)
1841							selected = selected || (inst.dates[i] &&
1842								printDate.getTime() == inst.dates[i].getTime());
1843						var empty = otherMonth && !showOtherMonths;
1844						html += '<td data-content="" class="' + this._dayClass[useTR] +
1845							((dow + firstDay + 6) % 7 >= 5 ? ' ' + this._weekendClass[useTR] : '') + // Highlight weekends
1846							(otherMonth ? ' ' + this._otherMonthClass[useTR] : '') + // Highlight days from other months
1847							((printDate.getTime() == cursorDate.getTime() &&
1848							drawMonth == inst.cursorDate.getMonth() && inst.keyEvent) || // User pressed key
1849							(defaultDate.getTime() == printDate.getTime() &&
1850							defaultDate.getTime() == cursorDate.getTime()) ?
1851							// Or defaultDate is selected printedDate and defaultDate is cursorDate
1852							' ' + $.datepick._dayOverClass[useTR] : '') + // Highlight selected day
1853							(unselectable ? ' ' + this._unselectableClass[useTR] :
1854							' ' + this._selectableClass[useTR]) +  // Highlight unselectable days
1855							(empty ? '' : ' ' + daySettings[1] + // Highlight custom dates
1856							(selected ? ' ' + this._selectedClass[useTR] : '') + // Currently selected
1857							// Highlight today (if different)
1858							(printDate.getTime() == today.getTime() ? ' ' + this._todayClass[useTR] : '')) + '"' +
1859							(!empty && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // Cell title
1860							(unselectable ? '' : ' onmouseover="' + 'jQuery.datepick._doMouseOver(this,\'' +
1861							inst.id + '\',' + printDate.getTime() + ')"' +
1862							' onmouseout="jQuery.datepick._doMouseOut(this,\'' + inst.id + '\')"' +
1863							' onclick="jQuery.datepick._selectDay(this,\'#' + // Select
1864							inst.id + '\',' + printDate.getTime() + ')"') + '>'+
1865                                                        '<div class="check-in-div"><div></div></div>' +
1866                                                        '<div class="check-out-div"><div></div></div>' +
1867                                                        '<div class="date-content-top">' +
1868                                                            ( unselectable ? '': ( ( typeof( wpbc_show_date_info_top ) == 'function' ) ? wpbc_show_date_info_top( inst.id, printDate.getTime() ) : '' ) )  +
1869                                                        '</div>' +
1870							(empty ? '&#xa0;' : // Not showing other months //FixIn:6.0.1.2
1871							(unselectable ? '<span>' + printDate.getDate()+ '</span>' : '<a>' + printDate.getDate() + '</a>')) +                                                                
1872                                                        '<div class="date-content-bottom">'+
1873                                                           ( unselectable ? '': ( ( typeof( wpbc_show_date_info_bottom ) == 'function' ) ? wpbc_show_date_info_bottom( inst.id, printDate.getTime() ) : '' ) )  +
1874                                                        '</div>' +                                                        
1875                                                        '</td>';
1876						printDate.setDate(printDate.getDate() + 1);
1877						printDate = this._daylightSavingAdjust(printDate);
1878					}
1879					html += '</tr>';
1880				}
1881				drawMonth++;
1882				if (drawMonth > 11) {
1883					drawMonth = 0;
1884					drawYear++;
1885				}
1886				html += '</tbody></table></div>';
1887			}
1888			if (useTR)
1889				html += '<div class="' + this._newRowClass[useTR] + '"></div>';
1890		}
1891		html += (showStatus ? '<div style="clear: both;"></div><div id="' + this._statusId[useTR] +
1892			inst.id +'" class="' + this._statusClass[useTR] + '">' + initStatus + '</div>' : '') +
1893			(!closeAtTop && !inst.inline ? controls : '') +
1894			'<div style="clear: both;"></div>' +
1895			($.browser_is_supported_datepick.msie && parseInt($.browser_is_supported_datepick.version, 10) < 7 && !inst.inline ?
1896			'<iframe src="javascript:false;" class="' + this._coverClass[useTR] + '"></iframe>' : '');
1897		inst.keyEvent = false;
1898		return html;
1899	},
1900
1901	/* Generate the month and year header.
1902	   @param  inst        (object) the instance settings for this datepicker
1903	   @param  drawMonth   (number) the current month
1904	   @param  drawYear    (number) the current year
1905	   @param  minDate     (Date) the minimum allowed date or null if none
1906	   @param  maxDate     (Date) the maximum allowed date or null if none
1907	   @param  cursorDate  (Date) the current date position
1908	   @param  secondary   (boolean) true if not the first month/year header
1909	   @param  useTR       (number) 1 if applying ThemeRoller styling, 0 if not
1910	   @param  showStatus  (boolean) true if status bar is visible
1911	   @param  initStatus  (string) the default status message
1912	   @param  monthNames  (string[12]) the names of the months
1913	   @return  (string) the HTML for the month and year */
1914	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
1915			cursorDate, secondary, useTR, showStatus, initStatus, monthNames) {
1916		var minDraw = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1));
1917		minDate = (minDate && minDraw < minDate ? minDraw : minDate);
1918		var changeMonth = this._get(inst, 'changeMonth');
1919		var changeYear = this._get(inst, 'changeYear');
1920		var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
1921		var html = '<div class="' + this._monthYearClass[useTR] + '">';
1922		var monthHtml = '';
1923		// Month selection
1924		if (secondary || !changeMonth)
1925			monthHtml += '<span class="' + this._monthClass[useTR] + '">' +
1926				monthNames[drawMonth] + '</span>';
1927		else {
1928			var inMinYear = (minDate && minDate.getFullYear() == drawYear);
1929			var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
1930			monthHtml += '<select class="' + this._monthSelectClass[useTR] + '" ' +
1931				'onchange="jQuery.datepick._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
1932				'onclick="jQuery.datepick._clickMonthYear(\'#' + inst.id + '\');"' +
1933				this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'monthStatus'),
1934				initStatus) + '>';
1935			for (var month = 0; month < 12; month++) {
1936				if ((!inMinYear || month >= minDate.getMonth()) &&
1937						(!inMaxYear || month <= maxDate.getMonth()))
1938					monthHtml += '<option value="' + month + '"' +
1939						(month == drawMonth ? ' selected="selected"' : '') +
1940						'>' + monthNames[month] + '</option>';
1941			}
1942			monthHtml += '</select>';
1943		}
1944		if (!showMonthAfterYear)
1945			html += monthHtml + (secondary || !changeMonth || !changeYear ? '&#xa0;' : '');
1946		// Year selection
1947		if (secondary || !changeYear)
1948			html += '<span class="' + this._yearClass[useTR] + '">' + drawYear + '</span>';
1949		else {
1950			// Determine range of years to display
1951			var years = this._get(inst, 'yearRange').split(':');
1952			var year = 0;
1953			var endYear = 0;
1954			if (years.length != 2) {
1955				year = drawYear - 10;
1956				endYear = drawYear + 10;
1957			} else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
1958				year = drawYear + parseInt(years[0], 10);
1959				endYear = drawYear + parseInt(years[1], 10);
1960			} else {
1961				year = parseInt(years[0], 10);
1962				endYear = parseInt(years[1], 10);
1963			}
1964			year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
1965			endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
1966			html += '<select class="' + this._yearSelectClass[useTR] + '" ' +
1967				'onchange="jQuery.datepick._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
1968				'onclick="jQuery.datepick._clickMonthYear(\'#' + inst.id + '\');"' +
1969				this._addStatus(useTR, showStatus, inst.id, this._get(inst, 'yearStatus'),
1970				initStatus) + '>';
1971			for (; year <= endYear; year++) {
1972				html += '<option value="' + year + '"' +
1973					(year == drawYear ? ' selected="selected"' : '') +
1974					'>' + year + '</option>';
1975			}
1976			html += '</select>';
1977		}
1978		html += this._get(inst, 'yearSuffix');
1979		if (showMonthAfterYear)
1980			html += (secondary || !changeMonth || !changeYear ? '&#xa0;' : '') + monthHtml;
1981		html += '</div>'; // Close datepicker_header
1982		return html;
1983	},
1984
1985	/* Provide code to set and clear the status panel.
1986	   @param  useTR       (number) 1 if applying ThemeRoller styling, 0 if not
1987	   @param  showStatus  (boolean) true if the status bar is shown
1988	   @param  id          (string) the ID of the datepicker instance
1989	   @param  text        (string) the status text to display
1990	   @param  initStatus  (string) the default status message
1991	   @return  (string) hover actions for the status messages */
1992	_addStatus: function(useTR, showStatus, id, text, initStatus) {
1993		return (showStatus ? ' onmouseover="jQuery(\'#' + this._statusId[useTR] + id +
1994			'\').html(\'' + (text || initStatus) + '\');" ' +
1995			'onmouseout="jQuery(\'#' + this._statusId[useTR] + id +
1996			'\').html(\'' + initStatus + '\');"' : '');
1997	},
1998
1999	/* Adjust one of the date sub-fields.
2000	   @param  inst    (object) the instance settings for this datepicker
2001	   @param  offset  (number) the change to apply
2002	   @param  period  (string) 'D' for days, 'M' for months, 'Y' for years */
2003	_adjustInstDate: function(inst, offset, period) {
2004		var yearMonth = inst.drawYear + '/' + inst.drawMonth;
2005		var year = inst.drawYear + (period == 'Y' ? offset : 0);
2006		var month = inst.drawMonth + (period == 'M' ? offset : 0);
2007		var day = Math.min(inst.cursorDate.getDate(), this._getDaysInMonth(year, month)) +
2008			(period == 'D' ? offset : 0);
2009		inst.cursorDate = this._restrictMinMax(inst,
2010			this._daylightSavingAdjust(new Date(year, month, day)));
2011		inst.drawMonth = inst.cursorDate.getMonth();
2012		inst.drawYear = inst.cursorDate.getFullYear();
2013		if (yearMonth != inst.drawYear + '/' + inst.drawMonth)
2014			this._notifyChange(inst);
2015	},
2016
2017	/* Ensure a date is within any min/max bounds.
2018	   @param  inst  (object) the instance settings for this datepicker
2019	   @param  date  (Date) the date to check
2020	   @return  (Date) the restricted date */
2021	_restrictMinMax: function(inst, date) {
2022		var minDate = this._getMinMaxDate(inst, 'min', true);
2023		var maxDate = this._getMinMaxDate(inst, 'max');
2024		date = (minDate && date < minDate ? new Date(minDate.getTime()) : date);
2025		date = (maxDate && date > maxDate ? new Date(maxDate.getTime()) : date);
2026		return date;
2027	},
2028
2029	/* Notify change of month/year.
2030	   @param  inst  (object) the instance settings for this datepicker */
2031	_notifyChange: function(inst) {
2032		var onChange = this._get(inst, 'onChangeMonthYear');
2033		if (onChange)
2034			onChange.apply((inst.input ? inst.input[0] : null),
2035				[inst.cursorDate.getFullYear(), inst.cursorDate.getMonth() + 1,
2036				this._daylightSavingAdjust(new Date(
2037				inst.cursorDate.getFullYear(), inst.cursorDate.getMonth(), 1)), inst]);
2038	},
2039
2040	/* Determine the number of months to show.
2041	   @param  inst  (object) the instance settings for this datepicker
2042	   @return  (number[2]) the number of rows and columns to display */
2043	_getNumberOfMonths: function(inst) {
2044		var numMonths = this._get(inst, 'numberOfMonths');
2045		return (numMonths == null ? [1, 1] :
2046			(typeof numMonths == 'number' ? [1, numMonths] : numMonths));
2047	},
2048
2049	/* Determine the current minimum/maximum date.
2050	   Ensure no time components are set. May be overridden for a range.
2051	   @param  inst        (object) the instance settings for this datepicker
2052	   @param  minMax      (string) 'min' or 'max' for required date
2053	   @param  checkRange  (boolean) true to allow override for a range minimum
2054	   @return  (Date) the minimum/maximum date or null if none */
2055	_getMinMaxDate: function(inst, minMax, checkRange) {
2056		var date = this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
2057		var rangeMin = this._getRangeMin(inst);
2058		return (checkRange && rangeMin && (!date || rangeMin > date) ? rangeMin : date);
2059	},
2060
2061	/* Retrieve the temporary range minimum when in the process of selecting.
2062	   @param  inst  (object) the instance settings for this datepicker
2063	   @return  (Date) the temporary minimum or null */
2064	_getRangeMin: function(inst) {
2065		return (this._get(inst, 'rangeSelect') && inst.dates[0] &&
2066			!inst.dates[1] ? inst.dates[0] : null);
2067	},
2068
2069	/* Find the number of days in a given month.
2070	   @param  year   (number) the full year
2071	   @param  month  (number) the month (0 to 11)
2072	   @return  (number) the number of days in this month */
2073	_getDaysInMonth: function(year, month) {
2074		return 32 - new Date(year, month, 32).getDate();
2075	},
2076
2077	/* Find the day of the week of the first of a month.
2078	   @param  year   (number) the full year
2079	   @param  month  (number) the month (0 to 11)
2080	   @return  (number) 0 = Sunday, 1 = Monday, ... */
2081	_getFirstDayOfMonth: function(year, month) {
2082		return new Date(year, month, 1).getDay();
2083	},
2084
2085	/* Determines if we should allow a "prev/next" month display change.
2086	   @param  inst      (object) the instance settings for this datepicker
2087	   @param  offset    (number) the number of months to change by
2088	   @param  curYear   (number) the full current year
2089	   @param  curMonth  (number) the current month (0 to 11)
2090	   @return  (boolean) true if prev/next allowed, false if not */
2091	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
2092		var numMonths = this._getNumberOfMonths(inst);
2093		var date = this._daylightSavingAdjust(new Date(curYear,
2094			curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
2095		if (offset < 0)
2096			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
2097		return this._isInRange(inst, date);
2098	},
2099
2100	/* Is the given date in the accepted range?
2101	   @param  inst  (object) the instance settings for this datepicker
2102	   @param  date  (Date) the date to check
2103	   @return  (boolean) true if the date is in the allowed minimum/maximum, false if not */
2104	_isInRange: function(inst, date) {
2105		// During range selection, use minimum of selected date and range start
2106		var minDate = this._getRangeMin(inst) || this._getMinMaxDate(inst, 'min');
2107		var maxDate = this._getMinMaxDate(inst, 'max');
2108		return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
2109	},
2110
2111	/* Provide the configuration settings for formatting/parsing.
2112	   @param  inst  (object) the instance settings for this datepicker
2113	   @return  (object) the settings subset */
2114	_getFormatConfig: function(inst) {
2115		return {shortYearCutoff: this._get(inst, 'shortYearCutoff'),
2116			dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
2117			monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
2118	},
2119
2120	/* Format the given date for display.
2121	   @param  inst   (object) the instance settings for this datepicker
2122	   @param  year   (number, optional) the full year
2123	   @param  month  (number, optional) the month of the year (0 to 11)
2124	   @param  day    (number, optional) the day of the month
2125	   @return  (string) formatted date */
2126	_formatDate: function(inst, year, month, day) {
2127		if (!year)
2128			inst.dates[0] = new Date(inst.cursorDate.getTime());
2129		var date = (year ? (typeof year == 'object' ? year :
2130			this._daylightSavingAdjust(new Date(year, month, day))) : inst.dates[0]);
2131		return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
2132	}
2133});
2134
2135/* jQuery extend now ignores nulls!
2136   @param  target  (object) the object to extend
2137   @param  props   (object) the new settings
2138   @return  (object) the updated object */
2139function extendRemove(target, props) {
2140	$.extend(target, props);
2141	for (var name in props)
2142		if (props[name] == null || props[name] == undefined)
2143			target[name] = props[name];
2144	return target;
2145};
2146
2147/* Determine whether an object is an array.
2148   @param  a  (object) the object to test
2149   @return  (boolean) true if an array, false if not */
2150function isArray(a) {
2151	return (a && a.constructor == Array);
2152};
2153
2154/* Invoke the datepicker functionality.
2155   @param  options  (string) a command, optionally followed by additional parameters or
2156                    (object) settings for attaching new datepicker functionality
2157   @return  (jQuery) jQuery object */
2158$.fn.datepick = function(options){
2159	var otherArgs = Array.prototype.slice.call(arguments, 1);
2160	if (typeof options == 'string' && (options == 'isDisabled' ||
2161			options == 'getDate' || options == 'settings'))
2162		return $.datepick['_' + options + 'Datepick'].
2163			apply($.datepick, [this[0]].concat(otherArgs));
2164	if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
2165		return $.datepick['_' + options + 'Datepick'].
2166			apply($.datepick, [this[0]].concat(otherArgs));
2167	return this.each(function() {
2168		typeof options == 'string' ?
2169			$.datepick['_' + options + 'Datepick'].
2170				apply($.datepick, [this].concat(otherArgs)) :
2171			$.datepick._attachDatepick(this, options);
2172	});
2173};
2174
2175$.datepick = new Datepick(); // Singleton instance
2176
2177$(function() {
2178	$(document).mousedown($.datepick._checkExternalClick).
2179		find('body').append($.datepick.dpDiv);
2180});
2181
2182})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.