PluginProbe
Booking Calendar / 10.1.3
Booking Calendar v10.1.3
11.9 11.8.4 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 All 205 releases
booking / js / datepick / jquery.datepick.wpbc.9.0.js

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

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