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

UCC git Repository :: git.ucc.asn.au