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