1 /*! jQuery UI - v1.13.0 - 2021-10-07
3 * Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
4 * Copyright jQuery Foundation and other contributors; Licensed MIT */
6 ( function( factory ) {
9 if ( typeof define === "function" && define.amd ) {
11 // AMD. Register as an anonymous module.
12 define( [ "jquery" ], factory );
23 var version = $.ui.version = "1.13.0";
27 * jQuery UI Widget 1.13.0
30 * Copyright jQuery Foundation and other contributors
31 * Released under the MIT license.
32 * http://jquery.org/license
37 //>>description: Provides a factory for creating stateful widgets with a common API.
38 //>>docs: http://api.jqueryui.com/jQuery.widget/
39 //>>demos: http://jqueryui.com/widget/
43 var widgetHasOwnProperty = Array.prototype.hasOwnProperty;
44 var widgetSlice = Array.prototype.slice;
46 $.cleanData = ( function( orig ) {
47 return function( elems ) {
49 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
51 // Only trigger remove when necessary to save time
52 events = $._data( elem, "events" );
53 if ( events && events.remove ) {
54 $( elem ).triggerHandler( "remove" );
61 $.widget = function( name, base, prototype ) {
62 var existingConstructor, constructor, basePrototype;
64 // ProxiedPrototype allows the provided prototype to remain unmodified
65 // so that it can be used as a mixin for multiple widgets (#8876)
66 var proxiedPrototype = {};
68 var namespace = name.split( "." )[ 0 ];
69 name = name.split( "." )[ 1 ];
70 var fullName = namespace + "-" + name;
77 if ( Array.isArray( prototype ) ) {
78 prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
81 // Create selector for plugin
82 $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) {
83 return !!$.data( elem, fullName );
86 $[ namespace ] = $[ namespace ] || {};
87 existingConstructor = $[ namespace ][ name ];
88 constructor = $[ namespace ][ name ] = function( options, element ) {
90 // Allow instantiation without "new" keyword
91 if ( !this._createWidget ) {
92 return new constructor( options, element );
95 // Allow instantiation without initializing for simple inheritance
96 // must use "new" keyword (the code above always passes args)
97 if ( arguments.length ) {
98 this._createWidget( options, element );
102 // Extend with the existing constructor to carry over any static properties
103 $.extend( constructor, existingConstructor, {
104 version: prototype.version,
106 // Copy the object used to create the prototype in case we need to
107 // redefine the widget later
108 _proto: $.extend( {}, prototype ),
110 // Track widgets that inherit from this widget in case this widget is
111 // redefined after a widget inherits from it
112 _childConstructors: []
115 basePrototype = new base();
117 // We need to make the options hash a property directly on the new instance
118 // otherwise we'll modify the options hash on the prototype that we're
120 basePrototype.options = $.widget.extend( {}, basePrototype.options );
121 $.each( prototype, function( prop, value ) {
122 if ( typeof value !== "function" ) {
123 proxiedPrototype[ prop ] = value;
126 proxiedPrototype[ prop ] = ( function() {
128 return base.prototype[ prop ].apply( this, arguments );
131 function _superApply( args ) {
132 return base.prototype[ prop ].apply( this, args );
136 var __super = this._super;
137 var __superApply = this._superApply;
140 this._super = _super;
141 this._superApply = _superApply;
143 returnValue = value.apply( this, arguments );
145 this._super = __super;
146 this._superApply = __superApply;
152 constructor.prototype = $.widget.extend( basePrototype, {
154 // TODO: remove support for widgetEventPrefix
155 // always use the name + a colon as the prefix, e.g., draggable:start
156 // don't prefix for widgets that aren't DOM-based
157 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
158 }, proxiedPrototype, {
159 constructor: constructor,
160 namespace: namespace,
162 widgetFullName: fullName
165 // If this widget is being redefined then we need to find all widgets that
166 // are inheriting from it and redefine all of them so that they inherit from
167 // the new version of this widget. We're essentially trying to replace one
168 // level in the prototype chain.
169 if ( existingConstructor ) {
170 $.each( existingConstructor._childConstructors, function( i, child ) {
171 var childPrototype = child.prototype;
173 // Redefine the child widget using the same prototype that was
174 // originally used, but inherit from the new version of the base
175 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
179 // Remove the list of existing child constructors from the old constructor
180 // so the old child constructors can be garbage collected
181 delete existingConstructor._childConstructors;
183 base._childConstructors.push( constructor );
186 $.widget.bridge( name, constructor );
191 $.widget.extend = function( target ) {
192 var input = widgetSlice.call( arguments, 1 );
194 var inputLength = input.length;
198 for ( ; inputIndex < inputLength; inputIndex++ ) {
199 for ( key in input[ inputIndex ] ) {
200 value = input[ inputIndex ][ key ];
201 if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) {
204 if ( $.isPlainObject( value ) ) {
205 target[ key ] = $.isPlainObject( target[ key ] ) ?
206 $.widget.extend( {}, target[ key ], value ) :
208 // Don't extend strings, arrays, etc. with objects
209 $.widget.extend( {}, value );
211 // Copy everything else by reference
213 target[ key ] = value;
221 $.widget.bridge = function( name, object ) {
222 var fullName = object.prototype.widgetFullName || name;
223 $.fn[ name ] = function( options ) {
224 var isMethodCall = typeof options === "string";
225 var args = widgetSlice.call( arguments, 1 );
226 var returnValue = this;
228 if ( isMethodCall ) {
230 // If this is an empty collection, we need to have the instance method
231 // return undefined instead of the jQuery instance
232 if ( !this.length && options === "instance" ) {
233 returnValue = undefined;
235 this.each( function() {
237 var instance = $.data( this, fullName );
239 if ( options === "instance" ) {
240 returnValue = instance;
245 return $.error( "cannot call methods on " + name +
246 " prior to initialization; " +
247 "attempted to call method '" + options + "'" );
250 if ( typeof instance[ options ] !== "function" ||
251 options.charAt( 0 ) === "_" ) {
252 return $.error( "no such method '" + options + "' for " + name +
253 " widget instance" );
256 methodValue = instance[ options ].apply( instance, args );
258 if ( methodValue !== instance && methodValue !== undefined ) {
259 returnValue = methodValue && methodValue.jquery ?
260 returnValue.pushStack( methodValue.get() ) :
268 // Allow multiple hashes to be passed on init
270 options = $.widget.extend.apply( null, [ options ].concat( args ) );
273 this.each( function() {
274 var instance = $.data( this, fullName );
276 instance.option( options || {} );
277 if ( instance._init ) {
281 $.data( this, fullName, new object( options, this ) );
290 $.Widget = function( /* options, element */ ) {};
291 $.Widget._childConstructors = [];
293 $.Widget.prototype = {
294 widgetName: "widget",
295 widgetEventPrefix: "",
296 defaultElement: "<div>",
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;
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 ) {
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 );
336 this.options = $.widget.extend( {},
338 this._getCreateOptions(),
343 if ( this.options.disabled ) {
344 this._setOptionDisabled( this.options.disabled );
347 this._trigger( "create", null, this._getCreateEventData() );
351 _getCreateOptions: function() {
355 _getCreateEventData: $.noop,
361 destroy: function() {
365 $.each( this.classesElementLookup, function( key, value ) {
366 that._removeClass( value, key );
369 // We can probably remove the unbind calls in 2.0
370 // all event bindings should go through this._on()
372 .off( this.eventNamespace )
373 .removeData( this.widgetFullName );
375 .off( this.eventNamespace )
376 .removeAttr( "aria-disabled" );
378 // Clean up events and states
379 this.bindings.off( this.eventNamespace );
388 option: function( key, value ) {
394 if ( arguments.length === 0 ) {
396 // Don't return a reference to the internal hash
397 return $.widget.extend( {}, this.options );
400 if ( typeof key === "string" ) {
402 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
404 parts = key.split( "." );
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 ] ];
413 if ( arguments.length === 1 ) {
414 return curOption[ key ] === undefined ? null : curOption[ key ];
416 curOption[ key ] = value;
418 if ( arguments.length === 1 ) {
419 return this.options[ key ] === undefined ? null : this.options[ key ];
421 options[ key ] = value;
425 this._setOptions( options );
430 _setOptions: function( options ) {
433 for ( key in options ) {
434 this._setOption( key, options[ key ] );
440 _setOption: function( key, value ) {
441 if ( key === "classes" ) {
442 this._setOptionClasses( value );
445 this.options[ key ] = value;
447 if ( key === "disabled" ) {
448 this._setOptionDisabled( value );
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 ] ||
461 !currentElements.length ) {
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
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( {
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
490 this._removeClass( this.hoverable, null, "ui-state-hover" );
491 this._removeClass( this.focusable, null, "ui-state-focus" );
496 return this._setOptions( { disabled: false } );
499 disable: function() {
500 return this._setOptions( { disabled: true } );
503 _classes: function( options ) {
507 options = $.extend( {
508 element: this.element,
509 classes: this.options.classes || {}
512 function bindRemoveEvent() {
513 options.element.each( function( _, element ) {
514 var isTracked = $.map( that.classesElementLookup, function( elements ) {
517 .some( function( elements ) {
518 return elements.is( element );
522 that._on( $( element ), {
523 remove: "_untrackClassesElement"
529 function processClassString( classes, checkOption ) {
531 for ( i = 0; i < classes.length; i++ ) {
532 current = that.classesElementLookup[ classes[ i ] ] || $();
535 current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) );
537 current = $( current.not( options.element ).get() );
539 that.classesElementLookup[ classes[ i ] ] = current;
540 full.push( classes[ i ] );
541 if ( checkOption && options.classes[ classes[ i ] ] ) {
542 full.push( options.classes[ classes[ i ] ] );
547 if ( options.keys ) {
548 processClassString( options.keys.match( /\S+/g ) || [], true );
550 if ( options.extra ) {
551 processClassString( options.extra.match( /\S+/g ) || [] );
554 return full.join( " " );
557 _untrackClassesElement: function( event ) {
559 $.each( that.classesElementLookup, function( key, value ) {
560 if ( $.inArray( event.target, value ) !== -1 ) {
561 that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
565 this._off( $( event.target ) );
568 _removeClass: function( element, keys, extra ) {
569 return this._toggleClass( element, keys, extra, false );
572 _addClass: function( element, keys, extra ) {
573 return this._toggleClass( element, keys, extra, true );
576 _toggleClass: function( element, keys, extra, add ) {
577 add = ( typeof add === "boolean" ) ? add : extra;
578 var shift = ( typeof element === "string" || element === null ),
580 extra: shift ? keys : extra,
581 keys: shift ? element : keys,
582 element: shift ? this.element : element,
585 options.element.toggleClass( this._classes( options ), add );
589 _on: function( suppressDisabledCheck, element, handlers ) {
593 // No suppressDisabledCheck flag, shuffle arguments
594 if ( typeof suppressDisabledCheck !== "boolean" ) {
596 element = suppressDisabledCheck;
597 suppressDisabledCheck = false;
600 // No element argument, shuffle and use this.element
603 element = this.element;
604 delegateElement = this.widget();
606 element = delegateElement = $( element );
607 this.bindings = this.bindings.add( element );
610 $.each( handlers, function( event, handler ) {
611 function handlerProxy() {
613 // Allow widgets to customize the disabled handling
614 // - disabled as an array instead of boolean
615 // - disabled class as method for disabling individual parts
616 if ( !suppressDisabledCheck &&
617 ( instance.options.disabled === true ||
618 $( this ).hasClass( "ui-state-disabled" ) ) ) {
621 return ( typeof handler === "string" ? instance[ handler ] : handler )
622 .apply( instance, arguments );
625 // Copy the guid so direct unbinding works
626 if ( typeof handler !== "string" ) {
627 handlerProxy.guid = handler.guid =
628 handler.guid || handlerProxy.guid || $.guid++;
631 var match = event.match( /^([\w:-]*)\s*(.*)$/ );
632 var eventName = match[ 1 ] + instance.eventNamespace;
633 var selector = match[ 2 ];
636 delegateElement.on( eventName, selector, handlerProxy );
638 element.on( eventName, handlerProxy );
643 _off: function( element, eventName ) {
644 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
646 element.off( eventName );
648 // Clear the stack to avoid memory leaks (#10056)
649 this.bindings = $( this.bindings.not( element ).get() );
650 this.focusable = $( this.focusable.not( element ).get() );
651 this.hoverable = $( this.hoverable.not( element ).get() );
654 _delay: function( handler, delay ) {
655 function handlerProxy() {
656 return ( typeof handler === "string" ? instance[ handler ] : handler )
657 .apply( instance, arguments );
660 return setTimeout( handlerProxy, delay || 0 );
663 _hoverable: function( element ) {
664 this.hoverable = this.hoverable.add( element );
666 mouseenter: function( event ) {
667 this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
669 mouseleave: function( event ) {
670 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
675 _focusable: function( element ) {
676 this.focusable = this.focusable.add( element );
678 focusin: function( event ) {
679 this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
681 focusout: function( event ) {
682 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
687 _trigger: function( type, event, data ) {
689 var callback = this.options[ type ];
692 event = $.Event( event );
693 event.type = ( type === this.widgetEventPrefix ?
695 this.widgetEventPrefix + type ).toLowerCase();
697 // The original event may come from any element
698 // so we need to reset the target on the new event
699 event.target = this.element[ 0 ];
701 // Copy original event properties over to the new event
702 orig = event.originalEvent;
704 for ( prop in orig ) {
705 if ( !( prop in event ) ) {
706 event[ prop ] = orig[ prop ];
711 this.element.trigger( event, data );
712 return !( typeof callback === "function" &&
713 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
714 event.isDefaultPrevented() );
718 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
719 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
720 if ( typeof options === "string" ) {
721 options = { effect: options };
725 var effectName = !options ?
727 options === true || typeof options === "number" ?
729 options.effect || defaultEffect;
731 options = options || {};
732 if ( typeof options === "number" ) {
733 options = { duration: options };
734 } else if ( options === true ) {
738 hasOptions = !$.isEmptyObject( options );
739 options.complete = callback;
741 if ( options.delay ) {
742 element.delay( options.delay );
745 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
746 element[ method ]( options );
747 } else if ( effectName !== method && element[ effectName ] ) {
748 element[ effectName ]( options.duration, options.easing, callback );
750 element.queue( function( next ) {
751 $( this )[ method ]();
753 callback.call( element[ 0 ] );
761 var widget = $.widget;
765 * jQuery UI Position 1.13.0
766 * http://jqueryui.com
768 * Copyright jQuery Foundation and other contributors
769 * Released under the MIT license.
770 * http://jquery.org/license
772 * http://api.jqueryui.com/position/
777 //>>description: Positions elements relative to other elements.
778 //>>docs: http://api.jqueryui.com/position/
779 //>>demos: http://jqueryui.com/position/
783 var cachedScrollbarWidth,
786 rhorizontal = /left|center|right/,
787 rvertical = /top|center|bottom/,
788 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
791 _position = $.fn.position;
793 function getOffsets( offsets, width, height ) {
795 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
796 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
800 function parseCss( element, property ) {
801 return parseInt( $.css( element, property ), 10 ) || 0;
804 function isWindow( obj ) {
805 return obj != null && obj === obj.window;
808 function getDimensions( elem ) {
810 if ( raw.nodeType === 9 ) {
813 height: elem.height(),
814 offset: { top: 0, left: 0 }
817 if ( isWindow( raw ) ) {
820 height: elem.height(),
821 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
824 if ( raw.preventDefault ) {
828 offset: { top: raw.pageY, left: raw.pageX }
832 width: elem.outerWidth(),
833 height: elem.outerHeight(),
834 offset: elem.offset()
839 scrollbarWidth: function() {
840 if ( cachedScrollbarWidth !== undefined ) {
841 return cachedScrollbarWidth;
844 div = $( "<div style=" +
845 "'display:block;position:absolute;width:200px;height:200px;overflow:hidden;'>" +
846 "<div style='height:300px;width:auto;'></div></div>" ),
847 innerDiv = div.children()[ 0 ];
849 $( "body" ).append( div );
850 w1 = innerDiv.offsetWidth;
851 div.css( "overflow", "scroll" );
853 w2 = innerDiv.offsetWidth;
856 w2 = div[ 0 ].clientWidth;
861 return ( cachedScrollbarWidth = w1 - w2 );
863 getScrollInfo: function( within ) {
864 var overflowX = within.isWindow || within.isDocument ? "" :
865 within.element.css( "overflow-x" ),
866 overflowY = within.isWindow || within.isDocument ? "" :
867 within.element.css( "overflow-y" ),
868 hasOverflowX = overflowX === "scroll" ||
869 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
870 hasOverflowY = overflowY === "scroll" ||
871 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
873 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
874 height: hasOverflowX ? $.position.scrollbarWidth() : 0
877 getWithinInfo: function( element ) {
878 var withinElement = $( element || window ),
879 isElemWindow = isWindow( withinElement[ 0 ] ),
880 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
881 hasOffset = !isElemWindow && !isDocument;
883 element: withinElement,
884 isWindow: isElemWindow,
885 isDocument: isDocument,
886 offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
887 scrollLeft: withinElement.scrollLeft(),
888 scrollTop: withinElement.scrollTop(),
889 width: withinElement.outerWidth(),
890 height: withinElement.outerHeight()
895 $.fn.position = function( options ) {
896 if ( !options || !options.of ) {
897 return _position.apply( this, arguments );
900 // Make a copy, we don't want to modify arguments
901 options = $.extend( {}, options );
903 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
905 // Make sure string options are treated as CSS selectors
906 target = typeof options.of === "string" ?
907 $( document ).find( options.of ) :
910 within = $.position.getWithinInfo( options.within ),
911 scrollInfo = $.position.getScrollInfo( within ),
912 collision = ( options.collision || "flip" ).split( " " ),
915 dimensions = getDimensions( target );
916 if ( target[ 0 ].preventDefault ) {
918 // Force left top to allow flipping
919 options.at = "left top";
921 targetWidth = dimensions.width;
922 targetHeight = dimensions.height;
923 targetOffset = dimensions.offset;
925 // Clone to reuse original targetOffset later
926 basePosition = $.extend( {}, targetOffset );
928 // Force my and at to have valid horizontal and vertical positions
929 // if a value is missing or invalid, it will be converted to center
930 $.each( [ "my", "at" ], function() {
931 var pos = ( options[ this ] || "" ).split( " " ),
935 if ( pos.length === 1 ) {
936 pos = rhorizontal.test( pos[ 0 ] ) ?
937 pos.concat( [ "center" ] ) :
938 rvertical.test( pos[ 0 ] ) ?
939 [ "center" ].concat( pos ) :
940 [ "center", "center" ];
942 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
943 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
946 horizontalOffset = roffset.exec( pos[ 0 ] );
947 verticalOffset = roffset.exec( pos[ 1 ] );
949 horizontalOffset ? horizontalOffset[ 0 ] : 0,
950 verticalOffset ? verticalOffset[ 0 ] : 0
953 // Reduce to just the positions without the offsets
955 rposition.exec( pos[ 0 ] )[ 0 ],
956 rposition.exec( pos[ 1 ] )[ 0 ]
960 // Normalize collision option
961 if ( collision.length === 1 ) {
962 collision[ 1 ] = collision[ 0 ];
965 if ( options.at[ 0 ] === "right" ) {
966 basePosition.left += targetWidth;
967 } else if ( options.at[ 0 ] === "center" ) {
968 basePosition.left += targetWidth / 2;
971 if ( options.at[ 1 ] === "bottom" ) {
972 basePosition.top += targetHeight;
973 } else if ( options.at[ 1 ] === "center" ) {
974 basePosition.top += targetHeight / 2;
977 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
978 basePosition.left += atOffset[ 0 ];
979 basePosition.top += atOffset[ 1 ];
981 return this.each( function() {
982 var collisionPosition, using,
984 elemWidth = elem.outerWidth(),
985 elemHeight = elem.outerHeight(),
986 marginLeft = parseCss( this, "marginLeft" ),
987 marginTop = parseCss( this, "marginTop" ),
988 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
990 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
992 position = $.extend( {}, basePosition ),
993 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
995 if ( options.my[ 0 ] === "right" ) {
996 position.left -= elemWidth;
997 } else if ( options.my[ 0 ] === "center" ) {
998 position.left -= elemWidth / 2;
1001 if ( options.my[ 1 ] === "bottom" ) {
1002 position.top -= elemHeight;
1003 } else if ( options.my[ 1 ] === "center" ) {
1004 position.top -= elemHeight / 2;
1007 position.left += myOffset[ 0 ];
1008 position.top += myOffset[ 1 ];
1010 collisionPosition = {
1011 marginLeft: marginLeft,
1012 marginTop: marginTop
1015 $.each( [ "left", "top" ], function( i, dir ) {
1016 if ( $.ui.position[ collision[ i ] ] ) {
1017 $.ui.position[ collision[ i ] ][ dir ]( position, {
1018 targetWidth: targetWidth,
1019 targetHeight: targetHeight,
1020 elemWidth: elemWidth,
1021 elemHeight: elemHeight,
1022 collisionPosition: collisionPosition,
1023 collisionWidth: collisionWidth,
1024 collisionHeight: collisionHeight,
1025 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1034 if ( options.using ) {
1036 // Adds feedback as second argument to using callback, if present
1037 using = function( props ) {
1038 var left = targetOffset.left - position.left,
1039 right = left + targetWidth - elemWidth,
1040 top = targetOffset.top - position.top,
1041 bottom = top + targetHeight - elemHeight,
1045 left: targetOffset.left,
1046 top: targetOffset.top,
1048 height: targetHeight
1052 left: position.left,
1057 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1058 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1060 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1061 feedback.horizontal = "center";
1063 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1064 feedback.vertical = "middle";
1066 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1067 feedback.important = "horizontal";
1069 feedback.important = "vertical";
1071 options.using.call( this, props, feedback );
1075 elem.offset( $.extend( position, { using: using } ) );
1081 left: function( position, data ) {
1082 var within = data.within,
1083 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1084 outerWidth = within.width,
1085 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1086 overLeft = withinOffset - collisionPosLeft,
1087 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1090 // Element is wider than within
1091 if ( data.collisionWidth > outerWidth ) {
1093 // Element is initially over the left side of within
1094 if ( overLeft > 0 && overRight <= 0 ) {
1095 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
1097 position.left += overLeft - newOverRight;
1099 // Element is initially over right side of within
1100 } else if ( overRight > 0 && overLeft <= 0 ) {
1101 position.left = withinOffset;
1103 // Element is initially over both left and right sides of within
1105 if ( overLeft > overRight ) {
1106 position.left = withinOffset + outerWidth - data.collisionWidth;
1108 position.left = withinOffset;
1112 // Too far left -> align with left edge
1113 } else if ( overLeft > 0 ) {
1114 position.left += overLeft;
1116 // Too far right -> align with right edge
1117 } else if ( overRight > 0 ) {
1118 position.left -= overRight;
1120 // Adjust based on position and margin
1122 position.left = max( position.left - collisionPosLeft, position.left );
1125 top: function( position, data ) {
1126 var within = data.within,
1127 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1128 outerHeight = data.within.height,
1129 collisionPosTop = position.top - data.collisionPosition.marginTop,
1130 overTop = withinOffset - collisionPosTop,
1131 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1134 // Element is taller than within
1135 if ( data.collisionHeight > outerHeight ) {
1137 // Element is initially over the top of within
1138 if ( overTop > 0 && overBottom <= 0 ) {
1139 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
1141 position.top += overTop - newOverBottom;
1143 // Element is initially over bottom of within
1144 } else if ( overBottom > 0 && overTop <= 0 ) {
1145 position.top = withinOffset;
1147 // Element is initially over both top and bottom of within
1149 if ( overTop > overBottom ) {
1150 position.top = withinOffset + outerHeight - data.collisionHeight;
1152 position.top = withinOffset;
1156 // Too far up -> align with top
1157 } else if ( overTop > 0 ) {
1158 position.top += overTop;
1160 // Too far down -> align with bottom edge
1161 } else if ( overBottom > 0 ) {
1162 position.top -= overBottom;
1164 // Adjust based on position and margin
1166 position.top = max( position.top - collisionPosTop, position.top );
1171 left: function( position, data ) {
1172 var within = data.within,
1173 withinOffset = within.offset.left + within.scrollLeft,
1174 outerWidth = within.width,
1175 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1176 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1177 overLeft = collisionPosLeft - offsetLeft,
1178 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1179 myOffset = data.my[ 0 ] === "left" ?
1181 data.my[ 0 ] === "right" ?
1184 atOffset = data.at[ 0 ] === "left" ?
1186 data.at[ 0 ] === "right" ?
1189 offset = -2 * data.offset[ 0 ],
1193 if ( overLeft < 0 ) {
1194 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
1195 outerWidth - withinOffset;
1196 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1197 position.left += myOffset + atOffset + offset;
1199 } else if ( overRight > 0 ) {
1200 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
1201 atOffset + offset - offsetLeft;
1202 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1203 position.left += myOffset + atOffset + offset;
1207 top: function( position, data ) {
1208 var within = data.within,
1209 withinOffset = within.offset.top + within.scrollTop,
1210 outerHeight = within.height,
1211 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1212 collisionPosTop = position.top - data.collisionPosition.marginTop,
1213 overTop = collisionPosTop - offsetTop,
1214 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1215 top = data.my[ 1 ] === "top",
1218 data.my[ 1 ] === "bottom" ?
1221 atOffset = data.at[ 1 ] === "top" ?
1223 data.at[ 1 ] === "bottom" ?
1224 -data.targetHeight :
1226 offset = -2 * data.offset[ 1 ],
1229 if ( overTop < 0 ) {
1230 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
1231 outerHeight - withinOffset;
1232 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1233 position.top += myOffset + atOffset + offset;
1235 } else if ( overBottom > 0 ) {
1236 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
1238 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1239 position.top += myOffset + atOffset + offset;
1246 $.ui.position.flip.left.apply( this, arguments );
1247 $.ui.position.fit.left.apply( this, arguments );
1250 $.ui.position.flip.top.apply( this, arguments );
1251 $.ui.position.fit.top.apply( this, arguments );
1258 var position = $.ui.position;
1262 * jQuery UI :data 1.13.0
1263 * http://jqueryui.com
1265 * Copyright jQuery Foundation and other contributors
1266 * Released under the MIT license.
1267 * http://jquery.org/license
1270 //>>label: :data Selector
1272 //>>description: Selects elements which have data stored under the specified key.
1273 //>>docs: http://api.jqueryui.com/data-selector/
1276 var data = $.extend( $.expr.pseudos, {
1277 data: $.expr.createPseudo ?
1278 $.expr.createPseudo( function( dataName ) {
1279 return function( elem ) {
1280 return !!$.data( elem, dataName );
1284 // Support: jQuery <1.8
1285 function( elem, i, match ) {
1286 return !!$.data( elem, match[ 3 ] );
1291 * jQuery UI Disable Selection 1.13.0
1292 * http://jqueryui.com
1294 * Copyright jQuery Foundation and other contributors
1295 * Released under the MIT license.
1296 * http://jquery.org/license
1299 //>>label: disableSelection
1301 //>>description: Disable selection of text content within the set of matched elements.
1302 //>>docs: http://api.jqueryui.com/disableSelection/
1304 // This file is deprecated
1306 var disableSelection = $.fn.extend( {
1307 disableSelection: ( function() {
1308 var eventType = "onselectstart" in document.createElement( "div" ) ?
1313 return this.on( eventType + ".ui-disableSelection", function( event ) {
1314 event.preventDefault();
1319 enableSelection: function() {
1320 return this.off( ".ui-disableSelection" );
1326 // Create a local jQuery because jQuery Color relies on it and the
1327 // global may not exist with AMD and a custom build (#10199).
1328 // This module is a noop if used as a regular AMD module.
1329 // eslint-disable-next-line no-unused-vars
1334 * jQuery Color Animations v2.2.0
1335 * https://github.com/jquery/jquery-color
1337 * Copyright OpenJS Foundation and other contributors
1338 * Released under the MIT license.
1339 * http://jquery.org/license
1341 * Date: Sun May 10 09:02:36 2020 +0200
1346 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
1347 "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
1350 toString = class2type.toString,
1352 // plusequals test for += 100 -= 100
1353 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
1355 // a set of RE's that can match strings and generate color tuples.
1357 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1358 parse: function( execResult ) {
1367 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1368 parse: function( execResult ) {
1370 execResult[ 1 ] * 2.55,
1371 execResult[ 2 ] * 2.55,
1372 execResult[ 3 ] * 2.55,
1378 // this regex ignores A-F because it's compared against an already lowercased string
1379 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/,
1380 parse: function( execResult ) {
1382 parseInt( execResult[ 1 ], 16 ),
1383 parseInt( execResult[ 2 ], 16 ),
1384 parseInt( execResult[ 3 ], 16 ),
1386 ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) :
1392 // this regex ignores A-F because it's compared against an already lowercased string
1393 re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/,
1394 parse: function( execResult ) {
1396 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
1397 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
1398 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ),
1400 ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 )
1406 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1408 parse: function( execResult ) {
1411 execResult[ 2 ] / 100,
1412 execResult[ 3 ] / 100,
1419 color = jQuery.Color = function( color, green, blue, alpha ) {
1420 return new jQuery.Color.fn.parse( color, green, blue, alpha );
1470 support = color.support = {},
1472 // element for support tests
1473 supportElem = jQuery( "<p>" )[ 0 ],
1475 // colors = jQuery.Color.names
1478 // local aliases of functions called often
1481 // determine rgba support immediately
1482 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
1483 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
1485 // define cache name and alpha properties
1486 // for rgba and hsla spaces
1487 each( spaces, function( spaceName, space ) {
1488 space.cache = "_" + spaceName;
1489 space.props.alpha = {
1496 // Populate the class2type map
1497 jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
1498 function( _i, name ) {
1499 class2type[ "[object " + name + "]" ] = name.toLowerCase();
1502 function getType( obj ) {
1503 if ( obj == null ) {
1507 return typeof obj === "object" ?
1508 class2type[ toString.call( obj ) ] || "object" :
1512 function clamp( value, prop, allowEmpty ) {
1513 var type = propTypes[ prop.type ] || {};
1515 if ( value == null ) {
1516 return ( allowEmpty || !prop.def ) ? null : prop.def;
1519 // ~~ is an short way of doing floor for positive numbers
1520 value = type.floor ? ~~value : parseFloat( value );
1522 // IE will pass in empty strings as value for alpha,
1523 // which will hit this case
1524 if ( isNaN( value ) ) {
1530 // we add mod before modding to make sure that negatives values
1531 // get converted properly: -10 -> 350
1532 return ( value + type.mod ) % type.mod;
1535 // for now all property types without mod have min and max
1536 return Math.min( type.max, Math.max( 0, value ) );
1539 function stringParse( string ) {
1541 rgba = inst._rgba = [];
1543 string = string.toLowerCase();
1545 each( stringParsers, function( _i, parser ) {
1547 match = parser.re.exec( string ),
1548 values = match && parser.parse( match ),
1549 spaceName = parser.space || "rgba";
1552 parsed = inst[ spaceName ]( values );
1554 // if this was an rgba parse the assignment might happen twice
1556 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
1557 rgba = inst._rgba = parsed._rgba;
1559 // exit each( stringParsers ) here because we matched
1564 // Found a stringParser that handled it
1565 if ( rgba.length ) {
1567 // if this came from a parsed string, force "transparent" when alpha is 0
1568 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
1569 if ( rgba.join() === "0,0,0,0" ) {
1570 jQuery.extend( rgba, colors.transparent );
1576 return colors[ string ];
1579 color.fn = jQuery.extend( color.prototype, {
1580 parse: function( red, green, blue, alpha ) {
1581 if ( red === undefined ) {
1582 this._rgba = [ null, null, null, null ];
1585 if ( red.jquery || red.nodeType ) {
1586 red = jQuery( red ).css( green );
1591 type = getType( red ),
1592 rgba = this._rgba = [];
1594 // more than 1 argument specified - assume ( red, green, blue, alpha )
1595 if ( green !== undefined ) {
1596 red = [ red, green, blue, alpha ];
1600 if ( type === "string" ) {
1601 return this.parse( stringParse( red ) || colors._default );
1604 if ( type === "array" ) {
1605 each( spaces.rgba.props, function( _key, prop ) {
1606 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
1611 if ( type === "object" ) {
1612 if ( red instanceof color ) {
1613 each( spaces, function( _spaceName, space ) {
1614 if ( red[ space.cache ] ) {
1615 inst[ space.cache ] = red[ space.cache ].slice();
1619 each( spaces, function( _spaceName, space ) {
1620 var cache = space.cache;
1621 each( space.props, function( key, prop ) {
1623 // if the cache doesn't exist, and we know how to convert
1624 if ( !inst[ cache ] && space.to ) {
1626 // if the value was null, we don't need to copy it
1627 // if the key was alpha, we don't need to copy it either
1628 if ( key === "alpha" || red[ key ] == null ) {
1631 inst[ cache ] = space.to( inst._rgba );
1634 // this is the only case where we allow nulls for ALL properties.
1635 // call clamp with alwaysAllowEmpty
1636 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
1639 // everything defined but alpha?
1640 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
1642 // use the default of 1
1643 if ( inst[ cache ][ 3 ] == null ) {
1644 inst[ cache ][ 3 ] = 1;
1648 inst._rgba = space.from( inst[ cache ] );
1656 is: function( compare ) {
1657 var is = color( compare ),
1661 each( spaces, function( _, space ) {
1663 isCache = is[ space.cache ];
1665 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
1666 each( space.props, function( _, prop ) {
1667 if ( isCache[ prop.idx ] != null ) {
1668 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
1677 _space: function() {
1680 each( spaces, function( spaceName, space ) {
1681 if ( inst[ space.cache ] ) {
1682 used.push( spaceName );
1687 transition: function( other, distance ) {
1688 var end = color( other ),
1689 spaceName = end._space(),
1690 space = spaces[ spaceName ],
1691 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
1692 start = startColor[ space.cache ] || space.to( startColor._rgba ),
1693 result = start.slice();
1695 end = end[ space.cache ];
1696 each( space.props, function( _key, prop ) {
1697 var index = prop.idx,
1698 startValue = start[ index ],
1699 endValue = end[ index ],
1700 type = propTypes[ prop.type ] || {};
1702 // if null, don't override start value
1703 if ( endValue === null ) {
1707 // if null - use end
1708 if ( startValue === null ) {
1709 result[ index ] = endValue;
1712 if ( endValue - startValue > type.mod / 2 ) {
1713 startValue += type.mod;
1714 } else if ( startValue - endValue > type.mod / 2 ) {
1715 startValue -= type.mod;
1718 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
1721 return this[ spaceName ]( result );
1723 blend: function( opaque ) {
1725 // if we are already opaque - return ourself
1726 if ( this._rgba[ 3 ] === 1 ) {
1730 var rgb = this._rgba.slice(),
1732 blend = color( opaque )._rgba;
1734 return color( jQuery.map( rgb, function( v, i ) {
1735 return ( 1 - a ) * blend[ i ] + a * v;
1738 toRgbaString: function() {
1739 var prefix = "rgba(",
1740 rgba = jQuery.map( this._rgba, function( v, i ) {
1744 return i > 2 ? 1 : 0;
1747 if ( rgba[ 3 ] === 1 ) {
1752 return prefix + rgba.join() + ")";
1754 toHslaString: function() {
1755 var prefix = "hsla(",
1756 hsla = jQuery.map( this.hsla(), function( v, i ) {
1763 v = Math.round( v * 100 ) + "%";
1768 if ( hsla[ 3 ] === 1 ) {
1772 return prefix + hsla.join() + ")";
1774 toHexString: function( includeAlpha ) {
1775 var rgba = this._rgba.slice(),
1778 if ( includeAlpha ) {
1779 rgba.push( ~~( alpha * 255 ) );
1782 return "#" + jQuery.map( rgba, function( v ) {
1784 // default to 0 when nulls exist
1785 v = ( v || 0 ).toString( 16 );
1786 return v.length === 1 ? "0" + v : v;
1789 toString: function() {
1790 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
1793 color.fn.parse.prototype = color.fn;
1795 // hsla conversions adapted from:
1796 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
1798 function hue2rgb( p, q, h ) {
1801 return p + ( q - p ) * h * 6;
1807 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
1812 spaces.hsla.to = function( rgba ) {
1813 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
1814 return [ null, null, null, rgba[ 3 ] ];
1816 var r = rgba[ 0 ] / 255,
1817 g = rgba[ 1 ] / 255,
1818 b = rgba[ 2 ] / 255,
1820 max = Math.max( r, g, b ),
1821 min = Math.min( r, g, b ),
1827 if ( min === max ) {
1829 } else if ( r === max ) {
1830 h = ( 60 * ( g - b ) / diff ) + 360;
1831 } else if ( g === max ) {
1832 h = ( 60 * ( b - r ) / diff ) + 120;
1834 h = ( 60 * ( r - g ) / diff ) + 240;
1837 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
1838 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
1841 } else if ( l <= 0.5 ) {
1844 s = diff / ( 2 - add );
1846 return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
1849 spaces.hsla.from = function( hsla ) {
1850 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
1851 return [ null, null, null, hsla[ 3 ] ];
1853 var h = hsla[ 0 ] / 360,
1857 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
1861 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
1862 Math.round( hue2rgb( p, q, h ) * 255 ),
1863 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
1869 each( spaces, function( spaceName, space ) {
1870 var props = space.props,
1871 cache = space.cache,
1875 // makes rgba() and hsla()
1876 color.fn[ spaceName ] = function( value ) {
1878 // generate a cache for this space if it doesn't exist
1879 if ( to && !this[ cache ] ) {
1880 this[ cache ] = to( this._rgba );
1882 if ( value === undefined ) {
1883 return this[ cache ].slice();
1887 type = getType( value ),
1888 arr = ( type === "array" || type === "object" ) ? value : arguments,
1889 local = this[ cache ].slice();
1891 each( props, function( key, prop ) {
1892 var val = arr[ type === "object" ? key : prop.idx ];
1893 if ( val == null ) {
1894 val = local[ prop.idx ];
1896 local[ prop.idx ] = clamp( val, prop );
1900 ret = color( from( local ) );
1901 ret[ cache ] = local;
1904 return color( local );
1908 // makes red() green() blue() alpha() hue() saturation() lightness()
1909 each( props, function( key, prop ) {
1911 // alpha is included in more than one space
1912 if ( color.fn[ key ] ) {
1915 color.fn[ key ] = function( value ) {
1916 var local, cur, match, fn,
1917 vtype = getType( value );
1919 if ( key === "alpha" ) {
1920 fn = this._hsla ? "hsla" : "rgba";
1924 local = this[ fn ]();
1925 cur = local[ prop.idx ];
1927 if ( vtype === "undefined" ) {
1931 if ( vtype === "function" ) {
1932 value = value.call( this, cur );
1933 vtype = getType( value );
1935 if ( value == null && prop.empty ) {
1938 if ( vtype === "string" ) {
1939 match = rplusequals.exec( value );
1941 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
1944 local[ prop.idx ] = value;
1945 return this[ fn ]( local );
1950 // add cssHook and .fx.step function for each named hook.
1951 // accept a space separated string of properties
1952 color.hook = function( hook ) {
1953 var hooks = hook.split( " " );
1954 each( hooks, function( _i, hook ) {
1955 jQuery.cssHooks[ hook ] = {
1956 set: function( elem, value ) {
1957 var parsed, curElem,
1958 backgroundColor = "";
1960 if ( value !== "transparent" && ( getType( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
1961 value = color( parsed || value );
1962 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
1963 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
1965 ( backgroundColor === "" || backgroundColor === "transparent" ) &&
1966 curElem && curElem.style
1969 backgroundColor = jQuery.css( curElem, "backgroundColor" );
1970 curElem = curElem.parentNode;
1975 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
1980 value = value.toRgbaString();
1983 elem.style[ hook ] = value;
1986 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
1990 jQuery.fx.step[ hook ] = function( fx ) {
1991 if ( !fx.colorInit ) {
1992 fx.start = color( fx.elem, hook );
1993 fx.end = color( fx.end );
1994 fx.colorInit = true;
1996 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
2002 color.hook( stepHooks );
2004 jQuery.cssHooks.borderColor = {
2005 expand: function( value ) {
2008 each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) {
2009 expanded[ "border" + part + "Color" ] = value;
2015 // Basic color names only.
2016 // Usage of any of the other color names requires adding yourself or including
2017 // jquery.color.svg-names.js.
2018 colors = jQuery.Color.names = {
2020 // 4.1. Basic color keywords
2038 // 4.2.3. "transparent" color keyword
2039 transparent: [ null, null, null, 0 ],
2046 * jQuery UI Effects 1.13.0
2047 * http://jqueryui.com
2049 * Copyright jQuery Foundation and other contributors
2050 * Released under the MIT license.
2051 * http://jquery.org/license
2054 //>>label: Effects Core
2056 /* eslint-disable max-len */
2057 //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
2058 /* eslint-enable max-len */
2059 //>>docs: http://api.jqueryui.com/category/effects-core/
2060 //>>demos: http://jqueryui.com/effect/
2063 var dataSpace = "ui-effects-",
2064 dataSpaceStyle = "ui-effects-style",
2065 dataSpaceAnimated = "ui-effects-animated";
2071 /******************************************************************************/
2072 /****************************** CLASS ANIMATIONS ******************************/
2073 /******************************************************************************/
2076 var classAnimationActions = [ "add", "remove", "toggle" ],
2090 [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
2091 function( _, prop ) {
2092 $.fx.step[ prop ] = function( fx ) {
2093 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
2094 jQuery.style( fx.elem, prop, fx.end );
2101 function camelCase( string ) {
2102 return string.replace( /-([\da-z])/gi, function( all, letter ) {
2103 return letter.toUpperCase();
2107 function getElementStyles( elem ) {
2109 style = elem.ownerDocument.defaultView ?
2110 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
2114 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
2118 if ( typeof style[ key ] === "string" ) {
2119 styles[ camelCase( key ) ] = style[ key ];
2123 // Support: Opera, IE <9
2125 for ( key in style ) {
2126 if ( typeof style[ key ] === "string" ) {
2127 styles[ key ] = style[ key ];
2135 function styleDifference( oldStyle, newStyle ) {
2139 for ( name in newStyle ) {
2140 value = newStyle[ name ];
2141 if ( oldStyle[ name ] !== value ) {
2142 if ( !shorthandStyles[ name ] ) {
2143 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
2144 diff[ name ] = value;
2153 // Support: jQuery <1.8
2154 if ( !$.fn.addBack ) {
2155 $.fn.addBack = function( selector ) {
2156 return this.add( selector == null ?
2157 this.prevObject : this.prevObject.filter( selector )
2162 $.effects.animateClass = function( value, duration, easing, callback ) {
2163 var o = $.speed( duration, easing, callback );
2165 return this.queue( function() {
2166 var animated = $( this ),
2167 baseClass = animated.attr( "class" ) || "",
2169 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
2171 // Map the animated objects to store the original styles.
2172 allAnimations = allAnimations.map( function() {
2176 start: getElementStyles( this )
2180 // Apply class change
2181 applyClassChange = function() {
2182 $.each( classAnimationActions, function( i, action ) {
2183 if ( value[ action ] ) {
2184 animated[ action + "Class" ]( value[ action ] );
2190 // Map all animated objects again - calculate new styles and diff
2191 allAnimations = allAnimations.map( function() {
2192 this.end = getElementStyles( this.el[ 0 ] );
2193 this.diff = styleDifference( this.start, this.end );
2197 // Apply original class
2198 animated.attr( "class", baseClass );
2200 // Map all animated objects again - this time collecting a promise
2201 allAnimations = allAnimations.map( function() {
2202 var styleInfo = this,
2204 opts = $.extend( {}, o, {
2206 complete: function() {
2207 dfd.resolve( styleInfo );
2211 this.el.animate( this.diff, opts );
2212 return dfd.promise();
2215 // Once all animations have completed:
2216 $.when.apply( $, allAnimations.get() ).done( function() {
2218 // Set the final class
2221 // For each animated element,
2222 // clear all css properties that were animated
2223 $.each( arguments, function() {
2225 $.each( this.diff, function( key ) {
2230 // This is guarnteed to be there if you use jQuery.speed()
2231 // it also handles dequeuing the next anim...
2232 o.complete.call( animated[ 0 ] );
2238 addClass: ( function( orig ) {
2239 return function( classNames, speed, easing, callback ) {
2241 $.effects.animateClass.call( this,
2242 { add: classNames }, speed, easing, callback ) :
2243 orig.apply( this, arguments );
2245 } )( $.fn.addClass ),
2247 removeClass: ( function( orig ) {
2248 return function( classNames, speed, easing, callback ) {
2249 return arguments.length > 1 ?
2250 $.effects.animateClass.call( this,
2251 { remove: classNames }, speed, easing, callback ) :
2252 orig.apply( this, arguments );
2254 } )( $.fn.removeClass ),
2256 toggleClass: ( function( orig ) {
2257 return function( classNames, force, speed, easing, callback ) {
2258 if ( typeof force === "boolean" || force === undefined ) {
2261 // Without speed parameter
2262 return orig.apply( this, arguments );
2264 return $.effects.animateClass.call( this,
2265 ( force ? { add: classNames } : { remove: classNames } ),
2266 speed, easing, callback );
2270 // Without force parameter
2271 return $.effects.animateClass.call( this,
2272 { toggle: classNames }, force, speed, easing );
2275 } )( $.fn.toggleClass ),
2277 switchClass: function( remove, add, speed, easing, callback ) {
2278 return $.effects.animateClass.call( this, {
2281 }, speed, easing, callback );
2287 /******************************************************************************/
2288 /*********************************** EFFECTS **********************************/
2289 /******************************************************************************/
2293 if ( $.expr && $.expr.pseudos && $.expr.pseudos.animated ) {
2294 $.expr.pseudos.animated = ( function( orig ) {
2295 return function( elem ) {
2296 return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
2298 } )( $.expr.pseudos.animated );
2301 if ( $.uiBackCompat !== false ) {
2302 $.extend( $.effects, {
2304 // Saves a set of properties in a data storage
2305 save: function( element, set ) {
2306 var i = 0, length = set.length;
2307 for ( ; i < length; i++ ) {
2308 if ( set[ i ] !== null ) {
2309 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
2314 // Restores a set of previously saved properties from a data storage
2315 restore: function( element, set ) {
2316 var val, i = 0, length = set.length;
2317 for ( ; i < length; i++ ) {
2318 if ( set[ i ] !== null ) {
2319 val = element.data( dataSpace + set[ i ] );
2320 element.css( set[ i ], val );
2325 setMode: function( el, mode ) {
2326 if ( mode === "toggle" ) {
2327 mode = el.is( ":hidden" ) ? "show" : "hide";
2332 // Wraps the element around a wrapper that copies position properties
2333 createWrapper: function( element ) {
2335 // If the element is already wrapped, return it
2336 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2337 return element.parent();
2342 width: element.outerWidth( true ),
2343 height: element.outerHeight( true ),
2344 "float": element.css( "float" )
2346 wrapper = $( "<div></div>" )
2347 .addClass( "ui-effects-wrapper" )
2350 background: "transparent",
2356 // Store the size in case width/height are defined in % - Fixes #5245
2358 width: element.width(),
2359 height: element.height()
2361 active = document.activeElement;
2364 // Firefox incorrectly exposes anonymous content
2365 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
2367 // eslint-disable-next-line no-unused-expressions
2370 active = document.body;
2373 element.wrap( wrapper );
2375 // Fixes #7595 - Elements lose focus when wrapped.
2376 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2377 $( active ).trigger( "focus" );
2380 // Hotfix for jQuery 1.4 since some change in wrap() seems to actually
2381 // lose the reference to the wrapped element
2382 wrapper = element.parent();
2384 // Transfer positioning properties to the wrapper
2385 if ( element.css( "position" ) === "static" ) {
2386 wrapper.css( { position: "relative" } );
2387 element.css( { position: "relative" } );
2390 position: element.css( "position" ),
2391 zIndex: element.css( "z-index" )
2393 $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
2394 props[ pos ] = element.css( pos );
2395 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
2396 props[ pos ] = "auto";
2400 position: "relative",
2407 element.css( size );
2409 return wrapper.css( props ).show();
2412 removeWrapper: function( element ) {
2413 var active = document.activeElement;
2415 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2416 element.parent().replaceWith( element );
2418 // Fixes #7595 - Elements lose focus when wrapped.
2419 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2420 $( active ).trigger( "focus" );
2429 $.extend( $.effects, {
2432 define: function( name, mode, effect ) {
2438 $.effects.effect[ name ] = effect;
2439 $.effects.effect[ name ].mode = mode;
2444 scaledDimensions: function( element, percent, direction ) {
2445 if ( percent === 0 ) {
2454 var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
2455 y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
2458 height: element.height() * y,
2459 width: element.width() * x,
2460 outerHeight: element.outerHeight() * y,
2461 outerWidth: element.outerWidth() * x
2466 clipToBox: function( animation ) {
2468 width: animation.clip.right - animation.clip.left,
2469 height: animation.clip.bottom - animation.clip.top,
2470 left: animation.clip.left,
2471 top: animation.clip.top
2475 // Injects recently queued functions to be first in line (after "inprogress")
2476 unshift: function( element, queueLength, count ) {
2477 var queue = element.queue();
2479 if ( queueLength > 1 ) {
2480 queue.splice.apply( queue,
2481 [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
2486 saveStyle: function( element ) {
2487 element.data( dataSpaceStyle, element[ 0 ].style.cssText );
2490 restoreStyle: function( element ) {
2491 element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
2492 element.removeData( dataSpaceStyle );
2495 mode: function( element, mode ) {
2496 var hidden = element.is( ":hidden" );
2498 if ( mode === "toggle" ) {
2499 mode = hidden ? "show" : "hide";
2501 if ( hidden ? mode === "hide" : mode === "show" ) {
2507 // Translates a [top,left] array into a baseline value
2508 getBaseline: function( origin, original ) {
2511 switch ( origin[ 0 ] ) {
2522 y = origin[ 0 ] / original.height;
2525 switch ( origin[ 1 ] ) {
2536 x = origin[ 1 ] / original.width;
2545 // Creates a placeholder element so that the original element can be made absolute
2546 createPlaceholder: function( element ) {
2548 cssPosition = element.css( "position" ),
2549 position = element.position();
2551 // Lock in margins first to account for form elements, which
2552 // will change margin if you explicitly set height
2553 // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
2556 marginTop: element.css( "marginTop" ),
2557 marginBottom: element.css( "marginBottom" ),
2558 marginLeft: element.css( "marginLeft" ),
2559 marginRight: element.css( "marginRight" )
2561 .outerWidth( element.outerWidth() )
2562 .outerHeight( element.outerHeight() );
2564 if ( /^(static|relative)/.test( cssPosition ) ) {
2565 cssPosition = "absolute";
2567 placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
2569 // Convert inline to inline block to account for inline elements
2570 // that turn to inline block based on content (like img)
2571 display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
2574 visibility: "hidden",
2576 // Margins need to be set to account for margin collapse
2577 marginTop: element.css( "marginTop" ),
2578 marginBottom: element.css( "marginBottom" ),
2579 marginLeft: element.css( "marginLeft" ),
2580 marginRight: element.css( "marginRight" ),
2581 "float": element.css( "float" )
2583 .outerWidth( element.outerWidth() )
2584 .outerHeight( element.outerHeight() )
2585 .addClass( "ui-effects-placeholder" );
2587 element.data( dataSpace + "placeholder", placeholder );
2591 position: cssPosition,
2592 left: position.left,
2599 removePlaceholder: function( element ) {
2600 var dataKey = dataSpace + "placeholder",
2601 placeholder = element.data( dataKey );
2603 if ( placeholder ) {
2604 placeholder.remove();
2605 element.removeData( dataKey );
2609 // Removes a placeholder if it exists and restores
2610 // properties that were modified during placeholder creation
2611 cleanUp: function( element ) {
2612 $.effects.restoreStyle( element );
2613 $.effects.removePlaceholder( element );
2616 setTransition: function( element, list, factor, value ) {
2617 value = value || {};
2618 $.each( list, function( i, x ) {
2619 var unit = element.cssUnit( x );
2620 if ( unit[ 0 ] > 0 ) {
2621 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
2628 // Return an effect options object for the given parameters:
2629 function _normalizeArguments( effect, options, speed, callback ) {
2631 // Allow passing all options as the first parameter
2632 if ( $.isPlainObject( effect ) ) {
2634 effect = effect.effect;
2637 // Convert to an object
2638 effect = { effect: effect };
2640 // Catch (effect, null, ...)
2641 if ( options == null ) {
2645 // Catch (effect, callback)
2646 if ( typeof options === "function" ) {
2652 // Catch (effect, speed, ?)
2653 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
2659 // Catch (effect, options, callback)
2660 if ( typeof speed === "function" ) {
2665 // Add options to effect
2667 $.extend( effect, options );
2670 speed = speed || options.duration;
2671 effect.duration = $.fx.off ? 0 :
2672 typeof speed === "number" ? speed :
2673 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
2674 $.fx.speeds._default;
2676 effect.complete = callback || options.complete;
2681 function standardAnimationOption( option ) {
2683 // Valid standard speeds (nothing, number, named speed)
2684 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
2688 // Invalid strings - treat as "normal" speed
2689 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
2693 // Complete callback
2694 if ( typeof option === "function" ) {
2698 // Options hash (but not naming an effect)
2699 if ( typeof option === "object" && !option.effect ) {
2703 // Didn't match any standard API
2708 effect: function( /* effect, options, speed, callback */ ) {
2709 var args = _normalizeArguments.apply( this, arguments ),
2710 effectMethod = $.effects.effect[ args.effect ],
2711 defaultMode = effectMethod.mode,
2713 queueName = queue || "fx",
2714 complete = args.complete,
2717 prefilter = function( next ) {
2719 normalizedMode = $.effects.mode( el, mode ) || defaultMode;
2721 // Sentinel for duck-punching the :animated pseudo-selector
2722 el.data( dataSpaceAnimated, true );
2724 // Save effect mode for later use,
2725 // we can't just call $.effects.mode again later,
2726 // as the .show() below destroys the initial state
2727 modes.push( normalizedMode );
2729 // See $.uiBackCompat inside of run() for removal of defaultMode in 1.14
2730 if ( defaultMode && ( normalizedMode === "show" ||
2731 ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
2735 if ( !defaultMode || normalizedMode !== "none" ) {
2736 $.effects.saveStyle( el );
2739 if ( typeof next === "function" ) {
2744 if ( $.fx.off || !effectMethod ) {
2746 // Delegate to the original method (e.g., .show()) if possible
2748 return this[ mode ]( args.duration, complete );
2750 return this.each( function() {
2752 complete.call( this );
2758 function run( next ) {
2759 var elem = $( this );
2761 function cleanup() {
2762 elem.removeData( dataSpaceAnimated );
2764 $.effects.cleanUp( elem );
2766 if ( args.mode === "hide" ) {
2774 if ( typeof complete === "function" ) {
2775 complete.call( elem[ 0 ] );
2778 if ( typeof next === "function" ) {
2783 // Override mode option on a per element basis,
2784 // as toggle can be either show or hide depending on element state
2785 args.mode = modes.shift();
2787 if ( $.uiBackCompat !== false && !defaultMode ) {
2788 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
2790 // Call the core method to track "olddisplay" properly
2794 effectMethod.call( elem[ 0 ], args, done );
2797 if ( args.mode === "none" ) {
2799 // Call the core method to track "olddisplay" properly
2803 effectMethod.call( elem[ 0 ], args, cleanup );
2808 // Run prefilter on all elements first to ensure that
2809 // any showing or hiding happens before placeholder creation,
2810 // which ensures that any layout changes are correctly captured.
2811 return queue === false ?
2812 this.each( prefilter ).each( run ) :
2813 this.queue( queueName, prefilter ).queue( queueName, run );
2816 show: ( function( orig ) {
2817 return function( option ) {
2818 if ( standardAnimationOption( option ) ) {
2819 return orig.apply( this, arguments );
2821 var args = _normalizeArguments.apply( this, arguments );
2823 return this.effect.call( this, args );
2828 hide: ( function( orig ) {
2829 return function( option ) {
2830 if ( standardAnimationOption( option ) ) {
2831 return orig.apply( this, arguments );
2833 var args = _normalizeArguments.apply( this, arguments );
2835 return this.effect.call( this, args );
2840 toggle: ( function( orig ) {
2841 return function( option ) {
2842 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
2843 return orig.apply( this, arguments );
2845 var args = _normalizeArguments.apply( this, arguments );
2846 args.mode = "toggle";
2847 return this.effect.call( this, args );
2852 cssUnit: function( key ) {
2853 var style = this.css( key ),
2856 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
2857 if ( style.indexOf( unit ) > 0 ) {
2858 val = [ parseFloat( style ), unit ];
2864 cssClip: function( clipObj ) {
2866 return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
2867 clipObj.bottom + "px " + clipObj.left + "px)" );
2869 return parseClip( this.css( "clip" ), this );
2872 transfer: function( options, done ) {
2873 var element = $( this ),
2874 target = $( options.to ),
2875 targetFixed = target.css( "position" ) === "fixed",
2877 fixTop = targetFixed ? body.scrollTop() : 0,
2878 fixLeft = targetFixed ? body.scrollLeft() : 0,
2879 endPosition = target.offset(),
2881 top: endPosition.top - fixTop,
2882 left: endPosition.left - fixLeft,
2883 height: target.innerHeight(),
2884 width: target.innerWidth()
2886 startPosition = element.offset(),
2887 transfer = $( "<div class='ui-effects-transfer'></div>" );
2891 .addClass( options.className )
2893 top: startPosition.top - fixTop,
2894 left: startPosition.left - fixLeft,
2895 height: element.innerHeight(),
2896 width: element.innerWidth(),
2897 position: targetFixed ? "fixed" : "absolute"
2899 .animate( animation, options.duration, options.easing, function() {
2901 if ( typeof done === "function" ) {
2908 function parseClip( str, element ) {
2909 var outerWidth = element.outerWidth(),
2910 outerHeight = element.outerHeight(),
2911 clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
2912 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
2915 top: parseFloat( values[ 1 ] ) || 0,
2916 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
2917 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
2918 left: parseFloat( values[ 4 ] ) || 0
2922 $.fx.step.clip = function( fx ) {
2923 if ( !fx.clipInit ) {
2924 fx.start = $( fx.elem ).cssClip();
2925 if ( typeof fx.end === "string" ) {
2926 fx.end = parseClip( fx.end, fx.elem );
2931 $( fx.elem ).cssClip( {
2932 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
2933 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
2934 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
2935 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
2941 /******************************************************************************/
2942 /*********************************** EASING ***********************************/
2943 /******************************************************************************/
2947 // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
2949 var baseEasings = {};
2951 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
2952 baseEasings[ name ] = function( p ) {
2953 return Math.pow( p, i + 2 );
2957 $.extend( baseEasings, {
2958 Sine: function( p ) {
2959 return 1 - Math.cos( p * Math.PI / 2 );
2961 Circ: function( p ) {
2962 return 1 - Math.sqrt( 1 - p * p );
2964 Elastic: function( p ) {
2965 return p === 0 || p === 1 ? p :
2966 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
2968 Back: function( p ) {
2969 return p * p * ( 3 * p - 2 );
2971 Bounce: function( p ) {
2975 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
2976 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
2980 $.each( baseEasings, function( name, easeIn ) {
2981 $.easing[ "easeIn" + name ] = easeIn;
2982 $.easing[ "easeOut" + name ] = function( p ) {
2983 return 1 - easeIn( 1 - p );
2985 $.easing[ "easeInOut" + name ] = function( p ) {
2987 easeIn( p * 2 ) / 2 :
2988 1 - easeIn( p * -2 + 2 ) / 2;
2994 var effect = $.effects;
2998 * jQuery UI Effects Blind 1.13.0
2999 * http://jqueryui.com
3001 * Copyright jQuery Foundation and other contributors
3002 * Released under the MIT license.
3003 * http://jquery.org/license
3006 //>>label: Blind Effect
3008 //>>description: Blinds the element.
3009 //>>docs: http://api.jqueryui.com/blind-effect/
3010 //>>demos: http://jqueryui.com/effect/
3013 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
3015 up: [ "bottom", "top" ],
3016 vertical: [ "bottom", "top" ],
3017 down: [ "top", "bottom" ],
3018 left: [ "right", "left" ],
3019 horizontal: [ "right", "left" ],
3020 right: [ "left", "right" ]
3022 element = $( this ),
3023 direction = options.direction || "up",
3024 start = element.cssClip(),
3025 animate = { clip: $.extend( {}, start ) },
3026 placeholder = $.effects.createPlaceholder( element );
3028 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
3030 if ( options.mode === "show" ) {
3031 element.cssClip( animate.clip );
3032 if ( placeholder ) {
3033 placeholder.css( $.effects.clipToBox( animate ) );
3036 animate.clip = start;
3039 if ( placeholder ) {
3040 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
3043 element.animate( animate, {
3045 duration: options.duration,
3046 easing: options.easing,
3053 * jQuery UI Effects Bounce 1.13.0
3054 * http://jqueryui.com
3056 * Copyright jQuery Foundation and other contributors
3057 * Released under the MIT license.
3058 * http://jquery.org/license
3061 //>>label: Bounce Effect
3063 //>>description: Bounces an element horizontally or vertically n times.
3064 //>>docs: http://api.jqueryui.com/bounce-effect/
3065 //>>demos: http://jqueryui.com/effect/
3068 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
3069 var upAnim, downAnim, refValue,
3070 element = $( this ),
3073 mode = options.mode,
3074 hide = mode === "hide",
3075 show = mode === "show",
3076 direction = options.direction || "up",
3077 distance = options.distance,
3078 times = options.times || 5,
3080 // Number of internal animations
3081 anims = times * 2 + ( show || hide ? 1 : 0 ),
3082 speed = options.duration / anims,
3083 easing = options.easing,
3086 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3087 motion = ( direction === "up" || direction === "left" ),
3090 queuelen = element.queue().length;
3092 $.effects.createPlaceholder( element );
3094 refValue = element.css( ref );
3096 // Default distance for the BIGGEST bounce is the outer Distance / 3
3098 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
3102 downAnim = { opacity: 1 };
3103 downAnim[ ref ] = refValue;
3105 // If we are showing, force opacity 0 and set the initial position
3106 // then do the "first" animation
3108 .css( "opacity", 0 )
3109 .css( ref, motion ? -distance * 2 : distance * 2 )
3110 .animate( downAnim, speed, easing );
3113 // Start at the smallest distance if we are hiding
3115 distance = distance / Math.pow( 2, times - 1 );
3119 downAnim[ ref ] = refValue;
3121 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
3122 for ( ; i < times; i++ ) {
3124 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3127 .animate( upAnim, speed, easing )
3128 .animate( downAnim, speed, easing );
3130 distance = hide ? distance * 2 : distance / 2;
3133 // Last Bounce when Hiding
3135 upAnim = { opacity: 0 };
3136 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3138 element.animate( upAnim, speed, easing );
3141 element.queue( done );
3143 $.effects.unshift( element, queuelen, anims + 1 );
3148 * jQuery UI Effects Clip 1.13.0
3149 * http://jqueryui.com
3151 * Copyright jQuery Foundation and other contributors
3152 * Released under the MIT license.
3153 * http://jquery.org/license
3156 //>>label: Clip Effect
3158 //>>description: Clips the element on and off like an old TV.
3159 //>>docs: http://api.jqueryui.com/clip-effect/
3160 //>>demos: http://jqueryui.com/effect/
3163 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
3166 element = $( this ),
3167 direction = options.direction || "vertical",
3168 both = direction === "both",
3169 horizontal = both || direction === "horizontal",
3170 vertical = both || direction === "vertical";
3172 start = element.cssClip();
3174 top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
3175 right: horizontal ? ( start.right - start.left ) / 2 : start.right,
3176 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
3177 left: horizontal ? ( start.right - start.left ) / 2 : start.left
3180 $.effects.createPlaceholder( element );
3182 if ( options.mode === "show" ) {
3183 element.cssClip( animate.clip );
3184 animate.clip = start;
3187 element.animate( animate, {
3189 duration: options.duration,
3190 easing: options.easing,
3198 * jQuery UI Effects Drop 1.13.0
3199 * http://jqueryui.com
3201 * Copyright jQuery Foundation and other contributors
3202 * Released under the MIT license.
3203 * http://jquery.org/license
3206 //>>label: Drop Effect
3208 //>>description: Moves an element in one direction and hides it at the same time.
3209 //>>docs: http://api.jqueryui.com/drop-effect/
3210 //>>demos: http://jqueryui.com/effect/
3213 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
3216 element = $( this ),
3217 mode = options.mode,
3218 show = mode === "show",
3219 direction = options.direction || "left",
3220 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3221 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
3222 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
3227 $.effects.createPlaceholder( element );
3229 distance = options.distance ||
3230 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
3232 animation[ ref ] = motion + distance;
3235 element.css( animation );
3237 animation[ ref ] = oppositeMotion + distance;
3238 animation.opacity = 1;
3242 element.animate( animation, {
3244 duration: options.duration,
3245 easing: options.easing,
3252 * jQuery UI Effects Explode 1.13.0
3253 * http://jqueryui.com
3255 * Copyright jQuery Foundation and other contributors
3256 * Released under the MIT license.
3257 * http://jquery.org/license
3260 //>>label: Explode Effect
3262 /* eslint-disable max-len */
3263 //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
3264 /* eslint-enable max-len */
3265 //>>docs: http://api.jqueryui.com/explode-effect/
3266 //>>demos: http://jqueryui.com/effect/
3269 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
3271 var i, j, left, top, mx, my,
3272 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
3274 element = $( this ),
3275 mode = options.mode,
3276 show = mode === "show",
3278 // Show and then visibility:hidden the element before calculating offset
3279 offset = element.show().css( "visibility", "hidden" ).offset(),
3281 // Width and height of a piece
3282 width = Math.ceil( element.outerWidth() / cells ),
3283 height = Math.ceil( element.outerHeight() / rows ),
3286 // Children animate complete:
3287 function childComplete() {
3288 pieces.push( this );
3289 if ( pieces.length === rows * cells ) {
3294 // Clone the element for each row and cell.
3295 for ( i = 0; i < rows; i++ ) { // ===>
3296 top = offset.top + i * height;
3297 my = i - ( rows - 1 ) / 2;
3299 for ( j = 0; j < cells; j++ ) { // |||
3300 left = offset.left + j * width;
3301 mx = j - ( cells - 1 ) / 2;
3303 // Create a clone of the now hidden main element that will be absolute positioned
3304 // within a wrapper div off the -left and -top equal to size of our pieces
3308 .wrap( "<div></div>" )
3310 position: "absolute",
3311 visibility: "visible",
3316 // Select the wrapper - make it overflow: hidden and absolute positioned based on
3317 // where the original was located +left and +top equal to the size of pieces
3319 .addClass( "ui-effects-explode" )
3321 position: "absolute",
3325 left: left + ( show ? mx * width : 0 ),
3326 top: top + ( show ? my * height : 0 ),
3327 opacity: show ? 0 : 1
3330 left: left + ( show ? 0 : mx * width ),
3331 top: top + ( show ? 0 : my * height ),
3332 opacity: show ? 1 : 0
3333 }, options.duration || 500, options.easing, childComplete );
3337 function animComplete() {
3339 visibility: "visible"
3341 $( pieces ).remove();
3348 * jQuery UI Effects Fade 1.13.0
3349 * http://jqueryui.com
3351 * Copyright jQuery Foundation and other contributors
3352 * Released under the MIT license.
3353 * http://jquery.org/license
3356 //>>label: Fade Effect
3358 //>>description: Fades the element.
3359 //>>docs: http://api.jqueryui.com/fade-effect/
3360 //>>demos: http://jqueryui.com/effect/
3363 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
3364 var show = options.mode === "show";
3367 .css( "opacity", show ? 0 : 1 )
3369 opacity: show ? 1 : 0
3372 duration: options.duration,
3373 easing: options.easing,
3380 * jQuery UI Effects Fold 1.13.0
3381 * http://jqueryui.com
3383 * Copyright jQuery Foundation and other contributors
3384 * Released under the MIT license.
3385 * http://jquery.org/license
3388 //>>label: Fold Effect
3390 //>>description: Folds an element first horizontally and then vertically.
3391 //>>docs: http://api.jqueryui.com/fold-effect/
3392 //>>demos: http://jqueryui.com/effect/
3395 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
3398 var element = $( this ),
3399 mode = options.mode,
3400 show = mode === "show",
3401 hide = mode === "hide",
3402 size = options.size || 15,
3403 percent = /([0-9]+)%/.exec( size ),
3404 horizFirst = !!options.horizFirst,
3405 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
3406 duration = options.duration / 2,
3408 placeholder = $.effects.createPlaceholder( element ),
3410 start = element.cssClip(),
3411 animation1 = { clip: $.extend( {}, start ) },
3412 animation2 = { clip: $.extend( {}, start ) },
3414 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
3416 queuelen = element.queue().length;
3419 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
3421 animation1.clip[ ref[ 0 ] ] = size;
3422 animation2.clip[ ref[ 0 ] ] = size;
3423 animation2.clip[ ref[ 1 ] ] = 0;
3426 element.cssClip( animation2.clip );
3427 if ( placeholder ) {
3428 placeholder.css( $.effects.clipToBox( animation2 ) );
3431 animation2.clip = start;
3436 .queue( function( next ) {
3437 if ( placeholder ) {
3439 .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
3440 .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
3445 .animate( animation1, duration, options.easing )
3446 .animate( animation2, duration, options.easing )
3449 $.effects.unshift( element, queuelen, 4 );
3454 * jQuery UI Effects Highlight 1.13.0
3455 * http://jqueryui.com
3457 * Copyright jQuery Foundation and other contributors
3458 * Released under the MIT license.
3459 * http://jquery.org/license
3462 //>>label: Highlight Effect
3464 //>>description: Highlights the background of an element in a defined color for a custom duration.
3465 //>>docs: http://api.jqueryui.com/highlight-effect/
3466 //>>demos: http://jqueryui.com/effect/
3469 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
3470 var element = $( this ),
3472 backgroundColor: element.css( "backgroundColor" )
3475 if ( options.mode === "hide" ) {
3476 animation.opacity = 0;
3479 $.effects.saveStyle( element );
3483 backgroundImage: "none",
3484 backgroundColor: options.color || "#ffff99"
3486 .animate( animation, {
3488 duration: options.duration,
3489 easing: options.easing,
3496 * jQuery UI Effects Size 1.13.0
3497 * http://jqueryui.com
3499 * Copyright jQuery Foundation and other contributors
3500 * Released under the MIT license.
3501 * http://jquery.org/license
3504 //>>label: Size Effect
3506 //>>description: Resize an element to a specified width and height.
3507 //>>docs: http://api.jqueryui.com/size-effect/
3508 //>>demos: http://jqueryui.com/effect/
3511 var effectsEffectSize = $.effects.define( "size", function( options, done ) {
3514 var baseline, factor, temp,
3515 element = $( this ),
3517 // Copy for children
3518 cProps = [ "fontSize" ],
3519 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
3520 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
3523 mode = options.mode,
3524 restore = mode !== "effect",
3525 scale = options.scale || "both",
3526 origin = options.origin || [ "middle", "center" ],
3527 position = element.css( "position" ),
3528 pos = element.position(),
3529 original = $.effects.scaledDimensions( element ),
3530 from = options.from || original,
3531 to = options.to || $.effects.scaledDimensions( element, 0 );
3533 $.effects.createPlaceholder( element );
3535 if ( mode === "show" ) {
3541 // Set scaling factor
3544 y: from.height / original.height,
3545 x: from.width / original.width
3548 y: to.height / original.height,
3549 x: to.width / original.width
3553 // Scale the css box
3554 if ( scale === "box" || scale === "both" ) {
3556 // Vertical props scaling
3557 if ( factor.from.y !== factor.to.y ) {
3558 from = $.effects.setTransition( element, vProps, factor.from.y, from );
3559 to = $.effects.setTransition( element, vProps, factor.to.y, to );
3562 // Horizontal props scaling
3563 if ( factor.from.x !== factor.to.x ) {
3564 from = $.effects.setTransition( element, hProps, factor.from.x, from );
3565 to = $.effects.setTransition( element, hProps, factor.to.x, to );
3569 // Scale the content
3570 if ( scale === "content" || scale === "both" ) {
3572 // Vertical props scaling
3573 if ( factor.from.y !== factor.to.y ) {
3574 from = $.effects.setTransition( element, cProps, factor.from.y, from );
3575 to = $.effects.setTransition( element, cProps, factor.to.y, to );
3579 // Adjust the position properties based on the provided origin points
3581 baseline = $.effects.getBaseline( origin, original );
3582 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
3583 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
3584 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
3585 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
3587 delete from.outerHeight;
3588 delete from.outerWidth;
3589 element.css( from );
3591 // Animate the children if desired
3592 if ( scale === "content" || scale === "both" ) {
3594 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
3595 hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
3597 // Only animate children with width attributes specified
3598 // TODO: is this right? should we include anything with css width specified as well
3599 element.find( "*[width]" ).each( function() {
3600 var child = $( this ),
3601 childOriginal = $.effects.scaledDimensions( child ),
3603 height: childOriginal.height * factor.from.y,
3604 width: childOriginal.width * factor.from.x,
3605 outerHeight: childOriginal.outerHeight * factor.from.y,
3606 outerWidth: childOriginal.outerWidth * factor.from.x
3609 height: childOriginal.height * factor.to.y,
3610 width: childOriginal.width * factor.to.x,
3611 outerHeight: childOriginal.height * factor.to.y,
3612 outerWidth: childOriginal.width * factor.to.x
3615 // Vertical props scaling
3616 if ( factor.from.y !== factor.to.y ) {
3617 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
3618 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
3621 // Horizontal props scaling
3622 if ( factor.from.x !== factor.to.x ) {
3623 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
3624 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
3628 $.effects.saveStyle( child );
3632 child.css( childFrom );
3633 child.animate( childTo, options.duration, options.easing, function() {
3637 $.effects.restoreStyle( child );
3644 element.animate( to, {
3646 duration: options.duration,
3647 easing: options.easing,
3648 complete: function() {
3650 var offset = element.offset();
3652 if ( to.opacity === 0 ) {
3653 element.css( "opacity", from.opacity );
3658 .css( "position", position === "static" ? "relative" : position )
3661 // Need to save style here so that automatic style restoration
3662 // doesn't restore to the original styles from before the animation.
3663 $.effects.saveStyle( element );
3674 * jQuery UI Effects Scale 1.13.0
3675 * http://jqueryui.com
3677 * Copyright jQuery Foundation and other contributors
3678 * Released under the MIT license.
3679 * http://jquery.org/license
3682 //>>label: Scale Effect
3684 //>>description: Grows or shrinks an element and its content.
3685 //>>docs: http://api.jqueryui.com/scale-effect/
3686 //>>demos: http://jqueryui.com/effect/
3689 var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
3693 mode = options.mode,
3694 percent = parseInt( options.percent, 10 ) ||
3695 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
3697 newOptions = $.extend( true, {
3698 from: $.effects.scaledDimensions( el ),
3699 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
3700 origin: options.origin || [ "middle", "center" ]
3703 // Fade option to support puff
3704 if ( options.fade ) {
3705 newOptions.from.opacity = 1;
3706 newOptions.to.opacity = 0;
3709 $.effects.effect.size.call( this, newOptions, done );
3714 * jQuery UI Effects Puff 1.13.0
3715 * http://jqueryui.com
3717 * Copyright jQuery Foundation and other contributors
3718 * Released under the MIT license.
3719 * http://jquery.org/license
3722 //>>label: Puff Effect
3724 //>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
3725 //>>docs: http://api.jqueryui.com/puff-effect/
3726 //>>demos: http://jqueryui.com/effect/
3729 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
3730 var newOptions = $.extend( true, {}, options, {
3732 percent: parseInt( options.percent, 10 ) || 150
3735 $.effects.effect.scale.call( this, newOptions, done );
3740 * jQuery UI Effects Pulsate 1.13.0
3741 * http://jqueryui.com
3743 * Copyright jQuery Foundation and other contributors
3744 * Released under the MIT license.
3745 * http://jquery.org/license
3748 //>>label: Pulsate Effect
3750 //>>description: Pulsates an element n times by changing the opacity to zero and back.
3751 //>>docs: http://api.jqueryui.com/pulsate-effect/
3752 //>>demos: http://jqueryui.com/effect/
3755 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
3756 var element = $( this ),
3757 mode = options.mode,
3758 show = mode === "show",
3759 hide = mode === "hide",
3760 showhide = show || hide,
3762 // Showing or hiding leaves off the "last" animation
3763 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
3764 duration = options.duration / anims,
3767 queuelen = element.queue().length;
3769 if ( show || !element.is( ":visible" ) ) {
3770 element.css( "opacity", 0 ).show();
3774 // Anims - 1 opacity "toggles"
3775 for ( ; i < anims; i++ ) {
3776 element.animate( { opacity: animateTo }, duration, options.easing );
3777 animateTo = 1 - animateTo;
3780 element.animate( { opacity: animateTo }, duration, options.easing );
3782 element.queue( done );
3784 $.effects.unshift( element, queuelen, anims + 1 );
3789 * jQuery UI Effects Shake 1.13.0
3790 * http://jqueryui.com
3792 * Copyright jQuery Foundation and other contributors
3793 * Released under the MIT license.
3794 * http://jquery.org/license
3797 //>>label: Shake Effect
3799 //>>description: Shakes an element horizontally or vertically n times.
3800 //>>docs: http://api.jqueryui.com/shake-effect/
3801 //>>demos: http://jqueryui.com/effect/
3804 var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
3807 element = $( this ),
3808 direction = options.direction || "left",
3809 distance = options.distance || 20,
3810 times = options.times || 3,
3811 anims = times * 2 + 1,
3812 speed = Math.round( options.duration / anims ),
3813 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3814 positiveMotion = ( direction === "up" || direction === "left" ),
3819 queuelen = element.queue().length;
3821 $.effects.createPlaceholder( element );
3824 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
3825 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
3826 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
3829 element.animate( animation, speed, options.easing );
3832 for ( ; i < times; i++ ) {
3834 .animate( animation1, speed, options.easing )
3835 .animate( animation2, speed, options.easing );
3839 .animate( animation1, speed, options.easing )
3840 .animate( animation, speed / 2, options.easing )
3843 $.effects.unshift( element, queuelen, anims + 1 );
3848 * jQuery UI Effects Slide 1.13.0
3849 * http://jqueryui.com
3851 * Copyright jQuery Foundation and other contributors
3852 * Released under the MIT license.
3853 * http://jquery.org/license
3856 //>>label: Slide Effect
3858 //>>description: Slides an element in and out of the viewport.
3859 //>>docs: http://api.jqueryui.com/slide-effect/
3860 //>>demos: http://jqueryui.com/effect/
3863 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
3864 var startClip, startRef,
3865 element = $( this ),
3867 up: [ "bottom", "top" ],
3868 down: [ "top", "bottom" ],
3869 left: [ "right", "left" ],
3870 right: [ "left", "right" ]
3872 mode = options.mode,
3873 direction = options.direction || "left",
3874 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3875 positiveMotion = ( direction === "up" || direction === "left" ),
3876 distance = options.distance ||
3877 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
3880 $.effects.createPlaceholder( element );
3882 startClip = element.cssClip();
3883 startRef = element.position()[ ref ];
3885 // Define hide animation
3886 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
3887 animation.clip = element.cssClip();
3888 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
3890 // Reverse the animation if we're showing
3891 if ( mode === "show" ) {
3892 element.cssClip( animation.clip );
3893 element.css( ref, animation[ ref ] );
3894 animation.clip = startClip;
3895 animation[ ref ] = startRef;
3899 element.animate( animation, {
3901 duration: options.duration,
3902 easing: options.easing,
3909 * jQuery UI Effects Transfer 1.13.0
3910 * http://jqueryui.com
3912 * Copyright jQuery Foundation and other contributors
3913 * Released under the MIT license.
3914 * http://jquery.org/license
3917 //>>label: Transfer Effect
3919 //>>description: Displays a transfer effect from one element to another.
3920 //>>docs: http://api.jqueryui.com/transfer-effect/
3921 //>>demos: http://jqueryui.com/effect/
3925 if ( $.uiBackCompat !== false ) {
3926 effect = $.effects.define( "transfer", function( options, done ) {
3927 $( this ).transfer( options, done );
3930 var effectsEffectTransfer = effect;
3934 * jQuery UI Focusable 1.13.0
3935 * http://jqueryui.com
3937 * Copyright jQuery Foundation and other contributors
3938 * Released under the MIT license.
3939 * http://jquery.org/license
3942 //>>label: :focusable Selector
3944 //>>description: Selects elements which can be focused.
3945 //>>docs: http://api.jqueryui.com/focusable-selector/
3949 $.ui.focusable = function( element, hasTabindex ) {
3950 var map, mapName, img, focusableIfVisible, fieldset,
3951 nodeName = element.nodeName.toLowerCase();
3953 if ( "area" === nodeName ) {
3954 map = element.parentNode;
3956 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
3959 img = $( "img[usemap='#" + mapName + "']" );
3960 return img.length > 0 && img.is( ":visible" );
3963 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
3964 focusableIfVisible = !element.disabled;
3966 if ( focusableIfVisible ) {
3968 // Form controls within a disabled fieldset are disabled.
3969 // However, controls within the fieldset's legend do not get disabled.
3970 // Since controls generally aren't placed inside legends, we skip
3971 // this portion of the check.
3972 fieldset = $( element ).closest( "fieldset" )[ 0 ];
3974 focusableIfVisible = !fieldset.disabled;
3977 } else if ( "a" === nodeName ) {
3978 focusableIfVisible = element.href || hasTabindex;
3980 focusableIfVisible = hasTabindex;
3983 return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
3986 // Support: IE 8 only
3987 // IE 8 doesn't resolve inherit to visible/hidden for computed values
3988 function visible( element ) {
3989 var visibility = element.css( "visibility" );
3990 while ( visibility === "inherit" ) {
3991 element = element.parent();
3992 visibility = element.css( "visibility" );
3994 return visibility === "visible";
3997 $.extend( $.expr.pseudos, {
3998 focusable: function( element ) {
3999 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
4003 var focusable = $.ui.focusable;
4007 // Support: IE8 Only
4008 // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
4009 // with a string, so we need to find the proper form.
4010 var form = $.fn._form = function() {
4011 return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
4016 * jQuery UI Form Reset Mixin 1.13.0
4017 * http://jqueryui.com
4019 * Copyright jQuery Foundation and other contributors
4020 * Released under the MIT license.
4021 * http://jquery.org/license
4024 //>>label: Form Reset Mixin
4026 //>>description: Refresh input widgets when their form is reset
4027 //>>docs: http://api.jqueryui.com/form-reset-mixin/
4030 var formResetMixin = $.ui.formResetMixin = {
4031 _formResetHandler: function() {
4032 var form = $( this );
4034 // Wait for the form reset to actually happen before refreshing
4035 setTimeout( function() {
4036 var instances = form.data( "ui-form-reset-instances" );
4037 $.each( instances, function() {
4043 _bindFormResetHandler: function() {
4044 this.form = this.element._form();
4045 if ( !this.form.length ) {
4049 var instances = this.form.data( "ui-form-reset-instances" ) || [];
4050 if ( !instances.length ) {
4052 // We don't use _on() here because we use a single event handler per form
4053 this.form.on( "reset.ui-form-reset", this._formResetHandler );
4055 instances.push( this );
4056 this.form.data( "ui-form-reset-instances", instances );
4059 _unbindFormResetHandler: function() {
4060 if ( !this.form.length ) {
4064 var instances = this.form.data( "ui-form-reset-instances" );
4065 instances.splice( $.inArray( this, instances ), 1 );
4066 if ( instances.length ) {
4067 this.form.data( "ui-form-reset-instances", instances );
4070 .removeData( "ui-form-reset-instances" )
4071 .off( "reset.ui-form-reset" );
4078 * jQuery UI Support for jQuery core 1.8.x and newer 1.13.0
4079 * http://jqueryui.com
4081 * Copyright jQuery Foundation and other contributors
4082 * Released under the MIT license.
4083 * http://jquery.org/license
4087 //>>label: jQuery 1.8+ Support
4089 //>>description: Support version 1.8.x and newer of jQuery core
4092 // Support: jQuery 1.9.x or older
4093 // $.expr[ ":" ] is deprecated.
4094 if ( !$.expr.pseudos ) {
4095 $.expr.pseudos = $.expr[ ":" ];
4098 // Support: jQuery 1.11.x or older
4099 // $.unique has been renamed to $.uniqueSort
4100 if ( !$.uniqueSort ) {
4101 $.uniqueSort = $.unique;
4104 // Support: jQuery 2.2.x or older.
4105 // This method has been defined in jQuery 3.0.0.
4106 // Code from https://github.com/jquery/jquery/blob/e539bac79e666bba95bba86d690b4e609dca2286/src/selector/escapeSelector.js
4107 if ( !$.escapeSelector ) {
4109 // CSS string/identifier serialization
4110 // https://drafts.csswg.org/cssom/#common-serializing-idioms
4111 var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
4113 var fcssescape = function( ch, asCodePoint ) {
4114 if ( asCodePoint ) {
4116 // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
4117 if ( ch === "\0" ) {
4121 // Control characters and (dependent upon position) numbers get escaped as code points
4122 return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
4125 // Other potentially-special ASCII characters get backslash-escaped
4129 $.escapeSelector = function( sel ) {
4130 return ( sel + "" ).replace( rcssescape, fcssescape );
4134 // Support: jQuery 3.4.x or older
4135 // These methods have been defined in jQuery 3.5.0.
4136 if ( !$.fn.even || !$.fn.odd ) {
4139 return this.filter( function( i ) {
4144 return this.filter( function( i ) {
4153 * jQuery UI Keycode 1.13.0
4154 * http://jqueryui.com
4156 * Copyright jQuery Foundation and other contributors
4157 * Released under the MIT license.
4158 * http://jquery.org/license
4163 //>>description: Provide keycodes as keynames
4164 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
4167 var keycode = $.ui.keyCode = {
4188 * jQuery UI Labels 1.13.0
4189 * http://jqueryui.com
4191 * Copyright jQuery Foundation and other contributors
4192 * Released under the MIT license.
4193 * http://jquery.org/license
4198 //>>description: Find all the labels associated with a given input
4199 //>>docs: http://api.jqueryui.com/labels/
4202 var labels = $.fn.labels = function() {
4203 var ancestor, selector, id, labels, ancestors;
4205 if ( !this.length ) {
4206 return this.pushStack( [] );
4209 // Check control.labels first
4210 if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
4211 return this.pushStack( this[ 0 ].labels );
4214 // Support: IE <= 11, FF <= 37, Android <= 2.3 only
4215 // Above browsers do not support control.labels. Everything below is to support them
4216 // as well as document fragments. control.labels does not work on document fragments
4217 labels = this.eq( 0 ).parents( "label" );
4219 // Look for the label based on the id
4220 id = this.attr( "id" );
4223 // We don't search against the document in case the element
4224 // is disconnected from the DOM
4225 ancestor = this.eq( 0 ).parents().last();
4227 // Get a full set of top level ancestors
4228 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
4230 // Create a selector for the label based on the id
4231 selector = "label[for='" + $.escapeSelector( id ) + "']";
4233 labels = labels.add( ancestors.find( selector ).addBack( selector ) );
4237 // Return whatever we have found for labels
4238 return this.pushStack( labels );
4243 * jQuery UI Scroll Parent 1.13.0
4244 * http://jqueryui.com
4246 * Copyright jQuery Foundation and other contributors
4247 * Released under the MIT license.
4248 * http://jquery.org/license
4251 //>>label: scrollParent
4253 //>>description: Get the closest ancestor element that is scrollable.
4254 //>>docs: http://api.jqueryui.com/scrollParent/
4257 var scrollParent = $.fn.scrollParent = function( includeHidden ) {
4258 var position = this.css( "position" ),
4259 excludeStaticParent = position === "absolute",
4260 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
4261 scrollParent = this.parents().filter( function() {
4262 var parent = $( this );
4263 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
4266 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
4267 parent.css( "overflow-x" ) );
4270 return position === "fixed" || !scrollParent.length ?
4271 $( this[ 0 ].ownerDocument || document ) :
4277 * jQuery UI Tabbable 1.13.0
4278 * http://jqueryui.com
4280 * Copyright jQuery Foundation and other contributors
4281 * Released under the MIT license.
4282 * http://jquery.org/license
4285 //>>label: :tabbable Selector
4287 //>>description: Selects elements which can be tabbed to.
4288 //>>docs: http://api.jqueryui.com/tabbable-selector/
4291 var tabbable = $.extend( $.expr.pseudos, {
4292 tabbable: function( element ) {
4293 var tabIndex = $.attr( element, "tabindex" ),
4294 hasTabindex = tabIndex != null;
4295 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
4301 * jQuery UI Unique ID 1.13.0
4302 * http://jqueryui.com
4304 * Copyright jQuery Foundation and other contributors
4305 * Released under the MIT license.
4306 * http://jquery.org/license
4311 //>>description: Functions to generate and remove uniqueId's
4312 //>>docs: http://api.jqueryui.com/uniqueId/
4315 var uniqueId = $.fn.extend( {
4316 uniqueId: ( function() {
4320 return this.each( function() {
4322 this.id = "ui-id-" + ( ++uuid );
4328 removeUniqueId: function() {
4329 return this.each( function() {
4330 if ( /^ui-id-\d+$/.test( this.id ) ) {
4331 $( this ).removeAttr( "id" );
4339 * jQuery UI Accordion 1.13.0
4340 * http://jqueryui.com
4342 * Copyright jQuery Foundation and other contributors
4343 * Released under the MIT license.
4344 * http://jquery.org/license
4347 //>>label: Accordion
4349 /* eslint-disable max-len */
4350 //>>description: Displays collapsible content panels for presenting information in a limited amount of space.
4351 /* eslint-enable max-len */
4352 //>>docs: http://api.jqueryui.com/accordion/
4353 //>>demos: http://jqueryui.com/accordion/
4354 //>>css.structure: ../../themes/base/core.css
4355 //>>css.structure: ../../themes/base/accordion.css
4356 //>>css.theme: ../../themes/base/theme.css
4359 var widgetsAccordion = $.widget( "ui.accordion", {
4365 "ui-accordion-header": "ui-corner-top",
4366 "ui-accordion-header-collapsed": "ui-corner-all",
4367 "ui-accordion-content": "ui-corner-bottom"
4371 header: function( elem ) {
4372 return elem.find( "> li > :first-child" ).add( elem.find( "> :not(li)" ).even() );
4374 heightStyle: "auto",
4376 activeHeader: "ui-icon-triangle-1-s",
4377 header: "ui-icon-triangle-1-e"
4382 beforeActivate: null
4386 borderTopWidth: "hide",
4387 borderBottomWidth: "hide",
4389 paddingBottom: "hide",
4394 borderTopWidth: "show",
4395 borderBottomWidth: "show",
4397 paddingBottom: "show",
4401 _create: function() {
4402 var options = this.options;
4404 this.prevShow = this.prevHide = $();
4405 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
4406 this.element.attr( "role", "tablist" );
4408 // Don't allow collapsible: false and active: false / null
4409 if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
4413 this._processPanels();
4415 // handle negative values
4416 if ( options.active < 0 ) {
4417 options.active += this.headers.length;
4422 _getCreateEventData: function() {
4424 header: this.active,
4425 panel: !this.active.length ? $() : this.active.next()
4429 _createIcons: function() {
4431 icons = this.options.icons;
4434 icon = $( "<span>" );
4435 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
4436 icon.prependTo( this.headers );
4437 children = this.active.children( ".ui-accordion-header-icon" );
4438 this._removeClass( children, icons.header )
4439 ._addClass( children, null, icons.activeHeader )
4440 ._addClass( this.headers, "ui-accordion-icons" );
4444 _destroyIcons: function() {
4445 this._removeClass( this.headers, "ui-accordion-icons" );
4446 this.headers.children( ".ui-accordion-header-icon" ).remove();
4449 _destroy: function() {
4452 // Clean up main element
4453 this.element.removeAttr( "role" );
4457 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
4460 this._destroyIcons();
4462 // Clean up content panels
4463 contents = this.headers.next()
4464 .css( "display", "" )
4465 .removeAttr( "role aria-hidden aria-labelledby" )
4468 if ( this.options.heightStyle !== "content" ) {
4469 contents.css( "height", "" );
4473 _setOption: function( key, value ) {
4474 if ( key === "active" ) {
4476 // _activate() will handle invalid values and update this.options
4477 this._activate( value );
4481 if ( key === "event" ) {
4482 if ( this.options.event ) {
4483 this._off( this.headers, this.options.event );
4485 this._setupEvents( value );
4488 this._super( key, value );
4490 // Setting collapsible: false while collapsed; open first panel
4491 if ( key === "collapsible" && !value && this.options.active === false ) {
4492 this._activate( 0 );
4495 if ( key === "icons" ) {
4496 this._destroyIcons();
4498 this._createIcons();
4503 _setOptionDisabled: function( value ) {
4504 this._super( value );
4506 this.element.attr( "aria-disabled", value );
4508 // Support: IE8 Only
4509 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
4510 // so we need to add the disabled class to the headers and panels
4511 this._toggleClass( null, "ui-state-disabled", !!value );
4512 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
4516 _keydown: function( event ) {
4517 if ( event.altKey || event.ctrlKey ) {
4521 var keyCode = $.ui.keyCode,
4522 length = this.headers.length,
4523 currentIndex = this.headers.index( event.target ),
4526 switch ( event.keyCode ) {
4529 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4533 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4537 this._eventHandler( event );
4540 toFocus = this.headers[ 0 ];
4543 toFocus = this.headers[ length - 1 ];
4548 $( event.target ).attr( "tabIndex", -1 );
4549 $( toFocus ).attr( "tabIndex", 0 );
4550 $( toFocus ).trigger( "focus" );
4551 event.preventDefault();
4555 _panelKeyDown: function( event ) {
4556 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
4557 $( event.currentTarget ).prev().trigger( "focus" );
4561 refresh: function() {
4562 var options = this.options;
4563 this._processPanels();
4565 // Was collapsed or no panel
4566 if ( ( options.active === false && options.collapsible === true ) ||
4567 !this.headers.length ) {
4568 options.active = false;
4571 // active false only when collapsible is true
4572 } else if ( options.active === false ) {
4573 this._activate( 0 );
4575 // was active, but active panel is gone
4576 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
4578 // all remaining panel are disabled
4579 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
4580 options.active = false;
4583 // activate previous panel
4585 this._activate( Math.max( 0, options.active - 1 ) );
4588 // was active, active panel still exists
4591 // make sure active index is correct
4592 options.active = this.headers.index( this.active );
4595 this._destroyIcons();
4600 _processPanels: function() {
4601 var prevHeaders = this.headers,
4602 prevPanels = this.panels;
4604 if ( typeof this.options.header === "function" ) {
4605 this.headers = this.options.header( this.element );
4607 this.headers = this.element.find( this.options.header );
4609 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
4610 "ui-state-default" );
4612 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
4613 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
4615 // Avoid memory leaks (#10056)
4617 this._off( prevHeaders.not( this.headers ) );
4618 this._off( prevPanels.not( this.panels ) );
4622 _refresh: function() {
4624 options = this.options,
4625 heightStyle = options.heightStyle,
4626 parent = this.element.parent();
4628 this.active = this._findActive( options.active );
4629 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
4630 ._removeClass( this.active, "ui-accordion-header-collapsed" );
4631 this._addClass( this.active.next(), "ui-accordion-content-active" );
4632 this.active.next().show();
4635 .attr( "role", "tab" )
4637 var header = $( this ),
4638 headerId = header.uniqueId().attr( "id" ),
4639 panel = header.next(),
4640 panelId = panel.uniqueId().attr( "id" );
4641 header.attr( "aria-controls", panelId );
4642 panel.attr( "aria-labelledby", headerId );
4645 .attr( "role", "tabpanel" );
4650 "aria-selected": "false",
4651 "aria-expanded": "false",
4656 "aria-hidden": "true"
4660 // Make sure at least one header is in the tab order
4661 if ( !this.active.length ) {
4662 this.headers.eq( 0 ).attr( "tabIndex", 0 );
4665 "aria-selected": "true",
4666 "aria-expanded": "true",
4671 "aria-hidden": "false"
4675 this._createIcons();
4677 this._setupEvents( options.event );
4679 if ( heightStyle === "fill" ) {
4680 maxHeight = parent.height();
4681 this.element.siblings( ":visible" ).each( function() {
4682 var elem = $( this ),
4683 position = elem.css( "position" );
4685 if ( position === "absolute" || position === "fixed" ) {
4688 maxHeight -= elem.outerHeight( true );
4691 this.headers.each( function() {
4692 maxHeight -= $( this ).outerHeight( true );
4697 $( this ).height( Math.max( 0, maxHeight -
4698 $( this ).innerHeight() + $( this ).height() ) );
4700 .css( "overflow", "auto" );
4701 } else if ( heightStyle === "auto" ) {
4705 var isVisible = $( this ).is( ":visible" );
4709 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
4714 .height( maxHeight );
4718 _activate: function( index ) {
4719 var active = this._findActive( index )[ 0 ];
4721 // Trying to activate the already active panel
4722 if ( active === this.active[ 0 ] ) {
4726 // Trying to collapse, simulate a click on the currently active header
4727 active = active || this.active[ 0 ];
4729 this._eventHandler( {
4731 currentTarget: active,
4732 preventDefault: $.noop
4736 _findActive: function( selector ) {
4737 return typeof selector === "number" ? this.headers.eq( selector ) : $();
4740 _setupEvents: function( event ) {
4745 $.each( event.split( " " ), function( index, eventName ) {
4746 events[ eventName ] = "_eventHandler";
4750 this._off( this.headers.add( this.headers.next() ) );
4751 this._on( this.headers, events );
4752 this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
4753 this._hoverable( this.headers );
4754 this._focusable( this.headers );
4757 _eventHandler: function( event ) {
4758 var activeChildren, clickedChildren,
4759 options = this.options,
4760 active = this.active,
4761 clicked = $( event.currentTarget ),
4762 clickedIsActive = clicked[ 0 ] === active[ 0 ],
4763 collapsing = clickedIsActive && options.collapsible,
4764 toShow = collapsing ? $() : clicked.next(),
4765 toHide = active.next(),
4769 newHeader: collapsing ? $() : clicked,
4773 event.preventDefault();
4777 // click on active header, but not collapsible
4778 ( clickedIsActive && !options.collapsible ) ||
4780 // allow canceling activation
4781 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
4785 options.active = collapsing ? false : this.headers.index( clicked );
4787 // When the call to ._toggle() comes after the class changes
4788 // it causes a very odd bug in IE 8 (see #6720)
4789 this.active = clickedIsActive ? $() : clicked;
4790 this._toggle( eventData );
4793 // corner classes on the previously active header stay after the animation
4794 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
4795 if ( options.icons ) {
4796 activeChildren = active.children( ".ui-accordion-header-icon" );
4797 this._removeClass( activeChildren, null, options.icons.activeHeader )
4798 ._addClass( activeChildren, null, options.icons.header );
4801 if ( !clickedIsActive ) {
4802 this._removeClass( clicked, "ui-accordion-header-collapsed" )
4803 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
4804 if ( options.icons ) {
4805 clickedChildren = clicked.children( ".ui-accordion-header-icon" );
4806 this._removeClass( clickedChildren, null, options.icons.header )
4807 ._addClass( clickedChildren, null, options.icons.activeHeader );
4810 this._addClass( clicked.next(), "ui-accordion-content-active" );
4814 _toggle: function( data ) {
4815 var toShow = data.newPanel,
4816 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
4818 // Handle activating a panel during the animation for another activation
4819 this.prevShow.add( this.prevHide ).stop( true, true );
4820 this.prevShow = toShow;
4821 this.prevHide = toHide;
4823 if ( this.options.animate ) {
4824 this._animate( toShow, toHide, data );
4828 this._toggleComplete( data );
4832 "aria-hidden": "true"
4834 toHide.prev().attr( {
4835 "aria-selected": "false",
4836 "aria-expanded": "false"
4839 // if we're switching panels, remove the old header from the tab order
4840 // if we're opening from collapsed state, remove the previous header from the tab order
4841 // if we're collapsing, then keep the collapsing header in the tab order
4842 if ( toShow.length && toHide.length ) {
4843 toHide.prev().attr( {
4845 "aria-expanded": "false"
4847 } else if ( toShow.length ) {
4848 this.headers.filter( function() {
4849 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
4851 .attr( "tabIndex", -1 );
4855 .attr( "aria-hidden", "false" )
4858 "aria-selected": "true",
4859 "aria-expanded": "true",
4864 _animate: function( toShow, toHide, data ) {
4865 var total, easing, duration,
4868 boxSizing = toShow.css( "box-sizing" ),
4869 down = toShow.length &&
4870 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
4871 animate = this.options.animate || {},
4872 options = down && animate.down || animate,
4873 complete = function() {
4874 that._toggleComplete( data );
4877 if ( typeof options === "number" ) {
4880 if ( typeof options === "string" ) {
4884 // fall back from options to animation in case of partial down settings
4885 easing = easing || options.easing || animate.easing;
4886 duration = duration || options.duration || animate.duration;
4888 if ( !toHide.length ) {
4889 return toShow.animate( this.showProps, duration, easing, complete );
4891 if ( !toShow.length ) {
4892 return toHide.animate( this.hideProps, duration, easing, complete );
4895 total = toShow.show().outerHeight();
4896 toHide.animate( this.hideProps, {
4899 step: function( now, fx ) {
4900 fx.now = Math.round( now );
4905 .animate( this.showProps, {
4909 step: function( now, fx ) {
4910 fx.now = Math.round( now );
4911 if ( fx.prop !== "height" ) {
4912 if ( boxSizing === "content-box" ) {
4915 } else if ( that.options.heightStyle !== "content" ) {
4916 fx.now = Math.round( total - toHide.outerHeight() - adjust );
4923 _toggleComplete: function( data ) {
4924 var toHide = data.oldPanel,
4925 prev = toHide.prev();
4927 this._removeClass( toHide, "ui-accordion-content-active" );
4928 this._removeClass( prev, "ui-accordion-header-active" )
4929 ._addClass( prev, "ui-accordion-header-collapsed" );
4931 // Work around for rendering bug in IE (#5421)
4932 if ( toHide.length ) {
4933 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
4935 this._trigger( "activate", null, data );
4941 var safeActiveElement = $.ui.safeActiveElement = function( document ) {
4944 // Support: IE 9 only
4945 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
4947 activeElement = document.activeElement;
4949 activeElement = document.body;
4952 // Support: IE 9 - 11 only
4953 // IE may return null instead of an element
4954 // Interestingly, this only seems to occur when NOT in an iframe
4955 if ( !activeElement ) {
4956 activeElement = document.body;
4959 // Support: IE 11 only
4960 // IE11 returns a seemingly empty object in some cases when accessing
4961 // document.activeElement from an <iframe>
4962 if ( !activeElement.nodeName ) {
4963 activeElement = document.body;
4966 return activeElement;
4971 * jQuery UI Menu 1.13.0
4972 * http://jqueryui.com
4974 * Copyright jQuery Foundation and other contributors
4975 * Released under the MIT license.
4976 * http://jquery.org/license
4981 //>>description: Creates nestable menus.
4982 //>>docs: http://api.jqueryui.com/menu/
4983 //>>demos: http://jqueryui.com/menu/
4984 //>>css.structure: ../../themes/base/core.css
4985 //>>css.structure: ../../themes/base/menu.css
4986 //>>css.theme: ../../themes/base/theme.css
4989 var widgetsMenu = $.widget( "ui.menu", {
4991 defaultElement: "<ul>",
4995 submenu: "ui-icon-caret-1-e"
5011 _create: function() {
5012 this.activeMenu = this.element;
5014 // Flag used to prevent firing of the click handler
5015 // as the event bubbles up through nested menus
5016 this.mouseHandled = false;
5017 this.lastMousePosition = { x: null, y: null };
5021 role: this.options.role,
5025 this._addClass( "ui-menu", "ui-widget ui-widget-content" );
5028 // Prevent focus from sticking to links inside menu after clicking
5029 // them (focus should always stay on UL during navigation).
5030 "mousedown .ui-menu-item": function( event ) {
5031 event.preventDefault();
5033 this._activateItem( event );
5035 "click .ui-menu-item": function( event ) {
5036 var target = $( event.target );
5037 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
5038 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
5039 this.select( event );
5041 // Only set the mouseHandled flag if the event will bubble, see #9469.
5042 if ( !event.isPropagationStopped() ) {
5043 this.mouseHandled = true;
5046 // Open submenu on click
5047 if ( target.has( ".ui-menu" ).length ) {
5048 this.expand( event );
5049 } else if ( !this.element.is( ":focus" ) &&
5050 active.closest( ".ui-menu" ).length ) {
5052 // Redirect focus to the menu
5053 this.element.trigger( "focus", [ true ] );
5055 // If the active item is on the top level, let it stay active.
5056 // Otherwise, blur the active item since it is no longer visible.
5057 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
5058 clearTimeout( this.timer );
5063 "mouseenter .ui-menu-item": "_activateItem",
5064 "mousemove .ui-menu-item": "_activateItem",
5065 mouseleave: "collapseAll",
5066 "mouseleave .ui-menu": "collapseAll",
5067 focus: function( event, keepActiveItem ) {
5069 // If there's already an active item, keep it active
5070 // If not, activate the first item
5071 var item = this.active || this._menuItems().first();
5073 if ( !keepActiveItem ) {
5074 this.focus( event, item );
5077 blur: function( event ) {
5078 this._delay( function() {
5079 var notContained = !$.contains(
5081 $.ui.safeActiveElement( this.document[ 0 ] )
5083 if ( notContained ) {
5084 this.collapseAll( event );
5093 // Clicks outside of a menu collapse any open menus
5094 this._on( this.document, {
5095 click: function( event ) {
5096 if ( this._closeOnDocumentClick( event ) ) {
5097 this.collapseAll( event, true );
5100 // Reset the mouseHandled flag
5101 this.mouseHandled = false;
5106 _activateItem: function( event ) {
5108 // Ignore mouse events while typeahead is active, see #10458.
5109 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
5110 // is over an item in the menu
5111 if ( this.previousFilter ) {
5115 // If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356)
5116 if ( event.clientX === this.lastMousePosition.x &&
5117 event.clientY === this.lastMousePosition.y ) {
5121 this.lastMousePosition = {
5126 var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
5127 target = $( event.currentTarget );
5129 // Ignore bubbled events on parent items, see #11641
5130 if ( actualTarget[ 0 ] !== target[ 0 ] ) {
5134 // If the item is already active, there's nothing to do
5135 if ( target.is( ".ui-state-active" ) ) {
5139 // Remove ui-state-active class from siblings of the newly focused menu item
5140 // to avoid a jump caused by adjacent elements both having a class with a border
5141 this._removeClass( target.siblings().children( ".ui-state-active" ),
5142 null, "ui-state-active" );
5143 this.focus( event, target );
5146 _destroy: function() {
5147 var items = this.element.find( ".ui-menu-item" )
5148 .removeAttr( "role aria-disabled" ),
5149 submenus = items.children( ".ui-menu-item-wrapper" )
5151 .removeAttr( "tabIndex role aria-haspopup" );
5153 // Destroy (sub)menus
5155 .removeAttr( "aria-activedescendant" )
5156 .find( ".ui-menu" ).addBack()
5157 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
5162 submenus.children().each( function() {
5163 var elem = $( this );
5164 if ( elem.data( "ui-menu-submenu-caret" ) ) {
5170 _keydown: function( event ) {
5171 var match, prev, character, skip,
5172 preventDefault = true;
5174 switch ( event.keyCode ) {
5175 case $.ui.keyCode.PAGE_UP:
5176 this.previousPage( event );
5178 case $.ui.keyCode.PAGE_DOWN:
5179 this.nextPage( event );
5181 case $.ui.keyCode.HOME:
5182 this._move( "first", "first", event );
5184 case $.ui.keyCode.END:
5185 this._move( "last", "last", event );
5187 case $.ui.keyCode.UP:
5188 this.previous( event );
5190 case $.ui.keyCode.DOWN:
5193 case $.ui.keyCode.LEFT:
5194 this.collapse( event );
5196 case $.ui.keyCode.RIGHT:
5197 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5198 this.expand( event );
5201 case $.ui.keyCode.ENTER:
5202 case $.ui.keyCode.SPACE:
5203 this._activate( event );
5205 case $.ui.keyCode.ESCAPE:
5206 this.collapse( event );
5209 preventDefault = false;
5210 prev = this.previousFilter || "";
5213 // Support number pad values
5214 character = event.keyCode >= 96 && event.keyCode <= 105 ?
5215 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
5217 clearTimeout( this.filterTimer );
5219 if ( character === prev ) {
5222 character = prev + character;
5225 match = this._filterMenuItems( character );
5226 match = skip && match.index( this.active.next() ) !== -1 ?
5227 this.active.nextAll( ".ui-menu-item" ) :
5230 // If no matches on the current filter, reset to the last character pressed
5231 // to move down the menu to the first item that starts with that character
5232 if ( !match.length ) {
5233 character = String.fromCharCode( event.keyCode );
5234 match = this._filterMenuItems( character );
5237 if ( match.length ) {
5238 this.focus( event, match );
5239 this.previousFilter = character;
5240 this.filterTimer = this._delay( function() {
5241 delete this.previousFilter;
5244 delete this.previousFilter;
5248 if ( preventDefault ) {
5249 event.preventDefault();
5253 _activate: function( event ) {
5254 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5255 if ( this.active.children( "[aria-haspopup='true']" ).length ) {
5256 this.expand( event );
5258 this.select( event );
5263 refresh: function() {
5264 var menus, items, newSubmenus, newItems, newWrappers,
5266 icon = this.options.icons.submenu,
5267 submenus = this.element.find( this.options.menus );
5269 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
5271 // Initialize nested menus
5272 newSubmenus = submenus.filter( ":not(.ui-menu)" )
5275 role: this.options.role,
5276 "aria-hidden": "true",
5277 "aria-expanded": "false"
5280 var menu = $( this ),
5282 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
5284 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
5286 .attr( "aria-haspopup", "true" )
5287 .prepend( submenuCaret );
5288 menu.attr( "aria-labelledby", item.attr( "id" ) );
5291 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
5293 menus = submenus.add( this.element );
5294 items = menus.find( this.options.items );
5296 // Initialize menu-items containing spaces and/or dashes only as dividers
5297 items.not( ".ui-menu-item" ).each( function() {
5298 var item = $( this );
5299 if ( that._isDivider( item ) ) {
5300 that._addClass( item, "ui-menu-divider", "ui-widget-content" );
5304 // Don't refresh list items that are already adapted
5305 newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
5306 newWrappers = newItems.children()
5311 role: this._itemRole()
5313 this._addClass( newItems, "ui-menu-item" )
5314 ._addClass( newWrappers, "ui-menu-item-wrapper" );
5316 // Add aria-disabled attribute to any disabled menu item
5317 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
5319 // If the active item has been removed, blur the menu
5320 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
5325 _itemRole: function() {
5329 }[ this.options.role ];
5332 _setOption: function( key, value ) {
5333 if ( key === "icons" ) {
5334 var icons = this.element.find( ".ui-menu-icon" );
5335 this._removeClass( icons, null, this.options.icons.submenu )
5336 ._addClass( icons, null, value.submenu );
5338 this._super( key, value );
5341 _setOptionDisabled: function( value ) {
5342 this._super( value );
5344 this.element.attr( "aria-disabled", String( value ) );
5345 this._toggleClass( null, "ui-state-disabled", !!value );
5348 focus: function( event, item ) {
5349 var nested, focused, activeParent;
5350 this.blur( event, event && event.type === "focus" );
5352 this._scrollIntoView( item );
5354 this.active = item.first();
5356 focused = this.active.children( ".ui-menu-item-wrapper" );
5357 this._addClass( focused, null, "ui-state-active" );
5359 // Only update aria-activedescendant if there's a role
5360 // otherwise we assume focus is managed elsewhere
5361 if ( this.options.role ) {
5362 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
5365 // Highlight active parent menu item, if any
5366 activeParent = this.active
5368 .closest( ".ui-menu-item" )
5369 .children( ".ui-menu-item-wrapper" );
5370 this._addClass( activeParent, null, "ui-state-active" );
5372 if ( event && event.type === "keydown" ) {
5375 this.timer = this._delay( function() {
5380 nested = item.children( ".ui-menu" );
5381 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
5382 this._startOpening( nested );
5384 this.activeMenu = item.parent();
5386 this._trigger( "focus", event, { item: item } );
5389 _scrollIntoView: function( item ) {
5390 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
5391 if ( this._hasScroll() ) {
5392 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
5393 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
5394 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
5395 scroll = this.activeMenu.scrollTop();
5396 elementHeight = this.activeMenu.height();
5397 itemHeight = item.outerHeight();
5400 this.activeMenu.scrollTop( scroll + offset );
5401 } else if ( offset + itemHeight > elementHeight ) {
5402 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
5407 blur: function( event, fromFocus ) {
5409 clearTimeout( this.timer );
5412 if ( !this.active ) {
5416 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
5417 null, "ui-state-active" );
5419 this._trigger( "blur", event, { item: this.active } );
5423 _startOpening: function( submenu ) {
5424 clearTimeout( this.timer );
5426 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
5427 // shift in the submenu position when mousing over the caret icon
5428 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
5432 this.timer = this._delay( function() {
5434 this._open( submenu );
5438 _open: function( submenu ) {
5439 var position = $.extend( {
5441 }, this.options.position );
5443 clearTimeout( this.timer );
5444 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
5446 .attr( "aria-hidden", "true" );
5450 .removeAttr( "aria-hidden" )
5451 .attr( "aria-expanded", "true" )
5452 .position( position );
5455 collapseAll: function( event, all ) {
5456 clearTimeout( this.timer );
5457 this.timer = this._delay( function() {
5459 // If we were passed an event, look for the submenu that contains the event
5460 var currentMenu = all ? this.element :
5461 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
5463 // If we found no valid submenu ancestor, use the main menu to close all
5465 if ( !currentMenu.length ) {
5466 currentMenu = this.element;
5469 this._close( currentMenu );
5473 // Work around active item staying active after menu is blurred
5474 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
5476 this.activeMenu = currentMenu;
5477 }, all ? 0 : this.delay );
5480 // With no arguments, closes the currently active menu - if nothing is active
5481 // it closes all menus. If passed an argument, it will search for menus BELOW
5482 _close: function( startMenu ) {
5484 startMenu = this.active ? this.active.parent() : this.element;
5487 startMenu.find( ".ui-menu" )
5489 .attr( "aria-hidden", "true" )
5490 .attr( "aria-expanded", "false" );
5493 _closeOnDocumentClick: function( event ) {
5494 return !$( event.target ).closest( ".ui-menu" ).length;
5497 _isDivider: function( item ) {
5499 // Match hyphen, em dash, en dash
5500 return !/[^\-\u2014\u2013\s]/.test( item.text() );
5503 collapse: function( event ) {
5504 var newItem = this.active &&
5505 this.active.parent().closest( ".ui-menu-item", this.element );
5506 if ( newItem && newItem.length ) {
5508 this.focus( event, newItem );
5512 expand: function( event ) {
5513 var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first();
5515 if ( newItem && newItem.length ) {
5516 this._open( newItem.parent() );
5518 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
5519 this._delay( function() {
5520 this.focus( event, newItem );
5525 next: function( event ) {
5526 this._move( "next", "first", event );
5529 previous: function( event ) {
5530 this._move( "prev", "last", event );
5533 isFirstItem: function() {
5534 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
5537 isLastItem: function() {
5538 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
5541 _menuItems: function( menu ) {
5542 return ( menu || this.element )
5543 .find( this.options.items )
5544 .filter( ".ui-menu-item" );
5547 _move: function( direction, filter, event ) {
5549 if ( this.active ) {
5550 if ( direction === "first" || direction === "last" ) {
5552 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
5556 [ direction + "All" ]( ".ui-menu-item" )
5560 if ( !next || !next.length || !this.active ) {
5561 next = this._menuItems( this.activeMenu )[ filter ]();
5564 this.focus( event, next );
5567 nextPage: function( event ) {
5568 var item, base, height;
5570 if ( !this.active ) {
5574 if ( this.isLastItem() ) {
5577 if ( this._hasScroll() ) {
5578 base = this.active.offset().top;
5579 height = this.element.innerHeight();
5581 // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
5582 if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
5583 height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
5586 this.active.nextAll( ".ui-menu-item" ).each( function() {
5588 return item.offset().top - base - height < 0;
5591 this.focus( event, item );
5593 this.focus( event, this._menuItems( this.activeMenu )
5594 [ !this.active ? "first" : "last" ]() );
5598 previousPage: function( event ) {
5599 var item, base, height;
5600 if ( !this.active ) {
5604 if ( this.isFirstItem() ) {
5607 if ( this._hasScroll() ) {
5608 base = this.active.offset().top;
5609 height = this.element.innerHeight();
5611 // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
5612 if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
5613 height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
5616 this.active.prevAll( ".ui-menu-item" ).each( function() {
5618 return item.offset().top - base + height > 0;
5621 this.focus( event, item );
5623 this.focus( event, this._menuItems( this.activeMenu ).first() );
5627 _hasScroll: function() {
5628 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
5631 select: function( event ) {
5633 // TODO: It should never be possible to not have an active item at this
5634 // point, but the tests don't trigger mouseenter before click.
5635 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
5636 var ui = { item: this.active };
5637 if ( !this.active.has( ".ui-menu" ).length ) {
5638 this.collapseAll( event, true );
5640 this._trigger( "select", event, ui );
5643 _filterMenuItems: function( character ) {
5644 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
5645 regex = new RegExp( "^" + escapedCharacter, "i" );
5647 return this.activeMenu
5648 .find( this.options.items )
5650 // Only match on items, not dividers or other content (#10571)
5651 .filter( ".ui-menu-item" )
5652 .filter( function() {
5654 String.prototype.trim.call(
5655 $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
5662 * jQuery UI Autocomplete 1.13.0
5663 * http://jqueryui.com
5665 * Copyright jQuery Foundation and other contributors
5666 * Released under the MIT license.
5667 * http://jquery.org/license
5670 //>>label: Autocomplete
5672 //>>description: Lists suggested words as the user is typing.
5673 //>>docs: http://api.jqueryui.com/autocomplete/
5674 //>>demos: http://jqueryui.com/autocomplete/
5675 //>>css.structure: ../../themes/base/core.css
5676 //>>css.structure: ../../themes/base/autocomplete.css
5677 //>>css.theme: ../../themes/base/theme.css
5680 $.widget( "ui.autocomplete", {
5682 defaultElement: "<input>",
5708 _create: function() {
5710 // Some browsers only repeat keydown events, not keypress events,
5711 // so we use the suppressKeyPress flag to determine if we've already
5712 // handled the keydown event. #7269
5713 // Unfortunately the code for & in keypress is the same as the up arrow,
5714 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
5715 // events when we know the keydown event was used to modify the
5716 // search term. #7799
5717 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
5718 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
5719 isTextarea = nodeName === "textarea",
5720 isInput = nodeName === "input";
5722 // Textareas are always multi-line
5723 // Inputs are always single-line, even if inside a contentEditable element
5724 // IE also treats inputs as contentEditable
5725 // All other element types are determined by whether or not they're contentEditable
5726 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
5728 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
5729 this.isNewMenu = true;
5731 this._addClass( "ui-autocomplete-input" );
5732 this.element.attr( "autocomplete", "off" );
5734 this._on( this.element, {
5735 keydown: function( event ) {
5736 if ( this.element.prop( "readOnly" ) ) {
5737 suppressKeyPress = true;
5738 suppressInput = true;
5739 suppressKeyPressRepeat = true;
5743 suppressKeyPress = false;
5744 suppressInput = false;
5745 suppressKeyPressRepeat = false;
5746 var keyCode = $.ui.keyCode;
5747 switch ( event.keyCode ) {
5748 case keyCode.PAGE_UP:
5749 suppressKeyPress = true;
5750 this._move( "previousPage", event );
5752 case keyCode.PAGE_DOWN:
5753 suppressKeyPress = true;
5754 this._move( "nextPage", event );
5757 suppressKeyPress = true;
5758 this._keyEvent( "previous", event );
5761 suppressKeyPress = true;
5762 this._keyEvent( "next", event );
5766 // when menu is open and has focus
5767 if ( this.menu.active ) {
5769 // #6055 - Opera still allows the keypress to occur
5770 // which causes forms to submit
5771 suppressKeyPress = true;
5772 event.preventDefault();
5773 this.menu.select( event );
5777 if ( this.menu.active ) {
5778 this.menu.select( event );
5781 case keyCode.ESCAPE:
5782 if ( this.menu.element.is( ":visible" ) ) {
5783 if ( !this.isMultiLine ) {
5784 this._value( this.term );
5786 this.close( event );
5788 // Different browsers have different default behavior for escape
5789 // Single press can mean undo or clear
5790 // Double press in IE means clear the whole form
5791 event.preventDefault();
5795 suppressKeyPressRepeat = true;
5797 // search timeout should be triggered before the input value is changed
5798 this._searchTimeout( event );
5802 keypress: function( event ) {
5803 if ( suppressKeyPress ) {
5804 suppressKeyPress = false;
5805 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5806 event.preventDefault();
5810 if ( suppressKeyPressRepeat ) {
5814 // Replicate some key handlers to allow them to repeat in Firefox and Opera
5815 var keyCode = $.ui.keyCode;
5816 switch ( event.keyCode ) {
5817 case keyCode.PAGE_UP:
5818 this._move( "previousPage", event );
5820 case keyCode.PAGE_DOWN:
5821 this._move( "nextPage", event );
5824 this._keyEvent( "previous", event );
5827 this._keyEvent( "next", event );
5831 input: function( event ) {
5832 if ( suppressInput ) {
5833 suppressInput = false;
5834 event.preventDefault();
5837 this._searchTimeout( event );
5840 this.selectedItem = null;
5841 this.previous = this._value();
5843 blur: function( event ) {
5844 clearTimeout( this.searching );
5845 this.close( event );
5846 this._change( event );
5851 this.menu = $( "<ul>" )
5852 .appendTo( this._appendTo() )
5855 // disable ARIA support, the live region takes care of that
5860 // Support: IE 11 only, Edge <= 14
5861 // For other browsers, we preventDefault() on the mousedown event
5862 // to keep the dropdown from taking focus from the input. This doesn't
5863 // work for IE/Edge, causing problems with selection and scrolling (#9638)
5864 // Happily, IE and Edge support an "unselectable" attribute that
5865 // prevents an element from receiving focus, exactly what we want here.
5867 "unselectable": "on"
5869 .menu( "instance" );
5871 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
5872 this._on( this.menu.element, {
5873 mousedown: function( event ) {
5875 // Prevent moving focus out of the text field
5876 event.preventDefault();
5878 menufocus: function( event, ui ) {
5882 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
5883 if ( this.isNewMenu ) {
5884 this.isNewMenu = false;
5885 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5888 this.document.one( "mousemove", function() {
5889 $( event.target ).trigger( event.originalEvent );
5896 item = ui.item.data( "ui-autocomplete-item" );
5897 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5899 // use value to match what will end up in the input, if it was a key event
5900 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5901 this._value( item.value );
5905 // Announce the value in the liveRegion
5906 label = ui.item.attr( "aria-label" ) || item.value;
5907 if ( label && String.prototype.trim.call( label ).length ) {
5908 this.liveRegion.children().hide();
5909 $( "<div>" ).text( label ).appendTo( this.liveRegion );
5912 menuselect: function( event, ui ) {
5913 var item = ui.item.data( "ui-autocomplete-item" ),
5914 previous = this.previous;
5916 // Only trigger when focus was lost (click on menu)
5917 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5918 this.element.trigger( "focus" );
5919 this.previous = previous;
5921 // #6109 - IE triggers two focus events and the second
5922 // is asynchronous, so we need to reset the previous
5923 // term synchronously and asynchronously :-(
5924 this._delay( function() {
5925 this.previous = previous;
5926 this.selectedItem = item;
5930 if ( false !== this._trigger( "select", event, { item: item } ) ) {
5931 this._value( item.value );
5934 // reset the term after the select event
5935 // this allows custom select handling to work properly
5936 this.term = this._value();
5938 this.close( event );
5939 this.selectedItem = item;
5943 this.liveRegion = $( "<div>", {
5945 "aria-live": "assertive",
5946 "aria-relevant": "additions"
5948 .appendTo( this.document[ 0 ].body );
5950 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
5952 // Turning off autocomplete prevents the browser from remembering the
5953 // value when navigating through history, so we re-enable autocomplete
5954 // if the page is unloaded before the widget is destroyed. #7790
5955 this._on( this.window, {
5956 beforeunload: function() {
5957 this.element.removeAttr( "autocomplete" );
5962 _destroy: function() {
5963 clearTimeout( this.searching );
5964 this.element.removeAttr( "autocomplete" );
5965 this.menu.element.remove();
5966 this.liveRegion.remove();
5969 _setOption: function( key, value ) {
5970 this._super( key, value );
5971 if ( key === "source" ) {
5974 if ( key === "appendTo" ) {
5975 this.menu.element.appendTo( this._appendTo() );
5977 if ( key === "disabled" && value && this.xhr ) {
5982 _isEventTargetInWidget: function( event ) {
5983 var menuElement = this.menu.element[ 0 ];
5985 return event.target === this.element[ 0 ] ||
5986 event.target === menuElement ||
5987 $.contains( menuElement, event.target );
5990 _closeOnClickOutside: function( event ) {
5991 if ( !this._isEventTargetInWidget( event ) ) {
5996 _appendTo: function() {
5997 var element = this.options.appendTo;
6000 element = element.jquery || element.nodeType ?
6002 this.document.find( element ).eq( 0 );
6005 if ( !element || !element[ 0 ] ) {
6006 element = this.element.closest( ".ui-front, dialog" );
6009 if ( !element.length ) {
6010 element = this.document[ 0 ].body;
6016 _initSource: function() {
6019 if ( Array.isArray( this.options.source ) ) {
6020 array = this.options.source;
6021 this.source = function( request, response ) {
6022 response( $.ui.autocomplete.filter( array, request.term ) );
6024 } else if ( typeof this.options.source === "string" ) {
6025 url = this.options.source;
6026 this.source = function( request, response ) {
6030 that.xhr = $.ajax( {
6034 success: function( data ) {
6043 this.source = this.options.source;
6047 _searchTimeout: function( event ) {
6048 clearTimeout( this.searching );
6049 this.searching = this._delay( function() {
6051 // Search if the value has changed, or if the user retypes the same value (see #7434)
6052 var equalValues = this.term === this._value(),
6053 menuVisible = this.menu.element.is( ":visible" ),
6054 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
6056 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
6057 this.selectedItem = null;
6058 this.search( null, event );
6060 }, this.options.delay );
6063 search: function( value, event ) {
6064 value = value != null ? value : this._value();
6066 // Always save the actual value, not the one passed as an argument
6067 this.term = this._value();
6069 if ( value.length < this.options.minLength ) {
6070 return this.close( event );
6073 if ( this._trigger( "search", event ) === false ) {
6077 return this._search( value );
6080 _search: function( value ) {
6082 this._addClass( "ui-autocomplete-loading" );
6083 this.cancelSearch = false;
6085 this.source( { term: value }, this._response() );
6088 _response: function() {
6089 var index = ++this.requestIndex;
6091 return function( content ) {
6092 if ( index === this.requestIndex ) {
6093 this.__response( content );
6097 if ( !this.pending ) {
6098 this._removeClass( "ui-autocomplete-loading" );
6103 __response: function( content ) {
6105 content = this._normalize( content );
6107 this._trigger( "response", null, { content: content } );
6108 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6109 this._suggest( content );
6110 this._trigger( "open" );
6113 // use ._close() instead of .close() so we don't cancel future searches
6118 close: function( event ) {
6119 this.cancelSearch = true;
6120 this._close( event );
6123 _close: function( event ) {
6125 // Remove the handler that closes the menu on outside clicks
6126 this._off( this.document, "mousedown" );
6128 if ( this.menu.element.is( ":visible" ) ) {
6129 this.menu.element.hide();
6131 this.isNewMenu = true;
6132 this._trigger( "close", event );
6136 _change: function( event ) {
6137 if ( this.previous !== this._value() ) {
6138 this._trigger( "change", event, { item: this.selectedItem } );
6142 _normalize: function( items ) {
6144 // assume all items have the right format when the first item is complete
6145 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
6148 return $.map( items, function( item ) {
6149 if ( typeof item === "string" ) {
6155 return $.extend( {}, item, {
6156 label: item.label || item.value,
6157 value: item.value || item.label
6162 _suggest: function( items ) {
6163 var ul = this.menu.element.empty();
6164 this._renderMenu( ul, items );
6165 this.isNewMenu = true;
6166 this.menu.refresh();
6168 // Size and position menu
6171 ul.position( $.extend( {
6173 }, this.options.position ) );
6175 if ( this.options.autoFocus ) {
6179 // Listen for interactions outside of the widget (#6642)
6180 this._on( this.document, {
6181 mousedown: "_closeOnClickOutside"
6185 _resizeMenu: function() {
6186 var ul = this.menu.element;
6187 ul.outerWidth( Math.max(
6189 // Firefox wraps long text (possibly a rounding bug)
6190 // so we add 1px to avoid the wrapping (#7513)
6191 ul.width( "" ).outerWidth() + 1,
6192 this.element.outerWidth()
6196 _renderMenu: function( ul, items ) {
6198 $.each( items, function( index, item ) {
6199 that._renderItemData( ul, item );
6203 _renderItemData: function( ul, item ) {
6204 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
6207 _renderItem: function( ul, item ) {
6209 .append( $( "<div>" ).text( item.label ) )
6213 _move: function( direction, event ) {
6214 if ( !this.menu.element.is( ":visible" ) ) {
6215 this.search( null, event );
6218 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
6219 this.menu.isLastItem() && /^next/.test( direction ) ) {
6221 if ( !this.isMultiLine ) {
6222 this._value( this.term );
6228 this.menu[ direction ]( event );
6231 widget: function() {
6232 return this.menu.element;
6235 _value: function() {
6236 return this.valueMethod.apply( this.element, arguments );
6239 _keyEvent: function( keyEvent, event ) {
6240 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6241 this._move( keyEvent, event );
6243 // Prevents moving cursor to beginning/end of the text field in some browsers
6244 event.preventDefault();
6248 // Support: Chrome <=50
6249 // We should be able to just use this.element.prop( "isContentEditable" )
6250 // but hidden elements always report false in Chrome.
6251 // https://code.google.com/p/chromium/issues/detail?id=313082
6252 _isContentEditable: function( element ) {
6253 if ( !element.length ) {
6257 var editable = element.prop( "contentEditable" );
6259 if ( editable === "inherit" ) {
6260 return this._isContentEditable( element.parent() );
6263 return editable === "true";
6267 $.extend( $.ui.autocomplete, {
6268 escapeRegex: function( value ) {
6269 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
6271 filter: function( array, term ) {
6272 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
6273 return $.grep( array, function( value ) {
6274 return matcher.test( value.label || value.value || value );
6279 // Live region extension, adding a `messages` option
6280 // NOTE: This is an experimental API. We are still investigating
6281 // a full solution for string manipulation and internationalization.
6282 $.widget( "ui.autocomplete", $.ui.autocomplete, {
6285 noResults: "No search results.",
6286 results: function( amount ) {
6287 return amount + ( amount > 1 ? " results are" : " result is" ) +
6288 " available, use up and down arrow keys to navigate.";
6293 __response: function( content ) {
6295 this._superApply( arguments );
6296 if ( this.options.disabled || this.cancelSearch ) {
6299 if ( content && content.length ) {
6300 message = this.options.messages.results( content.length );
6302 message = this.options.messages.noResults;
6304 this.liveRegion.children().hide();
6305 $( "<div>" ).text( message ).appendTo( this.liveRegion );
6309 var widgetsAutocomplete = $.ui.autocomplete;
6313 * jQuery UI Controlgroup 1.13.0
6314 * http://jqueryui.com
6316 * Copyright jQuery Foundation and other contributors
6317 * Released under the MIT license.
6318 * http://jquery.org/license
6321 //>>label: Controlgroup
6323 //>>description: Visually groups form control widgets
6324 //>>docs: http://api.jqueryui.com/controlgroup/
6325 //>>demos: http://jqueryui.com/controlgroup/
6326 //>>css.structure: ../../themes/base/core.css
6327 //>>css.structure: ../../themes/base/controlgroup.css
6328 //>>css.theme: ../../themes/base/theme.css
6331 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
6333 var widgetsControlgroup = $.widget( "ui.controlgroup", {
6335 defaultElement: "<div>",
6337 direction: "horizontal",
6341 "button": "input[type=button], input[type=submit], input[type=reset], button, a",
6342 "controlgroupLabel": ".ui-controlgroup-label",
6343 "checkboxradio": "input[type='checkbox'], input[type='radio']",
6344 "selectmenu": "select",
6345 "spinner": ".ui-spinner-input"
6349 _create: function() {
6353 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
6354 _enhance: function() {
6355 this.element.attr( "role", "toolbar" );
6359 _destroy: function() {
6360 this._callChildMethod( "destroy" );
6361 this.childWidgets.removeData( "ui-controlgroup-data" );
6362 this.element.removeAttr( "role" );
6363 if ( this.options.items.controlgroupLabel ) {
6365 .find( this.options.items.controlgroupLabel )
6366 .find( ".ui-controlgroup-label-contents" )
6367 .contents().unwrap();
6371 _initWidgets: function() {
6375 // First we iterate over each of the items options
6376 $.each( this.options.items, function( widget, selector ) {
6380 // Make sure the widget has a selector set
6385 if ( widget === "controlgroupLabel" ) {
6386 labels = that.element.find( selector );
6387 labels.each( function() {
6388 var element = $( this );
6390 if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
6394 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
6396 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
6397 childWidgets = childWidgets.concat( labels.get() );
6401 // Make sure the widget actually exists
6402 if ( !$.fn[ widget ] ) {
6406 // We assume everything is in the middle to start because we can't determine
6407 // first / last elements until all enhancments are done.
6408 if ( that[ "_" + widget + "Options" ] ) {
6409 options = that[ "_" + widget + "Options" ]( "middle" );
6411 options = { classes: {} };
6414 // Find instances of this widget inside controlgroup and init them
6418 var element = $( this );
6419 var instance = element[ widget ]( "instance" );
6421 // We need to clone the default options for this type of widget to avoid
6422 // polluting the variable options which has a wider scope than a single widget.
6423 var instanceOptions = $.widget.extend( {}, options );
6425 // If the button is the child of a spinner ignore it
6426 // TODO: Find a more generic solution
6427 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
6431 // Create the widget if it doesn't exist
6433 instance = element[ widget ]()[ widget ]( "instance" );
6436 instanceOptions.classes =
6437 that._resolveClassesValues( instanceOptions.classes, instance );
6439 element[ widget ]( instanceOptions );
6441 // Store an instance of the controlgroup to be able to reference
6442 // from the outermost element for changing options and refresh
6443 var widgetElement = element[ widget ]( "widget" );
6444 $.data( widgetElement[ 0 ], "ui-controlgroup-data",
6445 instance ? instance : element[ widget ]( "instance" ) );
6447 childWidgets.push( widgetElement[ 0 ] );
6451 this.childWidgets = $( $.uniqueSort( childWidgets ) );
6452 this._addClass( this.childWidgets, "ui-controlgroup-item" );
6455 _callChildMethod: function( method ) {
6456 this.childWidgets.each( function() {
6457 var element = $( this ),
6458 data = element.data( "ui-controlgroup-data" );
6459 if ( data && data[ method ] ) {
6465 _updateCornerClass: function( element, position ) {
6466 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
6467 var add = this._buildSimpleOptions( position, "label" ).classes.label;
6469 this._removeClass( element, null, remove );
6470 this._addClass( element, null, add );
6473 _buildSimpleOptions: function( position, key ) {
6474 var direction = this.options.direction === "vertical";
6478 result.classes[ key ] = {
6480 "first": "ui-corner-" + ( direction ? "top" : "left" ),
6481 "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
6482 "only": "ui-corner-all"
6488 _spinnerOptions: function( position ) {
6489 var options = this._buildSimpleOptions( position, "ui-spinner" );
6491 options.classes[ "ui-spinner-up" ] = "";
6492 options.classes[ "ui-spinner-down" ] = "";
6497 _buttonOptions: function( position ) {
6498 return this._buildSimpleOptions( position, "ui-button" );
6501 _checkboxradioOptions: function( position ) {
6502 return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
6505 _selectmenuOptions: function( position ) {
6506 var direction = this.options.direction === "vertical";
6508 width: direction ? "auto" : false,
6511 "ui-selectmenu-button-open": "",
6512 "ui-selectmenu-button-closed": ""
6515 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
6516 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
6519 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
6520 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
6523 "ui-selectmenu-button-open": "ui-corner-top",
6524 "ui-selectmenu-button-closed": "ui-corner-all"
6531 _resolveClassesValues: function( classes, instance ) {
6533 $.each( classes, function( key ) {
6534 var current = instance.options.classes[ key ] || "";
6535 current = String.prototype.trim.call( current.replace( controlgroupCornerRegex, "" ) );
6536 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
6541 _setOption: function( key, value ) {
6542 if ( key === "direction" ) {
6543 this._removeClass( "ui-controlgroup-" + this.options.direction );
6546 this._super( key, value );
6547 if ( key === "disabled" ) {
6548 this._callChildMethod( value ? "disable" : "enable" );
6555 refresh: function() {
6559 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
6561 if ( this.options.direction === "horizontal" ) {
6562 this._addClass( null, "ui-helper-clearfix" );
6564 this._initWidgets();
6566 children = this.childWidgets;
6568 // We filter here because we need to track all childWidgets not just the visible ones
6569 if ( this.options.onlyVisible ) {
6570 children = children.filter( ":visible" );
6573 if ( children.length ) {
6575 // We do this last because we need to make sure all enhancment is done
6576 // before determining first and last
6577 $.each( [ "first", "last" ], function( index, value ) {
6578 var instance = children[ value ]().data( "ui-controlgroup-data" );
6580 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
6581 var options = that[ "_" + instance.widgetName + "Options" ](
6582 children.length === 1 ? "only" : value
6584 options.classes = that._resolveClassesValues( options.classes, instance );
6585 instance.element[ instance.widgetName ]( options );
6587 that._updateCornerClass( children[ value ](), value );
6591 // Finally call the refresh method on each of the child widgets.
6592 this._callChildMethod( "refresh" );
6598 * jQuery UI Checkboxradio 1.13.0
6599 * http://jqueryui.com
6601 * Copyright jQuery Foundation and other contributors
6602 * Released under the MIT license.
6603 * http://jquery.org/license
6606 //>>label: Checkboxradio
6608 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
6609 //>>docs: http://api.jqueryui.com/checkboxradio/
6610 //>>demos: http://jqueryui.com/checkboxradio/
6611 //>>css.structure: ../../themes/base/core.css
6612 //>>css.structure: ../../themes/base/button.css
6613 //>>css.structure: ../../themes/base/checkboxradio.css
6614 //>>css.theme: ../../themes/base/theme.css
6617 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
6624 "ui-checkboxradio-label": "ui-corner-all",
6625 "ui-checkboxradio-icon": "ui-corner-all"
6629 _getCreateOptions: function() {
6630 var disabled, labels;
6632 var options = this._super() || {};
6634 // We read the type here, because it makes more sense to throw a element type error first,
6635 // rather then the error for lack of a label. Often if its the wrong type, it
6636 // won't have a label (e.g. calling on a div, btn, etc)
6639 labels = this.element.labels();
6641 // If there are multiple labels, use the last one
6642 this.label = $( labels[ labels.length - 1 ] );
6643 if ( !this.label.length ) {
6644 $.error( "No label found for checkboxradio widget" );
6647 this.originalLabel = "";
6649 // We need to get the label text but this may also need to make sure it does not contain the
6651 this.label.contents().not( this.element[ 0 ] ).each( function() {
6653 // The label contents could be text, html, or a mix. We concat each element to get a
6654 // string representation of the label, without the input as part of it.
6655 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
6658 // Set the label option if we found label text
6659 if ( this.originalLabel ) {
6660 options.label = this.originalLabel;
6663 disabled = this.element[ 0 ].disabled;
6664 if ( disabled != null ) {
6665 options.disabled = disabled;
6670 _create: function() {
6671 var checked = this.element[ 0 ].checked;
6673 this._bindFormResetHandler();
6675 if ( this.options.disabled == null ) {
6676 this.options.disabled = this.element[ 0 ].disabled;
6679 this._setOption( "disabled", this.options.disabled );
6680 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
6681 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
6683 if ( this.type === "radio" ) {
6684 this._addClass( this.label, "ui-checkboxradio-radio-label" );
6687 if ( this.options.label && this.options.label !== this.originalLabel ) {
6688 this._updateLabel();
6689 } else if ( this.originalLabel ) {
6690 this.options.label = this.originalLabel;
6696 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
6700 change: "_toggleClasses",
6702 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
6705 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
6710 _readType: function() {
6711 var nodeName = this.element[ 0 ].nodeName.toLowerCase();
6712 this.type = this.element[ 0 ].type;
6713 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
6714 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
6715 " and element.type=" + this.type );
6719 // Support jQuery Mobile enhanced option
6720 _enhance: function() {
6721 this._updateIcon( this.element[ 0 ].checked );
6724 widget: function() {
6728 _getRadioGroup: function() {
6730 var name = this.element[ 0 ].name;
6731 var nameSelector = "input[name='" + $.escapeSelector( name ) + "']";
6737 if ( this.form.length ) {
6738 group = $( this.form[ 0 ].elements ).filter( nameSelector );
6741 // Not inside a form, check all inputs that also are not inside a form
6742 group = $( nameSelector ).filter( function() {
6743 return $( this )._form().length === 0;
6747 return group.not( this.element );
6750 _toggleClasses: function() {
6751 var checked = this.element[ 0 ].checked;
6752 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6754 if ( this.options.icon && this.type === "checkbox" ) {
6755 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
6756 ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
6759 if ( this.type === "radio" ) {
6760 this._getRadioGroup()
6762 var instance = $( this ).checkboxradio( "instance" );
6765 instance._removeClass( instance.label,
6766 "ui-checkboxradio-checked", "ui-state-active" );
6772 _destroy: function() {
6773 this._unbindFormResetHandler();
6777 this.iconSpace.remove();
6781 _setOption: function( key, value ) {
6783 // We don't allow the value to be set to nothing
6784 if ( key === "label" && !value ) {
6788 this._super( key, value );
6790 if ( key === "disabled" ) {
6791 this._toggleClass( this.label, null, "ui-state-disabled", value );
6792 this.element[ 0 ].disabled = value;
6794 // Don't refresh when setting disabled
6800 _updateIcon: function( checked ) {
6801 var toAdd = "ui-icon ui-icon-background ";
6803 if ( this.options.icon ) {
6805 this.icon = $( "<span>" );
6806 this.iconSpace = $( "<span> </span>" );
6807 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
6810 if ( this.type === "checkbox" ) {
6811 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
6812 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
6814 toAdd += "ui-icon-blank";
6816 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
6818 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
6820 this.icon.prependTo( this.label ).after( this.iconSpace );
6821 } else if ( this.icon !== undefined ) {
6823 this.iconSpace.remove();
6828 _updateLabel: function() {
6830 // Remove the contents of the label ( minus the icon, icon space, and input )
6831 var contents = this.label.contents().not( this.element[ 0 ] );
6833 contents = contents.not( this.icon[ 0 ] );
6835 if ( this.iconSpace ) {
6836 contents = contents.not( this.iconSpace[ 0 ] );
6840 this.label.append( this.options.label );
6843 refresh: function() {
6844 var checked = this.element[ 0 ].checked,
6845 isDisabled = this.element[ 0 ].disabled;
6847 this._updateIcon( checked );
6848 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6849 if ( this.options.label !== null ) {
6850 this._updateLabel();
6853 if ( isDisabled !== this.options.disabled ) {
6854 this._setOptions( { "disabled": isDisabled } );
6860 var widgetsCheckboxradio = $.ui.checkboxradio;
6864 * jQuery UI Button 1.13.0
6865 * http://jqueryui.com
6867 * Copyright jQuery Foundation and other contributors
6868 * Released under the MIT license.
6869 * http://jquery.org/license
6874 //>>description: Enhances a form with themeable buttons.
6875 //>>docs: http://api.jqueryui.com/button/
6876 //>>demos: http://jqueryui.com/button/
6877 //>>css.structure: ../../themes/base/core.css
6878 //>>css.structure: ../../themes/base/button.css
6879 //>>css.theme: ../../themes/base/theme.css
6882 $.widget( "ui.button", {
6884 defaultElement: "<button>",
6887 "ui-button": "ui-corner-all"
6891 iconPosition: "beginning",
6896 _getCreateOptions: function() {
6899 // This is to support cases like in jQuery Mobile where the base widget does have
6900 // an implementation of _getCreateOptions
6901 options = this._super() || {};
6903 this.isInput = this.element.is( "input" );
6905 disabled = this.element[ 0 ].disabled;
6906 if ( disabled != null ) {
6907 options.disabled = disabled;
6910 this.originalLabel = this.isInput ? this.element.val() : this.element.html();
6911 if ( this.originalLabel ) {
6912 options.label = this.originalLabel;
6918 _create: function() {
6919 if ( !this.option.showLabel & !this.options.icon ) {
6920 this.options.showLabel = true;
6923 // We have to check the option again here even though we did in _getCreateOptions,
6924 // because null may have been passed on init which would override what was set in
6925 // _getCreateOptions
6926 if ( this.options.disabled == null ) {
6927 this.options.disabled = this.element[ 0 ].disabled || false;
6930 this.hasTitle = !!this.element.attr( "title" );
6932 // Check to see if the label needs to be set or if its already correct
6933 if ( this.options.label && this.options.label !== this.originalLabel ) {
6934 if ( this.isInput ) {
6935 this.element.val( this.options.label );
6937 this.element.html( this.options.label );
6940 this._addClass( "ui-button", "ui-widget" );
6941 this._setOption( "disabled", this.options.disabled );
6944 if ( this.element.is( "a" ) ) {
6946 "keyup": function( event ) {
6947 if ( event.keyCode === $.ui.keyCode.SPACE ) {
6948 event.preventDefault();
6950 // Support: PhantomJS <= 1.9, IE 8 Only
6951 // If a native click is available use it so we actually cause navigation
6952 // otherwise just trigger a click event
6953 if ( this.element[ 0 ].click ) {
6954 this.element[ 0 ].click();
6956 this.element.trigger( "click" );
6964 _enhance: function() {
6965 if ( !this.element.is( "button" ) ) {
6966 this.element.attr( "role", "button" );
6969 if ( this.options.icon ) {
6970 this._updateIcon( "icon", this.options.icon );
6971 this._updateTooltip();
6975 _updateTooltip: function() {
6976 this.title = this.element.attr( "title" );
6978 if ( !this.options.showLabel && !this.title ) {
6979 this.element.attr( "title", this.options.label );
6983 _updateIcon: function( option, value ) {
6984 var icon = option !== "iconPosition",
6985 position = icon ? this.options.iconPosition : value,
6986 displayBlock = position === "top" || position === "bottom";
6990 this.icon = $( "<span>" );
6992 this._addClass( this.icon, "ui-button-icon", "ui-icon" );
6994 if ( !this.options.showLabel ) {
6995 this._addClass( "ui-button-icon-only" );
6997 } else if ( icon ) {
6999 // If we are updating the icon remove the old icon class
7000 this._removeClass( this.icon, null, this.options.icon );
7003 // If we are updating the icon add the new icon class
7005 this._addClass( this.icon, null, value );
7008 this._attachIcon( position );
7010 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
7011 // the iconSpace if there is one.
7012 if ( displayBlock ) {
7013 this._addClass( this.icon, null, "ui-widget-icon-block" );
7014 if ( this.iconSpace ) {
7015 this.iconSpace.remove();
7019 // Position is beginning or end so remove the ui-widget-icon-block class and add the
7020 // space if it does not exist
7021 if ( !this.iconSpace ) {
7022 this.iconSpace = $( "<span> </span>" );
7023 this._addClass( this.iconSpace, "ui-button-icon-space" );
7025 this._removeClass( this.icon, null, "ui-wiget-icon-block" );
7026 this._attachIconSpace( position );
7030 _destroy: function() {
7031 this.element.removeAttr( "role" );
7036 if ( this.iconSpace ) {
7037 this.iconSpace.remove();
7039 if ( !this.hasTitle ) {
7040 this.element.removeAttr( "title" );
7044 _attachIconSpace: function( iconPosition ) {
7045 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
7048 _attachIcon: function( iconPosition ) {
7049 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
7052 _setOptions: function( options ) {
7053 var newShowLabel = options.showLabel === undefined ?
7054 this.options.showLabel :
7056 newIcon = options.icon === undefined ? this.options.icon : options.icon;
7058 if ( !newShowLabel && !newIcon ) {
7059 options.showLabel = true;
7061 this._super( options );
7064 _setOption: function( key, value ) {
7065 if ( key === "icon" ) {
7067 this._updateIcon( key, value );
7068 } else if ( this.icon ) {
7070 if ( this.iconSpace ) {
7071 this.iconSpace.remove();
7076 if ( key === "iconPosition" ) {
7077 this._updateIcon( key, value );
7080 // Make sure we can't end up with a button that has neither text nor icon
7081 if ( key === "showLabel" ) {
7082 this._toggleClass( "ui-button-icon-only", null, !value );
7083 this._updateTooltip();
7086 if ( key === "label" ) {
7087 if ( this.isInput ) {
7088 this.element.val( value );
7091 // If there is an icon, append it, else nothing then append the value
7092 // this avoids removal of the icon when setting label text
7093 this.element.html( value );
7095 this._attachIcon( this.options.iconPosition );
7096 this._attachIconSpace( this.options.iconPosition );
7101 this._super( key, value );
7103 if ( key === "disabled" ) {
7104 this._toggleClass( null, "ui-state-disabled", value );
7105 this.element[ 0 ].disabled = value;
7107 this.element.trigger( "blur" );
7112 refresh: function() {
7114 // Make sure to only check disabled if its an element that supports this otherwise
7115 // check for the disabled class to determine state
7116 var isDisabled = this.element.is( "input, button" ) ?
7117 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
7119 if ( isDisabled !== this.options.disabled ) {
7120 this._setOptions( { disabled: isDisabled } );
7123 this._updateTooltip();
7128 if ( $.uiBackCompat !== false ) {
7130 // Text and Icons options
7131 $.widget( "ui.button", $.ui.button, {
7140 _create: function() {
7141 if ( this.options.showLabel && !this.options.text ) {
7142 this.options.showLabel = this.options.text;
7144 if ( !this.options.showLabel && this.options.text ) {
7145 this.options.text = this.options.showLabel;
7147 if ( !this.options.icon && ( this.options.icons.primary ||
7148 this.options.icons.secondary ) ) {
7149 if ( this.options.icons.primary ) {
7150 this.options.icon = this.options.icons.primary;
7152 this.options.icon = this.options.icons.secondary;
7153 this.options.iconPosition = "end";
7155 } else if ( this.options.icon ) {
7156 this.options.icons.primary = this.options.icon;
7161 _setOption: function( key, value ) {
7162 if ( key === "text" ) {
7163 this._super( "showLabel", value );
7166 if ( key === "showLabel" ) {
7167 this.options.text = value;
7169 if ( key === "icon" ) {
7170 this.options.icons.primary = value;
7172 if ( key === "icons" ) {
7173 if ( value.primary ) {
7174 this._super( "icon", value.primary );
7175 this._super( "iconPosition", "beginning" );
7176 } else if ( value.secondary ) {
7177 this._super( "icon", value.secondary );
7178 this._super( "iconPosition", "end" );
7181 this._superApply( arguments );
7185 $.fn.button = ( function( orig ) {
7186 return function( options ) {
7187 var isMethodCall = typeof options === "string";
7188 var args = Array.prototype.slice.call( arguments, 1 );
7189 var returnValue = this;
7191 if ( isMethodCall ) {
7193 // If this is an empty collection, we need to have the instance method
7194 // return undefined instead of the jQuery instance
7195 if ( !this.length && options === "instance" ) {
7196 returnValue = undefined;
7198 this.each( function() {
7200 var type = $( this ).attr( "type" );
7201 var name = type !== "checkbox" && type !== "radio" ?
7204 var instance = $.data( this, "ui-" + name );
7206 if ( options === "instance" ) {
7207 returnValue = instance;
7212 return $.error( "cannot call methods on button" +
7213 " prior to initialization; " +
7214 "attempted to call method '" + options + "'" );
7217 if ( typeof instance[ options ] !== "function" ||
7218 options.charAt( 0 ) === "_" ) {
7219 return $.error( "no such method '" + options + "' for button" +
7220 " widget instance" );
7223 methodValue = instance[ options ].apply( instance, args );
7225 if ( methodValue !== instance && methodValue !== undefined ) {
7226 returnValue = methodValue && methodValue.jquery ?
7227 returnValue.pushStack( methodValue.get() ) :
7235 // Allow multiple hashes to be passed on init
7236 if ( args.length ) {
7237 options = $.widget.extend.apply( null, [ options ].concat( args ) );
7240 this.each( function() {
7241 var type = $( this ).attr( "type" );
7242 var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio";
7243 var instance = $.data( this, "ui-" + name );
7246 instance.option( options || {} );
7247 if ( instance._init ) {
7251 if ( name === "button" ) {
7252 orig.call( $( this ), options );
7256 $( this ).checkboxradio( $.extend( { icon: false }, options ) );
7265 $.fn.buttonset = function() {
7266 if ( !$.ui.controlgroup ) {
7267 $.error( "Controlgroup widget missing" );
7269 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
7270 return this.controlgroup.apply( this,
7271 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
7273 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
7274 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
7276 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
7277 arguments[ 0 ].items = {
7278 button: arguments[ 0 ].items
7281 return this.controlgroup.apply( this, arguments );
7285 var widgetsButton = $.ui.button;
7288 /* eslint-disable max-len, camelcase */
7290 * jQuery UI Datepicker 1.13.0
7291 * http://jqueryui.com
7293 * Copyright jQuery Foundation and other contributors
7294 * Released under the MIT license.
7295 * http://jquery.org/license
7298 //>>label: Datepicker
7300 //>>description: Displays a calendar from an input or inline for selecting dates.
7301 //>>docs: http://api.jqueryui.com/datepicker/
7302 //>>demos: http://jqueryui.com/datepicker/
7303 //>>css.structure: ../../themes/base/core.css
7304 //>>css.structure: ../../themes/base/datepicker.css
7305 //>>css.theme: ../../themes/base/theme.css
7308 $.extend( $.ui, { datepicker: { version: "1.13.0" } } );
7310 var datepicker_instActive;
7312 function datepicker_getZindex( elem ) {
7313 var position, value;
7314 while ( elem.length && elem[ 0 ] !== document ) {
7316 // Ignore z-index if position is set to a value where z-index is ignored by the browser
7317 // This makes behavior of this function consistent across browsers
7318 // WebKit always returns auto if the element is positioned
7319 position = elem.css( "position" );
7320 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
7322 // IE returns 0 when zIndex is not specified
7323 // other browsers return a string
7324 // we ignore the case of nested elements with an explicit value of 0
7325 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
7326 value = parseInt( elem.css( "zIndex" ), 10 );
7327 if ( !isNaN( value ) && value !== 0 ) {
7331 elem = elem.parent();
7337 /* Date picker manager.
7338 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7339 Settings for (groups of) date pickers are maintained in an instance object,
7340 allowing multiple different settings on the same page. */
7342 function Datepicker() {
7343 this._curInst = null; // The current instance in use
7344 this._keyEvent = false; // If the last event was a key event
7345 this._disabledInputs = []; // List of date picker inputs that have been disabled
7346 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7347 this._inDialog = false; // True if showing within a "dialog", false if not
7348 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
7349 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
7350 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
7351 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
7352 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
7353 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
7354 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
7355 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
7356 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
7357 this.regional = []; // Available regional settings, indexed by language code
7358 this.regional[ "" ] = { // Default regional settings
7359 closeText: "Done", // Display text for close link
7360 prevText: "Prev", // Display text for previous month link
7361 nextText: "Next", // Display text for next month link
7362 currentText: "Today", // Display text for current month link
7363 monthNames: [ "January", "February", "March", "April", "May", "June",
7364 "July", "August", "September", "October", "November", "December" ], // Names of months for drop-down and formatting
7365 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
7366 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
7367 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
7368 dayNamesMin: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ], // Column headings for days starting at Sunday
7369 weekHeader: "Wk", // Column header for week of the year
7370 dateFormat: "mm/dd/yy", // See format options on parseDate
7371 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7372 isRTL: false, // True if right-to-left language, false if left-to-right
7373 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7374 yearSuffix: "", // Additional text to append to the year in the month headers,
7375 selectMonthLabel: "Select month", // Invisible label for month selector
7376 selectYearLabel: "Select year" // Invisible label for year selector
7378 this._defaults = { // Global defaults for all the date picker instances
7379 showOn: "focus", // "focus" for popup on focus,
7380 // "button" for trigger button, or "both" for either
7381 showAnim: "fadeIn", // Name of jQuery animation for popup
7382 showOptions: {}, // Options for enhanced animations
7383 defaultDate: null, // Used when field is blank: actual date,
7384 // +/-number for offset from today, null for today
7385 appendText: "", // Display text following the input box, e.g. showing the format
7386 buttonText: "...", // Text for trigger button
7387 buttonImage: "", // URL for trigger button image
7388 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7389 hideIfNoPrevNext: false, // True to hide next/previous month links
7390 // if not applicable, false to just disable them
7391 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7392 gotoCurrent: false, // True if today link goes back to current selection instead
7393 changeMonth: false, // True if month can be selected directly, false if only prev/next
7394 changeYear: false, // True if year can be selected directly, false if only prev/next
7395 yearRange: "c-10:c+10", // Range of years to display in drop-down,
7396 // either relative to today's year (-nn:+nn), relative to currently displayed year
7397 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7398 showOtherMonths: false, // True to show dates in other months, false to leave blank
7399 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7400 showWeek: false, // True to show week of the year, false to not show it
7401 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7402 // takes a Date and returns the number of the week for it
7403 shortYearCutoff: "+10", // Short year values < this are in the current century,
7404 // > this are in the previous century,
7405 // string value starting with "+" for current year + value
7406 minDate: null, // The earliest selectable date, or null for no limit
7407 maxDate: null, // The latest selectable date, or null for no limit
7408 duration: "fast", // Duration of display/closure
7409 beforeShowDay: null, // Function that takes a date and returns an array with
7410 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
7411 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7412 beforeShow: null, // Function that takes an input field and
7413 // returns a set of custom settings for the date picker
7414 onSelect: null, // Define a callback function when a date is selected
7415 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7416 onClose: null, // Define a callback function when the datepicker is closed
7417 onUpdateDatepicker: null, // Define a callback function when the datepicker is updated
7418 numberOfMonths: 1, // Number of months to show at a time
7419 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7420 stepMonths: 1, // Number of months to step back/forward
7421 stepBigMonths: 12, // Number of months to step back/forward for the big links
7422 altField: "", // Selector for an alternate field to store selected dates into
7423 altFormat: "", // The date format to use for the alternate field
7424 constrainInput: true, // The input is constrained by the current date format
7425 showButtonPanel: false, // True to show button panel, false to not show it
7426 autoSize: false, // True to size the input for the date format, false to leave as is
7427 disabled: false // The initial disabled state
7429 $.extend( this._defaults, this.regional[ "" ] );
7430 this.regional.en = $.extend( true, {}, this.regional[ "" ] );
7431 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
7432 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
7435 $.extend( Datepicker.prototype, {
7437 /* Class name added to elements to indicate already configured with a date picker. */
7438 markerClassName: "hasDatepicker",
7440 //Keep track of the maximum number of rows displayed (see #7043)
7443 // TODO rename to "widget" when switching to widget factory
7444 _widgetDatepicker: function() {
7448 /* Override the default settings for all instances of the date picker.
7449 * @param settings object - the new settings to use as defaults (anonymous object)
7450 * @return the manager object
7452 setDefaults: function( settings ) {
7453 datepicker_extendRemove( this._defaults, settings || {} );
7457 /* Attach the date picker to a jQuery selection.
7458 * @param target element - the target input field or division or span
7459 * @param settings object - the new settings to use for this date picker instance (anonymous)
7461 _attachDatepicker: function( target, settings ) {
7462 var nodeName, inline, inst;
7463 nodeName = target.nodeName.toLowerCase();
7464 inline = ( nodeName === "div" || nodeName === "span" );
7467 target.id = "dp" + this.uuid;
7469 inst = this._newInst( $( target ), inline );
7470 inst.settings = $.extend( {}, settings || {} );
7471 if ( nodeName === "input" ) {
7472 this._connectDatepicker( target, inst );
7473 } else if ( inline ) {
7474 this._inlineDatepicker( target, inst );
7478 /* Create a new instance object. */
7479 _newInst: function( target, inline ) {
7480 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
7481 return { id: id, input: target, // associated target
7482 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7483 drawMonth: 0, drawYear: 0, // month being drawn
7484 inline: inline, // is datepicker inline or not
7485 dpDiv: ( !inline ? this.dpDiv : // presentation div
7486 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
7489 /* Attach the date picker to an input field. */
7490 _connectDatepicker: function( target, inst ) {
7491 var input = $( target );
7492 inst.append = $( [] );
7493 inst.trigger = $( [] );
7494 if ( input.hasClass( this.markerClassName ) ) {
7497 this._attachments( input, inst );
7498 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
7499 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
7500 this._autoSize( inst );
7501 $.data( target, "datepicker", inst );
7503 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7504 if ( inst.settings.disabled ) {
7505 this._disableDatepicker( target );
7509 /* Make attachments based on settings. */
7510 _attachments: function( input, inst ) {
7511 var showOn, buttonText, buttonImage,
7512 appendText = this._get( inst, "appendText" ),
7513 isRTL = this._get( inst, "isRTL" );
7515 if ( inst.append ) {
7516 inst.append.remove();
7519 inst.append = $( "<span>" )
7520 .addClass( this._appendClass )
7521 .text( appendText );
7522 input[ isRTL ? "before" : "after" ]( inst.append );
7525 input.off( "focus", this._showDatepicker );
7527 if ( inst.trigger ) {
7528 inst.trigger.remove();
7531 showOn = this._get( inst, "showOn" );
7532 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
7533 input.on( "focus", this._showDatepicker );
7535 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
7536 buttonText = this._get( inst, "buttonText" );
7537 buttonImage = this._get( inst, "buttonImage" );
7539 if ( this._get( inst, "buttonImageOnly" ) ) {
7540 inst.trigger = $( "<img>" )
7541 .addClass( this._triggerClass )
7548 inst.trigger = $( "<button type='button'>" )
7549 .addClass( this._triggerClass );
7550 if ( buttonImage ) {
7560 inst.trigger.text( buttonText );
7564 input[ isRTL ? "before" : "after" ]( inst.trigger );
7565 inst.trigger.on( "click", function() {
7566 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
7567 $.datepicker._hideDatepicker();
7568 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
7569 $.datepicker._hideDatepicker();
7570 $.datepicker._showDatepicker( input[ 0 ] );
7572 $.datepicker._showDatepicker( input[ 0 ] );
7579 /* Apply the maximum length for the date format. */
7580 _autoSize: function( inst ) {
7581 if ( this._get( inst, "autoSize" ) && !inst.inline ) {
7582 var findMax, max, maxI, i,
7583 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
7584 dateFormat = this._get( inst, "dateFormat" );
7586 if ( dateFormat.match( /[DM]/ ) ) {
7587 findMax = function( names ) {
7590 for ( i = 0; i < names.length; i++ ) {
7591 if ( names[ i ].length > max ) {
7592 max = names[ i ].length;
7598 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
7599 "monthNames" : "monthNamesShort" ) ) ) );
7600 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
7601 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
7603 inst.input.attr( "size", this._formatDate( inst, date ).length );
7607 /* Attach an inline date picker to a div. */
7608 _inlineDatepicker: function( target, inst ) {
7609 var divSpan = $( target );
7610 if ( divSpan.hasClass( this.markerClassName ) ) {
7613 divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
7614 $.data( target, "datepicker", inst );
7615 this._setDate( inst, this._getDefaultDate( inst ), true );
7616 this._updateDatepicker( inst );
7617 this._updateAlternate( inst );
7619 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7620 if ( inst.settings.disabled ) {
7621 this._disableDatepicker( target );
7624 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7625 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7626 inst.dpDiv.css( "display", "block" );
7629 /* Pop-up the date picker in a "dialog" box.
7630 * @param input element - ignored
7631 * @param date string or Date - the initial date to display
7632 * @param onSelect function - the function to call when a date is selected
7633 * @param settings object - update the dialog date picker instance's settings (anonymous object)
7634 * @param pos int[2] - coordinates for the dialog's position within the screen or
7635 * event - with x/y coordinates or
7636 * leave empty for default (screen centre)
7637 * @return the manager object
7639 _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
7640 var id, browserWidth, browserHeight, scrollX, scrollY,
7641 inst = this._dialogInst; // internal instance
7645 id = "dp" + this.uuid;
7646 this._dialogInput = $( "<input type='text' id='" + id +
7647 "' style='position: absolute; top: -100px; width: 0px;'/>" );
7648 this._dialogInput.on( "keydown", this._doKeyDown );
7649 $( "body" ).append( this._dialogInput );
7650 inst = this._dialogInst = this._newInst( this._dialogInput, false );
7652 $.data( this._dialogInput[ 0 ], "datepicker", inst );
7654 datepicker_extendRemove( inst.settings, settings || {} );
7655 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
7656 this._dialogInput.val( date );
7658 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
7660 browserWidth = document.documentElement.clientWidth;
7661 browserHeight = document.documentElement.clientHeight;
7662 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7663 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7664 this._pos = // should use actual width/height below
7665 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
7668 // Move input on screen for focus, but hidden behind dialog
7669 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
7670 inst.settings.onSelect = onSelect;
7671 this._inDialog = true;
7672 this.dpDiv.addClass( this._dialogClass );
7673 this._showDatepicker( this._dialogInput[ 0 ] );
7675 $.blockUI( this.dpDiv );
7677 $.data( this._dialogInput[ 0 ], "datepicker", inst );
7681 /* Detach a datepicker from its control.
7682 * @param target element - the target input field or division or span
7684 _destroyDatepicker: function( target ) {
7686 $target = $( target ),
7687 inst = $.data( target, "datepicker" );
7689 if ( !$target.hasClass( this.markerClassName ) ) {
7693 nodeName = target.nodeName.toLowerCase();
7694 $.removeData( target, "datepicker" );
7695 if ( nodeName === "input" ) {
7696 inst.append.remove();
7697 inst.trigger.remove();
7698 $target.removeClass( this.markerClassName ).
7699 off( "focus", this._showDatepicker ).
7700 off( "keydown", this._doKeyDown ).
7701 off( "keypress", this._doKeyPress ).
7702 off( "keyup", this._doKeyUp );
7703 } else if ( nodeName === "div" || nodeName === "span" ) {
7704 $target.removeClass( this.markerClassName ).empty();
7707 if ( datepicker_instActive === inst ) {
7708 datepicker_instActive = null;
7709 this._curInst = null;
7713 /* Enable the date picker to a jQuery selection.
7714 * @param target element - the target input field or division or span
7716 _enableDatepicker: function( target ) {
7717 var nodeName, inline,
7718 $target = $( target ),
7719 inst = $.data( target, "datepicker" );
7721 if ( !$target.hasClass( this.markerClassName ) ) {
7725 nodeName = target.nodeName.toLowerCase();
7726 if ( nodeName === "input" ) {
7727 target.disabled = false;
7728 inst.trigger.filter( "button" ).
7730 this.disabled = false;
7732 filter( "img" ).css( { opacity: "1.0", cursor: "" } );
7733 } else if ( nodeName === "div" || nodeName === "span" ) {
7734 inline = $target.children( "." + this._inlineClass );
7735 inline.children().removeClass( "ui-state-disabled" );
7736 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7737 prop( "disabled", false );
7739 this._disabledInputs = $.map( this._disabledInputs,
7743 return ( value === target ? null : value );
7747 /* Disable the date picker to a jQuery selection.
7748 * @param target element - the target input field or division or span
7750 _disableDatepicker: function( target ) {
7751 var nodeName, inline,
7752 $target = $( target ),
7753 inst = $.data( target, "datepicker" );
7755 if ( !$target.hasClass( this.markerClassName ) ) {
7759 nodeName = target.nodeName.toLowerCase();
7760 if ( nodeName === "input" ) {
7761 target.disabled = true;
7762 inst.trigger.filter( "button" ).
7764 this.disabled = true;
7766 filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
7767 } else if ( nodeName === "div" || nodeName === "span" ) {
7768 inline = $target.children( "." + this._inlineClass );
7769 inline.children().addClass( "ui-state-disabled" );
7770 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7771 prop( "disabled", true );
7773 this._disabledInputs = $.map( this._disabledInputs,
7777 return ( value === target ? null : value );
7779 this._disabledInputs[ this._disabledInputs.length ] = target;
7782 /* Is the first field in a jQuery collection disabled as a datepicker?
7783 * @param target element - the target input field or division or span
7784 * @return boolean - true if disabled, false if enabled
7786 _isDisabledDatepicker: function( target ) {
7790 for ( var i = 0; i < this._disabledInputs.length; i++ ) {
7791 if ( this._disabledInputs[ i ] === target ) {
7798 /* Retrieve the instance data for the target control.
7799 * @param target element - the target input field or division or span
7800 * @return object - the associated instance data
7801 * @throws error if a jQuery problem getting data
7803 _getInst: function( target ) {
7805 return $.data( target, "datepicker" );
7807 throw "Missing instance data for this datepicker";
7811 /* Update or retrieve the settings for a date picker attached to an input field or division.
7812 * @param target element - the target input field or division or span
7813 * @param name object - the new settings to update or
7814 * string - the name of the setting to change or retrieve,
7815 * when retrieving also "all" for all instance settings or
7816 * "defaults" for all global defaults
7817 * @param value any - the new value for the setting
7818 * (omit if above is an object or to retrieve a value)
7820 _optionDatepicker: function( target, name, value ) {
7821 var settings, date, minDate, maxDate,
7822 inst = this._getInst( target );
7824 if ( arguments.length === 2 && typeof name === "string" ) {
7825 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
7826 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
7827 this._get( inst, name ) ) : null ) );
7830 settings = name || {};
7831 if ( typeof name === "string" ) {
7833 settings[ name ] = value;
7837 if ( this._curInst === inst ) {
7838 this._hideDatepicker();
7841 date = this._getDateDatepicker( target, true );
7842 minDate = this._getMinMaxDate( inst, "min" );
7843 maxDate = this._getMinMaxDate( inst, "max" );
7844 datepicker_extendRemove( inst.settings, settings );
7846 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
7847 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
7848 inst.settings.minDate = this._formatDate( inst, minDate );
7850 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
7851 inst.settings.maxDate = this._formatDate( inst, maxDate );
7853 if ( "disabled" in settings ) {
7854 if ( settings.disabled ) {
7855 this._disableDatepicker( target );
7857 this._enableDatepicker( target );
7860 this._attachments( $( target ), inst );
7861 this._autoSize( inst );
7862 this._setDate( inst, date );
7863 this._updateAlternate( inst );
7864 this._updateDatepicker( inst );
7868 // Change method deprecated
7869 _changeDatepicker: function( target, name, value ) {
7870 this._optionDatepicker( target, name, value );
7873 /* Redraw the date picker attached to an input field or division.
7874 * @param target element - the target input field or division or span
7876 _refreshDatepicker: function( target ) {
7877 var inst = this._getInst( target );
7879 this._updateDatepicker( inst );
7883 /* Set the dates for a jQuery selection.
7884 * @param target element - the target input field or division or span
7885 * @param date Date - the new date
7887 _setDateDatepicker: function( target, date ) {
7888 var inst = this._getInst( target );
7890 this._setDate( inst, date );
7891 this._updateDatepicker( inst );
7892 this._updateAlternate( inst );
7896 /* Get the date(s) for the first entry in a jQuery selection.
7897 * @param target element - the target input field or division or span
7898 * @param noDefault boolean - true if no default date is to be used
7899 * @return Date - the current date
7901 _getDateDatepicker: function( target, noDefault ) {
7902 var inst = this._getInst( target );
7903 if ( inst && !inst.inline ) {
7904 this._setDateFromField( inst, noDefault );
7906 return ( inst ? this._getDate( inst ) : null );
7909 /* Handle keystrokes. */
7910 _doKeyDown: function( event ) {
7911 var onSelect, dateStr, sel,
7912 inst = $.datepicker._getInst( event.target ),
7914 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
7916 inst._keyEvent = true;
7917 if ( $.datepicker._datepickerShowing ) {
7918 switch ( event.keyCode ) {
7919 case 9: $.datepicker._hideDatepicker();
7921 break; // hide on tab out
7922 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
7923 $.datepicker._currentClass + ")", inst.dpDiv );
7925 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
7928 onSelect = $.datepicker._get( inst, "onSelect" );
7930 dateStr = $.datepicker._formatDate( inst );
7932 // Trigger custom callback
7933 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
7935 $.datepicker._hideDatepicker();
7938 return false; // don't submit the form
7939 case 27: $.datepicker._hideDatepicker();
7940 break; // hide on escape
7941 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7942 -$.datepicker._get( inst, "stepBigMonths" ) :
7943 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
7944 break; // previous month/year on page up/+ ctrl
7945 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7946 +$.datepicker._get( inst, "stepBigMonths" ) :
7947 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
7948 break; // next month/year on page down/+ ctrl
7949 case 35: if ( event.ctrlKey || event.metaKey ) {
7950 $.datepicker._clearDate( event.target );
7952 handled = event.ctrlKey || event.metaKey;
7953 break; // clear on ctrl or command +end
7954 case 36: if ( event.ctrlKey || event.metaKey ) {
7955 $.datepicker._gotoToday( event.target );
7957 handled = event.ctrlKey || event.metaKey;
7958 break; // current on ctrl or command +home
7959 case 37: if ( event.ctrlKey || event.metaKey ) {
7960 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
7962 handled = event.ctrlKey || event.metaKey;
7964 // -1 day on ctrl or command +left
7965 if ( event.originalEvent.altKey ) {
7966 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7967 -$.datepicker._get( inst, "stepBigMonths" ) :
7968 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
7971 // next month/year on alt +left on Mac
7973 case 38: if ( event.ctrlKey || event.metaKey ) {
7974 $.datepicker._adjustDate( event.target, -7, "D" );
7976 handled = event.ctrlKey || event.metaKey;
7977 break; // -1 week on ctrl or command +up
7978 case 39: if ( event.ctrlKey || event.metaKey ) {
7979 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
7981 handled = event.ctrlKey || event.metaKey;
7983 // +1 day on ctrl or command +right
7984 if ( event.originalEvent.altKey ) {
7985 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7986 +$.datepicker._get( inst, "stepBigMonths" ) :
7987 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
7990 // next month/year on alt +right
7992 case 40: if ( event.ctrlKey || event.metaKey ) {
7993 $.datepicker._adjustDate( event.target, +7, "D" );
7995 handled = event.ctrlKey || event.metaKey;
7996 break; // +1 week on ctrl or command +down
7997 default: handled = false;
7999 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
8000 $.datepicker._showDatepicker( this );
8006 event.preventDefault();
8007 event.stopPropagation();
8011 /* Filter entered characters - based on date format. */
8012 _doKeyPress: function( event ) {
8014 inst = $.datepicker._getInst( event.target );
8016 if ( $.datepicker._get( inst, "constrainInput" ) ) {
8017 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
8018 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
8019 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
8023 /* Synchronise manual entry and field/alternate field. */
8024 _doKeyUp: function( event ) {
8026 inst = $.datepicker._getInst( event.target );
8028 if ( inst.input.val() !== inst.lastVal ) {
8030 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
8031 ( inst.input ? inst.input.val() : null ),
8032 $.datepicker._getFormatConfig( inst ) );
8034 if ( date ) { // only if valid
8035 $.datepicker._setDateFromField( inst );
8036 $.datepicker._updateAlternate( inst );
8037 $.datepicker._updateDatepicker( inst );
8045 /* Pop-up the date picker for a given input field.
8046 * If false returned from beforeShow event handler do not show.
8047 * @param input element - the input field attached to the date picker or
8048 * event - if triggered by focus
8050 _showDatepicker: function( input ) {
8051 input = input.target || input;
8052 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
8053 input = $( "input", input.parentNode )[ 0 ];
8056 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
8060 var inst, beforeShow, beforeShowSettings, isFixed,
8061 offset, showAnim, duration;
8063 inst = $.datepicker._getInst( input );
8064 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
8065 $.datepicker._curInst.dpDiv.stop( true, true );
8066 if ( inst && $.datepicker._datepickerShowing ) {
8067 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
8071 beforeShow = $.datepicker._get( inst, "beforeShow" );
8072 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
8073 if ( beforeShowSettings === false ) {
8076 datepicker_extendRemove( inst.settings, beforeShowSettings );
8078 inst.lastVal = null;
8079 $.datepicker._lastInput = input;
8080 $.datepicker._setDateFromField( inst );
8082 if ( $.datepicker._inDialog ) { // hide cursor
8085 if ( !$.datepicker._pos ) { // position below input
8086 $.datepicker._pos = $.datepicker._findPos( input );
8087 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
8091 $( input ).parents().each( function() {
8092 isFixed |= $( this ).css( "position" ) === "fixed";
8096 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
8097 $.datepicker._pos = null;
8099 //to avoid flashes on Firefox
8102 // determine sizing offscreen
8103 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
8104 $.datepicker._updateDatepicker( inst );
8106 // fix width for dynamic number of date pickers
8107 // and adjust position before showing
8108 offset = $.datepicker._checkOffset( inst, offset, isFixed );
8109 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
8110 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
8111 left: offset.left + "px", top: offset.top + "px" } );
8113 if ( !inst.inline ) {
8114 showAnim = $.datepicker._get( inst, "showAnim" );
8115 duration = $.datepicker._get( inst, "duration" );
8116 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
8117 $.datepicker._datepickerShowing = true;
8119 if ( $.effects && $.effects.effect[ showAnim ] ) {
8120 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
8122 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
8125 if ( $.datepicker._shouldFocusInput( inst ) ) {
8126 inst.input.trigger( "focus" );
8129 $.datepicker._curInst = inst;
8133 /* Generate the date picker content. */
8134 _updateDatepicker: function( inst ) {
8135 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
8136 datepicker_instActive = inst; // for delegate hover events
8137 inst.dpDiv.empty().append( this._generateHTML( inst ) );
8138 this._attachHandlers( inst );
8141 numMonths = this._getNumberOfMonths( inst ),
8142 cols = numMonths[ 1 ],
8144 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ),
8145 onUpdateDatepicker = $.datepicker._get( inst, "onUpdateDatepicker" );
8147 if ( activeCell.length > 0 ) {
8148 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
8151 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
8153 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
8155 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
8156 "Class" ]( "ui-datepicker-multi" );
8157 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
8158 "Class" ]( "ui-datepicker-rtl" );
8160 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
8161 inst.input.trigger( "focus" );
8164 // Deffered render of the years select (to avoid flashes on Firefox)
8165 if ( inst.yearshtml ) {
8166 origyearshtml = inst.yearshtml;
8167 setTimeout( function() {
8169 //assure that inst.yearshtml didn't change.
8170 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
8171 inst.dpDiv.find( "select.ui-datepicker-year" ).first().replaceWith( inst.yearshtml );
8173 origyearshtml = inst.yearshtml = null;
8177 if ( onUpdateDatepicker ) {
8178 onUpdateDatepicker.apply( ( inst.input ? inst.input[ 0 ] : null ), [ inst ] );
8182 // #6694 - don't focus the input if it's already focused
8183 // this breaks the change event in IE
8184 // Support: IE and jQuery <1.9
8185 _shouldFocusInput: function( inst ) {
8186 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
8189 /* Check positioning to remain on screen. */
8190 _checkOffset: function( inst, offset, isFixed ) {
8191 var dpWidth = inst.dpDiv.outerWidth(),
8192 dpHeight = inst.dpDiv.outerHeight(),
8193 inputWidth = inst.input ? inst.input.outerWidth() : 0,
8194 inputHeight = inst.input ? inst.input.outerHeight() : 0,
8195 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
8196 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
8198 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
8199 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
8200 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
8202 // Now check if datepicker is showing outside window viewport - move to a better place if so.
8203 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
8204 Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
8205 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
8206 Math.abs( dpHeight + inputHeight ) : 0 );
8211 /* Find an object's position on the screen. */
8212 _findPos: function( obj ) {
8214 inst = this._getInst( obj ),
8215 isRTL = this._get( inst, "isRTL" );
8217 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.pseudos.hidden( obj ) ) ) {
8218 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
8221 position = $( obj ).offset();
8222 return [ position.left, position.top ];
8225 /* Hide the date picker from view.
8226 * @param input element - the input field attached to the date picker
8228 _hideDatepicker: function( input ) {
8229 var showAnim, duration, postProcess, onClose,
8230 inst = this._curInst;
8232 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
8236 if ( this._datepickerShowing ) {
8237 showAnim = this._get( inst, "showAnim" );
8238 duration = this._get( inst, "duration" );
8239 postProcess = function() {
8240 $.datepicker._tidyDialog( inst );
8243 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8244 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8245 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
8247 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
8248 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
8254 this._datepickerShowing = false;
8256 onClose = this._get( inst, "onClose" );
8258 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
8261 this._lastInput = null;
8262 if ( this._inDialog ) {
8263 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
8266 $( "body" ).append( this.dpDiv );
8269 this._inDialog = false;
8273 /* Tidy up after a dialog display. */
8274 _tidyDialog: function( inst ) {
8275 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
8278 /* Close date picker if clicked elsewhere. */
8279 _checkExternalClick: function( event ) {
8280 if ( !$.datepicker._curInst ) {
8284 var $target = $( event.target ),
8285 inst = $.datepicker._getInst( $target[ 0 ] );
8287 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
8288 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
8289 !$target.hasClass( $.datepicker.markerClassName ) &&
8290 !$target.closest( "." + $.datepicker._triggerClass ).length &&
8291 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
8292 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
8293 $.datepicker._hideDatepicker();
8297 /* Adjust one of the date sub-fields. */
8298 _adjustDate: function( id, offset, period ) {
8299 var target = $( id ),
8300 inst = this._getInst( target[ 0 ] );
8302 if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
8305 this._adjustInstDate( inst, offset, period );
8306 this._updateDatepicker( inst );
8309 /* Action for current link. */
8310 _gotoToday: function( id ) {
8313 inst = this._getInst( target[ 0 ] );
8315 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
8316 inst.selectedDay = inst.currentDay;
8317 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8318 inst.drawYear = inst.selectedYear = inst.currentYear;
8321 inst.selectedDay = date.getDate();
8322 inst.drawMonth = inst.selectedMonth = date.getMonth();
8323 inst.drawYear = inst.selectedYear = date.getFullYear();
8325 this._notifyChange( inst );
8326 this._adjustDate( target );
8329 /* Action for selecting a new month/year. */
8330 _selectMonthYear: function( id, select, period ) {
8331 var target = $( id ),
8332 inst = this._getInst( target[ 0 ] );
8334 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
8335 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
8336 parseInt( select.options[ select.selectedIndex ].value, 10 );
8338 this._notifyChange( inst );
8339 this._adjustDate( target );
8342 /* Action for selecting a day. */
8343 _selectDay: function( id, month, year, td ) {
8347 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
8351 inst = this._getInst( target[ 0 ] );
8352 inst.selectedDay = inst.currentDay = parseInt( $( "a", td ).attr( "data-date" ) );
8353 inst.selectedMonth = inst.currentMonth = month;
8354 inst.selectedYear = inst.currentYear = year;
8355 this._selectDate( id, this._formatDate( inst,
8356 inst.currentDay, inst.currentMonth, inst.currentYear ) );
8359 /* Erase the input field and hide the date picker. */
8360 _clearDate: function( id ) {
8361 var target = $( id );
8362 this._selectDate( target, "" );
8365 /* Update the input field with the selected date. */
8366 _selectDate: function( id, dateStr ) {
8369 inst = this._getInst( target[ 0 ] );
8371 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
8373 inst.input.val( dateStr );
8375 this._updateAlternate( inst );
8377 onSelect = this._get( inst, "onSelect" );
8379 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
8380 } else if ( inst.input ) {
8381 inst.input.trigger( "change" ); // fire the change event
8384 if ( inst.inline ) {
8385 this._updateDatepicker( inst );
8387 this._hideDatepicker();
8388 this._lastInput = inst.input[ 0 ];
8389 if ( typeof( inst.input[ 0 ] ) !== "object" ) {
8390 inst.input.trigger( "focus" ); // restore focus
8392 this._lastInput = null;
8396 /* Update any alternate field to synchronise with the main field. */
8397 _updateAlternate: function( inst ) {
8398 var altFormat, date, dateStr,
8399 altField = this._get( inst, "altField" );
8401 if ( altField ) { // update alternate field too
8402 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
8403 date = this._getDate( inst );
8404 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
8405 $( document ).find( altField ).val( dateStr );
8409 /* Set as beforeShowDay function to prevent selection of weekends.
8410 * @param date Date - the date to customise
8411 * @return [boolean, string] - is this date selectable?, what is its CSS class?
8413 noWeekends: function( date ) {
8414 var day = date.getDay();
8415 return [ ( day > 0 && day < 6 ), "" ];
8418 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8419 * @param date Date - the date to get the week for
8420 * @return number - the number of the week within the year that contains this date
8422 iso8601Week: function( date ) {
8424 checkDate = new Date( date.getTime() );
8426 // Find Thursday of this week starting on Monday
8427 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
8429 time = checkDate.getTime();
8430 checkDate.setMonth( 0 ); // Compare with Jan 1
8431 checkDate.setDate( 1 );
8432 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
8435 /* Parse a string value into a date object.
8436 * See formatDate below for the possible formats.
8438 * @param format string - the expected format of the date
8439 * @param value string - the date in the above format
8440 * @param settings Object - attributes include:
8441 * shortYearCutoff number - the cutoff year for determining the century (optional)
8442 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8443 * dayNames string[7] - names of the days from Sunday (optional)
8444 * monthNamesShort string[12] - abbreviated names of the months (optional)
8445 * monthNames string[12] - names of the months (optional)
8446 * @return Date - the extracted date value or null if value is blank
8448 parseDate: function( format, value, settings ) {
8449 if ( format == null || value == null ) {
8450 throw "Invalid arguments";
8453 value = ( typeof value === "object" ? value.toString() : value + "" );
8454 if ( value === "" ) {
8458 var iFormat, dim, extra,
8460 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
8461 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
8462 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
8463 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8464 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8465 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8466 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8474 // Check whether a format character is doubled
8475 lookAhead = function( match ) {
8476 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8483 // Extract a number from the string value
8484 getNumber = function( match ) {
8485 var isDoubled = lookAhead( match ),
8486 size = ( match === "@" ? 14 : ( match === "!" ? 20 :
8487 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
8488 minSize = ( match === "y" ? size : 1 ),
8489 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
8490 num = value.substring( iValue ).match( digits );
8492 throw "Missing number at position " + iValue;
8494 iValue += num[ 0 ].length;
8495 return parseInt( num[ 0 ], 10 );
8498 // Extract a name from the string value and convert to an index
8499 getName = function( match, shortNames, longNames ) {
8501 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
8502 return [ [ k, v ] ];
8503 } ).sort( function( a, b ) {
8504 return -( a[ 1 ].length - b[ 1 ].length );
8507 $.each( names, function( i, pair ) {
8508 var name = pair[ 1 ];
8509 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
8511 iValue += name.length;
8515 if ( index !== -1 ) {
8518 throw "Unknown name at position " + iValue;
8522 // Confirm that a literal character matches the string value
8523 checkLiteral = function() {
8524 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
8525 throw "Unexpected literal at position " + iValue;
8530 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8532 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8538 switch ( format.charAt( iFormat ) ) {
8540 day = getNumber( "d" );
8543 getName( "D", dayNamesShort, dayNames );
8546 doy = getNumber( "o" );
8549 month = getNumber( "m" );
8552 month = getName( "M", monthNamesShort, monthNames );
8555 year = getNumber( "y" );
8558 date = new Date( getNumber( "@" ) );
8559 year = date.getFullYear();
8560 month = date.getMonth() + 1;
8561 day = date.getDate();
8564 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
8565 year = date.getFullYear();
8566 month = date.getMonth() + 1;
8567 day = date.getDate();
8570 if ( lookAhead( "'" ) ) {
8582 if ( iValue < value.length ) {
8583 extra = value.substr( iValue );
8584 if ( !/^\s+/.test( extra ) ) {
8585 throw "Extra/unparsed characters found in date: " + extra;
8589 if ( year === -1 ) {
8590 year = new Date().getFullYear();
8591 } else if ( year < 100 ) {
8592 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8593 ( year <= shortYearCutoff ? 0 : -100 );
8600 dim = this._getDaysInMonth( year, month - 1 );
8609 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
8610 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
8611 throw "Invalid date"; // E.g. 31/02/00
8616 /* Standard date formats. */
8617 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
8618 COOKIE: "D, dd M yy",
8619 ISO_8601: "yy-mm-dd",
8620 RFC_822: "D, d M y",
8621 RFC_850: "DD, dd-M-y",
8622 RFC_1036: "D, d M y",
8623 RFC_1123: "D, d M yy",
8624 RFC_2822: "D, d M yy",
8625 RSS: "D, d M y", // RFC 822
8628 W3C: "yy-mm-dd", // ISO 8601
8630 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
8631 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
8633 /* Format a date object into a string value.
8634 * The format can be combinations of the following:
8635 * d - day of month (no leading zero)
8636 * dd - day of month (two digit)
8637 * o - day of year (no leading zeros)
8638 * oo - day of year (three digit)
8639 * D - day name short
8640 * DD - day name long
8641 * m - month of year (no leading zero)
8642 * mm - month of year (two digit)
8643 * M - month name short
8644 * MM - month name long
8645 * y - year (two digit)
8646 * yy - year (four digit)
8647 * @ - Unix timestamp (ms since 01/01/1970)
8648 * ! - Windows ticks (100ns since 01/01/0001)
8649 * "..." - literal text
8652 * @param format string - the desired format of the date
8653 * @param date Date - the date value to format
8654 * @param settings Object - attributes include:
8655 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8656 * dayNames string[7] - names of the days from Sunday (optional)
8657 * monthNamesShort string[12] - abbreviated names of the months (optional)
8658 * monthNames string[12] - names of the months (optional)
8659 * @return string - the date in the above format
8661 formatDate: function( format, date, settings ) {
8667 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8668 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8669 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8670 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8672 // Check whether a format character is doubled
8673 lookAhead = function( match ) {
8674 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8681 // Format a number, with leading zero if necessary
8682 formatNumber = function( match, value, len ) {
8683 var num = "" + value;
8684 if ( lookAhead( match ) ) {
8685 while ( num.length < len ) {
8692 // Format a name, short or long as requested
8693 formatName = function( match, value, shortNames, longNames ) {
8694 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
8700 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8702 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8705 output += format.charAt( iFormat );
8708 switch ( format.charAt( iFormat ) ) {
8710 output += formatNumber( "d", date.getDate(), 2 );
8713 output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
8716 output += formatNumber( "o",
8717 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
8720 output += formatNumber( "m", date.getMonth() + 1, 2 );
8723 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
8726 output += ( lookAhead( "y" ) ? date.getFullYear() :
8727 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
8730 output += date.getTime();
8733 output += date.getTime() * 10000 + this._ticksTo1970;
8736 if ( lookAhead( "'" ) ) {
8743 output += format.charAt( iFormat );
8751 /* Extract all possible characters from the date format. */
8752 _possibleChars: function( format ) {
8757 // Check whether a format character is doubled
8758 lookAhead = function( match ) {
8759 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8766 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8768 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8771 chars += format.charAt( iFormat );
8774 switch ( format.charAt( iFormat ) ) {
8775 case "d": case "m": case "y": case "@":
8776 chars += "0123456789";
8779 return null; // Accept anything
8781 if ( lookAhead( "'" ) ) {
8788 chars += format.charAt( iFormat );
8795 /* Get a setting value, defaulting if necessary. */
8796 _get: function( inst, name ) {
8797 return inst.settings[ name ] !== undefined ?
8798 inst.settings[ name ] : this._defaults[ name ];
8801 /* Parse existing date and initialise date picker. */
8802 _setDateFromField: function( inst, noDefault ) {
8803 if ( inst.input.val() === inst.lastVal ) {
8807 var dateFormat = this._get( inst, "dateFormat" ),
8808 dates = inst.lastVal = inst.input ? inst.input.val() : null,
8809 defaultDate = this._getDefaultDate( inst ),
8811 settings = this._getFormatConfig( inst );
8814 date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
8816 dates = ( noDefault ? "" : dates );
8818 inst.selectedDay = date.getDate();
8819 inst.drawMonth = inst.selectedMonth = date.getMonth();
8820 inst.drawYear = inst.selectedYear = date.getFullYear();
8821 inst.currentDay = ( dates ? date.getDate() : 0 );
8822 inst.currentMonth = ( dates ? date.getMonth() : 0 );
8823 inst.currentYear = ( dates ? date.getFullYear() : 0 );
8824 this._adjustInstDate( inst );
8827 /* Retrieve the default date shown on opening. */
8828 _getDefaultDate: function( inst ) {
8829 return this._restrictMinMax( inst,
8830 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
8833 /* A date may be specified as an exact value or a relative one. */
8834 _determineDate: function( inst, date, defaultDate ) {
8835 var offsetNumeric = function( offset ) {
8836 var date = new Date();
8837 date.setDate( date.getDate() + offset );
8840 offsetString = function( offset ) {
8842 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
8843 offset, $.datepicker._getFormatConfig( inst ) );
8849 var date = ( offset.toLowerCase().match( /^c/ ) ?
8850 $.datepicker._getDate( inst ) : null ) || new Date(),
8851 year = date.getFullYear(),
8852 month = date.getMonth(),
8853 day = date.getDate(),
8854 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
8855 matches = pattern.exec( offset );
8858 switch ( matches[ 2 ] || "d" ) {
8859 case "d" : case "D" :
8860 day += parseInt( matches[ 1 ], 10 ); break;
8861 case "w" : case "W" :
8862 day += parseInt( matches[ 1 ], 10 ) * 7; break;
8863 case "m" : case "M" :
8864 month += parseInt( matches[ 1 ], 10 );
8865 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8867 case "y": case "Y" :
8868 year += parseInt( matches[ 1 ], 10 );
8869 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8872 matches = pattern.exec( offset );
8874 return new Date( year, month, day );
8876 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
8877 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
8879 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
8881 newDate.setHours( 0 );
8882 newDate.setMinutes( 0 );
8883 newDate.setSeconds( 0 );
8884 newDate.setMilliseconds( 0 );
8886 return this._daylightSavingAdjust( newDate );
8889 /* Handle switch to/from daylight saving.
8890 * Hours may be non-zero on daylight saving cut-over:
8891 * > 12 when midnight changeover, but then cannot generate
8892 * midnight datetime, so jump to 1AM, otherwise reset.
8893 * @param date (Date) the date to check
8894 * @return (Date) the corrected date
8896 _daylightSavingAdjust: function( date ) {
8900 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
8904 /* Set the date(s) directly. */
8905 _setDate: function( inst, date, noChange ) {
8907 origMonth = inst.selectedMonth,
8908 origYear = inst.selectedYear,
8909 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
8911 inst.selectedDay = inst.currentDay = newDate.getDate();
8912 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
8913 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
8914 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
8915 this._notifyChange( inst );
8917 this._adjustInstDate( inst );
8919 inst.input.val( clear ? "" : this._formatDate( inst ) );
8923 /* Retrieve the date(s) directly. */
8924 _getDate: function( inst ) {
8925 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
8926 this._daylightSavingAdjust( new Date(
8927 inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
8931 /* Attach the onxxx handlers. These are declared statically so
8932 * they work with static code transformers like Caja.
8934 _attachHandlers: function( inst ) {
8935 var stepMonths = this._get( inst, "stepMonths" ),
8936 id = "#" + inst.id.replace( /\\\\/g, "\\" );
8937 inst.dpDiv.find( "[data-handler]" ).map( function() {
8940 $.datepicker._adjustDate( id, -stepMonths, "M" );
8943 $.datepicker._adjustDate( id, +stepMonths, "M" );
8946 $.datepicker._hideDatepicker();
8949 $.datepicker._gotoToday( id );
8951 selectDay: function() {
8952 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
8955 selectMonth: function() {
8956 $.datepicker._selectMonthYear( id, this, "M" );
8959 selectYear: function() {
8960 $.datepicker._selectMonthYear( id, this, "Y" );
8964 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
8968 /* Generate the HTML for the current state of the date picker. */
8969 _generateHTML: function( inst ) {
8970 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
8971 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
8972 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
8973 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
8974 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
8975 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
8976 tempDate = new Date(),
8977 today = this._daylightSavingAdjust(
8978 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
8979 isRTL = this._get( inst, "isRTL" ),
8980 showButtonPanel = this._get( inst, "showButtonPanel" ),
8981 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
8982 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
8983 numMonths = this._getNumberOfMonths( inst ),
8984 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
8985 stepMonths = this._get( inst, "stepMonths" ),
8986 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
8987 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
8988 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
8989 minDate = this._getMinMaxDate( inst, "min" ),
8990 maxDate = this._getMinMaxDate( inst, "max" ),
8991 drawMonth = inst.drawMonth - showCurrentAtPos,
8992 drawYear = inst.drawYear;
8994 if ( drawMonth < 0 ) {
8999 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
9000 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
9001 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
9002 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
9004 if ( drawMonth < 0 ) {
9010 inst.drawMonth = drawMonth;
9011 inst.drawYear = drawYear;
9013 prevText = this._get( inst, "prevText" );
9014 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
9015 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
9016 this._getFormatConfig( inst ) ) );
9018 if ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ) {
9021 "class": "ui-datepicker-prev ui-corner-all",
9022 "data-handler": "prev",
9023 "data-event": "click",
9028 .addClass( "ui-icon ui-icon-circle-triangle-" +
9029 ( isRTL ? "e" : "w" ) )
9032 } else if ( hideIfNoPrevNext ) {
9037 "class": "ui-datepicker-prev ui-corner-all ui-state-disabled",
9042 .addClass( "ui-icon ui-icon-circle-triangle-" +
9043 ( isRTL ? "e" : "w" ) )
9048 nextText = this._get( inst, "nextText" );
9049 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
9050 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
9051 this._getFormatConfig( inst ) ) );
9053 if ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ) {
9056 "class": "ui-datepicker-next ui-corner-all",
9057 "data-handler": "next",
9058 "data-event": "click",
9063 .addClass( "ui-icon ui-icon-circle-triangle-" +
9064 ( isRTL ? "w" : "e" ) )
9067 } else if ( hideIfNoPrevNext ) {
9072 "class": "ui-datepicker-next ui-corner-all ui-state-disabled",
9077 .attr( "class", "ui-icon ui-icon-circle-triangle-" +
9078 ( isRTL ? "w" : "e" ) )
9083 currentText = this._get( inst, "currentText" );
9084 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
9085 currentText = ( !navigationAsDateFormat ? currentText :
9086 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
9089 if ( !inst.inline ) {
9090 controls = $( "<button>" )
9093 "class": "ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all",
9094 "data-handler": "hide",
9095 "data-event": "click"
9097 .text( this._get( inst, "closeText" ) )[ 0 ].outerHTML;
9101 if ( showButtonPanel ) {
9102 buttonPanel = $( "<div class='ui-datepicker-buttonpane ui-widget-content'>" )
9103 .append( isRTL ? controls : "" )
9104 .append( this._isInRange( inst, gotoDate ) ?
9108 "class": "ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all",
9109 "data-handler": "today",
9110 "data-event": "click"
9112 .text( currentText ) :
9114 .append( isRTL ? "" : controls )[ 0 ].outerHTML;
9117 firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
9118 firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
9120 showWeek = this._get( inst, "showWeek" );
9121 dayNames = this._get( inst, "dayNames" );
9122 dayNamesMin = this._get( inst, "dayNamesMin" );
9123 monthNames = this._get( inst, "monthNames" );
9124 monthNamesShort = this._get( inst, "monthNamesShort" );
9125 beforeShowDay = this._get( inst, "beforeShowDay" );
9126 showOtherMonths = this._get( inst, "showOtherMonths" );
9127 selectOtherMonths = this._get( inst, "selectOtherMonths" );
9128 defaultDate = this._getDefaultDate( inst );
9131 for ( row = 0; row < numMonths[ 0 ]; row++ ) {
9134 for ( col = 0; col < numMonths[ 1 ]; col++ ) {
9135 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
9136 cornerClass = " ui-corner-all";
9138 if ( isMultiMonth ) {
9139 calender += "<div class='ui-datepicker-group";
9140 if ( numMonths[ 1 ] > 1 ) {
9142 case 0: calender += " ui-datepicker-group-first";
9143 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
9144 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
9145 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
9146 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
9151 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
9152 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
9153 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
9154 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
9155 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
9156 "</div><table class='ui-datepicker-calendar'><thead>" +
9158 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
9159 for ( dow = 0; dow < 7; dow++ ) { // days of the week
9160 day = ( dow + firstDay ) % 7;
9161 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
9162 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
9164 calender += thead + "</tr></thead><tbody>";
9165 daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
9166 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
9167 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
9169 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
9170 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
9171 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
9172 this.maxRows = numRows;
9173 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
9174 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
9176 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
9177 this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
9178 for ( dow = 0; dow < 7; dow++ ) { // create date picker days
9179 daySettings = ( beforeShowDay ?
9180 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
9181 otherMonth = ( printDate.getMonth() !== drawMonth );
9182 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
9183 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
9184 tbody += "<td class='" +
9185 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
9186 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
9187 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
9188 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
9190 // or defaultDate is current printedDate and defaultDate is selectedDate
9191 " " + this._dayOverClass : "" ) + // highlight selected day
9192 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
9193 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
9194 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
9195 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
9196 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title
9197 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
9198 ( otherMonth && !showOtherMonths ? " " : // display for other months
9199 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
9200 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
9201 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
9202 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
9203 "' href='#' aria-current='" + ( printDate.getTime() === currentDate.getTime() ? "true" : "false" ) + // mark date as selected for screen reader
9204 "' data-date='" + printDate.getDate() + // store date as data
9205 "'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
9206 printDate.setDate( printDate.getDate() + 1 );
9207 printDate = this._daylightSavingAdjust( printDate );
9209 calender += tbody + "</tr>";
9212 if ( drawMonth > 11 ) {
9216 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
9217 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
9222 html += buttonPanel;
9223 inst._keyEvent = false;
9227 /* Generate the month and year header. */
9228 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
9229 secondary, monthNames, monthNamesShort ) {
9231 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
9232 changeMonth = this._get( inst, "changeMonth" ),
9233 changeYear = this._get( inst, "changeYear" ),
9234 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
9235 selectMonthLabel = this._get( inst, "selectMonthLabel" ),
9236 selectYearLabel = this._get( inst, "selectYearLabel" ),
9237 html = "<div class='ui-datepicker-title'>",
9241 if ( secondary || !changeMonth ) {
9242 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
9244 inMinYear = ( minDate && minDate.getFullYear() === drawYear );
9245 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
9246 monthHtml += "<select class='ui-datepicker-month' aria-label='" + selectMonthLabel + "' data-handler='selectMonth' data-event='change'>";
9247 for ( month = 0; month < 12; month++ ) {
9248 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
9249 monthHtml += "<option value='" + month + "'" +
9250 ( month === drawMonth ? " selected='selected'" : "" ) +
9251 ">" + monthNamesShort[ month ] + "</option>";
9254 monthHtml += "</select>";
9257 if ( !showMonthAfterYear ) {
9258 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" );
9262 if ( !inst.yearshtml ) {
9263 inst.yearshtml = "";
9264 if ( secondary || !changeYear ) {
9265 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9268 // determine range of years to display
9269 years = this._get( inst, "yearRange" ).split( ":" );
9270 thisYear = new Date().getFullYear();
9271 determineYear = function( value ) {
9272 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
9273 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
9274 parseInt( value, 10 ) ) );
9275 return ( isNaN( year ) ? thisYear : year );
9277 year = determineYear( years[ 0 ] );
9278 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
9279 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
9280 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
9281 inst.yearshtml += "<select class='ui-datepicker-year' aria-label='" + selectYearLabel + "' data-handler='selectYear' data-event='change'>";
9282 for ( ; year <= endYear; year++ ) {
9283 inst.yearshtml += "<option value='" + year + "'" +
9284 ( year === drawYear ? " selected='selected'" : "" ) +
9285 ">" + year + "</option>";
9287 inst.yearshtml += "</select>";
9289 html += inst.yearshtml;
9290 inst.yearshtml = null;
9294 html += this._get( inst, "yearSuffix" );
9295 if ( showMonthAfterYear ) {
9296 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml;
9298 html += "</div>"; // Close datepicker_header
9302 /* Adjust one of the date sub-fields. */
9303 _adjustInstDate: function( inst, offset, period ) {
9304 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
9305 month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
9306 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
9307 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
9309 inst.selectedDay = date.getDate();
9310 inst.drawMonth = inst.selectedMonth = date.getMonth();
9311 inst.drawYear = inst.selectedYear = date.getFullYear();
9312 if ( period === "M" || period === "Y" ) {
9313 this._notifyChange( inst );
9317 /* Ensure a date is within any min/max bounds. */
9318 _restrictMinMax: function( inst, date ) {
9319 var minDate = this._getMinMaxDate( inst, "min" ),
9320 maxDate = this._getMinMaxDate( inst, "max" ),
9321 newDate = ( minDate && date < minDate ? minDate : date );
9322 return ( maxDate && newDate > maxDate ? maxDate : newDate );
9325 /* Notify change of month/year. */
9326 _notifyChange: function( inst ) {
9327 var onChange = this._get( inst, "onChangeMonthYear" );
9329 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
9330 [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
9334 /* Determine the number of months to show. */
9335 _getNumberOfMonths: function( inst ) {
9336 var numMonths = this._get( inst, "numberOfMonths" );
9337 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
9340 /* Determine the current maximum date - ensure no time components are set. */
9341 _getMinMaxDate: function( inst, minMax ) {
9342 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
9345 /* Find the number of days in a given month. */
9346 _getDaysInMonth: function( year, month ) {
9347 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
9350 /* Find the day of the week of the first of a month. */
9351 _getFirstDayOfMonth: function( year, month ) {
9352 return new Date( year, month, 1 ).getDay();
9355 /* Determines if we should allow a "next/prev" month display change. */
9356 _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
9357 var numMonths = this._getNumberOfMonths( inst ),
9358 date = this._daylightSavingAdjust( new Date( curYear,
9359 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
9362 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
9364 return this._isInRange( inst, date );
9367 /* Is the given date in the accepted range? */
9368 _isInRange: function( inst, date ) {
9369 var yearSplit, currentYear,
9370 minDate = this._getMinMaxDate( inst, "min" ),
9371 maxDate = this._getMinMaxDate( inst, "max" ),
9374 years = this._get( inst, "yearRange" );
9376 yearSplit = years.split( ":" );
9377 currentYear = new Date().getFullYear();
9378 minYear = parseInt( yearSplit[ 0 ], 10 );
9379 maxYear = parseInt( yearSplit[ 1 ], 10 );
9380 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
9381 minYear += currentYear;
9383 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
9384 maxYear += currentYear;
9388 return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
9389 ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
9390 ( !minYear || date.getFullYear() >= minYear ) &&
9391 ( !maxYear || date.getFullYear() <= maxYear ) );
9394 /* Provide the configuration settings for formatting/parsing. */
9395 _getFormatConfig: function( inst ) {
9396 var shortYearCutoff = this._get( inst, "shortYearCutoff" );
9397 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
9398 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
9399 return { shortYearCutoff: shortYearCutoff,
9400 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
9401 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
9404 /* Format the given date for display. */
9405 _formatDate: function( inst, day, month, year ) {
9407 inst.currentDay = inst.selectedDay;
9408 inst.currentMonth = inst.selectedMonth;
9409 inst.currentYear = inst.selectedYear;
9411 var date = ( day ? ( typeof day === "object" ? day :
9412 this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
9413 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
9414 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
9419 * Bind hover events for datepicker elements.
9420 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9421 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9423 function datepicker_bindHover( dpDiv ) {
9424 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9425 return dpDiv.on( "mouseout", selector, function() {
9426 $( this ).removeClass( "ui-state-hover" );
9427 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9428 $( this ).removeClass( "ui-datepicker-prev-hover" );
9430 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9431 $( this ).removeClass( "ui-datepicker-next-hover" );
9434 .on( "mouseover", selector, datepicker_handleMouseover );
9437 function datepicker_handleMouseover() {
9438 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
9439 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
9440 $( this ).addClass( "ui-state-hover" );
9441 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9442 $( this ).addClass( "ui-datepicker-prev-hover" );
9444 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9445 $( this ).addClass( "ui-datepicker-next-hover" );
9450 /* jQuery extend now ignores nulls! */
9451 function datepicker_extendRemove( target, props ) {
9452 $.extend( target, props );
9453 for ( var name in props ) {
9454 if ( props[ name ] == null ) {
9455 target[ name ] = props[ name ];
9461 /* Invoke the datepicker functionality.
9462 @param options string - a command, optionally followed by additional parameters or
9463 Object - settings for attaching new datepicker functionality
9464 @return jQuery object */
9465 $.fn.datepicker = function( options ) {
9467 /* Verify an empty collection wasn't passed - Fixes #6976 */
9468 if ( !this.length ) {
9472 /* Initialise the date picker. */
9473 if ( !$.datepicker.initialized ) {
9474 $( document ).on( "mousedown", $.datepicker._checkExternalClick );
9475 $.datepicker.initialized = true;
9478 /* Append datepicker main container to body if not exist. */
9479 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
9480 $( "body" ).append( $.datepicker.dpDiv );
9483 var otherArgs = Array.prototype.slice.call( arguments, 1 );
9484 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
9485 return $.datepicker[ "_" + options + "Datepicker" ].
9486 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9488 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
9489 return $.datepicker[ "_" + options + "Datepicker" ].
9490 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9492 return this.each( function() {
9493 if ( typeof options === "string" ) {
9494 $.datepicker[ "_" + options + "Datepicker" ]
9495 .apply( $.datepicker, [ this ].concat( otherArgs ) );
9497 $.datepicker._attachDatepicker( this, options );
9502 $.datepicker = new Datepicker(); // singleton instance
9503 $.datepicker.initialized = false;
9504 $.datepicker.uuid = new Date().getTime();
9505 $.datepicker.version = "1.13.0";
9507 var widgetsDatepicker = $.datepicker;
9511 // This file is deprecated
9512 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
9515 * jQuery UI Mouse 1.13.0
9516 * http://jqueryui.com
9518 * Copyright jQuery Foundation and other contributors
9519 * Released under the MIT license.
9520 * http://jquery.org/license
9525 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
9526 //>>docs: http://api.jqueryui.com/mouse/
9529 var mouseHandled = false;
9530 $( document ).on( "mouseup", function() {
9531 mouseHandled = false;
9534 var widgetsMouse = $.widget( "ui.mouse", {
9537 cancel: "input, textarea, button, select, option",
9541 _mouseInit: function() {
9545 .on( "mousedown." + this.widgetName, function( event ) {
9546 return that._mouseDown( event );
9548 .on( "click." + this.widgetName, function( event ) {
9549 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
9550 $.removeData( event.target, that.widgetName + ".preventClickEvent" );
9551 event.stopImmediatePropagation();
9556 this.started = false;
9559 // TODO: make sure destroying one instance of mouse doesn't mess with
9560 // other instances of mouse
9561 _mouseDestroy: function() {
9562 this.element.off( "." + this.widgetName );
9563 if ( this._mouseMoveDelegate ) {
9565 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9566 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9570 _mouseDown: function( event ) {
9572 // don't let more than one widget handle mouseStart
9573 if ( mouseHandled ) {
9577 this._mouseMoved = false;
9579 // We may have missed mouseup (out of window)
9580 if ( this._mouseStarted ) {
9581 this._mouseUp( event );
9584 this._mouseDownEvent = event;
9587 btnIsLeft = ( event.which === 1 ),
9589 // event.target.nodeName works around a bug in IE 8 with
9590 // disabled inputs (#7620)
9591 elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
9592 $( event.target ).closest( this.options.cancel ).length : false );
9593 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
9597 this.mouseDelayMet = !this.options.delay;
9598 if ( !this.mouseDelayMet ) {
9599 this._mouseDelayTimer = setTimeout( function() {
9600 that.mouseDelayMet = true;
9601 }, this.options.delay );
9604 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9605 this._mouseStarted = ( this._mouseStart( event ) !== false );
9606 if ( !this._mouseStarted ) {
9607 event.preventDefault();
9612 // Click event may never have fired (Gecko & Opera)
9613 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
9614 $.removeData( event.target, this.widgetName + ".preventClickEvent" );
9617 // These delegates are required to keep context
9618 this._mouseMoveDelegate = function( event ) {
9619 return that._mouseMove( event );
9621 this._mouseUpDelegate = function( event ) {
9622 return that._mouseUp( event );
9626 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9627 .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
9629 event.preventDefault();
9631 mouseHandled = true;
9635 _mouseMove: function( event ) {
9637 // Only check for mouseups outside the document if you've moved inside the document
9638 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
9639 // fire a mousemove event if content is placed under the cursor. See #7778
9641 if ( this._mouseMoved ) {
9643 // IE mouseup check - mouseup happened when mouse was out of window
9644 if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
9646 return this._mouseUp( event );
9648 // Iframe mouseup check - mouseup occurred in another document
9649 } else if ( !event.which ) {
9651 // Support: Safari <=8 - 9
9652 // Safari sets which to 0 if you press any of the following keys
9653 // during a drag (#14461)
9654 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
9655 event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
9656 this.ignoreMissingWhich = true;
9657 } else if ( !this.ignoreMissingWhich ) {
9658 return this._mouseUp( event );
9663 if ( event.which || event.button ) {
9664 this._mouseMoved = true;
9667 if ( this._mouseStarted ) {
9668 this._mouseDrag( event );
9669 return event.preventDefault();
9672 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9673 this._mouseStarted =
9674 ( this._mouseStart( this._mouseDownEvent, event ) !== false );
9675 if ( this._mouseStarted ) {
9676 this._mouseDrag( event );
9678 this._mouseUp( event );
9682 return !this._mouseStarted;
9685 _mouseUp: function( event ) {
9687 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9688 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9690 if ( this._mouseStarted ) {
9691 this._mouseStarted = false;
9693 if ( event.target === this._mouseDownEvent.target ) {
9694 $.data( event.target, this.widgetName + ".preventClickEvent", true );
9697 this._mouseStop( event );
9700 if ( this._mouseDelayTimer ) {
9701 clearTimeout( this._mouseDelayTimer );
9702 delete this._mouseDelayTimer;
9705 this.ignoreMissingWhich = false;
9706 mouseHandled = false;
9707 event.preventDefault();
9710 _mouseDistanceMet: function( event ) {
9712 Math.abs( this._mouseDownEvent.pageX - event.pageX ),
9713 Math.abs( this._mouseDownEvent.pageY - event.pageY )
9714 ) >= this.options.distance
9718 _mouseDelayMet: function( /* event */ ) {
9719 return this.mouseDelayMet;
9722 // These are placeholder methods, to be overriden by extending plugin
9723 _mouseStart: function( /* event */ ) {},
9724 _mouseDrag: function( /* event */ ) {},
9725 _mouseStop: function( /* event */ ) {},
9726 _mouseCapture: function( /* event */ ) {
9733 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
9734 var plugin = $.ui.plugin = {
9735 add: function( module, option, set ) {
9737 proto = $.ui[ module ].prototype;
9739 proto.plugins[ i ] = proto.plugins[ i ] || [];
9740 proto.plugins[ i ].push( [ option, set[ i ] ] );
9743 call: function( instance, name, args, allowDisconnected ) {
9745 set = instance.plugins[ name ];
9751 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
9752 instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
9756 for ( i = 0; i < set.length; i++ ) {
9757 if ( instance.options[ set[ i ][ 0 ] ] ) {
9758 set[ i ][ 1 ].apply( instance.element, args );
9766 var safeBlur = $.ui.safeBlur = function( element ) {
9768 // Support: IE9 - 10 only
9769 // If the <body> is blurred, IE will switch windows, see #9420
9770 if ( element && element.nodeName.toLowerCase() !== "body" ) {
9771 $( element ).trigger( "blur" );
9777 * jQuery UI Draggable 1.13.0
9778 * http://jqueryui.com
9780 * Copyright jQuery Foundation and other contributors
9781 * Released under the MIT license.
9782 * http://jquery.org/license
9785 //>>label: Draggable
9786 //>>group: Interactions
9787 //>>description: Enables dragging functionality for any element.
9788 //>>docs: http://api.jqueryui.com/draggable/
9789 //>>demos: http://jqueryui.com/draggable/
9790 //>>css.structure: ../../themes/base/draggable.css
9793 $.widget( "ui.draggable", $.ui.mouse, {
9795 widgetEventPrefix: "drag",
9800 connectToSortable: false,
9809 refreshPositions: false,
9811 revertDuration: 500,
9814 scrollSensitivity: 20,
9827 _create: function() {
9829 if ( this.options.helper === "original" ) {
9830 this._setPositionRelative();
9832 if ( this.options.addClasses ) {
9833 this._addClass( "ui-draggable" );
9835 this._setHandleClassName();
9840 _setOption: function( key, value ) {
9841 this._super( key, value );
9842 if ( key === "handle" ) {
9843 this._removeHandleClassName();
9844 this._setHandleClassName();
9848 _destroy: function() {
9849 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
9850 this.destroyOnClear = true;
9853 this._removeHandleClassName();
9854 this._mouseDestroy();
9857 _mouseCapture: function( event ) {
9858 var o = this.options;
9860 // Among others, prevent a drag on a resizable-handle
9861 if ( this.helper || o.disabled ||
9862 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
9866 //Quit if we're not on a valid handle
9867 this.handle = this._getHandle( event );
9868 if ( !this.handle ) {
9872 this._blurActiveElement( event );
9874 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
9880 _blockFrames: function( selector ) {
9881 this.iframeBlocks = this.document.find( selector ).map( function() {
9882 var iframe = $( this );
9885 .css( "position", "absolute" )
9886 .appendTo( iframe.parent() )
9887 .outerWidth( iframe.outerWidth() )
9888 .outerHeight( iframe.outerHeight() )
9889 .offset( iframe.offset() )[ 0 ];
9893 _unblockFrames: function() {
9894 if ( this.iframeBlocks ) {
9895 this.iframeBlocks.remove();
9896 delete this.iframeBlocks;
9900 _blurActiveElement: function( event ) {
9901 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
9902 target = $( event.target );
9904 // Don't blur if the event occurred on an element that is within
9905 // the currently focused element
9906 // See #10527, #12472
9907 if ( target.closest( activeElement ).length ) {
9911 // Blur any element that currently has focus, see #4261
9912 $.ui.safeBlur( activeElement );
9915 _mouseStart: function( event ) {
9917 var o = this.options;
9919 //Create and append the visible helper
9920 this.helper = this._createHelper( event );
9922 this._addClass( this.helper, "ui-draggable-dragging" );
9924 //Cache the helper size
9925 this._cacheHelperProportions();
9927 //If ddmanager is used for droppables, set the global draggable
9928 if ( $.ui.ddmanager ) {
9929 $.ui.ddmanager.current = this;
9933 * - Position generation -
9934 * This block generates everything position related - it's the core of draggables.
9937 //Cache the margins of the original element
9938 this._cacheMargins();
9940 //Store the helper's css position
9941 this.cssPosition = this.helper.css( "position" );
9942 this.scrollParent = this.helper.scrollParent( true );
9943 this.offsetParent = this.helper.offsetParent();
9944 this.hasFixedAncestor = this.helper.parents().filter( function() {
9945 return $( this ).css( "position" ) === "fixed";
9948 //The element's absolute position on the page minus margins
9949 this.positionAbs = this.element.offset();
9950 this._refreshOffsets( event );
9952 //Generate the original position
9953 this.originalPosition = this.position = this._generatePosition( event, false );
9954 this.originalPageX = event.pageX;
9955 this.originalPageY = event.pageY;
9957 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
9959 this._adjustOffsetFromHelper( o.cursorAt );
9962 //Set a containment if given in the options
9963 this._setContainment();
9965 //Trigger event + callbacks
9966 if ( this._trigger( "start", event ) === false ) {
9971 //Recache the helper size
9972 this._cacheHelperProportions();
9974 //Prepare the droppable offsets
9975 if ( $.ui.ddmanager && !o.dropBehaviour ) {
9976 $.ui.ddmanager.prepareOffsets( this, event );
9979 // Execute the drag once - this causes the helper not to be visible before getting its
9981 this._mouseDrag( event, true );
9983 // If the ddmanager is used for droppables, inform the manager that dragging has started
9985 if ( $.ui.ddmanager ) {
9986 $.ui.ddmanager.dragStart( this, event );
9992 _refreshOffsets: function( event ) {
9994 top: this.positionAbs.top - this.margins.top,
9995 left: this.positionAbs.left - this.margins.left,
9997 parent: this._getParentOffset(),
9998 relative: this._getRelativeOffset()
10001 this.offset.click = {
10002 left: event.pageX - this.offset.left,
10003 top: event.pageY - this.offset.top
10007 _mouseDrag: function( event, noPropagation ) {
10009 // reset any necessary cached properties (see #5009)
10010 if ( this.hasFixedAncestor ) {
10011 this.offset.parent = this._getParentOffset();
10014 //Compute the helpers position
10015 this.position = this._generatePosition( event, true );
10016 this.positionAbs = this._convertPositionTo( "absolute" );
10018 //Call plugins and callbacks and use the resulting position if something is returned
10019 if ( !noPropagation ) {
10020 var ui = this._uiHash();
10021 if ( this._trigger( "drag", event, ui ) === false ) {
10022 this._mouseUp( new $.Event( "mouseup", event ) );
10025 this.position = ui.position;
10028 this.helper[ 0 ].style.left = this.position.left + "px";
10029 this.helper[ 0 ].style.top = this.position.top + "px";
10031 if ( $.ui.ddmanager ) {
10032 $.ui.ddmanager.drag( this, event );
10038 _mouseStop: function( event ) {
10040 //If we are using droppables, inform the manager about the drop
10043 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
10044 dropped = $.ui.ddmanager.drop( this, event );
10047 //if a drop comes from outside (a sortable)
10048 if ( this.dropped ) {
10049 dropped = this.dropped;
10050 this.dropped = false;
10053 if ( ( this.options.revert === "invalid" && !dropped ) ||
10054 ( this.options.revert === "valid" && dropped ) ||
10055 this.options.revert === true || ( typeof this.options.revert === "function" &&
10056 this.options.revert.call( this.element, dropped ) )
10058 $( this.helper ).animate(
10059 this.originalPosition,
10060 parseInt( this.options.revertDuration, 10 ),
10062 if ( that._trigger( "stop", event ) !== false ) {
10068 if ( this._trigger( "stop", event ) !== false ) {
10076 _mouseUp: function( event ) {
10077 this._unblockFrames();
10079 // If the ddmanager is used for droppables, inform the manager that dragging has stopped
10081 if ( $.ui.ddmanager ) {
10082 $.ui.ddmanager.dragStop( this, event );
10085 // Only need to focus if the event occurred on the draggable itself, see #10527
10086 if ( this.handleElement.is( event.target ) ) {
10088 // The interaction is over; whether or not the click resulted in a drag,
10089 // focus the element
10090 this.element.trigger( "focus" );
10093 return $.ui.mouse.prototype._mouseUp.call( this, event );
10096 cancel: function() {
10098 if ( this.helper.is( ".ui-draggable-dragging" ) ) {
10099 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
10108 _getHandle: function( event ) {
10109 return this.options.handle ?
10110 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
10114 _setHandleClassName: function() {
10115 this.handleElement = this.options.handle ?
10116 this.element.find( this.options.handle ) : this.element;
10117 this._addClass( this.handleElement, "ui-draggable-handle" );
10120 _removeHandleClassName: function() {
10121 this._removeClass( this.handleElement, "ui-draggable-handle" );
10124 _createHelper: function( event ) {
10126 var o = this.options,
10127 helperIsFunction = typeof o.helper === "function",
10128 helper = helperIsFunction ?
10129 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
10130 ( o.helper === "clone" ?
10131 this.element.clone().removeAttr( "id" ) :
10134 if ( !helper.parents( "body" ).length ) {
10135 helper.appendTo( ( o.appendTo === "parent" ?
10136 this.element[ 0 ].parentNode :
10140 // Http://bugs.jqueryui.com/ticket/9446
10141 // a helper function can return the original element
10142 // which wouldn't have been set to relative in _create
10143 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
10144 this._setPositionRelative();
10147 if ( helper[ 0 ] !== this.element[ 0 ] &&
10148 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
10149 helper.css( "position", "absolute" );
10156 _setPositionRelative: function() {
10157 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
10158 this.element[ 0 ].style.position = "relative";
10162 _adjustOffsetFromHelper: function( obj ) {
10163 if ( typeof obj === "string" ) {
10164 obj = obj.split( " " );
10166 if ( Array.isArray( obj ) ) {
10167 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
10169 if ( "left" in obj ) {
10170 this.offset.click.left = obj.left + this.margins.left;
10172 if ( "right" in obj ) {
10173 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
10175 if ( "top" in obj ) {
10176 this.offset.click.top = obj.top + this.margins.top;
10178 if ( "bottom" in obj ) {
10179 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
10183 _isRootNode: function( element ) {
10184 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
10187 _getParentOffset: function() {
10189 //Get the offsetParent and cache its position
10190 var po = this.offsetParent.offset(),
10191 document = this.document[ 0 ];
10193 // This is a special case where we need to modify a offset calculated on start, since the
10194 // following happened:
10195 // 1. The position of the helper is absolute, so it's position is calculated based on the
10196 // next positioned parent
10197 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
10198 // the document, which means that the scroll is included in the initial calculation of the
10199 // offset of the parent, and never recalculated upon drag
10200 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
10201 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
10202 po.left += this.scrollParent.scrollLeft();
10203 po.top += this.scrollParent.scrollTop();
10206 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
10207 po = { top: 0, left: 0 };
10211 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
10212 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
10217 _getRelativeOffset: function() {
10218 if ( this.cssPosition !== "relative" ) {
10219 return { top: 0, left: 0 };
10222 var p = this.element.position(),
10223 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
10226 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
10227 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
10228 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
10229 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
10234 _cacheMargins: function() {
10236 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
10237 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
10238 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
10239 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
10243 _cacheHelperProportions: function() {
10244 this.helperProportions = {
10245 width: this.helper.outerWidth(),
10246 height: this.helper.outerHeight()
10250 _setContainment: function() {
10252 var isUserScrollable, c, ce,
10254 document = this.document[ 0 ];
10256 this.relativeContainer = null;
10258 if ( !o.containment ) {
10259 this.containment = null;
10263 if ( o.containment === "window" ) {
10264 this.containment = [
10265 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
10266 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
10267 $( window ).scrollLeft() + $( window ).width() -
10268 this.helperProportions.width - this.margins.left,
10269 $( window ).scrollTop() +
10270 ( $( window ).height() || document.body.parentNode.scrollHeight ) -
10271 this.helperProportions.height - this.margins.top
10276 if ( o.containment === "document" ) {
10277 this.containment = [
10280 $( document ).width() - this.helperProportions.width - this.margins.left,
10281 ( $( document ).height() || document.body.parentNode.scrollHeight ) -
10282 this.helperProportions.height - this.margins.top
10287 if ( o.containment.constructor === Array ) {
10288 this.containment = o.containment;
10292 if ( o.containment === "parent" ) {
10293 o.containment = this.helper[ 0 ].parentNode;
10296 c = $( o.containment );
10303 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
10305 this.containment = [
10306 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
10307 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
10308 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
10309 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
10310 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
10311 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
10312 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
10313 this.helperProportions.width -
10314 this.margins.left -
10315 this.margins.right,
10316 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
10317 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
10318 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
10319 this.helperProportions.height -
10321 this.margins.bottom
10323 this.relativeContainer = c;
10326 _convertPositionTo: function( d, pos ) {
10329 pos = this.position;
10332 var mod = d === "absolute" ? 1 : -1,
10333 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
10338 // The absolute mouse position
10341 // Only for relative positioned nodes: Relative offset from element to offset parent
10342 this.offset.relative.top * mod +
10344 // The offsetParent's offset without borders (offset + border)
10345 this.offset.parent.top * mod -
10346 ( ( this.cssPosition === "fixed" ?
10347 -this.offset.scroll.top :
10348 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
10352 // The absolute mouse position
10355 // Only for relative positioned nodes: Relative offset from element to offset parent
10356 this.offset.relative.left * mod +
10358 // The offsetParent's offset without borders (offset + border)
10359 this.offset.parent.left * mod -
10360 ( ( this.cssPosition === "fixed" ?
10361 -this.offset.scroll.left :
10362 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
10368 _generatePosition: function( event, constrainPosition ) {
10370 var containment, co, top, left,
10372 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
10373 pageX = event.pageX,
10374 pageY = event.pageY;
10376 // Cache the scroll
10377 if ( !scrollIsRootNode || !this.offset.scroll ) {
10378 this.offset.scroll = {
10379 top: this.scrollParent.scrollTop(),
10380 left: this.scrollParent.scrollLeft()
10385 * - Position constraining -
10386 * Constrain the position to a mix of grid, containment.
10389 // If we are not dragging yet, we won't check for options
10390 if ( constrainPosition ) {
10391 if ( this.containment ) {
10392 if ( this.relativeContainer ) {
10393 co = this.relativeContainer.offset();
10395 this.containment[ 0 ] + co.left,
10396 this.containment[ 1 ] + co.top,
10397 this.containment[ 2 ] + co.left,
10398 this.containment[ 3 ] + co.top
10401 containment = this.containment;
10404 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
10405 pageX = containment[ 0 ] + this.offset.click.left;
10407 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
10408 pageY = containment[ 1 ] + this.offset.click.top;
10410 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
10411 pageX = containment[ 2 ] + this.offset.click.left;
10413 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
10414 pageY = containment[ 3 ] + this.offset.click.top;
10420 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
10421 // argument errors in IE (see ticket #6950)
10422 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
10423 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
10424 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
10425 top - this.offset.click.top > containment[ 3 ] ) ?
10427 ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
10428 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
10430 left = o.grid[ 0 ] ? this.originalPageX +
10431 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
10432 this.originalPageX;
10433 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
10434 left - this.offset.click.left > containment[ 2 ] ) ?
10436 ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
10437 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
10440 if ( o.axis === "y" ) {
10441 pageX = this.originalPageX;
10444 if ( o.axis === "x" ) {
10445 pageY = this.originalPageY;
10452 // The absolute mouse position
10455 // Click offset (relative to the element)
10456 this.offset.click.top -
10458 // Only for relative positioned nodes: Relative offset from element to offset parent
10459 this.offset.relative.top -
10461 // The offsetParent's offset without borders (offset + border)
10462 this.offset.parent.top +
10463 ( this.cssPosition === "fixed" ?
10464 -this.offset.scroll.top :
10465 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
10469 // The absolute mouse position
10472 // Click offset (relative to the element)
10473 this.offset.click.left -
10475 // Only for relative positioned nodes: Relative offset from element to offset parent
10476 this.offset.relative.left -
10478 // The offsetParent's offset without borders (offset + border)
10479 this.offset.parent.left +
10480 ( this.cssPosition === "fixed" ?
10481 -this.offset.scroll.left :
10482 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
10488 _clear: function() {
10489 this._removeClass( this.helper, "ui-draggable-dragging" );
10490 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
10491 this.helper.remove();
10493 this.helper = null;
10494 this.cancelHelperRemoval = false;
10495 if ( this.destroyOnClear ) {
10500 // From now on bulk stuff - mainly helpers
10502 _trigger: function( type, event, ui ) {
10503 ui = ui || this._uiHash();
10504 $.ui.plugin.call( this, type, [ event, ui, this ], true );
10506 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
10507 if ( /^(drag|start|stop)/.test( type ) ) {
10508 this.positionAbs = this._convertPositionTo( "absolute" );
10509 ui.offset = this.positionAbs;
10511 return $.Widget.prototype._trigger.call( this, type, event, ui );
10516 _uiHash: function() {
10518 helper: this.helper,
10519 position: this.position,
10520 originalPosition: this.originalPosition,
10521 offset: this.positionAbs
10527 $.ui.plugin.add( "draggable", "connectToSortable", {
10528 start: function( event, ui, draggable ) {
10529 var uiSortable = $.extend( {}, ui, {
10530 item: draggable.element
10533 draggable.sortables = [];
10534 $( draggable.options.connectToSortable ).each( function() {
10535 var sortable = $( this ).sortable( "instance" );
10537 if ( sortable && !sortable.options.disabled ) {
10538 draggable.sortables.push( sortable );
10540 // RefreshPositions is called at drag start to refresh the containerCache
10541 // which is used in drag. This ensures it's initialized and synchronized
10542 // with any changes that might have happened on the page since initialization.
10543 sortable.refreshPositions();
10544 sortable._trigger( "activate", event, uiSortable );
10548 stop: function( event, ui, draggable ) {
10549 var uiSortable = $.extend( {}, ui, {
10550 item: draggable.element
10553 draggable.cancelHelperRemoval = false;
10555 $.each( draggable.sortables, function() {
10556 var sortable = this;
10558 if ( sortable.isOver ) {
10559 sortable.isOver = 0;
10561 // Allow this sortable to handle removing the helper
10562 draggable.cancelHelperRemoval = true;
10563 sortable.cancelHelperRemoval = false;
10565 // Use _storedCSS To restore properties in the sortable,
10566 // as this also handles revert (#9675) since the draggable
10567 // may have modified them in unexpected ways (#8809)
10568 sortable._storedCSS = {
10569 position: sortable.placeholder.css( "position" ),
10570 top: sortable.placeholder.css( "top" ),
10571 left: sortable.placeholder.css( "left" )
10574 sortable._mouseStop( event );
10576 // Once drag has ended, the sortable should return to using
10577 // its original helper, not the shared helper from draggable
10578 sortable.options.helper = sortable.options._helper;
10581 // Prevent this Sortable from removing the helper.
10582 // However, don't set the draggable to remove the helper
10583 // either as another connected Sortable may yet handle the removal.
10584 sortable.cancelHelperRemoval = true;
10586 sortable._trigger( "deactivate", event, uiSortable );
10590 drag: function( event, ui, draggable ) {
10591 $.each( draggable.sortables, function() {
10592 var innermostIntersecting = false,
10595 // Copy over variables that sortable's _intersectsWith uses
10596 sortable.positionAbs = draggable.positionAbs;
10597 sortable.helperProportions = draggable.helperProportions;
10598 sortable.offset.click = draggable.offset.click;
10600 if ( sortable._intersectsWith( sortable.containerCache ) ) {
10601 innermostIntersecting = true;
10603 $.each( draggable.sortables, function() {
10605 // Copy over variables that sortable's _intersectsWith uses
10606 this.positionAbs = draggable.positionAbs;
10607 this.helperProportions = draggable.helperProportions;
10608 this.offset.click = draggable.offset.click;
10610 if ( this !== sortable &&
10611 this._intersectsWith( this.containerCache ) &&
10612 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
10613 innermostIntersecting = false;
10616 return innermostIntersecting;
10620 if ( innermostIntersecting ) {
10622 // If it intersects, we use a little isOver variable and set it once,
10623 // so that the move-in stuff gets fired only once.
10624 if ( !sortable.isOver ) {
10625 sortable.isOver = 1;
10627 // Store draggable's parent in case we need to reappend to it later.
10628 draggable._parent = ui.helper.parent();
10630 sortable.currentItem = ui.helper
10631 .appendTo( sortable.element )
10632 .data( "ui-sortable-item", true );
10634 // Store helper option to later restore it
10635 sortable.options._helper = sortable.options.helper;
10637 sortable.options.helper = function() {
10638 return ui.helper[ 0 ];
10641 // Fire the start events of the sortable with our passed browser event,
10642 // and our own helper (so it doesn't create a new one)
10643 event.target = sortable.currentItem[ 0 ];
10644 sortable._mouseCapture( event, true );
10645 sortable._mouseStart( event, true, true );
10647 // Because the browser event is way off the new appended portlet,
10648 // modify necessary variables to reflect the changes
10649 sortable.offset.click.top = draggable.offset.click.top;
10650 sortable.offset.click.left = draggable.offset.click.left;
10651 sortable.offset.parent.left -= draggable.offset.parent.left -
10652 sortable.offset.parent.left;
10653 sortable.offset.parent.top -= draggable.offset.parent.top -
10654 sortable.offset.parent.top;
10656 draggable._trigger( "toSortable", event );
10658 // Inform draggable that the helper is in a valid drop zone,
10659 // used solely in the revert option to handle "valid/invalid".
10660 draggable.dropped = sortable.element;
10662 // Need to refreshPositions of all sortables in the case that
10663 // adding to one sortable changes the location of the other sortables (#9675)
10664 $.each( draggable.sortables, function() {
10665 this.refreshPositions();
10668 // Hack so receive/update callbacks work (mostly)
10669 draggable.currentItem = draggable.element;
10670 sortable.fromOutside = draggable;
10673 if ( sortable.currentItem ) {
10674 sortable._mouseDrag( event );
10676 // Copy the sortable's position because the draggable's can potentially reflect
10677 // a relative position, while sortable is always absolute, which the dragged
10678 // element has now become. (#8809)
10679 ui.position = sortable.position;
10683 // If it doesn't intersect with the sortable, and it intersected before,
10684 // we fake the drag stop of the sortable, but make sure it doesn't remove
10685 // the helper by using cancelHelperRemoval.
10686 if ( sortable.isOver ) {
10688 sortable.isOver = 0;
10689 sortable.cancelHelperRemoval = true;
10691 // Calling sortable's mouseStop would trigger a revert,
10692 // so revert must be temporarily false until after mouseStop is called.
10693 sortable.options._revert = sortable.options.revert;
10694 sortable.options.revert = false;
10696 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
10697 sortable._mouseStop( event, true );
10699 // Restore sortable behaviors that were modfied
10700 // when the draggable entered the sortable area (#9481)
10701 sortable.options.revert = sortable.options._revert;
10702 sortable.options.helper = sortable.options._helper;
10704 if ( sortable.placeholder ) {
10705 sortable.placeholder.remove();
10708 // Restore and recalculate the draggable's offset considering the sortable
10709 // may have modified them in unexpected ways. (#8809, #10669)
10710 ui.helper.appendTo( draggable._parent );
10711 draggable._refreshOffsets( event );
10712 ui.position = draggable._generatePosition( event, true );
10714 draggable._trigger( "fromSortable", event );
10716 // Inform draggable that the helper is no longer in a valid drop zone
10717 draggable.dropped = false;
10719 // Need to refreshPositions of all sortables just in case removing
10720 // from one sortable changes the location of other sortables (#9675)
10721 $.each( draggable.sortables, function() {
10722 this.refreshPositions();
10730 $.ui.plugin.add( "draggable", "cursor", {
10731 start: function( event, ui, instance ) {
10732 var t = $( "body" ),
10733 o = instance.options;
10735 if ( t.css( "cursor" ) ) {
10736 o._cursor = t.css( "cursor" );
10738 t.css( "cursor", o.cursor );
10740 stop: function( event, ui, instance ) {
10741 var o = instance.options;
10743 $( "body" ).css( "cursor", o._cursor );
10748 $.ui.plugin.add( "draggable", "opacity", {
10749 start: function( event, ui, instance ) {
10750 var t = $( ui.helper ),
10751 o = instance.options;
10752 if ( t.css( "opacity" ) ) {
10753 o._opacity = t.css( "opacity" );
10755 t.css( "opacity", o.opacity );
10757 stop: function( event, ui, instance ) {
10758 var o = instance.options;
10759 if ( o._opacity ) {
10760 $( ui.helper ).css( "opacity", o._opacity );
10765 $.ui.plugin.add( "draggable", "scroll", {
10766 start: function( event, ui, i ) {
10767 if ( !i.scrollParentNotHidden ) {
10768 i.scrollParentNotHidden = i.helper.scrollParent( false );
10771 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
10772 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
10773 i.overflowOffset = i.scrollParentNotHidden.offset();
10776 drag: function( event, ui, i ) {
10780 scrollParent = i.scrollParentNotHidden[ 0 ],
10781 document = i.document[ 0 ];
10783 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
10784 if ( !o.axis || o.axis !== "x" ) {
10785 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
10786 o.scrollSensitivity ) {
10787 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
10788 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
10789 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
10793 if ( !o.axis || o.axis !== "y" ) {
10794 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
10795 o.scrollSensitivity ) {
10796 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
10797 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
10798 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
10804 if ( !o.axis || o.axis !== "x" ) {
10805 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
10806 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
10807 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
10808 o.scrollSensitivity ) {
10809 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
10813 if ( !o.axis || o.axis !== "y" ) {
10814 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
10815 scrolled = $( document ).scrollLeft(
10816 $( document ).scrollLeft() - o.scrollSpeed
10818 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
10819 o.scrollSensitivity ) {
10820 scrolled = $( document ).scrollLeft(
10821 $( document ).scrollLeft() + o.scrollSpeed
10828 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
10829 $.ui.ddmanager.prepareOffsets( i, event );
10835 $.ui.plugin.add( "draggable", "snap", {
10836 start: function( event, ui, i ) {
10840 i.snapElements = [];
10842 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
10843 .each( function() {
10844 var $t = $( this ),
10846 if ( this !== i.element[ 0 ] ) {
10847 i.snapElements.push( {
10849 width: $t.outerWidth(), height: $t.outerHeight(),
10850 top: $o.top, left: $o.left
10856 drag: function( event, ui, inst ) {
10858 var ts, bs, ls, rs, l, r, t, b, i, first,
10860 d = o.snapTolerance,
10861 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
10862 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
10864 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
10866 l = inst.snapElements[ i ].left - inst.margins.left;
10867 r = l + inst.snapElements[ i ].width;
10868 t = inst.snapElements[ i ].top - inst.margins.top;
10869 b = t + inst.snapElements[ i ].height;
10871 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
10872 !$.contains( inst.snapElements[ i ].item.ownerDocument,
10873 inst.snapElements[ i ].item ) ) {
10874 if ( inst.snapElements[ i ].snapping ) {
10875 if ( inst.options.snap.release ) {
10876 inst.options.snap.release.call(
10879 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
10883 inst.snapElements[ i ].snapping = false;
10887 if ( o.snapMode !== "inner" ) {
10888 ts = Math.abs( t - y2 ) <= d;
10889 bs = Math.abs( b - y1 ) <= d;
10890 ls = Math.abs( l - x2 ) <= d;
10891 rs = Math.abs( r - x1 ) <= d;
10893 ui.position.top = inst._convertPositionTo( "relative", {
10894 top: t - inst.helperProportions.height,
10899 ui.position.top = inst._convertPositionTo( "relative", {
10905 ui.position.left = inst._convertPositionTo( "relative", {
10907 left: l - inst.helperProportions.width
10911 ui.position.left = inst._convertPositionTo( "relative", {
10918 first = ( ts || bs || ls || rs );
10920 if ( o.snapMode !== "outer" ) {
10921 ts = Math.abs( t - y1 ) <= d;
10922 bs = Math.abs( b - y2 ) <= d;
10923 ls = Math.abs( l - x1 ) <= d;
10924 rs = Math.abs( r - x2 ) <= d;
10926 ui.position.top = inst._convertPositionTo( "relative", {
10932 ui.position.top = inst._convertPositionTo( "relative", {
10933 top: b - inst.helperProportions.height,
10938 ui.position.left = inst._convertPositionTo( "relative", {
10944 ui.position.left = inst._convertPositionTo( "relative", {
10946 left: r - inst.helperProportions.width
10951 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
10952 if ( inst.options.snap.snap ) {
10953 inst.options.snap.snap.call(
10956 $.extend( inst._uiHash(), {
10957 snapItem: inst.snapElements[ i ].item
10961 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
10968 $.ui.plugin.add( "draggable", "stack", {
10969 start: function( event, ui, instance ) {
10971 o = instance.options,
10972 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
10973 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
10974 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
10977 if ( !group.length ) {
10981 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
10982 $( group ).each( function( i ) {
10983 $( this ).css( "zIndex", min + i );
10985 this.css( "zIndex", ( min + group.length ) );
10989 $.ui.plugin.add( "draggable", "zIndex", {
10990 start: function( event, ui, instance ) {
10991 var t = $( ui.helper ),
10992 o = instance.options;
10994 if ( t.css( "zIndex" ) ) {
10995 o._zIndex = t.css( "zIndex" );
10997 t.css( "zIndex", o.zIndex );
10999 stop: function( event, ui, instance ) {
11000 var o = instance.options;
11003 $( ui.helper ).css( "zIndex", o._zIndex );
11008 var widgetsDraggable = $.ui.draggable;
11012 * jQuery UI Resizable 1.13.0
11013 * http://jqueryui.com
11015 * Copyright jQuery Foundation and other contributors
11016 * Released under the MIT license.
11017 * http://jquery.org/license
11020 //>>label: Resizable
11021 //>>group: Interactions
11022 //>>description: Enables resize functionality for any element.
11023 //>>docs: http://api.jqueryui.com/resizable/
11024 //>>demos: http://jqueryui.com/resizable/
11025 //>>css.structure: ../../themes/base/core.css
11026 //>>css.structure: ../../themes/base/resizable.css
11027 //>>css.theme: ../../themes/base/theme.css
11030 $.widget( "ui.resizable", $.ui.mouse, {
11032 widgetEventPrefix: "resize",
11036 animateDuration: "slow",
11037 animateEasing: "swing",
11038 aspectRatio: false,
11041 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
11043 containment: false,
11062 _num: function( value ) {
11063 return parseFloat( value ) || 0;
11066 _isNumber: function( value ) {
11067 return !isNaN( parseFloat( value ) );
11070 _hasScroll: function( el, a ) {
11072 if ( $( el ).css( "overflow" ) === "hidden" ) {
11076 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
11079 if ( el[ scroll ] > 0 ) {
11083 // TODO: determine which cases actually cause this to happen
11084 // if the element doesn't have the scroll set, see if it's possible to
11088 has = ( el[ scroll ] > 0 );
11092 // `el` might be a string, then setting `scroll` will throw
11093 // an error in strict mode; ignore it.
11098 _create: function() {
11103 this._addClass( "ui-resizable" );
11106 _aspectRatio: !!( o.aspectRatio ),
11107 aspectRatio: o.aspectRatio,
11108 originalElement: this.element,
11109 _proportionallyResizeElements: [],
11110 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
11113 // Wrap the element if it cannot hold child nodes
11114 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
11117 $( "<div class='ui-wrapper'></div>" ).css( {
11118 overflow: "hidden",
11119 position: this.element.css( "position" ),
11120 width: this.element.outerWidth(),
11121 height: this.element.outerHeight(),
11122 top: this.element.css( "top" ),
11123 left: this.element.css( "left" )
11127 this.element = this.element.parent().data(
11128 "ui-resizable", this.element.resizable( "instance" )
11131 this.elementIsWrapper = true;
11134 marginTop: this.originalElement.css( "marginTop" ),
11135 marginRight: this.originalElement.css( "marginRight" ),
11136 marginBottom: this.originalElement.css( "marginBottom" ),
11137 marginLeft: this.originalElement.css( "marginLeft" )
11140 this.element.css( margins );
11141 this.originalElement.css( "margin", 0 );
11144 // Prevent Safari textarea resize
11145 this.originalResizeStyle = this.originalElement.css( "resize" );
11146 this.originalElement.css( "resize", "none" );
11148 this._proportionallyResizeElements.push( this.originalElement.css( {
11149 position: "static",
11155 // avoid IE jump (hard set the margin)
11156 this.originalElement.css( margins );
11158 this._proportionallyResize();
11161 this._setupHandles();
11163 if ( o.autoHide ) {
11165 .on( "mouseenter", function() {
11166 if ( o.disabled ) {
11169 that._removeClass( "ui-resizable-autohide" );
11170 that._handles.show();
11172 .on( "mouseleave", function() {
11173 if ( o.disabled ) {
11176 if ( !that.resizing ) {
11177 that._addClass( "ui-resizable-autohide" );
11178 that._handles.hide();
11186 _destroy: function() {
11188 this._mouseDestroy();
11189 this._addedHandles.remove();
11192 _destroy = function( exp ) {
11194 .removeData( "resizable" )
11195 .removeData( "ui-resizable" )
11196 .off( ".resizable" );
11199 // TODO: Unwrap at same DOM position
11200 if ( this.elementIsWrapper ) {
11201 _destroy( this.element );
11202 wrapper = this.element;
11203 this.originalElement.css( {
11204 position: wrapper.css( "position" ),
11205 width: wrapper.outerWidth(),
11206 height: wrapper.outerHeight(),
11207 top: wrapper.css( "top" ),
11208 left: wrapper.css( "left" )
11209 } ).insertAfter( wrapper );
11213 this.originalElement.css( "resize", this.originalResizeStyle );
11214 _destroy( this.originalElement );
11219 _setOption: function( key, value ) {
11220 this._super( key, value );
11224 this._removeHandles();
11225 this._setupHandles();
11227 case "aspectRatio":
11228 this._aspectRatio = !!value;
11235 _setupHandles: function() {
11236 var o = this.options, handle, i, n, hname, axis, that = this;
11237 this.handles = o.handles ||
11238 ( !$( ".ui-resizable-handle", this.element ).length ?
11240 n: ".ui-resizable-n",
11241 e: ".ui-resizable-e",
11242 s: ".ui-resizable-s",
11243 w: ".ui-resizable-w",
11244 se: ".ui-resizable-se",
11245 sw: ".ui-resizable-sw",
11246 ne: ".ui-resizable-ne",
11247 nw: ".ui-resizable-nw"
11250 this._handles = $();
11251 this._addedHandles = $();
11252 if ( this.handles.constructor === String ) {
11254 if ( this.handles === "all" ) {
11255 this.handles = "n,e,s,w,se,sw,ne,nw";
11258 n = this.handles.split( "," );
11261 for ( i = 0; i < n.length; i++ ) {
11263 handle = String.prototype.trim.call( n[ i ] );
11264 hname = "ui-resizable-" + handle;
11265 axis = $( "<div>" );
11266 this._addClass( axis, "ui-resizable-handle " + hname );
11268 axis.css( { zIndex: o.zIndex } );
11270 this.handles[ handle ] = ".ui-resizable-" + handle;
11271 if ( !this.element.children( this.handles[ handle ] ).length ) {
11272 this.element.append( axis );
11273 this._addedHandles = this._addedHandles.add( axis );
11279 this._renderAxis = function( target ) {
11281 var i, axis, padPos, padWrapper;
11283 target = target || this.element;
11285 for ( i in this.handles ) {
11287 if ( this.handles[ i ].constructor === String ) {
11288 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
11289 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
11290 this.handles[ i ] = $( this.handles[ i ] );
11291 this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
11294 if ( this.elementIsWrapper &&
11295 this.originalElement[ 0 ]
11297 .match( /^(textarea|input|select|button)$/i ) ) {
11298 axis = $( this.handles[ i ], this.element );
11300 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
11301 axis.outerHeight() :
11304 padPos = [ "padding",
11305 /ne|nw|n/.test( i ) ? "Top" :
11306 /se|sw|s/.test( i ) ? "Bottom" :
11307 /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
11309 target.css( padPos, padWrapper );
11311 this._proportionallyResize();
11314 this._handles = this._handles.add( this.handles[ i ] );
11318 // TODO: make renderAxis a prototype function
11319 this._renderAxis( this.element );
11321 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
11322 this._handles.disableSelection();
11324 this._handles.on( "mouseover", function() {
11325 if ( !that.resizing ) {
11326 if ( this.className ) {
11327 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
11329 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
11333 if ( o.autoHide ) {
11334 this._handles.hide();
11335 this._addClass( "ui-resizable-autohide" );
11339 _removeHandles: function() {
11340 this._addedHandles.remove();
11343 _mouseCapture: function( event ) {
11347 for ( i in this.handles ) {
11348 handle = $( this.handles[ i ] )[ 0 ];
11349 if ( handle === event.target || $.contains( handle, event.target ) ) {
11354 return !this.options.disabled && capture;
11357 _mouseStart: function( event ) {
11359 var curleft, curtop, cursor,
11363 this.resizing = true;
11365 this._renderProxy();
11367 curleft = this._num( this.helper.css( "left" ) );
11368 curtop = this._num( this.helper.css( "top" ) );
11370 if ( o.containment ) {
11371 curleft += $( o.containment ).scrollLeft() || 0;
11372 curtop += $( o.containment ).scrollTop() || 0;
11375 this.offset = this.helper.offset();
11376 this.position = { left: curleft, top: curtop };
11378 this.size = this._helper ? {
11379 width: this.helper.width(),
11380 height: this.helper.height()
11383 height: el.height()
11386 this.originalSize = this._helper ? {
11387 width: el.outerWidth(),
11388 height: el.outerHeight()
11391 height: el.height()
11395 width: el.outerWidth() - el.width(),
11396 height: el.outerHeight() - el.height()
11399 this.originalPosition = { left: curleft, top: curtop };
11400 this.originalMousePosition = { left: event.pageX, top: event.pageY };
11402 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
11404 ( ( this.originalSize.width / this.originalSize.height ) || 1 );
11406 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
11407 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
11409 this._addClass( "ui-resizable-resizing" );
11410 this._propagate( "start", event );
11414 _mouseDrag: function( event ) {
11417 smp = this.originalMousePosition,
11419 dx = ( event.pageX - smp.left ) || 0,
11420 dy = ( event.pageY - smp.top ) || 0,
11421 trigger = this._change[ a ];
11423 this._updatePrevProperties();
11429 data = trigger.apply( this, [ event, dx, dy ] );
11431 this._updateVirtualBoundaries( event.shiftKey );
11432 if ( this._aspectRatio || event.shiftKey ) {
11433 data = this._updateRatio( data, event );
11436 data = this._respectSize( data, event );
11438 this._updateCache( data );
11440 this._propagate( "resize", event );
11442 props = this._applyChanges();
11444 if ( !this._helper && this._proportionallyResizeElements.length ) {
11445 this._proportionallyResize();
11448 if ( !$.isEmptyObject( props ) ) {
11449 this._updatePrevProperties();
11450 this._trigger( "resize", event, this.ui() );
11451 this._applyChanges();
11457 _mouseStop: function( event ) {
11459 this.resizing = false;
11460 var pr, ista, soffseth, soffsetw, s, left, top,
11461 o = this.options, that = this;
11463 if ( this._helper ) {
11465 pr = this._proportionallyResizeElements;
11466 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
11467 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
11468 soffsetw = ista ? 0 : that.sizeDiff.width;
11471 width: ( that.helper.width() - soffsetw ),
11472 height: ( that.helper.height() - soffseth )
11474 left = ( parseFloat( that.element.css( "left" ) ) +
11475 ( that.position.left - that.originalPosition.left ) ) || null;
11476 top = ( parseFloat( that.element.css( "top" ) ) +
11477 ( that.position.top - that.originalPosition.top ) ) || null;
11479 if ( !o.animate ) {
11480 this.element.css( $.extend( s, { top: top, left: left } ) );
11483 that.helper.height( that.size.height );
11484 that.helper.width( that.size.width );
11486 if ( this._helper && !o.animate ) {
11487 this._proportionallyResize();
11491 $( "body" ).css( "cursor", "auto" );
11493 this._removeClass( "ui-resizable-resizing" );
11495 this._propagate( "stop", event );
11497 if ( this._helper ) {
11498 this.helper.remove();
11505 _updatePrevProperties: function() {
11506 this.prevPosition = {
11507 top: this.position.top,
11508 left: this.position.left
11511 width: this.size.width,
11512 height: this.size.height
11516 _applyChanges: function() {
11519 if ( this.position.top !== this.prevPosition.top ) {
11520 props.top = this.position.top + "px";
11522 if ( this.position.left !== this.prevPosition.left ) {
11523 props.left = this.position.left + "px";
11525 if ( this.size.width !== this.prevSize.width ) {
11526 props.width = this.size.width + "px";
11528 if ( this.size.height !== this.prevSize.height ) {
11529 props.height = this.size.height + "px";
11532 this.helper.css( props );
11537 _updateVirtualBoundaries: function( forceAspectRatio ) {
11538 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
11542 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
11543 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
11544 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
11545 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
11548 if ( this._aspectRatio || forceAspectRatio ) {
11549 pMinWidth = b.minHeight * this.aspectRatio;
11550 pMinHeight = b.minWidth / this.aspectRatio;
11551 pMaxWidth = b.maxHeight * this.aspectRatio;
11552 pMaxHeight = b.maxWidth / this.aspectRatio;
11554 if ( pMinWidth > b.minWidth ) {
11555 b.minWidth = pMinWidth;
11557 if ( pMinHeight > b.minHeight ) {
11558 b.minHeight = pMinHeight;
11560 if ( pMaxWidth < b.maxWidth ) {
11561 b.maxWidth = pMaxWidth;
11563 if ( pMaxHeight < b.maxHeight ) {
11564 b.maxHeight = pMaxHeight;
11567 this._vBoundaries = b;
11570 _updateCache: function( data ) {
11571 this.offset = this.helper.offset();
11572 if ( this._isNumber( data.left ) ) {
11573 this.position.left = data.left;
11575 if ( this._isNumber( data.top ) ) {
11576 this.position.top = data.top;
11578 if ( this._isNumber( data.height ) ) {
11579 this.size.height = data.height;
11581 if ( this._isNumber( data.width ) ) {
11582 this.size.width = data.width;
11586 _updateRatio: function( data ) {
11588 var cpos = this.position,
11592 if ( this._isNumber( data.height ) ) {
11593 data.width = ( data.height * this.aspectRatio );
11594 } else if ( this._isNumber( data.width ) ) {
11595 data.height = ( data.width / this.aspectRatio );
11598 if ( a === "sw" ) {
11599 data.left = cpos.left + ( csize.width - data.width );
11602 if ( a === "nw" ) {
11603 data.top = cpos.top + ( csize.height - data.height );
11604 data.left = cpos.left + ( csize.width - data.width );
11610 _respectSize: function( data ) {
11612 var o = this._vBoundaries,
11614 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
11615 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
11616 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
11617 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
11618 dw = this.originalPosition.left + this.originalSize.width,
11619 dh = this.originalPosition.top + this.originalSize.height,
11620 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
11622 data.width = o.minWidth;
11625 data.height = o.minHeight;
11628 data.width = o.maxWidth;
11631 data.height = o.maxHeight;
11634 if ( isminw && cw ) {
11635 data.left = dw - o.minWidth;
11637 if ( ismaxw && cw ) {
11638 data.left = dw - o.maxWidth;
11640 if ( isminh && ch ) {
11641 data.top = dh - o.minHeight;
11643 if ( ismaxh && ch ) {
11644 data.top = dh - o.maxHeight;
11647 // Fixing jump error on top/left - bug #2330
11648 if ( !data.width && !data.height && !data.left && data.top ) {
11650 } else if ( !data.width && !data.height && !data.top && data.left ) {
11657 _getPaddingPlusBorderDimensions: function( element ) {
11661 element.css( "borderTopWidth" ),
11662 element.css( "borderRightWidth" ),
11663 element.css( "borderBottomWidth" ),
11664 element.css( "borderLeftWidth" )
11667 element.css( "paddingTop" ),
11668 element.css( "paddingRight" ),
11669 element.css( "paddingBottom" ),
11670 element.css( "paddingLeft" )
11673 for ( ; i < 4; i++ ) {
11674 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
11675 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
11679 height: widths[ 0 ] + widths[ 2 ],
11680 width: widths[ 1 ] + widths[ 3 ]
11684 _proportionallyResize: function() {
11686 if ( !this._proportionallyResizeElements.length ) {
11692 element = this.helper || this.element;
11694 for ( ; i < this._proportionallyResizeElements.length; i++ ) {
11696 prel = this._proportionallyResizeElements[ i ];
11698 // TODO: Seems like a bug to cache this.outerDimensions
11699 // considering that we are in a loop.
11700 if ( !this.outerDimensions ) {
11701 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
11705 height: ( element.height() - this.outerDimensions.height ) || 0,
11706 width: ( element.width() - this.outerDimensions.width ) || 0
11713 _renderProxy: function() {
11715 var el = this.element, o = this.options;
11716 this.elementOffset = el.offset();
11718 if ( this._helper ) {
11720 this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } );
11722 this._addClass( this.helper, this._helper );
11724 width: this.element.outerWidth(),
11725 height: this.element.outerHeight(),
11726 position: "absolute",
11727 left: this.elementOffset.left + "px",
11728 top: this.elementOffset.top + "px",
11729 zIndex: ++o.zIndex //TODO: Don't modify option
11733 .appendTo( "body" )
11734 .disableSelection();
11737 this.helper = this.element;
11743 e: function( event, dx ) {
11744 return { width: this.originalSize.width + dx };
11746 w: function( event, dx ) {
11747 var cs = this.originalSize, sp = this.originalPosition;
11748 return { left: sp.left + dx, width: cs.width - dx };
11750 n: function( event, dx, dy ) {
11751 var cs = this.originalSize, sp = this.originalPosition;
11752 return { top: sp.top + dy, height: cs.height - dy };
11754 s: function( event, dx, dy ) {
11755 return { height: this.originalSize.height + dy };
11757 se: function( event, dx, dy ) {
11758 return $.extend( this._change.s.apply( this, arguments ),
11759 this._change.e.apply( this, [ event, dx, dy ] ) );
11761 sw: function( event, dx, dy ) {
11762 return $.extend( this._change.s.apply( this, arguments ),
11763 this._change.w.apply( this, [ event, dx, dy ] ) );
11765 ne: function( event, dx, dy ) {
11766 return $.extend( this._change.n.apply( this, arguments ),
11767 this._change.e.apply( this, [ event, dx, dy ] ) );
11769 nw: function( event, dx, dy ) {
11770 return $.extend( this._change.n.apply( this, arguments ),
11771 this._change.w.apply( this, [ event, dx, dy ] ) );
11775 _propagate: function( n, event ) {
11776 $.ui.plugin.call( this, n, [ event, this.ui() ] );
11777 if ( n !== "resize" ) {
11778 this._trigger( n, event, this.ui() );
11786 originalElement: this.originalElement,
11787 element: this.element,
11788 helper: this.helper,
11789 position: this.position,
11791 originalSize: this.originalSize,
11792 originalPosition: this.originalPosition
11799 * Resizable Extensions
11802 $.ui.plugin.add( "resizable", "animate", {
11804 stop: function( event ) {
11805 var that = $( this ).resizable( "instance" ),
11807 pr = that._proportionallyResizeElements,
11808 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
11809 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
11810 soffsetw = ista ? 0 : that.sizeDiff.width,
11812 width: ( that.size.width - soffsetw ),
11813 height: ( that.size.height - soffseth )
11815 left = ( parseFloat( that.element.css( "left" ) ) +
11816 ( that.position.left - that.originalPosition.left ) ) || null,
11817 top = ( parseFloat( that.element.css( "top" ) ) +
11818 ( that.position.top - that.originalPosition.top ) ) || null;
11820 that.element.animate(
11821 $.extend( style, top && left ? { top: top, left: left } : {} ), {
11822 duration: o.animateDuration,
11823 easing: o.animateEasing,
11827 width: parseFloat( that.element.css( "width" ) ),
11828 height: parseFloat( that.element.css( "height" ) ),
11829 top: parseFloat( that.element.css( "top" ) ),
11830 left: parseFloat( that.element.css( "left" ) )
11833 if ( pr && pr.length ) {
11834 $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
11837 // Propagating resize, and updating values for each animation step
11838 that._updateCache( data );
11839 that._propagate( "resize", event );
11848 $.ui.plugin.add( "resizable", "containment", {
11850 start: function() {
11851 var element, p, co, ch, cw, width, height,
11852 that = $( this ).resizable( "instance" ),
11855 oc = o.containment,
11856 ce = ( oc instanceof $ ) ?
11858 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
11864 that.containerElement = $( ce );
11866 if ( /document/.test( oc ) || oc === document ) {
11867 that.containerOffset = {
11871 that.containerPosition = {
11876 that.parentData = {
11877 element: $( document ),
11880 width: $( document ).width(),
11881 height: $( document ).height() || document.body.parentNode.scrollHeight
11886 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
11887 p[ i ] = that._num( element.css( "padding" + name ) );
11890 that.containerOffset = element.offset();
11891 that.containerPosition = element.position();
11892 that.containerSize = {
11893 height: ( element.innerHeight() - p[ 3 ] ),
11894 width: ( element.innerWidth() - p[ 1 ] )
11897 co = that.containerOffset;
11898 ch = that.containerSize.height;
11899 cw = that.containerSize.width;
11900 width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw );
11901 height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch );
11903 that.parentData = {
11913 resize: function( event ) {
11914 var woset, hoset, isParent, isOffsetRelative,
11915 that = $( this ).resizable( "instance" ),
11917 co = that.containerOffset,
11918 cp = that.position,
11919 pRatio = that._aspectRatio || event.shiftKey,
11924 ce = that.containerElement,
11925 continueResize = true;
11927 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
11931 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
11932 that.size.width = that.size.width +
11934 ( that.position.left - co.left ) :
11935 ( that.position.left - cop.left ) );
11938 that.size.height = that.size.width / that.aspectRatio;
11939 continueResize = false;
11941 that.position.left = o.helper ? co.left : 0;
11944 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
11945 that.size.height = that.size.height +
11947 ( that.position.top - co.top ) :
11948 that.position.top );
11951 that.size.width = that.size.height * that.aspectRatio;
11952 continueResize = false;
11954 that.position.top = that._helper ? co.top : 0;
11957 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
11958 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
11960 if ( isParent && isOffsetRelative ) {
11961 that.offset.left = that.parentData.left + that.position.left;
11962 that.offset.top = that.parentData.top + that.position.top;
11964 that.offset.left = that.element.offset().left;
11965 that.offset.top = that.element.offset().top;
11968 woset = Math.abs( that.sizeDiff.width +
11970 that.offset.left - cop.left :
11971 ( that.offset.left - co.left ) ) );
11973 hoset = Math.abs( that.sizeDiff.height +
11975 that.offset.top - cop.top :
11976 ( that.offset.top - co.top ) ) );
11978 if ( woset + that.size.width >= that.parentData.width ) {
11979 that.size.width = that.parentData.width - woset;
11981 that.size.height = that.size.width / that.aspectRatio;
11982 continueResize = false;
11986 if ( hoset + that.size.height >= that.parentData.height ) {
11987 that.size.height = that.parentData.height - hoset;
11989 that.size.width = that.size.height * that.aspectRatio;
11990 continueResize = false;
11994 if ( !continueResize ) {
11995 that.position.left = that.prevPosition.left;
11996 that.position.top = that.prevPosition.top;
11997 that.size.width = that.prevSize.width;
11998 that.size.height = that.prevSize.height;
12003 var that = $( this ).resizable( "instance" ),
12005 co = that.containerOffset,
12006 cop = that.containerPosition,
12007 ce = that.containerElement,
12008 helper = $( that.helper ),
12009 ho = helper.offset(),
12010 w = helper.outerWidth() - that.sizeDiff.width,
12011 h = helper.outerHeight() - that.sizeDiff.height;
12013 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
12015 left: ho.left - cop.left - co.left,
12021 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
12023 left: ho.left - cop.left - co.left,
12031 $.ui.plugin.add( "resizable", "alsoResize", {
12033 start: function() {
12034 var that = $( this ).resizable( "instance" ),
12037 $( o.alsoResize ).each( function() {
12038 var el = $( this );
12039 el.data( "ui-resizable-alsoresize", {
12040 width: parseFloat( el.width() ), height: parseFloat( el.height() ),
12041 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
12046 resize: function( event, ui ) {
12047 var that = $( this ).resizable( "instance" ),
12049 os = that.originalSize,
12050 op = that.originalPosition,
12052 height: ( that.size.height - os.height ) || 0,
12053 width: ( that.size.width - os.width ) || 0,
12054 top: ( that.position.top - op.top ) || 0,
12055 left: ( that.position.left - op.left ) || 0
12058 $( o.alsoResize ).each( function() {
12059 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
12060 css = el.parents( ui.originalElement[ 0 ] ).length ?
12061 [ "width", "height" ] :
12062 [ "width", "height", "top", "left" ];
12064 $.each( css, function( i, prop ) {
12065 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
12066 if ( sum && sum >= 0 ) {
12067 style[ prop ] = sum || null;
12076 $( this ).removeData( "ui-resizable-alsoresize" );
12080 $.ui.plugin.add( "resizable", "ghost", {
12082 start: function() {
12084 var that = $( this ).resizable( "instance" ), cs = that.size;
12086 that.ghost = that.originalElement.clone();
12090 position: "relative",
12098 that._addClass( that.ghost, "ui-resizable-ghost" );
12101 // TODO: remove after 1.12
12102 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
12105 that.ghost.addClass( this.options.ghost );
12108 that.ghost.appendTo( that.helper );
12112 resize: function() {
12113 var that = $( this ).resizable( "instance" );
12114 if ( that.ghost ) {
12116 position: "relative",
12117 height: that.size.height,
12118 width: that.size.width
12124 var that = $( this ).resizable( "instance" );
12125 if ( that.ghost && that.helper ) {
12126 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
12132 $.ui.plugin.add( "resizable", "grid", {
12134 resize: function() {
12135 var outerDimensions,
12136 that = $( this ).resizable( "instance" ),
12139 os = that.originalSize,
12140 op = that.originalPosition,
12142 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
12143 gridX = ( grid[ 0 ] || 1 ),
12144 gridY = ( grid[ 1 ] || 1 ),
12145 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
12146 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
12147 newWidth = os.width + ox,
12148 newHeight = os.height + oy,
12149 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
12150 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
12151 isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
12152 isMinHeight = o.minHeight && ( o.minHeight > newHeight );
12156 if ( isMinWidth ) {
12159 if ( isMinHeight ) {
12160 newHeight += gridY;
12162 if ( isMaxWidth ) {
12165 if ( isMaxHeight ) {
12166 newHeight -= gridY;
12169 if ( /^(se|s|e)$/.test( a ) ) {
12170 that.size.width = newWidth;
12171 that.size.height = newHeight;
12172 } else if ( /^(ne)$/.test( a ) ) {
12173 that.size.width = newWidth;
12174 that.size.height = newHeight;
12175 that.position.top = op.top - oy;
12176 } else if ( /^(sw)$/.test( a ) ) {
12177 that.size.width = newWidth;
12178 that.size.height = newHeight;
12179 that.position.left = op.left - ox;
12181 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
12182 outerDimensions = that._getPaddingPlusBorderDimensions( this );
12185 if ( newHeight - gridY > 0 ) {
12186 that.size.height = newHeight;
12187 that.position.top = op.top - oy;
12189 newHeight = gridY - outerDimensions.height;
12190 that.size.height = newHeight;
12191 that.position.top = op.top + os.height - newHeight;
12193 if ( newWidth - gridX > 0 ) {
12194 that.size.width = newWidth;
12195 that.position.left = op.left - ox;
12197 newWidth = gridX - outerDimensions.width;
12198 that.size.width = newWidth;
12199 that.position.left = op.left + os.width - newWidth;
12206 var widgetsResizable = $.ui.resizable;
12210 * jQuery UI Dialog 1.13.0
12211 * http://jqueryui.com
12213 * Copyright jQuery Foundation and other contributors
12214 * Released under the MIT license.
12215 * http://jquery.org/license
12220 //>>description: Displays customizable dialog windows.
12221 //>>docs: http://api.jqueryui.com/dialog/
12222 //>>demos: http://jqueryui.com/dialog/
12223 //>>css.structure: ../../themes/base/core.css
12224 //>>css.structure: ../../themes/base/dialog.css
12225 //>>css.theme: ../../themes/base/theme.css
12228 $.widget( "ui.dialog", {
12235 "ui-dialog": "ui-corner-all",
12236 "ui-dialog-titlebar": "ui-corner-all"
12238 closeOnEscape: true,
12239 closeText: "Close",
12254 // Ensure the titlebar is always visible
12255 using: function( pos ) {
12256 var topOffset = $( this ).css( pos ).offset().top;
12257 if ( topOffset < 0 ) {
12258 $( this ).css( "top", pos.top - topOffset );
12280 sizeRelatedOptions: {
12290 resizableRelatedOptions: {
12297 _create: function() {
12298 this.originalCss = {
12299 display: this.element[ 0 ].style.display,
12300 width: this.element[ 0 ].style.width,
12301 minHeight: this.element[ 0 ].style.minHeight,
12302 maxHeight: this.element[ 0 ].style.maxHeight,
12303 height: this.element[ 0 ].style.height
12305 this.originalPosition = {
12306 parent: this.element.parent(),
12307 index: this.element.parent().children().index( this.element )
12309 this.originalTitle = this.element.attr( "title" );
12310 if ( this.options.title == null && this.originalTitle != null ) {
12311 this.options.title = this.originalTitle;
12314 // Dialogs can't be disabled
12315 if ( this.options.disabled ) {
12316 this.options.disabled = false;
12319 this._createWrapper();
12323 .removeAttr( "title" )
12324 .appendTo( this.uiDialog );
12326 this._addClass( "ui-dialog-content", "ui-widget-content" );
12328 this._createTitlebar();
12329 this._createButtonPane();
12331 if ( this.options.draggable && $.fn.draggable ) {
12332 this._makeDraggable();
12334 if ( this.options.resizable && $.fn.resizable ) {
12335 this._makeResizable();
12338 this._isOpen = false;
12340 this._trackFocus();
12343 _init: function() {
12344 if ( this.options.autoOpen ) {
12349 _appendTo: function() {
12350 var element = this.options.appendTo;
12351 if ( element && ( element.jquery || element.nodeType ) ) {
12352 return $( element );
12354 return this.document.find( element || "body" ).eq( 0 );
12357 _destroy: function() {
12359 originalPosition = this.originalPosition;
12361 this._untrackInstance();
12362 this._destroyOverlay();
12366 .css( this.originalCss )
12368 // Without detaching first, the following becomes really slow
12371 this.uiDialog.remove();
12373 if ( this.originalTitle ) {
12374 this.element.attr( "title", this.originalTitle );
12377 next = originalPosition.parent.children().eq( originalPosition.index );
12379 // Don't try to place the dialog next to itself (#8613)
12380 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
12381 next.before( this.element );
12383 originalPosition.parent.append( this.element );
12387 widget: function() {
12388 return this.uiDialog;
12394 close: function( event ) {
12397 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
12401 this._isOpen = false;
12402 this._focusedElement = null;
12403 this._destroyOverlay();
12404 this._untrackInstance();
12406 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
12408 // Hiding a focused element doesn't trigger blur in WebKit
12409 // so in case we have nothing to focus on, explicitly blur the active element
12410 // https://bugs.webkit.org/show_bug.cgi?id=47182
12411 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
12414 this._hide( this.uiDialog, this.options.hide, function() {
12415 that._trigger( "close", event );
12419 isOpen: function() {
12420 return this._isOpen;
12423 moveToTop: function() {
12427 _moveToTop: function( event, silent ) {
12429 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
12430 return +$( this ).css( "z-index" );
12432 zIndexMax = Math.max.apply( null, zIndices );
12434 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
12435 this.uiDialog.css( "z-index", zIndexMax + 1 );
12439 if ( moved && !silent ) {
12440 this._trigger( "focus", event );
12447 if ( this._isOpen ) {
12448 if ( this._moveToTop() ) {
12449 this._focusTabbable();
12454 this._isOpen = true;
12455 this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
12459 this._createOverlay();
12460 this._moveToTop( null, true );
12462 // Ensure the overlay is moved to the top with the dialog, but only when
12463 // opening. The overlay shouldn't move after the dialog is open so that
12464 // modeless dialogs opened after the modal dialog stack properly.
12465 if ( this.overlay ) {
12466 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
12469 this._show( this.uiDialog, this.options.show, function() {
12470 that._focusTabbable();
12471 that._trigger( "focus" );
12474 // Track the dialog immediately upon opening in case a focus event
12475 // somehow occurs outside of the dialog before an element inside the
12476 // dialog is focused (#10152)
12477 this._makeFocusTarget();
12479 this._trigger( "open" );
12482 _focusTabbable: function() {
12484 // Set focus to the first match:
12485 // 1. An element that was focused previously
12486 // 2. First element inside the dialog matching [autofocus]
12487 // 3. Tabbable element inside the content element
12488 // 4. Tabbable element inside the buttonpane
12489 // 5. The close button
12490 // 6. The dialog itself
12491 var hasFocus = this._focusedElement;
12493 hasFocus = this.element.find( "[autofocus]" );
12495 if ( !hasFocus.length ) {
12496 hasFocus = this.element.find( ":tabbable" );
12498 if ( !hasFocus.length ) {
12499 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
12501 if ( !hasFocus.length ) {
12502 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
12504 if ( !hasFocus.length ) {
12505 hasFocus = this.uiDialog;
12507 hasFocus.eq( 0 ).trigger( "focus" );
12510 _restoreTabbableFocus: function() {
12511 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
12512 isActive = this.uiDialog[ 0 ] === activeElement ||
12513 $.contains( this.uiDialog[ 0 ], activeElement );
12515 this._focusTabbable();
12519 _keepFocus: function( event ) {
12520 event.preventDefault();
12521 this._restoreTabbableFocus();
12524 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
12525 // so we check again later
12526 this._delay( this._restoreTabbableFocus );
12529 _createWrapper: function() {
12530 this.uiDialog = $( "<div>" )
12534 // Setting tabIndex makes the div focusable
12538 .appendTo( this._appendTo() );
12540 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
12541 this._on( this.uiDialog, {
12542 keydown: function( event ) {
12543 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
12544 event.keyCode === $.ui.keyCode.ESCAPE ) {
12545 event.preventDefault();
12546 this.close( event );
12550 // Prevent tabbing out of dialogs
12551 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
12554 var tabbables = this.uiDialog.find( ":tabbable" ),
12555 first = tabbables.first(),
12556 last = tabbables.last();
12558 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
12559 !event.shiftKey ) {
12560 this._delay( function() {
12561 first.trigger( "focus" );
12563 event.preventDefault();
12564 } else if ( ( event.target === first[ 0 ] ||
12565 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
12566 this._delay( function() {
12567 last.trigger( "focus" );
12569 event.preventDefault();
12572 mousedown: function( event ) {
12573 if ( this._moveToTop( event ) ) {
12574 this._focusTabbable();
12579 // We assume that any existing aria-describedby attribute means
12580 // that the dialog content is marked up properly
12581 // otherwise we brute force the content as the description
12582 if ( !this.element.find( "[aria-describedby]" ).length ) {
12583 this.uiDialog.attr( {
12584 "aria-describedby": this.element.uniqueId().attr( "id" )
12589 _createTitlebar: function() {
12592 this.uiDialogTitlebar = $( "<div>" );
12593 this._addClass( this.uiDialogTitlebar,
12594 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
12595 this._on( this.uiDialogTitlebar, {
12596 mousedown: function( event ) {
12598 // Don't prevent click on close button (#8838)
12599 // Focusing a dialog that is partially scrolled out of view
12600 // causes the browser to scroll it into view, preventing the click event
12601 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
12603 // Dialog isn't getting focus when dragging (#8063)
12604 this.uiDialog.trigger( "focus" );
12610 // Use type="button" to prevent enter keypresses in textboxes from closing the
12611 // dialog in IE (#9312)
12612 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
12614 label: $( "<a>" ).text( this.options.closeText ).html(),
12615 icon: "ui-icon-closethick",
12618 .appendTo( this.uiDialogTitlebar );
12620 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
12621 this._on( this.uiDialogTitlebarClose, {
12622 click: function( event ) {
12623 event.preventDefault();
12624 this.close( event );
12628 uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
12629 this._addClass( uiDialogTitle, "ui-dialog-title" );
12630 this._title( uiDialogTitle );
12632 this.uiDialogTitlebar.prependTo( this.uiDialog );
12634 this.uiDialog.attr( {
12635 "aria-labelledby": uiDialogTitle.attr( "id" )
12639 _title: function( title ) {
12640 if ( this.options.title ) {
12641 title.text( this.options.title );
12643 title.html( " " );
12647 _createButtonPane: function() {
12648 this.uiDialogButtonPane = $( "<div>" );
12649 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
12650 "ui-widget-content ui-helper-clearfix" );
12652 this.uiButtonSet = $( "<div>" )
12653 .appendTo( this.uiDialogButtonPane );
12654 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
12656 this._createButtons();
12659 _createButtons: function() {
12661 buttons = this.options.buttons;
12663 // If we already have a button pane, remove it
12664 this.uiDialogButtonPane.remove();
12665 this.uiButtonSet.empty();
12667 if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) {
12668 this._removeClass( this.uiDialog, "ui-dialog-buttons" );
12672 $.each( buttons, function( name, props ) {
12673 var click, buttonOptions;
12674 props = typeof props === "function" ?
12675 { click: props, text: name } :
12678 // Default to a non-submitting button
12679 props = $.extend( { type: "button" }, props );
12681 // Change the context for the click callback to be the main element
12682 click = props.click;
12685 iconPosition: props.iconPosition,
12686 showLabel: props.showLabel,
12688 // Deprecated options
12689 icons: props.icons,
12693 delete props.click;
12695 delete props.iconPosition;
12696 delete props.showLabel;
12698 // Deprecated options
12699 delete props.icons;
12700 if ( typeof props.text === "boolean" ) {
12704 $( "<button></button>", props )
12705 .button( buttonOptions )
12706 .appendTo( that.uiButtonSet )
12707 .on( "click", function() {
12708 click.apply( that.element[ 0 ], arguments );
12711 this._addClass( this.uiDialog, "ui-dialog-buttons" );
12712 this.uiDialogButtonPane.appendTo( this.uiDialog );
12715 _makeDraggable: function() {
12717 options = this.options;
12719 function filteredUi( ui ) {
12721 position: ui.position,
12726 this.uiDialog.draggable( {
12727 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
12728 handle: ".ui-dialog-titlebar",
12729 containment: "document",
12730 start: function( event, ui ) {
12731 that._addClass( $( this ), "ui-dialog-dragging" );
12732 that._blockFrames();
12733 that._trigger( "dragStart", event, filteredUi( ui ) );
12735 drag: function( event, ui ) {
12736 that._trigger( "drag", event, filteredUi( ui ) );
12738 stop: function( event, ui ) {
12739 var left = ui.offset.left - that.document.scrollLeft(),
12740 top = ui.offset.top - that.document.scrollTop();
12742 options.position = {
12744 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12745 "top" + ( top >= 0 ? "+" : "" ) + top,
12748 that._removeClass( $( this ), "ui-dialog-dragging" );
12749 that._unblockFrames();
12750 that._trigger( "dragStop", event, filteredUi( ui ) );
12755 _makeResizable: function() {
12757 options = this.options,
12758 handles = options.resizable,
12760 // .ui-resizable has position: relative defined in the stylesheet
12761 // but dialogs have to use absolute or fixed positioning
12762 position = this.uiDialog.css( "position" ),
12763 resizeHandles = typeof handles === "string" ?
12765 "n,e,s,w,se,sw,ne,nw";
12767 function filteredUi( ui ) {
12769 originalPosition: ui.originalPosition,
12770 originalSize: ui.originalSize,
12771 position: ui.position,
12776 this.uiDialog.resizable( {
12777 cancel: ".ui-dialog-content",
12778 containment: "document",
12779 alsoResize: this.element,
12780 maxWidth: options.maxWidth,
12781 maxHeight: options.maxHeight,
12782 minWidth: options.minWidth,
12783 minHeight: this._minHeight(),
12784 handles: resizeHandles,
12785 start: function( event, ui ) {
12786 that._addClass( $( this ), "ui-dialog-resizing" );
12787 that._blockFrames();
12788 that._trigger( "resizeStart", event, filteredUi( ui ) );
12790 resize: function( event, ui ) {
12791 that._trigger( "resize", event, filteredUi( ui ) );
12793 stop: function( event, ui ) {
12794 var offset = that.uiDialog.offset(),
12795 left = offset.left - that.document.scrollLeft(),
12796 top = offset.top - that.document.scrollTop();
12798 options.height = that.uiDialog.height();
12799 options.width = that.uiDialog.width();
12800 options.position = {
12802 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12803 "top" + ( top >= 0 ? "+" : "" ) + top,
12806 that._removeClass( $( this ), "ui-dialog-resizing" );
12807 that._unblockFrames();
12808 that._trigger( "resizeStop", event, filteredUi( ui ) );
12811 .css( "position", position );
12814 _trackFocus: function() {
12815 this._on( this.widget(), {
12816 focusin: function( event ) {
12817 this._makeFocusTarget();
12818 this._focusedElement = $( event.target );
12823 _makeFocusTarget: function() {
12824 this._untrackInstance();
12825 this._trackingInstances().unshift( this );
12828 _untrackInstance: function() {
12829 var instances = this._trackingInstances(),
12830 exists = $.inArray( this, instances );
12831 if ( exists !== -1 ) {
12832 instances.splice( exists, 1 );
12836 _trackingInstances: function() {
12837 var instances = this.document.data( "ui-dialog-instances" );
12838 if ( !instances ) {
12840 this.document.data( "ui-dialog-instances", instances );
12845 _minHeight: function() {
12846 var options = this.options;
12848 return options.height === "auto" ?
12849 options.minHeight :
12850 Math.min( options.minHeight, options.height );
12853 _position: function() {
12855 // Need to show the dialog to get the actual offset in the position plugin
12856 var isVisible = this.uiDialog.is( ":visible" );
12857 if ( !isVisible ) {
12858 this.uiDialog.show();
12860 this.uiDialog.position( this.options.position );
12861 if ( !isVisible ) {
12862 this.uiDialog.hide();
12866 _setOptions: function( options ) {
12869 resizableOptions = {};
12871 $.each( options, function( key, value ) {
12872 that._setOption( key, value );
12874 if ( key in that.sizeRelatedOptions ) {
12877 if ( key in that.resizableRelatedOptions ) {
12878 resizableOptions[ key ] = value;
12886 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12887 this.uiDialog.resizable( "option", resizableOptions );
12891 _setOption: function( key, value ) {
12892 var isDraggable, isResizable,
12893 uiDialog = this.uiDialog;
12895 if ( key === "disabled" ) {
12899 this._super( key, value );
12901 if ( key === "appendTo" ) {
12902 this.uiDialog.appendTo( this._appendTo() );
12905 if ( key === "buttons" ) {
12906 this._createButtons();
12909 if ( key === "closeText" ) {
12910 this.uiDialogTitlebarClose.button( {
12912 // Ensure that we always pass a string
12913 label: $( "<a>" ).text( "" + this.options.closeText ).html()
12917 if ( key === "draggable" ) {
12918 isDraggable = uiDialog.is( ":data(ui-draggable)" );
12919 if ( isDraggable && !value ) {
12920 uiDialog.draggable( "destroy" );
12923 if ( !isDraggable && value ) {
12924 this._makeDraggable();
12928 if ( key === "position" ) {
12932 if ( key === "resizable" ) {
12934 // currently resizable, becoming non-resizable
12935 isResizable = uiDialog.is( ":data(ui-resizable)" );
12936 if ( isResizable && !value ) {
12937 uiDialog.resizable( "destroy" );
12940 // Currently resizable, changing handles
12941 if ( isResizable && typeof value === "string" ) {
12942 uiDialog.resizable( "option", "handles", value );
12945 // Currently non-resizable, becoming resizable
12946 if ( !isResizable && value !== false ) {
12947 this._makeResizable();
12951 if ( key === "title" ) {
12952 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
12956 _size: function() {
12958 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
12959 // divs will both have width and height set, so we need to reset them
12960 var nonContentHeight, minContentHeight, maxContentHeight,
12961 options = this.options;
12963 // Reset content sizing
12964 this.element.show().css( {
12971 if ( options.minWidth > options.width ) {
12972 options.width = options.minWidth;
12975 // Reset wrapper sizing
12976 // determine the height of all the non-content elements
12977 nonContentHeight = this.uiDialog.css( {
12979 width: options.width
12982 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
12983 maxContentHeight = typeof options.maxHeight === "number" ?
12984 Math.max( 0, options.maxHeight - nonContentHeight ) :
12987 if ( options.height === "auto" ) {
12988 this.element.css( {
12989 minHeight: minContentHeight,
12990 maxHeight: maxContentHeight,
12994 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
12997 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12998 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
13002 _blockFrames: function() {
13003 this.iframeBlocks = this.document.find( "iframe" ).map( function() {
13004 var iframe = $( this );
13006 return $( "<div>" )
13008 position: "absolute",
13009 width: iframe.outerWidth(),
13010 height: iframe.outerHeight()
13012 .appendTo( iframe.parent() )
13013 .offset( iframe.offset() )[ 0 ];
13017 _unblockFrames: function() {
13018 if ( this.iframeBlocks ) {
13019 this.iframeBlocks.remove();
13020 delete this.iframeBlocks;
13024 _allowInteraction: function( event ) {
13025 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
13029 // TODO: Remove hack when datepicker implements
13030 // the .ui-front logic (#8989)
13031 return !!$( event.target ).closest( ".ui-datepicker" ).length;
13034 _createOverlay: function() {
13035 if ( !this.options.modal ) {
13039 var jqMinor = $.fn.jquery.substring( 0, 4 );
13041 // We use a delay in case the overlay is created from an
13042 // event that we're going to be cancelling (#2804)
13043 var isOpening = true;
13044 this._delay( function() {
13048 if ( !this.document.data( "ui-dialog-overlays" ) ) {
13050 // Prevent use of anchors and inputs
13051 // This doesn't use `_on()` because it is a shared event handler
13052 // across all open modal dialogs.
13053 this.document.on( "focusin.ui-dialog", function( event ) {
13058 var instance = this._trackingInstances()[ 0 ];
13059 if ( !instance._allowInteraction( event ) ) {
13060 event.preventDefault();
13061 instance._focusTabbable();
13063 // Support: jQuery >=3.4 <3.6 only
13064 // Focus re-triggering in jQuery 3.4/3.5 makes the original element
13065 // have its focus event propagated last, breaking the re-targeting.
13066 // Trigger focus in a delay in addition if needed to avoid the issue
13067 // See https://github.com/jquery/jquery/issues/4382
13068 if ( jqMinor === "3.4." || jqMinor === "3.5." ) {
13069 instance._delay( instance._restoreTabbableFocus );
13075 this.overlay = $( "<div>" )
13076 .appendTo( this._appendTo() );
13078 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
13079 this._on( this.overlay, {
13080 mousedown: "_keepFocus"
13082 this.document.data( "ui-dialog-overlays",
13083 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
13086 _destroyOverlay: function() {
13087 if ( !this.options.modal ) {
13091 if ( this.overlay ) {
13092 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
13095 this.document.off( "focusin.ui-dialog" );
13096 this.document.removeData( "ui-dialog-overlays" );
13098 this.document.data( "ui-dialog-overlays", overlays );
13101 this.overlay.remove();
13102 this.overlay = null;
13108 // TODO: switch return back to widget declaration at top of file when this is removed
13109 if ( $.uiBackCompat !== false ) {
13111 // Backcompat for dialogClass option
13112 $.widget( "ui.dialog", $.ui.dialog, {
13116 _createWrapper: function() {
13118 this.uiDialog.addClass( this.options.dialogClass );
13120 _setOption: function( key, value ) {
13121 if ( key === "dialogClass" ) {
13123 .removeClass( this.options.dialogClass )
13124 .addClass( value );
13126 this._superApply( arguments );
13131 var widgetsDialog = $.ui.dialog;
13135 * jQuery UI Droppable 1.13.0
13136 * http://jqueryui.com
13138 * Copyright jQuery Foundation and other contributors
13139 * Released under the MIT license.
13140 * http://jquery.org/license
13143 //>>label: Droppable
13144 //>>group: Interactions
13145 //>>description: Enables drop targets for draggable elements.
13146 //>>docs: http://api.jqueryui.com/droppable/
13147 //>>demos: http://jqueryui.com/droppable/
13150 $.widget( "ui.droppable", {
13152 widgetEventPrefix: "drop",
13158 tolerance: "intersect",
13167 _create: function() {
13173 this.isover = false;
13176 this.accept = typeof accept === "function" ? accept : function( d ) {
13177 return d.is( accept );
13180 this.proportions = function( /* valueToWrite */ ) {
13181 if ( arguments.length ) {
13183 // Store the droppable's proportions
13184 proportions = arguments[ 0 ];
13187 // Retrieve or derive the droppable's proportions
13188 return proportions ?
13191 width: this.element[ 0 ].offsetWidth,
13192 height: this.element[ 0 ].offsetHeight
13197 this._addToManager( o.scope );
13199 if ( o.addClasses ) {
13200 this._addClass( "ui-droppable" );
13205 _addToManager: function( scope ) {
13207 // Add the reference and positions to the manager
13208 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
13209 $.ui.ddmanager.droppables[ scope ].push( this );
13212 _splice: function( drop ) {
13214 for ( ; i < drop.length; i++ ) {
13215 if ( drop[ i ] === this ) {
13216 drop.splice( i, 1 );
13221 _destroy: function() {
13222 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
13224 this._splice( drop );
13227 _setOption: function( key, value ) {
13229 if ( key === "accept" ) {
13230 this.accept = typeof value === "function" ? value : function( d ) {
13231 return d.is( value );
13233 } else if ( key === "scope" ) {
13234 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
13236 this._splice( drop );
13237 this._addToManager( value );
13240 this._super( key, value );
13243 _activate: function( event ) {
13244 var draggable = $.ui.ddmanager.current;
13246 this._addActiveClass();
13248 this._trigger( "activate", event, this.ui( draggable ) );
13252 _deactivate: function( event ) {
13253 var draggable = $.ui.ddmanager.current;
13255 this._removeActiveClass();
13257 this._trigger( "deactivate", event, this.ui( draggable ) );
13261 _over: function( event ) {
13263 var draggable = $.ui.ddmanager.current;
13265 // Bail if draggable and droppable are same element
13266 if ( !draggable || ( draggable.currentItem ||
13267 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13271 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
13272 draggable.element ) ) ) {
13273 this._addHoverClass();
13274 this._trigger( "over", event, this.ui( draggable ) );
13279 _out: function( event ) {
13281 var draggable = $.ui.ddmanager.current;
13283 // Bail if draggable and droppable are same element
13284 if ( !draggable || ( draggable.currentItem ||
13285 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13289 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
13290 draggable.element ) ) ) {
13291 this._removeHoverClass();
13292 this._trigger( "out", event, this.ui( draggable ) );
13297 _drop: function( event, custom ) {
13299 var draggable = custom || $.ui.ddmanager.current,
13300 childrenIntersection = false;
13302 // Bail if draggable and droppable are same element
13303 if ( !draggable || ( draggable.currentItem ||
13304 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13309 .find( ":data(ui-droppable)" )
13310 .not( ".ui-draggable-dragging" )
13311 .each( function() {
13312 var inst = $( this ).droppable( "instance" );
13314 inst.options.greedy &&
13315 !inst.options.disabled &&
13316 inst.options.scope === draggable.options.scope &&
13318 inst.element[ 0 ], ( draggable.currentItem || draggable.element )
13322 $.extend( inst, { offset: inst.element.offset() } ),
13323 inst.options.tolerance, event
13326 childrenIntersection = true;
13330 if ( childrenIntersection ) {
13334 if ( this.accept.call( this.element[ 0 ],
13335 ( draggable.currentItem || draggable.element ) ) ) {
13336 this._removeActiveClass();
13337 this._removeHoverClass();
13339 this._trigger( "drop", event, this.ui( draggable ) );
13340 return this.element;
13347 ui: function( c ) {
13349 draggable: ( c.currentItem || c.element ),
13351 position: c.position,
13352 offset: c.positionAbs
13356 // Extension points just to make backcompat sane and avoid duplicating logic
13357 // TODO: Remove in 1.14 along with call to it below
13358 _addHoverClass: function() {
13359 this._addClass( "ui-droppable-hover" );
13362 _removeHoverClass: function() {
13363 this._removeClass( "ui-droppable-hover" );
13366 _addActiveClass: function() {
13367 this._addClass( "ui-droppable-active" );
13370 _removeActiveClass: function() {
13371 this._removeClass( "ui-droppable-active" );
13375 $.ui.intersect = ( function() {
13376 function isOverAxis( x, reference, size ) {
13377 return ( x >= reference ) && ( x < ( reference + size ) );
13380 return function( draggable, droppable, toleranceMode, event ) {
13382 if ( !droppable.offset ) {
13386 var x1 = ( draggable.positionAbs ||
13387 draggable.position.absolute ).left + draggable.margins.left,
13388 y1 = ( draggable.positionAbs ||
13389 draggable.position.absolute ).top + draggable.margins.top,
13390 x2 = x1 + draggable.helperProportions.width,
13391 y2 = y1 + draggable.helperProportions.height,
13392 l = droppable.offset.left,
13393 t = droppable.offset.top,
13394 r = l + droppable.proportions().width,
13395 b = t + droppable.proportions().height;
13397 switch ( toleranceMode ) {
13399 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
13401 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
13402 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
13403 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
13404 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
13406 return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
13407 isOverAxis( event.pageX, l, droppable.proportions().width );
13410 ( y1 >= t && y1 <= b ) || // Top edge touching
13411 ( y2 >= t && y2 <= b ) || // Bottom edge touching
13412 ( y1 < t && y2 > b ) // Surrounded vertically
13414 ( x1 >= l && x1 <= r ) || // Left edge touching
13415 ( x2 >= l && x2 <= r ) || // Right edge touching
13416 ( x1 < l && x2 > r ) // Surrounded horizontally
13425 This manager tracks offsets of draggables and droppables
13429 droppables: { "default": [] },
13430 prepareOffsets: function( t, event ) {
13433 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
13434 type = event ? event.type : null, // workaround for #2317
13435 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
13437 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
13439 // No disabled and non-accepted
13440 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
13441 ( t.currentItem || t.element ) ) ) ) {
13445 // Filter out elements in the current dragged item
13446 for ( j = 0; j < list.length; j++ ) {
13447 if ( list[ j ] === m[ i ].element[ 0 ] ) {
13448 m[ i ].proportions().height = 0;
13449 continue droppablesLoop;
13453 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
13454 if ( !m[ i ].visible ) {
13458 // Activate the droppable if used directly from draggables
13459 if ( type === "mousedown" ) {
13460 m[ i ]._activate.call( m[ i ], event );
13463 m[ i ].offset = m[ i ].element.offset();
13464 m[ i ].proportions( {
13465 width: m[ i ].element[ 0 ].offsetWidth,
13466 height: m[ i ].element[ 0 ].offsetHeight
13472 drop: function( draggable, event ) {
13474 var dropped = false;
13476 // Create a copy of the droppables in case the list changes during the drop (#9116)
13477 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
13479 if ( !this.options ) {
13482 if ( !this.options.disabled && this.visible &&
13483 $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
13484 dropped = this._drop.call( this, event ) || dropped;
13487 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
13488 ( draggable.currentItem || draggable.element ) ) ) {
13490 this.isover = false;
13491 this._deactivate.call( this, event );
13498 dragStart: function( draggable, event ) {
13500 // Listen for scrolling so that if the dragging causes scrolling the position of the
13501 // droppables can be recalculated (see #5003)
13502 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
13503 if ( !draggable.options.refreshPositions ) {
13504 $.ui.ddmanager.prepareOffsets( draggable, event );
13508 drag: function( draggable, event ) {
13510 // If you have a highly dynamic page, you might try this option. It renders positions
13511 // every time you move the mouse.
13512 if ( draggable.options.refreshPositions ) {
13513 $.ui.ddmanager.prepareOffsets( draggable, event );
13516 // Run through all droppables and check their positions based on specific tolerance options
13517 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
13519 if ( this.options.disabled || this.greedyChild || !this.visible ) {
13523 var parentInstance, scope, parent,
13524 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
13525 c = !intersects && this.isover ?
13527 ( intersects && !this.isover ? "isover" : null );
13532 if ( this.options.greedy ) {
13534 // find droppable parents with same scope
13535 scope = this.options.scope;
13536 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
13537 return $( this ).droppable( "instance" ).options.scope === scope;
13540 if ( parent.length ) {
13541 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
13542 parentInstance.greedyChild = ( c === "isover" );
13546 // We just moved into a greedy child
13547 if ( parentInstance && c === "isover" ) {
13548 parentInstance.isover = false;
13549 parentInstance.isout = true;
13550 parentInstance._out.call( parentInstance, event );
13554 this[ c === "isout" ? "isover" : "isout" ] = false;
13555 this[ c === "isover" ? "_over" : "_out" ].call( this, event );
13557 // We just moved out of a greedy child
13558 if ( parentInstance && c === "isout" ) {
13559 parentInstance.isout = false;
13560 parentInstance.isover = true;
13561 parentInstance._over.call( parentInstance, event );
13566 dragStop: function( draggable, event ) {
13567 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
13569 // Call prepareOffsets one final time since IE does not fire return scroll events when
13570 // overflow was caused by drag (see #5003)
13571 if ( !draggable.options.refreshPositions ) {
13572 $.ui.ddmanager.prepareOffsets( draggable, event );
13578 // TODO: switch return back to widget declaration at top of file when this is removed
13579 if ( $.uiBackCompat !== false ) {
13581 // Backcompat for activeClass and hoverClass options
13582 $.widget( "ui.droppable", $.ui.droppable, {
13587 _addActiveClass: function() {
13589 if ( this.options.activeClass ) {
13590 this.element.addClass( this.options.activeClass );
13593 _removeActiveClass: function() {
13595 if ( this.options.activeClass ) {
13596 this.element.removeClass( this.options.activeClass );
13599 _addHoverClass: function() {
13601 if ( this.options.hoverClass ) {
13602 this.element.addClass( this.options.hoverClass );
13605 _removeHoverClass: function() {
13607 if ( this.options.hoverClass ) {
13608 this.element.removeClass( this.options.hoverClass );
13614 var widgetsDroppable = $.ui.droppable;
13618 * jQuery UI Progressbar 1.13.0
13619 * http://jqueryui.com
13621 * Copyright jQuery Foundation and other contributors
13622 * Released under the MIT license.
13623 * http://jquery.org/license
13626 //>>label: Progressbar
13628 /* eslint-disable max-len */
13629 //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
13630 /* eslint-enable max-len */
13631 //>>docs: http://api.jqueryui.com/progressbar/
13632 //>>demos: http://jqueryui.com/progressbar/
13633 //>>css.structure: ../../themes/base/core.css
13634 //>>css.structure: ../../themes/base/progressbar.css
13635 //>>css.theme: ../../themes/base/theme.css
13638 var widgetsProgressbar = $.widget( "ui.progressbar", {
13642 "ui-progressbar": "ui-corner-all",
13643 "ui-progressbar-value": "ui-corner-left",
13644 "ui-progressbar-complete": "ui-corner-right"
13655 _create: function() {
13657 // Constrain initial value
13658 this.oldValue = this.options.value = this._constrainedValue();
13660 this.element.attr( {
13662 // Only set static values; aria-valuenow and aria-valuemax are
13663 // set inside _refreshValue()
13664 role: "progressbar",
13665 "aria-valuemin": this.min
13667 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
13669 this.valueDiv = $( "<div>" ).appendTo( this.element );
13670 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
13671 this._refreshValue();
13674 _destroy: function() {
13675 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
13677 this.valueDiv.remove();
13680 value: function( newValue ) {
13681 if ( newValue === undefined ) {
13682 return this.options.value;
13685 this.options.value = this._constrainedValue( newValue );
13686 this._refreshValue();
13689 _constrainedValue: function( newValue ) {
13690 if ( newValue === undefined ) {
13691 newValue = this.options.value;
13694 this.indeterminate = newValue === false;
13697 if ( typeof newValue !== "number" ) {
13701 return this.indeterminate ? false :
13702 Math.min( this.options.max, Math.max( this.min, newValue ) );
13705 _setOptions: function( options ) {
13707 // Ensure "value" option is set after other values (like max)
13708 var value = options.value;
13709 delete options.value;
13711 this._super( options );
13713 this.options.value = this._constrainedValue( value );
13714 this._refreshValue();
13717 _setOption: function( key, value ) {
13718 if ( key === "max" ) {
13720 // Don't allow a max less than min
13721 value = Math.max( this.min, value );
13723 this._super( key, value );
13726 _setOptionDisabled: function( value ) {
13727 this._super( value );
13729 this.element.attr( "aria-disabled", value );
13730 this._toggleClass( null, "ui-state-disabled", !!value );
13733 _percentage: function() {
13734 return this.indeterminate ?
13736 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
13739 _refreshValue: function() {
13740 var value = this.options.value,
13741 percentage = this._percentage();
13744 .toggle( this.indeterminate || value > this.min )
13745 .width( percentage.toFixed( 0 ) + "%" );
13748 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
13749 value === this.options.max )
13750 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
13752 if ( this.indeterminate ) {
13753 this.element.removeAttr( "aria-valuenow" );
13754 if ( !this.overlayDiv ) {
13755 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
13756 this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
13759 this.element.attr( {
13760 "aria-valuemax": this.options.max,
13761 "aria-valuenow": value
13763 if ( this.overlayDiv ) {
13764 this.overlayDiv.remove();
13765 this.overlayDiv = null;
13769 if ( this.oldValue !== value ) {
13770 this.oldValue = value;
13771 this._trigger( "change" );
13773 if ( value === this.options.max ) {
13774 this._trigger( "complete" );
13781 * jQuery UI Selectable 1.13.0
13782 * http://jqueryui.com
13784 * Copyright jQuery Foundation and other contributors
13785 * Released under the MIT license.
13786 * http://jquery.org/license
13789 //>>label: Selectable
13790 //>>group: Interactions
13791 //>>description: Allows groups of elements to be selected with the mouse.
13792 //>>docs: http://api.jqueryui.com/selectable/
13793 //>>demos: http://jqueryui.com/selectable/
13794 //>>css.structure: ../../themes/base/selectable.css
13797 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
13804 tolerance: "touch",
13814 _create: function() {
13817 this._addClass( "ui-selectable" );
13819 this.dragged = false;
13821 // Cache selectee children based on filter
13822 this.refresh = function() {
13823 that.elementPos = $( that.element[ 0 ] ).offset();
13824 that.selectees = $( that.options.filter, that.element[ 0 ] );
13825 that._addClass( that.selectees, "ui-selectee" );
13826 that.selectees.each( function() {
13827 var $this = $( this ),
13828 selecteeOffset = $this.offset(),
13830 left: selecteeOffset.left - that.elementPos.left,
13831 top: selecteeOffset.top - that.elementPos.top
13833 $.data( this, "selectable-item", {
13838 right: pos.left + $this.outerWidth(),
13839 bottom: pos.top + $this.outerHeight(),
13840 startselected: false,
13841 selected: $this.hasClass( "ui-selected" ),
13842 selecting: $this.hasClass( "ui-selecting" ),
13843 unselecting: $this.hasClass( "ui-unselecting" )
13851 this.helper = $( "<div>" );
13852 this._addClass( this.helper, "ui-selectable-helper" );
13855 _destroy: function() {
13856 this.selectees.removeData( "selectable-item" );
13857 this._mouseDestroy();
13860 _mouseStart: function( event ) {
13862 options = this.options;
13864 this.opos = [ event.pageX, event.pageY ];
13865 this.elementPos = $( this.element[ 0 ] ).offset();
13867 if ( this.options.disabled ) {
13871 this.selectees = $( options.filter, this.element[ 0 ] );
13873 this._trigger( "start", event );
13875 $( options.appendTo ).append( this.helper );
13877 // position helper (lasso)
13879 "left": event.pageX,
13880 "top": event.pageY,
13885 if ( options.autoRefresh ) {
13889 this.selectees.filter( ".ui-selected" ).each( function() {
13890 var selectee = $.data( this, "selectable-item" );
13891 selectee.startselected = true;
13892 if ( !event.metaKey && !event.ctrlKey ) {
13893 that._removeClass( selectee.$element, "ui-selected" );
13894 selectee.selected = false;
13895 that._addClass( selectee.$element, "ui-unselecting" );
13896 selectee.unselecting = true;
13898 // selectable UNSELECTING callback
13899 that._trigger( "unselecting", event, {
13900 unselecting: selectee.element
13905 $( event.target ).parents().addBack().each( function() {
13907 selectee = $.data( this, "selectable-item" );
13909 doSelect = ( !event.metaKey && !event.ctrlKey ) ||
13910 !selectee.$element.hasClass( "ui-selected" );
13911 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
13912 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
13913 selectee.unselecting = !doSelect;
13914 selectee.selecting = doSelect;
13915 selectee.selected = doSelect;
13917 // selectable (UN)SELECTING callback
13919 that._trigger( "selecting", event, {
13920 selecting: selectee.element
13923 that._trigger( "unselecting", event, {
13924 unselecting: selectee.element
13933 _mouseDrag: function( event ) {
13935 this.dragged = true;
13937 if ( this.options.disabled ) {
13943 options = this.options,
13944 x1 = this.opos[ 0 ],
13945 y1 = this.opos[ 1 ],
13950 tmp = x2; x2 = x1; x1 = tmp;
13953 tmp = y2; y2 = y1; y1 = tmp;
13955 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
13957 this.selectees.each( function() {
13958 var selectee = $.data( this, "selectable-item" ),
13962 //prevent helper from being selected if appendTo: selectable
13963 if ( !selectee || selectee.element === that.element[ 0 ] ) {
13967 offset.left = selectee.left + that.elementPos.left;
13968 offset.right = selectee.right + that.elementPos.left;
13969 offset.top = selectee.top + that.elementPos.top;
13970 offset.bottom = selectee.bottom + that.elementPos.top;
13972 if ( options.tolerance === "touch" ) {
13973 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
13974 offset.bottom < y1 ) );
13975 } else if ( options.tolerance === "fit" ) {
13976 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
13977 offset.bottom < y2 );
13983 if ( selectee.selected ) {
13984 that._removeClass( selectee.$element, "ui-selected" );
13985 selectee.selected = false;
13987 if ( selectee.unselecting ) {
13988 that._removeClass( selectee.$element, "ui-unselecting" );
13989 selectee.unselecting = false;
13991 if ( !selectee.selecting ) {
13992 that._addClass( selectee.$element, "ui-selecting" );
13993 selectee.selecting = true;
13995 // selectable SELECTING callback
13996 that._trigger( "selecting", event, {
13997 selecting: selectee.element
14003 if ( selectee.selecting ) {
14004 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
14005 that._removeClass( selectee.$element, "ui-selecting" );
14006 selectee.selecting = false;
14007 that._addClass( selectee.$element, "ui-selected" );
14008 selectee.selected = true;
14010 that._removeClass( selectee.$element, "ui-selecting" );
14011 selectee.selecting = false;
14012 if ( selectee.startselected ) {
14013 that._addClass( selectee.$element, "ui-unselecting" );
14014 selectee.unselecting = true;
14017 // selectable UNSELECTING callback
14018 that._trigger( "unselecting", event, {
14019 unselecting: selectee.element
14023 if ( selectee.selected ) {
14024 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
14025 that._removeClass( selectee.$element, "ui-selected" );
14026 selectee.selected = false;
14028 that._addClass( selectee.$element, "ui-unselecting" );
14029 selectee.unselecting = true;
14031 // selectable UNSELECTING callback
14032 that._trigger( "unselecting", event, {
14033 unselecting: selectee.element
14043 _mouseStop: function( event ) {
14046 this.dragged = false;
14048 $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
14049 var selectee = $.data( this, "selectable-item" );
14050 that._removeClass( selectee.$element, "ui-unselecting" );
14051 selectee.unselecting = false;
14052 selectee.startselected = false;
14053 that._trigger( "unselected", event, {
14054 unselected: selectee.element
14057 $( ".ui-selecting", this.element[ 0 ] ).each( function() {
14058 var selectee = $.data( this, "selectable-item" );
14059 that._removeClass( selectee.$element, "ui-selecting" )
14060 ._addClass( selectee.$element, "ui-selected" );
14061 selectee.selecting = false;
14062 selectee.selected = true;
14063 selectee.startselected = true;
14064 that._trigger( "selected", event, {
14065 selected: selectee.element
14068 this._trigger( "stop", event );
14070 this.helper.remove();
14079 * jQuery UI Selectmenu 1.13.0
14080 * http://jqueryui.com
14082 * Copyright jQuery Foundation and other contributors
14083 * Released under the MIT license.
14084 * http://jquery.org/license
14087 //>>label: Selectmenu
14089 /* eslint-disable max-len */
14090 //>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
14091 /* eslint-enable max-len */
14092 //>>docs: http://api.jqueryui.com/selectmenu/
14093 //>>demos: http://jqueryui.com/selectmenu/
14094 //>>css.structure: ../../themes/base/core.css
14095 //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
14096 //>>css.theme: ../../themes/base/theme.css
14099 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
14101 defaultElement: "<select>",
14105 "ui-selectmenu-button-open": "ui-corner-top",
14106 "ui-selectmenu-button-closed": "ui-corner-all"
14110 button: "ui-icon-triangle-1-s"
14127 _create: function() {
14128 var selectmenuId = this.element.uniqueId().attr( "id" );
14130 element: selectmenuId,
14131 button: selectmenuId + "-button",
14132 menu: selectmenuId + "-menu"
14135 this._drawButton();
14137 this._bindFormResetHandler();
14139 this._rendered = false;
14140 this.menuItems = $();
14143 _drawButton: function() {
14146 item = this._parseOption(
14147 this.element.find( "option:selected" ),
14148 this.element[ 0 ].selectedIndex
14151 // Associate existing label with the new button
14152 this.labels = this.element.labels().attr( "for", this.ids.button );
14153 this._on( this.labels, {
14154 click: function( event ) {
14155 this.button.trigger( "focus" );
14156 event.preventDefault();
14160 // Hide original select element
14161 this.element.hide();
14164 this.button = $( "<span>", {
14165 tabindex: this.options.disabled ? -1 : 0,
14166 id: this.ids.button,
14168 "aria-expanded": "false",
14169 "aria-autocomplete": "list",
14170 "aria-owns": this.ids.menu,
14171 "aria-haspopup": "true",
14172 title: this.element.attr( "title" )
14174 .insertAfter( this.element );
14176 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
14177 "ui-button ui-widget" );
14179 icon = $( "<span>" ).appendTo( this.button );
14180 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
14181 this.buttonItem = this._renderButtonItem( item )
14182 .appendTo( this.button );
14184 if ( this.options.width !== false ) {
14185 this._resizeButton();
14188 this._on( this.button, this._buttonEvents );
14189 this.button.one( "focusin", function() {
14191 // Delay rendering the menu items until the button receives focus.
14192 // The menu may have already been rendered via a programmatic open.
14193 if ( !that._rendered ) {
14194 that._refreshMenu();
14199 _drawMenu: function() {
14203 this.menu = $( "<ul>", {
14204 "aria-hidden": "true",
14205 "aria-labelledby": this.ids.button,
14210 this.menuWrap = $( "<div>" ).append( this.menu );
14211 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
14212 this.menuWrap.appendTo( this._appendTo() );
14214 // Initialize menu widget
14215 this.menuInstance = this.menu
14218 "ui-menu": "ui-corner-bottom"
14221 select: function( event, ui ) {
14222 event.preventDefault();
14225 // If the item was selected via a click, the text selection
14226 // will be destroyed in IE
14227 that._setSelection();
14229 that._select( ui.item.data( "ui-selectmenu-item" ), event );
14231 focus: function( event, ui ) {
14232 var item = ui.item.data( "ui-selectmenu-item" );
14234 // Prevent inital focus from firing and check if its a newly focused item
14235 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
14236 that._trigger( "focus", event, { item: item } );
14237 if ( !that.isOpen ) {
14238 that._select( item, event );
14241 that.focusIndex = item.index;
14243 that.button.attr( "aria-activedescendant",
14244 that.menuItems.eq( item.index ).attr( "id" ) );
14247 .menu( "instance" );
14249 // Don't close the menu on mouseleave
14250 this.menuInstance._off( this.menu, "mouseleave" );
14252 // Cancel the menu's collapseAll on document click
14253 this.menuInstance._closeOnDocumentClick = function() {
14257 // Selects often contain empty items, but never contain dividers
14258 this.menuInstance._isDivider = function() {
14263 refresh: function() {
14264 this._refreshMenu();
14265 this.buttonItem.replaceWith(
14266 this.buttonItem = this._renderButtonItem(
14268 // Fall back to an empty object in case there are no options
14269 this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
14272 if ( this.options.width === null ) {
14273 this._resizeButton();
14277 _refreshMenu: function() {
14279 options = this.element.find( "option" );
14283 this._parseOptions( options );
14284 this._renderMenu( this.menu, this.items );
14286 this.menuInstance.refresh();
14287 this.menuItems = this.menu.find( "li" )
14288 .not( ".ui-selectmenu-optgroup" )
14289 .find( ".ui-menu-item-wrapper" );
14291 this._rendered = true;
14293 if ( !options.length ) {
14297 item = this._getSelectedItem();
14299 // Update the menu to have the correct item focused
14300 this.menuInstance.focus( null, item );
14301 this._setAria( item.data( "ui-selectmenu-item" ) );
14303 // Set disabled state
14304 this._setOption( "disabled", this.element.prop( "disabled" ) );
14307 open: function( event ) {
14308 if ( this.options.disabled ) {
14312 // If this is the first time the menu is being opened, render the items
14313 if ( !this._rendered ) {
14314 this._refreshMenu();
14317 // Menu clears focus on close, reset focus to selected item
14318 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
14319 this.menuInstance.focus( null, this._getSelectedItem() );
14322 // If there are no options, don't open the menu
14323 if ( !this.menuItems.length ) {
14327 this.isOpen = true;
14328 this._toggleAttr();
14329 this._resizeMenu();
14332 this._on( this.document, this._documentClick );
14334 this._trigger( "open", event );
14337 _position: function() {
14338 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
14341 close: function( event ) {
14342 if ( !this.isOpen ) {
14346 this.isOpen = false;
14347 this._toggleAttr();
14350 this._off( this.document );
14352 this._trigger( "close", event );
14355 widget: function() {
14356 return this.button;
14359 menuWidget: function() {
14363 _renderButtonItem: function( item ) {
14364 var buttonItem = $( "<span>" );
14366 this._setText( buttonItem, item.label );
14367 this._addClass( buttonItem, "ui-selectmenu-text" );
14372 _renderMenu: function( ul, items ) {
14374 currentOptgroup = "";
14376 $.each( items, function( index, item ) {
14379 if ( item.optgroup !== currentOptgroup ) {
14381 text: item.optgroup
14383 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
14384 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
14385 " ui-state-disabled" :
14390 currentOptgroup = item.optgroup;
14393 that._renderItemData( ul, item );
14397 _renderItemData: function( ul, item ) {
14398 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
14401 _renderItem: function( ul, item ) {
14402 var li = $( "<li>" ),
14403 wrapper = $( "<div>", {
14404 title: item.element.attr( "title" )
14407 if ( item.disabled ) {
14408 this._addClass( li, null, "ui-state-disabled" );
14410 this._setText( wrapper, item.label );
14412 return li.append( wrapper ).appendTo( ul );
14415 _setText: function( element, value ) {
14417 element.text( value );
14419 element.html( " " );
14423 _move: function( direction, event ) {
14425 filter = ".ui-menu-item";
14427 if ( this.isOpen ) {
14428 item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14430 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14431 filter += ":not(.ui-state-disabled)";
14434 if ( direction === "first" || direction === "last" ) {
14435 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
14437 next = item[ direction + "All" ]( filter ).eq( 0 );
14440 if ( next.length ) {
14441 this.menuInstance.focus( event, next );
14445 _getSelectedItem: function() {
14446 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14449 _toggle: function( event ) {
14450 this[ this.isOpen ? "close" : "open" ]( event );
14453 _setSelection: function() {
14456 if ( !this.range ) {
14460 if ( window.getSelection ) {
14461 selection = window.getSelection();
14462 selection.removeAllRanges();
14463 selection.addRange( this.range );
14467 this.range.select();
14471 // Setting the text selection kills the button focus in IE, but
14472 // restoring the focus doesn't kill the selection.
14473 this.button.focus();
14477 mousedown: function( event ) {
14478 if ( !this.isOpen ) {
14482 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
14483 $.escapeSelector( this.ids.button ) ).length ) {
14484 this.close( event );
14491 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
14492 mousedown: function() {
14495 if ( window.getSelection ) {
14496 selection = window.getSelection();
14497 if ( selection.rangeCount ) {
14498 this.range = selection.getRangeAt( 0 );
14503 this.range = document.selection.createRange();
14507 click: function( event ) {
14508 this._setSelection();
14509 this._toggle( event );
14512 keydown: function( event ) {
14513 var preventDefault = true;
14514 switch ( event.keyCode ) {
14515 case $.ui.keyCode.TAB:
14516 case $.ui.keyCode.ESCAPE:
14517 this.close( event );
14518 preventDefault = false;
14520 case $.ui.keyCode.ENTER:
14521 if ( this.isOpen ) {
14522 this._selectFocusedItem( event );
14525 case $.ui.keyCode.UP:
14526 if ( event.altKey ) {
14527 this._toggle( event );
14529 this._move( "prev", event );
14532 case $.ui.keyCode.DOWN:
14533 if ( event.altKey ) {
14534 this._toggle( event );
14536 this._move( "next", event );
14539 case $.ui.keyCode.SPACE:
14540 if ( this.isOpen ) {
14541 this._selectFocusedItem( event );
14543 this._toggle( event );
14546 case $.ui.keyCode.LEFT:
14547 this._move( "prev", event );
14549 case $.ui.keyCode.RIGHT:
14550 this._move( "next", event );
14552 case $.ui.keyCode.HOME:
14553 case $.ui.keyCode.PAGE_UP:
14554 this._move( "first", event );
14556 case $.ui.keyCode.END:
14557 case $.ui.keyCode.PAGE_DOWN:
14558 this._move( "last", event );
14561 this.menu.trigger( event );
14562 preventDefault = false;
14565 if ( preventDefault ) {
14566 event.preventDefault();
14571 _selectFocusedItem: function( event ) {
14572 var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14573 if ( !item.hasClass( "ui-state-disabled" ) ) {
14574 this._select( item.data( "ui-selectmenu-item" ), event );
14578 _select: function( item, event ) {
14579 var oldIndex = this.element[ 0 ].selectedIndex;
14581 // Change native select element
14582 this.element[ 0 ].selectedIndex = item.index;
14583 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
14584 this._setAria( item );
14585 this._trigger( "select", event, { item: item } );
14587 if ( item.index !== oldIndex ) {
14588 this._trigger( "change", event, { item: item } );
14591 this.close( event );
14594 _setAria: function( item ) {
14595 var id = this.menuItems.eq( item.index ).attr( "id" );
14597 this.button.attr( {
14598 "aria-labelledby": id,
14599 "aria-activedescendant": id
14601 this.menu.attr( "aria-activedescendant", id );
14604 _setOption: function( key, value ) {
14605 if ( key === "icons" ) {
14606 var icon = this.button.find( "span.ui-icon" );
14607 this._removeClass( icon, null, this.options.icons.button )
14608 ._addClass( icon, null, value.button );
14611 this._super( key, value );
14613 if ( key === "appendTo" ) {
14614 this.menuWrap.appendTo( this._appendTo() );
14617 if ( key === "width" ) {
14618 this._resizeButton();
14622 _setOptionDisabled: function( value ) {
14623 this._super( value );
14625 this.menuInstance.option( "disabled", value );
14626 this.button.attr( "aria-disabled", value );
14627 this._toggleClass( this.button, null, "ui-state-disabled", value );
14629 this.element.prop( "disabled", value );
14631 this.button.attr( "tabindex", -1 );
14634 this.button.attr( "tabindex", 0 );
14638 _appendTo: function() {
14639 var element = this.options.appendTo;
14642 element = element.jquery || element.nodeType ?
14644 this.document.find( element ).eq( 0 );
14647 if ( !element || !element[ 0 ] ) {
14648 element = this.element.closest( ".ui-front, dialog" );
14651 if ( !element.length ) {
14652 element = this.document[ 0 ].body;
14658 _toggleAttr: function() {
14659 this.button.attr( "aria-expanded", this.isOpen );
14661 // We can't use two _toggleClass() calls here, because we need to make sure
14662 // we always remove classes first and add them second, otherwise if both classes have the
14663 // same theme class, it will be removed after we add it.
14664 this._removeClass( this.button, "ui-selectmenu-button-" +
14665 ( this.isOpen ? "closed" : "open" ) )
14666 ._addClass( this.button, "ui-selectmenu-button-" +
14667 ( this.isOpen ? "open" : "closed" ) )
14668 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
14670 this.menu.attr( "aria-hidden", !this.isOpen );
14673 _resizeButton: function() {
14674 var width = this.options.width;
14676 // For `width: false`, just remove inline style and stop
14677 if ( width === false ) {
14678 this.button.css( "width", "" );
14682 // For `width: null`, match the width of the original element
14683 if ( width === null ) {
14684 width = this.element.show().outerWidth();
14685 this.element.hide();
14688 this.button.outerWidth( width );
14691 _resizeMenu: function() {
14692 this.menu.outerWidth( Math.max(
14693 this.button.outerWidth(),
14696 // IE10 wraps long text (possibly a rounding bug)
14697 // so we add 1px to avoid the wrapping
14698 this.menu.width( "" ).outerWidth() + 1
14702 _getCreateOptions: function() {
14703 var options = this._super();
14705 options.disabled = this.element.prop( "disabled" );
14710 _parseOptions: function( options ) {
14713 options.each( function( index, item ) {
14714 if ( item.hidden ) {
14718 data.push( that._parseOption( $( item ), index ) );
14723 _parseOption: function( option, index ) {
14724 var optgroup = option.parent( "optgroup" );
14729 value: option.val(),
14730 label: option.text(),
14731 optgroup: optgroup.attr( "label" ) || "",
14732 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
14736 _destroy: function() {
14737 this._unbindFormResetHandler();
14738 this.menuWrap.remove();
14739 this.button.remove();
14740 this.element.show();
14741 this.element.removeUniqueId();
14742 this.labels.attr( "for", this.ids.element );
14748 * jQuery UI Slider 1.13.0
14749 * http://jqueryui.com
14751 * Copyright jQuery Foundation and other contributors
14752 * Released under the MIT license.
14753 * http://jquery.org/license
14758 //>>description: Displays a flexible slider with ranges and accessibility via keyboard.
14759 //>>docs: http://api.jqueryui.com/slider/
14760 //>>demos: http://jqueryui.com/slider/
14761 //>>css.structure: ../../themes/base/core.css
14762 //>>css.structure: ../../themes/base/slider.css
14763 //>>css.theme: ../../themes/base/theme.css
14766 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
14768 widgetEventPrefix: "slide",
14773 "ui-slider": "ui-corner-all",
14774 "ui-slider-handle": "ui-corner-all",
14776 // Note: ui-widget-header isn't the most fittingly semantic framework class for this
14777 // element, but worked best visually with a variety of themes
14778 "ui-slider-range": "ui-corner-all ui-widget-header"
14783 orientation: "horizontal",
14796 // Number of pages in a slider
14797 // (how many times can you page up/down to go through the whole range)
14800 _create: function() {
14801 this._keySliding = false;
14802 this._mouseSliding = false;
14803 this._animateOff = true;
14804 this._handleIndex = null;
14805 this._detectOrientation();
14807 this._calculateNewMax();
14809 this._addClass( "ui-slider ui-slider-" + this.orientation,
14810 "ui-widget ui-widget-content" );
14814 this._animateOff = false;
14817 _refresh: function() {
14818 this._createRange();
14819 this._createHandles();
14820 this._setupEvents();
14821 this._refreshValue();
14824 _createHandles: function() {
14825 var i, handleCount,
14826 options = this.options,
14827 existingHandles = this.element.find( ".ui-slider-handle" ),
14828 handle = "<span tabindex='0'></span>",
14831 handleCount = ( options.values && options.values.length ) || 1;
14833 if ( existingHandles.length > handleCount ) {
14834 existingHandles.slice( handleCount ).remove();
14835 existingHandles = existingHandles.slice( 0, handleCount );
14838 for ( i = existingHandles.length; i < handleCount; i++ ) {
14839 handles.push( handle );
14842 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
14844 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
14846 this.handle = this.handles.eq( 0 );
14848 this.handles.each( function( i ) {
14850 .data( "ui-slider-handle-index", i )
14851 .attr( "tabIndex", 0 );
14855 _createRange: function() {
14856 var options = this.options;
14858 if ( options.range ) {
14859 if ( options.range === true ) {
14860 if ( !options.values ) {
14861 options.values = [ this._valueMin(), this._valueMin() ];
14862 } else if ( options.values.length && options.values.length !== 2 ) {
14863 options.values = [ options.values[ 0 ], options.values[ 0 ] ];
14864 } else if ( Array.isArray( options.values ) ) {
14865 options.values = options.values.slice( 0 );
14869 if ( !this.range || !this.range.length ) {
14870 this.range = $( "<div>" )
14871 .appendTo( this.element );
14873 this._addClass( this.range, "ui-slider-range" );
14875 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
14877 // Handle range switching from true to min/max
14883 if ( options.range === "min" || options.range === "max" ) {
14884 this._addClass( this.range, "ui-slider-range-" + options.range );
14887 if ( this.range ) {
14888 this.range.remove();
14894 _setupEvents: function() {
14895 this._off( this.handles );
14896 this._on( this.handles, this._handleEvents );
14897 this._hoverable( this.handles );
14898 this._focusable( this.handles );
14901 _destroy: function() {
14902 this.handles.remove();
14903 if ( this.range ) {
14904 this.range.remove();
14907 this._mouseDestroy();
14910 _mouseCapture: function( event ) {
14911 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
14915 if ( o.disabled ) {
14919 this.elementSize = {
14920 width: this.element.outerWidth(),
14921 height: this.element.outerHeight()
14923 this.elementOffset = this.element.offset();
14925 position = { x: event.pageX, y: event.pageY };
14926 normValue = this._normValueFromMouse( position );
14927 distance = this._valueMax() - this._valueMin() + 1;
14928 this.handles.each( function( i ) {
14929 var thisDistance = Math.abs( normValue - that.values( i ) );
14930 if ( ( distance > thisDistance ) ||
14931 ( distance === thisDistance &&
14932 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
14933 distance = thisDistance;
14934 closestHandle = $( this );
14939 allowed = this._start( event, index );
14940 if ( allowed === false ) {
14943 this._mouseSliding = true;
14945 this._handleIndex = index;
14947 this._addClass( closestHandle, null, "ui-state-active" );
14948 closestHandle.trigger( "focus" );
14950 offset = closestHandle.offset();
14951 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
14952 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
14953 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
14954 top: event.pageY - offset.top -
14955 ( closestHandle.height() / 2 ) -
14956 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
14957 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
14958 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
14961 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
14962 this._slide( event, index, normValue );
14964 this._animateOff = true;
14968 _mouseStart: function() {
14972 _mouseDrag: function( event ) {
14973 var position = { x: event.pageX, y: event.pageY },
14974 normValue = this._normValueFromMouse( position );
14976 this._slide( event, this._handleIndex, normValue );
14981 _mouseStop: function( event ) {
14982 this._removeClass( this.handles, null, "ui-state-active" );
14983 this._mouseSliding = false;
14985 this._stop( event, this._handleIndex );
14986 this._change( event, this._handleIndex );
14988 this._handleIndex = null;
14989 this._clickOffset = null;
14990 this._animateOff = false;
14995 _detectOrientation: function() {
14996 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
14999 _normValueFromMouse: function( position ) {
15006 if ( this.orientation === "horizontal" ) {
15007 pixelTotal = this.elementSize.width;
15008 pixelMouse = position.x - this.elementOffset.left -
15009 ( this._clickOffset ? this._clickOffset.left : 0 );
15011 pixelTotal = this.elementSize.height;
15012 pixelMouse = position.y - this.elementOffset.top -
15013 ( this._clickOffset ? this._clickOffset.top : 0 );
15016 percentMouse = ( pixelMouse / pixelTotal );
15017 if ( percentMouse > 1 ) {
15020 if ( percentMouse < 0 ) {
15023 if ( this.orientation === "vertical" ) {
15024 percentMouse = 1 - percentMouse;
15027 valueTotal = this._valueMax() - this._valueMin();
15028 valueMouse = this._valueMin() + percentMouse * valueTotal;
15030 return this._trimAlignValue( valueMouse );
15033 _uiHash: function( index, value, values ) {
15035 handle: this.handles[ index ],
15036 handleIndex: index,
15037 value: value !== undefined ? value : this.value()
15040 if ( this._hasMultipleValues() ) {
15041 uiHash.value = value !== undefined ? value : this.values( index );
15042 uiHash.values = values || this.values();
15048 _hasMultipleValues: function() {
15049 return this.options.values && this.options.values.length;
15052 _start: function( event, index ) {
15053 return this._trigger( "start", event, this._uiHash( index ) );
15056 _slide: function( event, index, newVal ) {
15057 var allowed, otherVal,
15058 currentValue = this.value(),
15059 newValues = this.values();
15061 if ( this._hasMultipleValues() ) {
15062 otherVal = this.values( index ? 0 : 1 );
15063 currentValue = this.values( index );
15065 if ( this.options.values.length === 2 && this.options.range === true ) {
15066 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
15069 newValues[ index ] = newVal;
15072 if ( newVal === currentValue ) {
15076 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
15078 // A slide can be canceled by returning false from the slide callback
15079 if ( allowed === false ) {
15083 if ( this._hasMultipleValues() ) {
15084 this.values( index, newVal );
15086 this.value( newVal );
15090 _stop: function( event, index ) {
15091 this._trigger( "stop", event, this._uiHash( index ) );
15094 _change: function( event, index ) {
15095 if ( !this._keySliding && !this._mouseSliding ) {
15097 //store the last changed value index for reference when handles overlap
15098 this._lastChangedValue = index;
15099 this._trigger( "change", event, this._uiHash( index ) );
15103 value: function( newValue ) {
15104 if ( arguments.length ) {
15105 this.options.value = this._trimAlignValue( newValue );
15106 this._refreshValue();
15107 this._change( null, 0 );
15111 return this._value();
15114 values: function( index, newValue ) {
15119 if ( arguments.length > 1 ) {
15120 this.options.values[ index ] = this._trimAlignValue( newValue );
15121 this._refreshValue();
15122 this._change( null, index );
15126 if ( arguments.length ) {
15127 if ( Array.isArray( arguments[ 0 ] ) ) {
15128 vals = this.options.values;
15129 newValues = arguments[ 0 ];
15130 for ( i = 0; i < vals.length; i += 1 ) {
15131 vals[ i ] = this._trimAlignValue( newValues[ i ] );
15132 this._change( null, i );
15134 this._refreshValue();
15136 if ( this._hasMultipleValues() ) {
15137 return this._values( index );
15139 return this.value();
15143 return this._values();
15147 _setOption: function( key, value ) {
15151 if ( key === "range" && this.options.range === true ) {
15152 if ( value === "min" ) {
15153 this.options.value = this._values( 0 );
15154 this.options.values = null;
15155 } else if ( value === "max" ) {
15156 this.options.value = this._values( this.options.values.length - 1 );
15157 this.options.values = null;
15161 if ( Array.isArray( this.options.values ) ) {
15162 valsLength = this.options.values.length;
15165 this._super( key, value );
15168 case "orientation":
15169 this._detectOrientation();
15170 this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
15171 ._addClass( "ui-slider-" + this.orientation );
15172 this._refreshValue();
15173 if ( this.options.range ) {
15174 this._refreshRange( value );
15177 // Reset positioning from previous orientation
15178 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
15181 this._animateOff = true;
15182 this._refreshValue();
15183 this._change( null, 0 );
15184 this._animateOff = false;
15187 this._animateOff = true;
15188 this._refreshValue();
15190 // Start from the last handle to prevent unreachable handles (#9046)
15191 for ( i = valsLength - 1; i >= 0; i-- ) {
15192 this._change( null, i );
15194 this._animateOff = false;
15199 this._animateOff = true;
15200 this._calculateNewMax();
15201 this._refreshValue();
15202 this._animateOff = false;
15205 this._animateOff = true;
15207 this._animateOff = false;
15212 _setOptionDisabled: function( value ) {
15213 this._super( value );
15215 this._toggleClass( null, "ui-state-disabled", !!value );
15218 //internal value getter
15219 // _value() returns value trimmed by min and max, aligned by step
15220 _value: function() {
15221 var val = this.options.value;
15222 val = this._trimAlignValue( val );
15227 //internal values getter
15228 // _values() returns array of values trimmed by min and max, aligned by step
15229 // _values( index ) returns single value trimmed by min and max, aligned by step
15230 _values: function( index ) {
15235 if ( arguments.length ) {
15236 val = this.options.values[ index ];
15237 val = this._trimAlignValue( val );
15240 } else if ( this._hasMultipleValues() ) {
15242 // .slice() creates a copy of the array
15243 // this copy gets trimmed by min and max and then returned
15244 vals = this.options.values.slice();
15245 for ( i = 0; i < vals.length; i += 1 ) {
15246 vals[ i ] = this._trimAlignValue( vals[ i ] );
15255 // Returns the step-aligned value that val is closest to, between (inclusive) min and max
15256 _trimAlignValue: function( val ) {
15257 if ( val <= this._valueMin() ) {
15258 return this._valueMin();
15260 if ( val >= this._valueMax() ) {
15261 return this._valueMax();
15263 var step = ( this.options.step > 0 ) ? this.options.step : 1,
15264 valModStep = ( val - this._valueMin() ) % step,
15265 alignValue = val - valModStep;
15267 if ( Math.abs( valModStep ) * 2 >= step ) {
15268 alignValue += ( valModStep > 0 ) ? step : ( -step );
15271 // Since JavaScript has problems with large floats, round
15272 // the final value to 5 digits after the decimal point (see #4124)
15273 return parseFloat( alignValue.toFixed( 5 ) );
15276 _calculateNewMax: function() {
15277 var max = this.options.max,
15278 min = this._valueMin(),
15279 step = this.options.step,
15280 aboveMin = Math.round( ( max - min ) / step ) * step;
15281 max = aboveMin + min;
15282 if ( max > this.options.max ) {
15284 //If max is not divisible by step, rounding off may increase its value
15287 this.max = parseFloat( max.toFixed( this._precision() ) );
15290 _precision: function() {
15291 var precision = this._precisionOf( this.options.step );
15292 if ( this.options.min !== null ) {
15293 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15298 _precisionOf: function( num ) {
15299 var str = num.toString(),
15300 decimal = str.indexOf( "." );
15301 return decimal === -1 ? 0 : str.length - decimal - 1;
15304 _valueMin: function() {
15305 return this.options.min;
15308 _valueMax: function() {
15312 _refreshRange: function( orientation ) {
15313 if ( orientation === "vertical" ) {
15314 this.range.css( { "width": "", "left": "" } );
15316 if ( orientation === "horizontal" ) {
15317 this.range.css( { "height": "", "bottom": "" } );
15321 _refreshValue: function() {
15322 var lastValPercent, valPercent, value, valueMin, valueMax,
15323 oRange = this.options.range,
15326 animate = ( !this._animateOff ) ? o.animate : false,
15329 if ( this._hasMultipleValues() ) {
15330 this.handles.each( function( i ) {
15331 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
15332 that._valueMin() ) * 100;
15333 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15334 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15335 if ( that.options.range === true ) {
15336 if ( that.orientation === "horizontal" ) {
15338 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15339 left: valPercent + "%"
15343 that.range[ animate ? "animate" : "css" ]( {
15344 width: ( valPercent - lastValPercent ) + "%"
15347 duration: o.animate
15352 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15353 bottom: ( valPercent ) + "%"
15357 that.range[ animate ? "animate" : "css" ]( {
15358 height: ( valPercent - lastValPercent ) + "%"
15361 duration: o.animate
15366 lastValPercent = valPercent;
15369 value = this.value();
15370 valueMin = this._valueMin();
15371 valueMax = this._valueMax();
15372 valPercent = ( valueMax !== valueMin ) ?
15373 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
15375 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15376 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15378 if ( oRange === "min" && this.orientation === "horizontal" ) {
15379 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15380 width: valPercent + "%"
15383 if ( oRange === "max" && this.orientation === "horizontal" ) {
15384 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15385 width: ( 100 - valPercent ) + "%"
15388 if ( oRange === "min" && this.orientation === "vertical" ) {
15389 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15390 height: valPercent + "%"
15393 if ( oRange === "max" && this.orientation === "vertical" ) {
15394 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15395 height: ( 100 - valPercent ) + "%"
15402 keydown: function( event ) {
15403 var allowed, curVal, newVal, step,
15404 index = $( event.target ).data( "ui-slider-handle-index" );
15406 switch ( event.keyCode ) {
15407 case $.ui.keyCode.HOME:
15408 case $.ui.keyCode.END:
15409 case $.ui.keyCode.PAGE_UP:
15410 case $.ui.keyCode.PAGE_DOWN:
15411 case $.ui.keyCode.UP:
15412 case $.ui.keyCode.RIGHT:
15413 case $.ui.keyCode.DOWN:
15414 case $.ui.keyCode.LEFT:
15415 event.preventDefault();
15416 if ( !this._keySliding ) {
15417 this._keySliding = true;
15418 this._addClass( $( event.target ), null, "ui-state-active" );
15419 allowed = this._start( event, index );
15420 if ( allowed === false ) {
15427 step = this.options.step;
15428 if ( this._hasMultipleValues() ) {
15429 curVal = newVal = this.values( index );
15431 curVal = newVal = this.value();
15434 switch ( event.keyCode ) {
15435 case $.ui.keyCode.HOME:
15436 newVal = this._valueMin();
15438 case $.ui.keyCode.END:
15439 newVal = this._valueMax();
15441 case $.ui.keyCode.PAGE_UP:
15442 newVal = this._trimAlignValue(
15443 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
15446 case $.ui.keyCode.PAGE_DOWN:
15447 newVal = this._trimAlignValue(
15448 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
15450 case $.ui.keyCode.UP:
15451 case $.ui.keyCode.RIGHT:
15452 if ( curVal === this._valueMax() ) {
15455 newVal = this._trimAlignValue( curVal + step );
15457 case $.ui.keyCode.DOWN:
15458 case $.ui.keyCode.LEFT:
15459 if ( curVal === this._valueMin() ) {
15462 newVal = this._trimAlignValue( curVal - step );
15466 this._slide( event, index, newVal );
15468 keyup: function( event ) {
15469 var index = $( event.target ).data( "ui-slider-handle-index" );
15471 if ( this._keySliding ) {
15472 this._keySliding = false;
15473 this._stop( event, index );
15474 this._change( event, index );
15475 this._removeClass( $( event.target ), null, "ui-state-active" );
15483 * jQuery UI Sortable 1.13.0
15484 * http://jqueryui.com
15486 * Copyright jQuery Foundation and other contributors
15487 * Released under the MIT license.
15488 * http://jquery.org/license
15491 //>>label: Sortable
15492 //>>group: Interactions
15493 //>>description: Enables items in a list to be sorted using the mouse.
15494 //>>docs: http://api.jqueryui.com/sortable/
15495 //>>demos: http://jqueryui.com/sortable/
15496 //>>css.structure: ../../themes/base/sortable.css
15499 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
15501 widgetEventPrefix: "sort",
15504 appendTo: "parent",
15506 connectWith: false,
15507 containment: false,
15511 forcePlaceholderSize: false,
15512 forceHelperSize: false,
15515 helper: "original",
15518 placeholder: false,
15521 scrollSensitivity: 20,
15524 tolerance: "intersect",
15542 _isOverAxis: function( x, reference, size ) {
15543 return ( x >= reference ) && ( x < ( reference + size ) );
15546 _isFloating: function( item ) {
15547 return ( /left|right/ ).test( item.css( "float" ) ) ||
15548 ( /inline|table-cell/ ).test( item.css( "display" ) );
15551 _create: function() {
15552 this.containerCache = {};
15553 this._addClass( "ui-sortable" );
15558 //Let's determine the parent's offset
15559 this.offset = this.element.offset();
15561 //Initialize mouse events for interaction
15564 this._setHandleClassName();
15566 //We're ready to go
15571 _setOption: function( key, value ) {
15572 this._super( key, value );
15574 if ( key === "handle" ) {
15575 this._setHandleClassName();
15579 _setHandleClassName: function() {
15581 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
15582 $.each( this.items, function() {
15584 this.instance.options.handle ?
15585 this.item.find( this.instance.options.handle ) :
15587 "ui-sortable-handle"
15592 _destroy: function() {
15593 this._mouseDestroy();
15595 for ( var i = this.items.length - 1; i >= 0; i-- ) {
15596 this.items[ i ].item.removeData( this.widgetName + "-item" );
15602 _mouseCapture: function( event, overrideHandle ) {
15603 var currentItem = null,
15604 validHandle = false,
15607 if ( this.reverting ) {
15611 if ( this.options.disabled || this.options.type === "static" ) {
15615 //We have to refresh the items data once first
15616 this._refreshItems( event );
15618 //Find out if the clicked node (or one of its parents) is a actual item in this.items
15619 $( event.target ).parents().each( function() {
15620 if ( $.data( this, that.widgetName + "-item" ) === that ) {
15621 currentItem = $( this );
15625 if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
15626 currentItem = $( event.target );
15629 if ( !currentItem ) {
15632 if ( this.options.handle && !overrideHandle ) {
15633 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
15634 if ( this === event.target ) {
15635 validHandle = true;
15638 if ( !validHandle ) {
15643 this.currentItem = currentItem;
15644 this._removeCurrentsFromItems();
15649 _mouseStart: function( event, overrideHandle, noActivation ) {
15654 this.currentContainer = this;
15656 //We only need to call refreshPositions, because the refreshItems call has been moved to
15658 this.refreshPositions();
15660 //Prepare the dragged items parent
15661 this.appendTo = $( o.appendTo !== "parent" ?
15663 this.currentItem.parent() );
15665 //Create and append the visible helper
15666 this.helper = this._createHelper( event );
15668 //Cache the helper size
15669 this._cacheHelperProportions();
15672 * - Position generation -
15673 * This block generates everything position related - it's the core of draggables.
15676 //Cache the margins of the original element
15677 this._cacheMargins();
15679 //The element's absolute position on the page minus margins
15680 this.offset = this.currentItem.offset();
15682 top: this.offset.top - this.margins.top,
15683 left: this.offset.left - this.margins.left
15686 $.extend( this.offset, {
15687 click: { //Where the click happened, relative to the element
15688 left: event.pageX - this.offset.left,
15689 top: event.pageY - this.offset.top
15692 // This is a relative to absolute position minus the actual position calculation -
15693 // only used for relative positioned helper
15694 relative: this._getRelativeOffset()
15697 // After we get the helper offset, but before we get the parent offset we can
15698 // change the helper's position to absolute
15699 // TODO: Still need to figure out a way to make relative sorting possible
15700 this.helper.css( "position", "absolute" );
15701 this.cssPosition = this.helper.css( "position" );
15703 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
15704 if ( o.cursorAt ) {
15705 this._adjustOffsetFromHelper( o.cursorAt );
15708 //Cache the former DOM position
15709 this.domPosition = {
15710 prev: this.currentItem.prev()[ 0 ],
15711 parent: this.currentItem.parent()[ 0 ]
15714 // If the helper is not the original, hide the original so it's not playing any role during
15715 // the drag, won't cause anything bad this way
15716 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
15717 this.currentItem.hide();
15720 //Create the placeholder
15721 this._createPlaceholder();
15723 //Get the next scrolling parent
15724 this.scrollParent = this.placeholder.scrollParent();
15726 $.extend( this.offset, {
15727 parent: this._getParentOffset()
15730 //Set a containment if given in the options
15731 if ( o.containment ) {
15732 this._setContainment();
15735 if ( o.cursor && o.cursor !== "auto" ) { // cursor option
15736 body = this.document.find( "body" );
15739 this.storedCursor = body.css( "cursor" );
15740 body.css( "cursor", o.cursor );
15742 this.storedStylesheet =
15743 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
15746 // We need to make sure to grab the zIndex before setting the
15747 // opacity, because setting the opacity to anything lower than 1
15748 // causes the zIndex to change from "auto" to 0.
15749 if ( o.zIndex ) { // zIndex option
15750 if ( this.helper.css( "zIndex" ) ) {
15751 this._storedZIndex = this.helper.css( "zIndex" );
15753 this.helper.css( "zIndex", o.zIndex );
15756 if ( o.opacity ) { // opacity option
15757 if ( this.helper.css( "opacity" ) ) {
15758 this._storedOpacity = this.helper.css( "opacity" );
15760 this.helper.css( "opacity", o.opacity );
15763 //Prepare scrolling
15764 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15765 this.scrollParent[ 0 ].tagName !== "HTML" ) {
15766 this.overflowOffset = this.scrollParent.offset();
15770 this._trigger( "start", event, this._uiHash() );
15772 //Recache the helper size
15773 if ( !this._preserveHelperProportions ) {
15774 this._cacheHelperProportions();
15777 //Post "activate" events to possible containers
15778 if ( !noActivation ) {
15779 for ( i = this.containers.length - 1; i >= 0; i-- ) {
15780 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
15784 //Prepare possible droppables
15785 if ( $.ui.ddmanager ) {
15786 $.ui.ddmanager.current = this;
15789 if ( $.ui.ddmanager && !o.dropBehaviour ) {
15790 $.ui.ddmanager.prepareOffsets( this, event );
15793 this.dragging = true;
15795 this._addClass( this.helper, "ui-sortable-helper" );
15797 //Move the helper, if needed
15798 if ( !this.helper.parent().is( this.appendTo ) ) {
15799 this.helper.detach().appendTo( this.appendTo );
15802 this.offset.parent = this._getParentOffset();
15805 //Generate the original position
15806 this.position = this.originalPosition = this._generatePosition( event );
15807 this.originalPageX = event.pageX;
15808 this.originalPageY = event.pageY;
15809 this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" );
15811 this._mouseDrag( event );
15817 _scroll: function( event ) {
15818 var o = this.options,
15821 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15822 this.scrollParent[ 0 ].tagName !== "HTML" ) {
15824 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
15825 event.pageY < o.scrollSensitivity ) {
15826 this.scrollParent[ 0 ].scrollTop =
15827 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
15828 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
15829 this.scrollParent[ 0 ].scrollTop =
15830 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
15833 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
15834 event.pageX < o.scrollSensitivity ) {
15835 this.scrollParent[ 0 ].scrollLeft = scrolled =
15836 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
15837 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
15838 this.scrollParent[ 0 ].scrollLeft = scrolled =
15839 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
15844 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
15845 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
15846 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
15847 o.scrollSensitivity ) {
15848 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
15851 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
15852 scrolled = this.document.scrollLeft(
15853 this.document.scrollLeft() - o.scrollSpeed
15855 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
15856 o.scrollSensitivity ) {
15857 scrolled = this.document.scrollLeft(
15858 this.document.scrollLeft() + o.scrollSpeed
15867 _mouseDrag: function( event ) {
15868 var i, item, itemElement, intersection,
15871 //Compute the helpers position
15872 this.position = this._generatePosition( event );
15873 this.positionAbs = this._convertPositionTo( "absolute" );
15875 //Set the helper position
15876 if ( !this.options.axis || this.options.axis !== "y" ) {
15877 this.helper[ 0 ].style.left = this.position.left + "px";
15879 if ( !this.options.axis || this.options.axis !== "x" ) {
15880 this.helper[ 0 ].style.top = this.position.top + "px";
15883 //Post events to containers
15884 this._contactContainers( event );
15886 if ( this.innermostContainer !== null ) {
15890 if ( this._scroll( event ) !== false ) {
15892 //Update item positions used in position checks
15893 this._refreshItemPositions( true );
15895 if ( $.ui.ddmanager && !o.dropBehaviour ) {
15896 $.ui.ddmanager.prepareOffsets( this, event );
15901 this.dragDirection = {
15902 vertical: this._getDragVerticalDirection(),
15903 horizontal: this._getDragHorizontalDirection()
15907 for ( i = this.items.length - 1; i >= 0; i-- ) {
15909 //Cache variables and intersection, continue if no intersection
15910 item = this.items[ i ];
15911 itemElement = item.item[ 0 ];
15912 intersection = this._intersectsWithPointer( item );
15913 if ( !intersection ) {
15917 // Only put the placeholder inside the current Container, skip all
15918 // items from other containers. This works because when moving
15919 // an item from one container to another the
15920 // currentContainer is switched before the placeholder is moved.
15922 // Without this, moving items in "sub-sortables" can cause
15923 // the placeholder to jitter between the outer and inner container.
15924 if ( item.instance !== this.currentContainer ) {
15928 // Cannot intersect with itself
15929 // no useless actions that have been done before
15930 // no action if the item moved is the parent of the item checked
15931 if ( itemElement !== this.currentItem[ 0 ] &&
15932 this.placeholder[ intersection === 1 ?
15933 "next" : "prev" ]()[ 0 ] !== itemElement &&
15934 !$.contains( this.placeholder[ 0 ], itemElement ) &&
15935 ( this.options.type === "semi-dynamic" ?
15936 !$.contains( this.element[ 0 ], itemElement ) :
15941 this.direction = intersection === 1 ? "down" : "up";
15943 if ( this.options.tolerance === "pointer" ||
15944 this._intersectsWithSides( item ) ) {
15945 this._rearrange( event, item );
15950 this._trigger( "change", event, this._uiHash() );
15956 //Interconnect with droppables
15957 if ( $.ui.ddmanager ) {
15958 $.ui.ddmanager.drag( this, event );
15962 this._trigger( "sort", event, this._uiHash() );
15964 this.lastPositionAbs = this.positionAbs;
15969 _mouseStop: function( event, noPropagation ) {
15975 //If we are using droppables, inform the manager about the drop
15976 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
15977 $.ui.ddmanager.drop( this, event );
15980 if ( this.options.revert ) {
15982 cur = this.placeholder.offset(),
15983 axis = this.options.axis,
15986 if ( !axis || axis === "x" ) {
15987 animation.left = cur.left - this.offset.parent.left - this.margins.left +
15988 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15990 this.offsetParent[ 0 ].scrollLeft
15993 if ( !axis || axis === "y" ) {
15994 animation.top = cur.top - this.offset.parent.top - this.margins.top +
15995 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15997 this.offsetParent[ 0 ].scrollTop
16000 this.reverting = true;
16001 $( this.helper ).animate(
16003 parseInt( this.options.revert, 10 ) || 500,
16005 that._clear( event );
16009 this._clear( event, noPropagation );
16016 cancel: function() {
16018 if ( this.dragging ) {
16020 this._mouseUp( new $.Event( "mouseup", { target: null } ) );
16022 if ( this.options.helper === "original" ) {
16023 this.currentItem.css( this._storedCSS );
16024 this._removeClass( this.currentItem, "ui-sortable-helper" );
16026 this.currentItem.show();
16029 //Post deactivating events to containers
16030 for ( var i = this.containers.length - 1; i >= 0; i-- ) {
16031 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
16032 if ( this.containers[ i ].containerCache.over ) {
16033 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
16034 this.containers[ i ].containerCache.over = 0;
16040 if ( this.placeholder ) {
16042 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
16043 // it unbinds ALL events from the original node!
16044 if ( this.placeholder[ 0 ].parentNode ) {
16045 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
16047 if ( this.options.helper !== "original" && this.helper &&
16048 this.helper[ 0 ].parentNode ) {
16049 this.helper.remove();
16059 if ( this.domPosition.prev ) {
16060 $( this.domPosition.prev ).after( this.currentItem );
16062 $( this.domPosition.parent ).prepend( this.currentItem );
16070 serialize: function( o ) {
16072 var items = this._getItemsAsjQuery( o && o.connected ),
16076 $( items ).each( function() {
16077 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
16078 .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
16081 ( o.key || res[ 1 ] + "[]" ) +
16082 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
16086 if ( !str.length && o.key ) {
16087 str.push( o.key + "=" );
16090 return str.join( "&" );
16094 toArray: function( o ) {
16096 var items = this._getItemsAsjQuery( o && o.connected ),
16101 items.each( function() {
16102 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
16108 /* Be careful with the following core functions */
16109 _intersectsWith: function( item ) {
16111 var x1 = this.positionAbs.left,
16112 x2 = x1 + this.helperProportions.width,
16113 y1 = this.positionAbs.top,
16114 y2 = y1 + this.helperProportions.height,
16116 r = l + item.width,
16118 b = t + item.height,
16119 dyClick = this.offset.click.top,
16120 dxClick = this.offset.click.left,
16121 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
16122 ( y1 + dyClick ) < b ),
16123 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
16124 ( x1 + dxClick ) < r ),
16125 isOverElement = isOverElementHeight && isOverElementWidth;
16127 if ( this.options.tolerance === "pointer" ||
16128 this.options.forcePointerForContainers ||
16129 ( this.options.tolerance !== "pointer" &&
16130 this.helperProportions[ this.floating ? "width" : "height" ] >
16131 item[ this.floating ? "width" : "height" ] )
16133 return isOverElement;
16136 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
16137 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
16138 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
16139 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
16144 _intersectsWithPointer: function( item ) {
16145 var verticalDirection, horizontalDirection,
16146 isOverElementHeight = ( this.options.axis === "x" ) ||
16148 this.positionAbs.top + this.offset.click.top, item.top, item.height ),
16149 isOverElementWidth = ( this.options.axis === "y" ) ||
16151 this.positionAbs.left + this.offset.click.left, item.left, item.width ),
16152 isOverElement = isOverElementHeight && isOverElementWidth;
16154 if ( !isOverElement ) {
16158 verticalDirection = this.dragDirection.vertical;
16159 horizontalDirection = this.dragDirection.horizontal;
16161 return this.floating ?
16162 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) :
16163 ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
16167 _intersectsWithSides: function( item ) {
16169 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
16170 this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
16171 isOverRightHalf = this._isOverAxis( this.positionAbs.left +
16172 this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
16173 verticalDirection = this.dragDirection.vertical,
16174 horizontalDirection = this.dragDirection.horizontal;
16176 if ( this.floating && horizontalDirection ) {
16177 return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
16178 ( horizontalDirection === "left" && !isOverRightHalf ) );
16180 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
16181 ( verticalDirection === "up" && !isOverBottomHalf ) );
16186 _getDragVerticalDirection: function() {
16187 var delta = this.positionAbs.top - this.lastPositionAbs.top;
16188 return delta !== 0 && ( delta > 0 ? "down" : "up" );
16191 _getDragHorizontalDirection: function() {
16192 var delta = this.positionAbs.left - this.lastPositionAbs.left;
16193 return delta !== 0 && ( delta > 0 ? "right" : "left" );
16196 refresh: function( event ) {
16197 this._refreshItems( event );
16198 this._setHandleClassName();
16199 this.refreshPositions();
16203 _connectWith: function() {
16204 var options = this.options;
16205 return options.connectWith.constructor === String ?
16206 [ options.connectWith ] :
16207 options.connectWith;
16210 _getItemsAsjQuery: function( connected ) {
16212 var i, j, cur, inst,
16215 connectWith = this._connectWith();
16217 if ( connectWith && connected ) {
16218 for ( i = connectWith.length - 1; i >= 0; i-- ) {
16219 cur = $( connectWith[ i ], this.document[ 0 ] );
16220 for ( j = cur.length - 1; j >= 0; j-- ) {
16221 inst = $.data( cur[ j ], this.widgetFullName );
16222 if ( inst && inst !== this && !inst.options.disabled ) {
16223 queries.push( [ typeof inst.options.items === "function" ?
16224 inst.options.items.call( inst.element ) :
16225 $( inst.options.items, inst.element )
16226 .not( ".ui-sortable-helper" )
16227 .not( ".ui-sortable-placeholder" ), inst ] );
16233 queries.push( [ typeof this.options.items === "function" ?
16235 .call( this.element, null, { options: this.options, item: this.currentItem } ) :
16236 $( this.options.items, this.element )
16237 .not( ".ui-sortable-helper" )
16238 .not( ".ui-sortable-placeholder" ), this ] );
16240 function addItems() {
16241 items.push( this );
16243 for ( i = queries.length - 1; i >= 0; i-- ) {
16244 queries[ i ][ 0 ].each( addItems );
16251 _removeCurrentsFromItems: function() {
16253 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
16255 this.items = $.grep( this.items, function( item ) {
16256 for ( var j = 0; j < list.length; j++ ) {
16257 if ( list[ j ] === item.item[ 0 ] ) {
16266 _refreshItems: function( event ) {
16269 this.containers = [ this ];
16271 var i, j, cur, inst, targetData, _queries, item, queriesLength,
16272 items = this.items,
16273 queries = [ [ typeof this.options.items === "function" ?
16274 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
16275 $( this.options.items, this.element ), this ] ],
16276 connectWith = this._connectWith();
16278 //Shouldn't be run the first time through due to massive slow-down
16279 if ( connectWith && this.ready ) {
16280 for ( i = connectWith.length - 1; i >= 0; i-- ) {
16281 cur = $( connectWith[ i ], this.document[ 0 ] );
16282 for ( j = cur.length - 1; j >= 0; j-- ) {
16283 inst = $.data( cur[ j ], this.widgetFullName );
16284 if ( inst && inst !== this && !inst.options.disabled ) {
16285 queries.push( [ typeof inst.options.items === "function" ?
16287 .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
16288 $( inst.options.items, inst.element ), inst ] );
16289 this.containers.push( inst );
16295 for ( i = queries.length - 1; i >= 0; i-- ) {
16296 targetData = queries[ i ][ 1 ];
16297 _queries = queries[ i ][ 0 ];
16299 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
16300 item = $( _queries[ j ] );
16302 // Data for target checking (mouse manager)
16303 item.data( this.widgetName + "-item", targetData );
16307 instance: targetData,
16308 width: 0, height: 0,
16316 _refreshItemPositions: function( fast ) {
16319 for ( i = this.items.length - 1; i >= 0; i-- ) {
16320 item = this.items[ i ];
16322 //We ignore calculating positions of all connected containers when we're not over them
16323 if ( this.currentContainer && item.instance !== this.currentContainer &&
16324 item.item[ 0 ] !== this.currentItem[ 0 ] ) {
16328 t = this.options.toleranceElement ?
16329 $( this.options.toleranceElement, item.item ) :
16333 item.width = t.outerWidth();
16334 item.height = t.outerHeight();
16338 item.left = p.left;
16343 refreshPositions: function( fast ) {
16345 // Determine whether items are being displayed horizontally
16346 this.floating = this.items.length ?
16347 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
16350 if ( this.innermostContainer !== null ) {
16351 this._refreshItemPositions( fast );
16356 if ( this.options.custom && this.options.custom.refreshContainers ) {
16357 this.options.custom.refreshContainers.call( this );
16359 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16360 p = this.containers[ i ].element.offset();
16361 this.containers[ i ].containerCache.left = p.left;
16362 this.containers[ i ].containerCache.top = p.top;
16363 this.containers[ i ].containerCache.width =
16364 this.containers[ i ].element.outerWidth();
16365 this.containers[ i ].containerCache.height =
16366 this.containers[ i ].element.outerHeight();
16373 _createPlaceholder: function( that ) {
16374 that = that || this;
16375 var className, nodeName,
16378 if ( !o.placeholder || o.placeholder.constructor === String ) {
16379 className = o.placeholder;
16380 nodeName = that.currentItem[ 0 ].nodeName.toLowerCase();
16382 element: function() {
16384 var element = $( "<" + nodeName + ">", that.document[ 0 ] );
16386 that._addClass( element, "ui-sortable-placeholder",
16387 className || that.currentItem[ 0 ].className )
16388 ._removeClass( element, "ui-sortable-helper" );
16390 if ( nodeName === "tbody" ) {
16391 that._createTrPlaceholder(
16392 that.currentItem.find( "tr" ).eq( 0 ),
16393 $( "<tr>", that.document[ 0 ] ).appendTo( element )
16395 } else if ( nodeName === "tr" ) {
16396 that._createTrPlaceholder( that.currentItem, element );
16397 } else if ( nodeName === "img" ) {
16398 element.attr( "src", that.currentItem.attr( "src" ) );
16401 if ( !className ) {
16402 element.css( "visibility", "hidden" );
16407 update: function( container, p ) {
16409 // 1. If a className is set as 'placeholder option, we don't force sizes -
16410 // the class is responsible for that
16411 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
16412 // class name is specified
16413 if ( className && !o.forcePlaceholderSize ) {
16417 // If the element doesn't have a actual height or width by itself (without
16418 // styles coming from a stylesheet), it receives the inline height and width
16419 // from the dragged item. Or, if it's a tbody or tr, it's going to have a height
16420 // anyway since we're populating them with <td>s above, but they're unlikely to
16421 // be the correct height on their own if the row heights are dynamic, so we'll
16422 // always assign the height of the dragged item given forcePlaceholderSize
16424 if ( !p.height() || ( o.forcePlaceholderSize &&
16425 ( nodeName === "tbody" || nodeName === "tr" ) ) ) {
16427 that.currentItem.innerHeight() -
16428 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
16429 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
16431 if ( !p.width() ) {
16433 that.currentItem.innerWidth() -
16434 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
16435 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
16441 //Create the placeholder
16442 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
16444 //Append it after the actual current item
16445 that.currentItem.after( that.placeholder );
16447 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
16448 o.placeholder.update( that, that.placeholder );
16452 _createTrPlaceholder: function( sourceTr, targetTr ) {
16455 sourceTr.children().each( function() {
16456 $( "<td> </td>", that.document[ 0 ] )
16457 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
16458 .appendTo( targetTr );
16462 _contactContainers: function( event ) {
16463 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
16465 innermostContainer = null,
16466 innermostIndex = null;
16468 // Get innermost container that intersects with item
16469 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16471 // Never consider a container that's located within the item itself
16472 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
16476 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
16478 // If we've already found a container and it's more "inner" than this, then continue
16479 if ( innermostContainer &&
16481 this.containers[ i ].element[ 0 ],
16482 innermostContainer.element[ 0 ] ) ) {
16486 innermostContainer = this.containers[ i ];
16487 innermostIndex = i;
16491 // container doesn't intersect. trigger "out" event if necessary
16492 if ( this.containers[ i ].containerCache.over ) {
16493 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
16494 this.containers[ i ].containerCache.over = 0;
16500 this.innermostContainer = innermostContainer;
16502 // If no intersecting containers found, return
16503 if ( !innermostContainer ) {
16507 // Move the item into the container if it's not there already
16508 if ( this.containers.length === 1 ) {
16509 if ( !this.containers[ innermostIndex ].containerCache.over ) {
16510 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16511 this.containers[ innermostIndex ].containerCache.over = 1;
16515 // When entering a new container, we will find the item with the least distance and
16516 // append our item near it
16518 itemWithLeastDistance = null;
16519 floating = innermostContainer.floating || this._isFloating( this.currentItem );
16520 posProperty = floating ? "left" : "top";
16521 sizeProperty = floating ? "width" : "height";
16522 axis = floating ? "pageX" : "pageY";
16524 for ( j = this.items.length - 1; j >= 0; j-- ) {
16526 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
16530 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
16534 cur = this.items[ j ].item.offset()[ posProperty ];
16535 nearBottom = false;
16536 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
16540 if ( Math.abs( event[ axis ] - cur ) < dist ) {
16541 dist = Math.abs( event[ axis ] - cur );
16542 itemWithLeastDistance = this.items[ j ];
16543 this.direction = nearBottom ? "up" : "down";
16547 //Check if dropOnEmpty is enabled
16548 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
16552 if ( this.currentContainer === this.containers[ innermostIndex ] ) {
16553 if ( !this.currentContainer.containerCache.over ) {
16554 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
16555 this.currentContainer.containerCache.over = 1;
16560 if ( itemWithLeastDistance ) {
16561 this._rearrange( event, itemWithLeastDistance, null, true );
16563 this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
16565 this._trigger( "change", event, this._uiHash() );
16566 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
16567 this.currentContainer = this.containers[ innermostIndex ];
16569 //Update the placeholder
16570 this.options.placeholder.update( this.currentContainer, this.placeholder );
16572 //Update scrollParent
16573 this.scrollParent = this.placeholder.scrollParent();
16575 //Update overflowOffset
16576 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16577 this.scrollParent[ 0 ].tagName !== "HTML" ) {
16578 this.overflowOffset = this.scrollParent.offset();
16581 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16582 this.containers[ innermostIndex ].containerCache.over = 1;
16587 _createHelper: function( event ) {
16589 var o = this.options,
16590 helper = typeof o.helper === "function" ?
16591 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
16592 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
16594 //Add the helper to the DOM if that didn't happen already
16595 if ( !helper.parents( "body" ).length ) {
16596 this.appendTo[ 0 ].appendChild( helper[ 0 ] );
16599 if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
16600 this._storedCSS = {
16601 width: this.currentItem[ 0 ].style.width,
16602 height: this.currentItem[ 0 ].style.height,
16603 position: this.currentItem.css( "position" ),
16604 top: this.currentItem.css( "top" ),
16605 left: this.currentItem.css( "left" )
16609 if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
16610 helper.width( this.currentItem.width() );
16612 if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
16613 helper.height( this.currentItem.height() );
16620 _adjustOffsetFromHelper: function( obj ) {
16621 if ( typeof obj === "string" ) {
16622 obj = obj.split( " " );
16624 if ( Array.isArray( obj ) ) {
16625 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
16627 if ( "left" in obj ) {
16628 this.offset.click.left = obj.left + this.margins.left;
16630 if ( "right" in obj ) {
16631 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
16633 if ( "top" in obj ) {
16634 this.offset.click.top = obj.top + this.margins.top;
16636 if ( "bottom" in obj ) {
16637 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
16641 _getParentOffset: function() {
16643 //Get the offsetParent and cache its position
16644 this.offsetParent = this.helper.offsetParent();
16645 var po = this.offsetParent.offset();
16647 // This is a special case where we need to modify a offset calculated on start, since the
16648 // following happened:
16649 // 1. The position of the helper is absolute, so it's position is calculated based on the
16650 // next positioned parent
16651 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
16652 // the document, which means that the scroll is included in the initial calculation of the
16653 // offset of the parent, and never recalculated upon drag
16654 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16655 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
16656 po.left += this.scrollParent.scrollLeft();
16657 po.top += this.scrollParent.scrollTop();
16660 // This needs to be actually done for all browsers, since pageX/pageY includes this
16661 // information with an ugly IE fix
16662 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
16663 ( this.offsetParent[ 0 ].tagName &&
16664 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
16665 po = { top: 0, left: 0 };
16669 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
16670 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
16675 _getRelativeOffset: function() {
16677 if ( this.cssPosition === "relative" ) {
16678 var p = this.currentItem.position();
16680 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
16681 this.scrollParent.scrollTop(),
16682 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
16683 this.scrollParent.scrollLeft()
16686 return { top: 0, left: 0 };
16691 _cacheMargins: function() {
16693 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
16694 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
16698 _cacheHelperProportions: function() {
16699 this.helperProportions = {
16700 width: this.helper.outerWidth(),
16701 height: this.helper.outerHeight()
16705 _setContainment: function() {
16709 if ( o.containment === "parent" ) {
16710 o.containment = this.helper[ 0 ].parentNode;
16712 if ( o.containment === "document" || o.containment === "window" ) {
16713 this.containment = [
16714 0 - this.offset.relative.left - this.offset.parent.left,
16715 0 - this.offset.relative.top - this.offset.parent.top,
16716 o.containment === "document" ?
16717 this.document.width() :
16718 this.window.width() - this.helperProportions.width - this.margins.left,
16719 ( o.containment === "document" ?
16720 ( this.document.height() || document.body.parentNode.scrollHeight ) :
16721 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
16722 ) - this.helperProportions.height - this.margins.top
16726 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
16727 ce = $( o.containment )[ 0 ];
16728 co = $( o.containment ).offset();
16729 over = ( $( ce ).css( "overflow" ) !== "hidden" );
16731 this.containment = [
16732 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
16733 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
16734 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
16735 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
16736 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
16737 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
16738 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
16739 this.helperProportions.width - this.margins.left,
16740 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
16741 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
16742 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
16743 this.helperProportions.height - this.margins.top
16749 _convertPositionTo: function( d, pos ) {
16752 pos = this.position;
16754 var mod = d === "absolute" ? 1 : -1,
16755 scroll = this.cssPosition === "absolute" &&
16756 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16757 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16758 this.offsetParent :
16760 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16765 // The absolute mouse position
16768 // Only for relative positioned nodes: Relative offset from element to offset parent
16769 this.offset.relative.top * mod +
16771 // The offsetParent's offset without borders (offset + border)
16772 this.offset.parent.top * mod -
16773 ( ( this.cssPosition === "fixed" ?
16774 -this.scrollParent.scrollTop() :
16775 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
16779 // The absolute mouse position
16782 // Only for relative positioned nodes: Relative offset from element to offset parent
16783 this.offset.relative.left * mod +
16785 // The offsetParent's offset without borders (offset + border)
16786 this.offset.parent.left * mod -
16787 ( ( this.cssPosition === "fixed" ?
16788 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
16789 scroll.scrollLeft() ) * mod )
16795 _generatePosition: function( event ) {
16799 pageX = event.pageX,
16800 pageY = event.pageY,
16801 scroll = this.cssPosition === "absolute" &&
16802 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16803 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16804 this.offsetParent :
16806 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16808 // This is another very weird special case that only happens for relative elements:
16809 // 1. If the css position is relative
16810 // 2. and the scroll parent is the document or similar to the offset parent
16811 // we have to refresh the relative offset during the scroll so there are no jumps
16812 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16813 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
16814 this.offset.relative = this._getRelativeOffset();
16818 * - Position constraining -
16819 * Constrain the position to a mix of grid, containment.
16822 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
16824 if ( this.containment ) {
16825 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
16826 pageX = this.containment[ 0 ] + this.offset.click.left;
16828 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
16829 pageY = this.containment[ 1 ] + this.offset.click.top;
16831 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
16832 pageX = this.containment[ 2 ] + this.offset.click.left;
16834 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
16835 pageY = this.containment[ 3 ] + this.offset.click.top;
16840 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
16841 o.grid[ 1 ] ) * o.grid[ 1 ];
16842 pageY = this.containment ?
16843 ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
16844 top - this.offset.click.top <= this.containment[ 3 ] ) ?
16846 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
16847 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
16850 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
16851 o.grid[ 0 ] ) * o.grid[ 0 ];
16852 pageX = this.containment ?
16853 ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
16854 left - this.offset.click.left <= this.containment[ 2 ] ) ?
16856 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
16857 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
16866 // The absolute mouse position
16869 // Click offset (relative to the element)
16870 this.offset.click.top -
16872 // Only for relative positioned nodes: Relative offset from element to offset parent
16873 this.offset.relative.top -
16875 // The offsetParent's offset without borders (offset + border)
16876 this.offset.parent.top +
16877 ( ( this.cssPosition === "fixed" ?
16878 -this.scrollParent.scrollTop() :
16879 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
16883 // The absolute mouse position
16886 // Click offset (relative to the element)
16887 this.offset.click.left -
16889 // Only for relative positioned nodes: Relative offset from element to offset parent
16890 this.offset.relative.left -
16892 // The offsetParent's offset without borders (offset + border)
16893 this.offset.parent.left +
16894 ( ( this.cssPosition === "fixed" ?
16895 -this.scrollParent.scrollLeft() :
16896 scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
16902 _rearrange: function( event, i, a, hardRefresh ) {
16905 a[ 0 ].appendChild( this.placeholder[ 0 ] );
16907 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
16908 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
16911 //Various things done here to improve the performance:
16912 // 1. we create a setTimeout, that calls refreshPositions
16913 // 2. on the instance, we have a counter variable, that get's higher after every append
16914 // 3. on the local scope, we copy the counter variable, and check in the timeout,
16915 // if it's still the same
16916 // 4. this lets only the last addition to the timeout stack through
16917 this.counter = this.counter ? ++this.counter : 1;
16918 var counter = this.counter;
16920 this._delay( function() {
16921 if ( counter === this.counter ) {
16923 //Precompute after each DOM insertion, NOT on mousemove
16924 this.refreshPositions( !hardRefresh );
16930 _clear: function( event, noPropagation ) {
16932 this.reverting = false;
16934 // We delay all events that have to be triggered to after the point where the placeholder
16935 // has been removed and everything else normalized again
16937 delayedTriggers = [];
16939 // We first have to update the dom position of the actual currentItem
16940 // Note: don't do it if the current item is already removed (by a user), or it gets
16941 // reappended (see #4088)
16942 if ( !this._noFinalSort && this.currentItem.parent().length ) {
16943 this.placeholder.before( this.currentItem );
16945 this._noFinalSort = null;
16947 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
16948 for ( i in this._storedCSS ) {
16949 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
16950 this._storedCSS[ i ] = "";
16953 this.currentItem.css( this._storedCSS );
16954 this._removeClass( this.currentItem, "ui-sortable-helper" );
16956 this.currentItem.show();
16959 if ( this.fromOutside && !noPropagation ) {
16960 delayedTriggers.push( function( event ) {
16961 this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
16964 if ( ( this.fromOutside ||
16965 this.domPosition.prev !==
16966 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
16967 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
16969 // Trigger update callback if the DOM position has changed
16970 delayedTriggers.push( function( event ) {
16971 this._trigger( "update", event, this._uiHash() );
16975 // Check if the items Container has Changed and trigger appropriate
16977 if ( this !== this.currentContainer ) {
16978 if ( !noPropagation ) {
16979 delayedTriggers.push( function( event ) {
16980 this._trigger( "remove", event, this._uiHash() );
16982 delayedTriggers.push( ( function( c ) {
16983 return function( event ) {
16984 c._trigger( "receive", event, this._uiHash( this ) );
16986 } ).call( this, this.currentContainer ) );
16987 delayedTriggers.push( ( function( c ) {
16988 return function( event ) {
16989 c._trigger( "update", event, this._uiHash( this ) );
16991 } ).call( this, this.currentContainer ) );
16995 //Post events to containers
16996 function delayEvent( type, instance, container ) {
16997 return function( event ) {
16998 container._trigger( type, event, instance._uiHash( instance ) );
17001 for ( i = this.containers.length - 1; i >= 0; i-- ) {
17002 if ( !noPropagation ) {
17003 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
17005 if ( this.containers[ i ].containerCache.over ) {
17006 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
17007 this.containers[ i ].containerCache.over = 0;
17011 //Do what was originally in plugins
17012 if ( this.storedCursor ) {
17013 this.document.find( "body" ).css( "cursor", this.storedCursor );
17014 this.storedStylesheet.remove();
17016 if ( this._storedOpacity ) {
17017 this.helper.css( "opacity", this._storedOpacity );
17019 if ( this._storedZIndex ) {
17020 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
17023 this.dragging = false;
17025 if ( !noPropagation ) {
17026 this._trigger( "beforeStop", event, this._uiHash() );
17029 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
17030 // it unbinds ALL events from the original node!
17031 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
17033 if ( !this.cancelHelperRemoval ) {
17034 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
17035 this.helper.remove();
17037 this.helper = null;
17040 if ( !noPropagation ) {
17041 for ( i = 0; i < delayedTriggers.length; i++ ) {
17043 // Trigger all delayed events
17044 delayedTriggers[ i ].call( this, event );
17046 this._trigger( "stop", event, this._uiHash() );
17049 this.fromOutside = false;
17050 return !this.cancelHelperRemoval;
17054 _trigger: function() {
17055 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
17060 _uiHash: function( _inst ) {
17061 var inst = _inst || this;
17063 helper: inst.helper,
17064 placeholder: inst.placeholder || $( [] ),
17065 position: inst.position,
17066 originalPosition: inst.originalPosition,
17067 offset: inst.positionAbs,
17068 item: inst.currentItem,
17069 sender: _inst ? _inst.element : null
17077 * jQuery UI Spinner 1.13.0
17078 * http://jqueryui.com
17080 * Copyright jQuery Foundation and other contributors
17081 * Released under the MIT license.
17082 * http://jquery.org/license
17087 //>>description: Displays buttons to easily input numbers via the keyboard or mouse.
17088 //>>docs: http://api.jqueryui.com/spinner/
17089 //>>demos: http://jqueryui.com/spinner/
17090 //>>css.structure: ../../themes/base/core.css
17091 //>>css.structure: ../../themes/base/spinner.css
17092 //>>css.theme: ../../themes/base/theme.css
17095 function spinnerModifier( fn ) {
17096 return function() {
17097 var previous = this.element.val();
17098 fn.apply( this, arguments );
17100 if ( previous !== this.element.val() ) {
17101 this._trigger( "change" );
17106 $.widget( "ui.spinner", {
17108 defaultElement: "<input>",
17109 widgetEventPrefix: "spin",
17112 "ui-spinner": "ui-corner-all",
17113 "ui-spinner-down": "ui-corner-br",
17114 "ui-spinner-up": "ui-corner-tr"
17118 down: "ui-icon-triangle-1-s",
17119 up: "ui-icon-triangle-1-n"
17124 numberFormat: null,
17134 _create: function() {
17136 // handle string values that need to be parsed
17137 this._setOption( "max", this.options.max );
17138 this._setOption( "min", this.options.min );
17139 this._setOption( "step", this.options.step );
17141 // Only format if there is a value, prevents the field from being marked
17142 // as invalid in Firefox, see #9573.
17143 if ( this.value() !== "" ) {
17145 // Format the value, but don't constrain.
17146 this._value( this.element.val(), true );
17150 this._on( this._events );
17153 // Turning off autocomplete prevents the browser from remembering the
17154 // value when navigating through history, so we re-enable autocomplete
17155 // if the page is unloaded before the widget is destroyed. #7790
17156 this._on( this.window, {
17157 beforeunload: function() {
17158 this.element.removeAttr( "autocomplete" );
17163 _getCreateOptions: function() {
17164 var options = this._super();
17165 var element = this.element;
17167 $.each( [ "min", "max", "step" ], function( i, option ) {
17168 var value = element.attr( option );
17169 if ( value != null && value.length ) {
17170 options[ option ] = value;
17178 keydown: function( event ) {
17179 if ( this._start( event ) && this._keydown( event ) ) {
17180 event.preventDefault();
17184 focus: function() {
17185 this.previous = this.element.val();
17187 blur: function( event ) {
17188 if ( this.cancelBlur ) {
17189 delete this.cancelBlur;
17195 if ( this.previous !== this.element.val() ) {
17196 this._trigger( "change", event );
17199 mousewheel: function( event, delta ) {
17200 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] );
17201 var isActive = this.element[ 0 ] === activeElement;
17203 if ( !isActive || !delta ) {
17207 if ( !this.spinning && !this._start( event ) ) {
17211 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
17212 clearTimeout( this.mousewheelTimer );
17213 this.mousewheelTimer = this._delay( function() {
17214 if ( this.spinning ) {
17215 this._stop( event );
17218 event.preventDefault();
17220 "mousedown .ui-spinner-button": function( event ) {
17223 // We never want the buttons to have focus; whenever the user is
17224 // interacting with the spinner, the focus should be on the input.
17225 // If the input is focused then this.previous is properly set from
17226 // when the input first received focus. If the input is not focused
17227 // then we need to set this.previous based on the value before spinning.
17228 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
17229 this.previous : this.element.val();
17230 function checkFocus() {
17231 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
17233 this.element.trigger( "focus" );
17234 this.previous = previous;
17237 // IE sets focus asynchronously, so we need to check if focus
17238 // moved off of the input because the user clicked on the button.
17239 this._delay( function() {
17240 this.previous = previous;
17245 // Ensure focus is on (or stays on) the text field
17246 event.preventDefault();
17247 checkFocus.call( this );
17250 // IE doesn't prevent moving focus even with event.preventDefault()
17251 // so we set a flag to know when we should ignore the blur event
17252 // and check (again) if focus moved off of the input.
17253 this.cancelBlur = true;
17254 this._delay( function() {
17255 delete this.cancelBlur;
17256 checkFocus.call( this );
17259 if ( this._start( event ) === false ) {
17263 this._repeat( null, $( event.currentTarget )
17264 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
17266 "mouseup .ui-spinner-button": "_stop",
17267 "mouseenter .ui-spinner-button": function( event ) {
17269 // button will add ui-state-active if mouse was down while mouseleave and kept down
17270 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
17274 if ( this._start( event ) === false ) {
17277 this._repeat( null, $( event.currentTarget )
17278 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
17281 // TODO: do we really want to consider this a stop?
17282 // shouldn't we just stop the repeater and wait until mouseup before
17283 // we trigger the stop event?
17284 "mouseleave .ui-spinner-button": "_stop"
17287 // Support mobile enhanced option and make backcompat more sane
17288 _enhance: function() {
17289 this.uiSpinner = this.element
17290 .attr( "autocomplete", "off" )
17300 _draw: function() {
17303 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
17304 this._addClass( "ui-spinner-input" );
17306 this.element.attr( "role", "spinbutton" );
17309 this.buttons = this.uiSpinner.children( "a" )
17310 .attr( "tabIndex", -1 )
17311 .attr( "aria-hidden", true )
17318 // TODO: Right now button does not support classes this is already updated in button PR
17319 this._removeClass( this.buttons, "ui-corner-all" );
17321 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
17322 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
17323 this.buttons.first().button( {
17324 "icon": this.options.icons.up,
17327 this.buttons.last().button( {
17328 "icon": this.options.icons.down,
17332 // IE 6 doesn't understand height: 50% for the buttons
17333 // unless the wrapper has an explicit height
17334 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
17335 this.uiSpinner.height() > 0 ) {
17336 this.uiSpinner.height( this.uiSpinner.height() );
17340 _keydown: function( event ) {
17341 var options = this.options,
17342 keyCode = $.ui.keyCode;
17344 switch ( event.keyCode ) {
17346 this._repeat( null, 1, event );
17349 this._repeat( null, -1, event );
17351 case keyCode.PAGE_UP:
17352 this._repeat( null, options.page, event );
17354 case keyCode.PAGE_DOWN:
17355 this._repeat( null, -options.page, event );
17362 _start: function( event ) {
17363 if ( !this.spinning && this._trigger( "start", event ) === false ) {
17367 if ( !this.counter ) {
17370 this.spinning = true;
17374 _repeat: function( i, steps, event ) {
17377 clearTimeout( this.timer );
17378 this.timer = this._delay( function() {
17379 this._repeat( 40, steps, event );
17382 this._spin( steps * this.options.step, event );
17385 _spin: function( step, event ) {
17386 var value = this.value() || 0;
17388 if ( !this.counter ) {
17392 value = this._adjustValue( value + step * this._increment( this.counter ) );
17394 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
17395 this._value( value );
17400 _increment: function( i ) {
17401 var incremental = this.options.incremental;
17403 if ( incremental ) {
17404 return typeof incremental === "function" ?
17406 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
17412 _precision: function() {
17413 var precision = this._precisionOf( this.options.step );
17414 if ( this.options.min !== null ) {
17415 precision = Math.max( precision, this._precisionOf( this.options.min ) );
17420 _precisionOf: function( num ) {
17421 var str = num.toString(),
17422 decimal = str.indexOf( "." );
17423 return decimal === -1 ? 0 : str.length - decimal - 1;
17426 _adjustValue: function( value ) {
17427 var base, aboveMin,
17428 options = this.options;
17430 // Make sure we're at a valid step
17431 // - find out where we are relative to the base (min or 0)
17432 base = options.min !== null ? options.min : 0;
17433 aboveMin = value - base;
17435 // - round to the nearest step
17436 aboveMin = Math.round( aboveMin / options.step ) * options.step;
17438 // - rounding is based on 0, so adjust back to our base
17439 value = base + aboveMin;
17441 // Fix precision from bad JS floating point math
17442 value = parseFloat( value.toFixed( this._precision() ) );
17445 if ( options.max !== null && value > options.max ) {
17446 return options.max;
17448 if ( options.min !== null && value < options.min ) {
17449 return options.min;
17455 _stop: function( event ) {
17456 if ( !this.spinning ) {
17460 clearTimeout( this.timer );
17461 clearTimeout( this.mousewheelTimer );
17463 this.spinning = false;
17464 this._trigger( "stop", event );
17467 _setOption: function( key, value ) {
17468 var prevValue, first, last;
17470 if ( key === "culture" || key === "numberFormat" ) {
17471 prevValue = this._parse( this.element.val() );
17472 this.options[ key ] = value;
17473 this.element.val( this._format( prevValue ) );
17477 if ( key === "max" || key === "min" || key === "step" ) {
17478 if ( typeof value === "string" ) {
17479 value = this._parse( value );
17482 if ( key === "icons" ) {
17483 first = this.buttons.first().find( ".ui-icon" );
17484 this._removeClass( first, null, this.options.icons.up );
17485 this._addClass( first, null, value.up );
17486 last = this.buttons.last().find( ".ui-icon" );
17487 this._removeClass( last, null, this.options.icons.down );
17488 this._addClass( last, null, value.down );
17491 this._super( key, value );
17494 _setOptionDisabled: function( value ) {
17495 this._super( value );
17497 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
17498 this.element.prop( "disabled", !!value );
17499 this.buttons.button( value ? "disable" : "enable" );
17502 _setOptions: spinnerModifier( function( options ) {
17503 this._super( options );
17506 _parse: function( val ) {
17507 if ( typeof val === "string" && val !== "" ) {
17508 val = window.Globalize && this.options.numberFormat ?
17509 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
17511 return val === "" || isNaN( val ) ? null : val;
17514 _format: function( value ) {
17515 if ( value === "" ) {
17518 return window.Globalize && this.options.numberFormat ?
17519 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
17523 _refresh: function() {
17524 this.element.attr( {
17525 "aria-valuemin": this.options.min,
17526 "aria-valuemax": this.options.max,
17528 // TODO: what should we do with values that can't be parsed?
17529 "aria-valuenow": this._parse( this.element.val() )
17533 isValid: function() {
17534 var value = this.value();
17537 if ( value === null ) {
17541 // If value gets adjusted, it's invalid
17542 return value === this._adjustValue( value );
17545 // Update the value without triggering change
17546 _value: function( value, allowAny ) {
17548 if ( value !== "" ) {
17549 parsed = this._parse( value );
17550 if ( parsed !== null ) {
17552 parsed = this._adjustValue( parsed );
17554 value = this._format( parsed );
17557 this.element.val( value );
17561 _destroy: function() {
17563 .prop( "disabled", false )
17564 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
17566 this.uiSpinner.replaceWith( this.element );
17569 stepUp: spinnerModifier( function( steps ) {
17570 this._stepUp( steps );
17572 _stepUp: function( steps ) {
17573 if ( this._start() ) {
17574 this._spin( ( steps || 1 ) * this.options.step );
17579 stepDown: spinnerModifier( function( steps ) {
17580 this._stepDown( steps );
17582 _stepDown: function( steps ) {
17583 if ( this._start() ) {
17584 this._spin( ( steps || 1 ) * -this.options.step );
17589 pageUp: spinnerModifier( function( pages ) {
17590 this._stepUp( ( pages || 1 ) * this.options.page );
17593 pageDown: spinnerModifier( function( pages ) {
17594 this._stepDown( ( pages || 1 ) * this.options.page );
17597 value: function( newVal ) {
17598 if ( !arguments.length ) {
17599 return this._parse( this.element.val() );
17601 spinnerModifier( this._value ).call( this, newVal );
17604 widget: function() {
17605 return this.uiSpinner;
17610 // TODO: switch return back to widget declaration at top of file when this is removed
17611 if ( $.uiBackCompat !== false ) {
17613 // Backcompat for spinner html extension points
17614 $.widget( "ui.spinner", $.ui.spinner, {
17615 _enhance: function() {
17616 this.uiSpinner = this.element
17617 .attr( "autocomplete", "off" )
17618 .wrap( this._uiSpinnerHtml() )
17622 .append( this._buttonHtml() );
17624 _uiSpinnerHtml: function() {
17628 _buttonHtml: function() {
17629 return "<a></a><a></a>";
17634 var widgetsSpinner = $.ui.spinner;
17638 * jQuery UI Tabs 1.13.0
17639 * http://jqueryui.com
17641 * Copyright jQuery Foundation and other contributors
17642 * Released under the MIT license.
17643 * http://jquery.org/license
17648 //>>description: Transforms a set of container elements into a tab structure.
17649 //>>docs: http://api.jqueryui.com/tabs/
17650 //>>demos: http://jqueryui.com/tabs/
17651 //>>css.structure: ../../themes/base/core.css
17652 //>>css.structure: ../../themes/base/tabs.css
17653 //>>css.theme: ../../themes/base/theme.css
17656 $.widget( "ui.tabs", {
17662 "ui-tabs": "ui-corner-all",
17663 "ui-tabs-nav": "ui-corner-all",
17664 "ui-tabs-panel": "ui-corner-bottom",
17665 "ui-tabs-tab": "ui-corner-top"
17667 collapsible: false,
17669 heightStyle: "content",
17675 beforeActivate: null,
17680 _isLocal: ( function() {
17681 var rhash = /#.*$/;
17683 return function( anchor ) {
17684 var anchorUrl, locationUrl;
17686 anchorUrl = anchor.href.replace( rhash, "" );
17687 locationUrl = location.href.replace( rhash, "" );
17689 // Decoding may throw an error if the URL isn't UTF-8 (#9518)
17691 anchorUrl = decodeURIComponent( anchorUrl );
17692 } catch ( error ) {}
17694 locationUrl = decodeURIComponent( locationUrl );
17695 } catch ( error ) {}
17697 return anchor.hash.length > 1 && anchorUrl === locationUrl;
17701 _create: function() {
17703 options = this.options;
17705 this.running = false;
17707 this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
17708 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
17710 this._processTabs();
17711 options.active = this._initialActive();
17713 // Take disabling tabs via class attribute from HTML
17714 // into account and update option properly.
17715 if ( Array.isArray( options.disabled ) ) {
17716 options.disabled = $.uniqueSort( options.disabled.concat(
17717 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
17718 return that.tabs.index( li );
17723 // Check for length avoids error when initializing empty list
17724 if ( this.options.active !== false && this.anchors.length ) {
17725 this.active = this._findActive( options.active );
17732 if ( this.active.length ) {
17733 this.load( options.active );
17737 _initialActive: function() {
17738 var active = this.options.active,
17739 collapsible = this.options.collapsible,
17740 locationHash = location.hash.substring( 1 );
17742 if ( active === null ) {
17744 // check the fragment identifier in the URL
17745 if ( locationHash ) {
17746 this.tabs.each( function( i, tab ) {
17747 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
17754 // Check for a tab marked active via a class
17755 if ( active === null ) {
17756 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
17759 // No active tab, set to false
17760 if ( active === null || active === -1 ) {
17761 active = this.tabs.length ? 0 : false;
17765 // Handle numbers: negative, out of range
17766 if ( active !== false ) {
17767 active = this.tabs.index( this.tabs.eq( active ) );
17768 if ( active === -1 ) {
17769 active = collapsible ? false : 0;
17773 // Don't allow collapsible: false and active: false
17774 if ( !collapsible && active === false && this.anchors.length ) {
17781 _getCreateEventData: function() {
17784 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
17788 _tabKeydown: function( event ) {
17789 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
17790 selectedIndex = this.tabs.index( focusedTab ),
17791 goingForward = true;
17793 if ( this._handlePageNav( event ) ) {
17797 switch ( event.keyCode ) {
17798 case $.ui.keyCode.RIGHT:
17799 case $.ui.keyCode.DOWN:
17802 case $.ui.keyCode.UP:
17803 case $.ui.keyCode.LEFT:
17804 goingForward = false;
17807 case $.ui.keyCode.END:
17808 selectedIndex = this.anchors.length - 1;
17810 case $.ui.keyCode.HOME:
17813 case $.ui.keyCode.SPACE:
17815 // Activate only, no collapsing
17816 event.preventDefault();
17817 clearTimeout( this.activating );
17818 this._activate( selectedIndex );
17820 case $.ui.keyCode.ENTER:
17822 // Toggle (cancel delayed activation, allow collapsing)
17823 event.preventDefault();
17824 clearTimeout( this.activating );
17826 // Determine if we should collapse or activate
17827 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
17833 // Focus the appropriate tab, based on which key was pressed
17834 event.preventDefault();
17835 clearTimeout( this.activating );
17836 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
17838 // Navigating with control/command key will prevent automatic activation
17839 if ( !event.ctrlKey && !event.metaKey ) {
17841 // Update aria-selected immediately so that AT think the tab is already selected.
17842 // Otherwise AT may confuse the user by stating that they need to activate the tab,
17843 // but the tab will already be activated by the time the announcement finishes.
17844 focusedTab.attr( "aria-selected", "false" );
17845 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
17847 this.activating = this._delay( function() {
17848 this.option( "active", selectedIndex );
17853 _panelKeydown: function( event ) {
17854 if ( this._handlePageNav( event ) ) {
17858 // Ctrl+up moves focus to the current tab
17859 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
17860 event.preventDefault();
17861 this.active.trigger( "focus" );
17865 // Alt+page up/down moves focus to the previous/next tab (and activates)
17866 _handlePageNav: function( event ) {
17867 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
17868 this._activate( this._focusNextTab( this.options.active - 1, false ) );
17871 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
17872 this._activate( this._focusNextTab( this.options.active + 1, true ) );
17877 _findNextTab: function( index, goingForward ) {
17878 var lastTabIndex = this.tabs.length - 1;
17880 function constrain() {
17881 if ( index > lastTabIndex ) {
17885 index = lastTabIndex;
17890 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
17891 index = goingForward ? index + 1 : index - 1;
17897 _focusNextTab: function( index, goingForward ) {
17898 index = this._findNextTab( index, goingForward );
17899 this.tabs.eq( index ).trigger( "focus" );
17903 _setOption: function( key, value ) {
17904 if ( key === "active" ) {
17906 // _activate() will handle invalid values and update this.options
17907 this._activate( value );
17911 this._super( key, value );
17913 if ( key === "collapsible" ) {
17914 this._toggleClass( "ui-tabs-collapsible", null, value );
17916 // Setting collapsible: false while collapsed; open first panel
17917 if ( !value && this.options.active === false ) {
17918 this._activate( 0 );
17922 if ( key === "event" ) {
17923 this._setupEvents( value );
17926 if ( key === "heightStyle" ) {
17927 this._setupHeightStyle( value );
17931 _sanitizeSelector: function( hash ) {
17932 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
17935 refresh: function() {
17936 var options = this.options,
17937 lis = this.tablist.children( ":has(a[href])" );
17939 // Get disabled tabs from class attribute from HTML
17940 // this will get converted to a boolean if needed in _refresh()
17941 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
17942 return lis.index( tab );
17945 this._processTabs();
17947 // Was collapsed or no tabs
17948 if ( options.active === false || !this.anchors.length ) {
17949 options.active = false;
17952 // was active, but active tab is gone
17953 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
17955 // all remaining tabs are disabled
17956 if ( this.tabs.length === options.disabled.length ) {
17957 options.active = false;
17960 // activate previous tab
17962 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
17965 // was active, active tab still exists
17968 // make sure active index is correct
17969 options.active = this.tabs.index( this.active );
17975 _refresh: function() {
17976 this._setOptionDisabled( this.options.disabled );
17977 this._setupEvents( this.options.event );
17978 this._setupHeightStyle( this.options.heightStyle );
17980 this.tabs.not( this.active ).attr( {
17981 "aria-selected": "false",
17982 "aria-expanded": "false",
17985 this.panels.not( this._getPanelForTab( this.active ) )
17988 "aria-hidden": "true"
17991 // Make sure one tab is in the tab order
17992 if ( !this.active.length ) {
17993 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
17997 "aria-selected": "true",
17998 "aria-expanded": "true",
18001 this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
18002 this._getPanelForTab( this.active )
18005 "aria-hidden": "false"
18010 _processTabs: function() {
18012 prevTabs = this.tabs,
18013 prevAnchors = this.anchors,
18014 prevPanels = this.panels;
18016 this.tablist = this._getList().attr( "role", "tablist" );
18017 this._addClass( this.tablist, "ui-tabs-nav",
18018 "ui-helper-reset ui-helper-clearfix ui-widget-header" );
18020 // Prevent users from focusing disabled tabs via click
18022 .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
18023 if ( $( this ).is( ".ui-state-disabled" ) ) {
18024 event.preventDefault();
18029 // Preventing the default action in mousedown doesn't prevent IE
18030 // from focusing the element, so if the anchor gets focused, blur.
18031 // We don't have to worry about focusing the previously focused
18032 // element since clicking on a non-focusable element should focus
18033 // the body anyway.
18034 .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
18035 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
18040 this.tabs = this.tablist.find( "> li:has(a[href])" )
18045 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
18047 this.anchors = this.tabs.map( function() {
18048 return $( "a", this )[ 0 ];
18053 this._addClass( this.anchors, "ui-tabs-anchor" );
18057 this.anchors.each( function( i, anchor ) {
18058 var selector, panel, panelId,
18059 anchorId = $( anchor ).uniqueId().attr( "id" ),
18060 tab = $( anchor ).closest( "li" ),
18061 originalAriaControls = tab.attr( "aria-controls" );
18064 if ( that._isLocal( anchor ) ) {
18065 selector = anchor.hash;
18066 panelId = selector.substring( 1 );
18067 panel = that.element.find( that._sanitizeSelector( selector ) );
18072 // If the tab doesn't already have aria-controls,
18073 // generate an id by using a throw-away element
18074 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
18075 selector = "#" + panelId;
18076 panel = that.element.find( selector );
18077 if ( !panel.length ) {
18078 panel = that._createPanel( panelId );
18079 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
18081 panel.attr( "aria-live", "polite" );
18084 if ( panel.length ) {
18085 that.panels = that.panels.add( panel );
18087 if ( originalAriaControls ) {
18088 tab.data( "ui-tabs-aria-controls", originalAriaControls );
18091 "aria-controls": panelId,
18092 "aria-labelledby": anchorId
18094 panel.attr( "aria-labelledby", anchorId );
18097 this.panels.attr( "role", "tabpanel" );
18098 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
18100 // Avoid memory leaks (#10056)
18102 this._off( prevTabs.not( this.tabs ) );
18103 this._off( prevAnchors.not( this.anchors ) );
18104 this._off( prevPanels.not( this.panels ) );
18108 // Allow overriding how to find the list for rare usage scenarios (#7715)
18109 _getList: function() {
18110 return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
18113 _createPanel: function( id ) {
18114 return $( "<div>" )
18116 .data( "ui-tabs-destroy", true );
18119 _setOptionDisabled: function( disabled ) {
18120 var currentItem, li, i;
18122 if ( Array.isArray( disabled ) ) {
18123 if ( !disabled.length ) {
18125 } else if ( disabled.length === this.anchors.length ) {
18131 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
18132 currentItem = $( li );
18133 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
18134 currentItem.attr( "aria-disabled", "true" );
18135 this._addClass( currentItem, null, "ui-state-disabled" );
18137 currentItem.removeAttr( "aria-disabled" );
18138 this._removeClass( currentItem, null, "ui-state-disabled" );
18142 this.options.disabled = disabled;
18144 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
18145 disabled === true );
18148 _setupEvents: function( event ) {
18151 $.each( event.split( " " ), function( index, eventName ) {
18152 events[ eventName ] = "_eventHandler";
18156 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
18158 // Always prevent the default action, even when disabled
18159 this._on( true, this.anchors, {
18160 click: function( event ) {
18161 event.preventDefault();
18164 this._on( this.anchors, events );
18165 this._on( this.tabs, { keydown: "_tabKeydown" } );
18166 this._on( this.panels, { keydown: "_panelKeydown" } );
18168 this._focusable( this.tabs );
18169 this._hoverable( this.tabs );
18172 _setupHeightStyle: function( heightStyle ) {
18174 parent = this.element.parent();
18176 if ( heightStyle === "fill" ) {
18177 maxHeight = parent.height();
18178 maxHeight -= this.element.outerHeight() - this.element.height();
18180 this.element.siblings( ":visible" ).each( function() {
18181 var elem = $( this ),
18182 position = elem.css( "position" );
18184 if ( position === "absolute" || position === "fixed" ) {
18187 maxHeight -= elem.outerHeight( true );
18190 this.element.children().not( this.panels ).each( function() {
18191 maxHeight -= $( this ).outerHeight( true );
18194 this.panels.each( function() {
18195 $( this ).height( Math.max( 0, maxHeight -
18196 $( this ).innerHeight() + $( this ).height() ) );
18198 .css( "overflow", "auto" );
18199 } else if ( heightStyle === "auto" ) {
18201 this.panels.each( function() {
18202 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
18203 } ).height( maxHeight );
18207 _eventHandler: function( event ) {
18208 var options = this.options,
18209 active = this.active,
18210 anchor = $( event.currentTarget ),
18211 tab = anchor.closest( "li" ),
18212 clickedIsActive = tab[ 0 ] === active[ 0 ],
18213 collapsing = clickedIsActive && options.collapsible,
18214 toShow = collapsing ? $() : this._getPanelForTab( tab ),
18215 toHide = !active.length ? $() : this._getPanelForTab( active ),
18219 newTab: collapsing ? $() : tab,
18223 event.preventDefault();
18225 if ( tab.hasClass( "ui-state-disabled" ) ||
18227 // tab is already loading
18228 tab.hasClass( "ui-tabs-loading" ) ||
18230 // can't switch durning an animation
18233 // click on active header, but not collapsible
18234 ( clickedIsActive && !options.collapsible ) ||
18236 // allow canceling activation
18237 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
18241 options.active = collapsing ? false : this.tabs.index( tab );
18243 this.active = clickedIsActive ? $() : tab;
18248 if ( !toHide.length && !toShow.length ) {
18249 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
18252 if ( toShow.length ) {
18253 this.load( this.tabs.index( tab ), event );
18255 this._toggle( event, eventData );
18258 // Handles show/hide for selecting tabs
18259 _toggle: function( event, eventData ) {
18261 toShow = eventData.newPanel,
18262 toHide = eventData.oldPanel;
18264 this.running = true;
18266 function complete() {
18267 that.running = false;
18268 that._trigger( "activate", event, eventData );
18272 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
18274 if ( toShow.length && that.options.show ) {
18275 that._show( toShow, that.options.show, complete );
18282 // Start out by hiding, then showing, then completing
18283 if ( toHide.length && this.options.hide ) {
18284 this._hide( toHide, this.options.hide, function() {
18285 that._removeClass( eventData.oldTab.closest( "li" ),
18286 "ui-tabs-active", "ui-state-active" );
18290 this._removeClass( eventData.oldTab.closest( "li" ),
18291 "ui-tabs-active", "ui-state-active" );
18296 toHide.attr( "aria-hidden", "true" );
18297 eventData.oldTab.attr( {
18298 "aria-selected": "false",
18299 "aria-expanded": "false"
18302 // If we're switching tabs, remove the old tab from the tab order.
18303 // If we're opening from collapsed state, remove the previous tab from the tab order.
18304 // If we're collapsing, then keep the collapsing tab in the tab order.
18305 if ( toShow.length && toHide.length ) {
18306 eventData.oldTab.attr( "tabIndex", -1 );
18307 } else if ( toShow.length ) {
18308 this.tabs.filter( function() {
18309 return $( this ).attr( "tabIndex" ) === 0;
18311 .attr( "tabIndex", -1 );
18314 toShow.attr( "aria-hidden", "false" );
18315 eventData.newTab.attr( {
18316 "aria-selected": "true",
18317 "aria-expanded": "true",
18322 _activate: function( index ) {
18324 active = this._findActive( index );
18326 // Trying to activate the already active panel
18327 if ( active[ 0 ] === this.active[ 0 ] ) {
18331 // Trying to collapse, simulate a click on the current active header
18332 if ( !active.length ) {
18333 active = this.active;
18336 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
18337 this._eventHandler( {
18339 currentTarget: anchor,
18340 preventDefault: $.noop
18344 _findActive: function( index ) {
18345 return index === false ? $() : this.tabs.eq( index );
18348 _getIndex: function( index ) {
18350 // meta-function to give users option to provide a href string instead of a numerical index.
18351 if ( typeof index === "string" ) {
18352 index = this.anchors.index( this.anchors.filter( "[href$='" +
18353 $.escapeSelector( index ) + "']" ) );
18359 _destroy: function() {
18365 .removeAttr( "role" )
18366 .off( this.eventNamespace );
18369 .removeAttr( "role tabIndex" )
18372 this.tabs.add( this.panels ).each( function() {
18373 if ( $.data( this, "ui-tabs-destroy" ) ) {
18374 $( this ).remove();
18376 $( this ).removeAttr( "role tabIndex " +
18377 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
18381 this.tabs.each( function() {
18382 var li = $( this ),
18383 prev = li.data( "ui-tabs-aria-controls" );
18386 .attr( "aria-controls", prev )
18387 .removeData( "ui-tabs-aria-controls" );
18389 li.removeAttr( "aria-controls" );
18393 this.panels.show();
18395 if ( this.options.heightStyle !== "content" ) {
18396 this.panels.css( "height", "" );
18400 enable: function( index ) {
18401 var disabled = this.options.disabled;
18402 if ( disabled === false ) {
18406 if ( index === undefined ) {
18409 index = this._getIndex( index );
18410 if ( Array.isArray( disabled ) ) {
18411 disabled = $.map( disabled, function( num ) {
18412 return num !== index ? num : null;
18415 disabled = $.map( this.tabs, function( li, num ) {
18416 return num !== index ? num : null;
18420 this._setOptionDisabled( disabled );
18423 disable: function( index ) {
18424 var disabled = this.options.disabled;
18425 if ( disabled === true ) {
18429 if ( index === undefined ) {
18432 index = this._getIndex( index );
18433 if ( $.inArray( index, disabled ) !== -1 ) {
18436 if ( Array.isArray( disabled ) ) {
18437 disabled = $.merge( [ index ], disabled ).sort();
18439 disabled = [ index ];
18442 this._setOptionDisabled( disabled );
18445 load: function( index, event ) {
18446 index = this._getIndex( index );
18448 tab = this.tabs.eq( index ),
18449 anchor = tab.find( ".ui-tabs-anchor" ),
18450 panel = this._getPanelForTab( tab ),
18455 complete = function( jqXHR, status ) {
18456 if ( status === "abort" ) {
18457 that.panels.stop( false, true );
18460 that._removeClass( tab, "ui-tabs-loading" );
18461 panel.removeAttr( "aria-busy" );
18463 if ( jqXHR === that.xhr ) {
18469 if ( this._isLocal( anchor[ 0 ] ) ) {
18473 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
18475 // Support: jQuery <1.8
18476 // jQuery <1.8 returns false if the request is canceled in beforeSend,
18477 // but as of 1.8, $.ajax() always returns a jqXHR object.
18478 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
18479 this._addClass( tab, "ui-tabs-loading" );
18480 panel.attr( "aria-busy", "true" );
18483 .done( function( response, status, jqXHR ) {
18485 // support: jQuery <1.8
18486 // http://bugs.jquery.com/ticket/11778
18487 setTimeout( function() {
18488 panel.html( response );
18489 that._trigger( "load", event, eventData );
18491 complete( jqXHR, status );
18494 .fail( function( jqXHR, status ) {
18496 // support: jQuery <1.8
18497 // http://bugs.jquery.com/ticket/11778
18498 setTimeout( function() {
18499 complete( jqXHR, status );
18505 _ajaxSettings: function( anchor, event, eventData ) {
18509 // Support: IE <11 only
18510 // Strip any hash that exists to prevent errors with the Ajax request
18511 url: anchor.attr( "href" ).replace( /#.*$/, "" ),
18512 beforeSend: function( jqXHR, settings ) {
18513 return that._trigger( "beforeLoad", event,
18514 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
18519 _getPanelForTab: function( tab ) {
18520 var id = $( tab ).attr( "aria-controls" );
18521 return this.element.find( this._sanitizeSelector( "#" + id ) );
18526 // TODO: Switch return back to widget declaration at top of file when this is removed
18527 if ( $.uiBackCompat !== false ) {
18529 // Backcompat for ui-tab class (now ui-tabs-tab)
18530 $.widget( "ui.tabs", $.ui.tabs, {
18531 _processTabs: function() {
18532 this._superApply( arguments );
18533 this._addClass( this.tabs, "ui-tab" );
18538 var widgetsTabs = $.ui.tabs;
18542 * jQuery UI Tooltip 1.13.0
18543 * http://jqueryui.com
18545 * Copyright jQuery Foundation and other contributors
18546 * Released under the MIT license.
18547 * http://jquery.org/license
18552 //>>description: Shows additional information for any element on hover or focus.
18553 //>>docs: http://api.jqueryui.com/tooltip/
18554 //>>demos: http://jqueryui.com/tooltip/
18555 //>>css.structure: ../../themes/base/core.css
18556 //>>css.structure: ../../themes/base/tooltip.css
18557 //>>css.theme: ../../themes/base/theme.css
18560 $.widget( "ui.tooltip", {
18564 "ui-tooltip": "ui-corner-all ui-widget-shadow"
18566 content: function() {
18567 var title = $( this ).attr( "title" );
18569 // Escape title, since we're going from an attribute to raw HTML
18570 return $( "<a>" ).text( title ).html();
18574 // Disabled elements have inconsistent behavior across browsers (#8661)
18575 items: "[title]:not([disabled])",
18579 collision: "flipfit flip"
18589 _addDescribedBy: function( elem, id ) {
18590 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
18591 describedby.push( id );
18593 .data( "ui-tooltip-id", id )
18594 .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) );
18597 _removeDescribedBy: function( elem ) {
18598 var id = elem.data( "ui-tooltip-id" ),
18599 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
18600 index = $.inArray( id, describedby );
18602 if ( index !== -1 ) {
18603 describedby.splice( index, 1 );
18606 elem.removeData( "ui-tooltip-id" );
18607 describedby = String.prototype.trim.call( describedby.join( " " ) );
18608 if ( describedby ) {
18609 elem.attr( "aria-describedby", describedby );
18611 elem.removeAttr( "aria-describedby" );
18615 _create: function() {
18621 // IDs of generated tooltips, needed for destroy
18622 this.tooltips = {};
18624 // IDs of parent tooltips where we removed the title attribute
18627 // Append the aria-live region so tooltips announce correctly
18628 this.liveRegion = $( "<div>" )
18631 "aria-live": "assertive",
18632 "aria-relevant": "additions"
18634 .appendTo( this.document[ 0 ].body );
18635 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
18637 this.disabledTitles = $( [] );
18640 _setOption: function( key, value ) {
18643 this._super( key, value );
18645 if ( key === "content" ) {
18646 $.each( this.tooltips, function( id, tooltipData ) {
18647 that._updateContent( tooltipData.element );
18652 _setOptionDisabled: function( value ) {
18653 this[ value ? "_disable" : "_enable" ]();
18656 _disable: function() {
18659 // Close open tooltips
18660 $.each( this.tooltips, function( id, tooltipData ) {
18661 var event = $.Event( "blur" );
18662 event.target = event.currentTarget = tooltipData.element[ 0 ];
18663 that.close( event, true );
18666 // Remove title attributes to prevent native tooltips
18667 this.disabledTitles = this.disabledTitles.add(
18668 this.element.find( this.options.items ).addBack()
18669 .filter( function() {
18670 var element = $( this );
18671 if ( element.is( "[title]" ) ) {
18673 .data( "ui-tooltip-title", element.attr( "title" ) )
18674 .removeAttr( "title" );
18680 _enable: function() {
18682 // restore title attributes
18683 this.disabledTitles.each( function() {
18684 var element = $( this );
18685 if ( element.data( "ui-tooltip-title" ) ) {
18686 element.attr( "title", element.data( "ui-tooltip-title" ) );
18689 this.disabledTitles = $( [] );
18692 open: function( event ) {
18694 target = $( event ? event.target : this.element )
18696 // we need closest here due to mouseover bubbling,
18697 // but always pointing at the same event target
18698 .closest( this.options.items );
18700 // No element to show a tooltip for or the tooltip is already open
18701 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
18705 if ( target.attr( "title" ) ) {
18706 target.data( "ui-tooltip-title", target.attr( "title" ) );
18709 target.data( "ui-tooltip-open", true );
18711 // Kill parent tooltips, custom or native, for hover
18712 if ( event && event.type === "mouseover" ) {
18713 target.parents().each( function() {
18714 var parent = $( this ),
18716 if ( parent.data( "ui-tooltip-open" ) ) {
18717 blurEvent = $.Event( "blur" );
18718 blurEvent.target = blurEvent.currentTarget = this;
18719 that.close( blurEvent, true );
18721 if ( parent.attr( "title" ) ) {
18723 that.parents[ this.id ] = {
18725 title: parent.attr( "title" )
18727 parent.attr( "title", "" );
18732 this._registerCloseHandlers( event, target );
18733 this._updateContent( target, event );
18736 _updateContent: function( target, event ) {
18738 contentOption = this.options.content,
18740 eventType = event ? event.type : null;
18742 if ( typeof contentOption === "string" || contentOption.nodeType ||
18743 contentOption.jquery ) {
18744 return this._open( event, target, contentOption );
18747 content = contentOption.call( target[ 0 ], function( response ) {
18749 // IE may instantly serve a cached response for ajax requests
18750 // delay this call to _open so the other call to _open runs first
18751 that._delay( function() {
18753 // Ignore async response if tooltip was closed already
18754 if ( !target.data( "ui-tooltip-open" ) ) {
18758 // JQuery creates a special event for focusin when it doesn't
18759 // exist natively. To improve performance, the native event
18760 // object is reused and the type is changed. Therefore, we can't
18761 // rely on the type being correct after the event finished
18762 // bubbling, so we set it back to the previous value. (#8740)
18764 event.type = eventType;
18766 this._open( event, target, response );
18770 this._open( event, target, content );
18774 _open: function( event, target, content ) {
18775 var tooltipData, tooltip, delayedShow, a11yContent,
18776 positionOption = $.extend( {}, this.options.position );
18782 // Content can be updated multiple times. If the tooltip already
18783 // exists, then just update the content and bail.
18784 tooltipData = this._find( target );
18785 if ( tooltipData ) {
18786 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
18790 // If we have a title, clear it to prevent the native tooltip
18791 // we have to check first to avoid defining a title if none exists
18792 // (we don't want to cause an element to start matching [title])
18794 // We use removeAttr only for key events, to allow IE to export the correct
18795 // accessible attributes. For mouse events, set to empty string to avoid
18796 // native tooltip showing up (happens only when removing inside mouseover).
18797 if ( target.is( "[title]" ) ) {
18798 if ( event && event.type === "mouseover" ) {
18799 target.attr( "title", "" );
18801 target.removeAttr( "title" );
18805 tooltipData = this._tooltip( target );
18806 tooltip = tooltipData.tooltip;
18807 this._addDescribedBy( target, tooltip.attr( "id" ) );
18808 tooltip.find( ".ui-tooltip-content" ).html( content );
18810 // Support: Voiceover on OS X, JAWS on IE <= 9
18811 // JAWS announces deletions even when aria-relevant="additions"
18812 // Voiceover will sometimes re-read the entire log region's contents from the beginning
18813 this.liveRegion.children().hide();
18814 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
18815 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
18816 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
18817 a11yContent.appendTo( this.liveRegion );
18819 function position( event ) {
18820 positionOption.of = event;
18821 if ( tooltip.is( ":hidden" ) ) {
18824 tooltip.position( positionOption );
18826 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
18827 this._on( this.document, {
18828 mousemove: position
18831 // trigger once to override element-relative positioning
18834 tooltip.position( $.extend( {
18836 }, this.options.position ) );
18841 this._show( tooltip, this.options.show );
18843 // Handle tracking tooltips that are shown with a delay (#8644). As soon
18844 // as the tooltip is visible, position the tooltip using the most recent
18846 // Adds the check to add the timers only when both delay and track options are set (#14682)
18847 if ( this.options.track && this.options.show && this.options.show.delay ) {
18848 delayedShow = this.delayedShow = setInterval( function() {
18849 if ( tooltip.is( ":visible" ) ) {
18850 position( positionOption.of );
18851 clearInterval( delayedShow );
18856 this._trigger( "open", event, { tooltip: tooltip } );
18859 _registerCloseHandlers: function( event, target ) {
18861 keyup: function( event ) {
18862 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
18863 var fakeEvent = $.Event( event );
18864 fakeEvent.currentTarget = target[ 0 ];
18865 this.close( fakeEvent, true );
18870 // Only bind remove handler for delegated targets. Non-delegated
18871 // tooltips will handle this in destroy.
18872 if ( target[ 0 ] !== this.element[ 0 ] ) {
18873 events.remove = function() {
18874 this._removeTooltip( this._find( target ).tooltip );
18878 if ( !event || event.type === "mouseover" ) {
18879 events.mouseleave = "close";
18881 if ( !event || event.type === "focusin" ) {
18882 events.focusout = "close";
18884 this._on( true, target, events );
18887 close: function( event ) {
18890 target = $( event ? event.currentTarget : this.element ),
18891 tooltipData = this._find( target );
18893 // The tooltip may already be closed
18894 if ( !tooltipData ) {
18896 // We set ui-tooltip-open immediately upon open (in open()), but only set the
18897 // additional data once there's actually content to show (in _open()). So even if the
18898 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
18899 // the period between open() and _open().
18900 target.removeData( "ui-tooltip-open" );
18904 tooltip = tooltipData.tooltip;
18906 // Disabling closes the tooltip, so we need to track when we're closing
18907 // to avoid an infinite loop in case the tooltip becomes disabled on close
18908 if ( tooltipData.closing ) {
18912 // Clear the interval for delayed tracking tooltips
18913 clearInterval( this.delayedShow );
18915 // Only set title if we had one before (see comment in _open())
18916 // If the title attribute has changed since open(), don't restore
18917 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
18918 target.attr( "title", target.data( "ui-tooltip-title" ) );
18921 this._removeDescribedBy( target );
18923 tooltipData.hiding = true;
18924 tooltip.stop( true );
18925 this._hide( tooltip, this.options.hide, function() {
18926 that._removeTooltip( $( this ) );
18929 target.removeData( "ui-tooltip-open" );
18930 this._off( target, "mouseleave focusout keyup" );
18932 // Remove 'remove' binding only on delegated targets
18933 if ( target[ 0 ] !== this.element[ 0 ] ) {
18934 this._off( target, "remove" );
18936 this._off( this.document, "mousemove" );
18938 if ( event && event.type === "mouseleave" ) {
18939 $.each( this.parents, function( id, parent ) {
18940 $( parent.element ).attr( "title", parent.title );
18941 delete that.parents[ id ];
18945 tooltipData.closing = true;
18946 this._trigger( "close", event, { tooltip: tooltip } );
18947 if ( !tooltipData.hiding ) {
18948 tooltipData.closing = false;
18952 _tooltip: function( element ) {
18953 var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
18954 content = $( "<div>" ).appendTo( tooltip ),
18955 id = tooltip.uniqueId().attr( "id" );
18957 this._addClass( content, "ui-tooltip-content" );
18958 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
18960 tooltip.appendTo( this._appendTo( element ) );
18962 return this.tooltips[ id ] = {
18968 _find: function( target ) {
18969 var id = target.data( "ui-tooltip-id" );
18970 return id ? this.tooltips[ id ] : null;
18973 _removeTooltip: function( tooltip ) {
18975 // Clear the interval for delayed tracking tooltips
18976 clearInterval( this.delayedShow );
18979 delete this.tooltips[ tooltip.attr( "id" ) ];
18982 _appendTo: function( target ) {
18983 var element = target.closest( ".ui-front, dialog" );
18985 if ( !element.length ) {
18986 element = this.document[ 0 ].body;
18992 _destroy: function() {
18995 // Close open tooltips
18996 $.each( this.tooltips, function( id, tooltipData ) {
18998 // Delegate to close method to handle common cleanup
18999 var event = $.Event( "blur" ),
19000 element = tooltipData.element;
19001 event.target = event.currentTarget = element[ 0 ];
19002 that.close( event, true );
19004 // Remove immediately; destroying an open tooltip doesn't use the
19006 $( "#" + id ).remove();
19008 // Restore the title
19009 if ( element.data( "ui-tooltip-title" ) ) {
19011 // If the title attribute has changed since open(), don't restore
19012 if ( !element.attr( "title" ) ) {
19013 element.attr( "title", element.data( "ui-tooltip-title" ) );
19015 element.removeData( "ui-tooltip-title" );
19018 this.liveRegion.remove();
19023 // TODO: Switch return back to widget declaration at top of file when this is removed
19024 if ( $.uiBackCompat !== false ) {
19026 // Backcompat for tooltipClass option
19027 $.widget( "ui.tooltip", $.ui.tooltip, {
19031 _tooltip: function() {
19032 var tooltipData = this._superApply( arguments );
19033 if ( this.options.tooltipClass ) {
19034 tooltipData.tooltip.addClass( this.options.tooltipClass );
19036 return tooltipData;
19041 var widgetsTooltip = $.ui.tooltip;