PageSourceSearch

https://www.ing.com.tr/documents/IngBank/assets/plugins/jquery-datepicker/jquery.datePicker.js?v=20260918

js ing.com.tr collected 2026-09-24 09:14:30 UTC 109,138 bytes, 2,511 lines download raw bytes

1/**
2 * Copyright (c) 2008 Kelvin Luck (http://www.kelvinluck.com/)
3 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
4 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
5 * .
6 * $Id$
7 **/
8
9(function ($) {
10
11    $.fn.extend({
12        /**
13         * Render a calendar table into any matched elements.
14         *
15         * @param Object s (optional) Customize your calendars.
16         * @option Number month The month to render (NOTE that months are zero based). Default is today's month.
17         * @option Number year The year to render. Default is today's year.
18         * @option Function renderCallback A reference to a function that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Default is no callback.
19         * @option Number showHeader Whether or not to show the header row, possible values are: $.dpConst.SHOW_HEADER_NONE (no header), $.dpConst.SHOW_HEADER_SHORT (first letter of each day) and $.dpConst.SHOW_HEADER_LONG (full name of each day). Default is $.dpConst.SHOW_HEADER_SHORT.
20         * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
21         * @type jQuery
22         * @name renderCalendar
23         * @cat plugins/datePicker
24         * @author Kelvin Luck (http://www.kelvinluck.com/)
25         *
26         * @example $('#calendar-me').renderCalendar({month:0, year:2007});
27         * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me.
28         *
29         * @example
30         * var testCallback = function($td, thisDate, month, year)
31         * {
32         * if ($td.is('.current-month') && thisDate.getDay() == 4) {
33         *		var d = thisDate.getDate();
34         *		$td.on(
35         *			'click',
36         *			function()
37         *			{
38         *				alert('You clicked on ' + d + '/' + (Number(month)+1) + '/' + year);
39         *			}
40         *		).addClass('thursday');
41         *	} else if (thisDate.getDay() == 5) {
42         *		$td.html('Friday the ' + $td.html() + 'th');
43         *	}
44         * }
45         * $('#calendar-me').renderCalendar({month:0, year:2007, renderCallback:testCallback});
46         *
47         * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me. Every Thursday in the current month has a class of "thursday" applied to it, is clickable and shows an alert when clicked. Every Friday on the calendar has the number inside replaced with text.
48         **/
49        renderCalendar: function (s) {
50            var dc = function (a) {
51                return document.createElement(a);
52            };
53
54            s = $.extend({}, $.fn.datePicker.defaults, s);
55
56            if (s.showHeader != $.dpConst.SHOW_HEADER_NONE) {
57                var headRow = $(dc('tr'));
58                for (var i = Date.firstDayOfWeek; i < Date.firstDayOfWeek + 7; i++) {
59                    var weekday = i % 7;
60                    var day = Date.dayNames[weekday];
61                    var dayShort = Date.abbrDayNames[weekday];
62                    headRow.append(
63						jQuery(dc('th')).attr({ 'scope': 'col', 'abbr': day, 'title': day, 'class': (weekday == 0 || weekday == 6 ? 'weekend' : 'weekday') }).html(s.showHeader == $.dpConst.SHOW_HEADER_SHORT ? dayShort : day)
64					);
65                }
66            };
67
68            var calendarTable = $(dc('table'))
69									.attr(
70										{
71										    'cellspacing': 2
72										}
73									)
74									.addClass('jCalendar')
75									.append(
76										(s.showHeader != $.dpConst.SHOW_HEADER_NONE ?
77											$(dc('thead'))
78												.append(headRow)
79											:
80											dc('thead')
81										)
82									);
83            var tbody = $(dc('tbody'));
84
85            var today = (new Date()).zeroTime();
86            today.setHours(12);
87
88            var month = s.month == undefined ? today.getMonth() : s.month;
89            var year = s.year || today.getFullYear();
90
91            var currentDate = (new Date(year, month, 1, 12, 0, 0));
92
93            var firstDayOffset = Date.firstDayOfWeek - currentDate.getDay() + 1;
94            if (firstDayOffset > 1) firstDayOffset -= 7;
95            var weeksToDraw = Math.ceil(((-1 * firstDayOffset + 1) + currentDate.getDaysInMonth()) / 7);
96            currentDate.addDays(firstDayOffset - 1);
97
98            var doHover = function (firstDayInBounds) {
99                return function () {
100                    if (s.hoverClass) {
101                        var $this = $(this);
102                        if (!s.selectWeek) {
103                            $this.addClass(s.hoverClass);
104                        } else if (firstDayInBounds && !$this.is('.disabled')) {
105                            $this.parent().addClass('activeWeekHover');
106                        }
107                    }
108                }
109            };
110            var unHover = function () {
111                if (s.hoverClass) {
112                    var $this = $(this);
113                    $this.removeClass(s.hoverClass);
114                    $this.parent().removeClass('activeWeekHover');
115                }
116            };
117
118            var w = 0;
119            while (w++ < weeksToDraw) {
120                var r = jQuery(dc('tr'));
121                var firstDayInBounds = s.dpController ? currentDate > s.dpController.startDate : false;
122                for (var i = 0; i < 7; i++) {
123                    var thisMonth = currentDate.getMonth() == month;
124                    var d = $(dc('td'))
125								.text(currentDate.getDate() + '')
126								.addClass((thisMonth ? 'current-month ' : 'other-month ') +
127													(currentDate.isWeekend() ? 'weekend ' : 'weekday ') +
128													(thisMonth && currentDate.getTime() == today.getTime() ? 'today ' : '')
129								)
130								.data('datePickerDate', currentDate.asString())
131								.hover(doHover(firstDayInBounds), unHover)
132                    ;
133                    r.append(d);
134                    if (s.renderCallback) {
135                        s.renderCallback(d, currentDate, month, year);
136                    }
137                    // addDays(1) fails in some locales due to daylight savings. See issue 39.
138                    //currentDate.addDays(1);
139                    // set the time to midday to avoid any weird timezone issues??
140                    currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1, 12, 0, 0);
141                }
142                tbody.append(r);
143            }
144            calendarTable.append(tbody);
145
146            return this.each(
147				function () {
148				    $(this).empty().append(calendarTable);
149				}
150			);
151        },
152        /**
153         * Create a datePicker associated with each of the matched elements.
154         *
155         * The matched element will receive a few custom events with the following signatures:
156         *
157         * dateSelected(event, date, $td, status)
158         * Triggered when a date is selected. event is a reference to the event, date is the Date selected, $td is a jquery object wrapped around the TD that was clicked on and status is whether the date was selected (true) or deselected (false)
159         *
160         * dpClosed(event, selected)
161         * Triggered when the date picker is closed. event is a reference to the event and selected is an Array containing Date objects.
162         *
163         * dpMonthChanged(event, displayedMonth, displayedYear)
164         * Triggered when the month of the popped up calendar is changed. event is a reference to the event, displayedMonth is the number of the month now displayed (zero based) and displayedYear is the year of the month.
165         *
166         * dpDisplayed(event, $datePickerDiv)
167         * Triggered when the date picker is created. $datePickerDiv is the div containing the date picker. Use this event to add custom content/ listeners to the popped up date picker.
168         *
169         * @param Object s (optional) Customize your date pickers.
170         * @option Number month The month to render when the date picker is opened (NOTE that months are zero based). Default is today's month.
171         * @option Number year The year to render when the date picker is opened. Default is today's year.
172         * @option String|Date startDate The first date date can be selected.
173         * @option String|Date endDate The last date that can be selected.
174         * @option Boolean inline Whether to create the datePicker as inline (e.g. always on the page) or as a model popup. Default is false (== modal popup)
175         * @option Boolean createButton Whether to create a .dp-choose-date anchor directly after the matched element which when clicked will trigger the showing of the date picker. Default is true.
176         * @option Boolean showYearNavigation Whether to display buttons which allow the user to navigate through the months a year at a time. Default is true.
177         * @option Boolean closeOnSelect Whether to close the date picker when a date is selected. Default is true.
178         * @option Boolean displayClose Whether to create a "Close" button within the date picker popup. Default is false.
179         * @option Boolean selectMultiple Whether a user should be able to select multiple dates with this date picker. Default is false.
180         * @option Number numSelectable The maximum number of dates that can be selected where selectMultiple is true. Default is a very high number.
181         * @option Boolean clickInput If the matched element is an input type="text" and this option is true then clicking on the input will cause the date picker to appear.
182         * @option Boolean rememberViewedMonth Whether the datePicker should remember the last viewed month and open on it. If false then the date picker will always open with the month for the first selected date visible.
183         * @option Boolean selectWeek Whether to select a complete week at a time...
184         * @option Number verticalPosition The vertical alignment of the popped up date picker to the matched element. One of $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM. Default is $.dpConst.POS_TOP.
185         * @option Number horizontalPosition The horizontal alignment of the popped up date picker to the matched element. One of $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT.
186         * @option Number verticalOffset The number of pixels offset from the defined verticalPosition of this date picker that it should pop up in. Default in 0.
187         * @option Number horizontalOffset The number of pixels offset from the defined horizontalPosition of this date picker that it should pop up in. Default in 0.
188         * @option (Function|Array) renderCallback A reference to a function (or an array of separate functions) that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Each callback function will receive four arguments;
188 a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year. Default is no callback.
189         * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
190         * @option String autoFocusNextInput Whether focus should be passed onto the next input in the form (true) or remain on this input (false) when a date is selected and the calendar closes
191         * @type jQuery
192         * @name datePicker
193         * @cat plugins/datePicker
194         * @author Kelvin Luck (http://www.kelvinluck.com/)
195         *
196         * @example $('input.date-picker').datePicker();
197         * @desc Creates a date picker button next to all matched input elements. When the button is clicked on the value of the selected date will be placed in the corresponding input (formatted according to Date.format).
198         *
199         * @example demo/index.html
200         * @desc See the projects homepage for many more complex examples...
201         **/
202        datePicker: function (s) {
203            if (!$.event._dpCache) $.event._dpCache = [];
204
205            // initialise the date picker controller with the relevant settings...
206            s = $.extend({}, $.fn.datePicker.defaults, s);
207            return this.each(
208				function () {
209				    var $this = $(this);
210				    var alreadyExists = true;
211
212				    if (!this._dpId) {
213				        this._dpId = $.guid++;
214				        $.event._dpCache[this._dpId] = new DatePicker(this);
215				        alreadyExists = false;
216				    }
217
218				    if (s.inline) {
219				        s.createButton = false;
220				        s.displayClose = false;
221				        s.closeOnSelect = false;
222				        $this.empty();
223				    }
224
225				    var controller = $.event._dpCache[this._dpId];
226
227				    controller.init(s);
228
229				    if (!alreadyExists && s.createButton) {
230				        // create it!
231				        controller.button = $('<a href="#" class="dp-choose-date" title="' + $.dpText.TEXT_CHOOSE_DATE + '">' + $.dpText.TEXT_CHOOSE_DATE + '</a>')
232								.on(
233									'click',
234									function () {
235									    $this.dpDisplay(this);
236									    this.blur();
237									    return false;
238									}
239								);
240				        $this.after(controller.button);
241				    }
242
243				    if (!alreadyExists && $this.is(':text')) {
244				        $this
245							.on(
246								'dateSelected',
247								function (e, selectedDate, $td) {
248								    this.value = selectedDate.asString();
249								}
250							).on(
251								'change',
252								function () {
253								    if (this.value == '') {
254								        controller.clearSelected();
255								    } else {
256								        var d = Date.fromString(this.value);
257								        if (d) {
258								            controller.setSelected(d, true, true);
259								        }
260								    }
261								}
262							);
263
264				        if (s.clickInput) {
265				            $this.on(
266								'click',
267								function () {
268								    // The change event doesn't happen until the input loses focus so we need to manually trigger it...
269								    $this.trigger('change');
270								    $this.dpDisplay();
271								}
272							);
273				        }
274				        var d = Date.fromString(this.value);
275				        if (this.value != '' && d) {
276				            controller.setSelected(d, true, true);
277				        }
278				    }
279
280				    $this.addClass('dp-applied');
281
282				}
283			)
284        },
285        /**
286         * Disables or enables this date picker
287         *
288         * @param Boolean s Whether to disable (true) or enable (false) this datePicker
289         * @type jQuery
290         * @name dpSetDisabled
291         * @cat plugins/datePicker
292         * @author Kelvin Luck (http://www.kelvinluck.com/)
293         *
294         * @example $('.date-picker').datePicker();
295         * $('.date-picker').dpSetDisabled(true);
296         * @desc Prevents this date picker from displaying and adds a class of dp-disabled to it (and it's associated button if it has one) for styling purposes. If the matched element is an input field then it will also set the disabled attribute to stop people directly editing the field.
297         **/
298        dpSetDisabled: function (s) {
299            return _w.call(this, 'setDisabled', s);
300        },
301        /**
302         * Updates the first selectable date for any date pickers on any matched elements.
303         *
304         * @param String|Date d A Date object or string representing the first selectable date (formatted according to Date.format).
305         * @type jQuery
306         * @name dpSetStartDate
307         * @cat plugins/datePicker
308         * @author Kelvin Luck (http://www.kelvinluck.com/)
309         *
310         * @example $('.date-picker').datePicker();
311         * $('.date-picker').dpSetStartDate('01/01/2000');
312         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the first selectable date for each of these to the first day of the millenium.
313         **/
314        dpSetStartDate: function (d) {
315            return _w.call(this, 'setStartDate', d);
316        },
317        /**
318         * Updates the last selectable date for any date pickers on any matched elements.
319         *
320         * @param String|Date d A Date object or string representing the last selectable date (formatted according to Date.format).
321         * @type jQuery
322         * @name dpSetEndDate
323         * @cat plugins/datePicker
324         * @author Kelvin Luck (http://www.kelvinluck.com/)
325         *
326         * @example $('.date-picker').datePicker();
327         * $('.date-picker').dpSetEndDate('01/01/2010');
328         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the last selectable date for each of these to the first Janurary 2010.
329         **/
330        dpSetEndDate: function (d) {
331            return _w.call(this, 'setEndDate', d);
332        },
333        /**
334         * Gets a list of Dates currently selected by this datePicker. This will be an empty array if no dates are currently selected or NULL if there is no datePicker associated with the matched element.
335         *
336         * @type Array
337         * @name dpGetSelected
338         * @cat plugins/datePicker
339         * @author Kelvin Luck (http://www.kelvinluck.com/)
340         *
341         * @example $('.date-picker').datePicker();
342         * alert($('.date-picker').dpGetSelected());
343         * @desc Will alert an empty array (as nothing is selected yet)
344         **/
345        dpGetSelected: function () {
346            var c = _getController(this[0]);
347            if (c) {
348                return c.getSelected();
349            }
350            return null;
351        },
352        dpGetDisplayedMonthYear: function () {
353            var c = _getController(this[0]);
354
355            return [c.displayedMonth, c.displayedYear];
356        },
357        /**
358         * Selects or deselects a date on any matched element's date pickers. Deselcting is only useful on date pickers where selectMultiple==true. Selecting will only work if the passed date is within the startDate and endDate boundries for a given date picker.
359         *
360         * @param String|Date d A Date object or string representing the date you want to select (formatted according to Date.format).
361         * @param Boolean v Whether you want to select (true) or deselect (false) this date. Optional - default = true.
362         * @param Boolean m Whether you want the date picker to open up on the month of this date when it is next opened. Optional - default = true.
363         * @param Boolean e Whether you want the date picker to dispatch events related to this change of selection. Optional - default = true.
364         * @type jQuery
365         * @name dpSetSelected
366         * @cat plugins/datePicker
367         * @author Kelvin Luck (http://www.kelvinluck.com/)
368         *
369         * @example $('.date-picker').datePicker();
370         * $('.date-picker').dpSetSelected('01/01/2010');
371         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
372         **/
373        dpSetSelected: function (d, v, m, e) {
374            if (v == undefined) v = true;
375            if (m == undefined) m = true;
376            if (e == undefined) e = true;
377            return _w.call(this, 'setSelected', Date.fromString(d), v, m, e);
378        },
379        /**
380         * Sets the month that will be displayed when the date picker is next opened. If the passed month is before startDate then the month containing startDate will be displayed instead. If the passed month is after endDate then the month containing the endDate will be displayed instead.
381         *
382         * @param Number m The month you want the date picker to display. Optional - defaults to the currently displayed month.
383         * @param Number y The year you want the date picker to display. Optional - defaults to the currently displayed year.
384         * @type jQuery
385         * @name dpSetDisplayedMonth
386         * @cat plugins/datePicker
387         * @author Kelvin Luck (http://www.kelvinluck.com/)
388         *
389         * @example $('.date-picker').datePicker();
390         * $('.date-picker').dpSetDisplayedMonth(10, 2008);
391         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
392         **/
393        dpSetDisplayedMonth: function (m, y) {
394            return _w.call(this, 'setDisplayedMonth', Number(m), Number(y), true);
395        },
396        /**
397         * Displays the date picker associated with the matched elements. Since only one date picker can be displayed at once then the date picker associated with the last matched element will be the one that is displayed.
398         *
399         * @param HTMLElement e An element that you want the date picker to pop up relative in position to. Optional - default behaviour is to pop up next to the element associated with this date picker.
400         * @type jQuery
401         * @name dpDisplay
402         * @cat plugins/datePicker
403         * @author Kelvin Luck (http://www.kelvinluck.com/)
404         *
405         * @example $('#date-picker').datePicker();
406         * $('#date-picker').dpDisplay();
407         * @desc Creates a date picker associated with the element with an id of date-picker and then causes it to pop up.
408         **/
409        dpDisplay: function (e) {
410            return _w.call(this, 'display', e);
411        },
412        /**
413         * Sets a function or array of functions that is called when each TD of the date picker popup is rendered to the page
414         *
415         * @param (Function|Array) a A function or an array of functions that are called when each td is rendered. Each function will receive four arguments; a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year.
416         * @type jQuery
417         * @name dpSetRenderCallback
418         * @cat plugins/datePicker
419         * @author Kelvin Luck (http://www.kelvinluck.com/)
420         *
421         * @example $('#date-picker').datePicker();
422         * $('#date-picker').dpSetRenderCallback(function($td, thisDate, month, year)
423         * {
424         * 	// do stuff as each td is rendered dependant on the date in the td and the displayed month and year
425         * });
426         * @desc Creates a date picker associated with the element with an id of date-picker and then creates a function which is called as each td is rendered when this date picker is displayed.
427         **/
428        dpSetRenderCallback: function (a) {
429            return _w.call(this, 'setRenderCallback', a);
430        },
431        /**
432         * Sets the position that the datePicker will pop up (relative to it's associated element)
433         *
434         * @param Number v The vertical alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM
435         * @param Number h The horizontal alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT
436         * @type jQuery
437         * @name dpSetPosition
438         * @cat plugins/datePicker
439         * @author Kelvin Luck (http://www.kelvinluck.com/)
440         *
441         * @example $('#date-picker').datePicker();
442         * $('#date-picker').dpSetPosition($.dpConst.POS_BOTTOM, $.dpConst.POS_RIGHT);
443         * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be bottom and right aligned to the #date-picker element.
444         **/
445        dpSetPosition: function (v, h) {
446            return _w.call(this, 'setPosition', v, h);
447        },
448        /**
449         * Sets the offset that the popped up date picker will have from it's default position relative to it's associated element (as set by dpSetPosition)
450         *
451         * @param Number v The vertical offset of the created date picker.
452         * @param Number h The horizontal offset of the created date picker.
453         * @type jQuery
454         * @name dpSetOffset
455         * @cat plugins/datePicker
456         * @author Kelvin Luck (http://www.kelvinluck.com/)
457         *
458         * @example $('#date-picker').datePicker();
459         * $('#date-picker').dpSetOffset(-20, 200);
460         * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be 20 pixels above and 200 pixels to the right of it's default position.
461         **/
462        dpSetOffset: function (v, h) {
463            return _w.call(this, 'setOffset', v, h);
464        },
465        /**
466         * Closes the open date picker associated with this element.
467         *
468         * @type jQuery
469         * @name dpClose
470         * @cat plugins/datePicker
471         * @author Kelvin Luck (http://www.kelvinluck.com/)
472         *
473         * @example $('.date-pick')
474         *		.datePicker()
475         *		.on(
476         *			'focus',
477         *			function()
478         *			{
479         *				$(this).dpDisplay();
480         *			}
481         *		).on(
482         *			'blur',
483         *			function()
484         *			{
485         *				$(this).dpClose();
486         *			}
487         *		);
488         **/
489        dpClose: function () {
490            return _w.call(this, '_closeCalendar', false, this[0]);
491        },
492        /**
493         * Rerenders the date picker's current month (for use with inline calendars and renderCallbacks).
494         *
495         * @type jQuery
496         * @name dpRerenderCalendar
497         * @cat plugins/datePicker
498         * @author Kelvin Luck (http://www.kelvinluck.com/)
499         *
500         **/
501        dpRerenderCalendar: function () {
502            return _w.call(this, '_rerenderCalendar');
503        },
504        // private function called on unload to clean up any expandos etc and prevent memory links...
505        _dpDestroy: function () {
506            // TODO - implement this?
507        }
508    });
509
510    // private internal function to cut down on the amount of code needed where we forward
511    // dp* methods on the jQuery object on to the relevant DatePicker controllers...
512    var _w = function (f, a1, a2, a3, a4) {
513        return this.each(
514			function () {
515			    var c = _getController(this);
516			    if (c) {
517			        c[f](a1, a2, a3, a4);
518			    }
519			}
520		);
521    };
522
523    function DatePicker(ele) {
524        this.ele = ele;
525
526        // initial values...
527        this.displayedMonth = null;
528        this.displayedYear = null;
529        this.startDate = null;
530        this.endDate = null;
531        this.showYearNavigation = null;
532        this.closeOnSelect = null;
533        this.displayClose = null;
534        this.rememberViewedMonth = null;
535        this.selectMultiple = null;
536        this.numSelectable = null;
537        this.numSelected = null;
538        this.verticalPosition = null;
539        this.horizontalPosition = null;
540        this.verticalOffset = null;
541        this.horizontalOffset = null;
542        this.button = null;
543        this.renderCallback = [];
544        this.selectedDates = {};
545        this.inline = null;
546        this.context = '#dp-popup';
547        this.uiForm = null;
548        this.settings = {};
549    };
550    $.extend(
551		DatePicker.prototype,
552		{
553		    init: function (s) {
554		        this.setStartDate(s.startDate);
555		        this.setEndDate(s.endDate);
556		        this.setDisplayedMonth(Number(s.month), Number(s.year));
557		        this.setRenderCallback(s.renderCallback);
558		        this.showYearNavigation = s.showYearNavigation;
559		        this.closeOnSelect = s.closeOnSelect;
560		        this.displayClose = s.displayClose;
561		        this.rememberViewedMonth = s.rememberViewedMonth;
562		        this.selectMultiple = s.selectMultiple;
563		        this.selectableDate = s.selectableDate || false;
564		        this.numSelectable = s.selectMultiple ? s.numSelectable : 1;
565		        this.numSelected = 0;
566		        this.verticalPosition = s.verticalPosition;
567		        this.horizontalPosition = s.horizontalPosition;
568		        this.hoverClass = s.hoverClass;
569		        this.setOffset(s.verticalOffset, s.horizontalOffset);
570		        this.inline = s.inline;
571		        this.settings = s;
572		        if (this.inline) {
573		            this.context = this.ele;
574		            this.display();
575		        }
576		    },
577		    setStartDate: function (d) {
578		        if (d) {
579		            if (d instanceof Date) {
580		                this.startDate = d;
581		            } else {
582		                this.startDate = Date.fromString(d);
583		            }
584		        }
585		        if (!this.startDate) {
586		            this.startDate = (new Date()).zeroTime();
587		        }
588		        this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
589		    },
590		    setEndDate: function (d) {
591		        if (d) {
592		            if (d instanceof Date) {
593		                this.endDate = d;
594		            } else {
595		                this.endDate = Date.fromString(d);
596		            }
597		        }
598		        if (!this.endDate) {
599		            this.endDate = (new Date('12/31/2999')); // using the JS Date.parse function which expects mm/dd/yyyy
600		        }
601		        if (this.endDate.getTime() < this.startDate.getTime()) {
602		            this.endDate = this.startDate;
603		        }
604		        this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
605		    },
606		    setPosition: function (v, h) {
607		        this.verticalPosition = v;
608		        this.horizontalPosition = h;
609		    },
610		    setOffset: function (v, h) {
611		        this.verticalOffset = parseInt(v) || 0;
612		        this.horizontalOffset = parseInt(h) || 0;
613		    },
614		    setDisabled: function (s) {
615		        $e = $(this.ele);
616		        $e[s ? 'addClass' : 'removeClass']('dp-disabled');
617		        if (this.button) {
618		            $but = $(this.button);
619		            $but[s ? 'addClass' : 'removeClass']('dp-disabled');
620		            $but.attr('title', s ? '' : $.dpText.TEXT_CHOOSE_DATE);
621		        }
622		        if ($e.is(':text')) {
623		            $e.attr('disabled', s ? 'disabled' : '');
624		        }
625		    },
626		    setDisplayedMonth: function (m, y, rerender) {
627		        if (this.startDate == undefined || this.endDate == undefined) {
628		            return;
629		        }
630		        var s = new Date(this.startDate.getTime());
631		        s.setDate(1);
632		        var e = new Date(this.endDate.getTime());
633		        e.setDate(1);
634
635		        var t;
636		        if ((!m && !y) || (isNaN(m) && isNaN(y))) {
637		            // no month or year passed - default to current month
638		            t = new Date().zeroTime();
639		            t.setDate(1);
640		        } else if (isNaN(m)) {
641		            // just year passed in - presume we want the displayedMonth
642		            t = new Date(y, this.displayedMonth, 1);
643		        } else if (isNaN(y)) {
644		            // just month passed in - presume we want the displayedYear
645		            t = new Date(this.displayedYear, m, 1);
646		        } else {
647		            // year and month passed in - that's the date we want!
648		            t = new Date(y, m, 1);
649		        }
650		        // check if the desired date is within the range of our defined startDate and endDate
651		        var oldMonth = this.displayedMonth,
652                                     oldYear = this.displayedYear;
653		        this.displayedMonth = t.getMonth();
654		        this.displayedYear = t.getFullYear();
655
656		        if (rerender && (this.displayedMonth != oldMonth || this.displayedYear != oldYear)) {
657		            this._rerenderCalendar();
658		            $(this.ele).trigger('dpMonthChanged', [this.displayedMonth, this.displayedYear]);
659		        }
660		    },
661		    setSelected: function (d, v, moveToMonth, dispatchEvents) {
662		        if (d < this.startDate || d.zeroTime() > this.endDate.zeroTime()) {
663		            // Don't allow people to select dates outside range...
664		            return;
665		        }
666		        var s = this.settings;
667		        if (s.selectWeek) {
668		            d = d.addDays(-(d.getDay() - Date.firstDayOfWeek + 7) % 7);
669		            if (d < this.startDate) // The first day of this week is before the start date so is unselectable...
670		            {
671		                return;
672		            }
673		        }
674		        if (v == this.isSelected(d)) // this date is already un/selected
675		        {
676		            return;
677		        }
678		        if (this.selectMultiple == false) {
679		            this.clearSelected();
680		        } else if (v && this.numSelected == this.numSelectable) {
681		            // can't select any more dates...
682		            return;
683		        }
684		        if (moveToMonth && (this.displayedMonth != d.getMonth() || this.displayedYear != d.getFullYear())) {
685		            this.setDisplayedMonth(d.getMonth(), d.getFullYear(), true);
686		        }
687		        this.selectedDates[d.asString()] = v;
688		        this.numSelected += v ? 1 : -1;
689		        var selectorString = 'td.' + (d.getMonth() == this.displayedMonth ? 'current-month' : 'other-month');
690		        var $td;
691		        $(selectorString, this.context).each(
692					function () {
693					    if ($(this).data('datePickerDate') == d.asString()) {
694					        $td = $(this);
695					        if (s.selectWeek) {
696					            $td.parent()[v ? 'addClass' : 'removeClass']('selectedWeek');
697					        }
698					        $td[v ? 'addClass' : 'removeClass']('selected');
699					    }
700					}
701				);
702		        $('td', this.context).not('.selected')[this.selectMultiple && this.numSelected == this.numSelectable ? 'addClass' : 'removeClass']('unselectable');
703
704		        if (dispatchEvents) {
705		            var s = this.isSelected(d);
706		            $e = $(this.ele);
707		            var dClone = Date.fromString(d.asString());
708		            $e.trigger('dateSelected', [dClone, $td, s]);
709		            $e.trigger('change');
710		        }
711		    },
712		    isSelected: function (d) {
713		        return this.selectedDates[d.asString()];
714		    },
715		    getSelected: function () {
716		        var r = [];
717		        for (var s in this.selectedDates) {
718		            if (this.selectedDates[s] == true) {
719		                r.push(Date.fromString(s));
720		            }
721		        }
722		        return r;
723		    },
724		    clearSelected: function () {
725		        this.selectedDates = {};
726		        this.numSelected = 0;
727		        $('td.selected', this.context).removeClass('selected').parent().removeClass('selectedWeek');
728		    },
729		    display: function (eleAlignTo) {
730		        if ($(this.ele).is('.dp-disabled')) return;
731
732		        eleAlignTo = eleAlignTo || this.ele;
733		        var c = this;
734		        var $ele = $(eleAlignTo);
735		        var eleOffset = $ele.offset();
736
737		        var $createIn;
738		        var attrs;
739		        var attrsCalendarHolder;
740		        var cssRules;
741
742		        if (c.inline) {
743		            $createIn = $(this.ele);
744		            attrs = {
745		                'id': 'calendar-' + this.ele._dpId,
746		                'class': 'dp-popup dp-popup-inline'
747		            };
748
749		            $('.dp-popup', $createIn).remove();
750		            cssRules = {
751		            };
752		        } else {
753		            $createIn = $('body');
754		            attrs = {
755		                'id': 'dp-popup',
756		                'class': 'dp-popup'
757		            };
758		            cssRules = {
759		                'top': eleOffset.top + c.verticalOffset,
760		                'left': eleOffset.left + c.horizontalOffset
761		            };
762
763		            var _checkMouse = function (e) {
764		                var el = e.target;
765		                var cal = $('#dp-popup')[0];
766
767		                while (true) {
768		                    if (el == cal) {
769		                        return true;
770		                    } else if (el == document) {
771		                        c._closeCalendar();
772		                        return false;
773		                    } else {
774		                        el = $(el).parent()[0];
775		                    }
776		                }
777		            };
778		            this._checkMouse = _checkMouse;
779
780		            c._closeCalendar(true);
781                    $(document).on(
782						'keydown.datepicker',
783						function (event) {
784						    if (event.keyCode == 27) {
785						        c._closeCalendar();
786						    }
787						}
788					);
789		        }
790
791		        if (!c.rememberViewedMonth) {
792		            var selectedDate = this.getSelected()[0];
793		            if (selectedDate) {
794		                selectedDate = new Date(selectedDate);
795		                this.setDisplayedMonth(selectedDate.getMonth(), selectedDate.getFullYear(), false);
796		            }
797		        }
798
799		        $createIn
800					.append(
801						$('<div></div>')
802							.attr(attrs)
803							.css(cssRules)
804							.append(
805//								$('<a href="#" class="selecteee">aaa</a>'),
806								$('<h2></h2>'),
807								$('<div class="dp-nav-prev"></div>')
808									.append(
809										$('<a class="dp-nav-prev-year" href="#" title="' + $.dpText.TEXT_PREV_YEAR + '">&lt;&lt;</a>')
810                                        .on(
811												'click',
812												function () {
813												    return c._displayNewMonth.call(c, this, 0, -1);
814												}
815											),
816										$('<a class="dp-nav-prev-month" href="#" title="' + $.dpText.TEXT_PREV_MONTH + '">&lt;</a>')
817                                            .on(
818												'click',
819												function () {
820												    return c._displayNewMonth.call(c, this, -1, 0);
821												}
822											)
823									),
824								$('<div class="dp-nav-next"></div>')
825									.append(
826										$('<a class="dp-nav-next-year" href="#" title="' + $.dpText.TEXT_NEXT_YEAR + '">&gt;&gt;</a>')
827                                        .on(
828												'click',
829												function () {
830												    return c._displayNewMonth.call(c, this, 0, 1);
831												}
832											),
833										$('<a class="dp-nav-next-month" href="#" title="' + $.dpText.TEXT_NEXT_MONTH + '">&gt;</a>')
834                                            .on(
835												'click',
836												function () {
837												    return c._displayNewMonth.call(c, this, 1, 0);
838												}
839											)
840									),
841								$('<div class="dp-calendar"></div>')
842							)
843							.bgIframe()
844						);
845
846		        var $pop = this.inline ? $('.dp-popup', this.context) : $('#dp-popup');
847
848		        if (this.showYearNavigation == false) {
849		            $('.dp-nav-prev-year, .dp-nav-next-year', c.context).css('display', 'none');
850		        }
851		        if (this.displayClose) {
852		            $pop.append(
853						$('<a href="#" id="dp-close">' + $.dpText.TEXT_CLOSE + '</a>')
854                            .on(
855								'click',
856								function () {
857								    c._closeCalendar();
858								    return false;
859								}
860							)
861					);
862		        }
863		        c._renderCalendar();
864
865		        $(this.ele).trigger('dpDisplayed', $pop);
866
867		        if (!c.inline) {
868		            if (this.verticalPosition == $.dpConst.POS_BOTTOM) {
869		                $pop.css('top', eleOffset.top + $ele.height() - $pop.height() + c.verticalOffset);
870		            }
871		            if (this.horizontalPosition == $.dpConst.POS_RIGHT) {
872		                $pop.css('left', eleOffset.left + $ele.width() - $pop.width() + c.horizontalOffset);
873		            }
874		            //					$('.selectee', this.context).focus();
875                    $(document).on('mousedown.datepicker', this._checkMouse);
876		        }
877
878		    },
879		    setRenderCallback: function (a) {
880		        if (a == null) return;
881		        if (a && typeof (a) == 'function') {
882		            a = [a];
883		        }
884		        this.renderCallback = this.renderCallback.concat(a);
885		    },
886		    cellRender: function ($td, thisDate, month, year) {
887		        var c = this.dpController;
888		        var d = new Date(thisDate.getTime());
889
890		        // add our click handlers to deal with it when the days are clicked...
891
892                $td.on(
893					'click',
894					function () {
895					    var $this = $(this);
896					    if (!$this.is('.disabled')) {
897					        c.setSelected(d, !$this.is('.selected') || !c.selectMultiple, false, true);
898					        if (c.closeOnSelect) {
899					            // Focus the next input in the form…
900					            if (c.settings.autoFocusNextInput) {
901					                var ele = c.ele;
902					                var found = false;
903					                $(':input', ele.form).each(
904										function () {
905										    if (found) {
906										        $(this).focus();
907										        return false;
908										    }
909										    if (this == ele) {
910										        found = true;
911										    }
912										}
913									);
914					            } else {
915					                try {
916					                    c.ele.focus();
917					                } catch (e) { }
918					            }
919					            c._closeCalendar();
920					        }
921					    }
922					}
923				);
924		        if (c.isSelected(d)) {
925		            $td.addClass('selected');
926		            if (c.settings.selectWeek) {
927		                $td.parent().addClass('selectedWeek');
928		            }
929		        } else if (c.selectMultiple && c.numSelected == c.numSelectable) {
930		            $td.addClass('unselectable');
931		        }
932
933		    },
934		    _applyRenderCallbacks: function () {
935		        var c = this;
936		        $('td', this.context).each(
937					function () {
938					    for (var i = 0; i < c.renderCallback.length; i++) {
939					        $td = $(this);
940					        c.renderCallback[i].apply(this, [$td, Date.fromString($td.data('datePickerDate')), c.displayedMonth, c.displayedYear]);
941					    }
942					}
943				);
944		        return;
945		    },
946		    // ele is the clicked button - only proceed if it doesn't have the class disabled...
947		    // m and y are -1, 0 or 1 depending which direction we want to go in...
948		    _displayNewMonth: function (ele, m, y) {
949		        if (!$(ele).is('.disabled')) {
950
951		            this.setDisplayedMonth(this.displayedMonth + m, this.displayedYear + y, true);
952
953		            /*if ( this.selectableDate && this.uiForm) {
954                        this.uiForm.update({
955                            m: this.displayedMonth,
956                            y: this.displayedYear
957                        });
958                    };*/
959		        }
960		        ele.blur();
961		        return false;
962		    },
963		    _displayNewDate: function (m, y) {
964		        this.setDisplayedMonth(m, y, true);
965
966		        return false;
967		    },
968		    _rerenderCalendar: function () {
969		        this._clearCalendar();
970		        this._renderCalendar();
971		        if (this.selectableDate && this.uiForm) {
972		            this._renderDateSelect();
973		        }
974		    },
975		    _renderDateSelect: function (title, displayedMonth, displayedYear) {
976		        var that = this,
977                    thisYear = (new Date()).getFullYear(),
978                    thisMonth = (new Date()).getMonth(),
979                    startYear = thisYear - 3,
980                    endYear = thisYear + 2,
981                    startMonth = 0,
982                    endMonth = 11;
983
984		        function getMY(d) {
985
986		            var d = Date.fromString(d, that.settings.dateFormat);
987
988		            return [d.getFullYear(), d.getMonth()];
989		        }
990
991		        if (this.settings.isLimited) {
992
993		            var start = getMY(this.settings.isLimited[0]),
994                        end = getMY(this.settings.isLimited[1]);
995
996		            startYear = start[0];
997		            endYear = end[0];
998		            if (startYear == endYear) {
999		                startMonth = start[1];
1000		                endMonth = end[1];
1001		            }
1002		        }
1003
1004		        if ((!title && this.uiForm) || title.hasClass('dp-active')) {
1005		            this.uiForm.update({
1006		                m: this.displayedMonth,
1007		                mm: Date.monthNames[this.displayedMonth],
1008		                y: this.displayedYear
1009		            });
1010		            return that;
1011		        }
1012
1013                var uiForm = $('<div class="ui-form" style="display: flex; gap: 5px;"><div class="form-element w-60"><select class="select-month small"></select></div><div class="form-element"><select class="select-year small"></select></div></div>')
1014		        selectYear = $('select.select-year', uiForm),
1015                selectMonth = $('select.select-month', uiForm);
1016
1017		        for (var i = startMonth; i <= endMonth; i++) {
1018		            var option = $('<option>').attr('value', i).html(Date.monthNames[i]);
1019		            if (i == displayedMonth) {
1020		                option.attr("selected", "selected").prop("selected", true);
1021		            }
1022		            option.appendTo(selectMonth);
1023		        };
1024		        for (var i = endYear; i > startYear - 1; i--) {
1025		            var option = $('<option>').attr('value', i).text(i);
1026		            if (i == displayedYear) {
1027		                option.attr("selected", "selected").prop("selected", true);
1028		            }
1029		            option.appendTo(selectYear);
1030		        };
1031
1032		        $('<div>').addClass('form-element f-none');
1033
1034		        uiForm.appendTo(title);
1035
1036		        title.addClass('dp-active');
1037
1038		        this.uiForm = $('.ui-form', title);
1039		        this.uiForm.update = function (values) {
1040		            $('select.select-year', this).selectbox('change', values.y.toString(), values.y);   // val(values.y);
1041		            $('select.select-month', this).selectbox('change', values.m.toString(), values.mm); // val(values.m);
1042		        };
1043                $('select', title).addClass('auto-list-width').selectbox().on("change", function (e) {
1044
1045		            e.preventDefault();
1046
1047		            var m = $('option', $('select.select-month', that.uiForm)).filter(':selected').val(),
1048                        y = $('option', $('select.select-year', that.uiForm)).filter(':selected').val();
1049
1050		            that._displayNewDate(m, y);
1051		        });
1052		    },
1053		    _renderCalendar: function () {
1054		        // set the title...
1055		        if (!this.selectableDate) {
1056		            $('h2', this.context).html((new Date(this.displayedYear, this.displayedMonth, 1)).asString($.dpText.HEADER_FORMAT));
1057		        } else {
1058		            var title = $('h2', this.context);
1059		            this._renderDateSelect.call(this, title, this.displayedMonth, this.displayedYear);
1060		        }
1061
1062		        // render the calendar...
1063		        $('.dp-calendar', this.context).renderCalendar(
1064					$.extend(
1065						{},
1066						this.settings,
1067						{
1068						    month: this.displayedMonth,
1069						    year: this.displayedYear,
1070						    renderCallback: this.cellRender,
1071						    dpController: this,
1072						    hoverClass: this.hoverClass
1073						})
1074				);
1075
1076		        // update the status of the control buttons and disable dates before startDate or after endDate...
1077		        // TODO: When should the year buttons be disabled? When you can't go forward a whole year from where you are or is that annoying?
1078		        if (this.displayedYear == this.startDate.getFullYear() && this.displayedMonth == this.startDate.getMonth()) {
1079		            $('.dp-nav-prev-year', this.context).addClass('disabled');
1080		            $('.dp-nav-prev-month', this.context).addClass('disabled');
1081		            $('.dp-calendar td.other-month', this.context).each(
1082						function () {
1083						    var $this = $(this);
1084						    if (Number($this.text()) > 20) {
1085						        $this.addClass('disabled');
1086						    }
1087						}
1088					);
1089		            var d = this.startDate.getDate();
1090		            $('.dp-calendar td.current-month', this.context).each(
1091						function () {
1092						    var $this = $(this);
1093						    if (Number($this.text()) < d) {
1094						        $this.addClass('disabled');
1095						    }
1096						}
1097					);
1098		        } else {
1099		            $('.dp-nav-prev-year', this.context).removeClass('disabled');
1100		            $('.dp-nav-prev-month', this.context).removeClass('disabled');
1101		            var d = this.startDate.getDate();
1102		            if (d > 20) {
1103		                // check if the startDate is last month as we might need to add some disabled classes...
1104		                var st = this.startDate.getTime();
1105		                var sd = new Date(st);
1106		                sd.addMonths(1);
1107		                if (this.displayedYear == sd.getFullYear() && this.displayedMonth == sd.getMonth()) {
1108		                    $('.dp-calendar td.other-month', this.context).each(
1109								function () {
1110								    var $this = $(this);
1111								    if (Date.fromString($this.data('datePickerDate')).getTime() < st) {
1112								        $this.addClass('disabled');
1113								    }
1114								}
1115							);
1116		                }
1117		            }
1118		        }
1119		        if (this.displayedYear == this.endDate.getFullYear() && this.displayedMonth == this.endDate.getMonth()) {
1120		            $('.dp-nav-next-year', this.context).addClass('disabled');
1121		            $('.dp-nav-next-month', this.context).addClass('disabled');
1122		            $('.dp-calendar td.other-month', this.context).each(
1123						function () {
1124						    var $this = $(this);
1125						    if (Number($this.text()) < 14) {
1126						        $this.addClass('disabled');
1127						    }
1128						}
1129					);
1130		            var d = this.endDate.getDate();
1131		            $('.dp-calendar td.current-month', this.context).each(
1132						function () {
1133						    var $this = $(this);
1134						    if (Number($this.text()) > d) {
1135						        $this.addClass('disabled');
1136						    }
1137						}
1138					);
1139		        } else {
1140		            $('.dp-nav-next-year', this.context).removeClass('disabled');
1141		            $('.dp-nav-next-month', this.context).removeClass('disabled');
1142		            var d = this.endDate.getDate();
1143		            if (d < 13) {
1144		                // check if the endDate is next month as we might need to add some disabled classes...
1145		                var ed = new Date(this.endDate.getTime());
1146		                ed.addMonths(-1);
1147		                if (this.displayedYear == ed.getFullYear() && this.displayedMonth == ed.getMonth()) {
1148		                    $('.dp-calendar td.other-month', this.context).each(
1149								function () {
1150								    var $this = $(this);
1151								    var cellDay = Number($this.text());
1152								    if (cellDay < 13 && cellDay > d) {
1153								        $this.addClass('disabled');
1154								    }
1155								}
1156							);
1157		                }
1158		            }
1159		        }
1160		        this._applyRenderCallbacks();
1161		    },
1162		    _closeCalendar: function (programatic, ele) {
1163		        if (!ele || ele == this.ele) {
1164		            $(document).off('mousedown.datepicker');
1165		            $(document).off('keydown.datepicker');
1166		            this._clearCalendar();
1167		            $('#dp-popup a').off();
1168		            $('#dp-popup').empty().remove();
1169		            if (!programatic) {
1170		                $(this.ele).trigger('dpClosed', [this.getSelected()]);
1171		            }
1172		        }
1173		    },
1174		    // empties the current dp-calendar div and makes sure that all events are unbound
1175		    // and expandos removed to avoid memory leaks...
1176		    _clearCalendar: function () {
1177		        // TODO.
1178		        $('.dp-calendar td', this.context).off();
1179		        $('.dp-calendar', this.context).empty();
1180		    }
1181		}
1182	);
1183
1184    // static constants
1185    $.dpConst = {
1186        SHOW_HEADER_NONE: 0,
1187        SHOW_HEADER_SHORT: 1,
1188        SHOW_HEADER_LONG: 2,
1189        POS_TOP: 0,
1190        POS_BOTTOM: 1,
1191        POS_LEFT: 0,
1192        POS_RIGHT: 1,
1193        DP_INTERNAL_FOCUS: 'dpInternalFocusTrigger'
1194    };
1195    // localisable text
1196    $.dpText = {
1197        TEXT_PREV_YEAR: Date.dpText.TEXT_PREV_YEAR || 'Previous year',
1198        TEXT_PREV_MONTH: Date.dpText.TEXT_PREV_MONTH || 'Previous month',
1199        TEXT_NEXT_YEAR: Date.dpText.TEXT_NEXT_YEAR || 'Next year',
1200        TEXT_NEXT_MONTH: Date.dpText.TEXT_NEXT_MONTH || 'Next month',
1201        TEXT_CLOSE: Date.dpText.TEXT_CLOSE || 'Close',
1202        TEXT_CHOOSE_DATE: Date.dpText.TEXT_CHOOSE_DATE || 'Choose date',
1203        HEADER_FORMAT: Date.dpText.HEADER_FORMAT || 'mmmm yyyy'
1204    };
1205    // version
1206    $.dpVersion = '$Id$';
1207
1208    $.fn.datePicker.defaults = {
1209        month: undefined,
1210        year: undefined,
1211        showHeader: $.dpConst.SHOW_HEADER_SHORT,
1212        startDate: undefined,
1213        endDate: undefined,
1214        inline: false,
1215        renderCallback: null,
1216        createButton: true,
1217        showYearNavigation: true,
1218        closeOnSelect: true,
1219        displayClose: false,
1220        selectMultiple: false,
1221        numSelectable: Number.MAX_VALUE,
1222        clickInput: false,
1223        rememberViewedMonth: true,
1224        selectWeek: false,
1225        selectableDate: false,
1226        verticalPosition: $.dpConst.POS_TOP,
1227        horizontalPosition: $.dpConst.POS_LEFT,
1228        verticalOffset: 0,
1229        horizontalOffset: 0,
1230        hoverClass: 'dp-hover',
1231        autoFocusNextInput: false
1232    };
1233
1234    function _getController(ele) {
1235        if (ele._dpId) return $.event._dpCache[ele._dpId];
1236        return false;
1237    };
1238
1239    // make it so that no error is thrown if bgIframe plugin isn't included (allows you to use conditional
1240    // comments to only include bgIframe where it is needed in IE without breaking this plugin).
1241    if ($.fn.bgIframe == undefined) {
1242        $.fn.bgIframe = function () { return this; };
1243    };
1244
1245
1246    // clean-up
1247    $(window)
1248		.on('unload', function () {
1249		    var els = $.event._dpCache || [];
1250		    for (var i in els) {
1251		        $(els[i].ele)._dpDestroy();
1252		    }
1253		});
1254
1255})(jQuery);
1256/**
1257 * Copyright (c) 2008 Kelvin Luck (http://www.kelvinluck.com/)
1258 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
1259 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
1260 * .
1261 * $Id$
1262 **/
1263
1264(function ($) {
1265
1266    $.fn.extend({
1267        /**
1268         * Render a calendar table into any matched elements.
1269         *
1270         * @param Object s (optional) Customize your calendars.
1271         * @option Number month The month to render (NOTE that months are zero based). Default is today's month.
1272         * @option Number year The year to render. Default is today's year.
1273         * @option Function renderCallback A reference to a function that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Default is no callback.
1274         * @option Number showHeader Whether or not to show the header row, possible values are: $.dpConst.SHOW_HEADER_NONE (no header), $.dpConst.SHOW_HEADER_SHORT (first letter of each day) and $.dpConst.SHOW_HEADER_LONG (full name of each day). Default is $.dpConst.SHOW_HEADER_SHORT.
1275         * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass fal
1275se if you don't want a hover class.
1276         * @type jQuery
1277         * @name renderCalendar
1278         * @cat plugins/datePicker
1279         * @author Kelvin Luck (http://www.kelvinluck.com/)
1280         *
1281         * @example $('#calendar-me').renderCalendar({month:0, year:2007});
1282         * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me.
1283         *
1284         * @example
1285         * var testCallback = function($td, thisDate, month, year)
1286         * {
1287         * if ($td.is('.current-month') && thisDate.getDay() == 4) {
1288         *		var d = thisDate.getDate();
1289         *		$td.on(
1290         *			'click',
1291         *			function()
1292         *			{
1293         *				alert('You clicked on ' + d + '/' + (Number(month)+1) + '/' + year);
1294         *			}
1295         *		).addClass('thursday');
1296         *	} else if (thisDate.getDay() == 5) {
1297         *		$td.html('Friday the ' + $td.html() + 'th');
1298         *	}
1299         * }
1300         * $('#calendar-me').renderCalendar({month:0, year:2007, renderCallback:testCallback});
1301         *
1302         * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me. Every Thursday in the current month has a class of "thursday" applied to it, is clickable and shows an alert when clicked. Every Friday on the calendar has the number inside replaced with text.
1303         **/
1304        renderCalendar: function (s) {
1305            var dc = function (a) {
1306                return document.createElement(a);
1307            };
1308
1309            s = $.extend({}, $.fn.datePicker.defaults, s);
1310
1311            if (s.showHeader != $.dpConst.SHOW_HEADER_NONE) {
1312                var headRow = $(dc('tr'));
1313                for (var i = Date.firstDayOfWeek; i < Date.firstDayOfWeek + 7; i++) {
1314                    var weekday = i % 7;
1315                    var day = Date.dayNames[weekday];
1316                    var dayShort = Date.abbrDayNames[weekday];
1317                    headRow.append(
1318						jQuery(dc('th')).attr({ 'scope': 'col', 'abbr': day, 'title': day, 'class': (weekday == 0 || weekday == 6 ? 'weekend' : 'weekday') }).html(s.showHeader == $.dpConst.SHOW_HEADER_SHORT ? dayShort : day)
1319					);
1320                }
1321            };
1322
1323            var calendarTable = $(dc('table'))
1324									.attr(
1325										{
1326										    'cellspacing': 2
1327										}
1328									)
1329									.addClass('jCalendar')
1330									.append(
1331										(s.showHeader != $.dpConst.SHOW_HEADER_NONE ?
1332											$(dc('thead'))
1333												.append(headRow)
1334											:
1335											dc('thead')
1336										)
1337									);
1338            var tbody = $(dc('tbody'));
1339
1340            var today = (new Date()).zeroTime();
1341            today.setHours(12);
1342
1343            var month = s.month == undefined ? today.getMonth() : s.month;
1344            var year = s.year || today.getFullYear();
1345
1346            var currentDate = (new Date(year, month, 1, 12, 0, 0));
1347
1348            var firstDayOffset = Date.firstDayOfWeek - currentDate.getDay() + 1;
1349            if (firstDayOffset > 1) firstDayOffset -= 7;
1350            var weeksToDraw = Math.ceil(((-1 * firstDayOffset + 1) + currentDate.getDaysInMonth()) / 7);
1351            currentDate.addDays(firstDayOffset - 1);
1352
1353            var doHover = function (firstDayInBounds) {
1354                return function () {
1355                    if (s.hoverClass) {
1356                        var $this = $(this);
1357                        if (!s.selectWeek) {
1358                            $this.addClass(s.hoverClass);
1359                        } else if (firstDayInBounds && !$this.is('.disabled')) {
1360                            $this.parent().addClass('activeWeekHover');
1361                        }
1362                    }
1363                }
1364            };
1365            var unHover = function () {
1366                if (s.hoverClass) {
1367                    var $this = $(this);
1368                    $this.removeClass(s.hoverClass);
1369                    $this.parent().removeClass('activeWeekHover');
1370                }
1371            };
1372
1373            var w = 0;
1374            while (w++ < weeksToDraw) {
1375                var r = jQuery(dc('tr'));
1376                var firstDayInBounds = s.dpController ? currentDate > s.dpController.startDate : false;
1377                for (var i = 0; i < 7; i++) {
1378                    var thisMonth = currentDate.getMonth() == month;
1379                    var d = $(dc('td'))
1380								.text(currentDate.getDate() + '')
1381								.addClass((thisMonth ? 'current-month ' : 'other-month ') +
1382													(currentDate.isWeekend() ? 'weekend ' : 'weekday ') +
1383													(thisMonth && currentDate.getTime() == today.getTime() ? 'today ' : '')
1384								)
1385								.data('datePickerDate', currentDate.asString())
1386								.hover(doHover(firstDayInBounds), unHover)
1387                    ;
1388                    r.append(d);
1389                    if (s.renderCallback) {
1390                        s.renderCallback(d, currentDate, month, year);
1391                    }
1392                    // addDays(1) fails in some locales due to daylight savings. See issue 39.
1393                    //currentDate.addDays(1);
1394                    // set the time to midday to avoid any weird timezone issues??
1395                    currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1, 12, 0, 0);
1396                }
1397                tbody.append(r);
1398            }
1399            calendarTable.append(tbody);
1400
1401            return this.each(
1402				function () {
1403				    $(this).empty().append(calendarTable);
1404				}
1405			);
1406        },
1407        /**
1408         * Create a datePicker associated with each of the matched elements.
1409         *
1410         * The matched element will receive a few custom events with the following signatures:
1411         *
1412         * dateSelected(event, date, $td, status)
1413         * Triggered when a date is selected. event is a reference to the event, date is the Date selected, $td is a jquery object wrapped around the TD that was clicked on and status is whether the date was selected (true) or deselected (false)
1414         *
1415         * dpClosed(event, selected)
1416         * Triggered when the date picker is closed. event is a reference to the event and selected is an Array containing Date objects.
1417         *
1418         * dpMonthChanged(event, displayedMonth, displayedYear)
1419         * Triggered when the month of the popped up calendar is changed. event is a reference to the event, displayedMonth is the number of the month now displayed (zero based) and displayedYear is the year of the month.
1420         *
1421         * dpDisplayed(event, $datePickerDiv)
1422         * Triggered when the date picker is created. $datePickerDiv is the div containing the date picker. Use this event to add custom content/ listeners to the popped up date picker.
1423         *
1424         * @param Object s (optional) Customize your date pickers.
1425         * @option Number month The month to render when the date picker is opened (NOTE that months are zero based). Default is today's month.
1426         * @option Number year The year to render when the date picker is opened. Default is today's year.
1427         * @option String|Date startDate The first date date can be selected.
1428         * @option String|Date endDate The last date that can be selected.
1429         * @option Boolean inline Whether to create the datePicker as inline (e.g. always on the page) or as a model popup. Default is false (== modal popup)
1430         * @option Boolean createButton Whether to create a .dp-choose-date anchor directly after the matched element which when clicked will trigger the showing of the date picker. Default is true.
1431         * @option Boolean showYearNavigation Whether to display buttons which allow the user to navigate through the months a year at a time. Default is true.
1432         * @option Boolean closeOnSelect Whether to close the date picker when a date is selected. Default is true.
1433         * @option Boolean displayClose Whether to create a "Close" button within the date picker popup. Default is false.
1434         * @option Boolean selectMultiple Whether a user should be able to select multiple dates with this date picker. Default is false.
1435         * @option Number numSelectable The maximum number of dates that can be selected where selectMultiple is true. Default is a very high number.
1436         * @option Boolean clickInput If the matched element is an input type="text" and this option is true then clicking on the input will cause the date picker to appear.
1437         * @option Boolean rememberViewedMonth Whether the datePicker should remember the last viewed month and open on it. If false then the date picker will always open with the month for the first selected date visible.
1438         * @option Boolean selectWeek Whether to select a complete week at a time...
1439         * @option Number verticalPosition The vertical alignment of the popped up date picker to the matched element. One of $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM. Default is $.dpConst.POS_TOP.
1440         * @option Number horizontalPosition The horizontal alignment of the popped up date picker to the matched element. One of $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT.
1441         * @option Number verticalOffset The number of pixels offset from the defined verticalPosition of this date picker that it should pop up in. Default in 0.
1442         * @option Number horizontalOffset The number of pixels offset from the defined horizontalPosition of this date picker that it should pop up in. Default in 0.
1443         * @option (Function|Array) renderCallback A reference to a function (or an array of separate functions) that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Each callback function will receive four arguments;
1443 a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year. Default is no callback.
1444         * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
1445         * @option String autoFocusNextInput Whether focus should be passed onto the next input in the form (true) or remain on this input (false) when a date is selected and the calendar closes
1446         * @type jQuery
1447         * @name datePicker
1448         * @cat plugins/datePicker
1449         * @author Kelvin Luck (http://www.kelvinluck.com/)
1450         *
1451         * @example $('input.date-picker').datePicker();
1452         * @desc Creates a date picker button next to all matched input elements. When the button is clicked on the value of the selected date will be placed in the corresponding input (formatted according to Date.format).
1453         *
1454         * @example demo/index.html
1455         * @desc See the projects homepage for many more complex examples...
1456         **/
1457        datePicker: function (s) {
1458            if (!$.event._dpCache) $.event._dpCache = [];
1459
1460            // initialise the date picker controller with the relevant settings...
1461            s = $.extend({}, $.fn.datePicker.defaults, s);
1462            return this.each(
1463				function () {
1464				    var $this = $(this);
1465				    var alreadyExists = true;
1466
1467				    if (!this._dpId) {
1468				        this._dpId = $.guid++;
1469				        $.event._dpCache[this._dpId] = new DatePicker(this);
1470				        alreadyExists = false;
1471				    }
1472
1473				    if (s.inline) {
1474				        s.createButton = false;
1475				        s.displayClose = false;
1476				        s.closeOnSelect = false;
1477				        $this.empty();
1478				    }
1479
1480				    var controller = $.event._dpCache[this._dpId];
1481
1482				    controller.init(s);
1483
1484				    if (!alreadyExists && s.createButton) {
1485				        // create it!
1486				        controller.button = $('<a href="#" class="dp-choose-date" title="' + $.dpText.TEXT_CHOOSE_DATE + '">' + $.dpText.TEXT_CHOOSE_DATE + '</a>')
1487								.on(
1488									'click',
1489									function () {
1490									    $this.dpDisplay(this);
1491									    this.blur();
1492									    return false;
1493									}
1494								);
1495				        $this.after(controller.button);
1496				    }
1497
1498				    if (!alreadyExists && $this.is(':text')) {
1499				        $this
1500							.on(
1501								'dateSelected',
1502								function (e, selectedDate, $td) {
1503								    this.value = selectedDate.asString();
1504								}
1505							).on(
1506								'change',
1507								function () {
1508								    if (this.value == '') {
1509								        controller.clearSelected();
1510								    } else {
1511								        var d = Date.fromString(this.value);
1512								        if (d) {
1513								            controller.setSelected(d, true, true);
1514								        }
1515								    }
1516								}
1517							);
1518
1519				        if (s.clickInput) {
1520                            $this.on(
1521								'click',
1522								function () {
1523								    // The change event doesn't happen until the input loses focus so we need to manually trigger it...
1524								    $this.trigger('change');
1525								    $this.dpDisplay();
1526								}
1527							);
1528				        }
1529				        var d = Date.fromString(this.value);
1530				        if (this.value != '' && d) {
1531				            controller.setSelected(d, true, true);
1532				        }
1533				    }
1534
1535				    $this.addClass('dp-applied');
1536
1537				}
1538			)
1539        },
1540        /**
1541         * Disables or enables this date picker
1542         *
1543         * @param Boolean s Whether to disable (true) or enable (false) this datePicker
1544         * @type jQuery
1545         * @name dpSetDisabled
1546         * @cat plugins/datePicker
1547         * @author Kelvin Luck (http://www.kelvinluck.com/)
1548         *
1549         * @example $('.date-picker').datePicker();
1550         * $('.date-picker').dpSetDisabled(true);
1551         * @desc Prevents this date picker from displaying and adds a class of dp-disabled to it (and it's associated button if it has one) for styling purposes. If the matched element is an input field then it will also set the disabled attribute to stop people directly editing the field.
1552         **/
1553        dpSetDisabled: function (s) {
1554            return _w.call(this, 'setDisabled', s);
1555        },
1556        /**
1557         * Updates the first selectable date for any date pickers on any matched elements.
1558         *
1559         * @param String|Date d A Date object or string representing the first selectable date (formatted according to Date.format).
1560         * @type jQuery
1561         * @name dpSetStartDate
1562         * @cat plugins/datePicker
1563         * @author Kelvin Luck (http://www.kelvinluck.com/)
1564         *
1565         * @example $('.date-picker').datePicker();
1566         * $('.date-picker').dpSetStartDate('01/01/2000');
1567         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the first selectable date for each of these to the first day of the millenium.
1568         **/
1569        dpSetStartDate: function (d) {
1570            return _w.call(this, 'setStartDate', d);
1571        },
1572        /**
1573         * Updates the last selectable date for any date pickers on any matched elements.
1574         *
1575         * @param String|Date d A Date object or string representing the last selectable date (formatted according to Date.format).
1576         * @type jQuery
1577         * @name dpSetEndDate
1578         * @cat plugins/datePicker
1579         * @author Kelvin Luck (http://www.kelvinluck.com/)
1580         *
1581         * @example $('.date-picker').datePicker();
1582         * $('.date-picker').dpSetEndDate('01/01/2010');
1583         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the last selectable date for each of these to the first Janurary 2010.
1584         **/
1585        dpSetEndDate: function (d) {
1586            return _w.call(this, 'setEndDate', d);
1587        },
1588        /**
1589         * Gets a list of Dates currently selected by this datePicker. This will be an empty array if no dates are currently selected or NULL if there is no datePicker associated with the matched element.
1590         *
1591         * @type Array
1592         * @name dpGetSelected
1593         * @cat plugins/datePicker
1594         * @author Kelvin Luck (http://www.kelvinluck.com/)
1595         *
1596         * @example $('.date-picker').datePicker();
1597         * alert($('.date-picker').dpGetSelected());
1598         * @desc Will alert an empty array (as nothing is selected yet)
1599         **/
1600        dpGetSelected: function () {
1601            var c = _getController(this[0]);
1602            if (c) {
1603                return c.getSelected();
1604            }
1605            return null;
1606        },
1607        dpGetDisplayedMonthYear: function () {
1608            var c = _getController(this[0]);
1609
1610            return [c.displayedMonth, c.displayedYear];
1611        },
1612        /**
1613         * Selects or deselects a date on any matched element's date pickers. Deselcting is only useful on date pickers where selectMultiple==true. Selecting will only work if the passed date is within the startDate and endDate boundries for a given date picker.
1614         *
1615         * @param String|Date d A Date object or string representing the date you want to select (formatted according to Date.format).
1616         * @param Boolean v Whether you want to select (true) or deselect (false) this date. Optional - default = true.
1617         * @param Boolean m Whether you want the date picker to open up on the month of this date when it is next opened. Optional - default = true.
1618         * @param Boolean e Whether you want the date picker to dispatch events related to this change of selection. Optional - default = true.
1619         * @type jQuery
1620         * @name dpSetSelected
1621         * @cat plugins/datePicker
1622         * @author Kelvin Luck (http://www.kelvinluck.com/)
1623         *
1624         * @example $('.date-picker').datePicker();
1625         * $('.date-picker').dpSetSelected('01/01/2010');
1626         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
1627         **/
1628        dpSetSelected: function (d, v, m, e) {
1629            if (v == undefined) v = true;
1630            if (m == undefined) m = true;
1631            if (e == undefined) e = true;
1632            return _w.call(this, 'setSelected', Date.fromString(d), v, m, e);
1633        },
1634        /**
1635         * Sets the month that will be displayed when the date picker is next opened. If the passed month is before startDate then the month containing startDate will be displayed instead. If the passed month is after endDate then the month containing the endDate will be displayed instead.
1636         *
1637         * @param Number m The month you want the date picker to display. Optional - defaults to the currently displayed month.
1638         * @param Number y The year you want the date picker to display. Optional - defaults to the currently displayed year.
1639         * @type jQuery
1640         * @name dpSetDisplayedMonth
1641         * @cat plugins/datePicker
1642         * @author Kelvin Luck (http://www.kelvinluck.com/)
1643         *
1644         * @example $('.date-picker').datePicker();
1645         * $('.date-picker').dpSetDisplayedMonth(10, 2008);
1646         * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
1647         **/
1648        dpSetDisplayedMonth: function (m, y) {
1649            return _w.call(this, 'setDisplayedMonth', Number(m), Number(y), true);
1650        },
1651        /**
1652         * Displays the date picker associated with the matched elements. Since only one date picker can be displayed at once then the date picker associated with the last matched element will be the one that is displayed.
1653         *
1654         * @param HTMLElement e An element that you want the date picker to pop up relative in position to. Optional - default behaviour is to pop up next to the element associated with this date picker.
1655         * @type jQuery
1656         * @name dpDisplay
1657         * @cat plugins/datePicker
1658         * @author Kelvin Luck (http://www.kelvinluck.com/)
1659         *
1660         * @example $('#date-picker').datePicker();
1661         * $('#date-picker').dpDisplay();
1662         * @desc Creates a date picker associated with the element with an id of date-picker and then causes it to pop up.
1663         **/
1664        dpDisplay: function (e) {
1665            return _w.call(this, 'display', e);
1666        },
1667        /**
1668         * Sets a function or array of functions that is called when each TD of the date picker popup is rendered to the page
1669         *
1670         * @param (Function|Array) a A function or an array of functions that are called when each td is rendered. Each function will receive four arguments; a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year.
1671         * @type jQuery
1672         * @name dpSetRenderCallback
1673         * @cat plugins/datePicker
1674         * @author Kelvin Luck (http://www.kelvinluck.com/)
1675         *
1676         * @example $('#date-picker').datePicker();
1677         * $('#date-picker').dpSetRenderCallback(function($td, thisDate, month, year)
1678         * {
1679         * 	// do stuff as each td is rendered dependant on the date in the td and the displayed month and year
1680         * });
1681         * @desc Creates a date picker associated with the element with an id of date-picker and then creates a function which is called as each td is rendered when this date picker is displayed.
1682         **/
1683        dpSetRenderCallback: function (a) {
1684            return _w.call(this, 'setRenderCallback', a);
1685        },
1686        /**
1687         * Sets the position that the datePicker will pop up (relative to it's associated element)
1688         *
1689         * @param Number v The vertical alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM
1690         * @param Number h The horizontal alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT
1691         * @type jQuery
1692         * @name dpSetPosition
1693         * @cat plugins/datePicker
1694         * @author Kelvin Luck (http://www.kelvinluck.com/)
1695         *
1696         * @example $('#date-picker').datePicker();
1697         * $('#date-picker').dpSetPosition($.dpConst.POS_BOTTOM, $.dpConst.POS_RIGHT);
1698         * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be bottom and right aligned to the #date-picker element.
1699         **/
1700        dpSetPosition: function (v, h) {
1701            return _w.call(this, 'setPosition', v, h);
1702        },
1703        /**
1704         * Sets the offset that the popped up date picker will have from it's default position relative to it's associated element (as set by dpSetPosition)
1705         *
1706         * @param Number v The vertical offset of the created date picker.
1707         * @param Number h The horizontal offset of the created date picker.
1708         * @type jQuery
1709         * @name dpSetOffset
1710         * @cat plugins/datePicker
1711         * @author Kelvin Luck (http://www.kelvinluck.com/)
1712         *
1713         * @example $('#date-picker').datePicker();
1714         * $('#date-picker').dpSetOffset(-20, 200);
1715         * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be 20 pixels above and 200 pixels to the right of it's default position.
1716         **/
1717        dpSetOffset: function (v, h) {
1718            return _w.call(this, 'setOffset', v, h);
1719        },
1720        /**
1721         * Closes the open date picker associated with this element.
1722         *
1723         * @type jQuery
1724         * @name dpClose
1725         * @cat plugins/datePicker
1726         * @author Kelvin Luck (http://www.kelvinluck.com/)
1727         *
1728         * @example $('.date-pick')
1729         *		.datePicker()
1730         *		.on(
1731         *			'focus',
1732         *			function()
1733         *			{
1734         *				$(this).dpDisplay();
1735         *			}
1736         *		).on(
1737         *			'blur',
1738         *			function()
1739         *			{
1740         *				$(this).dpClose();
1741         *			}
1742         *		);
1743         **/
1744        dpClose: function () {
1745            return _w.call(this, '_closeCalendar', false, this[0]);
1746        },
1747        /**
1748         * Rerenders the date picker's current month (for use with inline calendars and renderCallbacks).
1749         *
1750         * @type jQuery
1751         * @name dpRerenderCalendar
1752         * @cat plugins/datePicker
1753         * @author Kelvin Luck (http://www.kelvinluck.com/)
1754         *
1755         **/
1756        dpRerenderCalendar: function () {
1757            return _w.call(this, '_rerenderCalendar');
1758        },
1759        // private function called on unload to clean up any expandos etc and prevent memory links...
1760        _dpDestroy: function () {
1761            // TODO - implement this?
1762        }
1763    });
1764
1765    // private internal function to cut down on the amount of code needed where we forward
1766    // dp* methods on the jQuery object on to the relevant DatePicker controllers...
1767    var _w = function (f, a1, a2, a3, a4) {
1768        return this.each(
1769			function () {
1770			    var c = _getController(this);
1771			    if (c) {
1772			        c[f](a1, a2, a3, a4);
1773			    }
1774			}
1775		);
1776    };
1777
1778    function DatePicker(ele) {
1779        this.ele = ele;
1780
1781        // initial values...
1782        this.displayedMonth = null;
1783        this.displayedYear = null;
1784        this.startDate = null;
1785        this.endDate = null;
1786        this.showYearNavigation = null;
1787        this.closeOnSelect = null;
1788        this.displayClose = null;
1789        this.rememberViewedMonth = null;
1790        this.selectMultiple = null;
1791        this.numSelectable = null;
1792        this.numSelected = null;
1793        this.verticalPosition = null;
1794        this.horizontalPosition = null;
1795        this.verticalOffset = null;
1796        this.horizontalOffset = null;
1797        this.button = null;
1798        this.renderCallback = [];
1799        this.selectedDates = {};
1800        this.inline = null;
1801        this.context = '#dp-popup';
1802        this.uiForm = null;
1803        this.settings = {};
1804    };
1805    $.extend(
1806		DatePicker.prototype,
1807		{
1808		    init: function (s) {
1809		        this.setStartDate(s.startDate);
1810		        this.setEndDate(s.endDate);
1811		        this.setDisplayedMonth(Number(s.month), Number(s.year));
1812		        this.setRenderCallback(s.renderCallback);
1813		        this.showYearNavigation = s.showYearNavigation;
1814		        this.closeOnSelect = s.closeOnSelect;
1815		        this.displayClose = s.displayClose;
1816		        this.rememberViewedMonth = s.rememberViewedMonth;
1817		        this.selectMultiple = s.selectMultiple;
1818		        this.selectableDate = s.selectableDate || false;
1819		        this.numSelectable = s.selectMultiple ? s.numSelectable : 1;
1820		        this.numSelected = 0;
1821		        this.verticalPosition = s.verticalPosition;
1822		        this.horizontalPosition = s.horizontalPosition;
1823		        this.hoverClass = s.hoverClass;
1824		        this.setOffset(s.verticalOffset, s.horizontalOffset);
1825		        this.inline = s.inline;
1826		        this.settings = s;
1827		        if (this.inline) {
1828		            this.context = this.ele;
1829		            this.display();
1830		        }
1831		    },
1832		    setStartDate: function (d) {
1833		        if (d) {
1834		            if (d instanceof Date) {
1835		                this.startDate = d;
1836		            } else {
1837		                this.startDate = Date.fromString(d);
1838		            }
1839		        }
1840		        if (!this.startDate) {
1841		            this.startDate = (new Date()).zeroTime();
1842		        }
1843		        this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
1844		    },
1845		    setEndDate: function (d) {
1846		        if (d) {
1847		            if (d instanceof Date) {
1848		                this.endDate = d;
1849		            } else {
1850		                this.endDate = Date.fromString(d);
1851		            }
1852		        }
1853		        if (!this.endDate) {
1854		            this.endDate = (new Date('12/31/2999')); // using the JS Date.parse function which expects mm/dd/yyyy
1855		        }
1856		        if (this.endDate.getTime() < this.startDate.getTime()) {
1857		            this.endDate = this.startDate;
1858		        }
1859		        this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
1860		    },
1861		    setPosition: function (v, h) {
1862		        this.verticalPosition = v;
1863		        this.horizontalPosition = h;
1864		    },
1865		    setOffset: function (v, h) {
1866		        this.verticalOffset = parseInt(v) || 0;
1867		        this.horizontalOffset = parseInt(h) || 0;
1868		    },
1869		    setDisabled: function (s) {
1870		        $e = $(this.ele);
1871		        $e[s ? 'addClass' : 'removeClass']('dp-disabled');
1872		        if (this.button) {
1873		            $but = $(this.button);
1874		            $but[s ? 'addClass' : 'removeClass']('dp-disabled');
1875		            $but.attr('title', s ? '' : $.dpText.TEXT_CHOOSE_DATE);
1876		        }
1877		        if ($e.is(':text')) {
1878		            $e.attr('disabled', s ? 'disabled' : '');
1879		        }
1880		    },
1881		    setDisplayedMonth: function (m, y, rerender) {
1882		        if (this.startDate == undefined || this.endDate == undefined) {
1883		            return;
1884		        }
1885		        var s = new Date(this.startDate.getTime());
1886		        s.setDate(1);
1887		        var e = new Date(this.endDate.getTime());
1888		        e.setDate(1);
1889
1890		        var t;
1891		        if ((!m && !y) || (isNaN(m) && isNaN(y))) {
1892		            // no month or year passed - default to current month
1893		            t = new Date().zeroTime();
1894		            t.setDate(1);
1895		        } else if (isNaN(m)) {
1896		            // just year passed in - presume we want the displayedMonth
1897		            t = new Date(y, this.displayedMonth, 1);
1898		        } else if (isNaN(y)) {
1899		            // just month passed in - presume we want the displayedYear
1900		            t = new Date(this.displayedYear, m, 1);
1901		        } else {
1902		            // year and month passed in - that's the date we want!
1903		            t = new Date(y, m, 1);
1904		        }
1905		        // check if the desired date is within the range of our defined startDate and endDate
1906		        var oldMonth = this.displayedMonth,
1907                                     oldYear = this.displayedYear;
1908		        this.displayedMonth = t.getMonth();
1909		        this.displayedYear = t.getFullYear();
1910
1911		        if (rerender && (this.displayedMonth != oldMonth || this.displayedYear != oldYear)) {
1912		            this._rerenderCalendar();
1913		            $(this.ele).trigger('dpMonthChanged', [this.displayedMonth, this.displayedYear]);
1914		        }
1915		    },
1916		    setSelected: function (d, v, moveToMonth, dispatchEvents) {
1917		        if (d < this.startDate || d.zeroTime() > this.endDate.zeroTime()) {
1918		            // Don't allow people to select dates outside range...
1919		            return;
1920		        }
1921		        var s = this.settings;
1922		        if (s.selectWeek) {
1923		            d = d.addDays(-(d.getDay() - Date.firstDayOfWeek + 7) % 7);
1924		            if (d < this.startDate) // The first day of this week is before the start date so is unselectable...
1925		            {
1926		                return;
1927		            }
1928		        }
1929		        if (v == this.isSelected(d)) // this date is already un/selected
1930		        {
1931		            return;
1932		        }
1933		        if (this.selectMultiple == false) {
1934		            this.clearSelected();
1935		        } else if (v && this.numSelected == this.numSelectable) {
1936		            // can't select any more dates...
1937		            return;
1938		        }
1939		        if (moveToMonth && (this.displayedMonth != d.getMonth() || this.displayedYear != d.getFullYear())) {
1940		            this.setDisplayedMonth(d.getMonth(), d.getFullYear(), true);
1941		        }
1942		        this.selectedDates[d.asString()] = v;
1943		        this.numSelected += v ? 1 : -1;
1944		        var selectorString = 'td.' + (d.getMonth() == this.displayedMonth ? 'current-month' : 'other-month');
1945		        var $td;
1946		        $(selectorString, this.context).each(
1947					function () {
1948					    if ($(this).data('datePickerDate') == d.asString()) {
1949					        $td = $(this);
1950					        if (s.selectWeek) {
1951					            $td.parent()[v ? 'addClass' : 'removeClass']('selectedWeek');
1952					        }
1953					        $td[v ? 'addClass' : 'removeClass']('selected');
1954					    }
1955					}
1956				);
1957		        $('td', this.context).not('.selected')[this.selectMultiple && this.numSelected == this.numSelectable ? 'addClass' : 'removeClass']('unselectable');
1958
1959		        if (dispatchEvents) {
1960		            var s = this.isSelected(d);
1961		            $e = $(this.ele);
1962		            var dClone = Date.fromString(d.asString());
1963		            $e.trigger('dateSelected', [dClone, $td, s]);
1964		            $e.trigger('change');
1965		        }
1966		    },
1967		    isSelected: function (d) {
1968		        return this.selectedDates[d.asString()];
1969		    },
1970		    getSelected: function () {
1971		        var r = [];
1972		        for (var s in this.selectedDates) {
1973		            if (this.selectedDates[s] == true) {
1974		                r.push(Date.fromString(s));
1975		            }
1976		        }
1977		        return r;
1978		    },
1979		    clearSelected: function () {
1980		        this.selectedDates = {};
1981		        this.numSelected = 0;
1982		        $('td.selected', this.context).removeClass('selected').parent().removeClass('selectedWeek');
1983		    },
1984		    display: function (eleAlignTo) {
1985		        if ($(this.ele).is('.dp-disabled')) return;
1986
1987		        eleAlignTo = eleAlignTo || this.ele;
1988		        var c = this;
1989		        var $ele = $(eleAlignTo);
1990		        var eleOffset = $ele.offset();
1991
1992		        var $createIn;
1993		        var attrs;
1994		        var attrsCalendarHolder;
1995		        var cssRules;
1996
1997		        if (c.inline) {
1998		            $createIn = $(this.ele);
1999		            attrs = {
2000		                'id': 'calendar-' + this.ele._dpId,
2001		                'class': 'dp-popup dp-popup-inline'
2002		            };
2003
2004		            $('.dp-popup', $createIn).remove();
2005		            cssRules = {
2006		            };
2007		        } else {
2008		            $createIn = $('body');
2009		            attrs = {
2010		                'id': 'dp-popup',
2011		                'class': 'dp-popup'
2012		            };
2013		            cssRules = {
2014		                'top': eleOffset.top + c.verticalOffset,
2015		                'left': eleOffset.left + c.horizontalOffset
2016		            };
2017
2018		            var _checkMouse = function (e) {
2019		                var el = e.target;
2020		                var cal = $('#dp-popup')[0];
2021
2022		                while (true) {
2023		                    if (el == cal) {
2024		                        return true;
2025		                    } else if (el == document) {
2026		                        c._closeCalendar();
2027		                        return false;
2028		                    } else {
2029		                        el = $(el).parent()[0];
2030		                    }
2031		                }
2032		            };
2033		            this._checkMouse = _checkMouse;
2034
2035		            c._closeCalendar(true);
2036		            $(document).on(
2037						'keydown.datepicker',
2038						function (event) {
2039						    if (event.keyCode == 27) {
2040						        c._closeCalendar();
2041						    }
2042						}
2043					);
2044		        }
2045
2046		        if (!c.rememberViewedMonth) {
2047		            var selectedDate = this.getSelected()[0];
2048		            if (selectedDate) {
2049		                selectedDate = new Date(selectedDate);
2050		                this.setDisplayedMonth(selectedDate.getMonth(), selectedDate.getFullYear(), false);
2051		            }
2052		        }
2053
2054		        $createIn
2055					.append(
2056						$('<div></div>')
2057							.attr(attrs)
2058							.css(cssRules)
2059							.append(
2060                            $('<div class="dp-top"></div>').append(
2061								$('<h2></h2>'),
2062								$('<div class="dp-nav-prev"></div>')
2063									.append(
2064										$('<a class="dp-nav-prev-year" href="#" title="' + $.dpText.TEXT_PREV_YEAR + '">&lt;&lt;</a>')
2065											.on(
2066												'click',
2067												function () {
2068												    return c._displayNewMonth.call(c, this, 0, -1);
2069												}
2070											),
2071										$('<a class="dp-nav-prev-month" href="#" title="' + $.dpText.TEXT_PREV_MONTH + '">&lt;</a>')
2072											.on(
2073												'click',
2074												function () {
2075												    return c._displayNewMonth.call(c, this, -1, 0);
2076												}
2077											)
2078									),
2079								$('<div class="dp-nav-next"></div>')
2080									.append(
2081										$('<a class="dp-nav-next-year" href="#" title="' + $.dpText.TEXT_NEXT_YEAR + '">&gt;&gt;</a>')
2082											.on(
2083												'click',
2084												function () {
2085												    return c._displayNewMonth.call(c, this, 0, 1);
2086												}
2087											),
2088										$('<a class="dp-nav-next-month" href="#" title="' + $.dpText.TEXT_NEXT_MONTH + '">&gt;</a>')
2089											.on(
2090												'click',
2091												function () {
2092												    return c._displayNewMonth.call(c, this, 1, 0);
2093												}
2094											)
2095                                )
2096                            ),
2097                        $('<div class="dp-calendar"></div>')
2098							)
2099							.bgIframe()
2100						);
2101
2102		        var $pop = this.inline ? $('.dp-popup', this.context) : $('#dp-popup');
2103
2104		        if (this.showYearNavigation == false) {
2105		            $('.dp-nav-prev-year, .dp-nav-next-year', c.context).css('display', 'none');
2106		        }
2107		        if (this.displayClose) {
2108		            $pop.append(
2109						$('<a href="#" id="dp-close">' + $.dpText.TEXT_CLOSE + '</a>')
2110                            .on(
2111								'click',
2112								function () {
2113								    c._closeCalendar();
2114								    return false;
2115								}
2116							)
2117					);
2118		        }
2119		        c._renderCalendar();
2120
2121		        $(this.ele).trigger('dpDisplayed', $pop);
2122
2123		        if (!c.inline) {
2124		            if (this.verticalPosition == $.dpConst.POS_BOTTOM) {
2125		                $pop.css('top', eleOffset.top + $ele.height() - $pop.height() + c.verticalOffset);
2126		            }
2127		            if (this.horizontalPosition == $.dpConst.POS_RIGHT) {
2128		                $pop.css('left', eleOffset.left + $ele.width() - $pop.width() + c.horizontalOffset);
2129		            }
2130		            //					$('.selectee', this.context).focus();
2131                    $(document).on('mousedown.datepicker', this._checkMouse);
2132		        }
2133
2134		    },
2135		    setRenderCallback: function (a) {
2136		        if (a == null) return;
2137		        if (a && typeof (a) == 'function') {
2138		            a = [a];
2139		        }
2140		        this.renderCallback = this.renderCallback.concat(a);
2141		    },
2142		    cellRender: function ($td, thisDate, month, year) {
2143		        var c = this.dpController;
2144		        var d = new Date(thisDate.getTime());
2145
2146		        // add our click handlers to deal with it when the days are clicked...
2147
2148                $td.on(
2149					'click',
2150					function () {
2151					    var $this = $(this);
2152					    if (!$this.is('.disabled')) {
2153					        c.setSelected(d, !$this.is('.selected') || !c.selectMultiple, false, true);
2154					        if (c.closeOnSelect) {
2155					            // Focus the next input in the form…
2156					            if (c.settings.autoFocusNextInput) {
2157					                var ele = c.ele;
2158					                var found = false;
2159					                $(':input', ele.form).each(
2160										function () {
2161										    if (found) {
2162										        $(this).focus();
2163										        return false;
2164										    }
2165										    if (this == ele) {
2166										        found = true;
2167										    }
2168										}
2169									);
2170					            } else {
2171					                try {
2172					                    c.ele.focus();
2173					                } catch (e) { }
2174					            }
2175					            c._closeCalendar();
2176					        }
2177					    }
2178					}
2179				);
2180		        if (c.isSelected(d)) {
2181		            $td.addClass('selected');
2182		            if (c.settings.selectWeek) {
2183		                $td.parent().addClass('selectedWeek');
2184		            }
2185		        } else if (c.selectMultiple && c.numSelected == c.numSelectable) {
2186		            $td.addClass('unselectable');
2187		        }
2188
2189		    },
2190		    _applyRenderCallbacks: function () {
2191		        var c = this;
2192		        $('td', this.context).each(
2193					function () {
2194					    for (var i = 0; i < c.renderCallback.length; i++) {
2195					        $td = $(this);
2196					        c.renderCallback[i].apply(this, [$td, Date.fromString($td.data('datePickerDate')), c.displayedMonth, c.displayedYear]);
2197					    }
2198					}
2199				);
2200		        return;
2201		    },
2202		    // ele is the clicked button - only proceed if it doesn't have the class disabled...
2203		    // m and y are -1, 0 or 1 depending which direction we want to go in...
2204		    _displayNewMonth: function (ele, m, y) {
2205		        if (!$(ele).is('.disabled')) {
2206
2207		            this.setDisplayedMonth(this.displayedMonth + m, this.displayedYear + y, true);
2208
2209		            /*if ( this.selectableDate && this.uiForm) {
2210                        this.uiForm.update({
2211                            m: this.displayedMonth,
2212                            y: this.displayedYear
2213                        });
2214                    };*/
2215		        }
2216		        ele.blur();
2217		        return false;
2218		    },
2219		    _displayNewDate: function (m, y) {
2220		        this.setDisplayedMonth(m, y, true);
2221
2222		        return false;
2223		    },
2224		    _rerenderCalendar: function () {
2225		        this._clearCalendar();
2226		        this._renderCalendar();
2227		        if (this.selectableDate && this.uiForm) {
2228		            this._renderDateSelect();
2229		        }
2230		    },
2231		    _renderDateSelect: function (title, displayedMonth, displayedYear) {
2232		        var that = this,
2233                    thisYear = (new Date()).getFullYear(),
2234                    thisMonth = (new Date()).getMonth(),
2235                    startYear = thisYear - 3,
2236                    endYear = thisYear + 2,
2237                    startMonth = 0,
2238                    endMonth = 11;
2239
2240		        function getMY(d) {
2241
2242		            var d = Date.fromString(d, that.settings.dateFormat);
2243
2244		            return [d.getFullYear(), d.getMonth()];
2245		        }
2246
2247		        if (this.settings.isLimited) {
2248
2249		            var start = getMY(this.settings.isLimited[0]),
2250                        end = getMY(this.settings.isLimited[1]);
2251
2252		            startYear = start[0];
2253		            endYear = end[0];
2254		            if (startYear == endYear) {
2255		                startMonth = start[1];
2256		                endMonth = end[1];
2257		            }
2258		        }
2259
2260		        if ((!title && this.uiForm) || title.hasClass('dp-active')) {
2261		            this.uiForm.update({
2262		                m: this.displayedMonth,
2263		                mm: Date.monthNames[this.displayedMonth],
2264		                y: this.displayedYear
2265		            });
2266		            return that;
2267		        }
2268
2269                var uiForm = $('<div class="ui-form" style="display: flex; gap: 5px;"><div class="form-element w-60"><select class="select-month small"></select></div><div class="form-element"><select class="select-year small"></select></div></div>')
2270		        selectYear = $('select.select-year', uiForm),
2271                selectMonth = $('select.select-month', uiForm);
2272
2273		        for (var i = startMonth; i <= endMonth; i++) {
2274		            var option = $('<option>').attr('value', i).html(Date.monthNames[i]);
2275		            if (i == displayedMonth) {
2276		                option.attr("selected", "selected").prop("selected", true);
2277		            }
2278		            option.appendTo(selectMonth);
2279		        };
2280		        for (var i = endYear; i > startYear - 1; i--) {
2281		            var option = $('<option>').attr('value', i).text(i);
2282		            if (i == displayedYear) {
2283		                option.attr("selected", "selected").prop("selected", true);
2284		            }
2285		            option.appendTo(selectYear);
2286		        };
2287
2288		        $('<div>').addClass('form-element f-none');
2289
2290		        uiForm.appendTo(title);
2291
2292		        title.addClass('dp-active');
2293
2294		        this.uiForm = $('.ui-form', title);
2295		        this.uiForm.update = function (values) {
2296		            $('select.select-year', this).selectbox('change', values.y.toString(), values.y);   // val(values.y);
2297		            $('select.select-month', this).selectbox('change', values.m.toString(), values.mm); // val(values.m);
2298		        };
2299                $('select', title).addClass('auto-list-width').selectbox().on("change", function (e) {
2300
2301		            e.preventDefault();
2302
2303		            var m = $('option', $('select.select-month', that.uiForm)).filter(':selected').val(),
2304                        y = $('option', $('select.select-year', that.uiForm)).filter(':selected').val();
2305
2306		            that._displayNewDate(m, y);
2307		        });
2308		    },
2309		    _renderCalendar: function () {
2310		        // set the title...
2311		        if (!this.selectableDate) {
2312		            $('h2', this.context).html((new Date(this.displayedYear, this.displayedMonth, 1)).asString($.dpText.HEADER_FORMAT));
2313		        } else {
2314		            var title = $('h2', this.context);
2315		            this._renderDateSelect.call(this, title, this.displayedMonth, this.displayedYear);
2316		        }
2317
2318		        // render the calendar...
2319		        $('.dp-calendar', this.context).renderCalendar(
2320					$.extend(
2321						{},
2322						this.settings,
2323						{
2324						    month: this.displayedMonth,
2325						    year: this.displayedYear,
2326						    renderCallback: this.cellRender,
2327						    dpController: this,
2328						    hoverClass: this.hoverClass
2329						})
2330				);
2331
2332		        // update the status of the control buttons and disable dates before startDate or after endDate...
2333		        // TODO: When should the year buttons be disabled? When you can't go forward a whole year from where you are or is that annoying?
2334		        if (this.displayedYear == this.startDate.getFullYear() && this.displayedMonth == this.startDate.getMonth()) {
2335		            $('.dp-nav-prev-year', this.context).addClass('disabled');
2336		            $('.dp-nav-prev-month', this.context).addClass('disabled');
2337		            $('.dp-calendar td.other-month', this.context).each(
2338						function () {
2339						    var $this = $(this);
2340						    if (Number($this.text()) > 20) {
2341						        $this.addClass('disabled');
2342						    }
2343						}
2344					);
2345		            var d = this.startDate.getDate();
2346		            $('.dp-calendar td.current-month', this.context).each(
2347						function () {
2348						    var $this = $(this);
2349						    if (Number($this.text()) < d) {
2350						        $this.addClass('disabled');
2351						    }
2352						}
2353					);
2354		        } else {
2355		            $('.dp-nav-prev-year', this.context).removeClass('disabled');
2356		            $('.dp-nav-prev-month', this.context).removeClass('disabled');
2357		            var d = this.startDate.getDate();
2358		            if (d > 20) {
2359		                // check if the startDate is last month as we might need to add some disabled classes...
2360		                var st = this.startDate.getTime();
2361		                var sd = new Date(st);
2362		                sd.addMonths(1);
2363		                if (this.displayedYear == sd.getFullYear() && this.displayedMonth == sd.getMonth()) {
2364		                    $('.dp-calendar td.other-month', this.context).each(
2365								function () {
2366								    var $this = $(this);
2367								    if (Date.fromString($this.data('datePickerDate')).getTime() < st) {
2368								        $this.addClass('disabled');
2369								    }
2370								}
2371							);
2372		                }
2373		            }
2374		        }
2375		        if (this.displayedYear == this.endDate.getFullYear() && this.displayedMonth == this.endDate.getMonth()) {
2376		            $('.dp-nav-next-year', this.context).addClass('disabled');
2377		            $('.dp-nav-next-month', this.context).addClass('disabled');
2378		            $('.dp-calendar td.other-month', this.context).each(
2379						function () {
2380						    var $this = $(this);
2381						    if (Number($this.text()) < 14) {
2382						        $this.addClass('disabled');
2383						    }
2384						}
2385					);
2386		            var d = this.endDate.getDate();
2387		            $('.dp-calendar td.current-month', this.context).each(
2388						function () {
2389						    var $this = $(this);
2390						    if (Number($this.text()) > d) {
2391						        $this.addClass('disabled');
2392						    }
2393						}
2394					);
2395		        } else {
2396		            $('.dp-nav-next-year', this.context).removeClass('disabled');
2397		            $('.dp-nav-next-month', this.context).removeClass('disabled');
2398		            var d = this.endDate.getDate();
2399		            if (d < 13) {
2400		                // check if the endDate is next month as we might need to add some disabled classes...
2401		                var ed = new Date(this.endDate.getTime());
2402		                ed.addMonths(-1);
2403		                if (this.displayedYear == ed.getFullYear() && this.displayedMonth == ed.getMonth()) {
2404		                    $('.dp-calendar td.other-month', this.context).each(
2405								function () {
2406								    var $this = $(this);
2407								    var cellDay = Number($this.text());
2408								    if (cellDay < 13 && cellDay > d) {
2409								        $this.addClass('disabled');
2410								    }
2411								}
2412							);
2413		                }
2414		            }
2415		        }
2416		        this._applyRenderCallbacks();
2417		    },
2418		    _closeCalendar: function (programatic, ele) {
2419		        if (!ele || ele == this.ele) {
2420		            $(document).off('mousedown.datepicker');
2421		            $(document).off('keydown.datepicker');
2422		            this._clearCalendar();
2423		            $('#dp-popup a').off();
2424		            $('#dp-popup').empty().remove();
2425		            if (!programatic) {
2426		                $(this.ele).trigger('dpClosed', [this.getSelected()]);
2427		            }
2428		        }
2429		    },
2430		    // empties the current dp-calendar div and makes sure that all events are unbound
2431		    // and expandos removed to avoid memory leaks...
2432		    _clearCalendar: function () {
2433		        // TODO.
2434		        $('.dp-calendar td', this.context).off();
2435		        $('.dp-calendar', this.context).empty();
2436		    }
2437		}
2438	);
2439
2440    // static constants
2441    $.dpConst = {
2442        SHOW_HEADER_NONE: 0,
2443        SHOW_HEADER_SHORT: 1,
2444        SHOW_HEADER_LONG: 2,
2445        POS_TOP: 0,
2446        POS_BOTTOM: 1,
2447        POS_LEFT: 0,
2448        POS_RIGHT: 1,
2449        DP_INTERNAL_FOCUS: 'dpInternalFocusTrigger'
2450    };
2451    // localisable text
2452    $.dpText = {
2453        TEXT_PREV_YEAR: Date.dpText.TEXT_PREV_YEAR || 'Previous year',
2454        TEXT_PREV_MONTH: Date.dpText.TEXT_PREV_MONTH || 'Previous month',
2455        TEXT_NEXT_YEAR: Date.dpText.TEXT_NEXT_YEAR || 'Next year',
2456        TEXT_NEXT_MONTH: Date.dpText.TEXT_NEXT_MONTH || 'Next month',
2457        TEXT_CLOSE: Date.dpText.TEXT_CLOSE || 'Close',
2458        TEXT_CHOOSE_DATE: Date.dpText.TEXT_CHOOSE_DATE || 'Choose date',
2459        HEADER_FORMAT: Date.dpText.HEADER_FORMAT || 'mmmm yyyy'
2460    };
2461    // version
2462    $.dpVersion = '$Id$';
2463
2464    $.fn.datePicker.defaults = {
2465        month: undefined,
2466        year: undefined,
2467        showHeader: $.dpConst.SHOW_HEADER_SHORT,
2468        startDate: undefined,
2469        endDate: undefined,
2470        inline: false,
2471        renderCallback: null,
2472        createButton: true,
2473        showYearNavigation: true,
2474        closeOnSelect: true,
2475        displayClose: false,
2476        selectMultiple: false,
2477        numSelectable: Number.MAX_VALUE,
2478        clickInput: false,
2479        rememberViewedMonth: true,
2480        selectWeek: false,
2481        selectableDate: false,
2482        verticalPosition: $.dpConst.POS_TOP,
2483        horizontalPosition: $.dpConst.POS_LEFT,
2484        verticalOffset: 0,
2485        horizontalOffset: 0,
2486        hoverClass: 'dp-hover',
2487        autoFocusNextInput: false
2488    };
2489
2490    function _getController(ele) {
2491        if (ele._dpId) return $.event._dpCache[ele._dpId];
2492        return false;
2493    };
2494
2495    // make it so that no error is thrown if bgIframe plugin isn't included (allows you to use conditional
2496    // comments to only include bgIframe where it is needed in IE without breaking this plugin).
2497    if ($.fn.bgIframe == undefined) {
2498        $.fn.bgIframe = function () { return this; };
2499    };
2500
2501
2502    // clean-up
2503    $(window)
2504        .on('unload', function () {
2505		    var els = $.event._dpCache || [];
2506		    for (var i in els) {
2507		        $(els[i].ele)._dpDestroy();
2508		    }
2509		});
2510
2511})(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.