PluginProbe ʕ •ᴥ•ʔ
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel / 1.3.1
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel v1.3.1
trunk 0.9.0 0.9.1 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.2.1 1.2.10 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.14 1.4.15 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0
wp-all-export / static / js / jquery / ui.datepicker.js
wp-all-export / static / js / jquery Last commit date
css 8 years ago chosen.jquery.js 8 years ago chosen.jquery.min.js 10 years ago jquery.ddslick.min.js 10 years ago jquery.mjs.pmxe_nestedSortable.js 7 years ago jquery.timepicker.js 8 years ago jquery.tipsy.js 5 years ago moment.js 9 years ago select2.min.js 12 years ago ui.autocomplete.js 12 years ago ui.datepicker.js 12 years ago
ui.datepicker.js
1637 lines
1 /*
2 * jQuery UI Datepicker 1.7.3
3 *
4 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT (MIT-LICENSE.txt)
6 * and GPL (GPL-LICENSE.txt) licenses.
7 *
8 * http://docs.jquery.com/UI/Datepicker
9 *
10 * Depends:
11 * ui.core.js
12 */
13
14 (function($) { // hide the namespace
15
16 $.extend($.ui, { datepicker: { version: "1.7.3" } });
17
18 var PROP_NAME = 'datepicker';
19
20 /* Date picker manager.
21 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
22 Settings for (groups of) date pickers are maintained in an instance object,
23 allowing multiple different settings on the same page. */
24
25 function Datepicker() {
26 this.debug = false; // Change this to true to start debugging
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 dateFormat: 'mm/dd/yy', // See format options on parseDate
54 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
55 isRTL: false // True if right-to-left language, false if left-to-right
56 };
57 this._defaults = { // Global defaults for all the date picker instances
58 showOn: 'focus', // 'focus' for popup on focus,
59 // 'button' for trigger button, or 'both' for either
60 showAnim: 'show', // Name of jQuery animation for popup
61 showOptions: {}, // Options for enhanced animations
62 defaultDate: null, // Used when field is blank: actual date,
63 // +/-number for offset from today, null for today
64 appendText: '', // Display text following the input box, e.g. showing the format
65 buttonText: '...', // Text for trigger button
66 buttonImage: '', // URL for trigger button image
67 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
68 hideIfNoPrevNext: false, // True to hide next/previous month links
69 // if not applicable, false to just disable them
70 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
71 gotoCurrent: false, // True if today link goes back to current selection instead
72 changeMonth: false, // True if month can be selected directly, false if only prev/next
73 changeYear: false, // True if year can be selected directly, false if only prev/next
74 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
75 yearRange: '-10:+10', // Range of years to display in drop-down,
76 // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
77 showOtherMonths: false, // True to show dates in other months, false to leave blank
78 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
79 // takes a Date and returns the number of the week for it
80 shortYearCutoff: '+10', // Short year values < this are in the current century,
81 // > this are in the previous century,
82 // string value starting with '+' for current year + value
83 minDate: null, // The earliest selectable date, or null for no limit
84 maxDate: null, // The latest selectable date, or null for no limit
85 duration: 'normal', // Duration of display/closure
86 beforeShowDay: null, // Function that takes a date and returns an array with
87 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
88 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
89 beforeShow: null, // Function that takes an input field and
90 // returns a set of custom settings for the date picker
91 onSelect: null, // Define a callback function when a date is selected
92 onChangeMonthYear: null, // Define a callback function when the month or year is changed
93 onClose: null, // Define a callback function when the datepicker is closed
94 numberOfMonths: 1, // Number of months to show at a time
95 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
96 stepMonths: 1, // Number of months to step back/forward
97 stepBigMonths: 12, // Number of months to step back/forward for the big links
98 altField: '', // Selector for an alternate field to store selected dates into
99 altFormat: '', // The date format to use for the alternate field
100 constrainInput: true, // The input is constrained by the current date format
101 showButtonPanel: false // True to show button panel, false to not show it
102 };
103 $.extend(this._defaults, this.regional['']);
104 this.dpDiv = $('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>');
105 }
106
107 $.extend(Datepicker.prototype, {
108 /* Class name added to elements to indicate already configured with a date picker. */
109 markerClassName: 'hasDatepicker',
110
111 /* Debug logging (if enabled). */
112 log: function () {
113 if (this.debug)
114 console.log.apply('', arguments);
115 },
116
117 /* Override the default settings for all instances of the date picker.
118 @param settings object - the new settings to use as defaults (anonymous object)
119 @return the manager object */
120 setDefaults: function(settings) {
121 extendRemove(this._defaults, settings || {});
122 return this;
123 },
124
125 /* Attach the date picker to a jQuery selection.
126 @param target element - the target input field or division or span
127 @param settings object - the new settings to use for this date picker instance (anonymous) */
128 _attachDatepicker: function(target, settings) {
129 // check for settings on the control itself - in namespace 'date:'
130 var inlineSettings = null;
131 for (var attrName in this._defaults) {
132 var attrValue = target.getAttribute('date:' + attrName);
133 if (attrValue) {
134 inlineSettings = inlineSettings || {};
135 try {
136 inlineSettings[attrName] = eval(attrValue);
137 } catch (err) {
138 inlineSettings[attrName] = attrValue;
139 }
140 }
141 }
142 var nodeName = target.nodeName.toLowerCase();
143 var inline = (nodeName == 'div' || nodeName == 'span');
144 if (!target.id)
145 target.id = 'dp' + (++this.uuid);
146 var inst = this._newInst($(target), inline);
147 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
148 if (nodeName == 'input') {
149 this._connectDatepicker(target, inst);
150 } else if (inline) {
151 this._inlineDatepicker(target, inst);
152 }
153 },
154
155 /* Create a new instance object. */
156 _newInst: function(target, inline) {
157 var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars
158 return {id: id, input: target, // associated target
159 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
160 drawMonth: 0, drawYear: 0, // month being drawn
161 inline: inline, // is datepicker inline or not
162 dpDiv: (!inline ? this.dpDiv : // presentation div
163 $('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))};
164 },
165
166 /* Attach the date picker to an input field. */
167 _connectDatepicker: function(target, inst) {
168 var input = $(target);
169 inst.append = $([]);
170 inst.trigger = $([]);
171 if (input.hasClass(this.markerClassName))
172 return;
173 var appendText = this._get(inst, 'appendText');
174 var isRTL = this._get(inst, 'isRTL');
175 if (appendText) {
176 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
177 input[isRTL ? 'before' : 'after'](inst.append);
178 }
179 var showOn = this._get(inst, 'showOn');
180 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
181 input.focus(this._showDatepicker);
182 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
183 var buttonText = this._get(inst, 'buttonText');
184 var buttonImage = this._get(inst, 'buttonImage');
185 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
186 $('<img/>').addClass(this._triggerClass).
187 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
188 $('<button type="button"></button>').addClass(this._triggerClass).
189 html(buttonImage == '' ? buttonText : $('<img/>').attr(
190 { src:buttonImage, alt:buttonText, title:buttonText })));
191 input[isRTL ? 'before' : 'after'](inst.trigger);
192 inst.trigger.click(function() {
193 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target)
194 $.datepicker._hideDatepicker();
195 else
196 $.datepicker._showDatepicker(target);
197 return false;
198 });
199 }
200 input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
201 bind("setData.datepicker", function(event, key, value) {
202 inst.settings[key] = value;
203 }).bind("getData.datepicker", function(event, key) {
204 return this._get(inst, key);
205 });
206 $.data(target, PROP_NAME, inst);
207 },
208
209 /* Attach an inline date picker to a div. */
210 _inlineDatepicker: function(target, inst) {
211 var divSpan = $(target);
212 if (divSpan.hasClass(this.markerClassName))
213 return;
214 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
215 bind("setData.datepicker", function(event, key, value){
216 inst.settings[key] = value;
217 }).bind("getData.datepicker", function(event, key){
218 return this._get(inst, key);
219 });
220 $.data(target, PROP_NAME, inst);
221 this._setDate(inst, this._getDefaultDate(inst));
222 this._updateDatepicker(inst);
223 this._updateAlternate(inst);
224 },
225
226 /* Pop-up the date picker in a "dialog" box.
227 @param input element - ignored
228 @param dateText string - the initial date to display (in the current format)
229 @param onSelect function - the function(dateText) to call when a date is selected
230 @param settings object - update the dialog date picker instance's settings (anonymous object)
231 @param pos int[2] - coordinates for the dialog's position within the screen or
232 event - with x/y coordinates or
233 leave empty for default (screen centre)
234 @return the manager object */
235 _dialogDatepicker: function(input, dateText, onSelect, settings, pos) {
236 var inst = this._dialogInst; // internal instance
237 if (!inst) {
238 var id = 'dp' + (++this.uuid);
239 this._dialogInput = $('<input type="text" id="' + id +
240 '" size="1" style="position: absolute; top: -100px;"/>');
241 this._dialogInput.keydown(this._doKeyDown);
242 $('body').append(this._dialogInput);
243 inst = this._dialogInst = this._newInst(this._dialogInput, false);
244 inst.settings = {};
245 $.data(this._dialogInput[0], PROP_NAME, inst);
246 }
247 extendRemove(inst.settings, settings || {});
248 this._dialogInput.val(dateText);
249
250 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
251 if (!this._pos) {
252 var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
253 var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
254 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
255 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
256 this._pos = // should use actual width/height below
257 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
258 }
259
260 // move input on screen for focus, but hidden behind dialog
261 this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
262 inst.settings.onSelect = onSelect;
263 this._inDialog = true;
264 this.dpDiv.addClass(this._dialogClass);
265 this._showDatepicker(this._dialogInput[0]);
266 if ($.blockUI)
267 $.blockUI(this.dpDiv);
268 $.data(this._dialogInput[0], PROP_NAME, inst);
269 return this;
270 },
271
272 /* Detach a datepicker from its control.
273 @param target element - the target input field or division or span */
274 _destroyDatepicker: function(target) {
275 var $target = $(target);
276 var inst = $.data(target, PROP_NAME);
277 if (!$target.hasClass(this.markerClassName)) {
278 return;
279 }
280 var nodeName = target.nodeName.toLowerCase();
281 $.removeData(target, PROP_NAME);
282 if (nodeName == 'input') {
283 inst.append.remove();
284 inst.trigger.remove();
285 $target.removeClass(this.markerClassName).
286 unbind('focus', this._showDatepicker).
287 unbind('keydown', this._doKeyDown).
288 unbind('keypress', this._doKeyPress);
289 } else if (nodeName == 'div' || nodeName == 'span')
290 $target.removeClass(this.markerClassName).empty();
291 },
292
293 /* Enable the date picker to a jQuery selection.
294 @param target element - the target input field or division or span */
295 _enableDatepicker: function(target) {
296 var $target = $(target);
297 var inst = $.data(target, PROP_NAME);
298 if (!$target.hasClass(this.markerClassName)) {
299 return;
300 }
301 var nodeName = target.nodeName.toLowerCase();
302 if (nodeName == 'input') {
303 target.disabled = false;
304 inst.trigger.filter('button').
305 each(function() { this.disabled = false; }).end().
306 filter('img').css({opacity: '1.0', cursor: ''});
307 }
308 else if (nodeName == 'div' || nodeName == 'span') {
309 var inline = $target.children('.' + this._inlineClass);
310 inline.children().removeClass('ui-state-disabled');
311 }
312 this._disabledInputs = $.map(this._disabledInputs,
313 function(value) { return (value == target ? null : value); }); // delete entry
314 },
315
316 /* Disable the date picker to a jQuery selection.
317 @param target element - the target input field or division or span */
318 _disableDatepicker: function(target) {
319 var $target = $(target);
320 var inst = $.data(target, PROP_NAME);
321 if (!$target.hasClass(this.markerClassName)) {
322 return;
323 }
324 var nodeName = target.nodeName.toLowerCase();
325 if (nodeName == 'input') {
326 target.disabled = true;
327 inst.trigger.filter('button').
328 each(function() { this.disabled = true; }).end().
329 filter('img').css({opacity: '0.5', cursor: 'default'});
330 }
331 else if (nodeName == 'div' || nodeName == 'span') {
332 var inline = $target.children('.' + this._inlineClass);
333 inline.children().addClass('ui-state-disabled');
334 }
335 this._disabledInputs = $.map(this._disabledInputs,
336 function(value) { return (value == target ? null : value); }); // delete entry
337 this._disabledInputs[this._disabledInputs.length] = target;
338 },
339
340 /* Is the first field in a jQuery collection disabled as a datepicker?
341 @param target element - the target input field or division or span
342 @return boolean - true if disabled, false if enabled */
343 _isDisabledDatepicker: function(target) {
344 if (!target) {
345 return false;
346 }
347 for (var i = 0; i < this._disabledInputs.length; i++) {
348 if (this._disabledInputs[i] == target)
349 return true;
350 }
351 return false;
352 },
353
354 /* Retrieve the instance data for the target control.
355 @param target element - the target input field or division or span
356 @return object - the associated instance data
357 @throws error if a jQuery problem getting data */
358 _getInst: function(target) {
359 try {
360 return $.data(target, PROP_NAME);
361 }
362 catch (err) {
363 throw 'Missing instance data for this datepicker';
364 }
365 },
366
367 /* Update or retrieve the settings for a date picker attached to an input field or division.
368 @param target element - the target input field or division or span
369 @param name object - the new settings to update or
370 string - the name of the setting to change or retrieve,
371 when retrieving also 'all' for all instance settings or
372 'defaults' for all global defaults
373 @param value any - the new value for the setting
374 (omit if above is an object or to retrieve a value) */
375 _optionDatepicker: function(target, name, value) {
376 var inst = this._getInst(target);
377 if (arguments.length == 2 && typeof name == 'string') {
378 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
379 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
380 this._get(inst, name)) : null));
381 }
382 var settings = name || {};
383 if (typeof name == 'string') {
384 settings = {};
385 settings[name] = value;
386 }
387 if (inst) {
388 if (this._curInst == inst) {
389 this._hideDatepicker(null);
390 }
391 var date = this._getDateDatepicker(target);
392 extendRemove(inst.settings, settings);
393 this._setDateDatepicker(target, date);
394 this._updateDatepicker(inst);
395 }
396 },
397
398 // change method deprecated
399 _changeDatepicker: function(target, name, value) {
400 this._optionDatepicker(target, name, value);
401 },
402
403 /* Redraw the date picker attached to an input field or division.
404 @param target element - the target input field or division or span */
405 _refreshDatepicker: function(target) {
406 var inst = this._getInst(target);
407 if (inst) {
408 this._updateDatepicker(inst);
409 }
410 },
411
412 /* Set the dates for a jQuery selection.
413 @param target element - the target input field or division or span
414 @param date Date - the new date
415 @param endDate Date - the new end date for a range (optional) */
416 _setDateDatepicker: function(target, date, endDate) {
417 var inst = this._getInst(target);
418 if (inst) {
419 this._setDate(inst, date, endDate);
420 this._updateDatepicker(inst);
421 this._updateAlternate(inst);
422 }
423 },
424
425 /* Get the date(s) for the first entry in a jQuery selection.
426 @param target element - the target input field or division or span
427 @return Date - the current date or
428 Date[2] - the current dates for a range */
429 _getDateDatepicker: function(target) {
430 var inst = this._getInst(target);
431 if (inst && !inst.inline)
432 this._setDateFromField(inst);
433 return (inst ? this._getDate(inst) : null);
434 },
435
436 /* Handle keystrokes. */
437 _doKeyDown: function(event) {
438 var inst = $.datepicker._getInst(event.target);
439 var handled = true;
440 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
441 inst._keyEvent = true;
442 if ($.datepicker._datepickerShowing)
443 switch (event.keyCode) {
444 case 9: $.datepicker._hideDatepicker(null, '');
445 break; // hide on tab out
446 case 13: var sel = $('td.' + $.datepicker._dayOverClass +
447 ', td.' + $.datepicker._currentClass, inst.dpDiv);
448 if (sel[0])
449 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
450 else
451 $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
452 return false; // don't submit the form
453 break; // select the value on enter
454 case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
455 break; // hide on escape
456 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
457 -$.datepicker._get(inst, 'stepBigMonths') :
458 -$.datepicker._get(inst, 'stepMonths')), 'M');
459 break; // previous month/year on page up/+ ctrl
460 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
461 +$.datepicker._get(inst, 'stepBigMonths') :
462 +$.datepicker._get(inst, 'stepMonths')), 'M');
463 break; // next month/year on page down/+ ctrl
464 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
465 handled = event.ctrlKey || event.metaKey;
466 break; // clear on ctrl or command +end
467 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
468 handled = event.ctrlKey || event.metaKey;
469 break; // current on ctrl or command +home
470 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
471 handled = event.ctrlKey || event.metaKey;
472 // -1 day on ctrl or command +left
473 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
474 -$.datepicker._get(inst, 'stepBigMonths') :
475 -$.datepicker._get(inst, 'stepMonths')), 'M');
476 // next month/year on alt +left on Mac
477 break;
478 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
479 handled = event.ctrlKey || event.metaKey;
480 break; // -1 week on ctrl or command +up
481 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
482 handled = event.ctrlKey || event.metaKey;
483 // +1 day on ctrl or command +right
484 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
485 +$.datepicker._get(inst, 'stepBigMonths') :
486 +$.datepicker._get(inst, 'stepMonths')), 'M');
487 // next month/year on alt +right
488 break;
489 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
490 handled = event.ctrlKey || event.metaKey;
491 break; // +1 week on ctrl or command +down
492 default: handled = false;
493 }
494 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
495 $.datepicker._showDatepicker(this);
496 else {
497 handled = false;
498 }
499 if (handled) {
500 event.preventDefault();
501 event.stopPropagation();
502 }
503 },
504
505 /* Filter entered characters - based on date format. */
506 _doKeyPress: function(event) {
507 var inst = $.datepicker._getInst(event.target);
508 if ($.datepicker._get(inst, 'constrainInput')) {
509 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
510 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
511 return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
512 }
513 },
514
515 /* Pop-up the date picker for a given input field.
516 @param input element - the input field attached to the date picker or
517 event - if triggered by focus */
518 _showDatepicker: function(input) {
519 input = input.target || input;
520 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
521 input = $('input', input.parentNode)[0];
522 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
523 return;
524 var inst = $.datepicker._getInst(input);
525 var beforeShow = $.datepicker._get(inst, 'beforeShow');
526 extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
527 $.datepicker._hideDatepicker(null, '');
528 $.datepicker._lastInput = input;
529 $.datepicker._setDateFromField(inst);
530 if ($.datepicker._inDialog) // hide cursor
531 input.value = '';
532 if (!$.datepicker._pos) { // position below input
533 $.datepicker._pos = $.datepicker._findPos(input);
534 $.datepicker._pos[1] += input.offsetHeight; // add the height
535 }
536 var isFixed = false;
537 $(input).parents().each(function() {
538 isFixed |= $(this).css('position') == 'fixed';
539 return !isFixed;
540 });
541 if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
542 $.datepicker._pos[0] -= document.documentElement.scrollLeft;
543 $.datepicker._pos[1] -= document.documentElement.scrollTop;
544 }
545 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
546 $.datepicker._pos = null;
547 inst.rangeStart = null;
548 // determine sizing offscreen
549 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
550 $.datepicker._updateDatepicker(inst);
551 // fix width for dynamic number of date pickers
552 // and adjust position before showing
553 offset = $.datepicker._checkOffset(inst, offset, isFixed);
554 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
555 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
556 left: offset.left + 'px', top: offset.top + 'px'});
557 if (!inst.inline) {
558 var showAnim = $.datepicker._get(inst, 'showAnim') || 'show';
559 var duration = $.datepicker._get(inst, 'duration');
560 var postProcess = function() {
561 $.datepicker._datepickerShowing = true;
562 if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems
563 $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
564 height: inst.dpDiv.height() + 4});
565 };
566 if ($.effects && $.effects[showAnim])
567 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
568 else
569 inst.dpDiv[showAnim](duration, postProcess);
570 if (duration == '')
571 postProcess();
572 if (inst.input[0].type != 'hidden')
573 inst.input[0].focus();
574 $.datepicker._curInst = inst;
575 }
576 },
577
578 /* Generate the date picker content. */
579 _updateDatepicker: function(inst) {
580 var dims = {width: inst.dpDiv.width() + 4,
581 height: inst.dpDiv.height() + 4};
582 var self = this;
583 inst.dpDiv.empty().append(this._generateHTML(inst))
584 .find('iframe.ui-datepicker-cover').
585 css({width: dims.width, height: dims.height})
586 .end()
587 .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')
588 .bind('mouseout', function(){
589 $(this).removeClass('ui-state-hover');
590 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
591 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
592 })
593 .bind('mouseover', function(){
594 if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {
595 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
596 $(this).addClass('ui-state-hover');
597 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
598 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
599 }
600 })
601 .end()
602 .find('.' + this._dayOverClass + ' a')
603 .trigger('mouseover')
604 .end();
605 var numMonths = this._getNumberOfMonths(inst);
606 var cols = numMonths[1];
607 var width = 17;
608 if (cols > 1) {
609 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
610 } else {
611 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
612 }
613 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
614 'Class']('ui-datepicker-multi');
615 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
616 'Class']('ui-datepicker-rtl');
617 if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst)
618 $(inst.input[0]).focus();
619 },
620
621 /* Check positioning to remain on screen. */
622 _checkOffset: function(inst, offset, isFixed) {
623 var dpWidth = inst.dpDiv.outerWidth();
624 var dpHeight = inst.dpDiv.outerHeight();
625 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
626 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
627 var viewWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft();
628 var viewHeight = (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) + $(document).scrollTop();
629
630 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
631 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
632 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
633
634 // now check if datepicker is showing outside window viewport - move to a better place if so.
635 offset.left -= (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0;
636 offset.top -= (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(offset.top + dpHeight + inputHeight*2 - viewHeight) : 0;
637
638 return offset;
639 },
640
641 /* Find an object's position on the screen. */
642 _findPos: function(obj) {
643 while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
644 obj = obj.nextSibling;
645 }
646 var position = $(obj).offset();
647 return [position.left, position.top];
648 },
649
650 /* Hide the date picker from view.
651 @param input element - the input field attached to the date picker
652 @param duration string - the duration over which to close the date picker */
653 _hideDatepicker: function(input, duration) {
654 var inst = this._curInst;
655 if (!inst || (input && inst != $.data(input, PROP_NAME)))
656 return;
657 if (inst.stayOpen)
658 this._selectDate('#' + inst.id, this._formatDate(inst,
659 inst.currentDay, inst.currentMonth, inst.currentYear));
660 inst.stayOpen = false;
661 if (this._datepickerShowing) {
662 duration = (duration != null ? duration : this._get(inst, 'duration'));
663 var showAnim = this._get(inst, 'showAnim');
664 var postProcess = function() {
665 $.datepicker._tidyDialog(inst);
666 };
667 if (duration != '' && $.effects && $.effects[showAnim])
668 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
669 duration, postProcess);
670 else
671 inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
672 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
673 if (duration == '')
674 this._tidyDialog(inst);
675 var onClose = this._get(inst, 'onClose');
676 if (onClose)
677 onClose.apply((inst.input ? inst.input[0] : null),
678 [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback
679 this._datepickerShowing = false;
680 this._lastInput = null;
681 if (this._inDialog) {
682 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
683 if ($.blockUI) {
684 $.unblockUI();
685 $('body').append(this.dpDiv);
686 }
687 }
688 this._inDialog = false;
689 }
690 this._curInst = null;
691 },
692
693 /* Tidy up after a dialog display. */
694 _tidyDialog: function(inst) {
695 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
696 },
697
698 /* Close date picker if clicked elsewhere. */
699 _checkExternalClick: function(event) {
700 if (!$.datepicker._curInst)
701 return;
702 var $target = $(event.target);
703 if (($target.parents('#' + $.datepicker._mainDivId).length == 0) &&
704 !$target.hasClass($.datepicker.markerClassName) &&
705 !$target.hasClass($.datepicker._triggerClass) &&
706 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
707 $.datepicker._hideDatepicker(null, '');
708 },
709
710 /* Adjust one of the date sub-fields. */
711 _adjustDate: function(id, offset, period) {
712 var target = $(id);
713 var inst = this._getInst(target[0]);
714 if (this._isDisabledDatepicker(target[0])) {
715 return;
716 }
717 this._adjustInstDate(inst, offset +
718 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
719 period);
720 this._updateDatepicker(inst);
721 },
722
723 /* Action for current link. */
724 _gotoToday: function(id) {
725 var target = $(id);
726 var inst = this._getInst(target[0]);
727 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
728 inst.selectedDay = inst.currentDay;
729 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
730 inst.drawYear = inst.selectedYear = inst.currentYear;
731 }
732 else {
733 var date = new Date();
734 inst.selectedDay = date.getDate();
735 inst.drawMonth = inst.selectedMonth = date.getMonth();
736 inst.drawYear = inst.selectedYear = date.getFullYear();
737 }
738 this._notifyChange(inst);
739 this._adjustDate(target);
740 },
741
742 /* Action for selecting a new month/year. */
743 _selectMonthYear: function(id, select, period) {
744 var target = $(id);
745 var inst = this._getInst(target[0]);
746 inst._selectingMonthYear = false;
747 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
748 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
749 parseInt(select.options[select.selectedIndex].value,10);
750 this._notifyChange(inst);
751 this._adjustDate(target);
752 },
753
754 /* Restore input focus after not changing month/year. */
755 _clickMonthYear: function(id) {
756 var target = $(id);
757 var inst = this._getInst(target[0]);
758 if (inst.input && inst._selectingMonthYear && !$.browser.msie)
759 inst.input[0].focus();
760 inst._selectingMonthYear = !inst._selectingMonthYear;
761 },
762
763 /* Action for selecting a day. */
764 _selectDay: function(id, month, year, td) {
765 var target = $(id);
766 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
767 return;
768 }
769 var inst = this._getInst(target[0]);
770 inst.selectedDay = inst.currentDay = $('a', td).html();
771 inst.selectedMonth = inst.currentMonth = month;
772 inst.selectedYear = inst.currentYear = year;
773 if (inst.stayOpen) {
774 inst.endDay = inst.endMonth = inst.endYear = null;
775 }
776 this._selectDate(id, this._formatDate(inst,
777 inst.currentDay, inst.currentMonth, inst.currentYear));
778 if (inst.stayOpen) {
779 inst.rangeStart = this._daylightSavingAdjust(
780 new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
781 this._updateDatepicker(inst);
782 }
783 },
784
785 /* Erase the input field and hide the date picker. */
786 _clearDate: function(id) {
787 var target = $(id);
788 var inst = this._getInst(target[0]);
789 inst.stayOpen = false;
790 inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
791 this._selectDate(target, '');
792 },
793
794 /* Update the input field with the selected date. */
795 _selectDate: function(id, dateStr) {
796 var target = $(id);
797 var inst = this._getInst(target[0]);
798 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
799 if (inst.input)
800 inst.input.val(dateStr);
801 this._updateAlternate(inst);
802 var onSelect = this._get(inst, 'onSelect');
803 if (onSelect)
804 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
805 else if (inst.input)
806 inst.input.trigger('change'); // fire the change event
807 if (inst.inline)
808 this._updateDatepicker(inst);
809 else if (!inst.stayOpen) {
810 this._hideDatepicker(null, this._get(inst, 'duration'));
811 this._lastInput = inst.input[0];
812 if (typeof(inst.input[0]) != 'object')
813 inst.input[0].focus(); // restore focus
814 this._lastInput = null;
815 }
816 },
817
818 /* Update any alternate field to synchronise with the main field. */
819 _updateAlternate: function(inst) {
820 var altField = this._get(inst, 'altField');
821 if (altField) { // update alternate field too
822 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
823 var date = this._getDate(inst);
824 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
825 $(altField).each(function() { $(this).val(dateStr); });
826 }
827 },
828
829 /* Set as beforeShowDay function to prevent selection of weekends.
830 @param date Date - the date to customise
831 @return [boolean, string] - is this date selectable?, what is its CSS class? */
832 noWeekends: function(date) {
833 var day = date.getDay();
834 return [(day > 0 && day < 6), ''];
835 },
836
837 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
838 @param date Date - the date to get the week for
839 @return number - the number of the week within the year that contains this date */
840 iso8601Week: function(date) {
841 var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
842 var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
843 var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
844 firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
845 if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
846 checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
847 return $.datepicker.iso8601Week(checkDate);
848 } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
849 firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
850 if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
851 return 1;
852 }
853 }
854 return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
855 },
856
857 /* Parse a string value into a date object.
858 See formatDate below for the possible formats.
859
860 @param format string - the expected format of the date
861 @param value string - the date in the above format
862 @param settings Object - attributes include:
863 shortYearCutoff number - the cutoff year for determining the century (optional)
864 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
865 dayNames string[7] - names of the days from Sunday (optional)
866 monthNamesShort string[12] - abbreviated names of the months (optional)
867 monthNames string[12] - names of the months (optional)
868 @return Date - the extracted date value or null if value is blank */
869 parseDate: function (format, value, settings) {
870 if (format == null || value == null)
871 throw 'Invalid arguments';
872 value = (typeof value == 'object' ? value.toString() : value + '');
873 if (value == '')
874 return null;
875 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
876 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
877 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
878 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
879 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
880 var year = -1;
881 var month = -1;
882 var day = -1;
883 var doy = -1;
884 var literal = false;
885 // Check whether a format character is doubled
886 var lookAhead = function(match) {
887 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
888 if (matches)
889 iFormat++;
890 return matches;
891 };
892 // Extract a number from the string value
893 var getNumber = function(match) {
894 lookAhead(match);
895 var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2)));
896 var size = origSize;
897 var num = 0;
898 while (size > 0 && iValue < value.length &&
899 value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
900 num = num * 10 + parseInt(value.charAt(iValue++),10);
901 size--;
902 }
903 if (size == origSize)
904 throw 'Missing number at position ' + iValue;
905 return num;
906 };
907 // Extract a name from the string value and convert to an index
908 var getName = function(match, shortNames, longNames) {
909 var names = (lookAhead(match) ? longNames : shortNames);
910 var size = 0;
911 for (var j = 0; j < names.length; j++)
912 size = Math.max(size, names[j].length);
913 var name = '';
914 var iInit = iValue;
915 while (size > 0 && iValue < value.length) {
916 name += value.charAt(iValue++);
917 for (var i = 0; i < names.length; i++)
918 if (name == names[i])
919 return i + 1;
920 size--;
921 }
922 throw 'Unknown name at position ' + iInit;
923 };
924 // Confirm that a literal character matches the string value
925 var checkLiteral = function() {
926 if (value.charAt(iValue) != format.charAt(iFormat))
927 throw 'Unexpected literal at position ' + iValue;
928 iValue++;
929 };
930 var iValue = 0;
931 for (var iFormat = 0; iFormat < format.length; iFormat++) {
932 if (literal)
933 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
934 literal = false;
935 else
936 checkLiteral();
937 else
938 switch (format.charAt(iFormat)) {
939 case 'd':
940 day = getNumber('d');
941 break;
942 case 'D':
943 getName('D', dayNamesShort, dayNames);
944 break;
945 case 'o':
946 doy = getNumber('o');
947 break;
948 case 'm':
949 month = getNumber('m');
950 break;
951 case 'M':
952 month = getName('M', monthNamesShort, monthNames);
953 break;
954 case 'y':
955 year = getNumber('y');
956 break;
957 case '@':
958 var date = new Date(getNumber('@'));
959 year = date.getFullYear();
960 month = date.getMonth() + 1;
961 day = date.getDate();
962 break;
963 case "'":
964 if (lookAhead("'"))
965 checkLiteral();
966 else
967 literal = true;
968 break;
969 default:
970 checkLiteral();
971 }
972 }
973 if (year == -1)
974 year = new Date().getFullYear();
975 else if (year < 100)
976 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
977 (year <= shortYearCutoff ? 0 : -100);
978 if (doy > -1) {
979 month = 1;
980 day = doy;
981 do {
982 var dim = this._getDaysInMonth(year, month - 1);
983 if (day <= dim)
984 break;
985 month++;
986 day -= dim;
987 } while (true);
988 }
989 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
990 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
991 throw 'Invalid date'; // E.g. 31/02/*
992 return date;
993 },
994
995 /* Standard date formats. */
996 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
997 COOKIE: 'D, dd M yy',
998 ISO_8601: 'yy-mm-dd',
999 RFC_822: 'D, d M y',
1000 RFC_850: 'DD, dd-M-y',
1001 RFC_1036: 'D, d M y',
1002 RFC_1123: 'D, d M yy',
1003 RFC_2822: 'D, d M yy',
1004 RSS: 'D, d M y', // RFC 822
1005 TIMESTAMP: '@',
1006 W3C: 'yy-mm-dd', // ISO 8601
1007
1008 /* Format a date object into a string value.
1009 The format can be combinations of the following:
1010 d - day of month (no leading zero)
1011 dd - day of month (two digit)
1012 o - day of year (no leading zeros)
1013 oo - day of year (three digit)
1014 D - day name short
1015 DD - day name long
1016 m - month of year (no leading zero)
1017 mm - month of year (two digit)
1018 M - month name short
1019 MM - month name long
1020 y - year (two digit)
1021 yy - year (four digit)
1022 @ - Unix timestamp (ms since 01/01/1970)
1023 '...' - literal text
1024 '' - single quote
1025
1026 @param format string - the desired format of the date
1027 @param date Date - the date value to format
1028 @param settings Object - attributes include:
1029 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
1030 dayNames string[7] - names of the days from Sunday (optional)
1031 monthNamesShort string[12] - abbreviated names of the months (optional)
1032 monthNames string[12] - names of the months (optional)
1033 @return string - the date in the above format */
1034 formatDate: function (format, date, settings) {
1035 if (!date)
1036 return '';
1037 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
1038 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
1039 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
1040 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
1041 // Check whether a format character is doubled
1042 var lookAhead = function(match) {
1043 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
1044 if (matches)
1045 iFormat++;
1046 return matches;
1047 };
1048 // Format a number, with leading zero if necessary
1049 var formatNumber = function(match, value, len) {
1050 var num = '' + value;
1051 if (lookAhead(match))
1052 while (num.length < len)
1053 num = '0' + num;
1054 return num;
1055 };
1056 // Format a name, short or long as requested
1057 var formatName = function(match, value, shortNames, longNames) {
1058 return (lookAhead(match) ? longNames[value] : shortNames[value]);
1059 };
1060 var output = '';
1061 var literal = false;
1062 if (date)
1063 for (var iFormat = 0; iFormat < format.length; iFormat++) {
1064 if (literal)
1065 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
1066 literal = false;
1067 else
1068 output += format.charAt(iFormat);
1069 else
1070 switch (format.charAt(iFormat)) {
1071 case 'd':
1072 output += formatNumber('d', date.getDate(), 2);
1073 break;
1074 case 'D':
1075 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
1076 break;
1077 case 'o':
1078 var doy = date.getDate();
1079 for (var m = date.getMonth() - 1; m >= 0; m--)
1080 doy += this._getDaysInMonth(date.getFullYear(), m);
1081 output += formatNumber('o', doy, 3);
1082 break;
1083 case 'm':
1084 output += formatNumber('m', date.getMonth() + 1, 2);
1085 break;
1086 case 'M':
1087 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
1088 break;
1089 case 'y':
1090 output += (lookAhead('y') ? date.getFullYear() :
1091 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
1092 break;
1093 case '@':
1094 output += date.getTime();
1095 break;
1096 case "'":
1097 if (lookAhead("'"))
1098 output += "'";
1099 else
1100 literal = true;
1101 break;
1102 default:
1103 output += format.charAt(iFormat);
1104 }
1105 }
1106 return output;
1107 },
1108
1109 /* Extract all possible characters from the date format. */
1110 _possibleChars: function (format) {
1111 var chars = '';
1112 var literal = false;
1113 for (var iFormat = 0; iFormat < format.length; iFormat++)
1114 if (literal)
1115 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
1116 literal = false;
1117 else
1118 chars += format.charAt(iFormat);
1119 else
1120 switch (format.charAt(iFormat)) {
1121 case 'd': case 'm': case 'y': case '@':
1122 chars += '0123456789';
1123 break;
1124 case 'D': case 'M':
1125 return null; // Accept anything
1126 case "'":
1127 if (lookAhead("'"))
1128 chars += "'";
1129 else
1130 literal = true;
1131 break;
1132 default:
1133 chars += format.charAt(iFormat);
1134 }
1135 return chars;
1136 },
1137
1138 /* Get a setting value, defaulting if necessary. */
1139 _get: function(inst, name) {
1140 return inst.settings[name] !== undefined ?
1141 inst.settings[name] : this._defaults[name];
1142 },
1143
1144 /* Parse existing date and initialise date picker. */
1145 _setDateFromField: function(inst) {
1146 var dateFormat = this._get(inst, 'dateFormat');
1147 var dates = inst.input ? inst.input.val() : null;
1148 inst.endDay = inst.endMonth = inst.endYear = null;
1149 var date = defaultDate = this._getDefaultDate(inst);
1150 var settings = this._getFormatConfig(inst);
1151 try {
1152 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
1153 } catch (event) {
1154 this.log(event);
1155 date = defaultDate;
1156 }
1157 inst.selectedDay = date.getDate();
1158 inst.drawMonth = inst.selectedMonth = date.getMonth();
1159 inst.drawYear = inst.selectedYear = date.getFullYear();
1160 inst.currentDay = (dates ? date.getDate() : 0);
1161 inst.currentMonth = (dates ? date.getMonth() : 0);
1162 inst.currentYear = (dates ? date.getFullYear() : 0);
1163 this._adjustInstDate(inst);
1164 },
1165
1166 /* Retrieve the default date shown on opening. */
1167 _getDefaultDate: function(inst) {
1168 var date = this._determineDate(this._get(inst, 'defaultDate'), new Date());
1169 var minDate = this._getMinMaxDate(inst, 'min', true);
1170 var maxDate = this._getMinMaxDate(inst, 'max');
1171 date = (minDate && date < minDate ? minDate : date);
1172 date = (maxDate && date > maxDate ? maxDate : date);
1173 return date;
1174 },
1175
1176 /* A date may be specified as an exact value or a relative one. */
1177 _determineDate: function(date, defaultDate) {
1178 var offsetNumeric = function(offset) {
1179 var date = new Date();
1180 date.setDate(date.getDate() + offset);
1181 return date;
1182 };
1183 var offsetString = function(offset, getDaysInMonth) {
1184 var date = new Date();
1185 var year = date.getFullYear();
1186 var month = date.getMonth();
1187 var day = date.getDate();
1188 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
1189 var matches = pattern.exec(offset);
1190 while (matches) {
1191 switch (matches[2] || 'd') {
1192 case 'd' : case 'D' :
1193 day += parseInt(matches[1],10); break;
1194 case 'w' : case 'W' :
1195 day += parseInt(matches[1],10) * 7; break;
1196 case 'm' : case 'M' :
1197 month += parseInt(matches[1],10);
1198 day = Math.min(day, getDaysInMonth(year, month));
1199 break;
1200 case 'y': case 'Y' :
1201 year += parseInt(matches[1],10);
1202 day = Math.min(day, getDaysInMonth(year, month));
1203 break;
1204 }
1205 matches = pattern.exec(offset);
1206 }
1207 return new Date(year, month, day);
1208 };
1209 date = (date == null ? defaultDate :
1210 (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
1211 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
1212 date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
1213 if (date) {
1214 date.setHours(0);
1215 date.setMinutes(0);
1216 date.setSeconds(0);
1217 date.setMilliseconds(0);
1218 }
1219 return this._daylightSavingAdjust(date);
1220 },
1221
1222 /* Handle switch to/from daylight saving.
1223 Hours may be non-zero on daylight saving cut-over:
1224 > 12 when midnight changeover, but then cannot generate
1225 midnight datetime, so jump to 1AM, otherwise reset.
1226 @param date (Date) the date to check
1227 @return (Date) the corrected date */
1228 _daylightSavingAdjust: function(date) {
1229 if (!date) return null;
1230 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
1231 return date;
1232 },
1233
1234 /* Set the date(s) directly. */
1235 _setDate: function(inst, date, endDate) {
1236 var clear = !(date);
1237 var origMonth = inst.selectedMonth;
1238 var origYear = inst.selectedYear;
1239 date = this._determineDate(date, new Date());
1240 inst.selectedDay = inst.currentDay = date.getDate();
1241 inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
1242 inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
1243 if (origMonth != inst.selectedMonth || origYear != inst.selectedYear)
1244 this._notifyChange(inst);
1245 this._adjustInstDate(inst);
1246 if (inst.input) {
1247 inst.input.val(clear ? '' : this._formatDate(inst));
1248 }
1249 },
1250
1251 /* Retrieve the date(s) directly. */
1252 _getDate: function(inst) {
1253 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
1254 this._daylightSavingAdjust(new Date(
1255 inst.currentYear, inst.currentMonth, inst.currentDay)));
1256 return startDate;
1257 },
1258
1259 /* Generate the HTML for the current state of the date picker. */
1260 _generateHTML: function(inst) {
1261 var today = new Date();
1262 today = this._daylightSavingAdjust(
1263 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
1264 var isRTL = this._get(inst, 'isRTL');
1265 var showButtonPanel = this._get(inst, 'showButtonPanel');
1266 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
1267 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
1268 var numMonths = this._getNumberOfMonths(inst);
1269 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
1270 var stepMonths = this._get(inst, 'stepMonths');
1271 var stepBigMonths = this._get(inst, 'stepBigMonths');
1272 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
1273 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
1274 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
1275 var minDate = this._getMinMaxDate(inst, 'min', true);
1276 var maxDate = this._getMinMaxDate(inst, 'max');
1277 var drawMonth = inst.drawMonth - showCurrentAtPos;
1278 var drawYear = inst.drawYear;
1279 if (drawMonth < 0) {
1280 drawMonth += 12;
1281 drawYear--;
1282 }
1283 if (maxDate) {
1284 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
1285 maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate()));
1286 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
1287 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
1288 drawMonth--;
1289 if (drawMonth < 0) {
1290 drawMonth = 11;
1291 drawYear--;
1292 }
1293 }
1294 }
1295 inst.drawMonth = drawMonth;
1296 inst.drawYear = drawYear;
1297 var prevText = this._get(inst, 'prevText');
1298 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
1299 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
1300 this._getFormatConfig(inst)));
1301 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
1302 '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
1303 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
1304 (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>'));
1305 var nextText = this._get(inst, 'nextText');
1306 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
1307 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
1308 this._getFormatConfig(inst)));
1309 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
1310 '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
1311 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
1312 (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>'));
1313 var currentText = this._get(inst, 'currentText');
1314 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
1315 currentText = (!navigationAsDateFormat ? currentText :
1316 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
1317 var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
1318 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
1319 (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery.datepicker._gotoToday(\'#' + inst.id + '\');"' +
1320 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
1321 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
1322 firstDay = (isNaN(firstDay) ? 0 : firstDay);
1323 var dayNames = this._get(inst, 'dayNames');
1324 var dayNamesShort = this._get(inst, 'dayNamesShort');
1325 var dayNamesMin = this._get(inst, 'dayNamesMin');
1326 var monthNames = this._get(inst, 'monthNames');
1327 var monthNamesShort = this._get(inst, 'monthNamesShort');
1328 var beforeShowDay = this._get(inst, 'beforeShowDay');
1329 var showOtherMonths = this._get(inst, 'showOtherMonths');
1330 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
1331 var endDate = inst.endDay ? this._daylightSavingAdjust(
1332 new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate;
1333 var defaultDate = this._getDefaultDate(inst);
1334 var html = '';
1335 for (var row = 0; row < numMonths[0]; row++) {
1336 var group = '';
1337 for (var col = 0; col < numMonths[1]; col++) {
1338 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
1339 var cornerClass = ' ui-corner-all';
1340 var calender = '';
1341 if (isMultiMonth) {
1342 calender += '<div class="ui-datepicker-group ui-datepicker-group-';
1343 switch (col) {
1344 case 0: calender += 'first'; cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
1345 case numMonths[1]-1: calender += 'last'; cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
1346 default: calender += 'middle'; cornerClass = ''; break;
1347 }
1348 calender += '">';
1349 }
1350 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
1351 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
1352 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
1353 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
1354 selectedDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
1355 '</div><table class="ui-datepicker-calendar"><thead>' +
1356 '<tr>';
1357 var thead = '';
1358 for (var dow = 0; dow < 7; dow++) { // days of the week
1359 var day = (dow + firstDay) % 7;
1360 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
1361 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
1362 }
1363 calender += thead + '</tr></thead><tbody>';
1364 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
1365 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
1366 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
1367 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
1368 var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
1369 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
1370 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
1371 calender += '<tr>';
1372 var tbody = '';
1373 for (var dow = 0; dow < 7; dow++) { // create date picker days
1374 var daySettings = (beforeShowDay ?
1375 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
1376 var otherMonth = (printDate.getMonth() != drawMonth);
1377 var unselectable = otherMonth || !daySettings[0] ||
1378 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
1379 tbody += '<td class="' +
1380 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
1381 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
1382 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
1383 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
1384 // or defaultDate is current printedDate and defaultDate is selectedDate
1385 ' ' + this._dayOverClass : '') + // highlight selected day
1386 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
1387 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
1388 (printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ? // in current range
1389 ' ' + this._currentClass : '') + // highlight selected day
1390 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
1391 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
1392 (unselectable ? '' : ' onclick="DP_jQuery.datepicker._selectDay(\'#' +
1393 inst.id + '\',' + drawMonth + ',' + drawYear + ', this);return false;"') + '>' + // actions
1394 (otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
1395 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
1396 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
1397 (printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ? // in current range
1398 ' ui-state-active' : '') + // highlight selected day
1399 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
1400 printDate.setDate(printDate.getDate() + 1);
1401 printDate = this._daylightSavingAdjust(printDate);
1402 }
1403 calender += tbody + '</tr>';
1404 }
1405 drawMonth++;
1406 if (drawMonth > 11) {
1407 drawMonth = 0;
1408 drawYear++;
1409 }
1410 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
1411 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
1412 group += calender;
1413 }
1414 html += group;
1415 }
1416 html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
1417 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
1418 inst._keyEvent = false;
1419 return html;
1420 },
1421
1422 /* Generate the month and year header. */
1423 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
1424 selectedDate, secondary, monthNames, monthNamesShort) {
1425 minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
1426 var changeMonth = this._get(inst, 'changeMonth');
1427 var changeYear = this._get(inst, 'changeYear');
1428 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
1429 var html = '<div class="ui-datepicker-title">';
1430 var monthHtml = '';
1431 // month selection
1432 if (secondary || !changeMonth)
1433 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span> ';
1434 else {
1435 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
1436 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
1437 monthHtml += '<select class="ui-datepicker-month" ' +
1438 'onchange="DP_jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
1439 'onclick="DP_jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
1440 '>';
1441 for (var month = 0; month < 12; month++) {
1442 if ((!inMinYear || month >= minDate.getMonth()) &&
1443 (!inMaxYear || month <= maxDate.getMonth()))
1444 monthHtml += '<option value="' + month + '"' +
1445 (month == drawMonth ? ' selected="selected"' : '') +
1446 '>' + monthNamesShort[month] + '</option>';
1447 }
1448 monthHtml += '</select>';
1449 }
1450 if (!showMonthAfterYear)
1451 html += monthHtml + ((secondary || changeMonth || changeYear) && (!(changeMonth && changeYear)) ? '&#xa0;' : '');
1452 // year selection
1453 if (secondary || !changeYear)
1454 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
1455 else {
1456 // determine range of years to display
1457 var years = this._get(inst, 'yearRange').split(':');
1458 var year = 0;
1459 var endYear = 0;
1460 if (years.length != 2) {
1461 year = drawYear - 10;
1462 endYear = drawYear + 10;
1463 } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
1464 year = drawYear + parseInt(years[0], 10);
1465 endYear = drawYear + parseInt(years[1], 10);
1466 } else {
1467 year = parseInt(years[0], 10);
1468 endYear = parseInt(years[1], 10);
1469 }
1470 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
1471 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
1472 html += '<select class="ui-datepicker-year" ' +
1473 'onchange="DP_jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
1474 'onclick="DP_jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
1475 '>';
1476 for (; year <= endYear; year++) {
1477 html += '<option value="' + year + '"' +
1478 (year == drawYear ? ' selected="selected"' : '') +
1479 '>' + year + '</option>';
1480 }
1481 html += '</select>';
1482 }
1483 if (showMonthAfterYear)
1484 html += (secondary || changeMonth || changeYear ? '&#xa0;' : '') + monthHtml;
1485 html += '</div>'; // Close datepicker_header
1486 return html;
1487 },
1488
1489 /* Adjust one of the date sub-fields. */
1490 _adjustInstDate: function(inst, offset, period) {
1491 var year = inst.drawYear + (period == 'Y' ? offset : 0);
1492 var month = inst.drawMonth + (period == 'M' ? offset : 0);
1493 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
1494 (period == 'D' ? offset : 0);
1495 var date = this._daylightSavingAdjust(new Date(year, month, day));
1496 // ensure it is within the bounds set
1497 var minDate = this._getMinMaxDate(inst, 'min', true);
1498 var maxDate = this._getMinMaxDate(inst, 'max');
1499 date = (minDate && date < minDate ? minDate : date);
1500 date = (maxDate && date > maxDate ? maxDate : date);
1501 inst.selectedDay = date.getDate();
1502 inst.drawMonth = inst.selectedMonth = date.getMonth();
1503 inst.drawYear = inst.selectedYear = date.getFullYear();
1504 if (period == 'M' || period == 'Y')
1505 this._notifyChange(inst);
1506 },
1507
1508 /* Notify change of month/year. */
1509 _notifyChange: function(inst) {
1510 var onChange = this._get(inst, 'onChangeMonthYear');
1511 if (onChange)
1512 onChange.apply((inst.input ? inst.input[0] : null),
1513 [inst.selectedYear, inst.selectedMonth + 1, inst]);
1514 },
1515
1516 /* Determine the number of months to show. */
1517 _getNumberOfMonths: function(inst) {
1518 var numMonths = this._get(inst, 'numberOfMonths');
1519 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
1520 },
1521
1522 /* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */
1523 _getMinMaxDate: function(inst, minMax, checkRange) {
1524 var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
1525 return (!checkRange || !inst.rangeStart ? date :
1526 (!date || inst.rangeStart > date ? inst.rangeStart : date));
1527 },
1528
1529 /* Find the number of days in a given month. */
1530 _getDaysInMonth: function(year, month) {
1531 return 32 - new Date(year, month, 32).getDate();
1532 },
1533
1534 /* Find the day of the week of the first of a month. */
1535 _getFirstDayOfMonth: function(year, month) {
1536 return new Date(year, month, 1).getDay();
1537 },
1538
1539 /* Determines if we should allow a "next/prev" month display change. */
1540 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
1541 var numMonths = this._getNumberOfMonths(inst);
1542 var date = this._daylightSavingAdjust(new Date(
1543 curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1));
1544 if (offset < 0)
1545 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
1546 return this._isInRange(inst, date);
1547 },
1548
1549 /* Is the given date in the accepted range? */
1550 _isInRange: function(inst, date) {
1551 // during range selection, use minimum of selected date and range start
1552 var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust(
1553 new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)));
1554 newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
1555 var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
1556 var maxDate = this._getMinMaxDate(inst, 'max');
1557 return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
1558 },
1559
1560 /* Provide the configuration settings for formatting/parsing. */
1561 _getFormatConfig: function(inst) {
1562 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
1563 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
1564 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
1565 return {shortYearCutoff: shortYearCutoff,
1566 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
1567 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
1568 },
1569
1570 /* Format the given date for display. */
1571 _formatDate: function(inst, day, month, year) {
1572 if (!day) {
1573 inst.currentDay = inst.selectedDay;
1574 inst.currentMonth = inst.selectedMonth;
1575 inst.currentYear = inst.selectedYear;
1576 }
1577 var date = (day ? (typeof day == 'object' ? day :
1578 this._daylightSavingAdjust(new Date(year, month, day))) :
1579 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
1580 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
1581 }
1582 });
1583
1584 /* jQuery extend now ignores nulls! */
1585 function extendRemove(target, props) {
1586 $.extend(target, props);
1587 for (var name in props)
1588 if (props[name] == null || props[name] == undefined)
1589 target[name] = props[name];
1590 return target;
1591 };
1592
1593 /* Determine whether an object is an array. */
1594 function isArray(a) {
1595 return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
1596 (a.constructor && a.constructor.toString().match(/\Array\(\)/))));
1597 };
1598
1599 /* Invoke the datepicker functionality.
1600 @param options string - a command, optionally followed by additional parameters or
1601 Object - settings for attaching new datepicker functionality
1602 @return jQuery object */
1603 $.fn.datepicker = function(options){
1604
1605 /* Initialise the date picker. */
1606 if (!$.datepicker.initialized) {
1607 $(document).mousedown($.datepicker._checkExternalClick).
1608 find('body').append($.datepicker.dpDiv);
1609 $.datepicker.initialized = true;
1610 }
1611
1612 var otherArgs = Array.prototype.slice.call(arguments, 1);
1613 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate'))
1614 return $.datepicker['_' + options + 'Datepicker'].
1615 apply($.datepicker, [this[0]].concat(otherArgs));
1616 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
1617 return $.datepicker['_' + options + 'Datepicker'].
1618 apply($.datepicker, [this[0]].concat(otherArgs));
1619 return this.each(function() {
1620 typeof options == 'string' ?
1621 $.datepicker['_' + options + 'Datepicker'].
1622 apply($.datepicker, [this].concat(otherArgs)) :
1623 $.datepicker._attachDatepicker(this, options);
1624 });
1625 };
1626
1627 $.datepicker = new Datepicker(); // singleton instance
1628 $.datepicker.initialized = false;
1629 $.datepicker.uuid = new Date().getTime();
1630 $.datepicker.version = "1.7.3";
1631
1632 // Workaround for #4055
1633 // Add another global to avoid noConflict issues with inline event handlers
1634 window.DP_jQuery = $;
1635
1636 })(jQuery);
1637