Bug 14862: Upgrade jQuery from 1.7 to 3.4.1 in OPAC
[koha.git] / koha-tmpl / opac-tmpl / bootstrap / lib / jquery / jquery-ui-1.12.1.js
blob3c9f3eae852132f3b5e303204bae2f61022cbc4c
1 /*! jQuery UI - v1.12.1 - 2019-08-16
2 * http://jqueryui.com
3 * Includes: widget.js, position.js, data.js, keycode.js, scroll-parent.js, unique-id.js, widgets/sortable.js, widgets/autocomplete.js, widgets/datepicker.js, widgets/menu.js, widgets/mouse.js, widgets/slider.js, widgets/tabs.js, widgets/tooltip.js
4 * Copyright jQuery Foundation and other contributors; Licensed MIT */
6 (function( factory ) {
7         if ( typeof define === "function" && define.amd ) {
9                 // AMD. Register as an anonymous module.
10                 define([ "jquery" ], factory );
11         } else {
13                 // Browser globals
14                 factory( jQuery );
15         }
16 }(function( $ ) {
18 $.ui = $.ui || {};
20 var version = $.ui.version = "1.12.1";
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  */
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/
40 var widgetUuid = 0;
41 var widgetSlice = Array.prototype.slice;
43 $.cleanData = ( function( orig ) {
44         return function( elems ) {
45                 var events, elem, i;
46                 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
47                         try {
49                                 // Only trigger remove when necessary to save time
50                                 events = $._data( elem, "events" );
51                                 if ( events && events.remove ) {
52                                         $( elem ).triggerHandler( "remove" );
53                                 }
55                         // Http://bugs.jquery.com/ticket/8235
56                         } catch ( e ) {}
57                 }
58                 orig( elems );
59         };
60 } )( $.cleanData );
62 $.widget = function( name, base, prototype ) {
63         var existingConstructor, constructor, basePrototype;
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 = {};
69         var namespace = name.split( "." )[ 0 ];
70         name = name.split( "." )[ 1 ];
71         var fullName = namespace + "-" + name;
73         if ( !prototype ) {
74                 prototype = base;
75                 base = $.Widget;
76         }
78         if ( $.isArray( prototype ) ) {
79                 prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
80         }
82         // Create selector for plugin
83         $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
84                 return !!$.data( elem, fullName );
85         };
87         $[ namespace ] = $[ namespace ] || {};
88         existingConstructor = $[ namespace ][ name ];
89         constructor = $[ namespace ][ name ] = function( options, element ) {
91                 // Allow instantiation without "new" keyword
92                 if ( !this._createWidget ) {
93                         return new constructor( options, element );
94                 }
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         };
103         // Extend with the existing constructor to carry over any static properties
104         $.extend( constructor, existingConstructor, {
105                 version: prototype.version,
107                 // Copy the object used to create the prototype in case we need to
108                 // redefine the widget later
109                 _proto: $.extend( {}, prototype ),
111                 // Track widgets that inherit from this widget in case this widget is
112                 // redefined after a widget inherits from it
113                 _childConstructors: []
114         } );
116         basePrototype = new base();
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                         }
132                         function _superApply( args ) {
133                                 return base.prototype[ prop ].apply( this, args );
134                         }
136                         return function() {
137                                 var __super = this._super;
138                                 var __superApply = this._superApply;
139                                 var returnValue;
141                                 this._super = _super;
142                                 this._superApply = _superApply;
144                                 returnValue = value.apply( this, arguments );
146                                 this._super = __super;
147                                 this._superApply = __superApply;
149                                 return returnValue;
150                         };
151                 } )();
152         } );
153         constructor.prototype = $.widget.extend( basePrototype, {
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         } );
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;
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                 } );
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         }
187         $.widget.bridge( name, constructor );
189         return constructor;
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;
199         for ( ; inputIndex < inputLength; inputIndex++ ) {
200                 for ( key in input[ inputIndex ] ) {
201                         value = input[ inputIndex ][ key ];
202                         if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
204                                 // Clone objects
205                                 if ( $.isPlainObject( value ) ) {
206                                         target[ key ] = $.isPlainObject( target[ key ] ) ?
207                                                 $.widget.extend( {}, target[ key ], value ) :
209                                                 // Don't extend strings, arrays, etc. with objects
210                                                 $.widget.extend( {}, value );
212                                 // Copy everything else by reference
213                                 } else {
214                                         target[ key ] = value;
215                                 }
216                         }
217                 }
218         }
219         return target;
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;
229                 if ( isMethodCall ) {
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 );
240                                         if ( options === "instance" ) {
241                                                 returnValue = instance;
242                                                 return false;
243                                         }
245                                         if ( !instance ) {
246                                                 return $.error( "cannot call methods on " + name +
247                                                         " prior to initialization; " +
248                                                         "attempted to call method '" + options + "'" );
249                                         }
251                                         if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
252                                                 return $.error( "no such method '" + options + "' for " + name +
253                                                         " widget instance" );
254                                         }
256                                         methodValue = instance[ options ].apply( instance, args );
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 {
268                         // Allow multiple hashes to be passed on init
269                         if ( args.length ) {
270                                 options = $.widget.extend.apply( null, [ options ].concat( args ) );
271                         }
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                 }
286                 return returnValue;
287         };
290 $.Widget = function( /* options, element */ ) {};
291 $.Widget._childConstructors = [];
293 $.Widget.prototype = {
294         widgetName: "widget",
295         widgetEventPrefix: "",
296         defaultElement: "<div>",
298         options: {
299                 classes: {},
300                 disabled: false,
302                 // Callbacks
303                 create: null
304         },
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;
312                 this.bindings = $();
313                 this.hoverable = $();
314                 this.focusable = $();
315                 this.classesElementLookup = {};
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 ?
328                                 // Element within the document
329                                 element.ownerDocument :
331                                 // Element is window or document
332                                 element.document || element );
333                         this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
334                 }
336                 this.options = $.widget.extend( {},
337                         this.options,
338                         this._getCreateOptions(),
339                         options );
341                 this._create();
343                 if ( this.options.disabled ) {
344                         this._setOptionDisabled( this.options.disabled );
345                 }
347                 this._trigger( "create", null, this._getCreateEventData() );
348                 this._init();
349         },
351         _getCreateOptions: function() {
352                 return {};
353         },
355         _getCreateEventData: $.noop,
357         _create: $.noop,
359         _init: $.noop,
361         destroy: function() {
362                 var that = this;
364                 this._destroy();
365                 $.each( this.classesElementLookup, function( key, value ) {
366                         that._removeClass( value, key );
367                 } );
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" );
378                 // Clean up events and states
379                 this.bindings.off( this.eventNamespace );
380         },
382         _destroy: $.noop,
384         widget: function() {
385                 return this.element;
386         },
388         option: function( key, value ) {
389                 var options = key;
390                 var parts;
391                 var curOption;
392                 var i;
394                 if ( arguments.length === 0 ) {
396                         // Don't return a reference to the internal hash
397                         return $.widget.extend( {}, this.options );
398                 }
400                 if ( typeof key === "string" ) {
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                 }
425                 this._setOptions( options );
427                 return this;
428         },
430         _setOptions: function( options ) {
431                 var key;
433                 for ( key in options ) {
434                         this._setOption( key, options[ key ] );
435                 }
437                 return this;
438         },
440         _setOption: function( key, value ) {
441                 if ( key === "classes" ) {
442                         this._setOptionClasses( value );
443                 }
445                 this.options[ key ] = value;
447                 if ( key === "disabled" ) {
448                         this._setOptionDisabled( value );
449                 }
451                 return this;
452         },
454         _setOptionClasses: function( value ) {
455                 var classKey, elements, currentElements;
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                         }
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 );
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         },
485         _setOptionDisabled: function( value ) {
486                 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
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         },
495         enable: function() {
496                 return this._setOptions( { disabled: false } );
497         },
499         disable: function() {
500                 return this._setOptions( { disabled: true } );
501         },
503         _classes: function( options ) {
504                 var full = [];
505                 var that = this;
507                 options = $.extend( {
508                         element: this.element,
509                         classes: this.options.classes || {}
510                 }, options );
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                 }
529                 this._on( options.element, {
530                         "remove": "_untrackClassesElement"
531                 } );
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                 }
540                 return full.join( " " );
541         },
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         },
552         _removeClass: function( element, keys, extra ) {
553                 return this._toggleClass( element, keys, extra, false );
554         },
556         _addClass: function( element, keys, extra ) {
557                 return this._toggleClass( element, keys, extra, true );
558         },
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         },
573         _on: function( suppressDisabledCheck, element, handlers ) {
574                 var delegateElement;
575                 var instance = this;
577                 // No suppressDisabledCheck flag, shuffle arguments
578                 if ( typeof suppressDisabledCheck !== "boolean" ) {
579                         handlers = element;
580                         element = suppressDisabledCheck;
581                         suppressDisabledCheck = false;
582                 }
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                 }
594                 $.each( handlers, function( event, handler ) {
595                         function handlerProxy() {
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                         }
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                         }
615                         var match = event.match( /^([\w:-]*)\s*(.*)$/ );
616                         var eventName = match[ 1 ] + instance.eventNamespace;
617                         var selector = match[ 2 ];
619                         if ( selector ) {
620                                 delegateElement.on( eventName, selector, handlerProxy );
621                         } else {
622                                 element.on( eventName, handlerProxy );
623                         }
624                 } );
625         },
627         _off: function( element, eventName ) {
628                 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
629                         this.eventNamespace;
630                 element.off( eventName ).off( eventName );
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         },
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         },
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         },
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         },
671         _trigger: function( type, event, data ) {
672                 var prop, orig;
673                 var callback = this.options[ type ];
675                 data = data || {};
676                 event = $.Event( event );
677                 event.type = ( type === this.widgetEventPrefix ?
678                         type :
679                         this.widgetEventPrefix + type ).toLowerCase();
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 ];
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                 }
695                 this.element.trigger( event, data );
696                 return !( $.isFunction( callback ) &&
697                         callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
698                         event.isDefaultPrevented() );
699         }
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                 }
708                 var hasOptions;
709                 var effectName = !options ?
710                         method :
711                         options === true || typeof options === "number" ?
712                                 defaultEffect :
713                                 options.effect || defaultEffect;
715                 options = options || {};
716                 if ( typeof options === "number" ) {
717                         options = { duration: options };
718                 }
720                 hasOptions = !$.isEmptyObject( options );
721                 options.complete = callback;
723                 if ( options.delay ) {
724                         element.delay( options.delay );
725                 }
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 } );
743 var widget = $.widget;
747  * jQuery UI Position 1.12.1
748  * http://jqueryui.com
750  * Copyright jQuery Foundation and other contributors
751  * Released under the MIT license.
752  * http://jquery.org/license
754  * http://api.jqueryui.com/position/
755  */
757 //>>label: Position
758 //>>group: Core
759 //>>description: Positions elements relative to other elements.
760 //>>docs: http://api.jqueryui.com/position/
761 //>>demos: http://jqueryui.com/position/
764 ( function() {
765 var cachedScrollbarWidth,
766         max = Math.max,
767         abs = Math.abs,
768         rhorizontal = /left|center|right/,
769         rvertical = /top|center|bottom/,
770         roffset = /[\+\-]\d+(\.[\d]+)?%?/,
771         rposition = /^\w+/,
772         rpercent = /%$/,
773         _position = $.fn.position;
775 function getOffsets( offsets, width, height ) {
776         return [
777                 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
778                 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
779         ];
782 function parseCss( element, property ) {
783         return parseInt( $.css( element, property ), 10 ) || 0;
786 function getDimensions( elem ) {
787         var raw = elem[ 0 ];
788         if ( raw.nodeType === 9 ) {
789                 return {
790                         width: elem.width(),
791                         height: elem.height(),
792                         offset: { top: 0, left: 0 }
793                 };
794         }
795         if ( $.isWindow( raw ) ) {
796                 return {
797                         width: elem.width(),
798                         height: elem.height(),
799                         offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
800                 };
801         }
802         if ( raw.preventDefault ) {
803                 return {
804                         width: 0,
805                         height: 0,
806                         offset: { top: raw.pageY, left: raw.pageX }
807                 };
808         }
809         return {
810                 width: elem.outerWidth(),
811                 height: elem.outerHeight(),
812                 offset: elem.offset()
813         };
816 $.position = {
817         scrollbarWidth: function() {
818                 if ( cachedScrollbarWidth !== undefined ) {
819                         return cachedScrollbarWidth;
820                 }
821                 var w1, w2,
822                         div = $( "<div " +
823                                 "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
824                                 "<div style='height:100px;width:auto;'></div></div>" ),
825                         innerDiv = div.children()[ 0 ];
827                 $( "body" ).append( div );
828                 w1 = innerDiv.offsetWidth;
829                 div.css( "overflow", "scroll" );
831                 w2 = innerDiv.offsetWidth;
833                 if ( w1 === w2 ) {
834                         w2 = div[ 0 ].clientWidth;
835                 }
837                 div.remove();
839                 return ( cachedScrollbarWidth = w1 - w2 );
840         },
841         getScrollInfo: function( within ) {
842                 var overflowX = within.isWindow || within.isDocument ? "" :
843                                 within.element.css( "overflow-x" ),
844                         overflowY = within.isWindow || within.isDocument ? "" :
845                                 within.element.css( "overflow-y" ),
846                         hasOverflowX = overflowX === "scroll" ||
847                                 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
848                         hasOverflowY = overflowY === "scroll" ||
849                                 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
850                 return {
851                         width: hasOverflowY ? $.position.scrollbarWidth() : 0,
852                         height: hasOverflowX ? $.position.scrollbarWidth() : 0
853                 };
854         },
855         getWithinInfo: function( element ) {
856                 var withinElement = $( element || window ),
857                         isWindow = $.isWindow( withinElement[ 0 ] ),
858                         isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
859                         hasOffset = !isWindow && !isDocument;
860                 return {
861                         element: withinElement,
862                         isWindow: isWindow,
863                         isDocument: isDocument,
864                         offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
865                         scrollLeft: withinElement.scrollLeft(),
866                         scrollTop: withinElement.scrollTop(),
867                         width: withinElement.outerWidth(),
868                         height: withinElement.outerHeight()
869                 };
870         }
873 $.fn.position = function( options ) {
874         if ( !options || !options.of ) {
875                 return _position.apply( this, arguments );
876         }
878         // Make a copy, we don't want to modify arguments
879         options = $.extend( {}, options );
881         var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
882                 target = $( options.of ),
883                 within = $.position.getWithinInfo( options.within ),
884                 scrollInfo = $.position.getScrollInfo( within ),
885                 collision = ( options.collision || "flip" ).split( " " ),
886                 offsets = {};
888         dimensions = getDimensions( target );
889         if ( target[ 0 ].preventDefault ) {
891                 // Force left top to allow flipping
892                 options.at = "left top";
893         }
894         targetWidth = dimensions.width;
895         targetHeight = dimensions.height;
896         targetOffset = dimensions.offset;
898         // Clone to reuse original targetOffset later
899         basePosition = $.extend( {}, targetOffset );
901         // Force my and at to have valid horizontal and vertical positions
902         // if a value is missing or invalid, it will be converted to center
903         $.each( [ "my", "at" ], function() {
904                 var pos = ( options[ this ] || "" ).split( " " ),
905                         horizontalOffset,
906                         verticalOffset;
908                 if ( pos.length === 1 ) {
909                         pos = rhorizontal.test( pos[ 0 ] ) ?
910                                 pos.concat( [ "center" ] ) :
911                                 rvertical.test( pos[ 0 ] ) ?
912                                         [ "center" ].concat( pos ) :
913                                         [ "center", "center" ];
914                 }
915                 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
916                 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
918                 // Calculate offsets
919                 horizontalOffset = roffset.exec( pos[ 0 ] );
920                 verticalOffset = roffset.exec( pos[ 1 ] );
921                 offsets[ this ] = [
922                         horizontalOffset ? horizontalOffset[ 0 ] : 0,
923                         verticalOffset ? verticalOffset[ 0 ] : 0
924                 ];
926                 // Reduce to just the positions without the offsets
927                 options[ this ] = [
928                         rposition.exec( pos[ 0 ] )[ 0 ],
929                         rposition.exec( pos[ 1 ] )[ 0 ]
930                 ];
931         } );
933         // Normalize collision option
934         if ( collision.length === 1 ) {
935                 collision[ 1 ] = collision[ 0 ];
936         }
938         if ( options.at[ 0 ] === "right" ) {
939                 basePosition.left += targetWidth;
940         } else if ( options.at[ 0 ] === "center" ) {
941                 basePosition.left += targetWidth / 2;
942         }
944         if ( options.at[ 1 ] === "bottom" ) {
945                 basePosition.top += targetHeight;
946         } else if ( options.at[ 1 ] === "center" ) {
947                 basePosition.top += targetHeight / 2;
948         }
950         atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
951         basePosition.left += atOffset[ 0 ];
952         basePosition.top += atOffset[ 1 ];
954         return this.each( function() {
955                 var collisionPosition, using,
956                         elem = $( this ),
957                         elemWidth = elem.outerWidth(),
958                         elemHeight = elem.outerHeight(),
959                         marginLeft = parseCss( this, "marginLeft" ),
960                         marginTop = parseCss( this, "marginTop" ),
961                         collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
962                                 scrollInfo.width,
963                         collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
964                                 scrollInfo.height,
965                         position = $.extend( {}, basePosition ),
966                         myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
968                 if ( options.my[ 0 ] === "right" ) {
969                         position.left -= elemWidth;
970                 } else if ( options.my[ 0 ] === "center" ) {
971                         position.left -= elemWidth / 2;
972                 }
974                 if ( options.my[ 1 ] === "bottom" ) {
975                         position.top -= elemHeight;
976                 } else if ( options.my[ 1 ] === "center" ) {
977                         position.top -= elemHeight / 2;
978                 }
980                 position.left += myOffset[ 0 ];
981                 position.top += myOffset[ 1 ];
983                 collisionPosition = {
984                         marginLeft: marginLeft,
985                         marginTop: marginTop
986                 };
988                 $.each( [ "left", "top" ], function( i, dir ) {
989                         if ( $.ui.position[ collision[ i ] ] ) {
990                                 $.ui.position[ collision[ i ] ][ dir ]( position, {
991                                         targetWidth: targetWidth,
992                                         targetHeight: targetHeight,
993                                         elemWidth: elemWidth,
994                                         elemHeight: elemHeight,
995                                         collisionPosition: collisionPosition,
996                                         collisionWidth: collisionWidth,
997                                         collisionHeight: collisionHeight,
998                                         offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
999                                         my: options.my,
1000                                         at: options.at,
1001                                         within: within,
1002                                         elem: elem
1003                                 } );
1004                         }
1005                 } );
1007                 if ( options.using ) {
1009                         // Adds feedback as second argument to using callback, if present
1010                         using = function( props ) {
1011                                 var left = targetOffset.left - position.left,
1012                                         right = left + targetWidth - elemWidth,
1013                                         top = targetOffset.top - position.top,
1014                                         bottom = top + targetHeight - elemHeight,
1015                                         feedback = {
1016                                                 target: {
1017                                                         element: target,
1018                                                         left: targetOffset.left,
1019                                                         top: targetOffset.top,
1020                                                         width: targetWidth,
1021                                                         height: targetHeight
1022                                                 },
1023                                                 element: {
1024                                                         element: elem,
1025                                                         left: position.left,
1026                                                         top: position.top,
1027                                                         width: elemWidth,
1028                                                         height: elemHeight
1029                                                 },
1030                                                 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1031                                                 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1032                                         };
1033                                 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1034                                         feedback.horizontal = "center";
1035                                 }
1036                                 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1037                                         feedback.vertical = "middle";
1038                                 }
1039                                 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1040                                         feedback.important = "horizontal";
1041                                 } else {
1042                                         feedback.important = "vertical";
1043                                 }
1044                                 options.using.call( this, props, feedback );
1045                         };
1046                 }
1048                 elem.offset( $.extend( position, { using: using } ) );
1049         } );
1052 $.ui.position = {
1053         fit: {
1054                 left: function( position, data ) {
1055                         var within = data.within,
1056                                 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1057                                 outerWidth = within.width,
1058                                 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1059                                 overLeft = withinOffset - collisionPosLeft,
1060                                 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1061                                 newOverRight;
1063                         // Element is wider than within
1064                         if ( data.collisionWidth > outerWidth ) {
1066                                 // Element is initially over the left side of within
1067                                 if ( overLeft > 0 && overRight <= 0 ) {
1068                                         newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
1069                                                 withinOffset;
1070                                         position.left += overLeft - newOverRight;
1072                                 // Element is initially over right side of within
1073                                 } else if ( overRight > 0 && overLeft <= 0 ) {
1074                                         position.left = withinOffset;
1076                                 // Element is initially over both left and right sides of within
1077                                 } else {
1078                                         if ( overLeft > overRight ) {
1079                                                 position.left = withinOffset + outerWidth - data.collisionWidth;
1080                                         } else {
1081                                                 position.left = withinOffset;
1082                                         }
1083                                 }
1085                         // Too far left -> align with left edge
1086                         } else if ( overLeft > 0 ) {
1087                                 position.left += overLeft;
1089                         // Too far right -> align with right edge
1090                         } else if ( overRight > 0 ) {
1091                                 position.left -= overRight;
1093                         // Adjust based on position and margin
1094                         } else {
1095                                 position.left = max( position.left - collisionPosLeft, position.left );
1096                         }
1097                 },
1098                 top: function( position, data ) {
1099                         var within = data.within,
1100                                 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1101                                 outerHeight = data.within.height,
1102                                 collisionPosTop = position.top - data.collisionPosition.marginTop,
1103                                 overTop = withinOffset - collisionPosTop,
1104                                 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1105                                 newOverBottom;
1107                         // Element is taller than within
1108                         if ( data.collisionHeight > outerHeight ) {
1110                                 // Element is initially over the top of within
1111                                 if ( overTop > 0 && overBottom <= 0 ) {
1112                                         newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
1113                                                 withinOffset;
1114                                         position.top += overTop - newOverBottom;
1116                                 // Element is initially over bottom of within
1117                                 } else if ( overBottom > 0 && overTop <= 0 ) {
1118                                         position.top = withinOffset;
1120                                 // Element is initially over both top and bottom of within
1121                                 } else {
1122                                         if ( overTop > overBottom ) {
1123                                                 position.top = withinOffset + outerHeight - data.collisionHeight;
1124                                         } else {
1125                                                 position.top = withinOffset;
1126                                         }
1127                                 }
1129                         // Too far up -> align with top
1130                         } else if ( overTop > 0 ) {
1131                                 position.top += overTop;
1133                         // Too far down -> align with bottom edge
1134                         } else if ( overBottom > 0 ) {
1135                                 position.top -= overBottom;
1137                         // Adjust based on position and margin
1138                         } else {
1139                                 position.top = max( position.top - collisionPosTop, position.top );
1140                         }
1141                 }
1142         },
1143         flip: {
1144                 left: function( position, data ) {
1145                         var within = data.within,
1146                                 withinOffset = within.offset.left + within.scrollLeft,
1147                                 outerWidth = within.width,
1148                                 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1149                                 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1150                                 overLeft = collisionPosLeft - offsetLeft,
1151                                 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1152                                 myOffset = data.my[ 0 ] === "left" ?
1153                                         -data.elemWidth :
1154                                         data.my[ 0 ] === "right" ?
1155                                                 data.elemWidth :
1156                                                 0,
1157                                 atOffset = data.at[ 0 ] === "left" ?
1158                                         data.targetWidth :
1159                                         data.at[ 0 ] === "right" ?
1160                                                 -data.targetWidth :
1161                                                 0,
1162                                 offset = -2 * data.offset[ 0 ],
1163                                 newOverRight,
1164                                 newOverLeft;
1166                         if ( overLeft < 0 ) {
1167                                 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
1168                                         outerWidth - withinOffset;
1169                                 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1170                                         position.left += myOffset + atOffset + offset;
1171                                 }
1172                         } else if ( overRight > 0 ) {
1173                                 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
1174                                         atOffset + offset - offsetLeft;
1175                                 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1176                                         position.left += myOffset + atOffset + offset;
1177                                 }
1178                         }
1179                 },
1180                 top: function( position, data ) {
1181                         var within = data.within,
1182                                 withinOffset = within.offset.top + within.scrollTop,
1183                                 outerHeight = within.height,
1184                                 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1185                                 collisionPosTop = position.top - data.collisionPosition.marginTop,
1186                                 overTop = collisionPosTop - offsetTop,
1187                                 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1188                                 top = data.my[ 1 ] === "top",
1189                                 myOffset = top ?
1190                                         -data.elemHeight :
1191                                         data.my[ 1 ] === "bottom" ?
1192                                                 data.elemHeight :
1193                                                 0,
1194                                 atOffset = data.at[ 1 ] === "top" ?
1195                                         data.targetHeight :
1196                                         data.at[ 1 ] === "bottom" ?
1197                                                 -data.targetHeight :
1198                                                 0,
1199                                 offset = -2 * data.offset[ 1 ],
1200                                 newOverTop,
1201                                 newOverBottom;
1202                         if ( overTop < 0 ) {
1203                                 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
1204                                         outerHeight - withinOffset;
1205                                 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1206                                         position.top += myOffset + atOffset + offset;
1207                                 }
1208                         } else if ( overBottom > 0 ) {
1209                                 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
1210                                         offset - offsetTop;
1211                                 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1212                                         position.top += myOffset + atOffset + offset;
1213                                 }
1214                         }
1215                 }
1216         },
1217         flipfit: {
1218                 left: function() {
1219                         $.ui.position.flip.left.apply( this, arguments );
1220                         $.ui.position.fit.left.apply( this, arguments );
1221                 },
1222                 top: function() {
1223                         $.ui.position.flip.top.apply( this, arguments );
1224                         $.ui.position.fit.top.apply( this, arguments );
1225                 }
1226         }
1229 } )();
1231 var position = $.ui.position;
1235  * jQuery UI :data 1.12.1
1236  * http://jqueryui.com
1238  * Copyright jQuery Foundation and other contributors
1239  * Released under the MIT license.
1240  * http://jquery.org/license
1241  */
1243 //>>label: :data Selector
1244 //>>group: Core
1245 //>>description: Selects elements which have data stored under the specified key.
1246 //>>docs: http://api.jqueryui.com/data-selector/
1249 var data = $.extend( $.expr[ ":" ], {
1250         data: $.expr.createPseudo ?
1251                 $.expr.createPseudo( function( dataName ) {
1252                         return function( elem ) {
1253                                 return !!$.data( elem, dataName );
1254                         };
1255                 } ) :
1257                 // Support: jQuery <1.8
1258                 function( elem, i, match ) {
1259                         return !!$.data( elem, match[ 3 ] );
1260                 }
1261 } );
1264  * jQuery UI Keycode 1.12.1
1265  * http://jqueryui.com
1267  * Copyright jQuery Foundation and other contributors
1268  * Released under the MIT license.
1269  * http://jquery.org/license
1270  */
1272 //>>label: Keycode
1273 //>>group: Core
1274 //>>description: Provide keycodes as keynames
1275 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
1278 var keycode = $.ui.keyCode = {
1279         BACKSPACE: 8,
1280         COMMA: 188,
1281         DELETE: 46,
1282         DOWN: 40,
1283         END: 35,
1284         ENTER: 13,
1285         ESCAPE: 27,
1286         HOME: 36,
1287         LEFT: 37,
1288         PAGE_DOWN: 34,
1289         PAGE_UP: 33,
1290         PERIOD: 190,
1291         RIGHT: 39,
1292         SPACE: 32,
1293         TAB: 9,
1294         UP: 38
1299  * jQuery UI Scroll Parent 1.12.1
1300  * http://jqueryui.com
1302  * Copyright jQuery Foundation and other contributors
1303  * Released under the MIT license.
1304  * http://jquery.org/license
1305  */
1307 //>>label: scrollParent
1308 //>>group: Core
1309 //>>description: Get the closest ancestor element that is scrollable.
1310 //>>docs: http://api.jqueryui.com/scrollParent/
1314 var scrollParent = $.fn.scrollParent = function( includeHidden ) {
1315         var position = this.css( "position" ),
1316                 excludeStaticParent = position === "absolute",
1317                 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
1318                 scrollParent = this.parents().filter( function() {
1319                         var parent = $( this );
1320                         if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
1321                                 return false;
1322                         }
1323                         return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
1324                                 parent.css( "overflow-x" ) );
1325                 } ).eq( 0 );
1327         return position === "fixed" || !scrollParent.length ?
1328                 $( this[ 0 ].ownerDocument || document ) :
1329                 scrollParent;
1334  * jQuery UI Unique ID 1.12.1
1335  * http://jqueryui.com
1337  * Copyright jQuery Foundation and other contributors
1338  * Released under the MIT license.
1339  * http://jquery.org/license
1340  */
1342 //>>label: uniqueId
1343 //>>group: Core
1344 //>>description: Functions to generate and remove uniqueId's
1345 //>>docs: http://api.jqueryui.com/uniqueId/
1349 var uniqueId = $.fn.extend( {
1350         uniqueId: ( function() {
1351                 var uuid = 0;
1353                 return function() {
1354                         return this.each( function() {
1355                                 if ( !this.id ) {
1356                                         this.id = "ui-id-" + ( ++uuid );
1357                                 }
1358                         } );
1359                 };
1360         } )(),
1362         removeUniqueId: function() {
1363                 return this.each( function() {
1364                         if ( /^ui-id-\d+$/.test( this.id ) ) {
1365                                 $( this ).removeAttr( "id" );
1366                         }
1367                 } );
1368         }
1369 } );
1374 // This file is deprecated
1375 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
1378  * jQuery UI Mouse 1.12.1
1379  * http://jqueryui.com
1381  * Copyright jQuery Foundation and other contributors
1382  * Released under the MIT license.
1383  * http://jquery.org/license
1384  */
1386 //>>label: Mouse
1387 //>>group: Widgets
1388 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
1389 //>>docs: http://api.jqueryui.com/mouse/
1393 var mouseHandled = false;
1394 $( document ).on( "mouseup", function() {
1395         mouseHandled = false;
1396 } );
1398 var widgetsMouse = $.widget( "ui.mouse", {
1399         version: "1.12.1",
1400         options: {
1401                 cancel: "input, textarea, button, select, option",
1402                 distance: 1,
1403                 delay: 0
1404         },
1405         _mouseInit: function() {
1406                 var that = this;
1408                 this.element
1409                         .on( "mousedown." + this.widgetName, function( event ) {
1410                                 return that._mouseDown( event );
1411                         } )
1412                         .on( "click." + this.widgetName, function( event ) {
1413                                 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
1414                                         $.removeData( event.target, that.widgetName + ".preventClickEvent" );
1415                                         event.stopImmediatePropagation();
1416                                         return false;
1417                                 }
1418                         } );
1420                 this.started = false;
1421         },
1423         // TODO: make sure destroying one instance of mouse doesn't mess with
1424         // other instances of mouse
1425         _mouseDestroy: function() {
1426                 this.element.off( "." + this.widgetName );
1427                 if ( this._mouseMoveDelegate ) {
1428                         this.document
1429                                 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1430                                 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
1431                 }
1432         },
1434         _mouseDown: function( event ) {
1436                 // don't let more than one widget handle mouseStart
1437                 if ( mouseHandled ) {
1438                         return;
1439                 }
1441                 this._mouseMoved = false;
1443                 // We may have missed mouseup (out of window)
1444                 ( this._mouseStarted && this._mouseUp( event ) );
1446                 this._mouseDownEvent = event;
1448                 var that = this,
1449                         btnIsLeft = ( event.which === 1 ),
1451                         // event.target.nodeName works around a bug in IE 8 with
1452                         // disabled inputs (#7620)
1453                         elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
1454                                 $( event.target ).closest( this.options.cancel ).length : false );
1455                 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
1456                         return true;
1457                 }
1459                 this.mouseDelayMet = !this.options.delay;
1460                 if ( !this.mouseDelayMet ) {
1461                         this._mouseDelayTimer = setTimeout( function() {
1462                                 that.mouseDelayMet = true;
1463                         }, this.options.delay );
1464                 }
1466                 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
1467                         this._mouseStarted = ( this._mouseStart( event ) !== false );
1468                         if ( !this._mouseStarted ) {
1469                                 event.preventDefault();
1470                                 return true;
1471                         }
1472                 }
1474                 // Click event may never have fired (Gecko & Opera)
1475                 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
1476                         $.removeData( event.target, this.widgetName + ".preventClickEvent" );
1477                 }
1479                 // These delegates are required to keep context
1480                 this._mouseMoveDelegate = function( event ) {
1481                         return that._mouseMove( event );
1482                 };
1483                 this._mouseUpDelegate = function( event ) {
1484                         return that._mouseUp( event );
1485                 };
1487                 this.document
1488                         .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1489                         .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
1491                 event.preventDefault();
1493                 mouseHandled = true;
1494                 return true;
1495         },
1497         _mouseMove: function( event ) {
1499                 // Only check for mouseups outside the document if you've moved inside the document
1500                 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
1501                 // fire a mousemove event if content is placed under the cursor. See #7778
1502                 // Support: IE <9
1503                 if ( this._mouseMoved ) {
1505                         // IE mouseup check - mouseup happened when mouse was out of window
1506                         if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
1507                                         !event.button ) {
1508                                 return this._mouseUp( event );
1510                         // Iframe mouseup check - mouseup occurred in another document
1511                         } else if ( !event.which ) {
1513                                 // Support: Safari <=8 - 9
1514                                 // Safari sets which to 0 if you press any of the following keys
1515                                 // during a drag (#14461)
1516                                 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
1517                                                 event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
1518                                         this.ignoreMissingWhich = true;
1519                                 } else if ( !this.ignoreMissingWhich ) {
1520                                         return this._mouseUp( event );
1521                                 }
1522                         }
1523                 }
1525                 if ( event.which || event.button ) {
1526                         this._mouseMoved = true;
1527                 }
1529                 if ( this._mouseStarted ) {
1530                         this._mouseDrag( event );
1531                         return event.preventDefault();
1532                 }
1534                 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
1535                         this._mouseStarted =
1536                                 ( this._mouseStart( this._mouseDownEvent, event ) !== false );
1537                         ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
1538                 }
1540                 return !this._mouseStarted;
1541         },
1543         _mouseUp: function( event ) {
1544                 this.document
1545                         .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1546                         .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
1548                 if ( this._mouseStarted ) {
1549                         this._mouseStarted = false;
1551                         if ( event.target === this._mouseDownEvent.target ) {
1552                                 $.data( event.target, this.widgetName + ".preventClickEvent", true );
1553                         }
1555                         this._mouseStop( event );
1556                 }
1558                 if ( this._mouseDelayTimer ) {
1559                         clearTimeout( this._mouseDelayTimer );
1560                         delete this._mouseDelayTimer;
1561                 }
1563                 this.ignoreMissingWhich = false;
1564                 mouseHandled = false;
1565                 event.preventDefault();
1566         },
1568         _mouseDistanceMet: function( event ) {
1569                 return ( Math.max(
1570                                 Math.abs( this._mouseDownEvent.pageX - event.pageX ),
1571                                 Math.abs( this._mouseDownEvent.pageY - event.pageY )
1572                         ) >= this.options.distance
1573                 );
1574         },
1576         _mouseDelayMet: function( /* event */ ) {
1577                 return this.mouseDelayMet;
1578         },
1580         // These are placeholder methods, to be overriden by extending plugin
1581         _mouseStart: function( /* event */ ) {},
1582         _mouseDrag: function( /* event */ ) {},
1583         _mouseStop: function( /* event */ ) {},
1584         _mouseCapture: function( /* event */ ) { return true; }
1585 } );
1589  * jQuery UI Sortable 1.12.1
1590  * http://jqueryui.com
1592  * Copyright jQuery Foundation and other contributors
1593  * Released under the MIT license.
1594  * http://jquery.org/license
1595  */
1597 //>>label: Sortable
1598 //>>group: Interactions
1599 //>>description: Enables items in a list to be sorted using the mouse.
1600 //>>docs: http://api.jqueryui.com/sortable/
1601 //>>demos: http://jqueryui.com/sortable/
1602 //>>css.structure: ../../themes/base/sortable.css
1606 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
1607         version: "1.12.1",
1608         widgetEventPrefix: "sort",
1609         ready: false,
1610         options: {
1611                 appendTo: "parent",
1612                 axis: false,
1613                 connectWith: false,
1614                 containment: false,
1615                 cursor: "auto",
1616                 cursorAt: false,
1617                 dropOnEmpty: true,
1618                 forcePlaceholderSize: false,
1619                 forceHelperSize: false,
1620                 grid: false,
1621                 handle: false,
1622                 helper: "original",
1623                 items: "> *",
1624                 opacity: false,
1625                 placeholder: false,
1626                 revert: false,
1627                 scroll: true,
1628                 scrollSensitivity: 20,
1629                 scrollSpeed: 20,
1630                 scope: "default",
1631                 tolerance: "intersect",
1632                 zIndex: 1000,
1634                 // Callbacks
1635                 activate: null,
1636                 beforeStop: null,
1637                 change: null,
1638                 deactivate: null,
1639                 out: null,
1640                 over: null,
1641                 receive: null,
1642                 remove: null,
1643                 sort: null,
1644                 start: null,
1645                 stop: null,
1646                 update: null
1647         },
1649         _isOverAxis: function( x, reference, size ) {
1650                 return ( x >= reference ) && ( x < ( reference + size ) );
1651         },
1653         _isFloating: function( item ) {
1654                 return ( /left|right/ ).test( item.css( "float" ) ) ||
1655                         ( /inline|table-cell/ ).test( item.css( "display" ) );
1656         },
1658         _create: function() {
1659                 this.containerCache = {};
1660                 this._addClass( "ui-sortable" );
1662                 //Get the items
1663                 this.refresh();
1665                 //Let's determine the parent's offset
1666                 this.offset = this.element.offset();
1668                 //Initialize mouse events for interaction
1669                 this._mouseInit();
1671                 this._setHandleClassName();
1673                 //We're ready to go
1674                 this.ready = true;
1676         },
1678         _setOption: function( key, value ) {
1679                 this._super( key, value );
1681                 if ( key === "handle" ) {
1682                         this._setHandleClassName();
1683                 }
1684         },
1686         _setHandleClassName: function() {
1687                 var that = this;
1688                 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
1689                 $.each( this.items, function() {
1690                         that._addClass(
1691                                 this.instance.options.handle ?
1692                                         this.item.find( this.instance.options.handle ) :
1693                                         this.item,
1694                                 "ui-sortable-handle"
1695                         );
1696                 } );
1697         },
1699         _destroy: function() {
1700                 this._mouseDestroy();
1702                 for ( var i = this.items.length - 1; i >= 0; i-- ) {
1703                         this.items[ i ].item.removeData( this.widgetName + "-item" );
1704                 }
1706                 return this;
1707         },
1709         _mouseCapture: function( event, overrideHandle ) {
1710                 var currentItem = null,
1711                         validHandle = false,
1712                         that = this;
1714                 if ( this.reverting ) {
1715                         return false;
1716                 }
1718                 if ( this.options.disabled || this.options.type === "static" ) {
1719                         return false;
1720                 }
1722                 //We have to refresh the items data once first
1723                 this._refreshItems( event );
1725                 //Find out if the clicked node (or one of its parents) is a actual item in this.items
1726                 $( event.target ).parents().each( function() {
1727                         if ( $.data( this, that.widgetName + "-item" ) === that ) {
1728                                 currentItem = $( this );
1729                                 return false;
1730                         }
1731                 } );
1732                 if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
1733                         currentItem = $( event.target );
1734                 }
1736                 if ( !currentItem ) {
1737                         return false;
1738                 }
1739                 if ( this.options.handle && !overrideHandle ) {
1740                         $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
1741                                 if ( this === event.target ) {
1742                                         validHandle = true;
1743                                 }
1744                         } );
1745                         if ( !validHandle ) {
1746                                 return false;
1747                         }
1748                 }
1750                 this.currentItem = currentItem;
1751                 this._removeCurrentsFromItems();
1752                 return true;
1754         },
1756         _mouseStart: function( event, overrideHandle, noActivation ) {
1758                 var i, body,
1759                         o = this.options;
1761                 this.currentContainer = this;
1763                 //We only need to call refreshPositions, because the refreshItems call has been moved to
1764                 // mouseCapture
1765                 this.refreshPositions();
1767                 //Create and append the visible helper
1768                 this.helper = this._createHelper( event );
1770                 //Cache the helper size
1771                 this._cacheHelperProportions();
1773                 /*
1774                  * - Position generation -
1775                  * This block generates everything position related - it's the core of draggables.
1776                  */
1778                 //Cache the margins of the original element
1779                 this._cacheMargins();
1781                 //Get the next scrolling parent
1782                 this.scrollParent = this.helper.scrollParent();
1784                 //The element's absolute position on the page minus margins
1785                 this.offset = this.currentItem.offset();
1786                 this.offset = {
1787                         top: this.offset.top - this.margins.top,
1788                         left: this.offset.left - this.margins.left
1789                 };
1791                 $.extend( this.offset, {
1792                         click: { //Where the click happened, relative to the element
1793                                 left: event.pageX - this.offset.left,
1794                                 top: event.pageY - this.offset.top
1795                         },
1796                         parent: this._getParentOffset(),
1798                         // This is a relative to absolute position minus the actual position calculation -
1799                         // only used for relative positioned helper
1800                         relative: this._getRelativeOffset()
1801                 } );
1803                 // Only after we got the offset, we can change the helper's position to absolute
1804                 // TODO: Still need to figure out a way to make relative sorting possible
1805                 this.helper.css( "position", "absolute" );
1806                 this.cssPosition = this.helper.css( "position" );
1808                 //Generate the original position
1809                 this.originalPosition = this._generatePosition( event );
1810                 this.originalPageX = event.pageX;
1811                 this.originalPageY = event.pageY;
1813                 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
1814                 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
1816                 //Cache the former DOM position
1817                 this.domPosition = {
1818                         prev: this.currentItem.prev()[ 0 ],
1819                         parent: this.currentItem.parent()[ 0 ]
1820                 };
1822                 // If the helper is not the original, hide the original so it's not playing any role during
1823                 // the drag, won't cause anything bad this way
1824                 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
1825                         this.currentItem.hide();
1826                 }
1828                 //Create the placeholder
1829                 this._createPlaceholder();
1831                 //Set a containment if given in the options
1832                 if ( o.containment ) {
1833                         this._setContainment();
1834                 }
1836                 if ( o.cursor && o.cursor !== "auto" ) { // cursor option
1837                         body = this.document.find( "body" );
1839                         // Support: IE
1840                         this.storedCursor = body.css( "cursor" );
1841                         body.css( "cursor", o.cursor );
1843                         this.storedStylesheet =
1844                                 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
1845                 }
1847                 if ( o.opacity ) { // opacity option
1848                         if ( this.helper.css( "opacity" ) ) {
1849                                 this._storedOpacity = this.helper.css( "opacity" );
1850                         }
1851                         this.helper.css( "opacity", o.opacity );
1852                 }
1854                 if ( o.zIndex ) { // zIndex option
1855                         if ( this.helper.css( "zIndex" ) ) {
1856                                 this._storedZIndex = this.helper.css( "zIndex" );
1857                         }
1858                         this.helper.css( "zIndex", o.zIndex );
1859                 }
1861                 //Prepare scrolling
1862                 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1863                                 this.scrollParent[ 0 ].tagName !== "HTML" ) {
1864                         this.overflowOffset = this.scrollParent.offset();
1865                 }
1867                 //Call callbacks
1868                 this._trigger( "start", event, this._uiHash() );
1870                 //Recache the helper size
1871                 if ( !this._preserveHelperProportions ) {
1872                         this._cacheHelperProportions();
1873                 }
1875                 //Post "activate" events to possible containers
1876                 if ( !noActivation ) {
1877                         for ( i = this.containers.length - 1; i >= 0; i-- ) {
1878                                 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
1879                         }
1880                 }
1882                 //Prepare possible droppables
1883                 if ( $.ui.ddmanager ) {
1884                         $.ui.ddmanager.current = this;
1885                 }
1887                 if ( $.ui.ddmanager && !o.dropBehaviour ) {
1888                         $.ui.ddmanager.prepareOffsets( this, event );
1889                 }
1891                 this.dragging = true;
1893                 this._addClass( this.helper, "ui-sortable-helper" );
1895                 // Execute the drag once - this causes the helper not to be visiblebefore getting its
1896                 // correct position
1897                 this._mouseDrag( event );
1898                 return true;
1900         },
1902         _mouseDrag: function( event ) {
1903                 var i, item, itemElement, intersection,
1904                         o = this.options,
1905                         scrolled = false;
1907                 //Compute the helpers position
1908                 this.position = this._generatePosition( event );
1909                 this.positionAbs = this._convertPositionTo( "absolute" );
1911                 if ( !this.lastPositionAbs ) {
1912                         this.lastPositionAbs = this.positionAbs;
1913                 }
1915                 //Do scrolling
1916                 if ( this.options.scroll ) {
1917                         if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1918                                         this.scrollParent[ 0 ].tagName !== "HTML" ) {
1920                                 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
1921                                                 event.pageY < o.scrollSensitivity ) {
1922                                         this.scrollParent[ 0 ].scrollTop =
1923                                                 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
1924                                 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
1925                                         this.scrollParent[ 0 ].scrollTop =
1926                                                 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
1927                                 }
1929                                 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
1930                                                 event.pageX < o.scrollSensitivity ) {
1931                                         this.scrollParent[ 0 ].scrollLeft = scrolled =
1932                                                 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
1933                                 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
1934                                         this.scrollParent[ 0 ].scrollLeft = scrolled =
1935                                                 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
1936                                 }
1938                         } else {
1940                                 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
1941                                         scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
1942                                 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
1943                                                 o.scrollSensitivity ) {
1944                                         scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
1945                                 }
1947                                 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
1948                                         scrolled = this.document.scrollLeft(
1949                                                 this.document.scrollLeft() - o.scrollSpeed
1950                                         );
1951                                 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
1952                                                 o.scrollSensitivity ) {
1953                                         scrolled = this.document.scrollLeft(
1954                                                 this.document.scrollLeft() + o.scrollSpeed
1955                                         );
1956                                 }
1958                         }
1960                         if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
1961                                 $.ui.ddmanager.prepareOffsets( this, event );
1962                         }
1963                 }
1965                 //Regenerate the absolute position used for position checks
1966                 this.positionAbs = this._convertPositionTo( "absolute" );
1968                 //Set the helper position
1969                 if ( !this.options.axis || this.options.axis !== "y" ) {
1970                         this.helper[ 0 ].style.left = this.position.left + "px";
1971                 }
1972                 if ( !this.options.axis || this.options.axis !== "x" ) {
1973                         this.helper[ 0 ].style.top = this.position.top + "px";
1974                 }
1976                 //Rearrange
1977                 for ( i = this.items.length - 1; i >= 0; i-- ) {
1979                         //Cache variables and intersection, continue if no intersection
1980                         item = this.items[ i ];
1981                         itemElement = item.item[ 0 ];
1982                         intersection = this._intersectsWithPointer( item );
1983                         if ( !intersection ) {
1984                                 continue;
1985                         }
1987                         // Only put the placeholder inside the current Container, skip all
1988                         // items from other containers. This works because when moving
1989                         // an item from one container to another the
1990                         // currentContainer is switched before the placeholder is moved.
1991                         //
1992                         // Without this, moving items in "sub-sortables" can cause
1993                         // the placeholder to jitter between the outer and inner container.
1994                         if ( item.instance !== this.currentContainer ) {
1995                                 continue;
1996                         }
1998                         // Cannot intersect with itself
1999                         // no useless actions that have been done before
2000                         // no action if the item moved is the parent of the item checked
2001                         if ( itemElement !== this.currentItem[ 0 ] &&
2002                                 this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
2003                                 !$.contains( this.placeholder[ 0 ], itemElement ) &&
2004                                 ( this.options.type === "semi-dynamic" ?
2005                                         !$.contains( this.element[ 0 ], itemElement ) :
2006                                         true
2007                                 )
2008                         ) {
2010                                 this.direction = intersection === 1 ? "down" : "up";
2012                                 if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
2013                                         this._rearrange( event, item );
2014                                 } else {
2015                                         break;
2016                                 }
2018                                 this._trigger( "change", event, this._uiHash() );
2019                                 break;
2020                         }
2021                 }
2023                 //Post events to containers
2024                 this._contactContainers( event );
2026                 //Interconnect with droppables
2027                 if ( $.ui.ddmanager ) {
2028                         $.ui.ddmanager.drag( this, event );
2029                 }
2031                 //Call callbacks
2032                 this._trigger( "sort", event, this._uiHash() );
2034                 this.lastPositionAbs = this.positionAbs;
2035                 return false;
2037         },
2039         _mouseStop: function( event, noPropagation ) {
2041                 if ( !event ) {
2042                         return;
2043                 }
2045                 //If we are using droppables, inform the manager about the drop
2046                 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
2047                         $.ui.ddmanager.drop( this, event );
2048                 }
2050                 if ( this.options.revert ) {
2051                         var that = this,
2052                                 cur = this.placeholder.offset(),
2053                                 axis = this.options.axis,
2054                                 animation = {};
2056                         if ( !axis || axis === "x" ) {
2057                                 animation.left = cur.left - this.offset.parent.left - this.margins.left +
2058                                         ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
2059                                                 0 :
2060                                                 this.offsetParent[ 0 ].scrollLeft
2061                                         );
2062                         }
2063                         if ( !axis || axis === "y" ) {
2064                                 animation.top = cur.top - this.offset.parent.top - this.margins.top +
2065                                         ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
2066                                                 0 :
2067                                                 this.offsetParent[ 0 ].scrollTop
2068                                         );
2069                         }
2070                         this.reverting = true;
2071                         $( this.helper ).animate(
2072                                 animation,
2073                                 parseInt( this.options.revert, 10 ) || 500,
2074                                 function() {
2075                                         that._clear( event );
2076                                 }
2077                         );
2078                 } else {
2079                         this._clear( event, noPropagation );
2080                 }
2082                 return false;
2084         },
2086         cancel: function() {
2088                 if ( this.dragging ) {
2090                         this._mouseUp( new $.Event( "mouseup", { target: null } ) );
2092                         if ( this.options.helper === "original" ) {
2093                                 this.currentItem.css( this._storedCSS );
2094                                 this._removeClass( this.currentItem, "ui-sortable-helper" );
2095                         } else {
2096                                 this.currentItem.show();
2097                         }
2099                         //Post deactivating events to containers
2100                         for ( var i = this.containers.length - 1; i >= 0; i-- ) {
2101                                 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
2102                                 if ( this.containers[ i ].containerCache.over ) {
2103                                         this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
2104                                         this.containers[ i ].containerCache.over = 0;
2105                                 }
2106                         }
2108                 }
2110                 if ( this.placeholder ) {
2112                         //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
2113                         // it unbinds ALL events from the original node!
2114                         if ( this.placeholder[ 0 ].parentNode ) {
2115                                 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
2116                         }
2117                         if ( this.options.helper !== "original" && this.helper &&
2118                                         this.helper[ 0 ].parentNode ) {
2119                                 this.helper.remove();
2120                         }
2122                         $.extend( this, {
2123                                 helper: null,
2124                                 dragging: false,
2125                                 reverting: false,
2126                                 _noFinalSort: null
2127                         } );
2129                         if ( this.domPosition.prev ) {
2130                                 $( this.domPosition.prev ).after( this.currentItem );
2131                         } else {
2132                                 $( this.domPosition.parent ).prepend( this.currentItem );
2133                         }
2134                 }
2136                 return this;
2138         },
2140         serialize: function( o ) {
2142                 var items = this._getItemsAsjQuery( o && o.connected ),
2143                         str = [];
2144                 o = o || {};
2146                 $( items ).each( function() {
2147                         var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
2148                                 .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
2149                         if ( res ) {
2150                                 str.push(
2151                                         ( o.key || res[ 1 ] + "[]" ) +
2152                                         "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
2153                         }
2154                 } );
2156                 if ( !str.length && o.key ) {
2157                         str.push( o.key + "=" );
2158                 }
2160                 return str.join( "&" );
2162         },
2164         toArray: function( o ) {
2166                 var items = this._getItemsAsjQuery( o && o.connected ),
2167                         ret = [];
2169                 o = o || {};
2171                 items.each( function() {
2172                         ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
2173                 } );
2174                 return ret;
2176         },
2178         /* Be careful with the following core functions */
2179         _intersectsWith: function( item ) {
2181                 var x1 = this.positionAbs.left,
2182                         x2 = x1 + this.helperProportions.width,
2183                         y1 = this.positionAbs.top,
2184                         y2 = y1 + this.helperProportions.height,
2185                         l = item.left,
2186                         r = l + item.width,
2187                         t = item.top,
2188                         b = t + item.height,
2189                         dyClick = this.offset.click.top,
2190                         dxClick = this.offset.click.left,
2191                         isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
2192                                 ( y1 + dyClick ) < b ),
2193                         isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
2194                                 ( x1 + dxClick ) < r ),
2195                         isOverElement = isOverElementHeight && isOverElementWidth;
2197                 if ( this.options.tolerance === "pointer" ||
2198                         this.options.forcePointerForContainers ||
2199                         ( this.options.tolerance !== "pointer" &&
2200                                 this.helperProportions[ this.floating ? "width" : "height" ] >
2201                                 item[ this.floating ? "width" : "height" ] )
2202                 ) {
2203                         return isOverElement;
2204                 } else {
2206                         return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
2207                                 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
2208                                 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
2209                                 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
2211                 }
2212         },
2214         _intersectsWithPointer: function( item ) {
2215                 var verticalDirection, horizontalDirection,
2216                         isOverElementHeight = ( this.options.axis === "x" ) ||
2217                                 this._isOverAxis(
2218                                         this.positionAbs.top + this.offset.click.top, item.top, item.height ),
2219                         isOverElementWidth = ( this.options.axis === "y" ) ||
2220                                 this._isOverAxis(
2221                                         this.positionAbs.left + this.offset.click.left, item.left, item.width ),
2222                         isOverElement = isOverElementHeight && isOverElementWidth;
2224                 if ( !isOverElement ) {
2225                         return false;
2226                 }
2228                 verticalDirection = this._getDragVerticalDirection();
2229                 horizontalDirection = this._getDragHorizontalDirection();
2231                 return this.floating ?
2232                         ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
2233                         : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
2235         },
2237         _intersectsWithSides: function( item ) {
2239                 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
2240                                 this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
2241                         isOverRightHalf = this._isOverAxis( this.positionAbs.left +
2242                                 this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
2243                         verticalDirection = this._getDragVerticalDirection(),
2244                         horizontalDirection = this._getDragHorizontalDirection();
2246                 if ( this.floating && horizontalDirection ) {
2247                         return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
2248                                 ( horizontalDirection === "left" && !isOverRightHalf ) );
2249                 } else {
2250                         return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
2251                                 ( verticalDirection === "up" && !isOverBottomHalf ) );
2252                 }
2254         },
2256         _getDragVerticalDirection: function() {
2257                 var delta = this.positionAbs.top - this.lastPositionAbs.top;
2258                 return delta !== 0 && ( delta > 0 ? "down" : "up" );
2259         },
2261         _getDragHorizontalDirection: function() {
2262                 var delta = this.positionAbs.left - this.lastPositionAbs.left;
2263                 return delta !== 0 && ( delta > 0 ? "right" : "left" );
2264         },
2266         refresh: function( event ) {
2267                 this._refreshItems( event );
2268                 this._setHandleClassName();
2269                 this.refreshPositions();
2270                 return this;
2271         },
2273         _connectWith: function() {
2274                 var options = this.options;
2275                 return options.connectWith.constructor === String ?
2276                         [ options.connectWith ] :
2277                         options.connectWith;
2278         },
2280         _getItemsAsjQuery: function( connected ) {
2282                 var i, j, cur, inst,
2283                         items = [],
2284                         queries = [],
2285                         connectWith = this._connectWith();
2287                 if ( connectWith && connected ) {
2288                         for ( i = connectWith.length - 1; i >= 0; i-- ) {
2289                                 cur = $( connectWith[ i ], this.document[ 0 ] );
2290                                 for ( j = cur.length - 1; j >= 0; j-- ) {
2291                                         inst = $.data( cur[ j ], this.widgetFullName );
2292                                         if ( inst && inst !== this && !inst.options.disabled ) {
2293                                                 queries.push( [ $.isFunction( inst.options.items ) ?
2294                                                         inst.options.items.call( inst.element ) :
2295                                                         $( inst.options.items, inst.element )
2296                                                                 .not( ".ui-sortable-helper" )
2297                                                                 .not( ".ui-sortable-placeholder" ), inst ] );
2298                                         }
2299                                 }
2300                         }
2301                 }
2303                 queries.push( [ $.isFunction( this.options.items ) ?
2304                         this.options.items
2305                                 .call( this.element, null, { options: this.options, item: this.currentItem } ) :
2306                         $( this.options.items, this.element )
2307                                 .not( ".ui-sortable-helper" )
2308                                 .not( ".ui-sortable-placeholder" ), this ] );
2310                 function addItems() {
2311                         items.push( this );
2312                 }
2313                 for ( i = queries.length - 1; i >= 0; i-- ) {
2314                         queries[ i ][ 0 ].each( addItems );
2315                 }
2317                 return $( items );
2319         },
2321         _removeCurrentsFromItems: function() {
2323                 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
2325                 this.items = $.grep( this.items, function( item ) {
2326                         for ( var j = 0; j < list.length; j++ ) {
2327                                 if ( list[ j ] === item.item[ 0 ] ) {
2328                                         return false;
2329                                 }
2330                         }
2331                         return true;
2332                 } );
2334         },
2336         _refreshItems: function( event ) {
2338                 this.items = [];
2339                 this.containers = [ this ];
2341                 var i, j, cur, inst, targetData, _queries, item, queriesLength,
2342                         items = this.items,
2343                         queries = [ [ $.isFunction( this.options.items ) ?
2344                                 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
2345                                 $( this.options.items, this.element ), this ] ],
2346                         connectWith = this._connectWith();
2348                 //Shouldn't be run the first time through due to massive slow-down
2349                 if ( connectWith && this.ready ) {
2350                         for ( i = connectWith.length - 1; i >= 0; i-- ) {
2351                                 cur = $( connectWith[ i ], this.document[ 0 ] );
2352                                 for ( j = cur.length - 1; j >= 0; j-- ) {
2353                                         inst = $.data( cur[ j ], this.widgetFullName );
2354                                         if ( inst && inst !== this && !inst.options.disabled ) {
2355                                                 queries.push( [ $.isFunction( inst.options.items ) ?
2356                                                         inst.options.items
2357                                                                 .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
2358                                                         $( inst.options.items, inst.element ), inst ] );
2359                                                 this.containers.push( inst );
2360                                         }
2361                                 }
2362                         }
2363                 }
2365                 for ( i = queries.length - 1; i >= 0; i-- ) {
2366                         targetData = queries[ i ][ 1 ];
2367                         _queries = queries[ i ][ 0 ];
2369                         for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
2370                                 item = $( _queries[ j ] );
2372                                 // Data for target checking (mouse manager)
2373                                 item.data( this.widgetName + "-item", targetData );
2375                                 items.push( {
2376                                         item: item,
2377                                         instance: targetData,
2378                                         width: 0, height: 0,
2379                                         left: 0, top: 0
2380                                 } );
2381                         }
2382                 }
2384         },
2386         refreshPositions: function( fast ) {
2388                 // Determine whether items are being displayed horizontally
2389                 this.floating = this.items.length ?
2390                         this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
2391                         false;
2393                 //This has to be redone because due to the item being moved out/into the offsetParent,
2394                 // the offsetParent's position will change
2395                 if ( this.offsetParent && this.helper ) {
2396                         this.offset.parent = this._getParentOffset();
2397                 }
2399                 var i, item, t, p;
2401                 for ( i = this.items.length - 1; i >= 0; i-- ) {
2402                         item = this.items[ i ];
2404                         //We ignore calculating positions of all connected containers when we're not over them
2405                         if ( item.instance !== this.currentContainer && this.currentContainer &&
2406                                         item.item[ 0 ] !== this.currentItem[ 0 ] ) {
2407                                 continue;
2408                         }
2410                         t = this.options.toleranceElement ?
2411                                 $( this.options.toleranceElement, item.item ) :
2412                                 item.item;
2414                         if ( !fast ) {
2415                                 item.width = t.outerWidth();
2416                                 item.height = t.outerHeight();
2417                         }
2419                         p = t.offset();
2420                         item.left = p.left;
2421                         item.top = p.top;
2422                 }
2424                 if ( this.options.custom && this.options.custom.refreshContainers ) {
2425                         this.options.custom.refreshContainers.call( this );
2426                 } else {
2427                         for ( i = this.containers.length - 1; i >= 0; i-- ) {
2428                                 p = this.containers[ i ].element.offset();
2429                                 this.containers[ i ].containerCache.left = p.left;
2430                                 this.containers[ i ].containerCache.top = p.top;
2431                                 this.containers[ i ].containerCache.width =
2432                                         this.containers[ i ].element.outerWidth();
2433                                 this.containers[ i ].containerCache.height =
2434                                         this.containers[ i ].element.outerHeight();
2435                         }
2436                 }
2438                 return this;
2439         },
2441         _createPlaceholder: function( that ) {
2442                 that = that || this;
2443                 var className,
2444                         o = that.options;
2446                 if ( !o.placeholder || o.placeholder.constructor === String ) {
2447                         className = o.placeholder;
2448                         o.placeholder = {
2449                                 element: function() {
2451                                         var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
2452                                                 element = $( "<" + nodeName + ">", that.document[ 0 ] );
2454                                                 that._addClass( element, "ui-sortable-placeholder",
2455                                                                 className || that.currentItem[ 0 ].className )
2456                                                         ._removeClass( element, "ui-sortable-helper" );
2458                                         if ( nodeName === "tbody" ) {
2459                                                 that._createTrPlaceholder(
2460                                                         that.currentItem.find( "tr" ).eq( 0 ),
2461                                                         $( "<tr>", that.document[ 0 ] ).appendTo( element )
2462                                                 );
2463                                         } else if ( nodeName === "tr" ) {
2464                                                 that._createTrPlaceholder( that.currentItem, element );
2465                                         } else if ( nodeName === "img" ) {
2466                                                 element.attr( "src", that.currentItem.attr( "src" ) );
2467                                         }
2469                                         if ( !className ) {
2470                                                 element.css( "visibility", "hidden" );
2471                                         }
2473                                         return element;
2474                                 },
2475                                 update: function( container, p ) {
2477                                         // 1. If a className is set as 'placeholder option, we don't force sizes -
2478                                         // the class is responsible for that
2479                                         // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
2480                                         // class name is specified
2481                                         if ( className && !o.forcePlaceholderSize ) {
2482                                                 return;
2483                                         }
2485                                         //If the element doesn't have a actual height by itself (without styles coming
2486                                         // from a stylesheet), it receives the inline height from the dragged item
2487                                         if ( !p.height() ) {
2488                                                 p.height(
2489                                                         that.currentItem.innerHeight() -
2490                                                         parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
2491                                                         parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
2492                                         }
2493                                         if ( !p.width() ) {
2494                                                 p.width(
2495                                                         that.currentItem.innerWidth() -
2496                                                         parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
2497                                                         parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
2498                                         }
2499                                 }
2500                         };
2501                 }
2503                 //Create the placeholder
2504                 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
2506                 //Append it after the actual current item
2507                 that.currentItem.after( that.placeholder );
2509                 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
2510                 o.placeholder.update( that, that.placeholder );
2512         },
2514         _createTrPlaceholder: function( sourceTr, targetTr ) {
2515                 var that = this;
2517                 sourceTr.children().each( function() {
2518                         $( "<td>&#160;</td>", that.document[ 0 ] )
2519                                 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
2520                                 .appendTo( targetTr );
2521                 } );
2522         },
2524         _contactContainers: function( event ) {
2525                 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
2526                         floating, axis,
2527                         innermostContainer = null,
2528                         innermostIndex = null;
2530                 // Get innermost container that intersects with item
2531                 for ( i = this.containers.length - 1; i >= 0; i-- ) {
2533                         // Never consider a container that's located within the item itself
2534                         if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
2535                                 continue;
2536                         }
2538                         if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
2540                                 // If we've already found a container and it's more "inner" than this, then continue
2541                                 if ( innermostContainer &&
2542                                                 $.contains(
2543                                                         this.containers[ i ].element[ 0 ],
2544                                                         innermostContainer.element[ 0 ] ) ) {
2545                                         continue;
2546                                 }
2548                                 innermostContainer = this.containers[ i ];
2549                                 innermostIndex = i;
2551                         } else {
2553                                 // container doesn't intersect. trigger "out" event if necessary
2554                                 if ( this.containers[ i ].containerCache.over ) {
2555                                         this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
2556                                         this.containers[ i ].containerCache.over = 0;
2557                                 }
2558                         }
2560                 }
2562                 // If no intersecting containers found, return
2563                 if ( !innermostContainer ) {
2564                         return;
2565                 }
2567                 // Move the item into the container if it's not there already
2568                 if ( this.containers.length === 1 ) {
2569                         if ( !this.containers[ innermostIndex ].containerCache.over ) {
2570                                 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
2571                                 this.containers[ innermostIndex ].containerCache.over = 1;
2572                         }
2573                 } else {
2575                         // When entering a new container, we will find the item with the least distance and
2576                         // append our item near it
2577                         dist = 10000;
2578                         itemWithLeastDistance = null;
2579                         floating = innermostContainer.floating || this._isFloating( this.currentItem );
2580                         posProperty = floating ? "left" : "top";
2581                         sizeProperty = floating ? "width" : "height";
2582                         axis = floating ? "pageX" : "pageY";
2584                         for ( j = this.items.length - 1; j >= 0; j-- ) {
2585                                 if ( !$.contains(
2586                                                 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
2587                                 ) {
2588                                         continue;
2589                                 }
2590                                 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
2591                                         continue;
2592                                 }
2594                                 cur = this.items[ j ].item.offset()[ posProperty ];
2595                                 nearBottom = false;
2596                                 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
2597                                         nearBottom = true;
2598                                 }
2600                                 if ( Math.abs( event[ axis ] - cur ) < dist ) {
2601                                         dist = Math.abs( event[ axis ] - cur );
2602                                         itemWithLeastDistance = this.items[ j ];
2603                                         this.direction = nearBottom ? "up" : "down";
2604                                 }
2605                         }
2607                         //Check if dropOnEmpty is enabled
2608                         if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
2609                                 return;
2610                         }
2612                         if ( this.currentContainer === this.containers[ innermostIndex ] ) {
2613                                 if ( !this.currentContainer.containerCache.over ) {
2614                                         this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
2615                                         this.currentContainer.containerCache.over = 1;
2616                                 }
2617                                 return;
2618                         }
2620                         itemWithLeastDistance ?
2621                                 this._rearrange( event, itemWithLeastDistance, null, true ) :
2622                                 this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
2623                         this._trigger( "change", event, this._uiHash() );
2624                         this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
2625                         this.currentContainer = this.containers[ innermostIndex ];
2627                         //Update the placeholder
2628                         this.options.placeholder.update( this.currentContainer, this.placeholder );
2630                         this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
2631                         this.containers[ innermostIndex ].containerCache.over = 1;
2632                 }
2634         },
2636         _createHelper: function( event ) {
2638                 var o = this.options,
2639                         helper = $.isFunction( o.helper ) ?
2640                                 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
2641                                 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
2643                 //Add the helper to the DOM if that didn't happen already
2644                 if ( !helper.parents( "body" ).length ) {
2645                         $( o.appendTo !== "parent" ?
2646                                 o.appendTo :
2647                                 this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
2648                 }
2650                 if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
2651                         this._storedCSS = {
2652                                 width: this.currentItem[ 0 ].style.width,
2653                                 height: this.currentItem[ 0 ].style.height,
2654                                 position: this.currentItem.css( "position" ),
2655                                 top: this.currentItem.css( "top" ),
2656                                 left: this.currentItem.css( "left" )
2657                         };
2658                 }
2660                 if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
2661                         helper.width( this.currentItem.width() );
2662                 }
2663                 if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
2664                         helper.height( this.currentItem.height() );
2665                 }
2667                 return helper;
2669         },
2671         _adjustOffsetFromHelper: function( obj ) {
2672                 if ( typeof obj === "string" ) {
2673                         obj = obj.split( " " );
2674                 }
2675                 if ( $.isArray( obj ) ) {
2676                         obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
2677                 }
2678                 if ( "left" in obj ) {
2679                         this.offset.click.left = obj.left + this.margins.left;
2680                 }
2681                 if ( "right" in obj ) {
2682                         this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
2683                 }
2684                 if ( "top" in obj ) {
2685                         this.offset.click.top = obj.top + this.margins.top;
2686                 }
2687                 if ( "bottom" in obj ) {
2688                         this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
2689                 }
2690         },
2692         _getParentOffset: function() {
2694                 //Get the offsetParent and cache its position
2695                 this.offsetParent = this.helper.offsetParent();
2696                 var po = this.offsetParent.offset();
2698                 // This is a special case where we need to modify a offset calculated on start, since the
2699                 // following happened:
2700                 // 1. The position of the helper is absolute, so it's position is calculated based on the
2701                 // next positioned parent
2702                 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
2703                 // the document, which means that the scroll is included in the initial calculation of the
2704                 // offset of the parent, and never recalculated upon drag
2705                 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
2706                                 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
2707                         po.left += this.scrollParent.scrollLeft();
2708                         po.top += this.scrollParent.scrollTop();
2709                 }
2711                 // This needs to be actually done for all browsers, since pageX/pageY includes this
2712                 // information with an ugly IE fix
2713                 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
2714                                 ( this.offsetParent[ 0 ].tagName &&
2715                                 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
2716                         po = { top: 0, left: 0 };
2717                 }
2719                 return {
2720                         top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
2721                         left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
2722                 };
2724         },
2726         _getRelativeOffset: function() {
2728                 if ( this.cssPosition === "relative" ) {
2729                         var p = this.currentItem.position();
2730                         return {
2731                                 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
2732                                         this.scrollParent.scrollTop(),
2733                                 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
2734                                         this.scrollParent.scrollLeft()
2735                         };
2736                 } else {
2737                         return { top: 0, left: 0 };
2738                 }
2740         },
2742         _cacheMargins: function() {
2743                 this.margins = {
2744                         left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
2745                         top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
2746                 };
2747         },
2749         _cacheHelperProportions: function() {
2750                 this.helperProportions = {
2751                         width: this.helper.outerWidth(),
2752                         height: this.helper.outerHeight()
2753                 };
2754         },
2756         _setContainment: function() {
2758                 var ce, co, over,
2759                         o = this.options;
2760                 if ( o.containment === "parent" ) {
2761                         o.containment = this.helper[ 0 ].parentNode;
2762                 }
2763                 if ( o.containment === "document" || o.containment === "window" ) {
2764                         this.containment = [
2765                                 0 - this.offset.relative.left - this.offset.parent.left,
2766                                 0 - this.offset.relative.top - this.offset.parent.top,
2767                                 o.containment === "document" ?
2768                                         this.document.width() :
2769                                         this.window.width() - this.helperProportions.width - this.margins.left,
2770                                 ( o.containment === "document" ?
2771                                         ( this.document.height() || document.body.parentNode.scrollHeight ) :
2772                                         this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
2773                                 ) - this.helperProportions.height - this.margins.top
2774                         ];
2775                 }
2777                 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
2778                         ce = $( o.containment )[ 0 ];
2779                         co = $( o.containment ).offset();
2780                         over = ( $( ce ).css( "overflow" ) !== "hidden" );
2782                         this.containment = [
2783                                 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
2784                                         ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
2785                                 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
2786                                         ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
2787                                 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
2788                                         ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
2789                                         ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
2790                                         this.helperProportions.width - this.margins.left,
2791                                 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
2792                                         ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
2793                                         ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
2794                                         this.helperProportions.height - this.margins.top
2795                         ];
2796                 }
2798         },
2800         _convertPositionTo: function( d, pos ) {
2802                 if ( !pos ) {
2803                         pos = this.position;
2804                 }
2805                 var mod = d === "absolute" ? 1 : -1,
2806                         scroll = this.cssPosition === "absolute" &&
2807                                 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
2808                                 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
2809                                         this.offsetParent :
2810                                         this.scrollParent,
2811                         scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
2813                 return {
2814                         top: (
2816                                 // The absolute mouse position
2817                                 pos.top +
2819                                 // Only for relative positioned nodes: Relative offset from element to offset parent
2820                                 this.offset.relative.top * mod +
2822                                 // The offsetParent's offset without borders (offset + border)
2823                                 this.offset.parent.top * mod -
2824                                 ( ( this.cssPosition === "fixed" ?
2825                                         -this.scrollParent.scrollTop() :
2826                                         ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
2827                         ),
2828                         left: (
2830                                 // The absolute mouse position
2831                                 pos.left +
2833                                 // Only for relative positioned nodes: Relative offset from element to offset parent
2834                                 this.offset.relative.left * mod +
2836                                 // The offsetParent's offset without borders (offset + border)
2837                                 this.offset.parent.left * mod   -
2838                                 ( ( this.cssPosition === "fixed" ?
2839                                         -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
2840                                         scroll.scrollLeft() ) * mod )
2841                         )
2842                 };
2844         },
2846         _generatePosition: function( event ) {
2848                 var top, left,
2849                         o = this.options,
2850                         pageX = event.pageX,
2851                         pageY = event.pageY,
2852                         scroll = this.cssPosition === "absolute" &&
2853                                 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
2854                                 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
2855                                         this.offsetParent :
2856                                         this.scrollParent,
2857                                 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
2859                 // This is another very weird special case that only happens for relative elements:
2860                 // 1. If the css position is relative
2861                 // 2. and the scroll parent is the document or similar to the offset parent
2862                 // we have to refresh the relative offset during the scroll so there are no jumps
2863                 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
2864                                 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
2865                         this.offset.relative = this._getRelativeOffset();
2866                 }
2868                 /*
2869                  * - Position constraining -
2870                  * Constrain the position to a mix of grid, containment.
2871                  */
2873                 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
2875                         if ( this.containment ) {
2876                                 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
2877                                         pageX = this.containment[ 0 ] + this.offset.click.left;
2878                                 }
2879                                 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
2880                                         pageY = this.containment[ 1 ] + this.offset.click.top;
2881                                 }
2882                                 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
2883                                         pageX = this.containment[ 2 ] + this.offset.click.left;
2884                                 }
2885                                 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
2886                                         pageY = this.containment[ 3 ] + this.offset.click.top;
2887                                 }
2888                         }
2890                         if ( o.grid ) {
2891                                 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
2892                                         o.grid[ 1 ] ) * o.grid[ 1 ];
2893                                 pageY = this.containment ?
2894                                         ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
2895                                                 top - this.offset.click.top <= this.containment[ 3 ] ) ?
2896                                                         top :
2897                                                         ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
2898                                                                 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
2899                                                                 top;
2901                                 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
2902                                         o.grid[ 0 ] ) * o.grid[ 0 ];
2903                                 pageX = this.containment ?
2904                                         ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
2905                                                 left - this.offset.click.left <= this.containment[ 2 ] ) ?
2906                                                         left :
2907                                                         ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
2908                                                                 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
2909                                                                 left;
2910                         }
2912                 }
2914                 return {
2915                         top: (
2917                                 // The absolute mouse position
2918                                 pageY -
2920                                 // Click offset (relative to the element)
2921                                 this.offset.click.top -
2923                                 // Only for relative positioned nodes: Relative offset from element to offset parent
2924                                 this.offset.relative.top -
2926                                 // The offsetParent's offset without borders (offset + border)
2927                                 this.offset.parent.top +
2928                                 ( ( this.cssPosition === "fixed" ?
2929                                         -this.scrollParent.scrollTop() :
2930                                         ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
2931                         ),
2932                         left: (
2934                                 // The absolute mouse position
2935                                 pageX -
2937                                 // Click offset (relative to the element)
2938                                 this.offset.click.left -
2940                                 // Only for relative positioned nodes: Relative offset from element to offset parent
2941                                 this.offset.relative.left -
2943                                 // The offsetParent's offset without borders (offset + border)
2944                                 this.offset.parent.left +
2945                                 ( ( this.cssPosition === "fixed" ?
2946                                         -this.scrollParent.scrollLeft() :
2947                                         scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
2948                         )
2949                 };
2951         },
2953         _rearrange: function( event, i, a, hardRefresh ) {
2955                 a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
2956                         i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
2957                                 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
2959                 //Various things done here to improve the performance:
2960                 // 1. we create a setTimeout, that calls refreshPositions
2961                 // 2. on the instance, we have a counter variable, that get's higher after every append
2962                 // 3. on the local scope, we copy the counter variable, and check in the timeout,
2963                 // if it's still the same
2964                 // 4. this lets only the last addition to the timeout stack through
2965                 this.counter = this.counter ? ++this.counter : 1;
2966                 var counter = this.counter;
2968                 this._delay( function() {
2969                         if ( counter === this.counter ) {
2971                                 //Precompute after each DOM insertion, NOT on mousemove
2972                                 this.refreshPositions( !hardRefresh );
2973                         }
2974                 } );
2976         },
2978         _clear: function( event, noPropagation ) {
2980                 this.reverting = false;
2982                 // We delay all events that have to be triggered to after the point where the placeholder
2983                 // has been removed and everything else normalized again
2984                 var i,
2985                         delayedTriggers = [];
2987                 // We first have to update the dom position of the actual currentItem
2988                 // Note: don't do it if the current item is already removed (by a user), or it gets
2989                 // reappended (see #4088)
2990                 if ( !this._noFinalSort && this.currentItem.parent().length ) {
2991                         this.placeholder.before( this.currentItem );
2992                 }
2993                 this._noFinalSort = null;
2995                 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
2996                         for ( i in this._storedCSS ) {
2997                                 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
2998                                         this._storedCSS[ i ] = "";
2999                                 }
3000                         }
3001                         this.currentItem.css( this._storedCSS );
3002                         this._removeClass( this.currentItem, "ui-sortable-helper" );
3003                 } else {
3004                         this.currentItem.show();
3005                 }
3007                 if ( this.fromOutside && !noPropagation ) {
3008                         delayedTriggers.push( function( event ) {
3009                                 this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
3010                         } );
3011                 }
3012                 if ( ( this.fromOutside ||
3013                                 this.domPosition.prev !==
3014                                 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
3015                                 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
3017                         // Trigger update callback if the DOM position has changed
3018                         delayedTriggers.push( function( event ) {
3019                                 this._trigger( "update", event, this._uiHash() );
3020                         } );
3021                 }
3023                 // Check if the items Container has Changed and trigger appropriate
3024                 // events.
3025                 if ( this !== this.currentContainer ) {
3026                         if ( !noPropagation ) {
3027                                 delayedTriggers.push( function( event ) {
3028                                         this._trigger( "remove", event, this._uiHash() );
3029                                 } );
3030                                 delayedTriggers.push( ( function( c ) {
3031                                         return function( event ) {
3032                                                 c._trigger( "receive", event, this._uiHash( this ) );
3033                                         };
3034                                 } ).call( this, this.currentContainer ) );
3035                                 delayedTriggers.push( ( function( c ) {
3036                                         return function( event ) {
3037                                                 c._trigger( "update", event, this._uiHash( this ) );
3038                                         };
3039                                 } ).call( this, this.currentContainer ) );
3040                         }
3041                 }
3043                 //Post events to containers
3044                 function delayEvent( type, instance, container ) {
3045                         return function( event ) {
3046                                 container._trigger( type, event, instance._uiHash( instance ) );
3047                         };
3048                 }
3049                 for ( i = this.containers.length - 1; i >= 0; i-- ) {
3050                         if ( !noPropagation ) {
3051                                 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
3052                         }
3053                         if ( this.containers[ i ].containerCache.over ) {
3054                                 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
3055                                 this.containers[ i ].containerCache.over = 0;
3056                         }
3057                 }
3059                 //Do what was originally in plugins
3060                 if ( this.storedCursor ) {
3061                         this.document.find( "body" ).css( "cursor", this.storedCursor );
3062                         this.storedStylesheet.remove();
3063                 }
3064                 if ( this._storedOpacity ) {
3065                         this.helper.css( "opacity", this._storedOpacity );
3066                 }
3067                 if ( this._storedZIndex ) {
3068                         this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
3069                 }
3071                 this.dragging = false;
3073                 if ( !noPropagation ) {
3074                         this._trigger( "beforeStop", event, this._uiHash() );
3075                 }
3077                 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
3078                 // it unbinds ALL events from the original node!
3079                 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
3081                 if ( !this.cancelHelperRemoval ) {
3082                         if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
3083                                 this.helper.remove();
3084                         }
3085                         this.helper = null;
3086                 }
3088                 if ( !noPropagation ) {
3089                         for ( i = 0; i < delayedTriggers.length; i++ ) {
3091                                 // Trigger all delayed events
3092                                 delayedTriggers[ i ].call( this, event );
3093                         }
3094                         this._trigger( "stop", event, this._uiHash() );
3095                 }
3097                 this.fromOutside = false;
3098                 return !this.cancelHelperRemoval;
3100         },
3102         _trigger: function() {
3103                 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
3104                         this.cancel();
3105                 }
3106         },
3108         _uiHash: function( _inst ) {
3109                 var inst = _inst || this;
3110                 return {
3111                         helper: inst.helper,
3112                         placeholder: inst.placeholder || $( [] ),
3113                         position: inst.position,
3114                         originalPosition: inst.originalPosition,
3115                         offset: inst.positionAbs,
3116                         item: inst.currentItem,
3117                         sender: _inst ? _inst.element : null
3118                 };
3119         }
3121 } );
3125 var safeActiveElement = $.ui.safeActiveElement = function( document ) {
3126         var activeElement;
3128         // Support: IE 9 only
3129         // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
3130         try {
3131                 activeElement = document.activeElement;
3132         } catch ( error ) {
3133                 activeElement = document.body;
3134         }
3136         // Support: IE 9 - 11 only
3137         // IE may return null instead of an element
3138         // Interestingly, this only seems to occur when NOT in an iframe
3139         if ( !activeElement ) {
3140                 activeElement = document.body;
3141         }
3143         // Support: IE 11 only
3144         // IE11 returns a seemingly empty object in some cases when accessing
3145         // document.activeElement from an <iframe>
3146         if ( !activeElement.nodeName ) {
3147                 activeElement = document.body;
3148         }
3150         return activeElement;
3155  * jQuery UI Menu 1.12.1
3156  * http://jqueryui.com
3158  * Copyright jQuery Foundation and other contributors
3159  * Released under the MIT license.
3160  * http://jquery.org/license
3161  */
3163 //>>label: Menu
3164 //>>group: Widgets
3165 //>>description: Creates nestable menus.
3166 //>>docs: http://api.jqueryui.com/menu/
3167 //>>demos: http://jqueryui.com/menu/
3168 //>>css.structure: ../../themes/base/core.css
3169 //>>css.structure: ../../themes/base/menu.css
3170 //>>css.theme: ../../themes/base/theme.css
3174 var widgetsMenu = $.widget( "ui.menu", {
3175         version: "1.12.1",
3176         defaultElement: "<ul>",
3177         delay: 300,
3178         options: {
3179                 icons: {
3180                         submenu: "ui-icon-caret-1-e"
3181                 },
3182                 items: "> *",
3183                 menus: "ul",
3184                 position: {
3185                         my: "left top",
3186                         at: "right top"
3187                 },
3188                 role: "menu",
3190                 // Callbacks
3191                 blur: null,
3192                 focus: null,
3193                 select: null
3194         },
3196         _create: function() {
3197                 this.activeMenu = this.element;
3199                 // Flag used to prevent firing of the click handler
3200                 // as the event bubbles up through nested menus
3201                 this.mouseHandled = false;
3202                 this.element
3203                         .uniqueId()
3204                         .attr( {
3205                                 role: this.options.role,
3206                                 tabIndex: 0
3207                         } );
3209                 this._addClass( "ui-menu", "ui-widget ui-widget-content" );
3210                 this._on( {
3212                         // Prevent focus from sticking to links inside menu after clicking
3213                         // them (focus should always stay on UL during navigation).
3214                         "mousedown .ui-menu-item": function( event ) {
3215                                 event.preventDefault();
3216                         },
3217                         "click .ui-menu-item": function( event ) {
3218                                 var target = $( event.target );
3219                                 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
3220                                 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
3221                                         this.select( event );
3223                                         // Only set the mouseHandled flag if the event will bubble, see #9469.
3224                                         if ( !event.isPropagationStopped() ) {
3225                                                 this.mouseHandled = true;
3226                                         }
3228                                         // Open submenu on click
3229                                         if ( target.has( ".ui-menu" ).length ) {
3230                                                 this.expand( event );
3231                                         } else if ( !this.element.is( ":focus" ) &&
3232                                                         active.closest( ".ui-menu" ).length ) {
3234                                                 // Redirect focus to the menu
3235                                                 this.element.trigger( "focus", [ true ] );
3237                                                 // If the active item is on the top level, let it stay active.
3238                                                 // Otherwise, blur the active item since it is no longer visible.
3239                                                 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
3240                                                         clearTimeout( this.timer );
3241                                                 }
3242                                         }
3243                                 }
3244                         },
3245                         "mouseenter .ui-menu-item": function( event ) {
3247                                 // Ignore mouse events while typeahead is active, see #10458.
3248                                 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
3249                                 // is over an item in the menu
3250                                 if ( this.previousFilter ) {
3251                                         return;
3252                                 }
3254                                 var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
3255                                         target = $( event.currentTarget );
3257                                 // Ignore bubbled events on parent items, see #11641
3258                                 if ( actualTarget[ 0 ] !== target[ 0 ] ) {
3259                                         return;
3260                                 }
3262                                 // Remove ui-state-active class from siblings of the newly focused menu item
3263                                 // to avoid a jump caused by adjacent elements both having a class with a border
3264                                 this._removeClass( target.siblings().children( ".ui-state-active" ),
3265                                         null, "ui-state-active" );
3266                                 this.focus( event, target );
3267                         },
3268                         mouseleave: "collapseAll",
3269                         "mouseleave .ui-menu": "collapseAll",
3270                         focus: function( event, keepActiveItem ) {
3272                                 // If there's already an active item, keep it active
3273                                 // If not, activate the first item
3274                                 var item = this.active || this.element.find( this.options.items ).eq( 0 );
3276                                 if ( !keepActiveItem ) {
3277                                         this.focus( event, item );
3278                                 }
3279                         },
3280                         blur: function( event ) {
3281                                 this._delay( function() {
3282                                         var notContained = !$.contains(
3283                                                 this.element[ 0 ],
3284                                                 $.ui.safeActiveElement( this.document[ 0 ] )
3285                                         );
3286                                         if ( notContained ) {
3287                                                 this.collapseAll( event );
3288                                         }
3289                                 } );
3290                         },
3291                         keydown: "_keydown"
3292                 } );
3294                 this.refresh();
3296                 // Clicks outside of a menu collapse any open menus
3297                 this._on( this.document, {
3298                         click: function( event ) {
3299                                 if ( this._closeOnDocumentClick( event ) ) {
3300                                         this.collapseAll( event );
3301                                 }
3303                                 // Reset the mouseHandled flag
3304                                 this.mouseHandled = false;
3305                         }
3306                 } );
3307         },
3309         _destroy: function() {
3310                 var items = this.element.find( ".ui-menu-item" )
3311                                 .removeAttr( "role aria-disabled" ),
3312                         submenus = items.children( ".ui-menu-item-wrapper" )
3313                                 .removeUniqueId()
3314                                 .removeAttr( "tabIndex role aria-haspopup" );
3316                 // Destroy (sub)menus
3317                 this.element
3318                         .removeAttr( "aria-activedescendant" )
3319                         .find( ".ui-menu" ).addBack()
3320                                 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
3321                                         "tabIndex" )
3322                                 .removeUniqueId()
3323                                 .show();
3325                 submenus.children().each( function() {
3326                         var elem = $( this );
3327                         if ( elem.data( "ui-menu-submenu-caret" ) ) {
3328                                 elem.remove();
3329                         }
3330                 } );
3331         },
3333         _keydown: function( event ) {
3334                 var match, prev, character, skip,
3335                         preventDefault = true;
3337                 switch ( event.keyCode ) {
3338                 case $.ui.keyCode.PAGE_UP:
3339                         this.previousPage( event );
3340                         break;
3341                 case $.ui.keyCode.PAGE_DOWN:
3342                         this.nextPage( event );
3343                         break;
3344                 case $.ui.keyCode.HOME:
3345                         this._move( "first", "first", event );
3346                         break;
3347                 case $.ui.keyCode.END:
3348                         this._move( "last", "last", event );
3349                         break;
3350                 case $.ui.keyCode.UP:
3351                         this.previous( event );
3352                         break;
3353                 case $.ui.keyCode.DOWN:
3354                         this.next( event );
3355                         break;
3356                 case $.ui.keyCode.LEFT:
3357                         this.collapse( event );
3358                         break;
3359                 case $.ui.keyCode.RIGHT:
3360                         if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
3361                                 this.expand( event );
3362                         }
3363                         break;
3364                 case $.ui.keyCode.ENTER:
3365                 case $.ui.keyCode.SPACE:
3366                         this._activate( event );
3367                         break;
3368                 case $.ui.keyCode.ESCAPE:
3369                         this.collapse( event );
3370                         break;
3371                 default:
3372                         preventDefault = false;
3373                         prev = this.previousFilter || "";
3374                         skip = false;
3376                         // Support number pad values
3377                         character = event.keyCode >= 96 && event.keyCode <= 105 ?
3378                                 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
3380                         clearTimeout( this.filterTimer );
3382                         if ( character === prev ) {
3383                                 skip = true;
3384                         } else {
3385                                 character = prev + character;
3386                         }
3388                         match = this._filterMenuItems( character );
3389                         match = skip && match.index( this.active.next() ) !== -1 ?
3390                                 this.active.nextAll( ".ui-menu-item" ) :
3391                                 match;
3393                         // If no matches on the current filter, reset to the last character pressed
3394                         // to move down the menu to the first item that starts with that character
3395                         if ( !match.length ) {
3396                                 character = String.fromCharCode( event.keyCode );
3397                                 match = this._filterMenuItems( character );
3398                         }
3400                         if ( match.length ) {
3401                                 this.focus( event, match );
3402                                 this.previousFilter = character;
3403                                 this.filterTimer = this._delay( function() {
3404                                         delete this.previousFilter;
3405                                 }, 1000 );
3406                         } else {
3407                                 delete this.previousFilter;
3408                         }
3409                 }
3411                 if ( preventDefault ) {
3412                         event.preventDefault();
3413                 }
3414         },
3416         _activate: function( event ) {
3417                 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
3418                         if ( this.active.children( "[aria-haspopup='true']" ).length ) {
3419                                 this.expand( event );
3420                         } else {
3421                                 this.select( event );
3422                         }
3423                 }
3424         },
3426         refresh: function() {
3427                 var menus, items, newSubmenus, newItems, newWrappers,
3428                         that = this,
3429                         icon = this.options.icons.submenu,
3430                         submenus = this.element.find( this.options.menus );
3432                 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
3434                 // Initialize nested menus
3435                 newSubmenus = submenus.filter( ":not(.ui-menu)" )
3436                         .hide()
3437                         .attr( {
3438                                 role: this.options.role,
3439                                 "aria-hidden": "true",
3440                                 "aria-expanded": "false"
3441                         } )
3442                         .each( function() {
3443                                 var menu = $( this ),
3444                                         item = menu.prev(),
3445                                         submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
3447                                 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
3448                                 item
3449                                         .attr( "aria-haspopup", "true" )
3450                                         .prepend( submenuCaret );
3451                                 menu.attr( "aria-labelledby", item.attr( "id" ) );
3452                         } );
3454                 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
3456                 menus = submenus.add( this.element );
3457                 items = menus.find( this.options.items );
3459                 // Initialize menu-items containing spaces and/or dashes only as dividers
3460                 items.not( ".ui-menu-item" ).each( function() {
3461                         var item = $( this );
3462                         if ( that._isDivider( item ) ) {
3463                                 that._addClass( item, "ui-menu-divider", "ui-widget-content" );
3464                         }
3465                 } );
3467                 // Don't refresh list items that are already adapted
3468                 newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
3469                 newWrappers = newItems.children()
3470                         .not( ".ui-menu" )
3471                                 .uniqueId()
3472                                 .attr( {
3473                                         tabIndex: -1,
3474                                         role: this._itemRole()
3475                                 } );
3476                 this._addClass( newItems, "ui-menu-item" )
3477                         ._addClass( newWrappers, "ui-menu-item-wrapper" );
3479                 // Add aria-disabled attribute to any disabled menu item
3480                 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
3482                 // If the active item has been removed, blur the menu
3483                 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
3484                         this.blur();
3485                 }
3486         },
3488         _itemRole: function() {
3489                 return {
3490                         menu: "menuitem",
3491                         listbox: "option"
3492                 }[ this.options.role ];
3493         },
3495         _setOption: function( key, value ) {
3496                 if ( key === "icons" ) {
3497                         var icons = this.element.find( ".ui-menu-icon" );
3498                         this._removeClass( icons, null, this.options.icons.submenu )
3499                                 ._addClass( icons, null, value.submenu );
3500                 }
3501                 this._super( key, value );
3502         },
3504         _setOptionDisabled: function( value ) {
3505                 this._super( value );
3507                 this.element.attr( "aria-disabled", String( value ) );
3508                 this._toggleClass( null, "ui-state-disabled", !!value );
3509         },
3511         focus: function( event, item ) {
3512                 var nested, focused, activeParent;
3513                 this.blur( event, event && event.type === "focus" );
3515                 this._scrollIntoView( item );
3517                 this.active = item.first();
3519                 focused = this.active.children( ".ui-menu-item-wrapper" );
3520                 this._addClass( focused, null, "ui-state-active" );
3522                 // Only update aria-activedescendant if there's a role
3523                 // otherwise we assume focus is managed elsewhere
3524                 if ( this.options.role ) {
3525                         this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
3526                 }
3528                 // Highlight active parent menu item, if any
3529                 activeParent = this.active
3530                         .parent()
3531                                 .closest( ".ui-menu-item" )
3532                                         .children( ".ui-menu-item-wrapper" );
3533                 this._addClass( activeParent, null, "ui-state-active" );
3535                 if ( event && event.type === "keydown" ) {
3536                         this._close();
3537                 } else {
3538                         this.timer = this._delay( function() {
3539                                 this._close();
3540                         }, this.delay );
3541                 }
3543                 nested = item.children( ".ui-menu" );
3544                 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
3545                         this._startOpening( nested );
3546                 }
3547                 this.activeMenu = item.parent();
3549                 this._trigger( "focus", event, { item: item } );
3550         },
3552         _scrollIntoView: function( item ) {
3553                 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
3554                 if ( this._hasScroll() ) {
3555                         borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
3556                         paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
3557                         offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
3558                         scroll = this.activeMenu.scrollTop();
3559                         elementHeight = this.activeMenu.height();
3560                         itemHeight = item.outerHeight();
3562                         if ( offset < 0 ) {
3563                                 this.activeMenu.scrollTop( scroll + offset );
3564                         } else if ( offset + itemHeight > elementHeight ) {
3565                                 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
3566                         }
3567                 }
3568         },
3570         blur: function( event, fromFocus ) {
3571                 if ( !fromFocus ) {
3572                         clearTimeout( this.timer );
3573                 }
3575                 if ( !this.active ) {
3576                         return;
3577                 }
3579                 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
3580                         null, "ui-state-active" );
3582                 this._trigger( "blur", event, { item: this.active } );
3583                 this.active = null;
3584         },
3586         _startOpening: function( submenu ) {
3587                 clearTimeout( this.timer );
3589                 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
3590                 // shift in the submenu position when mousing over the caret icon
3591                 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
3592                         return;
3593                 }
3595                 this.timer = this._delay( function() {
3596                         this._close();
3597                         this._open( submenu );
3598                 }, this.delay );
3599         },
3601         _open: function( submenu ) {
3602                 var position = $.extend( {
3603                         of: this.active
3604                 }, this.options.position );
3606                 clearTimeout( this.timer );
3607                 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
3608                         .hide()
3609                         .attr( "aria-hidden", "true" );
3611                 submenu
3612                         .show()
3613                         .removeAttr( "aria-hidden" )
3614                         .attr( "aria-expanded", "true" )
3615                         .position( position );
3616         },
3618         collapseAll: function( event, all ) {
3619                 clearTimeout( this.timer );
3620                 this.timer = this._delay( function() {
3622                         // If we were passed an event, look for the submenu that contains the event
3623                         var currentMenu = all ? this.element :
3624                                 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
3626                         // If we found no valid submenu ancestor, use the main menu to close all
3627                         // sub menus anyway
3628                         if ( !currentMenu.length ) {
3629                                 currentMenu = this.element;
3630                         }
3632                         this._close( currentMenu );
3634                         this.blur( event );
3636                         // Work around active item staying active after menu is blurred
3637                         this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
3639                         this.activeMenu = currentMenu;
3640                 }, this.delay );
3641         },
3643         // With no arguments, closes the currently active menu - if nothing is active
3644         // it closes all menus.  If passed an argument, it will search for menus BELOW
3645         _close: function( startMenu ) {
3646                 if ( !startMenu ) {
3647                         startMenu = this.active ? this.active.parent() : this.element;
3648                 }
3650                 startMenu.find( ".ui-menu" )
3651                         .hide()
3652                         .attr( "aria-hidden", "true" )
3653                         .attr( "aria-expanded", "false" );
3654         },
3656         _closeOnDocumentClick: function( event ) {
3657                 return !$( event.target ).closest( ".ui-menu" ).length;
3658         },
3660         _isDivider: function( item ) {
3662                 // Match hyphen, em dash, en dash
3663                 return !/[^\-\u2014\u2013\s]/.test( item.text() );
3664         },
3666         collapse: function( event ) {
3667                 var newItem = this.active &&
3668                         this.active.parent().closest( ".ui-menu-item", this.element );
3669                 if ( newItem && newItem.length ) {
3670                         this._close();
3671                         this.focus( event, newItem );
3672                 }
3673         },
3675         expand: function( event ) {
3676                 var newItem = this.active &&
3677                         this.active
3678                                 .children( ".ui-menu " )
3679                                         .find( this.options.items )
3680                                                 .first();
3682                 if ( newItem && newItem.length ) {
3683                         this._open( newItem.parent() );
3685                         // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
3686                         this._delay( function() {
3687                                 this.focus( event, newItem );
3688                         } );
3689                 }
3690         },
3692         next: function( event ) {
3693                 this._move( "next", "first", event );
3694         },
3696         previous: function( event ) {
3697                 this._move( "prev", "last", event );
3698         },
3700         isFirstItem: function() {
3701                 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
3702         },
3704         isLastItem: function() {
3705                 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
3706         },
3708         _move: function( direction, filter, event ) {
3709                 var next;
3710                 if ( this.active ) {
3711                         if ( direction === "first" || direction === "last" ) {
3712                                 next = this.active
3713                                         [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
3714                                         .eq( -1 );
3715                         } else {
3716                                 next = this.active
3717                                         [ direction + "All" ]( ".ui-menu-item" )
3718                                         .eq( 0 );
3719                         }
3720                 }
3721                 if ( !next || !next.length || !this.active ) {
3722                         next = this.activeMenu.find( this.options.items )[ filter ]();
3723                 }
3725                 this.focus( event, next );
3726         },
3728         nextPage: function( event ) {
3729                 var item, base, height;
3731                 if ( !this.active ) {
3732                         this.next( event );
3733                         return;
3734                 }
3735                 if ( this.isLastItem() ) {
3736                         return;
3737                 }
3738                 if ( this._hasScroll() ) {
3739                         base = this.active.offset().top;
3740                         height = this.element.height();
3741                         this.active.nextAll( ".ui-menu-item" ).each( function() {
3742                                 item = $( this );
3743                                 return item.offset().top - base - height < 0;
3744                         } );
3746                         this.focus( event, item );
3747                 } else {
3748                         this.focus( event, this.activeMenu.find( this.options.items )
3749                                 [ !this.active ? "first" : "last" ]() );
3750                 }
3751         },
3753         previousPage: function( event ) {
3754                 var item, base, height;
3755                 if ( !this.active ) {
3756                         this.next( event );
3757                         return;
3758                 }
3759                 if ( this.isFirstItem() ) {
3760                         return;
3761                 }
3762                 if ( this._hasScroll() ) {
3763                         base = this.active.offset().top;
3764                         height = this.element.height();
3765                         this.active.prevAll( ".ui-menu-item" ).each( function() {
3766                                 item = $( this );
3767                                 return item.offset().top - base + height > 0;
3768                         } );
3770                         this.focus( event, item );
3771                 } else {
3772                         this.focus( event, this.activeMenu.find( this.options.items ).first() );
3773                 }
3774         },
3776         _hasScroll: function() {
3777                 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
3778         },
3780         select: function( event ) {
3782                 // TODO: It should never be possible to not have an active item at this
3783                 // point, but the tests don't trigger mouseenter before click.
3784                 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
3785                 var ui = { item: this.active };
3786                 if ( !this.active.has( ".ui-menu" ).length ) {
3787                         this.collapseAll( event, true );
3788                 }
3789                 this._trigger( "select", event, ui );
3790         },
3792         _filterMenuItems: function( character ) {
3793                 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
3794                         regex = new RegExp( "^" + escapedCharacter, "i" );
3796                 return this.activeMenu
3797                         .find( this.options.items )
3799                                 // Only match on items, not dividers or other content (#10571)
3800                                 .filter( ".ui-menu-item" )
3801                                         .filter( function() {
3802                                                 return regex.test(
3803                                                         $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
3804                                         } );
3805         }
3806 } );
3810  * jQuery UI Autocomplete 1.12.1
3811  * http://jqueryui.com
3813  * Copyright jQuery Foundation and other contributors
3814  * Released under the MIT license.
3815  * http://jquery.org/license
3816  */
3818 //>>label: Autocomplete
3819 //>>group: Widgets
3820 //>>description: Lists suggested words as the user is typing.
3821 //>>docs: http://api.jqueryui.com/autocomplete/
3822 //>>demos: http://jqueryui.com/autocomplete/
3823 //>>css.structure: ../../themes/base/core.css
3824 //>>css.structure: ../../themes/base/autocomplete.css
3825 //>>css.theme: ../../themes/base/theme.css
3829 $.widget( "ui.autocomplete", {
3830         version: "1.12.1",
3831         defaultElement: "<input>",
3832         options: {
3833                 appendTo: null,
3834                 autoFocus: false,
3835                 delay: 300,
3836                 minLength: 1,
3837                 position: {
3838                         my: "left top",
3839                         at: "left bottom",
3840                         collision: "none"
3841                 },
3842                 source: null,
3844                 // Callbacks
3845                 change: null,
3846                 close: null,
3847                 focus: null,
3848                 open: null,
3849                 response: null,
3850                 search: null,
3851                 select: null
3852         },
3854         requestIndex: 0,
3855         pending: 0,
3857         _create: function() {
3859                 // Some browsers only repeat keydown events, not keypress events,
3860                 // so we use the suppressKeyPress flag to determine if we've already
3861                 // handled the keydown event. #7269
3862                 // Unfortunately the code for & in keypress is the same as the up arrow,
3863                 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
3864                 // events when we know the keydown event was used to modify the
3865                 // search term. #7799
3866                 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
3867                         nodeName = this.element[ 0 ].nodeName.toLowerCase(),
3868                         isTextarea = nodeName === "textarea",
3869                         isInput = nodeName === "input";
3871                 // Textareas are always multi-line
3872                 // Inputs are always single-line, even if inside a contentEditable element
3873                 // IE also treats inputs as contentEditable
3874                 // All other element types are determined by whether or not they're contentEditable
3875                 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
3877                 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
3878                 this.isNewMenu = true;
3880                 this._addClass( "ui-autocomplete-input" );
3881                 this.element.attr( "autocomplete", "off" );
3883                 this._on( this.element, {
3884                         keydown: function( event ) {
3885                                 if ( this.element.prop( "readOnly" ) ) {
3886                                         suppressKeyPress = true;
3887                                         suppressInput = true;
3888                                         suppressKeyPressRepeat = true;
3889                                         return;
3890                                 }
3892                                 suppressKeyPress = false;
3893                                 suppressInput = false;
3894                                 suppressKeyPressRepeat = false;
3895                                 var keyCode = $.ui.keyCode;
3896                                 switch ( event.keyCode ) {
3897                                 case keyCode.PAGE_UP:
3898                                         suppressKeyPress = true;
3899                                         this._move( "previousPage", event );
3900                                         break;
3901                                 case keyCode.PAGE_DOWN:
3902                                         suppressKeyPress = true;
3903                                         this._move( "nextPage", event );
3904                                         break;
3905                                 case keyCode.UP:
3906                                         suppressKeyPress = true;
3907                                         this._keyEvent( "previous", event );
3908                                         break;
3909                                 case keyCode.DOWN:
3910                                         suppressKeyPress = true;
3911                                         this._keyEvent( "next", event );
3912                                         break;
3913                                 case keyCode.ENTER:
3915                                         // when menu is open and has focus
3916                                         if ( this.menu.active ) {
3918                                                 // #6055 - Opera still allows the keypress to occur
3919                                                 // which causes forms to submit
3920                                                 suppressKeyPress = true;
3921                                                 event.preventDefault();
3922                                                 this.menu.select( event );
3923                                         }
3924                                         break;
3925                                 case keyCode.TAB:
3926                                         if ( this.menu.active ) {
3927                                                 this.menu.select( event );
3928                                         }
3929                                         break;
3930                                 case keyCode.ESCAPE:
3931                                         if ( this.menu.element.is( ":visible" ) ) {
3932                                                 if ( !this.isMultiLine ) {
3933                                                         this._value( this.term );
3934                                                 }
3935                                                 this.close( event );
3937                                                 // Different browsers have different default behavior for escape
3938                                                 // Single press can mean undo or clear
3939                                                 // Double press in IE means clear the whole form
3940                                                 event.preventDefault();
3941                                         }
3942                                         break;
3943                                 default:
3944                                         suppressKeyPressRepeat = true;
3946                                         // search timeout should be triggered before the input value is changed
3947                                         this._searchTimeout( event );
3948                                         break;
3949                                 }
3950                         },
3951                         keypress: function( event ) {
3952                                 if ( suppressKeyPress ) {
3953                                         suppressKeyPress = false;
3954                                         if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3955                                                 event.preventDefault();
3956                                         }
3957                                         return;
3958                                 }
3959                                 if ( suppressKeyPressRepeat ) {
3960                                         return;
3961                                 }
3963                                 // Replicate some key handlers to allow them to repeat in Firefox and Opera
3964                                 var keyCode = $.ui.keyCode;
3965                                 switch ( event.keyCode ) {
3966                                 case keyCode.PAGE_UP:
3967                                         this._move( "previousPage", event );
3968                                         break;
3969                                 case keyCode.PAGE_DOWN:
3970                                         this._move( "nextPage", event );
3971                                         break;
3972                                 case keyCode.UP:
3973                                         this._keyEvent( "previous", event );
3974                                         break;
3975                                 case keyCode.DOWN:
3976                                         this._keyEvent( "next", event );
3977                                         break;
3978                                 }
3979                         },
3980                         input: function( event ) {
3981                                 if ( suppressInput ) {
3982                                         suppressInput = false;
3983                                         event.preventDefault();
3984                                         return;
3985                                 }
3986                                 this._searchTimeout( event );
3987                         },
3988                         focus: function() {
3989                                 this.selectedItem = null;
3990                                 this.previous = this._value();
3991                         },
3992                         blur: function( event ) {
3993                                 if ( this.cancelBlur ) {
3994                                         delete this.cancelBlur;
3995                                         return;
3996                                 }
3998                                 clearTimeout( this.searching );
3999                                 this.close( event );
4000                                 this._change( event );
4001                         }
4002                 } );
4004                 this._initSource();
4005                 this.menu = $( "<ul>" )
4006                         .appendTo( this._appendTo() )
4007                         .menu( {
4009                                 // disable ARIA support, the live region takes care of that
4010                                 role: null
4011                         } )
4012                         .hide()
4013                         .menu( "instance" );
4015                 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
4016                 this._on( this.menu.element, {
4017                         mousedown: function( event ) {
4019                                 // prevent moving focus out of the text field
4020                                 event.preventDefault();
4022                                 // IE doesn't prevent moving focus even with event.preventDefault()
4023                                 // so we set a flag to know when we should ignore the blur event
4024                                 this.cancelBlur = true;
4025                                 this._delay( function() {
4026                                         delete this.cancelBlur;
4028                                         // Support: IE 8 only
4029                                         // Right clicking a menu item or selecting text from the menu items will
4030                                         // result in focus moving out of the input. However, we've already received
4031                                         // and ignored the blur event because of the cancelBlur flag set above. So
4032                                         // we restore focus to ensure that the menu closes properly based on the user's
4033                                         // next actions.
4034                                         if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
4035                                                 this.element.trigger( "focus" );
4036                                         }
4037                                 } );
4038                         },
4039                         menufocus: function( event, ui ) {
4040                                 var label, item;
4042                                 // support: Firefox
4043                                 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
4044                                 if ( this.isNewMenu ) {
4045                                         this.isNewMenu = false;
4046                                         if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
4047                                                 this.menu.blur();
4049                                                 this.document.one( "mousemove", function() {
4050                                                         $( event.target ).trigger( event.originalEvent );
4051                                                 } );
4053                                                 return;
4054                                         }
4055                                 }
4057                                 item = ui.item.data( "ui-autocomplete-item" );
4058                                 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
4060                                         // use value to match what will end up in the input, if it was a key event
4061                                         if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
4062                                                 this._value( item.value );
4063                                         }
4064                                 }
4066                                 // Announce the value in the liveRegion
4067                                 label = ui.item.attr( "aria-label" ) || item.value;
4068                                 if ( label && $.trim( label ).length ) {
4069                                         this.liveRegion.children().hide();
4070                                         $( "<div>" ).text( label ).appendTo( this.liveRegion );
4071                                 }
4072                         },
4073                         menuselect: function( event, ui ) {
4074                                 var item = ui.item.data( "ui-autocomplete-item" ),
4075                                         previous = this.previous;
4077                                 // Only trigger when focus was lost (click on menu)
4078                                 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
4079                                         this.element.trigger( "focus" );
4080                                         this.previous = previous;
4082                                         // #6109 - IE triggers two focus events and the second
4083                                         // is asynchronous, so we need to reset the previous
4084                                         // term synchronously and asynchronously :-(
4085                                         this._delay( function() {
4086                                                 this.previous = previous;
4087                                                 this.selectedItem = item;
4088                                         } );
4089                                 }
4091                                 if ( false !== this._trigger( "select", event, { item: item } ) ) {
4092                                         this._value( item.value );
4093                                 }
4095                                 // reset the term after the select event
4096                                 // this allows custom select handling to work properly
4097                                 this.term = this._value();
4099                                 this.close( event );
4100                                 this.selectedItem = item;
4101                         }
4102                 } );
4104                 this.liveRegion = $( "<div>", {
4105                         role: "status",
4106                         "aria-live": "assertive",
4107                         "aria-relevant": "additions"
4108                 } )
4109                         .appendTo( this.document[ 0 ].body );
4111                 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
4113                 // Turning off autocomplete prevents the browser from remembering the
4114                 // value when navigating through history, so we re-enable autocomplete
4115                 // if the page is unloaded before the widget is destroyed. #7790
4116                 this._on( this.window, {
4117                         beforeunload: function() {
4118                                 this.element.removeAttr( "autocomplete" );
4119                         }
4120                 } );
4121         },
4123         _destroy: function() {
4124                 clearTimeout( this.searching );
4125                 this.element.removeAttr( "autocomplete" );
4126                 this.menu.element.remove();
4127                 this.liveRegion.remove();
4128         },
4130         _setOption: function( key, value ) {
4131                 this._super( key, value );
4132                 if ( key === "source" ) {
4133                         this._initSource();
4134                 }
4135                 if ( key === "appendTo" ) {
4136                         this.menu.element.appendTo( this._appendTo() );
4137                 }
4138                 if ( key === "disabled" && value && this.xhr ) {
4139                         this.xhr.abort();
4140                 }
4141         },
4143         _isEventTargetInWidget: function( event ) {
4144                 var menuElement = this.menu.element[ 0 ];
4146                 return event.target === this.element[ 0 ] ||
4147                         event.target === menuElement ||
4148                         $.contains( menuElement, event.target );
4149         },
4151         _closeOnClickOutside: function( event ) {
4152                 if ( !this._isEventTargetInWidget( event ) ) {
4153                         this.close();
4154                 }
4155         },
4157         _appendTo: function() {
4158                 var element = this.options.appendTo;
4160                 if ( element ) {
4161                         element = element.jquery || element.nodeType ?
4162                                 $( element ) :
4163                                 this.document.find( element ).eq( 0 );
4164                 }
4166                 if ( !element || !element[ 0 ] ) {
4167                         element = this.element.closest( ".ui-front, dialog" );
4168                 }
4170                 if ( !element.length ) {
4171                         element = this.document[ 0 ].body;
4172                 }
4174                 return element;
4175         },
4177         _initSource: function() {
4178                 var array, url,
4179                         that = this;
4180                 if ( $.isArray( this.options.source ) ) {
4181                         array = this.options.source;
4182                         this.source = function( request, response ) {
4183                                 response( $.ui.autocomplete.filter( array, request.term ) );
4184                         };
4185                 } else if ( typeof this.options.source === "string" ) {
4186                         url = this.options.source;
4187                         this.source = function( request, response ) {
4188                                 if ( that.xhr ) {
4189                                         that.xhr.abort();
4190                                 }
4191                                 that.xhr = $.ajax( {
4192                                         url: url,
4193                                         data: request,
4194                                         dataType: "json",
4195                                         success: function( data ) {
4196                                                 response( data );
4197                                         },
4198                                         error: function() {
4199                                                 response( [] );
4200                                         }
4201                                 } );
4202                         };
4203                 } else {
4204                         this.source = this.options.source;
4205                 }
4206         },
4208         _searchTimeout: function( event ) {
4209                 clearTimeout( this.searching );
4210                 this.searching = this._delay( function() {
4212                         // Search if the value has changed, or if the user retypes the same value (see #7434)
4213                         var equalValues = this.term === this._value(),
4214                                 menuVisible = this.menu.element.is( ":visible" ),
4215                                 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
4217                         if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
4218                                 this.selectedItem = null;
4219                                 this.search( null, event );
4220                         }
4221                 }, this.options.delay );
4222         },
4224         search: function( value, event ) {
4225                 value = value != null ? value : this._value();
4227                 // Always save the actual value, not the one passed as an argument
4228                 this.term = this._value();
4230                 if ( value.length < this.options.minLength ) {
4231                         return this.close( event );
4232                 }
4234                 if ( this._trigger( "search", event ) === false ) {
4235                         return;
4236                 }
4238                 return this._search( value );
4239         },
4241         _search: function( value ) {
4242                 this.pending++;
4243                 this._addClass( "ui-autocomplete-loading" );
4244                 this.cancelSearch = false;
4246                 this.source( { term: value }, this._response() );
4247         },
4249         _response: function() {
4250                 var index = ++this.requestIndex;
4252                 return $.proxy( function( content ) {
4253                         if ( index === this.requestIndex ) {
4254                                 this.__response( content );
4255                         }
4257                         this.pending--;
4258                         if ( !this.pending ) {
4259                                 this._removeClass( "ui-autocomplete-loading" );
4260                         }
4261                 }, this );
4262         },
4264         __response: function( content ) {
4265                 if ( content ) {
4266                         content = this._normalize( content );
4267                 }
4268                 this._trigger( "response", null, { content: content } );
4269                 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
4270                         this._suggest( content );
4271                         this._trigger( "open" );
4272                 } else {
4274                         // use ._close() instead of .close() so we don't cancel future searches
4275                         this._close();
4276                 }
4277         },
4279         close: function( event ) {
4280                 this.cancelSearch = true;
4281                 this._close( event );
4282         },
4284         _close: function( event ) {
4286                 // Remove the handler that closes the menu on outside clicks
4287                 this._off( this.document, "mousedown" );
4289                 if ( this.menu.element.is( ":visible" ) ) {
4290                         this.menu.element.hide();
4291                         this.menu.blur();
4292                         this.isNewMenu = true;
4293                         this._trigger( "close", event );
4294                 }
4295         },
4297         _change: function( event ) {
4298                 if ( this.previous !== this._value() ) {
4299                         this._trigger( "change", event, { item: this.selectedItem } );
4300                 }
4301         },
4303         _normalize: function( items ) {
4305                 // assume all items have the right format when the first item is complete
4306                 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
4307                         return items;
4308                 }
4309                 return $.map( items, function( item ) {
4310                         if ( typeof item === "string" ) {
4311                                 return {
4312                                         label: item,
4313                                         value: item
4314                                 };
4315                         }
4316                         return $.extend( {}, item, {
4317                                 label: item.label || item.value,
4318                                 value: item.value || item.label
4319                         } );
4320                 } );
4321         },
4323         _suggest: function( items ) {
4324                 var ul = this.menu.element.empty();
4325                 this._renderMenu( ul, items );
4326                 this.isNewMenu = true;
4327                 this.menu.refresh();
4329                 // Size and position menu
4330                 ul.show();
4331                 this._resizeMenu();
4332                 ul.position( $.extend( {
4333                         of: this.element
4334                 }, this.options.position ) );
4336                 if ( this.options.autoFocus ) {
4337                         this.menu.next();
4338                 }
4340                 // Listen for interactions outside of the widget (#6642)
4341                 this._on( this.document, {
4342                         mousedown: "_closeOnClickOutside"
4343                 } );
4344         },
4346         _resizeMenu: function() {
4347                 var ul = this.menu.element;
4348                 ul.outerWidth( Math.max(
4350                         // Firefox wraps long text (possibly a rounding bug)
4351                         // so we add 1px to avoid the wrapping (#7513)
4352                         ul.width( "" ).outerWidth() + 1,
4353                         this.element.outerWidth()
4354                 ) );
4355         },
4357         _renderMenu: function( ul, items ) {
4358                 var that = this;
4359                 $.each( items, function( index, item ) {
4360                         that._renderItemData( ul, item );
4361                 } );
4362         },
4364         _renderItemData: function( ul, item ) {
4365                 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
4366         },
4368         _renderItem: function( ul, item ) {
4369                 return $( "<li>" )
4370                         .append( $( "<div>" ).text( item.label ) )
4371                         .appendTo( ul );
4372         },
4374         _move: function( direction, event ) {
4375                 if ( !this.menu.element.is( ":visible" ) ) {
4376                         this.search( null, event );
4377                         return;
4378                 }
4379                 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
4380                                 this.menu.isLastItem() && /^next/.test( direction ) ) {
4382                         if ( !this.isMultiLine ) {
4383                                 this._value( this.term );
4384                         }
4386                         this.menu.blur();
4387                         return;
4388                 }
4389                 this.menu[ direction ]( event );
4390         },
4392         widget: function() {
4393                 return this.menu.element;
4394         },
4396         _value: function() {
4397                 return this.valueMethod.apply( this.element, arguments );
4398         },
4400         _keyEvent: function( keyEvent, event ) {
4401                 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
4402                         this._move( keyEvent, event );
4404                         // Prevents moving cursor to beginning/end of the text field in some browsers
4405                         event.preventDefault();
4406                 }
4407         },
4409         // Support: Chrome <=50
4410         // We should be able to just use this.element.prop( "isContentEditable" )
4411         // but hidden elements always report false in Chrome.
4412         // https://code.google.com/p/chromium/issues/detail?id=313082
4413         _isContentEditable: function( element ) {
4414                 if ( !element.length ) {
4415                         return false;
4416                 }
4418                 var editable = element.prop( "contentEditable" );
4420                 if ( editable === "inherit" ) {
4421                   return this._isContentEditable( element.parent() );
4422                 }
4424                 return editable === "true";
4425         }
4426 } );
4428 $.extend( $.ui.autocomplete, {
4429         escapeRegex: function( value ) {
4430                 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
4431         },
4432         filter: function( array, term ) {
4433                 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
4434                 return $.grep( array, function( value ) {
4435                         return matcher.test( value.label || value.value || value );
4436                 } );
4437         }
4438 } );
4440 // Live region extension, adding a `messages` option
4441 // NOTE: This is an experimental API. We are still investigating
4442 // a full solution for string manipulation and internationalization.
4443 $.widget( "ui.autocomplete", $.ui.autocomplete, {
4444         options: {
4445                 messages: {
4446                         noResults: "No search results.",
4447                         results: function( amount ) {
4448                                 return amount + ( amount > 1 ? " results are" : " result is" ) +
4449                                         " available, use up and down arrow keys to navigate.";
4450                         }
4451                 }
4452         },
4454         __response: function( content ) {
4455                 var message;
4456                 this._superApply( arguments );
4457                 if ( this.options.disabled || this.cancelSearch ) {
4458                         return;
4459                 }
4460                 if ( content && content.length ) {
4461                         message = this.options.messages.results( content.length );
4462                 } else {
4463                         message = this.options.messages.noResults;
4464                 }
4465                 this.liveRegion.children().hide();
4466                 $( "<div>" ).text( message ).appendTo( this.liveRegion );
4467         }
4468 } );
4470 var widgetsAutocomplete = $.ui.autocomplete;
4473 // jscs:disable maximumLineLength
4474 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
4476  * jQuery UI Datepicker 1.12.1
4477  * http://jqueryui.com
4479  * Copyright jQuery Foundation and other contributors
4480  * Released under the MIT license.
4481  * http://jquery.org/license
4482  */
4484 //>>label: Datepicker
4485 //>>group: Widgets
4486 //>>description: Displays a calendar from an input or inline for selecting dates.
4487 //>>docs: http://api.jqueryui.com/datepicker/
4488 //>>demos: http://jqueryui.com/datepicker/
4489 //>>css.structure: ../../themes/base/core.css
4490 //>>css.structure: ../../themes/base/datepicker.css
4491 //>>css.theme: ../../themes/base/theme.css
4495 $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
4497 var datepicker_instActive;
4499 function datepicker_getZindex( elem ) {
4500         var position, value;
4501         while ( elem.length && elem[ 0 ] !== document ) {
4503                 // Ignore z-index if position is set to a value where z-index is ignored by the browser
4504                 // This makes behavior of this function consistent across browsers
4505                 // WebKit always returns auto if the element is positioned
4506                 position = elem.css( "position" );
4507                 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
4509                         // IE returns 0 when zIndex is not specified
4510                         // other browsers return a string
4511                         // we ignore the case of nested elements with an explicit value of 0
4512                         // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
4513                         value = parseInt( elem.css( "zIndex" ), 10 );
4514                         if ( !isNaN( value ) && value !== 0 ) {
4515                                 return value;
4516                         }
4517                 }
4518                 elem = elem.parent();
4519         }
4521         return 0;
4523 /* Date picker manager.
4524    Use the singleton instance of this class, $.datepicker, to interact with the date picker.
4525    Settings for (groups of) date pickers are maintained in an instance object,
4526    allowing multiple different settings on the same page. */
4528 function Datepicker() {
4529         this._curInst = null; // The current instance in use
4530         this._keyEvent = false; // If the last event was a key event
4531         this._disabledInputs = []; // List of date picker inputs that have been disabled
4532         this._datepickerShowing = false; // True if the popup picker is showing , false if not
4533         this._inDialog = false; // True if showing within a "dialog", false if not
4534         this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
4535         this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
4536         this._appendClass = "ui-datepicker-append"; // The name of the append marker class
4537         this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
4538         this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
4539         this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
4540         this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
4541         this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
4542         this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
4543         this.regional = []; // Available regional settings, indexed by language code
4544         this.regional[ "" ] = { // Default regional settings
4545                 closeText: "Done", // Display text for close link
4546                 prevText: "Prev", // Display text for previous month link
4547                 nextText: "Next", // Display text for next month link
4548                 currentText: "Today", // Display text for current month link
4549                 monthNames: [ "January","February","March","April","May","June",
4550                         "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
4551                 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
4552                 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
4553                 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
4554                 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
4555                 weekHeader: "Wk", // Column header for week of the year
4556                 dateFormat: "mm/dd/yy", // See format options on parseDate
4557                 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
4558                 isRTL: false, // True if right-to-left language, false if left-to-right
4559                 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
4560                 yearSuffix: "" // Additional text to append to the year in the month headers
4561         };
4562         this._defaults = { // Global defaults for all the date picker instances
4563                 showOn: "focus", // "focus" for popup on focus,
4564                         // "button" for trigger button, or "both" for either
4565                 showAnim: "fadeIn", // Name of jQuery animation for popup
4566                 showOptions: {}, // Options for enhanced animations
4567                 defaultDate: null, // Used when field is blank: actual date,
4568                         // +/-number for offset from today, null for today
4569                 appendText: "", // Display text following the input box, e.g. showing the format
4570                 buttonText: "...", // Text for trigger button
4571                 buttonImage: "", // URL for trigger button image
4572                 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
4573                 hideIfNoPrevNext: false, // True to hide next/previous month links
4574                         // if not applicable, false to just disable them
4575                 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
4576                 gotoCurrent: false, // True if today link goes back to current selection instead
4577                 changeMonth: false, // True if month can be selected directly, false if only prev/next
4578                 changeYear: false, // True if year can be selected directly, false if only prev/next
4579                 yearRange: "c-10:c+10", // Range of years to display in drop-down,
4580                         // either relative to today's year (-nn:+nn), relative to currently displayed year
4581                         // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
4582                 showOtherMonths: false, // True to show dates in other months, false to leave blank
4583                 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
4584                 showWeek: false, // True to show week of the year, false to not show it
4585                 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
4586                         // takes a Date and returns the number of the week for it
4587                 shortYearCutoff: "+10", // Short year values < this are in the current century,
4588                         // > this are in the previous century,
4589                         // string value starting with "+" for current year + value
4590                 minDate: null, // The earliest selectable date, or null for no limit
4591                 maxDate: null, // The latest selectable date, or null for no limit
4592                 duration: "fast", // Duration of display/closure
4593                 beforeShowDay: null, // Function that takes a date and returns an array with
4594                         // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
4595                         // [2] = cell title (optional), e.g. $.datepicker.noWeekends
4596                 beforeShow: null, // Function that takes an input field and
4597                         // returns a set of custom settings for the date picker
4598                 onSelect: null, // Define a callback function when a date is selected
4599                 onChangeMonthYear: null, // Define a callback function when the month or year is changed
4600                 onClose: null, // Define a callback function when the datepicker is closed
4601                 numberOfMonths: 1, // Number of months to show at a time
4602                 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
4603                 stepMonths: 1, // Number of months to step back/forward
4604                 stepBigMonths: 12, // Number of months to step back/forward for the big links
4605                 altField: "", // Selector for an alternate field to store selected dates into
4606                 altFormat: "", // The date format to use for the alternate field
4607                 constrainInput: true, // The input is constrained by the current date format
4608                 showButtonPanel: false, // True to show button panel, false to not show it
4609                 autoSize: false, // True to size the input for the date format, false to leave as is
4610                 disabled: false // The initial disabled state
4611         };
4612         $.extend( this._defaults, this.regional[ "" ] );
4613         this.regional.en = $.extend( true, {}, this.regional[ "" ] );
4614         this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
4615         this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
4618 $.extend( Datepicker.prototype, {
4619         /* Class name added to elements to indicate already configured with a date picker. */
4620         markerClassName: "hasDatepicker",
4622         //Keep track of the maximum number of rows displayed (see #7043)
4623         maxRows: 4,
4625         // TODO rename to "widget" when switching to widget factory
4626         _widgetDatepicker: function() {
4627                 return this.dpDiv;
4628         },
4630         /* Override the default settings for all instances of the date picker.
4631          * @param  settings  object - the new settings to use as defaults (anonymous object)
4632          * @return the manager object
4633          */
4634         setDefaults: function( settings ) {
4635                 datepicker_extendRemove( this._defaults, settings || {} );
4636                 return this;
4637         },
4639         /* Attach the date picker to a jQuery selection.
4640          * @param  target       element - the target input field or division or span
4641          * @param  settings  object - the new settings to use for this date picker instance (anonymous)
4642          */
4643         _attachDatepicker: function( target, settings ) {
4644                 var nodeName, inline, inst;
4645                 nodeName = target.nodeName.toLowerCase();
4646                 inline = ( nodeName === "div" || nodeName === "span" );
4647                 if ( !target.id ) {
4648                         this.uuid += 1;
4649                         target.id = "dp" + this.uuid;
4650                 }
4651                 inst = this._newInst( $( target ), inline );
4652                 inst.settings = $.extend( {}, settings || {} );
4653                 if ( nodeName === "input" ) {
4654                         this._connectDatepicker( target, inst );
4655                 } else if ( inline ) {
4656                         this._inlineDatepicker( target, inst );
4657                 }
4658         },
4660         /* Create a new instance object. */
4661         _newInst: function( target, inline ) {
4662                 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
4663                 return { id: id, input: target, // associated target
4664                         selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
4665                         drawMonth: 0, drawYear: 0, // month being drawn
4666                         inline: inline, // is datepicker inline or not
4667                         dpDiv: ( !inline ? this.dpDiv : // presentation div
4668                         datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
4669         },
4671         /* Attach the date picker to an input field. */
4672         _connectDatepicker: function( target, inst ) {
4673                 var input = $( target );
4674                 inst.append = $( [] );
4675                 inst.trigger = $( [] );
4676                 if ( input.hasClass( this.markerClassName ) ) {
4677                         return;
4678                 }
4679                 this._attachments( input, inst );
4680                 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
4681                         on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
4682                 this._autoSize( inst );
4683                 $.data( target, "datepicker", inst );
4685                 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
4686                 if ( inst.settings.disabled ) {
4687                         this._disableDatepicker( target );
4688                 }
4689         },
4691         /* Make attachments based on settings. */
4692         _attachments: function( input, inst ) {
4693                 var showOn, buttonText, buttonImage,
4694                         appendText = this._get( inst, "appendText" ),
4695                         isRTL = this._get( inst, "isRTL" );
4697                 if ( inst.append ) {
4698                         inst.append.remove();
4699                 }
4700                 if ( appendText ) {
4701                         inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
4702                         input[ isRTL ? "before" : "after" ]( inst.append );
4703                 }
4705                 input.off( "focus", this._showDatepicker );
4707                 if ( inst.trigger ) {
4708                         inst.trigger.remove();
4709                 }
4711                 showOn = this._get( inst, "showOn" );
4712                 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
4713                         input.on( "focus", this._showDatepicker );
4714                 }
4715                 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
4716                         buttonText = this._get( inst, "buttonText" );
4717                         buttonImage = this._get( inst, "buttonImage" );
4718                         inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
4719                                 $( "<img/>" ).addClass( this._triggerClass ).
4720                                         attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
4721                                 $( "<button type='button'></button>" ).addClass( this._triggerClass ).
4722                                         html( !buttonImage ? buttonText : $( "<img/>" ).attr(
4723                                         { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
4724                         input[ isRTL ? "before" : "after" ]( inst.trigger );
4725                         inst.trigger.on( "click", function() {
4726                                 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
4727                                         $.datepicker._hideDatepicker();
4728                                 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
4729                                         $.datepicker._hideDatepicker();
4730                                         $.datepicker._showDatepicker( input[ 0 ] );
4731                                 } else {
4732                                         $.datepicker._showDatepicker( input[ 0 ] );
4733                                 }
4734                                 return false;
4735                         } );
4736                 }
4737         },
4739         /* Apply the maximum length for the date format. */
4740         _autoSize: function( inst ) {
4741                 if ( this._get( inst, "autoSize" ) && !inst.inline ) {
4742                         var findMax, max, maxI, i,
4743                                 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
4744                                 dateFormat = this._get( inst, "dateFormat" );
4746                         if ( dateFormat.match( /[DM]/ ) ) {
4747                                 findMax = function( names ) {
4748                                         max = 0;
4749                                         maxI = 0;
4750                                         for ( i = 0; i < names.length; i++ ) {
4751                                                 if ( names[ i ].length > max ) {
4752                                                         max = names[ i ].length;
4753                                                         maxI = i;
4754                                                 }
4755                                         }
4756                                         return maxI;
4757                                 };
4758                                 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
4759                                         "monthNames" : "monthNamesShort" ) ) ) );
4760                                 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
4761                                         "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
4762                         }
4763                         inst.input.attr( "size", this._formatDate( inst, date ).length );
4764                 }
4765         },
4767         /* Attach an inline date picker to a div. */
4768         _inlineDatepicker: function( target, inst ) {
4769                 var divSpan = $( target );
4770                 if ( divSpan.hasClass( this.markerClassName ) ) {
4771                         return;
4772                 }
4773                 divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
4774                 $.data( target, "datepicker", inst );
4775                 this._setDate( inst, this._getDefaultDate( inst ), true );
4776                 this._updateDatepicker( inst );
4777                 this._updateAlternate( inst );
4779                 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4780                 if ( inst.settings.disabled ) {
4781                         this._disableDatepicker( target );
4782                 }
4784                 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4785                 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4786                 inst.dpDiv.css( "display", "block" );
4787         },
4789         /* Pop-up the date picker in a "dialog" box.
4790          * @param  input element - ignored
4791          * @param  date string or Date - the initial date to display
4792          * @param  onSelect  function - the function to call when a date is selected
4793          * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
4794          * @param  pos int[2] - coordinates for the dialog's position within the screen or
4795          *                                      event - with x/y coordinates or
4796          *                                      leave empty for default (screen centre)
4797          * @return the manager object
4798          */
4799         _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
4800                 var id, browserWidth, browserHeight, scrollX, scrollY,
4801                         inst = this._dialogInst; // internal instance
4803                 if ( !inst ) {
4804                         this.uuid += 1;
4805                         id = "dp" + this.uuid;
4806                         this._dialogInput = $( "<input type='text' id='" + id +
4807                                 "' style='position: absolute; top: -100px; width: 0px;'/>" );
4808                         this._dialogInput.on( "keydown", this._doKeyDown );
4809                         $( "body" ).append( this._dialogInput );
4810                         inst = this._dialogInst = this._newInst( this._dialogInput, false );
4811                         inst.settings = {};
4812                         $.data( this._dialogInput[ 0 ], "datepicker", inst );
4813                 }
4814                 datepicker_extendRemove( inst.settings, settings || {} );
4815                 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
4816                 this._dialogInput.val( date );
4818                 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
4819                 if ( !this._pos ) {
4820                         browserWidth = document.documentElement.clientWidth;
4821                         browserHeight = document.documentElement.clientHeight;
4822                         scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4823                         scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4824                         this._pos = // should use actual width/height below
4825                                 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
4826                 }
4828                 // Move input on screen for focus, but hidden behind dialog
4829                 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
4830                 inst.settings.onSelect = onSelect;
4831                 this._inDialog = true;
4832                 this.dpDiv.addClass( this._dialogClass );
4833                 this._showDatepicker( this._dialogInput[ 0 ] );
4834                 if ( $.blockUI ) {
4835                         $.blockUI( this.dpDiv );
4836                 }
4837                 $.data( this._dialogInput[ 0 ], "datepicker", inst );
4838                 return this;
4839         },
4841         /* Detach a datepicker from its control.
4842          * @param  target       element - the target input field or division or span
4843          */
4844         _destroyDatepicker: function( target ) {
4845                 var nodeName,
4846                         $target = $( target ),
4847                         inst = $.data( target, "datepicker" );
4849                 if ( !$target.hasClass( this.markerClassName ) ) {
4850                         return;
4851                 }
4853                 nodeName = target.nodeName.toLowerCase();
4854                 $.removeData( target, "datepicker" );
4855                 if ( nodeName === "input" ) {
4856                         inst.append.remove();
4857                         inst.trigger.remove();
4858                         $target.removeClass( this.markerClassName ).
4859                                 off( "focus", this._showDatepicker ).
4860                                 off( "keydown", this._doKeyDown ).
4861                                 off( "keypress", this._doKeyPress ).
4862                                 off( "keyup", this._doKeyUp );
4863                 } else if ( nodeName === "div" || nodeName === "span" ) {
4864                         $target.removeClass( this.markerClassName ).empty();
4865                 }
4867                 if ( datepicker_instActive === inst ) {
4868                         datepicker_instActive = null;
4869                 }
4870         },
4872         /* Enable the date picker to a jQuery selection.
4873          * @param  target       element - the target input field or division or span
4874          */
4875         _enableDatepicker: function( target ) {
4876                 var nodeName, inline,
4877                         $target = $( target ),
4878                         inst = $.data( target, "datepicker" );
4880                 if ( !$target.hasClass( this.markerClassName ) ) {
4881                         return;
4882                 }
4884                 nodeName = target.nodeName.toLowerCase();
4885                 if ( nodeName === "input" ) {
4886                         target.disabled = false;
4887                         inst.trigger.filter( "button" ).
4888                                 each( function() { this.disabled = false; } ).end().
4889                                 filter( "img" ).css( { opacity: "1.0", cursor: "" } );
4890                 } else if ( nodeName === "div" || nodeName === "span" ) {
4891                         inline = $target.children( "." + this._inlineClass );
4892                         inline.children().removeClass( "ui-state-disabled" );
4893                         inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
4894                                 prop( "disabled", false );
4895                 }
4896                 this._disabledInputs = $.map( this._disabledInputs,
4897                         function( value ) { return ( value === target ? null : value ); } ); // delete entry
4898         },
4900         /* Disable the date picker to a jQuery selection.
4901          * @param  target       element - the target input field or division or span
4902          */
4903         _disableDatepicker: function( target ) {
4904                 var nodeName, inline,
4905                         $target = $( target ),
4906                         inst = $.data( target, "datepicker" );
4908                 if ( !$target.hasClass( this.markerClassName ) ) {
4909                         return;
4910                 }
4912                 nodeName = target.nodeName.toLowerCase();
4913                 if ( nodeName === "input" ) {
4914                         target.disabled = true;
4915                         inst.trigger.filter( "button" ).
4916                                 each( function() { this.disabled = true; } ).end().
4917                                 filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
4918                 } else if ( nodeName === "div" || nodeName === "span" ) {
4919                         inline = $target.children( "." + this._inlineClass );
4920                         inline.children().addClass( "ui-state-disabled" );
4921                         inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
4922                                 prop( "disabled", true );
4923                 }
4924                 this._disabledInputs = $.map( this._disabledInputs,
4925                         function( value ) { return ( value === target ? null : value ); } ); // delete entry
4926                 this._disabledInputs[ this._disabledInputs.length ] = target;
4927         },
4929         /* Is the first field in a jQuery collection disabled as a datepicker?
4930          * @param  target       element - the target input field or division or span
4931          * @return boolean - true if disabled, false if enabled
4932          */
4933         _isDisabledDatepicker: function( target ) {
4934                 if ( !target ) {
4935                         return false;
4936                 }
4937                 for ( var i = 0; i < this._disabledInputs.length; i++ ) {
4938                         if ( this._disabledInputs[ i ] === target ) {
4939                                 return true;
4940                         }
4941                 }
4942                 return false;
4943         },
4945         /* Retrieve the instance data for the target control.
4946          * @param  target  element - the target input field or division or span
4947          * @return  object - the associated instance data
4948          * @throws  error if a jQuery problem getting data
4949          */
4950         _getInst: function( target ) {
4951                 try {
4952                         return $.data( target, "datepicker" );
4953                 }
4954                 catch ( err ) {
4955                         throw "Missing instance data for this datepicker";
4956                 }
4957         },
4959         /* Update or retrieve the settings for a date picker attached to an input field or division.
4960          * @param  target  element - the target input field or division or span
4961          * @param  name object - the new settings to update or
4962          *                              string - the name of the setting to change or retrieve,
4963          *                              when retrieving also "all" for all instance settings or
4964          *                              "defaults" for all global defaults
4965          * @param  value   any - the new value for the setting
4966          *                              (omit if above is an object or to retrieve a value)
4967          */
4968         _optionDatepicker: function( target, name, value ) {
4969                 var settings, date, minDate, maxDate,
4970                         inst = this._getInst( target );
4972                 if ( arguments.length === 2 && typeof name === "string" ) {
4973                         return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
4974                                 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
4975                                 this._get( inst, name ) ) : null ) );
4976                 }
4978                 settings = name || {};
4979                 if ( typeof name === "string" ) {
4980                         settings = {};
4981                         settings[ name ] = value;
4982                 }
4984                 if ( inst ) {
4985                         if ( this._curInst === inst ) {
4986                                 this._hideDatepicker();
4987                         }
4989                         date = this._getDateDatepicker( target, true );
4990                         minDate = this._getMinMaxDate( inst, "min" );
4991                         maxDate = this._getMinMaxDate( inst, "max" );
4992                         datepicker_extendRemove( inst.settings, settings );
4994                         // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4995                         if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
4996                                 inst.settings.minDate = this._formatDate( inst, minDate );
4997                         }
4998                         if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
4999                                 inst.settings.maxDate = this._formatDate( inst, maxDate );
5000                         }
5001                         if ( "disabled" in settings ) {
5002                                 if ( settings.disabled ) {
5003                                         this._disableDatepicker( target );
5004                                 } else {
5005                                         this._enableDatepicker( target );
5006                                 }
5007                         }
5008                         this._attachments( $( target ), inst );
5009                         this._autoSize( inst );
5010                         this._setDate( inst, date );
5011                         this._updateAlternate( inst );
5012                         this._updateDatepicker( inst );
5013                 }
5014         },
5016         // Change method deprecated
5017         _changeDatepicker: function( target, name, value ) {
5018                 this._optionDatepicker( target, name, value );
5019         },
5021         /* Redraw the date picker attached to an input field or division.
5022          * @param  target  element - the target input field or division or span
5023          */
5024         _refreshDatepicker: function( target ) {
5025                 var inst = this._getInst( target );
5026                 if ( inst ) {
5027                         this._updateDatepicker( inst );
5028                 }
5029         },
5031         /* Set the dates for a jQuery selection.
5032          * @param  target element - the target input field or division or span
5033          * @param  date Date - the new date
5034          */
5035         _setDateDatepicker: function( target, date ) {
5036                 var inst = this._getInst( target );
5037                 if ( inst ) {
5038                         this._setDate( inst, date );
5039                         this._updateDatepicker( inst );
5040                         this._updateAlternate( inst );
5041                 }
5042         },
5044         /* Get the date(s) for the first entry in a jQuery selection.
5045          * @param  target element - the target input field or division or span
5046          * @param  noDefault boolean - true if no default date is to be used
5047          * @return Date - the current date
5048          */
5049         _getDateDatepicker: function( target, noDefault ) {
5050                 var inst = this._getInst( target );
5051                 if ( inst && !inst.inline ) {
5052                         this._setDateFromField( inst, noDefault );
5053                 }
5054                 return ( inst ? this._getDate( inst ) : null );
5055         },
5057         /* Handle keystrokes. */
5058         _doKeyDown: function( event ) {
5059                 var onSelect, dateStr, sel,
5060                         inst = $.datepicker._getInst( event.target ),
5061                         handled = true,
5062                         isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
5064                 inst._keyEvent = true;
5065                 if ( $.datepicker._datepickerShowing ) {
5066                         switch ( event.keyCode ) {
5067                                 case 9: $.datepicker._hideDatepicker();
5068                                                 handled = false;
5069                                                 break; // hide on tab out
5070                                 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
5071                                                                         $.datepicker._currentClass + ")", inst.dpDiv );
5072                                                 if ( sel[ 0 ] ) {
5073                                                         $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
5074                                                 }
5076                                                 onSelect = $.datepicker._get( inst, "onSelect" );
5077                                                 if ( onSelect ) {
5078                                                         dateStr = $.datepicker._formatDate( inst );
5080                                                         // Trigger custom callback
5081                                                         onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
5082                                                 } else {
5083                                                         $.datepicker._hideDatepicker();
5084                                                 }
5086                                                 return false; // don't submit the form
5087                                 case 27: $.datepicker._hideDatepicker();
5088                                                 break; // hide on escape
5089                                 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
5090                                                         -$.datepicker._get( inst, "stepBigMonths" ) :
5091                                                         -$.datepicker._get( inst, "stepMonths" ) ), "M" );
5092                                                 break; // previous month/year on page up/+ ctrl
5093                                 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
5094                                                         +$.datepicker._get( inst, "stepBigMonths" ) :
5095                                                         +$.datepicker._get( inst, "stepMonths" ) ), "M" );
5096                                                 break; // next month/year on page down/+ ctrl
5097                                 case 35: if ( event.ctrlKey || event.metaKey ) {
5098                                                         $.datepicker._clearDate( event.target );
5099                                                 }
5100                                                 handled = event.ctrlKey || event.metaKey;
5101                                                 break; // clear on ctrl or command +end
5102                                 case 36: if ( event.ctrlKey || event.metaKey ) {
5103                                                         $.datepicker._gotoToday( event.target );
5104                                                 }
5105                                                 handled = event.ctrlKey || event.metaKey;
5106                                                 break; // current on ctrl or command +home
5107                                 case 37: if ( event.ctrlKey || event.metaKey ) {
5108                                                         $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
5109                                                 }
5110                                                 handled = event.ctrlKey || event.metaKey;
5112                                                 // -1 day on ctrl or command +left
5113                                                 if ( event.originalEvent.altKey ) {
5114                                                         $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
5115                                                                 -$.datepicker._get( inst, "stepBigMonths" ) :
5116                                                                 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
5117                                                 }
5119                                                 // next month/year on alt +left on Mac
5120                                                 break;
5121                                 case 38: if ( event.ctrlKey || event.metaKey ) {
5122                                                         $.datepicker._adjustDate( event.target, -7, "D" );
5123                                                 }
5124                                                 handled = event.ctrlKey || event.metaKey;
5125                                                 break; // -1 week on ctrl or command +up
5126                                 case 39: if ( event.ctrlKey || event.metaKey ) {
5127                                                         $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
5128                                                 }
5129                                                 handled = event.ctrlKey || event.metaKey;
5131                                                 // +1 day on ctrl or command +right
5132                                                 if ( event.originalEvent.altKey ) {
5133                                                         $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
5134                                                                 +$.datepicker._get( inst, "stepBigMonths" ) :
5135                                                                 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
5136                                                 }
5138                                                 // next month/year on alt +right
5139                                                 break;
5140                                 case 40: if ( event.ctrlKey || event.metaKey ) {
5141                                                         $.datepicker._adjustDate( event.target, +7, "D" );
5142                                                 }
5143                                                 handled = event.ctrlKey || event.metaKey;
5144                                                 break; // +1 week on ctrl or command +down
5145                                 default: handled = false;
5146                         }
5147                 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
5148                         $.datepicker._showDatepicker( this );
5149                 } else {
5150                         handled = false;
5151                 }
5153                 if ( handled ) {
5154                         event.preventDefault();
5155                         event.stopPropagation();
5156                 }
5157         },
5159         /* Filter entered characters - based on date format. */
5160         _doKeyPress: function( event ) {
5161                 var chars, chr,
5162                         inst = $.datepicker._getInst( event.target );
5164                 if ( $.datepicker._get( inst, "constrainInput" ) ) {
5165                         chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
5166                         chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
5167                         return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
5168                 }
5169         },
5171         /* Synchronise manual entry and field/alternate field. */
5172         _doKeyUp: function( event ) {
5173                 var date,
5174                         inst = $.datepicker._getInst( event.target );
5176                 if ( inst.input.val() !== inst.lastVal ) {
5177                         try {
5178                                 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
5179                                         ( inst.input ? inst.input.val() : null ),
5180                                         $.datepicker._getFormatConfig( inst ) );
5182                                 if ( date ) { // only if valid
5183                                         $.datepicker._setDateFromField( inst );
5184                                         $.datepicker._updateAlternate( inst );
5185                                         $.datepicker._updateDatepicker( inst );
5186                                 }
5187                         }
5188                         catch ( err ) {
5189                         }
5190                 }
5191                 return true;
5192         },
5194         /* Pop-up the date picker for a given input field.
5195          * If false returned from beforeShow event handler do not show.
5196          * @param  input  element - the input field attached to the date picker or
5197          *                                      event - if triggered by focus
5198          */
5199         _showDatepicker: function( input ) {
5200                 input = input.target || input;
5201                 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
5202                         input = $( "input", input.parentNode )[ 0 ];
5203                 }
5205                 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
5206                         return;
5207                 }
5209                 var inst, beforeShow, beforeShowSettings, isFixed,
5210                         offset, showAnim, duration;
5212                 inst = $.datepicker._getInst( input );
5213                 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
5214                         $.datepicker._curInst.dpDiv.stop( true, true );
5215                         if ( inst && $.datepicker._datepickerShowing ) {
5216                                 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
5217                         }
5218                 }
5220                 beforeShow = $.datepicker._get( inst, "beforeShow" );
5221                 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
5222                 if ( beforeShowSettings === false ) {
5223                         return;
5224                 }
5225                 datepicker_extendRemove( inst.settings, beforeShowSettings );
5227                 inst.lastVal = null;
5228                 $.datepicker._lastInput = input;
5229                 $.datepicker._setDateFromField( inst );
5231                 if ( $.datepicker._inDialog ) { // hide cursor
5232                         input.value = "";
5233                 }
5234                 if ( !$.datepicker._pos ) { // position below input
5235                         $.datepicker._pos = $.datepicker._findPos( input );
5236                         $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
5237                 }
5239                 isFixed = false;
5240                 $( input ).parents().each( function() {
5241                         isFixed |= $( this ).css( "position" ) === "fixed";
5242                         return !isFixed;
5243                 } );
5245                 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
5246                 $.datepicker._pos = null;
5248                 //to avoid flashes on Firefox
5249                 inst.dpDiv.empty();
5251                 // determine sizing offscreen
5252                 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
5253                 $.datepicker._updateDatepicker( inst );
5255                 // fix width for dynamic number of date pickers
5256                 // and adjust position before showing
5257                 offset = $.datepicker._checkOffset( inst, offset, isFixed );
5258                 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
5259                         "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
5260                         left: offset.left + "px", top: offset.top + "px" } );
5262                 if ( !inst.inline ) {
5263                         showAnim = $.datepicker._get( inst, "showAnim" );
5264                         duration = $.datepicker._get( inst, "duration" );
5265                         inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
5266                         $.datepicker._datepickerShowing = true;
5268                         if ( $.effects && $.effects.effect[ showAnim ] ) {
5269                                 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
5270                         } else {
5271                                 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
5272                         }
5274                         if ( $.datepicker._shouldFocusInput( inst ) ) {
5275                                 inst.input.trigger( "focus" );
5276                         }
5278                         $.datepicker._curInst = inst;
5279                 }
5280         },
5282         /* Generate the date picker content. */
5283         _updateDatepicker: function( inst ) {
5284                 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
5285                 datepicker_instActive = inst; // for delegate hover events
5286                 inst.dpDiv.empty().append( this._generateHTML( inst ) );
5287                 this._attachHandlers( inst );
5289                 var origyearshtml,
5290                         numMonths = this._getNumberOfMonths( inst ),
5291                         cols = numMonths[ 1 ],
5292                         width = 17,
5293                         activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
5295                 if ( activeCell.length > 0 ) {
5296                         datepicker_handleMouseover.apply( activeCell.get( 0 ) );
5297                 }
5299                 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
5300                 if ( cols > 1 ) {
5301                         inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
5302                 }
5303                 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
5304                         "Class" ]( "ui-datepicker-multi" );
5305                 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
5306                         "Class" ]( "ui-datepicker-rtl" );
5308                 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
5309                         inst.input.trigger( "focus" );
5310                 }
5312                 // Deffered render of the years select (to avoid flashes on Firefox)
5313                 if ( inst.yearshtml ) {
5314                         origyearshtml = inst.yearshtml;
5315                         setTimeout( function() {
5317                                 //assure that inst.yearshtml didn't change.
5318                                 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
5319                                         inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
5320                                 }
5321                                 origyearshtml = inst.yearshtml = null;
5322                         }, 0 );
5323                 }
5324         },
5326         // #6694 - don't focus the input if it's already focused
5327         // this breaks the change event in IE
5328         // Support: IE and jQuery <1.9
5329         _shouldFocusInput: function( inst ) {
5330                 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
5331         },
5333         /* Check positioning to remain on screen. */
5334         _checkOffset: function( inst, offset, isFixed ) {
5335                 var dpWidth = inst.dpDiv.outerWidth(),
5336                         dpHeight = inst.dpDiv.outerHeight(),
5337                         inputWidth = inst.input ? inst.input.outerWidth() : 0,
5338                         inputHeight = inst.input ? inst.input.outerHeight() : 0,
5339                         viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
5340                         viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
5342                 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
5343                 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
5344                 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
5346                 // Now check if datepicker is showing outside window viewport - move to a better place if so.
5347                 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
5348                         Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
5349                 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
5350                         Math.abs( dpHeight + inputHeight ) : 0 );
5352                 return offset;
5353         },
5355         /* Find an object's position on the screen. */
5356         _findPos: function( obj ) {
5357                 var position,
5358                         inst = this._getInst( obj ),
5359                         isRTL = this._get( inst, "isRTL" );
5361                 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
5362                         obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
5363                 }
5365                 position = $( obj ).offset();
5366                 return [ position.left, position.top ];
5367         },
5369         /* Hide the date picker from view.
5370          * @param  input  element - the input field attached to the date picker
5371          */
5372         _hideDatepicker: function( input ) {
5373                 var showAnim, duration, postProcess, onClose,
5374                         inst = this._curInst;
5376                 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
5377                         return;
5378                 }
5380                 if ( this._datepickerShowing ) {
5381                         showAnim = this._get( inst, "showAnim" );
5382                         duration = this._get( inst, "duration" );
5383                         postProcess = function() {
5384                                 $.datepicker._tidyDialog( inst );
5385                         };
5387                         // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
5388                         if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
5389                                 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
5390                         } else {
5391                                 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
5392                                         ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
5393                         }
5395                         if ( !showAnim ) {
5396                                 postProcess();
5397                         }
5398                         this._datepickerShowing = false;
5400                         onClose = this._get( inst, "onClose" );
5401                         if ( onClose ) {
5402                                 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
5403                         }
5405                         this._lastInput = null;
5406                         if ( this._inDialog ) {
5407                                 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
5408                                 if ( $.blockUI ) {
5409                                         $.unblockUI();
5410                                         $( "body" ).append( this.dpDiv );
5411                                 }
5412                         }
5413                         this._inDialog = false;
5414                 }
5415         },
5417         /* Tidy up after a dialog display. */
5418         _tidyDialog: function( inst ) {
5419                 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
5420         },
5422         /* Close date picker if clicked elsewhere. */
5423         _checkExternalClick: function( event ) {
5424                 if ( !$.datepicker._curInst ) {
5425                         return;
5426                 }
5428                 var $target = $( event.target ),
5429                         inst = $.datepicker._getInst( $target[ 0 ] );
5431                 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
5432                                 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
5433                                 !$target.hasClass( $.datepicker.markerClassName ) &&
5434                                 !$target.closest( "." + $.datepicker._triggerClass ).length &&
5435                                 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
5436                         ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
5437                                 $.datepicker._hideDatepicker();
5438                 }
5439         },
5441         /* Adjust one of the date sub-fields. */
5442         _adjustDate: function( id, offset, period ) {
5443                 var target = $( id ),
5444                         inst = this._getInst( target[ 0 ] );
5446                 if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
5447                         return;
5448                 }
5449                 this._adjustInstDate( inst, offset +
5450                         ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
5451                         period );
5452                 this._updateDatepicker( inst );
5453         },
5455         /* Action for current link. */
5456         _gotoToday: function( id ) {
5457                 var date,
5458                         target = $( id ),
5459                         inst = this._getInst( target[ 0 ] );
5461                 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
5462                         inst.selectedDay = inst.currentDay;
5463                         inst.drawMonth = inst.selectedMonth = inst.currentMonth;
5464                         inst.drawYear = inst.selectedYear = inst.currentYear;
5465                 } else {
5466                         date = new Date();
5467                         inst.selectedDay = date.getDate();
5468                         inst.drawMonth = inst.selectedMonth = date.getMonth();
5469                         inst.drawYear = inst.selectedYear = date.getFullYear();
5470                 }
5471                 this._notifyChange( inst );
5472                 this._adjustDate( target );
5473         },
5475         /* Action for selecting a new month/year. */
5476         _selectMonthYear: function( id, select, period ) {
5477                 var target = $( id ),
5478                         inst = this._getInst( target[ 0 ] );
5480                 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
5481                 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
5482                         parseInt( select.options[ select.selectedIndex ].value, 10 );
5484                 this._notifyChange( inst );
5485                 this._adjustDate( target );
5486         },
5488         /* Action for selecting a day. */
5489         _selectDay: function( id, month, year, td ) {
5490                 var inst,
5491                         target = $( id );
5493                 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
5494                         return;
5495                 }
5497                 inst = this._getInst( target[ 0 ] );
5498                 inst.selectedDay = inst.currentDay = $( "a", td ).html();
5499                 inst.selectedMonth = inst.currentMonth = month;
5500                 inst.selectedYear = inst.currentYear = year;
5501                 this._selectDate( id, this._formatDate( inst,
5502                         inst.currentDay, inst.currentMonth, inst.currentYear ) );
5503         },
5505         /* Erase the input field and hide the date picker. */
5506         _clearDate: function( id ) {
5507                 var target = $( id );
5508                 this._selectDate( target, "" );
5509         },
5511         /* Update the input field with the selected date. */
5512         _selectDate: function( id, dateStr ) {
5513                 var onSelect,
5514                         target = $( id ),
5515                         inst = this._getInst( target[ 0 ] );
5517                 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
5518                 if ( inst.input ) {
5519                         inst.input.val( dateStr );
5520                 }
5521                 this._updateAlternate( inst );
5523                 onSelect = this._get( inst, "onSelect" );
5524                 if ( onSelect ) {
5525                         onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
5526                 } else if ( inst.input ) {
5527                         inst.input.trigger( "change" ); // fire the change event
5528                 }
5530                 if ( inst.inline ) {
5531                         this._updateDatepicker( inst );
5532                 } else {
5533                         this._hideDatepicker();
5534                         this._lastInput = inst.input[ 0 ];
5535                         if ( typeof( inst.input[ 0 ] ) !== "object" ) {
5536                                 inst.input.trigger( "focus" ); // restore focus
5537                         }
5538                         this._lastInput = null;
5539                 }
5540         },
5542         /* Update any alternate field to synchronise with the main field. */
5543         _updateAlternate: function( inst ) {
5544                 var altFormat, date, dateStr,
5545                         altField = this._get( inst, "altField" );
5547                 if ( altField ) { // update alternate field too
5548                         altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
5549                         date = this._getDate( inst );
5550                         dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
5551                         $( altField ).val( dateStr );
5552                 }
5553         },
5555         /* Set as beforeShowDay function to prevent selection of weekends.
5556          * @param  date  Date - the date to customise
5557          * @return [boolean, string] - is this date selectable?, what is its CSS class?
5558          */
5559         noWeekends: function( date ) {
5560                 var day = date.getDay();
5561                 return [ ( day > 0 && day < 6 ), "" ];
5562         },
5564         /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
5565          * @param  date  Date - the date to get the week for
5566          * @return  number - the number of the week within the year that contains this date
5567          */
5568         iso8601Week: function( date ) {
5569                 var time,
5570                         checkDate = new Date( date.getTime() );
5572                 // Find Thursday of this week starting on Monday
5573                 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
5575                 time = checkDate.getTime();
5576                 checkDate.setMonth( 0 ); // Compare with Jan 1
5577                 checkDate.setDate( 1 );
5578                 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
5579         },
5581         /* Parse a string value into a date object.
5582          * See formatDate below for the possible formats.
5583          *
5584          * @param  format string - the expected format of the date
5585          * @param  value string - the date in the above format
5586          * @param  settings Object - attributes include:
5587          *                                      shortYearCutoff  number - the cutoff year for determining the century (optional)
5588          *                                      dayNamesShort   string[7] - abbreviated names of the days from Sunday (optional)
5589          *                                      dayNames                string[7] - names of the days from Sunday (optional)
5590          *                                      monthNamesShort string[12] - abbreviated names of the months (optional)
5591          *                                      monthNames              string[12] - names of the months (optional)
5592          * @return  Date - the extracted date value or null if value is blank
5593          */
5594         parseDate: function( format, value, settings ) {
5595                 if ( format == null || value == null ) {
5596                         throw "Invalid arguments";
5597                 }
5599                 value = ( typeof value === "object" ? value.toString() : value + "" );
5600                 if ( value === "" ) {
5601                         return null;
5602                 }
5604                 var iFormat, dim, extra,
5605                         iValue = 0,
5606                         shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
5607                         shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
5608                                 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
5609                         dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
5610                         dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
5611                         monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
5612                         monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
5613                         year = -1,
5614                         month = -1,
5615                         day = -1,
5616                         doy = -1,
5617                         literal = false,
5618                         date,
5620                         // Check whether a format character is doubled
5621                         lookAhead = function( match ) {
5622                                 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
5623                                 if ( matches ) {
5624                                         iFormat++;
5625                                 }
5626                                 return matches;
5627                         },
5629                         // Extract a number from the string value
5630                         getNumber = function( match ) {
5631                                 var isDoubled = lookAhead( match ),
5632                                         size = ( match === "@" ? 14 : ( match === "!" ? 20 :
5633                                         ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
5634                                         minSize = ( match === "y" ? size : 1 ),
5635                                         digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
5636                                         num = value.substring( iValue ).match( digits );
5637                                 if ( !num ) {
5638                                         throw "Missing number at position " + iValue;
5639                                 }
5640                                 iValue += num[ 0 ].length;
5641                                 return parseInt( num[ 0 ], 10 );
5642                         },
5644                         // Extract a name from the string value and convert to an index
5645                         getName = function( match, shortNames, longNames ) {
5646                                 var index = -1,
5647                                         names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
5648                                                 return [ [ k, v ] ];
5649                                         } ).sort( function( a, b ) {
5650                                                 return -( a[ 1 ].length - b[ 1 ].length );
5651                                         } );
5653                                 $.each( names, function( i, pair ) {
5654                                         var name = pair[ 1 ];
5655                                         if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
5656                                                 index = pair[ 0 ];
5657                                                 iValue += name.length;
5658                                                 return false;
5659                                         }
5660                                 } );
5661                                 if ( index !== -1 ) {
5662                                         return index + 1;
5663                                 } else {
5664                                         throw "Unknown name at position " + iValue;
5665                                 }
5666                         },
5668                         // Confirm that a literal character matches the string value
5669                         checkLiteral = function() {
5670                                 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
5671                                         throw "Unexpected literal at position " + iValue;
5672                                 }
5673                                 iValue++;
5674                         };
5676                 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
5677                         if ( literal ) {
5678                                 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
5679                                         literal = false;
5680                                 } else {
5681                                         checkLiteral();
5682                                 }
5683                         } else {
5684                                 switch ( format.charAt( iFormat ) ) {
5685                                         case "d":
5686                                                 day = getNumber( "d" );
5687                                                 break;
5688                                         case "D":
5689                                                 getName( "D", dayNamesShort, dayNames );
5690                                                 break;
5691                                         case "o":
5692                                                 doy = getNumber( "o" );
5693                                                 break;
5694                                         case "m":
5695                                                 month = getNumber( "m" );
5696                                                 break;
5697                                         case "M":
5698                                                 month = getName( "M", monthNamesShort, monthNames );
5699                                                 break;
5700                                         case "y":
5701                                                 year = getNumber( "y" );
5702                                                 break;
5703                                         case "@":
5704                                                 date = new Date( getNumber( "@" ) );
5705                                                 year = date.getFullYear();
5706                                                 month = date.getMonth() + 1;
5707                                                 day = date.getDate();
5708                                                 break;
5709                                         case "!":
5710                                                 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
5711                                                 year = date.getFullYear();
5712                                                 month = date.getMonth() + 1;
5713                                                 day = date.getDate();
5714                                                 break;
5715                                         case "'":
5716                                                 if ( lookAhead( "'" ) ) {
5717                                                         checkLiteral();
5718                                                 } else {
5719                                                         literal = true;
5720                                                 }
5721                                                 break;
5722                                         default:
5723                                                 checkLiteral();
5724                                 }
5725                         }
5726                 }
5728                 if ( iValue < value.length ) {
5729                         extra = value.substr( iValue );
5730                         if ( !/^\s+/.test( extra ) ) {
5731                                 throw "Extra/unparsed characters found in date: " + extra;
5732                         }
5733                 }
5735                 if ( year === -1 ) {
5736                         year = new Date().getFullYear();
5737                 } else if ( year < 100 ) {
5738                         year += new Date().getFullYear() - new Date().getFullYear() % 100 +
5739                                 ( year <= shortYearCutoff ? 0 : -100 );
5740                 }
5742                 if ( doy > -1 ) {
5743                         month = 1;
5744                         day = doy;
5745                         do {
5746                                 dim = this._getDaysInMonth( year, month - 1 );
5747                                 if ( day <= dim ) {
5748                                         break;
5749                                 }
5750                                 month++;
5751                                 day -= dim;
5752                         } while ( true );
5753                 }
5755                 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
5756                 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
5757                         throw "Invalid date"; // E.g. 31/02/00
5758                 }
5759                 return date;
5760         },
5762         /* Standard date formats. */
5763         ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5764         COOKIE: "D, dd M yy",
5765         ISO_8601: "yy-mm-dd",
5766         RFC_822: "D, d M y",
5767         RFC_850: "DD, dd-M-y",
5768         RFC_1036: "D, d M y",
5769         RFC_1123: "D, d M yy",
5770         RFC_2822: "D, d M yy",
5771         RSS: "D, d M y", // RFC 822
5772         TICKS: "!",
5773         TIMESTAMP: "@",
5774         W3C: "yy-mm-dd", // ISO 8601
5776         _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
5777                 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
5779         /* Format a date object into a string value.
5780          * The format can be combinations of the following:
5781          * d  - day of month (no leading zero)
5782          * dd - day of month (two digit)
5783          * o  - day of year (no leading zeros)
5784          * oo - day of year (three digit)
5785          * D  - day name short
5786          * DD - day name long
5787          * m  - month of year (no leading zero)
5788          * mm - month of year (two digit)
5789          * M  - month name short
5790          * MM - month name long
5791          * y  - year (two digit)
5792          * yy - year (four digit)
5793          * @ - Unix timestamp (ms since 01/01/1970)
5794          * ! - Windows ticks (100ns since 01/01/0001)
5795          * "..." - literal text
5796          * '' - single quote
5797          *
5798          * @param  format string - the desired format of the date
5799          * @param  date Date - the date value to format
5800          * @param  settings Object - attributes include:
5801          *                                      dayNamesShort   string[7] - abbreviated names of the days from Sunday (optional)
5802          *                                      dayNames                string[7] - names of the days from Sunday (optional)
5803          *                                      monthNamesShort string[12] - abbreviated names of the months (optional)
5804          *                                      monthNames              string[12] - names of the months (optional)
5805          * @return  string - the date in the above format
5806          */
5807         formatDate: function( format, date, settings ) {
5808                 if ( !date ) {
5809                         return "";
5810                 }
5812                 var iFormat,
5813                         dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
5814                         dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
5815                         monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
5816                         monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
5818                         // Check whether a format character is doubled
5819                         lookAhead = function( match ) {
5820                                 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
5821                                 if ( matches ) {
5822                                         iFormat++;
5823                                 }
5824                                 return matches;
5825                         },
5827                         // Format a number, with leading zero if necessary
5828                         formatNumber = function( match, value, len ) {
5829                                 var num = "" + value;
5830                                 if ( lookAhead( match ) ) {
5831                                         while ( num.length < len ) {
5832                                                 num = "0" + num;
5833                                         }
5834                                 }
5835                                 return num;
5836                         },
5838                         // Format a name, short or long as requested
5839                         formatName = function( match, value, shortNames, longNames ) {
5840                                 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
5841                         },
5842                         output = "",
5843                         literal = false;
5845                 if ( date ) {
5846                         for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
5847                                 if ( literal ) {
5848                                         if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
5849                                                 literal = false;
5850                                         } else {
5851                                                 output += format.charAt( iFormat );
5852                                         }
5853                                 } else {
5854                                         switch ( format.charAt( iFormat ) ) {
5855                                                 case "d":
5856                                                         output += formatNumber( "d", date.getDate(), 2 );
5857                                                         break;
5858                                                 case "D":
5859                                                         output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
5860                                                         break;
5861                                                 case "o":
5862                                                         output += formatNumber( "o",
5863                                                                 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
5864                                                         break;
5865                                                 case "m":
5866                                                         output += formatNumber( "m", date.getMonth() + 1, 2 );
5867                                                         break;
5868                                                 case "M":
5869                                                         output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
5870                                                         break;
5871                                                 case "y":
5872                                                         output += ( lookAhead( "y" ) ? date.getFullYear() :
5873                                                                 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
5874                                                         break;
5875                                                 case "@":
5876                                                         output += date.getTime();
5877                                                         break;
5878                                                 case "!":
5879                                                         output += date.getTime() * 10000 + this._ticksTo1970;
5880                                                         break;
5881                                                 case "'":
5882                                                         if ( lookAhead( "'" ) ) {
5883                                                                 output += "'";
5884                                                         } else {
5885                                                                 literal = true;
5886                                                         }
5887                                                         break;
5888                                                 default:
5889                                                         output += format.charAt( iFormat );
5890                                         }
5891                                 }
5892                         }
5893                 }
5894                 return output;
5895         },
5897         /* Extract all possible characters from the date format. */
5898         _possibleChars: function( format ) {
5899                 var iFormat,
5900                         chars = "",
5901                         literal = false,
5903                         // Check whether a format character is doubled
5904                         lookAhead = function( match ) {
5905                                 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
5906                                 if ( matches ) {
5907                                         iFormat++;
5908                                 }
5909                                 return matches;
5910                         };
5912                 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
5913                         if ( literal ) {
5914                                 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
5915                                         literal = false;
5916                                 } else {
5917                                         chars += format.charAt( iFormat );
5918                                 }
5919                         } else {
5920                                 switch ( format.charAt( iFormat ) ) {
5921                                         case "d": case "m": case "y": case "@":
5922                                                 chars += "0123456789";
5923                                                 break;
5924                                         case "D": case "M":
5925                                                 return null; // Accept anything
5926                                         case "'":
5927                                                 if ( lookAhead( "'" ) ) {
5928                                                         chars += "'";
5929                                                 } else {
5930                                                         literal = true;
5931                                                 }
5932                                                 break;
5933                                         default:
5934                                                 chars += format.charAt( iFormat );
5935                                 }
5936                         }
5937                 }
5938                 return chars;
5939         },
5941         /* Get a setting value, defaulting if necessary. */
5942         _get: function( inst, name ) {
5943                 return inst.settings[ name ] !== undefined ?
5944                         inst.settings[ name ] : this._defaults[ name ];
5945         },
5947         /* Parse existing date and initialise date picker. */
5948         _setDateFromField: function( inst, noDefault ) {
5949                 if ( inst.input.val() === inst.lastVal ) {
5950                         return;
5951                 }
5953                 var dateFormat = this._get( inst, "dateFormat" ),
5954                         dates = inst.lastVal = inst.input ? inst.input.val() : null,
5955                         defaultDate = this._getDefaultDate( inst ),
5956                         date = defaultDate,
5957                         settings = this._getFormatConfig( inst );
5959                 try {
5960                         date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
5961                 } catch ( event ) {
5962                         dates = ( noDefault ? "" : dates );
5963                 }
5964                 inst.selectedDay = date.getDate();
5965                 inst.drawMonth = inst.selectedMonth = date.getMonth();
5966                 inst.drawYear = inst.selectedYear = date.getFullYear();
5967                 inst.currentDay = ( dates ? date.getDate() : 0 );
5968                 inst.currentMonth = ( dates ? date.getMonth() : 0 );
5969                 inst.currentYear = ( dates ? date.getFullYear() : 0 );
5970                 this._adjustInstDate( inst );
5971         },
5973         /* Retrieve the default date shown on opening. */
5974         _getDefaultDate: function( inst ) {
5975                 return this._restrictMinMax( inst,
5976                         this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
5977         },
5979         /* A date may be specified as an exact value or a relative one. */
5980         _determineDate: function( inst, date, defaultDate ) {
5981                 var offsetNumeric = function( offset ) {
5982                                 var date = new Date();
5983                                 date.setDate( date.getDate() + offset );
5984                                 return date;
5985                         },
5986                         offsetString = function( offset ) {
5987                                 try {
5988                                         return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
5989                                                 offset, $.datepicker._getFormatConfig( inst ) );
5990                                 }
5991                                 catch ( e ) {
5993                                         // Ignore
5994                                 }
5996                                 var date = ( offset.toLowerCase().match( /^c/ ) ?
5997                                         $.datepicker._getDate( inst ) : null ) || new Date(),
5998                                         year = date.getFullYear(),
5999                                         month = date.getMonth(),
6000                                         day = date.getDate(),
6001                                         pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
6002                                         matches = pattern.exec( offset );
6004                                 while ( matches ) {
6005                                         switch ( matches[ 2 ] || "d" ) {
6006                                                 case "d" : case "D" :
6007                                                         day += parseInt( matches[ 1 ], 10 ); break;
6008                                                 case "w" : case "W" :
6009                                                         day += parseInt( matches[ 1 ], 10 ) * 7; break;
6010                                                 case "m" : case "M" :
6011                                                         month += parseInt( matches[ 1 ], 10 );
6012                                                         day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
6013                                                         break;
6014                                                 case "y": case "Y" :
6015                                                         year += parseInt( matches[ 1 ], 10 );
6016                                                         day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
6017                                                         break;
6018                                         }
6019                                         matches = pattern.exec( offset );
6020                                 }
6021                                 return new Date( year, month, day );
6022                         },
6023                         newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
6024                                 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
6026                 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
6027                 if ( newDate ) {
6028                         newDate.setHours( 0 );
6029                         newDate.setMinutes( 0 );
6030                         newDate.setSeconds( 0 );
6031                         newDate.setMilliseconds( 0 );
6032                 }
6033                 return this._daylightSavingAdjust( newDate );
6034         },
6036         /* Handle switch to/from daylight saving.
6037          * Hours may be non-zero on daylight saving cut-over:
6038          * > 12 when midnight changeover, but then cannot generate
6039          * midnight datetime, so jump to 1AM, otherwise reset.
6040          * @param  date  (Date) the date to check
6041          * @return  (Date) the corrected date
6042          */
6043         _daylightSavingAdjust: function( date ) {
6044                 if ( !date ) {
6045                         return null;
6046                 }
6047                 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
6048                 return date;
6049         },
6051         /* Set the date(s) directly. */
6052         _setDate: function( inst, date, noChange ) {
6053                 var clear = !date,
6054                         origMonth = inst.selectedMonth,
6055                         origYear = inst.selectedYear,
6056                         newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
6058                 inst.selectedDay = inst.currentDay = newDate.getDate();
6059                 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
6060                 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
6061                 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
6062                         this._notifyChange( inst );
6063                 }
6064                 this._adjustInstDate( inst );
6065                 if ( inst.input ) {
6066                         inst.input.val( clear ? "" : this._formatDate( inst ) );
6067                 }
6068         },
6070         /* Retrieve the date(s) directly. */
6071         _getDate: function( inst ) {
6072                 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
6073                         this._daylightSavingAdjust( new Date(
6074                         inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
6075                         return startDate;
6076         },
6078         /* Attach the onxxx handlers.  These are declared statically so
6079          * they work with static code transformers like Caja.
6080          */
6081         _attachHandlers: function( inst ) {
6082                 var stepMonths = this._get( inst, "stepMonths" ),
6083                         id = "#" + inst.id.replace( /\\\\/g, "\\" );
6084                 inst.dpDiv.find( "[data-handler]" ).map( function() {
6085                         var handler = {
6086                                 prev: function() {
6087                                         $.datepicker._adjustDate( id, -stepMonths, "M" );
6088                                 },
6089                                 next: function() {
6090                                         $.datepicker._adjustDate( id, +stepMonths, "M" );
6091                                 },
6092                                 hide: function() {
6093                                         $.datepicker._hideDatepicker();
6094                                 },
6095                                 today: function() {
6096                                         $.datepicker._gotoToday( id );
6097                                 },
6098                                 selectDay: function() {
6099                                         $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
6100                                         return false;
6101                                 },
6102                                 selectMonth: function() {
6103                                         $.datepicker._selectMonthYear( id, this, "M" );
6104                                         return false;
6105                                 },
6106                                 selectYear: function() {
6107                                         $.datepicker._selectMonthYear( id, this, "Y" );
6108                                         return false;
6109                                 }
6110                         };
6111                         $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
6112                 } );
6113         },
6115         /* Generate the HTML for the current state of the date picker. */
6116         _generateHTML: function( inst ) {
6117                 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
6118                         controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
6119                         monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
6120                         selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
6121                         cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
6122                         printDate, dRow, tbody, daySettings, otherMonth, unselectable,
6123                         tempDate = new Date(),
6124                         today = this._daylightSavingAdjust(
6125                                 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
6126                         isRTL = this._get( inst, "isRTL" ),
6127                         showButtonPanel = this._get( inst, "showButtonPanel" ),
6128                         hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
6129                         navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
6130                         numMonths = this._getNumberOfMonths( inst ),
6131                         showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
6132                         stepMonths = this._get( inst, "stepMonths" ),
6133                         isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
6134                         currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
6135                                 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
6136                         minDate = this._getMinMaxDate( inst, "min" ),
6137                         maxDate = this._getMinMaxDate( inst, "max" ),
6138                         drawMonth = inst.drawMonth - showCurrentAtPos,
6139                         drawYear = inst.drawYear;
6141                 if ( drawMonth < 0 ) {
6142                         drawMonth += 12;
6143                         drawYear--;
6144                 }
6145                 if ( maxDate ) {
6146                         maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
6147                                 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
6148                         maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
6149                         while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
6150                                 drawMonth--;
6151                                 if ( drawMonth < 0 ) {
6152                                         drawMonth = 11;
6153                                         drawYear--;
6154                                 }
6155                         }
6156                 }
6157                 inst.drawMonth = drawMonth;
6158                 inst.drawYear = drawYear;
6160                 prevText = this._get( inst, "prevText" );
6161                 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
6162                         this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
6163                         this._getFormatConfig( inst ) ) );
6165                 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
6166                         "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
6167                         " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
6168                         ( 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>" ) );
6170                 nextText = this._get( inst, "nextText" );
6171                 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
6172                         this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
6173                         this._getFormatConfig( inst ) ) );
6175                 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
6176                         "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
6177                         " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
6178                         ( 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>" ) );
6180                 currentText = this._get( inst, "currentText" );
6181                 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
6182                 currentText = ( !navigationAsDateFormat ? currentText :
6183                         this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
6185                 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'>" +
6186                         this._get( inst, "closeText" ) + "</button>" : "" );
6188                 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
6189                         ( 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'" +
6190                         ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
6192                 firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
6193                 firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
6195                 showWeek = this._get( inst, "showWeek" );
6196                 dayNames = this._get( inst, "dayNames" );
6197                 dayNamesMin = this._get( inst, "dayNamesMin" );
6198                 monthNames = this._get( inst, "monthNames" );
6199                 monthNamesShort = this._get( inst, "monthNamesShort" );
6200                 beforeShowDay = this._get( inst, "beforeShowDay" );
6201                 showOtherMonths = this._get( inst, "showOtherMonths" );
6202                 selectOtherMonths = this._get( inst, "selectOtherMonths" );
6203                 defaultDate = this._getDefaultDate( inst );
6204                 html = "";
6206                 for ( row = 0; row < numMonths[ 0 ]; row++ ) {
6207                         group = "";
6208                         this.maxRows = 4;
6209                         for ( col = 0; col < numMonths[ 1 ]; col++ ) {
6210                                 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
6211                                 cornerClass = " ui-corner-all";
6212                                 calender = "";
6213                                 if ( isMultiMonth ) {
6214                                         calender += "<div class='ui-datepicker-group";
6215                                         if ( numMonths[ 1 ] > 1 ) {
6216                                                 switch ( col ) {
6217                                                         case 0: calender += " ui-datepicker-group-first";
6218                                                                 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
6219                                                         case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
6220                                                                 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
6221                                                         default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
6222                                                 }
6223                                         }
6224                                         calender += "'>";
6225                                 }
6226                                 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
6227                                         ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
6228                                         ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
6229                                         this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
6230                                         row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
6231                                         "</div><table class='ui-datepicker-calendar'><thead>" +
6232                                         "<tr>";
6233                                 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
6234                                 for ( dow = 0; dow < 7; dow++ ) { // days of the week
6235                                         day = ( dow + firstDay ) % 7;
6236                                         thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
6237                                                 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
6238                                 }
6239                                 calender += thead + "</tr></thead><tbody>";
6240                                 daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
6241                                 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
6242                                         inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
6243                                 }
6244                                 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
6245                                 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
6246                                 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
6247                                 this.maxRows = numRows;
6248                                 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
6249                                 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
6250                                         calender += "<tr>";
6251                                         tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
6252                                                 this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
6253                                         for ( dow = 0; dow < 7; dow++ ) { // create date picker days
6254                                                 daySettings = ( beforeShowDay ?
6255                                                         beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
6256                                                 otherMonth = ( printDate.getMonth() !== drawMonth );
6257                                                 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
6258                                                         ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
6259                                                 tbody += "<td class='" +
6260                                                         ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
6261                                                         ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
6262                                                         ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
6263                                                         ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
6265                                                         // or defaultDate is current printedDate and defaultDate is selectedDate
6266                                                         " " + this._dayOverClass : "" ) + // highlight selected day
6267                                                         ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
6268                                                         ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
6269                                                         ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
6270                                                         ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
6271                                                         ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
6272                                                         ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
6273                                                         ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
6274                                                         ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
6275                                                         ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
6276                                                         ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
6277                                                         ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
6278                                                         "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
6279                                                 printDate.setDate( printDate.getDate() + 1 );
6280                                                 printDate = this._daylightSavingAdjust( printDate );
6281                                         }
6282                                         calender += tbody + "</tr>";
6283                                 }
6284                                 drawMonth++;
6285                                 if ( drawMonth > 11 ) {
6286                                         drawMonth = 0;
6287                                         drawYear++;
6288                                 }
6289                                 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
6290                                                         ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
6291                                 group += calender;
6292                         }
6293                         html += group;
6294                 }
6295                 html += buttonPanel;
6296                 inst._keyEvent = false;
6297                 return html;
6298         },
6300         /* Generate the month and year header. */
6301         _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
6302                         secondary, monthNames, monthNamesShort ) {
6304                 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
6305                         changeMonth = this._get( inst, "changeMonth" ),
6306                         changeYear = this._get( inst, "changeYear" ),
6307                         showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
6308                         html = "<div class='ui-datepicker-title'>",
6309                         monthHtml = "";
6311                 // Month selection
6312                 if ( secondary || !changeMonth ) {
6313                         monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
6314                 } else {
6315                         inMinYear = ( minDate && minDate.getFullYear() === drawYear );
6316                         inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
6317                         monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
6318                         for ( month = 0; month < 12; month++ ) {
6319                                 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
6320                                         monthHtml += "<option value='" + month + "'" +
6321                                                 ( month === drawMonth ? " selected='selected'" : "" ) +
6322                                                 ">" + monthNamesShort[ month ] + "</option>";
6323                                 }
6324                         }
6325                         monthHtml += "</select>";
6326                 }
6328                 if ( !showMonthAfterYear ) {
6329                         html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
6330                 }
6332                 // Year selection
6333                 if ( !inst.yearshtml ) {
6334                         inst.yearshtml = "";
6335                         if ( secondary || !changeYear ) {
6336                                 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
6337                         } else {
6339                                 // determine range of years to display
6340                                 years = this._get( inst, "yearRange" ).split( ":" );
6341                                 thisYear = new Date().getFullYear();
6342                                 determineYear = function( value ) {
6343                                         var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
6344                                                 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
6345                                                 parseInt( value, 10 ) ) );
6346                                         return ( isNaN( year ) ? thisYear : year );
6347                                 };
6348                                 year = determineYear( years[ 0 ] );
6349                                 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
6350                                 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
6351                                 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
6352                                 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
6353                                 for ( ; year <= endYear; year++ ) {
6354                                         inst.yearshtml += "<option value='" + year + "'" +
6355                                                 ( year === drawYear ? " selected='selected'" : "" ) +
6356                                                 ">" + year + "</option>";
6357                                 }
6358                                 inst.yearshtml += "</select>";
6360                                 html += inst.yearshtml;
6361                                 inst.yearshtml = null;
6362                         }
6363                 }
6365                 html += this._get( inst, "yearSuffix" );
6366                 if ( showMonthAfterYear ) {
6367                         html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
6368                 }
6369                 html += "</div>"; // Close datepicker_header
6370                 return html;
6371         },
6373         /* Adjust one of the date sub-fields. */
6374         _adjustInstDate: function( inst, offset, period ) {
6375                 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
6376                         month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
6377                         day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
6378                         date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
6380                 inst.selectedDay = date.getDate();
6381                 inst.drawMonth = inst.selectedMonth = date.getMonth();
6382                 inst.drawYear = inst.selectedYear = date.getFullYear();
6383                 if ( period === "M" || period === "Y" ) {
6384                         this._notifyChange( inst );
6385                 }
6386         },
6388         /* Ensure a date is within any min/max bounds. */
6389         _restrictMinMax: function( inst, date ) {
6390                 var minDate = this._getMinMaxDate( inst, "min" ),
6391                         maxDate = this._getMinMaxDate( inst, "max" ),
6392                         newDate = ( minDate && date < minDate ? minDate : date );
6393                 return ( maxDate && newDate > maxDate ? maxDate : newDate );
6394         },
6396         /* Notify change of month/year. */
6397         _notifyChange: function( inst ) {
6398                 var onChange = this._get( inst, "onChangeMonthYear" );
6399                 if ( onChange ) {
6400                         onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
6401                                 [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
6402                 }
6403         },
6405         /* Determine the number of months to show. */
6406         _getNumberOfMonths: function( inst ) {
6407                 var numMonths = this._get( inst, "numberOfMonths" );
6408                 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
6409         },
6411         /* Determine the current maximum date - ensure no time components are set. */
6412         _getMinMaxDate: function( inst, minMax ) {
6413                 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
6414         },
6416         /* Find the number of days in a given month. */
6417         _getDaysInMonth: function( year, month ) {
6418                 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
6419         },
6421         /* Find the day of the week of the first of a month. */
6422         _getFirstDayOfMonth: function( year, month ) {
6423                 return new Date( year, month, 1 ).getDay();
6424         },
6426         /* Determines if we should allow a "next/prev" month display change. */
6427         _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
6428                 var numMonths = this._getNumberOfMonths( inst ),
6429                         date = this._daylightSavingAdjust( new Date( curYear,
6430                         curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
6432                 if ( offset < 0 ) {
6433                         date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
6434                 }
6435                 return this._isInRange( inst, date );
6436         },
6438         /* Is the given date in the accepted range? */
6439         _isInRange: function( inst, date ) {
6440                 var yearSplit, currentYear,
6441                         minDate = this._getMinMaxDate( inst, "min" ),
6442                         maxDate = this._getMinMaxDate( inst, "max" ),
6443                         minYear = null,
6444                         maxYear = null,
6445                         years = this._get( inst, "yearRange" );
6446                         if ( years ) {
6447                                 yearSplit = years.split( ":" );
6448                                 currentYear = new Date().getFullYear();
6449                                 minYear = parseInt( yearSplit[ 0 ], 10 );
6450                                 maxYear = parseInt( yearSplit[ 1 ], 10 );
6451                                 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
6452                                         minYear += currentYear;
6453                                 }
6454                                 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
6455                                         maxYear += currentYear;
6456                                 }
6457                         }
6459                 return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
6460                         ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
6461                         ( !minYear || date.getFullYear() >= minYear ) &&
6462                         ( !maxYear || date.getFullYear() <= maxYear ) );
6463         },
6465         /* Provide the configuration settings for formatting/parsing. */
6466         _getFormatConfig: function( inst ) {
6467                 var shortYearCutoff = this._get( inst, "shortYearCutoff" );
6468                 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
6469                         new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
6470                 return { shortYearCutoff: shortYearCutoff,
6471                         dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
6472                         monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
6473         },
6475         /* Format the given date for display. */
6476         _formatDate: function( inst, day, month, year ) {
6477                 if ( !day ) {
6478                         inst.currentDay = inst.selectedDay;
6479                         inst.currentMonth = inst.selectedMonth;
6480                         inst.currentYear = inst.selectedYear;
6481                 }
6482                 var date = ( day ? ( typeof day === "object" ? day :
6483                         this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
6484                         this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
6485                 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
6486         }
6487 } );
6490  * Bind hover events for datepicker elements.
6491  * Done via delegate so the binding only occurs once in the lifetime of the parent div.
6492  * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
6493  */
6494 function datepicker_bindHover( dpDiv ) {
6495         var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
6496         return dpDiv.on( "mouseout", selector, function() {
6497                         $( this ).removeClass( "ui-state-hover" );
6498                         if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
6499                                 $( this ).removeClass( "ui-datepicker-prev-hover" );
6500                         }
6501                         if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
6502                                 $( this ).removeClass( "ui-datepicker-next-hover" );
6503                         }
6504                 } )
6505                 .on( "mouseover", selector, datepicker_handleMouseover );
6508 function datepicker_handleMouseover() {
6509         if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
6510                 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
6511                 $( this ).addClass( "ui-state-hover" );
6512                 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
6513                         $( this ).addClass( "ui-datepicker-prev-hover" );
6514                 }
6515                 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
6516                         $( this ).addClass( "ui-datepicker-next-hover" );
6517                 }
6518         }
6521 /* jQuery extend now ignores nulls! */
6522 function datepicker_extendRemove( target, props ) {
6523         $.extend( target, props );
6524         for ( var name in props ) {
6525                 if ( props[ name ] == null ) {
6526                         target[ name ] = props[ name ];
6527                 }
6528         }
6529         return target;
6532 /* Invoke the datepicker functionality.
6533    @param  options  string - a command, optionally followed by additional parameters or
6534                                         Object - settings for attaching new datepicker functionality
6535    @return  jQuery object */
6536 $.fn.datepicker = function( options ) {
6538         /* Verify an empty collection wasn't passed - Fixes #6976 */
6539         if ( !this.length ) {
6540                 return this;
6541         }
6543         /* Initialise the date picker. */
6544         if ( !$.datepicker.initialized ) {
6545                 $( document ).on( "mousedown", $.datepicker._checkExternalClick );
6546                 $.datepicker.initialized = true;
6547         }
6549         /* Append datepicker main container to body if not exist. */
6550         if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
6551                 $( "body" ).append( $.datepicker.dpDiv );
6552         }
6554         var otherArgs = Array.prototype.slice.call( arguments, 1 );
6555         if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
6556                 return $.datepicker[ "_" + options + "Datepicker" ].
6557                         apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
6558         }
6559         if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
6560                 return $.datepicker[ "_" + options + "Datepicker" ].
6561                         apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
6562         }
6563         return this.each( function() {
6564                 typeof options === "string" ?
6565                         $.datepicker[ "_" + options + "Datepicker" ].
6566                                 apply( $.datepicker, [ this ].concat( otherArgs ) ) :
6567                         $.datepicker._attachDatepicker( this, options );
6568         } );
6571 $.datepicker = new Datepicker(); // singleton instance
6572 $.datepicker.initialized = false;
6573 $.datepicker.uuid = new Date().getTime();
6574 $.datepicker.version = "1.12.1";
6576 var widgetsDatepicker = $.datepicker;
6580  * jQuery UI Slider 1.12.1
6581  * http://jqueryui.com
6583  * Copyright jQuery Foundation and other contributors
6584  * Released under the MIT license.
6585  * http://jquery.org/license
6586  */
6588 //>>label: Slider
6589 //>>group: Widgets
6590 //>>description: Displays a flexible slider with ranges and accessibility via keyboard.
6591 //>>docs: http://api.jqueryui.com/slider/
6592 //>>demos: http://jqueryui.com/slider/
6593 //>>css.structure: ../../themes/base/core.css
6594 //>>css.structure: ../../themes/base/slider.css
6595 //>>css.theme: ../../themes/base/theme.css
6599 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
6600         version: "1.12.1",
6601         widgetEventPrefix: "slide",
6603         options: {
6604                 animate: false,
6605                 classes: {
6606                         "ui-slider": "ui-corner-all",
6607                         "ui-slider-handle": "ui-corner-all",
6609                         // Note: ui-widget-header isn't the most fittingly semantic framework class for this
6610                         // element, but worked best visually with a variety of themes
6611                         "ui-slider-range": "ui-corner-all ui-widget-header"
6612                 },
6613                 distance: 0,
6614                 max: 100,
6615                 min: 0,
6616                 orientation: "horizontal",
6617                 range: false,
6618                 step: 1,
6619                 value: 0,
6620                 values: null,
6622                 // Callbacks
6623                 change: null,
6624                 slide: null,
6625                 start: null,
6626                 stop: null
6627         },
6629         // Number of pages in a slider
6630         // (how many times can you page up/down to go through the whole range)
6631         numPages: 5,
6633         _create: function() {
6634                 this._keySliding = false;
6635                 this._mouseSliding = false;
6636                 this._animateOff = true;
6637                 this._handleIndex = null;
6638                 this._detectOrientation();
6639                 this._mouseInit();
6640                 this._calculateNewMax();
6642                 this._addClass( "ui-slider ui-slider-" + this.orientation,
6643                         "ui-widget ui-widget-content" );
6645                 this._refresh();
6647                 this._animateOff = false;
6648         },
6650         _refresh: function() {
6651                 this._createRange();
6652                 this._createHandles();
6653                 this._setupEvents();
6654                 this._refreshValue();
6655         },
6657         _createHandles: function() {
6658                 var i, handleCount,
6659                         options = this.options,
6660                         existingHandles = this.element.find( ".ui-slider-handle" ),
6661                         handle = "<span tabindex='0'></span>",
6662                         handles = [];
6664                 handleCount = ( options.values && options.values.length ) || 1;
6666                 if ( existingHandles.length > handleCount ) {
6667                         existingHandles.slice( handleCount ).remove();
6668                         existingHandles = existingHandles.slice( 0, handleCount );
6669                 }
6671                 for ( i = existingHandles.length; i < handleCount; i++ ) {
6672                         handles.push( handle );
6673                 }
6675                 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
6677                 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
6679                 this.handle = this.handles.eq( 0 );
6681                 this.handles.each( function( i ) {
6682                         $( this )
6683                                 .data( "ui-slider-handle-index", i )
6684                                 .attr( "tabIndex", 0 );
6685                 } );
6686         },
6688         _createRange: function() {
6689                 var options = this.options;
6691                 if ( options.range ) {
6692                         if ( options.range === true ) {
6693                                 if ( !options.values ) {
6694                                         options.values = [ this._valueMin(), this._valueMin() ];
6695                                 } else if ( options.values.length && options.values.length !== 2 ) {
6696                                         options.values = [ options.values[ 0 ], options.values[ 0 ] ];
6697                                 } else if ( $.isArray( options.values ) ) {
6698                                         options.values = options.values.slice( 0 );
6699                                 }
6700                         }
6702                         if ( !this.range || !this.range.length ) {
6703                                 this.range = $( "<div>" )
6704                                         .appendTo( this.element );
6706                                 this._addClass( this.range, "ui-slider-range" );
6707                         } else {
6708                                 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
6710                                 // Handle range switching from true to min/max
6711                                 this.range.css( {
6712                                         "left": "",
6713                                         "bottom": ""
6714                                 } );
6715                         }
6716                         if ( options.range === "min" || options.range === "max" ) {
6717                                 this._addClass( this.range, "ui-slider-range-" + options.range );
6718                         }
6719                 } else {
6720                         if ( this.range ) {
6721                                 this.range.remove();
6722                         }
6723                         this.range = null;
6724                 }
6725         },
6727         _setupEvents: function() {
6728                 this._off( this.handles );
6729                 this._on( this.handles, this._handleEvents );
6730                 this._hoverable( this.handles );
6731                 this._focusable( this.handles );
6732         },
6734         _destroy: function() {
6735                 this.handles.remove();
6736                 if ( this.range ) {
6737                         this.range.remove();
6738                 }
6740                 this._mouseDestroy();
6741         },
6743         _mouseCapture: function( event ) {
6744                 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
6745                         that = this,
6746                         o = this.options;
6748                 if ( o.disabled ) {
6749                         return false;
6750                 }
6752                 this.elementSize = {
6753                         width: this.element.outerWidth(),
6754                         height: this.element.outerHeight()
6755                 };
6756                 this.elementOffset = this.element.offset();
6758                 position = { x: event.pageX, y: event.pageY };
6759                 normValue = this._normValueFromMouse( position );
6760                 distance = this._valueMax() - this._valueMin() + 1;
6761                 this.handles.each( function( i ) {
6762                         var thisDistance = Math.abs( normValue - that.values( i ) );
6763                         if ( ( distance > thisDistance ) ||
6764                                 ( distance === thisDistance &&
6765                                         ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
6766                                 distance = thisDistance;
6767                                 closestHandle = $( this );
6768                                 index = i;
6769                         }
6770                 } );
6772                 allowed = this._start( event, index );
6773                 if ( allowed === false ) {
6774                         return false;
6775                 }
6776                 this._mouseSliding = true;
6778                 this._handleIndex = index;
6780                 this._addClass( closestHandle, null, "ui-state-active" );
6781                 closestHandle.trigger( "focus" );
6783                 offset = closestHandle.offset();
6784                 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
6785                 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
6786                         left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
6787                         top: event.pageY - offset.top -
6788                                 ( closestHandle.height() / 2 ) -
6789                                 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
6790                                 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
6791                                 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
6792                 };
6794                 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
6795                         this._slide( event, index, normValue );
6796                 }
6797                 this._animateOff = true;
6798                 return true;
6799         },
6801         _mouseStart: function() {
6802                 return true;
6803         },
6805         _mouseDrag: function( event ) {
6806                 var position = { x: event.pageX, y: event.pageY },
6807                         normValue = this._normValueFromMouse( position );
6809                 this._slide( event, this._handleIndex, normValue );
6811                 return false;
6812         },
6814         _mouseStop: function( event ) {
6815                 this._removeClass( this.handles, null, "ui-state-active" );
6816                 this._mouseSliding = false;
6818                 this._stop( event, this._handleIndex );
6819                 this._change( event, this._handleIndex );
6821                 this._handleIndex = null;
6822                 this._clickOffset = null;
6823                 this._animateOff = false;
6825                 return false;
6826         },
6828         _detectOrientation: function() {
6829                 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
6830         },
6832         _normValueFromMouse: function( position ) {
6833                 var pixelTotal,
6834                         pixelMouse,
6835                         percentMouse,
6836                         valueTotal,
6837                         valueMouse;
6839                 if ( this.orientation === "horizontal" ) {
6840                         pixelTotal = this.elementSize.width;
6841                         pixelMouse = position.x - this.elementOffset.left -
6842                                 ( this._clickOffset ? this._clickOffset.left : 0 );
6843                 } else {
6844                         pixelTotal = this.elementSize.height;
6845                         pixelMouse = position.y - this.elementOffset.top -
6846                                 ( this._clickOffset ? this._clickOffset.top : 0 );
6847                 }
6849                 percentMouse = ( pixelMouse / pixelTotal );
6850                 if ( percentMouse > 1 ) {
6851                         percentMouse = 1;
6852                 }
6853                 if ( percentMouse < 0 ) {
6854                         percentMouse = 0;
6855                 }
6856                 if ( this.orientation === "vertical" ) {
6857                         percentMouse = 1 - percentMouse;
6858                 }
6860                 valueTotal = this._valueMax() - this._valueMin();
6861                 valueMouse = this._valueMin() + percentMouse * valueTotal;
6863                 return this._trimAlignValue( valueMouse );
6864         },
6866         _uiHash: function( index, value, values ) {
6867                 var uiHash = {
6868                         handle: this.handles[ index ],
6869                         handleIndex: index,
6870                         value: value !== undefined ? value : this.value()
6871                 };
6873                 if ( this._hasMultipleValues() ) {
6874                         uiHash.value = value !== undefined ? value : this.values( index );
6875                         uiHash.values = values || this.values();
6876                 }
6878                 return uiHash;
6879         },
6881         _hasMultipleValues: function() {
6882                 return this.options.values && this.options.values.length;
6883         },
6885         _start: function( event, index ) {
6886                 return this._trigger( "start", event, this._uiHash( index ) );
6887         },
6889         _slide: function( event, index, newVal ) {
6890                 var allowed, otherVal,
6891                         currentValue = this.value(),
6892                         newValues = this.values();
6894                 if ( this._hasMultipleValues() ) {
6895                         otherVal = this.values( index ? 0 : 1 );
6896                         currentValue = this.values( index );
6898                         if ( this.options.values.length === 2 && this.options.range === true ) {
6899                                 newVal =  index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
6900                         }
6902                         newValues[ index ] = newVal;
6903                 }
6905                 if ( newVal === currentValue ) {
6906                         return;
6907                 }
6909                 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
6911                 // A slide can be canceled by returning false from the slide callback
6912                 if ( allowed === false ) {
6913                         return;
6914                 }
6916                 if ( this._hasMultipleValues() ) {
6917                         this.values( index, newVal );
6918                 } else {
6919                         this.value( newVal );
6920                 }
6921         },
6923         _stop: function( event, index ) {
6924                 this._trigger( "stop", event, this._uiHash( index ) );
6925         },
6927         _change: function( event, index ) {
6928                 if ( !this._keySliding && !this._mouseSliding ) {
6930                         //store the last changed value index for reference when handles overlap
6931                         this._lastChangedValue = index;
6932                         this._trigger( "change", event, this._uiHash( index ) );
6933                 }
6934         },
6936         value: function( newValue ) {
6937                 if ( arguments.length ) {
6938                         this.options.value = this._trimAlignValue( newValue );
6939                         this._refreshValue();
6940                         this._change( null, 0 );
6941                         return;
6942                 }
6944                 return this._value();
6945         },
6947         values: function( index, newValue ) {
6948                 var vals,
6949                         newValues,
6950                         i;
6952                 if ( arguments.length > 1 ) {
6953                         this.options.values[ index ] = this._trimAlignValue( newValue );
6954                         this._refreshValue();
6955                         this._change( null, index );
6956                         return;
6957                 }
6959                 if ( arguments.length ) {
6960                         if ( $.isArray( arguments[ 0 ] ) ) {
6961                                 vals = this.options.values;
6962                                 newValues = arguments[ 0 ];
6963                                 for ( i = 0; i < vals.length; i += 1 ) {
6964                                         vals[ i ] = this._trimAlignValue( newValues[ i ] );
6965                                         this._change( null, i );
6966                                 }
6967                                 this._refreshValue();
6968                         } else {
6969                                 if ( this._hasMultipleValues() ) {
6970                                         return this._values( index );
6971                                 } else {
6972                                         return this.value();
6973                                 }
6974                         }
6975                 } else {
6976                         return this._values();
6977                 }
6978         },
6980         _setOption: function( key, value ) {
6981                 var i,
6982                         valsLength = 0;
6984                 if ( key === "range" && this.options.range === true ) {
6985                         if ( value === "min" ) {
6986                                 this.options.value = this._values( 0 );
6987                                 this.options.values = null;
6988                         } else if ( value === "max" ) {
6989                                 this.options.value = this._values( this.options.values.length - 1 );
6990                                 this.options.values = null;
6991                         }
6992                 }
6994                 if ( $.isArray( this.options.values ) ) {
6995                         valsLength = this.options.values.length;
6996                 }
6998                 this._super( key, value );
7000                 switch ( key ) {
7001                         case "orientation":
7002                                 this._detectOrientation();
7003                                 this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
7004                                         ._addClass( "ui-slider-" + this.orientation );
7005                                 this._refreshValue();
7006                                 if ( this.options.range ) {
7007                                         this._refreshRange( value );
7008                                 }
7010                                 // Reset positioning from previous orientation
7011                                 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
7012                                 break;
7013                         case "value":
7014                                 this._animateOff = true;
7015                                 this._refreshValue();
7016                                 this._change( null, 0 );
7017                                 this._animateOff = false;
7018                                 break;
7019                         case "values":
7020                                 this._animateOff = true;
7021                                 this._refreshValue();
7023                                 // Start from the last handle to prevent unreachable handles (#9046)
7024                                 for ( i = valsLength - 1; i >= 0; i-- ) {
7025                                         this._change( null, i );
7026                                 }
7027                                 this._animateOff = false;
7028                                 break;
7029                         case "step":
7030                         case "min":
7031                         case "max":
7032                                 this._animateOff = true;
7033                                 this._calculateNewMax();
7034                                 this._refreshValue();
7035                                 this._animateOff = false;
7036                                 break;
7037                         case "range":
7038                                 this._animateOff = true;
7039                                 this._refresh();
7040                                 this._animateOff = false;
7041                                 break;
7042                 }
7043         },
7045         _setOptionDisabled: function( value ) {
7046                 this._super( value );
7048                 this._toggleClass( null, "ui-state-disabled", !!value );
7049         },
7051         //internal value getter
7052         // _value() returns value trimmed by min and max, aligned by step
7053         _value: function() {
7054                 var val = this.options.value;
7055                 val = this._trimAlignValue( val );
7057                 return val;
7058         },
7060         //internal values getter
7061         // _values() returns array of values trimmed by min and max, aligned by step
7062         // _values( index ) returns single value trimmed by min and max, aligned by step
7063         _values: function( index ) {
7064                 var val,
7065                         vals,
7066                         i;
7068                 if ( arguments.length ) {
7069                         val = this.options.values[ index ];
7070                         val = this._trimAlignValue( val );
7072                         return val;
7073                 } else if ( this._hasMultipleValues() ) {
7075                         // .slice() creates a copy of the array
7076                         // this copy gets trimmed by min and max and then returned
7077                         vals = this.options.values.slice();
7078                         for ( i = 0; i < vals.length; i += 1 ) {
7079                                 vals[ i ] = this._trimAlignValue( vals[ i ] );
7080                         }
7082                         return vals;
7083                 } else {
7084                         return [];
7085                 }
7086         },
7088         // Returns the step-aligned value that val is closest to, between (inclusive) min and max
7089         _trimAlignValue: function( val ) {
7090                 if ( val <= this._valueMin() ) {
7091                         return this._valueMin();
7092                 }
7093                 if ( val >= this._valueMax() ) {
7094                         return this._valueMax();
7095                 }
7096                 var step = ( this.options.step > 0 ) ? this.options.step : 1,
7097                         valModStep = ( val - this._valueMin() ) % step,
7098                         alignValue = val - valModStep;
7100                 if ( Math.abs( valModStep ) * 2 >= step ) {
7101                         alignValue += ( valModStep > 0 ) ? step : ( -step );
7102                 }
7104                 // Since JavaScript has problems with large floats, round
7105                 // the final value to 5 digits after the decimal point (see #4124)
7106                 return parseFloat( alignValue.toFixed( 5 ) );
7107         },
7109         _calculateNewMax: function() {
7110                 var max = this.options.max,
7111                         min = this._valueMin(),
7112                         step = this.options.step,
7113                         aboveMin = Math.round( ( max - min ) / step ) * step;
7114                 max = aboveMin + min;
7115                 if ( max > this.options.max ) {
7117                         //If max is not divisible by step, rounding off may increase its value
7118                         max -= step;
7119                 }
7120                 this.max = parseFloat( max.toFixed( this._precision() ) );
7121         },
7123         _precision: function() {
7124                 var precision = this._precisionOf( this.options.step );
7125                 if ( this.options.min !== null ) {
7126                         precision = Math.max( precision, this._precisionOf( this.options.min ) );
7127                 }
7128                 return precision;
7129         },
7131         _precisionOf: function( num ) {
7132                 var str = num.toString(),
7133                         decimal = str.indexOf( "." );
7134                 return decimal === -1 ? 0 : str.length - decimal - 1;
7135         },
7137         _valueMin: function() {
7138                 return this.options.min;
7139         },
7141         _valueMax: function() {
7142                 return this.max;
7143         },
7145         _refreshRange: function( orientation ) {
7146                 if ( orientation === "vertical" ) {
7147                         this.range.css( { "width": "", "left": "" } );
7148                 }
7149                 if ( orientation === "horizontal" ) {
7150                         this.range.css( { "height": "", "bottom": "" } );
7151                 }
7152         },
7154         _refreshValue: function() {
7155                 var lastValPercent, valPercent, value, valueMin, valueMax,
7156                         oRange = this.options.range,
7157                         o = this.options,
7158                         that = this,
7159                         animate = ( !this._animateOff ) ? o.animate : false,
7160                         _set = {};
7162                 if ( this._hasMultipleValues() ) {
7163                         this.handles.each( function( i ) {
7164                                 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
7165                                         that._valueMin() ) * 100;
7166                                 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
7167                                 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
7168                                 if ( that.options.range === true ) {
7169                                         if ( that.orientation === "horizontal" ) {
7170                                                 if ( i === 0 ) {
7171                                                         that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
7172                                                                 left: valPercent + "%"
7173                                                         }, o.animate );
7174                                                 }
7175                                                 if ( i === 1 ) {
7176                                                         that.range[ animate ? "animate" : "css" ]( {
7177                                                                 width: ( valPercent - lastValPercent ) + "%"
7178                                                         }, {
7179                                                                 queue: false,
7180                                                                 duration: o.animate
7181                                                         } );
7182                                                 }
7183                                         } else {
7184                                                 if ( i === 0 ) {
7185                                                         that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
7186                                                                 bottom: ( valPercent ) + "%"
7187                                                         }, o.animate );
7188                                                 }
7189                                                 if ( i === 1 ) {
7190                                                         that.range[ animate ? "animate" : "css" ]( {
7191                                                                 height: ( valPercent - lastValPercent ) + "%"
7192                                                         }, {
7193                                                                 queue: false,
7194                                                                 duration: o.animate
7195                                                         } );
7196                                                 }
7197                                         }
7198                                 }
7199                                 lastValPercent = valPercent;
7200                         } );
7201                 } else {
7202                         value = this.value();
7203                         valueMin = this._valueMin();
7204                         valueMax = this._valueMax();
7205                         valPercent = ( valueMax !== valueMin ) ?
7206                                         ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
7207                                         0;
7208                         _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
7209                         this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
7211                         if ( oRange === "min" && this.orientation === "horizontal" ) {
7212                                 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
7213                                         width: valPercent + "%"
7214                                 }, o.animate );
7215                         }
7216                         if ( oRange === "max" && this.orientation === "horizontal" ) {
7217                                 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
7218                                         width: ( 100 - valPercent ) + "%"
7219                                 }, o.animate );
7220                         }
7221                         if ( oRange === "min" && this.orientation === "vertical" ) {
7222                                 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
7223                                         height: valPercent + "%"
7224                                 }, o.animate );
7225                         }
7226                         if ( oRange === "max" && this.orientation === "vertical" ) {
7227                                 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
7228                                         height: ( 100 - valPercent ) + "%"
7229                                 }, o.animate );
7230                         }
7231                 }
7232         },
7234         _handleEvents: {
7235                 keydown: function( event ) {
7236                         var allowed, curVal, newVal, step,
7237                                 index = $( event.target ).data( "ui-slider-handle-index" );
7239                         switch ( event.keyCode ) {
7240                                 case $.ui.keyCode.HOME:
7241                                 case $.ui.keyCode.END:
7242                                 case $.ui.keyCode.PAGE_UP:
7243                                 case $.ui.keyCode.PAGE_DOWN:
7244                                 case $.ui.keyCode.UP:
7245                                 case $.ui.keyCode.RIGHT:
7246                                 case $.ui.keyCode.DOWN:
7247                                 case $.ui.keyCode.LEFT:
7248                                         event.preventDefault();
7249                                         if ( !this._keySliding ) {
7250                                                 this._keySliding = true;
7251                                                 this._addClass( $( event.target ), null, "ui-state-active" );
7252                                                 allowed = this._start( event, index );
7253                                                 if ( allowed === false ) {
7254                                                         return;
7255                                                 }
7256                                         }
7257                                         break;
7258                         }
7260                         step = this.options.step;
7261                         if ( this._hasMultipleValues() ) {
7262                                 curVal = newVal = this.values( index );
7263                         } else {
7264                                 curVal = newVal = this.value();
7265                         }
7267                         switch ( event.keyCode ) {
7268                                 case $.ui.keyCode.HOME:
7269                                         newVal = this._valueMin();
7270                                         break;
7271                                 case $.ui.keyCode.END:
7272                                         newVal = this._valueMax();
7273                                         break;
7274                                 case $.ui.keyCode.PAGE_UP:
7275                                         newVal = this._trimAlignValue(
7276                                                 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
7277                                         );
7278                                         break;
7279                                 case $.ui.keyCode.PAGE_DOWN:
7280                                         newVal = this._trimAlignValue(
7281                                                 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
7282                                         break;
7283                                 case $.ui.keyCode.UP:
7284                                 case $.ui.keyCode.RIGHT:
7285                                         if ( curVal === this._valueMax() ) {
7286                                                 return;
7287                                         }
7288                                         newVal = this._trimAlignValue( curVal + step );
7289                                         break;
7290                                 case $.ui.keyCode.DOWN:
7291                                 case $.ui.keyCode.LEFT:
7292                                         if ( curVal === this._valueMin() ) {
7293                                                 return;
7294                                         }
7295                                         newVal = this._trimAlignValue( curVal - step );
7296                                         break;
7297                         }
7299                         this._slide( event, index, newVal );
7300                 },
7301                 keyup: function( event ) {
7302                         var index = $( event.target ).data( "ui-slider-handle-index" );
7304                         if ( this._keySliding ) {
7305                                 this._keySliding = false;
7306                                 this._stop( event, index );
7307                                 this._change( event, index );
7308                                 this._removeClass( $( event.target ), null, "ui-state-active" );
7309                         }
7310                 }
7311         }
7312 } );
7317 // Internal use only
7318 var escapeSelector = $.ui.escapeSelector = ( function() {
7319         var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
7320         return function( selector ) {
7321                 return selector.replace( selectorEscape, "\\$1" );
7322         };
7323 } )();
7327  * jQuery UI Tabs 1.12.1
7328  * http://jqueryui.com
7330  * Copyright jQuery Foundation and other contributors
7331  * Released under the MIT license.
7332  * http://jquery.org/license
7333  */
7335 //>>label: Tabs
7336 //>>group: Widgets
7337 //>>description: Transforms a set of container elements into a tab structure.
7338 //>>docs: http://api.jqueryui.com/tabs/
7339 //>>demos: http://jqueryui.com/tabs/
7340 //>>css.structure: ../../themes/base/core.css
7341 //>>css.structure: ../../themes/base/tabs.css
7342 //>>css.theme: ../../themes/base/theme.css
7346 $.widget( "ui.tabs", {
7347         version: "1.12.1",
7348         delay: 300,
7349         options: {
7350                 active: null,
7351                 classes: {
7352                         "ui-tabs": "ui-corner-all",
7353                         "ui-tabs-nav": "ui-corner-all",
7354                         "ui-tabs-panel": "ui-corner-bottom",
7355                         "ui-tabs-tab": "ui-corner-top"
7356                 },
7357                 collapsible: false,
7358                 event: "click",
7359                 heightStyle: "content",
7360                 hide: null,
7361                 show: null,
7363                 // Callbacks
7364                 activate: null,
7365                 beforeActivate: null,
7366                 beforeLoad: null,
7367                 load: null
7368         },
7370         _isLocal: ( function() {
7371                 var rhash = /#.*$/;
7373                 return function( anchor ) {
7374                         var anchorUrl, locationUrl;
7376                         anchorUrl = anchor.href.replace( rhash, "" );
7377                         locationUrl = location.href.replace( rhash, "" );
7379                         // Decoding may throw an error if the URL isn't UTF-8 (#9518)
7380                         try {
7381                                 anchorUrl = decodeURIComponent( anchorUrl );
7382                         } catch ( error ) {}
7383                         try {
7384                                 locationUrl = decodeURIComponent( locationUrl );
7385                         } catch ( error ) {}
7387                         return anchor.hash.length > 1 && anchorUrl === locationUrl;
7388                 };
7389         } )(),
7391         _create: function() {
7392                 var that = this,
7393                         options = this.options;
7395                 this.running = false;
7397                 this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
7398                 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
7400                 this._processTabs();
7401                 options.active = this._initialActive();
7403                 // Take disabling tabs via class attribute from HTML
7404                 // into account and update option properly.
7405                 if ( $.isArray( options.disabled ) ) {
7406                         options.disabled = $.unique( options.disabled.concat(
7407                                 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
7408                                         return that.tabs.index( li );
7409                                 } )
7410                         ) ).sort();
7411                 }
7413                 // Check for length avoids error when initializing empty list
7414                 if ( this.options.active !== false && this.anchors.length ) {
7415                         this.active = this._findActive( options.active );
7416                 } else {
7417                         this.active = $();
7418                 }
7420                 this._refresh();
7422                 if ( this.active.length ) {
7423                         this.load( options.active );
7424                 }
7425         },
7427         _initialActive: function() {
7428                 var active = this.options.active,
7429                         collapsible = this.options.collapsible,
7430                         locationHash = location.hash.substring( 1 );
7432                 if ( active === null ) {
7434                         // check the fragment identifier in the URL
7435                         if ( locationHash ) {
7436                                 this.tabs.each( function( i, tab ) {
7437                                         if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
7438                                                 active = i;
7439                                                 return false;
7440                                         }
7441                                 } );
7442                         }
7444                         // Check for a tab marked active via a class
7445                         if ( active === null ) {
7446                                 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
7447                         }
7449                         // No active tab, set to false
7450                         if ( active === null || active === -1 ) {
7451                                 active = this.tabs.length ? 0 : false;
7452                         }
7453                 }
7455                 // Handle numbers: negative, out of range
7456                 if ( active !== false ) {
7457                         active = this.tabs.index( this.tabs.eq( active ) );
7458                         if ( active === -1 ) {
7459                                 active = collapsible ? false : 0;
7460                         }
7461                 }
7463                 // Don't allow collapsible: false and active: false
7464                 if ( !collapsible && active === false && this.anchors.length ) {
7465                         active = 0;
7466                 }
7468                 return active;
7469         },
7471         _getCreateEventData: function() {
7472                 return {
7473                         tab: this.active,
7474                         panel: !this.active.length ? $() : this._getPanelForTab( this.active )
7475                 };
7476         },
7478         _tabKeydown: function( event ) {
7479                 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
7480                         selectedIndex = this.tabs.index( focusedTab ),
7481                         goingForward = true;
7483                 if ( this._handlePageNav( event ) ) {
7484                         return;
7485                 }
7487                 switch ( event.keyCode ) {
7488                 case $.ui.keyCode.RIGHT:
7489                 case $.ui.keyCode.DOWN:
7490                         selectedIndex++;
7491                         break;
7492                 case $.ui.keyCode.UP:
7493                 case $.ui.keyCode.LEFT:
7494                         goingForward = false;
7495                         selectedIndex--;
7496                         break;
7497                 case $.ui.keyCode.END:
7498                         selectedIndex = this.anchors.length - 1;
7499                         break;
7500                 case $.ui.keyCode.HOME:
7501                         selectedIndex = 0;
7502                         break;
7503                 case $.ui.keyCode.SPACE:
7505                         // Activate only, no collapsing
7506                         event.preventDefault();
7507                         clearTimeout( this.activating );
7508                         this._activate( selectedIndex );
7509                         return;
7510                 case $.ui.keyCode.ENTER:
7512                         // Toggle (cancel delayed activation, allow collapsing)
7513                         event.preventDefault();
7514                         clearTimeout( this.activating );
7516                         // Determine if we should collapse or activate
7517                         this._activate( selectedIndex === this.options.active ? false : selectedIndex );
7518                         return;
7519                 default:
7520                         return;
7521                 }
7523                 // Focus the appropriate tab, based on which key was pressed
7524                 event.preventDefault();
7525                 clearTimeout( this.activating );
7526                 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
7528                 // Navigating with control/command key will prevent automatic activation
7529                 if ( !event.ctrlKey && !event.metaKey ) {
7531                         // Update aria-selected immediately so that AT think the tab is already selected.
7532                         // Otherwise AT may confuse the user by stating that they need to activate the tab,
7533                         // but the tab will already be activated by the time the announcement finishes.
7534                         focusedTab.attr( "aria-selected", "false" );
7535                         this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
7537                         this.activating = this._delay( function() {
7538                                 this.option( "active", selectedIndex );
7539                         }, this.delay );
7540                 }
7541         },
7543         _panelKeydown: function( event ) {
7544                 if ( this._handlePageNav( event ) ) {
7545                         return;
7546                 }
7548                 // Ctrl+up moves focus to the current tab
7549                 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
7550                         event.preventDefault();
7551                         this.active.trigger( "focus" );
7552                 }
7553         },
7555         // Alt+page up/down moves focus to the previous/next tab (and activates)
7556         _handlePageNav: function( event ) {
7557                 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
7558                         this._activate( this._focusNextTab( this.options.active - 1, false ) );
7559                         return true;
7560                 }
7561                 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
7562                         this._activate( this._focusNextTab( this.options.active + 1, true ) );
7563                         return true;
7564                 }
7565         },
7567         _findNextTab: function( index, goingForward ) {
7568                 var lastTabIndex = this.tabs.length - 1;
7570                 function constrain() {
7571                         if ( index > lastTabIndex ) {
7572                                 index = 0;
7573                         }
7574                         if ( index < 0 ) {
7575                                 index = lastTabIndex;
7576                         }
7577                         return index;
7578                 }
7580                 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
7581                         index = goingForward ? index + 1 : index - 1;
7582                 }
7584                 return index;
7585         },
7587         _focusNextTab: function( index, goingForward ) {
7588                 index = this._findNextTab( index, goingForward );
7589                 this.tabs.eq( index ).trigger( "focus" );
7590                 return index;
7591         },
7593         _setOption: function( key, value ) {
7594                 if ( key === "active" ) {
7596                         // _activate() will handle invalid values and update this.options
7597                         this._activate( value );
7598                         return;
7599                 }
7601                 this._super( key, value );
7603                 if ( key === "collapsible" ) {
7604                         this._toggleClass( "ui-tabs-collapsible", null, value );
7606                         // Setting collapsible: false while collapsed; open first panel
7607                         if ( !value && this.options.active === false ) {
7608                                 this._activate( 0 );
7609                         }
7610                 }
7612                 if ( key === "event" ) {
7613                         this._setupEvents( value );
7614                 }
7616                 if ( key === "heightStyle" ) {
7617                         this._setupHeightStyle( value );
7618                 }
7619         },
7621         _sanitizeSelector: function( hash ) {
7622                 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
7623         },
7625         refresh: function() {
7626                 var options = this.options,
7627                         lis = this.tablist.children( ":has(a[href])" );
7629                 // Get disabled tabs from class attribute from HTML
7630                 // this will get converted to a boolean if needed in _refresh()
7631                 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
7632                         return lis.index( tab );
7633                 } );
7635                 this._processTabs();
7637                 // Was collapsed or no tabs
7638                 if ( options.active === false || !this.anchors.length ) {
7639                         options.active = false;
7640                         this.active = $();
7642                 // was active, but active tab is gone
7643                 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
7645                         // all remaining tabs are disabled
7646                         if ( this.tabs.length === options.disabled.length ) {
7647                                 options.active = false;
7648                                 this.active = $();
7650                         // activate previous tab
7651                         } else {
7652                                 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
7653                         }
7655                 // was active, active tab still exists
7656                 } else {
7658                         // make sure active index is correct
7659                         options.active = this.tabs.index( this.active );
7660                 }
7662                 this._refresh();
7663         },
7665         _refresh: function() {
7666                 this._setOptionDisabled( this.options.disabled );
7667                 this._setupEvents( this.options.event );
7668                 this._setupHeightStyle( this.options.heightStyle );
7670                 this.tabs.not( this.active ).attr( {
7671                         "aria-selected": "false",
7672                         "aria-expanded": "false",
7673                         tabIndex: -1
7674                 } );
7675                 this.panels.not( this._getPanelForTab( this.active ) )
7676                         .hide()
7677                         .attr( {
7678                                 "aria-hidden": "true"
7679                         } );
7681                 // Make sure one tab is in the tab order
7682                 if ( !this.active.length ) {
7683                         this.tabs.eq( 0 ).attr( "tabIndex", 0 );
7684                 } else {
7685                         this.active
7686                                 .attr( {
7687                                         "aria-selected": "true",
7688                                         "aria-expanded": "true",
7689                                         tabIndex: 0
7690                                 } );
7691                         this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
7692                         this._getPanelForTab( this.active )
7693                                 .show()
7694                                 .attr( {
7695                                         "aria-hidden": "false"
7696                                 } );
7697                 }
7698         },
7700         _processTabs: function() {
7701                 var that = this,
7702                         prevTabs = this.tabs,
7703                         prevAnchors = this.anchors,
7704                         prevPanels = this.panels;
7706                 this.tablist = this._getList().attr( "role", "tablist" );
7707                 this._addClass( this.tablist, "ui-tabs-nav",
7708                         "ui-helper-reset ui-helper-clearfix ui-widget-header" );
7710                 // Prevent users from focusing disabled tabs via click
7711                 this.tablist
7712                         .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
7713                                 if ( $( this ).is( ".ui-state-disabled" ) ) {
7714                                         event.preventDefault();
7715                                 }
7716                         } )
7718                         // Support: IE <9
7719                         // Preventing the default action in mousedown doesn't prevent IE
7720                         // from focusing the element, so if the anchor gets focused, blur.
7721                         // We don't have to worry about focusing the previously focused
7722                         // element since clicking on a non-focusable element should focus
7723                         // the body anyway.
7724                         .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
7725                                 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
7726                                         this.blur();
7727                                 }
7728                         } );
7730                 this.tabs = this.tablist.find( "> li:has(a[href])" )
7731                         .attr( {
7732                                 role: "tab",
7733                                 tabIndex: -1
7734                         } );
7735                 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
7737                 this.anchors = this.tabs.map( function() {
7738                         return $( "a", this )[ 0 ];
7739                 } )
7740                         .attr( {
7741                                 role: "presentation",
7742                                 tabIndex: -1
7743                         } );
7744                 this._addClass( this.anchors, "ui-tabs-anchor" );
7746                 this.panels = $();
7748                 this.anchors.each( function( i, anchor ) {
7749                         var selector, panel, panelId,
7750                                 anchorId = $( anchor ).uniqueId().attr( "id" ),
7751                                 tab = $( anchor ).closest( "li" ),
7752                                 originalAriaControls = tab.attr( "aria-controls" );
7754                         // Inline tab
7755                         if ( that._isLocal( anchor ) ) {
7756                                 selector = anchor.hash;
7757                                 panelId = selector.substring( 1 );
7758                                 panel = that.element.find( that._sanitizeSelector( selector ) );
7760                         // remote tab
7761                         } else {
7763                                 // If the tab doesn't already have aria-controls,
7764                                 // generate an id by using a throw-away element
7765                                 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
7766                                 selector = "#" + panelId;
7767                                 panel = that.element.find( selector );
7768                                 if ( !panel.length ) {
7769                                         panel = that._createPanel( panelId );
7770                                         panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
7771                                 }
7772                                 panel.attr( "aria-live", "polite" );
7773                         }
7775                         if ( panel.length ) {
7776                                 that.panels = that.panels.add( panel );
7777                         }
7778                         if ( originalAriaControls ) {
7779                                 tab.data( "ui-tabs-aria-controls", originalAriaControls );
7780                         }
7781                         tab.attr( {
7782                                 "aria-controls": panelId,
7783                                 "aria-labelledby": anchorId
7784                         } );
7785                         panel.attr( "aria-labelledby", anchorId );
7786                 } );
7788                 this.panels.attr( "role", "tabpanel" );
7789                 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
7791                 // Avoid memory leaks (#10056)
7792                 if ( prevTabs ) {
7793                         this._off( prevTabs.not( this.tabs ) );
7794                         this._off( prevAnchors.not( this.anchors ) );
7795                         this._off( prevPanels.not( this.panels ) );
7796                 }
7797         },
7799         // Allow overriding how to find the list for rare usage scenarios (#7715)
7800         _getList: function() {
7801                 return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
7802         },
7804         _createPanel: function( id ) {
7805                 return $( "<div>" )
7806                         .attr( "id", id )
7807                         .data( "ui-tabs-destroy", true );
7808         },
7810         _setOptionDisabled: function( disabled ) {
7811                 var currentItem, li, i;
7813                 if ( $.isArray( disabled ) ) {
7814                         if ( !disabled.length ) {
7815                                 disabled = false;
7816                         } else if ( disabled.length === this.anchors.length ) {
7817                                 disabled = true;
7818                         }
7819                 }
7821                 // Disable tabs
7822                 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
7823                         currentItem = $( li );
7824                         if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
7825                                 currentItem.attr( "aria-disabled", "true" );
7826                                 this._addClass( currentItem, null, "ui-state-disabled" );
7827                         } else {
7828                                 currentItem.removeAttr( "aria-disabled" );
7829                                 this._removeClass( currentItem, null, "ui-state-disabled" );
7830                         }
7831                 }
7833                 this.options.disabled = disabled;
7835                 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
7836                         disabled === true );
7837         },
7839         _setupEvents: function( event ) {
7840                 var events = {};
7841                 if ( event ) {
7842                         $.each( event.split( " " ), function( index, eventName ) {
7843                                 events[ eventName ] = "_eventHandler";
7844                         } );
7845                 }
7847                 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
7849                 // Always prevent the default action, even when disabled
7850                 this._on( true, this.anchors, {
7851                         click: function( event ) {
7852                                 event.preventDefault();
7853                         }
7854                 } );
7855                 this._on( this.anchors, events );
7856                 this._on( this.tabs, { keydown: "_tabKeydown" } );
7857                 this._on( this.panels, { keydown: "_panelKeydown" } );
7859                 this._focusable( this.tabs );
7860                 this._hoverable( this.tabs );
7861         },
7863         _setupHeightStyle: function( heightStyle ) {
7864                 var maxHeight,
7865                         parent = this.element.parent();
7867                 if ( heightStyle === "fill" ) {
7868                         maxHeight = parent.height();
7869                         maxHeight -= this.element.outerHeight() - this.element.height();
7871                         this.element.siblings( ":visible" ).each( function() {
7872                                 var elem = $( this ),
7873                                         position = elem.css( "position" );
7875                                 if ( position === "absolute" || position === "fixed" ) {
7876                                         return;
7877                                 }
7878                                 maxHeight -= elem.outerHeight( true );
7879                         } );
7881                         this.element.children().not( this.panels ).each( function() {
7882                                 maxHeight -= $( this ).outerHeight( true );
7883                         } );
7885                         this.panels.each( function() {
7886                                 $( this ).height( Math.max( 0, maxHeight -
7887                                         $( this ).innerHeight() + $( this ).height() ) );
7888                         } )
7889                                 .css( "overflow", "auto" );
7890                 } else if ( heightStyle === "auto" ) {
7891                         maxHeight = 0;
7892                         this.panels.each( function() {
7893                                 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
7894                         } ).height( maxHeight );
7895                 }
7896         },
7898         _eventHandler: function( event ) {
7899                 var options = this.options,
7900                         active = this.active,
7901                         anchor = $( event.currentTarget ),
7902                         tab = anchor.closest( "li" ),
7903                         clickedIsActive = tab[ 0 ] === active[ 0 ],
7904                         collapsing = clickedIsActive && options.collapsible,
7905                         toShow = collapsing ? $() : this._getPanelForTab( tab ),
7906                         toHide = !active.length ? $() : this._getPanelForTab( active ),
7907                         eventData = {
7908                                 oldTab: active,
7909                                 oldPanel: toHide,
7910                                 newTab: collapsing ? $() : tab,
7911                                 newPanel: toShow
7912                         };
7914                 event.preventDefault();
7916                 if ( tab.hasClass( "ui-state-disabled" ) ||
7918                                 // tab is already loading
7919                                 tab.hasClass( "ui-tabs-loading" ) ||
7921                                 // can't switch durning an animation
7922                                 this.running ||
7924                                 // click on active header, but not collapsible
7925                                 ( clickedIsActive && !options.collapsible ) ||
7927                                 // allow canceling activation
7928                                 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
7929                         return;
7930                 }
7932                 options.active = collapsing ? false : this.tabs.index( tab );
7934                 this.active = clickedIsActive ? $() : tab;
7935                 if ( this.xhr ) {
7936                         this.xhr.abort();
7937                 }
7939                 if ( !toHide.length && !toShow.length ) {
7940                         $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
7941                 }
7943                 if ( toShow.length ) {
7944                         this.load( this.tabs.index( tab ), event );
7945                 }
7946                 this._toggle( event, eventData );
7947         },
7949         // Handles show/hide for selecting tabs
7950         _toggle: function( event, eventData ) {
7951                 var that = this,
7952                         toShow = eventData.newPanel,
7953                         toHide = eventData.oldPanel;
7955                 this.running = true;
7957                 function complete() {
7958                         that.running = false;
7959                         that._trigger( "activate", event, eventData );
7960                 }
7962                 function show() {
7963                         that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
7965                         if ( toShow.length && that.options.show ) {
7966                                 that._show( toShow, that.options.show, complete );
7967                         } else {
7968                                 toShow.show();
7969                                 complete();
7970                         }
7971                 }
7973                 // Start out by hiding, then showing, then completing
7974                 if ( toHide.length && this.options.hide ) {
7975                         this._hide( toHide, this.options.hide, function() {
7976                                 that._removeClass( eventData.oldTab.closest( "li" ),
7977                                         "ui-tabs-active", "ui-state-active" );
7978                                 show();
7979                         } );
7980                 } else {
7981                         this._removeClass( eventData.oldTab.closest( "li" ),
7982                                 "ui-tabs-active", "ui-state-active" );
7983                         toHide.hide();
7984                         show();
7985                 }
7987                 toHide.attr( "aria-hidden", "true" );
7988                 eventData.oldTab.attr( {
7989                         "aria-selected": "false",
7990                         "aria-expanded": "false"
7991                 } );
7993                 // If we're switching tabs, remove the old tab from the tab order.
7994                 // If we're opening from collapsed state, remove the previous tab from the tab order.
7995                 // If we're collapsing, then keep the collapsing tab in the tab order.
7996                 if ( toShow.length && toHide.length ) {
7997                         eventData.oldTab.attr( "tabIndex", -1 );
7998                 } else if ( toShow.length ) {
7999                         this.tabs.filter( function() {
8000                                 return $( this ).attr( "tabIndex" ) === 0;
8001                         } )
8002                                 .attr( "tabIndex", -1 );
8003                 }
8005                 toShow.attr( "aria-hidden", "false" );
8006                 eventData.newTab.attr( {
8007                         "aria-selected": "true",
8008                         "aria-expanded": "true",
8009                         tabIndex: 0
8010                 } );
8011         },
8013         _activate: function( index ) {
8014                 var anchor,
8015                         active = this._findActive( index );
8017                 // Trying to activate the already active panel
8018                 if ( active[ 0 ] === this.active[ 0 ] ) {
8019                         return;
8020                 }
8022                 // Trying to collapse, simulate a click on the current active header
8023                 if ( !active.length ) {
8024                         active = this.active;
8025                 }
8027                 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
8028                 this._eventHandler( {
8029                         target: anchor,
8030                         currentTarget: anchor,
8031                         preventDefault: $.noop
8032                 } );
8033         },
8035         _findActive: function( index ) {
8036                 return index === false ? $() : this.tabs.eq( index );
8037         },
8039         _getIndex: function( index ) {
8041                 // meta-function to give users option to provide a href string instead of a numerical index.
8042                 if ( typeof index === "string" ) {
8043                         index = this.anchors.index( this.anchors.filter( "[href$='" +
8044                                 $.ui.escapeSelector( index ) + "']" ) );
8045                 }
8047                 return index;
8048         },
8050         _destroy: function() {
8051                 if ( this.xhr ) {
8052                         this.xhr.abort();
8053                 }
8055                 this.tablist
8056                         .removeAttr( "role" )
8057                         .off( this.eventNamespace );
8059                 this.anchors
8060                         .removeAttr( "role tabIndex" )
8061                         .removeUniqueId();
8063                 this.tabs.add( this.panels ).each( function() {
8064                         if ( $.data( this, "ui-tabs-destroy" ) ) {
8065                                 $( this ).remove();
8066                         } else {
8067                                 $( this ).removeAttr( "role tabIndex " +
8068                                         "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
8069                         }
8070                 } );
8072                 this.tabs.each( function() {
8073                         var li = $( this ),
8074                                 prev = li.data( "ui-tabs-aria-controls" );
8075                         if ( prev ) {
8076                                 li
8077                                         .attr( "aria-controls", prev )
8078                                         .removeData( "ui-tabs-aria-controls" );
8079                         } else {
8080                                 li.removeAttr( "aria-controls" );
8081                         }
8082                 } );
8084                 this.panels.show();
8086                 if ( this.options.heightStyle !== "content" ) {
8087                         this.panels.css( "height", "" );
8088                 }
8089         },
8091         enable: function( index ) {
8092                 var disabled = this.options.disabled;
8093                 if ( disabled === false ) {
8094                         return;
8095                 }
8097                 if ( index === undefined ) {
8098                         disabled = false;
8099                 } else {
8100                         index = this._getIndex( index );
8101                         if ( $.isArray( disabled ) ) {
8102                                 disabled = $.map( disabled, function( num ) {
8103                                         return num !== index ? num : null;
8104                                 } );
8105                         } else {
8106                                 disabled = $.map( this.tabs, function( li, num ) {
8107                                         return num !== index ? num : null;
8108                                 } );
8109                         }
8110                 }
8111                 this._setOptionDisabled( disabled );
8112         },
8114         disable: function( index ) {
8115                 var disabled = this.options.disabled;
8116                 if ( disabled === true ) {
8117                         return;
8118                 }
8120                 if ( index === undefined ) {
8121                         disabled = true;
8122                 } else {
8123                         index = this._getIndex( index );
8124                         if ( $.inArray( index, disabled ) !== -1 ) {
8125                                 return;
8126                         }
8127                         if ( $.isArray( disabled ) ) {
8128                                 disabled = $.merge( [ index ], disabled ).sort();
8129                         } else {
8130                                 disabled = [ index ];
8131                         }
8132                 }
8133                 this._setOptionDisabled( disabled );
8134         },
8136         load: function( index, event ) {
8137                 index = this._getIndex( index );
8138                 var that = this,
8139                         tab = this.tabs.eq( index ),
8140                         anchor = tab.find( ".ui-tabs-anchor" ),
8141                         panel = this._getPanelForTab( tab ),
8142                         eventData = {
8143                                 tab: tab,
8144                                 panel: panel
8145                         },
8146                         complete = function( jqXHR, status ) {
8147                                 if ( status === "abort" ) {
8148                                         that.panels.stop( false, true );
8149                                 }
8151                                 that._removeClass( tab, "ui-tabs-loading" );
8152                                 panel.removeAttr( "aria-busy" );
8154                                 if ( jqXHR === that.xhr ) {
8155                                         delete that.xhr;
8156                                 }
8157                         };
8159                 // Not remote
8160                 if ( this._isLocal( anchor[ 0 ] ) ) {
8161                         return;
8162                 }
8164                 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
8166                 // Support: jQuery <1.8
8167                 // jQuery <1.8 returns false if the request is canceled in beforeSend,
8168                 // but as of 1.8, $.ajax() always returns a jqXHR object.
8169                 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
8170                         this._addClass( tab, "ui-tabs-loading" );
8171                         panel.attr( "aria-busy", "true" );
8173                         this.xhr
8174                                 .done( function( response, status, jqXHR ) {
8176                                         // support: jQuery <1.8
8177                                         // http://bugs.jquery.com/ticket/11778
8178                                         setTimeout( function() {
8179                                                 panel.html( response );
8180                                                 that._trigger( "load", event, eventData );
8182                                                 complete( jqXHR, status );
8183                                         }, 1 );
8184                                 } )
8185                                 .fail( function( jqXHR, status ) {
8187                                         // support: jQuery <1.8
8188                                         // http://bugs.jquery.com/ticket/11778
8189                                         setTimeout( function() {
8190                                                 complete( jqXHR, status );
8191                                         }, 1 );
8192                                 } );
8193                 }
8194         },
8196         _ajaxSettings: function( anchor, event, eventData ) {
8197                 var that = this;
8198                 return {
8200                         // Support: IE <11 only
8201                         // Strip any hash that exists to prevent errors with the Ajax request
8202                         url: anchor.attr( "href" ).replace( /#.*$/, "" ),
8203                         beforeSend: function( jqXHR, settings ) {
8204                                 return that._trigger( "beforeLoad", event,
8205                                         $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
8206                         }
8207                 };
8208         },
8210         _getPanelForTab: function( tab ) {
8211                 var id = $( tab ).attr( "aria-controls" );
8212                 return this.element.find( this._sanitizeSelector( "#" + id ) );
8213         }
8214 } );
8216 // DEPRECATED
8217 // TODO: Switch return back to widget declaration at top of file when this is removed
8218 if ( $.uiBackCompat !== false ) {
8220         // Backcompat for ui-tab class (now ui-tabs-tab)
8221         $.widget( "ui.tabs", $.ui.tabs, {
8222                 _processTabs: function() {
8223                         this._superApply( arguments );
8224                         this._addClass( this.tabs, "ui-tab" );
8225                 }
8226         } );
8229 var widgetsTabs = $.ui.tabs;
8233  * jQuery UI Tooltip 1.12.1
8234  * http://jqueryui.com
8236  * Copyright jQuery Foundation and other contributors
8237  * Released under the MIT license.
8238  * http://jquery.org/license
8239  */
8241 //>>label: Tooltip
8242 //>>group: Widgets
8243 //>>description: Shows additional information for any element on hover or focus.
8244 //>>docs: http://api.jqueryui.com/tooltip/
8245 //>>demos: http://jqueryui.com/tooltip/
8246 //>>css.structure: ../../themes/base/core.css
8247 //>>css.structure: ../../themes/base/tooltip.css
8248 //>>css.theme: ../../themes/base/theme.css
8252 $.widget( "ui.tooltip", {
8253         version: "1.12.1",
8254         options: {
8255                 classes: {
8256                         "ui-tooltip": "ui-corner-all ui-widget-shadow"
8257                 },
8258                 content: function() {
8260                         // support: IE<9, Opera in jQuery <1.7
8261                         // .text() can't accept undefined, so coerce to a string
8262                         var title = $( this ).attr( "title" ) || "";
8264                         // Escape title, since we're going from an attribute to raw HTML
8265                         return $( "<a>" ).text( title ).html();
8266                 },
8267                 hide: true,
8269                 // Disabled elements have inconsistent behavior across browsers (#8661)
8270                 items: "[title]:not([disabled])",
8271                 position: {
8272                         my: "left top+15",
8273                         at: "left bottom",
8274                         collision: "flipfit flip"
8275                 },
8276                 show: true,
8277                 track: false,
8279                 // Callbacks
8280                 close: null,
8281                 open: null
8282         },
8284         _addDescribedBy: function( elem, id ) {
8285                 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
8286                 describedby.push( id );
8287                 elem
8288                         .data( "ui-tooltip-id", id )
8289                         .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
8290         },
8292         _removeDescribedBy: function( elem ) {
8293                 var id = elem.data( "ui-tooltip-id" ),
8294                         describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
8295                         index = $.inArray( id, describedby );
8297                 if ( index !== -1 ) {
8298                         describedby.splice( index, 1 );
8299                 }
8301                 elem.removeData( "ui-tooltip-id" );
8302                 describedby = $.trim( describedby.join( " " ) );
8303                 if ( describedby ) {
8304                         elem.attr( "aria-describedby", describedby );
8305                 } else {
8306                         elem.removeAttr( "aria-describedby" );
8307                 }
8308         },
8310         _create: function() {
8311                 this._on( {
8312                         mouseover: "open",
8313                         focusin: "open"
8314                 } );
8316                 // IDs of generated tooltips, needed for destroy
8317                 this.tooltips = {};
8319                 // IDs of parent tooltips where we removed the title attribute
8320                 this.parents = {};
8322                 // Append the aria-live region so tooltips announce correctly
8323                 this.liveRegion = $( "<div>" )
8324                         .attr( {
8325                                 role: "log",
8326                                 "aria-live": "assertive",
8327                                 "aria-relevant": "additions"
8328                         } )
8329                         .appendTo( this.document[ 0 ].body );
8330                 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
8332                 this.disabledTitles = $( [] );
8333         },
8335         _setOption: function( key, value ) {
8336                 var that = this;
8338                 this._super( key, value );
8340                 if ( key === "content" ) {
8341                         $.each( this.tooltips, function( id, tooltipData ) {
8342                                 that._updateContent( tooltipData.element );
8343                         } );
8344                 }
8345         },
8347         _setOptionDisabled: function( value ) {
8348                 this[ value ? "_disable" : "_enable" ]();
8349         },
8351         _disable: function() {
8352                 var that = this;
8354                 // Close open tooltips
8355                 $.each( this.tooltips, function( id, tooltipData ) {
8356                         var event = $.Event( "blur" );
8357                         event.target = event.currentTarget = tooltipData.element[ 0 ];
8358                         that.close( event, true );
8359                 } );
8361                 // Remove title attributes to prevent native tooltips
8362                 this.disabledTitles = this.disabledTitles.add(
8363                         this.element.find( this.options.items ).addBack()
8364                                 .filter( function() {
8365                                         var element = $( this );
8366                                         if ( element.is( "[title]" ) ) {
8367                                                 return element
8368                                                         .data( "ui-tooltip-title", element.attr( "title" ) )
8369                                                         .removeAttr( "title" );
8370                                         }
8371                                 } )
8372                 );
8373         },
8375         _enable: function() {
8377                 // restore title attributes
8378                 this.disabledTitles.each( function() {
8379                         var element = $( this );
8380                         if ( element.data( "ui-tooltip-title" ) ) {
8381                                 element.attr( "title", element.data( "ui-tooltip-title" ) );
8382                         }
8383                 } );
8384                 this.disabledTitles = $( [] );
8385         },
8387         open: function( event ) {
8388                 var that = this,
8389                         target = $( event ? event.target : this.element )
8391                                 // we need closest here due to mouseover bubbling,
8392                                 // but always pointing at the same event target
8393                                 .closest( this.options.items );
8395                 // No element to show a tooltip for or the tooltip is already open
8396                 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
8397                         return;
8398                 }
8400                 if ( target.attr( "title" ) ) {
8401                         target.data( "ui-tooltip-title", target.attr( "title" ) );
8402                 }
8404                 target.data( "ui-tooltip-open", true );
8406                 // Kill parent tooltips, custom or native, for hover
8407                 if ( event && event.type === "mouseover" ) {
8408                         target.parents().each( function() {
8409                                 var parent = $( this ),
8410                                         blurEvent;
8411                                 if ( parent.data( "ui-tooltip-open" ) ) {
8412                                         blurEvent = $.Event( "blur" );
8413                                         blurEvent.target = blurEvent.currentTarget = this;
8414                                         that.close( blurEvent, true );
8415                                 }
8416                                 if ( parent.attr( "title" ) ) {
8417                                         parent.uniqueId();
8418                                         that.parents[ this.id ] = {
8419                                                 element: this,
8420                                                 title: parent.attr( "title" )
8421                                         };
8422                                         parent.attr( "title", "" );
8423                                 }
8424                         } );
8425                 }
8427                 this._registerCloseHandlers( event, target );
8428                 this._updateContent( target, event );
8429         },
8431         _updateContent: function( target, event ) {
8432                 var content,
8433                         contentOption = this.options.content,
8434                         that = this,
8435                         eventType = event ? event.type : null;
8437                 if ( typeof contentOption === "string" || contentOption.nodeType ||
8438                                 contentOption.jquery ) {
8439                         return this._open( event, target, contentOption );
8440                 }
8442                 content = contentOption.call( target[ 0 ], function( response ) {
8444                         // IE may instantly serve a cached response for ajax requests
8445                         // delay this call to _open so the other call to _open runs first
8446                         that._delay( function() {
8448                                 // Ignore async response if tooltip was closed already
8449                                 if ( !target.data( "ui-tooltip-open" ) ) {
8450                                         return;
8451                                 }
8453                                 // JQuery creates a special event for focusin when it doesn't
8454                                 // exist natively. To improve performance, the native event
8455                                 // object is reused and the type is changed. Therefore, we can't
8456                                 // rely on the type being correct after the event finished
8457                                 // bubbling, so we set it back to the previous value. (#8740)
8458                                 if ( event ) {
8459                                         event.type = eventType;
8460                                 }
8461                                 this._open( event, target, response );
8462                         } );
8463                 } );
8464                 if ( content ) {
8465                         this._open( event, target, content );
8466                 }
8467         },
8469         _open: function( event, target, content ) {
8470                 var tooltipData, tooltip, delayedShow, a11yContent,
8471                         positionOption = $.extend( {}, this.options.position );
8473                 if ( !content ) {
8474                         return;
8475                 }
8477                 // Content can be updated multiple times. If the tooltip already
8478                 // exists, then just update the content and bail.
8479                 tooltipData = this._find( target );
8480                 if ( tooltipData ) {
8481                         tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
8482                         return;
8483                 }
8485                 // If we have a title, clear it to prevent the native tooltip
8486                 // we have to check first to avoid defining a title if none exists
8487                 // (we don't want to cause an element to start matching [title])
8488                 //
8489                 // We use removeAttr only for key events, to allow IE to export the correct
8490                 // accessible attributes. For mouse events, set to empty string to avoid
8491                 // native tooltip showing up (happens only when removing inside mouseover).
8492                 if ( target.is( "[title]" ) ) {
8493                         if ( event && event.type === "mouseover" ) {
8494                                 target.attr( "title", "" );
8495                         } else {
8496                                 target.removeAttr( "title" );
8497                         }
8498                 }
8500                 tooltipData = this._tooltip( target );
8501                 tooltip = tooltipData.tooltip;
8502                 this._addDescribedBy( target, tooltip.attr( "id" ) );
8503                 tooltip.find( ".ui-tooltip-content" ).html( content );
8505                 // Support: Voiceover on OS X, JAWS on IE <= 9
8506                 // JAWS announces deletions even when aria-relevant="additions"
8507                 // Voiceover will sometimes re-read the entire log region's contents from the beginning
8508                 this.liveRegion.children().hide();
8509                 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
8510                 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
8511                 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
8512                 a11yContent.appendTo( this.liveRegion );
8514                 function position( event ) {
8515                         positionOption.of = event;
8516                         if ( tooltip.is( ":hidden" ) ) {
8517                                 return;
8518                         }
8519                         tooltip.position( positionOption );
8520                 }
8521                 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
8522                         this._on( this.document, {
8523                                 mousemove: position
8524                         } );
8526                         // trigger once to override element-relative positioning
8527                         position( event );
8528                 } else {
8529                         tooltip.position( $.extend( {
8530                                 of: target
8531                         }, this.options.position ) );
8532                 }
8534                 tooltip.hide();
8536                 this._show( tooltip, this.options.show );
8538                 // Handle tracking tooltips that are shown with a delay (#8644). As soon
8539                 // as the tooltip is visible, position the tooltip using the most recent
8540                 // event.
8541                 // Adds the check to add the timers only when both delay and track options are set (#14682)
8542                 if ( this.options.track && this.options.show && this.options.show.delay ) {
8543                         delayedShow = this.delayedShow = setInterval( function() {
8544                                 if ( tooltip.is( ":visible" ) ) {
8545                                         position( positionOption.of );
8546                                         clearInterval( delayedShow );
8547                                 }
8548                         }, $.fx.interval );
8549                 }
8551                 this._trigger( "open", event, { tooltip: tooltip } );
8552         },
8554         _registerCloseHandlers: function( event, target ) {
8555                 var events = {
8556                         keyup: function( event ) {
8557                                 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
8558                                         var fakeEvent = $.Event( event );
8559                                         fakeEvent.currentTarget = target[ 0 ];
8560                                         this.close( fakeEvent, true );
8561                                 }
8562                         }
8563                 };
8565                 // Only bind remove handler for delegated targets. Non-delegated
8566                 // tooltips will handle this in destroy.
8567                 if ( target[ 0 ] !== this.element[ 0 ] ) {
8568                         events.remove = function() {
8569                                 this._removeTooltip( this._find( target ).tooltip );
8570                         };
8571                 }
8573                 if ( !event || event.type === "mouseover" ) {
8574                         events.mouseleave = "close";
8575                 }
8576                 if ( !event || event.type === "focusin" ) {
8577                         events.focusout = "close";
8578                 }
8579                 this._on( true, target, events );
8580         },
8582         close: function( event ) {
8583                 var tooltip,
8584                         that = this,
8585                         target = $( event ? event.currentTarget : this.element ),
8586                         tooltipData = this._find( target );
8588                 // The tooltip may already be closed
8589                 if ( !tooltipData ) {
8591                         // We set ui-tooltip-open immediately upon open (in open()), but only set the
8592                         // additional data once there's actually content to show (in _open()). So even if the
8593                         // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
8594                         // the period between open() and _open().
8595                         target.removeData( "ui-tooltip-open" );
8596                         return;
8597                 }
8599                 tooltip = tooltipData.tooltip;
8601                 // Disabling closes the tooltip, so we need to track when we're closing
8602                 // to avoid an infinite loop in case the tooltip becomes disabled on close
8603                 if ( tooltipData.closing ) {
8604                         return;
8605                 }
8607                 // Clear the interval for delayed tracking tooltips
8608                 clearInterval( this.delayedShow );
8610                 // Only set title if we had one before (see comment in _open())
8611                 // If the title attribute has changed since open(), don't restore
8612                 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
8613                         target.attr( "title", target.data( "ui-tooltip-title" ) );
8614                 }
8616                 this._removeDescribedBy( target );
8618                 tooltipData.hiding = true;
8619                 tooltip.stop( true );
8620                 this._hide( tooltip, this.options.hide, function() {
8621                         that._removeTooltip( $( this ) );
8622                 } );
8624                 target.removeData( "ui-tooltip-open" );
8625                 this._off( target, "mouseleave focusout keyup" );
8627                 // Remove 'remove' binding only on delegated targets
8628                 if ( target[ 0 ] !== this.element[ 0 ] ) {
8629                         this._off( target, "remove" );
8630                 }
8631                 this._off( this.document, "mousemove" );
8633                 if ( event && event.type === "mouseleave" ) {
8634                         $.each( this.parents, function( id, parent ) {
8635                                 $( parent.element ).attr( "title", parent.title );
8636                                 delete that.parents[ id ];
8637                         } );
8638                 }
8640                 tooltipData.closing = true;
8641                 this._trigger( "close", event, { tooltip: tooltip } );
8642                 if ( !tooltipData.hiding ) {
8643                         tooltipData.closing = false;
8644                 }
8645         },
8647         _tooltip: function( element ) {
8648                 var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
8649                         content = $( "<div>" ).appendTo( tooltip ),
8650                         id = tooltip.uniqueId().attr( "id" );
8652                 this._addClass( content, "ui-tooltip-content" );
8653                 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
8655                 tooltip.appendTo( this._appendTo( element ) );
8657                 return this.tooltips[ id ] = {
8658                         element: element,
8659                         tooltip: tooltip
8660                 };
8661         },
8663         _find: function( target ) {
8664                 var id = target.data( "ui-tooltip-id" );
8665                 return id ? this.tooltips[ id ] : null;
8666         },
8668         _removeTooltip: function( tooltip ) {
8669                 tooltip.remove();
8670                 delete this.tooltips[ tooltip.attr( "id" ) ];
8671         },
8673         _appendTo: function( target ) {
8674                 var element = target.closest( ".ui-front, dialog" );
8676                 if ( !element.length ) {
8677                         element = this.document[ 0 ].body;
8678                 }
8680                 return element;
8681         },
8683         _destroy: function() {
8684                 var that = this;
8686                 // Close open tooltips
8687                 $.each( this.tooltips, function( id, tooltipData ) {
8689                         // Delegate to close method to handle common cleanup
8690                         var event = $.Event( "blur" ),
8691                                 element = tooltipData.element;
8692                         event.target = event.currentTarget = element[ 0 ];
8693                         that.close( event, true );
8695                         // Remove immediately; destroying an open tooltip doesn't use the
8696                         // hide animation
8697                         $( "#" + id ).remove();
8699                         // Restore the title
8700                         if ( element.data( "ui-tooltip-title" ) ) {
8702                                 // If the title attribute has changed since open(), don't restore
8703                                 if ( !element.attr( "title" ) ) {
8704                                         element.attr( "title", element.data( "ui-tooltip-title" ) );
8705                                 }
8706                                 element.removeData( "ui-tooltip-title" );
8707                         }
8708                 } );
8709                 this.liveRegion.remove();
8710         }
8711 } );
8713 // DEPRECATED
8714 // TODO: Switch return back to widget declaration at top of file when this is removed
8715 if ( $.uiBackCompat !== false ) {
8717         // Backcompat for tooltipClass option
8718         $.widget( "ui.tooltip", $.ui.tooltip, {
8719                 options: {
8720                         tooltipClass: null
8721                 },
8722                 _tooltip: function() {
8723                         var tooltipData = this._superApply( arguments );
8724                         if ( this.options.tooltipClass ) {
8725                                 tooltipData.tooltip.addClass( this.options.tooltipClass );
8726                         }
8727                         return tooltipData;
8728                 }
8729         } );
8732 var widgetsTooltip = $.ui.tooltip;
8737 }));