1/*! jQuery UI - v1.12.1 - 2016-10-07 2* http://jqueryui.com 3* Includes: widget.js, keycode.js, widgets/datepick
vendor: 8,820 bytes, lines 3-330
3er.js 4* Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 6(function( factory ) { 7 if ( typeof define === "function" && define.amd ) { 8 9 // AMD. Register as an anonymous module. 10 define([ "jquery" ], factory ); 11 } else { 12 13 // Browser globals 14 factory( jQuery ); 15 } 16}(function( $ ) { 17 18$.ui = $.ui || {}; 19 20var version = $.ui.version = "1.12.1"; 21 22 23/*! 24 * jQuery UI Widget 1.12.1 25 * http://jqueryui.com 26 * 27 * Copyright jQuery Foundation and other contributors 28 * Released under the MIT license. 29 * http://jquery.org/license 30 */ 31 32//>>label: Widget 33//>>group: Core 34//>>description: Provides a factory for creating stateful widgets with a common API. 35//>>docs: http://api.jqueryui.com/jQuery.widget/ 36//>>demos: http://jqueryui.com/widget/ 37 38 39 40var widgetUuid = 0; 41var widgetSlice = Array.prototype.slice; 42 43$.cleanData = ( function( orig ) { 44 return function( elems ) { 45 var events, elem, i; 46 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { 47 try { 48 49 // Only trigger remove when necessary to save time 50 events = $._data( elem, "events" ); 51 if ( events && events.remove ) { 52 $( elem ).triggerHandler( "remove" ); 53 } 54 55 // Http://bugs.jquery.com/ticket/8235 56 } catch ( e ) {} 57 } 58 orig( elems ); 59 }; 60} )( $.cleanData ); 61 62$.widget = function( name, base, prototype ) { 63 var existingConstructor, constructor, basePrototype; 64 65 // ProxiedPrototype allows the provided prototype to remain unmodified 66 // so that it can be used as a mixin for multiple widgets (#8876) 67 var proxiedPrototype = {}; 68 69 var namespace = name.split( "." )[ 0 ]; 70 name = name.split( "." )[ 1 ]; 71 var fullName = namespace + "-" + name; 72 73 if ( !prototype ) { 74 prototype = base; 75 base = $.Widget; 76 } 77 78 if ( $.isArray( prototype ) ) { 79 prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); 80 } 81 82 // Create selector for plugin 83 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 84 return !!$.data( elem, fullName ); 85 }; 86 87 $[ namespace ] = $[ namespace ] || {}; 88 existingConstructor = $[ namespace ][ name ]; 89 constructor = $[ namespace ][ name ] = function( options, element ) { 90 91 // Allow instantiation without "new" keyword 92 if ( !this._createWidget ) { 93 return new constructor( options, element ); 94 } 95 96 // Allow instantiation without initializing for simple inheritance 97 // must use "new" keyword (the code above always passes args) 98 if ( arguments.length ) { 99 this._createWidget( options, element ); 100 } 101 }; 102 103 // Extend with the existing constructor to carry over any static properties 104 $.extend( constructor, existingConstructor, { 105 version: prototype.version, 106 107 // Copy the object used to create the prototype in case we need to 108 // redefine the widget later 109 _proto: $.extend( {}, prototype ), 110 111 // Track widgets that inherit from this widget in case this widget is 112 // redefined after a widget inherits from it 113 _childConstructors: [] 114 } ); 115 116 basePrototype = new base(); 117 118 // We need to make the options hash a property directly on the new instance 119 // otherwise we'll modify the options hash on the prototype that we're 120 // inheriting from 121 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 122 $.each( prototype, function( prop, value ) { 123 if ( !$.isFunction( value ) ) { 124 proxiedPrototype[ prop ] = value; 125 return; 126 } 127 proxiedPrototype[ prop ] = ( function() { 128 function _super() { 129 return base.prototype[ prop ].apply( this, arguments ); 130 } 131 132 function _superApply( args ) { 133 return base.prototype[ prop ].apply( this, args ); 134 } 135 136 return function() { 137 var __super = this._super; 138 var __superApply = this._superApply; 139 var returnValue; 140 141 this._super = _super; 142 this._superApply = _superApply; 143 144 returnValue = value.apply( this, arguments ); 145 146 this._super = __super; 147 this._superApply = __superApply; 148 149 return returnValue; 150 }; 151 } )(); 152 } ); 153 constructor.prototype = $.widget.extend( basePrototype, { 154 155 // TODO: remove support for widgetEventPrefix 156 // always use the name + a colon as the prefix, e.g., draggable:start 157 // don't prefix for widgets that aren't DOM-based 158 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name 159 }, proxiedPrototype, { 160 constructor: constructor, 161 namespace: namespace, 162 widgetName: name, 163 widgetFullName: fullName 164 } ); 165 166 // If this widget is being redefined then we need to find all widgets that 167 // are inheriting from it and redefine all of them so that they inherit from 168 // the new version of this widget. We're essentially trying to replace one 169 // level in the prototype chain. 170 if ( existingConstructor ) { 171 $.each( existingConstructor._childConstructors, function( i, child ) { 172 var childPrototype = child.prototype; 173 174 // Redefine the child widget using the same prototype that was 175 // originally used, but inherit from the new version of the base 176 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, 177 child._proto ); 178 } ); 179 180 // Remove the list of existing child constructors from the old constructor 181 // so the old child constructors can be garbage collected 182 delete existingConstructor._childConstructors; 183 } else { 184 base._childConstructors.push( constructor ); 185 } 186 187 $.widget.bridge( name, constructor ); 188 189 return constructor; 190}; 191 192$.widget.extend = function( target ) { 193 var input = widgetSlice.call( arguments, 1 ); 194 var inputIndex = 0; 195 var inputLength = input.length; 196 var key; 197 var value; 198 199 for ( ; inputIndex < inputLength; inputIndex++ ) { 200 for ( key in input[ inputIndex ] ) { 201 value = input[ inputIndex ][ key ]; 202 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 203 204 // Clone objects 205 if ( $.isPlainObject( value ) ) { 206 target[ key ] = $.isPlainObject( target[ key ] ) ? 207 $.widget.extend( {}, target[ key ], value ) : 208 209 // Don't extend strings, arrays, etc. with objects 210 $.widget.extend( {}, value ); 211 212 // Copy everything else by reference 213 } else { 214 target[ key ] = value; 215 } 216 } 217 } 218 } 219 return target; 220}; 221 222$.widget.bridge = function( name, object ) { 223 var fullName = object.prototype.widgetFullName || name; 224 $.fn[ name ] = function( options ) { 225 var isMethodCall = typeof options === "string"; 226 var args = widgetSlice.call( arguments, 1 ); 227 var returnValue = this; 228 229 if ( isMethodCall ) { 230 231 // If this is an empty collection, we need to have the instance method 232 // return undefined instead of the jQuery instance 233 if ( !this.length && options === "instance" ) { 234 returnValue = undefined; 235 } else { 236 this.each( function() { 237 var methodValue; 238 var instance = $.data( this, fullName ); 239 240 if ( options === "instance" ) { 241 returnValue = instance; 242 return false; 243 } 244 245 if ( !instance ) { 246 return $.error( "cannot call methods on " + name + 247 " prior to initialization; " + 248 "attempted to call method '" + options + "'" ); 249 } 250 251 if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { 252 return $.error( "no such method '" + options + "' for " + name + 253 " widget instance" ); 254 } 255 256 methodValue = instance[ options ].apply( instance, args ); 257 258 if ( methodValue !== instance && methodValue !== undefined ) { 259 returnValue = methodValue && methodValue.jquery ? 260 returnValue.pushStack( methodValue.get() ) : 261 methodValue; 262 return false; 263 } 264 } ); 265 } 266 } else { 267 268 // Allow multiple hashes to be passed on init 269 if ( args.length ) { 270 options = $.widget.extend.apply( null, [ options ].concat( args ) ); 271 } 272 273 this.each( function() { 274 var instance = $.data( this, fullName ); 275 if ( instance ) { 276 instance.option( options || {} ); 277 if ( instance._init ) { 278 instance._init(); 279 } 280 } else { 281 $.data( this, fullName, new object( options, this ) ); 282 } 283 } ); 284 } 285 286 return returnValue; 287 }; 288}; 289 290$.Widget = function( /* options, element */ ) {}; 291$.Widget._childConstructors = []; 292 293$.Widget.prototype = { 294 widgetName: "widget", 295 widgetEventPrefix: "", 296 defaultElement: "<div>", 297 298 options: { 299 classes: {}, 300 disabled: false, 301 302 // Callbacks 303 create: null 304 }, 305 306 _createWidget: function( options, element ) { 307 element = $( element || this.defaultElement || this )[ 0 ]; 308 this.element = $( element ); 309 this.uuid = widgetUuid++; 310 this.eventNamespace = "." + this.widgetName + this.uuid; 311 312 this.bindings = $(); 313 this.hoverable = $(); 314 this.focusable = $(); 315 this.classesElementLookup = {}; 316 317 if ( element !== this ) { 318 $.data( element, this.widgetFullName, this ); 319 this._on( true, this.element, { 320 remove: function( event ) { 321 if ( event.target === element ) { 322 this.destroy(); 323 } 324 } 325 } ); 326 this.document = $( element.style ? 327 328 // Element within the document 329 element.ownerDocument : 330
vendor: 11,069 bytes, lines 331-747
331 // Element is window or document 332 element.document || element ); 333 this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); 334 } 335 336 this.options = $.widget.extend( {}, 337 this.options, 338 this._getCreateOptions(), 339 options ); 340 341 this._create(); 342 343 if ( this.options.disabled ) { 344 this._setOptionDisabled( this.options.disabled ); 345 } 346 347 this._trigger( "create", null, this._getCreateEventData() ); 348 this._init(); 349 }, 350 351 _getCreateOptions: function() { 352 return {}; 353 }, 354 355 _getCreateEventData: $.noop, 356 357 _create: $.noop, 358 359 _init: $.noop, 360 361 destroy: function() { 362 var that = this; 363 364 this._destroy(); 365 $.each( this.classesElementLookup, function( key, value ) { 366 that._removeClass( value, key ); 367 } ); 368 369 // We can probably remove the unbind calls in 2.0 370 // all event bindings should go through this._on() 371 this.element 372 .off( this.eventNamespace ) 373 .removeData( this.widgetFullName ); 374 this.widget() 375 .off( this.eventNamespace ) 376 .removeAttr( "aria-disabled" ); 377 378 // Clean up events and states 379 this.bindings.off( this.eventNamespace ); 380 }, 381 382 _destroy: $.noop, 383 384 widget: function() { 385 return this.element; 386 }, 387 388 option: function( key, value ) { 389 var options = key; 390 var parts; 391 var curOption; 392 var i; 393 394 if ( arguments.length === 0 ) { 395 396 // Don't return a reference to the internal hash 397 return $.widget.extend( {}, this.options ); 398 } 399 400 if ( typeof key === "string" ) { 401 402 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 403 options = {}; 404 parts = key.split( "." ); 405 key = parts.shift(); 406 if ( parts.length ) { 407 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 408 for ( i = 0; i < parts.length - 1; i++ ) { 409 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 410 curOption = curOption[ parts[ i ] ]; 411 } 412 key = parts.pop(); 413 if ( arguments.length === 1 ) { 414 return curOption[ key ] === undefined ? null : curOption[ key ]; 415 } 416 curOption[ key ] = value; 417 } else { 418 if ( arguments.length === 1 ) { 419 return this.options[ key ] === undefined ? null : this.options[ key ]; 420 } 421 options[ key ] = value; 422 } 423 } 424 425 this._setOptions( options ); 426 427 return this; 428 }, 429 430 _setOptions: function( options ) { 431 var key; 432 433 for ( key in options ) { 434 this._setOption( key, options[ key ] ); 435 } 436 437 return this; 438 }, 439 440 _setOption: function( key, value ) { 441 if ( key === "classes" ) { 442 this._setOptionClasses( value ); 443 } 444 445 this.options[ key ] = value; 446 447 if ( key === "disabled" ) { 448 this._setOptionDisabled( value ); 449 } 450 451 return this; 452 }, 453 454 _setOptionClasses: function( value ) { 455 var classKey, elements, currentElements; 456 457 for ( classKey in value ) { 458 currentElements = this.classesElementLookup[ classKey ]; 459 if ( value[ classKey ] === this.options.classes[ classKey ] || 460 !currentElements || 461 !currentElements.length ) { 462 continue; 463 } 464 465 // We are doing this to create a new jQuery object because the _removeClass() call 466 // on the next line is going to destroy the reference to the current elements being 467 // tracked. We need to save a copy of this collection so that we can add the new classes 468 // below. 469 elements = $( currentElements.get() ); 470 this._removeClass( currentElements, classKey ); 471 472 // We don't use _addClass() here, because that uses this.options.classes 473 // for generating the string of classes. We want to use the value passed in from 474 // _setOption(), this is the new value of the classes option which was passed to 475 // _setOption(). We pass this value directly to _classes(). 476 elements.addClass( this._classes( { 477 element: elements, 478 keys: classKey, 479 classes: value, 480 add: true 481 } ) ); 482 } 483 }, 484 485 _setOptionDisabled: function( value ) { 486 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); 487 488 // If the widget is becoming disabled, then nothing is interactive 489 if ( value ) { 490 this._removeClass( this.hoverable, null, "ui-state-hover" ); 491 this._removeClass( this.focusable, null, "ui-state-focus" ); 492 } 493 }, 494 495 enable: function() { 496 return this._setOptions( { disabled: false } ); 497 }, 498 499 disable: function() { 500 return this._setOptions( { disabled: true } ); 501 }, 502 503 _classes: function( options ) { 504 var full = []; 505 var that = this; 506 507 options = $.extend( { 508 element: this.element, 509 classes: this.options.classes || {} 510 }, options ); 511 512 function processClassString( classes, checkOption ) { 513 var current, i; 514 for ( i = 0; i < classes.length; i++ ) { 515 current = that.classesElementLookup[ classes[ i ] ] || $(); 516 if ( options.add ) { 517 current = $( $.unique( current.get().concat( options.element.get() ) ) ); 518 } else { 519 current = $( current.not( options.element ).get() ); 520 } 521 that.classesElementLookup[ classes[ i ] ] = current; 522 full.push( classes[ i ] ); 523 if ( checkOption && options.classes[ classes[ i ] ] ) { 524 full.push( options.classes[ classes[ i ] ] ); 525 } 526 } 527 } 528 529 this._on( options.element, { 530 "remove": "_untrackClassesElement" 531 } ); 532 533 if ( options.keys ) { 534 processClassString( options.keys.match( /\S+/g ) || [], true ); 535 } 536 if ( options.extra ) { 537 processClassString( options.extra.match( /\S+/g ) || [] ); 538 } 539 540 return full.join( " " ); 541 }, 542 543 _untrackClassesElement: function( event ) { 544 var that = this; 545 $.each( that.classesElementLookup, function( key, value ) { 546 if ( $.inArray( event.target, value ) !== -1 ) { 547 that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); 548 } 549 } ); 550 }, 551 552 _removeClass: function( element, keys, extra ) { 553 return this._toggleClass( element, keys, extra, false ); 554 }, 555 556 _addClass: function( element, keys, extra ) { 557 return this._toggleClass( element, keys, extra, true ); 558 }, 559 560 _toggleClass: function( element, keys, extra, add ) { 561 add = ( typeof add === "boolean" ) ? add : extra; 562 var shift = ( typeof element === "string" || element === null ), 563 options = { 564 extra: shift ? keys : extra, 565 keys: shift ? element : keys, 566 element: shift ? this.element : element, 567 add: add 568 }; 569 options.element.toggleClass( this._classes( options ), add ); 570 return this; 571 }, 572 573 _on: function( suppressDisabledCheck, element, handlers ) { 574 var delegateElement; 575 var instance = this; 576 577 // No suppressDisabledCheck flag, shuffle arguments 578 if ( typeof suppressDisabledCheck !== "boolean" ) { 579 handlers = element; 580 element = suppressDisabledCheck; 581 suppressDisabledCheck = false; 582 } 583 584 // No element argument, shuffle and use this.element 585 if ( !handlers ) { 586 handlers = element; 587 element = this.element; 588 delegateElement = this.widget(); 589 } else { 590 element = delegateElement = $( element ); 591 this.bindings = this.bindings.add( element ); 592 } 593 594 $.each( handlers, function( event, handler ) { 595 function handlerProxy() { 596 597 // Allow widgets to customize the disabled handling 598 // - disabled as an array instead of boolean 599 // - disabled class as method for disabling individual parts 600 if ( !suppressDisabledCheck && 601 ( instance.options.disabled === true || 602 $( this ).hasClass( "ui-state-disabled" ) ) ) { 603 return; 604 } 605 return ( typeof handler === "string" ? instance[ handler ] : handler ) 606 .apply( instance, arguments ); 607 } 608 609 // Copy the guid so direct unbinding works 610 if ( typeof handler !== "string" ) { 611 handlerProxy.guid = handler.guid = 612 handler.guid || handlerProxy.guid || $.guid++; 613 } 614 615 var match = event.match( /^([\w:-]*)\s*(.*)$/ ); 616 var eventName = match[ 1 ] + instance.eventNamespace; 617 var selector = match[ 2 ]; 618 619 if ( selector ) { 620 delegateElement.on( eventName, selector, handlerProxy ); 621 } else { 622 element.on( eventName, handlerProxy ); 623 } 624 } ); 625 }, 626 627 _off: function( element, eventName ) { 628 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + 629 this.eventNamespace; 630 element.off( eventName ).off( eventName ); 631 632 // Clear the stack to avoid memory leaks (#10056) 633 this.bindings = $( this.bindings.not( element ).get() ); 634 this.focusable = $( this.focusable.not( element ).get() ); 635 this.hoverable = $( this.hoverable.not( element ).get() ); 636 }, 637 638 _delay: function( handler, delay ) { 639 function handlerProxy() { 640 return ( typeof handler === "string" ? instance[ handler ] : handler ) 641 .apply( instance, arguments ); 642 } 643 var instance = this; 644 return setTimeout( handlerProxy, delay || 0 ); 645 }, 646 647 _hoverable: function( element ) { 648 this.hoverable = this.hoverable.add( element ); 649 this._on( element, { 650 mouseenter: function( event ) { 651 this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); 652 }, 653 mouseleave: function( event ) { 654 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); 655 } 656 } ); 657 }, 658 659 _focusable: function( element ) { 660 this.focusable = this.focusable.add( element ); 661 this._on( element, { 662 focusin: function( event ) { 663 this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); 664 }, 665 focusout: function( event ) { 666 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); 667 } 668 } ); 669 }, 670 671 _trigger: function( type, event, data ) { 672 var prop, orig; 673 var callback = this.options[ type ]; 674 675 data = data || {}; 676 event = $.Event( event ); 677 event.type = ( type === this.widgetEventPrefix ? 678 type : 679 this.widgetEventPrefix + type ).toLowerCase(); 680 681 // The original event may come from any element 682 // so we need to reset the target on the new event 683 event.target = this.element[ 0 ]; 684 685 // Copy original event properties over to the new event 686 orig = event.originalEvent; 687 if ( orig ) { 688 for ( prop in orig ) { 689 if ( !( prop in event ) ) { 690 event[ prop ] = orig[ prop ]; 691 } 692 } 693 } 694 695 this.element.trigger( event, data ); 696 return !( $.isFunction( callback ) && 697 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || 698 event.isDefaultPrevented() ); 699 } 700}; 701 702$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 703 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 704 if ( typeof options === "string" ) { 705 options = { effect: options }; 706 } 707 708 var hasOptions; 709 var effectName = !options ? 710 method : 711 options === true || typeof options === "number" ? 712 defaultEffect : 713 options.effect || defaultEffect; 714 715 options = options || {}; 716 if ( typeof options === "number" ) { 717 options = { duration: options }; 718 } 719 720 hasOptions = !$.isEmptyObject( options ); 721 options.complete = callback; 722 723 if ( options.delay ) { 724 element.delay( options.delay ); 725 } 726 727 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 728 element[ method ]( options ); 729 } else if ( effectName !== method && element[ effectName ] ) { 730 element[ effectName ]( options.duration, options.easing, callback ); 731 } else { 732 element.queue( function( next ) { 733 $( this )[ method ](); 734 if ( callback ) { 735 callback.call( element[ 0 ] ); 736 } 737 next(); 738 } ); 739 } 740 }; 741} ); 742 743var widget = $.widget; 744 745 746/*! 747 * jQuery UI
747Keycode 1.12.1 748 * http://jqueryui.com 749 * 750 * Copyright jQuery Foundation and other contributors 751 * Released under the MIT license. 752 * http://jquery.org/license 753 */ 754 755//>>label: Keycode 756//>>group: Core 757//>>description: Provide keycodes as keynames 758//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ 759 760 761var keycode = $.ui.keyCode = { 762 BACKSPACE: 8, 763 COMMA: 188, 764 DELETE: 46, 765 DOWN: 40, 766 END: 35, 767 ENTER: 13, 768 ESCAPE: 27, 769 HOME: 36, 770 LEFT: 37, 771 PAGE_DOWN: 34, 772 PAGE_UP: 33, 773 PERIOD: 190, 774 RIGHT: 39, 775 SPACE: 32, 776 TAB: 9, 777 UP: 38 778}
vendor: 80,540 bytes, lines 778-2888
778; 779 780 781// jscs:disable maximumLineLength 782/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */ 783/*! 784 * jQuery UI Datepicker 1.12.1 785 * http://jqueryui.com 786 * 787 * Copyright jQuery Foundation and other contributors 788 * Released under the MIT license. 789 * http://jquery.org/license 790 */ 791 792//>>label: Datepicker 793//>>group: Widgets 794//>>description: Displays a calendar from an input or inline for selecting dates. 795//>>docs: http://api.jqueryui.com/datepicker/ 796//>>demos: http://jqueryui.com/datepicker/ 797//>>css.structure: ../../themes/base/core.css 798//>>css.structure: ../../themes/base/datepicker.css 799//>>css.theme: ../../themes/base/theme.css 800 801 802 803$.extend( $.ui, { datepicker: { version: "1.12.1" } } ); 804 805var datepicker_instActive; 806 807function datepicker_getZindex( elem ) { 808 var position, value; 809 while ( elem.length && elem[ 0 ] !== document ) { 810 811 // Ignore z-index if position is set to a value where z-index is ignored by the browser 812 // This makes behavior of this function consistent across browsers 813 // WebKit always returns auto if the element is positioned 814 position = elem.css( "position" ); 815 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 816 817 // IE returns 0 when zIndex is not specified 818 // other browsers return a string 819 // we ignore the case of nested elements with an explicit value of 0 820 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 821 value = parseInt( elem.css( "zIndex" ), 10 ); 822 if ( !isNaN( value ) && value !== 0 ) { 823 return value; 824 } 825 } 826 elem = elem.parent(); 827 } 828 829 return 0; 830} 831/* Date picker manager. 832 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 833 Settings for (groups of) date pickers are maintained in an instance object, 834 allowing multiple different settings on the same page. */ 835 836function Datepicker() { 837 this._curInst = null; // The current instance in use 838 this._keyEvent = false; // If the last event was a key event 839 this._disabledInputs = []; // List of date picker inputs that have been disabled 840 this._datepickerShowing = false; // True if the popup picker is showing , false if not 841 this._inDialog = false; // True if showing within a "dialog", false if not 842 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 843 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 844 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 845 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 846 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 847 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 848 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 849 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 850 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 851 this.regional = []; // Available regional settings, indexed by language code 852 this.regional[ "" ] = { // Default regional settings 853 closeText: "Done", // Display text for close link 854 prevText: "Prev", // Display text for previous month link 855 nextText: "Next", // Display text for next month link 856 currentText: "Today", // Display text for current month link 857 monthNames: [ "January","February","March","April","May","June", 858 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting 859 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting 860 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting 861 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting 862 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday 863 weekHeader: "Wk", // Column header for week of the year 864 dateFormat: "mm/dd/yy", // See format options on parseDate 865 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 866 isRTL: false, // True if right-to-left language, false if left-to-right 867 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 868 yearSuffix: "" // Additional text to append to the year in the month headers 869 }; 870 this._defaults = { // Global defaults for all the date picker instances 871 showOn: "focus", // "focus" for popup on focus, 872 // "button" for trigger button, or "both" for either 873 showAnim: "fadeIn", // Name of jQuery animation for popup 874 showOptions: {}, // Options for enhanced animations 875 defaultDate: null, // Used when field is blank: actual date, 876 // +/-number for offset from today, null for today 877 appendText: "", // Display text following the input box, e.g. showing the format 878 buttonText: "...", // Text for trigger button 879 buttonImage: "", // URL for trigger button image 880 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 881 hideIfNoPrevNext: false, // True to hide next/previous month links 882 // if not applicable, false to just disable them 883 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 884 gotoCurrent: false, // True if today link goes back to current selection instead 885 changeMonth: false, // True if month can be selected directly, false if only prev/next 886 changeYear: false, // True if year can be selected directly, false if only prev/next 887 yearRange: "c-10:c+10", // Range of years to display in drop-down, 888 // either relative to today's year (-nn:+nn), relative to currently displayed year 889 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 890 showOtherMonths: false, // True to show dates in other months, false to leave blank 891 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 892 showWeek: false, // True to show week of the year, false to not show it 893 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 894 // takes a Date and returns the number of the week for it 895 shortYearCutoff: "+10", // Short year values < this are in the current century, 896 // > this are in the previous century, 897 // string value starting with "+" for current year + value 898 minDate: null, // The earliest selectable date, or null for no limit 899 maxDate: null, // The latest selectable date, or null for no limit 900 duration: "fast", // Duration of display/closure 901 beforeShowDay: null, // Function that takes a date and returns an array with 902 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 903 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 904 beforeShow: null, // Function that takes an input field and 905 // returns a set of custom settings for the date picker 906 onSelect: null, // Define a callback function when a date is selected 907 onChangeMonthYear: null, // Define a callback function when the month or year is changed 908 onClose: null, // Define a callback function when the datepicker is closed 909 numberOfMonths: 1, // Number of months to show at a time 910 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 911 stepMonths: 1, // Number of months to step back/forward 912 stepBigMonths: 12, // Number of months to step back/forward for the big links 913 altField: "", // Selector for an alternate field to store selected dates into 914 altFormat: "", // The date format to use for the alternate field 915 constrainInput: true, // The input is constrained by the current date format 916 showButtonPanel: false, // True to show button panel, false to not show it 917 autoSize: false, // True to size the input for the date format, false to leave as is 918 disabled: false // The initial disabled state 919 }; 920 $.extend( this._defaults, this.regional[ "" ] ); 921 this.regional.en = $.extend( true, {}, this.regional[ "" ] ); 922 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 923 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 924} 925 926$.extend( Datepicker.prototype, { 927 /* Class name added to elements to indicate already configured with a date picker. */ 928 markerClassName: "hasDatepicker", 929 930 //Keep track of the maximum number of rows displayed (see #7043) 931 maxRows: 4, 932 933 // TODO rename to "widget" when switching to widget factory 934 _widgetDatepicker: function() { 935 return this.dpDiv; 936 }, 937 938 /* Override the default settings for all instances of the date picker. 939 * @param settings object - the new settings to use as defaults (anonymous object) 940 * @return the manager object 941 */ 942 setDefaults: function( settings ) { 943 datepicker_extendRemove( this._defaults, settings || {} ); 944 return this; 945 }, 946 947 /* Attach the date picker to a jQuery selection. 948 * @param target element - the target input field or division or span 949 * @param settings object - the new settings to use for this date picker instance (anonymous) 950 */ 951 _attachDatepicker: function( target, settings ) { 952 var nodeName, inline, inst; 953 nodeName = target.nodeName.toLowerCase(); 954 inline = ( nodeName === "div" || nodeName === "span" ); 955 if ( !target.id ) { 956 this.uuid += 1; 957 target.id = "dp" + this.uuid; 958 } 959 inst = this._newInst( $( target ), inline ); 960 inst.settings = $.extend( {}, settings || {} ); 961 if ( nodeName === "input" ) { 962 this._connectDatepicker( target, inst ); 963 } else if ( inline ) { 964 this._inlineDatepicker( target, inst ); 965 } 966 }, 967 968 /* Create a new instance object. */ 969 _newInst: function( target, inline ) { 970 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars 971 return { id: id, input: target, // associated target 972 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 973 drawMonth: 0, drawYear: 0, // month being drawn 974 inline: inline, // is datepicker inline or not 975 dpDiv: ( !inline ? this.dpDiv : // presentation div 976 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) }; 977 }, 978 979 /* Attach the date picker to an input field. */ 980 _connectDatepicker: function( target, inst ) { 981 var input = $( target ); 982 inst.append = $( [] ); 983 inst.trigger = $( [] ); 984 if ( input.hasClass( this.markerClassName ) ) { 985 return; 986 } 987 this._attachments( input, inst ); 988 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ). 989 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp ); 990 this._autoSize( inst ); 991 $.data( target, "datepicker", inst ); 992 993 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 994 if ( inst.settings.disabled ) { 995 this._disableDatepicker( target ); 996 } 997 }, 998 999 /* Make attachments based on settings. */ 1000 _attachments: function( input, inst ) { 1001 var showOn, buttonText, buttonImage, 1002 appendText = this._get( inst, "appendText" ), 1003 isRTL = this._get( inst, "isRTL" ); 1004 1005 if ( inst.append ) { 1006 inst.append.remove(); 1007 } 1008 if ( appendText ) { 1009 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" ); 1010 input[ isRTL ? "before" : "after" ]( inst.append ); 1011 } 1012 1013 input.off( "focus", this._showDatepicker ); 1014 1015 if ( inst.trigger ) { 1016 inst.trigger.remove(); 1017 } 1018 1019 showOn = this._get( inst, "showOn" ); 1020 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field 1021 input.on( "focus", this._showDatepicker ); 1022 } 1023 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked 1024 buttonText = this._get( inst, "buttonText" ); 1025 buttonImage = this._get( inst, "buttonImage" ); 1026 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ? 1027 $( "<img/>" ).addClass( this._triggerClass ). 1028 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) : 1029 $( "<button type='button'></button>" ).addClass( this._triggerClass ). 1030 html( !buttonImage ? buttonText : $( "<img/>" ).attr( 1031 { src:buttonImage, alt:buttonText, title:buttonText } ) ) ); 1032 input[ isRTL ? "before" : "after" ]( inst.trigger ); 1033 inst.trigger.on( "click", function() { 1034 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) { 1035 $.datepicker._hideDatepicker(); 1036 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) { 1037 $.datepicker._hideDatepicker(); 1038 $.datepicker._showDatepicker( input[ 0 ] ); 1039 } else { 1040 $.datepicker._showDatepicker( input[ 0 ] ); 1041 } 1042 return false; 1043 } ); 1044 } 1045 }, 1046 1047 /* Apply the maximum length for the date format. */ 1048 _autoSize: function( inst ) { 1049 if ( this._get( inst, "autoSize" ) && !inst.inline ) { 1050 var findMax, max, maxI, i, 1051 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits 1052 dateFormat = this._get( inst, "dateFormat" ); 1053 1054 if ( dateFormat.match( /[DM]/ ) ) { 1055 findMax = function( names ) { 1056 max = 0; 1057 maxI = 0; 1058 for ( i = 0; i < names.length; i++ ) { 1059 if ( names[ i ].length > max ) { 1060 max = names[ i ].length; 1061 maxI = i; 1062 } 1063 } 1064 return maxI; 1065 }; 1066 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ? 1067 "monthNames" : "monthNamesShort" ) ) ) ); 1068 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ? 1069 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() ); 1070 } 1071 inst.input.attr( "size", this._formatDate( inst, date ).length ); 1072 } 1073 }, 1074 1075 /* Attach an inline date picker to a div. */ 1076 _inlineDatepicker: function( target, inst ) { 1077 var divSpan = $( target ); 1078 if ( divSpan.hasClass( this.markerClassName ) ) { 1079 return; 1080 } 1081 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 1082 $.data( target, "datepicker", inst ); 1083 this._setDate( inst, this._getDefaultDate( inst ), true ); 1084 this._updateDatepicker( inst ); 1085 this._updateAlternate( inst ); 1086 1087 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 1088 if ( inst.settings.disabled ) { 1089 this._disableDatepicker( target ); 1090 } 1091 1092 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 1093 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 1094 inst.dpDiv.css( "display", "block" ); 1095 }, 1096 1097 /* Pop-up the date picker in a "dialog" box. 1098 * @param input element - ignored 1099 * @param date string or Date - the initial date to display 1100 * @param onSelect function - the function to call when a date is selected 1101 * @param settings object - update the dialog date picker instance's settings (anonymous object) 1102 * @param pos int[2] - coordinates for the dialog's position within the screen or 1103 * event - with x/y coordinates or 1104 * leave empty for default (screen centre) 1105 * @return the manager object 1106 */ 1107 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 1108 var id, browserWidth, browserHeight, scrollX, scrollY, 1109 inst = this._dialogInst; // internal instance 1110 1111 if ( !inst ) { 1112 this.uuid += 1; 1113 id = "dp" + this.uuid; 1114 this._dialogInput = $( "<input type='text' id='" + id + 1115 "' style='position: absolute; top: -100px; width: 0px;'/>" ); 1116 this._dialogInput.on( "keydown", this._doKeyDown ); 1117 $( "body" ).append( this._dialogInput ); 1118 inst = this._dialogInst = this._newInst( this._dialogInput, false ); 1119 inst.settings = {}; 1120 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 1121 } 1122 datepicker_extendRemove( inst.settings, settings || {} ); 1123 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date ); 1124 this._dialogInput.val( date ); 1125 1126 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null ); 1127 if ( !this._pos ) { 1128 browserWidth = document.documentElement.clientWidth; 1129 browserHeight = document.documentElement.clientHeight; 1130 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 1131 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 1132 this._pos = // should use actual width/height below 1133 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 1134 } 1135 1136 // Move input on screen for focus, but hidden behind dialog 1137 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" ); 1138 inst.settings.onSelect = onSelect; 1139 this._inDialog = true; 1140 this.dpDiv.addClass( this._dialogClass ); 1141 this._showDatepicker( this._dialogInput[ 0 ] ); 1142 if ( $.blockUI ) { 1143 $.blockUI( this.dpDiv ); 1144 } 1145 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 1146 return this; 1147 }, 1148 1149 /* Detach a datepicker from its control. 1150 * @param target element - the target input field or division or span 1151 */ 1152 _destroyDatepicker: function( target ) { 1153 var nodeName, 1154 $target = $( target ), 1155 inst = $.data( target, "datepicker" ); 1156 1157 if ( !$target.hasClass( this.markerClassName ) ) { 1158 return; 1159 } 1160 1161 nodeName = target.nodeName.toLowerCase(); 1162 $.removeData( target, "datepicker" ); 1163 if ( nodeName === "input" ) { 1164 inst.append.remove(); 1165 inst.trigger.remove(); 1166 $target.removeClass( this.markerClassName ). 1167 off( "focus", this._showDatepicker ). 1168 off( "keydown", this._doKeyDown ). 1169 off( "keypress", this._doKeyPress ). 1170 off( "keyup", this._doKeyUp ); 1171 } else if ( nodeName === "div" || nodeName === "span" ) { 1172 $target.removeClass( this.markerClassName ).empty(); 1173 } 1174 1175 if ( datepicker_instActive === inst ) { 1176 datepicker_instActive = null; 1177 } 1178 }, 1179 1180 /* Enable the date picker to a jQuery selection. 1181 * @param target element - the target input field or division or span 1182 */ 1183 _enableDatepicker: function( target ) { 1184 var nodeName, inline, 1185 $target = $( target ), 1186 inst = $.data( target, "datepicker" ); 1187 1188 if ( !$target.hasClass( this.markerClassName ) ) { 1189 return; 1190 } 1191 1192 nodeName = target.nodeName.toLowerCase(); 1193 if ( nodeName === "input" ) { 1194 target.disabled = false; 1195 inst.trigger.filter( "button" ). 1196 each( function() { this.disabled = false; } ).end(). 1197 filter( "img" ).css( { opacity: "1.0", cursor: "" } ); 1198 } else if ( nodeName === "div" || nodeName === "span" ) { 1199 inline = $target.children( "." + this._inlineClass ); 1200 inline.children().removeClass( "ui-state-disabled" ); 1201 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 1202 prop( "disabled", false ); 1203 } 1204 this._disabledInputs = $.map( this._disabledInputs, 1205 function( value ) { return ( value === target ? null : value ); } ); // delete entry 1206 }, 1207 1208 /* Disable the date picker to a jQuery selection. 1209 * @param target element - the target input field or division or span 1210 */ 1211 _disableDatepicker: function( target ) { 1212 var nodeName, inline, 1213 $target = $( target ), 1214 inst = $.data( target, "datepicker" ); 1215 1216 if ( !$target.hasClass( this.markerClassName ) ) { 1217 return; 1218 } 1219 1220 nodeName = target.nodeName.toLowerCase(); 1221 if ( nodeName === "input" ) { 1222 target.disabled = true; 1223 inst.trigger.filter( "button" ). 1224 each( function() { this.disabled = true; } ).end(). 1225 filter( "img" ).css( { opacity: "0.5", cursor: "default" } ); 1226 } else if ( nodeName === "div" || nodeName === "span" ) { 1227 inline = $target.children( "." + this._inlineClass ); 1228 inline.children().addClass( "ui-state-disabled" ); 1229 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 1230 prop( "disabled", true ); 1231 } 1232 this._disabledInputs = $.map( this._disabledInputs, 1233 function( value ) { return ( value === target ? null : value ); } ); // delete entry 1234 this._disabledInputs[ this._disabledInputs.length ] = target; 1235 }, 1236 1237 /* Is the first field in a jQuery collection disabled as a datepicker? 1238 * @param target element - the target input field or division or span 1239 * @return boolean - true if disabled, false if enabled 1240 */ 1241 _isDisabledDatepicker: function( target ) { 1242 if ( !target ) { 1243 return false; 1244 } 1245 for ( var i = 0; i < this._disabledInputs.length; i++ ) { 1246 if ( this._disabledInputs[ i ] === target ) { 1247 return true; 1248 } 1249 } 1250 return false; 1251 }, 1252 1253 /* Retrieve the instance data for the target control. 1254 * @param target element - the target input field or division or span 1255 * @return object - the associated instance data 1256 * @throws error if a jQuery problem getting data 1257 */ 1258 _getInst: function( target ) { 1259 try { 1260 return $.data( target, "datepicker" ); 1261 } 1262 catch ( err ) { 1263 throw "Missing instance data for this datepicker"; 1264 } 1265 }, 1266 1267 /* Update or retrieve the settings for a date picker attached to an input field or division. 1268 * @param target element - the target input field or division or span 1269 * @param name object - the new settings to update or 1270 * string - the name of the setting to change or retrieve, 1271 * when retrieving also "all" for all instance settings or 1272 * "defaults" for all global defaults 1273 * @param value any - the new value for the setting 1274 * (omit if above is an object or to retrieve a value) 1275 */ 1276 _optionDatepicker: function( target, name, value ) { 1277 var settings, date, minDate, maxDate, 1278 inst = this._getInst( target ); 1279 1280 if ( arguments.length === 2 && typeof name === "string" ) { 1281 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) : 1282 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) : 1283 this._get( inst, name ) ) : null ) ); 1284 } 1285 1286 settings = name || {}; 1287 if ( typeof name === "string" ) { 1288 settings = {}; 1289 settings[ name ] = value; 1290 } 1291 1292 if ( inst ) { 1293 if ( this._curInst === inst ) { 1294 this._hideDatepicker(); 1295 } 1296 1297 date = this._getDateDatepicker( target, true ); 1298 minDate = this._getMinMaxDate( inst, "min" ); 1299 maxDate = this._getMinMaxDate( inst, "max" ); 1300 datepicker_extendRemove( inst.settings, settings ); 1301 1302 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 1303 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 1304 inst.settings.minDate = this._formatDate( inst, minDate ); 1305 } 1306 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 1307 inst.settings.maxDate = this._formatDate( inst, maxDate ); 1308 } 1309 if ( "disabled" in settings ) { 1310 if ( settings.disabled ) { 1311 this._disableDatepicker( target ); 1312 } else { 1313 this._enableDatepicker( target ); 1314 } 1315 } 1316 this._attachments( $( target ), inst ); 1317 this._autoSize( inst ); 1318 this._setDate( inst, date ); 1319 this._updateAlternate( inst ); 1320 this._updateDatepicker( inst ); 1321 } 1322 }, 1323 1324 // Change method deprecated 1325 _changeDatepicker: function( target, name, value ) { 1326 this._optionDatepicker( target, name, value ); 1327 }, 1328 1329 /* Redraw the date picker attached to an input field or division. 1330 * @param target element - the target input field or division or span 1331 */ 1332 _refreshDatepicker: function( target ) { 1333 var inst = this._getInst( target ); 1334 if ( inst ) { 1335 this._updateDatepicker( inst ); 1336 } 1337 }, 1338 1339 /* Set the dates for a jQuery selection. 1340 * @param target element - the target input field or division or span 1341 * @param date Date - the new date 1342 */ 1343 _setDateDatepicker: function( target, date ) { 1344 var inst = this._getInst( target ); 1345 if ( inst ) { 1346 this._setDate( inst, date ); 1347 this._updateDatepicker( inst ); 1348 this._updateAlternate( inst ); 1349 } 1350 }, 1351 1352 /* Get the date(s) for the first entry in a jQuery selection. 1353 * @param target element - the target input field or division or span 1354 * @param noDefault boolean - true if no default date is to be used 1355 * @return Date - the current date 1356 */ 1357 _getDateDatepicker: function( target, noDefault ) { 1358 var inst = this._getInst( target ); 1359 if ( inst && !inst.inline ) { 1360 this._setDateFromField( inst, noDefault ); 1361 } 1362 return ( inst ? this._getDate( inst ) : null ); 1363 }, 1364 1365 /* Handle keystrokes. */ 1366 _doKeyDown: function( event ) { 1367 var onSelect, dateStr, sel, 1368 inst = $.datepicker._getInst( event.target ), 1369 handled = true, 1370 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" ); 1371 1372 inst._keyEvent = true; 1373 if ( $.datepicker._datepickerShowing ) { 1374 switch ( event.keyCode ) { 1375 case 9: $.datepicker._hideDatepicker(); 1376 handled = false; 1377 break; // hide on tab out 1378 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." + 1379 $.datepicker._currentClass + ")", inst.dpDiv ); 1380 if ( sel[ 0 ] ) { 1381 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 1382 } 1383 1384 onSelect = $.datepicker._get( inst, "onSelect" ); 1385 if ( onSelect ) { 1386 dateStr = $.datepicker._formatDate( inst ); 1387 1388 // Trigger custom callback 1389 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); 1390 } else { 1391 $.datepicker._hideDatepicker(); 1392 } 1393 1394 return false; // don't submit the form 1395 case 27: $.datepicker._hideDatepicker(); 1396 break; // hide on escape 1397 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 1398 -$.datepicker._get( inst, "stepBigMonths" ) : 1399 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 1400 break; // previous month/year on page up/+ ctrl 1401 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 1402 +$.datepicker._get( inst, "stepBigMonths" ) : 1403 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 1404 break; // next month/year on page down/+ ctrl 1405 case 35: if ( event.ctrlKey || event.metaKey ) { 1406 $.datepicker._clearDate( event.target ); 1407 } 1408 handled = event.ctrlKey || event.metaKey; 1409 break; // clear on ctrl or command +end 1410 case 36: if ( event.ctrlKey || event.metaKey ) { 1411 $.datepicker._gotoToday( event.target ); 1412 } 1413 handled = event.ctrlKey || event.metaKey; 1414 break; // current on ctrl or command +home 1415 case 37: if ( event.ctrlKey || event.metaKey ) { 1416 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" ); 1417 } 1418 handled = event.ctrlKey || event.metaKey; 1419 1420 // -1 day on ctrl or command +left 1421 if ( event.originalEvent.altKey ) { 1422 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 1423 -$.datepicker._get( inst, "stepBigMonths" ) : 1424 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 1425 } 1426 1427 // next month/year on alt +left on Mac 1428 break; 1429 case 38: if ( event.ctrlKey || event.metaKey ) { 1430 $.datepicker._adjustDate( event.target, -7, "D" ); 1431 } 1432 handled = event.ctrlKey || event.metaKey; 1433 break; // -1 week on ctrl or command +up 1434 case 39: if ( event.ctrlKey || event.metaKey ) { 1435 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" ); 1436 } 1437 handled = event.ctrlKey || event.metaKey; 1438 1439 // +1 day on ctrl or command +right 1440 if ( event.originalEvent.altKey ) { 1441 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 1442 +$.datepicker._get( inst, "stepBigMonths" ) : 1443 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 1444 } 1445 1446 // next month/year on alt +right 1447 break; 1448 case 40: if ( event.ctrlKey || event.metaKey ) { 1449 $.datepicker._adjustDate( event.target, +7, "D" ); 1450 } 1451 handled = event.ctrlKey || event.metaKey; 1452 break; // +1 week on ctrl or command +down 1453 default: handled = false; 1454 } 1455 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home 1456 $.datepicker._showDatepicker( this ); 1457 } else { 1458 handled = false; 1459 } 1460 1461 if ( handled ) { 1462 event.preventDefault(); 1463 event.stopPropagation(); 1464 } 1465 }, 1466 1467 /* Filter entered characters - based on date format. */ 1468 _doKeyPress: function( event ) { 1469 var chars, chr, 1470 inst = $.datepicker._getInst( event.target ); 1471 1472 if ( $.datepicker._get( inst, "constrainInput" ) ) { 1473 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) ); 1474 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode ); 1475 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 ); 1476 } 1477 }, 1478 1479 /* Synchronise manual entry and field/alternate field. */ 1480 _doKeyUp: function( event ) { 1481 var date, 1482 inst = $.datepicker._getInst( event.target ); 1483 1484 if ( inst.input.val() !== inst.lastVal ) { 1485 try { 1486 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 1487 ( inst.input ? inst.input.val() : null ), 1488 $.datepicker._getFormatConfig( inst ) ); 1489 1490 if ( date ) { // only if valid 1491 $.datepicker._setDateFromField( inst ); 1492 $.datepicker._updateAlternate( inst ); 1493 $.datepicker._updateDatepicker( inst ); 1494 } 1495 } 1496 catch ( err ) { 1497 } 1498 } 1499 return true; 1500 }, 1501 1502 /* Pop-up the date picker for a given input field. 1503 * If false returned from beforeShow event handler do not show. 1504 * @param input element - the input field attached to the date picker or 1505 * event - if triggered by focus 1506 */ 1507 _showDatepicker: function( input ) { 1508 input = input.target || input; 1509 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger 1510 input = $( "input", input.parentNode )[ 0 ]; 1511 } 1512 1513 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here 1514 return; 1515 } 1516 1517 var inst, beforeShow, beforeShowSettings, isFixed, 1518 offset, showAnim, duration; 1519 1520 inst = $.datepicker._getInst( input ); 1521 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) { 1522 $.datepicker._curInst.dpDiv.stop( true, true ); 1523 if ( inst && $.datepicker._datepickerShowing ) { 1524 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] ); 1525 } 1526 } 1527 1528 beforeShow = $.datepicker._get( inst, "beforeShow" ); 1529 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 1530 if ( beforeShowSettings === false ) { 1531 return; 1532 } 1533 datepicker_extendRemove( inst.settings, beforeShowSettings ); 1534 1535 inst.lastVal = null; 1536 $.datepicker._lastInput = input; 1537 $.datepicker._setDateFromField( inst ); 1538 1539 if ( $.datepicker._inDialog ) { // hide cursor 1540 input.value = ""; 1541 } 1542 if ( !$.datepicker._pos ) { // position below input 1543 $.datepicker._pos = $.datepicker._findPos( input ); 1544 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height 1545 } 1546 1547 isFixed = false; 1548 $( input ).parents().each( function() { 1549 isFixed |= $( this ).css( "position" ) === "fixed"; 1550 return !isFixed; 1551 } ); 1552 1553 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] }; 1554 $.datepicker._pos = null; 1555 1556 //to avoid flashes on Firefox 1557 inst.dpDiv.empty(); 1558 1559 // determine sizing offscreen 1560 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } ); 1561 $.datepicker._updateDatepicker( inst ); 1562 1563 // fix width for dynamic number of date pickers 1564 // and adjust position before showing 1565 offset = $.datepicker._checkOffset( inst, offset, isFixed ); 1566 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ? 1567 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none", 1568 left: offset.left + "px", top: offset.top + "px" } ); 1569 1570 if ( !inst.inline ) { 1571 showAnim = $.datepicker._get( inst, "showAnim" ); 1572 duration = $.datepicker._get( inst, "duration" ); 1573 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 1574 $.datepicker._datepickerShowing = true; 1575 1576 if ( $.effects && $.effects.effect[ showAnim ] ) { 1577 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration ); 1578 } else { 1579 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null ); 1580 } 1581 1582 if ( $.datepicker._shouldFocusInput( inst ) ) { 1583 inst.input.trigger( "focus" ); 1584 } 1585 1586 $.datepicker._curInst = inst; 1587 } 1588 }, 1589 1590 /* Generate the date picker content. */ 1591 _updateDatepicker: function( inst ) { 1592 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 1593 datepicker_instActive = inst; // for delegate hover events 1594 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 1595 this._attachHandlers( inst ); 1596 1597 var origyearshtml, 1598 numMonths = this._getNumberOfMonths( inst ), 1599 cols = numMonths[ 1 ], 1600 width = 17, 1601 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); 1602 1603 if ( activeCell.length > 0 ) { 1604 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 1605 } 1606 1607 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" ); 1608 if ( cols > 1 ) { 1609 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" ); 1610 } 1611 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) + 1612 "Class" ]( "ui-datepicker-multi" ); 1613 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) + 1614 "Class" ]( "ui-datepicker-rtl" ); 1615 1616 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 1617 inst.input.trigger( "focus" ); 1618 } 1619 1620 // Deffered render of the years select (to avoid flashes on Firefox) 1621 if ( inst.yearshtml ) { 1622 origyearshtml = inst.yearshtml; 1623 setTimeout( function() { 1624 1625 //assure that inst.yearshtml didn't change. 1626 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) { 1627 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml ); 1628 } 1629 origyearshtml = inst.yearshtml = null; 1630 }, 0 ); 1631 } 1632 }, 1633 1634 // #6694 - don't focus the input if it's already focused 1635 // this breaks the change event in IE 1636 // Support: IE and jQuery <1.9 1637 _shouldFocusInput: function( inst ) { 1638 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); 1639 }, 1640 1641 /* Check positioning to remain on screen. */ 1642 _checkOffset: function( inst, offset, isFixed ) { 1643 var dpWidth = inst.dpDiv.outerWidth(), 1644 dpHeight = inst.dpDiv.outerHeight(), 1645 inputWidth = inst.input ? inst.input.outerWidth() : 0, 1646 inputHeight = inst.input ? inst.input.outerHeight() : 0, 1647 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 1648 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 1649 1650 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 ); 1651 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0; 1652 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0; 1653 1654 // Now check if datepicker is showing outside window viewport - move to a better place if so. 1655 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ? 1656 Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 1657 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ? 1658 Math.abs( dpHeight + inputHeight ) : 0 ); 1659 1660 return offset; 1661 }, 1662 1663 /* Find an object's position on the screen. */ 1664 _findPos: function( obj ) { 1665 var position, 1666 inst = this._getInst( obj ), 1667 isRTL = this._get( inst, "isRTL" ); 1668 1669 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) { 1670 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ]; 1671 } 1672 1673 position = $( obj ).offset(); 1674 return [ position.left, position.top ]; 1675 }, 1676 1677 /* Hide the date picker from view. 1678 * @param input element - the input field attached to the date picker 1679 */ 1680 _hideDatepicker: function( input ) { 1681 var showAnim, duration, postProcess, onClose, 1682 inst = this._curInst; 1683 1684 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) { 1685 return; 1686 } 1687 1688 if ( this._datepickerShowing ) { 1689 showAnim = this._get( inst, "showAnim" ); 1690 duration = this._get( inst, "duration" ); 1691 postProcess = function() { 1692 $.datepicker._tidyDialog( inst ); 1693 }; 1694 1695 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 1696 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 1697 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess ); 1698 } else { 1699 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" : 1700 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess ); 1701 } 1702 1703 if ( !showAnim ) { 1704 postProcess(); 1705 } 1706 this._datepickerShowing = false; 1707 1708 onClose = this._get( inst, "onClose" ); 1709 if ( onClose ) { 1710 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] ); 1711 } 1712 1713 this._lastInput = null; 1714 if ( this._inDialog ) { 1715 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } ); 1716 if ( $.blockUI ) { 1717 $.unblockUI(); 1718 $( "body" ).append( this.dpDiv ); 1719 } 1720 } 1721 this._inDialog = false; 1722 } 1723 }, 1724 1725 /* Tidy up after a dialog display. */ 1726 _tidyDialog: function( inst ) { 1727 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" ); 1728 }, 1729 1730 /* Close date picker if clicked elsewhere. */ 1731 _checkExternalClick: function( event ) { 1732 if ( !$.datepicker._curInst ) { 1733 return; 1734 } 1735 1736 var $target = $( event.target ), 1737 inst = $.datepicker._getInst( $target[ 0 ] ); 1738 1739 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId && 1740 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 && 1741 !$target.hasClass( $.datepicker.markerClassName ) && 1742 !$target.closest( "." + $.datepicker._triggerClass ).length && 1743 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) || 1744 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) { 1745 $.datepicker._hideDatepicker(); 1746 } 1747 }, 1748 1749 /* Adjust one of the date sub-fields. */ 1750 _adjustDate: function( id, offset, period ) { 1751 var target = $( id ), 1752 inst = this._getInst( target[ 0 ] ); 1753 1754 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 1755 return; 1756 } 1757 this._adjustInstDate( inst, offset + 1758 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning 1759 period ); 1760 this._updateDatepicker( inst ); 1761 }, 1762 1763 /* Action for current link. */ 1764 _gotoToday: function( id ) { 1765 var date, 1766 target = $( id ), 1767 inst = this._getInst( target[ 0 ] ); 1768 1769 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) { 1770 inst.selectedDay = inst.currentDay; 1771 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 1772 inst.drawYear = inst.selectedYear = inst.currentYear; 1773 } else { 1774 date = new Date(); 1775 inst.selectedDay = date.getDate(); 1776 inst.drawMonth = inst.selectedMonth = date.getMonth(); 1777 inst.drawYear = inst.selectedYear = date.getFullYear(); 1778 } 1779 this._notifyChange( inst ); 1780 this._adjustDate( target ); 1781 }, 1782 1783 /* Action for selecting a new month/year. */ 1784 _selectMonthYear: function( id, select, period ) { 1785 var target = $( id ), 1786 inst = this._getInst( target[ 0 ] ); 1787 1788 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] = 1789 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] = 1790 parseInt( select.options[ select.selectedIndex ].value, 10 ); 1791 1792 this._notifyChange( inst ); 1793 this._adjustDate( target ); 1794 }, 1795 1796 /* Action for selecting a day. */ 1797 _selectDay: function( id, month, year, td ) { 1798 var inst, 1799 target = $( id ); 1800 1801 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 1802 return; 1803 } 1804 1805 inst = this._getInst( target[ 0 ] ); 1806 inst.selectedDay = inst.currentDay = $( "a", td ).html(); 1807 inst.selectedMonth = inst.currentMonth = month; 1808 inst.selectedYear = inst.currentYear = year; 1809 this._selectDate( id, this._formatDate( inst, 1810 inst.currentDay, inst.currentMonth, inst.currentYear ) ); 1811 }, 1812 1813 /* Erase the input field and hide the date picker. */ 1814 _clearDate: function( id ) { 1815 var target = $( id ); 1816 this._selectDate( target, "" ); 1817 }, 1818 1819 /* Update the input field with the selected date. */ 1820 _selectDate: function( id, dateStr ) { 1821 var onSelect, 1822 target = $( id ), 1823 inst = this._getInst( target[ 0 ] ); 1824 1825 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) ); 1826 if ( inst.input ) { 1827 inst.input.val( dateStr ); 1828 } 1829 this._updateAlternate( inst ); 1830 1831 onSelect = this._get( inst, "onSelect" ); 1832 if ( onSelect ) { 1833 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback 1834 } else if ( inst.input ) { 1835 inst.input.trigger( "change" ); // fire the change event 1836 } 1837 1838 if ( inst.inline ) { 1839 this._updateDatepicker( inst ); 1840 } else { 1841 this._hideDatepicker(); 1842 this._lastInput = inst.input[ 0 ]; 1843 if ( typeof( inst.input[ 0 ] ) !== "object" ) { 1844 inst.input.trigger( "focus" ); // restore focus 1845 } 1846 this._lastInput = null; 1847 } 1848 }, 1849 1850 /* Update any alternate field to synchronise with the main field. */ 1851 _updateAlternate: function( inst ) { 1852 var altFormat, date, dateStr, 1853 altField = this._get( inst, "altField" ); 1854 1855 if ( altField ) { // update alternate field too 1856 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" ); 1857 date = this._getDate( inst ); 1858 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 1859 $( altField ).val( dateStr ); 1860 } 1861 }, 1862 1863 /* Set as beforeShowDay function to prevent selection of weekends. 1864 * @param date Date - the date to customise 1865 * @return [boolean, string] - is this date selectable?, what is its CSS class? 1866 */ 1867 noWeekends: function( date ) { 1868 var day = date.getDay(); 1869 return [ ( day > 0 && day < 6 ), "" ]; 1870 }, 1871 1872 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 1873 * @param date Date - the date to get the week for 1874 * @return number - the number of the week within the year that contains this date 1875 */ 1876 iso8601Week: function( date ) { 1877 var time, 1878 checkDate = new Date( date.getTime() ); 1879 1880 // Find Thursday of this week starting on Monday 1881 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 1882 1883 time = checkDate.getTime(); 1884 checkDate.setMonth( 0 ); // Compare with Jan 1 1885 checkDate.setDate( 1 ); 1886 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 1887 }, 1888 1889 /* Parse a string value into a date object. 1890 * See formatDate below for the possible formats. 1891 * 1892 * @param format string - the expected format of the date 1893 * @param value string - the date in the above format 1894 * @param settings Object - attributes include: 1895 * shortYearCutoff number - the cutoff year for determining the century (optional) 1896 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 1897 * dayNames string[7] - names of the days from Sunday (optional) 1898 * monthNamesShort string[12] - abbreviated names of the months (optional) 1899 * monthNames string[12] - names of the months (optional) 1900 * @return Date - the extracted date value or null if value is blank 1901 */ 1902 parseDate: function( format, value, settings ) { 1903 if ( format == null || value == null ) { 1904 throw "Invalid arguments"; 1905 } 1906 1907 value = ( typeof value === "object" ? value.toString() : value + "" ); 1908 if ( value === "" ) { 1909 return null; 1910 } 1911 1912 var iFormat, dim, extra, 1913 iValue = 0, 1914 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff, 1915 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 1916 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ), 1917 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 1918 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 1919 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 1920 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 1921 year = -1, 1922 month = -1, 1923 day = -1, 1924 doy = -1, 1925 literal = false, 1926 date, 1927 1928 // Check whether a format character is doubled 1929 lookAhead = function( match ) { 1930 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 1931 if ( matches ) { 1932 iFormat++; 1933 } 1934 return matches; 1935 }, 1936 1937 // Extract a number from the string value 1938 getNumber = function( match ) { 1939 var isDoubled = lookAhead( match ), 1940 size = ( match === "@" ? 14 : ( match === "!" ? 20 : 1941 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ), 1942 minSize = ( match === "y" ? size : 1 ), 1943 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ), 1944 num = value.substring( iValue ).match( digits ); 1945 if ( !num ) { 1946 throw "Missing number at position " + iValue; 1947 } 1948 iValue += num[ 0 ].length; 1949 return parseInt( num[ 0 ], 10 ); 1950 }, 1951 1952 // Extract a name from the string value and convert to an index 1953 getName = function( match, shortNames, longNames ) { 1954 var index = -1, 1955 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 1956 return [ [ k, v ] ]; 1957 } ).sort( function( a, b ) { 1958 return -( a[ 1 ].length - b[ 1 ].length ); 1959 } ); 1960 1961 $.each( names, function( i, pair ) { 1962 var name = pair[ 1 ]; 1963 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) { 1964 index = pair[ 0 ]; 1965 iValue += name.length; 1966 return false; 1967 } 1968 } ); 1969 if ( index !== -1 ) { 1970 return index + 1; 1971 } else { 1972 throw "Unknown name at position " + iValue; 1973 } 1974 }, 1975 1976 // Confirm that a literal character matches the string value 1977 checkLiteral = function() { 1978 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 1979 throw "Unexpected literal at position " + iValue; 1980 } 1981 iValue++; 1982 }; 1983 1984 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 1985 if ( literal ) { 1986 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 1987 literal = false; 1988 } else { 1989 checkLiteral(); 1990 } 1991 } else { 1992 switch ( format.charAt( iFormat ) ) { 1993 case "d": 1994 day = getNumber( "d" ); 1995 break; 1996 case "D": 1997 getName( "D", dayNamesShort, dayNames ); 1998 break; 1999 case "o": 2000 doy = getNumber( "o" ); 2001 break; 2002 case "m": 2003 month = getNumber( "m" ); 2004 break; 2005 case "M": 2006 month = getName( "M", monthNamesShort, monthNames ); 2007 break; 2008 case "y": 2009 year = getNumber( "y" ); 2010 break; 2011 case "@": 2012 date = new Date( getNumber( "@" ) ); 2013 year = date.getFullYear(); 2014 month = date.getMonth() + 1; 2015 day = date.getDate(); 2016 break; 2017 case "!": 2018 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 ); 2019 year = date.getFullYear(); 2020 month = date.getMonth() + 1; 2021 day = date.getDate(); 2022 break; 2023 case "'": 2024 if ( lookAhead( "'" ) ) { 2025 checkLiteral(); 2026 } else { 2027 literal = true; 2028 } 2029 break; 2030 default: 2031 checkLiteral(); 2032 } 2033 } 2034 } 2035 2036 if ( iValue < value.length ) { 2037 extra = value.substr( iValue ); 2038 if ( !/^\s+/.test( extra ) ) { 2039 throw "Extra/unparsed characters found in date: " + extra; 2040 } 2041 } 2042 2043 if ( year === -1 ) { 2044 year = new Date().getFullYear(); 2045 } else if ( year < 100 ) { 2046 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 2047 ( year <= shortYearCutoff ? 0 : -100 ); 2048 } 2049 2050 if ( doy > -1 ) { 2051 month = 1; 2052 day = doy; 2053 do { 2054 dim = this._getDaysInMonth( year, month - 1 ); 2055 if ( day <= dim ) { 2056 break; 2057 } 2058 month++; 2059 day -= dim; 2060 } while ( true ); 2061 } 2062 2063 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 2064 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 2065 throw "Invalid date"; // E.g. 31/02/00 2066 } 2067 return date; 2068 }, 2069 2070 /* Standard date formats. */ 2071 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 2072 COOKIE: "D, dd M yy", 2073 ISO_8601: "yy-mm-dd", 2074 RFC_822: "D, d M y", 2075 RFC_850: "DD, dd-M-y", 2076 RFC_1036: "D, d M y", 2077 RFC_1123: "D, d M yy", 2078 RFC_2822: "D, d M yy", 2079 RSS: "D, d M y", // RFC 822 2080 TICKS: "!", 2081 TIMESTAMP: "@", 2082 W3C: "yy-mm-dd", // ISO 8601 2083 2084 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + 2085 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ), 2086 2087 /* Format a date object into a string value. 2088 * The format can be combinations of the following: 2089 * d - day of month (no leading zero) 2090 * dd - day of month (two digit) 2091 * o - day of year (no leading zeros) 2092 * oo - day of year (three digit) 2093 * D - day name short 2094 * DD - day name long 2095 * m - month of year (no leading zero) 2096 * mm - month of year (two digit) 2097 * M - month name short 2098 * MM - month name long 2099 * y - year (two digit) 2100 * yy - year (four digit) 2101 * @ - Unix timestamp (ms since 01/01/1970) 2102 * ! - Windows ticks (100ns since 01/01/0001) 2103 * "..." - literal text 2104 * '' - single quote 2105 * 2106 * @param format string - the desired format of the date 2107 * @param date Date - the date value to format 2108 * @param settings Object - attributes include: 2109 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 2110 * dayNames string[7] - names of the days from Sunday (optional) 2111 * monthNamesShort string[12] - abbreviated names of the months (optional) 2112 * monthNames string[12] - names of the months (optional) 2113 * @return string - the date in the above format 2114 */ 2115 formatDate: function( format, date, settings ) { 2116 if ( !date ) { 2117 return ""; 2118 } 2119 2120 var iFormat, 2121 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 2122 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 2123 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 2124 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 2125 2126 // Check whether a format character is doubled 2127 lookAhead = function( match ) { 2128 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 2129 if ( matches ) { 2130 iFormat++; 2131 } 2132 return matches; 2133 }, 2134 2135 // Format a number, with leading zero if necessary 2136 formatNumber = function( match, value, len ) { 2137 var num = "" + value; 2138 if ( lookAhead( match ) ) { 2139 while ( num.length < len ) { 2140 num = "0" + num; 2141 } 2142 } 2143 return num; 2144 }, 2145 2146 // Format a name, short or long as requested 2147 formatName = function( match, value, shortNames, longNames ) { 2148 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] ); 2149 }, 2150 output = "", 2151 literal = false; 2152 2153 if ( date ) { 2154 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 2155 if ( literal ) { 2156 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 2157 literal = false; 2158 } else { 2159 output += format.charAt( iFormat ); 2160 } 2161 } else { 2162 switch ( format.charAt( iFormat ) ) { 2163 case "d": 2164 output += formatNumber( "d", date.getDate(), 2 ); 2165 break; 2166 case "D": 2167 output += formatName( "D", date.getDay(), dayNamesShort, dayNames ); 2168 break; 2169 case "o": 2170 output += formatNumber( "o", 2171 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 2172 break; 2173 case "m": 2174 output += formatNumber( "m", date.getMonth() + 1, 2 ); 2175 break; 2176 case "M": 2177 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames ); 2178 break; 2179 case "y": 2180 output += ( lookAhead( "y" ) ? date.getFullYear() : 2181 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 ); 2182 break; 2183 case "@": 2184 output += date.getTime(); 2185 break; 2186 case "!": 2187 output += date.getTime() * 10000 + this._ticksTo1970; 2188 break; 2189 case "'": 2190 if ( lookAhead( "'" ) ) { 2191 output += "'"; 2192 } else { 2193 literal = true; 2194 } 2195 break; 2196 default: 2197 output += format.charAt( iFormat ); 2198 } 2199 } 2200 } 2201 } 2202 return output; 2203 }, 2204 2205 /* Extract all possible characters from the date format. */ 2206 _possibleChars: function( format ) { 2207 var iFormat, 2208 chars = "", 2209 literal = false, 2210 2211 // Check whether a format character is doubled 2212 lookAhead = function( match ) { 2213 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 2214 if ( matches ) { 2215 iFormat++; 2216 } 2217 return matches; 2218 }; 2219 2220 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 2221 if ( literal ) { 2222 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 2223 literal = false; 2224 } else { 2225 chars += format.charAt( iFormat ); 2226 } 2227 } else { 2228 switch ( format.charAt( iFormat ) ) { 2229 case "d": case "m": case "y": case "@": 2230 chars += "0123456789"; 2231 break; 2232 case "D": case "M": 2233 return null; // Accept anything 2234 case "'": 2235 if ( lookAhead( "'" ) ) { 2236 chars += "'"; 2237 } else { 2238 literal = true; 2239 } 2240 break; 2241 default: 2242 chars += format.charAt( iFormat ); 2243 } 2244 } 2245 } 2246 return chars; 2247 }, 2248 2249 /* Get a setting value, defaulting if necessary. */ 2250 _get: function( inst, name ) { 2251 return inst.settings[ name ] !== undefined ? 2252 inst.settings[ name ] : this._defaults[ name ]; 2253 }, 2254 2255 /* Parse existing date and initialise date picker. */ 2256 _setDateFromField: function( inst, noDefault ) { 2257 if ( inst.input.val() === inst.lastVal ) { 2258 return; 2259 } 2260 2261 var dateFormat = this._get( inst, "dateFormat" ), 2262 dates = inst.lastVal = inst.input ? inst.input.val() : null, 2263 defaultDate = this._getDefaultDate( inst ), 2264 date = defaultDate, 2265 settings = this._getFormatConfig( inst ); 2266 2267 try { 2268 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 2269 } catch ( event ) { 2270 dates = ( noDefault ? "" : dates ); 2271 } 2272 inst.selectedDay = date.getDate(); 2273 inst.drawMonth = inst.selectedMonth = date.getMonth(); 2274 inst.drawYear = inst.selectedYear = date.getFullYear(); 2275 inst.currentDay = ( dates ? date.getDate() : 0 ); 2276 inst.currentMonth = ( dates ? date.getMonth() : 0 ); 2277 inst.currentYear = ( dates ? date.getFullYear() : 0 ); 2278 this._adjustInstDate( inst ); 2279 }, 2280 2281 /* Retrieve the default date shown on opening. */ 2282 _getDefaultDate: function( inst ) { 2283 return this._restrictMinMax( inst, 2284 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) ); 2285 }, 2286 2287 /* A date may be specified as an exact value or a relative one. */ 2288 _determineDate: function( inst, date, defaultDate ) { 2289 var offsetNumeric = function( offset ) { 2290 var date = new Date(); 2291 date.setDate( date.getDate() + offset ); 2292 return date; 2293 }, 2294 offsetString = function( offset ) { 2295 try { 2296 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 2297 offset, $.datepicker._getFormatConfig( inst ) ); 2298 } 2299 catch ( e ) { 2300 2301 // Ignore 2302 } 2303 2304 var date = ( offset.toLowerCase().match( /^c/ ) ? 2305 $.datepicker._getDate( inst ) : null ) || new Date(), 2306 year = date.getFullYear(), 2307 month = date.getMonth(), 2308 day = date.getDate(), 2309 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 2310 matches = pattern.exec( offset ); 2311 2312 while ( matches ) { 2313 switch ( matches[ 2 ] || "d" ) { 2314 case "d" : case "D" : 2315 day += parseInt( matches[ 1 ], 10 ); break; 2316 case "w" : case "W" : 2317 day += parseInt( matches[ 1 ], 10 ) * 7; break; 2318 case "m" : case "M" : 2319 month += parseInt( matches[ 1 ], 10 ); 2320 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 2321 break; 2322 case "y": case "Y" : 2323 year += parseInt( matches[ 1 ], 10 ); 2324 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 2325 break; 2326 } 2327 matches = pattern.exec( offset ); 2328 } 2329 return new Date( year, month, day ); 2330 }, 2331 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) : 2332 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) ); 2333 2334 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate ); 2335 if ( newDate ) { 2336 newDate.setHours( 0 ); 2337 newDate.setMinutes( 0 ); 2338 newDate.setSeconds( 0 ); 2339 newDate.setMilliseconds( 0 ); 2340 } 2341 return this._daylightSavingAdjust( newDate ); 2342 }, 2343 2344 /* Handle switch to/from daylight saving. 2345 * Hours may be non-zero on daylight saving cut-over: 2346 * > 12 when midnight changeover, but then cannot generate 2347 * midnight datetime, so jump to 1AM, otherwise reset. 2348 * @param date (Date) the date to check 2349 * @return (Date) the corrected date 2350 */ 2351 _daylightSavingAdjust: function( date ) { 2352 if ( !date ) { 2353 return null; 2354 } 2355 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 2356 return date; 2357 }, 2358 2359 /* Set the date(s) directly. */ 2360 _setDate: function( inst, date, noChange ) { 2361 var clear = !date, 2362 origMonth = inst.selectedMonth, 2363 origYear = inst.selectedYear, 2364 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 2365 2366 inst.selectedDay = inst.currentDay = newDate.getDate(); 2367 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 2368 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 2369 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) { 2370 this._notifyChange( inst ); 2371 } 2372 this._adjustInstDate( inst ); 2373 if ( inst.input ) { 2374 inst.input.val( clear ? "" : this._formatDate( inst ) ); 2375 } 2376 }, 2377 2378 /* Retrieve the date(s) directly. */ 2379 _getDate: function( inst ) { 2380 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null : 2381 this._daylightSavingAdjust( new Date( 2382 inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 2383 return startDate; 2384 }, 2385 2386 /* Attach the onxxx handlers. These are declared statically so 2387 * they work with static code transformers like Caja. 2388 */ 2389 _attachHandlers: function( inst ) { 2390 var stepMonths = this._get( inst, "stepMonths" ), 2391 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 2392 inst.dpDiv.find( "[data-handler]" ).map( function() { 2393 var handler = { 2394 prev: function() { 2395 $.datepicker._adjustDate( id, -stepMonths, "M" ); 2396 }, 2397 next: function() { 2398 $.datepicker._adjustDate( id, +stepMonths, "M" ); 2399 }, 2400 hide: function() { 2401 $.datepicker._hideDatepicker(); 2402 }, 2403 today: function() { 2404 $.datepicker._gotoToday( id ); 2405 }, 2406 selectDay: function() { 2407 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this ); 2408 return false; 2409 }, 2410 selectMonth: function() { 2411 $.datepicker._selectMonthYear( id, this, "M" ); 2412 return false; 2413 }, 2414 selectYear: function() { 2415 $.datepicker._selectMonthYear( id, this, "Y" ); 2416 return false; 2417 } 2418 }; 2419 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] ); 2420 } ); 2421 }, 2422 2423 /* Generate the HTML for the current state of the date picker. */ 2424 _generateHTML: function( inst ) { 2425 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 2426 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 2427 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 2428 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 2429 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 2430 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 2431 tempDate = new Date(), 2432 today = this._daylightSavingAdjust( 2433 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 2434 isRTL = this._get( inst, "isRTL" ), 2435 showButtonPanel = this._get( inst, "showButtonPanel" ), 2436 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ), 2437 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ), 2438 numMonths = this._getNumberOfMonths( inst ), 2439 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ), 2440 stepMonths = this._get( inst, "stepMonths" ), 2441 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ), 2442 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) : 2443 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ), 2444 minDate = this._getMinMaxDate( inst, "min" ), 2445 maxDate = this._getMinMaxDate( inst, "max" ), 2446 drawMonth = inst.drawMonth - showCurrentAtPos, 2447 drawYear = inst.drawYear; 2448 2449 if ( drawMonth < 0 ) { 2450 drawMonth += 12; 2451 drawYear--; 2452 } 2453 if ( maxDate ) { 2454 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), 2455 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 2456 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw ); 2457 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 2458 drawMonth--; 2459 if ( drawMonth < 0 ) { 2460 drawMonth = 11; 2461 drawYear--; 2462 } 2463 } 2464 } 2465 inst.drawMonth = drawMonth; 2466 inst.drawYear = drawYear; 2467 2468 prevText = this._get( inst, "prevText" ); 2469 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText, 2470 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), 2471 this._getFormatConfig( inst ) ) ); 2472 2473 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ? 2474 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + 2475 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" : 2476 ( 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>" ) ); 2477 2478 nextText = this._get( inst, "nextText" ); 2479 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText, 2480 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), 2481 this._getFormatConfig( inst ) ) ); 2482 2483 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ? 2484 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + 2485 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" : 2486 ( 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>" ) ); 2487 2488 currentText = this._get( inst, "currentText" ); 2489 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today ); 2490 currentText = ( !navigationAsDateFormat ? currentText : 2491 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) ); 2492 2493 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'>" + 2494 this._get( inst, "closeText" ) + "</button>" : "" ); 2495 2496 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) + 2497 ( 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'" + 2498 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : ""; 2499 2500 firstDay = parseInt( this._get( inst, "firstDay" ), 10 ); 2501 firstDay = ( isNaN( firstDay ) ? 0 : firstDay ); 2502 2503 showWeek = this._get( inst, "showWeek" ); 2504 dayNames = this._get( inst, "dayNames" ); 2505 dayNamesMin = this._get( inst, "dayNamesMin" ); 2506 monthNames = this._get( inst, "monthNames" ); 2507 monthNamesShort = this._get( inst, "monthNamesShort" ); 2508 beforeShowDay = this._get( inst, "beforeShowDay" ); 2509 showOtherMonths = this._get( inst, "showOtherMonths" ); 2510 selectOtherMonths = this._get( inst, "selectOtherMonths" ); 2511 defaultDate = this._getDefaultDate( inst ); 2512 html = ""; 2513 2514 for ( row = 0; row < numMonths[ 0 ]; row++ ) { 2515 group = ""; 2516 this.maxRows = 4; 2517 for ( col = 0; col < numMonths[ 1 ]; col++ ) { 2518 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 2519 cornerClass = " ui-corner-all"; 2520 calender = ""; 2521 if ( isMultiMonth ) { 2522 calender += "<div class='ui-datepicker-group"; 2523 if ( numMonths[ 1 ] > 1 ) { 2524 switch ( col ) { 2525 case 0: calender += " ui-datepicker-group-first"; 2526 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break; 2527 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last"; 2528 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break; 2529 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 2530 } 2531 } 2532 calender += "'>"; 2533 } 2534 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 2535 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) + 2536 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) + 2537 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate, 2538 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers 2539 "</div><table class='ui-datepicker-calendar'><thead>" + 2540 "<tr>"; 2541 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" ); 2542 for ( dow = 0; dow < 7; dow++ ) { // days of the week 2543 day = ( dow + firstDay ) % 7; 2544 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" + 2545 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>"; 2546 } 2547 calender += thead + "</tr></thead><tbody>"; 2548 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 2549 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 2550 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 2551 } 2552 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 2553 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate 2554 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043) 2555 this.maxRows = numRows; 2556 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 2557 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows 2558 calender += "<tr>"; 2559 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 2560 this._get( inst, "calculateWeek" )( printDate ) + "</td>" ); 2561 for ( dow = 0; dow < 7; dow++ ) { // create date picker days 2562 daySettings = ( beforeShowDay ? 2563 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] ); 2564 otherMonth = ( printDate.getMonth() !== drawMonth ); 2565 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] || 2566 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 2567 tbody += "<td class='" + 2568 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends 2569 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months 2570 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key 2571 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? 2572 2573 // or defaultDate is current printedDate and defaultDate is selectedDate 2574 " " + this._dayOverClass : "" ) + // highlight selected day 2575 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days 2576 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates 2577 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day 2578 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different) 2579 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title 2580 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions 2581 ( otherMonth && !showOtherMonths ? " " : // display for other months 2582 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 2583 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) + 2584 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day 2585 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months 2586 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date 2587 printDate.setDate( printDate.getDate() + 1 ); 2588 printDate = this._daylightSavingAdjust( printDate ); 2589 } 2590 calender += tbody + "</tr>"; 2591 } 2592 drawMonth++; 2593 if ( drawMonth > 11 ) { 2594 drawMonth = 0; 2595 drawYear++; 2596 } 2597 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" + 2598 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" ); 2599 group += calender; 2600 } 2601 html += group; 2602 } 2603 html += buttonPanel; 2604 inst._keyEvent = false; 2605 return html; 2606 }, 2607 2608 /* Generate the month and year header. */ 2609 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, 2610 secondary, monthNames, monthNamesShort ) { 2611 2612 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 2613 changeMonth = this._get( inst, "changeMonth" ), 2614 changeYear = this._get( inst, "changeYear" ), 2615 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ), 2616 html = "<div class='ui-datepicker-title'>", 2617 monthHtml = ""; 2618 2619 // Month selection 2620 if ( secondary || !changeMonth ) { 2621 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>"; 2622 } else { 2623 inMinYear = ( minDate && minDate.getFullYear() === drawYear ); 2624 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear ); 2625 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; 2626 for ( month = 0; month < 12; month++ ) { 2627 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) { 2628 monthHtml += "<option value='" + month + "'" + 2629 ( month === drawMonth ? " selected='selected'" : "" ) + 2630 ">" + monthNamesShort[ month ] + "</option>"; 2631 } 2632 } 2633 monthHtml += "</select>"; 2634 } 2635 2636 if ( !showMonthAfterYear ) { 2637 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" ); 2638 } 2639 2640 // Year selection 2641 if ( !inst.yearshtml ) { 2642 inst.yearshtml = ""; 2643 if ( secondary || !changeYear ) { 2644 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 2645 } else { 2646 2647 // determine range of years to display 2648 years = this._get( inst, "yearRange" ).split( ":" ); 2649 thisYear = new Date().getFullYear(); 2650 determineYear = function( value ) { 2651 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : 2652 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) : 2653 parseInt( value, 10 ) ) ); 2654 return ( isNaN( year ) ? thisYear : year ); 2655 }; 2656 year = determineYear( years[ 0 ] ); 2657 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) ); 2658 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year ); 2659 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear ); 2660 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; 2661 for ( ; year <= endYear; year++ ) { 2662 inst.yearshtml += "<option value='" + year + "'" + 2663 ( year === drawYear ? " selected='selected'" : "" ) + 2664 ">" + year + "</option>"; 2665 } 2666 inst.yearshtml += "</select>"; 2667 2668 html += inst.yearshtml; 2669 inst.yearshtml = null; 2670 } 2671 } 2672 2673 html += this._get( inst, "yearSuffix" ); 2674 if ( showMonthAfterYear ) { 2675 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml; 2676 } 2677 html += "</div>"; // Close datepicker_header 2678 return html; 2679 }, 2680 2681 /* Adjust one of the date sub-fields. */ 2682 _adjustInstDate: function( inst, offset, period ) { 2683 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ), 2684 month = inst.selectedMonth + ( period === "M" ? offset : 0 ), 2685 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ), 2686 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 2687 2688 inst.selectedDay = date.getDate(); 2689 inst.drawMonth = inst.selectedMonth = date.getMonth(); 2690 inst.drawYear = inst.selectedYear = date.getFullYear(); 2691 if ( period === "M" || period === "Y" ) { 2692 this._notifyChange( inst ); 2693 } 2694 }, 2695 2696 /* Ensure a date is within any min/max bounds. */ 2697 _restrictMinMax: function( inst, date ) { 2698 var minDate = this._getMinMaxDate( inst, "min" ), 2699 maxDate = this._getMinMaxDate( inst, "max" ), 2700 newDate = ( minDate && date < minDate ? minDate : date ); 2701 return ( maxDate && newDate > maxDate ? maxDate : newDate ); 2702 }, 2703 2704 /* Notify change of month/year. */ 2705 _notifyChange: function( inst ) { 2706 var onChange = this._get( inst, "onChangeMonthYear" ); 2707 if ( onChange ) { 2708 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ), 2709 [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 2710 } 2711 }, 2712 2713 /* Determine the number of months to show. */ 2714 _getNumberOfMonths: function( inst ) { 2715 var numMonths = this._get( inst, "numberOfMonths" ); 2716 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) ); 2717 }, 2718 2719 /* Determine the current maximum date - ensure no time components are set. */ 2720 _getMinMaxDate: function( inst, minMax ) { 2721 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null ); 2722 }, 2723 2724 /* Find the number of days in a given month. */ 2725 _getDaysInMonth: function( year, month ) { 2726 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 2727 }, 2728 2729 /* Find the day of the week of the first of a month. */ 2730 _getFirstDayOfMonth: function( year, month ) { 2731 return new Date( year, month, 1 ).getDay(); 2732 }, 2733 2734 /* Determines if we should allow a "next/prev" month display change. */ 2735 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 2736 var numMonths = this._getNumberOfMonths( inst ), 2737 date = this._daylightSavingAdjust( new Date( curYear, 2738 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 2739 2740 if ( offset < 0 ) { 2741 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 2742 } 2743 return this._isInRange( inst, date ); 2744 }, 2745 2746 /* Is the given date in the accepted range? */ 2747 _isInRange: function( inst, date ) { 2748 var yearSplit, currentYear, 2749 minDate = this._getMinMaxDate( inst, "min" ), 2750 maxDate = this._getMinMaxDate( inst, "max" ), 2751 minYear = null, 2752 maxYear = null, 2753 years = this._get( inst, "yearRange" ); 2754 if ( years ) { 2755 yearSplit = years.split( ":" ); 2756 currentYear = new Date().getFullYear(); 2757 minYear = parseInt( yearSplit[ 0 ], 10 ); 2758 maxYear = parseInt( yearSplit[ 1 ], 10 ); 2759 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) { 2760 minYear += currentYear; 2761 } 2762 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) { 2763 maxYear += currentYear; 2764 } 2765 } 2766 2767 return ( ( !minDate || date.getTime() >= minDate.getTime() ) && 2768 ( !maxDate || date.getTime() <= maxDate.getTime() ) && 2769 ( !minYear || date.getFullYear() >= minYear ) && 2770 ( !maxYear || date.getFullYear() <= maxYear ) ); 2771 }, 2772 2773 /* Provide the configuration settings for formatting/parsing. */ 2774 _getFormatConfig: function( inst ) { 2775 var shortYearCutoff = this._get( inst, "shortYearCutoff" ); 2776 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff : 2777 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) ); 2778 return { shortYearCutoff: shortYearCutoff, 2779 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ), 2780 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) }; 2781 }, 2782 2783 /* Format the given date for display. */ 2784 _formatDate: function( inst, day, month, year ) { 2785 if ( !day ) { 2786 inst.currentDay = inst.selectedDay; 2787 inst.currentMonth = inst.selectedMonth; 2788 inst.currentYear = inst.selectedYear; 2789 } 2790 var date = ( day ? ( typeof day === "object" ? day : 2791 this._daylightSavingAdjust( new Date( year, month, day ) ) ) : 2792 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 2793 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) ); 2794 } 2795} ); 2796 2797/* 2798 * Bind hover events for datepicker elements. 2799 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 2800 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 2801 */ 2802function datepicker_bindHover( dpDiv ) { 2803 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 2804 return dpDiv.on( "mouseout", selector, function() { 2805 $( this ).removeClass( "ui-state-hover" ); 2806 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 2807 $( this ).removeClass( "ui-datepicker-prev-hover" ); 2808 } 2809 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 2810 $( this ).removeClass( "ui-datepicker-next-hover" ); 2811 } 2812 } ) 2813 .on( "mouseover", selector, datepicker_handleMouseover ); 2814} 2815 2816function datepicker_handleMouseover() { 2817 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 2818 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" ); 2819 $( this ).addClass( "ui-state-hover" ); 2820 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 2821 $( this ).addClass( "ui-datepicker-prev-hover" ); 2822 } 2823 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 2824 $( this ).addClass( "ui-datepicker-next-hover" ); 2825 } 2826 } 2827} 2828 2829/* jQuery extend now ignores nulls! */ 2830function datepicker_extendRemove( target, props ) { 2831 $.extend( target, props ); 2832 for ( var name in props ) { 2833 if ( props[ name ] == null ) { 2834 target[ name ] = props[ name ]; 2835 } 2836 } 2837 return target; 2838} 2839 2840/* Invoke the datepicker functionality. 2841 @param options string - a command, optionally followed by additional parameters or 2842 Object - settings for attaching new datepicker functionality 2843 @return jQuery object */ 2844$.fn.datepicker = function( options ) { 2845 2846 /* Verify an empty collection wasn't passed - Fixes #6976 */ 2847 if ( !this.length ) { 2848 return this; 2849 } 2850 2851 /* Initialise the date picker. */ 2852 if ( !$.datepicker.initialized ) { 2853 $( document ).on( "mousedown", $.datepicker._checkExternalClick ); 2854 $.datepicker.initialized = true; 2855 } 2856 2857 /* Append datepicker main container to body if not exist. */ 2858 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) { 2859 $( "body" ).append( $.datepicker.dpDiv ); 2860 } 2861 2862 var otherArgs = Array.prototype.slice.call( arguments, 1 ); 2863 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) { 2864 return $.datepicker[ "_" + options + "Datepicker" ]. 2865 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 2866 } 2867 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) { 2868 return $.datepicker[ "_" + options + "Datepicker" ]. 2869 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 2870 } 2871 return this.each( function() { 2872 typeof options === "string" ? 2873 $.datepicker[ "_" + options + "Datepicker" ]. 2874 apply( $.datepicker, [ this ].concat( otherArgs ) ) : 2875 $.datepicker._attachDatepicker( this, options ); 2876 } ); 2877}; 2878 2879$.datepicker = new Datepicker(); // singleton instance 2880$.datepicker.initialized = false; 2881$.datepicker.uuid = new Date().getTime(); 2882$.datepicker.version = "1.12.1"; 2883 2884var widgetsDatepicker = $.datepicker; 2885 2886 2887 2888
2889}));
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.