PluginProbe
Booking Calendar / 11.0
Booking Calendar v11.0
11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 All 203 releases
booking / js / datepick / jquery.datepick.wpbc.9.0.js

jquery.datepick.wpbc.9.0.js in Booking Calendar 11.0, at js/datepick/jquery.datepick.wpbc.9.0.js

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