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