PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
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 11.9, at js/datepick/jquery.datepick.wpbc.9.0.js

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